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 }