1/* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package main 18 19import ( 20 example "MyGame/Example" // refers to generated code 21 "bytes" 22 "flag" 23 "fmt" 24 "io/ioutil" 25 "os" 26 "reflect" 27 "sort" 28 "testing" 29 30 flatbuffers "github.com/google/flatbuffers/go" 31) 32 33var ( 34 cppData, javaData, outData string 35 fuzz bool 36 fuzzFields, fuzzObjects int 37) 38 39func init() { 40 flag.StringVar(&cppData, "cpp_data", "", 41 "location of monsterdata_test.mon to verify against (required)") 42 flag.StringVar(&javaData, "java_data", "", 43 "location of monsterdata_java_wire.mon to verify against (optional)") 44 flag.StringVar(&outData, "out_data", "", 45 "location to write generated Go data") 46 flag.BoolVar(&fuzz, "fuzz", false, "perform fuzzing") 47 flag.IntVar(&fuzzFields, "fuzz_fields", 4, "fields per fuzzer object") 48 flag.IntVar(&fuzzObjects, "fuzz_objects", 10000, 49 "number of fuzzer objects (higher is slower and more thorough") 50 flag.Parse() 51 52 if cppData == "" { 53 fmt.Fprintf(os.Stderr, "cpp_data argument is required\n") 54 os.Exit(1) 55 } 56} 57 58// Store specific byte patterns in these variables for the fuzzer. These 59// values are taken verbatim from the C++ function FuzzTest1. 60var ( 61 overflowingInt32Val = flatbuffers.GetInt32([]byte{0x83, 0x33, 0x33, 0x33}) 62 overflowingInt64Val = flatbuffers.GetInt64([]byte{0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44}) 63) 64 65// TestAll runs all checks, failing if any errors occur. 66func TestAll(t *testing.T) { 67 // Verify that the Go FlatBuffers runtime library generates the 68 // expected bytes (does not use any schema): 69 CheckByteLayout(t.Fatalf) 70 CheckMutateMethods(t.Fatalf) 71 72 // Verify that panics are raised during exceptional conditions: 73 CheckNotInObjectError(t.Fatalf) 74 CheckStringIsNestedError(t.Fatalf) 75 CheckByteStringIsNestedError(t.Fatalf) 76 CheckStructIsNotInlineError(t.Fatalf) 77 CheckFinishedBytesError(t.Fatalf) 78 79 // Verify that GetRootAs works for non-root tables 80 CheckGetRootAsForNonRootTable(t.Fatalf) 81 CheckTableAccessors(t.Fatalf) 82 83 // Verify that using the generated Go code builds a buffer without 84 // returning errors: 85 generated, off := CheckGeneratedBuild(t.Fatalf) 86 87 // Verify that the buffer generated by Go code is readable by the 88 // generated Go code: 89 CheckReadBuffer(generated, off, t.Fatalf) 90 CheckMutateBuffer(generated, off, t.Fatalf) 91 92 // Verify that the buffer generated by C++ code is readable by the 93 // generated Go code: 94 monsterDataCpp, err := ioutil.ReadFile(cppData) 95 if err != nil { 96 t.Fatal(err) 97 } 98 CheckReadBuffer(monsterDataCpp, 0, t.Fatalf) 99 CheckMutateBuffer(monsterDataCpp, 0, t.Fatalf) 100 101 // Verify that vtables are deduplicated when written: 102 CheckVtableDeduplication(t.Fatalf) 103 104 // Verify the enum names 105 CheckEnumNames(t.Fatalf) 106 107 // Verify that the Go code used in FlatBuffers documentation passes 108 // some sanity checks: 109 CheckDocExample(generated, off, t.Fatalf) 110 111 // Check Builder.CreateByteVector 112 CheckCreateByteVector(t.Fatalf) 113 114 // If the filename of the FlatBuffers file generated by the Java test 115 // is given, check that Go code can read it, and that Go code 116 // generates an identical buffer when used to create the example data: 117 if javaData != "" { 118 monsterDataJava, err := ioutil.ReadFile(javaData) 119 if err != nil { 120 t.Fatal(err) 121 } 122 CheckReadBuffer(monsterDataJava, 0, t.Fatalf) 123 CheckByteEquality(generated[off:], monsterDataJava, t.Fatalf) 124 } 125 126 // Verify that various fuzzing scenarios produce a valid FlatBuffer. 127 if fuzz { 128 checkFuzz(fuzzFields, fuzzObjects, t.Fatalf) 129 } 130 131 // Write the generated buffer out to a file: 132 err = ioutil.WriteFile(outData, generated[off:], os.FileMode(0644)) 133 if err != nil { 134 t.Fatal(err) 135 } 136} 137 138// CheckReadBuffer checks that the given buffer is evaluated correctly 139// as the example Monster. 140func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) { 141 // try the two ways of generating a monster 142 monster1 := example.GetRootAsMonster(buf, offset) 143 monster2 := &example.Monster{} 144 flatbuffers.GetRootAs(buf, offset, monster2) 145 for _, monster := range []*example.Monster{monster1, monster2} { 146 if got := monster.Hp(); 80 != got { 147 fail(FailString("hp", 80, got)) 148 } 149 150 // default 151 if got := monster.Mana(); 150 != got { 152 fail(FailString("mana", 150, got)) 153 } 154 155 if got := monster.Name(); !bytes.Equal([]byte("MyMonster"), got) { 156 fail(FailString("name", "MyMonster", got)) 157 } 158 159 // initialize a Vec3 from Pos() 160 vec := new(example.Vec3) 161 vec = monster.Pos(vec) 162 if vec == nil { 163 fail("vec3 initialization failed") 164 } 165 166 // check that new allocs equal given ones: 167 vec2 := monster.Pos(nil) 168 if !reflect.DeepEqual(vec, vec2) { 169 fail("fresh allocation failed") 170 } 171 172 // verify the properties of the Vec3 173 if got := vec.X(); float32(1.0) != got { 174 fail(FailString("Pos.X", float32(1.0), got)) 175 } 176 177 if got := vec.Y(); float32(2.0) != got { 178 fail(FailString("Pos.Y", float32(2.0), got)) 179 } 180 181 if got := vec.Z(); float32(3.0) != got { 182 fail(FailString("Pos.Z", float32(3.0), got)) 183 } 184 185 if got := vec.Test1(); float64(3.0) != got { 186 fail(FailString("Pos.Test1", float64(3.0), got)) 187 } 188 189 if got := vec.Test2(); int8(2) != got { 190 fail(FailString("Pos.Test2", int8(2), got)) 191 } 192 193 // initialize a Test from Test3(...) 194 t := new(example.Test) 195 t = vec.Test3(t) 196 if t == nil { 197 fail("vec.Test3(&t) failed") 198 } 199 200 // check that new allocs equal given ones: 201 t2 := vec.Test3(nil) 202 if !reflect.DeepEqual(t, t2) { 203 fail("fresh allocation failed") 204 } 205 206 // verify the properties of the Test 207 if got := t.A(); int16(5) != got { 208 fail(FailString("t.A()", int16(5), got)) 209 } 210 211 if got := t.B(); int8(6) != got { 212 fail(FailString("t.B()", int8(6), got)) 213 } 214 215 if got := monster.TestType(); example.AnyMonster != got { 216 fail(FailString("monster.TestType()", example.AnyMonster, got)) 217 } 218 219 // initialize a Table from a union field Test(...) 220 var table2 flatbuffers.Table 221 if ok := monster.Test(&table2); !ok { 222 fail("monster.Test(&monster2) failed") 223 } 224 225 // initialize a Monster from the Table from the union 226 var monster2 example.Monster 227 monster2.Init(table2.Bytes, table2.Pos) 228 229 if got := monster2.Name(); !bytes.Equal([]byte("Fred"), got) { 230 fail(FailString("monster2.Name()", "Fred", got)) 231 } 232 233 inventorySlice := monster.InventoryBytes() 234 if len(inventorySlice) != monster.InventoryLength() { 235 fail(FailString("len(monster.InventoryBytes) != monster.InventoryLength", len(inventorySlice), monster.InventoryLength())) 236 } 237 238 if got := monster.InventoryLength(); 5 != got { 239 fail(FailString("monster.InventoryLength", 5, got)) 240 } 241 242 invsum := 0 243 l := monster.InventoryLength() 244 for i := 0; i < l; i++ { 245 v := monster.Inventory(i) 246 if v != inventorySlice[i] { 247 fail(FailString("monster inventory slice[i] != Inventory(i)", v, inventorySlice[i])) 248 } 249 invsum += int(v) 250 } 251 if invsum != 10 { 252 fail(FailString("monster inventory sum", 10, invsum)) 253 } 254 255 if got := monster.Test4Length(); 2 != got { 256 fail(FailString("monster.Test4Length()", 2, got)) 257 } 258 259 var test0 example.Test 260 ok := monster.Test4(&test0, 0) 261 if !ok { 262 fail(FailString("monster.Test4(&test0, 0)", true, ok)) 263 } 264 265 var test1 example.Test 266 ok = monster.Test4(&test1, 1) 267 if !ok { 268 fail(FailString("monster.Test4(&test1, 1)", true, ok)) 269 } 270 271 // the position of test0 and test1 are swapped in monsterdata_java_wire 272 // and monsterdata_test_wire, so ignore ordering 273 v0 := test0.A() 274 v1 := test0.B() 275 v2 := test1.A() 276 v3 := test1.B() 277 sum := int(v0) + int(v1) + int(v2) + int(v3) 278 279 if 100 != sum { 280 fail(FailString("test0 and test1 sum", 100, sum)) 281 } 282 283 if got := monster.TestarrayofstringLength(); 2 != got { 284 fail(FailString("Testarrayofstring length", 2, got)) 285 } 286 287 if got := monster.Testarrayofstring(0); !bytes.Equal([]byte("test1"), got) { 288 fail(FailString("Testarrayofstring(0)", "test1", got)) 289 } 290 291 if got := monster.Testarrayofstring(1); !bytes.Equal([]byte("test2"), got) { 292 fail(FailString("Testarrayofstring(1)", "test2", got)) 293 } 294 } 295} 296 297// CheckMutateBuffer checks that the given buffer can be mutated correctly 298// as the example Monster. Only available scalar values are mutated. 299func CheckMutateBuffer(org []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) { 300 // make a copy to mutate 301 buf := make([]byte, len(org)) 302 copy(buf, org) 303 304 // load monster data from the buffer 305 monster := example.GetRootAsMonster(buf, offset) 306 307 // test case struct 308 type testcase struct { 309 field string 310 testfn func() bool 311 } 312 313 testForOriginalValues := []testcase{ 314 testcase{"Hp", func() bool { return monster.Hp() == 80 }}, 315 testcase{"Mana", func() bool { return monster.Mana() == 150 }}, 316 testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(1.0) }}, 317 testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(2.0) }}, 318 testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(3.0) }}, 319 testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(3.0) }}, 320 testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == int8(2) }}, 321 testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(5) }}, 322 testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(6) }}, 323 } 324 325 testMutability := []testcase{ 326 testcase{"Hp", func() bool { return monster.MutateHp(70) }}, 327 testcase{"Mana", func() bool { return !monster.MutateMana(140) }}, 328 testcase{"Pos.X", func() bool { return monster.Pos(nil).MutateX(10.0) }}, 329 testcase{"Pos.Y", func() bool { return monster.Pos(nil).MutateY(20.0) }}, 330 testcase{"Pos.Z", func() bool { return monster.Pos(nil).MutateZ(30.0) }}, 331 testcase{"Pos.Test1", func() bool { return monster.Pos(nil).MutateTest1(30.0) }}, 332 testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(20) }}, 333 testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).MutateA(50) }}, 334 testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).MutateB(60) }}, 335 } 336 337 testForMutatedValues := []testcase{ 338 testcase{"Hp", func() bool { return monster.Hp() == 70 }}, 339 testcase{"Mana", func() bool { return monster.Mana() == 150 }}, 340 testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(10.0) }}, 341 testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(20.0) }}, 342 testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(30.0) }}, 343 testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(30.0) }}, 344 testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == int8(20) }}, 345 testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(50) }}, 346 testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(60) }}, 347 } 348 349 // make sure original values are okay 350 for _, t := range testForOriginalValues { 351 if !t.testfn() { 352 fail("field '" + t.field + "' doesn't have the expected original value") 353 } 354 } 355 356 // try to mutate fields and check mutability 357 for _, t := range testMutability { 358 if !t.testfn() { 359 fail(FailString("field '"+t.field+"' failed mutability test", true, false)) 360 } 361 } 362 363 // test whether values have changed 364 for _, t := range testForMutatedValues { 365 if !t.testfn() { 366 fail("field '" + t.field + "' doesn't have the expected mutated value") 367 } 368 } 369 370 // make sure the buffer has changed 371 if reflect.DeepEqual(buf, org) { 372 fail("mutate buffer failed") 373 } 374 375 // To make sure the buffer has changed accordingly 376 // Read data from the buffer and verify all fields 377 monster = example.GetRootAsMonster(buf, offset) 378 for _, t := range testForMutatedValues { 379 if !t.testfn() { 380 fail("field '" + t.field + "' doesn't have the expected mutated value") 381 } 382 } 383 384 // reverting all fields to original values should 385 // re-create the original buffer. Mutate all fields 386 // back to their original values and compare buffers. 387 // This test is done to make sure mutations do not do 388 // any unnecessary changes to the buffer. 389 monster = example.GetRootAsMonster(buf, offset) 390 monster.MutateHp(80) 391 monster.Pos(nil).MutateX(1.0) 392 monster.Pos(nil).MutateY(2.0) 393 monster.Pos(nil).MutateZ(3.0) 394 monster.Pos(nil).MutateTest1(3.0) 395 monster.Pos(nil).MutateTest2(2) 396 monster.Pos(nil).Test3(nil).MutateA(5) 397 monster.Pos(nil).Test3(nil).MutateB(6) 398 399 for _, t := range testForOriginalValues { 400 if !t.testfn() { 401 fail("field '" + t.field + "' doesn't have the expected original value") 402 } 403 } 404 405 // buffer should have original values 406 if !reflect.DeepEqual(buf, org) { 407 fail("revert changes failed") 408 } 409} 410 411// Low level stress/fuzz test: serialize/deserialize a variety of 412// different kinds of data in different combinations 413func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) { 414 415 // Values we're testing against: chosen to ensure no bits get chopped 416 // off anywhere, and also be different from eachother. 417 boolVal := true 418 int8Val := int8(-127) // 0x81 419 uint8Val := uint8(0xFF) 420 int16Val := int16(-32222) // 0x8222 421 uint16Val := uint16(0xFEEE) 422 int32Val := int32(overflowingInt32Val) 423 uint32Val := uint32(0xFDDDDDDD) 424 int64Val := int64(overflowingInt64Val) 425 uint64Val := uint64(0xFCCCCCCCCCCCCCCC) 426 float32Val := float32(3.14159) 427 float64Val := float64(3.14159265359) 428 429 testValuesMax := 11 // hardcoded to the number of scalar types 430 431 builder := flatbuffers.NewBuilder(0) 432 l := NewLCG() 433 434 objects := make([]flatbuffers.UOffsetT, fuzzObjects) 435 436 // Generate fuzzObjects random objects each consisting of 437 // fuzzFields fields, each of a random type. 438 for i := 0; i < fuzzObjects; i++ { 439 builder.StartObject(fuzzFields) 440 441 for f := 0; f < fuzzFields; f++ { 442 choice := l.Next() % uint32(testValuesMax) 443 switch choice { 444 case 0: 445 builder.PrependBoolSlot(int(f), boolVal, false) 446 case 1: 447 builder.PrependInt8Slot(int(f), int8Val, 0) 448 case 2: 449 builder.PrependUint8Slot(int(f), uint8Val, 0) 450 case 3: 451 builder.PrependInt16Slot(int(f), int16Val, 0) 452 case 4: 453 builder.PrependUint16Slot(int(f), uint16Val, 0) 454 case 5: 455 builder.PrependInt32Slot(int(f), int32Val, 0) 456 case 6: 457 builder.PrependUint32Slot(int(f), uint32Val, 0) 458 case 7: 459 builder.PrependInt64Slot(int(f), int64Val, 0) 460 case 8: 461 builder.PrependUint64Slot(int(f), uint64Val, 0) 462 case 9: 463 builder.PrependFloat32Slot(int(f), float32Val, 0) 464 case 10: 465 builder.PrependFloat64Slot(int(f), float64Val, 0) 466 } 467 } 468 469 off := builder.EndObject() 470 471 // store the offset from the end of the builder buffer, 472 // since it will keep growing: 473 objects[i] = off 474 } 475 476 // Do some bookkeeping to generate stats on fuzzes: 477 stats := map[string]int{} 478 check := func(desc string, want, got interface{}) { 479 stats[desc]++ 480 if want != got { 481 fail("%s want %v got %v", desc, want, got) 482 } 483 } 484 485 l = NewLCG() // Reset. 486 487 // Test that all objects we generated are readable and return the 488 // expected values. We generate random objects in the same order 489 // so this is deterministic. 490 for i := 0; i < fuzzObjects; i++ { 491 492 table := &flatbuffers.Table{ 493 Bytes: builder.Bytes, 494 Pos: flatbuffers.UOffsetT(len(builder.Bytes)) - objects[i], 495 } 496 497 for j := 0; j < fuzzFields; j++ { 498 f := flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + j) * flatbuffers.SizeVOffsetT) 499 choice := l.Next() % uint32(testValuesMax) 500 501 switch choice { 502 case 0: 503 check("bool", boolVal, table.GetBoolSlot(f, false)) 504 case 1: 505 check("int8", int8Val, table.GetInt8Slot(f, 0)) 506 case 2: 507 check("uint8", uint8Val, table.GetUint8Slot(f, 0)) 508 case 3: 509 check("int16", int16Val, table.GetInt16Slot(f, 0)) 510 case 4: 511 check("uint16", uint16Val, table.GetUint16Slot(f, 0)) 512 case 5: 513 check("int32", int32Val, table.GetInt32Slot(f, 0)) 514 case 6: 515 check("uint32", uint32Val, table.GetUint32Slot(f, 0)) 516 case 7: 517 check("int64", int64Val, table.GetInt64Slot(f, 0)) 518 case 8: 519 check("uint64", uint64Val, table.GetUint64Slot(f, 0)) 520 case 9: 521 check("float32", float32Val, table.GetFloat32Slot(f, 0)) 522 case 10: 523 check("float64", float64Val, table.GetFloat64Slot(f, 0)) 524 } 525 } 526 } 527 528 // If enough checks were made, verify that all scalar types were used: 529 if fuzzFields*fuzzObjects >= testValuesMax { 530 if len(stats) != testValuesMax { 531 fail("fuzzing failed to test all scalar types") 532 } 533 } 534 535 // Print some counts, if needed: 536 if testing.Verbose() { 537 if fuzzFields == 0 || fuzzObjects == 0 { 538 fmt.Printf("fuzz\tfields: %d\tobjects: %d\t[none]\t%d\n", 539 fuzzFields, fuzzObjects, 0) 540 } else { 541 keys := make([]string, 0, len(stats)) 542 for k := range stats { 543 keys = append(keys, k) 544 } 545 sort.Strings(keys) 546 for _, k := range keys { 547 fmt.Printf("fuzz\tfields: %d\tobjects: %d\t%s\t%d\n", 548 fuzzFields, fuzzObjects, k, stats[k]) 549 } 550 } 551 } 552 553 return 554} 555 556// FailString makes a message for when expectations differ from reality. 557func FailString(name string, want, got interface{}) string { 558 return fmt.Sprintf("bad %s: want %#v got %#v", name, want, got) 559} 560 561// CheckByteLayout verifies the bytes of a Builder in various scenarios. 562func CheckByteLayout(fail func(string, ...interface{})) { 563 var b *flatbuffers.Builder 564 565 var i int 566 check := func(want []byte) { 567 i++ 568 got := b.Bytes[b.Head():] 569 if !bytes.Equal(want, got) { 570 fail("case %d: want\n%v\nbut got\n%v\n", i, want, got) 571 } 572 } 573 574 // test 1: numbers 575 576 b = flatbuffers.NewBuilder(0) 577 check([]byte{}) 578 b.PrependBool(true) 579 check([]byte{1}) 580 b.PrependInt8(-127) 581 check([]byte{129, 1}) 582 b.PrependUint8(255) 583 check([]byte{255, 129, 1}) 584 b.PrependInt16(-32222) 585 check([]byte{0x22, 0x82, 0, 255, 129, 1}) // first pad 586 b.PrependUint16(0xFEEE) 587 check([]byte{0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1}) // no pad this time 588 b.PrependInt32(-53687092) 589 check([]byte{204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1}) 590 b.PrependUint32(0x98765432) 591 check([]byte{0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1}) 592 593 // test 1b: numbers 2 594 595 b = flatbuffers.NewBuilder(0) 596 b.PrependUint64(0x1122334455667788) 597 check([]byte{0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11}) 598 599 // test 2: 1xbyte vector 600 601 b = flatbuffers.NewBuilder(0) 602 check([]byte{}) 603 b.StartVector(flatbuffers.SizeByte, 1, 1) 604 check([]byte{0, 0, 0}) // align to 4bytes 605 b.PrependByte(1) 606 check([]byte{1, 0, 0, 0}) 607 b.EndVector(1) 608 check([]byte{1, 0, 0, 0, 1, 0, 0, 0}) // padding 609 610 // test 3: 2xbyte vector 611 612 b = flatbuffers.NewBuilder(0) 613 b.StartVector(flatbuffers.SizeByte, 2, 1) 614 check([]byte{0, 0}) // align to 4bytes 615 b.PrependByte(1) 616 check([]byte{1, 0, 0}) 617 b.PrependByte(2) 618 check([]byte{2, 1, 0, 0}) 619 b.EndVector(2) 620 check([]byte{2, 0, 0, 0, 2, 1, 0, 0}) // padding 621 622 // test 3b: 11xbyte vector matches builder size 623 624 b = flatbuffers.NewBuilder(12) 625 b.StartVector(flatbuffers.SizeByte, 8, 1) 626 start := []byte{} 627 check(start) 628 for i := 1; i < 12; i++ { 629 b.PrependByte(byte(i)) 630 start = append([]byte{byte(i)}, start...) 631 check(start) 632 } 633 b.EndVector(8) 634 check(append([]byte{8, 0, 0, 0}, start...)) 635 636 // test 4: 1xuint16 vector 637 638 b = flatbuffers.NewBuilder(0) 639 b.StartVector(flatbuffers.SizeUint16, 1, 1) 640 check([]byte{0, 0}) // align to 4bytes 641 b.PrependUint16(1) 642 check([]byte{1, 0, 0, 0}) 643 b.EndVector(1) 644 check([]byte{1, 0, 0, 0, 1, 0, 0, 0}) // padding 645 646 // test 5: 2xuint16 vector 647 648 b = flatbuffers.NewBuilder(0) 649 b.StartVector(flatbuffers.SizeUint16, 2, 1) 650 check([]byte{}) // align to 4bytes 651 b.PrependUint16(0xABCD) 652 check([]byte{0xCD, 0xAB}) 653 b.PrependUint16(0xDCBA) 654 check([]byte{0xBA, 0xDC, 0xCD, 0xAB}) 655 b.EndVector(2) 656 check([]byte{2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB}) 657 658 // test 6: CreateString 659 660 b = flatbuffers.NewBuilder(0) 661 b.CreateString("foo") 662 check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad 663 b.CreateString("moop") 664 check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad 665 3, 0, 0, 0, 'f', 'o', 'o', 0}) 666 667 // test 6b: CreateString unicode 668 669 b = flatbuffers.NewBuilder(0) 670 // These characters are chinese from blog.golang.org/strings 671 // We use escape codes here so that editors without unicode support 672 // aren't bothered: 673 uni_str := "\u65e5\u672c\u8a9e" 674 b.CreateString(uni_str) 675 check([]byte{9, 0, 0, 0, 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // null-terminated, 2-byte pad 676 0, 0}) 677 678 // test 6c: CreateByteString 679 680 b = flatbuffers.NewBuilder(0) 681 b.CreateByteString([]byte("foo")) 682 check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad 683 b.CreateByteString([]byte("moop")) 684 check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad 685 3, 0, 0, 0, 'f', 'o', 'o', 0}) 686 687 // test 7: empty vtable 688 b = flatbuffers.NewBuilder(0) 689 b.StartObject(0) 690 check([]byte{}) 691 b.EndObject() 692 check([]byte{4, 0, 4, 0, 4, 0, 0, 0}) 693 694 // test 8: vtable with one true bool 695 b = flatbuffers.NewBuilder(0) 696 check([]byte{}) 697 b.StartObject(1) 698 check([]byte{}) 699 b.PrependBoolSlot(0, true, false) 700 b.EndObject() 701 check([]byte{ 702 6, 0, // vtable bytes 703 8, 0, // length of object including vtable offset 704 7, 0, // start of bool value 705 6, 0, 0, 0, // offset for start of vtable (int32) 706 0, 0, 0, // padded to 4 bytes 707 1, // bool value 708 }) 709 710 // test 9: vtable with one default bool 711 b = flatbuffers.NewBuilder(0) 712 check([]byte{}) 713 b.StartObject(1) 714 check([]byte{}) 715 b.PrependBoolSlot(0, false, false) 716 b.EndObject() 717 check([]byte{ 718 4, 0, // vtable bytes 719 4, 0, // end of object from here 720 // entry 1 is zero and not stored. 721 4, 0, 0, 0, // offset for start of vtable (int32) 722 }) 723 724 // test 10: vtable with one int16 725 b = flatbuffers.NewBuilder(0) 726 b.StartObject(1) 727 b.PrependInt16Slot(0, 0x789A, 0) 728 b.EndObject() 729 check([]byte{ 730 6, 0, // vtable bytes 731 8, 0, // end of object from here 732 6, 0, // offset to value 733 6, 0, 0, 0, // offset for start of vtable (int32) 734 0, 0, // padding to 4 bytes 735 0x9A, 0x78, 736 }) 737 738 // test 11: vtable with two int16 739 b = flatbuffers.NewBuilder(0) 740 b.StartObject(2) 741 b.PrependInt16Slot(0, 0x3456, 0) 742 b.PrependInt16Slot(1, 0x789A, 0) 743 b.EndObject() 744 check([]byte{ 745 8, 0, // vtable bytes 746 8, 0, // end of object from here 747 6, 0, // offset to value 0 748 4, 0, // offset to value 1 749 8, 0, 0, 0, // offset for start of vtable (int32) 750 0x9A, 0x78, // value 1 751 0x56, 0x34, // value 0 752 }) 753 754 // test 12: vtable with int16 and bool 755 b = flatbuffers.NewBuilder(0) 756 b.StartObject(2) 757 b.PrependInt16Slot(0, 0x3456, 0) 758 b.PrependBoolSlot(1, true, false) 759 b.EndObject() 760 check([]byte{ 761 8, 0, // vtable bytes 762 8, 0, // end of object from here 763 6, 0, // offset to value 0 764 5, 0, // offset to value 1 765 8, 0, 0, 0, // offset for start of vtable (int32) 766 0, // padding 767 1, // value 1 768 0x56, 0x34, // value 0 769 }) 770 771 // test 12: vtable with empty vector 772 b = flatbuffers.NewBuilder(0) 773 b.StartVector(flatbuffers.SizeByte, 0, 1) 774 vecend := b.EndVector(0) 775 b.StartObject(1) 776 b.PrependUOffsetTSlot(0, vecend, 0) 777 b.EndObject() 778 check([]byte{ 779 6, 0, // vtable bytes 780 8, 0, 781 4, 0, // offset to vector offset 782 6, 0, 0, 0, // offset for start of vtable (int32) 783 4, 0, 0, 0, 784 0, 0, 0, 0, // length of vector (not in struct) 785 }) 786 787 // test 12b: vtable with empty vector of byte and some scalars 788 b = flatbuffers.NewBuilder(0) 789 b.StartVector(flatbuffers.SizeByte, 0, 1) 790 vecend = b.EndVector(0) 791 b.StartObject(2) 792 b.PrependInt16Slot(0, 55, 0) 793 b.PrependUOffsetTSlot(1, vecend, 0) 794 b.EndObject() 795 check([]byte{ 796 8, 0, // vtable bytes 797 12, 0, 798 10, 0, // offset to value 0 799 4, 0, // offset to vector offset 800 8, 0, 0, 0, // vtable loc 801 8, 0, 0, 0, // value 1 802 0, 0, 55, 0, // value 0 803 804 0, 0, 0, 0, // length of vector (not in struct) 805 }) 806 807 // test 13: vtable with 1 int16 and 2-vector of int16 808 b = flatbuffers.NewBuilder(0) 809 b.StartVector(flatbuffers.SizeInt16, 2, 1) 810 b.PrependInt16(0x1234) 811 b.PrependInt16(0x5678) 812 vecend = b.EndVector(2) 813 b.StartObject(2) 814 b.PrependUOffsetTSlot(1, vecend, 0) 815 b.PrependInt16Slot(0, 55, 0) 816 b.EndObject() 817 check([]byte{ 818 8, 0, // vtable bytes 819 12, 0, // length of object 820 6, 0, // start of value 0 from end of vtable 821 8, 0, // start of value 1 from end of buffer 822 8, 0, 0, 0, // offset for start of vtable (int32) 823 0, 0, // padding 824 55, 0, // value 0 825 4, 0, 0, 0, // vector position from here 826 2, 0, 0, 0, // length of vector (uint32) 827 0x78, 0x56, // vector value 1 828 0x34, 0x12, // vector value 0 829 }) 830 831 // test 14: vtable with 1 struct of 1 int8, 1 int16, 1 int32 832 b = flatbuffers.NewBuilder(0) 833 b.StartObject(1) 834 b.Prep(4+4+4, 0) 835 b.PrependInt8(55) 836 b.Pad(3) 837 b.PrependInt16(0x1234) 838 b.Pad(2) 839 b.PrependInt32(0x12345678) 840 structStart := b.Offset() 841 b.PrependStructSlot(0, structStart, 0) 842 b.EndObject() 843 check([]byte{ 844 6, 0, // vtable bytes 845 16, 0, // end of object from here 846 4, 0, // start of struct from here 847 6, 0, 0, 0, // offset for start of vtable (int32) 848 0x78, 0x56, 0x34, 0x12, // value 2 849 0, 0, // padding 850 0x34, 0x12, // value 1 851 0, 0, 0, // padding 852 55, // value 0 853 }) 854 855 // test 15: vtable with 1 vector of 2 struct of 2 int8 856 b = flatbuffers.NewBuilder(0) 857 b.StartVector(flatbuffers.SizeInt8*2, 2, 1) 858 b.PrependInt8(33) 859 b.PrependInt8(44) 860 b.PrependInt8(55) 861 b.PrependInt8(66) 862 vecend = b.EndVector(2) 863 b.StartObject(1) 864 b.PrependUOffsetTSlot(0, vecend, 0) 865 b.EndObject() 866 check([]byte{ 867 6, 0, // vtable bytes 868 8, 0, 869 4, 0, // offset of vector offset 870 6, 0, 0, 0, // offset for start of vtable (int32) 871 4, 0, 0, 0, // vector start offset 872 873 2, 0, 0, 0, // vector length 874 66, // vector value 1,1 875 55, // vector value 1,0 876 44, // vector value 0,1 877 33, // vector value 0,0 878 }) 879 880 // test 16: table with some elements 881 b = flatbuffers.NewBuilder(0) 882 b.StartObject(2) 883 b.PrependInt8Slot(0, 33, 0) 884 b.PrependInt16Slot(1, 66, 0) 885 off := b.EndObject() 886 b.Finish(off) 887 888 check([]byte{ 889 12, 0, 0, 0, // root of table: points to vtable offset 890 891 8, 0, // vtable bytes 892 8, 0, // end of object from here 893 7, 0, // start of value 0 894 4, 0, // start of value 1 895 896 8, 0, 0, 0, // offset for start of vtable (int32) 897 898 66, 0, // value 1 899 0, // padding 900 33, // value 0 901 }) 902 903 // test 17: one unfinished table and one finished table 904 b = flatbuffers.NewBuilder(0) 905 b.StartObject(2) 906 b.PrependInt8Slot(0, 33, 0) 907 b.PrependInt8Slot(1, 44, 0) 908 off = b.EndObject() 909 b.Finish(off) 910 911 b.StartObject(3) 912 b.PrependInt8Slot(0, 55, 0) 913 b.PrependInt8Slot(1, 66, 0) 914 b.PrependInt8Slot(2, 77, 0) 915 off = b.EndObject() 916 b.Finish(off) 917 918 check([]byte{ 919 16, 0, 0, 0, // root of table: points to object 920 0, 0, // padding 921 922 10, 0, // vtable bytes 923 8, 0, // size of object 924 7, 0, // start of value 0 925 6, 0, // start of value 1 926 5, 0, // start of value 2 927 10, 0, 0, 0, // offset for start of vtable (int32) 928 0, // padding 929 77, // value 2 930 66, // value 1 931 55, // value 0 932 933 12, 0, 0, 0, // root of table: points to object 934 935 8, 0, // vtable bytes 936 8, 0, // size of object 937 7, 0, // start of value 0 938 6, 0, // start of value 1 939 8, 0, 0, 0, // offset for start of vtable (int32) 940 0, 0, // padding 941 44, // value 1 942 33, // value 0 943 }) 944 945 // test 18: a bunch of bools 946 b = flatbuffers.NewBuilder(0) 947 b.StartObject(8) 948 b.PrependBoolSlot(0, true, false) 949 b.PrependBoolSlot(1, true, false) 950 b.PrependBoolSlot(2, true, false) 951 b.PrependBoolSlot(3, true, false) 952 b.PrependBoolSlot(4, true, false) 953 b.PrependBoolSlot(5, true, false) 954 b.PrependBoolSlot(6, true, false) 955 b.PrependBoolSlot(7, true, false) 956 off = b.EndObject() 957 b.Finish(off) 958 959 check([]byte{ 960 24, 0, 0, 0, // root of table: points to vtable offset 961 962 20, 0, // vtable bytes 963 12, 0, // size of object 964 11, 0, // start of value 0 965 10, 0, // start of value 1 966 9, 0, // start of value 2 967 8, 0, // start of value 3 968 7, 0, // start of value 4 969 6, 0, // start of value 5 970 5, 0, // start of value 6 971 4, 0, // start of value 7 972 20, 0, 0, 0, // vtable offset 973 974 1, // value 7 975 1, // value 6 976 1, // value 5 977 1, // value 4 978 1, // value 3 979 1, // value 2 980 1, // value 1 981 1, // value 0 982 }) 983 984 // test 19: three bools 985 b = flatbuffers.NewBuilder(0) 986 b.StartObject(3) 987 b.PrependBoolSlot(0, true, false) 988 b.PrependBoolSlot(1, true, false) 989 b.PrependBoolSlot(2, true, false) 990 off = b.EndObject() 991 b.Finish(off) 992 993 check([]byte{ 994 16, 0, 0, 0, // root of table: points to vtable offset 995 996 0, 0, // padding 997 998 10, 0, // vtable bytes 999 8, 0, // size of object 1000 7, 0, // start of value 0 1001 6, 0, // start of value 1 1002 5, 0, // start of value 2 1003 10, 0, 0, 0, // vtable offset from here 1004 1005 0, // padding 1006 1, // value 2 1007 1, // value 1 1008 1, // value 0 1009 }) 1010 1011 // test 20: some floats 1012 b = flatbuffers.NewBuilder(0) 1013 b.StartObject(1) 1014 b.PrependFloat32Slot(0, 1.0, 0.0) 1015 off = b.EndObject() 1016 1017 check([]byte{ 1018 6, 0, // vtable bytes 1019 8, 0, // size of object 1020 4, 0, // start of value 0 1021 6, 0, 0, 0, // vtable offset 1022 1023 0, 0, 128, 63, // value 0 1024 }) 1025} 1026 1027// CheckManualBuild builds a Monster manually. 1028func CheckManualBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) { 1029 b := flatbuffers.NewBuilder(0) 1030 str := b.CreateString("MyMonster") 1031 1032 b.StartVector(1, 5, 1) 1033 b.PrependByte(4) 1034 b.PrependByte(3) 1035 b.PrependByte(2) 1036 b.PrependByte(1) 1037 b.PrependByte(0) 1038 inv := b.EndVector(5) 1039 1040 b.StartObject(13) 1041 b.PrependInt16Slot(2, 20, 100) 1042 mon2 := b.EndObject() 1043 1044 // Test4Vector 1045 b.StartVector(4, 2, 1) 1046 1047 // Test 0 1048 b.Prep(2, 4) 1049 b.Pad(1) 1050 b.PlaceInt8(20) 1051 b.PlaceInt16(10) 1052 1053 // Test 1 1054 b.Prep(2, 4) 1055 b.Pad(1) 1056 b.PlaceInt8(40) 1057 b.PlaceInt16(30) 1058 1059 // end testvector 1060 test4 := b.EndVector(2) 1061 1062 b.StartObject(13) 1063 1064 // a vec3 1065 b.Prep(16, 32) 1066 b.Pad(2) 1067 b.Prep(2, 4) 1068 b.Pad(1) 1069 b.PlaceByte(6) 1070 b.PlaceInt16(5) 1071 b.Pad(1) 1072 b.PlaceByte(4) 1073 b.PlaceFloat64(3.0) 1074 b.Pad(4) 1075 b.PlaceFloat32(3.0) 1076 b.PlaceFloat32(2.0) 1077 b.PlaceFloat32(1.0) 1078 vec3Loc := b.Offset() 1079 // end vec3 1080 1081 b.PrependStructSlot(0, vec3Loc, 0) // vec3. noop 1082 b.PrependInt16Slot(2, 80, 100) // hp 1083 b.PrependUOffsetTSlot(3, str, 0) 1084 b.PrependUOffsetTSlot(5, inv, 0) // inventory 1085 b.PrependByteSlot(7, 1, 0) 1086 b.PrependUOffsetTSlot(8, mon2, 0) 1087 b.PrependUOffsetTSlot(9, test4, 0) 1088 mon := b.EndObject() 1089 1090 b.Finish(mon) 1091 1092 return b.Bytes, b.Head() 1093} 1094 1095func CheckGetRootAsForNonRootTable(fail func(string, ...interface{})) { 1096 b := flatbuffers.NewBuilder(0) 1097 str := b.CreateString("MyStat") 1098 example.StatStart(b) 1099 example.StatAddId(b, str) 1100 example.StatAddVal(b, 12345678) 1101 example.StatAddCount(b, 12345) 1102 stat_end := example.StatEnd(b) 1103 b.Finish(stat_end) 1104 1105 stat := example.GetRootAsStat(b.Bytes, b.Head()) 1106 1107 if got := stat.Id(); !bytes.Equal([]byte("MyStat"), got) { 1108 fail(FailString("stat.Id()", "MyStat", got)) 1109 } 1110 1111 if got := stat.Val(); 12345678 != got { 1112 fail(FailString("stat.Val()", 12345678, got)) 1113 } 1114 1115 if got := stat.Count(); 12345 != got { 1116 fail(FailString("stat.Count()", 12345, got)) 1117 } 1118} 1119 1120// CheckGeneratedBuild uses generated code to build the example Monster. 1121func CheckGeneratedBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) { 1122 b := flatbuffers.NewBuilder(0) 1123 str := b.CreateString("MyMonster") 1124 test1 := b.CreateString("test1") 1125 test2 := b.CreateString("test2") 1126 fred := b.CreateString("Fred") 1127 1128 example.MonsterStartInventoryVector(b, 5) 1129 b.PrependByte(4) 1130 b.PrependByte(3) 1131 b.PrependByte(2) 1132 b.PrependByte(1) 1133 b.PrependByte(0) 1134 inv := b.EndVector(5) 1135 1136 example.MonsterStart(b) 1137 example.MonsterAddName(b, fred) 1138 mon2 := example.MonsterEnd(b) 1139 1140 example.MonsterStartTest4Vector(b, 2) 1141 example.CreateTest(b, 10, 20) 1142 example.CreateTest(b, 30, 40) 1143 test4 := b.EndVector(2) 1144 1145 example.MonsterStartTestarrayofstringVector(b, 2) 1146 b.PrependUOffsetT(test2) 1147 b.PrependUOffsetT(test1) 1148 testArrayOfString := b.EndVector(2) 1149 1150 example.MonsterStart(b) 1151 1152 pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6) 1153 example.MonsterAddPos(b, pos) 1154 1155 example.MonsterAddHp(b, 80) 1156 example.MonsterAddName(b, str) 1157 example.MonsterAddInventory(b, inv) 1158 example.MonsterAddTestType(b, 1) 1159 example.MonsterAddTest(b, mon2) 1160 example.MonsterAddTest4(b, test4) 1161 example.MonsterAddTestarrayofstring(b, testArrayOfString) 1162 mon := example.MonsterEnd(b) 1163 1164 b.Finish(mon) 1165 1166 return b.Bytes, b.Head() 1167} 1168 1169// CheckTableAccessors checks that the table accessors work as expected. 1170func CheckTableAccessors(fail func(string, ...interface{})) { 1171 // test struct accessor 1172 b := flatbuffers.NewBuilder(0) 1173 pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 4, 5, 6) 1174 b.Finish(pos) 1175 vec3Bytes := b.FinishedBytes() 1176 vec3 := &example.Vec3{} 1177 flatbuffers.GetRootAs(vec3Bytes, 0, vec3) 1178 1179 if bytes.Compare(vec3Bytes, vec3.Table().Bytes) != 0 { 1180 fail("invalid vec3 table") 1181 } 1182 1183 // test table accessor 1184 b = flatbuffers.NewBuilder(0) 1185 str := b.CreateString("MyStat") 1186 example.StatStart(b) 1187 example.StatAddId(b, str) 1188 example.StatAddVal(b, 12345678) 1189 example.StatAddCount(b, 12345) 1190 pos = example.StatEnd(b) 1191 b.Finish(pos) 1192 statBytes := b.FinishedBytes() 1193 stat := &example.Stat{} 1194 flatbuffers.GetRootAs(statBytes, 0, stat) 1195 1196 if bytes.Compare(statBytes, stat.Table().Bytes) != 0 { 1197 fail("invalid stat table") 1198 } 1199} 1200 1201// CheckVtableDeduplication verifies that vtables are deduplicated. 1202func CheckVtableDeduplication(fail func(string, ...interface{})) { 1203 b := flatbuffers.NewBuilder(0) 1204 1205 b.StartObject(4) 1206 b.PrependByteSlot(0, 0, 0) 1207 b.PrependByteSlot(1, 11, 0) 1208 b.PrependByteSlot(2, 22, 0) 1209 b.PrependInt16Slot(3, 33, 0) 1210 obj0 := b.EndObject() 1211 1212 b.StartObject(4) 1213 b.PrependByteSlot(0, 0, 0) 1214 b.PrependByteSlot(1, 44, 0) 1215 b.PrependByteSlot(2, 55, 0) 1216 b.PrependInt16Slot(3, 66, 0) 1217 obj1 := b.EndObject() 1218 1219 b.StartObject(4) 1220 b.PrependByteSlot(0, 0, 0) 1221 b.PrependByteSlot(1, 77, 0) 1222 b.PrependByteSlot(2, 88, 0) 1223 b.PrependInt16Slot(3, 99, 0) 1224 obj2 := b.EndObject() 1225 1226 got := b.Bytes[b.Head():] 1227 1228 want := []byte{ 1229 240, 255, 255, 255, // == -12. offset to dedupped vtable. 1230 99, 0, 1231 88, 1232 77, 1233 248, 255, 255, 255, // == -8. offset to dedupped vtable. 1234 66, 0, 1235 55, 1236 44, 1237 12, 0, 1238 8, 0, 1239 0, 0, 1240 7, 0, 1241 6, 0, 1242 4, 0, 1243 12, 0, 0, 0, 1244 33, 0, 1245 22, 1246 11, 1247 } 1248 1249 if !bytes.Equal(want, got) { 1250 fail("testVtableDeduplication want:\n%d %v\nbut got:\n%d %v\n", 1251 len(want), want, len(got), got) 1252 } 1253 1254 table0 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj0} 1255 table1 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj1} 1256 table2 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj2} 1257 1258 testTable := func(tab *flatbuffers.Table, a flatbuffers.VOffsetT, b, c, d byte) { 1259 // vtable size 1260 if got := tab.GetVOffsetTSlot(0, 0); 12 != got { 1261 fail("failed 0, 0: %d", got) 1262 } 1263 // object size 1264 if got := tab.GetVOffsetTSlot(2, 0); 8 != got { 1265 fail("failed 2, 0: %d", got) 1266 } 1267 // default value 1268 if got := tab.GetVOffsetTSlot(4, 0); a != got { 1269 fail("failed 4, 0: %d", got) 1270 } 1271 if got := tab.GetByteSlot(6, 0); b != got { 1272 fail("failed 6, 0: %d", got) 1273 } 1274 if val := tab.GetByteSlot(8, 0); c != val { 1275 fail("failed 8, 0: %d", got) 1276 } 1277 if got := tab.GetByteSlot(10, 0); d != got { 1278 fail("failed 10, 0: %d", got) 1279 } 1280 } 1281 1282 testTable(table0, 0, 11, 22, 33) 1283 testTable(table1, 0, 44, 55, 66) 1284 testTable(table2, 0, 77, 88, 99) 1285} 1286 1287// CheckNotInObjectError verifies that `EndObject` fails if not inside an 1288// object. 1289func CheckNotInObjectError(fail func(string, ...interface{})) { 1290 b := flatbuffers.NewBuilder(0) 1291 1292 defer func() { 1293 r := recover() 1294 if r == nil { 1295 fail("expected panic in CheckNotInObjectError") 1296 } 1297 }() 1298 b.EndObject() 1299} 1300 1301// CheckStringIsNestedError verifies that a string can not be created inside 1302// another object. 1303func CheckStringIsNestedError(fail func(string, ...interface{})) { 1304 b := flatbuffers.NewBuilder(0) 1305 b.StartObject(0) 1306 defer func() { 1307 r := recover() 1308 if r == nil { 1309 fail("expected panic in CheckStringIsNestedError") 1310 } 1311 }() 1312 b.CreateString("foo") 1313} 1314 1315// CheckByteStringIsNestedError verifies that a bytestring can not be created 1316// inside another object. 1317func CheckByteStringIsNestedError(fail func(string, ...interface{})) { 1318 b := flatbuffers.NewBuilder(0) 1319 b.StartObject(0) 1320 defer func() { 1321 r := recover() 1322 if r == nil { 1323 fail("expected panic in CheckByteStringIsNestedError") 1324 } 1325 }() 1326 b.CreateByteString([]byte("foo")) 1327} 1328 1329// CheckStructIsNotInlineError verifies that writing a struct in a location 1330// away from where it is used will cause a panic. 1331func CheckStructIsNotInlineError(fail func(string, ...interface{})) { 1332 b := flatbuffers.NewBuilder(0) 1333 b.StartObject(0) 1334 defer func() { 1335 r := recover() 1336 if r == nil { 1337 fail("expected panic in CheckStructIsNotInlineError") 1338 } 1339 }() 1340 b.PrependStructSlot(0, 1, 0) 1341} 1342 1343// CheckFinishedBytesError verifies that `FinishedBytes` panics if the table 1344// is not finished. 1345func CheckFinishedBytesError(fail func(string, ...interface{})) { 1346 b := flatbuffers.NewBuilder(0) 1347 1348 defer func() { 1349 r := recover() 1350 if r == nil { 1351 fail("expected panic in CheckFinishedBytesError") 1352 } 1353 }() 1354 b.FinishedBytes() 1355} 1356 1357// CheckEnumNames checks that the generated enum names are correct. 1358func CheckEnumNames(fail func(string, ...interface{})) { 1359 type testEnumNames struct { 1360 EnumNames map[int]string 1361 Expected map[int]string 1362 } 1363 data := [...]testEnumNames{ 1364 {example.EnumNamesAny, 1365 map[int]string{ 1366 example.AnyNONE: "NONE", 1367 example.AnyMonster: "Monster", 1368 example.AnyTestSimpleTableWithEnum: "TestSimpleTableWithEnum", 1369 }, 1370 }, 1371 {example.EnumNamesColor, 1372 map[int]string{ 1373 example.ColorRed: "Red", 1374 example.ColorGreen: "Green", 1375 example.ColorBlue: "Blue", 1376 }, 1377 }, 1378 } 1379 for _, t := range data { 1380 for val, name := range t.Expected { 1381 if name != t.EnumNames[val] { 1382 fail("enum name is not equal") 1383 } 1384 } 1385 } 1386} 1387 1388// CheckDocExample checks that the code given in FlatBuffers documentation 1389// is syntactically correct. 1390func CheckDocExample(buf []byte, off flatbuffers.UOffsetT, fail func(string, ...interface{})) { 1391 monster := example.GetRootAsMonster(buf, off) 1392 _ = monster.Hp() 1393 _ = monster.Pos(nil) 1394 for i := 0; i < monster.InventoryLength(); i++ { 1395 _ = monster.Inventory(i) // do something here 1396 } 1397 1398 builder := flatbuffers.NewBuilder(0) 1399 1400 example.MonsterStartInventoryVector(builder, 5) 1401 for i := 4; i >= 0; i-- { 1402 builder.PrependByte(byte(i)) 1403 } 1404 inv := builder.EndVector(5) 1405 1406 str := builder.CreateString("MyMonster") 1407 example.MonsterStart(builder) 1408 example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, 4, 5, 6)) 1409 example.MonsterAddHp(builder, 80) 1410 example.MonsterAddName(builder, str) 1411 example.MonsterAddInventory(builder, inv) 1412 example.MonsterAddTestType(builder, 1) 1413 // example.MonsterAddTest(builder, mon2) 1414 // example.MonsterAddTest4(builder, test4s) 1415 _ = example.MonsterEnd(builder) 1416} 1417 1418func CheckCreateByteVector(fail func(string, ...interface{})) { 1419 raw := [30]byte{} 1420 for i := 0; i < len(raw); i++ { 1421 raw[i] = byte(i) 1422 } 1423 1424 for size := 0; size < len(raw); size++ { 1425 b1 := flatbuffers.NewBuilder(0) 1426 b2 := flatbuffers.NewBuilder(0) 1427 b1.StartVector(1, size, 1) 1428 for i := size - 1; i >= 0; i-- { 1429 b1.PrependByte(raw[i]) 1430 } 1431 b1.EndVector(size) 1432 b2.CreateByteVector(raw[:size]) 1433 CheckByteEquality(b1.Bytes, b2.Bytes, fail) 1434 } 1435} 1436 1437// Include simple random number generator to ensure results will be the 1438// same cross platform. 1439// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator 1440type LCG uint32 1441 1442const InitialLCGSeed = 48271 1443 1444func NewLCG() *LCG { 1445 n := uint32(InitialLCGSeed) 1446 l := LCG(n) 1447 return &l 1448} 1449 1450func (lcg *LCG) Reset() { 1451 *lcg = InitialLCGSeed 1452} 1453 1454func (lcg *LCG) Next() uint32 { 1455 n := uint32((uint64(*lcg) * uint64(279470273)) % uint64(4294967291)) 1456 *lcg = LCG(n) 1457 return n 1458} 1459 1460// CheckByteEquality verifies that two byte buffers are the same. 1461func CheckByteEquality(a, b []byte, fail func(string, ...interface{})) { 1462 if !bytes.Equal(a, b) { 1463 fail("objects are not byte-wise equal") 1464 } 1465} 1466 1467// CheckMutateMethods checks all mutate methods one by one 1468func CheckMutateMethods(fail func(string, ...interface{})) { 1469 b := flatbuffers.NewBuilder(0) 1470 b.StartObject(15) 1471 b.PrependBoolSlot(0, true, false) 1472 b.PrependByteSlot(1, 1, 0) 1473 b.PrependUint8Slot(2, 2, 0) 1474 b.PrependUint16Slot(3, 3, 0) 1475 b.PrependUint32Slot(4, 4, 0) 1476 b.PrependUint64Slot(5, 5, 0) 1477 b.PrependInt8Slot(6, 6, 0) 1478 b.PrependInt16Slot(7, 7, 0) 1479 b.PrependInt32Slot(8, 8, 0) 1480 b.PrependInt64Slot(9, 9, 0) 1481 b.PrependFloat32Slot(10, 10, 0) 1482 b.PrependFloat64Slot(11, 11, 0) 1483 1484 b.PrependUOffsetTSlot(12, 12, 0) 1485 uoVal := b.Offset() - 12 1486 1487 b.PrependVOffsetT(13) 1488 b.Slot(13) 1489 1490 b.PrependSOffsetT(14) 1491 b.Slot(14) 1492 soVal := flatbuffers.SOffsetT(b.Offset() - 14) 1493 1494 offset := b.EndObject() 1495 1496 t := &flatbuffers.Table{ 1497 Bytes: b.Bytes, 1498 Pos: flatbuffers.UOffsetT(len(b.Bytes)) - offset, 1499 } 1500 1501 calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) { 1502 return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT) 1503 } 1504 calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) { 1505 return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset)) 1506 } 1507 1508 type testcase struct { 1509 field string 1510 testfn func() bool 1511 } 1512 1513 testForOriginalValues := []testcase{ 1514 testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }}, 1515 testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }}, 1516 testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }}, 1517 testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }}, 1518 testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }}, 1519 testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }}, 1520 testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }}, 1521 testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }}, 1522 testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }}, 1523 testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }}, 1524 testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }}, 1525 testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }}, 1526 testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }}, 1527 testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }}, 1528 testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }}, 1529 } 1530 1531 testMutability := []testcase{ 1532 testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }}, 1533 testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }}, 1534 testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }}, 1535 testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }}, 1536 testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }}, 1537 testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }}, 1538 testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }}, 1539 testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }}, 1540 testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }}, 1541 testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }}, 1542 testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }}, 1543 testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }}, 1544 testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }}, 1545 testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }}, 1546 testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }}, 1547 } 1548 1549 testMutabilityWithoutSlot := []testcase{ 1550 testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }}, 1551 testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }}, 1552 testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }}, 1553 testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }}, 1554 testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }}, 1555 testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }}, 1556 testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }}, 1557 testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }}, 1558 testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }}, 1559 testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }}, 1560 testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }}, 1561 testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }}, 1562 } 1563 1564 testForMutatedValues := []testcase{ 1565 testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }}, 1566 testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }}, 1567 testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }}, 1568 testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }}, 1569 testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }}, 1570 testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }}, 1571 testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }}, 1572 testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }}, 1573 testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }}, 1574 testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }}, 1575 testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }}, 1576 testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }}, 1577 testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }}, 1578 testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }}, 1579 testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }}, 1580 } 1581 1582 // make sure original values are okay 1583 for _, t := range testForOriginalValues { 1584 if !t.testfn() { 1585 fail(t.field + "' field doesn't have the expected original value") 1586 } 1587 } 1588 1589 // try to mutate fields and check mutability 1590 for _, t := range testMutability { 1591 if !t.testfn() { 1592 fail(FailString(t.field+"' field failed mutability test", "passed", "failed")) 1593 } 1594 } 1595 1596 // try to mutate fields and check mutability 1597 // these have wrong slots so should fail 1598 for _, t := range testMutabilityWithoutSlot { 1599 if t.testfn() { 1600 fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed")) 1601 } 1602 } 1603 1604 // test whether values have changed 1605 for _, t := range testForMutatedValues { 1606 if !t.testfn() { 1607 fail(t.field + "' field doesn't have the expected mutated value") 1608 } 1609 } 1610} 1611 1612// BenchmarkVtableDeduplication measures the speed of vtable deduplication 1613// by creating prePop vtables, then populating b.N objects with a 1614// different single vtable. 1615// 1616// When b.N is large (as in long benchmarks), memory usage may be high. 1617func BenchmarkVtableDeduplication(b *testing.B) { 1618 prePop := 10 1619 builder := flatbuffers.NewBuilder(0) 1620 1621 // pre-populate some vtables: 1622 for i := 0; i < prePop; i++ { 1623 builder.StartObject(i) 1624 for j := 0; j < i; j++ { 1625 builder.PrependInt16Slot(j, int16(j), 0) 1626 } 1627 builder.EndObject() 1628 } 1629 1630 // benchmark deduplication of a new vtable: 1631 b.ResetTimer() 1632 for i := 0; i < b.N; i++ { 1633 lim := prePop 1634 1635 builder.StartObject(lim) 1636 for j := 0; j < lim; j++ { 1637 builder.PrependInt16Slot(j, int16(j), 0) 1638 } 1639 builder.EndObject() 1640 } 1641} 1642 1643// BenchmarkParseGold measures the speed of parsing the 'gold' data 1644// used throughout this test suite. 1645func BenchmarkParseGold(b *testing.B) { 1646 buf, offset := CheckGeneratedBuild(b.Fatalf) 1647 monster := example.GetRootAsMonster(buf, offset) 1648 1649 // use these to prevent allocations: 1650 reuse_pos := example.Vec3{} 1651 reuse_test3 := example.Test{} 1652 reuse_table2 := flatbuffers.Table{} 1653 reuse_monster2 := example.Monster{} 1654 reuse_test4_0 := example.Test{} 1655 reuse_test4_1 := example.Test{} 1656 1657 b.SetBytes(int64(len(buf[offset:]))) 1658 b.ReportAllocs() 1659 b.ResetTimer() 1660 for i := 0; i < b.N; i++ { 1661 monster.Hp() 1662 monster.Mana() 1663 name := monster.Name() 1664 _ = name[0] 1665 _ = name[len(name)-1] 1666 1667 monster.Pos(&reuse_pos) 1668 reuse_pos.X() 1669 reuse_pos.Y() 1670 reuse_pos.Z() 1671 reuse_pos.Test1() 1672 reuse_pos.Test2() 1673 reuse_pos.Test3(&reuse_test3) 1674 reuse_test3.A() 1675 reuse_test3.B() 1676 monster.TestType() 1677 monster.Test(&reuse_table2) 1678 reuse_monster2.Init(reuse_table2.Bytes, reuse_table2.Pos) 1679 name2 := reuse_monster2.Name() 1680 _ = name2[0] 1681 _ = name2[len(name2)-1] 1682 monster.InventoryLength() 1683 l := monster.InventoryLength() 1684 for i := 0; i < l; i++ { 1685 monster.Inventory(i) 1686 } 1687 monster.Test4Length() 1688 monster.Test4(&reuse_test4_0, 0) 1689 monster.Test4(&reuse_test4_1, 1) 1690 1691 reuse_test4_0.A() 1692 reuse_test4_0.B() 1693 reuse_test4_1.A() 1694 reuse_test4_1.B() 1695 1696 monster.TestarrayofstringLength() 1697 str0 := monster.Testarrayofstring(0) 1698 _ = str0[0] 1699 _ = str0[len(str0)-1] 1700 str1 := monster.Testarrayofstring(1) 1701 _ = str1[0] 1702 _ = str1[len(str1)-1] 1703 } 1704} 1705 1706// BenchmarkBuildGold uses generated code to build the example Monster. 1707func BenchmarkBuildGold(b *testing.B) { 1708 buf, offset := CheckGeneratedBuild(b.Fatalf) 1709 bytes_length := int64(len(buf[offset:])) 1710 1711 reuse_str := "MyMonster" 1712 reuse_test1 := "test1" 1713 reuse_test2 := "test2" 1714 reuse_fred := "Fred" 1715 1716 b.SetBytes(bytes_length) 1717 bldr := flatbuffers.NewBuilder(0) 1718 b.ResetTimer() 1719 b.ReportAllocs() 1720 for i := 0; i < b.N; i++ { 1721 bldr.Reset() 1722 1723 str := bldr.CreateString(reuse_str) 1724 test1 := bldr.CreateString(reuse_test1) 1725 test2 := bldr.CreateString(reuse_test2) 1726 fred := bldr.CreateString(reuse_fred) 1727 1728 example.MonsterStartInventoryVector(bldr, 5) 1729 bldr.PrependByte(4) 1730 bldr.PrependByte(3) 1731 bldr.PrependByte(2) 1732 bldr.PrependByte(1) 1733 bldr.PrependByte(0) 1734 inv := bldr.EndVector(5) 1735 1736 example.MonsterStart(bldr) 1737 example.MonsterAddName(bldr, fred) 1738 mon2 := example.MonsterEnd(bldr) 1739 1740 example.MonsterStartTest4Vector(bldr, 2) 1741 example.CreateTest(bldr, 10, 20) 1742 example.CreateTest(bldr, 30, 40) 1743 test4 := bldr.EndVector(2) 1744 1745 example.MonsterStartTestarrayofstringVector(bldr, 2) 1746 bldr.PrependUOffsetT(test2) 1747 bldr.PrependUOffsetT(test1) 1748 testArrayOfString := bldr.EndVector(2) 1749 1750 example.MonsterStart(bldr) 1751 1752 pos := example.CreateVec3(bldr, 1.0, 2.0, 3.0, 3.0, 2, 5, 6) 1753 example.MonsterAddPos(bldr, pos) 1754 1755 example.MonsterAddHp(bldr, 80) 1756 example.MonsterAddName(bldr, str) 1757 example.MonsterAddInventory(bldr, inv) 1758 example.MonsterAddTestType(bldr, 1) 1759 example.MonsterAddTest(bldr, mon2) 1760 example.MonsterAddTest4(bldr, test4) 1761 example.MonsterAddTestarrayofstring(bldr, testArrayOfString) 1762 mon := example.MonsterEnd(bldr) 1763 1764 bldr.Finish(mon) 1765 } 1766} 1767