blob: 6212e9e51a0984651944005b597f355cd051ab19 [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
Rob Pikeaaa3a622010-03-20 22:32:34 -070067var unMarshalTextTests = []UnmarshalTextTest{
68 // Basic
David Symonds9f402812011-04-28 18:08:44 +100069 {
Rob Pikeaaa3a622010-03-20 22:32:34 -070070 in: " count:42\n name:\"Dave\" ",
71 out: &MyMessage{
72 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -070073 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -070074 },
75 },
76
77 // Empty quoted string
David Symonds9f402812011-04-28 18:08:44 +100078 {
Rob Pikeaaa3a622010-03-20 22:32:34 -070079 in: `count:42 name:""`,
80 out: &MyMessage{
81 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -070082 Name: String(""),
Rob Pikeaaa3a622010-03-20 22:32:34 -070083 },
84 },
85
86 // Quoted string concatenation
David Symonds9f402812011-04-28 18:08:44 +100087 {
Rob Pikeaaa3a622010-03-20 22:32:34 -070088 in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
89 out: &MyMessage{
90 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -070091 Name: String("My name is elsewhere"),
Rob Pikeaaa3a622010-03-20 22:32:34 -070092 },
93 },
94
David Symonds183124e2012-03-23 13:20:23 +110095 // Quoted string with escaped apostrophe
96 {
97 in: `count:42 name: "HOLIDAY - New Year\'s Day"`,
98 out: &MyMessage{
99 Count: Int32(42),
100 Name: String("HOLIDAY - New Year's Day"),
101 },
102 },
103
Rob Pikeaaa3a622010-03-20 22:32:34 -0700104 // Bad quoted string
David Symonds9f402812011-04-28 18:08:44 +1000105 {
David Symonds5ed980c2011-11-29 09:52:21 +1100106 in: `inner: < host: "\0" >` + "\n",
107 err: `line 1.15: invalid quoted string "\0"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700108 },
109
110 // Number too large for int64
David Symonds9f402812011-04-28 18:08:44 +1000111 {
David Symonds5ed980c2011-11-29 09:52:21 +1100112 in: "count: 123456789012345678901",
113 err: "line 1.7: invalid int32: 123456789012345678901",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700114 },
115
116 // Number too large for int32
David Symonds9f402812011-04-28 18:08:44 +1000117 {
David Symonds5ed980c2011-11-29 09:52:21 +1100118 in: "count: 1234567890123",
119 err: "line 1.7: invalid int32: 1234567890123",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700120 },
121
122 // Number too large for float32
David Symonds9f402812011-04-28 18:08:44 +1000123 {
David Symonds5ed980c2011-11-29 09:52:21 +1100124 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
125 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700126 },
127
128 // Number posing as a quoted string
David Symonds9f402812011-04-28 18:08:44 +1000129 {
David Symonds5ed980c2011-11-29 09:52:21 +1100130 in: `inner: < host: 12 >` + "\n",
131 err: `line 1.15: invalid string: 12`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700132 },
133
134 // Quoted string posing as int32
David Symonds9f402812011-04-28 18:08:44 +1000135 {
David Symonds5ed980c2011-11-29 09:52:21 +1100136 in: `count: "12"`,
137 err: `line 1.7: invalid int32: "12"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700138 },
139
140 // Quoted string posing a float32
David Symonds9f402812011-04-28 18:08:44 +1000141 {
David Symonds5ed980c2011-11-29 09:52:21 +1100142 in: `others:< weight: "17.4" >`,
143 err: `line 1.17: invalid float32: "17.4"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700144 },
145
146 // Enum
David Symonds9f402812011-04-28 18:08:44 +1000147 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700148 in: `count:42 bikeshed: BLUE`,
149 out: &MyMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700150 Count: Int32(42),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700151 Bikeshed: NewMyMessage_Color(MyMessage_BLUE),
152 },
153 },
154
155 // Repeated field
David Symonds9f402812011-04-28 18:08:44 +1000156 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700157 in: `count:42 pet: "horsey" pet:"bunny"`,
158 out: &MyMessage{
159 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700160 Pet: []string{"horsey", "bunny"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700161 },
162 },
163
Rob Pikeaaf695a2010-06-22 15:51:21 -0700164 // Repeated message with/without colon and <>/{}
David Symonds9f402812011-04-28 18:08:44 +1000165 {
Rob Pikeaaf695a2010-06-22 15:51:21 -0700166 in: `count:42 others:{} others{} others:<> others:{}`,
167 out: &MyMessage{
168 Count: Int32(42),
169 Others: []*OtherMessage{
170 &OtherMessage{},
171 &OtherMessage{},
172 &OtherMessage{},
173 &OtherMessage{},
174 },
175 },
176 },
177
Rob Pikeaaa3a622010-03-20 22:32:34 -0700178 // Missing colon for inner message
David Symonds9f402812011-04-28 18:08:44 +1000179 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700180 in: `count:42 inner < host: "cauchy.syd" >`,
181 out: &MyMessage{
182 Count: Int32(42),
183 Inner: &InnerMessage{
184 Host: String("cauchy.syd"),
185 },
186 },
187 },
188
189 // Missing colon for string field
David Symonds9f402812011-04-28 18:08:44 +1000190 {
David Symonds5ed980c2011-11-29 09:52:21 +1100191 in: `name "Dave"`,
192 err: `line 1.5: expected ':', found "\"Dave\""`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700193 },
194
195 // Missing colon for int32 field
David Symonds9f402812011-04-28 18:08:44 +1000196 {
David Symonds5ed980c2011-11-29 09:52:21 +1100197 in: `count 42`,
198 err: `line 1.6: expected ':', found "42"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700199 },
200
201 // Missing required field
David Symonds9f402812011-04-28 18:08:44 +1000202 {
David Symonds5ed980c2011-11-29 09:52:21 +1100203 in: ``,
Rob Pikeb7907bf2012-02-13 14:25:20 +1100204 err: `line 1.0: message testdata.MyMessage missing required field "count"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700205 },
206
207 // Repeated non-repeated field
David Symonds9f402812011-04-28 18:08:44 +1000208 {
David Symonds5ed980c2011-11-29 09:52:21 +1100209 in: `name: "Rob" name: "Russ"`,
210 err: `line 1.12: non-repeated field "name" was repeated`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700211 },
212
David Symonds9f402812011-04-28 18:08:44 +1000213 // Group
214 {
215 in: `count: 17 SomeGroup { group_field: 12 }`,
216 out: &MyMessage{
217 Count: Int32(17),
218 Somegroup: &MyMessage_SomeGroup{
219 GroupField: Int32(12),
220 },
221 },
222 },
223
David Symonds54531052011-12-08 12:00:31 +1100224 // Extension
Rob Pikeb7907bf2012-02-13 14:25:20 +1100225 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
226 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
227 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
David Symonds54531052011-12-08 12:00:31 +1100228
Rob Pikeaaa3a622010-03-20 22:32:34 -0700229 // Big all-in-one
David Symonds9f402812011-04-28 18:08:44 +1000230 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700231 in: "count:42 # Meaning\n" +
232 `name:"Dave" ` +
233 `quote:"\"I didn't want to go.\"" ` +
234 `pet:"bunny" ` +
235 `pet:"kitty" ` +
236 `pet:"horsey" ` +
237 `inner:<` +
238 ` host:"footrest.syd" ` +
239 ` port:7001 ` +
240 ` connected:true ` +
241 `> ` +
242 `others:<` +
243 ` key:3735928559 ` +
244 ` value:"\x01A\a\f" ` +
245 `> ` +
246 `others:<` +
247 " weight:58.9 # Atomic weight of Co\n" +
248 ` inner:<` +
249 ` host:"lesha.mtv" ` +
250 ` port:8002 ` +
251 ` >` +
252 `>`,
253 out: &MyMessage{
254 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700255 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700256 Quote: String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -0700257 Pet: []string{"bunny", "kitty", "horsey"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700258 Inner: &InnerMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700259 Host: String("footrest.syd"),
260 Port: Int32(7001),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700261 Connected: Bool(true),
262 },
263 Others: []*OtherMessage{
264 &OtherMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700265 Key: Int64(3735928559),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700266 Value: []byte{0x1, 'A', '\a', '\f'},
267 },
268 &OtherMessage{
269 Weight: Float32(58.9),
270 Inner: &InnerMessage{
271 Host: String("lesha.mtv"),
272 Port: Int32(8002),
273 },
274 },
275 },
276 },
277 },
278}
279
280func TestUnmarshalText(t *testing.T) {
281 for i, test := range unMarshalTextTests {
282 pb := new(MyMessage)
283 err := UnmarshalText(test.in, pb)
David Symonds5ed980c2011-11-29 09:52:21 +1100284 if test.err == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700285 // We don't expect failure.
286 if err != nil {
287 t.Errorf("Test %d: Unexpected error: %v", i, err)
288 } else if !reflect.DeepEqual(pb, test.out) {
David Symondsef8f0e82011-10-13 12:57:34 +1100289 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
290 i, pb, test.out)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700291 }
292 } else {
293 // We do expect failure.
294 if err == nil {
David Symonds5ed980c2011-11-29 09:52:21 +1100295 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
296 } else if err.Error() != test.err {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700297 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
David Symonds5ed980c2011-11-29 09:52:21 +1100298 i, err.Error(), test.err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700299 }
300 }
301 }
302}
David Symonds79eae332010-10-16 11:33:20 +1100303
David Symondsef8f0e82011-10-13 12:57:34 +1100304// Regression test; this caused a panic.
305func TestRepeatedEnum(t *testing.T) {
306 pb := new(RepeatedEnum)
307 if err := UnmarshalText("color: RED", pb); err != nil {
308 t.Fatal(err)
309 }
310 exp := &RepeatedEnum{
311 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
312 }
313 if !reflect.DeepEqual(pb, exp) {
314 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
315 }
316}
317
David Symonds79eae332010-10-16 11:33:20 +1100318var benchInput string
319
320func init() {
321 benchInput = "count: 4\n"
322 for i := 0; i < 1000; i++ {
323 benchInput += "pet: \"fido\"\n"
324 }
325
326 // Check it is valid input.
327 pb := new(MyMessage)
328 err := UnmarshalText(benchInput, pb)
329 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700330 panic("Bad benchmark input: " + err.Error())
David Symonds79eae332010-10-16 11:33:20 +1100331 }
332}
333
334func BenchmarkUnmarshalText(b *testing.B) {
335 pb := new(MyMessage)
336 for i := 0; i < b.N; i++ {
337 UnmarshalText(benchInput, pb)
338 }
339 b.SetBytes(int64(len(benchInput)))
340}