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