blob: 9f334fb0951bd15a5a840250e233e48bc667b496 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 Google Inc. All rights reserved.
4// http://code.google.com/p/goprotobuf/
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
32package proto_test
33
34import (
Rob Pikeaaa3a622010-03-20 22:32:34 -070035 "reflect"
36 "testing"
David Symonds20c73662012-01-20 07:32:21 +110037
David Symonds704096f2012-03-15 15:10:26 +110038 . "./testdata"
David Symonds20c73662012-01-20 07:32:21 +110039 . "code.google.com/p/goprotobuf/proto"
Rob Pikeaaa3a622010-03-20 22:32:34 -070040)
41
42type UnmarshalTextTest struct {
David Symonds5ed980c2011-11-29 09:52:21 +110043 in string
44 err string // if "", no error expected
45 out *MyMessage
Rob Pikeaaa3a622010-03-20 22:32:34 -070046}
47
David Symonds54531052011-12-08 12:00:31 +110048func buildExtStructTest(text string) UnmarshalTextTest {
49 msg := &MyMessage{
50 Count: Int32(42),
51 }
52 SetExtension(msg, E_Ext_More, &Ext{
53 Data: String("Hello, world!"),
54 })
55 return UnmarshalTextTest{in: text, out: msg}
56}
57
58func buildExtDataTest(text string) UnmarshalTextTest {
59 msg := &MyMessage{
60 Count: Int32(42),
61 }
62 SetExtension(msg, E_Ext_Text, String("Hello, world!"))
63 SetExtension(msg, E_Ext_Number, Int32(1729))
64 return UnmarshalTextTest{in: text, out: msg}
65}
66
David Symonds61826da2012-05-05 09:31:28 +100067func buildExtRepStringTest(text string) UnmarshalTextTest {
68 msg := &MyMessage{
69 Count: Int32(42),
70 }
71 if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil {
72 panic(err)
73 }
74 return UnmarshalTextTest{in: text, out: msg}
75}
76
Rob Pikeaaa3a622010-03-20 22:32:34 -070077var unMarshalTextTests = []UnmarshalTextTest{
78 // Basic
David Symonds9f402812011-04-28 18:08:44 +100079 {
Rob Pikeaaa3a622010-03-20 22:32:34 -070080 in: " count:42\n name:\"Dave\" ",
81 out: &MyMessage{
82 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -070083 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -070084 },
85 },
86
87 // Empty quoted string
David Symonds9f402812011-04-28 18:08:44 +100088 {
Rob Pikeaaa3a622010-03-20 22:32:34 -070089 in: `count:42 name:""`,
90 out: &MyMessage{
91 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -070092 Name: String(""),
Rob Pikeaaa3a622010-03-20 22:32:34 -070093 },
94 },
95
96 // Quoted string concatenation
David Symonds9f402812011-04-28 18:08:44 +100097 {
Rob Pikeaaa3a622010-03-20 22:32:34 -070098 in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
99 out: &MyMessage{
100 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700101 Name: String("My name is elsewhere"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700102 },
103 },
104
David Symonds183124e2012-03-23 13:20:23 +1100105 // Quoted string with escaped apostrophe
106 {
107 in: `count:42 name: "HOLIDAY - New Year\'s Day"`,
108 out: &MyMessage{
109 Count: Int32(42),
110 Name: String("HOLIDAY - New Year's Day"),
111 },
112 },
113
David Symonds162d0032012-06-28 09:44:46 -0700114 // Quoted string with single quote
115 {
116 in: `count:42 name: 'Roger "The Ramster" Ramjet'`,
117 out: &MyMessage{
118 Count: Int32(42),
119 Name: String(`Roger "The Ramster" Ramjet`),
120 },
121 },
122
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123 // Bad quoted string
David Symonds9f402812011-04-28 18:08:44 +1000124 {
David Symonds5ed980c2011-11-29 09:52:21 +1100125 in: `inner: < host: "\0" >` + "\n",
126 err: `line 1.15: invalid quoted string "\0"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700127 },
128
129 // Number too large for int64
David Symonds9f402812011-04-28 18:08:44 +1000130 {
David Symonds5ed980c2011-11-29 09:52:21 +1100131 in: "count: 123456789012345678901",
132 err: "line 1.7: invalid int32: 123456789012345678901",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700133 },
134
135 // Number too large for int32
David Symonds9f402812011-04-28 18:08:44 +1000136 {
David Symonds5ed980c2011-11-29 09:52:21 +1100137 in: "count: 1234567890123",
138 err: "line 1.7: invalid int32: 1234567890123",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700139 },
140
David Symonds32612dd2012-06-15 07:59:05 -0700141 // Number in hexadecimal
142 {
143 in: "count: 0x2beef",
144 out: &MyMessage{
145 Count: Int32(0x2beef),
146 },
147 },
148
149 // Number in octal
150 {
151 in: "count: 024601",
152 out: &MyMessage{
153 Count: Int32(024601),
154 },
155 },
156
David Symonds6bd081e2012-06-28 10:46:25 -0700157 // Floating point number with "f" suffix
158 {
159 in: "count: 4 others:< weight: 17.0f >",
160 out: &MyMessage{
161 Count: Int32(4),
162 Others: []*OtherMessage{
163 {
164 Weight: Float32(17),
165 },
166 },
167 },
168 },
169
Rob Pikeaaa3a622010-03-20 22:32:34 -0700170 // Number too large for float32
David Symonds9f402812011-04-28 18:08:44 +1000171 {
David Symonds5ed980c2011-11-29 09:52:21 +1100172 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
173 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700174 },
175
176 // Number posing as a quoted string
David Symonds9f402812011-04-28 18:08:44 +1000177 {
David Symonds5ed980c2011-11-29 09:52:21 +1100178 in: `inner: < host: 12 >` + "\n",
179 err: `line 1.15: invalid string: 12`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700180 },
181
182 // Quoted string posing as int32
David Symonds9f402812011-04-28 18:08:44 +1000183 {
David Symonds5ed980c2011-11-29 09:52:21 +1100184 in: `count: "12"`,
185 err: `line 1.7: invalid int32: "12"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700186 },
187
188 // Quoted string posing a float32
David Symonds9f402812011-04-28 18:08:44 +1000189 {
David Symonds5ed980c2011-11-29 09:52:21 +1100190 in: `others:< weight: "17.4" >`,
191 err: `line 1.17: invalid float32: "17.4"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700192 },
193
194 // Enum
David Symonds9f402812011-04-28 18:08:44 +1000195 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700196 in: `count:42 bikeshed: BLUE`,
197 out: &MyMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700198 Count: Int32(42),
David Symondsefeca9a2012-05-08 10:36:04 +1000199 Bikeshed: MyMessage_BLUE.Enum(),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700200 },
201 },
202
203 // Repeated field
David Symonds9f402812011-04-28 18:08:44 +1000204 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700205 in: `count:42 pet: "horsey" pet:"bunny"`,
206 out: &MyMessage{
207 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700208 Pet: []string{"horsey", "bunny"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209 },
210 },
211
Rob Pikeaaf695a2010-06-22 15:51:21 -0700212 // Repeated message with/without colon and <>/{}
David Symonds9f402812011-04-28 18:08:44 +1000213 {
Rob Pikeaaf695a2010-06-22 15:51:21 -0700214 in: `count:42 others:{} others{} others:<> others:{}`,
215 out: &MyMessage{
216 Count: Int32(42),
217 Others: []*OtherMessage{
218 &OtherMessage{},
219 &OtherMessage{},
220 &OtherMessage{},
221 &OtherMessage{},
222 },
223 },
224 },
225
Rob Pikeaaa3a622010-03-20 22:32:34 -0700226 // Missing colon for inner message
David Symonds9f402812011-04-28 18:08:44 +1000227 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700228 in: `count:42 inner < host: "cauchy.syd" >`,
229 out: &MyMessage{
230 Count: Int32(42),
231 Inner: &InnerMessage{
232 Host: String("cauchy.syd"),
233 },
234 },
235 },
236
237 // Missing colon for string field
David Symonds9f402812011-04-28 18:08:44 +1000238 {
David Symonds5ed980c2011-11-29 09:52:21 +1100239 in: `name "Dave"`,
240 err: `line 1.5: expected ':', found "\"Dave\""`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700241 },
242
243 // Missing colon for int32 field
David Symonds9f402812011-04-28 18:08:44 +1000244 {
David Symonds5ed980c2011-11-29 09:52:21 +1100245 in: `count 42`,
246 err: `line 1.6: expected ':', found "42"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700247 },
248
249 // Missing required field
David Symonds9f402812011-04-28 18:08:44 +1000250 {
David Symonds5ed980c2011-11-29 09:52:21 +1100251 in: ``,
Rob Pikeb7907bf2012-02-13 14:25:20 +1100252 err: `line 1.0: message testdata.MyMessage missing required field "count"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700253 },
254
255 // Repeated non-repeated field
David Symonds9f402812011-04-28 18:08:44 +1000256 {
David Symonds5ed980c2011-11-29 09:52:21 +1100257 in: `name: "Rob" name: "Russ"`,
258 err: `line 1.12: non-repeated field "name" was repeated`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700259 },
260
David Symonds9f402812011-04-28 18:08:44 +1000261 // Group
262 {
263 in: `count: 17 SomeGroup { group_field: 12 }`,
264 out: &MyMessage{
265 Count: Int32(17),
266 Somegroup: &MyMessage_SomeGroup{
267 GroupField: Int32(12),
268 },
269 },
270 },
271
David Symonds54531052011-12-08 12:00:31 +1100272 // Extension
Rob Pikeb7907bf2012-02-13 14:25:20 +1100273 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
274 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
275 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
David Symonds61826da2012-05-05 09:31:28 +1000276 buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`),
David Symonds54531052011-12-08 12:00:31 +1100277
Rob Pikeaaa3a622010-03-20 22:32:34 -0700278 // Big all-in-one
David Symonds9f402812011-04-28 18:08:44 +1000279 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700280 in: "count:42 # Meaning\n" +
281 `name:"Dave" ` +
282 `quote:"\"I didn't want to go.\"" ` +
283 `pet:"bunny" ` +
284 `pet:"kitty" ` +
285 `pet:"horsey" ` +
286 `inner:<` +
287 ` host:"footrest.syd" ` +
288 ` port:7001 ` +
289 ` connected:true ` +
290 `> ` +
291 `others:<` +
292 ` key:3735928559 ` +
293 ` value:"\x01A\a\f" ` +
294 `> ` +
295 `others:<` +
296 " weight:58.9 # Atomic weight of Co\n" +
297 ` inner:<` +
298 ` host:"lesha.mtv" ` +
299 ` port:8002 ` +
300 ` >` +
301 `>`,
302 out: &MyMessage{
303 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700304 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700305 Quote: String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -0700306 Pet: []string{"bunny", "kitty", "horsey"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700307 Inner: &InnerMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700308 Host: String("footrest.syd"),
309 Port: Int32(7001),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700310 Connected: Bool(true),
311 },
312 Others: []*OtherMessage{
313 &OtherMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700314 Key: Int64(3735928559),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700315 Value: []byte{0x1, 'A', '\a', '\f'},
316 },
317 &OtherMessage{
318 Weight: Float32(58.9),
319 Inner: &InnerMessage{
320 Host: String("lesha.mtv"),
321 Port: Int32(8002),
322 },
323 },
324 },
325 },
326 },
327}
328
329func TestUnmarshalText(t *testing.T) {
330 for i, test := range unMarshalTextTests {
331 pb := new(MyMessage)
332 err := UnmarshalText(test.in, pb)
David Symonds5ed980c2011-11-29 09:52:21 +1100333 if test.err == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700334 // We don't expect failure.
335 if err != nil {
336 t.Errorf("Test %d: Unexpected error: %v", i, err)
337 } else if !reflect.DeepEqual(pb, test.out) {
David Symondsef8f0e82011-10-13 12:57:34 +1100338 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
339 i, pb, test.out)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700340 }
341 } else {
342 // We do expect failure.
343 if err == nil {
David Symonds5ed980c2011-11-29 09:52:21 +1100344 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
345 } else if err.Error() != test.err {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700346 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
David Symonds5ed980c2011-11-29 09:52:21 +1100347 i, err.Error(), test.err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700348 }
349 }
350 }
351}
David Symonds79eae332010-10-16 11:33:20 +1100352
David Symondsef8f0e82011-10-13 12:57:34 +1100353// Regression test; this caused a panic.
354func TestRepeatedEnum(t *testing.T) {
355 pb := new(RepeatedEnum)
356 if err := UnmarshalText("color: RED", pb); err != nil {
357 t.Fatal(err)
358 }
359 exp := &RepeatedEnum{
360 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
361 }
David Symonds007ed9d2012-07-24 10:59:36 +1000362 if !Equal(pb, exp) {
David Symondsef8f0e82011-10-13 12:57:34 +1100363 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
364 }
365}
366
David Symonds79eae332010-10-16 11:33:20 +1100367var benchInput string
368
369func init() {
370 benchInput = "count: 4\n"
371 for i := 0; i < 1000; i++ {
372 benchInput += "pet: \"fido\"\n"
373 }
374
375 // Check it is valid input.
376 pb := new(MyMessage)
377 err := UnmarshalText(benchInput, pb)
378 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700379 panic("Bad benchmark input: " + err.Error())
David Symonds79eae332010-10-16 11:33:20 +1100380 }
381}
382
383func BenchmarkUnmarshalText(b *testing.B) {
384 pb := new(MyMessage)
385 for i := 0; i < b.N; i++ {
386 UnmarshalText(benchInput, pb)
387 }
388 b.SetBytes(int64(len(benchInput)))
389}