blob: bca0ecb0409c0d5bea46ac692fa44fb5ae474fa5 [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
Rob Pikeaaa3a622010-03-20 22:32:34 -0700114 // Bad quoted string
David Symonds9f402812011-04-28 18:08:44 +1000115 {
David Symonds5ed980c2011-11-29 09:52:21 +1100116 in: `inner: < host: "\0" >` + "\n",
117 err: `line 1.15: invalid quoted string "\0"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700118 },
119
120 // Number too large for int64
David Symonds9f402812011-04-28 18:08:44 +1000121 {
David Symonds5ed980c2011-11-29 09:52:21 +1100122 in: "count: 123456789012345678901",
123 err: "line 1.7: invalid int32: 123456789012345678901",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700124 },
125
126 // Number too large for int32
David Symonds9f402812011-04-28 18:08:44 +1000127 {
David Symonds5ed980c2011-11-29 09:52:21 +1100128 in: "count: 1234567890123",
129 err: "line 1.7: invalid int32: 1234567890123",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700130 },
131
David Symonds32612dd2012-06-15 07:59:05 -0700132 // Number in hexadecimal
133 {
134 in: "count: 0x2beef",
135 out: &MyMessage{
136 Count: Int32(0x2beef),
137 },
138 },
139
140 // Number in octal
141 {
142 in: "count: 024601",
143 out: &MyMessage{
144 Count: Int32(024601),
145 },
146 },
147
Rob Pikeaaa3a622010-03-20 22:32:34 -0700148 // Number too large for float32
David Symonds9f402812011-04-28 18:08:44 +1000149 {
David Symonds5ed980c2011-11-29 09:52:21 +1100150 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
151 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 },
153
154 // Number posing as a quoted string
David Symonds9f402812011-04-28 18:08:44 +1000155 {
David Symonds5ed980c2011-11-29 09:52:21 +1100156 in: `inner: < host: 12 >` + "\n",
157 err: `line 1.15: invalid string: 12`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700158 },
159
160 // Quoted string posing as int32
David Symonds9f402812011-04-28 18:08:44 +1000161 {
David Symonds5ed980c2011-11-29 09:52:21 +1100162 in: `count: "12"`,
163 err: `line 1.7: invalid int32: "12"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700164 },
165
166 // Quoted string posing a float32
David Symonds9f402812011-04-28 18:08:44 +1000167 {
David Symonds5ed980c2011-11-29 09:52:21 +1100168 in: `others:< weight: "17.4" >`,
169 err: `line 1.17: invalid float32: "17.4"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700170 },
171
172 // Enum
David Symonds9f402812011-04-28 18:08:44 +1000173 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700174 in: `count:42 bikeshed: BLUE`,
175 out: &MyMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700176 Count: Int32(42),
David Symondsefeca9a2012-05-08 10:36:04 +1000177 Bikeshed: MyMessage_BLUE.Enum(),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700178 },
179 },
180
181 // Repeated field
David Symonds9f402812011-04-28 18:08:44 +1000182 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700183 in: `count:42 pet: "horsey" pet:"bunny"`,
184 out: &MyMessage{
185 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700186 Pet: []string{"horsey", "bunny"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700187 },
188 },
189
Rob Pikeaaf695a2010-06-22 15:51:21 -0700190 // Repeated message with/without colon and <>/{}
David Symonds9f402812011-04-28 18:08:44 +1000191 {
Rob Pikeaaf695a2010-06-22 15:51:21 -0700192 in: `count:42 others:{} others{} others:<> others:{}`,
193 out: &MyMessage{
194 Count: Int32(42),
195 Others: []*OtherMessage{
196 &OtherMessage{},
197 &OtherMessage{},
198 &OtherMessage{},
199 &OtherMessage{},
200 },
201 },
202 },
203
Rob Pikeaaa3a622010-03-20 22:32:34 -0700204 // Missing colon for inner message
David Symonds9f402812011-04-28 18:08:44 +1000205 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700206 in: `count:42 inner < host: "cauchy.syd" >`,
207 out: &MyMessage{
208 Count: Int32(42),
209 Inner: &InnerMessage{
210 Host: String("cauchy.syd"),
211 },
212 },
213 },
214
215 // Missing colon for string field
David Symonds9f402812011-04-28 18:08:44 +1000216 {
David Symonds5ed980c2011-11-29 09:52:21 +1100217 in: `name "Dave"`,
218 err: `line 1.5: expected ':', found "\"Dave\""`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700219 },
220
221 // Missing colon for int32 field
David Symonds9f402812011-04-28 18:08:44 +1000222 {
David Symonds5ed980c2011-11-29 09:52:21 +1100223 in: `count 42`,
224 err: `line 1.6: expected ':', found "42"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700225 },
226
227 // Missing required field
David Symonds9f402812011-04-28 18:08:44 +1000228 {
David Symonds5ed980c2011-11-29 09:52:21 +1100229 in: ``,
Rob Pikeb7907bf2012-02-13 14:25:20 +1100230 err: `line 1.0: message testdata.MyMessage missing required field "count"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231 },
232
233 // Repeated non-repeated field
David Symonds9f402812011-04-28 18:08:44 +1000234 {
David Symonds5ed980c2011-11-29 09:52:21 +1100235 in: `name: "Rob" name: "Russ"`,
236 err: `line 1.12: non-repeated field "name" was repeated`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700237 },
238
David Symonds9f402812011-04-28 18:08:44 +1000239 // Group
240 {
241 in: `count: 17 SomeGroup { group_field: 12 }`,
242 out: &MyMessage{
243 Count: Int32(17),
244 Somegroup: &MyMessage_SomeGroup{
245 GroupField: Int32(12),
246 },
247 },
248 },
249
David Symonds54531052011-12-08 12:00:31 +1100250 // Extension
Rob Pikeb7907bf2012-02-13 14:25:20 +1100251 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
252 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
253 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
David Symonds61826da2012-05-05 09:31:28 +1000254 buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`),
David Symonds54531052011-12-08 12:00:31 +1100255
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256 // Big all-in-one
David Symonds9f402812011-04-28 18:08:44 +1000257 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700258 in: "count:42 # Meaning\n" +
259 `name:"Dave" ` +
260 `quote:"\"I didn't want to go.\"" ` +
261 `pet:"bunny" ` +
262 `pet:"kitty" ` +
263 `pet:"horsey" ` +
264 `inner:<` +
265 ` host:"footrest.syd" ` +
266 ` port:7001 ` +
267 ` connected:true ` +
268 `> ` +
269 `others:<` +
270 ` key:3735928559 ` +
271 ` value:"\x01A\a\f" ` +
272 `> ` +
273 `others:<` +
274 " weight:58.9 # Atomic weight of Co\n" +
275 ` inner:<` +
276 ` host:"lesha.mtv" ` +
277 ` port:8002 ` +
278 ` >` +
279 `>`,
280 out: &MyMessage{
281 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700282 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700283 Quote: String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -0700284 Pet: []string{"bunny", "kitty", "horsey"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700285 Inner: &InnerMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700286 Host: String("footrest.syd"),
287 Port: Int32(7001),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700288 Connected: Bool(true),
289 },
290 Others: []*OtherMessage{
291 &OtherMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700292 Key: Int64(3735928559),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700293 Value: []byte{0x1, 'A', '\a', '\f'},
294 },
295 &OtherMessage{
296 Weight: Float32(58.9),
297 Inner: &InnerMessage{
298 Host: String("lesha.mtv"),
299 Port: Int32(8002),
300 },
301 },
302 },
303 },
304 },
305}
306
307func TestUnmarshalText(t *testing.T) {
308 for i, test := range unMarshalTextTests {
309 pb := new(MyMessage)
310 err := UnmarshalText(test.in, pb)
David Symonds5ed980c2011-11-29 09:52:21 +1100311 if test.err == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700312 // We don't expect failure.
313 if err != nil {
314 t.Errorf("Test %d: Unexpected error: %v", i, err)
315 } else if !reflect.DeepEqual(pb, test.out) {
David Symondsef8f0e82011-10-13 12:57:34 +1100316 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
317 i, pb, test.out)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700318 }
319 } else {
320 // We do expect failure.
321 if err == nil {
David Symonds5ed980c2011-11-29 09:52:21 +1100322 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
323 } else if err.Error() != test.err {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700324 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
David Symonds5ed980c2011-11-29 09:52:21 +1100325 i, err.Error(), test.err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700326 }
327 }
328 }
329}
David Symonds79eae332010-10-16 11:33:20 +1100330
David Symondsef8f0e82011-10-13 12:57:34 +1100331// Regression test; this caused a panic.
332func TestRepeatedEnum(t *testing.T) {
333 pb := new(RepeatedEnum)
334 if err := UnmarshalText("color: RED", pb); err != nil {
335 t.Fatal(err)
336 }
337 exp := &RepeatedEnum{
338 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
339 }
340 if !reflect.DeepEqual(pb, exp) {
341 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
342 }
343}
344
David Symonds79eae332010-10-16 11:33:20 +1100345var benchInput string
346
347func init() {
348 benchInput = "count: 4\n"
349 for i := 0; i < 1000; i++ {
350 benchInput += "pet: \"fido\"\n"
351 }
352
353 // Check it is valid input.
354 pb := new(MyMessage)
355 err := UnmarshalText(benchInput, pb)
356 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700357 panic("Bad benchmark input: " + err.Error())
David Symonds79eae332010-10-16 11:33:20 +1100358 }
359}
360
361func BenchmarkUnmarshalText(b *testing.B) {
362 pb := new(MyMessage)
363 for i := 0; i < b.N; i++ {
364 UnmarshalText(benchInput, pb)
365 }
366 b.SetBytes(int64(len(benchInput)))
367}