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