1
2
3
4
5 package prototext_test
6
7 import (
8 "math"
9 "strings"
10 "testing"
11
12 "google.golang.org/protobuf/encoding/prototext"
13 "google.golang.org/protobuf/internal/flags"
14 "google.golang.org/protobuf/proto"
15 "google.golang.org/protobuf/reflect/protoregistry"
16
17 testpb "google.golang.org/protobuf/internal/testprotos/test"
18 weakpb "google.golang.org/protobuf/internal/testprotos/test/weak1"
19 pb2 "google.golang.org/protobuf/internal/testprotos/textpb2"
20 pb3 "google.golang.org/protobuf/internal/testprotos/textpb3"
21 pbeditions "google.golang.org/protobuf/internal/testprotos/textpbeditions"
22 "google.golang.org/protobuf/types/known/anypb"
23 )
24
25 func TestUnmarshal(t *testing.T) {
26 tests := []struct {
27 desc string
28 umo prototext.UnmarshalOptions
29 inputMessage proto.Message
30 inputText string
31 wantMessage proto.Message
32 wantErr string
33 skip bool
34 }{{
35 desc: "proto2 empty message",
36 inputMessage: &pb2.Scalars{},
37 wantMessage: &pb2.Scalars{},
38 }, {
39 desc: "proto2 optional scalars set to zero values",
40 inputMessage: &pb2.Scalars{},
41 inputText: `opt_bool: false
42 opt_int32: 0
43 opt_int64: 0
44 opt_uint32: 0
45 opt_uint64: 0
46 opt_sint32: 0
47 opt_sint64: 0
48 opt_fixed32: 0
49 opt_fixed64: 0
50 opt_sfixed32: 0
51 opt_sfixed64: 0
52 opt_float: 0
53 opt_double: 0
54 opt_bytes: ""
55 opt_string: ""
56 `,
57 wantMessage: &pb2.Scalars{
58 OptBool: proto.Bool(false),
59 OptInt32: proto.Int32(0),
60 OptInt64: proto.Int64(0),
61 OptUint32: proto.Uint32(0),
62 OptUint64: proto.Uint64(0),
63 OptSint32: proto.Int32(0),
64 OptSint64: proto.Int64(0),
65 OptFixed32: proto.Uint32(0),
66 OptFixed64: proto.Uint64(0),
67 OptSfixed32: proto.Int32(0),
68 OptSfixed64: proto.Int64(0),
69 OptFloat: proto.Float32(0),
70 OptDouble: proto.Float64(0),
71 OptBytes: []byte{},
72 OptString: proto.String(""),
73 },
74 }, {
75 desc: "protoeditions explicit scalars set to zero values",
76 inputMessage: &pbeditions.Scalars{},
77 inputText: `opt_bool: false
78 opt_int32: 0
79 opt_int64: 0
80 opt_uint32: 0
81 opt_uint64: 0
82 opt_sint32: 0
83 opt_sint64: 0
84 opt_fixed32: 0
85 opt_fixed64: 0
86 opt_sfixed32: 0
87 opt_sfixed64: 0
88 opt_float: 0
89 opt_double: 0
90 opt_bytes: ""
91 opt_string: ""
92 `,
93 wantMessage: &pbeditions.Scalars{
94 OptBool: proto.Bool(false),
95 OptInt32: proto.Int32(0),
96 OptInt64: proto.Int64(0),
97 OptUint32: proto.Uint32(0),
98 OptUint64: proto.Uint64(0),
99 OptSint32: proto.Int32(0),
100 OptSint64: proto.Int64(0),
101 OptFixed32: proto.Uint32(0),
102 OptFixed64: proto.Uint64(0),
103 OptSfixed32: proto.Int32(0),
104 OptSfixed64: proto.Int64(0),
105 OptFloat: proto.Float32(0),
106 OptDouble: proto.Float64(0),
107 OptBytes: []byte{},
108 OptString: proto.String(""),
109 },
110 }, {
111 desc: "protoeditions implicit scalars set to zero values",
112 inputMessage: &pbeditions.ImplicitScalars{},
113 inputText: `s_bool: false
114 s_int32: 0
115 s_int64: 0
116 s_uint32: 0
117 s_uint64: 0
118 s_sint32: 0
119 s_sint64: 0
120 s_fixed32: 0
121 s_fixed64: 0
122 s_sfixed32: 0
123 s_sfixed64: 0
124 s_float: 0
125 s_double: 0
126 s_bytes: ""
127 s_string: ""
128 `,
129 wantMessage: &pbeditions.ImplicitScalars{},
130 }, {
131 desc: "proto3 scalars set to zero values",
132 inputMessage: &pb3.Scalars{},
133 inputText: `s_bool: false
134 s_int32: 0
135 s_int64: 0
136 s_uint32: 0
137 s_uint64: 0
138 s_sint32: 0
139 s_sint64: 0
140 s_fixed32: 0
141 s_fixed64: 0
142 s_sfixed32: 0
143 s_sfixed64: 0
144 s_float: 0
145 s_double: 0
146 s_bytes: ""
147 s_string: ""
148 `,
149 wantMessage: &pb3.Scalars{},
150 }, {
151 desc: "proto3 optional set to zero values",
152 inputMessage: &pb3.Proto3Optional{},
153 inputText: `opt_bool: false
154 opt_int32: 0
155 opt_int64: 0
156 opt_uint32: 0
157 opt_uint64: 0
158 opt_float: 0
159 opt_double: 0
160 opt_string: ""
161 opt_bytes: ""
162 opt_enum: ZERO
163 opt_message: {}
164 `,
165 wantMessage: &pb3.Proto3Optional{
166 OptBool: proto.Bool(false),
167 OptInt32: proto.Int32(0),
168 OptInt64: proto.Int64(0),
169 OptUint32: proto.Uint32(0),
170 OptUint64: proto.Uint64(0),
171 OptFloat: proto.Float32(0),
172 OptDouble: proto.Float64(0),
173 OptString: proto.String(""),
174 OptBytes: []byte{},
175 OptEnum: pb3.Enum_ZERO.Enum(),
176 OptMessage: &pb3.Nested{},
177 },
178 }, {
179 desc: "proto2 optional scalars",
180 inputMessage: &pb2.Scalars{},
181 inputText: `opt_bool: true
182 opt_int32: 255
183 opt_int64: 3735928559
184 opt_uint32: 0xff
185 opt_uint64: 0xdeadbeef
186 opt_sint32: -1001
187 opt_sint64: - 0xffff
188 opt_fixed64: 64
189 opt_sfixed32: - 32
190 opt_float: 1.234
191 opt_double: 1.23e+100
192 opt_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
193 opt_string: "谷歌"
194 `,
195 wantMessage: &pb2.Scalars{
196 OptBool: proto.Bool(true),
197 OptInt32: proto.Int32(0xff),
198 OptInt64: proto.Int64(0xdeadbeef),
199 OptUint32: proto.Uint32(0xff),
200 OptUint64: proto.Uint64(0xdeadbeef),
201 OptSint32: proto.Int32(-1001),
202 OptSint64: proto.Int64(-0xffff),
203 OptFixed64: proto.Uint64(64),
204 OptSfixed32: proto.Int32(-32),
205 OptFloat: proto.Float32(1.234),
206 OptDouble: proto.Float64(1.23e100),
207 OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
208 OptString: proto.String("谷歌"),
209 },
210 }, {
211 desc: "protoeditions explicit scalars",
212 inputMessage: &pbeditions.Scalars{},
213 inputText: `opt_bool: true
214 opt_int32: 255
215 opt_int64: 3735928559
216 opt_uint32: 0xff
217 opt_uint64: 0xdeadbeef
218 opt_sint32: -1001
219 opt_sint64: - 0xffff
220 opt_fixed64: 64
221 opt_sfixed32: - 32
222 opt_float: 1.234
223 opt_double: 1.23e+100
224 opt_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
225 opt_string: "谷歌"
226 `,
227 wantMessage: &pbeditions.Scalars{
228 OptBool: proto.Bool(true),
229 OptInt32: proto.Int32(0xff),
230 OptInt64: proto.Int64(0xdeadbeef),
231 OptUint32: proto.Uint32(0xff),
232 OptUint64: proto.Uint64(0xdeadbeef),
233 OptSint32: proto.Int32(-1001),
234 OptSint64: proto.Int64(-0xffff),
235 OptFixed64: proto.Uint64(64),
236 OptSfixed32: proto.Int32(-32),
237 OptFloat: proto.Float32(1.234),
238 OptDouble: proto.Float64(1.23e100),
239 OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
240 OptString: proto.String("谷歌"),
241 },
242 }, {
243 desc: "case sensitive",
244 inputMessage: &pb3.Scalars{},
245 inputText: `S_BOOL: true`,
246 wantErr: "unknown field: S_BOOL",
247 }, {
248 desc: "proto3 scalars",
249 inputMessage: &pb3.Scalars{},
250 inputText: `s_bool: true
251 s_int32: 255
252 s_int64: 3735928559
253 s_uint32: 0xff
254 s_uint64: 0xdeadbeef
255 s_sint32: -1001
256 s_sint64: - #
257 0xffff
258 s_fixed64: 64
259 s_sfixed32: -32
260 s_float: 1.234
261 s_double: 1.23e+100
262 s_bytes: "\xe8\xb0\xb7\xe6\xad\x8c"
263 s_string: "谷歌"
264 `,
265 wantMessage: &pb3.Scalars{
266 SBool: true,
267 SInt32: 0xff,
268 SInt64: 0xdeadbeef,
269 SUint32: 0xff,
270 SUint64: 0xdeadbeef,
271 SSint32: -1001,
272 SSint64: -0xffff,
273 SFixed64: 64,
274 SSfixed32: -32,
275 SFloat: 1.234,
276 SDouble: 1.23e100,
277 SBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
278 SString: "谷歌",
279 },
280 }, {
281 desc: "proto2 string with invalid UTF-8",
282 inputMessage: &pb2.Scalars{},
283 inputText: `opt_string: "abc\xff"`,
284 wantMessage: &pb2.Scalars{
285 OptString: proto.String("abc\xff"),
286 },
287 }, {
288 desc: "protoeditions unvalidated string with invalid UTF-8",
289 inputMessage: &pbeditions.Scalars{},
290 inputText: `opt_string: "abc\xff"`,
291 wantMessage: &pbeditions.Scalars{
292 OptString: proto.String("abc\xff"),
293 },
294 }, {
295 desc: "proto3 string with invalid UTF-8",
296 inputMessage: &pb3.Scalars{},
297 inputText: `s_string: "abc\xff"`,
298 wantErr: "(line 1:11): contains invalid UTF-8",
299 }, {
300 desc: "proto2 message contains unknown field",
301 inputMessage: &pb2.Scalars{},
302 inputText: "unknown_field: 123",
303 wantErr: "unknown field",
304 }, {
305 desc: "proto3 message contains unknown field",
306 inputMessage: &pb3.Scalars{},
307 inputText: "unknown_field: 456",
308 wantErr: "unknown field",
309 }, {
310 desc: "proto2 message contains discarded unknown field",
311 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
312 inputMessage: &pb2.Scalars{},
313 inputText: `unknown_field:123 1000:"hello"`,
314 }, {
315 desc: "protoeditions message contains discarded unknown field",
316 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
317 inputMessage: &pbeditions.Scalars{},
318 inputText: `unknown_field:123 1000:"hello"`,
319 }, {
320 desc: "proto3 message contains discarded unknown field",
321 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
322 inputMessage: &pb3.Scalars{},
323 inputText: `unknown_field:456 1000:"goodbye"`,
324 }, {
325 desc: "proto2 message cannot parse field number",
326 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
327 inputMessage: &pb2.Scalars{},
328 inputText: `13:"hello"`,
329 wantErr: "cannot specify field by number",
330 }, {
331 desc: "unknown list field",
332 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
333 inputMessage: &pb2.Scalars{},
334 inputText: `unknown_field: { strings: [ "" ] }`,
335 }, {
336 desc: "unknown list of list field",
337 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
338 inputMessage: &pb2.Scalars{},
339 inputText: `unknown_field: { strings: [ [ ] ] }`,
340 wantErr: `(line 1:29): invalid scalar value: [`,
341 }, {
342 desc: "unknown list of message field",
343 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
344 inputMessage: &pb2.Scalars{},
345 inputText: `unknown_field: [ { a: "b" }, { c: "d" } ]`,
346 }, {
347 desc: "proto3 message cannot parse field number",
348 umo: prototext.UnmarshalOptions{DiscardUnknown: true},
349 inputMessage: &pb3.Scalars{},
350 inputText: `13:"goodbye"`,
351 wantErr: "cannot specify field by number",
352 }, {
353 desc: "proto2 numeric key field",
354 inputMessage: &pb2.Scalars{},
355 inputText: "1: true",
356 wantErr: "cannot specify field by number",
357 }, {
358 desc: "proto3 numeric key field",
359 inputMessage: &pb3.Scalars{},
360 inputText: "1: true",
361 wantErr: "cannot specify field by number",
362 }, {
363 desc: "invalid bool value",
364 inputMessage: &pb3.Scalars{},
365 inputText: "s_bool: 123",
366 wantErr: "invalid value for bool",
367 }, {
368 desc: "invalid int32 value",
369 inputMessage: &pb3.Scalars{},
370 inputText: "s_int32: not_a_num",
371 wantErr: "invalid value for int32",
372 }, {
373 desc: "invalid int64 value",
374 inputMessage: &pb3.Scalars{},
375 inputText: "s_int64: 'not a num either'",
376 wantErr: "invalid value for int64",
377 }, {
378 desc: "invalid uint32 value",
379 inputMessage: &pb3.Scalars{},
380 inputText: "s_fixed32: -42",
381 wantErr: "invalid value for fixed32",
382 }, {
383 desc: "invalid uint64 value",
384 inputMessage: &pb3.Scalars{},
385 inputText: "s_uint64: -47",
386 wantErr: "invalid value for uint64",
387 }, {
388 desc: "invalid sint32 value",
389 inputMessage: &pb3.Scalars{},
390 inputText: "s_sint32: '42'",
391 wantErr: "invalid value for sint32",
392 }, {
393 desc: "invalid sint64 value",
394 inputMessage: &pb3.Scalars{},
395 inputText: "s_sint64: '-47'",
396 wantErr: "invalid value for sint64",
397 }, {
398 desc: "invalid fixed32 value",
399 inputMessage: &pb3.Scalars{},
400 inputText: "s_fixed32: -42",
401 wantErr: "invalid value for fixed32",
402 }, {
403 desc: "invalid fixed64 value",
404 inputMessage: &pb3.Scalars{},
405 inputText: "s_fixed64: -42",
406 wantErr: "invalid value for fixed64",
407 }, {
408 desc: "invalid sfixed32 value",
409 inputMessage: &pb3.Scalars{},
410 inputText: "s_sfixed32: 'not valid'",
411 wantErr: "invalid value for sfixed32",
412 }, {
413 desc: "invalid sfixed64 value",
414 inputMessage: &pb3.Scalars{},
415 inputText: "s_sfixed64: bad",
416 wantErr: "invalid value for sfixed64",
417 }, {
418 desc: "incomplete number value",
419 inputMessage: &pb3.Scalars{},
420 inputText: `s_int32: - `,
421 wantErr: "(line 1:10): invalid scalar value: -",
422 }, {
423 desc: "conformance: FloatFieldMaxValue",
424 inputMessage: &pb2.Scalars{},
425 inputText: `opt_float: 3.4028235e+38`,
426 wantMessage: &pb2.Scalars{
427 OptFloat: proto.Float32(3.40282347e+38),
428 },
429 }, {
430 desc: "conformance: FloatFieldLargerThanUint64",
431 inputMessage: &pb2.Scalars{},
432 inputText: `opt_float: 18446744073709551616`,
433 wantMessage: &pb2.Scalars{
434 OptFloat: proto.Float32(1.84467441e+19),
435 },
436 }, {
437 desc: "conformance: FloatFieldTooLarge",
438 inputMessage: &pb2.Scalars{},
439 inputText: `opt_float: 3.4028235e+39`,
440 wantMessage: &pb2.Scalars{
441 OptFloat: proto.Float32(float32(math.Inf(1))),
442 },
443 }, {
444 desc: "invalid string value",
445 inputMessage: &pb3.Scalars{},
446 inputText: "s_string: invalid_string",
447 wantErr: "invalid value for string type",
448 }, {
449 desc: "proto2 bytes set to empty string",
450 inputMessage: &pb2.Scalars{},
451 inputText: "opt_bytes: ''",
452 wantMessage: &pb2.Scalars{
453 OptBytes: []byte(""),
454 },
455 }, {
456 desc: "proto3 bytes set to empty string",
457 inputMessage: &pb3.Scalars{},
458 inputText: "s_bytes: ''",
459 wantMessage: &pb3.Scalars{},
460 }, {
461 desc: "proto2 duplicate singular field",
462 inputMessage: &pb2.Scalars{},
463 inputText: `
464 opt_bool: true
465 opt_bool: false
466 `,
467 wantErr: `(line 3:1): non-repeated field "opt_bool" is repeated`,
468 }, {
469 desc: "proto2 more duplicate singular field",
470 inputMessage: &pb2.Scalars{},
471 inputText: `
472 opt_bool: true
473 opt_string: "hello"
474 opt_bool: false
475 `,
476 wantErr: `(line 4:1): non-repeated field "opt_bool" is repeated`,
477 }, {
478 desc: "proto2 invalid singular field",
479 inputMessage: &pb2.Scalars{},
480 inputText: `
481 opt_bool: [true, false]
482 `,
483 wantErr: "(line 2:11): unexpected token: [",
484 }, {
485 desc: "proto3 duplicate singular field",
486 inputMessage: &pb3.Scalars{},
487 inputText: `
488 s_bool: false
489 s_bool: true
490 `,
491 wantErr: `non-repeated field "s_bool" is repeated`,
492 }, {
493 desc: "proto3 more duplicate singular field",
494 inputMessage: &pb3.Scalars{},
495 inputText: `
496 s_bool: false
497 s_string: ""
498 s_bool: true
499 `,
500 wantErr: `non-repeated field "s_bool" is repeated`,
501 }, {
502 desc: "proto2 enum",
503 inputMessage: &pb2.Enums{},
504 inputText: `
505 opt_enum: ONE
506 opt_nested_enum: UNO
507 `,
508 wantMessage: &pb2.Enums{
509 OptEnum: pb2.Enum_ONE.Enum(),
510 OptNestedEnum: pb2.Enums_UNO.Enum(),
511 },
512 }, {
513 desc: "protoeditions closed enum",
514 inputMessage: &pbeditions.Enums{},
515 inputText: `
516 opt_enum: ONE
517 opt_nested_enum: UNO
518 `,
519 wantMessage: &pbeditions.Enums{
520 OptEnum: pbeditions.Enum_ONE.Enum(),
521 OptNestedEnum: pbeditions.Enums_UNO.Enum(),
522 },
523 }, {
524 desc: "protoeditions open enum",
525 inputMessage: &pbeditions.Enums{},
526 inputText: `
527 implicit_enum: EINS
528 implicit_nested_enum: ZEHN
529 `,
530 wantMessage: &pbeditions.Enums{
531 ImplicitEnum: pbeditions.OpenEnum_EINS,
532 ImplicitNestedEnum: pbeditions.Enums_ZEHN,
533 },
534 }, {
535 desc: "protoeditions enum numeric value",
536 inputMessage: &pbeditions.Enums{},
537 inputText: `
538 implicit_enum: 1
539 implicit_nested_enum: 10
540 `,
541 wantMessage: &pbeditions.Enums{
542 ImplicitEnum: pbeditions.OpenEnum_EINS,
543 ImplicitNestedEnum: pbeditions.Enums_ZEHN,
544 },
545 }, {
546 desc: "proto2 enum set to numeric values",
547 inputMessage: &pb2.Enums{},
548 inputText: `
549 opt_enum: 2
550 opt_nested_enum: 2
551 `,
552 wantMessage: &pb2.Enums{
553 OptEnum: pb2.Enum_TWO.Enum(),
554 OptNestedEnum: pb2.Enums_DOS.Enum(),
555 },
556 }, {
557 desc: "proto2 enum set to unnamed numeric values",
558 inputMessage: &pb2.Enums{},
559 inputText: `
560 opt_enum: 101
561 opt_nested_enum: -101
562 `,
563 wantMessage: &pb2.Enums{
564 OptEnum: pb2.Enum(101).Enum(),
565 OptNestedEnum: pb2.Enums_NestedEnum(-101).Enum(),
566 },
567 }, {
568 desc: "proto2 enum set to invalid named",
569 inputMessage: &pb2.Enums{},
570 inputText: `
571 opt_enum: UNNAMED
572 opt_nested_enum: UNNAMED_TOO
573 `,
574 wantErr: "invalid value for enum type: UNNAMED",
575 }, {
576 desc: "proto3 enum name value",
577 inputMessage: &pb3.Enums{},
578 inputText: `
579 s_enum: ONE
580 s_nested_enum: DIEZ
581 `,
582 wantMessage: &pb3.Enums{
583 SEnum: pb3.Enum_ONE,
584 SNestedEnum: pb3.Enums_DIEZ,
585 },
586 }, {
587 desc: "proto3 enum numeric value",
588 inputMessage: &pb3.Enums{},
589 inputText: `
590 s_enum: 2
591 s_nested_enum: 2
592 `,
593 wantMessage: &pb3.Enums{
594 SEnum: pb3.Enum_TWO,
595 SNestedEnum: pb3.Enums_DOS,
596 },
597 }, {
598 desc: "proto3 enum unnamed numeric value",
599 inputMessage: &pb3.Enums{},
600 inputText: `
601 s_enum: 0x7fffffff
602 s_nested_enum: -0x80000000
603 `,
604 wantMessage: &pb3.Enums{
605 SEnum: 0x7fffffff,
606 SNestedEnum: -0x80000000,
607 },
608 }, {
609 desc: "proto2 nested empty messages",
610 inputMessage: &pb2.Nests{},
611 inputText: `
612 opt_nested: {}
613 OptGroup: {}
614 `,
615 wantMessage: &pb2.Nests{
616 OptNested: &pb2.Nested{},
617 Optgroup: &pb2.Nests_OptGroup{},
618 },
619 }, {
620 desc: "protoeditions nested empty messages",
621 inputMessage: &pbeditions.Nests{},
622 inputText: `
623 opt_nested: {}
624 OptGroup: {}
625 delimited_field: {}
626 `,
627 wantMessage: &pbeditions.Nests{
628 OptNested: &pbeditions.Nested{},
629 Optgroup: &pbeditions.Nests_OptGroup{},
630 DelimitedField: &pbeditions.Nests_OptGroup{},
631 },
632 }, {
633 desc: "message fields with no field separator",
634 inputMessage: &pb2.Nests{},
635 inputText: `
636 opt_nested {}
637 OptGroup {}
638 `,
639 wantMessage: &pb2.Nests{
640 OptNested: &pb2.Nested{},
641 Optgroup: &pb2.Nests_OptGroup{},
642 },
643 }, {
644 desc: "message fields with no field separator",
645 inputMessage: &pbeditions.Nests{},
646 inputText: `
647 opt_nested {}
648 OptGroup {}
649 delimited_field {}
650 `,
651 wantMessage: &pbeditions.Nests{
652 OptNested: &pbeditions.Nested{},
653 Optgroup: &pbeditions.Nests_OptGroup{},
654 DelimitedField: &pbeditions.Nests_OptGroup{},
655 },
656 }, {
657 desc: "group field name",
658 inputMessage: &pb2.Nests{},
659 inputText: `optgroup: {}`,
660 wantMessage: &pb2.Nests{
661 Optgroup: &pb2.Nests_OptGroup{},
662 },
663 }, {
664 desc: "delimited encoded group-like message field name",
665 inputMessage: &pbeditions.Nests{},
666 inputText: `optgroup {}`,
667 wantMessage: &pbeditions.Nests{
668 Optgroup: &pbeditions.Nests_OptGroup{},
669 },
670 }, {
671 desc: "delimited encoded message field name",
672 inputMessage: &pbeditions.Nests{},
673 inputText: `Delimited_Field: {}`,
674 wantErr: "unknown field: Delimited_Field",
675 }, {
676 desc: "proto2 nested messages",
677 inputMessage: &pb2.Nests{},
678 inputText: `
679 opt_nested: {
680 opt_string: "nested message"
681 opt_nested: {
682 opt_string: "another nested message"
683 }
684 }
685 `,
686 wantMessage: &pb2.Nests{
687 OptNested: &pb2.Nested{
688 OptString: proto.String("nested message"),
689 OptNested: &pb2.Nested{
690 OptString: proto.String("another nested message"),
691 },
692 },
693 },
694 }, {
695 desc: "protoeditions delimited encoded nested messages",
696 inputMessage: &pbeditions.Nests{},
697 inputText: `
698 opt_nested: {
699 opt_string: "nested message"
700 opt_nested: {
701 opt_string: "another nested message"
702 }
703 }
704 `,
705 wantMessage: &pbeditions.Nests{
706 OptNested: &pbeditions.Nested{
707 OptString: proto.String("nested message"),
708 OptNested: &pbeditions.Nested{
709 OptString: proto.String("another nested message"),
710 },
711 },
712 },
713 }, {
714 desc: "proto3 nested empty message",
715 inputMessage: &pb3.Nests{},
716 inputText: "s_nested: {}",
717 wantMessage: &pb3.Nests{
718 SNested: &pb3.Nested{},
719 },
720 }, {
721 desc: "proto3 nested message",
722 inputMessage: &pb3.Nests{},
723 inputText: `
724 s_nested: {
725 s_string: "nested message"
726 s_nested: {
727 s_string: "another nested message"
728 }
729 }
730 `,
731 wantMessage: &pb3.Nests{
732 SNested: &pb3.Nested{
733 SString: "nested message",
734 SNested: &pb3.Nested{
735 SString: "another nested message",
736 },
737 },
738 },
739 }, {
740 desc: "proto3 nested message contains invalid UTF-8",
741 inputMessage: &pb3.Nests{},
742 inputText: `s_nested: {
743 s_string: "abc\xff"
744 }
745 `,
746 wantErr: "contains invalid UTF-8",
747 }, {
748 desc: "oneof set to empty string",
749 inputMessage: &pb3.Oneofs{},
750 inputText: "oneof_string: ''",
751 wantMessage: &pb3.Oneofs{
752 Union: &pb3.Oneofs_OneofString{},
753 },
754 }, {
755 desc: "oneof set to string",
756 inputMessage: &pb3.Oneofs{},
757 inputText: "oneof_string: 'hello'",
758 wantMessage: &pb3.Oneofs{
759 Union: &pb3.Oneofs_OneofString{
760 OneofString: "hello",
761 },
762 },
763 }, {
764 desc: "oneof set to enum",
765 inputMessage: &pb3.Oneofs{},
766 inputText: "oneof_enum: TEN",
767 wantMessage: &pb3.Oneofs{
768 Union: &pb3.Oneofs_OneofEnum{
769 OneofEnum: pb3.Enum_TEN,
770 },
771 },
772 }, {
773 desc: "oneof set to empty message",
774 inputMessage: &pb3.Oneofs{},
775 inputText: "oneof_nested: {}",
776 wantMessage: &pb3.Oneofs{
777 Union: &pb3.Oneofs_OneofNested{
778 OneofNested: &pb3.Nested{},
779 },
780 },
781 }, {
782 desc: "oneof set to message",
783 inputMessage: &pb3.Oneofs{},
784 inputText: `
785 oneof_nested: {
786 s_string: "nested message"
787 }
788 `,
789 wantMessage: &pb3.Oneofs{
790 Union: &pb3.Oneofs_OneofNested{
791 OneofNested: &pb3.Nested{
792 SString: "nested message",
793 },
794 },
795 },
796 }, {
797 desc: "oneof set to more than one field",
798 inputMessage: &pb3.Oneofs{},
799 inputText: `
800 oneof_enum: ZERO
801 oneof_string: "hello"
802 `,
803 wantErr: `error parsing "oneof_string", oneof pb3.Oneofs.union is already set`,
804 }, {
805 desc: "repeated scalar using same field name",
806 inputMessage: &pb2.Repeats{},
807 inputText: `
808 rpt_string: "a"
809 rpt_string: "b"
810 rpt_int32: 0xff
811 rpt_float: 1.23
812 rpt_bytes: "bytes"
813 `,
814 wantMessage: &pb2.Repeats{
815 RptString: []string{"a", "b"},
816 RptInt32: []int32{0xff},
817 RptFloat: []float32{1.23},
818 RptBytes: [][]byte{[]byte("bytes")},
819 },
820 }, {
821 desc: "repeated using mix of [] and repeated field name",
822 inputMessage: &pb2.Repeats{},
823 inputText: `
824 rpt_string: "a"
825 rpt_bool: true
826 rpt_string: ["x", "y"]
827 rpt_bool: [ false, true ]
828 rpt_string: "b"
829 `,
830 wantMessage: &pb2.Repeats{
831 RptString: []string{"a", "x", "y", "b"},
832 RptBool: []bool{true, false, true},
833 },
834 }, {
835 desc: "repeated proto2 contains invalid UTF-8",
836 inputMessage: &pb2.Repeats{},
837 inputText: `rpt_string: "abc\xff"`,
838 wantMessage: &pb2.Repeats{
839 RptString: []string{"abc\xff"},
840 },
841 }, {
842 desc: "repeated proto3 contains invalid UTF-8",
843 inputMessage: &pb3.Repeats{},
844 inputText: `rpt_string: "abc\xff"`,
845 wantErr: "contains invalid UTF-8",
846 }, {
847 desc: "repeated enums",
848 inputMessage: &pb2.Enums{},
849 inputText: `
850 rpt_enum: TEN
851 rpt_enum: 1
852 rpt_nested_enum: [DOS, 2]
853 rpt_enum: 42
854 rpt_nested_enum: -47
855 `,
856 wantMessage: &pb2.Enums{
857 RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
858 RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
859 },
860 }, {
861 desc: "repeated nested messages",
862 inputMessage: &pb2.Nests{},
863 inputText: `
864 rpt_nested: {
865 opt_string: "repeat nested one"
866 }
867 rpt_nested: {
868 opt_string: "repeat nested two"
869 opt_nested: {
870 opt_string: "inside repeat nested two"
871 }
872 }
873 rpt_nested: {}
874 `,
875 wantMessage: &pb2.Nests{
876 RptNested: []*pb2.Nested{
877 {
878 OptString: proto.String("repeat nested one"),
879 },
880 {
881 OptString: proto.String("repeat nested two"),
882 OptNested: &pb2.Nested{
883 OptString: proto.String("inside repeat nested two"),
884 },
885 },
886 {},
887 },
888 },
889 }, {
890 desc: "repeated group fields",
891 inputMessage: &pb2.Nests{},
892 inputText: `
893 RptGroup: {
894 rpt_string: "hello"
895 rpt_string: "world"
896 }
897 RptGroup: {}
898 `,
899 wantMessage: &pb2.Nests{
900 Rptgroup: []*pb2.Nests_RptGroup{
901 {
902 RptString: []string{"hello", "world"},
903 },
904 {},
905 },
906 },
907 }, {
908 desc: "repeated delimited encoded message fields",
909 inputMessage: &pbeditions.Nests{},
910 inputText: `
911 RptGroup: {
912 rpt_string: "hello"
913 rpt_string: "world"
914 }
915 RptGroup: {}
916 `,
917 wantMessage: &pbeditions.Nests{
918 Rptgroup: []*pbeditions.Nests_RptGroup{
919 {
920 RptString: []string{"hello", "world"},
921 },
922 {},
923 },
924 },
925 }, {
926 desc: "repeated message fields without field separator",
927 inputMessage: &pb2.Nests{},
928 inputText: `
929 rpt_nested {
930 opt_string: "repeat nested one"
931 }
932 rpt_nested: [
933 {
934 opt_string: "repeat nested two"
935 },
936 {}
937 ]
938 `,
939 wantMessage: &pb2.Nests{
940 RptNested: []*pb2.Nested{
941 {
942 OptString: proto.String("repeat nested one"),
943 },
944 {
945 OptString: proto.String("repeat nested two"),
946 },
947 {},
948 },
949 },
950 }, {
951 desc: "bools",
952 inputMessage: &pb2.Repeats{},
953 inputText: `
954 rpt_bool: [ True, true, t, 1, False, false, f, 0 ]
955 `,
956 wantMessage: &pb2.Repeats{
957 RptBool: []bool{true, true, true, true, false, false, false, false},
958 },
959 }, {
960 desc: "special floats and doubles",
961 inputMessage: &pb2.Repeats{},
962 inputText: `
963 rpt_float: [ inf, Inf, infinity, InFiniTy, -inf, -inF, -infinitY, -InfinitY, nan, NaN, Nan ],
964 rpt_double: [ inf, Inf, infinity, InFiniTy, -inf, -inF, -infinitY, -InfinitY, nan, NaN, Nan ],
965 `,
966 wantMessage: &pb2.Repeats{
967 RptFloat: []float32{
968 float32(math.Inf(1)),
969 float32(math.Inf(1)),
970 float32(math.Inf(1)),
971 float32(math.Inf(1)),
972 float32(math.Inf(-1)),
973 float32(math.Inf(-1)),
974 float32(math.Inf(-1)),
975 float32(math.Inf(-1)),
976 float32(math.NaN()),
977 float32(math.NaN()),
978 float32(math.NaN()),
979 },
980 RptDouble: []float64{
981 math.Inf(1),
982 math.Inf(1),
983 math.Inf(1),
984 math.Inf(1),
985 math.Inf(-1),
986 math.Inf(-1),
987 math.Inf(-1),
988 math.Inf(-1),
989 math.NaN(),
990 math.NaN(),
991 math.NaN(),
992 },
993 },
994 }, {
995 desc: "map fields 1",
996 inputMessage: &pb3.Maps{},
997 inputText: `
998 int32_to_str: {
999 key: -101
1000 value: "-101"
1001 }
1002 int32_to_str {
1003 key: 0
1004 value: "zero"
1005 }
1006 bool_to_uint32: {
1007 key: false
1008 value: 101
1009 }
1010 int32_to_str: {
1011 key: 255
1012 value: "0xff"
1013 }
1014 bool_to_uint32 {
1015 key: true
1016 value: 42
1017 }
1018 `,
1019 wantMessage: &pb3.Maps{
1020 Int32ToStr: map[int32]string{
1021 -101: "-101",
1022 0xff: "0xff",
1023 0: "zero",
1024 },
1025 BoolToUint32: map[bool]uint32{
1026 true: 42,
1027 false: 101,
1028 },
1029 },
1030 }, {
1031 desc: "map fields 2",
1032 inputMessage: &pb3.Maps{},
1033 inputText: `
1034 uint64_to_enum: {
1035 key: 1
1036 value: ONE
1037 }
1038 uint64_to_enum: {
1039 key: 2
1040 value: 2
1041 }
1042 uint64_to_enum: {
1043 key: 10
1044 value: 101
1045 }
1046 `,
1047 wantMessage: &pb3.Maps{
1048 Uint64ToEnum: map[uint64]pb3.Enum{
1049 1: pb3.Enum_ONE,
1050 2: pb3.Enum_TWO,
1051 10: 101,
1052 },
1053 },
1054 }, {
1055 desc: "map fields 3",
1056 inputMessage: &pb3.Maps{},
1057 inputText: `
1058 str_to_nested: {
1059 key: "nested_one"
1060 value {
1061 s_string: "nested in a map"
1062 }
1063 }
1064 `,
1065 wantMessage: &pb3.Maps{
1066 StrToNested: map[string]*pb3.Nested{
1067 "nested_one": &pb3.Nested{
1068 SString: "nested in a map",
1069 },
1070 },
1071 },
1072 }, {
1073 desc: "map fields 4",
1074 inputMessage: &pb3.Maps{},
1075 inputText: `
1076 str_to_oneofs: {
1077 key: "nested"
1078 value: {
1079 oneof_nested: {
1080 s_string: "nested oneof in map field value"
1081 }
1082 }
1083 }
1084 str_to_oneofs: {
1085 key: "string"
1086 value: {
1087 oneof_string: "hello"
1088 }
1089 }
1090 `,
1091 wantMessage: &pb3.Maps{
1092 StrToOneofs: map[string]*pb3.Oneofs{
1093 "string": &pb3.Oneofs{
1094 Union: &pb3.Oneofs_OneofString{
1095 OneofString: "hello",
1096 },
1097 },
1098 "nested": &pb3.Oneofs{
1099 Union: &pb3.Oneofs_OneofNested{
1100 OneofNested: &pb3.Nested{
1101 SString: "nested oneof in map field value",
1102 },
1103 },
1104 },
1105 },
1106 },
1107 }, {
1108 desc: "map contains duplicate keys",
1109 inputMessage: &pb3.Maps{},
1110 inputText: `
1111 int32_to_str: {
1112 key: 0
1113 value: "cero"
1114 }
1115 int32_to_str: {
1116 key: 0
1117 value: "zero"
1118 }
1119 `,
1120 wantMessage: &pb3.Maps{
1121 Int32ToStr: map[int32]string{
1122 0: "zero",
1123 },
1124 },
1125 }, {
1126 desc: "map contains duplicate key fields",
1127 inputMessage: &pb3.Maps{},
1128 inputText: `
1129 int32_to_str: {
1130 key: 0
1131 key: 1
1132 value: "cero"
1133 }
1134 `,
1135 wantErr: `map entry "key" cannot be repeated`,
1136 }, {
1137 desc: "map contains duplicate value fields",
1138 inputMessage: &pb3.Maps{},
1139 inputText: `
1140 int32_to_str: {
1141 key: 1
1142 value: "cero"
1143 value: "uno"
1144 }
1145 `,
1146 wantErr: `map entry "value" cannot be repeated`,
1147 }, {
1148 desc: "map contains missing key",
1149 inputMessage: &pb3.Maps{},
1150 inputText: `
1151 int32_to_str: {
1152 value: "zero"
1153 }
1154 bool_to_uint32: {
1155 value: 47
1156 }
1157 str_to_nested: {
1158 value: {}
1159 }
1160 `,
1161 wantMessage: &pb3.Maps{
1162 Int32ToStr: map[int32]string{
1163 0: "zero",
1164 },
1165 BoolToUint32: map[bool]uint32{
1166 false: 47,
1167 },
1168 StrToNested: map[string]*pb3.Nested{
1169 "": {},
1170 },
1171 },
1172 }, {
1173 desc: "map contains missing value",
1174 inputMessage: &pb3.Maps{},
1175 inputText: `
1176 int32_to_str: {
1177 key: 100
1178 }
1179 bool_to_uint32: {
1180 key: true
1181 }
1182 uint64_to_enum: {
1183 key: 101
1184 }
1185 str_to_nested: {
1186 key: "hello"
1187 }
1188 `,
1189 wantMessage: &pb3.Maps{
1190 Int32ToStr: map[int32]string{
1191 100: "",
1192 },
1193 BoolToUint32: map[bool]uint32{
1194 true: 0,
1195 },
1196 Uint64ToEnum: map[uint64]pb3.Enum{
1197 101: pb3.Enum_ZERO,
1198 },
1199 StrToNested: map[string]*pb3.Nested{
1200 "hello": {},
1201 },
1202 },
1203 }, {
1204 desc: "map contains missing key and value",
1205 inputMessage: &pb3.Maps{},
1206 inputText: `
1207 int32_to_str: {}
1208 bool_to_uint32: {}
1209 uint64_to_enum: {}
1210 str_to_nested: {}
1211 `,
1212 wantMessage: &pb3.Maps{
1213 Int32ToStr: map[int32]string{
1214 0: "",
1215 },
1216 BoolToUint32: map[bool]uint32{
1217 false: 0,
1218 },
1219 Uint64ToEnum: map[uint64]pb3.Enum{
1220 0: pb3.Enum_ZERO,
1221 },
1222 StrToNested: map[string]*pb3.Nested{
1223 "": {},
1224 },
1225 },
1226 }, {
1227 desc: "map contains overriding entries",
1228 inputMessage: &pb3.Maps{},
1229 inputText: `
1230 int32_to_str: {
1231 key: 0
1232 }
1233 int32_to_str: {
1234 value: "empty"
1235 }
1236 int32_to_str: {}
1237 `,
1238 wantMessage: &pb3.Maps{
1239 Int32ToStr: map[int32]string{
1240 0: "",
1241 },
1242 },
1243 }, {
1244 desc: "proto2 map field value contains invalid UTF-8",
1245 inputMessage: &pb2.Maps{},
1246 inputText: `int32_to_str: {
1247 key: 101
1248 value: "abc\xff"
1249 }
1250 `,
1251 wantMessage: &pb2.Maps{
1252 Int32ToStr: map[int32]string{101: "abc\xff"},
1253 },
1254 }, {
1255 desc: "proto2 map field key contains invalid UTF-8",
1256 inputMessage: &pb2.Maps{},
1257 inputText: `str_to_nested: {
1258 key: "abc\xff"
1259 value: {}
1260 }
1261 `,
1262 wantMessage: &pb2.Maps{
1263 StrToNested: map[string]*pb2.Nested{"abc\xff": {}},
1264 },
1265 }, {
1266 desc: "proto3 map field value contains invalid UTF-8",
1267 inputMessage: &pb3.Maps{},
1268 inputText: `int32_to_str: {
1269 key: 101
1270 value: "abc\xff"
1271 }
1272 `,
1273 wantErr: "contains invalid UTF-8",
1274 }, {
1275 desc: "proto3 map field key contains invalid UTF-8",
1276 inputMessage: &pb3.Maps{},
1277 inputText: `str_to_nested: {
1278 key: "abc\xff"
1279 value: {}
1280 }
1281 `,
1282 wantErr: "contains invalid UTF-8",
1283 }, {
1284 desc: "map contains unknown field",
1285 inputMessage: &pb3.Maps{},
1286 inputText: `
1287 int32_to_str: {
1288 key: 0
1289 value: "cero"
1290 unknown: "bad"
1291 }
1292 `,
1293 wantErr: `(line 5:3): unknown map entry field "unknown"`,
1294 }, {
1295 desc: "map contains extension-like key field",
1296 inputMessage: &pb3.Maps{},
1297 inputText: `
1298 int32_to_str: {
1299 [key]: 10
1300 value: "ten"
1301 }
1302 `,
1303 wantErr: `unknown map entry field "[key]"`,
1304 }, {
1305 desc: "map contains invalid key",
1306 inputMessage: &pb3.Maps{},
1307 inputText: `
1308 int32_to_str: {
1309 key: "invalid"
1310 value: "cero"
1311 }
1312 `,
1313 wantErr: "(line 3:8): invalid value for int32 type",
1314 }, {
1315 desc: "map contains invalid value",
1316 inputMessage: &pb3.Maps{},
1317 inputText: `
1318 int32_to_str: {
1319 key: 100
1320 value: 101
1321 }
1322 `,
1323 wantErr: "(line 4:10): invalid value for string type",
1324 }, {
1325 desc: "map contains invalid message value",
1326 inputMessage: &pb3.Maps{},
1327 inputText: `
1328 str_to_nested: {
1329 key: "one"
1330 value: 1
1331 }
1332 `,
1333 wantErr: "syntax error (line 4:10): unexpected token: 1",
1334 }, {
1335 desc: "map using mix of [] and repeated",
1336 inputMessage: &pb3.Maps{},
1337 inputText: `
1338 int32_to_str: {
1339 key: 1
1340 value: "one"
1341 }
1342 int32_to_str: [
1343 {
1344 key: 2
1345 value: "not this"
1346 },
1347 {
1348 },
1349 {
1350 key: 3
1351 value: "three"
1352 }
1353 ]
1354 int32_to_str: {
1355 key: 2
1356 value: "two"
1357 }
1358 `,
1359 wantMessage: &pb3.Maps{
1360 Int32ToStr: map[int32]string{
1361 0: "",
1362 1: "one",
1363 2: "two",
1364 3: "three",
1365 },
1366 },
1367 }, {
1368 desc: "required fields not set",
1369 inputMessage: &pb2.Requireds{},
1370 wantErr: "required field",
1371 }, {
1372 desc: "required field set",
1373 inputMessage: &pb2.PartialRequired{},
1374 inputText: "req_string: 'this is required'",
1375 wantMessage: &pb2.PartialRequired{
1376 ReqString: proto.String("this is required"),
1377 },
1378 }, {
1379 desc: "required fields partially set",
1380 inputMessage: &pb2.Requireds{},
1381 inputText: `
1382 req_bool: false
1383 req_sfixed64: 3203386110
1384 req_string: "hello"
1385 req_enum: ONE
1386 `,
1387 wantMessage: &pb2.Requireds{
1388 ReqBool: proto.Bool(false),
1389 ReqSfixed64: proto.Int64(0xbeefcafe),
1390 ReqString: proto.String("hello"),
1391 ReqEnum: pb2.Enum_ONE.Enum(),
1392 },
1393 wantErr: "required field",
1394 }, {
1395 desc: "required fields partially set with AllowPartial",
1396 umo: prototext.UnmarshalOptions{AllowPartial: true},
1397 inputMessage: &pb2.Requireds{},
1398 inputText: `
1399 req_bool: false
1400 req_sfixed64: 3203386110
1401 req_string: "hello"
1402 req_enum: ONE
1403 `,
1404 wantMessage: &pb2.Requireds{
1405 ReqBool: proto.Bool(false),
1406 ReqSfixed64: proto.Int64(0xbeefcafe),
1407 ReqString: proto.String("hello"),
1408 ReqEnum: pb2.Enum_ONE.Enum(),
1409 },
1410 }, {
1411 desc: "required fields all set",
1412 inputMessage: &pb2.Requireds{},
1413 inputText: `
1414 req_bool: false
1415 req_sfixed64: 0
1416 req_double: 0
1417 req_string: ""
1418 req_enum: ONE
1419 req_nested: {}
1420 `,
1421 wantMessage: &pb2.Requireds{
1422 ReqBool: proto.Bool(false),
1423 ReqSfixed64: proto.Int64(0),
1424 ReqDouble: proto.Float64(0),
1425 ReqString: proto.String(""),
1426 ReqEnum: pb2.Enum_ONE.Enum(),
1427 ReqNested: &pb2.Nested{},
1428 },
1429 }, {
1430 desc: "indirect required field",
1431 inputMessage: &pb2.IndirectRequired{},
1432 inputText: "opt_nested: {}",
1433 wantMessage: &pb2.IndirectRequired{
1434 OptNested: &pb2.NestedWithRequired{},
1435 },
1436 wantErr: "required field",
1437 }, {
1438 desc: "indirect required field with AllowPartial",
1439 umo: prototext.UnmarshalOptions{AllowPartial: true},
1440 inputMessage: &pb2.IndirectRequired{},
1441 inputText: "opt_nested: {}",
1442 wantMessage: &pb2.IndirectRequired{
1443 OptNested: &pb2.NestedWithRequired{},
1444 },
1445 }, {
1446 desc: "indirect required field in repeated",
1447 inputMessage: &pb2.IndirectRequired{},
1448 inputText: `
1449 rpt_nested: {
1450 req_string: "one"
1451 }
1452 rpt_nested: {}
1453 `,
1454 wantMessage: &pb2.IndirectRequired{
1455 RptNested: []*pb2.NestedWithRequired{
1456 {
1457 ReqString: proto.String("one"),
1458 },
1459 {},
1460 },
1461 },
1462 wantErr: "required field",
1463 }, {
1464 desc: "indirect required field in repeated with AllowPartial",
1465 umo: prototext.UnmarshalOptions{AllowPartial: true},
1466 inputMessage: &pb2.IndirectRequired{},
1467 inputText: `
1468 rpt_nested: {
1469 req_string: "one"
1470 }
1471 rpt_nested: {}
1472 `,
1473 wantMessage: &pb2.IndirectRequired{
1474 RptNested: []*pb2.NestedWithRequired{
1475 {
1476 ReqString: proto.String("one"),
1477 },
1478 {},
1479 },
1480 },
1481 }, {
1482 desc: "indirect required field in map",
1483 inputMessage: &pb2.IndirectRequired{},
1484 inputText: `
1485 str_to_nested: {
1486 key: "missing"
1487 }
1488 str_to_nested: {
1489 key: "contains"
1490 value: {
1491 req_string: "here"
1492 }
1493 }
1494 `,
1495 wantMessage: &pb2.IndirectRequired{
1496 StrToNested: map[string]*pb2.NestedWithRequired{
1497 "missing": &pb2.NestedWithRequired{},
1498 "contains": &pb2.NestedWithRequired{
1499 ReqString: proto.String("here"),
1500 },
1501 },
1502 },
1503 wantErr: "required field",
1504 }, {
1505 desc: "indirect required field in map with AllowPartial",
1506 umo: prototext.UnmarshalOptions{AllowPartial: true},
1507 inputMessage: &pb2.IndirectRequired{},
1508 inputText: `
1509 str_to_nested: {
1510 key: "missing"
1511 }
1512 str_to_nested: {
1513 key: "contains"
1514 value: {
1515 req_string: "here"
1516 }
1517 }
1518 `,
1519 wantMessage: &pb2.IndirectRequired{
1520 StrToNested: map[string]*pb2.NestedWithRequired{
1521 "missing": &pb2.NestedWithRequired{},
1522 "contains": &pb2.NestedWithRequired{
1523 ReqString: proto.String("here"),
1524 },
1525 },
1526 },
1527 }, {
1528 desc: "indirect required field in oneof",
1529 inputMessage: &pb2.IndirectRequired{},
1530 inputText: `oneof_nested: {}
1531 `,
1532 wantMessage: &pb2.IndirectRequired{
1533 Union: &pb2.IndirectRequired_OneofNested{
1534 OneofNested: &pb2.NestedWithRequired{},
1535 },
1536 },
1537 wantErr: "required field",
1538 }, {
1539 desc: "indirect required field in oneof with AllowPartial",
1540 umo: prototext.UnmarshalOptions{AllowPartial: true},
1541 inputMessage: &pb2.IndirectRequired{},
1542 inputText: `oneof_nested: {}
1543 `,
1544 wantMessage: &pb2.IndirectRequired{
1545 Union: &pb2.IndirectRequired_OneofNested{
1546 OneofNested: &pb2.NestedWithRequired{},
1547 },
1548 },
1549 }, {
1550 desc: "ignore reserved field",
1551 inputMessage: &pb2.Nests{},
1552 inputText: "reserved_field: 'ignore this'",
1553 wantMessage: &pb2.Nests{},
1554 }, {
1555 desc: "extensions of non-repeated fields",
1556 inputMessage: &pb2.Extensions{},
1557 inputText: `opt_string: "non-extension field"
1558 [pb2.opt_ext_bool]: true
1559 opt_bool: true
1560 [pb2.opt_ext_nested]: {
1561 opt_string: "nested in an extension"
1562 opt_nested: {
1563 opt_string: "another nested in an extension"
1564 }
1565 }
1566 [pb2.opt_ext_string]: "extension field"
1567 opt_int32: 42
1568 [pb2.opt_ext_enum]: TEN
1569 `,
1570 wantMessage: func() proto.Message {
1571 m := &pb2.Extensions{
1572 OptString: proto.String("non-extension field"),
1573 OptBool: proto.Bool(true),
1574 OptInt32: proto.Int32(42),
1575 }
1576 proto.SetExtension(m, pb2.E_OptExtBool, true)
1577 proto.SetExtension(m, pb2.E_OptExtString, "extension field")
1578 proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
1579 proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{
1580 OptString: proto.String("nested in an extension"),
1581 OptNested: &pb2.Nested{
1582 OptString: proto.String("another nested in an extension"),
1583 },
1584 })
1585 return m
1586 }(),
1587 }, {
1588 desc: "extension field contains invalid UTF-8",
1589 inputMessage: &pb2.Extensions{},
1590 inputText: `[pb2.opt_ext_string]: "abc\xff"`,
1591 wantMessage: func() proto.Message {
1592 m := &pb2.Extensions{}
1593 proto.SetExtension(m, pb2.E_OptExtString, "abc\xff")
1594 return m
1595 }(),
1596 }, {
1597 desc: "extensions of repeated fields",
1598 inputMessage: &pb2.Extensions{},
1599 inputText: `[pb2.rpt_ext_enum]: TEN
1600 [pb2.rpt_ext_enum]: 101
1601 [pb2.rpt_ext_fixed32]: 42
1602 [pb2.rpt_ext_enum]: ONE
1603 [pb2.rpt_ext_nested]: {
1604 opt_string: "one"
1605 }
1606 [pb2.rpt_ext_nested]: {
1607 opt_string: "two"
1608 }
1609 [pb2.rpt_ext_fixed32]: 47
1610 [pb2.rpt_ext_nested]: {
1611 opt_string: "three"
1612 }
1613 `,
1614 wantMessage: func() proto.Message {
1615 m := &pb2.Extensions{}
1616 proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
1617 proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47})
1618 proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
1619 &pb2.Nested{OptString: proto.String("one")},
1620 &pb2.Nested{OptString: proto.String("two")},
1621 &pb2.Nested{OptString: proto.String("three")},
1622 })
1623 return m
1624 }(),
1625 }, {
1626 desc: "extensions of non-repeated fields in another message",
1627 inputMessage: &pb2.Extensions{},
1628 inputText: `[pb2.ExtensionsContainer.opt_ext_bool]: true
1629 [pb2.ExtensionsContainer.opt_ext_enum]: TEN
1630 [pb2.ExtensionsContainer.opt_ext_nested]: {
1631 opt_string: "nested in an extension"
1632 opt_nested: {
1633 opt_string: "another nested in an extension"
1634 }
1635 }
1636 [pb2.ExtensionsContainer.opt_ext_string]: "extension field"
1637 `,
1638 wantMessage: func() proto.Message {
1639 m := &pb2.Extensions{}
1640 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
1641 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
1642 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
1643 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
1644 OptString: proto.String("nested in an extension"),
1645 OptNested: &pb2.Nested{
1646 OptString: proto.String("another nested in an extension"),
1647 },
1648 })
1649 return m
1650 }(),
1651 }, {
1652 desc: "extensions of repeated fields in another message",
1653 inputMessage: &pb2.Extensions{},
1654 inputText: `opt_string: "non-extension field"
1655 opt_bool: true
1656 opt_int32: 42
1657 [pb2.ExtensionsContainer.rpt_ext_nested]: {
1658 opt_string: "one"
1659 }
1660 [pb2.ExtensionsContainer.rpt_ext_enum]: TEN
1661 [pb2.ExtensionsContainer.rpt_ext_nested]: {
1662 opt_string: "two"
1663 }
1664 [pb2.ExtensionsContainer.rpt_ext_enum]: 101
1665 [pb2.ExtensionsContainer.rpt_ext_string]: "hello"
1666 [pb2.ExtensionsContainer.rpt_ext_enum]: ONE
1667 [pb2.ExtensionsContainer.rpt_ext_nested]: {
1668 opt_string: "three"
1669 }
1670 [pb2.ExtensionsContainer.rpt_ext_string]: "world"
1671 `,
1672 wantMessage: func() proto.Message {
1673 m := &pb2.Extensions{
1674 OptString: proto.String("non-extension field"),
1675 OptBool: proto.Bool(true),
1676 OptInt32: proto.Int32(42),
1677 }
1678 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
1679 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"})
1680 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{
1681 &pb2.Nested{OptString: proto.String("one")},
1682 &pb2.Nested{OptString: proto.String("two")},
1683 &pb2.Nested{OptString: proto.String("three")},
1684 })
1685 return m
1686 }(),
1687 }, {
1688 desc: "invalid extension field name",
1689 inputMessage: &pb2.Extensions{},
1690 inputText: "[pb2.invalid_message_field]: true",
1691 wantErr: "unknown field",
1692 }, {
1693 desc: "MessageSet",
1694 inputMessage: &pb2.MessageSet{},
1695 inputText: `
1696 [pb2.MessageSetExtension]: {
1697 opt_string: "a messageset extension"
1698 }
1699 [pb2.MessageSetExtension.ext_nested]: {
1700 opt_string: "just a regular extension"
1701 }
1702 [pb2.MessageSetExtension.not_message_set_extension]: {
1703 opt_string: "not a messageset extension"
1704 }
1705 `,
1706 wantMessage: func() proto.Message {
1707 m := &pb2.MessageSet{}
1708 proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
1709 OptString: proto.String("a messageset extension"),
1710 })
1711 proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
1712 OptString: proto.String("not a messageset extension"),
1713 })
1714 proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
1715 OptString: proto.String("just a regular extension"),
1716 })
1717 return m
1718 }(),
1719 skip: !flags.ProtoLegacy,
1720 }, {
1721 desc: "not real MessageSet 1",
1722 inputMessage: &pb2.FakeMessageSet{},
1723 inputText: `
1724 [pb2.FakeMessageSetExtension.message_set_extension]: {
1725 opt_string: "not a messageset extension"
1726 }
1727 `,
1728 wantMessage: func() proto.Message {
1729 m := &pb2.FakeMessageSet{}
1730 proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
1731 OptString: proto.String("not a messageset extension"),
1732 })
1733 return m
1734 }(),
1735 skip: !flags.ProtoLegacy,
1736 }, {
1737 desc: "not real MessageSet 2",
1738 inputMessage: &pb2.FakeMessageSet{},
1739 inputText: `
1740 [pb2.FakeMessageSetExtension]: {
1741 opt_string: "not a messageset extension"
1742 }
1743 `,
1744 wantErr: `unable to resolve [[pb2.FakeMessageSetExtension]]: found wrong type`,
1745 skip: !flags.ProtoLegacy,
1746 }, {
1747 desc: "not real MessageSet 3",
1748 inputMessage: &pb2.MessageSet{},
1749 inputText: `
1750 [pb2.message_set_extension]: {
1751 opt_string: "another not a messageset extension"
1752 }`,
1753 wantMessage: func() proto.Message {
1754 m := &pb2.MessageSet{}
1755 proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
1756 OptString: proto.String("another not a messageset extension"),
1757 })
1758 return m
1759 }(),
1760 skip: !flags.ProtoLegacy,
1761 }, {
1762 desc: "Any not expanded",
1763 inputMessage: &anypb.Any{},
1764 inputText: `
1765 type_url: "pb2.Nested"
1766 value: "some bytes"
1767 `,
1768 wantMessage: &anypb.Any{
1769 TypeUrl: "pb2.Nested",
1770 Value: []byte("some bytes"),
1771 },
1772 }, {
1773 desc: "Any not expanded missing value",
1774 inputMessage: &anypb.Any{},
1775 inputText: `type_url: "pb2.Nested"`,
1776 wantMessage: &anypb.Any{
1777 TypeUrl: "pb2.Nested",
1778 },
1779 }, {
1780 desc: "Any not expanded missing type_url",
1781 inputMessage: &anypb.Any{},
1782 inputText: `value: "some bytes"`,
1783 wantMessage: &anypb.Any{
1784 Value: []byte("some bytes"),
1785 },
1786 }, {
1787 desc: "Any expanded",
1788 inputMessage: &anypb.Any{},
1789 inputText: `
1790 [foobar/pb2.Nested]: {
1791 opt_string: "embedded inside Any"
1792 opt_nested: {
1793 opt_string: "inception"
1794 }
1795 }
1796 `,
1797 wantMessage: func() proto.Message {
1798 m := &pb2.Nested{
1799 OptString: proto.String("embedded inside Any"),
1800 OptNested: &pb2.Nested{
1801 OptString: proto.String("inception"),
1802 },
1803 }
1804 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1805 if err != nil {
1806 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1807 }
1808 return &anypb.Any{
1809 TypeUrl: "foobar/pb2.Nested",
1810 Value: b,
1811 }
1812 }(),
1813 }, {
1814 desc: "Any expanded with empty value",
1815 inputMessage: &anypb.Any{},
1816 inputText: `[foo.com/pb2.Nested]: {}`,
1817 wantMessage: &anypb.Any{
1818 TypeUrl: "foo.com/pb2.Nested",
1819 },
1820 }, {
1821 desc: "Any expanded with missing required",
1822 inputMessage: &anypb.Any{},
1823 inputText: `
1824 [pb2.PartialRequired]: {
1825 opt_string: "embedded inside Any"
1826 }
1827 `,
1828 wantMessage: func() proto.Message {
1829 m := &pb2.PartialRequired{
1830 OptString: proto.String("embedded inside Any"),
1831 }
1832 b, err := proto.MarshalOptions{
1833 AllowPartial: true,
1834 Deterministic: true,
1835 }.Marshal(m)
1836 if err != nil {
1837 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1838 }
1839 return &anypb.Any{
1840 TypeUrl: "pb2.PartialRequired",
1841 Value: b,
1842 }
1843 }(),
1844 }, {
1845 desc: "Any with invalid UTF-8",
1846 inputMessage: &anypb.Any{},
1847 inputText: `
1848 [pb3.Nested]: {
1849 s_string: "abc\xff"
1850 }
1851 `,
1852 wantErr: "contains invalid UTF-8",
1853 }, {
1854 desc: "Any expanded with unregistered type",
1855 umo: prototext.UnmarshalOptions{Resolver: new(protoregistry.Types)},
1856 inputMessage: &anypb.Any{},
1857 inputText: `[SomeMessage]: {}`,
1858 wantErr: "unable to resolve message [SomeMessage]",
1859 }, {
1860 desc: "Any expanded with invalid value",
1861 inputMessage: &anypb.Any{},
1862 inputText: `[pb2.Nested]: 123`,
1863 wantErr: "unexpected token: 123",
1864 }, {
1865 desc: "Any expanded with unknown fields",
1866 inputMessage: &anypb.Any{},
1867 inputText: `
1868 [pb2.Nested]: {}
1869 unknown: ""
1870 `,
1871 wantErr: `invalid field name "unknown" in google.protobuf.Any message`,
1872 }, {
1873 desc: "Any contains expanded and unexpanded fields",
1874 inputMessage: &anypb.Any{},
1875 inputText: `
1876 [pb2.Nested]: {}
1877 type_url: "pb2.Nested"
1878 `,
1879 wantErr: "(line 3:1): conflict with [pb2.Nested] field",
1880 }, {
1881 desc: "weak fields",
1882 inputMessage: &testpb.TestWeak{},
1883 inputText: `weak_message1:{a:1}`,
1884 wantMessage: func() *testpb.TestWeak {
1885 m := new(testpb.TestWeak)
1886 m.SetWeakMessage1(&weakpb.WeakImportMessage1{A: proto.Int32(1)})
1887 return m
1888 }(),
1889 skip: !flags.ProtoLegacy,
1890 }, {
1891 desc: "weak fields; unknown field",
1892 inputMessage: &testpb.TestWeak{},
1893 inputText: `weak_message1:{a:1} weak_message2:{a:1}`,
1894 wantErr: "unknown field: weak_message2",
1895 skip: !flags.ProtoLegacy,
1896 }}
1897
1898 for _, tt := range tests {
1899 tt := tt
1900 if tt.skip {
1901 continue
1902 }
1903 t.Run(tt.desc, func(t *testing.T) {
1904 err := tt.umo.Unmarshal([]byte(tt.inputText), tt.inputMessage)
1905 if err != nil {
1906 if tt.wantErr == "" {
1907 t.Errorf("Unmarshal() got unexpected error: %v", err)
1908 } else if !strings.Contains(err.Error(), tt.wantErr) {
1909 t.Errorf("Unmarshal() error got %q, want %q", err, tt.wantErr)
1910 }
1911 return
1912 }
1913 if tt.wantErr != "" {
1914 t.Errorf("Unmarshal() got nil error, want error %q", tt.wantErr)
1915 return
1916 }
1917 if tt.wantMessage != nil && !proto.Equal(tt.inputMessage, tt.wantMessage) {
1918 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
1919 }
1920 })
1921 }
1922 }
1923
View as plain text