1
2
3
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
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: ×tamppb.Timestamp{},
1975 inputText: `"1970-01-01T00:00:00Z"`,
1976 wantMessage: ×tamppb.Timestamp{},
1977 }, {
1978 desc: "Timestamp with tz adjustment",
1979 inputMessage: ×tamppb.Timestamp{},
1980 inputText: `"1970-01-01T00:00:00+01:00"`,
1981 wantMessage: ×tamppb.Timestamp{Seconds: -3600},
1982 }, {
1983 desc: "Timestamp UTC",
1984 inputMessage: ×tamppb.Timestamp{},
1985 inputText: `"2019-03-19T23:03:21Z"`,
1986 wantMessage: ×tamppb.Timestamp{Seconds: 1553036601},
1987 }, {
1988 desc: "Timestamp with escaped unicode",
1989 inputMessage: ×tamppb.Timestamp{},
1990 inputText: `"2019-0\u0033-19T23:03:21Z"`,
1991 wantMessage: ×tamppb.Timestamp{Seconds: 1553036601},
1992 }, {
1993 desc: "Timestamp with nanos",
1994 inputMessage: ×tamppb.Timestamp{},
1995 inputText: `"2019-03-19T23:03:21.000000001Z"`,
1996 wantMessage: ×tamppb.Timestamp{Seconds: 1553036601, Nanos: 1},
1997 }, {
1998 desc: "Timestamp max value",
1999 inputMessage: ×tamppb.Timestamp{},
2000 inputText: `"9999-12-31T23:59:59.999999999Z"`,
2001 wantMessage: ×tamppb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
2002 }, {
2003 desc: "Timestamp above max value",
2004 inputMessage: ×tamppb.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: ×tamppb.Timestamp{},
2010 inputText: `"0001-01-01T00:00:00Z"`,
2011 wantMessage: ×tamppb.Timestamp{Seconds: -62135596800},
2012 }, {
2013 desc: "Timestamp below min value",
2014 inputMessage: ×tamppb.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: ×tamppb.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: ×tamppb.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: ×tamppb.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"`,
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
2742
2743
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