blob: 8cb7b97f36bd13fb69556a9f755b42a06603e448 [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
mygame "MyGame" // refers to generated code
example "MyGame/Example" // refers to generated code
"encoding/json"
optional_scalars "optional_scalars" // refers to generated code
"bytes"
"flag"
"fmt"
"os"
"reflect"
"sort"
"testing"
"testing/quick"
flatbuffers "github.com/google/flatbuffers/go"
)
var (
cppData, javaData, outData string
fuzz bool
fuzzFields, fuzzObjects int
)
func init() {
flag.StringVar(&cppData, "cpp_data", "",
"location of monsterdata_test.mon to verify against (required)")
flag.StringVar(&javaData, "java_data", "",
"location of monsterdata_java_wire.mon to verify against (optional)")
flag.StringVar(&outData, "out_data", "",
"location to write generated Go data")
flag.BoolVar(&fuzz, "fuzz", false, "perform fuzzing")
flag.IntVar(&fuzzFields, "fuzz_fields", 4, "fields per fuzzer object")
flag.IntVar(&fuzzObjects, "fuzz_objects", 10000,
"number of fuzzer objects (higher is slower and more thorough")
}
// Store specific byte patterns in these variables for the fuzzer. These
// values are taken verbatim from the C++ function FuzzTest1.
var (
overflowingInt32Val = flatbuffers.GetInt32([]byte{0x83, 0x33, 0x33, 0x33})
overflowingInt64Val = flatbuffers.GetInt64([]byte{0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44})
)
func TestMain(m *testing.M) {
flag.Parse()
if cppData == "" {
fmt.Fprintf(os.Stderr, "cpp_data argument is required\n")
os.Exit(1)
}
os.Exit(m.Run())
}
// TestTextParsing test if text parsing works with object API.
func TestTextParsing(t *testing.T) {
expectedMonster := example.MonsterT{
Mana: 42,
Name: "foo",
LongEnumNormalDefault: example.LongEnumLongTwo,
}
buf := new(bytes.Buffer)
if err := json.NewEncoder(buf).Encode(expectedMonster); err != nil {
t.Fatal(err)
}
var monster example.MonsterT
if err := json.NewDecoder(buf).Decode(&monster); err != nil {
t.Fatal(err)
}
if monster.Mana != expectedMonster.Mana {
t.Fatal("wrong mana:", monster.Mana)
}
if monster.Name != expectedMonster.Name {
t.Fatal("wrong name:", monster.Name)
}
if monster.LongEnumNormalDefault != expectedMonster.LongEnumNormalDefault {
t.Fatal("wrong enum:", monster.LongEnumNormalDefault)
}
}
// TestAll runs all checks, failing if any errors occur.
func TestAll(t *testing.T) {
// Verify that the Go FlatBuffers runtime library generates the
// expected bytes (does not use any schema):
CheckByteLayout(t.Fatalf)
CheckMutateMethods(t.Fatalf)
// Verify that panics are raised during exceptional conditions:
CheckNotInObjectError(t.Fatalf)
CheckStringIsNestedError(t.Fatalf)
CheckByteStringIsNestedError(t.Fatalf)
CheckStructIsNotInlineError(t.Fatalf)
CheckFinishedBytesError(t.Fatalf)
CheckSharedStrings(t.Fatalf)
CheckEmptiedBuilder(t.Fatalf)
// Verify that GetRootAs works for non-root tables
CheckGetRootAsForNonRootTable(t.Fatalf)
CheckTableAccessors(t.Fatalf)
// Verify that using the generated Go code builds a buffer without
// returning errors:
generated, off := CheckGeneratedBuild(false, t.Fatalf)
// Verify that the buffer generated by Go code is readable by the
// generated Go code:
CheckReadBuffer(generated, off, false, t.Fatalf)
CheckMutateBuffer(generated, off, false, t.Fatalf)
CheckObjectAPI(generated, off, false, t.Fatalf)
// Verify that the buffer generated by C++ code is readable by the
// generated Go code:
monsterDataCpp, err := os.ReadFile(cppData)
if err != nil {
t.Fatal(err)
}
CheckReadBuffer(monsterDataCpp, 0, false, t.Fatalf)
CheckMutateBuffer(monsterDataCpp, 0, false, t.Fatalf)
CheckObjectAPI(monsterDataCpp, 0, false, t.Fatalf)
// Verify that vtables are deduplicated when written:
CheckVtableDeduplication(t.Fatalf)
// Verify the enum names
CheckEnumNames(t.Fatalf)
// Verify enum String methods
CheckEnumString(t.Fatalf)
// Verify the enum values maps
CheckEnumValues(t.Fatalf)
// Verify that the Go code used in FlatBuffers documentation passes
// some sanity checks:
CheckDocExample(generated, off, t.Fatalf)
// Check Builder.CreateByteVector
CheckCreateByteVector(t.Fatalf)
// Check a parent namespace import
CheckParentNamespace(t.Fatalf)
// Check size-prefixed flatbuffers
CheckSizePrefixedBuffer(t.Fatalf)
// Check that optional scalars work
CheckOptionalScalars(t.Fatalf)
// If the filename of the FlatBuffers file generated by the Java test
// is given, check that Go code can read it, and that Go code
// generates an identical buffer when used to create the example data:
if javaData != "" {
monsterDataJava, err := os.ReadFile(javaData)
if err != nil {
t.Fatal(err)
}
CheckReadBuffer(monsterDataJava, 0, false, t.Fatalf)
CheckByteEquality(generated[off:], monsterDataJava, t.Fatalf)
}
// Verify that various fuzzing scenarios produce a valid FlatBuffer.
if fuzz {
checkFuzz(fuzzFields, fuzzObjects, t.Fatalf)
}
// Write the generated buffer out to a file:
err = os.WriteFile(outData, generated[off:], os.FileMode(0644))
if err != nil {
t.Fatal(err)
}
}
// CheckReadBuffer checks that the given buffer is evaluated correctly
// as the example Monster.
func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, sizePrefix bool, fail func(string, ...interface{})) {
// try the two ways of generating a monster
var monster1 *example.Monster
monster2 := &example.Monster{}
if sizePrefix {
monster1 = example.GetSizePrefixedRootAsMonster(buf, offset)
flatbuffers.GetSizePrefixedRootAs(buf, offset, monster2)
} else {
monster1 = example.GetRootAsMonster(buf, offset)
flatbuffers.GetRootAs(buf, offset, monster2)
}
for _, monster := range []*example.Monster{monster1, monster2} {
if got := monster.Hp(); 80 != got {
fail(FailString("hp", 80, got))
}
// default
if got := monster.Mana(); 150 != got {
fail(FailString("mana", 150, got))
}
if got := monster.Name(); !bytes.Equal([]byte("MyMonster"), got) {
fail(FailString("name", "MyMonster", got))
}
if got := monster.Color(); example.ColorBlue != got {
fail(FailString("color", example.ColorBlue, got))
}
if got := monster.Testbool(); true != got {
fail(FailString("testbool", true, got))
}
// initialize a Vec3 from Pos()
vec := new(example.Vec3)
vec = monster.Pos(vec)
if vec == nil {
fail("vec3 initialization failed")
}
// check that new allocs equal given ones:
vec2 := monster.Pos(nil)
if !reflect.DeepEqual(vec, vec2) {
fail("fresh allocation failed")
}
// verify the properties of the Vec3
if got := vec.X(); float32(1.0) != got {
fail(FailString("Pos.X", float32(1.0), got))
}
if got := vec.Y(); float32(2.0) != got {
fail(FailString("Pos.Y", float32(2.0), got))
}
if got := vec.Z(); float32(3.0) != got {
fail(FailString("Pos.Z", float32(3.0), got))
}
if got := vec.Test1(); float64(3.0) != got {
fail(FailString("Pos.Test1", float64(3.0), got))
}
if got := vec.Test2(); example.ColorGreen != got {
fail(FailString("Pos.Test2", example.ColorGreen, got))
}
// initialize a Test from Test3(...)
t := new(example.Test)
t = vec.Test3(t)
if t == nil {
fail("vec.Test3(&t) failed")
}
// check that new allocs equal given ones:
t2 := vec.Test3(nil)
if !reflect.DeepEqual(t, t2) {
fail("fresh allocation failed")
}
// verify the properties of the Test
if got := t.A(); int16(5) != got {
fail(FailString("t.A()", int16(5), got))
}
if got := t.B(); int8(6) != got {
fail(FailString("t.B()", int8(6), got))
}
if got := monster.TestType(); example.AnyMonster != got {
fail(FailString("monster.TestType()", example.AnyMonster, got))
}
// initialize a Table from a union field Test(...)
var table2 flatbuffers.Table
if ok := monster.Test(&table2); !ok {
fail("monster.Test(&monster2) failed")
}
// initialize a Monster from the Table from the union
var monster2 example.Monster
monster2.Init(table2.Bytes, table2.Pos)
if got := monster2.Name(); !bytes.Equal([]byte("Fred"), got) {
fail(FailString("monster2.Name()", "Fred", got))
}
inventorySlice := monster.InventoryBytes()
if len(inventorySlice) != monster.InventoryLength() {
fail(FailString("len(monster.InventoryBytes) != monster.InventoryLength", len(inventorySlice), monster.InventoryLength()))
}
if got := monster.InventoryLength(); 5 != got {
fail(FailString("monster.InventoryLength", 5, got))
}
invsum := 0
l := monster.InventoryLength()
for i := 0; i < l; i++ {
v := monster.Inventory(i)
if v != inventorySlice[i] {
fail(FailString("monster inventory slice[i] != Inventory(i)", v, inventorySlice[i]))
}
invsum += int(v)
}
if invsum != 10 {
fail(FailString("monster inventory sum", 10, invsum))
}
if got := monster.Test4Length(); 2 != got {
fail(FailString("monster.Test4Length()", 2, got))
}
var test0 example.Test
ok := monster.Test4(&test0, 0)
if !ok {
fail(FailString("monster.Test4(&test0, 0)", true, ok))
}
var test1 example.Test
ok = monster.Test4(&test1, 1)
if !ok {
fail(FailString("monster.Test4(&test1, 1)", true, ok))
}
// the position of test0 and test1 are swapped in monsterdata_java_wire
// and monsterdata_test_wire, so ignore ordering
v0 := test0.A()
v1 := test0.B()
v2 := test1.A()
v3 := test1.B()
sum := int(v0) + int(v1) + int(v2) + int(v3)
if 100 != sum {
fail(FailString("test0 and test1 sum", 100, sum))
}
if got := monster.TestarrayofstringLength(); 2 != got {
fail(FailString("Testarrayofstring length", 2, got))
}
if got := monster.Testarrayofstring(0); !bytes.Equal([]byte("test1"), got) {
fail(FailString("Testarrayofstring(0)", "test1", got))
}
if got := monster.Testarrayofstring(1); !bytes.Equal([]byte("test2"), got) {
fail(FailString("Testarrayofstring(1)", "test2", got))
}
}
}
// CheckMutateBuffer checks that the given buffer can be mutated correctly
// as the example Monster. Only available scalar values are mutated.
func CheckMutateBuffer(org []byte, offset flatbuffers.UOffsetT, sizePrefix bool, fail func(string, ...interface{})) {
// make a copy to mutate
buf := make([]byte, len(org))
copy(buf, org)
// load monster data from the buffer
var monster *example.Monster
if sizePrefix {
monster = example.GetSizePrefixedRootAsMonster(buf, offset)
} else {
monster = example.GetRootAsMonster(buf, offset)
}
// test case struct
type testcase struct {
field string
testfn func() bool
}
testForOriginalValues := []testcase{
testcase{"Hp", func() bool { return monster.Hp() == 80 }},
testcase{"Mana", func() bool { return monster.Mana() == 150 }},
testcase{"Testbool", func() bool { return monster.Testbool() == true }},
testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(1.0) }},
testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(2.0) }},
testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(3.0) }},
testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(3.0) }},
testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == example.ColorGreen }},
testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(5) }},
testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(6) }},
testcase{"Inventory[2]", func() bool { return monster.Inventory(2) == byte(2) }},
}
testMutability := []testcase{
testcase{"Hp", func() bool { return monster.MutateHp(70) }},
testcase{"Mana", func() bool { return !monster.MutateMana(140) }},
testcase{"Testbool", func() bool { return monster.MutateTestbool(false) }},
testcase{"Pos.X", func() bool { return monster.Pos(nil).MutateX(10.0) }},
testcase{"Pos.Y", func() bool { return monster.Pos(nil).MutateY(20.0) }},
testcase{"Pos.Z", func() bool { return monster.Pos(nil).MutateZ(30.0) }},
testcase{"Pos.Test1", func() bool { return monster.Pos(nil).MutateTest1(30.0) }},
testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(example.ColorBlue) }},
testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).MutateA(50) }},
testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).MutateB(60) }},
testcase{"Inventory[2]", func() bool { return monster.MutateInventory(2, 200) }},
}
testForMutatedValues := []testcase{
testcase{"Hp", func() bool { return monster.Hp() == 70 }},
testcase{"Mana", func() bool { return monster.Mana() == 150 }},
testcase{"Testbool", func() bool { return monster.Testbool() == false }},
testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(10.0) }},
testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(20.0) }},
testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(30.0) }},
testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(30.0) }},
testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == example.ColorBlue }},
testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(50) }},
testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(60) }},
testcase{"Inventory[2]", func() bool { return monster.Inventory(2) == byte(200) }},
}
testInvalidEnumValues := []testcase{
testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(example.Color(20)) }},
testcase{"Pos.Test2", func() bool { return monster.Pos(nil).Test2() == example.Color(20) }},
}
// make sure original values are okay
for _, t := range testForOriginalValues {
if !t.testfn() {
fail("field '" + t.field + "' doesn't have the expected original value")
}
}
// try to mutate fields and check mutability
for _, t := range testMutability {
if !t.testfn() {
fail(FailString("field '"+t.field+"' failed mutability test", true, false))
}
}
// test whether values have changed
for _, t := range testForMutatedValues {
if !t.testfn() {
fail("field '" + t.field + "' doesn't have the expected mutated value")
}
}
// make sure the buffer has changed
if reflect.DeepEqual(buf, org) {
fail("mutate buffer failed")
}
// To make sure the buffer has changed accordingly
// Read data from the buffer and verify all fields
if sizePrefix {
monster = example.GetSizePrefixedRootAsMonster(buf, offset)
} else {
monster = example.GetRootAsMonster(buf, offset)
}
for _, t := range testForMutatedValues {
if !t.testfn() {
fail("field '" + t.field + "' doesn't have the expected mutated value")
}
}
// a couple extra tests for "invalid" enum values, which don't correspond to
// anything in the schema, but are allowed
for _, t := range testInvalidEnumValues {
if !t.testfn() {
fail("field '" + t.field + "' doesn't work with an invalid enum value")
}
}
// reverting all fields to original values should
// re-create the original buffer. Mutate all fields
// back to their original values and compare buffers.
// This test is done to make sure mutations do not do
// any unnecessary changes to the buffer.
if sizePrefix {
monster = example.GetSizePrefixedRootAsMonster(buf, offset)
} else {
monster = example.GetRootAsMonster(buf, offset)
}
monster.MutateHp(80)
monster.MutateTestbool(true)
monster.Pos(nil).MutateX(1.0)
monster.Pos(nil).MutateY(2.0)
monster.Pos(nil).MutateZ(3.0)
monster.Pos(nil).MutateTest1(3.0)
monster.Pos(nil).MutateTest2(example.ColorGreen)
monster.Pos(nil).Test3(nil).MutateA(5)
monster.Pos(nil).Test3(nil).MutateB(6)
monster.MutateInventory(2, 2)
for _, t := range testForOriginalValues {
if !t.testfn() {
fail("field '" + t.field + "' doesn't have the expected original value")
}
}
// buffer should have original values
if !reflect.DeepEqual(buf, org) {
fail("revert changes failed")
}
}
func CheckObjectAPI(buf []byte, offset flatbuffers.UOffsetT, sizePrefix bool, fail func(string, ...interface{})) {
var monster *example.MonsterT
if sizePrefix {
monster = example.GetSizePrefixedRootAsMonster(buf, offset).UnPack()
} else {
monster = example.GetRootAsMonster(buf, offset).UnPack()
}
if got := monster.Hp; 80 != got {
fail(FailString("hp", 80, got))
}
// default
if got := monster.Mana; 150 != got {
fail(FailString("mana", 150, got))
}
builder := flatbuffers.NewBuilder(0)
builder.Finish(monster.Pack(builder))
monster2 := example.GetRootAsMonster(builder.FinishedBytes(), 0).UnPack()
if !reflect.DeepEqual(monster, monster2) {
fail(FailString("Pack/Unpack()", monster, monster2))
}
}
// Low level stress/fuzz test: serialize/deserialize a variety of
// different kinds of data in different combinations
func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) {
// Values we're testing against: chosen to ensure no bits get chopped
// off anywhere, and also be different from eachother.
boolVal := true
int8Val := int8(-127) // 0x81
uint8Val := uint8(0xFF)
int16Val := int16(-32222) // 0x8222
uint16Val := uint16(0xFEEE)
int32Val := int32(overflowingInt32Val)
uint32Val := uint32(0xFDDDDDDD)
int64Val := int64(overflowingInt64Val)
uint64Val := uint64(0xFCCCCCCCCCCCCCCC)
float32Val := float32(3.14159)
float64Val := float64(3.14159265359)
testValuesMax := 11 // hardcoded to the number of scalar types
builder := flatbuffers.NewBuilder(0)
l := NewLCG()
objects := make([]flatbuffers.UOffsetT, fuzzObjects)
// Generate fuzzObjects random objects each consisting of
// fuzzFields fields, each of a random type.
for i := 0; i < fuzzObjects; i++ {
builder.StartObject(fuzzFields)
for f := 0; f < fuzzFields; f++ {
choice := l.Next() % uint32(testValuesMax)
switch choice {
case 0:
builder.PrependBoolSlot(int(f), boolVal, false)
case 1:
builder.PrependInt8Slot(int(f), int8Val, 0)
case 2:
builder.PrependUint8Slot(int(f), uint8Val, 0)
case 3:
builder.PrependInt16Slot(int(f), int16Val, 0)
case 4:
builder.PrependUint16Slot(int(f), uint16Val, 0)
case 5:
builder.PrependInt32Slot(int(f), int32Val, 0)
case 6:
builder.PrependUint32Slot(int(f), uint32Val, 0)
case 7:
builder.PrependInt64Slot(int(f), int64Val, 0)
case 8:
builder.PrependUint64Slot(int(f), uint64Val, 0)
case 9:
builder.PrependFloat32Slot(int(f), float32Val, 0)
case 10:
builder.PrependFloat64Slot(int(f), float64Val, 0)
}
}
off := builder.EndObject()
// store the offset from the end of the builder buffer,
// since it will keep growing:
objects[i] = off
}
// Do some bookkeeping to generate stats on fuzzes:
stats := map[string]int{}
check := func(desc string, want, got interface{}) {
stats[desc]++
if want != got {
fail("%s want %v got %v", desc, want, got)
}
}
l = NewLCG() // Reset.
// Test that all objects we generated are readable and return the
// expected values. We generate random objects in the same order
// so this is deterministic.
for i := 0; i < fuzzObjects; i++ {
table := &flatbuffers.Table{
Bytes: builder.Bytes,
Pos: flatbuffers.UOffsetT(len(builder.Bytes)) - objects[i],
}
for j := 0; j < fuzzFields; j++ {
f := flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + j) * flatbuffers.SizeVOffsetT)
choice := l.Next() % uint32(testValuesMax)
switch choice {
case 0:
check("bool", boolVal, table.GetBoolSlot(f, false))
case 1:
check("int8", int8Val, table.GetInt8Slot(f, 0))
case 2:
check("uint8", uint8Val, table.GetUint8Slot(f, 0))
case 3:
check("int16", int16Val, table.GetInt16Slot(f, 0))
case 4:
check("uint16", uint16Val, table.GetUint16Slot(f, 0))
case 5:
check("int32", int32Val, table.GetInt32Slot(f, 0))
case 6:
check("uint32", uint32Val, table.GetUint32Slot(f, 0))
case 7:
check("int64", int64Val, table.GetInt64Slot(f, 0))
case 8:
check("uint64", uint64Val, table.GetUint64Slot(f, 0))
case 9:
check("float32", float32Val, table.GetFloat32Slot(f, 0))
case 10:
check("float64", float64Val, table.GetFloat64Slot(f, 0))
}
}
}
// If enough checks were made, verify that all scalar types were used:
if fuzzFields*fuzzObjects >= testValuesMax {
if len(stats) != testValuesMax {
fail("fuzzing failed to test all scalar types")
}
}
// Print some counts, if needed:
if testing.Verbose() {
if fuzzFields == 0 || fuzzObjects == 0 {
fmt.Printf("fuzz\tfields: %d\tobjects: %d\t[none]\t%d\n",
fuzzFields, fuzzObjects, 0)
} else {
keys := make([]string, 0, len(stats))
for k := range stats {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("fuzz\tfields: %d\tobjects: %d\t%s\t%d\n",
fuzzFields, fuzzObjects, k, stats[k])
}
}
}
return
}
// FailString makes a message for when expectations differ from reality.
func FailString(name string, want, got interface{}) string {
return fmt.Sprintf("bad %s: want %#v got %#v", name, want, got)
}
// CheckByteLayout verifies the bytes of a Builder in various scenarios.
func CheckByteLayout(fail func(string, ...interface{})) {
var b *flatbuffers.Builder
var i int
check := func(want []byte) {
i++
got := b.Bytes[b.Head():]
if !bytes.Equal(want, got) {
fail("case %d: want\n%v\nbut got\n%v\n", i, want, got)
}
}
// test 1: numbers
b = flatbuffers.NewBuilder(0)
check([]byte{})
b.PrependBool(true)
check([]byte{1})
b.PrependInt8(-127)
check([]byte{129, 1})
b.PrependUint8(255)
check([]byte{255, 129, 1})
b.PrependInt16(-32222)
check([]byte{0x22, 0x82, 0, 255, 129, 1}) // first pad
b.PrependUint16(0xFEEE)
check([]byte{0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1}) // no pad this time
b.PrependInt32(-53687092)
check([]byte{204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1})
b.PrependUint32(0x98765432)
check([]byte{0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1})
// test 1b: numbers 2
b = flatbuffers.NewBuilder(0)
b.PrependUint64(0x1122334455667788)
check([]byte{0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11})
// test 2: 1xbyte vector
b = flatbuffers.NewBuilder(0)
check([]byte{})
b.StartVector(flatbuffers.SizeByte, 1, 1)
check([]byte{0, 0, 0}) // align to 4bytes
b.PrependByte(1)
check([]byte{1, 0, 0, 0})
b.EndVector(1)
check([]byte{1, 0, 0, 0, 1, 0, 0, 0}) // padding
// test 3: 2xbyte vector
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeByte, 2, 1)
check([]byte{0, 0}) // align to 4bytes
b.PrependByte(1)
check([]byte{1, 0, 0})
b.PrependByte(2)
check([]byte{2, 1, 0, 0})
b.EndVector(2)
check([]byte{2, 0, 0, 0, 2, 1, 0, 0}) // padding
// test 3b: 11xbyte vector matches builder size
b = flatbuffers.NewBuilder(12)
b.StartVector(flatbuffers.SizeByte, 8, 1)
start := []byte{}
check(start)
for i := 1; i < 12; i++ {
b.PrependByte(byte(i))
start = append([]byte{byte(i)}, start...)
check(start)
}
b.EndVector(8)
check(append([]byte{8, 0, 0, 0}, start...))
// test 4: 1xuint16 vector
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeUint16, 1, 1)
check([]byte{0, 0}) // align to 4bytes
b.PrependUint16(1)
check([]byte{1, 0, 0, 0})
b.EndVector(1)
check([]byte{1, 0, 0, 0, 1, 0, 0, 0}) // padding
// test 5: 2xuint16 vector
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeUint16, 2, 1)
check([]byte{}) // align to 4bytes
b.PrependUint16(0xABCD)
check([]byte{0xCD, 0xAB})
b.PrependUint16(0xDCBA)
check([]byte{0xBA, 0xDC, 0xCD, 0xAB})
b.EndVector(2)
check([]byte{2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB})
// test 6: CreateString
b = flatbuffers.NewBuilder(0)
b.CreateString("foo")
check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad
b.CreateString("moop")
check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad
3, 0, 0, 0, 'f', 'o', 'o', 0})
// test 6b: CreateString unicode
b = flatbuffers.NewBuilder(0)
// These characters are chinese from blog.golang.org/strings
// We use escape codes here so that editors without unicode support
// aren't bothered:
uni_str := "\u65e5\u672c\u8a9e"
b.CreateString(uni_str)
check([]byte{9, 0, 0, 0, 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // null-terminated, 2-byte pad
0, 0})
// test 6c: CreateByteString
b = flatbuffers.NewBuilder(0)
b.CreateByteString([]byte("foo"))
check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad
b.CreateByteString([]byte("moop"))
check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad
3, 0, 0, 0, 'f', 'o', 'o', 0})
// test 7: empty vtable
b = flatbuffers.NewBuilder(0)
b.StartObject(0)
check([]byte{})
b.EndObject()
check([]byte{4, 0, 4, 0, 4, 0, 0, 0})
// test 8: vtable with one true bool
b = flatbuffers.NewBuilder(0)
check([]byte{})
b.StartObject(1)
check([]byte{})
b.PrependBoolSlot(0, true, false)
b.EndObject()
check([]byte{
6, 0, // vtable bytes
8, 0, // length of object including vtable offset
7, 0, // start of bool value
6, 0, 0, 0, // offset for start of vtable (int32)
0, 0, 0, // padded to 4 bytes
1, // bool value
})
// test 9: vtable with one default bool
b = flatbuffers.NewBuilder(0)
check([]byte{})
b.StartObject(1)
check([]byte{})
b.PrependBoolSlot(0, false, false)
b.EndObject()
check([]byte{
4, 0, // vtable bytes
4, 0, // end of object from here
// entry 1 is zero and not stored.
4, 0, 0, 0, // offset for start of vtable (int32)
})
// test 10: vtable with one int16
b = flatbuffers.NewBuilder(0)
b.StartObject(1)
b.PrependInt16Slot(0, 0x789A, 0)
b.EndObject()
check([]byte{
6, 0, // vtable bytes
8, 0, // end of object from here
6, 0, // offset to value
6, 0, 0, 0, // offset for start of vtable (int32)
0, 0, // padding to 4 bytes
0x9A, 0x78,
})
// test 11: vtable with two int16
b = flatbuffers.NewBuilder(0)
b.StartObject(2)
b.PrependInt16Slot(0, 0x3456, 0)
b.PrependInt16Slot(1, 0x789A, 0)
b.EndObject()
check([]byte{
8, 0, // vtable bytes
8, 0, // end of object from here
6, 0, // offset to value 0
4, 0, // offset to value 1
8, 0, 0, 0, // offset for start of vtable (int32)
0x9A, 0x78, // value 1
0x56, 0x34, // value 0
})
// test 12: vtable with int16 and bool
b = flatbuffers.NewBuilder(0)
b.StartObject(2)
b.PrependInt16Slot(0, 0x3456, 0)
b.PrependBoolSlot(1, true, false)
b.EndObject()
check([]byte{
8, 0, // vtable bytes
8, 0, // end of object from here
6, 0, // offset to value 0
5, 0, // offset to value 1
8, 0, 0, 0, // offset for start of vtable (int32)
0, // padding
1, // value 1
0x56, 0x34, // value 0
})
// test 12: vtable with empty vector
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeByte, 0, 1)
vecend := b.EndVector(0)
b.StartObject(1)
b.PrependUOffsetTSlot(0, vecend, 0)
b.EndObject()
check([]byte{
6, 0, // vtable bytes
8, 0,
4, 0, // offset to vector offset
6, 0, 0, 0, // offset for start of vtable (int32)
4, 0, 0, 0,
0, 0, 0, 0, // length of vector (not in struct)
})
// test 12b: vtable with empty vector of byte and some scalars
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeByte, 0, 1)
vecend = b.EndVector(0)
b.StartObject(2)
b.PrependInt16Slot(0, 55, 0)
b.PrependUOffsetTSlot(1, vecend, 0)
b.EndObject()
check([]byte{
8, 0, // vtable bytes
12, 0,
10, 0, // offset to value 0
4, 0, // offset to vector offset
8, 0, 0, 0, // vtable loc
8, 0, 0, 0, // value 1
0, 0, 55, 0, // value 0
0, 0, 0, 0, // length of vector (not in struct)
})
// test 13: vtable with 1 int16 and 2-vector of int16
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeInt16, 2, 1)
b.PrependInt16(0x1234)
b.PrependInt16(0x5678)
vecend = b.EndVector(2)
b.StartObject(2)
b.PrependUOffsetTSlot(1, vecend, 0)
b.PrependInt16Slot(0, 55, 0)
b.EndObject()
check([]byte{
8, 0, // vtable bytes
12, 0, // length of object
6, 0, // start of value 0 from end of vtable
8, 0, // start of value 1 from end of buffer
8, 0, 0, 0, // offset for start of vtable (int32)
0, 0, // padding
55, 0, // value 0
4, 0, 0, 0, // vector position from here
2, 0, 0, 0, // length of vector (uint32)
0x78, 0x56, // vector value 1
0x34, 0x12, // vector value 0
})
// test 14: vtable with 1 struct of 1 int8, 1 int16, 1 int32
b = flatbuffers.NewBuilder(0)
b.StartObject(1)
b.Prep(4+4+4, 0)
b.PrependInt8(55)
b.Pad(3)
b.PrependInt16(0x1234)
b.Pad(2)
b.PrependInt32(0x12345678)
structStart := b.Offset()
b.PrependStructSlot(0, structStart, 0)
b.EndObject()
check([]byte{
6, 0, // vtable bytes
16, 0, // end of object from here
4, 0, // start of struct from here
6, 0, 0, 0, // offset for start of vtable (int32)
0x78, 0x56, 0x34, 0x12, // value 2
0, 0, // padding
0x34, 0x12, // value 1
0, 0, 0, // padding
55, // value 0
})
// test 15: vtable with 1 vector of 2 struct of 2 int8
b = flatbuffers.NewBuilder(0)
b.StartVector(flatbuffers.SizeInt8*2, 2, 1)
b.PrependInt8(33)
b.PrependInt8(44)
b.PrependInt8(55)
b.PrependInt8(66)
vecend = b.EndVector(2)
b.StartObject(1)
b.PrependUOffsetTSlot(0, vecend, 0)
b.EndObject()
check([]byte{
6, 0, // vtable bytes
8, 0,
4, 0, // offset of vector offset
6, 0, 0, 0, // offset for start of vtable (int32)
4, 0, 0, 0, // vector start offset
2, 0, 0, 0, // vector length
66, // vector value 1,1
55, // vector value 1,0
44, // vector value 0,1
33, // vector value 0,0
})
// test 16: table with some elements
b = flatbuffers.NewBuilder(0)
b.StartObject(2)
b.PrependInt8Slot(0, 33, 0)
b.PrependInt16Slot(1, 66, 0)
off := b.EndObject()
b.Finish(off)
check([]byte{
12, 0, 0, 0, // root of table: points to vtable offset
8, 0, // vtable bytes
8, 0, // end of object from here
7, 0, // start of value 0
4, 0, // start of value 1
8, 0, 0, 0, // offset for start of vtable (int32)
66, 0, // value 1
0, // padding
33, // value 0
})
// test 17: one unfinished table and one finished table
b = flatbuffers.NewBuilder(0)
b.StartObject(2)
b.PrependInt8Slot(0, 33, 0)
b.PrependInt8Slot(1, 44, 0)
off = b.EndObject()
b.Finish(off)
b.StartObject(3)
b.PrependInt8Slot(0, 55, 0)
b.PrependInt8Slot(1, 66, 0)
b.PrependInt8Slot(2, 77, 0)
off = b.EndObject()
b.Finish(off)
check([]byte{
16, 0, 0, 0, // root of table: points to object
0, 0, // padding
10, 0, // vtable bytes
8, 0, // size of object
7, 0, // start of value 0
6, 0, // start of value 1
5, 0, // start of value 2
10, 0, 0, 0, // offset for start of vtable (int32)
0, // padding
77, // value 2
66, // value 1
55, // value 0
12, 0, 0, 0, // root of table: points to object
8, 0, // vtable bytes
8, 0, // size of object
7, 0, // start of value 0
6, 0, // start of value 1
8, 0, 0, 0, // offset for start of vtable (int32)
0, 0, // padding
44, // value 1
33, // value 0
})
// test 18: a bunch of bools
b = flatbuffers.NewBuilder(0)
b.StartObject(8)
b.PrependBoolSlot(0, true, false)
b.PrependBoolSlot(1, true, false)
b.PrependBoolSlot(2, true, false)
b.PrependBoolSlot(3, true, false)
b.PrependBoolSlot(4, true, false)
b.PrependBoolSlot(5, true, false)
b.PrependBoolSlot(6, true, false)
b.PrependBoolSlot(7, true, false)
off = b.EndObject()
b.Finish(off)
check([]byte{
24, 0, 0, 0, // root of table: points to vtable offset
20, 0, // vtable bytes
12, 0, // size of object
11, 0, // start of value 0
10, 0, // start of value 1
9, 0, // start of value 2
8, 0, // start of value 3
7, 0, // start of value 4
6, 0, // start of value 5
5, 0, // start of value 6
4, 0, // start of value 7
20, 0, 0, 0, // vtable offset
1, // value 7
1, // value 6
1, // value 5
1, // value 4
1, // value 3
1, // value 2
1, // value 1
1, // value 0
})
// test 19: three bools
b = flatbuffers.NewBuilder(0)
b.StartObject(3)
b.PrependBoolSlot(0, true, false)
b.PrependBoolSlot(1, true, false)
b.PrependBoolSlot(2, true, false)
off = b.EndObject()
b.Finish(off)
check([]byte{
16, 0, 0, 0, // root of table: points to vtable offset
0, 0, // padding
10, 0, // vtable bytes
8, 0, // size of object
7, 0, // start of value 0
6, 0, // start of value 1
5, 0, // start of value 2
10, 0, 0, 0, // vtable offset from here
0, // padding
1, // value 2
1, // value 1
1, // value 0
})
// test 20: some floats
b = flatbuffers.NewBuilder(0)
b.StartObject(1)
b.PrependFloat32Slot(0, 1.0, 0.0)
off = b.EndObject()
check([]byte{
6, 0, // vtable bytes
8, 0, // size of object
4, 0, // start of value 0
6, 0, 0, 0, // vtable offset
0, 0, 128, 63, // value 0
})
}
// CheckManualBuild builds a Monster manually.
func CheckManualBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) {
b := flatbuffers.NewBuilder(0)
str := b.CreateString("MyMonster")
b.StartVector(1, 5, 1)
b.PrependByte(4)
b.PrependByte(3)
b.PrependByte(2)
b.PrependByte(1)
b.PrependByte(0)
inv := b.EndVector(5)
b.StartObject(13)
b.PrependInt16Slot(2, 20, 100)
mon2 := b.EndObject()
// Test4Vector
b.StartVector(4, 2, 1)
// Test 0
b.Prep(2, 4)
b.Pad(1)
b.PlaceInt8(20)
b.PlaceInt16(10)
// Test 1
b.Prep(2, 4)
b.Pad(1)
b.PlaceInt8(40)
b.PlaceInt16(30)
// end testvector
test4 := b.EndVector(2)
b.StartObject(13)
// a vec3
b.Prep(16, 32)
b.Pad(2)
b.Prep(2, 4)
b.Pad(1)
b.PlaceByte(6)
b.PlaceInt16(5)
b.Pad(1)
b.PlaceByte(4)
b.PlaceFloat64(3.0)
b.Pad(4)
b.PlaceFloat32(3.0)
b.PlaceFloat32(2.0)
b.PlaceFloat32(1.0)
vec3Loc := b.Offset()
// end vec3
b.PrependStructSlot(0, vec3Loc, 0) // vec3. noop
b.PrependInt16Slot(2, 80, 100) // hp
b.PrependUOffsetTSlot(3, str, 0)
b.PrependUOffsetTSlot(5, inv, 0) // inventory
b.PrependByteSlot(7, 1, 0)
b.PrependUOffsetTSlot(8, mon2, 0)
b.PrependUOffsetTSlot(9, test4, 0)
mon := b.EndObject()
b.Finish(mon)
return b.Bytes, b.Head()
}
func CheckGetRootAsForNonRootTable(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
str := b.CreateString("MyStat")
example.StatStart(b)
example.StatAddId(b, str)
example.StatAddVal(b, 12345678)
example.StatAddCount(b, 12345)
stat_end := example.StatEnd(b)
b.Finish(stat_end)
stat := example.GetRootAsStat(b.Bytes, b.Head())
if got := stat.Id(); !bytes.Equal([]byte("MyStat"), got) {
fail(FailString("stat.Id()", "MyStat", got))
}
if got := stat.Val(); 12345678 != got {
fail(FailString("stat.Val()", 12345678, got))
}
if got := stat.Count(); 12345 != got {
fail(FailString("stat.Count()", 12345, got))
}
}
// CheckGeneratedBuild uses generated code to build the example Monster.
func CheckGeneratedBuild(sizePrefix bool, fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) {
b := flatbuffers.NewBuilder(0)
str := b.CreateString("MyMonster")
test1 := b.CreateString("test1")
test2 := b.CreateString("test2")
fred := b.CreateString("Fred")
example.MonsterStartInventoryVector(b, 5)
b.PrependByte(4)
b.PrependByte(3)
b.PrependByte(2)
b.PrependByte(1)
b.PrependByte(0)
inv := b.EndVector(5)
example.MonsterStart(b)
example.MonsterAddName(b, fred)
mon2 := example.MonsterEnd(b)
example.MonsterStartTest4Vector(b, 2)
example.CreateTest(b, 10, 20)
example.CreateTest(b, 30, 40)
test4 := b.EndVector(2)
example.MonsterStartTestarrayofstringVector(b, 2)
b.PrependUOffsetT(test2)
b.PrependUOffsetT(test1)
testArrayOfString := b.EndVector(2)
example.MonsterStart(b)
pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, example.ColorGreen, 5, 6)
example.MonsterAddPos(b, pos)
example.MonsterAddHp(b, 80)
example.MonsterAddName(b, str)
example.MonsterAddTestbool(b, true)
example.MonsterAddInventory(b, inv)
example.MonsterAddTestType(b, 1)
example.MonsterAddTest(b, mon2)
example.MonsterAddTest4(b, test4)
example.MonsterAddTestarrayofstring(b, testArrayOfString)
mon := example.MonsterEnd(b)
if sizePrefix {
b.FinishSizePrefixed(mon)
} else {
b.Finish(mon)
}
return b.Bytes, b.Head()
}
// CheckTableAccessors checks that the table accessors work as expected.
func CheckTableAccessors(fail func(string, ...interface{})) {
// test struct accessor
b := flatbuffers.NewBuilder(0)
pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 4, 5, 6)
b.Finish(pos)
vec3Bytes := b.FinishedBytes()
vec3 := &example.Vec3{}
flatbuffers.GetRootAs(vec3Bytes, 0, vec3)
if bytes.Compare(vec3Bytes, vec3.Table().Bytes) != 0 {
fail("invalid vec3 table")
}
// test table accessor
b = flatbuffers.NewBuilder(0)
str := b.CreateString("MyStat")
example.StatStart(b)
example.StatAddId(b, str)
example.StatAddVal(b, 12345678)
example.StatAddCount(b, 12345)
pos = example.StatEnd(b)
b.Finish(pos)
statBytes := b.FinishedBytes()
stat := &example.Stat{}
flatbuffers.GetRootAs(statBytes, 0, stat)
if bytes.Compare(statBytes, stat.Table().Bytes) != 0 {
fail("invalid stat table")
}
}
// CheckVtableDeduplication verifies that vtables are deduplicated.
func CheckVtableDeduplication(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
b.StartObject(4)
b.PrependByteSlot(0, 0, 0)
b.PrependByteSlot(1, 11, 0)
b.PrependByteSlot(2, 22, 0)
b.PrependInt16Slot(3, 33, 0)
obj0 := b.EndObject()
b.StartObject(4)
b.PrependByteSlot(0, 0, 0)
b.PrependByteSlot(1, 44, 0)
b.PrependByteSlot(2, 55, 0)
b.PrependInt16Slot(3, 66, 0)
obj1 := b.EndObject()
b.StartObject(4)
b.PrependByteSlot(0, 0, 0)
b.PrependByteSlot(1, 77, 0)
b.PrependByteSlot(2, 88, 0)
b.PrependInt16Slot(3, 99, 0)
obj2 := b.EndObject()
got := b.Bytes[b.Head():]
want := []byte{
240, 255, 255, 255, // == -12. offset to dedupped vtable.
99, 0,
88,
77,
248, 255, 255, 255, // == -8. offset to dedupped vtable.
66, 0,
55,
44,
12, 0,
8, 0,
0, 0,
7, 0,
6, 0,
4, 0,
12, 0, 0, 0,
33, 0,
22,
11,
}
if !bytes.Equal(want, got) {
fail("testVtableDeduplication want:\n%d %v\nbut got:\n%d %v\n",
len(want), want, len(got), got)
}
table0 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj0}
table1 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj1}
table2 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj2}
testTable := func(tab *flatbuffers.Table, a flatbuffers.VOffsetT, b, c, d byte) {
// vtable size
if got := tab.GetVOffsetTSlot(0, 0); 12 != got {
fail("failed 0, 0: %d", got)
}
// object size
if got := tab.GetVOffsetTSlot(2, 0); 8 != got {
fail("failed 2, 0: %d", got)
}
// default value
if got := tab.GetVOffsetTSlot(4, 0); a != got {
fail("failed 4, 0: %d", got)
}
if got := tab.GetByteSlot(6, 0); b != got {
fail("failed 6, 0: %d", got)
}
if val := tab.GetByteSlot(8, 0); c != val {
fail("failed 8, 0: %d", got)
}
if got := tab.GetByteSlot(10, 0); d != got {
fail("failed 10, 0: %d", got)
}
}
testTable(table0, 0, 11, 22, 33)
testTable(table1, 0, 44, 55, 66)
testTable(table2, 0, 77, 88, 99)
}
// CheckNotInObjectError verifies that `EndObject` fails if not inside an
// object.
func CheckNotInObjectError(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
defer func() {
r := recover()
if r == nil {
fail("expected panic in CheckNotInObjectError")
}
}()
b.EndObject()
}
// CheckStringIsNestedError verifies that a string can not be created inside
// another object.
func CheckStringIsNestedError(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
b.StartObject(0)
defer func() {
r := recover()
if r == nil {
fail("expected panic in CheckStringIsNestedError")
}
}()
b.CreateString("foo")
}
func CheckEmptiedBuilder(fail func(string, ...interface{})) {
f := func(a, b string) bool {
if a == b {
return true
}
builder := flatbuffers.NewBuilder(0)
a1 := builder.CreateSharedString(a)
b1 := builder.CreateSharedString(b)
builder.Reset()
b2 := builder.CreateSharedString(b)
a2 := builder.CreateSharedString(a)
return !(a1 == a2 || b1 == b2)
}
if err := quick.Check(f, nil); err != nil {
fail("expected different offset")
}
}
func CheckSharedStrings(fail func(string, ...interface{})) {
f := func(strings []string) bool {
b := flatbuffers.NewBuilder(0)
for _, s1 := range strings {
for _, s2 := range strings {
off1 := b.CreateSharedString(s1)
off2 := b.CreateSharedString(s2)
if (s1 == s2) && (off1 != off2) {
return false
}
if (s1 != s2) && (off1 == off2) {
return false
}
}
}
return true
}
if err := quick.Check(f, nil); err != nil {
fail("expected same offset")
}
}
// CheckByteStringIsNestedError verifies that a bytestring can not be created
// inside another object.
func CheckByteStringIsNestedError(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
b.StartObject(0)
defer func() {
r := recover()
if r == nil {
fail("expected panic in CheckByteStringIsNestedError")
}
}()
b.CreateByteString([]byte("foo"))
}
// CheckStructIsNotInlineError verifies that writing a struct in a location
// away from where it is used will cause a panic.
func CheckStructIsNotInlineError(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
b.StartObject(0)
defer func() {
r := recover()
if r == nil {
fail("expected panic in CheckStructIsNotInlineError")
}
}()
b.PrependStructSlot(0, 1, 0)
}
// CheckFinishedBytesError verifies that `FinishedBytes` panics if the table
// is not finished.
func CheckFinishedBytesError(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
defer func() {
r := recover()
if r == nil {
fail("expected panic in CheckFinishedBytesError")
}
}()
b.FinishedBytes()
}
// CheckEnumNames checks that the generated enum names are correct.
func CheckEnumNames(fail func(string, ...interface{})) {
{
want := map[example.Any]string{
example.AnyNONE: "NONE",
example.AnyMonster: "Monster",
example.AnyTestSimpleTableWithEnum: "TestSimpleTableWithEnum",
example.AnyMyGame_Example2_Monster: "MyGame_Example2_Monster",
}
got := example.EnumNamesAny
if !reflect.DeepEqual(got, want) {
fail("enum name is not equal")
}
}
{
want := map[example.Color]string{
example.ColorRed: "Red",
example.ColorGreen: "Green",
example.ColorBlue: "Blue",
}
got := example.EnumNamesColor
if !reflect.DeepEqual(got, want) {
fail("enum name is not equal")
}
}
}
// CheckEnumString checks the String method on generated enum types.
func CheckEnumString(fail func(string, ...interface{})) {
if got := example.AnyMonster.String(); got != "Monster" {
fail("Monster.String: %q != %q", got, "Monster")
}
if got := fmt.Sprintf("color: %s", example.ColorGreen); got != "color: Green" {
fail("color.String: %q != %q", got, "color: Green")
}
}
// CheckEnumValues checks that the generated enum values maps are correct.
func CheckEnumValues(fail func(string, ...interface{})) {
{
want := map[string]example.Any{
"NONE": example.AnyNONE,
"Monster": example.AnyMonster,
"TestSimpleTableWithEnum": example.AnyTestSimpleTableWithEnum,
"MyGame_Example2_Monster": example.AnyMyGame_Example2_Monster,
}
got := example.EnumValuesAny
if !reflect.DeepEqual(got, want) {
fail("enum name is not equal")
}
}
{
want := map[string]example.Color{
"Red": example.ColorRed,
"Green": example.ColorGreen,
"Blue": example.ColorBlue,
}
got := example.EnumValuesColor
if !reflect.DeepEqual(got, want) {
fail("enum name is not equal")
}
}
}
// CheckDocExample checks that the code given in FlatBuffers documentation
// is syntactically correct.
func CheckDocExample(buf []byte, off flatbuffers.UOffsetT, fail func(string, ...interface{})) {
monster := example.GetRootAsMonster(buf, off)
_ = monster.Hp()
_ = monster.Pos(nil)
for i := 0; i < monster.InventoryLength(); i++ {
_ = monster.Inventory(i) // do something here
}
builder := flatbuffers.NewBuilder(0)
example.MonsterStartInventoryVector(builder, 5)
for i := 4; i >= 0; i-- {
builder.PrependByte(byte(i))
}
inv := builder.EndVector(5)
str := builder.CreateString("MyMonster")
example.MonsterStart(builder)
example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, example.Color(4), 5, 6))
example.MonsterAddHp(builder, 80)
example.MonsterAddName(builder, str)
example.MonsterAddInventory(builder, inv)
example.MonsterAddTestType(builder, 1)
example.MonsterAddColor(builder, example.ColorRed)
// example.MonsterAddTest(builder, mon2)
// example.MonsterAddTest4(builder, test4s)
_ = example.MonsterEnd(builder)
}
func CheckCreateByteVector(fail func(string, ...interface{})) {
raw := [30]byte{}
for i := 0; i < len(raw); i++ {
raw[i] = byte(i)
}
for size := 0; size < len(raw); size++ {
b1 := flatbuffers.NewBuilder(0)
b2 := flatbuffers.NewBuilder(0)
b1.StartVector(1, size, 1)
for i := size - 1; i >= 0; i-- {
b1.PrependByte(raw[i])
}
b1.EndVector(size)
b2.CreateByteVector(raw[:size])
CheckByteEquality(b1.Bytes, b2.Bytes, fail)
}
}
func CheckParentNamespace(fail func(string, ...interface{})) {
var empty, nonempty []byte
// create monster with an empty parent namespace field
{
builder := flatbuffers.NewBuilder(0)
example.MonsterStart(builder)
m := example.MonsterEnd(builder)
builder.Finish(m)
empty = make([]byte, len(builder.FinishedBytes()))
copy(empty, builder.FinishedBytes())
}
// create monster with a non-empty parent namespace field
{
builder := flatbuffers.NewBuilder(0)
mygame.InParentNamespaceStart(builder)
pn := mygame.InParentNamespaceEnd(builder)
example.MonsterStart(builder)
example.MonsterAddParentNamespaceTest(builder, pn)
m := example.MonsterEnd(builder)
builder.Finish(m)
nonempty = make([]byte, len(builder.FinishedBytes()))
copy(nonempty, builder.FinishedBytes())
}
// read monster with empty parent namespace field
{
m := example.GetRootAsMonster(empty, 0)
if m.ParentNamespaceTest(nil) != nil {
fail("expected nil ParentNamespaceTest for empty field")
}
}
// read monster with non-empty parent namespace field
{
m := example.GetRootAsMonster(nonempty, 0)
if m.ParentNamespaceTest(nil) == nil {
fail("expected non-nil ParentNamespaceTest for non-empty field")
}
}
}
func CheckSizePrefixedBuffer(fail func(string, ...interface{})) {
// Generate a size-prefixed flatbuffer
generated, off := CheckGeneratedBuild(true, fail)
// Check that the size prefix is the size of monsterdata_go_wire.mon minus 4
size := flatbuffers.GetSizePrefix(generated, off)
if size != 220 {
fail("mismatch between size prefix and expected size")
}
// Check that the buffer can be used as expected
CheckReadBuffer(generated, off, true, fail)
CheckMutateBuffer(generated, off, true, fail)
CheckObjectAPI(generated, off, true, fail)
// Write generated bfufer out to a file
if err := os.WriteFile(outData+".sp", generated[off:], os.FileMode(0644)); err != nil {
fail("failed to write file: %s", err)
}
}
// Include simple random number generator to ensure results will be the
// same cross platform.
// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
type LCG uint32
const InitialLCGSeed = 48271
func NewLCG() *LCG {
n := uint32(InitialLCGSeed)
l := LCG(n)
return &l
}
func (lcg *LCG) Reset() {
*lcg = InitialLCGSeed
}
func (lcg *LCG) Next() uint32 {
n := uint32((uint64(*lcg) * uint64(279470273)) % uint64(4294967291))
*lcg = LCG(n)
return n
}
// CheckByteEquality verifies that two byte buffers are the same.
func CheckByteEquality(a, b []byte, fail func(string, ...interface{})) {
if !bytes.Equal(a, b) {
fail("objects are not byte-wise equal")
}
}
// CheckMutateMethods checks all mutate methods one by one
func CheckMutateMethods(fail func(string, ...interface{})) {
b := flatbuffers.NewBuilder(0)
b.StartObject(15)
b.PrependBoolSlot(0, true, false)
b.PrependByteSlot(1, 1, 0)
b.PrependUint8Slot(2, 2, 0)
b.PrependUint16Slot(3, 3, 0)
b.PrependUint32Slot(4, 4, 0)
b.PrependUint64Slot(5, 5, 0)
b.PrependInt8Slot(6, 6, 0)
b.PrependInt16Slot(7, 7, 0)
b.PrependInt32Slot(8, 8, 0)
b.PrependInt64Slot(9, 9, 0)
b.PrependFloat32Slot(10, 10, 0)
b.PrependFloat64Slot(11, 11, 0)
b.PrependUOffsetTSlot(12, 12, 0)
uoVal := b.Offset() - 12
b.PrependVOffsetT(13)
b.Slot(13)
b.PrependSOffsetT(14)
b.Slot(14)
soVal := flatbuffers.SOffsetT(b.Offset() - 14)
offset := b.EndObject()
t := &flatbuffers.Table{
Bytes: b.Bytes,
Pos: flatbuffers.UOffsetT(len(b.Bytes)) - offset,
}
calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) {
return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT)
}
calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) {
return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset))
}
type testcase struct {
field string
testfn func() bool
}
testForOriginalValues := []testcase{
testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }},
testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }},
testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }},
testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }},
testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }},
testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }},
testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }},
testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }},
testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }},
testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }},
testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }},
testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }},
testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }},
testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }},
testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }},
}
testMutability := []testcase{
testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }},
testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }},
testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }},
testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }},
testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }},
testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }},
testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }},
testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }},
testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }},
testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }},
testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }},
testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }},
testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }},
testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }},
testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }},
}
testMutabilityWithoutSlot := []testcase{
testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }},
testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }},
testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }},
testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }},
testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }},
testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }},
testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }},
testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }},
testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }},
testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }},
testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }},
testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }},
}
testForMutatedValues := []testcase{
testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }},
testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }},
testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }},
testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }},
testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }},
testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }},
testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }},
testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }},
testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }},
testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }},
testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }},
testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }},
testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }},
testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }},
testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }},
}
// make sure original values are okay
for _, t := range testForOriginalValues {
if !t.testfn() {
fail(t.field + "' field doesn't have the expected original value")
}
}
// try to mutate fields and check mutability
for _, t := range testMutability {
if !t.testfn() {
fail(FailString(t.field+"' field failed mutability test", "passed", "failed"))
}
}
// try to mutate fields and check mutability
// these have wrong slots so should fail
for _, t := range testMutabilityWithoutSlot {
if t.testfn() {
fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed"))
}
}
// test whether values have changed
for _, t := range testForMutatedValues {
if !t.testfn() {
fail(t.field + "' field doesn't have the expected mutated value")
}
}
}
// CheckOptionalScalars verifies against the ScalarStuff schema.
func CheckOptionalScalars(fail func(string, ...interface{})) {
type testCase struct {
what string
result, expect interface{}
}
makeDefaultTestCases := func(s *optional_scalars.ScalarStuff) []testCase {
return []testCase{
{"justI8", s.JustI8(), int8(0)},
{"maybeI8", s.MaybeI8(), (*int8)(nil)},
{"defaultI8", s.DefaultI8(), int8(42)},
{"justU8", s.JustU8(), byte(0)},
{"maybeU8", s.MaybeU8(), (*byte)(nil)},
{"defaultU8", s.DefaultU8(), byte(42)},
{"justI16", s.JustI16(), int16(0)},
{"maybeI16", s.MaybeI16(), (*int16)(nil)},
{"defaultI16", s.DefaultI16(), int16(42)},
{"justU16", s.JustU16(), uint16(0)},
{"maybeU16", s.MaybeU16(), (*uint16)(nil)},
{"defaultU16", s.DefaultU16(), uint16(42)},
{"justI32", s.JustI32(), int32(0)},
{"maybeI32", s.MaybeI32(), (*int32)(nil)},
{"defaultI32", s.DefaultI32(), int32(42)},
{"justU32", s.JustU32(), uint32(0)},
{"maybeU32", s.MaybeU32(), (*uint32)(nil)},
{"defaultU32", s.DefaultU32(), uint32(42)},
{"justI64", s.JustI64(), int64(0)},
{"maybeI64", s.MaybeI64(), (*int64)(nil)},
{"defaultI64", s.DefaultI64(), int64(42)},
{"justU64", s.JustU64(), uint64(0)},
{"maybeU64", s.MaybeU64(), (*uint64)(nil)},
{"defaultU64", s.DefaultU64(), uint64(42)},
{"justF32", s.JustF32(), float32(0)},
{"maybeF32", s.MaybeF32(), (*float32)(nil)},
{"defaultF32", s.DefaultF32(), float32(42)},
{"justF64", s.JustF64(), float64(0)},
{"maybeF64", s.MaybeF64(), (*float64)(nil)},
{"defaultF64", s.DefaultF64(), float64(42)},
{"justBool", s.JustBool(), false},
{"maybeBool", s.MaybeBool(), (*bool)(nil)},
{"defaultBool", s.DefaultBool(), true},
{"justEnum", s.JustEnum(), optional_scalars.OptionalByte(0)},
{"maybeEnum", s.MaybeEnum(), (*optional_scalars.OptionalByte)(nil)},
{"defaultEnum", s.DefaultEnum(), optional_scalars.OptionalByteOne},
}
}
makeAssignedTestCases := func(s *optional_scalars.ScalarStuff) []testCase {
return []testCase{
{"justI8", s.JustI8(), int8(5)},
{"maybeI8", s.MaybeI8(), int8(5)},
{"defaultI8", s.DefaultI8(), int8(5)},
{"justU8", s.JustU8(), byte(6)},
{"maybeU8", s.MaybeU8(), byte(6)},
{"defaultU8", s.DefaultU8(), byte(6)},
{"justI16", s.JustI16(), int16(7)},
{"maybeI16", s.MaybeI16(), int16(7)},
{"defaultI16", s.DefaultI16(), int16(7)},
{"justU16", s.JustU16(), uint16(8)},
{"maybeU16", s.MaybeU16(), uint16(8)},
{"defaultU16", s.DefaultU16(), uint16(8)},
{"justI32", s.JustI32(), int32(9)},
{"maybeI32", s.MaybeI32(), int32(9)},
{"defaultI32", s.DefaultI32(), int32(9)},
{"justU32", s.JustU32(), uint32(10)},
{"maybeU32", s.MaybeU32(), uint32(10)},
{"defaultU32", s.DefaultU32(), uint32(10)},
{"justI64", s.JustI64(), int64(11)},
{"maybeI64", s.MaybeI64(), int64(11)},
{"defaultI64", s.DefaultI64(), int64(11)},
{"justU64", s.JustU64(), uint64(12)},
{"maybeU64", s.MaybeU64(), uint64(12)},
{"defaultU64", s.DefaultU64(), uint64(12)},
{"justF32", s.JustF32(), float32(13)},
{"maybeF32", s.MaybeF32(), float32(13)},
{"defaultF32", s.DefaultF32(), float32(13)},
{"justF64", s.JustF64(), float64(14)},
{"maybeF64", s.MaybeF64(), float64(14)},
{"defaultF64", s.DefaultF64(), float64(14)},
{"justBool", s.JustBool(), true},
{"maybeBool", s.MaybeBool(), true},
{"defaultBool", s.DefaultBool(), false},
{"justEnum", s.JustEnum(), optional_scalars.OptionalByteTwo},
{"maybeEnum", s.MaybeEnum(), optional_scalars.OptionalByteTwo},
{"defaultEnum", s.DefaultEnum(), optional_scalars.OptionalByteTwo},
}
}
resolvePointer := func(v interface{}) interface{} {
switch v := v.(type) {
case *int8:
return *v
case *byte:
return *v
case *int16:
return *v
case *uint16:
return *v
case *int32:
return *v
case *uint32:
return *v
case *int64:
return *v
case *uint64:
return *v
case *float32:
return *v
case *float64:
return *v
case *bool:
return *v
case *optional_scalars.OptionalByte:
return *v
default:
return v
}
}
buildAssignedTable := func(b *flatbuffers.Builder) *optional_scalars.ScalarStuff {
optional_scalars.ScalarStuffStart(b)
optional_scalars.ScalarStuffAddJustI8(b, int8(5))
optional_scalars.ScalarStuffAddMaybeI8(b, int8(5))
optional_scalars.ScalarStuffAddDefaultI8(b, int8(5))
optional_scalars.ScalarStuffAddJustU8(b, byte(6))
optional_scalars.ScalarStuffAddMaybeU8(b, byte(6))
optional_scalars.ScalarStuffAddDefaultU8(b, byte(6))
optional_scalars.ScalarStuffAddJustI16(b, int16(7))
optional_scalars.ScalarStuffAddMaybeI16(b, int16(7))
optional_scalars.ScalarStuffAddDefaultI16(b, int16(7))
optional_scalars.ScalarStuffAddJustU16(b, uint16(8))
optional_scalars.ScalarStuffAddMaybeU16(b, uint16(8))
optional_scalars.ScalarStuffAddDefaultU16(b, uint16(8))
optional_scalars.ScalarStuffAddJustI32(b, int32(9))
optional_scalars.ScalarStuffAddMaybeI32(b, int32(9))
optional_scalars.ScalarStuffAddDefaultI32(b, int32(9))
optional_scalars.ScalarStuffAddJustU32(b, uint32(10))
optional_scalars.ScalarStuffAddMaybeU32(b, uint32(10))
optional_scalars.ScalarStuffAddDefaultU32(b, uint32(10))
optional_scalars.ScalarStuffAddJustI64(b, int64(11))
optional_scalars.ScalarStuffAddMaybeI64(b, int64(11))
optional_scalars.ScalarStuffAddDefaultI64(b, int64(11))
optional_scalars.ScalarStuffAddJustU64(b, uint64(12))
optional_scalars.ScalarStuffAddMaybeU64(b, uint64(12))
optional_scalars.ScalarStuffAddDefaultU64(b, uint64(12))
optional_scalars.ScalarStuffAddJustF32(b, float32(13))
optional_scalars.ScalarStuffAddMaybeF32(b, float32(13))
optional_scalars.ScalarStuffAddDefaultF32(b, float32(13))
optional_scalars.ScalarStuffAddJustF64(b, float64(14))
optional_scalars.ScalarStuffAddMaybeF64(b, float64(14))
optional_scalars.ScalarStuffAddDefaultF64(b, float64(14))
optional_scalars.ScalarStuffAddJustBool(b, true)
optional_scalars.ScalarStuffAddMaybeBool(b, true)
optional_scalars.ScalarStuffAddDefaultBool(b, false)
optional_scalars.ScalarStuffAddJustEnum(b, optional_scalars.OptionalByteTwo)
optional_scalars.ScalarStuffAddMaybeEnum(b, optional_scalars.OptionalByteTwo)
optional_scalars.ScalarStuffAddDefaultEnum(b, optional_scalars.OptionalByteTwo)
b.Finish(optional_scalars.ScalarStuffEnd(b))
return optional_scalars.GetRootAsScalarStuff(b.FinishedBytes(), 0)
}
// test default values
fbb := flatbuffers.NewBuilder(1)
optional_scalars.ScalarStuffStart(fbb)
fbb.Finish(optional_scalars.ScalarStuffEnd(fbb))
ss := optional_scalars.GetRootAsScalarStuff(fbb.FinishedBytes(), 0)
for _, tc := range makeDefaultTestCases(ss) {
if tc.result != tc.expect {
fail(FailString("Default ScalarStuff: "+tc.what, tc.expect, tc.result))
}
}
// test assigned values
fbb.Reset()
ss = buildAssignedTable(fbb)
for _, tc := range makeAssignedTestCases(ss) {
if resolvePointer(tc.result) != tc.expect {
fail(FailString("Assigned ScalarStuff: "+tc.what, tc.expect, tc.result))
}
}
// test native object pack
fbb.Reset()
i8 := int8(5)
u8 := byte(6)
i16 := int16(7)
u16 := uint16(8)
i32 := int32(9)
u32 := uint32(10)
i64 := int64(11)
u64 := uint64(12)
f32 := float32(13)
f64 := float64(14)
b := true
enum := optional_scalars.OptionalByteTwo
obj := optional_scalars.ScalarStuffT{
JustI8: 5,
MaybeI8: &i8,
DefaultI8: 5,
JustU8: 6,
MaybeU8: &u8,
DefaultU8: 6,
JustI16: 7,
MaybeI16: &i16,
DefaultI16: 7,
JustU16: 8,
MaybeU16: &u16,
DefaultU16: 8,
JustI32: 9,
MaybeI32: &i32,
DefaultI32: 9,
JustU32: 10,
MaybeU32: &u32,
DefaultU32: 10,
JustI64: 11,
MaybeI64: &i64,
DefaultI64: 11,
JustU64: 12,
MaybeU64: &u64,
DefaultU64: 12,
JustF32: 13,
MaybeF32: &f32,
DefaultF32: 13,
JustF64: 14,
MaybeF64: &f64,
DefaultF64: 14,
JustBool: true,
MaybeBool: &b,
DefaultBool: false,
JustEnum: optional_scalars.OptionalByteTwo,
MaybeEnum: &enum,
DefaultEnum: optional_scalars.OptionalByteTwo,
}
fbb.Finish(obj.Pack(fbb))
ss = optional_scalars.GetRootAsScalarStuff(fbb.FinishedBytes(), 0)
for _, tc := range makeAssignedTestCases(ss) {
if resolvePointer(tc.result) != tc.expect {
fail(FailString("Native Object ScalarStuff: "+tc.what, tc.expect, tc.result))
}
}
// test native object unpack
fbb.Reset()
ss = buildAssignedTable(fbb)
ss.UnPackTo(&obj)
expectEq := func(what string, a, b interface{}) {
if resolvePointer(a) != b {
fail(FailString("Native Object Unpack ScalarStuff: "+what, b, a))
}
}
expectEq("justI8", obj.JustI8, int8(5))
expectEq("maybeI8", obj.MaybeI8, int8(5))
expectEq("defaultI8", obj.DefaultI8, int8(5))
expectEq("justU8", obj.JustU8, byte(6))
expectEq("maybeU8", obj.MaybeU8, byte(6))
expectEq("defaultU8", obj.DefaultU8, byte(6))
expectEq("justI16", obj.JustI16, int16(7))
expectEq("maybeI16", obj.MaybeI16, int16(7))
expectEq("defaultI16", obj.DefaultI16, int16(7))
expectEq("justU16", obj.JustU16, uint16(8))
expectEq("maybeU16", obj.MaybeU16, uint16(8))
expectEq("defaultU16", obj.DefaultU16, uint16(8))
expectEq("justI32", obj.JustI32, int32(9))
expectEq("maybeI32", obj.MaybeI32, int32(9))
expectEq("defaultI32", obj.DefaultI32, int32(9))
expectEq("justU32", obj.JustU32, uint32(10))
expectEq("maybeU32", obj.MaybeU32, uint32(10))
expectEq("defaultU32", obj.DefaultU32, uint32(10))
expectEq("justI64", obj.JustI64, int64(11))
expectEq("maybeI64", obj.MaybeI64, int64(11))
expectEq("defaultI64", obj.DefaultI64, int64(11))
expectEq("justU64", obj.JustU64, uint64(12))
expectEq("maybeU64", obj.MaybeU64, uint64(12))
expectEq("defaultU64", obj.DefaultU64, uint64(12))
expectEq("justF32", obj.JustF32, float32(13))
expectEq("maybeF32", obj.MaybeF32, float32(13))
expectEq("defaultF32", obj.DefaultF32, float32(13))
expectEq("justF64", obj.JustF64, float64(14))
expectEq("maybeF64", obj.MaybeF64, float64(14))
expectEq("defaultF64", obj.DefaultF64, float64(14))
expectEq("justBool", obj.JustBool, true)
expectEq("maybeBool", obj.MaybeBool, true)
expectEq("defaultBool", obj.DefaultBool, false)
expectEq("justEnum", obj.JustEnum, optional_scalars.OptionalByteTwo)
expectEq("maybeEnum", obj.MaybeEnum, optional_scalars.OptionalByteTwo)
expectEq("defaultEnum", obj.DefaultEnum, optional_scalars.OptionalByteTwo)
}
// BenchmarkVtableDeduplication measures the speed of vtable deduplication
// by creating prePop vtables, then populating b.N objects with a
// different single vtable.
//
// When b.N is large (as in long benchmarks), memory usage may be high.
func BenchmarkVtableDeduplication(b *testing.B) {
prePop := 10
builder := flatbuffers.NewBuilder(0)
// pre-populate some vtables:
for i := 0; i < prePop; i++ {
builder.StartObject(i)
for j := 0; j < i; j++ {
builder.PrependInt16Slot(j, int16(j), 0)
}
builder.EndObject()
}
// benchmark deduplication of a new vtable:
b.ResetTimer()
for i := 0; i < b.N; i++ {
lim := prePop
builder.StartObject(lim)
for j := 0; j < lim; j++ {
builder.PrependInt16Slot(j, int16(j), 0)
}
builder.EndObject()
}
}
// BenchmarkParseGold measures the speed of parsing the 'gold' data
// used throughout this test suite.
func BenchmarkParseGold(b *testing.B) {
buf, offset := CheckGeneratedBuild(false, b.Fatalf)
monster := example.GetRootAsMonster(buf, offset)
// use these to prevent allocations:
reuse_pos := example.Vec3{}
reuse_test3 := example.Test{}
reuse_table2 := flatbuffers.Table{}
reuse_monster2 := example.Monster{}
reuse_test4_0 := example.Test{}
reuse_test4_1 := example.Test{}
b.SetBytes(int64(len(buf[offset:])))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
monster.Hp()
monster.Mana()
name := monster.Name()
_ = name[0]
_ = name[len(name)-1]
monster.Pos(&reuse_pos)
reuse_pos.X()
reuse_pos.Y()
reuse_pos.Z()
reuse_pos.Test1()
reuse_pos.Test2()
reuse_pos.Test3(&reuse_test3)
reuse_test3.A()
reuse_test3.B()
monster.TestType()
monster.Test(&reuse_table2)
reuse_monster2.Init(reuse_table2.Bytes, reuse_table2.Pos)
name2 := reuse_monster2.Name()
_ = name2[0]
_ = name2[len(name2)-1]
monster.InventoryLength()
l := monster.InventoryLength()
for i := 0; i < l; i++ {
monster.Inventory(i)
}
monster.Test4Length()
monster.Test4(&reuse_test4_0, 0)
monster.Test4(&reuse_test4_1, 1)
reuse_test4_0.A()
reuse_test4_0.B()
reuse_test4_1.A()
reuse_test4_1.B()
monster.TestarrayofstringLength()
str0 := monster.Testarrayofstring(0)
_ = str0[0]
_ = str0[len(str0)-1]
str1 := monster.Testarrayofstring(1)
_ = str1[0]
_ = str1[len(str1)-1]
}
}
// BenchmarkBuildGold uses generated code to build the example Monster.
func BenchmarkBuildGold(b *testing.B) {
buf, offset := CheckGeneratedBuild(false, b.Fatalf)
bytes_length := int64(len(buf[offset:]))
reuse_str := "MyMonster"
reuse_test1 := "test1"
reuse_test2 := "test2"
reuse_fred := "Fred"
b.SetBytes(bytes_length)
bldr := flatbuffers.NewBuilder(0)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
bldr.Reset()
str := bldr.CreateString(reuse_str)
test1 := bldr.CreateString(reuse_test1)
test2 := bldr.CreateString(reuse_test2)
fred := bldr.CreateString(reuse_fred)
example.MonsterStartInventoryVector(bldr, 5)
bldr.PrependByte(4)
bldr.PrependByte(3)
bldr.PrependByte(2)
bldr.PrependByte(1)
bldr.PrependByte(0)
inv := bldr.EndVector(5)
example.MonsterStart(bldr)
example.MonsterAddName(bldr, fred)
mon2 := example.MonsterEnd(bldr)
example.MonsterStartTest4Vector(bldr, 2)
example.CreateTest(bldr, 10, 20)
example.CreateTest(bldr, 30, 40)
test4 := bldr.EndVector(2)
example.MonsterStartTestarrayofstringVector(bldr, 2)
bldr.PrependUOffsetT(test2)
bldr.PrependUOffsetT(test1)
testArrayOfString := bldr.EndVector(2)
example.MonsterStart(bldr)
pos := example.CreateVec3(bldr, 1.0, 2.0, 3.0, 3.0, example.ColorGreen, 5, 6)
example.MonsterAddPos(bldr, pos)
example.MonsterAddHp(bldr, 80)
example.MonsterAddName(bldr, str)
example.MonsterAddInventory(bldr, inv)
example.MonsterAddTestType(bldr, 1)
example.MonsterAddTest(bldr, mon2)
example.MonsterAddTest4(bldr, test4)
example.MonsterAddTestarrayofstring(bldr, testArrayOfString)
mon := example.MonsterEnd(bldr)
bldr.Finish(mon)
}
}