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