gitee.com/quant1x/gox@v1.21.2/encoding/binary/struc/custom_test.go (about)

     1  package struc
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  	"reflect"
     8  	"strconv"
     9  	"testing"
    10  )
    11  
    12  // Custom Type
    13  type Int3 uint32
    14  
    15  // newInt3 returns a pointer to an Int3
    16  func newInt3(in int) *Int3 {
    17  	i := Int3(in)
    18  	return &i
    19  }
    20  
    21  type Int3Struct struct {
    22  	I Int3
    23  }
    24  
    25  func (i *Int3) Pack(p []byte, opt *Options) (int, error) {
    26  	var tmp [4]byte
    27  	binary.BigEndian.PutUint32(tmp[:], uint32(*i))
    28  	copy(p, tmp[1:])
    29  	return 3, nil
    30  }
    31  func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error {
    32  	var tmp [4]byte
    33  	if _, err := r.Read(tmp[1:]); err != nil {
    34  		return err
    35  	}
    36  	*i = Int3(binary.BigEndian.Uint32(tmp[:]))
    37  	return nil
    38  }
    39  func (i *Int3) Size(opt *Options) int {
    40  	return 3
    41  }
    42  func (i *Int3) String() string {
    43  	return strconv.FormatUint(uint64(*i), 10)
    44  }
    45  
    46  // Array of custom type
    47  type ArrayInt3Struct struct {
    48  	I [2]Int3
    49  }
    50  
    51  // Custom type of array of standard type
    52  type DoubleUInt8 [2]uint8
    53  
    54  type DoubleUInt8Struct struct {
    55  	I DoubleUInt8
    56  }
    57  
    58  func (di *DoubleUInt8) Pack(p []byte, opt *Options) (int, error) {
    59  	for i, value := range *di {
    60  		p[i] = value
    61  	}
    62  
    63  	return 2, nil
    64  }
    65  
    66  func (di *DoubleUInt8) Unpack(r io.Reader, length int, opt *Options) error {
    67  	for i := 0; i < 2; i++ {
    68  		var value uint8
    69  		if err := binary.Read(r, binary.LittleEndian, &value); err != nil {
    70  			if err == io.EOF {
    71  				return io.ErrUnexpectedEOF
    72  			}
    73  			return err
    74  		}
    75  		di[i] = value
    76  	}
    77  	return nil
    78  }
    79  
    80  func (di *DoubleUInt8) Size(opt *Options) int {
    81  	return 2
    82  }
    83  
    84  func (di *DoubleUInt8) String() string {
    85  	panic("not implemented")
    86  }
    87  
    88  // Custom type of array of custom type
    89  type DoubleInt3 [2]Int3
    90  
    91  type DoubleInt3Struct struct {
    92  	D DoubleInt3
    93  }
    94  
    95  func (di *DoubleInt3) Pack(p []byte, opt *Options) (int, error) {
    96  	var out []byte
    97  	for _, value := range *di {
    98  		tmp := make([]byte, 3)
    99  		if _, err := value.Pack(tmp, opt); err != nil {
   100  			return 0, err
   101  		}
   102  		out = append(out, tmp...)
   103  	}
   104  	copy(p, out)
   105  
   106  	return 6, nil
   107  }
   108  
   109  func (di *DoubleInt3) Unpack(r io.Reader, length int, opt *Options) error {
   110  	for i := 0; i < 2; i++ {
   111  		di[i].Unpack(r, 0, opt)
   112  	}
   113  	return nil
   114  }
   115  
   116  func (di *DoubleInt3) Size(opt *Options) int {
   117  	return 6
   118  }
   119  
   120  func (di *DoubleInt3) String() string {
   121  	panic("not implemented")
   122  }
   123  
   124  // Custom type of slice of standard type
   125  // Slice of uint8, stored in a zero terminated list.
   126  type SliceUInt8 []uint8
   127  
   128  type SliceUInt8Struct struct {
   129  	I SliceUInt8
   130  	N uint8 // A field after to ensure the length is correct.
   131  }
   132  
   133  func (ia *SliceUInt8) Pack(p []byte, opt *Options) (int, error) {
   134  	for i, value := range *ia {
   135  		p[i] = value
   136  	}
   137  
   138  	return len(*ia) + 1, nil
   139  }
   140  
   141  func (ia *SliceUInt8) Unpack(r io.Reader, length int, opt *Options) error {
   142  	for {
   143  		var value uint8
   144  		if err := binary.Read(r, binary.LittleEndian, &value); err != nil {
   145  			if err == io.EOF {
   146  				return io.ErrUnexpectedEOF
   147  			}
   148  			return err
   149  		}
   150  		if value == 0 {
   151  			break
   152  		}
   153  		*ia = append(*ia, value)
   154  	}
   155  	return nil
   156  }
   157  
   158  func (ia *SliceUInt8) Size(opt *Options) int {
   159  	return len(*ia) + 1
   160  }
   161  
   162  func (ia *SliceUInt8) String() string {
   163  	panic("not implemented")
   164  }
   165  
   166  type ArrayOfUInt8Struct struct {
   167  	I [2]uint8
   168  }
   169  
   170  func TestCustomTypes(t *testing.T) {
   171  	testCases := []struct {
   172  		name        string
   173  		packObj     interface{}
   174  		emptyObj    interface{}
   175  		expectBytes []byte
   176  		skip        bool // Skip the test, because it fails.
   177  		// Switch to expectFail when possible:
   178  		// https://github.com/golang/go/issues/25951
   179  	}{
   180  		// Start tests with unimplemented non-custom types.
   181  		{
   182  			name:        "ArrayOfUInt8",
   183  			packObj:     [2]uint8{32, 64},
   184  			emptyObj:    [2]uint8{0, 0},
   185  			expectBytes: []byte{32, 64},
   186  			skip:        true, // Not implemented.
   187  		},
   188  		{
   189  			name:        "PointerToArrayOfUInt8",
   190  			packObj:     &[2]uint8{32, 64},
   191  			emptyObj:    &[2]uint8{0, 0},
   192  			expectBytes: []byte{32, 64},
   193  			skip:        true, // Not implemented.
   194  		},
   195  		{
   196  			name:        "ArrayOfUInt8Struct",
   197  			packObj:     &ArrayOfUInt8Struct{I: [2]uint8{32, 64}},
   198  			emptyObj:    &ArrayOfUInt8Struct{},
   199  			expectBytes: []byte{32, 64},
   200  		},
   201  		{
   202  			name:        "CustomType",
   203  			packObj:     newInt3(3),
   204  			emptyObj:    newInt3(0),
   205  			expectBytes: []byte{0, 0, 3},
   206  		},
   207  		{
   208  			name:        "CustomType-Big",
   209  			packObj:     newInt3(4000),
   210  			emptyObj:    newInt3(0),
   211  			expectBytes: []byte{0, 15, 160},
   212  		},
   213  		{
   214  			name:        "CustomTypeStruct",
   215  			packObj:     &Int3Struct{3},
   216  			emptyObj:    &Int3Struct{},
   217  			expectBytes: []byte{0, 0, 3},
   218  		},
   219  		{
   220  			name:        "ArrayOfCustomType",
   221  			packObj:     [2]Int3{3, 4},
   222  			emptyObj:    [2]Int3{},
   223  			expectBytes: []byte{0, 0, 3, 0, 0, 4},
   224  			skip:        true, // Not implemented.
   225  		},
   226  		{
   227  			name:        "PointerToArrayOfCustomType",
   228  			packObj:     &[2]Int3{3, 4},
   229  			emptyObj:    &[2]Int3{},
   230  			expectBytes: []byte{0, 0, 3, 0, 0, 4},
   231  			skip:        true, // Not implemented.
   232  		},
   233  		{
   234  			name:        "ArrayOfCustomTypeStruct",
   235  			packObj:     &ArrayInt3Struct{[2]Int3{3, 4}},
   236  			emptyObj:    &ArrayInt3Struct{},
   237  			expectBytes: []byte{0, 0, 3, 0, 0, 4},
   238  			skip:        true, // Not implemented.
   239  		},
   240  		{
   241  			name:        "CustomTypeOfArrayOfUInt8",
   242  			packObj:     &DoubleUInt8{32, 64},
   243  			emptyObj:    &DoubleUInt8{},
   244  			expectBytes: []byte{32, 64},
   245  		},
   246  		{
   247  			name:        "CustomTypeOfArrayOfUInt8Struct",
   248  			packObj:     &DoubleUInt8Struct{I: DoubleUInt8{32, 64}},
   249  			emptyObj:    &DoubleUInt8Struct{},
   250  			expectBytes: []byte{32, 64},
   251  			skip:        true, // Not implemented.
   252  		},
   253  		{
   254  			name:        "CustomTypeOfArrayOfCustomType",
   255  			packObj:     &DoubleInt3{Int3(128), Int3(256)},
   256  			emptyObj:    &DoubleInt3{},
   257  			expectBytes: []byte{0, 0, 128, 0, 1, 0},
   258  		},
   259  		{
   260  			name:        "CustomTypeOfArrayOfCustomTypeStruct",
   261  			packObj:     &DoubleInt3Struct{D: DoubleInt3{Int3(128), Int3(256)}},
   262  			emptyObj:    &DoubleInt3Struct{},
   263  			expectBytes: []byte{0, 0, 128, 0, 1, 0},
   264  			skip:        true, // Not implemented.
   265  		},
   266  		{
   267  			name:        "CustomTypeOfSliceOfUInt8",
   268  			packObj:     &SliceUInt8{128, 64, 32},
   269  			emptyObj:    &SliceUInt8{},
   270  			expectBytes: []byte{128, 64, 32, 0},
   271  		},
   272  		{
   273  			name:        "CustomTypeOfSliceOfUInt8-Empty",
   274  			packObj:     &SliceUInt8{},
   275  			emptyObj:    &SliceUInt8{},
   276  			expectBytes: []byte{0},
   277  		},
   278  		{
   279  			name:        "CustomTypeOfSliceOfUInt8Struct",
   280  			packObj:     &SliceUInt8Struct{I: SliceUInt8{128, 64, 32}, N: 192},
   281  			emptyObj:    &SliceUInt8Struct{},
   282  			expectBytes: []byte{128, 64, 32, 0, 192},
   283  			skip:        true, // Not implemented.
   284  		},
   285  	}
   286  
   287  	for _, test := range testCases {
   288  		// TODO: Switch to t.Run() when Go 1.7 is the minimum supported version.
   289  		t.Log("RUN ", test.name)
   290  		runner := func(t *testing.T) {
   291  			defer func() {
   292  				if r := recover(); r != nil {
   293  					t.Log("unexpected panic:", r)
   294  				}
   295  			}()
   296  			if test.skip {
   297  				// TODO: Switch to t.Skip() when Go 1.7 is supported
   298  				t.Log("skipped unimplemented")
   299  				return
   300  			}
   301  			var buf bytes.Buffer
   302  			if err := Pack(&buf, test.packObj); err != nil {
   303  				t.Fatal(err)
   304  			}
   305  			if !bytes.Equal(buf.Bytes(), test.expectBytes) {
   306  				t.Fatal("error packing, expect:", test.expectBytes, "found:", buf.Bytes())
   307  			}
   308  			if err := Unpack(&buf, test.emptyObj); err != nil {
   309  				t.Fatal(err)
   310  			}
   311  			if !reflect.DeepEqual(test.packObj, test.emptyObj) {
   312  				t.Fatal("error unpacking, expect:", test.packObj, "found:", test.emptyObj)
   313  			}
   314  		}
   315  		runner(t)
   316  	}
   317  }