1
2
3
4
5 package proto_test
6
7 import (
8 "fmt"
9 "reflect"
10 "sync"
11 "testing"
12
13 "github.com/google/go-cmp/cmp"
14
15 "google.golang.org/protobuf/encoding/prototext"
16 "google.golang.org/protobuf/internal/protobuild"
17 "google.golang.org/protobuf/proto"
18 "google.golang.org/protobuf/reflect/protoreflect"
19 "google.golang.org/protobuf/testing/protocmp"
20 "google.golang.org/protobuf/testing/protopack"
21 "google.golang.org/protobuf/types/dynamicpb"
22
23 legacypb "google.golang.org/protobuf/internal/testprotos/legacy"
24 testpb "google.golang.org/protobuf/internal/testprotos/test"
25 test3pb "google.golang.org/protobuf/internal/testprotos/test3"
26 )
27
28 type testMerge struct {
29 desc string
30 dst protobuild.Message
31 src protobuild.Message
32 want protobuild.Message
33 types []proto.Message
34 }
35
36 var testMerges = []testMerge{{
37 desc: "clone a large message",
38 src: protobuild.Message{
39 "optional_int32": 1001,
40 "optional_int64": 1002,
41 "optional_uint32": 1003,
42 "optional_uint64": 1004,
43 "optional_sint32": 1005,
44 "optional_sint64": 1006,
45 "optional_fixed32": 1007,
46 "optional_fixed64": 1008,
47 "optional_sfixed32": 1009,
48 "optional_sfixed64": 1010,
49 "optional_float": 1011.5,
50 "optional_double": 1012.5,
51 "optional_bool": true,
52 "optional_string": "string",
53 "optional_bytes": []byte("bytes"),
54 "optional_nested_enum": 1,
55 "optional_nested_message": protobuild.Message{
56 "a": 100,
57 },
58 "repeated_int32": []int32{1001, 2001},
59 "repeated_int64": []int64{1002, 2002},
60 "repeated_uint32": []uint32{1003, 2003},
61 "repeated_uint64": []uint64{1004, 2004},
62 "repeated_sint32": []int32{1005, 2005},
63 "repeated_sint64": []int64{1006, 2006},
64 "repeated_fixed32": []uint32{1007, 2007},
65 "repeated_fixed64": []uint64{1008, 2008},
66 "repeated_sfixed32": []int32{1009, 2009},
67 "repeated_sfixed64": []int64{1010, 2010},
68 "repeated_float": []float32{1011.5, 2011.5},
69 "repeated_double": []float64{1012.5, 2012.5},
70 "repeated_bool": []bool{true, false},
71 "repeated_string": []string{"foo", "bar"},
72 "repeated_bytes": []string{"FOO", "BAR"},
73 "repeated_nested_enum": []string{"FOO", "BAR"},
74 "repeated_nested_message": []protobuild.Message{
75 {"a": 200},
76 {"a": 300},
77 },
78 },
79 }, {
80 desc: "clone maps",
81 src: protobuild.Message{
82 "map_int32_int32": map[int32]int32{1056: 1156, 2056: 2156},
83 "map_int64_int64": map[int64]int64{1057: 1157, 2057: 2157},
84 "map_uint32_uint32": map[uint32]uint32{1058: 1158, 2058: 2158},
85 "map_uint64_uint64": map[uint64]uint64{1059: 1159, 2059: 2159},
86 "map_sint32_sint32": map[int32]int32{1060: 1160, 2060: 2160},
87 "map_sint64_sint64": map[int64]int64{1061: 1161, 2061: 2161},
88 "map_fixed32_fixed32": map[uint32]uint32{1062: 1162, 2062: 2162},
89 "map_fixed64_fixed64": map[uint64]uint64{1063: 1163, 2063: 2163},
90 "map_sfixed32_sfixed32": map[int32]int32{1064: 1164, 2064: 2164},
91 "map_sfixed64_sfixed64": map[int64]int64{1065: 1165, 2065: 2165},
92 "map_int32_float": map[int32]float32{1066: 1166.5, 2066: 2166.5},
93 "map_int32_double": map[int32]float64{1067: 1167.5, 2067: 2167.5},
94 "map_bool_bool": map[bool]bool{true: false, false: true},
95 "map_string_string": map[string]string{"69.1.key": "69.1.val", "69.2.key": "69.2.val"},
96 "map_string_bytes": map[string][]byte{"70.1.key": []byte("70.1.val"), "70.2.key": []byte("70.2.val")},
97 "map_string_nested_message": map[string]protobuild.Message{
98 "71.1.key": {"a": 1171},
99 "71.2.key": {"a": 2171},
100 },
101 "map_string_nested_enum": map[string]string{"73.1.key": "FOO", "73.2.key": "BAR"},
102 },
103 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
104 }, {
105 desc: "clone oneof uint32",
106 src: protobuild.Message{
107 "oneof_uint32": 1111,
108 },
109 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
110 }, {
111 desc: "clone oneof string",
112 src: protobuild.Message{
113 "oneof_string": "string",
114 },
115 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
116 }, {
117 desc: "clone oneof bytes",
118 src: protobuild.Message{
119 "oneof_bytes": "bytes",
120 },
121 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
122 }, {
123 desc: "clone oneof bool",
124 src: protobuild.Message{
125 "oneof_bool": true,
126 },
127 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
128 }, {
129 desc: "clone oneof uint64",
130 src: protobuild.Message{
131 "oneof_uint64": 100,
132 },
133 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
134 }, {
135 desc: "clone oneof float",
136 src: protobuild.Message{
137 "oneof_float": 100,
138 },
139 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
140 }, {
141 desc: "clone oneof double",
142 src: protobuild.Message{
143 "oneof_double": 1111,
144 },
145 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
146 }, {
147 desc: "clone oneof enum",
148 src: protobuild.Message{
149 "oneof_enum": 1,
150 },
151 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
152 }, {
153 desc: "clone oneof message",
154 src: protobuild.Message{
155 "oneof_nested_message": protobuild.Message{
156 "a": 1,
157 },
158 },
159 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
160 }, {
161 desc: "clone oneof group",
162 src: protobuild.Message{
163 "oneofgroup": protobuild.Message{
164 "a": 1,
165 },
166 },
167 types: []proto.Message{&testpb.TestAllTypes{}},
168 }, {
169 desc: "merge bytes",
170 dst: protobuild.Message{
171 "optional_bytes": []byte{1, 2, 3},
172 "repeated_bytes": [][]byte{{1, 2}, {3, 4}},
173 "map_string_bytes": map[string][]byte{"alpha": {1, 2, 3}},
174 },
175 src: protobuild.Message{
176 "optional_bytes": []byte{4, 5, 6},
177 "repeated_bytes": [][]byte{{5, 6}, {7, 8}},
178 "map_string_bytes": map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
179 },
180 want: protobuild.Message{
181 "optional_bytes": []byte{4, 5, 6},
182 "repeated_bytes": [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
183 "map_string_bytes": map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
184 },
185 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
186 }, {
187 desc: "merge singular fields",
188 dst: protobuild.Message{
189 "optional_int32": 1,
190 "optional_int64": 1,
191 "optional_uint32": 1,
192 "optional_uint64": 1,
193 "optional_sint32": 1,
194 "optional_sint64": 1,
195 "optional_fixed32": 1,
196 "optional_fixed64": 1,
197 "optional_sfixed32": 1,
198 "optional_sfixed64": 1,
199 "optional_float": 1,
200 "optional_double": 1,
201 "optional_bool": false,
202 "optional_string": "1",
203 "optional_bytes": "1",
204 "optional_nested_enum": 1,
205 "optional_nested_message": protobuild.Message{
206 "a": 1,
207 "corecursive": protobuild.Message{
208 "optional_int64": 1,
209 },
210 },
211 },
212 src: protobuild.Message{
213 "optional_int32": 2,
214 "optional_int64": 2,
215 "optional_uint32": 2,
216 "optional_uint64": 2,
217 "optional_sint32": 2,
218 "optional_sint64": 2,
219 "optional_fixed32": 2,
220 "optional_fixed64": 2,
221 "optional_sfixed32": 2,
222 "optional_sfixed64": 2,
223 "optional_float": 2,
224 "optional_double": 2,
225 "optional_bool": true,
226 "optional_string": "2",
227 "optional_bytes": "2",
228 "optional_nested_enum": 2,
229 "optional_nested_message": protobuild.Message{
230 "a": 2,
231 "corecursive": protobuild.Message{
232 "optional_int64": 2,
233 },
234 },
235 },
236 want: protobuild.Message{
237 "optional_int32": 2,
238 "optional_int64": 2,
239 "optional_uint32": 2,
240 "optional_uint64": 2,
241 "optional_sint32": 2,
242 "optional_sint64": 2,
243 "optional_fixed32": 2,
244 "optional_fixed64": 2,
245 "optional_sfixed32": 2,
246 "optional_sfixed64": 2,
247 "optional_float": 2,
248 "optional_double": 2,
249 "optional_bool": true,
250 "optional_string": "2",
251 "optional_bytes": "2",
252 "optional_nested_enum": 2,
253 "optional_nested_message": protobuild.Message{
254 "a": 2,
255 "corecursive": protobuild.Message{
256 "optional_int64": 2,
257 },
258 },
259 },
260 }, {
261 desc: "no merge of empty singular fields",
262 dst: protobuild.Message{
263 "optional_int32": 1,
264 "optional_int64": 1,
265 "optional_uint32": 1,
266 "optional_uint64": 1,
267 "optional_sint32": 1,
268 "optional_sint64": 1,
269 "optional_fixed32": 1,
270 "optional_fixed64": 1,
271 "optional_sfixed32": 1,
272 "optional_sfixed64": 1,
273 "optional_float": 1,
274 "optional_double": 1,
275 "optional_bool": false,
276 "optional_string": "1",
277 "optional_bytes": "1",
278 "optional_nested_enum": 1,
279 "optional_nested_message": protobuild.Message{
280 "a": 1,
281 "corecursive": protobuild.Message{
282 "optional_int64": 1,
283 },
284 },
285 },
286 src: protobuild.Message{
287 "optional_nested_message": protobuild.Message{
288 "a": 1,
289 "corecursive": protobuild.Message{
290 "optional_int32": 2,
291 },
292 },
293 },
294 want: protobuild.Message{
295 "optional_int32": 1,
296 "optional_int64": 1,
297 "optional_uint32": 1,
298 "optional_uint64": 1,
299 "optional_sint32": 1,
300 "optional_sint64": 1,
301 "optional_fixed32": 1,
302 "optional_fixed64": 1,
303 "optional_sfixed32": 1,
304 "optional_sfixed64": 1,
305 "optional_float": 1,
306 "optional_double": 1,
307 "optional_bool": false,
308 "optional_string": "1",
309 "optional_bytes": "1",
310 "optional_nested_enum": 1,
311 "optional_nested_message": protobuild.Message{
312 "a": 1,
313 "corecursive": protobuild.Message{
314 "optional_int32": 2,
315 "optional_int64": 1,
316 },
317 },
318 },
319 }, {
320 desc: "merge list fields",
321 dst: protobuild.Message{
322 "repeated_int32": []int32{1, 2, 3},
323 "repeated_int64": []int64{1, 2, 3},
324 "repeated_uint32": []uint32{1, 2, 3},
325 "repeated_uint64": []uint64{1, 2, 3},
326 "repeated_sint32": []int32{1, 2, 3},
327 "repeated_sint64": []int64{1, 2, 3},
328 "repeated_fixed32": []uint32{1, 2, 3},
329 "repeated_fixed64": []uint64{1, 2, 3},
330 "repeated_sfixed32": []int32{1, 2, 3},
331 "repeated_sfixed64": []int64{1, 2, 3},
332 "repeated_float": []float32{1, 2, 3},
333 "repeated_double": []float64{1, 2, 3},
334 "repeated_bool": []bool{true},
335 "repeated_string": []string{"a", "b", "c"},
336 "repeated_bytes": []string{"a", "b", "c"},
337 "repeated_nested_enum": []int{1, 2, 3},
338 "repeated_nested_message": []protobuild.Message{
339 {"a": 100},
340 {"a": 200},
341 },
342 },
343 src: protobuild.Message{
344 "repeated_int32": []int32{4, 5, 6},
345 "repeated_int64": []int64{4, 5, 6},
346 "repeated_uint32": []uint32{4, 5, 6},
347 "repeated_uint64": []uint64{4, 5, 6},
348 "repeated_sint32": []int32{4, 5, 6},
349 "repeated_sint64": []int64{4, 5, 6},
350 "repeated_fixed32": []uint32{4, 5, 6},
351 "repeated_fixed64": []uint64{4, 5, 6},
352 "repeated_sfixed32": []int32{4, 5, 6},
353 "repeated_sfixed64": []int64{4, 5, 6},
354 "repeated_float": []float32{4, 5, 6},
355 "repeated_double": []float64{4, 5, 6},
356 "repeated_bool": []bool{false},
357 "repeated_string": []string{"d", "e", "f"},
358 "repeated_bytes": []string{"d", "e", "f"},
359 "repeated_nested_enum": []int{4, 5, 6},
360 "repeated_nested_message": []protobuild.Message{
361 {"a": 300},
362 {"a": 400},
363 },
364 },
365 want: protobuild.Message{
366 "repeated_int32": []int32{1, 2, 3, 4, 5, 6},
367 "repeated_int64": []int64{1, 2, 3, 4, 5, 6},
368 "repeated_uint32": []uint32{1, 2, 3, 4, 5, 6},
369 "repeated_uint64": []uint64{1, 2, 3, 4, 5, 6},
370 "repeated_sint32": []int32{1, 2, 3, 4, 5, 6},
371 "repeated_sint64": []int64{1, 2, 3, 4, 5, 6},
372 "repeated_fixed32": []uint32{1, 2, 3, 4, 5, 6},
373 "repeated_fixed64": []uint64{1, 2, 3, 4, 5, 6},
374 "repeated_sfixed32": []int32{1, 2, 3, 4, 5, 6},
375 "repeated_sfixed64": []int64{1, 2, 3, 4, 5, 6},
376 "repeated_float": []float32{1, 2, 3, 4, 5, 6},
377 "repeated_double": []float64{1, 2, 3, 4, 5, 6},
378 "repeated_bool": []bool{true, false},
379 "repeated_string": []string{"a", "b", "c", "d", "e", "f"},
380 "repeated_bytes": []string{"a", "b", "c", "d", "e", "f"},
381 "repeated_nested_enum": []int{1, 2, 3, 4, 5, 6},
382 "repeated_nested_message": []protobuild.Message{
383 {"a": 100},
384 {"a": 200},
385 {"a": 300},
386 {"a": 400},
387 },
388 },
389 }, {
390 desc: "merge map fields",
391 dst: protobuild.Message{
392 "map_int32_int32": map[int]int{1: 1, 3: 1},
393 "map_int64_int64": map[int]int{1: 1, 3: 1},
394 "map_uint32_uint32": map[int]int{1: 1, 3: 1},
395 "map_uint64_uint64": map[int]int{1: 1, 3: 1},
396 "map_sint32_sint32": map[int]int{1: 1, 3: 1},
397 "map_sint64_sint64": map[int]int{1: 1, 3: 1},
398 "map_fixed32_fixed32": map[int]int{1: 1, 3: 1},
399 "map_fixed64_fixed64": map[int]int{1: 1, 3: 1},
400 "map_sfixed32_sfixed32": map[int]int{1: 1, 3: 1},
401 "map_sfixed64_sfixed64": map[int]int{1: 1, 3: 1},
402 "map_int32_float": map[int]int{1: 1, 3: 1},
403 "map_int32_double": map[int]int{1: 1, 3: 1},
404 "map_bool_bool": map[bool]bool{true: true},
405 "map_string_string": map[string]string{"a": "1", "ab": "1"},
406 "map_string_bytes": map[string]string{"a": "1", "ab": "1"},
407 "map_string_nested_message": map[string]protobuild.Message{
408 "a": {"a": 1},
409 "ab": {
410 "a": 1,
411 "corecursive": protobuild.Message{
412 "map_int32_int32": map[int]int{1: 1, 3: 1},
413 },
414 },
415 },
416 "map_string_nested_enum": map[string]int{"a": 1, "ab": 1},
417 },
418 src: protobuild.Message{
419 "map_int32_int32": map[int]int{2: 2, 3: 2},
420 "map_int64_int64": map[int]int{2: 2, 3: 2},
421 "map_uint32_uint32": map[int]int{2: 2, 3: 2},
422 "map_uint64_uint64": map[int]int{2: 2, 3: 2},
423 "map_sint32_sint32": map[int]int{2: 2, 3: 2},
424 "map_sint64_sint64": map[int]int{2: 2, 3: 2},
425 "map_fixed32_fixed32": map[int]int{2: 2, 3: 2},
426 "map_fixed64_fixed64": map[int]int{2: 2, 3: 2},
427 "map_sfixed32_sfixed32": map[int]int{2: 2, 3: 2},
428 "map_sfixed64_sfixed64": map[int]int{2: 2, 3: 2},
429 "map_int32_float": map[int]int{2: 2, 3: 2},
430 "map_int32_double": map[int]int{2: 2, 3: 2},
431 "map_bool_bool": map[bool]bool{false: false},
432 "map_string_string": map[string]string{"b": "2", "ab": "2"},
433 "map_string_bytes": map[string]string{"b": "2", "ab": "2"},
434 "map_string_nested_message": map[string]protobuild.Message{
435 "b": {"a": 2},
436 "ab": {
437 "a": 2,
438 "corecursive": protobuild.Message{
439 "map_int32_int32": map[int]int{2: 2, 3: 2},
440 },
441 },
442 },
443 "map_string_nested_enum": map[string]int{"b": 2, "ab": 2},
444 },
445 want: protobuild.Message{
446 "map_int32_int32": map[int]int{1: 1, 2: 2, 3: 2},
447 "map_int64_int64": map[int]int{1: 1, 2: 2, 3: 2},
448 "map_uint32_uint32": map[int]int{1: 1, 2: 2, 3: 2},
449 "map_uint64_uint64": map[int]int{1: 1, 2: 2, 3: 2},
450 "map_sint32_sint32": map[int]int{1: 1, 2: 2, 3: 2},
451 "map_sint64_sint64": map[int]int{1: 1, 2: 2, 3: 2},
452 "map_fixed32_fixed32": map[int]int{1: 1, 2: 2, 3: 2},
453 "map_fixed64_fixed64": map[int]int{1: 1, 2: 2, 3: 2},
454 "map_sfixed32_sfixed32": map[int]int{1: 1, 2: 2, 3: 2},
455 "map_sfixed64_sfixed64": map[int]int{1: 1, 2: 2, 3: 2},
456 "map_int32_float": map[int]int{1: 1, 2: 2, 3: 2},
457 "map_int32_double": map[int]int{1: 1, 2: 2, 3: 2},
458 "map_bool_bool": map[bool]bool{true: true, false: false},
459 "map_string_string": map[string]string{"a": "1", "b": "2", "ab": "2"},
460 "map_string_bytes": map[string]string{"a": "1", "b": "2", "ab": "2"},
461 "map_string_nested_message": map[string]protobuild.Message{
462 "a": {"a": 1},
463 "b": {"a": 2},
464 "ab": {
465 "a": 2,
466 "corecursive": protobuild.Message{
467
468
469 "map_int32_int32": map[int]int{2: 2, 3: 2},
470 },
471 },
472 },
473 "map_string_nested_enum": map[string]int{"a": 1, "b": 2, "ab": 2},
474 },
475 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
476 }, {
477 desc: "merge oneof message fields",
478 dst: protobuild.Message{
479 "oneof_nested_message": protobuild.Message{
480 "a": 100,
481 },
482 },
483 src: protobuild.Message{
484 "oneof_nested_message": protobuild.Message{
485 "corecursive": protobuild.Message{
486 "optional_int64": 1000,
487 },
488 },
489 },
490 want: protobuild.Message{
491 "oneof_nested_message": protobuild.Message{
492 "a": 100,
493 "corecursive": protobuild.Message{
494 "optional_int64": 1000,
495 },
496 },
497 },
498 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
499 }, {
500 desc: "merge oneof scalar fields",
501 dst: protobuild.Message{
502 "oneof_uint32": 100,
503 },
504 src: protobuild.Message{
505 "oneof_float": 3.14152,
506 },
507 want: protobuild.Message{
508 "oneof_float": 3.14152,
509 },
510 types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
511 }, {
512 desc: "merge unknown fields",
513 dst: protobuild.Message{
514 protobuild.Unknown: protopack.Message{
515 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
516 }.Marshal(),
517 },
518 src: protobuild.Message{
519 protobuild.Unknown: protopack.Message{
520 protopack.Tag{Number: 500000, Type: protopack.VarintType}, protopack.Svarint(-50),
521 }.Marshal(),
522 },
523 want: protobuild.Message{
524 protobuild.Unknown: protopack.Message{
525 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
526 protopack.Tag{Number: 500000, Type: protopack.VarintType}, protopack.Svarint(-50),
527 }.Marshal(),
528 },
529 }, {
530 desc: "clone legacy message",
531 src: protobuild.Message{"f1": protobuild.Message{
532 "optional_int32": 1,
533 "optional_int64": 1,
534 "optional_uint32": 1,
535 "optional_uint64": 1,
536 "optional_sint32": 1,
537 "optional_sint64": 1,
538 "optional_fixed32": 1,
539 "optional_fixed64": 1,
540 "optional_sfixed32": 1,
541 "optional_sfixed64": 1,
542 "optional_float": 1,
543 "optional_double": 1,
544 "optional_bool": true,
545 "optional_string": "string",
546 "optional_bytes": "bytes",
547 "optional_sibling_enum": 1,
548 "optional_sibling_message": protobuild.Message{
549 "f1": "value",
550 },
551 "repeated_int32": []int32{1},
552 "repeated_int64": []int64{1},
553 "repeated_uint32": []uint32{1},
554 "repeated_uint64": []uint64{1},
555 "repeated_sint32": []int32{1},
556 "repeated_sint64": []int64{1},
557 "repeated_fixed32": []uint32{1},
558 "repeated_fixed64": []uint64{1},
559 "repeated_sfixed32": []int32{1},
560 "repeated_sfixed64": []int64{1},
561 "repeated_float": []float32{1},
562 "repeated_double": []float64{1},
563 "repeated_bool": []bool{true},
564 "repeated_string": []string{"string"},
565 "repeated_bytes": []string{"bytes"},
566 "repeated_sibling_enum": []int{1},
567 "repeated_sibling_message": []protobuild.Message{
568 {"f1": "1"},
569 },
570 "map_bool_int32": map[bool]int{true: 1},
571 "map_bool_int64": map[bool]int{true: 1},
572 "map_bool_uint32": map[bool]int{true: 1},
573 "map_bool_uint64": map[bool]int{true: 1},
574 "map_bool_sint32": map[bool]int{true: 1},
575 "map_bool_sint64": map[bool]int{true: 1},
576 "map_bool_fixed32": map[bool]int{true: 1},
577 "map_bool_fixed64": map[bool]int{true: 1},
578 "map_bool_sfixed32": map[bool]int{true: 1},
579 "map_bool_sfixed64": map[bool]int{true: 1},
580 "map_bool_float": map[bool]int{true: 1},
581 "map_bool_double": map[bool]int{true: 1},
582 "map_bool_bool": map[bool]bool{true: false},
583 "map_bool_string": map[bool]string{true: "1"},
584 "map_bool_bytes": map[bool]string{true: "1"},
585 "map_bool_sibling_message": map[bool]protobuild.Message{
586 true: {"f1": "1"},
587 },
588 "map_bool_sibling_enum": map[bool]int{true: 1},
589 "oneof_sibling_message": protobuild.Message{
590 "f1": "1",
591 },
592 }},
593 types: []proto.Message{&legacypb.Legacy{}},
594 }}
595
596 func TestMerge(t *testing.T) {
597 for _, tt := range testMerges {
598 for _, mt := range templateMessages(tt.types...) {
599 t.Run(fmt.Sprintf("%s (%v)", tt.desc, mt.Descriptor().FullName()), func(t *testing.T) {
600 dst := mt.New().Interface()
601 tt.dst.Build(dst.ProtoReflect())
602
603 src := mt.New().Interface()
604 tt.src.Build(src.ProtoReflect())
605
606 want := mt.New().Interface()
607 if tt.dst == nil && tt.want == nil {
608 tt.src.Build(want.ProtoReflect())
609 } else {
610 tt.want.Build(want.ProtoReflect())
611 }
612
613
614
615 b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(dst)
616 if err != nil {
617 t.Fatalf("Marshal(dst) error: %v", err)
618 }
619 b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(src)
620 if err != nil {
621 t.Fatalf("Marshal(src) error: %v", err)
622 }
623 unmarshaled := dst.ProtoReflect().New().Interface()
624 err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), unmarshaled)
625 if err != nil {
626 t.Fatalf("Unmarshal() error: %v", err)
627 }
628 if !proto.Equal(unmarshaled, want) {
629 t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch:\n got %v\nwant %v\ndiff (-want,+got):\n%v", unmarshaled, want, cmp.Diff(want, unmarshaled, protocmp.Transform()))
630 }
631
632
633
634 ddst := dynamicpb.NewMessage(mt.Descriptor())
635 tt.dst.Build(ddst.ProtoReflect())
636 proto.Merge(ddst, src)
637 if !proto.Equal(ddst, want) {
638 t.Fatalf("Merge() into dynamic message mismatch:\n got %v\nwant %v\ndiff (-want,+got):\n%v", ddst, want, cmp.Diff(want, ddst, protocmp.Transform()))
639 }
640
641 proto.Merge(dst, src)
642 if !proto.Equal(dst, want) {
643 t.Fatalf("Merge() mismatch:\n got %v\nwant %v\ndiff (-want,+got):\n%v", dst, want, cmp.Diff(want, dst, protocmp.Transform()))
644 }
645 mutateValue(protoreflect.ValueOfMessage(src.ProtoReflect()))
646 if !proto.Equal(dst, want) {
647 t.Fatalf("mutation observed after modifying source:\n got %v\nwant %v\ndiff (-want,+got):\n%v", dst, want, cmp.Diff(want, dst, protocmp.Transform()))
648 }
649 })
650 }
651 }
652 }
653
654 func TestMergeFromNil(t *testing.T) {
655 dst := &testpb.TestAllTypes{}
656 proto.Merge(dst, (*testpb.TestAllTypes)(nil))
657 if !proto.Equal(dst, &testpb.TestAllTypes{}) {
658 t.Errorf("destination should be empty after merging from nil message; got:\n%v", prototext.Format(dst))
659 }
660 }
661
662
663
664
665 func TestMergeAberrant(t *testing.T) {
666 tests := []struct {
667 label string
668 dst proto.Message
669 src proto.Message
670 check func(proto.Message) bool
671 }{{
672 label: "Proto2EmptyBytes",
673 dst: &testpb.TestAllTypes{OptionalBytes: nil},
674 src: &testpb.TestAllTypes{OptionalBytes: []byte{}},
675 check: func(m proto.Message) bool {
676 return m.(*testpb.TestAllTypes).OptionalBytes != nil
677 },
678 }, {
679 label: "Proto3EmptyBytes",
680 dst: &test3pb.TestAllTypes{SingularBytes: nil},
681 src: &test3pb.TestAllTypes{SingularBytes: []byte{}},
682 check: func(m proto.Message) bool {
683 return m.(*test3pb.TestAllTypes).SingularBytes == nil
684 },
685 }, {
686 label: "EmptyList",
687 dst: &testpb.TestAllTypes{RepeatedInt32: nil},
688 src: &testpb.TestAllTypes{RepeatedInt32: []int32{}},
689 check: func(m proto.Message) bool {
690 return m.(*testpb.TestAllTypes).RepeatedInt32 == nil
691 },
692 }, {
693 label: "ListWithNilBytes",
694 dst: &testpb.TestAllTypes{RepeatedBytes: nil},
695 src: &testpb.TestAllTypes{RepeatedBytes: [][]byte{nil}},
696 check: func(m proto.Message) bool {
697 return reflect.DeepEqual(m.(*testpb.TestAllTypes).RepeatedBytes, [][]byte{{}})
698 },
699 }, {
700 label: "ListWithEmptyBytes",
701 dst: &testpb.TestAllTypes{RepeatedBytes: nil},
702 src: &testpb.TestAllTypes{RepeatedBytes: [][]byte{{}}},
703 check: func(m proto.Message) bool {
704 return reflect.DeepEqual(m.(*testpb.TestAllTypes).RepeatedBytes, [][]byte{{}})
705 },
706 }, {
707 label: "ListWithNilMessage",
708 dst: &testpb.TestAllTypes{RepeatedNestedMessage: nil},
709 src: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{nil}},
710 check: func(m proto.Message) bool {
711 return m.(*testpb.TestAllTypes).RepeatedNestedMessage[0] != nil
712 },
713 }, {
714 label: "EmptyMap",
715 dst: &testpb.TestAllTypes{MapStringString: nil},
716 src: &testpb.TestAllTypes{MapStringString: map[string]string{}},
717 check: func(m proto.Message) bool {
718 return m.(*testpb.TestAllTypes).MapStringString == nil
719 },
720 }, {
721 label: "MapWithNilBytes",
722 dst: &testpb.TestAllTypes{MapStringBytes: nil},
723 src: &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"k": nil}},
724 check: func(m proto.Message) bool {
725 return reflect.DeepEqual(m.(*testpb.TestAllTypes).MapStringBytes, map[string][]byte{"k": {}})
726 },
727 }, {
728 label: "MapWithEmptyBytes",
729 dst: &testpb.TestAllTypes{MapStringBytes: nil},
730 src: &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"k": {}}},
731 check: func(m proto.Message) bool {
732 return reflect.DeepEqual(m.(*testpb.TestAllTypes).MapStringBytes, map[string][]byte{"k": {}})
733 },
734 }, {
735 label: "MapWithNilMessage",
736 dst: &testpb.TestAllTypes{MapStringNestedMessage: nil},
737 src: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": nil}},
738 check: func(m proto.Message) bool {
739 return m.(*testpb.TestAllTypes).MapStringNestedMessage["k"] != nil
740 },
741 }, {
742 label: "OneofWithTypedNilWrapper",
743 dst: &testpb.TestAllTypes{OneofField: nil},
744 src: &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofNestedMessage)(nil)},
745 check: func(m proto.Message) bool {
746 return m.(*testpb.TestAllTypes).OneofField == nil
747 },
748 }, {
749 label: "OneofWithNilMessage",
750 dst: &testpb.TestAllTypes{OneofField: nil},
751 src: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofNestedMessage{OneofNestedMessage: nil}},
752 check: func(m proto.Message) bool {
753 return m.(*testpb.TestAllTypes).OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage != nil
754 },
755
756
757
758
759 }}
760
761 for _, tt := range tests {
762 t.Run(tt.label, func(t *testing.T) {
763 var pass bool
764 func() {
765 defer func() { recover() }()
766 proto.Merge(tt.dst, tt.src)
767 pass = tt.check(tt.dst)
768 }()
769 if !pass {
770 t.Error("check failed")
771 }
772 })
773 }
774 }
775
776 func TestMergeRace(t *testing.T) {
777 dst := new(testpb.TestAllTypes)
778 srcs := []*testpb.TestAllTypes{
779 {OptionalInt32: proto.Int32(1)},
780 {OptionalString: proto.String("hello")},
781 {RepeatedInt32: []int32{2, 3, 4}},
782 {RepeatedString: []string{"goodbye"}},
783 {MapStringString: map[string]string{"key": "value"}},
784 {OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
785 A: proto.Int32(5),
786 }},
787 func() *testpb.TestAllTypes {
788 m := new(testpb.TestAllTypes)
789 m.ProtoReflect().SetUnknown(protopack.Message{
790 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
791 }.Marshal())
792 return m
793 }(),
794 }
795
796
797 var wg sync.WaitGroup
798 defer wg.Wait()
799 for _, src := range srcs {
800 wg.Add(1)
801 go func(src proto.Message) {
802 defer wg.Done()
803 proto.Merge(dst, src)
804 }(src)
805 }
806 }
807
808 func TestMergeSelf(t *testing.T) {
809 got := &testpb.TestAllTypes{
810 OptionalInt32: proto.Int32(1),
811 OptionalString: proto.String("hello"),
812 RepeatedInt32: []int32{2, 3, 4},
813 RepeatedString: []string{"goodbye"},
814 MapStringString: map[string]string{"key": "value"},
815 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
816 A: proto.Int32(5),
817 },
818 }
819 got.ProtoReflect().SetUnknown(protopack.Message{
820 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
821 }.Marshal())
822 proto.Merge(got, got)
823
824
825
826 want := &testpb.TestAllTypes{
827 OptionalInt32: proto.Int32(1),
828 OptionalString: proto.String("hello"),
829 RepeatedInt32: []int32{2, 3, 4, 2, 3, 4},
830 RepeatedString: []string{"goodbye", "goodbye"},
831 MapStringString: map[string]string{"key": "value"},
832 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
833 A: proto.Int32(5),
834 },
835 }
836 want.ProtoReflect().SetUnknown(protopack.Message{
837 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
838 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
839 }.Marshal())
840
841 if !proto.Equal(got, want) {
842 t.Errorf("Equal mismatch:\ngot %v\nwant %v", got, want)
843 }
844 }
845
846 func TestClone(t *testing.T) {
847 want := &testpb.TestAllTypes{
848 OptionalInt32: proto.Int32(1),
849 }
850 got := proto.Clone(want).(*testpb.TestAllTypes)
851 if !proto.Equal(got, want) {
852 t.Errorf("Clone(src) != src:\n got %v\nwant %v", got, want)
853 }
854 }
855
856
857
858
859
860 func mutateValue(v protoreflect.Value) protoreflect.Value {
861 switch v := v.Interface().(type) {
862 case bool:
863 return protoreflect.ValueOfBool(!v)
864 case protoreflect.EnumNumber:
865 return protoreflect.ValueOfEnum(v + 1)
866 case int32:
867 return protoreflect.ValueOfInt32(v + 1)
868 case int64:
869 return protoreflect.ValueOfInt64(v + 1)
870 case uint32:
871 return protoreflect.ValueOfUint32(v + 1)
872 case uint64:
873 return protoreflect.ValueOfUint64(v + 1)
874 case float32:
875 return protoreflect.ValueOfFloat32(v + 1)
876 case float64:
877 return protoreflect.ValueOfFloat64(v + 1)
878 case []byte:
879 for i := range v {
880 v[i]++
881 }
882 return protoreflect.ValueOfBytes(v)
883 case string:
884 return protoreflect.ValueOfString("_" + v)
885 case protoreflect.Message:
886 v.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
887 v.Set(fd, mutateValue(val))
888 return true
889 })
890 return protoreflect.ValueOfMessage(v)
891 case protoreflect.List:
892 for i := 0; i < v.Len(); i++ {
893 v.Set(i, mutateValue(v.Get(i)))
894 }
895 return protoreflect.ValueOfList(v)
896 case protoreflect.Map:
897 v.Range(func(mk protoreflect.MapKey, mv protoreflect.Value) bool {
898 v.Set(mk, mutateValue(mv))
899 return true
900 })
901 return protoreflect.ValueOfMap(v)
902 default:
903 panic(fmt.Sprintf("unknown value type %T", v))
904 }
905 }
906
View as plain text