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