OSDN Git Service

Merge pull request #31 from Bytom/dev_ipfs_transaction
[bytom/vapor.git] / vendor / github.com / gogo / protobuf / proto / text_parser_test.go
1 // Go support for Protocol Buffers - Google's data interchange format
2 //
3 // Copyright 2010 The Go Authors.  All rights reserved.
4 // https://github.com/golang/protobuf
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 // if "", no error expected
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         // Basic
81         {
82                 in: " count:42\n  name:\"Dave\" ",
83                 out: &MyMessage{
84                         Count: Int32(42),
85                         Name:  String("Dave"),
86                 },
87         },
88
89         // Empty quoted string
90         {
91                 in: `count:42 name:""`,
92                 out: &MyMessage{
93                         Count: Int32(42),
94                         Name:  String(""),
95                 },
96         },
97
98         // Quoted string concatenation with double quotes
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         // Quoted string concatenation with single quotes
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         // Quoted string concatenations with mixed quotes
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         // Quoted string with escaped apostrophe
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         // Quoted string with single quote
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         // Quoted string with all the accepted special characters from the C++ test
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         // Quoted string with quoted backslash
160         {
161                 in: `count:42 name: "\\'xyz"`,
162                 out: &MyMessage{
163                         Count: Int32(42),
164                         Name:  String(`\'xyz`),
165                 },
166         },
167
168         // Quoted string with UTF-8 bytes.
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         // Quoted string with unicode escapes.
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         // Bad quoted string
187         {
188                 in:  `inner: < host: "\0" >` + "\n",
189                 err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`,
190         },
191
192         // Bad \u escape
193         {
194                 in:  `count: 42 name: "\u000"`,
195                 err: `line 1.16: invalid quoted string "\u000": \u requires 4 following digits`,
196         },
197
198         // Bad \U escape
199         {
200                 in:  `count: 42 name: "\U0000000"`,
201                 err: `line 1.16: invalid quoted string "\U0000000": \U requires 8 following digits`,
202         },
203
204         // Bad \U escape
205         {
206                 in:  `count: 42 name: "\xxx"`,
207                 err: `line 1.16: invalid quoted string "\xxx": \xxx contains non-hexadecimal digits`,
208         },
209
210         // Number too large for int64
211         {
212                 in:  "count: 1 others { key: 123456789012345678901 }",
213                 err: "line 1.23: invalid int64: 123456789012345678901",
214         },
215
216         // Number too large for int32
217         {
218                 in:  "count: 1234567890123",
219                 err: "line 1.7: invalid int32: 1234567890123",
220         },
221
222         // Number in hexadecimal
223         {
224                 in: "count: 0x2beef",
225                 out: &MyMessage{
226                         Count: Int32(0x2beef),
227                 },
228         },
229
230         // Number in octal
231         {
232                 in: "count: 024601",
233                 out: &MyMessage{
234                         Count: Int32(024601),
235                 },
236         },
237
238         // Floating point number with "f" suffix
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         // Floating point positive infinity
252         {
253                 in: "count: 4 bigfloat: inf",
254                 out: &MyMessage{
255                         Count:    Int32(4),
256                         Bigfloat: Float64(math.Inf(1)),
257                 },
258         },
259
260         // Floating point negative infinity
261         {
262                 in: "count: 4 bigfloat: -inf",
263                 out: &MyMessage{
264                         Count:    Int32(4),
265                         Bigfloat: Float64(math.Inf(-1)),
266                 },
267         },
268
269         // Number too large for float32
270         {
271                 in:  "others:< weight: 12345678901234567890123456789012345678901234567890 >",
272                 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
273         },
274
275         // Number posing as a quoted string
276         {
277                 in:  `inner: < host: 12 >` + "\n",
278                 err: `line 1.15: invalid string: 12`,
279         },
280
281         // Quoted string posing as int32
282         {
283                 in:  `count: "12"`,
284                 err: `line 1.7: invalid int32: "12"`,
285         },
286
287         // Quoted string posing a float32
288         {
289                 in:  `others:< weight: "17.4" >`,
290                 err: `line 1.17: invalid float32: "17.4"`,
291         },
292
293         // unclosed bracket doesn't cause infinite loop
294         {
295                 in:  `[`,
296                 err: `line 1.0: unclosed type_url or extension name`,
297         },
298
299         // Enum
300         {
301                 in: `count:42 bikeshed: BLUE`,
302                 out: &MyMessage{
303                         Count:    Int32(42),
304                         Bikeshed: MyMessage_BLUE.Enum(),
305                 },
306         },
307
308         // Repeated field
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         // Repeated field with list notation
318         {
319                 in: `count:42 pet: ["horsey", "bunny"]`,
320                 out: &MyMessage{
321                         Count: Int32(42),
322                         Pet:   []string{"horsey", "bunny"},
323                 },
324         },
325
326         // Repeated message with/without colon and <>/{}
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         // Missing colon for inner message
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         // Missing colon for string field
352         {
353                 in:  `name "Dave"`,
354                 err: `line 1.5: expected ':', found "\"Dave\""`,
355         },
356
357         // Missing colon for int32 field
358         {
359                 in:  `count 42`,
360                 err: `line 1.6: expected ':', found "42"`,
361         },
362
363         // Missing required field
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         // Missing required field in a required submessage
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         // Repeated non-repeated field
383         {
384                 in:  `name: "Rob" name: "Russ"`,
385                 err: `line 1.12: non-repeated field "name" was repeated`,
386         },
387
388         // Group
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         // Semicolon between fields
400         {
401                 in: `count:3;name:"Calvin"`,
402                 out: &MyMessage{
403                         Count: Int32(3),
404                         Name:  String("Calvin"),
405                 },
406         },
407         // Comma between fields
408         {
409                 in: `count:4,name:"Ezekiel"`,
410                 out: &MyMessage{
411                         Count: Int32(4),
412                         Name:  String("Ezekiel"),
413                 },
414         },
415
416         // Boolean false
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         // Boolean true
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         // Boolean 0
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         // Boolean 1
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         // Boolean f
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         // Boolean t
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         // Boolean False
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         // Boolean True
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         // Extension
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         // Big all-in-one
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                         // We don't expect failure.
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                         // We do expect failure.
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 // Regression test; this caused a panic.
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>,>` + // separating commas are okay
632                 `msg_mapping<key:-2 value<f: 4.0>>` + // no colon after "value"
633                 `msg_mapping:<value:<f: 5.0>>` + // omitted key
634                 `msg_mapping:<key:1>` + // omitted value
635                 `byte_mapping:<key:true value:"so be it">` +
636                 `byte_mapping:<>` // omitted key and value
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         // Check it is valid input.
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 }