blob: c178449f15e5faae8def6a3eb5e3ca16014bc39c [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
95 // Bad quoted string
David Symonds9f402812011-04-28 18:08:44 +100096 {
David Symonds5ed980c2011-11-29 09:52:21 +110097 in: `inner: < host: "\0" >` + "\n",
98 err: `line 1.15: invalid quoted string "\0"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -070099 },
100
101 // Number too large for int64
David Symonds9f402812011-04-28 18:08:44 +1000102 {
David Symonds5ed980c2011-11-29 09:52:21 +1100103 in: "count: 123456789012345678901",
104 err: "line 1.7: invalid int32: 123456789012345678901",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700105 },
106
107 // Number too large for int32
David Symonds9f402812011-04-28 18:08:44 +1000108 {
David Symonds5ed980c2011-11-29 09:52:21 +1100109 in: "count: 1234567890123",
110 err: "line 1.7: invalid int32: 1234567890123",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700111 },
112
113 // Number too large for float32
David Symonds9f402812011-04-28 18:08:44 +1000114 {
David Symonds5ed980c2011-11-29 09:52:21 +1100115 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
116 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
Rob Pikeaaa3a622010-03-20 22:32:34 -0700117 },
118
119 // Number posing as a quoted string
David Symonds9f402812011-04-28 18:08:44 +1000120 {
David Symonds5ed980c2011-11-29 09:52:21 +1100121 in: `inner: < host: 12 >` + "\n",
122 err: `line 1.15: invalid string: 12`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700123 },
124
125 // Quoted string posing as int32
David Symonds9f402812011-04-28 18:08:44 +1000126 {
David Symonds5ed980c2011-11-29 09:52:21 +1100127 in: `count: "12"`,
128 err: `line 1.7: invalid int32: "12"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700129 },
130
131 // Quoted string posing a float32
David Symonds9f402812011-04-28 18:08:44 +1000132 {
David Symonds5ed980c2011-11-29 09:52:21 +1100133 in: `others:< weight: "17.4" >`,
134 err: `line 1.17: invalid float32: "17.4"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700135 },
136
137 // Enum
David Symonds9f402812011-04-28 18:08:44 +1000138 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700139 in: `count:42 bikeshed: BLUE`,
140 out: &MyMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700141 Count: Int32(42),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700142 Bikeshed: NewMyMessage_Color(MyMessage_BLUE),
143 },
144 },
145
146 // Repeated field
David Symonds9f402812011-04-28 18:08:44 +1000147 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700148 in: `count:42 pet: "horsey" pet:"bunny"`,
149 out: &MyMessage{
150 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700151 Pet: []string{"horsey", "bunny"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700152 },
153 },
154
Rob Pikeaaf695a2010-06-22 15:51:21 -0700155 // Repeated message with/without colon and <>/{}
David Symonds9f402812011-04-28 18:08:44 +1000156 {
Rob Pikeaaf695a2010-06-22 15:51:21 -0700157 in: `count:42 others:{} others{} others:<> others:{}`,
158 out: &MyMessage{
159 Count: Int32(42),
160 Others: []*OtherMessage{
161 &OtherMessage{},
162 &OtherMessage{},
163 &OtherMessage{},
164 &OtherMessage{},
165 },
166 },
167 },
168
Rob Pikeaaa3a622010-03-20 22:32:34 -0700169 // Missing colon for inner message
David Symonds9f402812011-04-28 18:08:44 +1000170 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700171 in: `count:42 inner < host: "cauchy.syd" >`,
172 out: &MyMessage{
173 Count: Int32(42),
174 Inner: &InnerMessage{
175 Host: String("cauchy.syd"),
176 },
177 },
178 },
179
180 // Missing colon for string field
David Symonds9f402812011-04-28 18:08:44 +1000181 {
David Symonds5ed980c2011-11-29 09:52:21 +1100182 in: `name "Dave"`,
183 err: `line 1.5: expected ':', found "\"Dave\""`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700184 },
185
186 // Missing colon for int32 field
David Symonds9f402812011-04-28 18:08:44 +1000187 {
David Symonds5ed980c2011-11-29 09:52:21 +1100188 in: `count 42`,
189 err: `line 1.6: expected ':', found "42"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700190 },
191
192 // Missing required field
David Symonds9f402812011-04-28 18:08:44 +1000193 {
David Symonds5ed980c2011-11-29 09:52:21 +1100194 in: ``,
Rob Pikeb7907bf2012-02-13 14:25:20 +1100195 err: `line 1.0: message testdata.MyMessage missing required field "count"`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700196 },
197
198 // Repeated non-repeated field
David Symonds9f402812011-04-28 18:08:44 +1000199 {
David Symonds5ed980c2011-11-29 09:52:21 +1100200 in: `name: "Rob" name: "Russ"`,
201 err: `line 1.12: non-repeated field "name" was repeated`,
Rob Pikeaaa3a622010-03-20 22:32:34 -0700202 },
203
David Symonds9f402812011-04-28 18:08:44 +1000204 // Group
205 {
206 in: `count: 17 SomeGroup { group_field: 12 }`,
207 out: &MyMessage{
208 Count: Int32(17),
209 Somegroup: &MyMessage_SomeGroup{
210 GroupField: Int32(12),
211 },
212 },
213 },
214
David Symonds54531052011-12-08 12:00:31 +1100215 // Extension
Rob Pikeb7907bf2012-02-13 14:25:20 +1100216 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
217 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
218 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
David Symonds54531052011-12-08 12:00:31 +1100219
Rob Pikeaaa3a622010-03-20 22:32:34 -0700220 // Big all-in-one
David Symonds9f402812011-04-28 18:08:44 +1000221 {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700222 in: "count:42 # Meaning\n" +
223 `name:"Dave" ` +
224 `quote:"\"I didn't want to go.\"" ` +
225 `pet:"bunny" ` +
226 `pet:"kitty" ` +
227 `pet:"horsey" ` +
228 `inner:<` +
229 ` host:"footrest.syd" ` +
230 ` port:7001 ` +
231 ` connected:true ` +
232 `> ` +
233 `others:<` +
234 ` key:3735928559 ` +
235 ` value:"\x01A\a\f" ` +
236 `> ` +
237 `others:<` +
238 " weight:58.9 # Atomic weight of Co\n" +
239 ` inner:<` +
240 ` host:"lesha.mtv" ` +
241 ` port:8002 ` +
242 ` >` +
243 `>`,
244 out: &MyMessage{
245 Count: Int32(42),
Rob Pike9caa5b92010-05-11 16:04:57 -0700246 Name: String("Dave"),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700247 Quote: String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -0700248 Pet: []string{"bunny", "kitty", "horsey"},
Rob Pikeaaa3a622010-03-20 22:32:34 -0700249 Inner: &InnerMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700250 Host: String("footrest.syd"),
251 Port: Int32(7001),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700252 Connected: Bool(true),
253 },
254 Others: []*OtherMessage{
255 &OtherMessage{
Rob Pike9caa5b92010-05-11 16:04:57 -0700256 Key: Int64(3735928559),
Rob Pikeaaa3a622010-03-20 22:32:34 -0700257 Value: []byte{0x1, 'A', '\a', '\f'},
258 },
259 &OtherMessage{
260 Weight: Float32(58.9),
261 Inner: &InnerMessage{
262 Host: String("lesha.mtv"),
263 Port: Int32(8002),
264 },
265 },
266 },
267 },
268 },
269}
270
271func TestUnmarshalText(t *testing.T) {
272 for i, test := range unMarshalTextTests {
273 pb := new(MyMessage)
274 err := UnmarshalText(test.in, pb)
David Symonds5ed980c2011-11-29 09:52:21 +1100275 if test.err == "" {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700276 // We don't expect failure.
277 if err != nil {
278 t.Errorf("Test %d: Unexpected error: %v", i, err)
279 } else if !reflect.DeepEqual(pb, test.out) {
David Symondsef8f0e82011-10-13 12:57:34 +1100280 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
281 i, pb, test.out)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700282 }
283 } else {
284 // We do expect failure.
285 if err == nil {
David Symonds5ed980c2011-11-29 09:52:21 +1100286 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
287 } else if err.Error() != test.err {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700288 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
David Symonds5ed980c2011-11-29 09:52:21 +1100289 i, err.Error(), test.err)
Rob Pikeaaa3a622010-03-20 22:32:34 -0700290 }
291 }
292 }
293}
David Symonds79eae332010-10-16 11:33:20 +1100294
David Symondsef8f0e82011-10-13 12:57:34 +1100295// Regression test; this caused a panic.
296func TestRepeatedEnum(t *testing.T) {
297 pb := new(RepeatedEnum)
298 if err := UnmarshalText("color: RED", pb); err != nil {
299 t.Fatal(err)
300 }
301 exp := &RepeatedEnum{
302 Color: []RepeatedEnum_Color{RepeatedEnum_RED},
303 }
304 if !reflect.DeepEqual(pb, exp) {
305 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
306 }
307}
308
David Symonds79eae332010-10-16 11:33:20 +1100309var benchInput string
310
311func init() {
312 benchInput = "count: 4\n"
313 for i := 0; i < 1000; i++ {
314 benchInput += "pet: \"fido\"\n"
315 }
316
317 // Check it is valid input.
318 pb := new(MyMessage)
319 err := UnmarshalText(benchInput, pb)
320 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700321 panic("Bad benchmark input: " + err.Error())
David Symonds79eae332010-10-16 11:33:20 +1100322 }
323}
324
325func BenchmarkUnmarshalText(b *testing.B) {
326 pb := new(MyMessage)
327 for i := 0; i < b.N; i++ {
328 UnmarshalText(benchInput, pb)
329 }
330 b.SetBytes(int64(len(benchInput)))
331}