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