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