blob: 65211a64043edf3e943e9b67dfd05917e46c5afb [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
Rob Pikeaaa3a622010-03-20 22:32:34 -0700157 // Number too large for float32
David Symonds9f402812011-04-28 18:08:44 +1000158 {
David Symonds5ed980c2011-11-29 09:52:21 +1100159 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
160 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161 },
162
163 // Number posing as a quoted string
David Symonds9f402812011-04-28 18:08:44 +1000164 {
David Symonds5ed980c2011-11-29 09:52:21 +1100165 in: `inner: < host: 12 >` + "\n",
166 err: `line 1.15: invalid string: 12`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700167 },
168
169 // Quoted string posing as int32
David Symonds9f402812011-04-28 18:08:44 +1000170 {
David Symonds5ed980c2011-11-29 09:52:21 +1100171 in: `count: "12"`,
172 err: `line 1.7: invalid int32: "12"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700173 },
174
175 // Quoted string posing a float32
David Symonds9f402812011-04-28 18:08:44 +1000176 {
David Symonds5ed980c2011-11-29 09:52:21 +1100177 in: `others:< weight: "17.4" >`,
178 err: `line 1.17: invalid float32: "17.4"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700179 },
180
181 // Enum
David Symonds9f402812011-04-28 18:08:44 +1000182 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700183 in: `count:42 bikeshed: BLUE`,
184 out: &MyMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700185 Count: Int32(42),
David Symondsefeca9a2012-05-08 10:36:04 +1000186 Bikeshed: MyMessage_BLUE.Enum(),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700187 },
188 },
189
190 // Repeated field
David Symonds9f402812011-04-28 18:08:44 +1000191 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700192 in: `count:42 pet: "horsey" pet:"bunny"`,
193 out: &MyMessage{
194 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700195 Pet: []string{"horsey", "bunny"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700196 },
197 },
198
Rob Pikeaaf695a2010-06-22 15:51:21 -0700199 // Repeated message with/without colon and <>/{}
David Symonds9f402812011-04-28 18:08:44 +1000200 {
Rob Pikeaaf695a2010-06-22 15:51:21 -0700201 in: `count:42 others:{} others{} others:<> others:{}`,
202 out: &MyMessage{
203 Count: Int32(42),
204 Others: []*OtherMessage{
205 &OtherMessage{},
206 &OtherMessage{},
207 &OtherMessage{},
208 &OtherMessage{},
209 },
210 },
211 },
212
Rob Pikeaaa3a622010-03-20 22:32:34 -0700213 // Missing colon for inner message
David Symonds9f402812011-04-28 18:08:44 +1000214 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700215 in: `count:42 inner < host: "cauchy.syd" >`,
216 out: &MyMessage{
217 Count: Int32(42),
218 Inner: &InnerMessage{
219 Host: String("cauchy.syd"),
220 },
221 },
222 },
223
224 // Missing colon for string field
David Symonds9f402812011-04-28 18:08:44 +1000225 {
David Symonds5ed980c2011-11-29 09:52:21 +1100226 in: `name "Dave"`,
227 err: `line 1.5: expected ':', found "\"Dave\""`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700228 },
229
230 // Missing colon for int32 field
David Symonds9f402812011-04-28 18:08:44 +1000231 {
David Symonds5ed980c2011-11-29 09:52:21 +1100232 in: `count 42`,
233 err: `line 1.6: expected ':', found "42"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700234 },
235
236 // Missing required field
David Symonds9f402812011-04-28 18:08:44 +1000237 {
David Symonds5ed980c2011-11-29 09:52:21 +1100238 in: ``,
Rob Pikeb7907bf2012-02-13 14:25:20 +1100239 err: `line 1.0: message testdata.MyMessage missing required field "count"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700240 },
241
242 // Repeated non-repeated field
David Symonds9f402812011-04-28 18:08:44 +1000243 {
David Symonds5ed980c2011-11-29 09:52:21 +1100244 in: `name: "Rob" name: "Russ"`,
245 err: `line 1.12: non-repeated field "name" was repeated`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700246 },
247
David Symonds9f402812011-04-28 18:08:44 +1000248 // Group
249 {
250 in: `count: 17 SomeGroup { group_field: 12 }`,
251 out: &MyMessage{
252 Count: Int32(17),
253 Somegroup: &MyMessage_SomeGroup{
254 GroupField: Int32(12),
255 },
256 },
257 },
258
David Symonds54531052011-12-08 12:00:31 +1100259 // Extension
Rob Pikeb7907bf2012-02-13 14:25:20 +1100260 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
261 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
262 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
David Symonds61826da2012-05-05 09:31:28 +1000263 buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`),
David Symonds54531052011-12-08 12:00:31 +1100264
Rob Pikeaaa3a622010-03-20 22:32:34 -0700265 // Big all-in-one
David Symonds9f402812011-04-28 18:08:44 +1000266 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700267 in: "count:42 # Meaning\n" +
268 `name:"Dave" ` +
269 `quote:"\"I didn't want to go.\"" ` +
270 `pet:"bunny" ` +
271 `pet:"kitty" ` +
272 `pet:"horsey" ` +
273 `inner:<` +
274 ` host:"footrest.syd" ` +
275 ` port:7001 ` +
276 ` connected:true ` +
277 `> ` +
278 `others:<` +
279 ` key:3735928559 ` +
280 ` value:"\x01A\a\f" ` +
281 `> ` +
282 `others:<` +
283 " weight:58.9 # Atomic weight of Co\n" +
284 ` inner:<` +
285 ` host:"lesha.mtv" ` +
286 ` port:8002 ` +
287 ` >` +
288 `>`,
289 out: &MyMessage{
290 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700291 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700292 Quote: String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -0700293 Pet: []string{"bunny", "kitty", "horsey"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700294 Inner: &InnerMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700295 Host: String("footrest.syd"),
296 Port: Int32(7001),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700297 Connected: Bool(true),
298 },
299 Others: []*OtherMessage{
300 &OtherMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700301 Key: Int64(3735928559),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700302 Value: []byte{0x1, 'A', '\a', '\f'},
303 },
304 &OtherMessage{
305 Weight: Float32(58.9),
306 Inner: &InnerMessage{
307 Host: String("lesha.mtv"),
308 Port: Int32(8002),
309 },
310 },
311 },
312 },
313 },
314}
315
316func TestUnmarshalText(t *testing.T) {
317 for i, test := range unMarshalTextTests {
318 pb := new(MyMessage)
319 err := UnmarshalText(test.in, pb)
David Symonds5ed980c2011-11-29 09:52:21 +1100320 if test.err == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700321 // We don't expect failure.
322 if err != nil {
323 t.Errorf("Test %d: Unexpected error: %v", i, err)
324 } else if !reflect.DeepEqual(pb, test.out) {
David Symondsef8f0e82011-10-13 12:57:34 +1100325 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
326 i, pb, test.out)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700327 }
328 } else {
329 // We do expect failure.
330 if err == nil {
David Symonds5ed980c2011-11-29 09:52:21 +1100331 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
332 } else if err.Error() != test.err {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700333 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
David Symonds5ed980c2011-11-29 09:52:21 +1100334 i, err.Error(), test.err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700335 }
336 }
337 }
338}
David Symonds79eae332010-10-16 11:33:20 +1100339
David Symondsef8f0e82011-10-13 12:57:34 +1100340// Regression test; this caused a panic.
341func TestRepeatedEnum(t *testing.T) {
342 pb := new(RepeatedEnum)
343 if err := UnmarshalText("color: RED", pb); err != nil {
344 t.Fatal(err)
345 }
346 exp := &RepeatedEnum{
347 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
348 }
349 if !reflect.DeepEqual(pb, exp) {
350 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
351 }
352}
353
David Symonds79eae332010-10-16 11:33:20 +1100354var benchInput string
355
356func init() {
357 benchInput = "count: 4\n"
358 for i := 0; i < 1000; i++ {
359 benchInput += "pet: \"fido\"\n"
360 }
361
362 // Check it is valid input.
363 pb := new(MyMessage)
364 err := UnmarshalText(benchInput, pb)
365 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700366 panic("Bad benchmark input: " + err.Error())
David Symonds79eae332010-10-16 11:33:20 +1100367 }
368}
369
370func BenchmarkUnmarshalText(b *testing.B) {
371 pb := new(MyMessage)
372 for i := 0; i < b.N; i++ {
373 UnmarshalText(benchInput, pb)
374 }
375 b.SetBytes(int64(len(benchInput)))
376}