1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package cuego
16
17 import (
18 "reflect"
19 "testing"
20 )
21
22 type Sum struct {
23 A int `cue:"C-B" json:",omitempty"`
24 B int `cue:"C-A" json:",omitempty"`
25 C int `cue:"A+B & >=5" json:",omitempty"`
26 }
27
28 func checkErr(t *testing.T, got error, want string) {
29 t.Helper()
30 if (got == nil) != (want == "") {
31 t.Errorf("error: got %v; want %v", got, want)
32 }
33 }
34 func TestValidate(t *testing.T) {
35 fail := "some error"
36 testCases := []struct {
37 name string
38 value interface{}
39 constraints string
40 err string
41 }{{
42 name: "Sum",
43 value: Sum{A: 1, B: 4, C: 5},
44 }, {
45 name: "*Sum",
46 value: &Sum{A: 1, B: 4, C: 5},
47 }, {
48 name: "*Sum: incorrect sum",
49 value: &Sum{A: 1, B: 4, C: 6},
50 err: fail,
51 }, {
52 name: "*Sum: field C is too low",
53 value: &Sum{A: 1, B: 3, C: 4},
54 err: fail,
55 }, {
56 name: "*Sum: nil value",
57 value: (*Sum)(nil),
58
59
60
61
62
63
64
65 }, {
66
67 name: "string list",
68 value: []string{"a", "b", "c"},
69 constraints: `[_, "b", ...]`,
70 }, {
71
72 name: "string list incompatible lengths",
73 value: []string{"a", "b", "c"},
74 constraints: `4*[string]`,
75 err: fail,
76 }}
77
78 for _, tc := range testCases {
79 t.Run(tc.name, func(t *testing.T) {
80 c := &Context{}
81 if tc.constraints != "" {
82 err := c.Constrain(tc.value, tc.constraints)
83 if err != nil {
84 t.Fatal(err)
85 }
86 }
87 err := c.Validate(tc.value)
88 checkErr(t, err, tc.err)
89 })
90 }
91 }
92
93 func TestUpdate(t *testing.T) {
94 type updated struct {
95 A []*int `cue:"[...int|*1]"`
96 B []int `cue:"3*[int|*1]"`
97
98
99 M map[string]int `cue:",opt"`
100 }
101 type sump struct {
102 A *int `cue:"C-B"`
103 B *int `cue:"C-A"`
104 C *int `cue:"A+B"`
105 }
106 one := 1
107 two := 2
108 fail := "some error"
109 _ = fail
110 _ = one
111 testCases := []struct {
112 name string
113 value interface{}
114 result interface{}
115 constraints string
116 err string
117 }{{
118 name: "*Sum",
119 value: &Sum{A: 1, B: 4, C: 5},
120 result: &Sum{A: 1, B: 4, C: 5},
121 }, {
122 name: "*Sum",
123 value: &Sum{A: 1, B: 4},
124 result: &Sum{A: 1, B: 4, C: 5},
125 }, {
126 name: "*sump",
127 value: &sump{A: &one, B: &one},
128 result: &sump{A: &one, B: &one, C: &two},
129 }, {
130 name: "*Sum: backwards",
131 value: &Sum{B: 4, C: 8},
132 result: &Sum{A: 4, B: 4, C: 8},
133 }, {
134 name: "*Sum: sum too low",
135 value: &Sum{A: 1, B: 3},
136 result: &Sum{A: 1, B: 3},
137 err: fail,
138 }, {
139 name: "*Sum: sum underspecified",
140 value: &Sum{A: 1},
141 result: &Sum{A: 1},
142 err: fail,
143 }, {
144 name: "Sum: cannot modify",
145 value: Sum{A: 3, B: 4, C: 7},
146 result: Sum{A: 3, B: 4, C: 7},
147 err: fail,
148 }, {
149 name: "*Sum: cannot update nil value",
150 value: (*Sum)(nil),
151 result: (*Sum)(nil),
152 err: fail,
153 }, {
154 name: "cannot modify slice",
155 value: []string{"a", "b", "c"},
156 result: []string{"a", "b", "c"},
157 err: fail,
158 }, {
159 name: "composite values update",
160
161
162 value: &updated{A: make([]*int, 3)},
163 result: &updated{
164 A: []*int{&one, &one, &one},
165 B: []int{1, 1, 1},
166 M: map[string]int(nil),
167 },
168 }, {
169 name: "composite values update with unsatisfied map constraints",
170 value: &updated{},
171 result: &updated{},
172
173 constraints: ` { M: {foo: bar, bar: foo} } `,
174 err: fail,
175 }, {
176 name: "composite values update with map constraints",
177 value: &updated{M: map[string]int{"foo": 1}},
178 constraints: ` { M: {foo: bar, bar: foo} } `,
179 result: &updated{
180
181
182
183
184 A: []*int{},
185 B: []int{1, 1, 1},
186 M: map[string]int{"bar": 1, "foo": 1},
187 },
188 }}
189 for _, tc := range testCases {
190 t.Run(tc.name, func(t *testing.T) {
191 c := &Context{}
192 if tc.constraints != "" {
193 err := c.Constrain(tc.value, tc.constraints)
194 if err != nil {
195 t.Fatal(err)
196 }
197 }
198 err := c.Complete(tc.value)
199 checkErr(t, err, tc.err)
200 if !reflect.DeepEqual(tc.value, tc.result) {
201 t.Errorf("value:\n got: %#v;\nwant: %#v", tc.value, tc.result)
202 }
203 })
204 }
205 }
206
View as plain text