1 package fieldmask
2
3 import (
4 "testing"
5
6 syntaxv1 "go.einride.tech/aip/proto/gen/einride/example/syntax/v1"
7 "google.golang.org/genproto/googleapis/example/library/v1"
8 "google.golang.org/protobuf/proto"
9 "google.golang.org/protobuf/testing/protocmp"
10 "google.golang.org/protobuf/types/known/fieldmaskpb"
11 "gotest.tools/v3/assert"
12 "gotest.tools/v3/assert/cmp"
13 )
14
15 func TestUpdate(t *testing.T) {
16 t.Parallel()
17 t.Run("should panic on different src and dst", func(t *testing.T) {
18 t.Parallel()
19 assert.Assert(t, cmp.Panics(func() {
20 Update(&fieldmaskpb.FieldMask{}, &library.Book{}, &library.Shelf{})
21 }))
22 })
23
24 t.Run("full replacement", func(t *testing.T) {
25 t.Parallel()
26 for _, tt := range []struct {
27 name string
28 src proto.Message
29 dst proto.Message
30 }{
31 {
32 name: "scalars",
33 src: &syntaxv1.Message{
34 Double: 111,
35 Float: 111,
36 Bool: true,
37 String_: "111",
38 Bytes: []byte{111},
39 },
40 dst: &syntaxv1.Message{
41 Double: 222,
42 Float: 222,
43 Bool: false,
44 String_: "222",
45 Bytes: []byte{222},
46 },
47 },
48 {
49 name: "repeated",
50 src: &syntaxv1.Message{
51 RepeatedDouble: []float64{111},
52 RepeatedFloat: []float32{111},
53 RepeatedBool: []bool{true},
54 RepeatedString: []string{"111"},
55 RepeatedBytes: [][]byte{{111}},
56 },
57 dst: &syntaxv1.Message{
58 RepeatedDouble: []float64{222},
59 RepeatedFloat: []float32{222},
60 RepeatedBool: []bool{false},
61 RepeatedString: []string{"222"},
62 RepeatedBytes: [][]byte{{222}},
63 },
64 },
65 {
66 name: "nested",
67 src: &syntaxv1.Message{
68 Message: &syntaxv1.Message{
69 String_: "src",
70 },
71 },
72 dst: &syntaxv1.Message{
73 Message: &syntaxv1.Message{
74 String_: "dst",
75 Int64: 222,
76 },
77 },
78 },
79 {
80 name: "maps",
81 src: &syntaxv1.Message{
82 MapStringString: map[string]string{
83 "src-key": "src-value",
84 },
85 MapStringMessage: map[string]*syntaxv1.Message{
86 "src-key": {
87 String_: "src-value",
88 },
89 },
90 },
91 dst: &syntaxv1.Message{
92 MapStringString: map[string]string{
93 "dst-key": "dst-value",
94 },
95 MapStringMessage: map[string]*syntaxv1.Message{
96 "dst-key": {
97 String_: "dst-value",
98 },
99 },
100 },
101 },
102 {
103 name: "oneof: swap",
104 src: &syntaxv1.Message{
105 Oneof: &syntaxv1.Message_OneofString{
106 OneofString: "src",
107 },
108 },
109 dst: &syntaxv1.Message{
110 Oneof: &syntaxv1.Message_OneofMessage2{
111 OneofMessage2: &syntaxv1.Message{
112 String_: "dst",
113 },
114 },
115 },
116 },
117 {
118 name: "oneof: message swap",
119 src: &syntaxv1.Message{
120 Oneof: &syntaxv1.Message_OneofMessage1{
121 OneofMessage1: &syntaxv1.Message{
122 String_: "src",
123 },
124 },
125 },
126 dst: &syntaxv1.Message{
127 Oneof: &syntaxv1.Message_OneofMessage2{
128 OneofMessage2: &syntaxv1.Message{
129 String_: "dst",
130 },
131 },
132 },
133 },
134 } {
135 tt := tt
136 t.Run(tt.name, func(t *testing.T) {
137 t.Parallel()
138 srcClone := proto.Clone(tt.src)
139 Update(&fieldmaskpb.FieldMask{Paths: []string{"*"}}, tt.dst, tt.src)
140 assert.DeepEqual(t, srcClone, tt.dst, protocmp.Transform())
141 })
142 }
143 })
144 t.Run("wire set fields", func(t *testing.T) {
145 t.Parallel()
146 for _, tt := range []struct {
147 name string
148 src proto.Message
149 dst proto.Message
150 expected proto.Message
151 }{
152 {
153 name: "scalars",
154 src: &syntaxv1.Message{
155 Double: 111,
156 Float: 111,
157 },
158 dst: &syntaxv1.Message{
159 Double: 222,
160 Float: 222,
161 Bool: false,
162 String_: "222",
163 Bytes: []byte{222},
164 },
165 expected: &syntaxv1.Message{
166 Double: 111,
167 Float: 111,
168 Bool: false,
169 String_: "222",
170 Bytes: []byte{222},
171 },
172 },
173 {
174 name: "repeated",
175 src: &syntaxv1.Message{
176 RepeatedDouble: []float64{111},
177 },
178 dst: &syntaxv1.Message{
179 RepeatedDouble: []float64{222},
180 RepeatedFloat: []float32{222},
181 RepeatedBool: []bool{false},
182 RepeatedString: []string{"222"},
183 RepeatedBytes: [][]byte{{222}},
184 },
185 expected: &syntaxv1.Message{
186 RepeatedDouble: []float64{111},
187 RepeatedFloat: []float32{222},
188 RepeatedBool: []bool{false},
189 RepeatedString: []string{"222"},
190 RepeatedBytes: [][]byte{{222}},
191 },
192 },
193 {
194 name: "nested",
195 src: &syntaxv1.Message{
196 Message: &syntaxv1.Message{String_: "src"},
197 },
198 dst: &syntaxv1.Message{
199 Message: &syntaxv1.Message{
200 String_: "dst",
201 Int64: 222,
202 },
203 },
204 expected: &syntaxv1.Message{
205 Message: &syntaxv1.Message{
206 String_: "src",
207 Int64: 222,
208 },
209 },
210 },
211 {
212 name: "nested: dst nil",
213 src: &syntaxv1.Message{
214 Message: &syntaxv1.Message{String_: "src"},
215 },
216 dst: &syntaxv1.Message{
217 Message: nil,
218 },
219 expected: &syntaxv1.Message{
220 Message: &syntaxv1.Message{String_: "src"},
221 },
222 },
223 {
224 name: "maps",
225 src: &syntaxv1.Message{
226 MapStringString: map[string]string{
227 "src-key": "src-value",
228 },
229 MapStringMessage: map[string]*syntaxv1.Message{
230 "src-key": {String_: "src-value"},
231 },
232 },
233 dst: &syntaxv1.Message{
234 MapStringString: map[string]string{
235 "dst-key": "dst-value",
236 },
237 MapStringMessage: map[string]*syntaxv1.Message{
238 "dst-key": {String_: "dst-value"},
239 },
240 },
241 expected: &syntaxv1.Message{
242 MapStringString: map[string]string{
243 "src-key": "src-value",
244 },
245 MapStringMessage: map[string]*syntaxv1.Message{
246 "src-key": {String_: "src-value"},
247 },
248 },
249 },
250 {
251 name: "maps: dst nil",
252 src: &syntaxv1.Message{
253 MapStringString: map[string]string{
254 "src-key": "src-value",
255 },
256 MapStringMessage: map[string]*syntaxv1.Message{
257 "src-key": {String_: "src-value"},
258 },
259 },
260 dst: &syntaxv1.Message{
261 MapStringString: nil,
262 MapStringMessage: nil,
263 },
264 expected: &syntaxv1.Message{
265 MapStringString: map[string]string{
266 "src-key": "src-value",
267 },
268 MapStringMessage: map[string]*syntaxv1.Message{
269 "src-key": {String_: "src-value"},
270 },
271 },
272 },
273 {
274 name: "oneof",
275 src: &syntaxv1.Message{
276 Oneof: &syntaxv1.Message_OneofMessage1{
277 OneofMessage1: &syntaxv1.Message{String_: "src"},
278 },
279 },
280 dst: &syntaxv1.Message{
281 Oneof: &syntaxv1.Message_OneofMessage1{
282 OneofMessage1: &syntaxv1.Message{
283 String_: "dst",
284 Int64: 222,
285 },
286 },
287 },
288 expected: &syntaxv1.Message{
289 Oneof: &syntaxv1.Message_OneofMessage1{
290 OneofMessage1: &syntaxv1.Message{
291 String_: "src",
292 Int64: 222,
293 },
294 },
295 },
296 },
297 {
298 name: "oneof: kind swap",
299 src: &syntaxv1.Message{
300 Oneof: &syntaxv1.Message_OneofString{
301 OneofString: "src",
302 },
303 },
304 dst: &syntaxv1.Message{
305 Oneof: &syntaxv1.Message_OneofMessage2{
306 OneofMessage2: &syntaxv1.Message{
307 String_: "dst",
308 },
309 },
310 },
311 expected: &syntaxv1.Message{
312 Oneof: &syntaxv1.Message_OneofString{
313 OneofString: "src",
314 },
315 },
316 },
317 {
318 name: "oneof: message swap",
319 src: &syntaxv1.Message{
320 Oneof: &syntaxv1.Message_OneofMessage1{
321 OneofMessage1: &syntaxv1.Message{
322 String_: "src",
323 },
324 },
325 },
326 dst: &syntaxv1.Message{
327 Oneof: &syntaxv1.Message_OneofMessage2{
328 OneofMessage2: &syntaxv1.Message{
329 String_: "dst",
330 },
331 },
332 },
333 expected: &syntaxv1.Message{
334 Oneof: &syntaxv1.Message_OneofMessage1{
335 OneofMessage1: &syntaxv1.Message{
336 String_: "src",
337 },
338 },
339 },
340 },
341 } {
342 tt := tt
343 t.Run(tt.name, func(t *testing.T) {
344 t.Parallel()
345 Update(nil, tt.dst, tt.src)
346 assert.DeepEqual(t, tt.expected, tt.dst, protocmp.Transform())
347 })
348 }
349 })
350 t.Run("paths", func(t *testing.T) {
351 t.Parallel()
352 for _, tt := range []struct {
353 name string
354 paths []string
355 src proto.Message
356 dst proto.Message
357 expected proto.Message
358 }{
359 {
360 name: "scalars",
361 paths: []string{
362 "double",
363 "bytes",
364 },
365 src: &syntaxv1.Message{
366 Double: 111,
367 Float: 111,
368 Bytes: []byte{111},
369 },
370 dst: &syntaxv1.Message{
371 Double: 222,
372 Float: 222,
373 Bool: false,
374 String_: "222",
375 Bytes: []byte{222},
376 },
377 expected: &syntaxv1.Message{
378 Double: 111,
379 Float: 222,
380 Bytes: []byte{111},
381 Bool: false,
382 String_: "222",
383 },
384 },
385 {
386 name: "repeated scalar",
387 paths: []string{
388 "repeated_double",
389 "repeated_string",
390 },
391 src: &syntaxv1.Message{
392 RepeatedDouble: []float64{111},
393 RepeatedFloat: []float32{111},
394 },
395 dst: &syntaxv1.Message{
396 RepeatedDouble: []float64{222},
397 RepeatedString: []string{"222"},
398 RepeatedBytes: [][]byte{{222}},
399 },
400 expected: &syntaxv1.Message{
401 RepeatedDouble: []float64{111},
402 RepeatedBytes: [][]byte{{222}},
403 },
404 },
405 {
406 name: "repeated message",
407 paths: []string{
408 "repeated_message",
409 },
410 src: &syntaxv1.Message{
411 RepeatedMessage: []*syntaxv1.Message{
412 {String_: "src"},
413 {Int64: 111},
414 },
415 },
416 dst: &syntaxv1.Message{
417 RepeatedMessage: []*syntaxv1.Message{
418 {Int64: 222},
419 {String_: "dst"},
420 },
421 },
422 expected: &syntaxv1.Message{
423 RepeatedMessage: []*syntaxv1.Message{
424 {String_: "src"},
425 {Int64: 111},
426 },
427 },
428 },
429 {
430
431 name: "repeated message: deep",
432 paths: []string{
433 "repeated_message.string",
434 },
435 src: &syntaxv1.Message{
436 RepeatedMessage: []*syntaxv1.Message{
437 {String_: "src"},
438 {Int64: 111},
439 },
440 },
441 dst: &syntaxv1.Message{
442 RepeatedMessage: []*syntaxv1.Message{
443 {Int64: 222},
444 {String_: "dst"},
445 },
446 },
447 expected: &syntaxv1.Message{
448 RepeatedMessage: []*syntaxv1.Message{
449 {Int64: 222},
450 {String_: "dst"},
451 },
452 },
453 },
454 {
455 name: "nested",
456 paths: []string{
457 "message",
458 },
459 src: &syntaxv1.Message{
460 Message: &syntaxv1.Message{
461 String_: "src",
462 },
463 },
464 dst: &syntaxv1.Message{
465 Message: &syntaxv1.Message{
466 String_: "dst",
467 Int64: 222,
468 },
469 },
470 expected: &syntaxv1.Message{
471 Message: &syntaxv1.Message{
472 String_: "src",
473 },
474 },
475 },
476 {
477 name: "nested: deep",
478 paths: []string{
479 "message.string",
480 },
481 src: &syntaxv1.Message{
482 Message: &syntaxv1.Message{
483 String_: "src",
484 },
485 },
486 dst: &syntaxv1.Message{
487 Message: &syntaxv1.Message{
488 String_: "dst",
489 Int64: 222,
490 },
491 },
492 expected: &syntaxv1.Message{
493 Message: &syntaxv1.Message{
494 String_: "src",
495 Int64: 222,
496 },
497 },
498 },
499 {
500 name: "nested: dst nil",
501 paths: []string{
502 "message",
503 },
504 src: &syntaxv1.Message{
505 Message: &syntaxv1.Message{
506 String_: "src",
507 },
508 },
509 dst: &syntaxv1.Message{
510 Message: nil,
511 },
512 expected: &syntaxv1.Message{
513 Message: &syntaxv1.Message{
514 String_: "src",
515 },
516 },
517 },
518 {
519 name: "nested: deep, dst nil",
520 paths: []string{
521 "message.string",
522 },
523 src: &syntaxv1.Message{
524 Message: &syntaxv1.Message{
525 String_: "src",
526 },
527 },
528 dst: &syntaxv1.Message{
529 Message: nil,
530 },
531 expected: &syntaxv1.Message{
532 Message: &syntaxv1.Message{
533 String_: "src",
534 },
535 },
536 },
537 {
538 name: "nested: deep, src nil",
539 paths: []string{
540 "message.string",
541 },
542 src: &syntaxv1.Message{
543 Message: nil,
544 },
545 dst: &syntaxv1.Message{
546 Message: &syntaxv1.Message{
547 String_: "src",
548 },
549 },
550 expected: &syntaxv1.Message{
551 Message: &syntaxv1.Message{},
552 },
553 },
554 {
555 name: "maps",
556 paths: []string{
557 "map_string_string",
558 },
559 src: &syntaxv1.Message{
560 MapStringString: map[string]string{
561 "src-key": "src-value",
562 },
563 MapStringMessage: map[string]*syntaxv1.Message{
564 "src-key": {String_: "src-value"},
565 },
566 },
567 dst: &syntaxv1.Message{
568 MapStringString: map[string]string{
569 "dst-key": "dst-value",
570 },
571 MapStringMessage: map[string]*syntaxv1.Message{
572 "dst-key": {String_: "dst-value"},
573 },
574 },
575 expected: &syntaxv1.Message{
576 MapStringString: map[string]string{
577 "src-key": "src-value",
578 },
579 MapStringMessage: map[string]*syntaxv1.Message{
580 "dst-key": {String_: "dst-value"},
581 },
582 },
583 },
584 {
585
586 name: "maps: deep",
587 paths: []string{
588 "map_string_string.src1",
589 },
590 src: &syntaxv1.Message{
591 MapStringString: map[string]string{
592 "src1": "src1-value",
593 "src2": "src2-value",
594 },
595 },
596 dst: &syntaxv1.Message{
597 MapStringString: map[string]string{
598 "dst-key": "dst-value",
599 },
600 },
601 expected: &syntaxv1.Message{
602 MapStringString: map[string]string{
603 "dst-key": "dst-value",
604 },
605 },
606 },
607 {
608 name: "maps: dst nil",
609 paths: []string{
610 "map_string_string",
611 },
612 src: &syntaxv1.Message{
613 MapStringString: map[string]string{
614 "src-key": "src-value",
615 },
616 MapStringMessage: map[string]*syntaxv1.Message{
617 "src-key": {String_: "src-value"},
618 },
619 },
620 dst: &syntaxv1.Message{},
621 expected: &syntaxv1.Message{
622 MapStringString: map[string]string{
623 "src-key": "src-value",
624 },
625 },
626 },
627 {
628 name: "maps: src nil",
629 paths: []string{
630 "map_string_string",
631 },
632 src: &syntaxv1.Message{},
633 dst: &syntaxv1.Message{
634 MapStringString: map[string]string{
635 "dst-key": "dst-value",
636 },
637 MapStringMessage: map[string]*syntaxv1.Message{
638 "dst-key": {String_: "dst-value"},
639 },
640 },
641 expected: &syntaxv1.Message{
642 MapStringMessage: map[string]*syntaxv1.Message{
643 "dst-key": {String_: "dst-value"},
644 },
645 },
646 },
647 {
648 name: "oneof",
649 paths: []string{
650 "oneof_message1",
651 },
652 src: &syntaxv1.Message{
653 Oneof: &syntaxv1.Message_OneofMessage1{
654 OneofMessage1: &syntaxv1.Message{
655 String_: "src",
656 },
657 },
658 },
659 dst: &syntaxv1.Message{
660 Oneof: &syntaxv1.Message_OneofMessage1{
661 OneofMessage1: &syntaxv1.Message{
662 String_: "dst",
663 Int64: 222,
664 },
665 },
666 },
667 expected: &syntaxv1.Message{
668 Oneof: &syntaxv1.Message_OneofMessage1{
669 OneofMessage1: &syntaxv1.Message{
670 String_: "src",
671 },
672 },
673 },
674 },
675 {
676 name: "oneof: kind swap",
677 paths: []string{
678 "oneof_string",
679 },
680 src: &syntaxv1.Message{
681 Oneof: &syntaxv1.Message_OneofString{
682 OneofString: "src",
683 },
684 },
685 dst: &syntaxv1.Message{
686 Oneof: &syntaxv1.Message_OneofMessage2{
687 OneofMessage2: &syntaxv1.Message{
688 String_: "dst",
689 },
690 },
691 },
692 expected: &syntaxv1.Message{
693 Oneof: &syntaxv1.Message_OneofString{
694 OneofString: "src",
695 },
696 },
697 },
698 {
699 name: "oneof: kind swap src nil",
700 paths: []string{
701 "oneof_message2",
702 },
703 src: &syntaxv1.Message{
704 Oneof: &syntaxv1.Message_OneofString{
705 OneofString: "src",
706 },
707 },
708 dst: &syntaxv1.Message{
709 Oneof: &syntaxv1.Message_OneofMessage2{
710 OneofMessage2: &syntaxv1.Message{
711 String_: "dst",
712 },
713 },
714 },
715 expected: &syntaxv1.Message{
716 Oneof: nil,
717 },
718 },
719 {
720 name: "oneof: deep",
721 paths: []string{
722 "oneof_message1.string",
723 },
724 src: &syntaxv1.Message{
725 Oneof: &syntaxv1.Message_OneofMessage1{
726 OneofMessage1: &syntaxv1.Message{
727 String_: "src",
728 },
729 },
730 },
731 dst: &syntaxv1.Message{
732 Oneof: &syntaxv1.Message_OneofMessage2{
733 OneofMessage2: &syntaxv1.Message{
734 String_: "dst",
735 },
736 },
737 },
738 expected: &syntaxv1.Message{
739 Oneof: &syntaxv1.Message_OneofMessage1{
740 OneofMessage1: &syntaxv1.Message{
741 String_: "src",
742 },
743 },
744 },
745 },
746 {
747 name: "oneof: deep src nil",
748 paths: []string{
749 "oneof_message2.string",
750 },
751 src: &syntaxv1.Message{
752 Oneof: &syntaxv1.Message_OneofMessage1{
753 OneofMessage1: &syntaxv1.Message{
754 String_: "src",
755 },
756 },
757 },
758 dst: &syntaxv1.Message{
759 Oneof: &syntaxv1.Message_OneofMessage2{
760 OneofMessage2: &syntaxv1.Message{
761 String_: "dst",
762 },
763 },
764 },
765 expected: &syntaxv1.Message{
766 Oneof: &syntaxv1.Message_OneofMessage2{
767 OneofMessage2: &syntaxv1.Message{},
768 },
769 },
770 },
771 {
772 name: "message: src nil",
773 paths: []string{
774 "message",
775 },
776 src: &syntaxv1.Message{
777 Message: nil,
778 },
779 dst: &syntaxv1.Message{
780 Message: &syntaxv1.Message{
781 Int32: 23,
782 },
783 },
784 expected: &syntaxv1.Message{
785 Message: nil,
786 },
787 },
788 } {
789 tt := tt
790 t.Run(tt.name, func(t *testing.T) {
791 t.Parallel()
792 Update(&fieldmaskpb.FieldMask{Paths: tt.paths}, tt.dst, tt.src)
793 assert.DeepEqual(t, tt.expected, tt.dst, protocmp.Transform())
794 })
795 }
796 })
797 }
798
View as plain text