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