diff --git a/internal/tests/utils/equal.go b/internal/tests/utils/equal.go new file mode 100644 index 000000000..71e48af80 --- /dev/null +++ b/internal/tests/utils/equal.go @@ -0,0 +1,74 @@ +package utils + +import ( + "bytes" + "fmt" + "gopkg.in/inf.v0" + "math/big" + "reflect" + "unsafe" + + "github.com/gocql/gocql/marshal/tests/mod" +) + +func EqualData(in1, in2 []byte) bool { + if in1 == nil || in2 == nil { + return in1 == nil && in2 == nil + } + return bytes.Equal(in1, in2) +} + +func EqualVals(in1, in2 interface{}) bool { + rin1 := reflect.ValueOf(in1) + rin2 := reflect.ValueOf(in2) + if rin1.Kind() != rin2.Kind() { + return false + } + if rin1.Kind() == reflect.Ptr && (rin1.IsNil() || rin2.IsNil()) { + return rin1.IsNil() && rin2.IsNil() + } + + switch vin1 := in1.(type) { + case float32: + vin2 := in2.(float32) + return *(*[4]byte)(unsafe.Pointer(&vin1)) == *(*[4]byte)(unsafe.Pointer(&vin2)) + case *float32: + vin2 := in2.(*float32) + return *(*[4]byte)(unsafe.Pointer(vin1)) == *(*[4]byte)(unsafe.Pointer(vin2)) + case *mod.Float32: + vin2 := in2.(*mod.Float32) + return *(*[4]byte)(unsafe.Pointer(vin1)) == *(*[4]byte)(unsafe.Pointer(vin2)) + case mod.Float32: + vin2 := in2.(mod.Float32) + return *(*[4]byte)(unsafe.Pointer(&vin1)) == *(*[4]byte)(unsafe.Pointer(&vin2)) + case float64: + vin2 := in2.(float64) + return *(*[8]byte)(unsafe.Pointer(&vin1)) == *(*[8]byte)(unsafe.Pointer(&vin2)) + case *float64: + vin2 := in2.(*float64) + return *(*[8]byte)(unsafe.Pointer(vin1)) == *(*[8]byte)(unsafe.Pointer(vin2)) + case *mod.Float64: + vin2 := in2.(*mod.Float64) + return *(*[8]byte)(unsafe.Pointer(vin1)) == *(*[8]byte)(unsafe.Pointer(vin2)) + case mod.Float64: + vin2 := in2.(mod.Float64) + return *(*[8]byte)(unsafe.Pointer(&vin1)) == *(*[8]byte)(unsafe.Pointer(&vin2)) + case big.Int: + vin2 := in2.(big.Int) + return vin1.Cmp(&vin2) == 0 + case *big.Int: + vin2 := in2.(*big.Int) + return vin1.Cmp(vin2) == 0 + case inf.Dec: + vin2 := in2.(inf.Dec) + return vin1.Cmp(&vin2) == 0 + case *inf.Dec: + vin2 := in2.(*inf.Dec) + return vin1.Cmp(vin2) == 0 + case fmt.Stringer: + vin2 := in2.(fmt.Stringer) + return vin1.String() == vin2.String() + default: + return reflect.DeepEqual(in1, in2) + } +} diff --git a/internal/tests/utils/new.go b/internal/tests/utils/new.go new file mode 100644 index 000000000..d2901db01 --- /dev/null +++ b/internal/tests/utils/new.go @@ -0,0 +1,18 @@ +package utils + +import ( + "reflect" +) + +func NewRef(in interface{}) interface{} { + out := reflect.New(reflect.TypeOf(in)).Interface() + return out +} + +func NewRefToZero(in interface{}) interface{} { + rv := reflect.ValueOf(in) + nw := reflect.New(rv.Type().Elem()) + out := reflect.New(rv.Type()) + out.Elem().Set(nw) + return out.Interface() +} diff --git a/internal/tests/utils/panic_err.go b/internal/tests/utils/panic_err.go new file mode 100644 index 000000000..45d27cb9c --- /dev/null +++ b/internal/tests/utils/panic_err.go @@ -0,0 +1,14 @@ +package utils + +import ( + "fmt" +) + +type PanicErr struct { + Err error + Stack []byte +} + +func (e PanicErr) Error() string { + return fmt.Sprintf("%v\n%s", e.Err, e.Stack) +} diff --git a/internal/tests/utils/string.go b/internal/tests/utils/string.go new file mode 100644 index 000000000..8d7712518 --- /dev/null +++ b/internal/tests/utils/string.go @@ -0,0 +1,14 @@ +package utils + +import ( + "fmt" +) + +const printLimit = 100 + +func StringData(p []byte) string { + if len(p) > printLimit { + p = p[:printLimit] + } + return fmt.Sprintf("[%x]", p) +} diff --git a/internal/tests/utils/string_vals.go b/internal/tests/utils/string_vals.go new file mode 100644 index 000000000..73bbf19ee --- /dev/null +++ b/internal/tests/utils/string_vals.go @@ -0,0 +1,52 @@ +package utils + +import ( + "fmt" + "gopkg.in/inf.v0" + "math/big" + "net" + "reflect" + "time" +) + +// StringValue returns (value_type)(value) in the human-readable format. +func StringValue(in interface{}) string { + valStr := stringValue(in) + if len(valStr) > printLimit { + valStr = valStr[:printLimit] + } + return fmt.Sprintf("(%T)(%s)", in, valStr) +} + +func stringValue(in interface{}) string { + switch i := in.(type) { + case string: + return i + case inf.Dec: + return fmt.Sprintf("%v", i.String()) + case big.Int: + return fmt.Sprintf("%v", i.String()) + case net.IP: + return fmt.Sprintf("%v", []byte(i)) + case time.Time: + return fmt.Sprintf("%v", i.UnixMilli()) + case nil: + return "nil" + } + + rv := reflect.ValueOf(in) + switch rv.Kind() { + case reflect.Ptr: + if rv.IsNil() { + return "*nil" + } + return fmt.Sprintf("*%s", stringValue(rv.Elem().Interface())) + case reflect.Slice: + if rv.IsNil() { + return "[nil]" + } + return fmt.Sprintf("%v", rv.Interface()) + default: + return fmt.Sprintf("%v", in) + } +} diff --git a/internal/tests/utils/utils.go b/internal/tests/utils/utils.go new file mode 100644 index 000000000..6b2239b48 --- /dev/null +++ b/internal/tests/utils/utils.go @@ -0,0 +1,23 @@ +package utils + +import ( + "reflect" +) + +func DeReference(in interface{}) interface{} { + return reflect.Indirect(reflect.ValueOf(in)).Interface() +} + +func Reference(val interface{}) interface{} { + out := reflect.New(reflect.TypeOf(val)) + out.Elem().Set(reflect.ValueOf(val)) + return out.Interface() +} + +func GetTypes(values ...interface{}) []reflect.Type { + types := make([]reflect.Type, len(values)) + for i, value := range values { + types[i] = reflect.TypeOf(value) + } + return types +} diff --git a/marshal/tests/mod/all.go b/marshal/tests/mod/all.go new file mode 100644 index 000000000..302374e5b --- /dev/null +++ b/marshal/tests/mod/all.go @@ -0,0 +1,16 @@ +package mod + +var All = []Mod{CustomType, Reference, CustomTypeRef} + +// Mod - value modifiers. +type Mod func(vals ...interface{}) []interface{} + +type Values []interface{} + +func (v Values) AddVariants(mods ...Mod) Values { + out := append(make([]interface{}, 0), v...) + for _, mod := range mods { + out = append(out, mod(v...)...) + } + return out +} diff --git a/marshal/tests/mod/custom.go b/marshal/tests/mod/custom.go new file mode 100644 index 000000000..3a14f8e2a --- /dev/null +++ b/marshal/tests/mod/custom.go @@ -0,0 +1,201 @@ +package mod + +type ( + Bool bool + + Int8 int8 + Int16 int16 + Int32 int32 + Int64 int64 + Int int + + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + Uint uint + + Float32 float32 + Float64 float64 + + String string + + Bytes []byte + Bytes4 [4]byte + Bytes16 [16]byte + + SliceInt16 []int16 + SliceInt16R []*int16 + SliceInt16C []Int16 + SliceInt16CR []*Int16 + SliceAny []interface{} + + Arr1Int16 [1]int16 + Arr1Int16R [1]*int16 + Arr1Int16C [1]Int16 + Arr1Int16CR [1]*Int16 + ArrAny [1]interface{} + + MapInt16 map[int16]int16 + MapInt16R map[int16]*int16 + MapInt16C map[Int16]Int16 + MapInt16CR map[Int16]*Int16 + + MapUDT map[string]interface{} +) + +var CustomType Mod = func(vals ...interface{}) []interface{} { + out := make([]interface{}, 0) + for i := range vals { + if vals[i] == nil { + continue + } + ct := customType(vals[i]) + if ct != nil { + out = append(out, ct) + } + } + return out +} + +func customType(i interface{}) interface{} { + switch v := i.(type) { + case bool: + return Bool(v) + case int8: + return Int8(v) + case int16: + return Int16(v) + case int32: + return Int32(v) + case int64: + return Int64(v) + case int: + return Int(v) + case uint: + return Uint(v) + case uint8: + return Uint8(v) + case uint16: + return Uint16(v) + case uint32: + return Uint32(v) + case uint64: + return Uint64(v) + case float32: + return Float32(v) + case float64: + return Float64(v) + case string: + return String(v) + case []byte: + return Bytes(v) + case [4]byte: + return Bytes4(v) + case [16]byte: + return Bytes16(v) + case []int16: + return SliceInt16(v) + case []*int16: + return SliceInt16R(v) + case []Int16: + return SliceInt16C(v) + case []*Int16: + return SliceInt16CR(v) + case [1]int16: + return Arr1Int16(v) + case [1]*int16: + return Arr1Int16R(v) + case [1]Int16: + return Arr1Int16C(v) + case [1]*Int16: + return Arr1Int16CR(v) + case map[int16]int16: + return MapInt16(v) + case map[int16]*int16: + return MapInt16R(v) + case map[Int16]Int16: + return MapInt16C(v) + case map[Int16]*Int16: + return MapInt16CR(v) + case map[string]interface{}: + return MapUDT(v) + case []interface{}: + return SliceAny(v) + case [1]interface{}: + return ArrAny(v) + default: + return intoCustomR(i) + } +} + +func intoCustomR(i interface{}) interface{} { + switch v := i.(type) { + case *bool: + return (*Bool)(v) + case *int8: + return (*Int8)(v) + case *int16: + return (*Int16)(v) + case *int32: + return (*Int32)(v) + case *int64: + return (*Int64)(v) + case *int: + return (*Int)(v) + case *uint: + return (*Uint)(v) + case *uint8: + return (*Uint8)(v) + case *uint16: + return (*Uint16)(v) + case *uint32: + return (*Uint32)(v) + case *uint64: + return (*Uint64)(v) + case *float32: + return (*Float32)(v) + case *float64: + return (*Float64)(v) + case *string: + return (*String)(v) + case *[]byte: + return (*Bytes)(v) + case *[4]byte: + return (*Bytes4)(v) + case *[16]byte: + return (*Bytes16)(v) + case *[]int16: + return (*SliceInt16)(v) + case *[]*int16: + return (*SliceInt16R)(v) + case *[]Int16: + return (*SliceInt16C)(v) + case *[]*Int16: + return (*SliceInt16CR)(v) + case *[1]int16: + return (*Arr1Int16)(v) + case *[1]*int16: + return (*Arr1Int16R)(v) + case *[1]Int16: + return (*Arr1Int16C)(v) + case *[1]*Int16: + return (*Arr1Int16CR)(v) + case *map[int16]int16: + return (*MapInt16)(v) + case *map[int16]*int16: + return (*MapInt16R)(v) + case *map[Int16]Int16: + return (*MapInt16C)(v) + case *map[Int16]*Int16: + return (*MapInt16CR)(v) + case *map[string]interface{}: + return (*MapUDT)(v) + case *[]interface{}: + return (*SliceAny)(v) + case *[1]interface{}: + return (*ArrAny)(v) + default: + return nil + } +} diff --git a/marshal/tests/mod/custom_refs.go b/marshal/tests/mod/custom_refs.go new file mode 100644 index 000000000..963a1df22 --- /dev/null +++ b/marshal/tests/mod/custom_refs.go @@ -0,0 +1,5 @@ +package mod + +var CustomTypeRef Mod = func(vals ...interface{}) []interface{} { + return Reference(CustomType(vals...)...) +} diff --git a/marshal/tests/mod/refs.go b/marshal/tests/mod/refs.go new file mode 100644 index 000000000..05c50f463 --- /dev/null +++ b/marshal/tests/mod/refs.go @@ -0,0 +1,20 @@ +package mod + +import "reflect" + +var Reference Mod = func(vals ...interface{}) []interface{} { + out := make([]interface{}, 0) + for i := range vals { + if vals[i] != nil { + out = append(out, reference(vals[i])) + } + } + return out +} + +func reference(val interface{}) interface{} { + inV := reflect.ValueOf(val) + out := reflect.New(reflect.TypeOf(val)) + out.Elem().Set(inV) + return out.Interface() +} diff --git a/marshal/tests/serialization/pointers.go b/marshal/tests/serialization/pointers.go new file mode 100644 index 000000000..dc4f69ea4 --- /dev/null +++ b/marshal/tests/serialization/pointers.go @@ -0,0 +1,54 @@ +package serialization + +import ( + "errors" + "reflect" +) + +// ErrFirstPtrChanged this error indicates that a double or single reference was passed to the Unmarshal function +// (example (**int)(**0) or (*int)(*0)) and Unmarshal overwritten first reference. +var ErrFirstPtrChanged = errors.New("unmarshal function rewrote first pointer") + +// ErrSecondPtrNotChanged this error indicates that a double reference was passed to the Unmarshal function +// (example (**int)(**0)) and the function did not overwrite the second reference. +// Of course, it's not friendly to the garbage collector, overwriting references to values all the time, +// but this is the current implementation `gocql` and changing it can lead to unexpected results in some cases. +var ErrSecondPtrNotChanged = errors.New("unmarshal function did not rewrite second pointer") + +func getPointers(i interface{}) *pointer { + rv := reflect.ValueOf(i) + if rv.Kind() != reflect.Ptr { + return nil + } + out := pointer{ + Fist: rv.Pointer(), + } + rt := rv.Type() + if rt.Elem().Kind() == reflect.Ptr && !rv.Elem().IsNil() { + out.Second = rv.Elem().Pointer() + } + return &out +} + +type pointer struct { + Fist uintptr + Second uintptr +} + +func (p *pointer) NotNil() bool { + return p != nil +} + +// Valid validates if pointers has been manipulated by unmarshal functions in an expected manner: +// Fist pointer should not be overwritten, +// Second pointer, if applicable, should be overwritten. +func (p *pointer) Valid(v interface{}) error { + p2 := getPointers(v) + if p.Fist != p2.Fist { + return ErrFirstPtrChanged + } + if p.Second != 0 && p2.Second != 0 && p2.Second == p.Second { + return ErrSecondPtrNotChanged + } + return nil +} diff --git a/marshal/tests/serialization/pointers_test.go b/marshal/tests/serialization/pointers_test.go new file mode 100644 index 000000000..3276b579b --- /dev/null +++ b/marshal/tests/serialization/pointers_test.go @@ -0,0 +1,38 @@ +package serialization + +import "testing" + +func Test1Pointers(t *testing.T) { + val1 := new(int16) + *val1 = int16(0) + testPtr := getPointers(val1) + + // the first pointer has not been changed - it must be not error. + if err := testPtr.Valid(val1); err != nil { + t.Error("valid function not should return error") + } + + val2 := new(int16) + // the first pointer has been changed - it must be an error. + if err := testPtr.Valid(val2); err == nil { + t.Error("valid function should return error") + } +} + +func Test2Pointers(t *testing.T) { + val1 := new(*int16) + *val1 = new(int16) + testPtr := getPointers(val1) + // the first pointer has not been changed - it must be not error, + // but the second pointer has not been changed too - it must be an error. + if err := testPtr.Valid(val1); err == nil { + t.Error("valid function should return error") + } + + *val1 = new(int16) + // the first pointer has not been changed - it must be not error, + // the second pointer has been changed - it must be not error. + if err := testPtr.Valid(val1); err != nil { + t.Error("valid function not should return error") + } +} diff --git a/marshal/tests/serialization/set.go b/marshal/tests/serialization/set.go new file mode 100644 index 000000000..7415d3990 --- /dev/null +++ b/marshal/tests/serialization/set.go @@ -0,0 +1,128 @@ +package serialization + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "runtime/debug" + "testing" + + "github.com/gocql/gocql/internal/tests/utils" +) + +type Sets []*Set + +// Set is a tool for generating test cases of marshal and unmarshall funcs. +// For cases when the function should no error, +// marshaled data from Set.Values should be equal with Set.Data, +// unmarshalled value from Set.Data should be equal with Set.Values. +type Set struct { + Data []byte + Values []interface{} + + BrokenMarshalTypes []reflect.Type + BrokenUnmarshalTypes []reflect.Type +} + +func (s Set) Run(name string, t *testing.T, marshal func(interface{}) ([]byte, error), unmarshal func([]byte, interface{}) error) { + if name == "" { + t.Fatal("name should be provided") + } + + t.Run(name, func(t *testing.T) { + for i := range s.Values { + val := s.Values[i] + + t.Run(fmt.Sprintf("%T", val), func(t *testing.T) { + if marshal != nil { + s.runMarshalTest(t, marshal, val) + } + + if unmarshal != nil { + if rt := reflect.TypeOf(val); rt.Kind() != reflect.Ptr { + unmarshalIn := utils.NewRef(val) + s.runUnmarshalTest("unmarshal", t, unmarshal, val, unmarshalIn) + } else { + // Test unmarshal to (*type)(nil) + unmarshalIn := utils.NewRef(val) + s.runUnmarshalTest("unmarshal**nil", t, unmarshal, val, unmarshalIn) + + // Test unmarshal to &type{} + unmarshalInZero := utils.NewRefToZero(val) + s.runUnmarshalTest("unmarshal**zero", t, unmarshal, val, unmarshalInZero) + } + } + }) + } + }) +} + +func (s Set) runMarshalTest(t *testing.T, f func(interface{}) ([]byte, error), val interface{}) { + t.Run("marshal", func(t *testing.T) { + + result, err := func() (d []byte, err error) { + defer func() { + if r := recover(); r != nil { + err = utils.PanicErr{Err: r.(error), Stack: debug.Stack()} + } + }() + return f(val) + }() + + expected := bytes.Clone(s.Data) + if err != nil { + if !errors.As(err, &utils.PanicErr{}) { + err = errors.Join(MarshalErr, err) + } + } else if !utils.EqualData(expected, result) { + err = UnequalError{Expected: utils.StringData(s.Data), Got: utils.StringData(result)} + } + + if isTypeOf(val, s.BrokenMarshalTypes) { + if err == nil { + t.Fatalf("expected to fail for (%T), but did not fail", val) + } + t.Skipf("skipped bacause there is unsolved problem") + } + if err != nil { + t.Error(err) + } + }) +} + +func (s Set) runUnmarshalTest(name string, t *testing.T, f func([]byte, interface{}) error, expected, result interface{}) { + t.Run(name, func(t *testing.T) { + + expectedPtr := getPointers(result) + + err := func() (err error) { + defer func() { + if r := recover(); r != nil { + err = utils.PanicErr{Err: fmt.Errorf("%s", r), Stack: debug.Stack()} + } + }() + return f(bytes.Clone(s.Data), result) + }() + + if err != nil { + if !errors.As(err, &utils.PanicErr{}) { + err = errors.Join(UnmarshalErr, err) + } + } else if !utils.EqualVals(expected, utils.DeReference(result)) { + err = UnequalError{Expected: utils.StringValue(expected), Got: utils.StringValue(result)} + } else { + err = expectedPtr.Valid(result) + } + + if isTypeOf(expected, s.BrokenUnmarshalTypes) { + if err == nil { + t.Fatalf("expected to fail for (%T), but did not fail", expected) + } + t.Skipf("skipped bacause there is unsolved problem") + } + if err != nil { + t.Error(err) + } + }) +} diff --git a/marshal/tests/serialization/utils.go b/marshal/tests/serialization/utils.go new file mode 100644 index 000000000..63010dd56 --- /dev/null +++ b/marshal/tests/serialization/utils.go @@ -0,0 +1,29 @@ +package serialization + +import ( + "errors" + "fmt" + "reflect" +) + +var UnmarshalErr = errors.New("unmarshal unexpectedly failed with error") +var MarshalErr = errors.New("marshal unexpectedly failed with error") + +type UnequalError struct { + Expected string + Got string +} + +func (e UnequalError) Error() string { + return fmt.Sprintf("expect %s but got %s", e.Expected, e.Got) +} + +func isTypeOf(value interface{}, types []reflect.Type) bool { + valueType := reflect.TypeOf(value) + for i := range types { + if types[i] == valueType { + return true + } + } + return false +} diff --git a/marshal_3_smallint_test.go b/marshal_3_smallint_test.go new file mode 100644 index 000000000..7d2a37953 --- /dev/null +++ b/marshal_3_smallint_test.go @@ -0,0 +1,92 @@ +package gocql + +import ( + "testing" + + "github.com/gocql/gocql/internal/tests/utils" + "github.com/gocql/gocql/marshal/tests/mod" + "github.com/gocql/gocql/marshal/tests/serialization" +) + +func TestMarshalSmallint(t *testing.T) { + marshal := func(i interface{}) ([]byte, error) { return Marshal(NativeType{proto: 4, typ: TypeSmallInt}, i) } + unmarshal := func(bytes []byte, i interface{}) error { + return Unmarshal(NativeType{proto: 4, typ: TypeSmallInt}, bytes, i) + } + + brokenTypes := utils.GetTypes(mod.String(""), (*mod.String)(nil)) + + serialization.Set{ + Data: nil, + Values: mod.Values{ + (*int8)(nil), (*int16)(nil), (*int32)(nil), (*int64)(nil), (*int)(nil), + (*uint8)(nil), (*uint16)(nil), (*uint32)(nil), (*uint64)(nil), (*uint)(nil), (*string)(nil), + }.AddVariants(mod.CustomType), + }.Run("[nil]refs", t, marshal, unmarshal) + + serialization.Set{ + Data: nil, + Values: mod.Values{ + int8(0), int16(0), int32(0), int64(0), int(0), + uint8(0), uint16(0), uint32(0), uint64(0), uint(0), "0", + }.AddVariants(mod.CustomType), + BrokenUnmarshalTypes: brokenTypes, + }.Run("unmarshal nil data", t, nil, unmarshal) + + serialization.Set{ + Data: make([]byte, 0), + Values: mod.Values{ + int8(0), int16(0), int32(0), int64(0), int(0), + uint8(0), uint16(0), uint32(0), uint64(0), uint(0), "0", + }.AddVariants(mod.All...), + BrokenUnmarshalTypes: brokenTypes, + }.Run("unmarshal zero data", t, nil, unmarshal) + + serialization.Set{ + Data: []byte("\x00\x00"), + Values: mod.Values{ + int8(0), int16(0), int32(0), int64(0), int(0), + uint8(0), uint16(0), uint32(0), uint64(0), uint(0), "0", + }.AddVariants(mod.All...), + BrokenMarshalTypes: brokenTypes, + BrokenUnmarshalTypes: brokenTypes, + }.Run("zeros", t, marshal, unmarshal) + + serialization.Set{ + Data: []byte("\x00\x7f"), + Values: mod.Values{int8(127), int16(127), int32(127), int64(127), int(127), "127"}.AddVariants(mod.All...), + BrokenMarshalTypes: brokenTypes, + BrokenUnmarshalTypes: brokenTypes, + }.Run("127", t, marshal, unmarshal) + + serialization.Set{ + Data: []byte("\xff\x80"), + Values: mod.Values{int8(-128), int16(-128), int32(-128), int64(-128), int(-128), "-128"}.AddVariants(mod.All...), + BrokenMarshalTypes: brokenTypes, + BrokenUnmarshalTypes: brokenTypes, + }.Run("-128", t, marshal, unmarshal) + + serialization.Set{ + Data: []byte("\x7f\xff"), + Values: mod.Values{int16(32767), int32(32767), int64(32767), int(32767), "32767"}.AddVariants(mod.All...), + BrokenMarshalTypes: brokenTypes, + BrokenUnmarshalTypes: brokenTypes, + }.Run("32767", t, marshal, unmarshal) + + serialization.Set{ + Data: []byte("\x80\x00"), + Values: mod.Values{int16(-32768), int32(-32768), int64(-32768), int(-32768), "-32768"}.AddVariants(mod.All...), + BrokenMarshalTypes: brokenTypes, + BrokenUnmarshalTypes: brokenTypes, + }.Run("-32768", t, marshal, unmarshal) + + serialization.Set{ + Data: []byte("\x00\xff"), + Values: mod.Values{uint8(255), uint16(255), uint32(255), uint64(255), uint(255)}.AddVariants(mod.All...), + }.Run("255", t, marshal, unmarshal) + + serialization.Set{ + Data: []byte("\xff\xff"), + Values: mod.Values{uint16(65535), uint32(65535), uint64(65535), uint(65535)}.AddVariants(mod.All...), + }.Run("65535", t, marshal, unmarshal) +}