blob: 2552275564e2a4dafb53578910dc2355340bda85 [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 Ongc96a79d2019-03-08 10:49:17 -080019)
20
Herbie Onge52379a2019-03-15 18:00:19 -070021func init() {
22 // TODO: remove these registerExtension calls when generated code registers
23 // to V2 global registry.
24 registerExtension(pb2.E_OptExtBool)
25 registerExtension(pb2.E_OptExtString)
26 registerExtension(pb2.E_OptExtEnum)
27 registerExtension(pb2.E_OptExtNested)
28 registerExtension(pb2.E_RptExtFixed32)
29 registerExtension(pb2.E_RptExtEnum)
30 registerExtension(pb2.E_RptExtNested)
31 registerExtension(pb2.E_ExtensionsContainer_OptExtBool)
32 registerExtension(pb2.E_ExtensionsContainer_OptExtString)
33 registerExtension(pb2.E_ExtensionsContainer_OptExtEnum)
34 registerExtension(pb2.E_ExtensionsContainer_OptExtNested)
35 registerExtension(pb2.E_ExtensionsContainer_RptExtString)
36 registerExtension(pb2.E_ExtensionsContainer_RptExtEnum)
37 registerExtension(pb2.E_ExtensionsContainer_RptExtNested)
38 registerExtension(pb2.E_MessageSetExtension)
39 registerExtension(pb2.E_MessageSetExtension_MessageSetExtension)
40 registerExtension(pb2.E_MessageSetExtension_NotMessageSetExtension)
41 registerExtension(pb2.E_MessageSetExtension_ExtNested)
42 registerExtension(pb2.E_FakeMessageSetExtension_MessageSetExtension)
43}
44
Joe Tsai4fddeba2019-03-20 18:29:32 -070045func registerExtension(xd *protoiface.ExtensionDescV1) {
Herbie Onge52379a2019-03-15 18:00:19 -070046 preg.GlobalTypes.Register(xd.Type)
47}
48
Herbie Ongc96a79d2019-03-08 10:49:17 -080049func TestUnmarshal(t *testing.T) {
50 tests := []struct {
51 desc string
52 umo jsonpb.UnmarshalOptions
53 inputMessage proto.Message
54 inputText string
55 wantMessage proto.Message
56 // TODO: verify expected error message substring.
57 wantErr bool
58 }{{
59 desc: "proto2 empty message",
60 inputMessage: &pb2.Scalars{},
61 inputText: "{}",
62 wantMessage: &pb2.Scalars{},
63 }, {
64 desc: "unexpected value instead of EOF",
65 inputMessage: &pb2.Scalars{},
66 inputText: "{} {}",
67 wantErr: true,
68 }, {
69 desc: "proto2 optional scalars set to zero values",
70 inputMessage: &pb2.Scalars{},
71 inputText: `{
72 "optBool": false,
73 "optInt32": 0,
74 "optInt64": 0,
75 "optUint32": 0,
76 "optUint64": 0,
77 "optSint32": 0,
78 "optSint64": 0,
79 "optFixed32": 0,
80 "optFixed64": 0,
81 "optSfixed32": 0,
82 "optSfixed64": 0,
83 "optFloat": 0,
84 "optDouble": 0,
85 "optBytes": "",
86 "optString": ""
87}`,
88 wantMessage: &pb2.Scalars{
89 OptBool: scalar.Bool(false),
90 OptInt32: scalar.Int32(0),
91 OptInt64: scalar.Int64(0),
92 OptUint32: scalar.Uint32(0),
93 OptUint64: scalar.Uint64(0),
94 OptSint32: scalar.Int32(0),
95 OptSint64: scalar.Int64(0),
96 OptFixed32: scalar.Uint32(0),
97 OptFixed64: scalar.Uint64(0),
98 OptSfixed32: scalar.Int32(0),
99 OptSfixed64: scalar.Int64(0),
100 OptFloat: scalar.Float32(0),
101 OptDouble: scalar.Float64(0),
102 OptBytes: []byte{},
103 OptString: scalar.String(""),
104 },
105 }, {
106 desc: "proto3 scalars set to zero values",
107 inputMessage: &pb3.Scalars{},
108 inputText: `{
109 "sBool": false,
110 "sInt32": 0,
111 "sInt64": 0,
112 "sUint32": 0,
113 "sUint64": 0,
114 "sSint32": 0,
115 "sSint64": 0,
116 "sFixed32": 0,
117 "sFixed64": 0,
118 "sSfixed32": 0,
119 "sSfixed64": 0,
120 "sFloat": 0,
121 "sDouble": 0,
122 "sBytes": "",
123 "sString": ""
124}`,
125 wantMessage: &pb3.Scalars{},
126 }, {
127 desc: "proto2 optional scalars set to null",
128 inputMessage: &pb2.Scalars{},
129 inputText: `{
130 "optBool": null,
131 "optInt32": null,
132 "optInt64": null,
133 "optUint32": null,
134 "optUint64": null,
135 "optSint32": null,
136 "optSint64": null,
137 "optFixed32": null,
138 "optFixed64": null,
139 "optSfixed32": null,
140 "optSfixed64": null,
141 "optFloat": null,
142 "optDouble": null,
143 "optBytes": null,
144 "optString": null
145}`,
146 wantMessage: &pb2.Scalars{},
147 }, {
148 desc: "proto3 scalars set to null",
149 inputMessage: &pb3.Scalars{},
150 inputText: `{
151 "sBool": null,
152 "sInt32": null,
153 "sInt64": null,
154 "sUint32": null,
155 "sUint64": null,
156 "sSint32": null,
157 "sSint64": null,
158 "sFixed32": null,
159 "sFixed64": null,
160 "sSfixed32": null,
161 "sSfixed64": null,
162 "sFloat": null,
163 "sDouble": null,
164 "sBytes": null,
165 "sString": null
166}`,
167 wantMessage: &pb3.Scalars{},
168 }, {
169 desc: "boolean",
170 inputMessage: &pb3.Scalars{},
171 inputText: `{"sBool": true}`,
172 wantMessage: &pb3.Scalars{
173 SBool: true,
174 },
175 }, {
176 desc: "not boolean",
177 inputMessage: &pb3.Scalars{},
178 inputText: `{"sBool": "true"}`,
179 wantErr: true,
180 }, {
181 desc: "float and double",
182 inputMessage: &pb3.Scalars{},
183 inputText: `{
184 "sFloat": 1.234,
185 "sDouble": 5.678
186}`,
187 wantMessage: &pb3.Scalars{
188 SFloat: 1.234,
189 SDouble: 5.678,
190 },
191 }, {
192 desc: "float and double in string",
193 inputMessage: &pb3.Scalars{},
194 inputText: `{
195 "sFloat": "1.234",
196 "sDouble": "5.678"
197}`,
198 wantMessage: &pb3.Scalars{
199 SFloat: 1.234,
200 SDouble: 5.678,
201 },
202 }, {
203 desc: "float and double in E notation",
204 inputMessage: &pb3.Scalars{},
205 inputText: `{
206 "sFloat": 12.34E-1,
207 "sDouble": 5.678e4
208}`,
209 wantMessage: &pb3.Scalars{
210 SFloat: 1.234,
211 SDouble: 56780,
212 },
213 }, {
214 desc: "float and double in string E notation",
215 inputMessage: &pb3.Scalars{},
216 inputText: `{
217 "sFloat": "12.34E-1",
218 "sDouble": "5.678e4"
219}`,
220 wantMessage: &pb3.Scalars{
221 SFloat: 1.234,
222 SDouble: 56780,
223 },
224 }, {
225 desc: "float exceeds limit",
226 inputMessage: &pb3.Scalars{},
227 inputText: `{"sFloat": 3.4e39}`,
228 wantErr: true,
229 }, {
230 desc: "float in string exceeds limit",
231 inputMessage: &pb3.Scalars{},
232 inputText: `{"sFloat": "-3.4e39"}`,
233 wantErr: true,
234 }, {
235 desc: "double exceeds limit",
236 inputMessage: &pb3.Scalars{},
237 inputText: `{"sFloat": -1.79e+309}`,
238 wantErr: true,
239 }, {
240 desc: "double in string exceeds limit",
241 inputMessage: &pb3.Scalars{},
242 inputText: `{"sFloat": "1.79e+309"}`,
243 wantErr: true,
244 }, {
245 desc: "infinites",
246 inputMessage: &pb3.Scalars{},
247 inputText: `{"sFloat": "Infinity", "sDouble": "-Infinity"}`,
248 wantMessage: &pb3.Scalars{
249 SFloat: float32(math.Inf(+1)),
250 SDouble: math.Inf(-1),
251 },
252 }, {
253 desc: "not float",
254 inputMessage: &pb3.Scalars{},
255 inputText: `{"sFloat": true}`,
256 wantErr: true,
257 }, {
258 desc: "not double",
259 inputMessage: &pb3.Scalars{},
260 inputText: `{"sDouble": "not a number"}`,
261 wantErr: true,
262 }, {
263 desc: "integers",
264 inputMessage: &pb3.Scalars{},
265 inputText: `{
266 "sInt32": 1234,
267 "sInt64": -1234,
268 "sUint32": 1e2,
269 "sUint64": 100E-2,
270 "sSint32": 1.0,
271 "sSint64": -1.0,
272 "sFixed32": 1.234e+5,
273 "sFixed64": 1200E-2,
274 "sSfixed32": -1.234e05,
275 "sSfixed64": -1200e-02
276}`,
277 wantMessage: &pb3.Scalars{
278 SInt32: 1234,
279 SInt64: -1234,
280 SUint32: 100,
281 SUint64: 1,
282 SSint32: 1,
283 SSint64: -1,
284 SFixed32: 123400,
285 SFixed64: 12,
286 SSfixed32: -123400,
287 SSfixed64: -12,
288 },
289 }, {
290 desc: "integers in string",
291 inputMessage: &pb3.Scalars{},
292 inputText: `{
293 "sInt32": "1234",
294 "sInt64": "-1234",
295 "sUint32": "1e2",
296 "sUint64": "100E-2",
297 "sSint32": "1.0",
298 "sSint64": "-1.0",
299 "sFixed32": "1.234e+5",
300 "sFixed64": "1200E-2",
301 "sSfixed32": "-1.234e05",
302 "sSfixed64": "-1200e-02"
303}`,
304 wantMessage: &pb3.Scalars{
305 SInt32: 1234,
306 SInt64: -1234,
307 SUint32: 100,
308 SUint64: 1,
309 SSint32: 1,
310 SSint64: -1,
311 SFixed32: 123400,
312 SFixed64: 12,
313 SSfixed32: -123400,
314 SSfixed64: -12,
315 },
316 }, {
317 desc: "integers in escaped string",
318 inputMessage: &pb3.Scalars{},
319 inputText: `{"sInt32": "\u0031\u0032"}`,
320 wantMessage: &pb3.Scalars{
321 SInt32: 12,
322 },
323 }, {
324 desc: "number is not an integer",
325 inputMessage: &pb3.Scalars{},
326 inputText: `{"sInt32": 1.001}`,
327 wantErr: true,
328 }, {
329 desc: "32-bit int exceeds limit",
330 inputMessage: &pb3.Scalars{},
331 inputText: `{"sInt32": 2e10}`,
332 wantErr: true,
333 }, {
334 desc: "64-bit int exceeds limit",
335 inputMessage: &pb3.Scalars{},
336 inputText: `{"sSfixed64": -9e19}`,
337 wantErr: true,
338 }, {
339 desc: "not integer",
340 inputMessage: &pb3.Scalars{},
341 inputText: `{"sInt32": "not a number"}`,
342 wantErr: true,
343 }, {
344 desc: "not unsigned integer",
345 inputMessage: &pb3.Scalars{},
346 inputText: `{"sUint32": "not a number"}`,
347 wantErr: true,
348 }, {
349 desc: "number is not an unsigned integer",
350 inputMessage: &pb3.Scalars{},
351 inputText: `{"sUint32": -1}`,
352 wantErr: true,
353 }, {
354 desc: "string",
355 inputMessage: &pb2.Scalars{},
356 inputText: `{"optString": "谷歌"}`,
357 wantMessage: &pb2.Scalars{
358 OptString: scalar.String("谷歌"),
359 },
360 }, {
361 desc: "string with invalid UTF-8",
362 inputMessage: &pb3.Scalars{},
363 inputText: "{\"sString\": \"\xff\"}",
364 wantMessage: &pb3.Scalars{
365 SString: "\xff",
366 },
367 wantErr: true,
368 }, {
369 desc: "not string",
370 inputMessage: &pb2.Scalars{},
371 inputText: `{"optString": 42}`,
372 wantErr: true,
373 }, {
374 desc: "bytes",
375 inputMessage: &pb3.Scalars{},
376 inputText: `{"sBytes": "aGVsbG8gd29ybGQ"}`,
377 wantMessage: &pb3.Scalars{
378 SBytes: []byte("hello world"),
379 },
380 }, {
381 desc: "bytes padded",
382 inputMessage: &pb3.Scalars{},
383 inputText: `{"sBytes": "aGVsbG8gd29ybGQ="}`,
384 wantMessage: &pb3.Scalars{
385 SBytes: []byte("hello world"),
386 },
387 }, {
388 desc: "not bytes",
389 inputMessage: &pb3.Scalars{},
390 inputText: `{"sBytes": true}`,
391 wantErr: true,
392 }, {
393 desc: "proto2 enum",
394 inputMessage: &pb2.Enums{},
395 inputText: `{
396 "optEnum": "ONE",
397 "optNestedEnum": "UNO"
398}`,
399 wantMessage: &pb2.Enums{
400 OptEnum: pb2.Enum_ONE.Enum(),
401 OptNestedEnum: pb2.Enums_UNO.Enum(),
402 },
403 }, {
404 desc: "proto3 enum",
405 inputMessage: &pb3.Enums{},
406 inputText: `{
407 "sEnum": "ONE",
408 "sNestedEnum": "DIEZ"
409}`,
410 wantMessage: &pb3.Enums{
411 SEnum: pb3.Enum_ONE,
412 SNestedEnum: pb3.Enums_DIEZ,
413 },
414 }, {
415 desc: "enum numeric value",
416 inputMessage: &pb3.Enums{},
417 inputText: `{
418 "sEnum": 2,
419 "sNestedEnum": 2
420}`,
421 wantMessage: &pb3.Enums{
422 SEnum: pb3.Enum_TWO,
423 SNestedEnum: pb3.Enums_DOS,
424 },
425 }, {
426 desc: "enum unnamed numeric value",
427 inputMessage: &pb3.Enums{},
428 inputText: `{
429 "sEnum": 101,
430 "sNestedEnum": -101
431}`,
432 wantMessage: &pb3.Enums{
433 SEnum: 101,
434 SNestedEnum: -101,
435 },
436 }, {
437 desc: "enum set to number string",
438 inputMessage: &pb3.Enums{},
439 inputText: `{
440 "sEnum": "1",
441}`,
442 wantErr: true,
443 }, {
444 desc: "enum set to invalid named",
445 inputMessage: &pb3.Enums{},
446 inputText: `{
447 "sEnum": "UNNAMED",
448}`,
449 wantErr: true,
450 }, {
451 desc: "enum set to not enum",
452 inputMessage: &pb3.Enums{},
453 inputText: `{
454 "sEnum": true,
455}`,
456 wantErr: true,
457 }, {
458 desc: "proto name",
459 inputMessage: &pb3.JSONNames{},
460 inputText: `{
461 "s_string": "proto name used"
462}`,
463 wantMessage: &pb3.JSONNames{
464 SString: "proto name used",
465 },
466 }, {
467 desc: "json_name",
468 inputMessage: &pb3.JSONNames{},
469 inputText: `{
470 "foo_bar": "json_name used"
471}`,
472 wantMessage: &pb3.JSONNames{
473 SString: "json_name used",
474 },
475 }, {
476 desc: "camelCase name",
477 inputMessage: &pb3.JSONNames{},
478 inputText: `{
479 "sString": "camelcase used"
480}`,
481 wantErr: true,
482 }, {
483 desc: "proto name and json_name",
484 inputMessage: &pb3.JSONNames{},
485 inputText: `{
486 "foo_bar": "json_name used",
487 "s_string": "proto name used"
488}`,
489 wantErr: true,
490 }, {
491 desc: "duplicate field names",
492 inputMessage: &pb3.JSONNames{},
493 inputText: `{
494 "foo_bar": "one",
495 "foo_bar": "two",
496}`,
497 wantErr: true,
498 }, {
499 desc: "null message",
500 inputMessage: &pb2.Nests{},
501 inputText: "null",
502 wantErr: true,
503 }, {
504 desc: "proto2 nested message not set",
505 inputMessage: &pb2.Nests{},
506 inputText: "{}",
507 wantMessage: &pb2.Nests{},
508 }, {
509 desc: "proto2 nested message set to null",
510 inputMessage: &pb2.Nests{},
511 inputText: `{
512 "optNested": null,
513 "optgroup": null
514}`,
515 wantMessage: &pb2.Nests{},
516 }, {
517 desc: "proto2 nested message set to empty",
518 inputMessage: &pb2.Nests{},
519 inputText: `{
520 "optNested": {},
521 "optgroup": {}
522}`,
523 wantMessage: &pb2.Nests{
524 OptNested: &pb2.Nested{},
525 Optgroup: &pb2.Nests_OptGroup{},
526 },
527 }, {
528 desc: "proto2 nested messages",
529 inputMessage: &pb2.Nests{},
530 inputText: `{
531 "optNested": {
532 "optString": "nested message",
533 "optNested": {
534 "optString": "another nested message"
535 }
536 }
537}`,
538 wantMessage: &pb2.Nests{
539 OptNested: &pb2.Nested{
540 OptString: scalar.String("nested message"),
541 OptNested: &pb2.Nested{
542 OptString: scalar.String("another nested message"),
543 },
544 },
545 },
546 }, {
547 desc: "proto2 groups",
548 inputMessage: &pb2.Nests{},
549 inputText: `{
550 "optgroup": {
551 "optString": "inside a group",
552 "optNested": {
553 "optString": "nested message inside a group"
554 },
555 "optnestedgroup": {
556 "optFixed32": 47
557 }
558 }
559}`,
560 wantMessage: &pb2.Nests{
561 Optgroup: &pb2.Nests_OptGroup{
562 OptString: scalar.String("inside a group"),
563 OptNested: &pb2.Nested{
564 OptString: scalar.String("nested message inside a group"),
565 },
566 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
567 OptFixed32: scalar.Uint32(47),
568 },
569 },
570 },
571 }, {
572 desc: "proto3 nested message not set",
573 inputMessage: &pb3.Nests{},
574 inputText: "{}",
575 wantMessage: &pb3.Nests{},
576 }, {
577 desc: "proto3 nested message set to null",
578 inputMessage: &pb3.Nests{},
579 inputText: `{"sNested": null}`,
580 wantMessage: &pb3.Nests{},
581 }, {
582 desc: "proto3 nested message set to empty",
583 inputMessage: &pb3.Nests{},
584 inputText: `{"sNested": {}}`,
585 wantMessage: &pb3.Nests{
586 SNested: &pb3.Nested{},
587 },
588 }, {
589 desc: "proto3 nested message",
590 inputMessage: &pb3.Nests{},
591 inputText: `{
592 "sNested": {
593 "sString": "nested message",
594 "sNested": {
595 "sString": "another nested message"
596 }
597 }
598}`,
599 wantMessage: &pb3.Nests{
600 SNested: &pb3.Nested{
601 SString: "nested message",
602 SNested: &pb3.Nested{
603 SString: "another nested message",
604 },
605 },
606 },
607 }, {
608 desc: "message set to non-message",
609 inputMessage: &pb3.Nests{},
610 inputText: `"not valid"`,
611 wantErr: true,
612 }, {
613 desc: "nested message set to non-message",
614 inputMessage: &pb3.Nests{},
615 inputText: `{"sNested": true}`,
616 wantErr: true,
617 }, {
618 desc: "oneof not set",
619 inputMessage: &pb3.Oneofs{},
620 inputText: "{}",
621 wantMessage: &pb3.Oneofs{},
622 }, {
623 desc: "oneof set to empty string",
624 inputMessage: &pb3.Oneofs{},
625 inputText: `{"oneofString": ""}`,
626 wantMessage: &pb3.Oneofs{
627 Union: &pb3.Oneofs_OneofString{},
628 },
629 }, {
630 desc: "oneof set to string",
631 inputMessage: &pb3.Oneofs{},
632 inputText: `{"oneofString": "hello"}`,
633 wantMessage: &pb3.Oneofs{
634 Union: &pb3.Oneofs_OneofString{
635 OneofString: "hello",
636 },
637 },
638 }, {
639 desc: "oneof set to enum",
640 inputMessage: &pb3.Oneofs{},
641 inputText: `{"oneofEnum": "ZERO"}`,
642 wantMessage: &pb3.Oneofs{
643 Union: &pb3.Oneofs_OneofEnum{
644 OneofEnum: pb3.Enum_ZERO,
645 },
646 },
647 }, {
648 desc: "oneof set to empty message",
649 inputMessage: &pb3.Oneofs{},
650 inputText: `{"oneofNested": {}}`,
651 wantMessage: &pb3.Oneofs{
652 Union: &pb3.Oneofs_OneofNested{
653 OneofNested: &pb3.Nested{},
654 },
655 },
656 }, {
657 desc: "oneof set to message",
658 inputMessage: &pb3.Oneofs{},
659 inputText: `{
660 "oneofNested": {
661 "sString": "nested message"
662 }
663}`,
664 wantMessage: &pb3.Oneofs{
665 Union: &pb3.Oneofs_OneofNested{
666 OneofNested: &pb3.Nested{
667 SString: "nested message",
668 },
669 },
670 },
671 }, {
672 desc: "repeated null fields",
673 inputMessage: &pb2.Repeats{},
674 inputText: `{
675 "rptString": null,
676 "rptInt32" : null,
677 "rptFloat" : null,
678 "rptBytes" : null
679}`,
680 wantMessage: &pb2.Repeats{},
681 }, {
682 desc: "repeated scalars",
683 inputMessage: &pb2.Repeats{},
684 inputText: `{
685 "rptString": ["hello", "world"],
686 "rptInt32" : [-1, 0, 1],
687 "rptBool" : [false, true]
688}`,
689 wantMessage: &pb2.Repeats{
690 RptString: []string{"hello", "world"},
691 RptInt32: []int32{-1, 0, 1},
692 RptBool: []bool{false, true},
693 },
694 }, {
695 desc: "repeated enums",
696 inputMessage: &pb2.Enums{},
697 inputText: `{
698 "rptEnum" : ["TEN", 1, 42],
699 "rptNestedEnum": ["DOS", 2, -47]
700}`,
701 wantMessage: &pb2.Enums{
702 RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
703 RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
704 },
705 }, {
706 desc: "repeated messages",
707 inputMessage: &pb2.Nests{},
708 inputText: `{
709 "rptNested": [
710 {
711 "optString": "repeat nested one"
712 },
713 {
714 "optString": "repeat nested two",
715 "optNested": {
716 "optString": "inside repeat nested two"
717 }
718 },
719 {}
720 ]
721}`,
722 wantMessage: &pb2.Nests{
723 RptNested: []*pb2.Nested{
724 {
725 OptString: scalar.String("repeat nested one"),
726 },
727 {
728 OptString: scalar.String("repeat nested two"),
729 OptNested: &pb2.Nested{
730 OptString: scalar.String("inside repeat nested two"),
731 },
732 },
733 {},
734 },
735 },
736 }, {
737 desc: "repeated groups",
738 inputMessage: &pb2.Nests{},
739 inputText: `{
740 "rptgroup": [
741 {
742 "rptString": ["hello", "world"]
743 },
744 {}
745 ]
746}
747`,
748 wantMessage: &pb2.Nests{
749 Rptgroup: []*pb2.Nests_RptGroup{
750 {
751 RptString: []string{"hello", "world"},
752 },
753 {},
754 },
755 },
756 }, {
757 desc: "repeated scalars containing invalid type",
758 inputMessage: &pb2.Repeats{},
759 inputText: `{"rptString": ["hello", null, "world"]}`,
760 wantErr: true,
761 }, {
762 desc: "repeated messages containing invalid type",
763 inputMessage: &pb2.Nests{},
764 inputText: `{"rptNested": [{}, null]}`,
765 wantErr: true,
766 }, {
767 desc: "map fields 1",
768 inputMessage: &pb3.Maps{},
769 inputText: `{
770 "int32ToStr": {
771 "-101": "-101",
772 "0" : "zero",
773 "255" : "0xff"
774 },
775 "boolToUint32": {
776 "false": 101,
777 "true" : "42"
778 }
779}`,
780 wantMessage: &pb3.Maps{
781 Int32ToStr: map[int32]string{
782 -101: "-101",
783 0xff: "0xff",
784 0: "zero",
785 },
786 BoolToUint32: map[bool]uint32{
787 true: 42,
788 false: 101,
789 },
790 },
791 }, {
792 desc: "map fields 2",
793 inputMessage: &pb3.Maps{},
794 inputText: `{
795 "uint64ToEnum": {
796 "1" : "ONE",
797 "2" : 2,
798 "10": 101
799 }
800}`,
801 wantMessage: &pb3.Maps{
802 Uint64ToEnum: map[uint64]pb3.Enum{
803 1: pb3.Enum_ONE,
804 2: pb3.Enum_TWO,
805 10: 101,
806 },
807 },
808 }, {
809 desc: "map fields 3",
810 inputMessage: &pb3.Maps{},
811 inputText: `{
812 "strToNested": {
813 "nested_one": {
814 "sString": "nested in a map"
815 },
816 "nested_two": {}
817 }
818}`,
819 wantMessage: &pb3.Maps{
820 StrToNested: map[string]*pb3.Nested{
821 "nested_one": {
822 SString: "nested in a map",
823 },
824 "nested_two": {},
825 },
826 },
827 }, {
828 desc: "map fields 4",
829 inputMessage: &pb3.Maps{},
830 inputText: `{
831 "strToOneofs": {
832 "nested": {
833 "oneofNested": {
834 "sString": "nested oneof in map field value"
835 }
836 },
837 "string": {
838 "oneofString": "hello"
839 }
840 }
841}`,
842 wantMessage: &pb3.Maps{
843 StrToOneofs: map[string]*pb3.Oneofs{
844 "string": {
845 Union: &pb3.Oneofs_OneofString{
846 OneofString: "hello",
847 },
848 },
849 "nested": {
850 Union: &pb3.Oneofs_OneofNested{
851 OneofNested: &pb3.Nested{
852 SString: "nested oneof in map field value",
853 },
854 },
855 },
856 },
857 },
858 }, {
859 desc: "map contains duplicate keys",
860 inputMessage: &pb3.Maps{},
861 inputText: `{
862 "int32ToStr": {
863 "0": "cero",
864 "0": "zero"
865 }
866}
867`,
868 wantErr: true,
869 }, {
870 desc: "map key empty string",
871 inputMessage: &pb3.Maps{},
872 inputText: `{
873 "strToNested": {
874 "": {}
875 }
876}`,
877 wantMessage: &pb3.Maps{
878 StrToNested: map[string]*pb3.Nested{
879 "": {},
880 },
881 },
882 }, {
883 desc: "map contains invalid key 1",
884 inputMessage: &pb3.Maps{},
885 inputText: `{
886 "int32ToStr": {
887 "invalid": "cero"
888}`,
889 wantErr: true,
890 }, {
891 desc: "map contains invalid key 2",
892 inputMessage: &pb3.Maps{},
893 inputText: `{
894 "int32ToStr": {
895 "1.02": "float"
896}`,
897 wantErr: true,
898 }, {
899 desc: "map contains invalid key 3",
900 inputMessage: &pb3.Maps{},
901 inputText: `{
902 "int32ToStr": {
903 "2147483648": "exceeds 32-bit integer max limit"
904}`,
905 wantErr: true,
906 }, {
907 desc: "map contains invalid key 4",
908 inputMessage: &pb3.Maps{},
909 inputText: `{
910 "uint64ToEnum": {
911 "-1": 0
912 }
913}`,
914 wantErr: true,
915 }, {
916 desc: "map contains invalid value",
917 inputMessage: &pb3.Maps{},
918 inputText: `{
919 "int32ToStr": {
920 "101": true
921}`,
922 wantErr: true,
923 }, {
924 desc: "map contains null for scalar value",
925 inputMessage: &pb3.Maps{},
926 inputText: `{
927 "int32ToStr": {
928 "101": null
929}`,
930 wantErr: true,
931 }, {
932 desc: "map contains null for message value",
933 inputMessage: &pb3.Maps{},
934 inputText: `{
935 "strToNested": {
936 "hello": null
937 }
938}`,
939 wantErr: true,
Herbie Onge52379a2019-03-15 18:00:19 -0700940 }, {
941 desc: "extensions of non-repeated fields",
942 inputMessage: &pb2.Extensions{},
943 inputText: `{
944 "optString": "non-extension field",
945 "optBool": true,
946 "optInt32": 42,
947 "[pb2.opt_ext_bool]": true,
948 "[pb2.opt_ext_nested]": {
949 "optString": "nested in an extension",
950 "opt_nested": {
951 "opt_string": "another nested in an extension"
952 }
953 },
954 "[pb2.opt_ext_string]": "extension field",
955 "[pb2.opt_ext_enum]": "TEN"
956}`,
957 wantMessage: func() proto.Message {
958 m := &pb2.Extensions{
959 OptString: scalar.String("non-extension field"),
960 OptBool: scalar.Bool(true),
961 OptInt32: scalar.Int32(42),
962 }
963 setExtension(m, pb2.E_OptExtBool, true)
964 setExtension(m, pb2.E_OptExtString, "extension field")
965 setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
966 setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
967 OptString: scalar.String("nested in an extension"),
968 OptNested: &pb2.Nested{
969 OptString: scalar.String("another nested in an extension"),
970 },
971 })
972 return m
973 }(),
974 }, {
975 desc: "extensions of repeated fields",
976 inputMessage: &pb2.Extensions{},
977 inputText: `{
978 "[pb2.rpt_ext_enum]": ["TEN", 101, "ONE"],
979 "[pb2.rpt_ext_fixed32]": [42, 47],
980 "[pb2.rpt_ext_nested]": [
981 {"optString": "one"},
982 {"optString": "two"},
983 {"optString": "three"}
984 ]
985}`,
986 wantMessage: func() proto.Message {
987 m := &pb2.Extensions{}
988 setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
989 setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
990 setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
991 &pb2.Nested{OptString: scalar.String("one")},
992 &pb2.Nested{OptString: scalar.String("two")},
993 &pb2.Nested{OptString: scalar.String("three")},
994 })
995 return m
996 }(),
997 }, {
998 desc: "extensions of non-repeated fields in another message",
999 inputMessage: &pb2.Extensions{},
1000 inputText: `{
1001 "[pb2.ExtensionsContainer.opt_ext_bool]": true,
1002 "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
1003 "[pb2.ExtensionsContainer.opt_ext_nested]": {
1004 "optString": "nested in an extension",
1005 "optNested": {
1006 "optString": "another nested in an extension"
1007 }
1008 },
1009 "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
1010}`,
1011 wantMessage: func() proto.Message {
1012 m := &pb2.Extensions{}
1013 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
1014 setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
1015 setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
1016 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
1017 OptString: scalar.String("nested in an extension"),
1018 OptNested: &pb2.Nested{
1019 OptString: scalar.String("another nested in an extension"),
1020 },
1021 })
1022 return m
1023 }(),
1024 }, {
1025 desc: "extensions of repeated fields in another message",
1026 inputMessage: &pb2.Extensions{},
1027 inputText: `{
1028 "optString": "non-extension field",
1029 "optBool": true,
1030 "optInt32": 42,
1031 "[pb2.ExtensionsContainer.rpt_ext_nested]": [
1032 {"optString": "one"},
1033 {"optString": "two"},
1034 {"optString": "three"}
1035 ],
1036 "[pb2.ExtensionsContainer.rpt_ext_enum]": ["TEN", 101, "ONE"],
1037 "[pb2.ExtensionsContainer.rpt_ext_string]": ["hello", "world"]
1038}`,
1039 wantMessage: func() proto.Message {
1040 m := &pb2.Extensions{
1041 OptString: scalar.String("non-extension field"),
1042 OptBool: scalar.Bool(true),
1043 OptInt32: scalar.Int32(42),
1044 }
1045 setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
1046 setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
1047 setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
1048 &pb2.Nested{OptString: scalar.String("one")},
1049 &pb2.Nested{OptString: scalar.String("two")},
1050 &pb2.Nested{OptString: scalar.String("three")},
1051 })
1052 return m
1053 }(),
1054 }, {
1055 desc: "invalid extension field name",
1056 inputMessage: &pb2.Extensions{},
1057 inputText: `{ "[pb2.invalid_message_field]": true }`,
1058 wantErr: true,
1059 }, {
1060 desc: "MessageSet",
1061 inputMessage: &pb2.MessageSet{},
1062 inputText: `{
1063 "[pb2.MessageSetExtension]": {
1064 "optString": "a messageset extension"
1065 },
1066 "[pb2.MessageSetExtension.ext_nested]": {
1067 "optString": "just a regular extension"
1068 },
1069 "[pb2.MessageSetExtension.not_message_set_extension]": {
1070 "optString": "not a messageset extension"
1071 }
1072}`,
1073 wantMessage: func() proto.Message {
1074 m := &pb2.MessageSet{}
1075 setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
1076 OptString: scalar.String("a messageset extension"),
1077 })
1078 setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
1079 OptString: scalar.String("not a messageset extension"),
1080 })
1081 setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
1082 OptString: scalar.String("just a regular extension"),
1083 })
1084 return m
1085 }(),
1086 }, {
1087 desc: "extension field set to null",
1088 inputMessage: &pb2.Extensions{},
1089 inputText: `{
1090 "[pb2.ExtensionsContainer.opt_ext_bool]": null,
1091 "[pb2.ExtensionsContainer.opt_ext_nested]": null
1092}`,
1093 wantMessage: func() proto.Message {
1094 m := &pb2.Extensions{}
1095 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, nil)
1096 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, nil)
1097 return m
1098 }(),
1099 }, {
1100 desc: "extensions of repeated field contains null",
1101 inputMessage: &pb2.Extensions{},
1102 inputText: `{
1103 "[pb2.ExtensionsContainer.rpt_ext_nested]": [
1104 {"optString": "one"},
1105 null,
1106 {"optString": "three"}
1107 ],
1108}`,
1109 wantErr: true,
1110 }, {
1111 desc: "not real MessageSet 1",
1112 inputMessage: &pb2.FakeMessageSet{},
1113 inputText: `{
1114 "[pb2.FakeMessageSetExtension.message_set_extension]": {
1115 "optString": "not a messageset extension"
1116 }
1117}`,
1118 wantMessage: func() proto.Message {
1119 m := &pb2.FakeMessageSet{}
1120 setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
1121 OptString: scalar.String("not a messageset extension"),
1122 })
1123 return m
1124 }(),
1125 }, {
1126 desc: "not real MessageSet 2",
1127 inputMessage: &pb2.FakeMessageSet{},
1128 inputText: `{
1129 "[pb2.FakeMessageSetExtension]": {
1130 "optString": "not a messageset extension"
1131 }
1132}`,
1133 wantErr: true,
1134 }, {
1135 desc: "not real MessageSet 3",
1136 inputMessage: &pb2.MessageSet{},
1137 inputText: `{
1138 "[pb2.message_set_extension]": {
1139 "optString": "another not a messageset extension"
1140 }
1141}`,
1142 wantMessage: func() proto.Message {
1143 m := &pb2.MessageSet{}
1144 setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
1145 OptString: scalar.String("another not a messageset extension"),
1146 })
1147 return m
1148 }(),
Herbie Ongc96a79d2019-03-08 10:49:17 -08001149 }}
1150
1151 for _, tt := range tests {
1152 tt := tt
1153 t.Run(tt.desc, func(t *testing.T) {
1154 err := tt.umo.Unmarshal(tt.inputMessage, []byte(tt.inputText))
1155 if err != nil && !tt.wantErr {
1156 t.Errorf("Unmarshal() returned error: %v\n\n", err)
1157 }
1158 if err == nil && tt.wantErr {
1159 t.Error("Unmarshal() got nil error, want error\n\n")
1160 }
1161 if tt.wantMessage != nil && !protoV1.Equal(tt.inputMessage.(protoV1.Message), tt.wantMessage.(protoV1.Message)) {
1162 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
1163 }
1164 })
1165 }
1166}