...

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

View as plain text