// Low level stress/fuzz test: serialize/deserialize a variety of // different kinds of data in different combinations func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) { // Values we're testing against: chosen to ensure no bits get chopped // off anywhere, and also be different from eachother. boolVal := true int8Val := int8(-127) // 0x81 uint8Val := uint8(0xFF) int16Val := int16(-32222) // 0x8222 uint16Val := uint16(0xFEEE) int32Val := int32(overflowingInt32Val) uint32Val := uint32(0xFDDDDDDD) int64Val := int64(overflowingInt64Val) uint64Val := uint64(0xFCCCCCCCCCCCCCCC) float32Val := float32(3.14159) float64Val := float64(3.14159265359) testValuesMax := 11 // hardcoded to the number of scalar types builder := flatbuffers.NewBuilder(0) l := NewLCG() objects := make([]flatbuffers.UOffsetT, fuzzObjects) // Generate fuzzObjects random objects each consisting of // fuzzFields fields, each of a random type. for i := 0; i < fuzzObjects; i++ { builder.StartObject(fuzzFields) for f := 0; f < fuzzFields; f++ { choice := l.Next() % uint32(testValuesMax) switch choice { case 0: builder.PrependBoolSlot(int(f), boolVal, false) case 1: builder.PrependInt8Slot(int(f), int8Val, 0) case 2: builder.PrependUint8Slot(int(f), uint8Val, 0) case 3: builder.PrependInt16Slot(int(f), int16Val, 0) case 4: builder.PrependUint16Slot(int(f), uint16Val, 0) case 5: builder.PrependInt32Slot(int(f), int32Val, 0) case 6: builder.PrependUint32Slot(int(f), uint32Val, 0) case 7: builder.PrependInt64Slot(int(f), int64Val, 0) case 8: builder.PrependUint64Slot(int(f), uint64Val, 0) case 9: builder.PrependFloat32Slot(int(f), float32Val, 0) case 10: builder.PrependFloat64Slot(int(f), float64Val, 0) } } off := builder.EndObject() // store the offset from the end of the builder buffer, // since it will keep growing: objects[i] = off } // Do some bookkeeping to generate stats on fuzzes: stats := map[string]int{} check := func(desc string, want, got interface{}) { stats[desc]++ if want != got { fail("%s want %v got %v", desc, want, got) } } l = NewLCG() // Reset. // Test that all objects we generated are readable and return the // expected values. We generate random objects in the same order // so this is deterministic. for i := 0; i < fuzzObjects; i++ { table := &flatbuffers.Table{ Bytes: builder.Bytes, Pos: flatbuffers.UOffsetT(len(builder.Bytes)) - objects[i], } for j := 0; j < fuzzFields; j++ { f := flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + j) * flatbuffers.SizeVOffsetT) choice := int(l.Next()) % testValuesMax switch choice { case 0: check("bool", boolVal, table.GetBoolSlot(f, false)) case 1: check("int8", int8Val, table.GetInt8Slot(f, 0)) case 2: check("uint8", uint8Val, table.GetUint8Slot(f, 0)) case 3: check("int16", int16Val, table.GetInt16Slot(f, 0)) case 4: check("uint16", uint16Val, table.GetUint16Slot(f, 0)) case 5: check("int32", int32Val, table.GetInt32Slot(f, 0)) case 6: check("uint32", uint32Val, table.GetUint32Slot(f, 0)) case 7: check("int64", int64Val, table.GetInt64Slot(f, 0)) case 8: check("uint64", uint64Val, table.GetUint64Slot(f, 0)) case 9: check("float32", float32Val, table.GetFloat32Slot(f, 0)) case 10: check("float64", float64Val, table.GetFloat64Slot(f, 0)) } } } // If enough checks were made, verify that all scalar types were used: if fuzzFields*fuzzObjects >= testValuesMax { if len(stats) != testValuesMax { fail("fuzzing failed to test all scalar types") } } // Print some counts, if needed: if testing.Verbose() { if fuzzFields == 0 || fuzzObjects == 0 { fmt.Printf("fuzz\tfields: %d\tobjects: %d\t[none]\t%d\n", fuzzFields, fuzzObjects, 0) } else { keys := make([]string, 0, len(stats)) for k := range stats { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Printf("fuzz\tfields: %d\tobjects: %d\t%s\t%d\n", fuzzFields, fuzzObjects, k, stats[k]) } } } return }
// CheckMutateMethods checks all mutate methods one by one func CheckMutateMethods(fail func(string, ...interface{})) { b := flatbuffers.NewBuilder(0) b.StartObject(15) b.PrependBoolSlot(0, true, false) b.PrependByteSlot(1, 1, 0) b.PrependUint8Slot(2, 2, 0) b.PrependUint16Slot(3, 3, 0) b.PrependUint32Slot(4, 4, 0) b.PrependUint64Slot(5, 5, 0) b.PrependInt8Slot(6, 6, 0) b.PrependInt16Slot(7, 7, 0) b.PrependInt32Slot(8, 8, 0) b.PrependInt64Slot(9, 9, 0) b.PrependFloat32Slot(10, 10, 0) b.PrependFloat64Slot(11, 11, 0) b.PrependUOffsetTSlot(12, 12, 0) uoVal := b.Offset() - 12 b.PrependVOffsetT(13) b.Slot(13) b.PrependSOffsetT(14) b.Slot(14) soVal := flatbuffers.SOffsetT(b.Offset() - 14) offset := b.EndObject() t := &flatbuffers.Table{ Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - offset, } calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) { return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT) } calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) { return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset)) } type testcase struct { field string testfn func() bool } testForOriginalValues := []testcase{ testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }}, testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }}, testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }}, testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }}, testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }}, testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }}, testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }}, testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }}, testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }}, testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }}, testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }}, testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }}, testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }}, testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }}, testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }}, } testMutability := []testcase{ testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }}, testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }}, testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }}, testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }}, testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }}, testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }}, testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }}, testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }}, testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }}, testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }}, testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }}, testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }}, testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }}, testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }}, testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }}, } testMutabilityWithoutSlot := []testcase{ testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }}, testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }}, testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }}, testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }}, testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }}, testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }}, testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }}, testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }}, testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }}, testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }}, testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }}, testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }}, } testForMutatedValues := []testcase{ testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }}, testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }}, testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }}, testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }}, testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }}, testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }}, testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }}, testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }}, testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }}, testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }}, testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }}, testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }}, testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }}, testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }}, testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }}, } // make sure original values are okay for _, t := range testForOriginalValues { if !t.testfn() { fail(t.field + "' field doesn't have the expected original value") } } // try to mutate fields and check mutability for _, t := range testMutability { if !t.testfn() { fail(FailString(t.field+"' field failed mutability test", "passed", "failed")) } } // try to mutate fields and check mutability // these have wrong slots so should fail for _, t := range testMutabilityWithoutSlot { if t.testfn() { fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed")) } } // test whether values have changed for _, t := range testForMutatedValues { if !t.testfn() { fail(t.field + "' field doesn't have the expected mutated value") } } }