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