github.com/whiteCcinn/protobuf-go@v1.0.9/encoding/prototext/decode_test.go (about)

     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  
     5  package prototext_test
     6  
     7  import (
     8  	"math"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/whiteCcinn/protobuf-go/encoding/prototext"
    13  	"github.com/whiteCcinn/protobuf-go/internal/flags"
    14  	"github.com/whiteCcinn/protobuf-go/proto"
    15  	"github.com/whiteCcinn/protobuf-go/reflect/protoregistry"
    16  
    17  	testpb "github.com/whiteCcinn/protobuf-go/internal/testprotos/test"
    18  	weakpb "github.com/whiteCcinn/protobuf-go/internal/testprotos/test/weak1"
    19  	pb2 "github.com/whiteCcinn/protobuf-go/internal/testprotos/textpb2"
    20  	pb3 "github.com/whiteCcinn/protobuf-go/internal/testprotos/textpb3"
    21  	"github.com/whiteCcinn/protobuf-go/types/known/anypb"
    22  )
    23  
    24  func 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
    41  opt_int32: 0
    42  opt_int64: 0
    43  opt_uint32: 0
    44  opt_uint64: 0
    45  opt_sint32: 0
    46  opt_sint64: 0
    47  opt_fixed32: 0
    48  opt_fixed64: 0
    49  opt_sfixed32: 0
    50  opt_sfixed64: 0
    51  opt_float: 0
    52  opt_double: 0
    53  opt_bytes: ""
    54  opt_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
    77  s_int32: 0
    78  s_int64: 0
    79  s_uint32: 0
    80  s_uint64: 0
    81  s_sint32: 0
    82  s_sint64: 0
    83  s_fixed32: 0
    84  s_fixed64: 0
    85  s_sfixed32: 0
    86  s_sfixed64: 0
    87  s_float: 0
    88  s_double: 0
    89  s_bytes: ""
    90  s_string: ""
    91  `,
    92  		wantMessage: &pb3.Scalars{},
    93  	}, {
    94  		desc:         "proto3 optional set to zero values",
    95  		inputMessage: &pb3.Proto3Optional{},
    96  		inputText: `opt_bool: false
    97  opt_int32: 0
    98  opt_int64: 0
    99  opt_uint32: 0
   100  opt_uint64: 0
   101  opt_float: 0
   102  opt_double: 0
   103  opt_string: ""
   104  opt_bytes: ""
   105  opt_enum: ZERO
   106  opt_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
   125  opt_int32: 255
   126  opt_int64: 3735928559
   127  opt_uint32: 0xff
   128  opt_uint64: 0xdeadbeef
   129  opt_sint32: -1001
   130  opt_sint64: -0xffff
   131  opt_fixed64: 64
   132  opt_sfixed32: -32
   133  opt_float: 1.234
   134  opt_double: 1.23e+100
   135  opt_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
   136  opt_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
   162  s_int32: 255
   163  s_int64: 3735928559
   164  s_uint32: 0xff
   165  s_uint64: 0xdeadbeef
   166  s_sint32: -1001
   167  s_sint64: -0xffff
   168  s_fixed64: 64
   169  s_sfixed32: -32
   170  s_float: 1.234
   171  s_double: 1.23e+100
   172  s_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
   173  s_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: `
   352  opt_bool: true
   353  opt_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: `
   360  opt_bool: true
   361  opt_string: "hello"
   362  opt_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: `
   369  opt_bool: [true, false]
   370  `,
   371  		wantErr: "(line 2:11): unexpected token: [",
   372  	}, {
   373  		desc:         "proto3 duplicate singular field",
   374  		inputMessage: &pb3.Scalars{},
   375  		inputText: `
   376  s_bool: false
   377  s_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: `
   384  s_bool: false
   385  s_string: ""
   386  s_bool: true
   387  `,
   388  		wantErr: `non-repeated field "s_bool" is repeated`,
   389  	}, {
   390  		desc:         "proto2 enum",
   391  		inputMessage: &pb2.Enums{},
   392  		inputText: `
   393  opt_enum: ONE
   394  opt_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: `
   404  opt_enum: 2
   405  opt_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: `
   415  opt_enum: 101
   416  opt_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: `
   426  opt_enum: UNNAMED
   427  opt_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: `
   434  s_enum: ONE
   435  s_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: `
   445  s_enum: 2
   446  s_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: `
   456  s_enum: 0x7fffffff
   457  s_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: `
   467  opt_nested: {}
   468  OptGroup: {}
   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: `
   478  opt_nested {}
   479  OptGroup {}
   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: `
   494  opt_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: `
   520  s_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: `
   581  oneof_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: `
   596  oneof_enum: ZERO
   597  oneof_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: `
   604  rpt_string: "a"
   605  rpt_string: "b"
   606  rpt_int32: 0xff
   607  rpt_float: 1.23
   608  rpt_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: `
   620  rpt_string: "a"
   621  rpt_bool: true
   622  rpt_string: ["x", "y"]
   623  rpt_bool: [ false, true ]
   624  rpt_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: `
   646  rpt_enum: TEN
   647  rpt_enum: 1
   648  rpt_nested_enum: [DOS, 2]
   649  rpt_enum: 42
   650  rpt_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: `
   660  rpt_nested: {
   661    opt_string: "repeat nested one"
   662  }
   663  rpt_nested: {
   664    opt_string: "repeat nested two"
   665    opt_nested: {
   666      opt_string: "inside repeat nested two"
   667    }
   668  }
   669  rpt_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: `
   689  RptGroup: {
   690    rpt_string: "hello"
   691    rpt_string: "world"
   692  }
   693  RptGroup: {}
   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: `
   707  rpt_nested {
   708    opt_string: "repeat nested one"
   709  }
   710  rpt_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: `
   732  rpt_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: `
   741  rpt_float: [ inf, Inf, infinity, InFiniTy, -inf, -inF, -infinitY, -InfinitY, nan, NaN, Nan ],
   742  rpt_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: `
   776  int32_to_str: {
   777    key: -101
   778    value: "-101"
   779  }
   780  int32_to_str {
   781    key: 0
   782    value: "zero"
   783  }
   784  bool_to_uint32: {
   785    key: false
   786    value: 101
   787  }
   788  int32_to_str: {
   789    key: 255
   790    value: "0xff"
   791  }
   792  bool_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: `
   812  uint64_to_enum: {
   813    key: 1
   814    value: ONE
   815  }
   816  uint64_to_enum: {
   817    key: 2
   818    value: 2
   819  }
   820  uint64_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: `
   836  str_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: `
   854  str_to_oneofs: {
   855    key: "nested"
   856    value: {
   857      oneof_nested: {
   858        s_string: "nested oneof in map field value"
   859      }
   860    }
   861  }
   862  str_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: `
   889  int32_to_str: {
   890    key: 0
   891    value: "cero"
   892  }
   893  int32_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: `
   907  int32_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: `
   918  int32_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: `
   929  int32_to_str: {
   930    value: "zero"
   931  }
   932  bool_to_uint32: {
   933    value: 47
   934  }
   935  str_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: `
   954  int32_to_str: {
   955    key: 100
   956  }
   957  bool_to_uint32: {
   958    key: true
   959  }
   960  uint64_to_enum: {
   961    key: 101
   962  }
   963  str_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: `
   985  int32_to_str: {}
   986  bool_to_uint32: {}
   987  uint64_to_enum: {}
   988  str_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: `
  1008  int32_to_str: {
  1009    key: 0
  1010  }
  1011  int32_to_str: {
  1012    value: "empty"
  1013  }
  1014  int32_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: `
  1065  int32_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: `
  1076  int32_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: `
  1086  int32_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: `
  1096  int32_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: `
  1106  str_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: `
  1116  int32_to_str: {
  1117    key: 1
  1118    value: "one"
  1119  }
  1120  int32_to_str: [
  1121    {
  1122      key: 2
  1123      value: "not this"
  1124    },
  1125    {
  1126    },
  1127    {
  1128      key: 3
  1129      value: "three"
  1130    }
  1131  ]
  1132  int32_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: `
  1160  req_bool: false
  1161  req_sfixed64: 3203386110
  1162  req_string: "hello"
  1163  req_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: `
  1177  req_bool: false
  1178  req_sfixed64: 3203386110
  1179  req_string: "hello"
  1180  req_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: `
  1192  req_bool: false
  1193  req_sfixed64: 0
  1194  req_double: 0
  1195  req_string: ""
  1196  req_enum: ONE
  1197  req_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: `
  1227  rpt_nested: {
  1228    req_string: "one"
  1229  }
  1230  rpt_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: `
  1246  rpt_nested: {
  1247    req_string: "one"
  1248  }
  1249  rpt_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: `
  1263  str_to_nested: {
  1264    key: "missing"
  1265  }
  1266  str_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: `
  1287  str_to_nested: {
  1288    key: "missing"
  1289  }
  1290  str_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
  1337  opt_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"
  1345  opt_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"
  1433  opt_bool: true
  1434  opt_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: `
  1543  type_url: "pb2.Nested"
  1544  value: "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(protoregistry.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]: {}
  1647  unknown: ""
  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]: {}
  1655  type_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  }