Go optional scalars (#7104)

* [go] always write required types

* support optional scalars in go

* generate optional_scalars and monster_test

* restore original behavior for non-optional scalars

* add tests
This commit is contained in:
Christopher Crawford
2022-02-16 15:02:54 -05:00
committed by GitHub
parent 57e338f819
commit 06f4af11b6
6 changed files with 1140 additions and 19 deletions

View File

@@ -17,8 +17,9 @@
package main
import (
mygame "MyGame" // refers to generated code
example "MyGame/Example" // refers to generated code
mygame "MyGame" // refers to generated code
example "MyGame/Example" // refers to generated code
optional_scalars "optional_scalars" // refers to generated code
"bytes"
"flag"
@@ -133,6 +134,9 @@ func TestAll(t *testing.T) {
// Check size-prefixed flatbuffers
CheckSizePrefixedBuffer(t.Fatalf)
// Check that optional scalars work
CheckOptionalScalars(t.Fatalf)
// If the filename of the FlatBuffers file generated by the Java test
// is given, check that Go code can read it, and that Go code
// generates an identical buffer when used to create the example data:
@@ -1861,6 +1865,296 @@ func CheckMutateMethods(fail func(string, ...interface{})) {
}
}
// CheckOptionalScalars verifies against the ScalarStuff schema.
func CheckOptionalScalars(fail func(string, ...interface{})) {
type testCase struct {
what string
result, expect interface{}
}
makeDefaultTestCases := func(s *optional_scalars.ScalarStuff) []testCase {
return []testCase{
{"justI8", s.JustI8(), int8(0)},
{"maybeI8", s.MaybeI8(), (*int8)(nil)},
{"defaultI8", s.DefaultI8(), int8(42)},
{"justU8", s.JustU8(), byte(0)},
{"maybeU8", s.MaybeU8(), (*byte)(nil)},
{"defaultU8", s.DefaultU8(), byte(42)},
{"justI16", s.JustI16(), int16(0)},
{"maybeI16", s.MaybeI16(), (*int16)(nil)},
{"defaultI16", s.DefaultI16(), int16(42)},
{"justU16", s.JustU16(), uint16(0)},
{"maybeU16", s.MaybeU16(), (*uint16)(nil)},
{"defaultU16", s.DefaultU16(), uint16(42)},
{"justI32", s.JustI32(), int32(0)},
{"maybeI32", s.MaybeI32(), (*int32)(nil)},
{"defaultI32", s.DefaultI32(), int32(42)},
{"justU32", s.JustU32(), uint32(0)},
{"maybeU32", s.MaybeU32(), (*uint32)(nil)},
{"defaultU32", s.DefaultU32(), uint32(42)},
{"justI64", s.JustI64(), int64(0)},
{"maybeI64", s.MaybeI64(), (*int64)(nil)},
{"defaultI64", s.DefaultI64(), int64(42)},
{"justU64", s.JustU64(), uint64(0)},
{"maybeU64", s.MaybeU64(), (*uint64)(nil)},
{"defaultU64", s.DefaultU64(), uint64(42)},
{"justF32", s.JustF32(), float32(0)},
{"maybeF32", s.MaybeF32(), (*float32)(nil)},
{"defaultF32", s.DefaultF32(), float32(42)},
{"justF64", s.JustF64(), float64(0)},
{"maybeF64", s.MaybeF64(), (*float64)(nil)},
{"defaultF64", s.DefaultF64(), float64(42)},
{"justBool", s.JustBool(), false},
{"maybeBool", s.MaybeBool(), (*bool)(nil)},
{"defaultBool", s.DefaultBool(), true},
{"justEnum", s.JustEnum(), optional_scalars.OptionalByte(0)},
{"maybeEnum", s.MaybeEnum(), (*optional_scalars.OptionalByte)(nil)},
{"defaultEnum", s.DefaultEnum(), optional_scalars.OptionalByteOne},
}
}
makeAssignedTestCases := func(s *optional_scalars.ScalarStuff) []testCase {
return []testCase{
{"justI8", s.JustI8(), int8(5)},
{"maybeI8", s.MaybeI8(), int8(5)},
{"defaultI8", s.DefaultI8(), int8(5)},
{"justU8", s.JustU8(), byte(6)},
{"maybeU8", s.MaybeU8(), byte(6)},
{"defaultU8", s.DefaultU8(), byte(6)},
{"justI16", s.JustI16(), int16(7)},
{"maybeI16", s.MaybeI16(), int16(7)},
{"defaultI16", s.DefaultI16(), int16(7)},
{"justU16", s.JustU16(), uint16(8)},
{"maybeU16", s.MaybeU16(), uint16(8)},
{"defaultU16", s.DefaultU16(), uint16(8)},
{"justI32", s.JustI32(), int32(9)},
{"maybeI32", s.MaybeI32(), int32(9)},
{"defaultI32", s.DefaultI32(), int32(9)},
{"justU32", s.JustU32(), uint32(10)},
{"maybeU32", s.MaybeU32(), uint32(10)},
{"defaultU32", s.DefaultU32(), uint32(10)},
{"justI64", s.JustI64(), int64(11)},
{"maybeI64", s.MaybeI64(), int64(11)},
{"defaultI64", s.DefaultI64(), int64(11)},
{"justU64", s.JustU64(), uint64(12)},
{"maybeU64", s.MaybeU64(), uint64(12)},
{"defaultU64", s.DefaultU64(), uint64(12)},
{"justF32", s.JustF32(), float32(13)},
{"maybeF32", s.MaybeF32(), float32(13)},
{"defaultF32", s.DefaultF32(), float32(13)},
{"justF64", s.JustF64(), float64(14)},
{"maybeF64", s.MaybeF64(), float64(14)},
{"defaultF64", s.DefaultF64(), float64(14)},
{"justBool", s.JustBool(), true},
{"maybeBool", s.MaybeBool(), true},
{"defaultBool", s.DefaultBool(), false},
{"justEnum", s.JustEnum(), optional_scalars.OptionalByteTwo},
{"maybeEnum", s.MaybeEnum(), optional_scalars.OptionalByteTwo},
{"defaultEnum", s.DefaultEnum(), optional_scalars.OptionalByteTwo},
}
}
resolvePointer := func(v interface{}) interface{} {
switch v := v.(type) {
case *int8:
return *v
case *byte:
return *v
case *int16:
return *v
case *uint16:
return *v
case *int32:
return *v
case *uint32:
return *v
case *int64:
return *v
case *uint64:
return *v
case *float32:
return *v
case *float64:
return *v
case *bool:
return *v
case *optional_scalars.OptionalByte:
return *v
default:
return v
}
}
buildAssignedTable := func(b *flatbuffers.Builder) *optional_scalars.ScalarStuff {
optional_scalars.ScalarStuffStart(b)
optional_scalars.ScalarStuffAddJustI8(b, int8(5))
optional_scalars.ScalarStuffAddMaybeI8(b, int8(5))
optional_scalars.ScalarStuffAddDefaultI8(b, int8(5))
optional_scalars.ScalarStuffAddJustU8(b, byte(6))
optional_scalars.ScalarStuffAddMaybeU8(b, byte(6))
optional_scalars.ScalarStuffAddDefaultU8(b, byte(6))
optional_scalars.ScalarStuffAddJustI16(b, int16(7))
optional_scalars.ScalarStuffAddMaybeI16(b, int16(7))
optional_scalars.ScalarStuffAddDefaultI16(b, int16(7))
optional_scalars.ScalarStuffAddJustU16(b, uint16(8))
optional_scalars.ScalarStuffAddMaybeU16(b, uint16(8))
optional_scalars.ScalarStuffAddDefaultU16(b, uint16(8))
optional_scalars.ScalarStuffAddJustI32(b, int32(9))
optional_scalars.ScalarStuffAddMaybeI32(b, int32(9))
optional_scalars.ScalarStuffAddDefaultI32(b, int32(9))
optional_scalars.ScalarStuffAddJustU32(b, uint32(10))
optional_scalars.ScalarStuffAddMaybeU32(b, uint32(10))
optional_scalars.ScalarStuffAddDefaultU32(b, uint32(10))
optional_scalars.ScalarStuffAddJustI64(b, int64(11))
optional_scalars.ScalarStuffAddMaybeI64(b, int64(11))
optional_scalars.ScalarStuffAddDefaultI64(b, int64(11))
optional_scalars.ScalarStuffAddJustU64(b, uint64(12))
optional_scalars.ScalarStuffAddMaybeU64(b, uint64(12))
optional_scalars.ScalarStuffAddDefaultU64(b, uint64(12))
optional_scalars.ScalarStuffAddJustF32(b, float32(13))
optional_scalars.ScalarStuffAddMaybeF32(b, float32(13))
optional_scalars.ScalarStuffAddDefaultF32(b, float32(13))
optional_scalars.ScalarStuffAddJustF64(b, float64(14))
optional_scalars.ScalarStuffAddMaybeF64(b, float64(14))
optional_scalars.ScalarStuffAddDefaultF64(b, float64(14))
optional_scalars.ScalarStuffAddJustBool(b, true)
optional_scalars.ScalarStuffAddMaybeBool(b, true)
optional_scalars.ScalarStuffAddDefaultBool(b, false)
optional_scalars.ScalarStuffAddJustEnum(b, optional_scalars.OptionalByteTwo)
optional_scalars.ScalarStuffAddMaybeEnum(b, optional_scalars.OptionalByteTwo)
optional_scalars.ScalarStuffAddDefaultEnum(b, optional_scalars.OptionalByteTwo)
b.Finish(optional_scalars.ScalarStuffEnd(b))
return optional_scalars.GetRootAsScalarStuff(b.FinishedBytes(), 0)
}
// test default values
fbb := flatbuffers.NewBuilder(1)
optional_scalars.ScalarStuffStart(fbb)
fbb.Finish(optional_scalars.ScalarStuffEnd(fbb))
ss := optional_scalars.GetRootAsScalarStuff(fbb.FinishedBytes(), 0)
for _, tc := range makeDefaultTestCases(ss) {
if tc.result != tc.expect {
fail(FailString("Default ScalarStuff: "+tc.what, tc.expect, tc.result))
}
}
// test assigned values
fbb.Reset()
ss = buildAssignedTable(fbb)
for _, tc := range makeAssignedTestCases(ss) {
if resolvePointer(tc.result) != tc.expect {
fail(FailString("Assigned ScalarStuff: "+tc.what, tc.expect, tc.result))
}
}
// test native object pack
fbb.Reset()
i8 := int8(5)
u8 := byte(6)
i16 := int16(7)
u16 := uint16(8)
i32 := int32(9)
u32 := uint32(10)
i64 := int64(11)
u64 := uint64(12)
f32 := float32(13)
f64 := float64(14)
b := true
enum := optional_scalars.OptionalByteTwo
obj := optional_scalars.ScalarStuffT{
JustI8: 5,
MaybeI8: &i8,
DefaultI8: 5,
JustU8: 6,
MaybeU8: &u8,
DefaultU8: 6,
JustI16: 7,
MaybeI16: &i16,
DefaultI16: 7,
JustU16: 8,
MaybeU16: &u16,
DefaultU16: 8,
JustI32: 9,
MaybeI32: &i32,
DefaultI32: 9,
JustU32: 10,
MaybeU32: &u32,
DefaultU32: 10,
JustI64: 11,
MaybeI64: &i64,
DefaultI64: 11,
JustU64: 12,
MaybeU64: &u64,
DefaultU64: 12,
JustF32: 13,
MaybeF32: &f32,
DefaultF32: 13,
JustF64: 14,
MaybeF64: &f64,
DefaultF64: 14,
JustBool: true,
MaybeBool: &b,
DefaultBool: false,
JustEnum: optional_scalars.OptionalByteTwo,
MaybeEnum: &enum,
DefaultEnum: optional_scalars.OptionalByteTwo,
}
fbb.Finish(obj.Pack(fbb))
ss = optional_scalars.GetRootAsScalarStuff(fbb.FinishedBytes(), 0)
for _, tc := range makeAssignedTestCases(ss) {
if resolvePointer(tc.result) != tc.expect {
fail(FailString("Native Object ScalarStuff: "+tc.what, tc.expect, tc.result))
}
}
// test native object unpack
fbb.Reset()
ss = buildAssignedTable(fbb)
ss.UnPackTo(&obj)
expectEq := func(what string, a, b interface{}) {
if resolvePointer(a) != b {
fail(FailString("Native Object Unpack ScalarStuff: "+what, b, a))
}
}
expectEq("justI8", obj.JustI8, int8(5))
expectEq("maybeI8", obj.MaybeI8, int8(5))
expectEq("defaultI8", obj.DefaultI8, int8(5))
expectEq("justU8", obj.JustU8, byte(6))
expectEq("maybeU8", obj.MaybeU8, byte(6))
expectEq("defaultU8", obj.DefaultU8, byte(6))
expectEq("justI16", obj.JustI16, int16(7))
expectEq("maybeI16", obj.MaybeI16, int16(7))
expectEq("defaultI16", obj.DefaultI16, int16(7))
expectEq("justU16", obj.JustU16, uint16(8))
expectEq("maybeU16", obj.MaybeU16, uint16(8))
expectEq("defaultU16", obj.DefaultU16, uint16(8))
expectEq("justI32", obj.JustI32, int32(9))
expectEq("maybeI32", obj.MaybeI32, int32(9))
expectEq("defaultI32", obj.DefaultI32, int32(9))
expectEq("justU32", obj.JustU32, uint32(10))
expectEq("maybeU32", obj.MaybeU32, uint32(10))
expectEq("defaultU32", obj.DefaultU32, uint32(10))
expectEq("justI64", obj.JustI64, int64(11))
expectEq("maybeI64", obj.MaybeI64, int64(11))
expectEq("defaultI64", obj.DefaultI64, int64(11))
expectEq("justU64", obj.JustU64, uint64(12))
expectEq("maybeU64", obj.MaybeU64, uint64(12))
expectEq("defaultU64", obj.DefaultU64, uint64(12))
expectEq("justF32", obj.JustF32, float32(13))
expectEq("maybeF32", obj.MaybeF32, float32(13))
expectEq("defaultF32", obj.DefaultF32, float32(13))
expectEq("justF64", obj.JustF64, float64(14))
expectEq("maybeF64", obj.MaybeF64, float64(14))
expectEq("defaultF64", obj.DefaultF64, float64(14))
expectEq("justBool", obj.JustBool, true)
expectEq("maybeBool", obj.MaybeBool, true)
expectEq("defaultBool", obj.DefaultBool, false)
expectEq("justEnum", obj.JustEnum, optional_scalars.OptionalByteTwo)
expectEq("maybeEnum", obj.MaybeEnum, optional_scalars.OptionalByteTwo)
expectEq("defaultEnum", obj.DefaultEnum, optional_scalars.OptionalByteTwo)
}
// BenchmarkVtableDeduplication measures the speed of vtable deduplication
// by creating prePop vtables, then populating b.N objects with a
// different single vtable.