1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package proto_test
33
34 import (
35 "fmt"
36 "math"
37 "testing"
38
39 . "github.com/gogo/protobuf/proto"
40 proto3pb "github.com/gogo/protobuf/proto/proto3_proto"
41 . "github.com/gogo/protobuf/proto/test_proto"
42 )
43
44 type UnmarshalTextTest struct {
45 in string
46 err string
47 out *MyMessage
48 }
49
50 func buildExtStructTest(text string) UnmarshalTextTest {
51 msg := &MyMessage{
52 Count: Int32(42),
53 }
54 SetExtension(msg, E_Ext_More, &Ext{
55 Data: String("Hello, world!"),
56 })
57 return UnmarshalTextTest{in: text, out: msg}
58 }
59
60 func buildExtDataTest(text string) UnmarshalTextTest {
61 msg := &MyMessage{
62 Count: Int32(42),
63 }
64 SetExtension(msg, E_Ext_Text, String("Hello, world!"))
65 SetExtension(msg, E_Ext_Number, Int32(1729))
66 return UnmarshalTextTest{in: text, out: msg}
67 }
68
69 func buildExtRepStringTest(text string) UnmarshalTextTest {
70 msg := &MyMessage{
71 Count: Int32(42),
72 }
73 if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil {
74 panic(err)
75 }
76 return UnmarshalTextTest{in: text, out: msg}
77 }
78
79 var unMarshalTextTests = []UnmarshalTextTest{
80
81 {
82 in: " count:42\n name:\"Dave\" ",
83 out: &MyMessage{
84 Count: Int32(42),
85 Name: String("Dave"),
86 },
87 },
88
89
90 {
91 in: `count:42 name:""`,
92 out: &MyMessage{
93 Count: Int32(42),
94 Name: String(""),
95 },
96 },
97
98
99 {
100 in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
101 out: &MyMessage{
102 Count: Int32(42),
103 Name: String("My name is elsewhere"),
104 },
105 },
106
107
108 {
109 in: "count:42 name: 'My name is '\n'elsewhere'",
110 out: &MyMessage{
111 Count: Int32(42),
112 Name: String("My name is elsewhere"),
113 },
114 },
115
116
117 {
118 in: "count:42 name: 'My name is '\n\"elsewhere\"",
119 out: &MyMessage{
120 Count: Int32(42),
121 Name: String("My name is elsewhere"),
122 },
123 },
124 {
125 in: "count:42 name: \"My name is \"\n'elsewhere'",
126 out: &MyMessage{
127 Count: Int32(42),
128 Name: String("My name is elsewhere"),
129 },
130 },
131
132
133 {
134 in: `count:42 name: "HOLIDAY - New Year\'s Day"`,
135 out: &MyMessage{
136 Count: Int32(42),
137 Name: String("HOLIDAY - New Year's Day"),
138 },
139 },
140
141
142 {
143 in: `count:42 name: 'Roger "The Ramster" Ramjet'`,
144 out: &MyMessage{
145 Count: Int32(42),
146 Name: String(`Roger "The Ramster" Ramjet`),
147 },
148 },
149
150
151 {
152 in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"",
153 out: &MyMessage{
154 Count: Int32(42),
155 Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"),
156 },
157 },
158
159
160 {
161 in: `count:42 name: "\\'xyz"`,
162 out: &MyMessage{
163 Count: Int32(42),
164 Name: String(`\'xyz`),
165 },
166 },
167
168
169 {
170 in: "count:42 name: '\303\277\302\201\x00\xAB\xCD\xEF'",
171 out: &MyMessage{
172 Count: Int32(42),
173 Name: String("\303\277\302\201\x00\xAB\xCD\xEF"),
174 },
175 },
176
177
178 {
179 in: `count: 42 name: "\u0047\U00000047\uffff\U0010ffff"`,
180 out: &MyMessage{
181 Count: Int32(42),
182 Name: String("GG\uffff\U0010ffff"),
183 },
184 },
185
186
187 {
188 in: `inner: < host: "\0" >` + "\n",
189 err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`,
190 },
191
192
193 {
194 in: `count: 42 name: "\u000"`,
195 err: `line 1.16: invalid quoted string "\u000": \u requires 4 following digits`,
196 },
197
198
199 {
200 in: `count: 42 name: "\U0000000"`,
201 err: `line 1.16: invalid quoted string "\U0000000": \U requires 8 following digits`,
202 },
203
204
205 {
206 in: `count: 42 name: "\xxx"`,
207 err: `line 1.16: invalid quoted string "\xxx": \xxx contains non-hexadecimal digits`,
208 },
209
210
211 {
212 in: "count: 1 others { key: 123456789012345678901 }",
213 err: "line 1.23: invalid int64: 123456789012345678901",
214 },
215
216
217 {
218 in: "count: 1234567890123",
219 err: "line 1.7: invalid int32: 1234567890123",
220 },
221
222
223 {
224 in: "count: 0x2beef",
225 out: &MyMessage{
226 Count: Int32(0x2beef),
227 },
228 },
229
230
231 {
232 in: "count: 024601",
233 out: &MyMessage{
234 Count: Int32(024601),
235 },
236 },
237
238
239 {
240 in: "count: 4 others:< weight: 17.0f >",
241 out: &MyMessage{
242 Count: Int32(4),
243 Others: []*OtherMessage{
244 {
245 Weight: Float32(17),
246 },
247 },
248 },
249 },
250
251
252 {
253 in: "count: 4 bigfloat: inf",
254 out: &MyMessage{
255 Count: Int32(4),
256 Bigfloat: Float64(math.Inf(1)),
257 },
258 },
259
260
261 {
262 in: "count: 4 bigfloat: -inf",
263 out: &MyMessage{
264 Count: Int32(4),
265 Bigfloat: Float64(math.Inf(-1)),
266 },
267 },
268
269
270 {
271 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
272 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
273 },
274
275
276 {
277 in: `inner: < host: 12 >` + "\n",
278 err: `line 1.15: invalid string: 12`,
279 },
280
281
282 {
283 in: `count: "12"`,
284 err: `line 1.7: invalid int32: "12"`,
285 },
286
287
288 {
289 in: `others:< weight: "17.4" >`,
290 err: `line 1.17: invalid float32: "17.4"`,
291 },
292
293
294 {
295 in: `[`,
296 err: `line 1.0: unclosed type_url or extension name`,
297 },
298
299
300 {
301 in: `count:42 bikeshed: BLUE`,
302 out: &MyMessage{
303 Count: Int32(42),
304 Bikeshed: MyMessage_BLUE.Enum(),
305 },
306 },
307
308
309 {
310 in: `count:42 pet: "horsey" pet:"bunny"`,
311 out: &MyMessage{
312 Count: Int32(42),
313 Pet: []string{"horsey", "bunny"},
314 },
315 },
316
317
318 {
319 in: `count:42 pet: ["horsey", "bunny"]`,
320 out: &MyMessage{
321 Count: Int32(42),
322 Pet: []string{"horsey", "bunny"},
323 },
324 },
325
326
327 {
328 in: `count:42 others:{} others{} others:<> others:{}`,
329 out: &MyMessage{
330 Count: Int32(42),
331 Others: []*OtherMessage{
332 {},
333 {},
334 {},
335 {},
336 },
337 },
338 },
339
340
341 {
342 in: `count:42 inner < host: "cauchy.syd" >`,
343 out: &MyMessage{
344 Count: Int32(42),
345 Inner: &InnerMessage{
346 Host: String("cauchy.syd"),
347 },
348 },
349 },
350
351
352 {
353 in: `name "Dave"`,
354 err: `line 1.5: expected ':', found "\"Dave\""`,
355 },
356
357
358 {
359 in: `count 42`,
360 err: `line 1.6: expected ':', found "42"`,
361 },
362
363
364 {
365 in: `name: "Pawel"`,
366 err: fmt.Sprintf(`proto: required field "%T.count" not set`, MyMessage{}),
367 out: &MyMessage{
368 Name: String("Pawel"),
369 },
370 },
371
372
373 {
374 in: `count: 42 we_must_go_deeper < leo_finally_won_an_oscar <> >`,
375 err: fmt.Sprintf(`proto: required field "%T.host" not set`, InnerMessage{}),
376 out: &MyMessage{
377 Count: Int32(42),
378 WeMustGoDeeper: &RequiredInnerMessage{LeoFinallyWonAnOscar: &InnerMessage{}},
379 },
380 },
381
382
383 {
384 in: `name: "Rob" name: "Russ"`,
385 err: `line 1.12: non-repeated field "name" was repeated`,
386 },
387
388
389 {
390 in: `count: 17 SomeGroup { group_field: 12 }`,
391 out: &MyMessage{
392 Count: Int32(17),
393 Somegroup: &MyMessage_SomeGroup{
394 GroupField: Int32(12),
395 },
396 },
397 },
398
399
400 {
401 in: `count:3;name:"Calvin"`,
402 out: &MyMessage{
403 Count: Int32(3),
404 Name: String("Calvin"),
405 },
406 },
407
408 {
409 in: `count:4,name:"Ezekiel"`,
410 out: &MyMessage{
411 Count: Int32(4),
412 Name: String("Ezekiel"),
413 },
414 },
415
416
417 {
418 in: `count:42 inner { host: "example.com" connected: false }`,
419 out: &MyMessage{
420 Count: Int32(42),
421 Inner: &InnerMessage{
422 Host: String("example.com"),
423 Connected: Bool(false),
424 },
425 },
426 },
427
428 {
429 in: `count:42 inner { host: "example.com" connected: true }`,
430 out: &MyMessage{
431 Count: Int32(42),
432 Inner: &InnerMessage{
433 Host: String("example.com"),
434 Connected: Bool(true),
435 },
436 },
437 },
438
439 {
440 in: `count:42 inner { host: "example.com" connected: 0 }`,
441 out: &MyMessage{
442 Count: Int32(42),
443 Inner: &InnerMessage{
444 Host: String("example.com"),
445 Connected: Bool(false),
446 },
447 },
448 },
449
450 {
451 in: `count:42 inner { host: "example.com" connected: 1 }`,
452 out: &MyMessage{
453 Count: Int32(42),
454 Inner: &InnerMessage{
455 Host: String("example.com"),
456 Connected: Bool(true),
457 },
458 },
459 },
460
461 {
462 in: `count:42 inner { host: "example.com" connected: f }`,
463 out: &MyMessage{
464 Count: Int32(42),
465 Inner: &InnerMessage{
466 Host: String("example.com"),
467 Connected: Bool(false),
468 },
469 },
470 },
471
472 {
473 in: `count:42 inner { host: "example.com" connected: t }`,
474 out: &MyMessage{
475 Count: Int32(42),
476 Inner: &InnerMessage{
477 Host: String("example.com"),
478 Connected: Bool(true),
479 },
480 },
481 },
482
483 {
484 in: `count:42 inner { host: "example.com" connected: False }`,
485 out: &MyMessage{
486 Count: Int32(42),
487 Inner: &InnerMessage{
488 Host: String("example.com"),
489 Connected: Bool(false),
490 },
491 },
492 },
493
494 {
495 in: `count:42 inner { host: "example.com" connected: True }`,
496 out: &MyMessage{
497 Count: Int32(42),
498 Inner: &InnerMessage{
499 Host: String("example.com"),
500 Connected: Bool(true),
501 },
502 },
503 },
504
505
506 buildExtStructTest(`count: 42 [test_proto.Ext.more]:<data:"Hello, world!" >`),
507 buildExtStructTest(`count: 42 [test_proto.Ext.more] {data:"Hello, world!"}`),
508 buildExtDataTest(`count: 42 [test_proto.Ext.text]:"Hello, world!" [test_proto.Ext.number]:1729`),
509 buildExtRepStringTest(`count: 42 [test_proto.greeting]:"bula" [test_proto.greeting]:"hola"`),
510
511
512 {
513 in: "count:42 # Meaning\n" +
514 `name:"Dave" ` +
515 `quote:"\"I didn't want to go.\"" ` +
516 `pet:"bunny" ` +
517 `pet:"kitty" ` +
518 `pet:"horsey" ` +
519 `inner:<` +
520 ` host:"footrest.syd" ` +
521 ` port:7001 ` +
522 ` connected:true ` +
523 `> ` +
524 `others:<` +
525 ` key:3735928559 ` +
526 ` value:"\x01A\a\f" ` +
527 `> ` +
528 `others:<` +
529 " weight:58.9 # Atomic weight of Co\n" +
530 ` inner:<` +
531 ` host:"lesha.mtv" ` +
532 ` port:8002 ` +
533 ` >` +
534 `>`,
535 out: &MyMessage{
536 Count: Int32(42),
537 Name: String("Dave"),
538 Quote: String(`"I didn't want to go."`),
539 Pet: []string{"bunny", "kitty", "horsey"},
540 Inner: &InnerMessage{
541 Host: String("footrest.syd"),
542 Port: Int32(7001),
543 Connected: Bool(true),
544 },
545 Others: []*OtherMessage{
546 {
547 Key: Int64(3735928559),
548 Value: []byte{0x1, 'A', '\a', '\f'},
549 },
550 {
551 Weight: Float32(58.9),
552 Inner: &InnerMessage{
553 Host: String("lesha.mtv"),
554 Port: Int32(8002),
555 },
556 },
557 },
558 },
559 },
560 }
561
562 func TestUnmarshalText(t *testing.T) {
563 for i, test := range unMarshalTextTests {
564 pb := new(MyMessage)
565 err := UnmarshalText(test.in, pb)
566 if test.err == "" {
567
568 if err != nil {
569 t.Errorf("Test %d: Unexpected error: %v", i, err)
570 } else if !Equal(pb, test.out) {
571 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
572 i, pb, test.out)
573 }
574 } else {
575
576 if err == nil {
577 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
578 } else if err.Error() != test.err {
579 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
580 i, err.Error(), test.err)
581 } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !Equal(pb, test.out) {
582 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
583 i, pb, test.out)
584 }
585 }
586 }
587 }
588
589 func TestUnmarshalTextCustomMessage(t *testing.T) {
590 msg := &textMessage{}
591 if err := UnmarshalText("custom", msg); err != nil {
592 t.Errorf("Unexpected error from custom unmarshal: %v", err)
593 }
594 if UnmarshalText("not custom", msg) == nil {
595 t.Errorf("Didn't get expected error from custom unmarshal")
596 }
597 }
598
599
600 func TestRepeatedEnum(t *testing.T) {
601 pb := new(RepeatedEnum)
602 if err := UnmarshalText("color: RED", pb); err != nil {
603 t.Fatal(err)
604 }
605 exp := &RepeatedEnum{
606 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
607 }
608 if !Equal(pb, exp) {
609 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
610 }
611 }
612
613 func TestProto3TextParsing(t *testing.T) {
614 m := new(proto3pb.Message)
615 const in = `name: "Wallace" true_scotsman: true`
616 want := &proto3pb.Message{
617 Name: "Wallace",
618 TrueScotsman: true,
619 }
620 if err := UnmarshalText(in, m); err != nil {
621 t.Fatal(err)
622 }
623 if !Equal(m, want) {
624 t.Errorf("\n got %v\nwant %v", m, want)
625 }
626 }
627
628 func TestMapParsing(t *testing.T) {
629 m := new(MessageWithMap)
630 const in = `name_mapping:<key:1234 value:"Feist"> name_mapping:<key:1 value:"Beatles">` +
631 `msg_mapping:<key:-4, value:<f: 2.0>,>` +
632 `msg_mapping<key:-2 value<f: 4.0>>` +
633 `msg_mapping:<value:<f: 5.0>>` +
634 `msg_mapping:<key:1>` +
635 `byte_mapping:<key:true value:"so be it">` +
636 `byte_mapping:<>`
637 want := &MessageWithMap{
638 NameMapping: map[int32]string{
639 1: "Beatles",
640 1234: "Feist",
641 },
642 MsgMapping: map[int64]*FloatingPoint{
643 -4: {F: Float64(2.0)},
644 -2: {F: Float64(4.0)},
645 0: {F: Float64(5.0)},
646 1: nil,
647 },
648 ByteMapping: map[bool][]byte{
649 false: nil,
650 true: []byte("so be it"),
651 },
652 }
653 if err := UnmarshalText(in, m); err != nil {
654 t.Fatal(err)
655 }
656 if !Equal(m, want) {
657 t.Errorf("\n got %v\nwant %v", m, want)
658 }
659 }
660
661 func TestOneofParsing(t *testing.T) {
662 const in = `name:"Shrek"`
663 m := new(Communique)
664 want := &Communique{Union: &Communique_Name{Name: "Shrek"}}
665 if err := UnmarshalText(in, m); err != nil {
666 t.Fatal(err)
667 }
668 if !Equal(m, want) {
669 t.Errorf("\n got %v\nwant %v", m, want)
670 }
671
672 const inOverwrite = `name:"Shrek" number:42`
673 m = new(Communique)
674 testErr := "line 1.13: field 'number' would overwrite already parsed oneof 'Union'"
675 if err := UnmarshalText(inOverwrite, m); err == nil {
676 t.Errorf("TestOneofParsing: Didn't get expected error: %v", testErr)
677 } else if err.Error() != testErr {
678 t.Errorf("TestOneofParsing: Incorrect error.\nHave: %v\nWant: %v",
679 err.Error(), testErr)
680 }
681
682 }
683
684 var benchInput string
685
686 func init() {
687 benchInput = "count: 4\n"
688 for i := 0; i < 1000; i++ {
689 benchInput += "pet: \"fido\"\n"
690 }
691
692
693 pb := new(MyMessage)
694 err := UnmarshalText(benchInput, pb)
695 if err != nil {
696 panic("Bad benchmark input: " + err.Error())
697 }
698 }
699
700 func BenchmarkUnmarshalText(b *testing.B) {
701 pb := new(MyMessage)
702 for i := 0; i < b.N; i++ {
703 UnmarshalText(benchInput, pb)
704 }
705 b.SetBytes(int64(len(benchInput)))
706 }
707
View as plain text