blob: e501fe536ed0a1c1188ae2403b990dce731dca4c [file] [log] [blame]
Herbie Ong800c9902018-12-06 15:28:53 -08001// Copyright 2018 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 textpb_test
6
7import (
8 "math"
9 "testing"
10
11 protoV1 "github.com/golang/protobuf/proto"
12 "github.com/golang/protobuf/v2/encoding/textpb"
13 "github.com/golang/protobuf/v2/internal/scalar"
Herbie Ong70651952018-12-13 14:19:50 -080014 "github.com/golang/protobuf/v2/proto"
Herbie Ong800c9902018-12-06 15:28:53 -080015
16 // The legacy package must be imported prior to use of any legacy messages.
17 // TODO: Remove this when protoV1 registers these hooks for you.
18 _ "github.com/golang/protobuf/v2/internal/legacy"
19
20 "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
21 "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
22)
23
24func TestUnmarshal(t *testing.T) {
Herbie Ong800c9902018-12-06 15:28:53 -080025 tests := []struct {
26 desc string
Herbie Ong70651952018-12-13 14:19:50 -080027 inputMessage proto.Message
Herbie Ong800c9902018-12-06 15:28:53 -080028 inputText string
Herbie Ong70651952018-12-13 14:19:50 -080029 wantMessage proto.Message
Herbie Ong800c9902018-12-06 15:28:53 -080030 wantErr bool
31 }{{
32 desc: "proto2 empty message",
33 inputMessage: &pb2.Scalars{},
34 wantMessage: &pb2.Scalars{},
35 }, {
36 desc: "proto2 optional scalar fields set to zero values",
37 inputMessage: &pb2.Scalars{},
38 inputText: `opt_bool: false
39opt_int32: 0
40opt_int64: 0
41opt_uint32: 0
42opt_uint64: 0
43opt_sint32: 0
44opt_sint64: 0
45opt_fixed32: 0
46opt_fixed64: 0
47opt_sfixed32: 0
48opt_sfixed64: 0
49opt_float: 0
50opt_double: 0
51opt_bytes: ""
52opt_string: ""
53`,
54 wantMessage: &pb2.Scalars{
55 OptBool: scalar.Bool(false),
56 OptInt32: scalar.Int32(0),
57 OptInt64: scalar.Int64(0),
58 OptUint32: scalar.Uint32(0),
59 OptUint64: scalar.Uint64(0),
60 OptSint32: scalar.Int32(0),
61 OptSint64: scalar.Int64(0),
62 OptFixed32: scalar.Uint32(0),
63 OptFixed64: scalar.Uint64(0),
64 OptSfixed32: scalar.Int32(0),
65 OptSfixed64: scalar.Int64(0),
66 OptFloat: scalar.Float32(0),
67 OptDouble: scalar.Float64(0),
68 OptBytes: []byte{},
69 OptString: scalar.String(""),
70 },
71 }, {
72 desc: "proto3 scalar fields set to zero values",
73 inputMessage: &pb3.Scalars{},
74 inputText: `s_bool: false
75s_int32: 0
76s_int64: 0
77s_uint32: 0
78s_uint64: 0
79s_sint32: 0
80s_sint64: 0
81s_fixed32: 0
82s_fixed64: 0
83s_sfixed32: 0
84s_sfixed64: 0
85s_float: 0
86s_double: 0
87s_bytes: ""
88s_string: ""
89`,
90 wantMessage: &pb3.Scalars{},
91 }, {
92 desc: "proto2 optional scalar fields",
93 inputMessage: &pb2.Scalars{},
94 inputText: `opt_bool: true
95opt_int32: 255
96opt_int64: 3735928559
97opt_uint32: 0xff
98opt_uint64: 0xdeadbeef
99opt_sint32: -1001
100opt_sint64: -0xffff
101opt_fixed64: 64
102opt_sfixed32: -32
103opt_float: 1.234
104opt_double: 1.23e+100
105opt_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
106opt_string: "谷歌"
107`,
108 wantMessage: &pb2.Scalars{
109 OptBool: scalar.Bool(true),
110 OptInt32: scalar.Int32(0xff),
111 OptInt64: scalar.Int64(0xdeadbeef),
112 OptUint32: scalar.Uint32(0xff),
113 OptUint64: scalar.Uint64(0xdeadbeef),
114 OptSint32: scalar.Int32(-1001),
115 OptSint64: scalar.Int64(-0xffff),
116 OptFixed64: scalar.Uint64(64),
117 OptSfixed32: scalar.Int32(-32),
118 OptFloat: scalar.Float32(1.234),
119 OptDouble: scalar.Float64(1.23e100),
120 OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
121 OptString: scalar.String("谷歌"),
122 },
123 }, {
124 desc: "proto3 scalar fields",
125 inputMessage: &pb3.Scalars{},
126 inputText: `s_bool: true
127s_int32: 255
128s_int64: 3735928559
129s_uint32: 0xff
130s_uint64: 0xdeadbeef
131s_sint32: -1001
132s_sint64: -0xffff
133s_fixed64: 64
134s_sfixed32: -32
135s_float: 1.234
136s_double: 1.23e+100
137s_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
138s_string: "谷歌"
139`,
140 wantMessage: &pb3.Scalars{
141 SBool: true,
142 SInt32: 0xff,
143 SInt64: 0xdeadbeef,
144 SUint32: 0xff,
145 SUint64: 0xdeadbeef,
146 SSint32: -1001,
147 SSint64: -0xffff,
148 SFixed64: 64,
149 SSfixed32: -32,
150 SFloat: 1.234,
151 SDouble: 1.23e100,
152 SBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
153 SString: "谷歌",
154 },
155 }, {
156 desc: "proto2 message contains unknown field",
157 inputMessage: &pb2.Scalars{},
158 inputText: "unknown_field: 123",
159 wantErr: true,
160 }, {
161 desc: "proto3 message contains unknown field",
162 inputMessage: &pb3.Scalars{},
163 inputText: "unknown_field: 456",
164 wantErr: true,
165 }, {
166 desc: "proto2 numeric key field",
167 inputMessage: &pb2.Scalars{},
168 inputText: "1: true",
169 wantErr: true,
170 }, {
171 desc: "proto3 numeric key field",
172 inputMessage: &pb3.Scalars{},
173 inputText: "1: true",
174 wantErr: true,
175 }, {
176 desc: "invalid bool value",
177 inputMessage: &pb3.Scalars{},
178 inputText: "s_bool: 123",
179 wantErr: true,
180 }, {
181 desc: "invalid int32 value",
182 inputMessage: &pb3.Scalars{},
183 inputText: "s_int32: not_a_num",
184 wantErr: true,
185 }, {
186 desc: "invalid int64 value",
187 inputMessage: &pb3.Scalars{},
188 inputText: "s_int64: 'not a num either'",
189 wantErr: true,
190 }, {
191 desc: "invalid uint32 value",
192 inputMessage: &pb3.Scalars{},
193 inputText: "s_fixed32: -42",
194 wantErr: true,
195 }, {
196 desc: "invalid uint64 value",
197 inputMessage: &pb3.Scalars{},
198 inputText: "s_uint64: -47",
199 wantErr: true,
200 }, {
201 desc: "invalid sint32 value",
202 inputMessage: &pb3.Scalars{},
203 inputText: "s_sint32: '42'",
204 wantErr: true,
205 }, {
206 desc: "invalid sint64 value",
207 inputMessage: &pb3.Scalars{},
208 inputText: "s_sint64: '-47'",
209 wantErr: true,
210 }, {
211 desc: "invalid fixed32 value",
212 inputMessage: &pb3.Scalars{},
213 inputText: "s_fixed32: -42",
214 wantErr: true,
215 }, {
216 desc: "invalid fixed64 value",
217 inputMessage: &pb3.Scalars{},
218 inputText: "s_fixed64: -42",
219 wantErr: true,
220 }, {
221 desc: "invalid sfixed32 value",
222 inputMessage: &pb3.Scalars{},
223 inputText: "s_sfixed32: 'not valid'",
224 wantErr: true,
225 }, {
226 desc: "invalid sfixed64 value",
227 inputMessage: &pb3.Scalars{},
228 inputText: "s_sfixed64: bad",
229 wantErr: true,
230 }, {
231 desc: "float32 positive infinity",
232 inputMessage: &pb3.Scalars{},
233 inputText: "s_float: inf",
234 wantMessage: &pb3.Scalars{
235 SFloat: float32(math.Inf(1)),
236 },
237 }, {
238 desc: "float32 negative infinity",
239 inputMessage: &pb3.Scalars{},
240 inputText: "s_float: -inf",
241 wantMessage: &pb3.Scalars{
242 SFloat: float32(math.Inf(-1)),
243 },
244 }, {
245 desc: "float64 positive infinity",
246 inputMessage: &pb3.Scalars{},
247 inputText: "s_double: inf",
248 wantMessage: &pb3.Scalars{
249 SDouble: math.Inf(1),
250 },
251 }, {
252 desc: "float64 negative infinity",
253 inputMessage: &pb3.Scalars{},
254 inputText: "s_double: -inf",
255 wantMessage: &pb3.Scalars{
256 SDouble: math.Inf(-1),
257 },
258 }, {
259 desc: "invalid string value",
260 inputMessage: &pb3.Scalars{},
261 inputText: "s_string: invalid_string",
262 wantErr: true,
263 }, {
264 desc: "proto2 bytes set to empty string",
265 inputMessage: &pb2.Scalars{},
266 inputText: "opt_bytes: ''",
267 wantMessage: &pb2.Scalars{
268 OptBytes: []byte(""),
269 },
270 }, {
271 desc: "proto3 bytes set to empty string",
272 inputMessage: &pb3.Scalars{},
273 inputText: "s_bytes: ''",
274 wantMessage: &pb3.Scalars{},
275 }, {
276 desc: "proto2 duplicate singular field",
277 inputMessage: &pb2.Scalars{},
278 inputText: `
279opt_bool: true
280opt_bool: false
281`,
282 wantErr: true,
283 }, {
284 desc: "proto2 invalid singular field",
285 inputMessage: &pb2.Scalars{},
286 inputText: `
287opt_bool: [true, false]
288`,
289 wantErr: true,
290 }, {
291 desc: "proto2 more duplicate singular field",
292 inputMessage: &pb2.Scalars{},
293 inputText: `
294opt_bool: true
295opt_string: "hello"
296opt_bool: false
297`,
298 wantErr: true,
299 }, {
300 desc: "proto3 duplicate singular field",
301 inputMessage: &pb3.Scalars{},
302 inputText: `
303s_bool: false
304s_bool: true
305`,
306 wantErr: true,
307 }, {
308 desc: "proto3 more duplicate singular field",
309 inputMessage: &pb3.Scalars{},
310 inputText: `
311s_bool: false
312s_string: ""
313s_bool: true
314`,
315 wantErr: true,
316 }, {
317 desc: "proto2 enum",
318 inputMessage: &pb2.Enums{},
319 inputText: `
320opt_enum: FIRST
321opt_nested_enum: UNO
322`,
323 wantMessage: &pb2.Enums{
324 OptEnum: pb2.Enum_FIRST.Enum(),
325 OptNestedEnum: pb2.Enums_UNO.Enum(),
326 },
327 }, {
328 desc: "proto2 enum set to numeric values",
329 inputMessage: &pb2.Enums{},
330 inputText: `
331opt_enum: 1
332opt_nested_enum: 2
333`,
334 wantMessage: &pb2.Enums{
335 OptEnum: pb2.Enum_FIRST.Enum(),
336 OptNestedEnum: pb2.Enums_DOS.Enum(),
337 },
338 }, {
339 desc: "proto2 enum set to unnamed numeric values",
340 inputMessage: &pb2.Enums{},
341 inputText: `
342opt_enum: 101
343opt_nested_enum: -101
344`,
345 wantMessage: &pb2.Enums{
346 OptEnum: pb2Enum(101),
347 OptNestedEnum: pb2Enums_NestedEnum(-101),
348 },
349 }, {
350 desc: "proto2 enum set to invalid named",
351 inputMessage: &pb2.Enums{},
352 inputText: `
353opt_enum: UNNAMED
354opt_nested_enum: UNNAMED_TOO
355`,
356 wantErr: true,
357 }, {
358 desc: "proto3 enum name value",
359 inputMessage: &pb3.Enums{},
360 inputText: `
361s_enum: ONE
362s_nested_enum: DIEZ
363`,
364 wantMessage: &pb3.Enums{
365 SEnum: pb3.Enum_ONE,
366 SNestedEnum: pb3.Enums_DIEZ,
367 },
368 }, {
369 desc: "proto3 enum numeric value",
370 inputMessage: &pb3.Enums{},
371 inputText: `
372s_enum: 2
373s_nested_enum: 1
374`,
375 wantMessage: &pb3.Enums{
376 SEnum: pb3.Enum_TWO,
377 SNestedEnum: pb3.Enums_UNO,
378 },
379 }, {
380 desc: "proto3 enum unnamed numeric value",
381 inputMessage: &pb3.Enums{},
382 inputText: `
383s_enum: 0x7fffffff
384s_nested_enum: -0x80000000
385`,
386 wantMessage: &pb3.Enums{
387 SEnum: 0x7fffffff,
388 SNestedEnum: -0x80000000,
389 },
390 }, {
391 desc: "proto2 nested empty messages",
392 inputMessage: &pb2.Nests{},
393 inputText: `
394opt_nested: {}
395optgroup: {}
396`,
397 wantMessage: &pb2.Nests{
398 OptNested: &pb2.Nested{},
399 Optgroup: &pb2.Nests_OptGroup{},
400 },
401 }, {
402 desc: "proto2 nested messages",
403 inputMessage: &pb2.Nests{},
404 inputText: `
405opt_nested: {
406 opt_string: "nested message"
407 opt_nested: {
408 opt_string: "another nested message"
409 }
410}
411`,
412 wantMessage: &pb2.Nests{
413 OptNested: &pb2.Nested{
414 OptString: scalar.String("nested message"),
415 OptNested: &pb2.Nested{
416 OptString: scalar.String("another nested message"),
417 },
418 },
419 },
420 }, {
421 desc: "proto3 nested empty message",
422 inputMessage: &pb3.Nests{},
423 inputText: "s_nested: {}",
424 wantMessage: &pb3.Nests{
425 SNested: &pb3.Nested{},
426 },
427 }, {
428 desc: "proto3 nested message",
429 inputMessage: &pb3.Nests{},
430 inputText: `
431s_nested: {
432 s_string: "nested message"
433 s_nested: {
434 s_string: "another nested message"
435 }
436}
437`,
438 wantMessage: &pb3.Nests{
439 SNested: &pb3.Nested{
440 SString: "nested message",
441 SNested: &pb3.Nested{
442 SString: "another nested message",
443 },
444 },
445 },
446 }, {
447 desc: "oneof field set to empty string",
448 inputMessage: &pb2.Oneofs{},
449 inputText: "str: ''",
450 wantMessage: &pb2.Oneofs{
451 Union: &pb2.Oneofs_Str{},
452 },
453 }, {
454 desc: "oneof field set to string",
455 inputMessage: &pb2.Oneofs{},
456 inputText: "str: 'hello'",
457 wantMessage: &pb2.Oneofs{
458 Union: &pb2.Oneofs_Str{
459 Str: "hello",
460 },
461 },
462 }, {
463 desc: "oneof field set to empty message",
464 inputMessage: &pb2.Oneofs{},
465 inputText: "msg: {}",
466 wantMessage: &pb2.Oneofs{
467 Union: &pb2.Oneofs_Msg{
468 Msg: &pb2.Nested{},
469 },
470 },
471 }, {
472 desc: "oneof field set to message",
473 inputMessage: &pb2.Oneofs{},
474 inputText: `
475msg: {
476 opt_string: "nested message"
477}
478`,
479 wantMessage: &pb2.Oneofs{
480 Union: &pb2.Oneofs_Msg{
481 Msg: &pb2.Nested{
482 OptString: scalar.String("nested message"),
483 },
484 },
485 },
486 }, {
487 desc: "repeated scalar using same field name",
488 inputMessage: &pb2.Repeats{},
489 inputText: `
490rpt_string: "a"
491rpt_string: "b"
492rpt_int32: 0xff
493rpt_float: 1.23
494rpt_bytes: "bytes"
495`,
496 wantMessage: &pb2.Repeats{
497 RptString: []string{"a", "b"},
498 RptInt32: []int32{0xff},
499 RptFloat: []float32{1.23},
500 RptBytes: [][]byte{[]byte("bytes")},
501 },
502 }, {
503 desc: "repeated using mix of [] and repeated field name",
504 inputMessage: &pb2.Repeats{},
505 inputText: `
506rpt_string: "a"
507rpt_bool: true
508rpt_string: ["x", "y"]
509rpt_bool: [ false, true ]
510rpt_string: "b"
511`,
512 wantMessage: &pb2.Repeats{
513 RptString: []string{"a", "x", "y", "b"},
514 RptBool: []bool{true, false, true},
515 },
516 }, {
517 desc: "repeated enums",
518 inputMessage: &pb2.Enums{},
519 inputText: `
520rpt_enum: TENTH
521rpt_enum: 1
522rpt_nested_enum: [DOS, 2]
523rpt_enum: 42
524rpt_nested_enum: -47
525`,
526 wantMessage: &pb2.Enums{
527 RptEnum: []pb2.Enum{pb2.Enum_TENTH, pb2.Enum_FIRST, 42},
528 RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
529 },
530 }, {
531 desc: "repeated nested messages",
532 inputMessage: &pb2.Nests{},
533 inputText: `
534rpt_nested: {
535 opt_string: "repeat nested one"
536}
537rpt_nested: {
538 opt_string: "repeat nested two"
539 opt_nested: {
540 opt_string: "inside repeat nested two"
541 }
542}
543rpt_nested: {}
544`,
545 wantMessage: &pb2.Nests{
546 RptNested: []*pb2.Nested{
547 {
548 OptString: scalar.String("repeat nested one"),
549 },
550 {
551 OptString: scalar.String("repeat nested two"),
552 OptNested: &pb2.Nested{
553 OptString: scalar.String("inside repeat nested two"),
554 },
555 },
556 {},
557 },
558 },
559 }, {
560 desc: "repeated group fields",
561 inputMessage: &pb2.Nests{},
562 inputText: `
563rptgroup: {
564 rpt_bool: true
565 rpt_bool: false
566}
567rptgroup: {}
568`,
569 wantMessage: &pb2.Nests{
570 Rptgroup: []*pb2.Nests_RptGroup{
571 {
572 RptBool: []bool{true, false},
573 },
574 {},
575 },
576 },
577 }, {
578 desc: "map fields 1",
579 inputMessage: &pb2.Maps{},
580 inputText: `
581int32_to_str: {
582 key: -101
583 value: "-101"
584}
585int32_to_str: {
586 key: 0
587 value: "zero"
588}
589sfixed64_to_bool: {
590 key: 0
591 value: false
592}
593int32_to_str: {
594 key: 255
595 value: "0xff"
596}
597bool_to_uint32: {
598 key: false
599 value: 101
600}
601sfixed64_to_bool: {
602 key: 51966
603 value: true
604}
605bool_to_uint32: {
606 key: true
607 value: 42
608}
609`,
610 wantMessage: &pb2.Maps{
611 Int32ToStr: map[int32]string{
612 -101: "-101",
613 0xff: "0xff",
614 0: "zero",
615 },
616 Sfixed64ToBool: map[int64]bool{
617 0xcafe: true,
618 0: false,
619 },
620 BoolToUint32: map[bool]uint32{
621 true: 42,
622 false: 101,
623 },
624 },
625 }, {
626 desc: "map fields 2",
627 inputMessage: &pb2.Maps{},
628 inputText: `
629uint64_to_enum: {
630 key: 1
631 value: FIRST
632}
633uint64_to_enum: {
634 key: 2
635 value: SECOND
636}
637uint64_to_enum: {
638 key: 10
639 value: TENTH
640}
641`,
642 wantMessage: &pb2.Maps{
643 Uint64ToEnum: map[uint64]pb2.Enum{
644 1: pb2.Enum_FIRST,
645 2: pb2.Enum_SECOND,
646 10: pb2.Enum_TENTH,
647 },
648 },
649 }, {
650 desc: "map fields 3",
651 inputMessage: &pb2.Maps{},
652 inputText: `
653str_to_nested: {
654 key: "nested_one"
655 value: {
656 opt_string: "nested in a map"
657 }
658}
659`,
660 wantMessage: &pb2.Maps{
661 StrToNested: map[string]*pb2.Nested{
662 "nested_one": &pb2.Nested{
663 OptString: scalar.String("nested in a map"),
664 },
665 },
666 },
667 }, {
668 desc: "map fields 4",
669 inputMessage: &pb2.Maps{},
670 inputText: `
671str_to_oneofs: {
672 key: "nested"
673 value: {
674 msg: {
675 opt_string: "nested oneof in map field value"
676 }
677 }
678}
679str_to_oneofs: {
680 key: "string"
681 value: {
682 str: "hello"
683 }
684}
685`,
686 wantMessage: &pb2.Maps{
687 StrToOneofs: map[string]*pb2.Oneofs{
688 "string": &pb2.Oneofs{
689 Union: &pb2.Oneofs_Str{
690 Str: "hello",
691 },
692 },
693 "nested": &pb2.Oneofs{
694 Union: &pb2.Oneofs_Msg{
695 Msg: &pb2.Nested{
696 OptString: scalar.String("nested oneof in map field value"),
697 },
698 },
699 },
700 },
701 },
702 }, {
703 desc: "map contains duplicate keys",
704 inputMessage: &pb2.Maps{},
705 inputText: `
706int32_to_str: {
707 key: 0
708 value: "cero"
709}
710int32_to_str: {
711 key: 0
712 value: "zero"
713}
714`,
715 wantMessage: &pb2.Maps{
716 Int32ToStr: map[int32]string{
717 0: "zero",
718 },
719 },
720 }, {
721 desc: "map contains duplicate key fields",
722 inputMessage: &pb2.Maps{},
723 inputText: `
724int32_to_str: {
725 key: 0
726 key: 1
727 value: "cero"
728}
729`,
730 wantErr: true,
731 }, {
732 desc: "map contains duplicate value fields",
733 inputMessage: &pb2.Maps{},
734 inputText: `
735int32_to_str: {
736 key: 1
737 value: "cero"
738 value: "uno"
739}
740`,
741 wantErr: true,
742 }, {
743 desc: "map contains missing key",
744 inputMessage: &pb2.Maps{},
745 inputText: `
746int32_to_str: {
747 value: "zero"
748}
749`,
750 wantMessage: &pb2.Maps{
751 Int32ToStr: map[int32]string{
752 0: "zero",
753 },
754 },
755 }, {
756 desc: "map contains missing value",
757 inputMessage: &pb2.Maps{},
758 inputText: `
759int32_to_str: {
760 key: 100
761}
762`,
763 wantMessage: &pb2.Maps{
764 Int32ToStr: map[int32]string{
765 100: "",
766 },
767 },
768 }, {
769 desc: "map contains missing key and value",
770 inputMessage: &pb2.Maps{},
771 inputText: `
772int32_to_str: {}
773`,
774 wantMessage: &pb2.Maps{
775 Int32ToStr: map[int32]string{
776 0: "",
777 },
778 },
779 }, {
780 desc: "map contains unknown field",
781 inputMessage: &pb2.Maps{},
782 inputText: `
783int32_to_str: {
784 key: 0
785 value: "cero"
786 unknown: "bad"
787}
788`,
789 wantErr: true,
790 }, {
791 desc: "map contains extension-like key field",
792 inputMessage: &pb2.Maps{},
793 inputText: `
794int32_to_str: {
795 [key]: 10
796 value: "ten"
797}
798`,
799 wantErr: true,
800 }, {
801 desc: "map contains invalid key",
802 inputMessage: &pb2.Maps{},
803 inputText: `
804int32_to_str: {
805 key: "invalid"
806 value: "cero"
807}
808`,
809 wantErr: true,
810 }, {
811 desc: "map contains invalid value",
812 inputMessage: &pb2.Maps{},
813 inputText: `
814int32_to_str: {
815 key: 100
816 value: 101
817}
818`,
819 wantErr: true,
820 }, {
821 desc: "map using mix of [] and repeated",
822 inputMessage: &pb2.Maps{},
823 inputText: `
824int32_to_str: {
825 key: 1
826 value: "one"
827}
828int32_to_str: [
829 {
830 key: 2
831 value: "not this"
832 },
833 {
834 },
835 {
836 key: 3
837 value: "three"
838 }
839]
840int32_to_str: {
841 key: 2
842 value: "two"
843}
844`,
845 wantMessage: &pb2.Maps{
846 Int32ToStr: map[int32]string{
847 0: "",
848 1: "one",
849 2: "two",
850 3: "three",
851 },
852 },
853 }, {
854 desc: "proto2 required fields not set",
855 inputMessage: &pb2.Requireds{},
856 wantErr: true,
857 }, {
858 desc: "proto2 required field set but not optional",
859 inputMessage: &pb2.PartialRequired{},
860 inputText: "req_string: 'this is required'",
861 wantMessage: &pb2.PartialRequired{
862 ReqString: scalar.String("this is required"),
863 },
864 }, {
865 desc: "proto2 required fields partially set",
866 inputMessage: &pb2.Requireds{},
867 inputText: `
868req_bool: false
869req_fixed32: 47
870req_sfixed64: 3203386110
871req_string: "hello"
872req_enum: FIRST
873`,
874 wantMessage: &pb2.Requireds{
875 ReqBool: scalar.Bool(false),
876 ReqFixed32: scalar.Uint32(47),
877 ReqSfixed64: scalar.Int64(0xbeefcafe),
878 ReqString: scalar.String("hello"),
879 ReqEnum: pb2.Enum_FIRST.Enum(),
880 },
881 wantErr: true,
882 }, {
883 desc: "proto2 required fields all set",
884 inputMessage: &pb2.Requireds{},
885 inputText: `
886req_bool: false
887req_fixed32: 0
888req_fixed64: 0
889req_sfixed32: 0
890req_sfixed64: 0
891req_float: 0
892req_double: 0
893req_string: ""
894req_bytes: ""
895req_enum: UNKNOWN
896req_nested: {}
897`,
898 wantMessage: &pb2.Requireds{
899 ReqBool: scalar.Bool(false),
900 ReqFixed32: scalar.Uint32(0),
901 ReqFixed64: scalar.Uint64(0),
902 ReqSfixed32: scalar.Int32(0),
903 ReqSfixed64: scalar.Int64(0),
904 ReqFloat: scalar.Float32(0),
905 ReqDouble: scalar.Float64(0),
906 ReqString: scalar.String(""),
907 ReqEnum: pb2.Enum_UNKNOWN.Enum(),
908 ReqBytes: []byte{},
909 ReqNested: &pb2.Nested{},
910 },
911 }, {
912 desc: "indirect required field",
913 inputMessage: &pb2.IndirectRequired{},
914 inputText: "opt_nested: {}",
915 wantMessage: &pb2.IndirectRequired{
916 OptNested: &pb2.NestedWithRequired{},
917 },
918 wantErr: true,
919 }, {
920 desc: "indirect required field in repeated",
921 inputMessage: &pb2.IndirectRequired{},
922 inputText: `
923rpt_nested: {
924 req_string: "one"
925}
926rpt_nested: {}
927rpt_nested: {
928 req_string: "three"
929}
930`,
931 wantMessage: &pb2.IndirectRequired{
932 RptNested: []*pb2.NestedWithRequired{
933 {
934 ReqString: scalar.String("one"),
935 },
936 {},
937 {
938 ReqString: scalar.String("three"),
939 },
940 },
941 },
942 wantErr: true,
943 }, {
944 desc: "indirect required field in map",
945 inputMessage: &pb2.IndirectRequired{},
946 inputText: `
947str_to_nested: {
948 key: "missing"
949}
950str_to_nested: {
951 key: "contains"
952 value: {
953 req_string: "here"
954 }
955}
956`,
957 wantMessage: &pb2.IndirectRequired{
958 StrToNested: map[string]*pb2.NestedWithRequired{
959 "missing": &pb2.NestedWithRequired{},
960 "contains": &pb2.NestedWithRequired{
961 ReqString: scalar.String("here"),
962 },
963 },
964 },
965 wantErr: true,
966 }}
967
968 for _, tt := range tests {
969 tt := tt
970 t.Run(tt.desc, func(t *testing.T) {
971 t.Parallel()
Herbie Ong70651952018-12-13 14:19:50 -0800972 err := textpb.Unmarshal(tt.inputMessage, []byte(tt.inputText))
Herbie Ong800c9902018-12-06 15:28:53 -0800973 if err != nil && !tt.wantErr {
974 t.Errorf("Unmarshal() returned error: %v\n\n", err)
975 }
976 if err == nil && tt.wantErr {
977 t.Error("Unmarshal() got nil error, want error\n\n")
978 }
Herbie Ong70651952018-12-13 14:19:50 -0800979 if tt.wantMessage != nil && !protoV1.Equal(tt.inputMessage.(protoV1.Message), tt.wantMessage.(protoV1.Message)) {
Herbie Ong800c9902018-12-06 15:28:53 -0800980 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
981 }
982 })
983 }
984}