diff --git a/encoding/openapi/decode_test.go b/encoding/openapi/decode_test.go index edf586788..6087e933d 100644 --- a/encoding/openapi/decode_test.go +++ b/encoding/openapi/decode_test.go @@ -39,8 +39,13 @@ import ( "cuelang.org/go/internal/cuetest" ) -// TestDecode reads the testdata/*.txtar files, converts the contained -// JSON schema to CUE and compares it against the output. +// TestDecode reads the testdata/script/*.txtar files, converts the +// contained JSON (or YAML) schema to CUE and compares it against the +// output. +// +// The first .json or .yaml file in the txtar archive (with no / in +// the name) is used as the input. The first .cue file in the archive +// (with no / in the name) is used as the expected output. // // Set CUE_UPDATE=1 to update test files with the corresponding output. func TestDecode(t *testing.T) { @@ -65,18 +70,29 @@ func TestDecode(t *testing.T) { outIndex := -1 for i, f := range a.Files { + if strings.Contains(f.Name, "/") { + continue + } switch path.Ext(f.Name) { case ".json": - var inExpr ast.Expr - inExpr, err = json.Extract(f.Name, f.Data) - inFile = internal.ToFile(inExpr) + if inFile == nil { + var inExpr ast.Expr + inExpr, err = json.Extract(f.Name, f.Data) + inFile = internal.ToFile(inExpr) + } case ".yaml": - inFile, err = yaml.Extract(f.Name, f.Data) + if inFile == nil { + inFile, err = yaml.Extract(f.Name, f.Data) + } case ".cue": - out = f.Data - outIndex = i + if out == nil { + out = f.Data + outIndex = i + } case ".err": - errout = f.Data + if errout == nil { + errout = f.Data + } } } if err != nil { diff --git a/encoding/openapi/openapi_test.go b/encoding/openapi/openapi_test.go index f2bd4d372..036e3e238 100644 --- a/encoding/openapi/openapi_test.go +++ b/encoding/openapi/openapi_test.go @@ -29,98 +29,90 @@ import ( "cuelang.org/go/cue/errors" "cuelang.org/go/cue/load" "cuelang.org/go/encoding/openapi" + "cuelang.org/go/internal/cuetdtest" "cuelang.org/go/internal/cuetest" + "cuelang.org/go/internal/cuetxtar" ) +var ( + matrix = cuetdtest.FullMatrix +) + +func TestGenerateOpenAPI(t *testing.T) { + test := cuetxtar.TxTarTest{ + Root: "./testdata", + Name: t.Name(), + Matrix: matrix, + } + + test.Run(t, func(t *cuetxtar.Test) { + if t.HasTag("skip-" + t.Name()) { + t.Skip() + } + + a := t.Instance() + ctx := t.CueContext() + v := ctx.BuildInstance(a) + + if err := v.Err(); err != nil { + t.Fatal(errors.Details(err, nil)) + } + + config := openapi.Config{} + if t.HasTag("ExpandReferences") { + config.ExpandReferences = true + } + if filter, ok := t.Value("FieldFilter"); ok { + config.FieldFilter = filter + } + if version, ok := t.Value("Version"); ok { + config.Version = version + } + + expectedErr, shouldErr := t.Value("ExpectError") + b, err := openapi.Gen(v, &config) + if err != nil { + details := errors.Details(err, nil) + if !shouldErr || !strings.Contains(details, expectedErr) { + t.Fatal("unexpected error:", details) + } + return + } + + if shouldErr { + t.Fatal("unexpected success") + } else { + _, err := openapi.Generate(v, &config) + if err != nil { + t.Fatal(err) + } + } + + var out = &bytes.Buffer{} + err = json.Indent(out, b, "", " ") + if err != nil { + t.Fatal(err) + } + + w := t.Writer("out.json") + jsonStr := out.String() + jsonStr = strings.TrimSpace(jsonStr) + "\n" + _, err = w.Write([]byte(jsonStr)) + if err != nil { + t.Fatal(err) + } + }) +} + func TestParseDefinitions(t *testing.T) { info := struct { Title string `json:"title"` Version string `json:"version"` }{"test", "v1"} - defaultConfig := &openapi.Config{} - resolveRefs := &openapi.Config{Info: info, ExpandReferences: true} - testCases := []struct { in, out string - variant string config *openapi.Config - err string }{{ - in: "structural.cue", - out: "structural.json", - config: resolveRefs, - }, { - in: "protobuf.cue", - out: "protobuf.json", - config: &openapi.Config{ - Info: info, - ExpandReferences: true, - }, - }, { - in: "nested.cue", - out: "nested.json", - config: defaultConfig, - }, { - in: "simple.cue", - out: "simple.json", - config: resolveRefs, - }, { - in: "simple.cue", - out: "simple-filter.json", - config: &openapi.Config{Info: info, FieldFilter: "min.*|max.*"}, - }, { - in: "array.cue", - out: "array.json", - config: defaultConfig, - }, { - in: "enum.cue", - out: "enum.json", - config: defaultConfig, - }, { - in: "struct.cue", - out: "struct.json", - config: defaultConfig, - }, { - in: "strings.cue", - out: "strings.json", - config: defaultConfig, - }, { - in: "nums.cue", - out: "nums.json", - config: defaultConfig, - }, { - in: "nums.cue", - out: "nums-v3.1.0.json", - config: &openapi.Config{Info: info, Version: "3.1.0"}, - }, { - in: "builtins.cue", - out: "builtins.json", - config: defaultConfig, - }, { - in: "oneof.cue", - out: "oneof.json", - config: defaultConfig, - }, { - in: "oneof.cue", - out: "oneof-resolve.json", - config: resolveRefs, - }, { - in: "openapi.cue", - out: "openapi.json", - config: defaultConfig, - }, { - in: "openapi.cue", - out: "openapi-norefs.json", - config: resolveRefs, - }, { - in: "embed.cue", - out: "embed.json", - config: defaultConfig, - }, { - in: "embed.cue", - out: "embed-norefs.json", - config: resolveRefs, - }, { in: "oneof.cue", out: "oneof-funcs.json", config: &openapi.Config{ @@ -154,71 +146,9 @@ func TestParseDefinitions(t *testing.T) { return strings.TrimPrefix(path.String(), "#") }, }, - }, { - in: "issue131.cue", - out: "issue131.json", - config: &openapi.Config{Info: info, SelfContained: true}, - }, { - // Issue #915 - in: "cycle.cue", - out: "cycle.json", - config: &openapi.Config{Info: info}, - }, { - // Issue #915 - in: "cycle.cue", - config: &openapi.Config{Info: info, ExpandReferences: true}, - err: "cycle", - }, { - in: "quotedfield.cue", - out: "quotedfield.json", - config: defaultConfig, - }, { - in: "omitvalue.cue", - out: "omitvalue.json", - config: defaultConfig, - }, { - in: "issue3718.cue", - out: "issue3718.json", - config: defaultConfig, }} for _, tc := range testCases { - t.Run(tc.out+tc.variant, func(t *testing.T) { - run := func(t *testing.T, inst cue.InstanceOrValue) { - b, err := openapi.Gen(inst, tc.config) - if err != nil { - if tc.err == "" { - t.Fatal("unexpected error:", errors.Details(err, nil)) - } - return - } - - if tc.err != "" { - t.Fatal("unexpected success:", tc.err) - } else { - _, err := openapi.Generate(inst, tc.config) - if err != nil { - t.Fatal(err) - } - } - - var out = &bytes.Buffer{} - _ = json.Indent(out, b, "", " ") - - wantFile := filepath.Join("testdata", tc.out) - if cuetest.UpdateGoldenFiles { - _ = os.WriteFile(wantFile, out.Bytes(), 0666) - return - } - - b, err = os.ReadFile(wantFile) - if err != nil { - t.Fatal(err) - } - - if d := cmp.Diff(string(b), out.String()); d != "" { - t.Errorf("files differ:\n%v", d) - } - } + t.Run(tc.out, func(t *testing.T) { filename := filepath.FromSlash(tc.in) inst := load.Instances([]string{filename}, &load.Config{ Dir: "./testdata", @@ -228,7 +158,34 @@ func TestParseDefinitions(t *testing.T) { if err := v.Err(); err != nil { t.Fatal(errors.Details(err, nil)) } - run(t, v) + + b, err := openapi.Gen(v, tc.config) + if err != nil { + t.Fatal("unexpected error:", errors.Details(err, nil)) + } + + _, err = openapi.Generate(v, tc.config) + if err != nil { + t.Fatal(err) + } + + var out = &bytes.Buffer{} + _ = json.Indent(out, b, "", " ") + + wantFile := filepath.Join("testdata", tc.out) + if cuetest.UpdateGoldenFiles { + _ = os.WriteFile(wantFile, out.Bytes(), 0666) + return + } + + b, err = os.ReadFile(wantFile) + if err != nil { + t.Fatal(err) + } + + if d := cmp.Diff(string(b), out.String()); d != "" { + t.Errorf("files differ:\n%v", d) + } }) } } diff --git a/encoding/openapi/testdata/array.cue b/encoding/openapi/testdata/array.cue deleted file mode 100644 index 8ef6b25ac..000000000 --- a/encoding/openapi/testdata/array.cue +++ /dev/null @@ -1,28 +0,0 @@ -import "list" - -#Arrays: { - bar?: [...#MyEnum] - foo?: [...#MyStruct] - - baz?: list.UniqueItems() - - qux?: list.MinItems(1) & list.MaxItems(3) - - closedConcreteList?: [1, 2, 3] - openConcreteList?: [1, 2, 3, ...] -} - -#Arrays: { - bar?: [...#MyEnum] - foo?: [...#MyStruct] -} - -// MyStruct -#MyStruct: { - a?: int - e?: [...#MyEnum] - e?: [...#MyEnum] -} - -// MyEnum -#MyEnum: *"1" | "2" | "3" diff --git a/encoding/openapi/testdata/array.json b/encoding/openapi/testdata/array.txtar similarity index 88% rename from encoding/openapi/testdata/array.json rename to encoding/openapi/testdata/array.txtar index 9028c75ea..a3bb3b8b4 100644 --- a/encoding/openapi/testdata/array.json +++ b/encoding/openapi/testdata/array.txtar @@ -1,3 +1,34 @@ +-- in.cue -- +import "list" + +#Arrays: { + bar?: [...#MyEnum] + foo?: [...#MyStruct] + + baz?: list.UniqueItems() + + qux?: list.MinItems(1) & list.MaxItems(3) + + closedConcreteList?: [1, 2, 3] + openConcreteList?: [1, 2, 3, ...] +} + +#Arrays: { + bar?: [...#MyEnum] + foo?: [...#MyStruct] +} + +// MyStruct +#MyStruct: { + a?: int + e?: [...#MyEnum] + e?: [...#MyEnum] +} + +// MyEnum +#MyEnum: *"1" | "2" | "3" + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/builtins.cue b/encoding/openapi/testdata/builtins.cue deleted file mode 100644 index cd51239d1..000000000 --- a/encoding/openapi/testdata/builtins.cue +++ /dev/null @@ -1,22 +0,0 @@ -import ( - "time" - "list" -) - -let _time = time - -#MyStruct: { - timestamp1?: time.Time - timestamp2?: time.Time() - timestamp3?: time.Format(time.RFC3339Nano) - timestamp4?: _time.Time - date1?: time.Format(time.RFC3339Date) - date2?: _time.Format(time.RFC3339Date) - - // This is not an OpenAPI type and has no format. In this case - // we map to a type so that it can be documented properly (without - // repeating it). - timeout?: time.Duration - - contains: list.Contains("foo") // not supported, but should be recognized as list -} diff --git a/encoding/openapi/testdata/builtins.json b/encoding/openapi/testdata/builtins.txtar similarity index 69% rename from encoding/openapi/testdata/builtins.json rename to encoding/openapi/testdata/builtins.txtar index 92dc87f93..3132b64ee 100644 --- a/encoding/openapi/testdata/builtins.json +++ b/encoding/openapi/testdata/builtins.txtar @@ -1,3 +1,28 @@ +-- in.cue -- +import ( + "time" + "list" +) + +let _time = time + +#MyStruct: { + timestamp1?: time.Time + timestamp2?: time.Time() + timestamp3?: time.Format(time.RFC3339Nano) + timestamp4?: _time.Time + date1?: time.Format(time.RFC3339Date) + date2?: _time.Format(time.RFC3339Date) + + // This is not an OpenAPI type and has no format. In this case + // we map to a type so that it can be documented properly (without + // repeating it). + timeout?: time.Duration + + contains: list.Contains("foo") // not supported, but should be recognized as list +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/cycle-norefs.txtar b/encoding/openapi/testdata/cycle-norefs.txtar new file mode 100644 index 000000000..827a07590 --- /dev/null +++ b/encoding/openapi/testdata/cycle-norefs.txtar @@ -0,0 +1,6 @@ +#ExpandReferences +#ExpectError: cycle in reference at #Foo +-- in.cue -- + // Issue #915 +#Foo: [string]: #Foo + diff --git a/encoding/openapi/testdata/cycle.cue b/encoding/openapi/testdata/cycle.cue deleted file mode 100644 index eb5cd110b..000000000 --- a/encoding/openapi/testdata/cycle.cue +++ /dev/null @@ -1,2 +0,0 @@ - // Issue #915 -#Foo: [string]: #Foo diff --git a/encoding/openapi/testdata/cycle.json b/encoding/openapi/testdata/cycle.txtar similarity index 66% rename from encoding/openapi/testdata/cycle.json rename to encoding/openapi/testdata/cycle.txtar index 49c86dcd2..7cd2d0cd3 100644 --- a/encoding/openapi/testdata/cycle.json +++ b/encoding/openapi/testdata/cycle.txtar @@ -1,8 +1,13 @@ +-- in.cue -- +// Issue #915 +#Foo: [string]: #Foo + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { @@ -16,4 +21,4 @@ } } } -} \ No newline at end of file +} diff --git a/encoding/openapi/testdata/embed-norefs.json b/encoding/openapi/testdata/embed-norefs.txtar similarity index 92% rename from encoding/openapi/testdata/embed-norefs.json rename to encoding/openapi/testdata/embed-norefs.txtar index 4274bcc71..e291b09ce 100644 --- a/encoding/openapi/testdata/embed-norefs.json +++ b/encoding/openapi/testdata/embed-norefs.txtar @@ -1,8 +1,24 @@ +#ExpandReferences +#skip-v3 +-- in.cue -- +#Foo: string + +#LoadBalancerSettings: { + {} | { + consistentHash: #ConsistentHashLB + b: #Foo + } + #ConsistentHashLB: {} | { + httpHeaderName: string + } +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { @@ -118,4 +134,4 @@ } } } -} \ No newline at end of file +} diff --git a/encoding/openapi/testdata/embed.cue b/encoding/openapi/testdata/embed.cue deleted file mode 100644 index c3bc3b4ff..000000000 --- a/encoding/openapi/testdata/embed.cue +++ /dev/null @@ -1,11 +0,0 @@ -#Foo: string - -#LoadBalancerSettings: { - {} | { - consistentHash: #ConsistentHashLB - b: #Foo - } - #ConsistentHashLB: {} | { - httpHeaderName: string - } -} diff --git a/encoding/openapi/testdata/embed.json b/encoding/openapi/testdata/embed.txtar similarity index 91% rename from encoding/openapi/testdata/embed.json rename to encoding/openapi/testdata/embed.txtar index d88cc2fe7..e4bb5942e 100644 --- a/encoding/openapi/testdata/embed.json +++ b/encoding/openapi/testdata/embed.txtar @@ -1,3 +1,19 @@ +#skip-v3 +#skip-v3-noshare +-- in.cue -- +#Foo: string + +#LoadBalancerSettings: { + {} | { + consistentHash: #ConsistentHashLB + b: #Foo + } + #ConsistentHashLB: {} | { + httpHeaderName: string + } +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/enum.cue b/encoding/openapi/testdata/enum.cue deleted file mode 100644 index 237ff5e57..000000000 --- a/encoding/openapi/testdata/enum.cue +++ /dev/null @@ -1,10 +0,0 @@ -#CaptureMode: { - "DEFAULT" - #enumValue: 0 -} | { - "IPTABLES" - #enumValue: 1 -} | { - "NONE" - #enumValue: 2 -} diff --git a/encoding/openapi/testdata/enum.json b/encoding/openapi/testdata/enum.txtar similarity index 69% rename from encoding/openapi/testdata/enum.json rename to encoding/openapi/testdata/enum.txtar index 81ca198eb..b5778a089 100644 --- a/encoding/openapi/testdata/enum.json +++ b/encoding/openapi/testdata/enum.txtar @@ -1,3 +1,16 @@ +-- in.cue -- +#CaptureMode: { + "DEFAULT" + #enumValue: 0 +} | { + "IPTABLES" + #enumValue: 1 +} | { + "NONE" + #enumValue: 2 +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/issue131.cue b/encoding/openapi/testdata/issue131.cue deleted file mode 100644 index a097d3f15..000000000 --- a/encoding/openapi/testdata/issue131.cue +++ /dev/null @@ -1,7 +0,0 @@ -package ext - -import "mod.test/blocks" - -#Blocks: { - block1: blocks.#Block -} diff --git a/encoding/openapi/testdata/issue131.json b/encoding/openapi/testdata/issue131.txtar similarity index 80% rename from encoding/openapi/testdata/issue131.json rename to encoding/openapi/testdata/issue131.txtar index 3025bf567..b58d56126 100644 --- a/encoding/openapi/testdata/issue131.json +++ b/encoding/openapi/testdata/issue131.txtar @@ -1,8 +1,19 @@ +#skip-v3-noshare +-- in.cue -- +package ext + +import "mod.test/blocks" + +#Blocks: { + block1: blocks.#Block +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { @@ -39,4 +50,4 @@ } } } -} \ No newline at end of file +} diff --git a/encoding/openapi/testdata/issue3718.cue b/encoding/openapi/testdata/issue3718.cue deleted file mode 100644 index 1abaa0e28..000000000 --- a/encoding/openapi/testdata/issue3718.cue +++ /dev/null @@ -1,9 +0,0 @@ -import ( - "encoding/json" -) - -let defaultPolicy = json.Marshal({ deny: "all" }) - -#Spec: { - policy?: string | *defaultPolicy -} diff --git a/encoding/openapi/testdata/issue3718.json b/encoding/openapi/testdata/issue3718.txtar similarity index 69% rename from encoding/openapi/testdata/issue3718.json rename to encoding/openapi/testdata/issue3718.txtar index 9e94e0436..09f0870eb 100644 --- a/encoding/openapi/testdata/issue3718.json +++ b/encoding/openapi/testdata/issue3718.txtar @@ -1,3 +1,15 @@ +-- in.cue -- +import ( + "encoding/json" +) + +let defaultPolicy = json.Marshal({ deny: "all" }) + +#Spec: { + policy?: string | *defaultPolicy +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/nested.cue b/encoding/openapi/testdata/nested.cue deleted file mode 100644 index 3de5f28ec..000000000 --- a/encoding/openapi/testdata/nested.cue +++ /dev/null @@ -1,11 +0,0 @@ -// File comment. - -#Struct: { - #T: int - - a?: #T - - {b?: #T} - - c?: [...#T] -} diff --git a/encoding/openapi/testdata/nested.json b/encoding/openapi/testdata/nested.txtar similarity index 85% rename from encoding/openapi/testdata/nested.json rename to encoding/openapi/testdata/nested.txtar index e11ce76cc..09087cfa7 100644 --- a/encoding/openapi/testdata/nested.json +++ b/encoding/openapi/testdata/nested.txtar @@ -1,3 +1,17 @@ +-- in.cue -- +// File comment. + +#Struct: { + #T: int + + a?: #T + + {b?: #T} + + c?: [...#T] +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/nums-v3.1.0.json b/encoding/openapi/testdata/nums-v3.1.0.txtar similarity index 79% rename from encoding/openapi/testdata/nums-v3.1.0.json rename to encoding/openapi/testdata/nums-v3.1.0.txtar index f752a1123..7653295cd 100644 --- a/encoding/openapi/testdata/nums-v3.1.0.json +++ b/encoding/openapi/testdata/nums-v3.1.0.txtar @@ -1,8 +1,23 @@ +#Version: 3.1.0 +-- in.cue -- +import "math" + +#mul: math.MultipleOf(5) + +#neq: !=4 + +#exMin: >5 +#exMax: <6 + +#int: int64 +#intNull: int64 | null + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.1.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { @@ -44,4 +59,4 @@ } } } -} \ No newline at end of file +} diff --git a/encoding/openapi/testdata/nums.cue b/encoding/openapi/testdata/nums.cue deleted file mode 100644 index 3c25531f4..000000000 --- a/encoding/openapi/testdata/nums.cue +++ /dev/null @@ -1,11 +0,0 @@ -import "math" - -#mul: math.MultipleOf(5) - -#neq: !=4 - -#exMin: >5 -#exMax: <6 - -#int: int64 -#intNull: int64 | null diff --git a/encoding/openapi/testdata/nums.json b/encoding/openapi/testdata/nums.txtar similarity index 86% rename from encoding/openapi/testdata/nums.json rename to encoding/openapi/testdata/nums.txtar index 81c025cd9..a5d86656b 100644 --- a/encoding/openapi/testdata/nums.json +++ b/encoding/openapi/testdata/nums.txtar @@ -1,3 +1,17 @@ +-- in.cue -- +import "math" + +#mul: math.MultipleOf(5) + +#neq: !=4 + +#exMin: >5 +#exMax: <6 + +#int: int64 +#intNull: int64 | null + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/omitvalue.cue b/encoding/openapi/testdata/omitvalue.cue deleted file mode 100644 index 1fbcc385b..000000000 --- a/encoding/openapi/testdata/omitvalue.cue +++ /dev/null @@ -1,8 +0,0 @@ -#D: { - a: int - #b: int - a_value: int - // Only definitions ending in _value are omitted. - #b_value: int - "a b_value": int -} diff --git a/encoding/openapi/testdata/omitvalue.json b/encoding/openapi/testdata/omitvalue.txtar similarity index 79% rename from encoding/openapi/testdata/omitvalue.json rename to encoding/openapi/testdata/omitvalue.txtar index c60a37e78..e415f576a 100644 --- a/encoding/openapi/testdata/omitvalue.json +++ b/encoding/openapi/testdata/omitvalue.txtar @@ -1,3 +1,14 @@ +-- in.cue -- +#D: { + a: int + #b: int + a_value: int + // Only definitions ending in _value are omitted. + #b_value: int + "a b_value": int +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/oneof-resolve.json b/encoding/openapi/testdata/oneof-resolve.txtar similarity index 94% rename from encoding/openapi/testdata/oneof-resolve.json rename to encoding/openapi/testdata/oneof-resolve.txtar index 643029de7..7de9e1612 100644 --- a/encoding/openapi/testdata/oneof-resolve.json +++ b/encoding/openapi/testdata/oneof-resolve.txtar @@ -1,8 +1,88 @@ +#ExpandReferences +#skip-v3 +#skip-v3-noshare +-- in.cue -- +// OpenAPI title. + +$version: "v1alpha1" + +#T: { + shared: int +} +#T: {} | { + exact: string +} | { + regex: string +} +#T: {} | { + count: int +} | { + amount: int +} +#T: { + shared2: int +} + +// This should be dedupped. +#T: {} | { + count: int +} | { + amount: int +} + +#MyInt: int + +#Foo: { + include: #T + exclude: [...#T] + count: #MyInt +} + +#Incompatible: { + shared: int +} | { + shared: int + extra1: int +} | { + shared: int + extra2: int +} + +#WithMap: { + shared: [string]: int +} | { + shared: [string]: int + extra: int +} | { + shared: string // incompatible + extra: int +} + +#Embed: { + a?: int + + close({}) | + close({b: #T}) | + close({c: int}) + + #T: {b?: int} + + close({}) | + close({d: #T}) | + close({e: int}) + + // TODO: maybe support builtin to write this as + // oneof({}, + // {b: int}, + // {c: int}) +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "OpenAPI title.", + "version": "v1alpha1" }, "paths": {}, "components": { @@ -516,4 +596,4 @@ } } } -} \ No newline at end of file +} diff --git a/encoding/openapi/testdata/oneof.json b/encoding/openapi/testdata/oneof.txtar similarity index 94% rename from encoding/openapi/testdata/oneof.json rename to encoding/openapi/testdata/oneof.txtar index 2c8429749..93ff4b055 100644 --- a/encoding/openapi/testdata/oneof.json +++ b/encoding/openapi/testdata/oneof.txtar @@ -1,3 +1,82 @@ +#skip-v3 +#skip-v3-noshare +-- in.cue -- +// OpenAPI title. + +$version: "v1alpha1" + +#T: { + shared: int +} +#T: {} | { + exact: string +} | { + regex: string +} +#T: {} | { + count: int +} | { + amount: int +} +#T: { + shared2: int +} + +// This should be dedupped. +#T: {} | { + count: int +} | { + amount: int +} + +#MyInt: int + +#Foo: { + include: #T + exclude: [...#T] + count: #MyInt +} + +#Incompatible: { + shared: int +} | { + shared: int + extra1: int +} | { + shared: int + extra2: int +} + +#WithMap: { + shared: [string]: int +} | { + shared: [string]: int + extra: int +} | { + shared: string // incompatible + extra: int +} + +#Embed: { + a?: int + + close({}) | + close({b: #T}) | + close({c: int}) + + #T: {b?: int} + + close({}) | + close({d: #T}) | + close({e: int}) + + // TODO: maybe support builtin to write this as + // oneof({}, + // {b: int}, + // {c: int}) +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/openapi-norefs.json b/encoding/openapi/testdata/openapi-norefs.txtar similarity index 86% rename from encoding/openapi/testdata/openapi-norefs.json rename to encoding/openapi/testdata/openapi-norefs.txtar index 69a9f98a8..cc0c02a67 100644 --- a/encoding/openapi/testdata/openapi-norefs.json +++ b/encoding/openapi/testdata/openapi-norefs.txtar @@ -1,8 +1,63 @@ +#ExpandReferences +-- in.cue -- +// An OpenAPI testing package. +package openapi + +$version: "v1beta2" + +info: { + contact: url: "https://cuelang.org" + contact: name: "John Doe" +} + +// MyMessage is my message. +#MyMessage: { + port?: #Port & {} @protobuf(1) + + foo: #Int32 & >10 & <1000 & int32 @protobuf(2) + + bar: [...string] @protobuf(3) +} + +#MyMessage: { + // Field a. + a: 1 +} | { + b: string //2: crash +} + +#YourMessage: ({a: number} | {b: string} | {b: number}) & {a?: string} + +#YourMessage2: ({a: number} | {b: number}) & + ({c: number} | {d: number}) & + ({e: number} | {f: number}) + +#Msg2: {b: number} | {a: string} + +#Int32: int32 + +#Enum: "foo" | "bar" | "baz" + +#List: [...number] | *[1, 2, 3] + +#DefaultStruct: #Port | *{port: 1} + +#Port: { + port: int + + obj: [...int] +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "contact": { + "url": "https://cuelang.org", + "name": "John Doe" + }, + "title": "An OpenAPI testing package.", + "version": "v1beta2" }, "paths": {}, "components": { @@ -257,4 +312,4 @@ } } } -} \ No newline at end of file +} diff --git a/encoding/openapi/testdata/openapi.cue b/encoding/openapi/testdata/openapi.cue deleted file mode 100644 index 83d81c19d..000000000 --- a/encoding/openapi/testdata/openapi.cue +++ /dev/null @@ -1,47 +0,0 @@ -// An OpenAPI testing package. -package openapi - -$version: "v1beta2" - -info: { - contact: url: "https://cuelang.org" - contact: name: "John Doe" -} - -// MyMessage is my message. -#MyMessage: { - port?: #Port & {} @protobuf(1) - - foo: #Int32 & >10 & <1000 & int32 @protobuf(2) - - bar: [...string] @protobuf(3) -} - -#MyMessage: { - // Field a. - a: 1 -} | { - b: string //2: crash -} - -#YourMessage: ({a: number} | {b: string} | {b: number}) & {a?: string} - -#YourMessage2: ({a: number} | {b: number}) & - ({c: number} | {d: number}) & - ({e: number} | {f: number}) - -#Msg2: {b: number} | {a: string} - -#Int32: int32 - -#Enum: "foo" | "bar" | "baz" - -#List: [...number] | *[1, 2, 3] - -#DefaultStruct: #Port | *{port: 1} - -#Port: { - port: int - - obj: [...int] -} diff --git a/encoding/openapi/testdata/openapi.json b/encoding/openapi/testdata/openapi.txtar similarity index 90% rename from encoding/openapi/testdata/openapi.json rename to encoding/openapi/testdata/openapi.txtar index 90fd2cbcc..aaca2ffad 100644 --- a/encoding/openapi/testdata/openapi.json +++ b/encoding/openapi/testdata/openapi.txtar @@ -1,3 +1,55 @@ +#skip-v3 +#skip-v3-noshare +-- in.cue -- +// An OpenAPI testing package. +package openapi + +$version: "v1beta2" + +info: { + contact: url: "https://cuelang.org" + contact: name: "John Doe" +} + +// MyMessage is my message. +#MyMessage: { + port?: #Port & {} @protobuf(1) + + foo: #Int32 & >10 & <1000 & int32 @protobuf(2) + + bar: [...string] @protobuf(3) +} + +#MyMessage: { + // Field a. + a: 1 +} | { + b: string //2: crash +} + +#YourMessage: ({a: number} | {b: string} | {b: number}) & {a?: string} + +#YourMessage2: ({a: number} | {b: number}) & + ({c: number} | {d: number}) & + ({e: number} | {f: number}) + +#Msg2: {b: number} | {a: string} + +#Int32: int32 + +#Enum: "foo" | "bar" | "baz" + +#List: [...number] | *[1, 2, 3] + +#DefaultStruct: #Port | *{port: 1} + +#Port: { + port: int + + obj: [...int] +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/protobuf.cue b/encoding/openapi/testdata/protobuf.cue deleted file mode 100644 index aeb3c25e9..000000000 --- a/encoding/openapi/testdata/protobuf.cue +++ /dev/null @@ -1,12 +0,0 @@ -// Note: This example originally derived from a CUE file converted from protobuf. - -#HTTPRoute: { - route: [...#HTTPRouteDestination] -} -#HTTPRouteDestination: { - headers: #Headers -} -#Headers: { - request: #HeaderOperations - #HeaderOperations: {} -} diff --git a/encoding/openapi/testdata/protobuf.json b/encoding/openapi/testdata/protobuf.txtar similarity index 81% rename from encoding/openapi/testdata/protobuf.json rename to encoding/openapi/testdata/protobuf.txtar index b23947592..cab1167a7 100644 --- a/encoding/openapi/testdata/protobuf.json +++ b/encoding/openapi/testdata/protobuf.txtar @@ -1,8 +1,25 @@ +#ExpandReferences +#skip-v3 +-- in.cue -- +// Note: This example originally derived from a CUE file converted from protobuf. + +#HTTPRoute: { + route: [...#HTTPRouteDestination] +} +#HTTPRouteDestination: { + headers: #Headers +} +#Headers: { + request: #HeaderOperations + #HeaderOperations: {} +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Note: This example originally derived from a CUE file converted from protobuf.", + "version": "no version" }, "paths": {}, "components": { diff --git a/encoding/openapi/testdata/quotedfield.cue b/encoding/openapi/testdata/quotedfield.cue deleted file mode 100644 index f55bd9756..000000000 --- a/encoding/openapi/testdata/quotedfield.cue +++ /dev/null @@ -1,3 +0,0 @@ -#Def: { - "@type": string -} diff --git a/encoding/openapi/testdata/quotedfield.json b/encoding/openapi/testdata/quotedfield.txtar similarity index 83% rename from encoding/openapi/testdata/quotedfield.json rename to encoding/openapi/testdata/quotedfield.txtar index c9994ffe6..85afbbaa6 100644 --- a/encoding/openapi/testdata/quotedfield.json +++ b/encoding/openapi/testdata/quotedfield.txtar @@ -1,3 +1,9 @@ +-- in.cue -- +#Def: { + "@type": string +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/script/basics.txtar b/encoding/openapi/testdata/script/basics.txtar index b5a5943c4..e856479b6 100644 --- a/encoding/openapi/testdata/script/basics.txtar +++ b/encoding/openapi/testdata/script/basics.txtar @@ -45,3 +45,39 @@ info: { address?: #PhoneNumber ... } +-- out/TestGenerateOpenAPI/out.json -- +{ + "openapi": "3.0.0", + "info": { + "title": "Users schema", + "version": "v1beta1", + "contact": { + "name": "The CUE Authors", + "url": "https://cuelang.org" + } + }, + "paths": {}, + "components": { + "schemas": { + "PhoneNumber": { + "description": "The number to dial.", + "type": "string" + }, + "User": { + "description": "A User uses something.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "address": { + "$ref": "#/components/schemas/PhoneNumber" + } + } + } + } + } +} diff --git a/encoding/openapi/testdata/simple-filter.json b/encoding/openapi/testdata/simple-filter.txtar similarity index 77% rename from encoding/openapi/testdata/simple-filter.json rename to encoding/openapi/testdata/simple-filter.txtar index fdf870822..b543f4d58 100644 --- a/encoding/openapi/testdata/simple-filter.json +++ b/encoding/openapi/testdata/simple-filter.txtar @@ -1,8 +1,21 @@ +#FieldFilter: min.*|max.* +-- in.cue -- +#MyStruct: { + mediumNum: int32 + smallNum: int8 + + float: float32 + double: float64 + + deprecatedField: string @protobuf(5,deprecated) +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { diff --git a/encoding/openapi/testdata/simple.cue b/encoding/openapi/testdata/simple.cue deleted file mode 100644 index 92b8475ce..000000000 --- a/encoding/openapi/testdata/simple.cue +++ /dev/null @@ -1,9 +0,0 @@ -#MyStruct: { - mediumNum: int32 - smallNum: int8 - - float: float32 - double: float64 - - deprecatedField: string @protobuf(5,deprecated) -} diff --git a/encoding/openapi/testdata/simple.json b/encoding/openapi/testdata/simple.txtar similarity index 79% rename from encoding/openapi/testdata/simple.json rename to encoding/openapi/testdata/simple.txtar index 4429e7037..cad8b4f37 100644 --- a/encoding/openapi/testdata/simple.json +++ b/encoding/openapi/testdata/simple.txtar @@ -1,8 +1,21 @@ +#ExpandReferences +-- in.cue -- +#MyStruct: { + mediumNum: int32 + smallNum: int8 + + float: float32 + double: float64 + + deprecatedField: string @protobuf(5,deprecated) +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { diff --git a/encoding/openapi/testdata/strings.cue b/encoding/openapi/testdata/strings.cue deleted file mode 100644 index 84e47c727..000000000 --- a/encoding/openapi/testdata/strings.cue +++ /dev/null @@ -1,9 +0,0 @@ -import "strings" - -#MyType: { - myString: strings.MinRunes(1) & strings.MaxRunes(5) - - myPattern: =~"foo.*bar" - - myAntiPattern: !~"foo.*bar" -} diff --git a/encoding/openapi/testdata/strings.json b/encoding/openapi/testdata/strings.txtar similarity index 81% rename from encoding/openapi/testdata/strings.json rename to encoding/openapi/testdata/strings.txtar index 2a5411fc0..4b15ce634 100644 --- a/encoding/openapi/testdata/strings.json +++ b/encoding/openapi/testdata/strings.txtar @@ -1,3 +1,15 @@ +-- in.cue -- +import "strings" + +#MyType: { + myString: strings.MinRunes(1) & strings.MaxRunes(5) + + myPattern: =~"foo.*bar" + + myAntiPattern: !~"foo.*bar" +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/struct.cue b/encoding/openapi/testdata/struct.cue deleted file mode 100644 index 82406f817..000000000 --- a/encoding/openapi/testdata/struct.cue +++ /dev/null @@ -1,8 +0,0 @@ -import "struct" - -#MyMap: struct.MinFields(4) -#MyMap: struct.MaxFields(9) - -#MyType: { - map: #MyMap -} diff --git a/encoding/openapi/testdata/struct.json b/encoding/openapi/testdata/struct.txtar similarity index 76% rename from encoding/openapi/testdata/struct.json rename to encoding/openapi/testdata/struct.txtar index 3af6ee365..991718e4c 100644 --- a/encoding/openapi/testdata/struct.json +++ b/encoding/openapi/testdata/struct.txtar @@ -1,3 +1,15 @@ +#skip-v3-noshare +-- in.cue -- +import "struct" + +#MyMap: struct.MinFields(4) +#MyMap: struct.MaxFields(9) + +#MyType: { + map: #MyMap +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { diff --git a/encoding/openapi/testdata/structural.cue b/encoding/openapi/testdata/structural.cue deleted file mode 100644 index 1f0b892cd..000000000 --- a/encoding/openapi/testdata/structural.cue +++ /dev/null @@ -1,44 +0,0 @@ -import "time" - -#Attributes: { - // A map of attribute name to its value. - attributes: { - [string]: #AttrValue - } -} - -// The attribute value. -#AttrValue: {} - -#AttrValue: { - // Used for values of type STRING, DNS_NAME, EMAIL_ADDRESS, and URI - stringValue: string @protobuf(2,name=string_value) -} | { - // Used for values of type INT64 - int64Value: int64 @protobuf(3,name=int64_value) -} | { - // Used for values of type DOUBLE - doubleValue: float64 @protobuf(4,type=double,name=double_value) -} | { - // Used for values of type BOOL - boolValue: bool @protobuf(5,name=bool_value) -} | { - // Used for values of type BYTES - bytesValue: bytes @protobuf(6,name=bytes_value) -} | { - // Used for values of type TIMESTAMP - timestampValue: time.Time @protobuf(7,type=google.protobuf.Timestamp,name=timestamp_value) -} | { - // Used for values of type DURATION - durationValue: time.Duration @protobuf(8,type=google.protobuf.Duration,name=duration_value) -} | { - // Used for values of type STRING_MAP - stringMapValue: #Attributes_StringMap @protobuf(9,type=StringMap,name=string_map_value) -} - -#Attributes_StringMap: { - // Holds a set of name/value pairs. - entries: { - [string]: string - } @protobuf(1,type=map) -} diff --git a/encoding/openapi/testdata/structural.json b/encoding/openapi/testdata/structural.txtar similarity index 85% rename from encoding/openapi/testdata/structural.json rename to encoding/openapi/testdata/structural.txtar index a483851f7..eac3c6f0c 100644 --- a/encoding/openapi/testdata/structural.json +++ b/encoding/openapi/testdata/structural.txtar @@ -1,8 +1,57 @@ +#ExpandReferences +#skip-v3 +-- in.cue -- +import "time" + +#Attributes: { + // A map of attribute name to its value. + attributes: { + [string]: #AttrValue + } +} + +// The attribute value. +#AttrValue: {} + +#AttrValue: { + // Used for values of type STRING, DNS_NAME, EMAIL_ADDRESS, and URI + stringValue: string @protobuf(2,name=string_value) +} | { + // Used for values of type INT64 + int64Value: int64 @protobuf(3,name=int64_value) +} | { + // Used for values of type DOUBLE + doubleValue: float64 @protobuf(4,type=double,name=double_value) +} | { + // Used for values of type BOOL + boolValue: bool @protobuf(5,name=bool_value) +} | { + // Used for values of type BYTES + bytesValue: bytes @protobuf(6,name=bytes_value) +} | { + // Used for values of type TIMESTAMP + timestampValue: time.Time @protobuf(7,type=google.protobuf.Timestamp,name=timestamp_value) +} | { + // Used for values of type DURATION + durationValue: time.Duration @protobuf(8,type=google.protobuf.Duration,name=duration_value) +} | { + // Used for values of type STRING_MAP + stringMapValue: #Attributes_StringMap @protobuf(9,type=StringMap,name=string_map_value) +} + +#Attributes_StringMap: { + // Holds a set of name/value pairs. + entries: { + [string]: string + } @protobuf(1,type=map) +} + +-- out/TestGenerateOpenAPI/out.json -- { "openapi": "3.0.0", "info": { - "title": "test", - "version": "v1" + "title": "Generated by cue.", + "version": "no version" }, "paths": {}, "components": { @@ -227,4 +276,4 @@ } } } -} \ No newline at end of file +}