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