1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package proto_test 6 7import ( 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 28type testMerge struct { 29 desc string 30 dst protobuild.Message 31 src protobuild.Message 32 want protobuild.Message // if dst and want are nil, want = src 33 types []proto.Message 34} 35 36var 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 // The map item "ab" was entirely replaced, so 468 // this does not contain 1:1 from dst. 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 596func 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 // Merge should be semantically equivalent to unmarshaling the 614 // encoded form of src into the current dst. 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 // Test heterogeneous MessageTypes by merging into a 633 // dynamic message. 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 654func 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// TestMergeAberrant tests inputs that are beyond the protobuf data model. 663// Just because there is a test for the current behavior does not mean that 664// this will behave the same way in the future. 665func 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 // TODO: extension, nil message 756 // TODO: repeated extension, nil 757 // TODO: extension bytes 758 // TODO: repeated extension, nil message 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 776func 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 // It should be safe to concurrently merge non-overlapping fields. 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 808func 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 // The main impact of merging to self is that repeated fields and 825 // unknown fields are doubled. 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 846func 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// mutateValue changes a Value, returning a new value. 857// 858// For scalar values, it returns a value different from the input. 859// For Message, List, and Map values, it mutates the input and returns it. 860func 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