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