...

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

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

     1  // Copyright 2019 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 protojson_test
     6  
     7  import (
     8  	"math"
     9  	"strings"
    10  	"testing"
    11  
    12  	"google.golang.org/protobuf/encoding/protojson"
    13  	"google.golang.org/protobuf/internal/errors"
    14  	"google.golang.org/protobuf/internal/flags"
    15  	"google.golang.org/protobuf/proto"
    16  	"google.golang.org/protobuf/reflect/protoregistry"
    17  
    18  	testpb "google.golang.org/protobuf/internal/testprotos/test"
    19  	weakpb "google.golang.org/protobuf/internal/testprotos/test/weak1"
    20  	pb2 "google.golang.org/protobuf/internal/testprotos/textpb2"
    21  	pb3 "google.golang.org/protobuf/internal/testprotos/textpb3"
    22  	"google.golang.org/protobuf/types/known/anypb"
    23  	"google.golang.org/protobuf/types/known/durationpb"
    24  	"google.golang.org/protobuf/types/known/emptypb"
    25  	"google.golang.org/protobuf/types/known/fieldmaskpb"
    26  	"google.golang.org/protobuf/types/known/structpb"
    27  	"google.golang.org/protobuf/types/known/timestamppb"
    28  	"google.golang.org/protobuf/types/known/wrapperspb"
    29  )
    30  
    31  func TestUnmarshal(t *testing.T) {
    32  	tests := []struct {
    33  		desc         string
    34  		umo          protojson.UnmarshalOptions
    35  		inputMessage proto.Message
    36  		inputText    string
    37  		wantMessage  proto.Message
    38  		wantErr      string // Expected error substring.
    39  		skip         bool
    40  	}{{
    41  		desc:         "proto2 empty message",
    42  		inputMessage: &pb2.Scalars{},
    43  		inputText:    "{}",
    44  		wantMessage:  &pb2.Scalars{},
    45  	}, {
    46  		desc:         "unexpected value instead of EOF",
    47  		inputMessage: &pb2.Scalars{},
    48  		inputText:    "{} {}",
    49  		wantErr:      `(line 1:4): unexpected token {`,
    50  	}, {
    51  		desc:         "proto2 optional scalars set to zero values",
    52  		inputMessage: &pb2.Scalars{},
    53  		inputText: `{
    54    "optBool": false,
    55    "optInt32": 0,
    56    "optInt64": 0,
    57    "optUint32": 0,
    58    "optUint64": 0,
    59    "optSint32": 0,
    60    "optSint64": 0,
    61    "optFixed32": 0,
    62    "optFixed64": 0,
    63    "optSfixed32": 0,
    64    "optSfixed64": 0,
    65    "optFloat": 0,
    66    "optDouble": 0,
    67    "optBytes": "",
    68    "optString": ""
    69  }`,
    70  		wantMessage: &pb2.Scalars{
    71  			OptBool:     proto.Bool(false),
    72  			OptInt32:    proto.Int32(0),
    73  			OptInt64:    proto.Int64(0),
    74  			OptUint32:   proto.Uint32(0),
    75  			OptUint64:   proto.Uint64(0),
    76  			OptSint32:   proto.Int32(0),
    77  			OptSint64:   proto.Int64(0),
    78  			OptFixed32:  proto.Uint32(0),
    79  			OptFixed64:  proto.Uint64(0),
    80  			OptSfixed32: proto.Int32(0),
    81  			OptSfixed64: proto.Int64(0),
    82  			OptFloat:    proto.Float32(0),
    83  			OptDouble:   proto.Float64(0),
    84  			OptBytes:    []byte{},
    85  			OptString:   proto.String(""),
    86  		},
    87  	}, {
    88  		desc:         "proto3 scalars set to zero values",
    89  		inputMessage: &pb3.Scalars{},
    90  		inputText: `{
    91    "sBool": false,
    92    "sInt32": 0,
    93    "sInt64": 0,
    94    "sUint32": 0,
    95    "sUint64": 0,
    96    "sSint32": 0,
    97    "sSint64": 0,
    98    "sFixed32": 0,
    99    "sFixed64": 0,
   100    "sSfixed32": 0,
   101    "sSfixed64": 0,
   102    "sFloat": 0,
   103    "sDouble": 0,
   104    "sBytes": "",
   105    "sString": ""
   106  }`,
   107  		wantMessage: &pb3.Scalars{},
   108  	}, {
   109  		desc:         "proto3 optional set to zero values",
   110  		inputMessage: &pb3.Proto3Optional{},
   111  		inputText: `{
   112    "optBool": false,
   113    "optInt32": 0,
   114    "optInt64": 0,
   115    "optUint32": 0,
   116    "optUint64": 0,
   117    "optFloat": 0,
   118    "optDouble": 0,
   119    "optString": "",
   120    "optBytes": "",
   121    "optEnum": "ZERO",
   122    "optMessage": {}
   123  }`,
   124  		wantMessage: &pb3.Proto3Optional{
   125  			OptBool:    proto.Bool(false),
   126  			OptInt32:   proto.Int32(0),
   127  			OptInt64:   proto.Int64(0),
   128  			OptUint32:  proto.Uint32(0),
   129  			OptUint64:  proto.Uint64(0),
   130  			OptFloat:   proto.Float32(0),
   131  			OptDouble:  proto.Float64(0),
   132  			OptString:  proto.String(""),
   133  			OptBytes:   []byte{},
   134  			OptEnum:    pb3.Enum_ZERO.Enum(),
   135  			OptMessage: &pb3.Nested{},
   136  		},
   137  	}, {
   138  		desc:         "proto2 optional scalars set to null",
   139  		inputMessage: &pb2.Scalars{},
   140  		inputText: `{
   141    "optBool": null,
   142    "optInt32": null,
   143    "optInt64": null,
   144    "optUint32": null,
   145    "optUint64": null,
   146    "optSint32": null,
   147    "optSint64": null,
   148    "optFixed32": null,
   149    "optFixed64": null,
   150    "optSfixed32": null,
   151    "optSfixed64": null,
   152    "optFloat": null,
   153    "optDouble": null,
   154    "optBytes": null,
   155    "optString": null
   156  }`,
   157  		wantMessage: &pb2.Scalars{},
   158  	}, {
   159  		desc:         "proto3 scalars set to null",
   160  		inputMessage: &pb3.Scalars{},
   161  		inputText: `{
   162    "sBool": null,
   163    "sInt32": null,
   164    "sInt64": null,
   165    "sUint32": null,
   166    "sUint64": null,
   167    "sSint32": null,
   168    "sSint64": null,
   169    "sFixed32": null,
   170    "sFixed64": null,
   171    "sSfixed32": null,
   172    "sSfixed64": null,
   173    "sFloat": null,
   174    "sDouble": null,
   175    "sBytes": null,
   176    "sString": null
   177  }`,
   178  		wantMessage: &pb3.Scalars{},
   179  	}, {
   180  		desc:         "boolean",
   181  		inputMessage: &pb3.Scalars{},
   182  		inputText:    `{"sBool": true}`,
   183  		wantMessage: &pb3.Scalars{
   184  			SBool: true,
   185  		},
   186  	}, {
   187  		desc:         "not boolean",
   188  		inputMessage: &pb3.Scalars{},
   189  		inputText:    `{"sBool": "true"}`,
   190  		wantErr:      `invalid value for bool type: "true"`,
   191  	}, {
   192  		desc:         "float and double",
   193  		inputMessage: &pb3.Scalars{},
   194  		inputText: `{
   195    "sFloat": 1.234,
   196    "sDouble": 5.678
   197  }`,
   198  		wantMessage: &pb3.Scalars{
   199  			SFloat:  1.234,
   200  			SDouble: 5.678,
   201  		},
   202  	}, {
   203  		desc:         "float and double in string",
   204  		inputMessage: &pb3.Scalars{},
   205  		inputText: `{
   206    "sFloat": "1.234",
   207    "sDouble": "5.678"
   208  }`,
   209  		wantMessage: &pb3.Scalars{
   210  			SFloat:  1.234,
   211  			SDouble: 5.678,
   212  		},
   213  	}, {
   214  		desc:         "float and double in E notation",
   215  		inputMessage: &pb3.Scalars{},
   216  		inputText: `{
   217    "sFloat": 12.34E-1,
   218    "sDouble": 5.678e4
   219  }`,
   220  		wantMessage: &pb3.Scalars{
   221  			SFloat:  1.234,
   222  			SDouble: 56780,
   223  		},
   224  	}, {
   225  		desc:         "float and double in string E notation",
   226  		inputMessage: &pb3.Scalars{},
   227  		inputText: `{
   228    "sFloat": "12.34E-1",
   229    "sDouble": "5.678e4"
   230  }`,
   231  		wantMessage: &pb3.Scalars{
   232  			SFloat:  1.234,
   233  			SDouble: 56780,
   234  		},
   235  	}, {
   236  		desc:         "float exceeds limit",
   237  		inputMessage: &pb3.Scalars{},
   238  		inputText:    `{"sFloat": 3.4e39}`,
   239  		wantErr:      `invalid value for float type: 3.4e39`,
   240  	}, {
   241  		desc:         "float in string exceeds limit",
   242  		inputMessage: &pb3.Scalars{},
   243  		inputText:    `{"sFloat": "-3.4e39"}`,
   244  		wantErr:      `invalid value for float type: "-3.4e39"`,
   245  	}, {
   246  		desc:         "double exceeds limit",
   247  		inputMessage: &pb3.Scalars{},
   248  		inputText:    `{"sDouble": -1.79e+309}`,
   249  		wantErr:      `invalid value for double type: -1.79e+309`,
   250  	}, {
   251  		desc:         "double in string exceeds limit",
   252  		inputMessage: &pb3.Scalars{},
   253  		inputText:    `{"sDouble": "1.79e+309"}`,
   254  		wantErr:      `invalid value for double type: "1.79e+309"`,
   255  	}, {
   256  		desc:         "infinites",
   257  		inputMessage: &pb3.Scalars{},
   258  		inputText:    `{"sFloat": "Infinity", "sDouble": "-Infinity"}`,
   259  		wantMessage: &pb3.Scalars{
   260  			SFloat:  float32(math.Inf(+1)),
   261  			SDouble: math.Inf(-1),
   262  		},
   263  	}, {
   264  		desc:         "float string with leading space",
   265  		inputMessage: &pb3.Scalars{},
   266  		inputText:    `{"sFloat": " 1.234"}`,
   267  		wantErr:      `invalid value for float type: " 1.234"`,
   268  	}, {
   269  		desc:         "double string with trailing space",
   270  		inputMessage: &pb3.Scalars{},
   271  		inputText:    `{"sDouble": "5.678 "}`,
   272  		wantErr:      `invalid value for double type: "5.678 "`,
   273  	}, {
   274  		desc:         "not float",
   275  		inputMessage: &pb3.Scalars{},
   276  		inputText:    `{"sFloat": true}`,
   277  		wantErr:      `invalid value for float type: true`,
   278  	}, {
   279  		desc:         "not double",
   280  		inputMessage: &pb3.Scalars{},
   281  		inputText:    `{"sDouble": "not a number"}`,
   282  		wantErr:      `invalid value for double type: "not a number"`,
   283  	}, {
   284  		desc:         "integers",
   285  		inputMessage: &pb3.Scalars{},
   286  		inputText: `{
   287    "sInt32": 1234,
   288    "sInt64": -1234,
   289    "sUint32": 1e2,
   290    "sUint64": 100E-2,
   291    "sSint32": 1.0,
   292    "sSint64": -1.0,
   293    "sFixed32": 1.234e+5,
   294    "sFixed64": 1200E-2,
   295    "sSfixed32": -1.234e05,
   296    "sSfixed64": -1200e-02
   297  }`,
   298  		wantMessage: &pb3.Scalars{
   299  			SInt32:    1234,
   300  			SInt64:    -1234,
   301  			SUint32:   100,
   302  			SUint64:   1,
   303  			SSint32:   1,
   304  			SSint64:   -1,
   305  			SFixed32:  123400,
   306  			SFixed64:  12,
   307  			SSfixed32: -123400,
   308  			SSfixed64: -12,
   309  		},
   310  	}, {
   311  		desc:         "integers in string",
   312  		inputMessage: &pb3.Scalars{},
   313  		inputText: `{
   314    "sInt32": "1234",
   315    "sInt64": "-1234",
   316    "sUint32": "1e2",
   317    "sUint64": "100E-2",
   318    "sSint32": "1.0",
   319    "sSint64": "-1.0",
   320    "sFixed32": "1.234e+5",
   321    "sFixed64": "1200E-2",
   322    "sSfixed32": "-1.234e05",
   323    "sSfixed64": "-1200e-02"
   324  }`,
   325  		wantMessage: &pb3.Scalars{
   326  			SInt32:    1234,
   327  			SInt64:    -1234,
   328  			SUint32:   100,
   329  			SUint64:   1,
   330  			SSint32:   1,
   331  			SSint64:   -1,
   332  			SFixed32:  123400,
   333  			SFixed64:  12,
   334  			SSfixed32: -123400,
   335  			SSfixed64: -12,
   336  		},
   337  	}, {
   338  		desc:         "integers in escaped string",
   339  		inputMessage: &pb3.Scalars{},
   340  		inputText:    `{"sInt32": "\u0031\u0032"}`,
   341  		wantMessage: &pb3.Scalars{
   342  			SInt32: 12,
   343  		},
   344  	}, {
   345  		desc:         "integer string with leading space",
   346  		inputMessage: &pb3.Scalars{},
   347  		inputText:    `{"sInt32": " 1234"}`,
   348  		wantErr:      `invalid value for int32 type: " 1234"`,
   349  	}, {
   350  		desc:         "integer string with trailing space",
   351  		inputMessage: &pb3.Scalars{},
   352  		inputText:    `{"sUint32": "1e2 "}`,
   353  		wantErr:      `invalid value for uint32 type: "1e2 "`,
   354  	}, {
   355  		desc:         "number is not an integer",
   356  		inputMessage: &pb3.Scalars{},
   357  		inputText:    `{"sInt32": 1.001}`,
   358  		wantErr:      `invalid value for int32 type: 1.001`,
   359  	}, {
   360  		desc:         "32-bit int exceeds limit",
   361  		inputMessage: &pb3.Scalars{},
   362  		inputText:    `{"sInt32": 2e10}`,
   363  		wantErr:      `invalid value for int32 type: 2e10`,
   364  	}, {
   365  		desc:         "64-bit int exceeds limit",
   366  		inputMessage: &pb3.Scalars{},
   367  		inputText:    `{"sSfixed64": -9e19}`,
   368  		wantErr:      `invalid value for sfixed64 type: -9e19`,
   369  	}, {
   370  		desc:         "not integer",
   371  		inputMessage: &pb3.Scalars{},
   372  		inputText:    `{"sInt32": "not a number"}`,
   373  		wantErr:      `invalid value for int32 type: "not a number"`,
   374  	}, {
   375  		desc:         "not unsigned integer",
   376  		inputMessage: &pb3.Scalars{},
   377  		inputText:    `{"sUint32": "not a number"}`,
   378  		wantErr:      `invalid value for uint32 type: "not a number"`,
   379  	}, {
   380  		desc:         "number is not an unsigned integer",
   381  		inputMessage: &pb3.Scalars{},
   382  		inputText:    `{"sUint32": -1}`,
   383  		wantErr:      `invalid value for uint32 type: -1`,
   384  	}, {
   385  		desc:         "string",
   386  		inputMessage: &pb2.Scalars{},
   387  		inputText:    `{"optString": "谷歌"}`,
   388  		wantMessage: &pb2.Scalars{
   389  			OptString: proto.String("谷歌"),
   390  		},
   391  	}, {
   392  		desc:         "string with invalid UTF-8",
   393  		inputMessage: &pb3.Scalars{},
   394  		inputText:    "{\"sString\": \"\xff\"}",
   395  		wantErr:      `(line 1:13): invalid UTF-8 in string`,
   396  	}, {
   397  		desc:         "not string",
   398  		inputMessage: &pb2.Scalars{},
   399  		inputText:    `{"optString": 42}`,
   400  		wantErr:      `invalid value for string type: 42`,
   401  	}, {
   402  		desc:         "bytes",
   403  		inputMessage: &pb3.Scalars{},
   404  		inputText:    `{"sBytes": "aGVsbG8gd29ybGQ"}`,
   405  		wantMessage: &pb3.Scalars{
   406  			SBytes: []byte("hello world"),
   407  		},
   408  	}, {
   409  		desc:         "bytes padded",
   410  		inputMessage: &pb3.Scalars{},
   411  		inputText:    `{"sBytes": "aGVsbG8gd29ybGQ="}`,
   412  		wantMessage: &pb3.Scalars{
   413  			SBytes: []byte("hello world"),
   414  		},
   415  	}, {
   416  		desc:         "not bytes",
   417  		inputMessage: &pb3.Scalars{},
   418  		inputText:    `{"sBytes": true}`,
   419  		wantErr:      `invalid value for bytes type: true`,
   420  	}, {
   421  		desc:         "proto2 enum",
   422  		inputMessage: &pb2.Enums{},
   423  		inputText: `{
   424    "optEnum": "ONE",
   425    "optNestedEnum": "UNO"
   426  }`,
   427  		wantMessage: &pb2.Enums{
   428  			OptEnum:       pb2.Enum_ONE.Enum(),
   429  			OptNestedEnum: pb2.Enums_UNO.Enum(),
   430  		},
   431  	}, {
   432  		desc:         "proto3 enum",
   433  		inputMessage: &pb3.Enums{},
   434  		inputText: `{
   435    "sEnum": "ONE",
   436    "sNestedEnum": "DIEZ"
   437  }`,
   438  		wantMessage: &pb3.Enums{
   439  			SEnum:       pb3.Enum_ONE,
   440  			SNestedEnum: pb3.Enums_DIEZ,
   441  		},
   442  	}, {
   443  		desc:         "enum numeric value",
   444  		inputMessage: &pb3.Enums{},
   445  		inputText: `{
   446    "sEnum": 2,
   447    "sNestedEnum": 2
   448  }`,
   449  		wantMessage: &pb3.Enums{
   450  			SEnum:       pb3.Enum_TWO,
   451  			SNestedEnum: pb3.Enums_DOS,
   452  		},
   453  	}, {
   454  		desc:         "enum unnamed numeric value",
   455  		inputMessage: &pb3.Enums{},
   456  		inputText: `{
   457    "sEnum": 101,
   458    "sNestedEnum": -101
   459  }`,
   460  		wantMessage: &pb3.Enums{
   461  			SEnum:       101,
   462  			SNestedEnum: -101,
   463  		},
   464  	}, {
   465  		desc:         "enum set to number string",
   466  		inputMessage: &pb3.Enums{},
   467  		inputText: `{
   468    "sEnum": "1"
   469  }`,
   470  		wantErr: `invalid value for enum type: "1"`,
   471  	}, {
   472  		desc:         "enum set to invalid named",
   473  		inputMessage: &pb3.Enums{},
   474  		inputText: `{
   475    "sEnum": "UNNAMED"
   476  }`,
   477  		wantErr: `invalid value for enum type: "UNNAMED"`,
   478  	}, {
   479  		desc:         "enum set to not enum",
   480  		inputMessage: &pb3.Enums{},
   481  		inputText: `{
   482    "sEnum": true
   483  }`,
   484  		wantErr: `invalid value for enum type: true`,
   485  	}, {
   486  		desc:         "enum set to JSON null",
   487  		inputMessage: &pb3.Enums{},
   488  		inputText: `{
   489    "sEnum": null
   490  }`,
   491  		wantMessage: &pb3.Enums{},
   492  	}, {
   493  		desc:         "proto name",
   494  		inputMessage: &pb3.JSONNames{},
   495  		inputText: `{
   496    "s_string": "proto name used"
   497  }`,
   498  		wantMessage: &pb3.JSONNames{
   499  			SString: "proto name used",
   500  		},
   501  	}, {
   502  		desc:         "proto group name",
   503  		inputMessage: &pb2.Nests{},
   504  		inputText: `{
   505  		"OptGroup": {"optString": "hello"},
   506  		"RptGroup": [{"rptString": ["goodbye"]}]
   507  	}`,
   508  		wantMessage: &pb2.Nests{
   509  			Optgroup: &pb2.Nests_OptGroup{OptString: proto.String("hello")},
   510  			Rptgroup: []*pb2.Nests_RptGroup{{RptString: []string{"goodbye"}}},
   511  		},
   512  	}, {
   513  		desc:         "json_name",
   514  		inputMessage: &pb3.JSONNames{},
   515  		inputText: `{
   516    "foo_bar": "json_name used"
   517  }`,
   518  		wantMessage: &pb3.JSONNames{
   519  			SString: "json_name used",
   520  		},
   521  	}, {
   522  		desc:         "camelCase name",
   523  		inputMessage: &pb3.JSONNames{},
   524  		inputText: `{
   525    "sString": "camelcase used"
   526  }`,
   527  		wantErr: `unknown field "sString"`,
   528  	}, {
   529  		desc:         "proto name and json_name",
   530  		inputMessage: &pb3.JSONNames{},
   531  		inputText: `{
   532    "foo_bar": "json_name used",
   533    "s_string": "proto name used"
   534  }`,
   535  		wantErr: `(line 3:3): duplicate field "s_string"`,
   536  	}, {
   537  		desc:         "duplicate field names",
   538  		inputMessage: &pb3.JSONNames{},
   539  		inputText: `{
   540    "foo_bar": "one",
   541    "foo_bar": "two",
   542  }`,
   543  		wantErr: `(line 3:3): duplicate field "foo_bar"`,
   544  	}, {
   545  		desc:         "null message",
   546  		inputMessage: &pb2.Nests{},
   547  		inputText:    "null",
   548  		wantErr:      `unexpected token null`,
   549  	}, {
   550  		desc:         "proto2 nested message not set",
   551  		inputMessage: &pb2.Nests{},
   552  		inputText:    "{}",
   553  		wantMessage:  &pb2.Nests{},
   554  	}, {
   555  		desc:         "proto2 nested message set to null",
   556  		inputMessage: &pb2.Nests{},
   557  		inputText: `{
   558    "optNested": null,
   559    "optgroup": null
   560  }`,
   561  		wantMessage: &pb2.Nests{},
   562  	}, {
   563  		desc:         "proto2 nested message set to empty",
   564  		inputMessage: &pb2.Nests{},
   565  		inputText: `{
   566    "optNested": {},
   567    "optgroup": {}
   568  }`,
   569  		wantMessage: &pb2.Nests{
   570  			OptNested: &pb2.Nested{},
   571  			Optgroup:  &pb2.Nests_OptGroup{},
   572  		},
   573  	}, {
   574  		desc:         "proto2 nested messages",
   575  		inputMessage: &pb2.Nests{},
   576  		inputText: `{
   577    "optNested": {
   578      "optString": "nested message",
   579      "optNested": {
   580        "optString": "another nested message"
   581      }
   582    }
   583  }`,
   584  		wantMessage: &pb2.Nests{
   585  			OptNested: &pb2.Nested{
   586  				OptString: proto.String("nested message"),
   587  				OptNested: &pb2.Nested{
   588  					OptString: proto.String("another nested message"),
   589  				},
   590  			},
   591  		},
   592  	}, {
   593  		desc:         "proto2 groups",
   594  		inputMessage: &pb2.Nests{},
   595  		inputText: `{
   596    "optgroup": {
   597      "optString": "inside a group",
   598      "optNested": {
   599        "optString": "nested message inside a group"
   600      },
   601      "optnestedgroup": {
   602        "optFixed32": 47
   603      }
   604    }
   605  }`,
   606  		wantMessage: &pb2.Nests{
   607  			Optgroup: &pb2.Nests_OptGroup{
   608  				OptString: proto.String("inside a group"),
   609  				OptNested: &pb2.Nested{
   610  					OptString: proto.String("nested message inside a group"),
   611  				},
   612  				Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
   613  					OptFixed32: proto.Uint32(47),
   614  				},
   615  			},
   616  		},
   617  	}, {
   618  		desc:         "proto3 nested message not set",
   619  		inputMessage: &pb3.Nests{},
   620  		inputText:    "{}",
   621  		wantMessage:  &pb3.Nests{},
   622  	}, {
   623  		desc:         "proto3 nested message set to null",
   624  		inputMessage: &pb3.Nests{},
   625  		inputText:    `{"sNested": null}`,
   626  		wantMessage:  &pb3.Nests{},
   627  	}, {
   628  		desc:         "proto3 nested message set to empty",
   629  		inputMessage: &pb3.Nests{},
   630  		inputText:    `{"sNested": {}}`,
   631  		wantMessage: &pb3.Nests{
   632  			SNested: &pb3.Nested{},
   633  		},
   634  	}, {
   635  		desc:         "proto3 nested message",
   636  		inputMessage: &pb3.Nests{},
   637  		inputText: `{
   638    "sNested": {
   639      "sString": "nested message",
   640      "sNested": {
   641        "sString": "another nested message"
   642      }
   643    }
   644  }`,
   645  		wantMessage: &pb3.Nests{
   646  			SNested: &pb3.Nested{
   647  				SString: "nested message",
   648  				SNested: &pb3.Nested{
   649  					SString: "another nested message",
   650  				},
   651  			},
   652  		},
   653  	}, {
   654  		desc:         "message set to non-message",
   655  		inputMessage: &pb3.Nests{},
   656  		inputText:    `"not valid"`,
   657  		wantErr:      `unexpected token "not valid"`,
   658  	}, {
   659  		desc:         "nested message set to non-message",
   660  		inputMessage: &pb3.Nests{},
   661  		inputText:    `{"sNested": true}`,
   662  		wantErr:      `(line 1:13): unexpected token true`,
   663  	}, {
   664  		desc:         "oneof not set",
   665  		inputMessage: &pb3.Oneofs{},
   666  		inputText:    "{}",
   667  		wantMessage:  &pb3.Oneofs{},
   668  	}, {
   669  		desc:         "oneof set to empty string",
   670  		inputMessage: &pb3.Oneofs{},
   671  		inputText:    `{"oneofString": ""}`,
   672  		wantMessage: &pb3.Oneofs{
   673  			Union: &pb3.Oneofs_OneofString{},
   674  		},
   675  	}, {
   676  		desc:         "oneof set to string",
   677  		inputMessage: &pb3.Oneofs{},
   678  		inputText:    `{"oneofString": "hello"}`,
   679  		wantMessage: &pb3.Oneofs{
   680  			Union: &pb3.Oneofs_OneofString{
   681  				OneofString: "hello",
   682  			},
   683  		},
   684  	}, {
   685  		desc:         "oneof set to enum",
   686  		inputMessage: &pb3.Oneofs{},
   687  		inputText:    `{"oneofEnum": "ZERO"}`,
   688  		wantMessage: &pb3.Oneofs{
   689  			Union: &pb3.Oneofs_OneofEnum{
   690  				OneofEnum: pb3.Enum_ZERO,
   691  			},
   692  		},
   693  	}, {
   694  		desc:         "oneof set to empty message",
   695  		inputMessage: &pb3.Oneofs{},
   696  		inputText:    `{"oneofNested": {}}`,
   697  		wantMessage: &pb3.Oneofs{
   698  			Union: &pb3.Oneofs_OneofNested{
   699  				OneofNested: &pb3.Nested{},
   700  			},
   701  		},
   702  	}, {
   703  		desc:         "oneof set to message",
   704  		inputMessage: &pb3.Oneofs{},
   705  		inputText: `{
   706    "oneofNested": {
   707      "sString": "nested message"
   708    }
   709  }`,
   710  		wantMessage: &pb3.Oneofs{
   711  			Union: &pb3.Oneofs_OneofNested{
   712  				OneofNested: &pb3.Nested{
   713  					SString: "nested message",
   714  				},
   715  			},
   716  		},
   717  	}, {
   718  		desc:         "oneof set to more than one field",
   719  		inputMessage: &pb3.Oneofs{},
   720  		inputText: `{
   721    "oneofEnum": "ZERO",
   722    "oneofString": "hello"
   723  }`,
   724  		wantErr: `(line 3:3): error parsing "oneofString", oneof pb3.Oneofs.union is already set`,
   725  	}, {
   726  		desc:         "oneof set to null and value",
   727  		inputMessage: &pb3.Oneofs{},
   728  		inputText: `{
   729    "oneofEnum": "ZERO",
   730    "oneofString": null
   731  }`,
   732  		wantMessage: &pb3.Oneofs{
   733  			Union: &pb3.Oneofs_OneofEnum{
   734  				OneofEnum: pb3.Enum_ZERO,
   735  			},
   736  		},
   737  	}, {
   738  		desc:         "repeated null fields",
   739  		inputMessage: &pb2.Repeats{},
   740  		inputText: `{
   741    "rptString": null,
   742    "rptInt32" : null,
   743    "rptFloat" : null,
   744    "rptBytes" : null
   745  }`,
   746  		wantMessage: &pb2.Repeats{},
   747  	}, {
   748  		desc:         "repeated scalars",
   749  		inputMessage: &pb2.Repeats{},
   750  		inputText: `{
   751    "rptString": ["hello", "world"],
   752    "rptInt32" : [-1, 0, 1],
   753    "rptBool"  : [false, true]
   754  }`,
   755  		wantMessage: &pb2.Repeats{
   756  			RptString: []string{"hello", "world"},
   757  			RptInt32:  []int32{-1, 0, 1},
   758  			RptBool:   []bool{false, true},
   759  		},
   760  	}, {
   761  		desc:         "repeated enums",
   762  		inputMessage: &pb2.Enums{},
   763  		inputText: `{
   764    "rptEnum"      : ["TEN", 1, 42],
   765    "rptNestedEnum": ["DOS", 2, -47]
   766  }`,
   767  		wantMessage: &pb2.Enums{
   768  			RptEnum:       []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
   769  			RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
   770  		},
   771  	}, {
   772  		desc:         "repeated messages",
   773  		inputMessage: &pb2.Nests{},
   774  		inputText: `{
   775    "rptNested": [
   776      {
   777        "optString": "repeat nested one"
   778      },
   779      {
   780        "optString": "repeat nested two",
   781        "optNested": {
   782          "optString": "inside repeat nested two"
   783        }
   784      },
   785      {}
   786    ]
   787  }`,
   788  		wantMessage: &pb2.Nests{
   789  			RptNested: []*pb2.Nested{
   790  				{
   791  					OptString: proto.String("repeat nested one"),
   792  				},
   793  				{
   794  					OptString: proto.String("repeat nested two"),
   795  					OptNested: &pb2.Nested{
   796  						OptString: proto.String("inside repeat nested two"),
   797  					},
   798  				},
   799  				{},
   800  			},
   801  		},
   802  	}, {
   803  		desc:         "repeated groups",
   804  		inputMessage: &pb2.Nests{},
   805  		inputText: `{
   806    "rptgroup": [
   807      {
   808        "rptString": ["hello", "world"]
   809      },
   810      {}
   811    ]
   812  }
   813  `,
   814  		wantMessage: &pb2.Nests{
   815  			Rptgroup: []*pb2.Nests_RptGroup{
   816  				{
   817  					RptString: []string{"hello", "world"},
   818  				},
   819  				{},
   820  			},
   821  		},
   822  	}, {
   823  		desc:         "repeated string contains invalid UTF8",
   824  		inputMessage: &pb2.Repeats{},
   825  		inputText:    `{"rptString": ["` + "abc\xff" + `"]}`,
   826  		wantErr:      `invalid UTF-8`,
   827  	}, {
   828  		desc:         "repeated messages contain invalid UTF8",
   829  		inputMessage: &pb2.Nests{},
   830  		inputText:    `{"rptNested": [{"optString": "` + "abc\xff" + `"}]}`,
   831  		wantErr:      `invalid UTF-8`,
   832  	}, {
   833  		desc:         "repeated scalars contain invalid type",
   834  		inputMessage: &pb2.Repeats{},
   835  		inputText:    `{"rptString": ["hello", null, "world"]}`,
   836  		wantErr:      `invalid value for string type: null`,
   837  	}, {
   838  		desc:         "repeated messages contain invalid type",
   839  		inputMessage: &pb2.Nests{},
   840  		inputText:    `{"rptNested": [{}, null]}`,
   841  		wantErr:      `unexpected token null`,
   842  	}, {
   843  		desc:         "map fields 1",
   844  		inputMessage: &pb3.Maps{},
   845  		inputText: `{
   846    "int32ToStr": {
   847      "-101": "-101",
   848  	"0"   : "zero",
   849  	"255" : "0xff"
   850    },
   851    "boolToUint32": {
   852      "false": 101,
   853  	"true" : "42"
   854    }
   855  }`,
   856  		wantMessage: &pb3.Maps{
   857  			Int32ToStr: map[int32]string{
   858  				-101: "-101",
   859  				0xff: "0xff",
   860  				0:    "zero",
   861  			},
   862  			BoolToUint32: map[bool]uint32{
   863  				true:  42,
   864  				false: 101,
   865  			},
   866  		},
   867  	}, {
   868  		desc:         "map fields 2",
   869  		inputMessage: &pb3.Maps{},
   870  		inputText: `{
   871    "uint64ToEnum": {
   872      "1" : "ONE",
   873  	"2" : 2,
   874  	"10": 101
   875    }
   876  }`,
   877  		wantMessage: &pb3.Maps{
   878  			Uint64ToEnum: map[uint64]pb3.Enum{
   879  				1:  pb3.Enum_ONE,
   880  				2:  pb3.Enum_TWO,
   881  				10: 101,
   882  			},
   883  		},
   884  	}, {
   885  		desc:         "map fields 3",
   886  		inputMessage: &pb3.Maps{},
   887  		inputText: `{
   888    "strToNested": {
   889      "nested_one": {
   890  	  "sString": "nested in a map"
   891      },
   892      "nested_two": {}
   893    }
   894  }`,
   895  		wantMessage: &pb3.Maps{
   896  			StrToNested: map[string]*pb3.Nested{
   897  				"nested_one": {
   898  					SString: "nested in a map",
   899  				},
   900  				"nested_two": {},
   901  			},
   902  		},
   903  	}, {
   904  		desc:         "map fields 4",
   905  		inputMessage: &pb3.Maps{},
   906  		inputText: `{
   907    "strToOneofs": {
   908      "nested": {
   909  	  "oneofNested": {
   910  	    "sString": "nested oneof in map field value"
   911        }
   912  	},
   913  	"string": {
   914        "oneofString": "hello"
   915      }
   916    }
   917  }`,
   918  		wantMessage: &pb3.Maps{
   919  			StrToOneofs: map[string]*pb3.Oneofs{
   920  				"string": {
   921  					Union: &pb3.Oneofs_OneofString{
   922  						OneofString: "hello",
   923  					},
   924  				},
   925  				"nested": {
   926  					Union: &pb3.Oneofs_OneofNested{
   927  						OneofNested: &pb3.Nested{
   928  							SString: "nested oneof in map field value",
   929  						},
   930  					},
   931  				},
   932  			},
   933  		},
   934  	}, {
   935  		desc:         "map contains duplicate keys",
   936  		inputMessage: &pb3.Maps{},
   937  		inputText: `{
   938    "int32ToStr": {
   939      "0": "cero",
   940      "0": "zero"
   941    }
   942  }
   943  `,
   944  		wantErr: `(line 4:5): duplicate map key "0"`,
   945  	}, {
   946  		desc:         "map key empty string",
   947  		inputMessage: &pb3.Maps{},
   948  		inputText: `{
   949    "strToNested": {
   950      "": {}
   951    }
   952  }`,
   953  		wantMessage: &pb3.Maps{
   954  			StrToNested: map[string]*pb3.Nested{
   955  				"": {},
   956  			},
   957  		},
   958  	}, {
   959  		desc:         "map contains invalid key 1",
   960  		inputMessage: &pb3.Maps{},
   961  		inputText: `{
   962    "int32ToStr": {
   963      "invalid": "cero"
   964    }
   965  }`,
   966  		wantErr: `invalid value for int32 key: "invalid"`,
   967  	}, {
   968  		desc:         "map contains invalid key 2",
   969  		inputMessage: &pb3.Maps{},
   970  		inputText: `{
   971    "int32ToStr": {
   972      "1.02": "float"
   973    }
   974  }`,
   975  		wantErr: `invalid value for int32 key: "1.02"`,
   976  	}, {
   977  		desc:         "map contains invalid key 3",
   978  		inputMessage: &pb3.Maps{},
   979  		inputText: `{
   980    "int32ToStr": {
   981      "2147483648": "exceeds 32-bit integer max limit"
   982    }
   983  }`,
   984  		wantErr: `invalid value for int32 key: "2147483648"`,
   985  	}, {
   986  		desc:         "map contains invalid key 4",
   987  		inputMessage: &pb3.Maps{},
   988  		inputText: `{
   989    "uint64ToEnum": {
   990      "-1": 0
   991    }
   992  }`,
   993  		wantErr: `invalid value for uint64 key: "-1"`,
   994  	}, {
   995  		desc:         "map contains invalid value",
   996  		inputMessage: &pb3.Maps{},
   997  		inputText: `{
   998    "int32ToStr": {
   999      "101": true
  1000  }`,
  1001  		wantErr: `invalid value for string type: true`,
  1002  	}, {
  1003  		desc:         "map contains null for scalar value",
  1004  		inputMessage: &pb3.Maps{},
  1005  		inputText: `{
  1006    "int32ToStr": {
  1007      "101": null
  1008  }`,
  1009  		wantErr: `invalid value for string type: null`,
  1010  	}, {
  1011  		desc:         "map contains null for message value",
  1012  		inputMessage: &pb3.Maps{},
  1013  		inputText: `{
  1014    "strToNested": {
  1015      "hello": null
  1016    }
  1017  }`,
  1018  		wantErr: `unexpected token null`,
  1019  	}, {
  1020  		desc:         "map contains contains message value with invalid UTF8",
  1021  		inputMessage: &pb3.Maps{},
  1022  		inputText: `{
  1023    "strToNested": {
  1024      "hello": {
  1025        "sString": "` + "abc\xff" + `"
  1026  	}
  1027    }
  1028  }`,
  1029  		wantErr: `invalid UTF-8`,
  1030  	}, {
  1031  		desc:         "map key contains invalid UTF8",
  1032  		inputMessage: &pb3.Maps{},
  1033  		inputText: `{
  1034    "strToNested": {
  1035      "` + "abc\xff" + `": {}
  1036    }
  1037  }`,
  1038  		wantErr: `invalid UTF-8`,
  1039  	}, {
  1040  		desc:         "required fields not set",
  1041  		inputMessage: &pb2.Requireds{},
  1042  		inputText:    `{}`,
  1043  		wantErr:      errors.RequiredNotSet("pb2.Requireds.req_bool").Error(),
  1044  	}, {
  1045  		desc:         "required field set",
  1046  		inputMessage: &pb2.PartialRequired{},
  1047  		inputText: `{
  1048    "reqString": "this is required"
  1049  }`,
  1050  		wantMessage: &pb2.PartialRequired{
  1051  			ReqString: proto.String("this is required"),
  1052  		},
  1053  	}, {
  1054  		desc:         "required fields partially set",
  1055  		inputMessage: &pb2.Requireds{},
  1056  		inputText: `{
  1057    "reqBool": false,
  1058    "reqSfixed64": 42,
  1059    "reqString": "hello",
  1060    "reqEnum": "ONE"
  1061  }`,
  1062  		wantMessage: &pb2.Requireds{
  1063  			ReqBool:     proto.Bool(false),
  1064  			ReqSfixed64: proto.Int64(42),
  1065  			ReqString:   proto.String("hello"),
  1066  			ReqEnum:     pb2.Enum_ONE.Enum(),
  1067  		},
  1068  		wantErr: errors.RequiredNotSet("pb2.Requireds.req_double").Error(),
  1069  	}, {
  1070  		desc:         "required fields partially set with AllowPartial",
  1071  		umo:          protojson.UnmarshalOptions{AllowPartial: true},
  1072  		inputMessage: &pb2.Requireds{},
  1073  		inputText: `{
  1074    "reqBool": false,
  1075    "reqSfixed64": 42,
  1076    "reqString": "hello",
  1077    "reqEnum": "ONE"
  1078  }`,
  1079  		wantMessage: &pb2.Requireds{
  1080  			ReqBool:     proto.Bool(false),
  1081  			ReqSfixed64: proto.Int64(42),
  1082  			ReqString:   proto.String("hello"),
  1083  			ReqEnum:     pb2.Enum_ONE.Enum(),
  1084  		},
  1085  	}, {
  1086  		desc:         "required fields all set",
  1087  		inputMessage: &pb2.Requireds{},
  1088  		inputText: `{
  1089    "reqBool": false,
  1090    "reqSfixed64": 42,
  1091    "reqDouble": 1.23,
  1092    "reqString": "hello",
  1093    "reqEnum": "ONE",
  1094    "reqNested": {}
  1095  }`,
  1096  		wantMessage: &pb2.Requireds{
  1097  			ReqBool:     proto.Bool(false),
  1098  			ReqSfixed64: proto.Int64(42),
  1099  			ReqDouble:   proto.Float64(1.23),
  1100  			ReqString:   proto.String("hello"),
  1101  			ReqEnum:     pb2.Enum_ONE.Enum(),
  1102  			ReqNested:   &pb2.Nested{},
  1103  		},
  1104  	}, {
  1105  		desc:         "indirect required field",
  1106  		inputMessage: &pb2.IndirectRequired{},
  1107  		inputText: `{
  1108    "optNested": {}
  1109  }`,
  1110  		wantMessage: &pb2.IndirectRequired{
  1111  			OptNested: &pb2.NestedWithRequired{},
  1112  		},
  1113  		wantErr: errors.RequiredNotSet("pb2.NestedWithRequired.req_string").Error(),
  1114  	}, {
  1115  		desc:         "indirect required field with AllowPartial",
  1116  		umo:          protojson.UnmarshalOptions{AllowPartial: true},
  1117  		inputMessage: &pb2.IndirectRequired{},
  1118  		inputText: `{
  1119    "optNested": {}
  1120  }`,
  1121  		wantMessage: &pb2.IndirectRequired{
  1122  			OptNested: &pb2.NestedWithRequired{},
  1123  		},
  1124  	}, {
  1125  		desc:         "indirect required field in repeated",
  1126  		inputMessage: &pb2.IndirectRequired{},
  1127  		inputText: `{
  1128    "rptNested": [
  1129      {"reqString": "one"},
  1130      {}
  1131    ]
  1132  }`,
  1133  		wantMessage: &pb2.IndirectRequired{
  1134  			RptNested: []*pb2.NestedWithRequired{
  1135  				{
  1136  					ReqString: proto.String("one"),
  1137  				},
  1138  				{},
  1139  			},
  1140  		},
  1141  		wantErr: errors.RequiredNotSet("pb2.NestedWithRequired.req_string").Error(),
  1142  	}, {
  1143  		desc:         "indirect required field in repeated with AllowPartial",
  1144  		umo:          protojson.UnmarshalOptions{AllowPartial: true},
  1145  		inputMessage: &pb2.IndirectRequired{},
  1146  		inputText: `{
  1147    "rptNested": [
  1148      {"reqString": "one"},
  1149      {}
  1150    ]
  1151  }`,
  1152  		wantMessage: &pb2.IndirectRequired{
  1153  			RptNested: []*pb2.NestedWithRequired{
  1154  				{
  1155  					ReqString: proto.String("one"),
  1156  				},
  1157  				{},
  1158  			},
  1159  		},
  1160  	}, {
  1161  		desc:         "indirect required field in map",
  1162  		inputMessage: &pb2.IndirectRequired{},
  1163  		inputText: `{
  1164    "strToNested": {
  1165      "missing": {},
  1166  	"contains": {
  1167        "reqString": "here"
  1168      }
  1169    }
  1170  }`,
  1171  		wantMessage: &pb2.IndirectRequired{
  1172  			StrToNested: map[string]*pb2.NestedWithRequired{
  1173  				"missing": &pb2.NestedWithRequired{},
  1174  				"contains": &pb2.NestedWithRequired{
  1175  					ReqString: proto.String("here"),
  1176  				},
  1177  			},
  1178  		},
  1179  		wantErr: errors.RequiredNotSet("pb2.NestedWithRequired.req_string").Error(),
  1180  	}, {
  1181  		desc:         "indirect required field in map with AllowPartial",
  1182  		umo:          protojson.UnmarshalOptions{AllowPartial: true},
  1183  		inputMessage: &pb2.IndirectRequired{},
  1184  		inputText: `{
  1185    "strToNested": {
  1186      "missing": {},
  1187  	"contains": {
  1188        "reqString": "here"
  1189      }
  1190    }
  1191  }`,
  1192  		wantMessage: &pb2.IndirectRequired{
  1193  			StrToNested: map[string]*pb2.NestedWithRequired{
  1194  				"missing": &pb2.NestedWithRequired{},
  1195  				"contains": &pb2.NestedWithRequired{
  1196  					ReqString: proto.String("here"),
  1197  				},
  1198  			},
  1199  		},
  1200  	}, {
  1201  		desc:         "indirect required field in oneof",
  1202  		inputMessage: &pb2.IndirectRequired{},
  1203  		inputText: `{
  1204    "oneofNested": {}
  1205  }`,
  1206  		wantMessage: &pb2.IndirectRequired{
  1207  			Union: &pb2.IndirectRequired_OneofNested{
  1208  				OneofNested: &pb2.NestedWithRequired{},
  1209  			},
  1210  		},
  1211  		wantErr: errors.RequiredNotSet("pb2.NestedWithRequired.req_string").Error(),
  1212  	}, {
  1213  		desc:         "indirect required field in oneof with AllowPartial",
  1214  		umo:          protojson.UnmarshalOptions{AllowPartial: true},
  1215  		inputMessage: &pb2.IndirectRequired{},
  1216  		inputText: `{
  1217    "oneofNested": {}
  1218  }`,
  1219  		wantMessage: &pb2.IndirectRequired{
  1220  			Union: &pb2.IndirectRequired_OneofNested{
  1221  				OneofNested: &pb2.NestedWithRequired{},
  1222  			},
  1223  		},
  1224  	}, {
  1225  		desc:         "extensions of non-repeated fields",
  1226  		inputMessage: &pb2.Extensions{},
  1227  		inputText: `{
  1228    "optString": "non-extension field",
  1229    "optBool": true,
  1230    "optInt32": 42,
  1231    "[pb2.opt_ext_bool]": true,
  1232    "[pb2.opt_ext_nested]": {
  1233      "optString": "nested in an extension",
  1234      "optNested": {
  1235        "optString": "another nested in an extension"
  1236      }
  1237    },
  1238    "[pb2.opt_ext_string]": "extension field",
  1239    "[pb2.opt_ext_enum]": "TEN"
  1240  }`,
  1241  		wantMessage: func() proto.Message {
  1242  			m := &pb2.Extensions{
  1243  				OptString: proto.String("non-extension field"),
  1244  				OptBool:   proto.Bool(true),
  1245  				OptInt32:  proto.Int32(42),
  1246  			}
  1247  			proto.SetExtension(m, pb2.E_OptExtBool, true)
  1248  			proto.SetExtension(m, pb2.E_OptExtString, "extension field")
  1249  			proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  1250  			proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  1251  				OptString: proto.String("nested in an extension"),
  1252  				OptNested: &pb2.Nested{
  1253  					OptString: proto.String("another nested in an extension"),
  1254  				},
  1255  			})
  1256  			return m
  1257  		}(),
  1258  	}, {
  1259  		desc:         "extensions of repeated fields",
  1260  		inputMessage: &pb2.Extensions{},
  1261  		inputText: `{
  1262    "[pb2.rpt_ext_enum]": ["TEN", 101, "ONE"],
  1263    "[pb2.rpt_ext_fixed32]": [42, 47],
  1264    "[pb2.rpt_ext_nested]": [
  1265      {"optString": "one"},
  1266  	{"optString": "two"},
  1267  	{"optString": "three"}
  1268    ]
  1269  }`,
  1270  		wantMessage: func() proto.Message {
  1271  			m := &pb2.Extensions{}
  1272  			proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1273  			proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47})
  1274  			proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
  1275  				&pb2.Nested{OptString: proto.String("one")},
  1276  				&pb2.Nested{OptString: proto.String("two")},
  1277  				&pb2.Nested{OptString: proto.String("three")},
  1278  			})
  1279  			return m
  1280  		}(),
  1281  	}, {
  1282  		desc:         "extensions of non-repeated fields in another message",
  1283  		inputMessage: &pb2.Extensions{},
  1284  		inputText: `{
  1285    "[pb2.ExtensionsContainer.opt_ext_bool]": true,
  1286    "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
  1287    "[pb2.ExtensionsContainer.opt_ext_nested]": {
  1288      "optString": "nested in an extension",
  1289      "optNested": {
  1290        "optString": "another nested in an extension"
  1291      }
  1292    },
  1293    "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
  1294  }`,
  1295  		wantMessage: func() proto.Message {
  1296  			m := &pb2.Extensions{}
  1297  			proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  1298  			proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  1299  			proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  1300  			proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  1301  				OptString: proto.String("nested in an extension"),
  1302  				OptNested: &pb2.Nested{
  1303  					OptString: proto.String("another nested in an extension"),
  1304  				},
  1305  			})
  1306  			return m
  1307  		}(),
  1308  	}, {
  1309  		desc:         "extensions of repeated fields in another message",
  1310  		inputMessage: &pb2.Extensions{},
  1311  		inputText: `{
  1312    "optString": "non-extension field",
  1313    "optBool": true,
  1314    "optInt32": 42,
  1315    "[pb2.ExtensionsContainer.rpt_ext_nested]": [
  1316      {"optString": "one"},
  1317      {"optString": "two"},
  1318      {"optString": "three"}
  1319    ],
  1320    "[pb2.ExtensionsContainer.rpt_ext_enum]": ["TEN", 101, "ONE"],
  1321    "[pb2.ExtensionsContainer.rpt_ext_string]": ["hello", "world"]
  1322  }`,
  1323  		wantMessage: func() proto.Message {
  1324  			m := &pb2.Extensions{
  1325  				OptString: proto.String("non-extension field"),
  1326  				OptBool:   proto.Bool(true),
  1327  				OptInt32:  proto.Int32(42),
  1328  			}
  1329  			proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1330  			proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"})
  1331  			proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{
  1332  				&pb2.Nested{OptString: proto.String("one")},
  1333  				&pb2.Nested{OptString: proto.String("two")},
  1334  				&pb2.Nested{OptString: proto.String("three")},
  1335  			})
  1336  			return m
  1337  		}(),
  1338  	}, {
  1339  		desc:         "invalid extension field name",
  1340  		inputMessage: &pb2.Extensions{},
  1341  		inputText:    `{ "[pb2.invalid_message_field]": true }`,
  1342  		wantErr:      `(line 1:3): unknown field "[pb2.invalid_message_field]"`,
  1343  	}, {
  1344  		desc:         "extensions of repeated field contains null",
  1345  		inputMessage: &pb2.Extensions{},
  1346  		inputText: `{
  1347    "[pb2.ExtensionsContainer.rpt_ext_nested]": [
  1348      {"optString": "one"},
  1349      null,
  1350      {"optString": "three"}
  1351    ],
  1352  }`,
  1353  		wantErr: `(line 4:5): unexpected token null`,
  1354  	}, {
  1355  		desc:         "MessageSet",
  1356  		inputMessage: &pb2.MessageSet{},
  1357  		inputText: `{
  1358    "[pb2.MessageSetExtension]": {
  1359      "optString": "a messageset extension"
  1360    },
  1361    "[pb2.MessageSetExtension.ext_nested]": {
  1362      "optString": "just a regular extension"
  1363    },
  1364    "[pb2.MessageSetExtension.not_message_set_extension]": {
  1365      "optString": "not a messageset extension"
  1366    }
  1367  }`,
  1368  		wantMessage: func() proto.Message {
  1369  			m := &pb2.MessageSet{}
  1370  			proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  1371  				OptString: proto.String("a messageset extension"),
  1372  			})
  1373  			proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  1374  				OptString: proto.String("not a messageset extension"),
  1375  			})
  1376  			proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  1377  				OptString: proto.String("just a regular extension"),
  1378  			})
  1379  			return m
  1380  		}(),
  1381  		skip: !flags.ProtoLegacy,
  1382  	}, {
  1383  		desc:         "not real MessageSet 1",
  1384  		inputMessage: &pb2.FakeMessageSet{},
  1385  		inputText: `{
  1386    "[pb2.FakeMessageSetExtension.message_set_extension]": {
  1387      "optString": "not a messageset extension"
  1388    }
  1389  }`,
  1390  		wantMessage: func() proto.Message {
  1391  			m := &pb2.FakeMessageSet{}
  1392  			proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1393  				OptString: proto.String("not a messageset extension"),
  1394  			})
  1395  			return m
  1396  		}(),
  1397  		skip: !flags.ProtoLegacy,
  1398  	}, {
  1399  		desc:         "not real MessageSet 2",
  1400  		inputMessage: &pb2.FakeMessageSet{},
  1401  		inputText: `{
  1402    "[pb2.FakeMessageSetExtension]": {
  1403      "optString": "not a messageset extension"
  1404    }
  1405  }`,
  1406  		wantErr: `unable to resolve "[pb2.FakeMessageSetExtension]": found wrong type`,
  1407  		skip:    !flags.ProtoLegacy,
  1408  	}, {
  1409  		desc:         "not real MessageSet 3",
  1410  		inputMessage: &pb2.MessageSet{},
  1411  		inputText: `{
  1412    "[pb2.message_set_extension]": {
  1413      "optString": "another not a messageset extension"
  1414    }
  1415  }`,
  1416  		wantMessage: func() proto.Message {
  1417  			m := &pb2.MessageSet{}
  1418  			proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1419  				OptString: proto.String("another not a messageset extension"),
  1420  			})
  1421  			return m
  1422  		}(),
  1423  		skip: !flags.ProtoLegacy,
  1424  	}, {
  1425  		desc:         "Empty",
  1426  		inputMessage: &emptypb.Empty{},
  1427  		inputText:    `{}`,
  1428  		wantMessage:  &emptypb.Empty{},
  1429  	}, {
  1430  		desc:         "Empty contains unknown",
  1431  		inputMessage: &emptypb.Empty{},
  1432  		inputText:    `{"unknown": null}`,
  1433  		wantErr:      `unknown field "unknown"`,
  1434  	}, {
  1435  		desc:         "BoolValue false",
  1436  		inputMessage: &wrapperspb.BoolValue{},
  1437  		inputText:    `false`,
  1438  		wantMessage:  &wrapperspb.BoolValue{},
  1439  	}, {
  1440  		desc:         "BoolValue true",
  1441  		inputMessage: &wrapperspb.BoolValue{},
  1442  		inputText:    `true`,
  1443  		wantMessage:  &wrapperspb.BoolValue{Value: true},
  1444  	}, {
  1445  		desc:         "BoolValue invalid value",
  1446  		inputMessage: &wrapperspb.BoolValue{},
  1447  		inputText:    `{}`,
  1448  		wantErr:      `invalid value for bool type: {`,
  1449  	}, {
  1450  		desc:         "Int32Value",
  1451  		inputMessage: &wrapperspb.Int32Value{},
  1452  		inputText:    `42`,
  1453  		wantMessage:  &wrapperspb.Int32Value{Value: 42},
  1454  	}, {
  1455  		desc:         "Int32Value in JSON string",
  1456  		inputMessage: &wrapperspb.Int32Value{},
  1457  		inputText:    `"1.23e3"`,
  1458  		wantMessage:  &wrapperspb.Int32Value{Value: 1230},
  1459  	}, {
  1460  		desc:         "Int64Value",
  1461  		inputMessage: &wrapperspb.Int64Value{},
  1462  		inputText:    `"42"`,
  1463  		wantMessage:  &wrapperspb.Int64Value{Value: 42},
  1464  	}, {
  1465  		desc:         "UInt32Value",
  1466  		inputMessage: &wrapperspb.UInt32Value{},
  1467  		inputText:    `42`,
  1468  		wantMessage:  &wrapperspb.UInt32Value{Value: 42},
  1469  	}, {
  1470  		desc:         "UInt64Value",
  1471  		inputMessage: &wrapperspb.UInt64Value{},
  1472  		inputText:    `"42"`,
  1473  		wantMessage:  &wrapperspb.UInt64Value{Value: 42},
  1474  	}, {
  1475  		desc:         "FloatValue",
  1476  		inputMessage: &wrapperspb.FloatValue{},
  1477  		inputText:    `1.02`,
  1478  		wantMessage:  &wrapperspb.FloatValue{Value: 1.02},
  1479  	}, {
  1480  		desc:         "FloatValue exceeds max limit",
  1481  		inputMessage: &wrapperspb.FloatValue{},
  1482  		inputText:    `1.23e+40`,
  1483  		wantErr:      `invalid value for float type: 1.23e+40`,
  1484  	}, {
  1485  		desc:         "FloatValue Infinity",
  1486  		inputMessage: &wrapperspb.FloatValue{},
  1487  		inputText:    `"-Infinity"`,
  1488  		wantMessage:  &wrapperspb.FloatValue{Value: float32(math.Inf(-1))},
  1489  	}, {
  1490  		desc:         "DoubleValue",
  1491  		inputMessage: &wrapperspb.DoubleValue{},
  1492  		inputText:    `1.02`,
  1493  		wantMessage:  &wrapperspb.DoubleValue{Value: 1.02},
  1494  	}, {
  1495  		desc:         "DoubleValue Infinity",
  1496  		inputMessage: &wrapperspb.DoubleValue{},
  1497  		inputText:    `"Infinity"`,
  1498  		wantMessage:  &wrapperspb.DoubleValue{Value: math.Inf(+1)},
  1499  	}, {
  1500  		desc:         "StringValue empty",
  1501  		inputMessage: &wrapperspb.StringValue{},
  1502  		inputText:    `""`,
  1503  		wantMessage:  &wrapperspb.StringValue{},
  1504  	}, {
  1505  		desc:         "StringValue",
  1506  		inputMessage: &wrapperspb.StringValue{},
  1507  		inputText:    `"谷歌"`,
  1508  		wantMessage:  &wrapperspb.StringValue{Value: "谷歌"},
  1509  	}, {
  1510  		desc:         "StringValue with invalid UTF8 error",
  1511  		inputMessage: &wrapperspb.StringValue{},
  1512  		inputText:    "\"abc\xff\"",
  1513  		wantErr:      `invalid UTF-8`,
  1514  	}, {
  1515  		desc:         "StringValue field with invalid UTF8 error",
  1516  		inputMessage: &pb2.KnownTypes{},
  1517  		inputText:    "{\n  \"optString\": \"abc\xff\"\n}",
  1518  		wantErr:      `invalid UTF-8`,
  1519  	}, {
  1520  		desc:         "NullValue field with JSON null",
  1521  		inputMessage: &pb2.KnownTypes{},
  1522  		inputText: `{
  1523    "optNull": null
  1524  }`,
  1525  		wantMessage: &pb2.KnownTypes{OptNull: new(structpb.NullValue)},
  1526  	}, {
  1527  		desc:         "NullValue field with string",
  1528  		inputMessage: &pb2.KnownTypes{},
  1529  		inputText: `{
  1530    "optNull": "NULL_VALUE"
  1531  }`,
  1532  		wantMessage: &pb2.KnownTypes{OptNull: new(structpb.NullValue)},
  1533  	}, {
  1534  		desc:         "BytesValue",
  1535  		inputMessage: &wrapperspb.BytesValue{},
  1536  		inputText:    `"aGVsbG8="`,
  1537  		wantMessage:  &wrapperspb.BytesValue{Value: []byte("hello")},
  1538  	}, {
  1539  		desc:         "Value null",
  1540  		inputMessage: &structpb.Value{},
  1541  		inputText:    `null`,
  1542  		wantMessage:  &structpb.Value{Kind: &structpb.Value_NullValue{}},
  1543  	}, {
  1544  		desc:         "Value field null",
  1545  		inputMessage: &pb2.KnownTypes{},
  1546  		inputText: `{
  1547    "optValue": null
  1548  }`,
  1549  		wantMessage: &pb2.KnownTypes{
  1550  			OptValue: &structpb.Value{Kind: &structpb.Value_NullValue{}},
  1551  		},
  1552  	}, {
  1553  		desc:         "Value bool",
  1554  		inputMessage: &structpb.Value{},
  1555  		inputText:    `false`,
  1556  		wantMessage:  &structpb.Value{Kind: &structpb.Value_BoolValue{}},
  1557  	}, {
  1558  		desc:         "Value field bool",
  1559  		inputMessage: &pb2.KnownTypes{},
  1560  		inputText: `{
  1561    "optValue": true
  1562  }`,
  1563  		wantMessage: &pb2.KnownTypes{
  1564  			OptValue: &structpb.Value{Kind: &structpb.Value_BoolValue{true}},
  1565  		},
  1566  	}, {
  1567  		desc:         "Value number",
  1568  		inputMessage: &structpb.Value{},
  1569  		inputText:    `1.02`,
  1570  		wantMessage:  &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}},
  1571  	}, {
  1572  		desc:         "Value field number",
  1573  		inputMessage: &pb2.KnownTypes{},
  1574  		inputText: `{
  1575    "optValue": 1.02
  1576  }`,
  1577  		wantMessage: &pb2.KnownTypes{
  1578  			OptValue: &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}},
  1579  		},
  1580  	}, {
  1581  		desc:         "Value string",
  1582  		inputMessage: &structpb.Value{},
  1583  		inputText:    `"hello"`,
  1584  		wantMessage:  &structpb.Value{Kind: &structpb.Value_StringValue{"hello"}},
  1585  	}, {
  1586  		desc:         "Value string with invalid UTF8",
  1587  		inputMessage: &structpb.Value{},
  1588  		inputText:    "\"\xff\"",
  1589  		wantErr:      `invalid UTF-8`,
  1590  	}, {
  1591  		desc:         "Value field string",
  1592  		inputMessage: &pb2.KnownTypes{},
  1593  		inputText: `{
  1594    "optValue": "NaN"
  1595  }`,
  1596  		wantMessage: &pb2.KnownTypes{
  1597  			OptValue: &structpb.Value{Kind: &structpb.Value_StringValue{"NaN"}},
  1598  		},
  1599  	}, {
  1600  		desc:         "Value field string with invalid UTF8",
  1601  		inputMessage: &pb2.KnownTypes{},
  1602  		inputText: `{
  1603    "optValue": "` + "\xff" + `"
  1604  }`,
  1605  		wantErr: `invalid UTF-8`,
  1606  	}, {
  1607  		desc:         "Value empty struct",
  1608  		inputMessage: &structpb.Value{},
  1609  		inputText:    `{}`,
  1610  		wantMessage: &structpb.Value{
  1611  			Kind: &structpb.Value_StructValue{
  1612  				&structpb.Struct{Fields: map[string]*structpb.Value{}},
  1613  			},
  1614  		},
  1615  	}, {
  1616  		desc:         "Value struct",
  1617  		inputMessage: &structpb.Value{},
  1618  		inputText: `{
  1619    "string": "hello",
  1620    "number": 123,
  1621    "null": null,
  1622    "bool": false,
  1623    "struct": {
  1624      "string": "world"
  1625    },
  1626    "list": []
  1627  }`,
  1628  		wantMessage: &structpb.Value{
  1629  			Kind: &structpb.Value_StructValue{
  1630  				&structpb.Struct{
  1631  					Fields: map[string]*structpb.Value{
  1632  						"string": {Kind: &structpb.Value_StringValue{"hello"}},
  1633  						"number": {Kind: &structpb.Value_NumberValue{123}},
  1634  						"null":   {Kind: &structpb.Value_NullValue{}},
  1635  						"bool":   {Kind: &structpb.Value_BoolValue{false}},
  1636  						"struct": {
  1637  							Kind: &structpb.Value_StructValue{
  1638  								&structpb.Struct{
  1639  									Fields: map[string]*structpb.Value{
  1640  										"string": {Kind: &structpb.Value_StringValue{"world"}},
  1641  									},
  1642  								},
  1643  							},
  1644  						},
  1645  						"list": {
  1646  							Kind: &structpb.Value_ListValue{&structpb.ListValue{}},
  1647  						},
  1648  					},
  1649  				},
  1650  			},
  1651  		},
  1652  	}, {
  1653  		desc:         "Value struct with invalid UTF8 string",
  1654  		inputMessage: &structpb.Value{},
  1655  		inputText:    "{\"string\": \"abc\xff\"}",
  1656  		wantErr:      `invalid UTF-8`,
  1657  	}, {
  1658  		desc:         "Value field struct",
  1659  		inputMessage: &pb2.KnownTypes{},
  1660  		inputText: `{
  1661    "optValue": {
  1662      "string": "hello"
  1663    }
  1664  }`,
  1665  		wantMessage: &pb2.KnownTypes{
  1666  			OptValue: &structpb.Value{
  1667  				Kind: &structpb.Value_StructValue{
  1668  					&structpb.Struct{
  1669  						Fields: map[string]*structpb.Value{
  1670  							"string": {Kind: &structpb.Value_StringValue{"hello"}},
  1671  						},
  1672  					},
  1673  				},
  1674  			},
  1675  		},
  1676  	}, {
  1677  		desc:         "Value empty list",
  1678  		inputMessage: &structpb.Value{},
  1679  		inputText:    `[]`,
  1680  		wantMessage: &structpb.Value{
  1681  			Kind: &structpb.Value_ListValue{
  1682  				&structpb.ListValue{Values: []*structpb.Value{}},
  1683  			},
  1684  		},
  1685  	}, {
  1686  		desc:         "Value list",
  1687  		inputMessage: &structpb.Value{},
  1688  		inputText: `[
  1689    "string",
  1690    123,
  1691    null,
  1692    true,
  1693    {},
  1694    [
  1695      "string",
  1696  	1.23,
  1697  	null,
  1698  	false
  1699    ]
  1700  ]`,
  1701  		wantMessage: &structpb.Value{
  1702  			Kind: &structpb.Value_ListValue{
  1703  				&structpb.ListValue{
  1704  					Values: []*structpb.Value{
  1705  						{Kind: &structpb.Value_StringValue{"string"}},
  1706  						{Kind: &structpb.Value_NumberValue{123}},
  1707  						{Kind: &structpb.Value_NullValue{}},
  1708  						{Kind: &structpb.Value_BoolValue{true}},
  1709  						{Kind: &structpb.Value_StructValue{&structpb.Struct{}}},
  1710  						{
  1711  							Kind: &structpb.Value_ListValue{
  1712  								&structpb.ListValue{
  1713  									Values: []*structpb.Value{
  1714  										{Kind: &structpb.Value_StringValue{"string"}},
  1715  										{Kind: &structpb.Value_NumberValue{1.23}},
  1716  										{Kind: &structpb.Value_NullValue{}},
  1717  										{Kind: &structpb.Value_BoolValue{false}},
  1718  									},
  1719  								},
  1720  							},
  1721  						},
  1722  					},
  1723  				},
  1724  			},
  1725  		},
  1726  	}, {
  1727  		desc:         "Value list with invalid UTF8 string",
  1728  		inputMessage: &structpb.Value{},
  1729  		inputText:    "[\"abc\xff\"]",
  1730  		wantErr:      `invalid UTF-8`,
  1731  	}, {
  1732  		desc:         "Value field list with invalid UTF8 string",
  1733  		inputMessage: &pb2.KnownTypes{},
  1734  		inputText: `{
  1735    "optValue": [ "` + "abc\xff" + `"]
  1736  }`,
  1737  		wantErr: `(line 2:17): invalid UTF-8`,
  1738  	}, {
  1739  		desc:         "Duration empty string",
  1740  		inputMessage: &durationpb.Duration{},
  1741  		inputText:    `""`,
  1742  		wantErr:      `invalid google.protobuf.Duration value ""`,
  1743  	}, {
  1744  		desc:         "Duration with secs",
  1745  		inputMessage: &durationpb.Duration{},
  1746  		inputText:    `"3s"`,
  1747  		wantMessage:  &durationpb.Duration{Seconds: 3},
  1748  	}, {
  1749  		desc:         "Duration with escaped unicode",
  1750  		inputMessage: &durationpb.Duration{},
  1751  		inputText:    `"\u0033s"`,
  1752  		wantMessage:  &durationpb.Duration{Seconds: 3},
  1753  	}, {
  1754  		desc:         "Duration with -secs",
  1755  		inputMessage: &durationpb.Duration{},
  1756  		inputText:    `"-3s"`,
  1757  		wantMessage:  &durationpb.Duration{Seconds: -3},
  1758  	}, {
  1759  		desc:         "Duration with plus sign",
  1760  		inputMessage: &durationpb.Duration{},
  1761  		inputText:    `"+3s"`,
  1762  		wantMessage:  &durationpb.Duration{Seconds: 3},
  1763  	}, {
  1764  		desc:         "Duration with nanos",
  1765  		inputMessage: &durationpb.Duration{},
  1766  		inputText:    `"0.001s"`,
  1767  		wantMessage:  &durationpb.Duration{Nanos: 1e6},
  1768  	}, {
  1769  		desc:         "Duration with -nanos",
  1770  		inputMessage: &durationpb.Duration{},
  1771  		inputText:    `"-0.001s"`,
  1772  		wantMessage:  &durationpb.Duration{Nanos: -1e6},
  1773  	}, {
  1774  		desc:         "Duration with -nanos",
  1775  		inputMessage: &durationpb.Duration{},
  1776  		inputText:    `"-.001s"`,
  1777  		wantMessage:  &durationpb.Duration{Nanos: -1e6},
  1778  	}, {
  1779  		desc:         "Duration with +nanos",
  1780  		inputMessage: &durationpb.Duration{},
  1781  		inputText:    `"+.001s"`,
  1782  		wantMessage:  &durationpb.Duration{Nanos: 1e6},
  1783  	}, {
  1784  		desc:         "Duration with -secs -nanos",
  1785  		inputMessage: &durationpb.Duration{},
  1786  		inputText:    `"-123.000000450s"`,
  1787  		wantMessage:  &durationpb.Duration{Seconds: -123, Nanos: -450},
  1788  	}, {
  1789  		desc:         "Duration with large secs",
  1790  		inputMessage: &durationpb.Duration{},
  1791  		inputText:    `"10000000000.000000001s"`,
  1792  		wantMessage:  &durationpb.Duration{Seconds: 1e10, Nanos: 1},
  1793  	}, {
  1794  		desc:         "Duration with decimal without fractional",
  1795  		inputMessage: &durationpb.Duration{},
  1796  		inputText:    `"3.s"`,
  1797  		wantMessage:  &durationpb.Duration{Seconds: 3},
  1798  	}, {
  1799  		desc:         "Duration with decimal without integer",
  1800  		inputMessage: &durationpb.Duration{},
  1801  		inputText:    `"0.5s"`,
  1802  		wantMessage:  &durationpb.Duration{Nanos: 5e8},
  1803  	}, {
  1804  		desc:         "Duration max value",
  1805  		inputMessage: &durationpb.Duration{},
  1806  		inputText:    `"315576000000.999999999s"`,
  1807  		wantMessage:  &durationpb.Duration{Seconds: 315576000000, Nanos: 999999999},
  1808  	}, {
  1809  		desc:         "Duration min value",
  1810  		inputMessage: &durationpb.Duration{},
  1811  		inputText:    `"-315576000000.999999999s"`,
  1812  		wantMessage:  &durationpb.Duration{Seconds: -315576000000, Nanos: -999999999},
  1813  	}, {
  1814  		desc:         "Duration with +secs out of range",
  1815  		inputMessage: &durationpb.Duration{},
  1816  		inputText:    `"315576000001s"`,
  1817  		wantErr:      `google.protobuf.Duration value out of range: "315576000001s"`,
  1818  	}, {
  1819  		desc:         "Duration with -secs out of range",
  1820  		inputMessage: &durationpb.Duration{},
  1821  		inputText:    `"-315576000001s"`,
  1822  		wantErr:      `google.protobuf.Duration value out of range: "-315576000001s"`,
  1823  	}, {
  1824  		desc:         "Duration with nanos beyond 9 digits",
  1825  		inputMessage: &durationpb.Duration{},
  1826  		inputText:    `"0.1000000000s"`,
  1827  		wantErr:      `invalid google.protobuf.Duration value "0.1000000000s"`,
  1828  	}, {
  1829  		desc:         "Duration without suffix s",
  1830  		inputMessage: &durationpb.Duration{},
  1831  		inputText:    `"123"`,
  1832  		wantErr:      `invalid google.protobuf.Duration value "123"`,
  1833  	}, {
  1834  		desc:         "Duration invalid signed fraction",
  1835  		inputMessage: &durationpb.Duration{},
  1836  		inputText:    `"123.+123s"`,
  1837  		wantErr:      `invalid google.protobuf.Duration value "123.+123s"`,
  1838  	}, {
  1839  		desc:         "Duration invalid multiple .",
  1840  		inputMessage: &durationpb.Duration{},
  1841  		inputText:    `"123.123.s"`,
  1842  		wantErr:      `invalid google.protobuf.Duration value "123.123.s"`,
  1843  	}, {
  1844  		desc:         "Duration invalid integer",
  1845  		inputMessage: &durationpb.Duration{},
  1846  		inputText:    `"01s"`,
  1847  		wantErr:      `invalid google.protobuf.Duration value "01s"`,
  1848  	}, {
  1849  		desc:         "Timestamp zero",
  1850  		inputMessage: &timestamppb.Timestamp{},
  1851  		inputText:    `"1970-01-01T00:00:00Z"`,
  1852  		wantMessage:  &timestamppb.Timestamp{},
  1853  	}, {
  1854  		desc:         "Timestamp with tz adjustment",
  1855  		inputMessage: &timestamppb.Timestamp{},
  1856  		inputText:    `"1970-01-01T00:00:00+01:00"`,
  1857  		wantMessage:  &timestamppb.Timestamp{Seconds: -3600},
  1858  	}, {
  1859  		desc:         "Timestamp UTC",
  1860  		inputMessage: &timestamppb.Timestamp{},
  1861  		inputText:    `"2019-03-19T23:03:21Z"`,
  1862  		wantMessage:  &timestamppb.Timestamp{Seconds: 1553036601},
  1863  	}, {
  1864  		desc:         "Timestamp with escaped unicode",
  1865  		inputMessage: &timestamppb.Timestamp{},
  1866  		inputText:    `"2019-0\u0033-19T23:03:21Z"`,
  1867  		wantMessage:  &timestamppb.Timestamp{Seconds: 1553036601},
  1868  	}, {
  1869  		desc:         "Timestamp with nanos",
  1870  		inputMessage: &timestamppb.Timestamp{},
  1871  		inputText:    `"2019-03-19T23:03:21.000000001Z"`,
  1872  		wantMessage:  &timestamppb.Timestamp{Seconds: 1553036601, Nanos: 1},
  1873  	}, {
  1874  		desc:         "Timestamp max value",
  1875  		inputMessage: &timestamppb.Timestamp{},
  1876  		inputText:    `"9999-12-31T23:59:59.999999999Z"`,
  1877  		wantMessage:  &timestamppb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
  1878  	}, {
  1879  		desc:         "Timestamp above max value",
  1880  		inputMessage: &timestamppb.Timestamp{},
  1881  		inputText:    `"9999-12-31T23:59:59-01:00"`,
  1882  		wantErr:      `google.protobuf.Timestamp value out of range: "9999-12-31T23:59:59-01:00"`,
  1883  	}, {
  1884  		desc:         "Timestamp min value",
  1885  		inputMessage: &timestamppb.Timestamp{},
  1886  		inputText:    `"0001-01-01T00:00:00Z"`,
  1887  		wantMessage:  &timestamppb.Timestamp{Seconds: -62135596800},
  1888  	}, {
  1889  		desc:         "Timestamp below min value",
  1890  		inputMessage: &timestamppb.Timestamp{},
  1891  		inputText:    `"0001-01-01T00:00:00+01:00"`,
  1892  		wantErr:      `google.protobuf.Timestamp value out of range: "0001-01-01T00:00:00+01:00"`,
  1893  	}, {
  1894  		desc:         "Timestamp with nanos beyond 9 digits",
  1895  		inputMessage: &timestamppb.Timestamp{},
  1896  		inputText:    `"1970-01-01T00:00:00.0000000001Z"`,
  1897  		wantErr:      `invalid google.protobuf.Timestamp value`,
  1898  	}, {
  1899  		desc:         "FieldMask empty",
  1900  		inputMessage: &fieldmaskpb.FieldMask{},
  1901  		inputText:    `""`,
  1902  		wantMessage:  &fieldmaskpb.FieldMask{Paths: []string{}},
  1903  	}, {
  1904  		desc:         "FieldMask",
  1905  		inputMessage: &fieldmaskpb.FieldMask{},
  1906  		inputText:    `"foo,fooBar,foo.barQux,Foo"`,
  1907  		wantMessage: &fieldmaskpb.FieldMask{
  1908  			Paths: []string{
  1909  				"foo",
  1910  				"foo_bar",
  1911  				"foo.bar_qux",
  1912  				"_foo",
  1913  			},
  1914  		},
  1915  	}, {
  1916  		desc:         "FieldMask empty path 1",
  1917  		inputMessage: &fieldmaskpb.FieldMask{},
  1918  		inputText:    `"foo,"`,
  1919  		wantErr:      `google.protobuf.FieldMask.paths contains invalid path: ""`,
  1920  	}, {
  1921  		desc:         "FieldMask empty path 2",
  1922  		inputMessage: &fieldmaskpb.FieldMask{},
  1923  		inputText:    `"foo,  ,bar"`,
  1924  		wantErr:      `google.protobuf.FieldMask.paths contains invalid path: "  "`,
  1925  	}, {
  1926  		desc:         "FieldMask invalid char 1",
  1927  		inputMessage: &fieldmaskpb.FieldMask{},
  1928  		inputText:    `"foo_bar"`,
  1929  		wantErr:      `google.protobuf.FieldMask.paths contains invalid path: "foo_bar"`,
  1930  	}, {
  1931  		desc:         "FieldMask invalid char 2",
  1932  		inputMessage: &fieldmaskpb.FieldMask{},
  1933  		inputText:    `"foo@bar"`,
  1934  		wantErr:      `google.protobuf.FieldMask.paths contains invalid path: "foo@bar"`,
  1935  	}, {
  1936  		desc:         "FieldMask field",
  1937  		inputMessage: &pb2.KnownTypes{},
  1938  		inputText: `{
  1939    "optFieldmask": "foo,qux.fooBar"
  1940  }`,
  1941  		wantMessage: &pb2.KnownTypes{
  1942  			OptFieldmask: &fieldmaskpb.FieldMask{
  1943  				Paths: []string{
  1944  					"foo",
  1945  					"qux.foo_bar",
  1946  				},
  1947  			},
  1948  		},
  1949  	}, {
  1950  		desc:         "Any empty",
  1951  		inputMessage: &anypb.Any{},
  1952  		inputText:    `{}`,
  1953  		wantMessage:  &anypb.Any{},
  1954  	}, {
  1955  		desc:         "Any with non-custom message",
  1956  		inputMessage: &anypb.Any{},
  1957  		inputText: `{
  1958    "@type": "foo/pb2.Nested",
  1959    "optString": "embedded inside Any",
  1960    "optNested": {
  1961      "optString": "inception"
  1962    }
  1963  }`,
  1964  		wantMessage: func() proto.Message {
  1965  			m := &pb2.Nested{
  1966  				OptString: proto.String("embedded inside Any"),
  1967  				OptNested: &pb2.Nested{
  1968  					OptString: proto.String("inception"),
  1969  				},
  1970  			}
  1971  			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1972  			if err != nil {
  1973  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1974  			}
  1975  			return &anypb.Any{
  1976  				TypeUrl: "foo/pb2.Nested",
  1977  				Value:   b,
  1978  			}
  1979  		}(),
  1980  	}, {
  1981  		desc:         "Any with empty embedded message",
  1982  		inputMessage: &anypb.Any{},
  1983  		inputText:    `{"@type": "foo/pb2.Nested"}`,
  1984  		wantMessage:  &anypb.Any{TypeUrl: "foo/pb2.Nested"},
  1985  	}, {
  1986  		desc:         "Any without registered type",
  1987  		umo:          protojson.UnmarshalOptions{Resolver: new(protoregistry.Types)},
  1988  		inputMessage: &anypb.Any{},
  1989  		inputText:    `{"@type": "foo/pb2.Nested"}`,
  1990  		wantErr:      `(line 1:11): unable to resolve "foo/pb2.Nested":`,
  1991  	}, {
  1992  		desc:         "Any with missing required",
  1993  		inputMessage: &anypb.Any{},
  1994  		inputText: `{
  1995    "@type": "pb2.PartialRequired",
  1996    "optString": "embedded inside Any"
  1997  }`,
  1998  		wantMessage: func() proto.Message {
  1999  			m := &pb2.PartialRequired{
  2000  				OptString: proto.String("embedded inside Any"),
  2001  			}
  2002  			b, err := proto.MarshalOptions{
  2003  				Deterministic: true,
  2004  				AllowPartial:  true,
  2005  			}.Marshal(m)
  2006  			if err != nil {
  2007  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2008  			}
  2009  			return &anypb.Any{
  2010  				TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
  2011  				Value:   b,
  2012  			}
  2013  		}(),
  2014  	}, {
  2015  		desc: "Any with partial required and AllowPartial",
  2016  		umo: protojson.UnmarshalOptions{
  2017  			AllowPartial: true,
  2018  		},
  2019  		inputMessage: &anypb.Any{},
  2020  		inputText: `{
  2021    "@type": "pb2.PartialRequired",
  2022    "optString": "embedded inside Any"
  2023  }`,
  2024  		wantMessage: func() proto.Message {
  2025  			m := &pb2.PartialRequired{
  2026  				OptString: proto.String("embedded inside Any"),
  2027  			}
  2028  			b, err := proto.MarshalOptions{
  2029  				Deterministic: true,
  2030  				AllowPartial:  true,
  2031  			}.Marshal(m)
  2032  			if err != nil {
  2033  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2034  			}
  2035  			return &anypb.Any{
  2036  				TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
  2037  				Value:   b,
  2038  			}
  2039  		}(),
  2040  	}, {
  2041  		desc:         "Any with invalid UTF8",
  2042  		inputMessage: &anypb.Any{},
  2043  		inputText: `{
  2044    "optString": "` + "abc\xff" + `",
  2045    "@type": "foo/pb2.Nested"
  2046  }`,
  2047  		wantErr: `(line 2:16): invalid UTF-8`,
  2048  	}, {
  2049  		desc:         "Any with BoolValue",
  2050  		inputMessage: &anypb.Any{},
  2051  		inputText: `{
  2052    "@type": "type.googleapis.com/google.protobuf.BoolValue",
  2053    "value": true
  2054  }`,
  2055  		wantMessage: func() proto.Message {
  2056  			m := &wrapperspb.BoolValue{Value: true}
  2057  			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  2058  			if err != nil {
  2059  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2060  			}
  2061  			return &anypb.Any{
  2062  				TypeUrl: "type.googleapis.com/google.protobuf.BoolValue",
  2063  				Value:   b,
  2064  			}
  2065  		}(),
  2066  	}, {
  2067  		desc:         "Any with Empty",
  2068  		inputMessage: &anypb.Any{},
  2069  		inputText: `{
  2070    "value": {},
  2071    "@type": "type.googleapis.com/google.protobuf.Empty"
  2072  }`,
  2073  		wantMessage: &anypb.Any{
  2074  			TypeUrl: "type.googleapis.com/google.protobuf.Empty",
  2075  		},
  2076  	}, {
  2077  		desc:         "Any with missing Empty",
  2078  		inputMessage: &anypb.Any{},
  2079  		inputText: `{
  2080    "@type": "type.googleapis.com/google.protobuf.Empty"
  2081  }`,
  2082  		wantErr: `(line 3:1): missing "value" field`,
  2083  	}, {
  2084  		desc:         "Any with StringValue containing invalid UTF8",
  2085  		inputMessage: &anypb.Any{},
  2086  		inputText: `{
  2087    "@type": "google.protobuf.StringValue",
  2088    "value": "` + "abc\xff" + `"
  2089  }`,
  2090  		wantErr: `(line 3:12): invalid UTF-8`,
  2091  	}, {
  2092  		desc:         "Any with Int64Value",
  2093  		inputMessage: &anypb.Any{},
  2094  		inputText: `{
  2095    "@type": "google.protobuf.Int64Value",
  2096    "value": "42"
  2097  }`,
  2098  		wantMessage: func() proto.Message {
  2099  			m := &wrapperspb.Int64Value{Value: 42}
  2100  			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  2101  			if err != nil {
  2102  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2103  			}
  2104  			return &anypb.Any{
  2105  				TypeUrl: "google.protobuf.Int64Value",
  2106  				Value:   b,
  2107  			}
  2108  		}(),
  2109  	}, {
  2110  		desc:         "Any with invalid Int64Value",
  2111  		inputMessage: &anypb.Any{},
  2112  		inputText: `{
  2113    "@type": "google.protobuf.Int64Value",
  2114    "value": "forty-two"
  2115  }`,
  2116  		wantErr: `(line 3:12): invalid value for int64 type: "forty-two"`,
  2117  	}, {
  2118  		desc:         "Any with invalid UInt64Value",
  2119  		inputMessage: &anypb.Any{},
  2120  		inputText: `{
  2121    "@type": "google.protobuf.UInt64Value",
  2122    "value": -42
  2123  }`,
  2124  		wantErr: `(line 3:12): invalid value for uint64 type: -42`,
  2125  	}, {
  2126  		desc:         "Any with Duration",
  2127  		inputMessage: &anypb.Any{},
  2128  		inputText: `{
  2129    "@type": "type.googleapis.com/google.protobuf.Duration",
  2130    "value": "0s"
  2131  }`,
  2132  		wantMessage: func() proto.Message {
  2133  			m := &durationpb.Duration{}
  2134  			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  2135  			if err != nil {
  2136  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2137  			}
  2138  			return &anypb.Any{
  2139  				TypeUrl: "type.googleapis.com/google.protobuf.Duration",
  2140  				Value:   b,
  2141  			}
  2142  		}(),
  2143  	}, {
  2144  		desc:         "Any with Value of StringValue",
  2145  		inputMessage: &anypb.Any{},
  2146  		inputText: `{
  2147    "@type": "google.protobuf.Value",
  2148    "value": "` + "abc\xff" + `"
  2149  }`,
  2150  		wantErr: `(line 3:12): invalid UTF-8`,
  2151  	}, {
  2152  		desc:         "Any with Value of NullValue",
  2153  		inputMessage: &anypb.Any{},
  2154  		inputText: `{
  2155    "@type": "google.protobuf.Value",
  2156    "value": null
  2157  }`,
  2158  		wantMessage: func() proto.Message {
  2159  			m := &structpb.Value{Kind: &structpb.Value_NullValue{}}
  2160  			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  2161  			if err != nil {
  2162  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2163  			}
  2164  			return &anypb.Any{
  2165  				TypeUrl: "google.protobuf.Value",
  2166  				Value:   b,
  2167  			}
  2168  		}(),
  2169  	}, {
  2170  		desc:         "Any with Struct",
  2171  		inputMessage: &anypb.Any{},
  2172  		inputText: `{
  2173    "@type": "google.protobuf.Struct",
  2174    "value": {
  2175      "bool": true,
  2176      "null": null,
  2177      "string": "hello",
  2178      "struct": {
  2179        "string": "world"
  2180      }
  2181    }
  2182  }`,
  2183  		wantMessage: func() proto.Message {
  2184  			m := &structpb.Struct{
  2185  				Fields: map[string]*structpb.Value{
  2186  					"bool":   {Kind: &structpb.Value_BoolValue{true}},
  2187  					"null":   {Kind: &structpb.Value_NullValue{}},
  2188  					"string": {Kind: &structpb.Value_StringValue{"hello"}},
  2189  					"struct": {
  2190  						Kind: &structpb.Value_StructValue{
  2191  							&structpb.Struct{
  2192  								Fields: map[string]*structpb.Value{
  2193  									"string": {Kind: &structpb.Value_StringValue{"world"}},
  2194  								},
  2195  							},
  2196  						},
  2197  					},
  2198  				},
  2199  			}
  2200  			b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  2201  			if err != nil {
  2202  				t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  2203  			}
  2204  			return &anypb.Any{
  2205  				TypeUrl: "google.protobuf.Struct",
  2206  				Value:   b,
  2207  			}
  2208  		}(),
  2209  	}, {
  2210  		desc:         "Any with missing @type",
  2211  		umo:          protojson.UnmarshalOptions{},
  2212  		inputMessage: &anypb.Any{},
  2213  		inputText: `{
  2214    "value": {}
  2215  }`,
  2216  		wantErr: `(line 1:1): missing "@type" field`,
  2217  	}, {
  2218  		desc:         "Any with empty @type",
  2219  		inputMessage: &anypb.Any{},
  2220  		inputText: `{
  2221    "@type": ""
  2222  }`,
  2223  		wantErr: `(line 2:12): @type field contains empty value`,
  2224  	}, {
  2225  		desc:         "Any with duplicate @type",
  2226  		inputMessage: &anypb.Any{},
  2227  		inputText: `{
  2228    "@type": "google.protobuf.StringValue",
  2229    "value": "hello",
  2230    "@type": "pb2.Nested"
  2231  }`,
  2232  		wantErr: `(line 4:3): duplicate "@type" field`,
  2233  	}, {
  2234  		desc:         "Any with duplicate value",
  2235  		inputMessage: &anypb.Any{},
  2236  		inputText: `{
  2237    "@type": "google.protobuf.StringValue",
  2238    "value": "hello",
  2239    "value": "world"
  2240  }`,
  2241  		wantErr: `(line 4:3): duplicate "value" field`,
  2242  	}, {
  2243  		desc:         "Any with unknown field",
  2244  		inputMessage: &anypb.Any{},
  2245  		inputText: `{
  2246    "@type": "pb2.Nested",
  2247    "optString": "hello",
  2248    "unknown": "world"
  2249  }`,
  2250  		wantErr: `(line 4:3): unknown field "unknown"`,
  2251  	}, {
  2252  		desc:         "Any with embedded type containing Any",
  2253  		inputMessage: &anypb.Any{},
  2254  		inputText: `{
  2255    "@type": "pb2.KnownTypes",
  2256    "optAny": {
  2257      "@type": "google.protobuf.StringValue",
  2258      "value": "` + "abc\xff" + `"
  2259    }
  2260  }`,
  2261  		wantErr: `(line 5:14): invalid UTF-8`,
  2262  	}, {
  2263  		desc:         "well known types as field values",
  2264  		inputMessage: &pb2.KnownTypes{},
  2265  		inputText: `{
  2266    "optBool": false,
  2267    "optInt32": 42,
  2268    "optInt64": "42",
  2269    "optUint32": 42,
  2270    "optUint64": "42",
  2271    "optFloat": 1.23,
  2272    "optDouble": 3.1415,
  2273    "optString": "hello",
  2274    "optBytes": "aGVsbG8=",
  2275    "optDuration": "123s",
  2276    "optTimestamp": "2019-03-19T23:03:21Z",
  2277    "optStruct": {
  2278      "string": "hello"
  2279    },
  2280    "optList": [
  2281      null,
  2282      "",
  2283      {},
  2284      []
  2285    ],
  2286    "optValue": "world",
  2287    "optEmpty": {},
  2288    "optAny": {
  2289      "@type": "google.protobuf.Empty",
  2290      "value": {}
  2291    },
  2292    "optFieldmask": "fooBar,barFoo"
  2293  }`,
  2294  		wantMessage: &pb2.KnownTypes{
  2295  			OptBool:      &wrapperspb.BoolValue{Value: false},
  2296  			OptInt32:     &wrapperspb.Int32Value{Value: 42},
  2297  			OptInt64:     &wrapperspb.Int64Value{Value: 42},
  2298  			OptUint32:    &wrapperspb.UInt32Value{Value: 42},
  2299  			OptUint64:    &wrapperspb.UInt64Value{Value: 42},
  2300  			OptFloat:     &wrapperspb.FloatValue{Value: 1.23},
  2301  			OptDouble:    &wrapperspb.DoubleValue{Value: 3.1415},
  2302  			OptString:    &wrapperspb.StringValue{Value: "hello"},
  2303  			OptBytes:     &wrapperspb.BytesValue{Value: []byte("hello")},
  2304  			OptDuration:  &durationpb.Duration{Seconds: 123},
  2305  			OptTimestamp: &timestamppb.Timestamp{Seconds: 1553036601},
  2306  			OptStruct: &structpb.Struct{
  2307  				Fields: map[string]*structpb.Value{
  2308  					"string": {Kind: &structpb.Value_StringValue{"hello"}},
  2309  				},
  2310  			},
  2311  			OptList: &structpb.ListValue{
  2312  				Values: []*structpb.Value{
  2313  					{Kind: &structpb.Value_NullValue{}},
  2314  					{Kind: &structpb.Value_StringValue{}},
  2315  					{
  2316  						Kind: &structpb.Value_StructValue{
  2317  							&structpb.Struct{Fields: map[string]*structpb.Value{}},
  2318  						},
  2319  					},
  2320  					{
  2321  						Kind: &structpb.Value_ListValue{
  2322  							&structpb.ListValue{Values: []*structpb.Value{}},
  2323  						},
  2324  					},
  2325  				},
  2326  			},
  2327  			OptValue: &structpb.Value{
  2328  				Kind: &structpb.Value_StringValue{"world"},
  2329  			},
  2330  			OptEmpty: &emptypb.Empty{},
  2331  			OptAny: &anypb.Any{
  2332  				TypeUrl: "google.protobuf.Empty",
  2333  			},
  2334  			OptFieldmask: &fieldmaskpb.FieldMask{
  2335  				Paths: []string{"foo_bar", "bar_foo"},
  2336  			},
  2337  		},
  2338  	}, {
  2339  		desc:         "DiscardUnknown: regular messages",
  2340  		umo:          protojson.UnmarshalOptions{DiscardUnknown: true},
  2341  		inputMessage: &pb3.Nests{},
  2342  		inputText: `{
  2343    "sNested": {
  2344      "unknown": {
  2345        "foo": 1,
  2346  	  "bar": [1, 2, 3]
  2347      }
  2348    },
  2349    "unknown": "not known"
  2350  }`,
  2351  		wantMessage: &pb3.Nests{SNested: &pb3.Nested{}},
  2352  	}, {
  2353  		desc:         "DiscardUnknown: repeated",
  2354  		umo:          protojson.UnmarshalOptions{DiscardUnknown: true},
  2355  		inputMessage: &pb2.Nests{},
  2356  		inputText: `{
  2357    "rptNested": [
  2358      {"unknown": "blah"},
  2359  	{"optString": "hello"}
  2360    ]
  2361  }`,
  2362  		wantMessage: &pb2.Nests{
  2363  			RptNested: []*pb2.Nested{
  2364  				{},
  2365  				{OptString: proto.String("hello")},
  2366  			},
  2367  		},
  2368  	}, {
  2369  		desc:         "DiscardUnknown: map",
  2370  		umo:          protojson.UnmarshalOptions{DiscardUnknown: true},
  2371  		inputMessage: &pb3.Maps{},
  2372  		inputText: `{
  2373    "strToNested": {
  2374      "nested_one": {
  2375  	  "unknown": "what you see is not"
  2376      }
  2377    }
  2378  }`,
  2379  		wantMessage: &pb3.Maps{
  2380  			StrToNested: map[string]*pb3.Nested{
  2381  				"nested_one": {},
  2382  			},
  2383  		},
  2384  	}, {
  2385  		desc:         "DiscardUnknown: extension",
  2386  		umo:          protojson.UnmarshalOptions{DiscardUnknown: true},
  2387  		inputMessage: &pb2.Extensions{},
  2388  		inputText: `{
  2389    "[pb2.opt_ext_nested]": {
  2390  	"unknown": []
  2391    }
  2392  }`,
  2393  		wantMessage: func() proto.Message {
  2394  			m := &pb2.Extensions{}
  2395  			proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{})
  2396  			return m
  2397  		}(),
  2398  	}, {
  2399  		desc:         "DiscardUnknown: Empty",
  2400  		umo:          protojson.UnmarshalOptions{DiscardUnknown: true},
  2401  		inputMessage: &emptypb.Empty{},
  2402  		inputText:    `{"unknown": "something"}`,
  2403  		wantMessage:  &emptypb.Empty{},
  2404  	}, {
  2405  		desc:         "DiscardUnknown: Any without type",
  2406  		umo:          protojson.UnmarshalOptions{DiscardUnknown: true},
  2407  		inputMessage: &anypb.Any{},
  2408  		inputText: `{
  2409    "value": {"foo": "bar"},
  2410    "unknown": true
  2411  }`,
  2412  		wantMessage: &anypb.Any{},
  2413  	}, {
  2414  		desc: "DiscardUnknown: Any",
  2415  		umo: protojson.UnmarshalOptions{
  2416  			DiscardUnknown: true,
  2417  		},
  2418  		inputMessage: &anypb.Any{},
  2419  		inputText: `{
  2420    "@type": "foo/pb2.Nested",
  2421    "unknown": "none"
  2422  }`,
  2423  		wantMessage: &anypb.Any{
  2424  			TypeUrl: "foo/pb2.Nested",
  2425  		},
  2426  	}, {
  2427  		desc: "DiscardUnknown: Any with Empty",
  2428  		umo: protojson.UnmarshalOptions{
  2429  			DiscardUnknown: true,
  2430  		},
  2431  		inputMessage: &anypb.Any{},
  2432  		inputText: `{
  2433    "@type": "type.googleapis.com/google.protobuf.Empty",
  2434    "value": {"unknown": 47}
  2435  }`,
  2436  		wantMessage: &anypb.Any{
  2437  			TypeUrl: "type.googleapis.com/google.protobuf.Empty",
  2438  		},
  2439  	}, {
  2440  		desc:         "DiscardUnknown: unknown enum name",
  2441  		inputMessage: &pb3.Enums{},
  2442  		inputText: `{
  2443    "sEnum": "UNNAMED"
  2444  }`,
  2445  		umo:         protojson.UnmarshalOptions{DiscardUnknown: true},
  2446  		wantMessage: &pb3.Enums{},
  2447  	}, {
  2448  		desc:         "DiscardUnknown: repeated enum unknown name",
  2449  		inputMessage: &pb2.Enums{},
  2450  		inputText: `{
  2451    "rptEnum"      : ["TEN", 1, 42, "UNNAMED"]
  2452  }`,
  2453  		umo: protojson.UnmarshalOptions{DiscardUnknown: true},
  2454  		wantMessage: &pb2.Enums{
  2455  			RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
  2456  		},
  2457  	}, {
  2458  		desc:         "DiscardUnknown: enum map value unknown name",
  2459  		inputMessage: &pb3.Maps{},
  2460  		inputText: `{
  2461    "uint64ToEnum": {
  2462      "1" : "ONE",
  2463  	"2" : 2,
  2464  	"10": 101,
  2465  	"3": "UNNAMED"
  2466    }
  2467  }`,
  2468  		umo: protojson.UnmarshalOptions{DiscardUnknown: true},
  2469  		wantMessage: &pb3.Maps{
  2470  			Uint64ToEnum: map[uint64]pb3.Enum{
  2471  				1:  pb3.Enum_ONE,
  2472  				2:  pb3.Enum_TWO,
  2473  				10: 101,
  2474  			},
  2475  		},
  2476  	}, {
  2477  		desc:         "weak fields",
  2478  		inputMessage: &testpb.TestWeak{},
  2479  		inputText:    `{"weak_message1":{"a":1}}`,
  2480  		wantMessage: func() *testpb.TestWeak {
  2481  			m := new(testpb.TestWeak)
  2482  			m.SetWeakMessage1(&weakpb.WeakImportMessage1{A: proto.Int32(1)})
  2483  			return m
  2484  		}(),
  2485  		skip: !flags.ProtoLegacy,
  2486  	}, {
  2487  		desc:         "weak fields; unknown field",
  2488  		inputMessage: &testpb.TestWeak{},
  2489  		inputText:    `{"weak_message1":{"a":1}, "weak_message2":{"a":1}}`,
  2490  		wantErr:      `unknown field "weak_message2"`, // weak_message2 is unknown since the package containing it is not imported
  2491  		skip:         !flags.ProtoLegacy,
  2492  	}, {
  2493  		desc:         "just at recursion limit: nested messages",
  2494  		inputMessage: &testpb.TestAllTypes{},
  2495  		inputText:    `{"optionalNestedMessage":{"corecursive":{"optionalNestedMessage":{"corecursive":{}}}}}`,
  2496  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5},
  2497  	}, {
  2498  		desc:         "exceed recursion limit: nested messages",
  2499  		inputMessage: &testpb.TestAllTypes{},
  2500  		inputText:    `{"optionalNestedMessage":{"corecursive":{"optionalNestedMessage":{"corecursive":{"optionalNestedMessage":{}}}}}}`,
  2501  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5},
  2502  		wantErr:      "exceeded max recursion depth",
  2503  	}, {
  2504  
  2505  		desc:         "just at recursion limit: maps",
  2506  		inputMessage: &testpb.TestAllTypes{},
  2507  		inputText:    `{"mapStringNestedMessage":{"key1":{"corecursive":{"mapStringNestedMessage":{}}}}}`,
  2508  		umo:          protojson.UnmarshalOptions{RecursionLimit: 3},
  2509  	}, {
  2510  		desc:         "exceed recursion limit: maps",
  2511  		inputMessage: &testpb.TestAllTypes{},
  2512  		inputText:    `{"mapStringNestedMessage":{"key1":{"corecursive":{"mapStringNestedMessage":{}}}}}`,
  2513  		umo:          protojson.UnmarshalOptions{RecursionLimit: 2},
  2514  		wantErr:      "exceeded max recursion depth",
  2515  	}, {
  2516  		desc:         "just at recursion limit: arrays",
  2517  		inputMessage: &testpb.TestAllTypes{},
  2518  		inputText:    `{"repeatedNestedMessage":[{"corecursive":{"repeatedInt32":[1,2,3]}}]}`,
  2519  		umo:          protojson.UnmarshalOptions{RecursionLimit: 3},
  2520  	}, {
  2521  		desc:         "exceed recursion limit: arrays",
  2522  		inputMessage: &testpb.TestAllTypes{},
  2523  		inputText:    `{"repeatedNestedMessage":[{"corecursive":{"repeatedNestedMessage":[{}]}}]}`,
  2524  		umo:          protojson.UnmarshalOptions{RecursionLimit: 3},
  2525  		wantErr:      "exceeded max recursion depth",
  2526  	}, {
  2527  		desc:         "just at recursion limit: value",
  2528  		inputMessage: &structpb.Value{},
  2529  		inputText:    `{"a":{"b":{"c":{"d":{}}}}}`,
  2530  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5},
  2531  	}, {
  2532  		desc:         "exceed recursion limit: value",
  2533  		inputMessage: &structpb.Value{},
  2534  		inputText:    `{"a":{"b":{"c":{"d":{"e":[]}}}}}`,
  2535  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5},
  2536  		wantErr:      "exceeded max recursion depth",
  2537  	}, {
  2538  		desc:         "just at recursion limit: list value",
  2539  		inputMessage: &structpb.ListValue{},
  2540  		inputText:    `[[[[[1, 2, 3, 4]]]]]`,
  2541  		// Note: the JSON appears to have recursion of only 5. But it's actually 6 because the
  2542  		// first leaf value (1) is actually a message (google.protobuf.Value), even though the
  2543  		// JSON doesn't use an open brace.
  2544  		umo: protojson.UnmarshalOptions{RecursionLimit: 6},
  2545  	}, {
  2546  		desc:         "exceed recursion limit: list value",
  2547  		inputMessage: &structpb.ListValue{},
  2548  		inputText:    `[[[[[1, 2, 3, 4, ["a", "b"]]]]]]`,
  2549  		umo:          protojson.UnmarshalOptions{RecursionLimit: 6},
  2550  		wantErr:      "exceeded max recursion depth",
  2551  	}, {
  2552  		desc:         "just at recursion limit: struct value",
  2553  		inputMessage: &structpb.Struct{},
  2554  		inputText:    `{"a":{"b":{"c":{"d":{}}}}}`,
  2555  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5},
  2556  	}, {
  2557  		desc:         "exceed recursion limit: struct value",
  2558  		inputMessage: &structpb.Struct{},
  2559  		inputText:    `{"a":{"b":{"c":{"d":{"e":{}]}}}}}`,
  2560  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5},
  2561  		wantErr:      "exceeded max recursion depth",
  2562  	}, {
  2563  		desc:         "just at recursion limit: skip unknown",
  2564  		inputMessage: &testpb.TestAllTypes{},
  2565  		inputText:    `{"foo":{"bar":[{"baz":{}}]}}`,
  2566  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5, DiscardUnknown: true},
  2567  	}, {
  2568  		desc:         "exceed recursion limit: skip unknown",
  2569  		inputMessage: &testpb.TestAllTypes{},
  2570  		inputText:    `{"foo":{"bar":[{"baz":[{}]]}}`,
  2571  		umo:          protojson.UnmarshalOptions{RecursionLimit: 5, DiscardUnknown: true},
  2572  		wantErr:      "exceeded max recursion depth",
  2573  	}}
  2574  
  2575  	for _, tt := range tests {
  2576  		tt := tt
  2577  		if tt.skip {
  2578  			continue
  2579  		}
  2580  		t.Run(tt.desc, func(t *testing.T) {
  2581  			err := tt.umo.Unmarshal([]byte(tt.inputText), tt.inputMessage)
  2582  			if err != nil {
  2583  				if tt.wantErr == "" {
  2584  					t.Errorf("Unmarshal() got unexpected error: %v", err)
  2585  				} else if !strings.Contains(err.Error(), tt.wantErr) {
  2586  					t.Errorf("Unmarshal() error got %q, want %q", err, tt.wantErr)
  2587  				}
  2588  				return
  2589  			}
  2590  			if tt.wantErr != "" {
  2591  				t.Errorf("Unmarshal() got nil error, want error %q", tt.wantErr)
  2592  			}
  2593  			if tt.wantMessage != nil && !proto.Equal(tt.inputMessage, tt.wantMessage) {
  2594  				t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
  2595  			}
  2596  		})
  2597  	}
  2598  }
  2599  

View as plain text