1// Copyright 2018 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 prototext_test 6 7import ( 8 "math" 9 "strings" 10 "testing" 11 12 "google.golang.org/protobuf/encoding/prototext" 13 "google.golang.org/protobuf/internal/flags" 14 "google.golang.org/protobuf/proto" 15 "google.golang.org/protobuf/reflect/protoregistry" 16 17 testpb "google.golang.org/protobuf/internal/testprotos/test" 18 weakpb "google.golang.org/protobuf/internal/testprotos/test/weak1" 19 pb2 "google.golang.org/protobuf/internal/testprotos/textpb2" 20 pb3 "google.golang.org/protobuf/internal/testprotos/textpb3" 21 "google.golang.org/protobuf/types/known/anypb" 22) 23 24func TestUnmarshal(t *testing.T) { 25 tests := []struct { 26 desc string 27 umo prototext.UnmarshalOptions 28 inputMessage proto.Message 29 inputText string 30 wantMessage proto.Message 31 wantErr string // Expected error substring. 32 skip bool 33 }{{ 34 desc: "proto2 empty message", 35 inputMessage: &pb2.Scalars{}, 36 wantMessage: &pb2.Scalars{}, 37 }, { 38 desc: "proto2 optional scalars set to zero values", 39 inputMessage: &pb2.Scalars{}, 40 inputText: `opt_bool: false 41opt_int32: 0 42opt_int64: 0 43opt_uint32: 0 44opt_uint64: 0 45opt_sint32: 0 46opt_sint64: 0 47opt_fixed32: 0 48opt_fixed64: 0 49opt_sfixed32: 0 50opt_sfixed64: 0 51opt_float: 0 52opt_double: 0 53opt_bytes: "" 54opt_string: "" 55`, 56 wantMessage: &pb2.Scalars{ 57 OptBool: proto.Bool(false), 58 OptInt32: proto.Int32(0), 59 OptInt64: proto.Int64(0), 60 OptUint32: proto.Uint32(0), 61 OptUint64: proto.Uint64(0), 62 OptSint32: proto.Int32(0), 63 OptSint64: proto.Int64(0), 64 OptFixed32: proto.Uint32(0), 65 OptFixed64: proto.Uint64(0), 66 OptSfixed32: proto.Int32(0), 67 OptSfixed64: proto.Int64(0), 68 OptFloat: proto.Float32(0), 69 OptDouble: proto.Float64(0), 70 OptBytes: []byte{}, 71 OptString: proto.String(""), 72 }, 73 }, { 74 desc: "proto3 scalars set to zero values", 75 inputMessage: &pb3.Scalars{}, 76 inputText: `s_bool: false 77s_int32: 0 78s_int64: 0 79s_uint32: 0 80s_uint64: 0 81s_sint32: 0 82s_sint64: 0 83s_fixed32: 0 84s_fixed64: 0 85s_sfixed32: 0 86s_sfixed64: 0 87s_float: 0 88s_double: 0 89s_bytes: "" 90s_string: "" 91`, 92 wantMessage: &pb3.Scalars{}, 93 }, { 94 desc: "proto3 optional set to zero values", 95 inputMessage: &pb3.Proto3Optional{}, 96 inputText: `opt_bool: false 97opt_int32: 0 98opt_int64: 0 99opt_uint32: 0 100opt_uint64: 0 101opt_float: 0 102opt_double: 0 103opt_string: "" 104opt_bytes: "" 105opt_enum: ZERO 106opt_message: {} 107`, 108 wantMessage: &pb3.Proto3Optional{ 109 OptBool: proto.Bool(false), 110 OptInt32: proto.Int32(0), 111 OptInt64: proto.Int64(0), 112 OptUint32: proto.Uint32(0), 113 OptUint64: proto.Uint64(0), 114 OptFloat: proto.Float32(0), 115 OptDouble: proto.Float64(0), 116 OptString: proto.String(""), 117 OptBytes: []byte{}, 118 OptEnum: pb3.Enum_ZERO.Enum(), 119 OptMessage: &pb3.Nested{}, 120 }, 121 }, { 122 desc: "proto2 optional scalars", 123 inputMessage: &pb2.Scalars{}, 124 inputText: `opt_bool: true 125opt_int32: 255 126opt_int64: 3735928559 127opt_uint32: 0xff 128opt_uint64: 0xdeadbeef 129opt_sint32: -1001 130opt_sint64: - 0xffff 131opt_fixed64: 64 132opt_sfixed32: - 32 133opt_float: 1.234 134opt_double: 1.23e+100 135opt_bytes: "\xe8\xb0\xb7\xe6\xad\x8c" 136opt_string: "谷歌" 137`, 138 wantMessage: &pb2.Scalars{ 139 OptBool: proto.Bool(true), 140 OptInt32: proto.Int32(0xff), 141 OptInt64: proto.Int64(0xdeadbeef), 142 OptUint32: proto.Uint32(0xff), 143 OptUint64: proto.Uint64(0xdeadbeef), 144 OptSint32: proto.Int32(-1001), 145 OptSint64: proto.Int64(-0xffff), 146 OptFixed64: proto.Uint64(64), 147 OptSfixed32: proto.Int32(-32), 148 OptFloat: proto.Float32(1.234), 149 OptDouble: proto.Float64(1.23e100), 150 OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"), 151 OptString: proto.String("谷歌"), 152 }, 153 }, { 154 desc: "case sensitive", 155 inputMessage: &pb3.Scalars{}, 156 inputText: `S_BOOL: true`, 157 wantErr: "unknown field: S_BOOL", 158 }, { 159 desc: "proto3 scalars", 160 inputMessage: &pb3.Scalars{}, 161 inputText: `s_bool: true 162s_int32: 255 163s_int64: 3735928559 164s_uint32: 0xff 165s_uint64: 0xdeadbeef 166s_sint32: -1001 167s_sint64: - # 168 0xffff 169s_fixed64: 64 170s_sfixed32: -32 171s_float: 1.234 172s_double: 1.23e+100 173s_bytes: "\xe8\xb0\xb7\xe6\xad\x8c" 174s_string: "谷歌" 175`, 176 wantMessage: &pb3.Scalars{ 177 SBool: true, 178 SInt32: 0xff, 179 SInt64: 0xdeadbeef, 180 SUint32: 0xff, 181 SUint64: 0xdeadbeef, 182 SSint32: -1001, 183 SSint64: -0xffff, 184 SFixed64: 64, 185 SSfixed32: -32, 186 SFloat: 1.234, 187 SDouble: 1.23e100, 188 SBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"), 189 SString: "谷歌", 190 }, 191 }, { 192 desc: "proto2 string with invalid UTF-8", 193 inputMessage: &pb2.Scalars{}, 194 inputText: `opt_string: "abc\xff"`, 195 wantMessage: &pb2.Scalars{ 196 OptString: proto.String("abc\xff"), 197 }, 198 }, { 199 desc: "proto3 string with invalid UTF-8", 200 inputMessage: &pb3.Scalars{}, 201 inputText: `s_string: "abc\xff"`, 202 wantErr: "(line 1:11): contains invalid UTF-8", 203 }, { 204 desc: "proto2 message contains unknown field", 205 inputMessage: &pb2.Scalars{}, 206 inputText: "unknown_field: 123", 207 wantErr: "unknown field", 208 }, { 209 desc: "proto3 message contains unknown field", 210 inputMessage: &pb3.Scalars{}, 211 inputText: "unknown_field: 456", 212 wantErr: "unknown field", 213 }, { 214 desc: "proto2 message contains discarded unknown field", 215 umo: prototext.UnmarshalOptions{DiscardUnknown: true}, 216 inputMessage: &pb2.Scalars{}, 217 inputText: `unknown_field:123 1000:"hello"`, 218 }, { 219 desc: "proto3 message contains discarded unknown field", 220 umo: prototext.UnmarshalOptions{DiscardUnknown: true}, 221 inputMessage: &pb3.Scalars{}, 222 inputText: `unknown_field:456 1000:"goodbye"`, 223 }, { 224 desc: "proto2 message cannot parse field number", 225 umo: prototext.UnmarshalOptions{DiscardUnknown: true}, 226 inputMessage: &pb2.Scalars{}, 227 inputText: `13:"hello"`, 228 wantErr: "cannot specify field by number", 229 }, { 230 desc: "unknown list field", 231 umo: prototext.UnmarshalOptions{DiscardUnknown: true}, 232 inputMessage: &pb2.Scalars{}, 233 inputText: `unknown_field: { strings: [ "" ] }`, 234 }, { 235 desc: "unknown list of list field", 236 umo: prototext.UnmarshalOptions{DiscardUnknown: true}, 237 inputMessage: &pb2.Scalars{}, 238 inputText: `unknown_field: { strings: [ [ ] ] }`, 239 wantErr: `(line 1:29): invalid scalar value: [`, 240 }, { 241 desc: "proto3 message cannot parse field number", 242 umo: prototext.UnmarshalOptions{DiscardUnknown: true}, 243 inputMessage: &pb3.Scalars{}, 244 inputText: `13:"goodbye"`, 245 wantErr: "cannot specify field by number", 246 }, { 247 desc: "proto2 numeric key field", 248 inputMessage: &pb2.Scalars{}, 249 inputText: "1: true", 250 wantErr: "cannot specify field by number", 251 }, { 252 desc: "proto3 numeric key field", 253 inputMessage: &pb3.Scalars{}, 254 inputText: "1: true", 255 wantErr: "cannot specify field by number", 256 }, { 257 desc: "invalid bool value", 258 inputMessage: &pb3.Scalars{}, 259 inputText: "s_bool: 123", 260 wantErr: "invalid value for bool", 261 }, { 262 desc: "invalid int32 value", 263 inputMessage: &pb3.Scalars{}, 264 inputText: "s_int32: not_a_num", 265 wantErr: "invalid value for int32", 266 }, { 267 desc: "invalid int64 value", 268 inputMessage: &pb3.Scalars{}, 269 inputText: "s_int64: 'not a num either'", 270 wantErr: "invalid value for int64", 271 }, { 272 desc: "invalid uint32 value", 273 inputMessage: &pb3.Scalars{}, 274 inputText: "s_fixed32: -42", 275 wantErr: "invalid value for fixed32", 276 }, { 277 desc: "invalid uint64 value", 278 inputMessage: &pb3.Scalars{}, 279 inputText: "s_uint64: -47", 280 wantErr: "invalid value for uint64", 281 }, { 282 desc: "invalid sint32 value", 283 inputMessage: &pb3.Scalars{}, 284 inputText: "s_sint32: '42'", 285 wantErr: "invalid value for sint32", 286 }, { 287 desc: "invalid sint64 value", 288 inputMessage: &pb3.Scalars{}, 289 inputText: "s_sint64: '-47'", 290 wantErr: "invalid value for sint64", 291 }, { 292 desc: "invalid fixed32 value", 293 inputMessage: &pb3.Scalars{}, 294 inputText: "s_fixed32: -42", 295 wantErr: "invalid value for fixed32", 296 }, { 297 desc: "invalid fixed64 value", 298 inputMessage: &pb3.Scalars{}, 299 inputText: "s_fixed64: -42", 300 wantErr: "invalid value for fixed64", 301 }, { 302 desc: "invalid sfixed32 value", 303 inputMessage: &pb3.Scalars{}, 304 inputText: "s_sfixed32: 'not valid'", 305 wantErr: "invalid value for sfixed32", 306 }, { 307 desc: "invalid sfixed64 value", 308 inputMessage: &pb3.Scalars{}, 309 inputText: "s_sfixed64: bad", 310 wantErr: "invalid value for sfixed64", 311 }, { 312 desc: "incomplete number value", 313 inputMessage: &pb3.Scalars{}, 314 inputText: `s_int32: - `, 315 wantErr: "(line 1:10): invalid scalar value: -", 316 }, { 317 desc: "conformance: FloatFieldMaxValue", 318 inputMessage: &pb2.Scalars{}, 319 inputText: `opt_float: 3.4028235e+38`, 320 wantMessage: &pb2.Scalars{ 321 OptFloat: proto.Float32(3.40282347e+38), 322 }, 323 }, { 324 desc: "conformance: FloatFieldLargerThanUint64", 325 inputMessage: &pb2.Scalars{}, 326 inputText: `opt_float: 18446744073709551616`, 327 wantMessage: &pb2.Scalars{ 328 OptFloat: proto.Float32(1.84467441e+19), 329 }, 330 }, { 331 desc: "conformance: FloatFieldTooLarge", 332 inputMessage: &pb2.Scalars{}, 333 inputText: `opt_float: 3.4028235e+39`, 334 wantMessage: &pb2.Scalars{ 335 OptFloat: proto.Float32(float32(math.Inf(1))), 336 }, 337 }, { 338 desc: "invalid string value", 339 inputMessage: &pb3.Scalars{}, 340 inputText: "s_string: invalid_string", 341 wantErr: "invalid value for string type", 342 }, { 343 desc: "proto2 bytes set to empty string", 344 inputMessage: &pb2.Scalars{}, 345 inputText: "opt_bytes: ''", 346 wantMessage: &pb2.Scalars{ 347 OptBytes: []byte(""), 348 }, 349 }, { 350 desc: "proto3 bytes set to empty string", 351 inputMessage: &pb3.Scalars{}, 352 inputText: "s_bytes: ''", 353 wantMessage: &pb3.Scalars{}, 354 }, { 355 desc: "proto2 duplicate singular field", 356 inputMessage: &pb2.Scalars{}, 357 inputText: ` 358opt_bool: true 359opt_bool: false 360`, 361 wantErr: `(line 3:1): non-repeated field "opt_bool" is repeated`, 362 }, { 363 desc: "proto2 more duplicate singular field", 364 inputMessage: &pb2.Scalars{}, 365 inputText: ` 366opt_bool: true 367opt_string: "hello" 368opt_bool: false 369`, 370 wantErr: `(line 4:1): non-repeated field "opt_bool" is repeated`, 371 }, { 372 desc: "proto2 invalid singular field", 373 inputMessage: &pb2.Scalars{}, 374 inputText: ` 375opt_bool: [true, false] 376`, 377 wantErr: "(line 2:11): unexpected token: [", 378 }, { 379 desc: "proto3 duplicate singular field", 380 inputMessage: &pb3.Scalars{}, 381 inputText: ` 382s_bool: false 383s_bool: true 384`, 385 wantErr: `non-repeated field "s_bool" is repeated`, 386 }, { 387 desc: "proto3 more duplicate singular field", 388 inputMessage: &pb3.Scalars{}, 389 inputText: ` 390s_bool: false 391s_string: "" 392s_bool: true 393`, 394 wantErr: `non-repeated field "s_bool" is repeated`, 395 }, { 396 desc: "proto2 enum", 397 inputMessage: &pb2.Enums{}, 398 inputText: ` 399opt_enum: ONE 400opt_nested_enum: UNO 401`, 402 wantMessage: &pb2.Enums{ 403 OptEnum: pb2.Enum_ONE.Enum(), 404 OptNestedEnum: pb2.Enums_UNO.Enum(), 405 }, 406 }, { 407 desc: "proto2 enum set to numeric values", 408 inputMessage: &pb2.Enums{}, 409 inputText: ` 410opt_enum: 2 411opt_nested_enum: 2 412`, 413 wantMessage: &pb2.Enums{ 414 OptEnum: pb2.Enum_TWO.Enum(), 415 OptNestedEnum: pb2.Enums_DOS.Enum(), 416 }, 417 }, { 418 desc: "proto2 enum set to unnamed numeric values", 419 inputMessage: &pb2.Enums{}, 420 inputText: ` 421opt_enum: 101 422opt_nested_enum: -101 423`, 424 wantMessage: &pb2.Enums{ 425 OptEnum: pb2.Enum(101).Enum(), 426 OptNestedEnum: pb2.Enums_NestedEnum(-101).Enum(), 427 }, 428 }, { 429 desc: "proto2 enum set to invalid named", 430 inputMessage: &pb2.Enums{}, 431 inputText: ` 432opt_enum: UNNAMED 433opt_nested_enum: UNNAMED_TOO 434`, 435 wantErr: "invalid value for enum type: UNNAMED", 436 }, { 437 desc: "proto3 enum name value", 438 inputMessage: &pb3.Enums{}, 439 inputText: ` 440s_enum: ONE 441s_nested_enum: DIEZ 442`, 443 wantMessage: &pb3.Enums{ 444 SEnum: pb3.Enum_ONE, 445 SNestedEnum: pb3.Enums_DIEZ, 446 }, 447 }, { 448 desc: "proto3 enum numeric value", 449 inputMessage: &pb3.Enums{}, 450 inputText: ` 451s_enum: 2 452s_nested_enum: 2 453`, 454 wantMessage: &pb3.Enums{ 455 SEnum: pb3.Enum_TWO, 456 SNestedEnum: pb3.Enums_DOS, 457 }, 458 }, { 459 desc: "proto3 enum unnamed numeric value", 460 inputMessage: &pb3.Enums{}, 461 inputText: ` 462s_enum: 0x7fffffff 463s_nested_enum: -0x80000000 464`, 465 wantMessage: &pb3.Enums{ 466 SEnum: 0x7fffffff, 467 SNestedEnum: -0x80000000, 468 }, 469 }, { 470 desc: "proto2 nested empty messages", 471 inputMessage: &pb2.Nests{}, 472 inputText: ` 473opt_nested: {} 474OptGroup: {} 475`, 476 wantMessage: &pb2.Nests{ 477 OptNested: &pb2.Nested{}, 478 Optgroup: &pb2.Nests_OptGroup{}, 479 }, 480 }, { 481 desc: "message fields with no field separator", 482 inputMessage: &pb2.Nests{}, 483 inputText: ` 484opt_nested {} 485OptGroup {} 486`, 487 wantMessage: &pb2.Nests{ 488 OptNested: &pb2.Nested{}, 489 Optgroup: &pb2.Nests_OptGroup{}, 490 }, 491 }, { 492 desc: "group field name", 493 inputMessage: &pb2.Nests{}, 494 inputText: `optgroup: {}`, 495 wantErr: "unknown field: optgroup", 496 }, { 497 desc: "proto2 nested messages", 498 inputMessage: &pb2.Nests{}, 499 inputText: ` 500opt_nested: { 501 opt_string: "nested message" 502 opt_nested: { 503 opt_string: "another nested message" 504 } 505} 506`, 507 wantMessage: &pb2.Nests{ 508 OptNested: &pb2.Nested{ 509 OptString: proto.String("nested message"), 510 OptNested: &pb2.Nested{ 511 OptString: proto.String("another nested message"), 512 }, 513 }, 514 }, 515 }, { 516 desc: "proto3 nested empty message", 517 inputMessage: &pb3.Nests{}, 518 inputText: "s_nested: {}", 519 wantMessage: &pb3.Nests{ 520 SNested: &pb3.Nested{}, 521 }, 522 }, { 523 desc: "proto3 nested message", 524 inputMessage: &pb3.Nests{}, 525 inputText: ` 526s_nested: { 527 s_string: "nested message" 528 s_nested: { 529 s_string: "another nested message" 530 } 531} 532`, 533 wantMessage: &pb3.Nests{ 534 SNested: &pb3.Nested{ 535 SString: "nested message", 536 SNested: &pb3.Nested{ 537 SString: "another nested message", 538 }, 539 }, 540 }, 541 }, { 542 desc: "proto3 nested message contains invalid UTF-8", 543 inputMessage: &pb3.Nests{}, 544 inputText: `s_nested: { 545 s_string: "abc\xff" 546} 547`, 548 wantErr: "contains invalid UTF-8", 549 }, { 550 desc: "oneof set to empty string", 551 inputMessage: &pb3.Oneofs{}, 552 inputText: "oneof_string: ''", 553 wantMessage: &pb3.Oneofs{ 554 Union: &pb3.Oneofs_OneofString{}, 555 }, 556 }, { 557 desc: "oneof set to string", 558 inputMessage: &pb3.Oneofs{}, 559 inputText: "oneof_string: 'hello'", 560 wantMessage: &pb3.Oneofs{ 561 Union: &pb3.Oneofs_OneofString{ 562 OneofString: "hello", 563 }, 564 }, 565 }, { 566 desc: "oneof set to enum", 567 inputMessage: &pb3.Oneofs{}, 568 inputText: "oneof_enum: TEN", 569 wantMessage: &pb3.Oneofs{ 570 Union: &pb3.Oneofs_OneofEnum{ 571 OneofEnum: pb3.Enum_TEN, 572 }, 573 }, 574 }, { 575 desc: "oneof set to empty message", 576 inputMessage: &pb3.Oneofs{}, 577 inputText: "oneof_nested: {}", 578 wantMessage: &pb3.Oneofs{ 579 Union: &pb3.Oneofs_OneofNested{ 580 OneofNested: &pb3.Nested{}, 581 }, 582 }, 583 }, { 584 desc: "oneof set to message", 585 inputMessage: &pb3.Oneofs{}, 586 inputText: ` 587oneof_nested: { 588 s_string: "nested message" 589} 590`, 591 wantMessage: &pb3.Oneofs{ 592 Union: &pb3.Oneofs_OneofNested{ 593 OneofNested: &pb3.Nested{ 594 SString: "nested message", 595 }, 596 }, 597 }, 598 }, { 599 desc: "oneof set to more than one field", 600 inputMessage: &pb3.Oneofs{}, 601 inputText: ` 602oneof_enum: ZERO 603oneof_string: "hello" 604`, 605 wantErr: `error parsing "oneof_string", oneof pb3.Oneofs.union is already set`, 606 }, { 607 desc: "repeated scalar using same field name", 608 inputMessage: &pb2.Repeats{}, 609 inputText: ` 610rpt_string: "a" 611rpt_string: "b" 612rpt_int32: 0xff 613rpt_float: 1.23 614rpt_bytes: "bytes" 615`, 616 wantMessage: &pb2.Repeats{ 617 RptString: []string{"a", "b"}, 618 RptInt32: []int32{0xff}, 619 RptFloat: []float32{1.23}, 620 RptBytes: [][]byte{[]byte("bytes")}, 621 }, 622 }, { 623 desc: "repeated using mix of [] and repeated field name", 624 inputMessage: &pb2.Repeats{}, 625 inputText: ` 626rpt_string: "a" 627rpt_bool: true 628rpt_string: ["x", "y"] 629rpt_bool: [ false, true ] 630rpt_string: "b" 631`, 632 wantMessage: &pb2.Repeats{ 633 RptString: []string{"a", "x", "y", "b"}, 634 RptBool: []bool{true, false, true}, 635 }, 636 }, { 637 desc: "repeated proto2 contains invalid UTF-8", 638 inputMessage: &pb2.Repeats{}, 639 inputText: `rpt_string: "abc\xff"`, 640 wantMessage: &pb2.Repeats{ 641 RptString: []string{"abc\xff"}, 642 }, 643 }, { 644 desc: "repeated proto3 contains invalid UTF-8", 645 inputMessage: &pb3.Repeats{}, 646 inputText: `rpt_string: "abc\xff"`, 647 wantErr: "contains invalid UTF-8", 648 }, { 649 desc: "repeated enums", 650 inputMessage: &pb2.Enums{}, 651 inputText: ` 652rpt_enum: TEN 653rpt_enum: 1 654rpt_nested_enum: [DOS, 2] 655rpt_enum: 42 656rpt_nested_enum: -47 657`, 658 wantMessage: &pb2.Enums{ 659 RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42}, 660 RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47}, 661 }, 662 }, { 663 desc: "repeated nested messages", 664 inputMessage: &pb2.Nests{}, 665 inputText: ` 666rpt_nested: { 667 opt_string: "repeat nested one" 668} 669rpt_nested: { 670 opt_string: "repeat nested two" 671 opt_nested: { 672 opt_string: "inside repeat nested two" 673 } 674} 675rpt_nested: {} 676`, 677 wantMessage: &pb2.Nests{ 678 RptNested: []*pb2.Nested{ 679 { 680 OptString: proto.String("repeat nested one"), 681 }, 682 { 683 OptString: proto.String("repeat nested two"), 684 OptNested: &pb2.Nested{ 685 OptString: proto.String("inside repeat nested two"), 686 }, 687 }, 688 {}, 689 }, 690 }, 691 }, { 692 desc: "repeated group fields", 693 inputMessage: &pb2.Nests{}, 694 inputText: ` 695RptGroup: { 696 rpt_string: "hello" 697 rpt_string: "world" 698} 699RptGroup: {} 700`, 701 wantMessage: &pb2.Nests{ 702 Rptgroup: []*pb2.Nests_RptGroup{ 703 { 704 RptString: []string{"hello", "world"}, 705 }, 706 {}, 707 }, 708 }, 709 }, { 710 desc: "repeated message fields without field separator", 711 inputMessage: &pb2.Nests{}, 712 inputText: ` 713rpt_nested { 714 opt_string: "repeat nested one" 715} 716rpt_nested: [ 717 { 718 opt_string: "repeat nested two" 719 }, 720 {} 721] 722`, 723 wantMessage: &pb2.Nests{ 724 RptNested: []*pb2.Nested{ 725 { 726 OptString: proto.String("repeat nested one"), 727 }, 728 { 729 OptString: proto.String("repeat nested two"), 730 }, 731 {}, 732 }, 733 }, 734 }, { 735 desc: "bools", 736 inputMessage: &pb2.Repeats{}, 737 inputText: ` 738rpt_bool: [ True, true, t, 1, False, false, f, 0 ] 739`, 740 wantMessage: &pb2.Repeats{ 741 RptBool: []bool{true, true, true, true, false, false, false, false}, 742 }, 743 }, { 744 desc: "special floats and doubles", 745 inputMessage: &pb2.Repeats{}, 746 inputText: ` 747rpt_float: [ inf, Inf, infinity, InFiniTy, -inf, -inF, -infinitY, -InfinitY, nan, NaN, Nan ], 748rpt_double: [ inf, Inf, infinity, InFiniTy, -inf, -inF, -infinitY, -InfinitY, nan, NaN, Nan ], 749`, 750 wantMessage: &pb2.Repeats{ 751 RptFloat: []float32{ 752 float32(math.Inf(1)), 753 float32(math.Inf(1)), 754 float32(math.Inf(1)), 755 float32(math.Inf(1)), 756 float32(math.Inf(-1)), 757 float32(math.Inf(-1)), 758 float32(math.Inf(-1)), 759 float32(math.Inf(-1)), 760 float32(math.NaN()), 761 float32(math.NaN()), 762 float32(math.NaN()), 763 }, 764 RptDouble: []float64{ 765 math.Inf(1), 766 math.Inf(1), 767 math.Inf(1), 768 math.Inf(1), 769 math.Inf(-1), 770 math.Inf(-1), 771 math.Inf(-1), 772 math.Inf(-1), 773 math.NaN(), 774 math.NaN(), 775 math.NaN(), 776 }, 777 }, 778 }, { 779 desc: "map fields 1", 780 inputMessage: &pb3.Maps{}, 781 inputText: ` 782int32_to_str: { 783 key: -101 784 value: "-101" 785} 786int32_to_str { 787 key: 0 788 value: "zero" 789} 790bool_to_uint32: { 791 key: false 792 value: 101 793} 794int32_to_str: { 795 key: 255 796 value: "0xff" 797} 798bool_to_uint32 { 799 key: true 800 value: 42 801} 802`, 803 wantMessage: &pb3.Maps{ 804 Int32ToStr: map[int32]string{ 805 -101: "-101", 806 0xff: "0xff", 807 0: "zero", 808 }, 809 BoolToUint32: map[bool]uint32{ 810 true: 42, 811 false: 101, 812 }, 813 }, 814 }, { 815 desc: "map fields 2", 816 inputMessage: &pb3.Maps{}, 817 inputText: ` 818uint64_to_enum: { 819 key: 1 820 value: ONE 821} 822uint64_to_enum: { 823 key: 2 824 value: 2 825} 826uint64_to_enum: { 827 key: 10 828 value: 101 829} 830`, 831 wantMessage: &pb3.Maps{ 832 Uint64ToEnum: map[uint64]pb3.Enum{ 833 1: pb3.Enum_ONE, 834 2: pb3.Enum_TWO, 835 10: 101, 836 }, 837 }, 838 }, { 839 desc: "map fields 3", 840 inputMessage: &pb3.Maps{}, 841 inputText: ` 842str_to_nested: { 843 key: "nested_one" 844 value { 845 s_string: "nested in a map" 846 } 847} 848`, 849 wantMessage: &pb3.Maps{ 850 StrToNested: map[string]*pb3.Nested{ 851 "nested_one": &pb3.Nested{ 852 SString: "nested in a map", 853 }, 854 }, 855 }, 856 }, { 857 desc: "map fields 4", 858 inputMessage: &pb3.Maps{}, 859 inputText: ` 860str_to_oneofs: { 861 key: "nested" 862 value: { 863 oneof_nested: { 864 s_string: "nested oneof in map field value" 865 } 866 } 867} 868str_to_oneofs: { 869 key: "string" 870 value: { 871 oneof_string: "hello" 872 } 873} 874`, 875 wantMessage: &pb3.Maps{ 876 StrToOneofs: map[string]*pb3.Oneofs{ 877 "string": &pb3.Oneofs{ 878 Union: &pb3.Oneofs_OneofString{ 879 OneofString: "hello", 880 }, 881 }, 882 "nested": &pb3.Oneofs{ 883 Union: &pb3.Oneofs_OneofNested{ 884 OneofNested: &pb3.Nested{ 885 SString: "nested oneof in map field value", 886 }, 887 }, 888 }, 889 }, 890 }, 891 }, { 892 desc: "map contains duplicate keys", 893 inputMessage: &pb3.Maps{}, 894 inputText: ` 895int32_to_str: { 896 key: 0 897 value: "cero" 898} 899int32_to_str: { 900 key: 0 901 value: "zero" 902} 903`, 904 wantMessage: &pb3.Maps{ 905 Int32ToStr: map[int32]string{ 906 0: "zero", 907 }, 908 }, 909 }, { 910 desc: "map contains duplicate key fields", 911 inputMessage: &pb3.Maps{}, 912 inputText: ` 913int32_to_str: { 914 key: 0 915 key: 1 916 value: "cero" 917} 918`, 919 wantErr: `map entry "key" cannot be repeated`, 920 }, { 921 desc: "map contains duplicate value fields", 922 inputMessage: &pb3.Maps{}, 923 inputText: ` 924int32_to_str: { 925 key: 1 926 value: "cero" 927 value: "uno" 928} 929`, 930 wantErr: `map entry "value" cannot be repeated`, 931 }, { 932 desc: "map contains missing key", 933 inputMessage: &pb3.Maps{}, 934 inputText: ` 935int32_to_str: { 936 value: "zero" 937} 938bool_to_uint32: { 939 value: 47 940} 941str_to_nested: { 942 value: {} 943} 944`, 945 wantMessage: &pb3.Maps{ 946 Int32ToStr: map[int32]string{ 947 0: "zero", 948 }, 949 BoolToUint32: map[bool]uint32{ 950 false: 47, 951 }, 952 StrToNested: map[string]*pb3.Nested{ 953 "": {}, 954 }, 955 }, 956 }, { 957 desc: "map contains missing value", 958 inputMessage: &pb3.Maps{}, 959 inputText: ` 960int32_to_str: { 961 key: 100 962} 963bool_to_uint32: { 964 key: true 965} 966uint64_to_enum: { 967 key: 101 968} 969str_to_nested: { 970 key: "hello" 971} 972`, 973 wantMessage: &pb3.Maps{ 974 Int32ToStr: map[int32]string{ 975 100: "", 976 }, 977 BoolToUint32: map[bool]uint32{ 978 true: 0, 979 }, 980 Uint64ToEnum: map[uint64]pb3.Enum{ 981 101: pb3.Enum_ZERO, 982 }, 983 StrToNested: map[string]*pb3.Nested{ 984 "hello": {}, 985 }, 986 }, 987 }, { 988 desc: "map contains missing key and value", 989 inputMessage: &pb3.Maps{}, 990 inputText: ` 991int32_to_str: {} 992bool_to_uint32: {} 993uint64_to_enum: {} 994str_to_nested: {} 995`, 996 wantMessage: &pb3.Maps{ 997 Int32ToStr: map[int32]string{ 998 0: "", 999 }, 1000 BoolToUint32: map[bool]uint32{ 1001 false: 0, 1002 }, 1003 Uint64ToEnum: map[uint64]pb3.Enum{ 1004 0: pb3.Enum_ZERO, 1005 }, 1006 StrToNested: map[string]*pb3.Nested{ 1007 "": {}, 1008 }, 1009 }, 1010 }, { 1011 desc: "map contains overriding entries", 1012 inputMessage: &pb3.Maps{}, 1013 inputText: ` 1014int32_to_str: { 1015 key: 0 1016} 1017int32_to_str: { 1018 value: "empty" 1019} 1020int32_to_str: {} 1021`, 1022 wantMessage: &pb3.Maps{ 1023 Int32ToStr: map[int32]string{ 1024 0: "", 1025 }, 1026 }, 1027 }, { 1028 desc: "proto2 map field value contains invalid UTF-8", 1029 inputMessage: &pb2.Maps{}, 1030 inputText: `int32_to_str: { 1031 key: 101 1032 value: "abc\xff" 1033} 1034`, 1035 wantMessage: &pb2.Maps{ 1036 Int32ToStr: map[int32]string{101: "abc\xff"}, 1037 }, 1038 }, { 1039 desc: "proto2 map field key contains invalid UTF-8", 1040 inputMessage: &pb2.Maps{}, 1041 inputText: `str_to_nested: { 1042 key: "abc\xff" 1043 value: {} 1044} 1045`, 1046 wantMessage: &pb2.Maps{ 1047 StrToNested: map[string]*pb2.Nested{"abc\xff": {}}, 1048 }, 1049 }, { 1050 desc: "proto3 map field value contains invalid UTF-8", 1051 inputMessage: &pb3.Maps{}, 1052 inputText: `int32_to_str: { 1053 key: 101 1054 value: "abc\xff" 1055} 1056`, 1057 wantErr: "contains invalid UTF-8", 1058 }, { 1059 desc: "proto3 map field key contains invalid UTF-8", 1060 inputMessage: &pb3.Maps{}, 1061 inputText: `str_to_nested: { 1062 key: "abc\xff" 1063 value: {} 1064} 1065`, 1066 wantErr: "contains invalid UTF-8", 1067 }, { 1068 desc: "map contains unknown field", 1069 inputMessage: &pb3.Maps{}, 1070 inputText: ` 1071int32_to_str: { 1072 key: 0 1073 value: "cero" 1074 unknown: "bad" 1075} 1076`, 1077 wantErr: `(line 5:3): unknown map entry field "unknown"`, 1078 }, { 1079 desc: "map contains extension-like key field", 1080 inputMessage: &pb3.Maps{}, 1081 inputText: ` 1082int32_to_str: { 1083 [key]: 10 1084 value: "ten" 1085} 1086`, 1087 wantErr: `unknown map entry field "[key]"`, 1088 }, { 1089 desc: "map contains invalid key", 1090 inputMessage: &pb3.Maps{}, 1091 inputText: ` 1092int32_to_str: { 1093 key: "invalid" 1094 value: "cero" 1095} 1096`, 1097 wantErr: "(line 3:8): invalid value for int32 type", 1098 }, { 1099 desc: "map contains invalid value", 1100 inputMessage: &pb3.Maps{}, 1101 inputText: ` 1102int32_to_str: { 1103 key: 100 1104 value: 101 1105} 1106`, 1107 wantErr: "(line 4:10): invalid value for string type", 1108 }, { 1109 desc: "map contains invalid message value", 1110 inputMessage: &pb3.Maps{}, 1111 inputText: ` 1112str_to_nested: { 1113 key: "one" 1114 value: 1 1115} 1116`, 1117 wantErr: "syntax error (line 4:10): unexpected token: 1", 1118 }, { 1119 desc: "map using mix of [] and repeated", 1120 inputMessage: &pb3.Maps{}, 1121 inputText: ` 1122int32_to_str: { 1123 key: 1 1124 value: "one" 1125} 1126int32_to_str: [ 1127 { 1128 key: 2 1129 value: "not this" 1130 }, 1131 { 1132 }, 1133 { 1134 key: 3 1135 value: "three" 1136 } 1137] 1138int32_to_str: { 1139 key: 2 1140 value: "two" 1141} 1142`, 1143 wantMessage: &pb3.Maps{ 1144 Int32ToStr: map[int32]string{ 1145 0: "", 1146 1: "one", 1147 2: "two", 1148 3: "three", 1149 }, 1150 }, 1151 }, { 1152 desc: "required fields not set", 1153 inputMessage: &pb2.Requireds{}, 1154 wantErr: "required field", 1155 }, { 1156 desc: "required field set", 1157 inputMessage: &pb2.PartialRequired{}, 1158 inputText: "req_string: 'this is required'", 1159 wantMessage: &pb2.PartialRequired{ 1160 ReqString: proto.String("this is required"), 1161 }, 1162 }, { 1163 desc: "required fields partially set", 1164 inputMessage: &pb2.Requireds{}, 1165 inputText: ` 1166req_bool: false 1167req_sfixed64: 3203386110 1168req_string: "hello" 1169req_enum: ONE 1170`, 1171 wantMessage: &pb2.Requireds{ 1172 ReqBool: proto.Bool(false), 1173 ReqSfixed64: proto.Int64(0xbeefcafe), 1174 ReqString: proto.String("hello"), 1175 ReqEnum: pb2.Enum_ONE.Enum(), 1176 }, 1177 wantErr: "required field", 1178 }, { 1179 desc: "required fields partially set with AllowPartial", 1180 umo: prototext.UnmarshalOptions{AllowPartial: true}, 1181 inputMessage: &pb2.Requireds{}, 1182 inputText: ` 1183req_bool: false 1184req_sfixed64: 3203386110 1185req_string: "hello" 1186req_enum: ONE 1187`, 1188 wantMessage: &pb2.Requireds{ 1189 ReqBool: proto.Bool(false), 1190 ReqSfixed64: proto.Int64(0xbeefcafe), 1191 ReqString: proto.String("hello"), 1192 ReqEnum: pb2.Enum_ONE.Enum(), 1193 }, 1194 }, { 1195 desc: "required fields all set", 1196 inputMessage: &pb2.Requireds{}, 1197 inputText: ` 1198req_bool: false 1199req_sfixed64: 0 1200req_double: 0 1201req_string: "" 1202req_enum: ONE 1203req_nested: {} 1204`, 1205 wantMessage: &pb2.Requireds{ 1206 ReqBool: proto.Bool(false), 1207 ReqSfixed64: proto.Int64(0), 1208 ReqDouble: proto.Float64(0), 1209 ReqString: proto.String(""), 1210 ReqEnum: pb2.Enum_ONE.Enum(), 1211 ReqNested: &pb2.Nested{}, 1212 }, 1213 }, { 1214 desc: "indirect required field", 1215 inputMessage: &pb2.IndirectRequired{}, 1216 inputText: "opt_nested: {}", 1217 wantMessage: &pb2.IndirectRequired{ 1218 OptNested: &pb2.NestedWithRequired{}, 1219 }, 1220 wantErr: "required field", 1221 }, { 1222 desc: "indirect required field with AllowPartial", 1223 umo: prototext.UnmarshalOptions{AllowPartial: true}, 1224 inputMessage: &pb2.IndirectRequired{}, 1225 inputText: "opt_nested: {}", 1226 wantMessage: &pb2.IndirectRequired{ 1227 OptNested: &pb2.NestedWithRequired{}, 1228 }, 1229 }, { 1230 desc: "indirect required field in repeated", 1231 inputMessage: &pb2.IndirectRequired{}, 1232 inputText: ` 1233rpt_nested: { 1234 req_string: "one" 1235} 1236rpt_nested: {} 1237`, 1238 wantMessage: &pb2.IndirectRequired{ 1239 RptNested: []*pb2.NestedWithRequired{ 1240 { 1241 ReqString: proto.String("one"), 1242 }, 1243 {}, 1244 }, 1245 }, 1246 wantErr: "required field", 1247 }, { 1248 desc: "indirect required field in repeated with AllowPartial", 1249 umo: prototext.UnmarshalOptions{AllowPartial: true}, 1250 inputMessage: &pb2.IndirectRequired{}, 1251 inputText: ` 1252rpt_nested: { 1253 req_string: "one" 1254} 1255rpt_nested: {} 1256`, 1257 wantMessage: &pb2.IndirectRequired{ 1258 RptNested: []*pb2.NestedWithRequired{ 1259 { 1260 ReqString: proto.String("one"), 1261 }, 1262 {}, 1263 }, 1264 }, 1265 }, { 1266 desc: "indirect required field in map", 1267 inputMessage: &pb2.IndirectRequired{}, 1268 inputText: ` 1269str_to_nested: { 1270 key: "missing" 1271} 1272str_to_nested: { 1273 key: "contains" 1274 value: { 1275 req_string: "here" 1276 } 1277} 1278`, 1279 wantMessage: &pb2.IndirectRequired{ 1280 StrToNested: map[string]*pb2.NestedWithRequired{ 1281 "missing": &pb2.NestedWithRequired{}, 1282 "contains": &pb2.NestedWithRequired{ 1283 ReqString: proto.String("here"), 1284 }, 1285 }, 1286 }, 1287 wantErr: "required field", 1288 }, { 1289 desc: "indirect required field in map with AllowPartial", 1290 umo: prototext.UnmarshalOptions{AllowPartial: true}, 1291 inputMessage: &pb2.IndirectRequired{}, 1292 inputText: ` 1293str_to_nested: { 1294 key: "missing" 1295} 1296str_to_nested: { 1297 key: "contains" 1298 value: { 1299 req_string: "here" 1300 } 1301} 1302`, 1303 wantMessage: &pb2.IndirectRequired{ 1304 StrToNested: map[string]*pb2.NestedWithRequired{ 1305 "missing": &pb2.NestedWithRequired{}, 1306 "contains": &pb2.NestedWithRequired{ 1307 ReqString: proto.String("here"), 1308 }, 1309 }, 1310 }, 1311 }, { 1312 desc: "indirect required field in oneof", 1313 inputMessage: &pb2.IndirectRequired{}, 1314 inputText: `oneof_nested: {} 1315`, 1316 wantMessage: &pb2.IndirectRequired{ 1317 Union: &pb2.IndirectRequired_OneofNested{ 1318 OneofNested: &pb2.NestedWithRequired{}, 1319 }, 1320 }, 1321 wantErr: "required field", 1322 }, { 1323 desc: "indirect required field in oneof with AllowPartial", 1324 umo: prototext.UnmarshalOptions{AllowPartial: true}, 1325 inputMessage: &pb2.IndirectRequired{}, 1326 inputText: `oneof_nested: {} 1327`, 1328 wantMessage: &pb2.IndirectRequired{ 1329 Union: &pb2.IndirectRequired_OneofNested{ 1330 OneofNested: &pb2.NestedWithRequired{}, 1331 }, 1332 }, 1333 }, { 1334 desc: "ignore reserved field", 1335 inputMessage: &pb2.Nests{}, 1336 inputText: "reserved_field: 'ignore this'", 1337 wantMessage: &pb2.Nests{}, 1338 }, { 1339 desc: "extensions of non-repeated fields", 1340 inputMessage: &pb2.Extensions{}, 1341 inputText: `opt_string: "non-extension field" 1342[pb2.opt_ext_bool]: true 1343opt_bool: true 1344[pb2.opt_ext_nested]: { 1345 opt_string: "nested in an extension" 1346 opt_nested: { 1347 opt_string: "another nested in an extension" 1348 } 1349} 1350[pb2.opt_ext_string]: "extension field" 1351opt_int32: 42 1352[pb2.opt_ext_enum]: TEN 1353`, 1354 wantMessage: func() proto.Message { 1355 m := &pb2.Extensions{ 1356 OptString: proto.String("non-extension field"), 1357 OptBool: proto.Bool(true), 1358 OptInt32: proto.Int32(42), 1359 } 1360 proto.SetExtension(m, pb2.E_OptExtBool, true) 1361 proto.SetExtension(m, pb2.E_OptExtString, "extension field") 1362 proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN) 1363 proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{ 1364 OptString: proto.String("nested in an extension"), 1365 OptNested: &pb2.Nested{ 1366 OptString: proto.String("another nested in an extension"), 1367 }, 1368 }) 1369 return m 1370 }(), 1371 }, { 1372 desc: "extension field contains invalid UTF-8", 1373 inputMessage: &pb2.Extensions{}, 1374 inputText: `[pb2.opt_ext_string]: "abc\xff"`, 1375 wantMessage: func() proto.Message { 1376 m := &pb2.Extensions{} 1377 proto.SetExtension(m, pb2.E_OptExtString, "abc\xff") 1378 return m 1379 }(), 1380 }, { 1381 desc: "extensions of repeated fields", 1382 inputMessage: &pb2.Extensions{}, 1383 inputText: `[pb2.rpt_ext_enum]: TEN 1384[pb2.rpt_ext_enum]: 101 1385[pb2.rpt_ext_fixed32]: 42 1386[pb2.rpt_ext_enum]: ONE 1387[pb2.rpt_ext_nested]: { 1388 opt_string: "one" 1389} 1390[pb2.rpt_ext_nested]: { 1391 opt_string: "two" 1392} 1393[pb2.rpt_ext_fixed32]: 47 1394[pb2.rpt_ext_nested]: { 1395 opt_string: "three" 1396} 1397`, 1398 wantMessage: func() proto.Message { 1399 m := &pb2.Extensions{} 1400 proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE}) 1401 proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47}) 1402 proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{ 1403 &pb2.Nested{OptString: proto.String("one")}, 1404 &pb2.Nested{OptString: proto.String("two")}, 1405 &pb2.Nested{OptString: proto.String("three")}, 1406 }) 1407 return m 1408 }(), 1409 }, { 1410 desc: "extensions of non-repeated fields in another message", 1411 inputMessage: &pb2.Extensions{}, 1412 inputText: `[pb2.ExtensionsContainer.opt_ext_bool]: true 1413[pb2.ExtensionsContainer.opt_ext_enum]: TEN 1414[pb2.ExtensionsContainer.opt_ext_nested]: { 1415 opt_string: "nested in an extension" 1416 opt_nested: { 1417 opt_string: "another nested in an extension" 1418 } 1419} 1420[pb2.ExtensionsContainer.opt_ext_string]: "extension field" 1421`, 1422 wantMessage: func() proto.Message { 1423 m := &pb2.Extensions{} 1424 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true) 1425 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field") 1426 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN) 1427 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{ 1428 OptString: proto.String("nested in an extension"), 1429 OptNested: &pb2.Nested{ 1430 OptString: proto.String("another nested in an extension"), 1431 }, 1432 }) 1433 return m 1434 }(), 1435 }, { 1436 desc: "extensions of repeated fields in another message", 1437 inputMessage: &pb2.Extensions{}, 1438 inputText: `opt_string: "non-extension field" 1439opt_bool: true 1440opt_int32: 42 1441[pb2.ExtensionsContainer.rpt_ext_nested]: { 1442 opt_string: "one" 1443} 1444[pb2.ExtensionsContainer.rpt_ext_enum]: TEN 1445[pb2.ExtensionsContainer.rpt_ext_nested]: { 1446 opt_string: "two" 1447} 1448[pb2.ExtensionsContainer.rpt_ext_enum]: 101 1449[pb2.ExtensionsContainer.rpt_ext_string]: "hello" 1450[pb2.ExtensionsContainer.rpt_ext_enum]: ONE 1451[pb2.ExtensionsContainer.rpt_ext_nested]: { 1452 opt_string: "three" 1453} 1454[pb2.ExtensionsContainer.rpt_ext_string]: "world" 1455`, 1456 wantMessage: func() proto.Message { 1457 m := &pb2.Extensions{ 1458 OptString: proto.String("non-extension field"), 1459 OptBool: proto.Bool(true), 1460 OptInt32: proto.Int32(42), 1461 } 1462 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE}) 1463 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"}) 1464 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{ 1465 &pb2.Nested{OptString: proto.String("one")}, 1466 &pb2.Nested{OptString: proto.String("two")}, 1467 &pb2.Nested{OptString: proto.String("three")}, 1468 }) 1469 return m 1470 }(), 1471 }, { 1472 desc: "invalid extension field name", 1473 inputMessage: &pb2.Extensions{}, 1474 inputText: "[pb2.invalid_message_field]: true", 1475 wantErr: "unknown field", 1476 }, { 1477 desc: "MessageSet", 1478 inputMessage: &pb2.MessageSet{}, 1479 inputText: ` 1480[pb2.MessageSetExtension]: { 1481 opt_string: "a messageset extension" 1482} 1483[pb2.MessageSetExtension.ext_nested]: { 1484 opt_string: "just a regular extension" 1485} 1486[pb2.MessageSetExtension.not_message_set_extension]: { 1487 opt_string: "not a messageset extension" 1488} 1489`, 1490 wantMessage: func() proto.Message { 1491 m := &pb2.MessageSet{} 1492 proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{ 1493 OptString: proto.String("a messageset extension"), 1494 }) 1495 proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{ 1496 OptString: proto.String("not a messageset extension"), 1497 }) 1498 proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{ 1499 OptString: proto.String("just a regular extension"), 1500 }) 1501 return m 1502 }(), 1503 skip: !flags.ProtoLegacy, 1504 }, { 1505 desc: "not real MessageSet 1", 1506 inputMessage: &pb2.FakeMessageSet{}, 1507 inputText: ` 1508[pb2.FakeMessageSetExtension.message_set_extension]: { 1509 opt_string: "not a messageset extension" 1510} 1511`, 1512 wantMessage: func() proto.Message { 1513 m := &pb2.FakeMessageSet{} 1514 proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{ 1515 OptString: proto.String("not a messageset extension"), 1516 }) 1517 return m 1518 }(), 1519 skip: !flags.ProtoLegacy, 1520 }, { 1521 desc: "not real MessageSet 2", 1522 inputMessage: &pb2.FakeMessageSet{}, 1523 inputText: ` 1524[pb2.FakeMessageSetExtension]: { 1525 opt_string: "not a messageset extension" 1526} 1527`, 1528 wantErr: `unable to resolve [[pb2.FakeMessageSetExtension]]: found wrong type`, 1529 skip: !flags.ProtoLegacy, 1530 }, { 1531 desc: "not real MessageSet 3", 1532 inputMessage: &pb2.MessageSet{}, 1533 inputText: ` 1534[pb2.message_set_extension]: { 1535 opt_string: "another not a messageset extension" 1536}`, 1537 wantMessage: func() proto.Message { 1538 m := &pb2.MessageSet{} 1539 proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{ 1540 OptString: proto.String("another not a messageset extension"), 1541 }) 1542 return m 1543 }(), 1544 skip: !flags.ProtoLegacy, 1545 }, { 1546 desc: "Any not expanded", 1547 inputMessage: &anypb.Any{}, 1548 inputText: ` 1549type_url: "pb2.Nested" 1550value: "some bytes" 1551`, 1552 wantMessage: &anypb.Any{ 1553 TypeUrl: "pb2.Nested", 1554 Value: []byte("some bytes"), 1555 }, 1556 }, { 1557 desc: "Any not expanded missing value", 1558 inputMessage: &anypb.Any{}, 1559 inputText: `type_url: "pb2.Nested"`, 1560 wantMessage: &anypb.Any{ 1561 TypeUrl: "pb2.Nested", 1562 }, 1563 }, { 1564 desc: "Any not expanded missing type_url", 1565 inputMessage: &anypb.Any{}, 1566 inputText: `value: "some bytes"`, 1567 wantMessage: &anypb.Any{ 1568 Value: []byte("some bytes"), 1569 }, 1570 }, { 1571 desc: "Any expanded", 1572 inputMessage: &anypb.Any{}, 1573 inputText: ` 1574[foobar/pb2.Nested]: { 1575 opt_string: "embedded inside Any" 1576 opt_nested: { 1577 opt_string: "inception" 1578 } 1579} 1580`, 1581 wantMessage: func() proto.Message { 1582 m := &pb2.Nested{ 1583 OptString: proto.String("embedded inside Any"), 1584 OptNested: &pb2.Nested{ 1585 OptString: proto.String("inception"), 1586 }, 1587 } 1588 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) 1589 if err != nil { 1590 t.Fatalf("error in binary marshaling message for Any.value: %v", err) 1591 } 1592 return &anypb.Any{ 1593 TypeUrl: "foobar/pb2.Nested", 1594 Value: b, 1595 } 1596 }(), 1597 }, { 1598 desc: "Any expanded with empty value", 1599 inputMessage: &anypb.Any{}, 1600 inputText: `[foo.com/pb2.Nested]: {}`, 1601 wantMessage: &anypb.Any{ 1602 TypeUrl: "foo.com/pb2.Nested", 1603 }, 1604 }, { 1605 desc: "Any expanded with missing required", 1606 inputMessage: &anypb.Any{}, 1607 inputText: ` 1608[pb2.PartialRequired]: { 1609 opt_string: "embedded inside Any" 1610} 1611`, 1612 wantMessage: func() proto.Message { 1613 m := &pb2.PartialRequired{ 1614 OptString: proto.String("embedded inside Any"), 1615 } 1616 b, err := proto.MarshalOptions{ 1617 AllowPartial: true, 1618 Deterministic: true, 1619 }.Marshal(m) 1620 if err != nil { 1621 t.Fatalf("error in binary marshaling message for Any.value: %v", err) 1622 } 1623 return &anypb.Any{ 1624 TypeUrl: "pb2.PartialRequired", 1625 Value: b, 1626 } 1627 }(), 1628 }, { 1629 desc: "Any with invalid UTF-8", 1630 inputMessage: &anypb.Any{}, 1631 inputText: ` 1632[pb3.Nested]: { 1633 s_string: "abc\xff" 1634} 1635`, 1636 wantErr: "contains invalid UTF-8", 1637 }, { 1638 desc: "Any expanded with unregistered type", 1639 umo: prototext.UnmarshalOptions{Resolver: new(protoregistry.Types)}, 1640 inputMessage: &anypb.Any{}, 1641 inputText: `[SomeMessage]: {}`, 1642 wantErr: "unable to resolve message [SomeMessage]", 1643 }, { 1644 desc: "Any expanded with invalid value", 1645 inputMessage: &anypb.Any{}, 1646 inputText: `[pb2.Nested]: 123`, 1647 wantErr: "unexpected token: 123", 1648 }, { 1649 desc: "Any expanded with unknown fields", 1650 inputMessage: &anypb.Any{}, 1651 inputText: ` 1652[pb2.Nested]: {} 1653unknown: "" 1654`, 1655 wantErr: `invalid field name "unknown" in google.protobuf.Any message`, 1656 }, { 1657 desc: "Any contains expanded and unexpanded fields", 1658 inputMessage: &anypb.Any{}, 1659 inputText: ` 1660[pb2.Nested]: {} 1661type_url: "pb2.Nested" 1662`, 1663 wantErr: "(line 3:1): conflict with [pb2.Nested] field", 1664 }, { 1665 desc: "weak fields", 1666 inputMessage: &testpb.TestWeak{}, 1667 inputText: `weak_message1:{a:1}`, 1668 wantMessage: func() *testpb.TestWeak { 1669 m := new(testpb.TestWeak) 1670 m.SetWeakMessage1(&weakpb.WeakImportMessage1{A: proto.Int32(1)}) 1671 return m 1672 }(), 1673 skip: !flags.ProtoLegacy, 1674 }, { 1675 desc: "weak fields; unknown field", 1676 inputMessage: &testpb.TestWeak{}, 1677 inputText: `weak_message1:{a:1} weak_message2:{a:1}`, 1678 wantErr: "unknown field: weak_message2", // weak_message2 is unknown since the package containing it is not imported 1679 skip: !flags.ProtoLegacy, 1680 }} 1681 1682 for _, tt := range tests { 1683 tt := tt 1684 if tt.skip { 1685 continue 1686 } 1687 t.Run(tt.desc, func(t *testing.T) { 1688 err := tt.umo.Unmarshal([]byte(tt.inputText), tt.inputMessage) 1689 if err != nil { 1690 if tt.wantErr == "" { 1691 t.Errorf("Unmarshal() got unexpected error: %v", err) 1692 } else if !strings.Contains(err.Error(), tt.wantErr) { 1693 t.Errorf("Unmarshal() error got %q, want %q", err, tt.wantErr) 1694 } 1695 return 1696 } 1697 if tt.wantErr != "" { 1698 t.Errorf("Unmarshal() got nil error, want error %q", tt.wantErr) 1699 return 1700 } 1701 if tt.wantMessage != nil && !proto.Equal(tt.inputMessage, tt.wantMessage) { 1702 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage) 1703 } 1704 }) 1705 } 1706} 1707