1package jsonschema
2
3import (
4 "strings"
5 "testing"
6
7 "github.com/go-quicktest/qt"
8
9 "cuelang.org/go/cue"
10 "cuelang.org/go/cue/ast"
11 "cuelang.org/go/cue/ast/astutil"
12 "cuelang.org/go/cue/format"
13 "cuelang.org/go/cue/token"
14 "cuelang.org/go/internal"
15)
16
17func TestStructBuilderShadowedRef(t *testing.T) {
18 var b structBuilder
19 ref, err := b.getRef(cue.ParsePath("#foo.bar.baz"))
20 qt.Assert(t, qt.IsNil(err))
21 ok := b.put(cue.ParsePath("#foo.bar.baz"), ast.NewString("hello"), nil)
22 qt.Assert(t, qt.IsTrue(ok))
23 ok = b.put(cue.ParsePath("#bar.#foo.xxx"), ref, nil)
24 qt.Assert(t, qt.IsTrue(ok))
25 assertStructBuilderSyntax(t, &b, `#bar: #foo: xxx: #foo_9.bar.baz
26
27#foo_9=#foo: bar: baz: "hello"
28`)
29}
30
31func TestStructBuilderSelfRef(t *testing.T) {
32 var b structBuilder
33 ref, err := b.getRef(cue.Path{})
34 qt.Assert(t, qt.IsNil(err))
35 ok := b.put(cue.Path{}, ast.NewStruct(ast.NewIdent("next"), token.OPTION, ref), nil)
36 qt.Assert(t, qt.IsTrue(ok))
37 assertStructBuilderSyntax(t, &b, `
38_schema
39_schema: {
40 next?: _schema
41}
42`)
43}
44
45func TestStructBuilderEntryInsideValue(t *testing.T) {
46 var b structBuilder
47 ok := b.put(cue.ParsePath("#foo"), ast.NewString("hello"), internal.NewComment(true, "foo comment"))
48 qt.Assert(t, qt.IsTrue(ok))
49 ok = b.put(cue.ParsePath("#foo.#bar.#baz"), ast.NewString("goodbye"), internal.NewComment(true, "baz comment"))
50 qt.Assert(t, qt.IsTrue(ok))
51 assertStructBuilderSyntax(t, &b, `
52// foo comment
53#foo: {
54 "hello"
55
56 // baz comment
57 #bar: #baz: "goodbye"
58}
59`)
60}
61
62func TestStructBuilderNonIdentifierStringNode(t *testing.T) {
63 var b structBuilder
64 ref, err := b.getRef(cue.ParsePath(`#foo."a b".baz`))
65 qt.Assert(t, qt.IsNil(err))
66 ok := b.put(cue.ParsePath(`#foo."a b".baz`), ast.NewString("hello"), nil)
67 qt.Assert(t, qt.IsTrue(ok))
68 ok = b.put(cue.ParsePath("#bar.#foo.xxx"), ref, nil)
69 qt.Assert(t, qt.IsTrue(ok))
70 assertStructBuilderSyntax(t, &b, `
71#bar: #foo: xxx: #foo_9."a b".baz
72
73#foo_9=#foo: "a b": baz: "hello"
74`)
75}
76
77func TestStructBuilderNonIdentifierStringNodeAtRoot(t *testing.T) {
78 var b structBuilder
79 _, err := b.getRef(cue.ParsePath(`"a b".baz`))
80 qt.Assert(t, qt.ErrorMatches(err, `initial element of path "\\"a b\\"\.baz" must be expressed as an identifier`))
81}
82
83func TestStructBuilderRedefinition(t *testing.T) {
84 var b structBuilder
85 ok := b.put(cue.ParsePath(`a.b.c`), ast.NewString("hello"), nil)
86 qt.Assert(t, qt.IsTrue(ok))
87 ok = b.put(cue.ParsePath(`a.b.c`), ast.NewString("hello"), nil)
88 qt.Assert(t, qt.IsFalse(ok))
89}
90
91func TestStructBuilderNonPresentNodeOmittedFromSyntax(t *testing.T) {
92 var b structBuilder
93 _, err := b.getRef(cue.ParsePath(`b.c`))
94 qt.Assert(t, qt.IsNil(err))
95 _, err = b.getRef(cue.ParsePath(`a.c.d`))
96 qt.Assert(t, qt.IsNil(err))
97 ok := b.put(cue.ParsePath(`a.b`), ast.NewString("hello"), nil)
98 qt.Assert(t, qt.IsTrue(ok))
99 assertStructBuilderSyntax(t, &b, `a: b: "hello"`)
100}
101
102func assertStructBuilderSyntax(t *testing.T, b *structBuilder, want string) {
103 f, err := b.syntax()
104 qt.Assert(t, qt.IsNil(err))
105 err = astutil.Sanitize(f)
106 qt.Assert(t, qt.IsNil(err))
107 data, err := format.Node(f)
108 qt.Assert(t, qt.IsNil(err))
109 qt.Assert(t, qt.Equals(strings.TrimSpace(string(data)), strings.TrimSpace(want)))
110}