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