Skip to content

Commit 112a244

Browse files
committed
tools: smoke test generating Go from JSON schemas
Use go-jsonschema to generate Go code from the JSON schemas. We explicitly don't want to distribute that generated code, but it's helpful to verify that at least one tool is able to do codegen without error from the schema files. By asserting that there are no warnings we also catch cases where identical schema object names result in duplicate type definitions that require clunky suffixing. This is a strong indicator there's schema elements we should de-duplicate and catching these early helps make the schemas _and_ the generated code better.
1 parent 85497e7 commit 112a244

File tree

4 files changed

+105
-2
lines changed

4 files changed

+105
-2
lines changed

.github/workflows/vectorlint.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ jobs:
4242

4343
- name: Run twistcheck
4444
run: go run ./tools/twistcheck
45+
46+
- name: Run schemagen
47+
run: go run ./tools/schemagen

go.mod

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
module github.com/c2sp/wycheproof
22

3-
go 1.23.6
3+
go 1.24.0
44

55
require (
66
filippo.io/edwards25519 v1.1.0
77
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
88
)
99

10-
require golang.org/x/text v0.14.0 // indirect
10+
require (
11+
dario.cat/mergo v1.0.2 // indirect
12+
github.com/atombender/go-jsonschema v0.22.0 // indirect
13+
github.com/goccy/go-yaml v1.19.2 // indirect
14+
github.com/google/go-cmp v0.7.0 // indirect
15+
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
16+
github.com/sanity-io/litter v1.5.8 // indirect
17+
github.com/sosodev/duration v1.3.1 // indirect
18+
golang.org/x/text v0.14.0 // indirect
19+
)

go.sum

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1+
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
2+
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
13
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
24
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
5+
github.com/atombender/go-jsonschema v0.22.0 h1:7H48X5fUccsfsacar5UfP6nnOXuQzmnr6lQmH/Fj2pQ=
6+
github.com/atombender/go-jsonschema v0.22.0/go.mod h1:8Q281v0ozTIfvdnbwDoWQDIk0syH6F0Fpoq+Z1cs+rM=
7+
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
38
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
49
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
10+
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
11+
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
12+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
13+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
14+
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
15+
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
16+
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
17+
github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=
18+
github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
519
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
620
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
21+
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
22+
github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
23+
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
724
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
825
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

tools/schemagen/schemagen.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// schemagen is a smoke test that go-jsonschema is able to generate Go code
2+
// for the Wycheproof JSON schemas without any errors or warnings.
3+
//
4+
// In particular this is useful for catching cases where we are emitting
5+
// schema types with conflicting names as this is often a strong indicator
6+
// that there's commonality we can lift into a single shared definition.
7+
// Ignoring these warnings results in generated types with clunky numeric
8+
// suffixes (e.g. `SignatureTestCase` and `SignatureTestCase_1`)
9+
package main
10+
11+
import (
12+
"flag"
13+
"log"
14+
"os"
15+
"path/filepath"
16+
17+
"github.com/atombender/go-jsonschema/pkg/generator"
18+
)
19+
20+
var schemaDirectory = flag.String("schemas-dir", "schemas", "directory containing schema files")
21+
22+
func main() {
23+
flag.Parse()
24+
25+
var warnings []string
26+
27+
ouputName := "schema.go"
28+
cfg := generator.Config{
29+
DefaultPackageName: "wycheproof",
30+
DefaultOutputName: ouputName,
31+
Tags: []string{"json"},
32+
Warner: func(message string) {
33+
warnings = append(warnings, message)
34+
},
35+
}
36+
gen, err := generator.New(cfg)
37+
if err != nil {
38+
log.Fatal(err)
39+
}
40+
41+
entries, err := os.ReadDir(*schemaDirectory)
42+
if err != nil {
43+
log.Fatalf("reading schemas dir: %v", err)
44+
}
45+
46+
for _, entry := range entries {
47+
if entry.IsDir() {
48+
continue
49+
}
50+
schemaFile := filepath.Join(*schemaDirectory, entry.Name())
51+
err = gen.DoFile(schemaFile)
52+
if err != nil {
53+
log.Fatalf("processing %s: %v", schemaFile, err)
54+
}
55+
}
56+
57+
sources, err := gen.Sources()
58+
if err != nil {
59+
log.Fatalf("error generating sources: %v\n", err)
60+
}
61+
if sourceCount := len(sources); sourceCount != 1 {
62+
log.Fatalf("expected to generate 1 source file, got %d\n", sourceCount)
63+
}
64+
_, ok := sources[ouputName]
65+
if !ok {
66+
log.Fatalf("missing generated %q output file source", ouputName)
67+
}
68+
69+
for _, warning := range warnings {
70+
log.Printf("⚠️ Warning: %s", warning)
71+
}
72+
73+
os.Exit(len(warnings))
74+
}

0 commit comments

Comments
 (0)