blob: e7f42391d33a11f77c78638f3938113da1fdd3d4 [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 }, {
1760 desc: "Duration with nanos",
1761 inputMessage: &knownpb.Duration{},
1762 inputText: `"0.001s"`,
1763 wantMessage: &knownpb.Duration{Nanos: 1e6},
1764 }, {
1765 desc: "Duration with -nanos",
1766 inputMessage: &knownpb.Duration{},
1767 inputText: `"-0.001s"`,
1768 wantMessage: &knownpb.Duration{Nanos: -1e6},
1769 }, {
1770 desc: "Duration with -secs -nanos",
1771 inputMessage: &knownpb.Duration{},
1772 inputText: `"-123.000000450s"`,
1773 wantMessage: &knownpb.Duration{Seconds: -123, Nanos: -450},
1774 }, {
1775 desc: "Duration with large secs",
1776 inputMessage: &knownpb.Duration{},
1777 inputText: `"10000000000.000000001s"`,
1778 wantMessage: &knownpb.Duration{Seconds: 1e10, Nanos: 1},
1779 }, {
1780 desc: "Duration with decimal without fractional",
1781 inputMessage: &knownpb.Duration{},
1782 inputText: `"3.s"`,
1783 wantMessage: &knownpb.Duration{Seconds: 3},
1784 }, {
1785 desc: "Duration with decimal without integer",
1786 inputMessage: &knownpb.Duration{},
1787 inputText: `"0.5s"`,
1788 wantMessage: &knownpb.Duration{Nanos: 5e8},
1789 }, {
1790 desc: "Duration with +secs out of range",
1791 inputMessage: &knownpb.Duration{},
1792 inputText: `"315576000001s"`,
1793 wantErr: true,
1794 }, {
1795 desc: "Duration with -secs out of range",
1796 inputMessage: &knownpb.Duration{},
1797 inputText: `"-315576000001s"`,
1798 wantErr: true,
1799 }, {
1800 desc: "Duration with nanos beyond 9 digits",
1801 inputMessage: &knownpb.Duration{},
1802 inputText: `"0.9999999990s"`,
1803 wantErr: true,
1804 }, {
1805 desc: "Duration without suffix s",
1806 inputMessage: &knownpb.Duration{},
1807 inputText: `"123"`,
1808 wantErr: true,
1809 }, {
1810 desc: "Timestamp zero",
1811 inputMessage: &knownpb.Timestamp{},
1812 inputText: `"1970-01-01T00:00:00Z"`,
1813 wantMessage: &knownpb.Timestamp{},
1814 }, {
1815 desc: "Timestamp with tz adjustment",
1816 inputMessage: &knownpb.Timestamp{},
1817 inputText: `"1970-01-01T00:00:00+01:00"`,
1818 wantMessage: &knownpb.Timestamp{Seconds: -3600},
1819 }, {
1820 desc: "Timestamp UTC",
1821 inputMessage: &knownpb.Timestamp{},
1822 inputText: `"2019-03-19T23:03:21Z"`,
1823 wantMessage: &knownpb.Timestamp{Seconds: 1553036601},
1824 }, {
1825 desc: "Timestamp with escaped unicode",
1826 inputMessage: &knownpb.Timestamp{},
1827 inputText: `"2019-0\u0033-19T23:03:21Z"`,
1828 wantMessage: &knownpb.Timestamp{Seconds: 1553036601},
1829 }, {
1830 desc: "Timestamp with nanos",
1831 inputMessage: &knownpb.Timestamp{},
1832 inputText: `"2019-03-19T23:03:21.000000001Z"`,
1833 wantMessage: &knownpb.Timestamp{Seconds: 1553036601, Nanos: 1},
1834 }, {
1835 desc: "Timestamp upper limit",
1836 inputMessage: &knownpb.Timestamp{},
1837 inputText: `"9999-12-31T23:59:59.999999999Z"`,
1838 wantMessage: &knownpb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
1839 }, {
1840 desc: "Timestamp above upper limit",
1841 inputMessage: &knownpb.Timestamp{},
1842 inputText: `"9999-12-31T23:59:59-01:00"`,
1843 wantErr: true,
1844 }, {
1845 desc: "Timestamp lower limit",
1846 inputMessage: &knownpb.Timestamp{},
1847 inputText: `"0001-01-01T00:00:00Z"`,
1848 wantMessage: &knownpb.Timestamp{Seconds: -62135596800},
1849 }, {
1850 desc: "Timestamp below lower limit",
1851 inputMessage: &knownpb.Timestamp{},
1852 inputText: `"0001-01-01T00:00:00+01:00"`,
1853 wantErr: true,
1854 }, {
1855 desc: "Timestamp with nanos beyond 9 digits",
1856 inputMessage: &knownpb.Timestamp{},
1857 inputText: `"1970-01-01T00:00:00.0000000001Z"`,
1858 wantErr: true,
1859 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -07001860 desc: "FieldMask empty",
1861 inputMessage: &knownpb.FieldMask{},
1862 inputText: `""`,
1863 wantMessage: &knownpb.FieldMask{Paths: []string{}},
1864 }, {
1865 desc: "FieldMask",
1866 inputMessage: &knownpb.FieldMask{},
1867 inputText: `"foo,fooBar , foo.barQux ,Foo"`,
1868 wantMessage: &knownpb.FieldMask{
1869 Paths: []string{
1870 "foo",
1871 "foo_bar",
1872 "foo.bar_qux",
1873 "_foo",
1874 },
1875 },
1876 }, {
1877 desc: "FieldMask field",
1878 inputMessage: &pb2.KnownTypes{},
1879 inputText: `{
1880 "optFieldmask": "foo, qux.fooBar"
1881}`,
1882 wantMessage: &pb2.KnownTypes{
1883 OptFieldmask: &knownpb.FieldMask{
1884 Paths: []string{
1885 "foo",
1886 "qux.foo_bar",
1887 },
1888 },
1889 },
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001890 }, {
1891 desc: "Any empty",
1892 inputMessage: &knownpb.Any{},
1893 inputText: `{}`,
1894 wantMessage: &knownpb.Any{},
1895 }, {
1896 desc: "Any with non-custom message",
1897 umo: jsonpb.UnmarshalOptions{
1898 Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
1899 },
1900 inputMessage: &knownpb.Any{},
1901 inputText: `{
1902 "@type": "foo/pb2.Nested",
1903 "optString": "embedded inside Any",
1904 "optNested": {
1905 "optString": "inception"
1906 }
1907}`,
1908 wantMessage: func() proto.Message {
1909 m := &pb2.Nested{
1910 OptString: scalar.String("embedded inside Any"),
1911 OptNested: &pb2.Nested{
1912 OptString: scalar.String("inception"),
1913 },
1914 }
1915 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1916 if err != nil {
1917 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1918 }
1919 return &knownpb.Any{
1920 TypeUrl: "foo/pb2.Nested",
1921 Value: b,
1922 }
1923 }(),
1924 }, {
1925 desc: "Any with empty embedded message",
1926 umo: jsonpb.UnmarshalOptions{
1927 Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
1928 },
1929 inputMessage: &knownpb.Any{},
1930 inputText: `{
1931 "@type": "foo/pb2.Nested"
1932}`,
1933 wantMessage: &knownpb.Any{TypeUrl: "foo/pb2.Nested"},
1934 }, {
1935 desc: "Any without registered type",
1936 umo: jsonpb.UnmarshalOptions{Resolver: preg.NewTypes()},
1937 inputMessage: &knownpb.Any{},
1938 inputText: `{
1939 "@type": "foo/pb2.Nested"
1940}`,
1941 wantErr: true,
1942 }, {
1943 desc: "Any with missing required error",
1944 umo: jsonpb.UnmarshalOptions{
1945 Resolver: preg.NewTypes((&pb2.PartialRequired{}).ProtoReflect().Type()),
1946 },
1947 inputMessage: &knownpb.Any{},
1948 inputText: `{
1949 "@type": "pb2.PartialRequired",
1950 "optString": "embedded inside Any"
1951}`,
1952 wantMessage: func() proto.Message {
1953 m := &pb2.PartialRequired{
1954 OptString: scalar.String("embedded inside Any"),
1955 }
1956 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1957 // TODO: Marshal may fail due to required field not set at some
1958 // point. Need to ignore required not set error here.
1959 if err != nil {
1960 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1961 }
1962 return &knownpb.Any{
1963 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1964 Value: b,
1965 }
1966 }(),
1967 wantErr: true,
1968 }, {
1969 desc: "Any with partial required and AllowPartial",
1970 umo: jsonpb.UnmarshalOptions{
1971 AllowPartial: true,
1972 Resolver: preg.NewTypes((&pb2.PartialRequired{}).ProtoReflect().Type()),
1973 },
1974 inputMessage: &knownpb.Any{},
1975 inputText: `{
1976 "@type": "pb2.PartialRequired",
1977 "optString": "embedded inside Any"
1978}`,
1979 wantMessage: func() proto.Message {
1980 m := &pb2.PartialRequired{
1981 OptString: scalar.String("embedded inside Any"),
1982 }
1983 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1984 // TODO: Marshal may fail due to required field not set at some
1985 // point. Need to ignore required not set error here.
1986 if err != nil {
1987 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1988 }
1989 return &knownpb.Any{
1990 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1991 Value: b,
1992 }
1993 }(),
1994 }, {
1995 desc: "Any with invalid UTF8",
1996 umo: jsonpb.UnmarshalOptions{
1997 Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
1998 },
1999 inputMessage: &knownpb.Any{},
2000 inputText: `{
2001 "optString": "` + "abc\xff" + `",
2002 "@type": "foo/pb2.Nested"
2003}`,
2004 wantMessage: func() proto.Message {
2005 m := &pb2.Nested{
2006 OptString: scalar.String("abc\xff"),
2007 }
2008 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2009 if err != nil {
2010 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2011 }
2012 return &knownpb.Any{
2013 TypeUrl: "foo/pb2.Nested",
2014 Value: b,
2015 }
2016 }(),
2017 wantErr: true,
2018 }, {
2019 desc: "Any with BoolValue",
2020 umo: jsonpb.UnmarshalOptions{
2021 Resolver: preg.NewTypes((&knownpb.BoolValue{}).ProtoReflect().Type()),
2022 },
2023 inputMessage: &knownpb.Any{},
2024 inputText: `{
2025 "@type": "type.googleapis.com/google.protobuf.BoolValue",
2026 "value": true
2027}`,
2028 wantMessage: func() proto.Message {
2029 m := &knownpb.BoolValue{Value: true}
2030 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2031 if err != nil {
2032 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2033 }
2034 return &knownpb.Any{
2035 TypeUrl: "type.googleapis.com/google.protobuf.BoolValue",
2036 Value: b,
2037 }
2038 }(),
2039 }, {
2040 desc: "Any with Empty",
2041 umo: jsonpb.UnmarshalOptions{
2042 Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
2043 },
2044 inputMessage: &knownpb.Any{},
2045 inputText: `{
2046 "value": {},
2047 "@type": "type.googleapis.com/google.protobuf.Empty"
2048}`,
2049 wantMessage: func() proto.Message {
2050 m := &knownpb.Empty{}
2051 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2052 if err != nil {
2053 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2054 }
2055 return &knownpb.Any{
2056 TypeUrl: "type.googleapis.com/google.protobuf.Empty",
2057 Value: b,
2058 }
2059 }(),
2060 }, {
2061 desc: "Any with missing Empty",
2062 umo: jsonpb.UnmarshalOptions{
2063 Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
2064 },
2065 inputMessage: &knownpb.Any{},
2066 inputText: `{
2067 "@type": "type.googleapis.com/google.protobuf.Empty"
2068}`,
2069 wantErr: true,
2070 }, {
2071 desc: "Any with StringValue containing invalid UTF8",
2072 umo: jsonpb.UnmarshalOptions{
2073 Resolver: preg.NewTypes((&knownpb.StringValue{}).ProtoReflect().Type()),
2074 },
2075 inputMessage: &knownpb.Any{},
2076 inputText: `{
2077 "@type": "google.protobuf.StringValue",
2078 "value": "` + "abc\xff" + `"
2079}`,
2080 wantMessage: func() proto.Message {
2081 m := &knownpb.StringValue{Value: "abc\xff"}
2082 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2083 if err != nil {
2084 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2085 }
2086 return &knownpb.Any{
2087 TypeUrl: "google.protobuf.StringValue",
2088 Value: b,
2089 }
2090 }(),
2091 wantErr: true,
2092 }, {
2093 desc: "Any with Int64Value",
2094 umo: jsonpb.UnmarshalOptions{
2095 Resolver: preg.NewTypes((&knownpb.Int64Value{}).ProtoReflect().Type()),
2096 },
2097 inputMessage: &knownpb.Any{},
2098 inputText: `{
2099 "@type": "google.protobuf.Int64Value",
2100 "value": "42"
2101}`,
2102 wantMessage: func() proto.Message {
2103 m := &knownpb.Int64Value{Value: 42}
2104 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2105 if err != nil {
2106 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2107 }
2108 return &knownpb.Any{
2109 TypeUrl: "google.protobuf.Int64Value",
2110 Value: b,
2111 }
2112 }(),
2113 }, {
2114 desc: "Any with invalid Int64Value",
2115 umo: jsonpb.UnmarshalOptions{
2116 Resolver: preg.NewTypes((&knownpb.Int64Value{}).ProtoReflect().Type()),
2117 },
2118 inputMessage: &knownpb.Any{},
2119 inputText: `{
2120 "@type": "google.protobuf.Int64Value",
2121 "value": "forty-two"
2122}`,
2123 wantErr: true,
2124 }, {
2125 desc: "Any with invalid UInt64Value",
2126 umo: jsonpb.UnmarshalOptions{
2127 Resolver: preg.NewTypes((&knownpb.UInt64Value{}).ProtoReflect().Type()),
2128 },
2129 inputMessage: &knownpb.Any{},
2130 inputText: `{
2131 "@type": "google.protobuf.UInt64Value",
2132 "value": -42
2133}`,
2134 wantErr: true,
2135 }, {
2136 desc: "Any with Duration",
2137 umo: jsonpb.UnmarshalOptions{
2138 Resolver: preg.NewTypes((&knownpb.Duration{}).ProtoReflect().Type()),
2139 },
2140 inputMessage: &knownpb.Any{},
2141 inputText: `{
2142 "@type": "type.googleapis.com/google.protobuf.Duration",
2143 "value": "0s"
2144}`,
2145 wantMessage: func() proto.Message {
2146 m := &knownpb.Duration{}
2147 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2148 if err != nil {
2149 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2150 }
2151 return &knownpb.Any{
2152 TypeUrl: "type.googleapis.com/google.protobuf.Duration",
2153 Value: b,
2154 }
2155 }(),
2156 }, {
2157 desc: "Any with Value of StringValue",
2158 umo: jsonpb.UnmarshalOptions{
2159 Resolver: preg.NewTypes((&knownpb.Value{}).ProtoReflect().Type()),
2160 },
2161 inputMessage: &knownpb.Any{},
2162 inputText: `{
2163 "@type": "google.protobuf.Value",
2164 "value": "` + "abc\xff" + `"
2165}`,
2166 wantMessage: func() proto.Message {
2167 m := &knownpb.Value{Kind: &knownpb.Value_StringValue{"abc\xff"}}
2168 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2169 if err != nil {
2170 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2171 }
2172 return &knownpb.Any{
2173 TypeUrl: "google.protobuf.Value",
2174 Value: b,
2175 }
2176 }(),
2177 wantErr: true,
2178 }, {
2179 desc: "Any with Value of NullValue",
2180 umo: jsonpb.UnmarshalOptions{
2181 Resolver: preg.NewTypes((&knownpb.Value{}).ProtoReflect().Type()),
2182 },
2183 inputMessage: &knownpb.Any{},
2184 inputText: `{
2185 "@type": "google.protobuf.Value",
2186 "value": null
2187}`,
2188 wantMessage: func() proto.Message {
2189 m := &knownpb.Value{Kind: &knownpb.Value_NullValue{}}
2190 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2191 if err != nil {
2192 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2193 }
2194 return &knownpb.Any{
2195 TypeUrl: "google.protobuf.Value",
2196 Value: b,
2197 }
2198 }(),
2199 }, {
2200 desc: "Any with Struct",
2201 umo: jsonpb.UnmarshalOptions{
2202 Resolver: preg.NewTypes(
2203 (&knownpb.Struct{}).ProtoReflect().Type(),
2204 (&knownpb.Value{}).ProtoReflect().Type(),
2205 (&knownpb.BoolValue{}).ProtoReflect().Type(),
2206 knownpb.NullValue_NULL_VALUE.Type(),
2207 (&knownpb.StringValue{}).ProtoReflect().Type(),
2208 ),
2209 },
2210 inputMessage: &knownpb.Any{},
2211 inputText: `{
2212 "@type": "google.protobuf.Struct",
2213 "value": {
2214 "bool": true,
2215 "null": null,
2216 "string": "hello",
2217 "struct": {
2218 "string": "world"
2219 }
2220 }
2221}`,
2222 wantMessage: func() proto.Message {
2223 m := &knownpb.Struct{
2224 Fields: map[string]*knownpb.Value{
2225 "bool": {Kind: &knownpb.Value_BoolValue{true}},
2226 "null": {Kind: &knownpb.Value_NullValue{}},
2227 "string": {Kind: &knownpb.Value_StringValue{"hello"}},
2228 "struct": {
2229 Kind: &knownpb.Value_StructValue{
2230 &knownpb.Struct{
2231 Fields: map[string]*knownpb.Value{
2232 "string": {Kind: &knownpb.Value_StringValue{"world"}},
2233 },
2234 },
2235 },
2236 },
2237 },
2238 }
2239 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
2240 if err != nil {
2241 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2242 }
2243 return &knownpb.Any{
2244 TypeUrl: "google.protobuf.Struct",
2245 Value: b,
2246 }
2247 }(),
2248 }, {
2249 desc: "Any with missing @type",
2250 umo: jsonpb.UnmarshalOptions{},
2251 inputMessage: &knownpb.Any{},
2252 inputText: `{
2253 "value": {}
2254}`,
2255 wantErr: true,
2256 }, {
2257 desc: "Any with empty @type",
2258 inputMessage: &knownpb.Any{},
2259 inputText: `{
2260 "@type": ""
2261}`,
2262 wantErr: true,
2263 }, {
2264 desc: "Any with duplicate @type",
2265 umo: jsonpb.UnmarshalOptions{
2266 Resolver: preg.NewTypes(
2267 (&pb2.Nested{}).ProtoReflect().Type(),
2268 (&knownpb.StringValue{}).ProtoReflect().Type(),
2269 ),
2270 },
2271 inputMessage: &knownpb.Any{},
2272 inputText: `{
2273 "@type": "google.protobuf.StringValue",
2274 "value": "hello",
2275 "@type": "pb2.Nested"
2276}`,
2277 wantErr: true,
2278 }, {
2279 desc: "Any with duplicate value",
2280 umo: jsonpb.UnmarshalOptions{
2281 Resolver: preg.NewTypes((&knownpb.StringValue{}).ProtoReflect().Type()),
2282 },
2283 inputMessage: &knownpb.Any{},
2284 inputText: `{
2285 "@type": "google.protobuf.StringValue",
2286 "value": "hello",
2287 "value": "world"
2288}`,
2289 wantErr: true,
2290 }, {
2291 desc: "Any with unknown field",
2292 umo: jsonpb.UnmarshalOptions{
2293 Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
2294 },
2295 inputMessage: &knownpb.Any{},
2296 inputText: `{
2297 "@type": "pb2.Nested",
2298 "optString": "hello",
2299 "unknown": "world"
2300}`,
2301 wantErr: true,
2302 }, {
2303 desc: "Any with embedded type containing Any",
2304 umo: jsonpb.UnmarshalOptions{
2305 Resolver: preg.NewTypes(
2306 (&pb2.KnownTypes{}).ProtoReflect().Type(),
2307 (&knownpb.Any{}).ProtoReflect().Type(),
2308 (&knownpb.StringValue{}).ProtoReflect().Type(),
2309 ),
2310 },
2311 inputMessage: &knownpb.Any{},
2312 inputText: `{
2313 "@type": "pb2.KnownTypes",
2314 "optAny": {
2315 "@type": "google.protobuf.StringValue",
2316 "value": "` + "abc\xff" + `"
2317 }
2318}`,
2319 wantMessage: func() proto.Message {
2320 m1 := &knownpb.StringValue{Value: "abc\xff"}
2321 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m1)
2322 if err != nil {
2323 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2324 }
2325 m2 := &knownpb.Any{
2326 TypeUrl: "google.protobuf.StringValue",
2327 Value: b,
2328 }
2329 m3 := &pb2.KnownTypes{OptAny: m2}
2330 b, err = proto.MarshalOptions{Deterministic: true}.Marshal(m3)
2331 if err != nil {
2332 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
2333 }
2334 return &knownpb.Any{
2335 TypeUrl: "pb2.KnownTypes",
2336 Value: b,
2337 }
2338 }(),
2339 wantErr: true,
2340 }, {
2341 desc: "well known types as field values",
2342 umo: jsonpb.UnmarshalOptions{
2343 Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
2344 },
2345 inputMessage: &pb2.KnownTypes{},
2346 inputText: `{
2347 "optBool": false,
2348 "optInt32": 42,
2349 "optInt64": "42",
2350 "optUint32": 42,
2351 "optUint64": "42",
2352 "optFloat": 1.23,
2353 "optDouble": 3.1415,
2354 "optString": "hello",
2355 "optBytes": "aGVsbG8=",
2356 "optDuration": "123s",
2357 "optTimestamp": "2019-03-19T23:03:21Z",
2358 "optStruct": {
2359 "string": "hello"
2360 },
2361 "optList": [
2362 null,
2363 "",
2364 {},
2365 []
2366 ],
2367 "optValue": "world",
2368 "optEmpty": {},
2369 "optAny": {
2370 "@type": "google.protobuf.Empty",
2371 "value": {}
2372 },
2373 "optFieldmask": "fooBar,barFoo"
2374}`,
2375 wantMessage: &pb2.KnownTypes{
2376 OptBool: &knownpb.BoolValue{Value: false},
2377 OptInt32: &knownpb.Int32Value{Value: 42},
2378 OptInt64: &knownpb.Int64Value{Value: 42},
2379 OptUint32: &knownpb.UInt32Value{Value: 42},
2380 OptUint64: &knownpb.UInt64Value{Value: 42},
2381 OptFloat: &knownpb.FloatValue{Value: 1.23},
2382 OptDouble: &knownpb.DoubleValue{Value: 3.1415},
2383 OptString: &knownpb.StringValue{Value: "hello"},
2384 OptBytes: &knownpb.BytesValue{Value: []byte("hello")},
2385 OptDuration: &knownpb.Duration{Seconds: 123},
2386 OptTimestamp: &knownpb.Timestamp{Seconds: 1553036601},
2387 OptStruct: &knownpb.Struct{
2388 Fields: map[string]*knownpb.Value{
2389 "string": {Kind: &knownpb.Value_StringValue{"hello"}},
2390 },
2391 },
2392 OptList: &knownpb.ListValue{
2393 Values: []*knownpb.Value{
2394 {Kind: &knownpb.Value_NullValue{}},
2395 {Kind: &knownpb.Value_StringValue{}},
2396 {
2397 Kind: &knownpb.Value_StructValue{
2398 &knownpb.Struct{Fields: map[string]*knownpb.Value{}},
2399 },
2400 },
2401 {
2402 Kind: &knownpb.Value_ListValue{
2403 &knownpb.ListValue{Values: []*knownpb.Value{}},
2404 },
2405 },
2406 },
2407 },
2408 OptValue: &knownpb.Value{
2409 Kind: &knownpb.Value_StringValue{"world"},
2410 },
2411 OptEmpty: &knownpb.Empty{},
2412 OptAny: &knownpb.Any{
2413 TypeUrl: "google.protobuf.Empty",
2414 },
2415 OptFieldmask: &knownpb.FieldMask{
2416 Paths: []string{"foo_bar", "bar_foo"},
2417 },
2418 },
Herbie Ongc96a79d2019-03-08 10:49:17 -08002419 }}
2420
2421 for _, tt := range tests {
2422 tt := tt
2423 t.Run(tt.desc, func(t *testing.T) {
2424 err := tt.umo.Unmarshal(tt.inputMessage, []byte(tt.inputText))
2425 if err != nil && !tt.wantErr {
2426 t.Errorf("Unmarshal() returned error: %v\n\n", err)
2427 }
2428 if err == nil && tt.wantErr {
2429 t.Error("Unmarshal() got nil error, want error\n\n")
2430 }
2431 if tt.wantMessage != nil && !protoV1.Equal(tt.inputMessage.(protoV1.Message), tt.wantMessage.(protoV1.Message)) {
2432 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
2433 }
2434 })
2435 }
2436}