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 }