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