"refactor(common): 重构序列化工具包,将serialize重命名为utils并添加bitset组件"
This commit is contained in:
360
common/utils/sturc/custom_test.go
Normal file
360
common/utils/sturc/custom_test.go
Normal file
@@ -0,0 +1,360 @@
|
||||
package struc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Custom Type
|
||||
type Int3 uint32
|
||||
|
||||
// newInt3 returns a pointer to an Int3
|
||||
func newInt3(in int) *Int3 {
|
||||
i := Int3(in)
|
||||
return &i
|
||||
}
|
||||
|
||||
type Int3Struct struct {
|
||||
I Int3
|
||||
}
|
||||
|
||||
func (i *Int3) Pack(p []byte, opt *Options) (int, error) {
|
||||
var tmp [4]byte
|
||||
binary.BigEndian.PutUint32(tmp[:], uint32(*i))
|
||||
copy(p, tmp[1:])
|
||||
return 3, nil
|
||||
}
|
||||
func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error {
|
||||
var tmp [4]byte
|
||||
if _, err := r.Read(tmp[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
*i = Int3(binary.BigEndian.Uint32(tmp[:]))
|
||||
return nil
|
||||
}
|
||||
func (i *Int3) Size(opt *Options) int {
|
||||
return 3
|
||||
}
|
||||
func (i *Int3) String() string {
|
||||
return strconv.FormatUint(uint64(*i), 10)
|
||||
}
|
||||
|
||||
// Array of custom type
|
||||
type ArrayInt3Struct struct {
|
||||
I [2]Int3
|
||||
}
|
||||
|
||||
// Custom type of array of standard type
|
||||
type DoubleUInt8 [2]uint8
|
||||
|
||||
type DoubleUInt8Struct struct {
|
||||
I DoubleUInt8
|
||||
}
|
||||
|
||||
func (di *DoubleUInt8) Pack(p []byte, opt *Options) (int, error) {
|
||||
for i, value := range *di {
|
||||
p[i] = value
|
||||
}
|
||||
|
||||
return 2, nil
|
||||
}
|
||||
|
||||
func (di *DoubleUInt8) Unpack(r io.Reader, length int, opt *Options) error {
|
||||
for i := 0; i < 2; i++ {
|
||||
var value uint8
|
||||
if err := binary.Read(r, binary.LittleEndian, &value); err != nil {
|
||||
if err == io.EOF {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
di[i] = value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (di *DoubleUInt8) Size(opt *Options) int {
|
||||
return 2
|
||||
}
|
||||
|
||||
func (di *DoubleUInt8) String() string {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Custom type of array of custom type
|
||||
type DoubleInt3 [2]Int3
|
||||
|
||||
type DoubleInt3Struct struct {
|
||||
D DoubleInt3
|
||||
}
|
||||
|
||||
func (di *DoubleInt3) Pack(p []byte, opt *Options) (int, error) {
|
||||
var out []byte
|
||||
for _, value := range *di {
|
||||
tmp := make([]byte, 3)
|
||||
if _, err := value.Pack(tmp, opt); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
out = append(out, tmp...)
|
||||
}
|
||||
copy(p, out)
|
||||
|
||||
return 6, nil
|
||||
}
|
||||
|
||||
func (di *DoubleInt3) Unpack(r io.Reader, length int, opt *Options) error {
|
||||
for i := 0; i < 2; i++ {
|
||||
di[i].Unpack(r, 0, opt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (di *DoubleInt3) Size(opt *Options) int {
|
||||
return 6
|
||||
}
|
||||
|
||||
func (di *DoubleInt3) String() string {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Custom type of slice of standard type
|
||||
// Slice of uint8, stored in a zero terminated list.
|
||||
type SliceUInt8 []uint8
|
||||
|
||||
type SliceUInt8Struct struct {
|
||||
I SliceUInt8
|
||||
N uint8 // A field after to ensure the length is correct.
|
||||
}
|
||||
|
||||
func (ia *SliceUInt8) Pack(p []byte, opt *Options) (int, error) {
|
||||
for i, value := range *ia {
|
||||
p[i] = value
|
||||
}
|
||||
|
||||
return len(*ia) + 1, nil
|
||||
}
|
||||
|
||||
func (ia *SliceUInt8) Unpack(r io.Reader, length int, opt *Options) error {
|
||||
for {
|
||||
var value uint8
|
||||
if err := binary.Read(r, binary.LittleEndian, &value); err != nil {
|
||||
if err == io.EOF {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
if value == 0 {
|
||||
break
|
||||
}
|
||||
*ia = append(*ia, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ia *SliceUInt8) Size(opt *Options) int {
|
||||
return len(*ia) + 1
|
||||
}
|
||||
|
||||
func (ia *SliceUInt8) String() string {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
type ArrayOfUInt8Struct struct {
|
||||
I [2]uint8
|
||||
}
|
||||
|
||||
// Custom 4-character fixed string, similar to CHAR(4) in SQL.
|
||||
type Char4 string
|
||||
|
||||
func (*Char4) Size(opt *Options) int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (c *Char4) Pack(p []byte, opt *Options) (int, error) {
|
||||
buf := []byte(*c)
|
||||
buf = append(buf, make([]byte, c.Size(nil)-len(buf))...)
|
||||
|
||||
copy(p, buf)
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func (c *Char4) Unpack(r io.Reader, length int, opt *Options) error {
|
||||
buf := bytes.Buffer{}
|
||||
if _, err := buf.ReadFrom(r); err != nil {
|
||||
if err == io.EOF {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
*c = Char4(buf.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Char4) String() string {
|
||||
return string(*c)
|
||||
}
|
||||
|
||||
type Char4Struct struct {
|
||||
C Char4
|
||||
}
|
||||
|
||||
func TestCustomTypes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
packObj interface{}
|
||||
emptyObj interface{}
|
||||
expectBytes []byte
|
||||
skip bool // Skip the test, because it fails.
|
||||
// Switch to expectFail when possible:
|
||||
// https://github.com/golang/go/issues/25951
|
||||
}{
|
||||
// Start tests with unimplemented non-custom types.
|
||||
{
|
||||
name: "ArrayOfUInt8",
|
||||
packObj: [2]uint8{32, 64},
|
||||
emptyObj: [2]uint8{0, 0},
|
||||
expectBytes: []byte{32, 64},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "PointerToArrayOfUInt8",
|
||||
packObj: &[2]uint8{32, 64},
|
||||
emptyObj: &[2]uint8{0, 0},
|
||||
expectBytes: []byte{32, 64},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "ArrayOfUInt8Struct",
|
||||
packObj: &ArrayOfUInt8Struct{I: [2]uint8{32, 64}},
|
||||
emptyObj: &ArrayOfUInt8Struct{},
|
||||
expectBytes: []byte{32, 64},
|
||||
},
|
||||
{
|
||||
name: "CustomType",
|
||||
packObj: newInt3(3),
|
||||
emptyObj: newInt3(0),
|
||||
expectBytes: []byte{0, 0, 3},
|
||||
},
|
||||
{
|
||||
name: "CustomType-Big",
|
||||
packObj: newInt3(4000),
|
||||
emptyObj: newInt3(0),
|
||||
expectBytes: []byte{0, 15, 160},
|
||||
},
|
||||
{
|
||||
name: "CustomTypeStruct",
|
||||
packObj: &Int3Struct{3},
|
||||
emptyObj: &Int3Struct{},
|
||||
expectBytes: []byte{0, 0, 3},
|
||||
},
|
||||
{
|
||||
name: "ArrayOfCustomType",
|
||||
packObj: [2]Int3{3, 4},
|
||||
emptyObj: [2]Int3{},
|
||||
expectBytes: []byte{0, 0, 3, 0, 0, 4},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "PointerToArrayOfCustomType",
|
||||
packObj: &[2]Int3{3, 4},
|
||||
emptyObj: &[2]Int3{},
|
||||
expectBytes: []byte{0, 0, 3, 0, 0, 4},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "ArrayOfCustomTypeStruct",
|
||||
packObj: &ArrayInt3Struct{[2]Int3{3, 4}},
|
||||
emptyObj: &ArrayInt3Struct{},
|
||||
expectBytes: []byte{0, 0, 3, 0, 0, 4},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfArrayOfUInt8",
|
||||
packObj: &DoubleUInt8{32, 64},
|
||||
emptyObj: &DoubleUInt8{},
|
||||
expectBytes: []byte{32, 64},
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfArrayOfUInt8Struct",
|
||||
packObj: &DoubleUInt8Struct{I: DoubleUInt8{32, 64}},
|
||||
emptyObj: &DoubleUInt8Struct{},
|
||||
expectBytes: []byte{32, 64},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfArrayOfCustomType",
|
||||
packObj: &DoubleInt3{Int3(128), Int3(256)},
|
||||
emptyObj: &DoubleInt3{},
|
||||
expectBytes: []byte{0, 0, 128, 0, 1, 0},
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfArrayOfCustomTypeStruct",
|
||||
packObj: &DoubleInt3Struct{D: DoubleInt3{Int3(128), Int3(256)}},
|
||||
emptyObj: &DoubleInt3Struct{},
|
||||
expectBytes: []byte{0, 0, 128, 0, 1, 0},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfSliceOfUInt8",
|
||||
packObj: &SliceUInt8{128, 64, 32},
|
||||
emptyObj: &SliceUInt8{},
|
||||
expectBytes: []byte{128, 64, 32, 0},
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfSliceOfUInt8-Empty",
|
||||
packObj: &SliceUInt8{},
|
||||
emptyObj: &SliceUInt8{},
|
||||
expectBytes: []byte{0},
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfSliceOfUInt8Struct",
|
||||
packObj: &SliceUInt8Struct{I: SliceUInt8{128, 64, 32}, N: 192},
|
||||
emptyObj: &SliceUInt8Struct{},
|
||||
expectBytes: []byte{128, 64, 32, 0, 192},
|
||||
skip: true, // Not implemented.
|
||||
},
|
||||
{
|
||||
name: "CustomTypeOfChar4Struct",
|
||||
packObj: &Char4Struct{C: Char4("foo\x00")},
|
||||
emptyObj: &Char4Struct{},
|
||||
expectBytes: []byte{102, 111, 111, 0},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
// TODO: Switch to t.Run() when Go 1.7 is the minimum supported version.
|
||||
t.Log("RUN ", test.name)
|
||||
runner := func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Log("unexpected panic:", r)
|
||||
t.Error(r)
|
||||
}
|
||||
}()
|
||||
if test.skip {
|
||||
// TODO: Switch to t.Skip() when Go 1.7 is supported
|
||||
t.Log("skipped unimplemented")
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := Pack(&buf, test.packObj); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(buf.Bytes(), test.expectBytes) {
|
||||
t.Fatal("error packing, expect:", test.expectBytes, "found:", buf.Bytes())
|
||||
}
|
||||
if err := Unpack(&buf, test.emptyObj); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(test.packObj, test.emptyObj) {
|
||||
t.Fatal("error unpacking, expect:", test.packObj, "found:", test.emptyObj)
|
||||
}
|
||||
}
|
||||
runner(t)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user