github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/goprotobuf/proto/text_parser_test.go (about) 1 // Go support for Protocol Buffers - Google's data interchange format 2 // 3 // Copyright 2010 The Go Authors. 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 32 package proto_test 33 34 import ( 35 "math" 36 "reflect" 37 "testing" 38 39 . "./testdata" 40 . "github.com/coreos/etcd/third_party/code.google.com/p/goprotobuf/proto" 41 ) 42 43 type UnmarshalTextTest struct { 44 in string 45 err string // if "", no error expected 46 out *MyMessage 47 } 48 49 func buildExtStructTest(text string) UnmarshalTextTest { 50 msg := &MyMessage{ 51 Count: Int32(42), 52 } 53 SetExtension(msg, E_Ext_More, &Ext{ 54 Data: String("Hello, world!"), 55 }) 56 return UnmarshalTextTest{in: text, out: msg} 57 } 58 59 func buildExtDataTest(text string) UnmarshalTextTest { 60 msg := &MyMessage{ 61 Count: Int32(42), 62 } 63 SetExtension(msg, E_Ext_Text, String("Hello, world!")) 64 SetExtension(msg, E_Ext_Number, Int32(1729)) 65 return UnmarshalTextTest{in: text, out: msg} 66 } 67 68 func buildExtRepStringTest(text string) UnmarshalTextTest { 69 msg := &MyMessage{ 70 Count: Int32(42), 71 } 72 if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil { 73 panic(err) 74 } 75 return UnmarshalTextTest{in: text, out: msg} 76 } 77 78 var unMarshalTextTests = []UnmarshalTextTest{ 79 // Basic 80 { 81 in: " count:42\n name:\"Dave\" ", 82 out: &MyMessage{ 83 Count: Int32(42), 84 Name: String("Dave"), 85 }, 86 }, 87 88 // Empty quoted string 89 { 90 in: `count:42 name:""`, 91 out: &MyMessage{ 92 Count: Int32(42), 93 Name: String(""), 94 }, 95 }, 96 97 // Quoted string concatenation 98 { 99 in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`, 100 out: &MyMessage{ 101 Count: Int32(42), 102 Name: String("My name is elsewhere"), 103 }, 104 }, 105 106 // Quoted string with escaped apostrophe 107 { 108 in: `count:42 name: "HOLIDAY - New Year\'s Day"`, 109 out: &MyMessage{ 110 Count: Int32(42), 111 Name: String("HOLIDAY - New Year's Day"), 112 }, 113 }, 114 115 // Quoted string with single quote 116 { 117 in: `count:42 name: 'Roger "The Ramster" Ramjet'`, 118 out: &MyMessage{ 119 Count: Int32(42), 120 Name: String(`Roger "The Ramster" Ramjet`), 121 }, 122 }, 123 124 // Quoted string with all the accepted special characters from the C++ test 125 { 126 in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"", 127 out: &MyMessage{ 128 Count: Int32(42), 129 Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"), 130 }, 131 }, 132 133 // Quoted string with quoted backslash 134 { 135 in: `count:42 name: "\\'xyz"`, 136 out: &MyMessage{ 137 Count: Int32(42), 138 Name: String(`\'xyz`), 139 }, 140 }, 141 142 // Quoted string with UTF-8 bytes. 143 { 144 in: "count:42 name: '\303\277\302\201\xAB'", 145 out: &MyMessage{ 146 Count: Int32(42), 147 Name: String("\303\277\302\201\xAB"), 148 }, 149 }, 150 151 // Bad quoted string 152 { 153 in: `inner: < host: "\0" >` + "\n", 154 err: `line 1.15: invalid quoted string "\0"`, 155 }, 156 157 // Number too large for int64 158 { 159 in: "count: 123456789012345678901", 160 err: "line 1.7: invalid int32: 123456789012345678901", 161 }, 162 163 // Number too large for int32 164 { 165 in: "count: 1234567890123", 166 err: "line 1.7: invalid int32: 1234567890123", 167 }, 168 169 // Number in hexadecimal 170 { 171 in: "count: 0x2beef", 172 out: &MyMessage{ 173 Count: Int32(0x2beef), 174 }, 175 }, 176 177 // Number in octal 178 { 179 in: "count: 024601", 180 out: &MyMessage{ 181 Count: Int32(024601), 182 }, 183 }, 184 185 // Floating point number with "f" suffix 186 { 187 in: "count: 4 others:< weight: 17.0f >", 188 out: &MyMessage{ 189 Count: Int32(4), 190 Others: []*OtherMessage{ 191 { 192 Weight: Float32(17), 193 }, 194 }, 195 }, 196 }, 197 198 // Floating point positive infinity 199 { 200 in: "count: 4 bigfloat: inf", 201 out: &MyMessage{ 202 Count: Int32(4), 203 Bigfloat: Float64(math.Inf(1)), 204 }, 205 }, 206 207 // Floating point negative infinity 208 { 209 in: "count: 4 bigfloat: -inf", 210 out: &MyMessage{ 211 Count: Int32(4), 212 Bigfloat: Float64(math.Inf(-1)), 213 }, 214 }, 215 216 // Number too large for float32 217 { 218 in: "others:< weight: 12345678901234567890123456789012345678901234567890 >", 219 err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890", 220 }, 221 222 // Number posing as a quoted string 223 { 224 in: `inner: < host: 12 >` + "\n", 225 err: `line 1.15: invalid string: 12`, 226 }, 227 228 // Quoted string posing as int32 229 { 230 in: `count: "12"`, 231 err: `line 1.7: invalid int32: "12"`, 232 }, 233 234 // Quoted string posing a float32 235 { 236 in: `others:< weight: "17.4" >`, 237 err: `line 1.17: invalid float32: "17.4"`, 238 }, 239 240 // Enum 241 { 242 in: `count:42 bikeshed: BLUE`, 243 out: &MyMessage{ 244 Count: Int32(42), 245 Bikeshed: MyMessage_BLUE.Enum(), 246 }, 247 }, 248 249 // Repeated field 250 { 251 in: `count:42 pet: "horsey" pet:"bunny"`, 252 out: &MyMessage{ 253 Count: Int32(42), 254 Pet: []string{"horsey", "bunny"}, 255 }, 256 }, 257 258 // Repeated message with/without colon and <>/{} 259 { 260 in: `count:42 others:{} others{} others:<> others:{}`, 261 out: &MyMessage{ 262 Count: Int32(42), 263 Others: []*OtherMessage{ 264 {}, 265 {}, 266 {}, 267 {}, 268 }, 269 }, 270 }, 271 272 // Missing colon for inner message 273 { 274 in: `count:42 inner < host: "cauchy.syd" >`, 275 out: &MyMessage{ 276 Count: Int32(42), 277 Inner: &InnerMessage{ 278 Host: String("cauchy.syd"), 279 }, 280 }, 281 }, 282 283 // Missing colon for string field 284 { 285 in: `name "Dave"`, 286 err: `line 1.5: expected ':', found "\"Dave\""`, 287 }, 288 289 // Missing colon for int32 field 290 { 291 in: `count 42`, 292 err: `line 1.6: expected ':', found "42"`, 293 }, 294 295 // Missing required field 296 { 297 in: ``, 298 err: `line 1.0: message testdata.MyMessage missing required field "count"`, 299 }, 300 301 // Repeated non-repeated field 302 { 303 in: `name: "Rob" name: "Russ"`, 304 err: `line 1.12: non-repeated field "name" was repeated`, 305 }, 306 307 // Group 308 { 309 in: `count: 17 SomeGroup { group_field: 12 }`, 310 out: &MyMessage{ 311 Count: Int32(17), 312 Somegroup: &MyMessage_SomeGroup{ 313 GroupField: Int32(12), 314 }, 315 }, 316 }, 317 318 // Semicolon between fields 319 { 320 in: `count:3;name:"Calvin"`, 321 out: &MyMessage{ 322 Count: Int32(3), 323 Name: String("Calvin"), 324 }, 325 }, 326 // Comma between fields 327 { 328 in: `count:4,name:"Ezekiel"`, 329 out: &MyMessage{ 330 Count: Int32(4), 331 Name: String("Ezekiel"), 332 }, 333 }, 334 335 // Extension 336 buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`), 337 buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`), 338 buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`), 339 buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`), 340 341 // Big all-in-one 342 { 343 in: "count:42 # Meaning\n" + 344 `name:"Dave" ` + 345 `quote:"\"I didn't want to go.\"" ` + 346 `pet:"bunny" ` + 347 `pet:"kitty" ` + 348 `pet:"horsey" ` + 349 `inner:<` + 350 ` host:"footrest.syd" ` + 351 ` port:7001 ` + 352 ` connected:true ` + 353 `> ` + 354 `others:<` + 355 ` key:3735928559 ` + 356 ` value:"\x01A\a\f" ` + 357 `> ` + 358 `others:<` + 359 " weight:58.9 # Atomic weight of Co\n" + 360 ` inner:<` + 361 ` host:"lesha.mtv" ` + 362 ` port:8002 ` + 363 ` >` + 364 `>`, 365 out: &MyMessage{ 366 Count: Int32(42), 367 Name: String("Dave"), 368 Quote: String(`"I didn't want to go."`), 369 Pet: []string{"bunny", "kitty", "horsey"}, 370 Inner: &InnerMessage{ 371 Host: String("footrest.syd"), 372 Port: Int32(7001), 373 Connected: Bool(true), 374 }, 375 Others: []*OtherMessage{ 376 { 377 Key: Int64(3735928559), 378 Value: []byte{0x1, 'A', '\a', '\f'}, 379 }, 380 { 381 Weight: Float32(58.9), 382 Inner: &InnerMessage{ 383 Host: String("lesha.mtv"), 384 Port: Int32(8002), 385 }, 386 }, 387 }, 388 }, 389 }, 390 } 391 392 func TestUnmarshalText(t *testing.T) { 393 for i, test := range unMarshalTextTests { 394 pb := new(MyMessage) 395 err := UnmarshalText(test.in, pb) 396 if test.err == "" { 397 // We don't expect failure. 398 if err != nil { 399 t.Errorf("Test %d: Unexpected error: %v", i, err) 400 } else if !reflect.DeepEqual(pb, test.out) { 401 t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", 402 i, pb, test.out) 403 } 404 } else { 405 // We do expect failure. 406 if err == nil { 407 t.Errorf("Test %d: Didn't get expected error: %v", i, test.err) 408 } else if err.Error() != test.err { 409 t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", 410 i, err.Error(), test.err) 411 } 412 } 413 } 414 } 415 416 // Regression test; this caused a panic. 417 func TestRepeatedEnum(t *testing.T) { 418 pb := new(RepeatedEnum) 419 if err := UnmarshalText("color: RED", pb); err != nil { 420 t.Fatal(err) 421 } 422 exp := &RepeatedEnum{ 423 Color: []RepeatedEnum_Color{RepeatedEnum_RED}, 424 } 425 if !Equal(pb, exp) { 426 t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp) 427 } 428 } 429 430 var benchInput string 431 432 func init() { 433 benchInput = "count: 4\n" 434 for i := 0; i < 1000; i++ { 435 benchInput += "pet: \"fido\"\n" 436 } 437 438 // Check it is valid input. 439 pb := new(MyMessage) 440 err := UnmarshalText(benchInput, pb) 441 if err != nil { 442 panic("Bad benchmark input: " + err.Error()) 443 } 444 } 445 446 func BenchmarkUnmarshalText(b *testing.B) { 447 pb := new(MyMessage) 448 for i := 0; i < b.N; i++ { 449 UnmarshalText(benchInput, pb) 450 } 451 b.SetBytes(int64(len(benchInput))) 452 }