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