1
16
17 package typed_test
18
19 import (
20 "fmt"
21 "testing"
22
23 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
24 "sigs.k8s.io/structured-merge-diff/v4/typed"
25 "sigs.k8s.io/structured-merge-diff/v4/value"
26 )
27
28 type objSetPair struct {
29 object typed.YAMLObject
30 set *fieldpath.Set
31 }
32
33 type fieldsetTestCase struct {
34 name string
35 rootTypeName string
36 schema typed.YAMLObject
37 pairs []objSetPair
38 }
39
40 var (
41
42 _NS = fieldpath.NewSet
43 _P = fieldpath.MakePathOrDie
44 _KBF = fieldpath.KeyByFields
45 _V = value.NewValueInterface
46 )
47
48 var fieldsetCases = []fieldsetTestCase{{
49 name: "simple pair",
50 rootTypeName: "stringPair",
51 schema: `types:
52 - name: stringPair
53 map:
54 fields:
55 - name: key
56 type:
57 scalar: string
58 - name: value
59 type:
60 namedType: __untyped_atomic_
61 - name: __untyped_atomic_
62 scalar: untyped
63 list:
64 elementType:
65 namedType: __untyped_atomic_
66 elementRelationship: atomic
67 map:
68 elementType:
69 namedType: __untyped_atomic_
70 elementRelationship: atomic
71 `,
72 pairs: []objSetPair{
73 {`{"key":"foo","value":1}`, _NS(_P("key"), _P("value"))},
74 {`{"key":"foo","value":{"a": "b"}}`, _NS(_P("key"), _P("value"))},
75 {`{"key":"foo","value":null}`, _NS(_P("key"), _P("value"))},
76 {`{"key":"foo"}`, _NS(_P("key"))},
77 {`{"key":"foo","value":true}`, _NS(_P("key"), _P("value"))},
78 },
79 }, {
80 name: "struct grab bag",
81 rootTypeName: "myStruct",
82 schema: `types:
83 - name: myStruct
84 map:
85 fields:
86 - name: numeric
87 type:
88 scalar: numeric
89 - name: string
90 type:
91 scalar: string
92 - name: bool
93 type:
94 scalar: boolean
95 - name: setStr
96 type:
97 list:
98 elementType:
99 scalar: string
100 elementRelationship: associative
101 - name: setBool
102 type:
103 list:
104 elementType:
105 scalar: boolean
106 elementRelationship: associative
107 - name: setNumeric
108 type:
109 list:
110 elementType:
111 scalar: numeric
112 elementRelationship: associative
113 - name: color
114 type:
115 map:
116 fields:
117 - name: R
118 type:
119 scalar: numeric
120 - name: G
121 type:
122 scalar: numeric
123 - name: B
124 type:
125 scalar: numeric
126 elementRelationship: atomic
127 - name: arbitraryWavelengthColor
128 type:
129 map:
130 elementType:
131 scalar: numeric
132 elementRelationship: atomic
133 - name: args
134 type:
135 list:
136 elementType:
137 map:
138 fields:
139 - name: key
140 type:
141 scalar: string
142 - name: value
143 type:
144 scalar: string
145 elementRelationship: atomic
146 `,
147 pairs: []objSetPair{
148 {`{"numeric":1}`, _NS(_P("numeric"))},
149 {`{"numeric":3.14159}`, _NS(_P("numeric"))},
150 {`{"string":"aoeu"}`, _NS(_P("string"))},
151 {`{"bool":true}`, _NS(_P("bool"))},
152 {`{"bool":false}`, _NS(_P("bool"))},
153 {`{"setStr":["a","b","c"]}`, _NS(
154 _P("setStr", _V("a")),
155 _P("setStr", _V("b")),
156 _P("setStr", _V("c")),
157 )},
158 {`{"setStr":["a","b","c","a","b","c","c"]}`, _NS(
159 _P("setStr", _V("a")),
160 _P("setStr", _V("b")),
161 _P("setStr", _V("c")),
162 )},
163 {`{"setBool":[true,false,true]}`, _NS(
164 _P("setBool", _V(true)),
165 _P("setBool", _V(false)),
166 )},
167 {`{"setNumeric":[1,2,3,3.14159]}`, _NS(
168 _P("setNumeric", _V(1)),
169 _P("setNumeric", _V(2)),
170 _P("setNumeric", _V(3)),
171 _P("setNumeric", _V(3.14159)),
172 )},
173 {`{"color":{}}`, _NS(_P("color"))},
174 {`{"color":null}`, _NS(_P("color"))},
175 {`{"color":{"R":255,"G":0,"B":0}}`, _NS(_P("color"))},
176 {`{"arbitraryWavelengthColor":{}}`, _NS(_P("arbitraryWavelengthColor"))},
177 {`{"arbitraryWavelengthColor":null}`, _NS(_P("arbitraryWavelengthColor"))},
178 {`{"arbitraryWavelengthColor":{"IR":255}}`, _NS(_P("arbitraryWavelengthColor"))},
179 {`{"args":[]}`, _NS(_P("args"))},
180 {`{"args":null}`, _NS(_P("args"))},
181 {`{"args":[null]}`, _NS(_P("args"))},
182 {`{"args":[{"key":"a","value":"b"},{"key":"c","value":"d"}]}`, _NS(_P("args"))},
183 },
184 }, {
185 name: "associative list",
186 rootTypeName: "myRoot",
187 schema: `types:
188 - name: myRoot
189 map:
190 fields:
191 - name: list
192 type:
193 namedType: myList
194 - name: atomicList
195 type:
196 namedType: mySequence
197 - name: myList
198 list:
199 elementType:
200 namedType: myElement
201 elementRelationship: associative
202 keys:
203 - key
204 - id
205 - name: mySequence
206 list:
207 elementType:
208 scalar: string
209 elementRelationship: atomic
210 - name: myElement
211 map:
212 fields:
213 - name: key
214 type:
215 scalar: string
216 - name: id
217 type:
218 scalar: numeric
219 - name: value
220 type:
221 namedType: myValue
222 - name: bv
223 type:
224 scalar: boolean
225 - name: nv
226 type:
227 scalar: numeric
228 - name: myValue
229 map:
230 elementType:
231 scalar: string
232 `,
233 pairs: []objSetPair{
234 {`{"list":[]}`, _NS()},
235 {`{"list":[{"key":"a","id":1,"value":{"a":"a"}}]}`, _NS(
236 _P("list", _KBF("key", "a", "id", 1)),
237 _P("list", _KBF("key", "a", "id", 1), "key"),
238 _P("list", _KBF("key", "a", "id", 1), "id"),
239 _P("list", _KBF("key", "a", "id", 1), "value", "a"),
240 )},
241 {`{"list":[{"key":"a","id":1},{"key":"a","id":2},{"key":"b","id":1}]}`, _NS(
242 _P("list", _KBF("key", "a", "id", 1)),
243 _P("list", _KBF("key", "a", "id", 2)),
244 _P("list", _KBF("key", "b", "id", 1)),
245 _P("list", _KBF("key", "a", "id", 1), "key"),
246 _P("list", _KBF("key", "a", "id", 1), "id"),
247 _P("list", _KBF("key", "a", "id", 2), "key"),
248 _P("list", _KBF("key", "a", "id", 2), "id"),
249 _P("list", _KBF("key", "b", "id", 1), "key"),
250 _P("list", _KBF("key", "b", "id", 1), "id"),
251 )},
252 {`{"list":[{"key":"a","id":1,"nv":2},{"key":"a","id":2,"nv":3},{"key":"b","id":1},{"key":"a","id":2,"bv":true}]}`, _NS(
253 _P("list", _KBF("key", "a", "id", 1)),
254 _P("list", _KBF("key", "a", "id", 1), "key"),
255 _P("list", _KBF("key", "a", "id", 1), "id"),
256 _P("list", _KBF("key", "a", "id", 1), "nv"),
257 _P("list", _KBF("key", "a", "id", 2)),
258 _P("list", _KBF("key", "b", "id", 1)),
259 _P("list", _KBF("key", "b", "id", 1), "key"),
260 _P("list", _KBF("key", "b", "id", 1), "id"),
261 )},
262 {`{"atomicList":["a","a","a"]}`, _NS(_P("atomicList"))},
263 },
264 }}
265
266 func (tt fieldsetTestCase) test(t *testing.T) {
267 parser, err := typed.NewParser(tt.schema)
268 if err != nil {
269 t.Fatalf("failed to create schema: %v", err)
270 }
271 for i, v := range tt.pairs {
272 v := v
273 t.Run(fmt.Sprintf("%v-%v", tt.name, i), func(t *testing.T) {
274 t.Parallel()
275 tv, err := parser.Type(tt.rootTypeName).FromYAML(v.object, typed.AllowDuplicates)
276 if err != nil {
277 t.Fatalf("failed to parse object: %v", err)
278 }
279 fs, err := tv.ToFieldSet()
280 if err != nil {
281 t.Fatalf("got validation errors: %v", err)
282 }
283 if !fs.Equals(v.set) {
284 t.Errorf("wanted\n%s\ngot\n%s\n", v.set, fs)
285 }
286 })
287 }
288 }
289
290 func TestToFieldSet(t *testing.T) {
291 for _, tt := range fieldsetCases {
292 tt := tt
293 t.Run(tt.name, func(t *testing.T) {
294 t.Parallel()
295 tt.test(t)
296 })
297 }
298 }
299
View as plain text