github.com/alloyzeus/go-azfl@v0.0.0-20231220071816-9740126a2d07/azid/bin_test.go (about)

     1  package azid_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"testing"
     7  
     8  	errors "github.com/alloyzeus/go-azfl/azerrs"
     9  	"github.com/alloyzeus/go-azfl/azid"
    10  )
    11  
    12  type int32IDNum int32
    13  
    14  var _ azid.BinFieldMarshalable = int32IDNum(0)
    15  
    16  func (id int32IDNum) AZIDBinField() ([]byte, azid.BinDataType) {
    17  	b := make([]byte, 4)
    18  	binary.BigEndian.PutUint32(b, uint32(id))
    19  	return b, azid.BinDataTypeInt32
    20  }
    21  
    22  func (id *int32IDNum) UnmarshalAZIDBinField(b []byte, typeHint azid.BinDataType) (readLen int, err error) {
    23  	i, readLen, err := int32IDNumFromAZIDBinField(b, typeHint)
    24  	if err == nil {
    25  		*id = i
    26  	}
    27  	return readLen, err
    28  }
    29  
    30  func int32IDNumFromAZIDBinField(
    31  	b []byte, typeHint azid.BinDataType,
    32  ) (id int32IDNum, readLen int, err error) {
    33  	if typeHint != azid.BinDataTypeUnspecified && typeHint != azid.BinDataTypeInt32 {
    34  		return int32IDNum(0), 0,
    35  			errors.ArgValueUnsupported("typeHint")
    36  	}
    37  	i := binary.BigEndian.Uint32(b)
    38  	return int32IDNum(i), 4, nil
    39  }
    40  
    41  type int32ID int32IDNum
    42  
    43  var _ azid.BinMarshalable = int32ID(0)
    44  var _ azid.BinFieldMarshalable = int32ID(0)
    45  
    46  func int32IDFromAZIDBinField(
    47  	b []byte, typeHint azid.BinDataType,
    48  ) (id int32ID, readLen int, err error) {
    49  	idNum, n, err := int32IDNumFromAZIDBinField(b, typeHint)
    50  	if err != nil {
    51  		return int32ID(0), n, err
    52  	}
    53  	return int32ID(idNum), n, nil
    54  }
    55  
    56  func (id int32ID) AZIDBin() []byte {
    57  	b := make([]byte, 5)
    58  	b[0] = azid.BinDataTypeInt32.Byte()
    59  	binary.BigEndian.PutUint32(b[1:], uint32(id))
    60  	return b
    61  }
    62  
    63  func int32IDFromAZIDBin(idBin []byte) (id int32ID, readLen int, err error) {
    64  	typ, err := azid.BinDataTypeFromByte(idBin[0])
    65  	if err != nil {
    66  		return int32ID(0), 0,
    67  			errors.Arg("idBin").Fieldset(errors.
    68  				NamedValueMalformed("type").Wrap(err))
    69  	}
    70  	if typ != azid.BinDataTypeInt32 {
    71  		return int32ID(0), 0,
    72  			errors.Arg("idBin").Fieldset(errors.
    73  				NamedValueUnsupported("type"))
    74  	}
    75  
    76  	i, readLen, err := int32IDNumFromAZIDBinField(idBin[1:], typ)
    77  	if err != nil {
    78  		return int32ID(0), 0,
    79  			errors.Arg("idBin").Fieldset(errors.
    80  				NamedValueMalformed("id data").Wrap(err))
    81  	}
    82  
    83  	return int32ID(i), 1 + readLen, nil
    84  }
    85  
    86  func (id int32ID) AZIDBinField() ([]byte, azid.BinDataType) {
    87  	return int32IDNum(id).AZIDBinField()
    88  }
    89  
    90  type adjunctIDNum int16
    91  
    92  func adjunctIDNumFromAZIDBinField(
    93  	b []byte, typeHint azid.BinDataType,
    94  ) (id adjunctIDNum, readLen int, err error) {
    95  	if typeHint != azid.BinDataTypeUnspecified && typeHint != azid.BinDataTypeInt16 {
    96  		return adjunctIDNum(0), 0,
    97  			errors.ArgValueUnsupported("typeHint")
    98  	}
    99  	i := binary.BigEndian.Uint16(b)
   100  	return adjunctIDNum(i), 2, nil
   101  }
   102  
   103  func (id adjunctIDNum) AZIDBinField() ([]byte, azid.BinDataType) {
   104  	b := make([]byte, 2)
   105  	binary.BigEndian.PutUint16(b, uint16(id))
   106  	return b, azid.BinDataTypeInt16
   107  }
   108  
   109  type adjunctID struct {
   110  	parent int32ID
   111  	idNum  adjunctIDNum
   112  }
   113  
   114  const adjunctIDFieldCount = 2
   115  
   116  func adjunctIDFromAZIDBinField(
   117  	idBinField []byte, typeHint azid.BinDataType,
   118  ) (id adjunctID, readLen int, err error) {
   119  	if typeHint != azid.BinDataTypeArray {
   120  		return adjunctID{}, 0,
   121  			errors.ArgValueUnsupported("typeHint")
   122  	}
   123  
   124  	arrayLen := int(idBinField[0])
   125  	if arrayLen != adjunctIDFieldCount {
   126  		return adjunctID{}, 0,
   127  			errors.Arg("idBinField").Fieldset(errors.
   128  				N("field count").Desc(errors.ErrValueMismatch))
   129  	}
   130  
   131  	typeCursor := 1
   132  	dataCursor := typeCursor + arrayLen
   133  
   134  	parentType, err := azid.BinDataTypeFromByte(idBinField[typeCursor])
   135  	if err != nil {
   136  		return adjunctID{}, 0,
   137  			errors.Arg("idBinField").Fieldset(errors.
   138  				NamedValueMalformed("parent type").Wrap(err))
   139  	}
   140  	typeCursor++
   141  	parentID, readLen, err := int32IDFromAZIDBinField(idBinField[dataCursor:], parentType)
   142  	if err != nil {
   143  		return adjunctID{}, 0,
   144  			errors.Arg("idBinField").Fieldset(errors.
   145  				NamedValueMalformed("parent data").Wrap(err))
   146  	}
   147  	dataCursor += readLen
   148  
   149  	idType, err := azid.BinDataTypeFromByte(idBinField[typeCursor])
   150  	if err != nil {
   151  		return adjunctID{}, 0,
   152  			errors.Arg("idBinField").Fieldset(errors.
   153  				NamedValueMalformed("id type").Wrap(err))
   154  	}
   155  	typeCursor++
   156  	idNum, readLen, err := adjunctIDNumFromAZIDBinField(idBinField[dataCursor:], idType)
   157  	if err != nil {
   158  		return adjunctID{}, 0,
   159  			errors.Arg("idBinField").Fieldset(errors.
   160  				NamedValueMalformed("id data").Wrap(err))
   161  	}
   162  	dataCursor += readLen
   163  
   164  	return adjunctID{parentID, idNum}, dataCursor, nil
   165  }
   166  
   167  func adjunctIDFromAZIDBin(
   168  	idBin []byte,
   169  ) (id adjunctID, readLen int, err error) {
   170  	typ, err := azid.BinDataTypeFromByte(idBin[0])
   171  	if err != nil {
   172  		return adjunctID{}, 0,
   173  			errors.Arg("idBin").Fieldset(errors.
   174  				NamedValueMalformed("type").Wrap(err))
   175  	}
   176  	if typ != azid.BinDataTypeArray {
   177  		return adjunctID{}, 0,
   178  			errors.Arg("idBin").Fieldset(errors.
   179  				NamedValueUnsupported("type"))
   180  	}
   181  
   182  	id, readLen, err = adjunctIDFromAZIDBinField(idBin[1:], typ)
   183  	return id, readLen + 1, err
   184  }
   185  
   186  func (id adjunctID) AZIDBinField() ([]byte, azid.BinDataType) {
   187  	var typesBytes []byte
   188  	var dataBytes []byte
   189  	var fieldBytes []byte
   190  	var fieldType azid.BinDataType
   191  
   192  	fieldBytes, fieldType = id.parent.AZIDBinField()
   193  	typesBytes = append(typesBytes, fieldType.Byte())
   194  	dataBytes = append(dataBytes, fieldBytes...)
   195  
   196  	fieldBytes, fieldType = id.idNum.AZIDBinField()
   197  	typesBytes = append(typesBytes, fieldType.Byte())
   198  	dataBytes = append(dataBytes, fieldBytes...)
   199  
   200  	var out = []byte{byte(len(typesBytes))}
   201  	out = append(out, typesBytes...)
   202  	out = append(out, dataBytes...)
   203  	return out, azid.BinDataTypeArray
   204  }
   205  
   206  func (id adjunctID) AZIDBin() []byte {
   207  	data, typ := id.AZIDBinField()
   208  	out := []byte{typ.Byte()}
   209  	return append(out, data...)
   210  }
   211  
   212  func TestEncodeField(t *testing.T) {
   213  	testCases := []struct {
   214  		in      int32IDNum
   215  		outData []byte
   216  		outType azid.BinDataType
   217  	}{
   218  		{int32IDNum(0), []byte{0, 0, 0, 0}, azid.BinDataTypeInt32},
   219  		{int32IDNum(1), []byte{0, 0, 0, 1}, azid.BinDataTypeInt32},
   220  		{int32IDNum(1 << 24), []byte{1, 0, 0, 0}, azid.BinDataTypeInt32},
   221  	}
   222  
   223  	for _, testCase := range testCases {
   224  		outData, outType := testCase.in.AZIDBinField()
   225  		if !bytes.Equal(outData, testCase.outData) {
   226  			t.Errorf("Expected: %#v, actual: %#v", testCase.outData, outData)
   227  		}
   228  		if outType != testCase.outType {
   229  			t.Errorf("Expected: %#v, actual: %#v", testCase.outType, outType)
   230  		}
   231  	}
   232  }
   233  
   234  func TestEncodeID(t *testing.T) {
   235  	testCases := []struct {
   236  		in      int32ID
   237  		outData []byte
   238  	}{
   239  		{int32ID(0), []byte{0x13, 0, 0, 0, 0}},
   240  		{int32ID(1), []byte{0x13, 0, 0, 0, 1}},
   241  		{int32ID(1 << 24), []byte{0x13, 1, 0, 0, 0}},
   242  	}
   243  
   244  	for _, testCase := range testCases {
   245  		outData := testCase.in.AZIDBin()
   246  		if !bytes.Equal(outData, testCase.outData) {
   247  			t.Errorf("Expected: %#v, actual: %#v", testCase.outData, outData)
   248  		}
   249  	}
   250  }
   251  
   252  func TestEncodeAdjunct(t *testing.T) {
   253  	testCases := []struct {
   254  		in      adjunctID
   255  		outData []byte
   256  	}{
   257  		{adjunctID{int32ID(0), adjunctIDNum(0)},
   258  			[]byte{0x40, 0x2, 0x13, 0x12, 0, 0, 0, 0, 0, 0}},
   259  		{adjunctID{int32ID(0), adjunctIDNum(1)},
   260  			[]byte{0x40, 0x2, 0x13, 0x12, 0, 0, 0, 0, 0, 1}},
   261  		{adjunctID{int32ID(1), adjunctIDNum(0)},
   262  			[]byte{0x40, 0x2, 0x13, 0x12, 0, 0, 0, 1, 0, 0}},
   263  	}
   264  
   265  	for _, testCase := range testCases {
   266  		outData := testCase.in.AZIDBin()
   267  		if !bytes.Equal(outData, testCase.outData) {
   268  			t.Errorf("Expected: %#v, actual: %#v", testCase.outData, outData)
   269  		}
   270  	}
   271  }
   272  
   273  func TestDecodeToAdjunct(t *testing.T) {
   274  	testCases := []struct {
   275  		in      []byte
   276  		out     adjunctID
   277  		readLen int
   278  		err     error
   279  	}{
   280  		{[]byte{0x40, 0x2, 0x13, 0x12, 0, 0, 0, 0, 0, 0},
   281  			adjunctID{int32ID(0), adjunctIDNum(0)}, 10, nil},
   282  		{[]byte{0x40, 0x2, 0x13, 0x12, 0, 0, 0, 0, 0, 1},
   283  			adjunctID{int32ID(0), adjunctIDNum(1)}, 10, nil},
   284  		{[]byte{0x40, 0x2, 0x13, 0x12, 0, 0, 0, 1, 0, 0},
   285  			adjunctID{int32ID(1), adjunctIDNum(0)}, 10, nil},
   286  	}
   287  
   288  	for _, testCase := range testCases {
   289  		id, readLen, err := adjunctIDFromAZIDBin(testCase.in)
   290  		if err != testCase.err {
   291  			t.Errorf("Expected: %#v, actual: %#v", testCase.err, err)
   292  		}
   293  		if readLen != testCase.readLen || readLen != len(testCase.in) {
   294  			t.Errorf("Expected: %#v, actual: %#v", testCase.readLen, readLen)
   295  		}
   296  		if id.parent != testCase.out.parent || id.idNum != testCase.out.idNum {
   297  			t.Errorf("Expected: %#v, actual: %#v", testCase.out, id)
   298  		}
   299  	}
   300  }