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 removeTestCase struct {
29 name string
30 rootTypeName string
31 schema typed.YAMLObject
32 quadruplets []removeQuadruplet
33 }
34
35 type removeQuadruplet struct {
36 object typed.YAMLObject
37 set *fieldpath.Set
38 removeOutput typed.YAMLObject
39 extractOutput typed.YAMLObject
40 }
41
42 var simplePairSchema = `types:
43 - name: stringPair
44 map:
45 fields:
46 - name: key
47 type:
48 scalar: string
49 - name: value
50 type:
51 namedType: __untyped_atomic_
52 - name: __untyped_atomic_
53 scalar: untyped
54 list:
55 elementType:
56 namedType: __untyped_atomic_
57 elementRelationship: atomic
58 map:
59 elementType:
60 namedType: __untyped_atomic_
61 elementRelationship: atomic
62 `
63
64 var structGrabBagSchema = `types:
65 - name: myStruct
66 map:
67 fields:
68 - name: numeric
69 type:
70 scalar: numeric
71 - name: string
72 type:
73 scalar: string
74 - name: bool
75 type:
76 scalar: boolean
77 - name: setStr
78 type:
79 list:
80 elementType:
81 scalar: string
82 elementRelationship: associative
83 - name: setBool
84 type:
85 list:
86 elementType:
87 scalar: boolean
88 elementRelationship: associative
89 - name: setNumeric
90 type:
91 list:
92 elementType:
93 scalar: numeric
94 elementRelationship: associative
95 `
96
97 var associativeAndAtomicSchema = `types:
98 - name: myRoot
99 map:
100 fields:
101 - name: list
102 type:
103 namedType: myList
104 - name: atomicList
105 type:
106 namedType: mySequence
107 - name: atomicMap
108 type:
109 namedType: myAtomicMap
110 - name: myList
111 list:
112 elementType:
113 namedType: myElement
114 elementRelationship: associative
115 keys:
116 - key
117 - id
118 - name: myAtomicMap
119 map:
120 elementType:
121 scalar: string
122 elementRelationship: atomic
123 - name: mySequence
124 list:
125 elementType:
126 scalar: string
127 elementRelationship: atomic
128 - name: myElement
129 map:
130 fields:
131 - name: key
132 type:
133 scalar: string
134 - name: id
135 type:
136 scalar: numeric
137 - name: value
138 type:
139 namedType: myValue
140 - name: bv
141 type:
142 scalar: boolean
143 - name: nv
144 type:
145 scalar: numeric
146 - name: myValue
147 map:
148 elementType:
149 scalar: string
150 `
151 var atomicTypesSchema = `types:
152 - name: myRoot
153 map:
154 fields:
155 - name: atomicMap
156 type:
157 namedType: myAtomicMap
158 - name: atomicList
159 type:
160 namedType: mySequence
161 - name: myAtomicMap
162 map:
163 elementType:
164 scalar: string
165 elementRelationship: atomic
166 - name: mySequence
167 list:
168 elementType:
169 scalar: string
170 elementRelationship: atomic
171 `
172
173 var nestedTypesSchema = `types:
174 - name: type
175 map:
176 fields:
177 - name: listOfLists
178 type:
179 namedType: listOfLists
180 - name: listOfMaps
181 type:
182 namedType: listOfMaps
183 - name: mapOfLists
184 type:
185 namedType: mapOfLists
186 - name: mapOfMaps
187 type:
188 namedType: mapOfMaps
189 - name: mapOfMapsRecursive
190 type:
191 namedType: mapOfMapsRecursive
192 - name: struct
193 type:
194 namedType: struct
195 - name: struct
196 map:
197 fields:
198 - name: name
199 type:
200 scalar: string
201 - name: value
202 type:
203 scalar: number
204 - name: listOfLists
205 list:
206 elementType:
207 map:
208 fields:
209 - name: name
210 type:
211 scalar: string
212 - name: value
213 type:
214 namedType: list
215 elementRelationship: associative
216 keys:
217 - name
218 - name: list
219 list:
220 elementType:
221 scalar: string
222 elementRelationship: associative
223 - name: listOfMaps
224 list:
225 elementType:
226 map:
227 fields:
228 - name: name
229 type:
230 scalar: string
231 - name: value
232 type:
233 namedType: map
234 elementRelationship: associative
235 keys:
236 - name
237 - name: map
238 map:
239 elementType:
240 scalar: string
241 elementRelationship: associative
242 - name: mapOfLists
243 map:
244 elementType:
245 namedType: list
246 elementRelationship: associative
247 - name: mapOfMaps
248 map:
249 elementType:
250 namedType: map
251 elementRelationship: associative
252 - name: mapOfMapsRecursive
253 map:
254 elementType:
255 namedType: mapOfMapsRecursive
256 elementRelationship: associative
257 `
258
259 var removeCases = []removeTestCase{{
260 name: "simple pair",
261 rootTypeName: "stringPair",
262 schema: typed.YAMLObject(simplePairSchema),
263 quadruplets: []removeQuadruplet{{
264 `{"key":"foo"}`,
265 _NS(_P("key")),
266 ``,
267 `{"key":"foo"}`,
268 }, {
269 `{"key":"foo"}`,
270 _NS(),
271 `{"key":"foo"}`,
272 ``,
273 }, {
274 `{"key":"foo","value":true}`,
275 _NS(_P("key")),
276 `{"value":true}`,
277 `{"key":"foo"}`,
278 }, {
279 `{"key":"foo","value":{"a": "b"}}`,
280 _NS(_P("value")),
281 `{"key":"foo"}`,
282 `{"value":{"a": "b"}}`,
283 }},
284 }, {
285 name: "struct grab bag",
286 rootTypeName: "myStruct",
287 schema: typed.YAMLObject(structGrabBagSchema),
288 quadruplets: []removeQuadruplet{{
289 `{"setBool":[false]}`,
290 _NS(_P("setBool", _V(false))),
291 `{"setBool":null}`,
292 `{"setBool":[false]}`,
293 }, {
294 `{"setBool":[false]}`,
295 _NS(_P("setBool", _V(true))),
296 `{"setBool":[false]}`,
297 `{"setBool":null}`,
298 }, {
299 `{"setBool":[true,false]}`,
300 _NS(_P("setBool", _V(true))),
301 `{"setBool":[false]}`,
302 `{"setBool":[true]}`,
303 }, {
304 `{"setBool":[true,false]}`,
305 _NS(_P("setBool")),
306 ``,
307 `{"setBool":null}`,
308 }, {
309 `{"setNumeric":[1,2,3,4.5]}`,
310 _NS(_P("setNumeric", _V(1)), _P("setNumeric", _V(4.5))),
311 `{"setNumeric":[2,3]}`,
312 `{"setNumeric":[1,4.5]}`,
313 }, {
314 `{"setStr":["a","b","c"]}`,
315 _NS(_P("setStr", _V("a"))),
316 `{"setStr":["b","c"]}`,
317 `{"setStr":["a"]}`,
318 }},
319 }, {
320 name: "associative and atomic",
321 rootTypeName: "myRoot",
322 schema: typed.YAMLObject(associativeAndAtomicSchema),
323 quadruplets: []removeQuadruplet{{
324
325 `{"list":[{"key":"a","id":1},{"key":"a","id":2},{"key":"b","id":1}]}`,
326 _NS(
327 _P("list", _KBF("key", "a", "id", 1), "key"),
328 _P("list", _KBF("key", "a", "id", 1), "id"),
329 ),
330 `unparseable`,
331 `{"list":[{"key":"a","id":1}]}`,
332 }, {
333
334 `{"list":[{"key":"a","id":1},{"key":"a","id":2},{"key":"b","id":1}]}`,
335 _NS(
336 _P("list", _KBF("key", "a", "id", 1)),
337 ),
338 `{"list":[{"key":"a","id":2},{"key":"b","id":1}]}`,
339 `unparseable`,
340 }, {
341 `{"atomicList":["a", "a", "a"]}`,
342 _NS(_P("atomicList")),
343 ``,
344
345 `{"atomicList":["a", "a", "a"]}`,
346 }, {
347 `{"atomicMap":{"a": "c", "b": "d"}}`,
348 _NS(_P("atomicMap")),
349 ``,
350
351 `{"atomicMap":{"a": "c", "b": "d"}}`,
352 }},
353 }, {
354 name: "nested types",
355 rootTypeName: "type",
356 schema: typed.YAMLObject(nestedTypesSchema),
357 quadruplets: []removeQuadruplet{{
358
359 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
360 _NS(
361 _P("listOfLists", _KBF("name", "a"), "name"),
362 _P("listOfLists", _KBF("name", "a"), "value", _V("b")),
363 _P("listOfLists", _KBF("name", "a"), "value", _V("c")),
364 _P("listOfLists", _KBF("name", "d"), "name"),
365 ),
366 `unparseable`,
367 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
368 }, {
369
370 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
371 _NS(
372 _P("listOfLists"),
373 ),
374 ``,
375 `{"listOfLists": null}`,
376 }, {
377
378 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
379 _NS(_P("listOfLists", _KBF("name", "d"), "name")),
380
381 `unparseable`,
382 `{"listOfLists": [{"name": "d"}]}`,
383 }, {
384
385 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
386 _NS(_P("listOfLists", _KBF("name", "d"))),
387 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}]}`,
388 `unparseable`,
389 }, {
390
391 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
392 _NS(
393 _P("listOfLists", _KBF("name", "a"), "name"),
394 ),
395 `unparseable`,
396 `{"listOfLists": [{"name": "a"}]}`,
397 }, {
398
399 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
400 _NS(
401 _P("listOfLists", _KBF("name", "a")),
402 ),
403 `{"listOfLists": [{"name": "d"}]}`,
404 `unparseable`,
405 }, {
406
407 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
408 _NS(
409 _P("listOfLists", _KBF("name", "a"), "value", _V("b")),
410 ),
411 `{"listOfLists": [{"name":"a", "value": ["c"]}, {"name": "d"}]}`,
412 `unparseable`,
413 }, {
414
415 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
416 _NS(
417 _P("listOfLists", _KBF("name", "a"), "name"),
418 _P("listOfLists", _KBF("name", "a"), "value", _V("b")),
419 ),
420 `unparseable`,
421 `{"listOfLists": [{"name": "a", "value": ["b"]}]}`,
422 }, {
423
424 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
425 _NS(
426 _P("listOfLists", _KBF("name", "x")),
427 ),
428 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
429 `{"listOfLists":null}`,
430 }, {
431
432 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
433 _NS(
434 _P("listOfLists", _KBF("name", "a"), "value", _V("x")),
435 ),
436 `{"listOfLists": [{"name":"a", "value": ["b","c"]}, {"name": "d"}]}`,
437 `unparseable`,
438 }, {
439
440 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
441 _NS(
442 _P("listOfLists", _KBF("name", "a"), "name"),
443 _P("listOfLists", _KBF("name", "a"), "value", _V("x")),
444 ),
445 `unparseable`,
446 `unparseable`,
447 }, {
448
449 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
450 _NS(
451 _P(_V("b")),
452 ),
453 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
454 ``,
455 }, {
456
457 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
458 _NS(
459 _P("listOfMaps", _KBF("name", "a"), "name"),
460 _P("listOfMaps", _KBF("name", "a"), "value", "b"),
461 _P("listOfMaps", _KBF("name", "a"), "value", "c"),
462 _P("listOfMaps", _KBF("name", "d"), "name"),
463 _P("listOfMaps", _KBF("name", "d"), "value", "e"),
464 ),
465 `unparseable`,
466 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
467 }, {
468
469 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
470 _NS(
471 _P("listOfMaps"),
472 ),
473 ``,
474 `{"listOfMaps"}`,
475 }, {
476
477 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
478 _NS(
479 _P("listOfMaps", _KBF("name", "a"), "name"),
480 ),
481 `unparseable`,
482 `{"listOfMaps": [{"name": "a"}]}`,
483 }, {
484
485 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
486 _NS(
487 _P("listOfMaps", _KBF("name", "a")),
488 ),
489 `{"listOfMaps": [{"name": "d", "value": {"e":"z"}}]}`,
490 `unparseable`,
491 }, {
492
493 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
494 _NS(
495 _P("listOfMaps", _KBF("name", "a"), "value", "b"),
496 ),
497 `{"listOfMaps": [{"name": "a", "value": {"c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
498 `unparseable`,
499 }, {
500
501 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
502 _NS(
503 _P("listOfMaps", _KBF("name", "a"), "name"),
504 _P("listOfMaps", _KBF("name", "a"), "value", "b"),
505 ),
506 `unparseable`,
507 `{"listOfMaps": [{"name": "a", "value": {"b":"x"}}]}`,
508 }, {
509
510 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
511 _NS(
512 _P("listOfMaps", _KBF("name", "q"), "name"),
513 ),
514 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
515 `{"listOfMaps":null}`,
516 }, {
517
518 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
519 _NS(
520 _P("listOfMaps", _KBF("name", "a"), "value", "q"),
521 ),
522 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
523 `unparseable`,
524 }, {
525
526 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
527 _NS(
528 _P("listOfMaps", _KBF("name", "a"), "name"),
529 _P("listOfMaps", _KBF("name", "a"), "value", "q"),
530 ),
531 `unparseable`,
532 `{"listOfMaps": [{"name":"a", "value": null}]}`,
533 }, {
534
535 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
536 _NS(
537 _P("mapOfLists", "b", _V("a")),
538 _P("mapOfLists", "b", _V("c")),
539 _P("mapOfLists", "d", _V("e")),
540 _P("mapOfLists", "d", _V("f")),
541 ),
542 `unparseable`,
543 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
544 }, {
545
546 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
547 _NS(
548 _P("mapOfLists"),
549 ),
550 ``,
551 `{"mapOfLists":null}`,
552 }, {
553
554 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
555 _NS(
556 _P("mapOfLists", "b"),
557 ),
558 `{"mapOfLists": {"d":["e", "f"]}}`,
559 `{"mapOfLists": {"b":null}}`,
560 }, {
561
562 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
563 _NS(
564 _P("mapOfLists", "b", _V("a")),
565 ),
566 `{"mapOfLists":{"b":["c"],"d":["e", "f"]}}`,
567 `{"mapOfLists":{"b":["a"]}}`,
568 }, {
569
570 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
571 _NS(
572 _P("mapOfLists", "q"),
573 ),
574 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
575 `{"mapOfLists":null}`,
576 }, {
577
578 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
579 _NS(
580 _P("mapOfLists", "b", _V("q")),
581 ),
582 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
583 `{"mapOfLists":{"b":null}}`,
584 }, {
585
586 `{"mapOfLists": {"b":null, "d":["e", "f"]}}`,
587 _NS(
588 _P("mapOfLists", "b"),
589 ),
590 `{"mapOfLists": {"d":["e", "f"]}}`,
591 `{"mapOfLists":{"b":null}}`,
592 }, {
593
594 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
595 _NS(
596 _P(_V("a")),
597 ),
598 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
599 ``,
600 }, {
601
602 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
603 _NS(
604 _P("mapOfMaps", "b", "a"),
605 _P("mapOfMaps", "b", "c"),
606 _P("mapOfMaps", "d", "e"),
607 _P("mapOfMaps", "d", "f"),
608 ),
609 `unparseable`,
610 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
611 }, {
612
613 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
614 _NS(
615 _P("mapOfMaps"),
616 ),
617 ``,
618 `{"mapOfMaps":null}`,
619 }, {
620
621 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
622 _NS(
623 _P("mapOfMaps", "b"),
624 ),
625 `{"mapOfMaps": {"d":{"e":"y", "f":"w"}}}`,
626 `{"mapOfMaps": {"b":null}}`,
627 }, {
628
629 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
630 _NS(
631 _P("mapOfMaps", "b", "a"),
632 ),
633 `{"mapOfMaps": {"b":{"c":"z"},"d":{"e":"y", "f":"w"}}}`,
634 `{"mapOfMaps": {"b":{"a":"x"}}}`,
635 }, {
636
637 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
638 _NS(
639 _P("mapOfMaps", "q"),
640 ),
641 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
642 `{"mapOfMaps": null}`,
643 }, {
644
645 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
646 _NS(
647 _P("mapOfMaps", "b", "q"),
648 ),
649 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
650 `{"mapOfMaps": {"b":null}}`,
651 }, {
652
653 `{"mapOfMaps": {"b":null, "d":{"e":"y", "f":"w"}}}`,
654 _NS(
655 _P("mapOfMaps", "b"),
656 ),
657 `{"mapOfMaps": {"d":{"e":"y", "f":"w"}}}`,
658 `{"mapOfMaps": {"b":null}}`,
659 }, {
660
661 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
662 _NS(
663 _P("a"),
664 ),
665 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
666 ``,
667 }, {
668
669 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}}}}`,
670 _NS(
671 _P("mapOfMapsRecursive"),
672 ),
673 ``,
674 `{"mapOfMapsRecursive":null}`,
675 }, {
676
677 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}}}}`,
678 _NS(
679 _P("mapOfMapsRecursive", "a"),
680 ),
681 `{"mapOfMapsRecursive"}`,
682 `{"mapOfMapsRecursive": {"a":null}}`,
683 }, {
684
685 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}}}}`,
686 _NS(
687 _P("mapOfMapsRecursive", "a", "b"),
688 ),
689 `{"mapOfMapsRecursive":{"a":null}}`,
690 `{"mapOfMapsRecursive": {"a":{"b":null}}}`,
691 }, {
692
693 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}}}}`,
694 _NS(
695 _P("mapOfMapsRecursive", "a", "b", "c"),
696 ),
697 `{"mapOfMapsRecursive":{"a":{"b":null}}}`,
698 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}}}}`,
699 }},
700 }}
701
702 func (tt removeTestCase) test(t *testing.T) {
703 parser, err := typed.NewParser(tt.schema)
704 if err != nil {
705 t.Fatalf("failed to create schema: %v", err)
706 }
707 pt := parser.Type(tt.rootTypeName)
708
709 for i, quadruplet := range tt.quadruplets {
710 quadruplet := quadruplet
711 t.Run(fmt.Sprintf("%v-valid-%v", tt.name, i), func(t *testing.T) {
712 t.Parallel()
713
714 tv, err := pt.FromYAML(quadruplet.object)
715 if err != nil {
716 t.Fatalf("unable to parser/validate object yaml: %v\n%v", err, quadruplet.object)
717 }
718
719
720 if quadruplet.removeOutput != "unparseable" {
721 rmOut, err := pt.FromYAML(quadruplet.removeOutput)
722 if err != nil {
723 t.Fatalf("unable to parser/validate removeOutput yaml: %v\n%v", err, quadruplet.removeOutput)
724 }
725
726 rmGot := tv.RemoveItems(quadruplet.set)
727 if !value.Equals(rmGot.AsValue(), rmOut.AsValue()) {
728 t.Errorf("RemoveItems expected\n%v\nbut got\n%v\n",
729 value.ToString(rmOut.AsValue()), value.ToString(rmGot.AsValue()),
730 )
731 }
732 }
733
734
735 if quadruplet.extractOutput != "unparseable" {
736 exOut, err := pt.FromYAML(quadruplet.extractOutput)
737 if err != nil {
738 t.Fatalf("unable to parser/validate extractOutput yaml: %v\n%v", err, quadruplet.extractOutput)
739 }
740 exGot := tv.ExtractItems(quadruplet.set)
741 if !value.Equals(exGot.AsValue(), exOut.AsValue()) {
742 t.Errorf("ExtractItems expected\n%v\nbut got\n%v\n",
743 value.ToString(exOut.AsValue()), value.ToString(exGot.AsValue()),
744 )
745 }
746
747 }
748 })
749 }
750 }
751
752 func TestRemove(t *testing.T) {
753 for _, tt := range removeCases {
754 tt := tt
755 t.Run(tt.name, func(t *testing.T) {
756 t.Parallel()
757 tt.test(t)
758 })
759 }
760 }
761
762 type reversibleExtractTestCase struct {
763 name string
764 rootTypeName string
765 schema typed.YAMLObject
766 pairs []reversibleExtractPair
767 }
768
769 type reversibleExtractPair struct {
770 object typed.YAMLObject
771 pso typed.YAMLObject
772 }
773
774 var reversibleExtractCases = []reversibleExtractTestCase{{
775 name: "nested types",
776 rootTypeName: "type",
777 schema: typed.YAMLObject(nestedTypesSchema),
778 pairs: []reversibleExtractPair{{
779
780 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
781 `{"listOfLists": [{"name": "f", "value": ["j", "k"]},]}`,
782 }, {
783
784 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
785 `{"listOfLists": [{"name": "a", "value": ["j", "k"]},]}`,
786 }, {
787
788 `{"listOfLists": [{"name": "a", "value": ["b", "c"]}, {"name": "d"}]}`,
789 `{"listOfLists": [{"name": "a", "value": null},]}`,
790 }, {
791
792 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
793 `{"listOfMaps": [{"name": "f", "value": {"q":"p"}}]}`,
794 }, {
795
796 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
797 `{"listOfMaps": [{"name": "a", "value": {"f":"p"}}]}`,
798 }, {
799
800 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
801 `{"listOfMaps": [{"name": "a", "value": {"b":"p"}}]}`,
802 }, {
803
804 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
805 `{"listOfMaps": [{"name": "a", "value": null}]}`,
806 }, {
807
808 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
809 `{"mapOfLists": {"x":["y","z"]}}`,
810 }, {
811
812 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
813 `{"mapOfLists": {"b":["y","z"]}}`,
814 }, {
815
816 `{"mapOfLists": {"b":["a","c"], "d":["e", "f"]}}`,
817 `{"mapOfLists": {"b":null}}`,
818 }, {
819
820 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
821 `{"mapOfMaps": {"i":{"j":"k"}}}`,
822 }, {
823
824 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
825 `{"mapOfMaps": {"b":{"j":"k"}}}`,
826 }, {
827
828 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
829 `{"mapOfMaps": {"b":{"a":"k"}}}`,
830 }, {
831
832 `{"mapOfMaps": {"b":{"a":"x","c":"z"}, "d":{"e":"y", "f":"w"}}}`,
833 `{"mapOfMaps": {"b": null}}`,
834 }, {
835
836 `{"listOfMaps": [{"name": "a", "value": {"b":"x", "c":"y"}}, {"name": "d", "value": {"e":"z"}}]}`,
837 `{"mapOfLists": {"b":["y","z"]}}`,
838 }, {
839
840 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}, "d":{"e":{"f":null}, "g":null}}}}`,
841 `{"mapOfMapsRecursive": {"a":{"d":{"e":{"f":{"q":null}, "p":null}}}}}`,
842 }, {
843
844 `{"mapOfMapsRecursive": {"a":{"b":{"c":{"d":{"e":{"f":null}}, "g":{"h":null}, "i":null}}}}}`,
845 `{"mapOfMapsRecursive": {"a":{"b":{"c":null}}}}`,
846 }},
847 }}
848
849 func (tt reversibleExtractTestCase) test(t *testing.T) {
850 parser, err := typed.NewParser(tt.schema)
851 if err != nil {
852 t.Fatalf("failed to create schema: %v", err)
853 }
854 pt := parser.Type(tt.rootTypeName)
855
856 for i, pair := range tt.pairs {
857 pair := pair
858 t.Run(fmt.Sprintf("%v-valid-%v", tt.name, i), func(t *testing.T) {
859 t.Parallel()
860
861 initialObj, err := pt.FromYAML(pair.object)
862 if err != nil {
863 t.Fatalf("unable to parser/validate initial object yaml: %v\n%v", err, pair.object)
864 }
865
866 pso, err := pt.FromYAML(pair.pso)
867 if err != nil {
868 t.Fatalf("unable to parser/validate PSO yaml: %v\n%v", err, pair.pso)
869 }
870
871 mergedObj, err := initialObj.Merge(pso)
872 if err != nil {
873 t.Fatalf("unable to merge PSO into initial object: %v\n", err)
874 }
875
876 fieldSet, err := pso.ToFieldSet()
877 if err != nil {
878 t.Fatalf("unable to convert pso to fieldset: %v\n%v", err, pso)
879 }
880
881
882
883 extractSet := fieldSet.Leaves()
884
885 extracted := mergedObj.ExtractItems(extractSet)
886
887 if !value.Equals(pso.AsValue(), extracted.AsValue()) {
888 t.Errorf("ExtractItems not reversible expected\n%v\nbut got\n%v\n",
889 value.ToString(pso.AsValue()), value.ToString(extracted.AsValue()),
890 )
891 }
892 })
893 }
894 }
895
896
897
898
899
900 func TestReversibleExtract(t *testing.T) {
901 for _, tt := range reversibleExtractCases {
902 tt := tt
903 t.Run(tt.name, func(t *testing.T) {
904 t.Parallel()
905 tt.test(t)
906 })
907 }
908 }
909
View as plain text