blob: 648a3b19480755805add76055c0a80ab889b4c1e [file] [log] [blame]
Herbie Ongc96a79d2019-03-08 10:49:17 -08001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package jsonpb_test
6
7import (
8 "math"
9 "testing"
10
11 protoV1 "github.com/golang/protobuf/proto"
12 "github.com/golang/protobuf/v2/encoding/jsonpb"
13 "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
14 "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
15 "github.com/golang/protobuf/v2/internal/scalar"
16 "github.com/golang/protobuf/v2/proto"
Herbie Onge52379a2019-03-15 18:00:19 -070017 preg "github.com/golang/protobuf/v2/reflect/protoregistry"
Joe Tsai4fddeba2019-03-20 18:29:32 -070018 "github.com/golang/protobuf/v2/runtime/protoiface"
Herbie Onge63c4c42019-03-22 22:20:22 -070019
20 knownpb "github.com/golang/protobuf/v2/types/known"
Herbie Ongc96a79d2019-03-08 10:49:17 -080021)
22
Herbie Onge52379a2019-03-15 18:00:19 -070023func init() {
24 // TODO: remove these registerExtension calls when generated code registers
25 // to V2 global registry.
26 registerExtension(pb2.E_OptExtBool)
27 registerExtension(pb2.E_OptExtString)
28 registerExtension(pb2.E_OptExtEnum)
29 registerExtension(pb2.E_OptExtNested)
30 registerExtension(pb2.E_RptExtFixed32)
31 registerExtension(pb2.E_RptExtEnum)
32 registerExtension(pb2.E_RptExtNested)
33 registerExtension(pb2.E_ExtensionsContainer_OptExtBool)
34 registerExtension(pb2.E_ExtensionsContainer_OptExtString)
35 registerExtension(pb2.E_ExtensionsContainer_OptExtEnum)
36 registerExtension(pb2.E_ExtensionsContainer_OptExtNested)
37 registerExtension(pb2.E_ExtensionsContainer_RptExtString)
38 registerExtension(pb2.E_ExtensionsContainer_RptExtEnum)
39 registerExtension(pb2.E_ExtensionsContainer_RptExtNested)
40 registerExtension(pb2.E_MessageSetExtension)
41 registerExtension(pb2.E_MessageSetExtension_MessageSetExtension)
42 registerExtension(pb2.E_MessageSetExtension_NotMessageSetExtension)
43 registerExtension(pb2.E_MessageSetExtension_ExtNested)
44 registerExtension(pb2.E_FakeMessageSetExtension_MessageSetExtension)
45}
46
Joe Tsai4fddeba2019-03-20 18:29:32 -070047func registerExtension(xd *protoiface.ExtensionDescV1) {
Herbie Onge52379a2019-03-15 18:00:19 -070048 preg.GlobalTypes.Register(xd.Type)
49}
50
Herbie Ongc96a79d2019-03-08 10:49:17 -080051func TestUnmarshal(t *testing.T) {
52 tests := []struct {
53 desc string
54 umo jsonpb.UnmarshalOptions
55 inputMessage proto.Message
56 inputText string
57 wantMessage proto.Message
58 // TODO: verify expected error message substring.
59 wantErr bool
60 }{{
61 desc: "proto2 empty message",
62 inputMessage: &pb2.Scalars{},
63 inputText: "{}",
64 wantMessage: &pb2.Scalars{},
65 }, {
66 desc: "unexpected value instead of EOF",
67 inputMessage: &pb2.Scalars{},
68 inputText: "{} {}",
69 wantErr: true,
70 }, {
71 desc: "proto2 optional scalars set to zero values",
72 inputMessage: &pb2.Scalars{},
73 inputText: `{
74 "optBool": false,
75 "optInt32": 0,
76 "optInt64": 0,
77 "optUint32": 0,
78 "optUint64": 0,
79 "optSint32": 0,
80 "optSint64": 0,
81 "optFixed32": 0,
82 "optFixed64": 0,
83 "optSfixed32": 0,
84 "optSfixed64": 0,
85 "optFloat": 0,
86 "optDouble": 0,
87 "optBytes": "",
88 "optString": ""
89}`,
90 wantMessage: &pb2.Scalars{
91 OptBool: scalar.Bool(false),
92 OptInt32: scalar.Int32(0),
93 OptInt64: scalar.Int64(0),
94 OptUint32: scalar.Uint32(0),
95 OptUint64: scalar.Uint64(0),
96 OptSint32: scalar.Int32(0),
97 OptSint64: scalar.Int64(0),
98 OptFixed32: scalar.Uint32(0),
99 OptFixed64: scalar.Uint64(0),
100 OptSfixed32: scalar.Int32(0),
101 OptSfixed64: scalar.Int64(0),
102 OptFloat: scalar.Float32(0),
103 OptDouble: scalar.Float64(0),
104 OptBytes: []byte{},
105 OptString: scalar.String(""),
106 },
107 }, {
108 desc: "proto3 scalars set to zero values",
109 inputMessage: &pb3.Scalars{},
110 inputText: `{
111 "sBool": false,
112 "sInt32": 0,
113 "sInt64": 0,
114 "sUint32": 0,
115 "sUint64": 0,
116 "sSint32": 0,
117 "sSint64": 0,
118 "sFixed32": 0,
119 "sFixed64": 0,
120 "sSfixed32": 0,
121 "sSfixed64": 0,
122 "sFloat": 0,
123 "sDouble": 0,
124 "sBytes": "",
125 "sString": ""
126}`,
127 wantMessage: &pb3.Scalars{},
128 }, {
129 desc: "proto2 optional scalars set to null",
130 inputMessage: &pb2.Scalars{},
131 inputText: `{
132 "optBool": null,
133 "optInt32": null,
134 "optInt64": null,
135 "optUint32": null,
136 "optUint64": null,
137 "optSint32": null,
138 "optSint64": null,
139 "optFixed32": null,
140 "optFixed64": null,
141 "optSfixed32": null,
142 "optSfixed64": null,
143 "optFloat": null,
144 "optDouble": null,
145 "optBytes": null,
146 "optString": null
147}`,
148 wantMessage: &pb2.Scalars{},
149 }, {
150 desc: "proto3 scalars set to null",
151 inputMessage: &pb3.Scalars{},
152 inputText: `{
153 "sBool": null,
154 "sInt32": null,
155 "sInt64": null,
156 "sUint32": null,
157 "sUint64": null,
158 "sSint32": null,
159 "sSint64": null,
160 "sFixed32": null,
161 "sFixed64": null,
162 "sSfixed32": null,
163 "sSfixed64": null,
164 "sFloat": null,
165 "sDouble": null,
166 "sBytes": null,
167 "sString": null
168}`,
169 wantMessage: &pb3.Scalars{},
170 }, {
171 desc: "boolean",
172 inputMessage: &pb3.Scalars{},
173 inputText: `{"sBool": true}`,
174 wantMessage: &pb3.Scalars{
175 SBool: true,
176 },
177 }, {
178 desc: "not boolean",
179 inputMessage: &pb3.Scalars{},
180 inputText: `{"sBool": "true"}`,
181 wantErr: true,
182 }, {
183 desc: "float and double",
184 inputMessage: &pb3.Scalars{},
185 inputText: `{
186 "sFloat": 1.234,
187 "sDouble": 5.678
188}`,
189 wantMessage: &pb3.Scalars{
190 SFloat: 1.234,
191 SDouble: 5.678,
192 },
193 }, {
194 desc: "float and double in string",
195 inputMessage: &pb3.Scalars{},
196 inputText: `{
197 "sFloat": "1.234",
198 "sDouble": "5.678"
199}`,
200 wantMessage: &pb3.Scalars{
201 SFloat: 1.234,
202 SDouble: 5.678,
203 },
204 }, {
205 desc: "float and double in E notation",
206 inputMessage: &pb3.Scalars{},
207 inputText: `{
208 "sFloat": 12.34E-1,
209 "sDouble": 5.678e4
210}`,
211 wantMessage: &pb3.Scalars{
212 SFloat: 1.234,
213 SDouble: 56780,
214 },
215 }, {
216 desc: "float and double in string E notation",
217 inputMessage: &pb3.Scalars{},
218 inputText: `{
219 "sFloat": "12.34E-1",
220 "sDouble": "5.678e4"
221}`,
222 wantMessage: &pb3.Scalars{
223 SFloat: 1.234,
224 SDouble: 56780,
225 },
226 }, {
227 desc: "float exceeds limit",
228 inputMessage: &pb3.Scalars{},
229 inputText: `{"sFloat": 3.4e39}`,
230 wantErr: true,
231 }, {
232 desc: "float in string exceeds limit",
233 inputMessage: &pb3.Scalars{},
234 inputText: `{"sFloat": "-3.4e39"}`,
235 wantErr: true,
236 }, {
237 desc: "double exceeds limit",
238 inputMessage: &pb3.Scalars{},
239 inputText: `{"sFloat": -1.79e+309}`,
240 wantErr: true,
241 }, {
242 desc: "double in string exceeds limit",
243 inputMessage: &pb3.Scalars{},
244 inputText: `{"sFloat": "1.79e+309"}`,
245 wantErr: true,
246 }, {
247 desc: "infinites",
248 inputMessage: &pb3.Scalars{},
249 inputText: `{"sFloat": "Infinity", "sDouble": "-Infinity"}`,
250 wantMessage: &pb3.Scalars{
251 SFloat: float32(math.Inf(+1)),
252 SDouble: math.Inf(-1),
253 },
254 }, {
255 desc: "not float",
256 inputMessage: &pb3.Scalars{},
257 inputText: `{"sFloat": true}`,
258 wantErr: true,
259 }, {
260 desc: "not double",
261 inputMessage: &pb3.Scalars{},
262 inputText: `{"sDouble": "not a number"}`,
263 wantErr: true,
264 }, {
265 desc: "integers",
266 inputMessage: &pb3.Scalars{},
267 inputText: `{
268 "sInt32": 1234,
269 "sInt64": -1234,
270 "sUint32": 1e2,
271 "sUint64": 100E-2,
272 "sSint32": 1.0,
273 "sSint64": -1.0,
274 "sFixed32": 1.234e+5,
275 "sFixed64": 1200E-2,
276 "sSfixed32": -1.234e05,
277 "sSfixed64": -1200e-02
278}`,
279 wantMessage: &pb3.Scalars{
280 SInt32: 1234,
281 SInt64: -1234,
282 SUint32: 100,
283 SUint64: 1,
284 SSint32: 1,
285 SSint64: -1,
286 SFixed32: 123400,
287 SFixed64: 12,
288 SSfixed32: -123400,
289 SSfixed64: -12,
290 },
291 }, {
292 desc: "integers in string",
293 inputMessage: &pb3.Scalars{},
294 inputText: `{
295 "sInt32": "1234",
296 "sInt64": "-1234",
297 "sUint32": "1e2",
298 "sUint64": "100E-2",
299 "sSint32": "1.0",
300 "sSint64": "-1.0",
301 "sFixed32": "1.234e+5",
302 "sFixed64": "1200E-2",
303 "sSfixed32": "-1.234e05",
304 "sSfixed64": "-1200e-02"
305}`,
306 wantMessage: &pb3.Scalars{
307 SInt32: 1234,
308 SInt64: -1234,
309 SUint32: 100,
310 SUint64: 1,
311 SSint32: 1,
312 SSint64: -1,
313 SFixed32: 123400,
314 SFixed64: 12,
315 SSfixed32: -123400,
316 SSfixed64: -12,
317 },
318 }, {
319 desc: "integers in escaped string",
320 inputMessage: &pb3.Scalars{},
321 inputText: `{"sInt32": "\u0031\u0032"}`,
322 wantMessage: &pb3.Scalars{
323 SInt32: 12,
324 },
325 }, {
326 desc: "number is not an integer",
327 inputMessage: &pb3.Scalars{},
328 inputText: `{"sInt32": 1.001}`,
329 wantErr: true,
330 }, {
331 desc: "32-bit int exceeds limit",
332 inputMessage: &pb3.Scalars{},
333 inputText: `{"sInt32": 2e10}`,
334 wantErr: true,
335 }, {
336 desc: "64-bit int exceeds limit",
337 inputMessage: &pb3.Scalars{},
338 inputText: `{"sSfixed64": -9e19}`,
339 wantErr: true,
340 }, {
341 desc: "not integer",
342 inputMessage: &pb3.Scalars{},
343 inputText: `{"sInt32": "not a number"}`,
344 wantErr: true,
345 }, {
346 desc: "not unsigned integer",
347 inputMessage: &pb3.Scalars{},
348 inputText: `{"sUint32": "not a number"}`,
349 wantErr: true,
350 }, {
351 desc: "number is not an unsigned integer",
352 inputMessage: &pb3.Scalars{},
353 inputText: `{"sUint32": -1}`,
354 wantErr: true,
355 }, {
356 desc: "string",
357 inputMessage: &pb2.Scalars{},
358 inputText: `{"optString": "谷歌"}`,
359 wantMessage: &pb2.Scalars{
360 OptString: scalar.String("谷歌"),
361 },
362 }, {
363 desc: "string with invalid UTF-8",
364 inputMessage: &pb3.Scalars{},
365 inputText: "{\"sString\": \"\xff\"}",
366 wantMessage: &pb3.Scalars{
367 SString: "\xff",
368 },
369 wantErr: true,
370 }, {
371 desc: "not string",
372 inputMessage: &pb2.Scalars{},
373 inputText: `{"optString": 42}`,
374 wantErr: true,
375 }, {
376 desc: "bytes",
377 inputMessage: &pb3.Scalars{},
378 inputText: `{"sBytes": "aGVsbG8gd29ybGQ"}`,
379 wantMessage: &pb3.Scalars{
380 SBytes: []byte("hello world"),
381 },
382 }, {
383 desc: "bytes padded",
384 inputMessage: &pb3.Scalars{},
385 inputText: `{"sBytes": "aGVsbG8gd29ybGQ="}`,
386 wantMessage: &pb3.Scalars{
387 SBytes: []byte("hello world"),
388 },
389 }, {
390 desc: "not bytes",
391 inputMessage: &pb3.Scalars{},
392 inputText: `{"sBytes": true}`,
393 wantErr: true,
394 }, {
395 desc: "proto2 enum",
396 inputMessage: &pb2.Enums{},
397 inputText: `{
398 "optEnum": "ONE",
399 "optNestedEnum": "UNO"
400}`,
401 wantMessage: &pb2.Enums{
402 OptEnum: pb2.Enum_ONE.Enum(),
403 OptNestedEnum: pb2.Enums_UNO.Enum(),
404 },
405 }, {
406 desc: "proto3 enum",
407 inputMessage: &pb3.Enums{},
408 inputText: `{
409 "sEnum": "ONE",
410 "sNestedEnum": "DIEZ"
411}`,
412 wantMessage: &pb3.Enums{
413 SEnum: pb3.Enum_ONE,
414 SNestedEnum: pb3.Enums_DIEZ,
415 },
416 }, {
417 desc: "enum numeric value",
418 inputMessage: &pb3.Enums{},
419 inputText: `{
420 "sEnum": 2,
421 "sNestedEnum": 2
422}`,
423 wantMessage: &pb3.Enums{
424 SEnum: pb3.Enum_TWO,
425 SNestedEnum: pb3.Enums_DOS,
426 },
427 }, {
428 desc: "enum unnamed numeric value",
429 inputMessage: &pb3.Enums{},
430 inputText: `{
431 "sEnum": 101,
432 "sNestedEnum": -101
433}`,
434 wantMessage: &pb3.Enums{
435 SEnum: 101,
436 SNestedEnum: -101,
437 },
438 }, {
439 desc: "enum set to number string",
440 inputMessage: &pb3.Enums{},
441 inputText: `{
442 "sEnum": "1",
443}`,
444 wantErr: true,
445 }, {
446 desc: "enum set to invalid named",
447 inputMessage: &pb3.Enums{},
448 inputText: `{
449 "sEnum": "UNNAMED",
450}`,
451 wantErr: true,
452 }, {
453 desc: "enum set to not enum",
454 inputMessage: &pb3.Enums{},
455 inputText: `{
456 "sEnum": true,
457}`,
458 wantErr: true,
459 }, {
460 desc: "proto name",
461 inputMessage: &pb3.JSONNames{},
462 inputText: `{
463 "s_string": "proto name used"
464}`,
465 wantMessage: &pb3.JSONNames{
466 SString: "proto name used",
467 },
468 }, {
469 desc: "json_name",
470 inputMessage: &pb3.JSONNames{},
471 inputText: `{
472 "foo_bar": "json_name used"
473}`,
474 wantMessage: &pb3.JSONNames{
475 SString: "json_name used",
476 },
477 }, {
478 desc: "camelCase name",
479 inputMessage: &pb3.JSONNames{},
480 inputText: `{
481 "sString": "camelcase used"
482}`,
483 wantErr: true,
484 }, {
485 desc: "proto name and json_name",
486 inputMessage: &pb3.JSONNames{},
487 inputText: `{
488 "foo_bar": "json_name used",
489 "s_string": "proto name used"
490}`,
491 wantErr: true,
492 }, {
493 desc: "duplicate field names",
494 inputMessage: &pb3.JSONNames{},
495 inputText: `{
496 "foo_bar": "one",
497 "foo_bar": "two",
498}`,
499 wantErr: true,
500 }, {
501 desc: "null message",
502 inputMessage: &pb2.Nests{},
503 inputText: "null",
504 wantErr: true,
505 }, {
506 desc: "proto2 nested message not set",
507 inputMessage: &pb2.Nests{},
508 inputText: "{}",
509 wantMessage: &pb2.Nests{},
510 }, {
511 desc: "proto2 nested message set to null",
512 inputMessage: &pb2.Nests{},
513 inputText: `{
514 "optNested": null,
515 "optgroup": null
516}`,
517 wantMessage: &pb2.Nests{},
518 }, {
519 desc: "proto2 nested message set to empty",
520 inputMessage: &pb2.Nests{},
521 inputText: `{
522 "optNested": {},
523 "optgroup": {}
524}`,
525 wantMessage: &pb2.Nests{
526 OptNested: &pb2.Nested{},
527 Optgroup: &pb2.Nests_OptGroup{},
528 },
529 }, {
530 desc: "proto2 nested messages",
531 inputMessage: &pb2.Nests{},
532 inputText: `{
533 "optNested": {
534 "optString": "nested message",
535 "optNested": {
536 "optString": "another nested message"
537 }
538 }
539}`,
540 wantMessage: &pb2.Nests{
541 OptNested: &pb2.Nested{
542 OptString: scalar.String("nested message"),
543 OptNested: &pb2.Nested{
544 OptString: scalar.String("another nested message"),
545 },
546 },
547 },
548 }, {
549 desc: "proto2 groups",
550 inputMessage: &pb2.Nests{},
551 inputText: `{
552 "optgroup": {
553 "optString": "inside a group",
554 "optNested": {
555 "optString": "nested message inside a group"
556 },
557 "optnestedgroup": {
558 "optFixed32": 47
559 }
560 }
561}`,
562 wantMessage: &pb2.Nests{
563 Optgroup: &pb2.Nests_OptGroup{
564 OptString: scalar.String("inside a group"),
565 OptNested: &pb2.Nested{
566 OptString: scalar.String("nested message inside a group"),
567 },
568 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
569 OptFixed32: scalar.Uint32(47),
570 },
571 },
572 },
573 }, {
574 desc: "proto3 nested message not set",
575 inputMessage: &pb3.Nests{},
576 inputText: "{}",
577 wantMessage: &pb3.Nests{},
578 }, {
579 desc: "proto3 nested message set to null",
580 inputMessage: &pb3.Nests{},
581 inputText: `{"sNested": null}`,
582 wantMessage: &pb3.Nests{},
583 }, {
584 desc: "proto3 nested message set to empty",
585 inputMessage: &pb3.Nests{},
586 inputText: `{"sNested": {}}`,
587 wantMessage: &pb3.Nests{
588 SNested: &pb3.Nested{},
589 },
590 }, {
591 desc: "proto3 nested message",
592 inputMessage: &pb3.Nests{},
593 inputText: `{
594 "sNested": {
595 "sString": "nested message",
596 "sNested": {
597 "sString": "another nested message"
598 }
599 }
600}`,
601 wantMessage: &pb3.Nests{
602 SNested: &pb3.Nested{
603 SString: "nested message",
604 SNested: &pb3.Nested{
605 SString: "another nested message",
606 },
607 },
608 },
609 }, {
610 desc: "message set to non-message",
611 inputMessage: &pb3.Nests{},
612 inputText: `"not valid"`,
613 wantErr: true,
614 }, {
615 desc: "nested message set to non-message",
616 inputMessage: &pb3.Nests{},
617 inputText: `{"sNested": true}`,
618 wantErr: true,
619 }, {
620 desc: "oneof not set",
621 inputMessage: &pb3.Oneofs{},
622 inputText: "{}",
623 wantMessage: &pb3.Oneofs{},
624 }, {
625 desc: "oneof set to empty string",
626 inputMessage: &pb3.Oneofs{},
627 inputText: `{"oneofString": ""}`,
628 wantMessage: &pb3.Oneofs{
629 Union: &pb3.Oneofs_OneofString{},
630 },
631 }, {
632 desc: "oneof set to string",
633 inputMessage: &pb3.Oneofs{},
634 inputText: `{"oneofString": "hello"}`,
635 wantMessage: &pb3.Oneofs{
636 Union: &pb3.Oneofs_OneofString{
637 OneofString: "hello",
638 },
639 },
640 }, {
641 desc: "oneof set to enum",
642 inputMessage: &pb3.Oneofs{},
643 inputText: `{"oneofEnum": "ZERO"}`,
644 wantMessage: &pb3.Oneofs{
645 Union: &pb3.Oneofs_OneofEnum{
646 OneofEnum: pb3.Enum_ZERO,
647 },
648 },
649 }, {
650 desc: "oneof set to empty message",
651 inputMessage: &pb3.Oneofs{},
652 inputText: `{"oneofNested": {}}`,
653 wantMessage: &pb3.Oneofs{
654 Union: &pb3.Oneofs_OneofNested{
655 OneofNested: &pb3.Nested{},
656 },
657 },
658 }, {
659 desc: "oneof set to message",
660 inputMessage: &pb3.Oneofs{},
661 inputText: `{
662 "oneofNested": {
663 "sString": "nested message"
664 }
665}`,
666 wantMessage: &pb3.Oneofs{
667 Union: &pb3.Oneofs_OneofNested{
668 OneofNested: &pb3.Nested{
669 SString: "nested message",
670 },
671 },
672 },
673 }, {
674 desc: "repeated null fields",
675 inputMessage: &pb2.Repeats{},
676 inputText: `{
677 "rptString": null,
678 "rptInt32" : null,
679 "rptFloat" : null,
680 "rptBytes" : null
681}`,
682 wantMessage: &pb2.Repeats{},
683 }, {
684 desc: "repeated scalars",
685 inputMessage: &pb2.Repeats{},
686 inputText: `{
687 "rptString": ["hello", "world"],
688 "rptInt32" : [-1, 0, 1],
689 "rptBool" : [false, true]
690}`,
691 wantMessage: &pb2.Repeats{
692 RptString: []string{"hello", "world"},
693 RptInt32: []int32{-1, 0, 1},
694 RptBool: []bool{false, true},
695 },
696 }, {
697 desc: "repeated enums",
698 inputMessage: &pb2.Enums{},
699 inputText: `{
700 "rptEnum" : ["TEN", 1, 42],
701 "rptNestedEnum": ["DOS", 2, -47]
702}`,
703 wantMessage: &pb2.Enums{
704 RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
705 RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
706 },
707 }, {
708 desc: "repeated messages",
709 inputMessage: &pb2.Nests{},
710 inputText: `{
711 "rptNested": [
712 {
713 "optString": "repeat nested one"
714 },
715 {
716 "optString": "repeat nested two",
717 "optNested": {
718 "optString": "inside repeat nested two"
719 }
720 },
721 {}
722 ]
723}`,
724 wantMessage: &pb2.Nests{
725 RptNested: []*pb2.Nested{
726 {
727 OptString: scalar.String("repeat nested one"),
728 },
729 {
730 OptString: scalar.String("repeat nested two"),
731 OptNested: &pb2.Nested{
732 OptString: scalar.String("inside repeat nested two"),
733 },
734 },
735 {},
736 },
737 },
738 }, {
739 desc: "repeated groups",
740 inputMessage: &pb2.Nests{},
741 inputText: `{
742 "rptgroup": [
743 {
744 "rptString": ["hello", "world"]
745 },
746 {}
747 ]
748}
749`,
750 wantMessage: &pb2.Nests{
751 Rptgroup: []*pb2.Nests_RptGroup{
752 {
753 RptString: []string{"hello", "world"},
754 },
755 {},
756 },
757 },
758 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -0700759 desc: "repeated string contains invalid UTF8",
760 inputMessage: &pb2.Repeats{},
761 inputText: `{"rptString": ["` + "abc\xff" + `"]}`,
762 wantMessage: &pb2.Repeats{
763 RptString: []string{"abc\xff"},
764 },
765 wantErr: true,
766 }, {
767 desc: "repeated messages contain invalid UTF8",
768 inputMessage: &pb2.Nests{},
769 inputText: `{"rptNested": [{"optString": "` + "abc\xff" + `"}]}`,
770 wantMessage: &pb2.Nests{
771 RptNested: []*pb2.Nested{{OptString: scalar.String("abc\xff")}},
772 },
773 wantErr: true,
774 }, {
775 desc: "repeated scalars contain invalid type",
Herbie Ongc96a79d2019-03-08 10:49:17 -0800776 inputMessage: &pb2.Repeats{},
777 inputText: `{"rptString": ["hello", null, "world"]}`,
778 wantErr: true,
779 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -0700780 desc: "repeated messages contain invalid type",
Herbie Ongc96a79d2019-03-08 10:49:17 -0800781 inputMessage: &pb2.Nests{},
782 inputText: `{"rptNested": [{}, null]}`,
783 wantErr: true,
784 }, {
785 desc: "map fields 1",
786 inputMessage: &pb3.Maps{},
787 inputText: `{
788 "int32ToStr": {
789 "-101": "-101",
790 "0" : "zero",
791 "255" : "0xff"
792 },
793 "boolToUint32": {
794 "false": 101,
795 "true" : "42"
796 }
797}`,
798 wantMessage: &pb3.Maps{
799 Int32ToStr: map[int32]string{
800 -101: "-101",
801 0xff: "0xff",
802 0: "zero",
803 },
804 BoolToUint32: map[bool]uint32{
805 true: 42,
806 false: 101,
807 },
808 },
809 }, {
810 desc: "map fields 2",
811 inputMessage: &pb3.Maps{},
812 inputText: `{
813 "uint64ToEnum": {
814 "1" : "ONE",
815 "2" : 2,
816 "10": 101
817 }
818}`,
819 wantMessage: &pb3.Maps{
820 Uint64ToEnum: map[uint64]pb3.Enum{
821 1: pb3.Enum_ONE,
822 2: pb3.Enum_TWO,
823 10: 101,
824 },
825 },
826 }, {
827 desc: "map fields 3",
828 inputMessage: &pb3.Maps{},
829 inputText: `{
830 "strToNested": {
831 "nested_one": {
832 "sString": "nested in a map"
833 },
834 "nested_two": {}
835 }
836}`,
837 wantMessage: &pb3.Maps{
838 StrToNested: map[string]*pb3.Nested{
839 "nested_one": {
840 SString: "nested in a map",
841 },
842 "nested_two": {},
843 },
844 },
845 }, {
846 desc: "map fields 4",
847 inputMessage: &pb3.Maps{},
848 inputText: `{
849 "strToOneofs": {
850 "nested": {
851 "oneofNested": {
852 "sString": "nested oneof in map field value"
853 }
854 },
855 "string": {
856 "oneofString": "hello"
857 }
858 }
859}`,
860 wantMessage: &pb3.Maps{
861 StrToOneofs: map[string]*pb3.Oneofs{
862 "string": {
863 Union: &pb3.Oneofs_OneofString{
864 OneofString: "hello",
865 },
866 },
867 "nested": {
868 Union: &pb3.Oneofs_OneofNested{
869 OneofNested: &pb3.Nested{
870 SString: "nested oneof in map field value",
871 },
872 },
873 },
874 },
875 },
876 }, {
877 desc: "map contains duplicate keys",
878 inputMessage: &pb3.Maps{},
879 inputText: `{
880 "int32ToStr": {
881 "0": "cero",
882 "0": "zero"
883 }
884}
885`,
886 wantErr: true,
887 }, {
888 desc: "map key empty string",
889 inputMessage: &pb3.Maps{},
890 inputText: `{
891 "strToNested": {
892 "": {}
893 }
894}`,
895 wantMessage: &pb3.Maps{
896 StrToNested: map[string]*pb3.Nested{
897 "": {},
898 },
899 },
900 }, {
901 desc: "map contains invalid key 1",
902 inputMessage: &pb3.Maps{},
903 inputText: `{
904 "int32ToStr": {
905 "invalid": "cero"
906}`,
907 wantErr: true,
908 }, {
909 desc: "map contains invalid key 2",
910 inputMessage: &pb3.Maps{},
911 inputText: `{
912 "int32ToStr": {
913 "1.02": "float"
914}`,
915 wantErr: true,
916 }, {
917 desc: "map contains invalid key 3",
918 inputMessage: &pb3.Maps{},
919 inputText: `{
920 "int32ToStr": {
921 "2147483648": "exceeds 32-bit integer max limit"
922}`,
923 wantErr: true,
924 }, {
925 desc: "map contains invalid key 4",
926 inputMessage: &pb3.Maps{},
927 inputText: `{
928 "uint64ToEnum": {
929 "-1": 0
930 }
931}`,
932 wantErr: true,
933 }, {
934 desc: "map contains invalid value",
935 inputMessage: &pb3.Maps{},
936 inputText: `{
937 "int32ToStr": {
938 "101": true
939}`,
940 wantErr: true,
941 }, {
942 desc: "map contains null for scalar value",
943 inputMessage: &pb3.Maps{},
944 inputText: `{
945 "int32ToStr": {
946 "101": null
947}`,
948 wantErr: true,
949 }, {
950 desc: "map contains null for message value",
951 inputMessage: &pb3.Maps{},
952 inputText: `{
953 "strToNested": {
954 "hello": null
955 }
956}`,
957 wantErr: true,
Herbie Onge52379a2019-03-15 18:00:19 -0700958 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -0700959 desc: "map contains contains message value with invalid UTF8",
960 inputMessage: &pb3.Maps{},
961 inputText: `{
962 "strToNested": {
963 "hello": {
964 "sString": "` + "abc\xff" + `"
965 }
966 }
967}`,
968 wantMessage: &pb3.Maps{
969 StrToNested: map[string]*pb3.Nested{
970 "hello": {SString: "abc\xff"},
971 },
972 },
973 wantErr: true,
974 }, {
975 desc: "map key contains invalid UTF8",
976 inputMessage: &pb3.Maps{},
977 inputText: `{
978 "strToNested": {
979 "` + "abc\xff" + `": {}
980 }
981}`,
982 wantMessage: &pb3.Maps{
983 StrToNested: map[string]*pb3.Nested{
984 "abc\xff": {},
985 },
986 },
987 wantErr: true,
988 }, {
Herbie Onge52379a2019-03-15 18:00:19 -0700989 desc: "extensions of non-repeated fields",
990 inputMessage: &pb2.Extensions{},
991 inputText: `{
992 "optString": "non-extension field",
993 "optBool": true,
994 "optInt32": 42,
995 "[pb2.opt_ext_bool]": true,
996 "[pb2.opt_ext_nested]": {
997 "optString": "nested in an extension",
Herbie Onge63c4c42019-03-22 22:20:22 -0700998 "optNested": {
999 "optString": "another nested in an extension"
Herbie Onge52379a2019-03-15 18:00:19 -07001000 }
1001 },
1002 "[pb2.opt_ext_string]": "extension field",
1003 "[pb2.opt_ext_enum]": "TEN"
1004}`,
1005 wantMessage: func() proto.Message {
1006 m := &pb2.Extensions{
1007 OptString: scalar.String("non-extension field"),
1008 OptBool: scalar.Bool(true),
1009 OptInt32: scalar.Int32(42),
1010 }
1011 setExtension(m, pb2.E_OptExtBool, true)
1012 setExtension(m, pb2.E_OptExtString, "extension field")
1013 setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
1014 setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
1015 OptString: scalar.String("nested in an extension"),
1016 OptNested: &pb2.Nested{
1017 OptString: scalar.String("another nested in an extension"),
1018 },
1019 })
1020 return m
1021 }(),
1022 }, {
1023 desc: "extensions of repeated fields",
1024 inputMessage: &pb2.Extensions{},
1025 inputText: `{
1026 "[pb2.rpt_ext_enum]": ["TEN", 101, "ONE"],
1027 "[pb2.rpt_ext_fixed32]": [42, 47],
1028 "[pb2.rpt_ext_nested]": [
1029 {"optString": "one"},
1030 {"optString": "two"},
1031 {"optString": "three"}
1032 ]
1033}`,
1034 wantMessage: func() proto.Message {
1035 m := &pb2.Extensions{}
1036 setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
1037 setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
1038 setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
1039 &pb2.Nested{OptString: scalar.String("one")},
1040 &pb2.Nested{OptString: scalar.String("two")},
1041 &pb2.Nested{OptString: scalar.String("three")},
1042 })
1043 return m
1044 }(),
1045 }, {
1046 desc: "extensions of non-repeated fields in another message",
1047 inputMessage: &pb2.Extensions{},
1048 inputText: `{
1049 "[pb2.ExtensionsContainer.opt_ext_bool]": true,
1050 "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
1051 "[pb2.ExtensionsContainer.opt_ext_nested]": {
1052 "optString": "nested in an extension",
1053 "optNested": {
1054 "optString": "another nested in an extension"
1055 }
1056 },
1057 "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
1058}`,
1059 wantMessage: func() proto.Message {
1060 m := &pb2.Extensions{}
1061 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
1062 setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
1063 setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
1064 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
1065 OptString: scalar.String("nested in an extension"),
1066 OptNested: &pb2.Nested{
1067 OptString: scalar.String("another nested in an extension"),
1068 },
1069 })
1070 return m
1071 }(),
1072 }, {
1073 desc: "extensions of repeated fields in another message",
1074 inputMessage: &pb2.Extensions{},
1075 inputText: `{
1076 "optString": "non-extension field",
1077 "optBool": true,
1078 "optInt32": 42,
1079 "[pb2.ExtensionsContainer.rpt_ext_nested]": [
1080 {"optString": "one"},
1081 {"optString": "two"},
1082 {"optString": "three"}
1083 ],
1084 "[pb2.ExtensionsContainer.rpt_ext_enum]": ["TEN", 101, "ONE"],
1085 "[pb2.ExtensionsContainer.rpt_ext_string]": ["hello", "world"]
1086}`,
1087 wantMessage: func() proto.Message {
1088 m := &pb2.Extensions{
1089 OptString: scalar.String("non-extension field"),
1090 OptBool: scalar.Bool(true),
1091 OptInt32: scalar.Int32(42),
1092 }
1093 setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
1094 setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
1095 setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
1096 &pb2.Nested{OptString: scalar.String("one")},
1097 &pb2.Nested{OptString: scalar.String("two")},
1098 &pb2.Nested{OptString: scalar.String("three")},
1099 })
1100 return m
1101 }(),
1102 }, {
1103 desc: "invalid extension field name",
1104 inputMessage: &pb2.Extensions{},
1105 inputText: `{ "[pb2.invalid_message_field]": true }`,
1106 wantErr: true,
1107 }, {
1108 desc: "MessageSet",
1109 inputMessage: &pb2.MessageSet{},
1110 inputText: `{
1111 "[pb2.MessageSetExtension]": {
1112 "optString": "a messageset extension"
1113 },
1114 "[pb2.MessageSetExtension.ext_nested]": {
1115 "optString": "just a regular extension"
1116 },
1117 "[pb2.MessageSetExtension.not_message_set_extension]": {
1118 "optString": "not a messageset extension"
1119 }
1120}`,
1121 wantMessage: func() proto.Message {
1122 m := &pb2.MessageSet{}
1123 setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
1124 OptString: scalar.String("a messageset extension"),
1125 })
1126 setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
1127 OptString: scalar.String("not a messageset extension"),
1128 })
1129 setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
1130 OptString: scalar.String("just a regular extension"),
1131 })
1132 return m
1133 }(),
1134 }, {
1135 desc: "extension field set to null",
1136 inputMessage: &pb2.Extensions{},
1137 inputText: `{
1138 "[pb2.ExtensionsContainer.opt_ext_bool]": null,
1139 "[pb2.ExtensionsContainer.opt_ext_nested]": null
1140}`,
1141 wantMessage: func() proto.Message {
1142 m := &pb2.Extensions{}
1143 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, nil)
1144 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, nil)
1145 return m
1146 }(),
1147 }, {
1148 desc: "extensions of repeated field contains null",
1149 inputMessage: &pb2.Extensions{},
1150 inputText: `{
1151 "[pb2.ExtensionsContainer.rpt_ext_nested]": [
1152 {"optString": "one"},
1153 null,
1154 {"optString": "three"}
1155 ],
1156}`,
1157 wantErr: true,
1158 }, {
1159 desc: "not real MessageSet 1",
1160 inputMessage: &pb2.FakeMessageSet{},
1161 inputText: `{
1162 "[pb2.FakeMessageSetExtension.message_set_extension]": {
1163 "optString": "not a messageset extension"
1164 }
1165}`,
1166 wantMessage: func() proto.Message {
1167 m := &pb2.FakeMessageSet{}
1168 setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
1169 OptString: scalar.String("not a messageset extension"),
1170 })
1171 return m
1172 }(),
1173 }, {
1174 desc: "not real MessageSet 2",
1175 inputMessage: &pb2.FakeMessageSet{},
1176 inputText: `{
1177 "[pb2.FakeMessageSetExtension]": {
1178 "optString": "not a messageset extension"
1179 }
1180}`,
1181 wantErr: true,
1182 }, {
1183 desc: "not real MessageSet 3",
1184 inputMessage: &pb2.MessageSet{},
1185 inputText: `{
1186 "[pb2.message_set_extension]": {
1187 "optString": "another not a messageset extension"
1188 }
1189}`,
1190 wantMessage: func() proto.Message {
1191 m := &pb2.MessageSet{}
1192 setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
1193 OptString: scalar.String("another not a messageset extension"),
1194 })
1195 return m
1196 }(),
Herbie Onge63c4c42019-03-22 22:20:22 -07001197 }, {
1198 desc: "Empty",
1199 inputMessage: &knownpb.Empty{},
1200 inputText: `{}`,
1201 wantMessage: &knownpb.Empty{},
1202 }, {
1203 desc: "Empty contains unknown",
1204 inputMessage: &knownpb.Empty{},
1205 inputText: `{"unknown": null}`,
1206 wantErr: true,
1207 }, {
1208 desc: "BoolValue false",
1209 inputMessage: &knownpb.BoolValue{},
1210 inputText: `false`,
1211 wantMessage: &knownpb.BoolValue{},
1212 }, {
1213 desc: "BoolValue true",
1214 inputMessage: &knownpb.BoolValue{},
1215 inputText: `true`,
1216 wantMessage: &knownpb.BoolValue{Value: true},
1217 }, {
1218 desc: "BoolValue invalid value",
1219 inputMessage: &knownpb.BoolValue{},
1220 inputText: `{}`,
1221 wantErr: true,
1222 }, {
1223 desc: "Int32Value",
1224 inputMessage: &knownpb.Int32Value{},
1225 inputText: `42`,
1226 wantMessage: &knownpb.Int32Value{Value: 42},
1227 }, {
1228 desc: "Int32Value in JSON string",
1229 inputMessage: &knownpb.Int32Value{},
1230 inputText: `"1.23e3"`,
1231 wantMessage: &knownpb.Int32Value{Value: 1230},
1232 }, {
1233 desc: "Int64Value",
1234 inputMessage: &knownpb.Int64Value{},
1235 inputText: `"42"`,
1236 wantMessage: &knownpb.Int64Value{Value: 42},
1237 }, {
1238 desc: "UInt32Value",
1239 inputMessage: &knownpb.UInt32Value{},
1240 inputText: `42`,
1241 wantMessage: &knownpb.UInt32Value{Value: 42},
1242 }, {
1243 desc: "UInt64Value",
1244 inputMessage: &knownpb.UInt64Value{},
1245 inputText: `"42"`,
1246 wantMessage: &knownpb.UInt64Value{Value: 42},
1247 }, {
1248 desc: "FloatValue",
1249 inputMessage: &knownpb.FloatValue{},
1250 inputText: `1.02`,
1251 wantMessage: &knownpb.FloatValue{Value: 1.02},
1252 }, {
1253 desc: "FloatValue exceeds max limit",
1254 inputMessage: &knownpb.FloatValue{},
1255 inputText: `1.23+40`,
1256 wantErr: true,
1257 }, {
1258 desc: "FloatValue Infinity",
1259 inputMessage: &knownpb.FloatValue{},
1260 inputText: `"-Infinity"`,
1261 wantMessage: &knownpb.FloatValue{Value: float32(math.Inf(-1))},
1262 }, {
1263 desc: "DoubleValue",
1264 inputMessage: &knownpb.DoubleValue{},
1265 inputText: `1.02`,
1266 wantMessage: &knownpb.DoubleValue{Value: 1.02},
1267 }, {
1268 desc: "DoubleValue Infinity",
1269 inputMessage: &knownpb.DoubleValue{},
1270 inputText: `"Infinity"`,
1271 wantMessage: &knownpb.DoubleValue{Value: math.Inf(+1)},
1272 }, {
1273 desc: "StringValue empty",
1274 inputMessage: &knownpb.StringValue{},
1275 inputText: `""`,
1276 wantMessage: &knownpb.StringValue{},
1277 }, {
1278 desc: "StringValue",
1279 inputMessage: &knownpb.StringValue{},
1280 inputText: `"谷歌"`,
1281 wantMessage: &knownpb.StringValue{Value: "谷歌"},
1282 }, {
1283 desc: "StringValue with invalid UTF8 error",
1284 inputMessage: &knownpb.StringValue{},
1285 inputText: "\"abc\xff\"",
1286 wantMessage: &knownpb.StringValue{Value: "abc\xff"},
1287 wantErr: true,
1288 }, {
1289 desc: "StringValue field with invalid UTF8 error",
1290 inputMessage: &pb2.KnownTypes{},
1291 inputText: "{\n \"optString\": \"abc\xff\"\n}",
1292 wantMessage: &pb2.KnownTypes{
1293 OptString: &knownpb.StringValue{Value: "abc\xff"},
1294 },
1295 wantErr: true,
1296 }, {
1297 desc: "BytesValue",
1298 inputMessage: &knownpb.BytesValue{},
1299 inputText: `"aGVsbG8="`,
1300 wantMessage: &knownpb.BytesValue{Value: []byte("hello")},
1301 }, {
1302 desc: "Value null",
1303 inputMessage: &knownpb.Value{},
1304 inputText: `null`,
1305 wantMessage: &knownpb.Value{Kind: &knownpb.Value_NullValue{}},
1306 }, {
1307 desc: "Value field null",
1308 inputMessage: &pb2.KnownTypes{},
1309 inputText: `{
1310 "optValue": null
1311}`,
1312 wantMessage: &pb2.KnownTypes{
1313 OptValue: &knownpb.Value{Kind: &knownpb.Value_NullValue{}},
1314 },
1315 }, {
1316 desc: "Value bool",
1317 inputMessage: &knownpb.Value{},
1318 inputText: `false`,
1319 wantMessage: &knownpb.Value{Kind: &knownpb.Value_BoolValue{}},
1320 }, {
1321 desc: "Value field bool",
1322 inputMessage: &pb2.KnownTypes{},
1323 inputText: `{
1324 "optValue": true
1325}`,
1326 wantMessage: &pb2.KnownTypes{
1327 OptValue: &knownpb.Value{Kind: &knownpb.Value_BoolValue{true}},
1328 },
1329 }, {
1330 desc: "Value number",
1331 inputMessage: &knownpb.Value{},
1332 inputText: `1.02`,
1333 wantMessage: &knownpb.Value{Kind: &knownpb.Value_NumberValue{1.02}},
1334 }, {
1335 desc: "Value field number",
1336 inputMessage: &pb2.KnownTypes{},
1337 inputText: `{
1338 "optValue": 1.02
1339}`,
1340 wantMessage: &pb2.KnownTypes{
1341 OptValue: &knownpb.Value{Kind: &knownpb.Value_NumberValue{1.02}},
1342 },
1343 }, {
1344 desc: "Value string",
1345 inputMessage: &knownpb.Value{},
1346 inputText: `"hello"`,
1347 wantMessage: &knownpb.Value{Kind: &knownpb.Value_StringValue{"hello"}},
1348 }, {
1349 desc: "Value string with invalid UTF8",
1350 inputMessage: &knownpb.Value{},
1351 inputText: "\"\xff\"",
1352 wantMessage: &knownpb.Value{Kind: &knownpb.Value_StringValue{"\xff"}},
1353 wantErr: true,
1354 }, {
1355 desc: "Value field string",
1356 inputMessage: &pb2.KnownTypes{},
1357 inputText: `{
1358 "optValue": "NaN"
1359}`,
1360 wantMessage: &pb2.KnownTypes{
1361 OptValue: &knownpb.Value{Kind: &knownpb.Value_StringValue{"NaN"}},
1362 },
1363 }, {
1364 desc: "Value field string with invalid UTF8",
1365 inputMessage: &pb2.KnownTypes{},
1366 inputText: `{
1367 "optValue": "` + "\xff" + `"
1368}`,
1369 wantMessage: &pb2.KnownTypes{
1370 OptValue: &knownpb.Value{Kind: &knownpb.Value_StringValue{"\xff"}},
1371 },
1372 wantErr: true,
1373 }, {
1374 desc: "Value empty struct",
1375 inputMessage: &knownpb.Value{},
1376 inputText: `{}`,
1377 wantMessage: &knownpb.Value{
1378 Kind: &knownpb.Value_StructValue{
1379 &knownpb.Struct{Fields: map[string]*knownpb.Value{}},
1380 },
1381 },
1382 }, {
1383 desc: "Value struct",
1384 inputMessage: &knownpb.Value{},
1385 inputText: `{
1386 "string": "hello",
1387 "number": 123,
1388 "null": null,
1389 "bool": false,
1390 "struct": {
1391 "string": "world"
1392 },
1393 "list": []
1394}`,
1395 wantMessage: &knownpb.Value{
1396 Kind: &knownpb.Value_StructValue{
1397 &knownpb.Struct{
1398 Fields: map[string]*knownpb.Value{
1399 "string": {Kind: &knownpb.Value_StringValue{"hello"}},
1400 "number": {Kind: &knownpb.Value_NumberValue{123}},
1401 "null": {Kind: &knownpb.Value_NullValue{}},
1402 "bool": {Kind: &knownpb.Value_BoolValue{false}},
1403 "struct": {
1404 Kind: &knownpb.Value_StructValue{
1405 &knownpb.Struct{
1406 Fields: map[string]*knownpb.Value{
1407 "string": {Kind: &knownpb.Value_StringValue{"world"}},
1408 },
1409 },
1410 },
1411 },
1412 "list": {
1413 Kind: &knownpb.Value_ListValue{&knownpb.ListValue{}},
1414 },
1415 },
1416 },
1417 },
1418 },
1419 }, {
1420 desc: "Value struct with invalid UTF8 string",
1421 inputMessage: &knownpb.Value{},
1422 inputText: "{\"string\": \"abc\xff\"}",
1423 wantMessage: &knownpb.Value{
1424 Kind: &knownpb.Value_StructValue{
1425 &knownpb.Struct{
1426 Fields: map[string]*knownpb.Value{
1427 "string": {Kind: &knownpb.Value_StringValue{"abc\xff"}},
1428 },
1429 },
1430 },
1431 },
1432 wantErr: true,
1433 }, {
1434 desc: "Value field struct",
1435 inputMessage: &pb2.KnownTypes{},
1436 inputText: `{
1437 "optValue": {
1438 "string": "hello"
1439 }
1440}`,
1441 wantMessage: &pb2.KnownTypes{
1442 OptValue: &knownpb.Value{
1443 Kind: &knownpb.Value_StructValue{
1444 &knownpb.Struct{
1445 Fields: map[string]*knownpb.Value{
1446 "string": {Kind: &knownpb.Value_StringValue{"hello"}},
1447 },
1448 },
1449 },
1450 },
1451 },
1452 }, {
1453 desc: "Value empty list",
1454 inputMessage: &knownpb.Value{},
1455 inputText: `[]`,
1456 wantMessage: &knownpb.Value{
1457 Kind: &knownpb.Value_ListValue{
1458 &knownpb.ListValue{Values: []*knownpb.Value{}},
1459 },
1460 },
1461 }, {
1462 desc: "Value list",
1463 inputMessage: &knownpb.Value{},
1464 inputText: `[
1465 "string",
1466 123,
1467 null,
1468 true,
1469 {},
1470 [
1471 "string",
1472 1.23,
1473 null,
1474 false
1475 ]
1476]`,
1477 wantMessage: &knownpb.Value{
1478 Kind: &knownpb.Value_ListValue{
1479 &knownpb.ListValue{
1480 Values: []*knownpb.Value{
1481 {Kind: &knownpb.Value_StringValue{"string"}},
1482 {Kind: &knownpb.Value_NumberValue{123}},
1483 {Kind: &knownpb.Value_NullValue{}},
1484 {Kind: &knownpb.Value_BoolValue{true}},
1485 {Kind: &knownpb.Value_StructValue{&knownpb.Struct{}}},
1486 {
1487 Kind: &knownpb.Value_ListValue{
1488 &knownpb.ListValue{
1489 Values: []*knownpb.Value{
1490 {Kind: &knownpb.Value_StringValue{"string"}},
1491 {Kind: &knownpb.Value_NumberValue{1.23}},
1492 {Kind: &knownpb.Value_NullValue{}},
1493 {Kind: &knownpb.Value_BoolValue{false}},
1494 },
1495 },
1496 },
1497 },
1498 },
1499 },
1500 },
1501 },
1502 }, {
1503 desc: "Value list with invalid UTF8 string",
1504 inputMessage: &knownpb.Value{},
1505 inputText: "[\"abc\xff\"]",
1506 wantMessage: &knownpb.Value{
1507 Kind: &knownpb.Value_ListValue{
1508 &knownpb.ListValue{
1509 Values: []*knownpb.Value{
1510 {Kind: &knownpb.Value_StringValue{"abc\xff"}},
1511 },
1512 },
1513 },
1514 },
1515 wantErr: true,
1516 }, {
1517 desc: "Value field list with invalid UTF8 string",
1518 inputMessage: &pb2.KnownTypes{},
1519 inputText: `{
1520 "optValue": [ "` + "abc\xff" + `"]
1521}`,
1522 wantMessage: &pb2.KnownTypes{
1523 OptValue: &knownpb.Value{
1524 Kind: &knownpb.Value_ListValue{
1525 &knownpb.ListValue{
1526 Values: []*knownpb.Value{
1527 {Kind: &knownpb.Value_StringValue{"abc\xff"}},
1528 },
1529 },
1530 },
1531 },
1532 },
1533 wantErr: true,
1534 }, {
Herbie Ongc4450372019-03-27 09:59:51 -07001535 desc: "Duration empty string",
1536 inputMessage: &knownpb.Duration{},
1537 inputText: `""`,
1538 wantErr: true,
1539 }, {
1540 desc: "Duration with secs",
1541 inputMessage: &knownpb.Duration{},
1542 inputText: `"3s"`,
1543 wantMessage: &knownpb.Duration{Seconds: 3},
1544 }, {
1545 desc: "Duration with escaped unicode",
1546 inputMessage: &knownpb.Duration{},
1547 inputText: `"\u0033s"`,
1548 wantMessage: &knownpb.Duration{Seconds: 3},
1549 }, {
1550 desc: "Duration with -secs",
1551 inputMessage: &knownpb.Duration{},
1552 inputText: `"-3s"`,
1553 wantMessage: &knownpb.Duration{Seconds: -3},
1554 }, {
1555 desc: "Duration with nanos",
1556 inputMessage: &knownpb.Duration{},
1557 inputText: `"0.001s"`,
1558 wantMessage: &knownpb.Duration{Nanos: 1e6},
1559 }, {
1560 desc: "Duration with -nanos",
1561 inputMessage: &knownpb.Duration{},
1562 inputText: `"-0.001s"`,
1563 wantMessage: &knownpb.Duration{Nanos: -1e6},
1564 }, {
1565 desc: "Duration with -secs -nanos",
1566 inputMessage: &knownpb.Duration{},
1567 inputText: `"-123.000000450s"`,
1568 wantMessage: &knownpb.Duration{Seconds: -123, Nanos: -450},
1569 }, {
1570 desc: "Duration with large secs",
1571 inputMessage: &knownpb.Duration{},
1572 inputText: `"10000000000.000000001s"`,
1573 wantMessage: &knownpb.Duration{Seconds: 1e10, Nanos: 1},
1574 }, {
1575 desc: "Duration with decimal without fractional",
1576 inputMessage: &knownpb.Duration{},
1577 inputText: `"3.s"`,
1578 wantMessage: &knownpb.Duration{Seconds: 3},
1579 }, {
1580 desc: "Duration with decimal without integer",
1581 inputMessage: &knownpb.Duration{},
1582 inputText: `"0.5s"`,
1583 wantMessage: &knownpb.Duration{Nanos: 5e8},
1584 }, {
1585 desc: "Duration with +secs out of range",
1586 inputMessage: &knownpb.Duration{},
1587 inputText: `"315576000001s"`,
1588 wantErr: true,
1589 }, {
1590 desc: "Duration with -secs out of range",
1591 inputMessage: &knownpb.Duration{},
1592 inputText: `"-315576000001s"`,
1593 wantErr: true,
1594 }, {
1595 desc: "Duration with nanos beyond 9 digits",
1596 inputMessage: &knownpb.Duration{},
1597 inputText: `"0.9999999990s"`,
1598 wantErr: true,
1599 }, {
1600 desc: "Duration without suffix s",
1601 inputMessage: &knownpb.Duration{},
1602 inputText: `"123"`,
1603 wantErr: true,
1604 }, {
1605 desc: "Timestamp zero",
1606 inputMessage: &knownpb.Timestamp{},
1607 inputText: `"1970-01-01T00:00:00Z"`,
1608 wantMessage: &knownpb.Timestamp{},
1609 }, {
1610 desc: "Timestamp with tz adjustment",
1611 inputMessage: &knownpb.Timestamp{},
1612 inputText: `"1970-01-01T00:00:00+01:00"`,
1613 wantMessage: &knownpb.Timestamp{Seconds: -3600},
1614 }, {
1615 desc: "Timestamp UTC",
1616 inputMessage: &knownpb.Timestamp{},
1617 inputText: `"2019-03-19T23:03:21Z"`,
1618 wantMessage: &knownpb.Timestamp{Seconds: 1553036601},
1619 }, {
1620 desc: "Timestamp with escaped unicode",
1621 inputMessage: &knownpb.Timestamp{},
1622 inputText: `"2019-0\u0033-19T23:03:21Z"`,
1623 wantMessage: &knownpb.Timestamp{Seconds: 1553036601},
1624 }, {
1625 desc: "Timestamp with nanos",
1626 inputMessage: &knownpb.Timestamp{},
1627 inputText: `"2019-03-19T23:03:21.000000001Z"`,
1628 wantMessage: &knownpb.Timestamp{Seconds: 1553036601, Nanos: 1},
1629 }, {
1630 desc: "Timestamp upper limit",
1631 inputMessage: &knownpb.Timestamp{},
1632 inputText: `"9999-12-31T23:59:59.999999999Z"`,
1633 wantMessage: &knownpb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
1634 }, {
1635 desc: "Timestamp above upper limit",
1636 inputMessage: &knownpb.Timestamp{},
1637 inputText: `"9999-12-31T23:59:59-01:00"`,
1638 wantErr: true,
1639 }, {
1640 desc: "Timestamp lower limit",
1641 inputMessage: &knownpb.Timestamp{},
1642 inputText: `"0001-01-01T00:00:00Z"`,
1643 wantMessage: &knownpb.Timestamp{Seconds: -62135596800},
1644 }, {
1645 desc: "Timestamp below lower limit",
1646 inputMessage: &knownpb.Timestamp{},
1647 inputText: `"0001-01-01T00:00:00+01:00"`,
1648 wantErr: true,
1649 }, {
1650 desc: "Timestamp with nanos beyond 9 digits",
1651 inputMessage: &knownpb.Timestamp{},
1652 inputText: `"1970-01-01T00:00:00.0000000001Z"`,
1653 wantErr: true,
1654 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -07001655 desc: "FieldMask empty",
1656 inputMessage: &knownpb.FieldMask{},
1657 inputText: `""`,
1658 wantMessage: &knownpb.FieldMask{Paths: []string{}},
1659 }, {
1660 desc: "FieldMask",
1661 inputMessage: &knownpb.FieldMask{},
1662 inputText: `"foo,fooBar , foo.barQux ,Foo"`,
1663 wantMessage: &knownpb.FieldMask{
1664 Paths: []string{
1665 "foo",
1666 "foo_bar",
1667 "foo.bar_qux",
1668 "_foo",
1669 },
1670 },
1671 }, {
1672 desc: "FieldMask field",
1673 inputMessage: &pb2.KnownTypes{},
1674 inputText: `{
1675 "optFieldmask": "foo, qux.fooBar"
1676}`,
1677 wantMessage: &pb2.KnownTypes{
1678 OptFieldmask: &knownpb.FieldMask{
1679 Paths: []string{
1680 "foo",
1681 "qux.foo_bar",
1682 },
1683 },
1684 },
Herbie Ongc96a79d2019-03-08 10:49:17 -08001685 }}
1686
1687 for _, tt := range tests {
1688 tt := tt
1689 t.Run(tt.desc, func(t *testing.T) {
1690 err := tt.umo.Unmarshal(tt.inputMessage, []byte(tt.inputText))
1691 if err != nil && !tt.wantErr {
1692 t.Errorf("Unmarshal() returned error: %v\n\n", err)
1693 }
1694 if err == nil && tt.wantErr {
1695 t.Error("Unmarshal() got nil error, want error\n\n")
1696 }
1697 if tt.wantMessage != nil && !protoV1.Equal(tt.inputMessage.(protoV1.Message), tt.wantMessage.(protoV1.Message)) {
1698 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
1699 }
1700 })
1701 }
1702}