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