blob: dbd6b2ca674ee35eed4019328565afd6113783a0 [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
132 // Number too large for float32
David Symonds9f402812011-04-28 18:08:44 +1000133 {
David Symonds5ed980c2011-11-29 09:52:21 +1100134 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
135 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700136 },
137
138 // Number posing as a quoted string
David Symonds9f402812011-04-28 18:08:44 +1000139 {
David Symonds5ed980c2011-11-29 09:52:21 +1100140 in: `inner: < host: 12 >` + "\n",
141 err: `line 1.15: invalid string: 12`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700142 },
143
144 // Quoted string posing as int32
David Symonds9f402812011-04-28 18:08:44 +1000145 {
David Symonds5ed980c2011-11-29 09:52:21 +1100146 in: `count: "12"`,
147 err: `line 1.7: invalid int32: "12"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700148 },
149
150 // Quoted string posing a float32
David Symonds9f402812011-04-28 18:08:44 +1000151 {
David Symonds5ed980c2011-11-29 09:52:21 +1100152 in: `others:< weight: "17.4" >`,
153 err: `line 1.17: invalid float32: "17.4"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700154 },
155
156 // Enum
David Symonds9f402812011-04-28 18:08:44 +1000157 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700158 in: `count:42 bikeshed: BLUE`,
159 out: &MyMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700160 Count: Int32(42),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161 Bikeshed: NewMyMessage_Color(MyMessage_BLUE),
162 },
163 },
164
165 // Repeated field
David Symonds9f402812011-04-28 18:08:44 +1000166 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700167 in: `count:42 pet: "horsey" pet:"bunny"`,
168 out: &MyMessage{
169 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700170 Pet: []string{"horsey", "bunny"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700171 },
172 },
173
Rob Pikeaaf695a2010-06-22 15:51:21 -0700174 // Repeated message with/without colon and <>/{}
David Symonds9f402812011-04-28 18:08:44 +1000175 {
Rob Pikeaaf695a2010-06-22 15:51:21 -0700176 in: `count:42 others:{} others{} others:<> others:{}`,
177 out: &MyMessage{
178 Count: Int32(42),
179 Others: []*OtherMessage{
180 &OtherMessage{},
181 &OtherMessage{},
182 &OtherMessage{},
183 &OtherMessage{},
184 },
185 },
186 },
187
Rob Pikeaaa3a622010-03-20 22:32:34 -0700188 // Missing colon for inner message
David Symonds9f402812011-04-28 18:08:44 +1000189 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700190 in: `count:42 inner < host: "cauchy.syd" >`,
191 out: &MyMessage{
192 Count: Int32(42),
193 Inner: &InnerMessage{
194 Host: String("cauchy.syd"),
195 },
196 },
197 },
198
199 // Missing colon for string field
David Symonds9f402812011-04-28 18:08:44 +1000200 {
David Symonds5ed980c2011-11-29 09:52:21 +1100201 in: `name "Dave"`,
202 err: `line 1.5: expected ':', found "\"Dave\""`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700203 },
204
205 // Missing colon for int32 field
David Symonds9f402812011-04-28 18:08:44 +1000206 {
David Symonds5ed980c2011-11-29 09:52:21 +1100207 in: `count 42`,
208 err: `line 1.6: expected ':', found "42"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209 },
210
211 // Missing required field
David Symonds9f402812011-04-28 18:08:44 +1000212 {
David Symonds5ed980c2011-11-29 09:52:21 +1100213 in: ``,
Rob Pikeb7907bf2012-02-13 14:25:20 +1100214 err: `line 1.0: message testdata.MyMessage missing required field "count"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700215 },
216
217 // Repeated non-repeated field
David Symonds9f402812011-04-28 18:08:44 +1000218 {
David Symonds5ed980c2011-11-29 09:52:21 +1100219 in: `name: "Rob" name: "Russ"`,
220 err: `line 1.12: non-repeated field "name" was repeated`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700221 },
222
David Symonds9f402812011-04-28 18:08:44 +1000223 // Group
224 {
225 in: `count: 17 SomeGroup { group_field: 12 }`,
226 out: &MyMessage{
227 Count: Int32(17),
228 Somegroup: &MyMessage_SomeGroup{
229 GroupField: Int32(12),
230 },
231 },
232 },
233
David Symonds54531052011-12-08 12:00:31 +1100234 // Extension
Rob Pikeb7907bf2012-02-13 14:25:20 +1100235 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
236 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
237 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
David Symonds61826da2012-05-05 09:31:28 +1000238 buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`),
David Symonds54531052011-12-08 12:00:31 +1100239
Rob Pikeaaa3a622010-03-20 22:32:34 -0700240 // Big all-in-one
David Symonds9f402812011-04-28 18:08:44 +1000241 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700242 in: "count:42 # Meaning\n" +
243 `name:"Dave" ` +
244 `quote:"\"I didn't want to go.\"" ` +
245 `pet:"bunny" ` +
246 `pet:"kitty" ` +
247 `pet:"horsey" ` +
248 `inner:<` +
249 ` host:"footrest.syd" ` +
250 ` port:7001 ` +
251 ` connected:true ` +
252 `> ` +
253 `others:<` +
254 ` key:3735928559 ` +
255 ` value:"\x01A\a\f" ` +
256 `> ` +
257 `others:<` +
258 " weight:58.9 # Atomic weight of Co\n" +
259 ` inner:<` +
260 ` host:"lesha.mtv" ` +
261 ` port:8002 ` +
262 ` >` +
263 `>`,
264 out: &MyMessage{
265 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700266 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700267 Quote: String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -0700268 Pet: []string{"bunny", "kitty", "horsey"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700269 Inner: &InnerMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700270 Host: String("footrest.syd"),
271 Port: Int32(7001),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700272 Connected: Bool(true),
273 },
274 Others: []*OtherMessage{
275 &OtherMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700276 Key: Int64(3735928559),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700277 Value: []byte{0x1, 'A', '\a', '\f'},
278 },
279 &OtherMessage{
280 Weight: Float32(58.9),
281 Inner: &InnerMessage{
282 Host: String("lesha.mtv"),
283 Port: Int32(8002),
284 },
285 },
286 },
287 },
288 },
289}
290
291func TestUnmarshalText(t *testing.T) {
292 for i, test := range unMarshalTextTests {
293 pb := new(MyMessage)
294 err := UnmarshalText(test.in, pb)
David Symonds5ed980c2011-11-29 09:52:21 +1100295 if test.err == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700296 // We don't expect failure.
297 if err != nil {
298 t.Errorf("Test %d: Unexpected error: %v", i, err)
299 } else if !reflect.DeepEqual(pb, test.out) {
David Symondsef8f0e82011-10-13 12:57:34 +1100300 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
301 i, pb, test.out)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700302 }
303 } else {
304 // We do expect failure.
305 if err == nil {
David Symonds5ed980c2011-11-29 09:52:21 +1100306 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
307 } else if err.Error() != test.err {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700308 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
David Symonds5ed980c2011-11-29 09:52:21 +1100309 i, err.Error(), test.err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700310 }
311 }
312 }
313}
David Symonds79eae332010-10-16 11:33:20 +1100314
David Symondsef8f0e82011-10-13 12:57:34 +1100315// Regression test; this caused a panic.
316func TestRepeatedEnum(t *testing.T) {
317 pb := new(RepeatedEnum)
318 if err := UnmarshalText("color: RED", pb); err != nil {
319 t.Fatal(err)
320 }
321 exp := &RepeatedEnum{
322 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
323 }
324 if !reflect.DeepEqual(pb, exp) {
325 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
326 }
327}
328
David Symonds79eae332010-10-16 11:33:20 +1100329var benchInput string
330
331func init() {
332 benchInput = "count: 4\n"
333 for i := 0; i < 1000; i++ {
334 benchInput += "pet: \"fido\"\n"
335 }
336
337 // Check it is valid input.
338 pb := new(MyMessage)
339 err := UnmarshalText(benchInput, pb)
340 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700341 panic("Bad benchmark input: " + err.Error())
David Symonds79eae332010-10-16 11:33:20 +1100342 }
343}
344
345func BenchmarkUnmarshalText(b *testing.B) {
346 pb := new(MyMessage)
347 for i := 0; i < b.N; i++ {
348 UnmarshalText(benchInput, pb)
349 }
350 b.SetBytes(int64(len(benchInput)))
351}