...

Source file src/google.golang.org/protobuf/encoding/prototext/decode_test.go

Documentation: google.golang.org/protobuf/encoding/prototext

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

View as plain text