github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/encoding/binary/binary_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package binary 6 7 import ( 8 "bytes" 9 "io" 10 "math" 11 "reflect" 12 "strings" 13 "testing" 14 ) 15 16 type Struct struct { 17 Int8 int8 18 Int16 int16 19 Int32 int32 20 Int64 int64 21 Uint8 uint8 22 Uint16 uint16 23 Uint32 uint32 24 Uint64 uint64 25 Float32 float32 26 Float64 float64 27 Complex64 complex64 28 Complex128 complex128 29 Array [4]uint8 30 } 31 32 type T struct { 33 Int int 34 Uint uint 35 Uintptr uintptr 36 Array [4]int 37 } 38 39 var s = Struct{ 40 0x01, 41 0x0203, 42 0x04050607, 43 0x08090a0b0c0d0e0f, 44 0x10, 45 0x1112, 46 0x13141516, 47 0x1718191a1b1c1d1e, 48 49 math.Float32frombits(0x1f202122), 50 math.Float64frombits(0x232425262728292a), 51 complex( 52 math.Float32frombits(0x2b2c2d2e), 53 math.Float32frombits(0x2f303132), 54 ), 55 complex( 56 math.Float64frombits(0x333435363738393a), 57 math.Float64frombits(0x3b3c3d3e3f404142), 58 ), 59 60 [4]uint8{0x43, 0x44, 0x45, 0x46}, 61 } 62 63 var big = []byte{ 64 1, 65 2, 3, 66 4, 5, 6, 7, 67 8, 9, 10, 11, 12, 13, 14, 15, 68 16, 69 17, 18, 70 19, 20, 21, 22, 71 23, 24, 25, 26, 27, 28, 29, 30, 72 73 31, 32, 33, 34, 74 35, 36, 37, 38, 39, 40, 41, 42, 75 43, 44, 45, 46, 47, 48, 49, 50, 76 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 77 78 67, 68, 69, 70, 79 } 80 81 var little = []byte{ 82 1, 83 3, 2, 84 7, 6, 5, 4, 85 15, 14, 13, 12, 11, 10, 9, 8, 86 16, 87 18, 17, 88 22, 21, 20, 19, 89 30, 29, 28, 27, 26, 25, 24, 23, 90 91 34, 33, 32, 31, 92 42, 41, 40, 39, 38, 37, 36, 35, 93 46, 45, 44, 43, 50, 49, 48, 47, 94 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59, 95 96 67, 68, 69, 70, 97 } 98 99 var src = []byte{1, 2, 3, 4, 5, 6, 7, 8} 100 var res = []int32{0x01020304, 0x05060708} 101 102 func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) { 103 if err != nil { 104 t.Errorf("%v %v: %v", dir, order, err) 105 return 106 } 107 if !reflect.DeepEqual(have, want) { 108 t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want) 109 } 110 } 111 112 func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) { 113 var s2 Struct 114 err := Read(bytes.NewReader(b), order, &s2) 115 checkResult(t, "Read", order, err, s2, s1) 116 } 117 118 func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) { 119 buf := new(bytes.Buffer) 120 err := Write(buf, order, s1) 121 checkResult(t, "Write", order, err, buf.Bytes(), b) 122 } 123 124 func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) } 125 func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) } 126 func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) } 127 128 func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) } 129 func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) } 130 func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) } 131 132 func TestReadSlice(t *testing.T) { 133 slice := make([]int32, 2) 134 err := Read(bytes.NewReader(src), BigEndian, slice) 135 checkResult(t, "ReadSlice", BigEndian, err, slice, res) 136 } 137 138 func TestWriteSlice(t *testing.T) { 139 buf := new(bytes.Buffer) 140 err := Write(buf, BigEndian, res) 141 checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src) 142 } 143 144 // Addresses of arrays are easier to manipulate with reflection than are slices. 145 var intArrays = []interface{}{ 146 &[100]int8{}, 147 &[100]int16{}, 148 &[100]int32{}, 149 &[100]int64{}, 150 &[100]uint8{}, 151 &[100]uint16{}, 152 &[100]uint32{}, 153 &[100]uint64{}, 154 } 155 156 func TestSliceRoundTrip(t *testing.T) { 157 buf := new(bytes.Buffer) 158 for _, array := range intArrays { 159 src := reflect.ValueOf(array).Elem() 160 unsigned := false 161 switch src.Index(0).Kind() { 162 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 163 unsigned = true 164 } 165 for i := 0; i < src.Len(); i++ { 166 if unsigned { 167 src.Index(i).SetUint(uint64(i * 0x07654321)) 168 } else { 169 src.Index(i).SetInt(int64(i * 0x07654321)) 170 } 171 } 172 buf.Reset() 173 srcSlice := src.Slice(0, src.Len()) 174 err := Write(buf, BigEndian, srcSlice.Interface()) 175 if err != nil { 176 t.Fatal(err) 177 } 178 dst := reflect.New(src.Type()).Elem() 179 dstSlice := dst.Slice(0, dst.Len()) 180 err = Read(buf, BigEndian, dstSlice.Interface()) 181 if err != nil { 182 t.Fatal(err) 183 } 184 if !reflect.DeepEqual(src.Interface(), dst.Interface()) { 185 t.Fatal(src) 186 } 187 } 188 } 189 190 func TestWriteT(t *testing.T) { 191 buf := new(bytes.Buffer) 192 ts := T{} 193 if err := Write(buf, BigEndian, ts); err == nil { 194 t.Errorf("WriteT: have err == nil, want non-nil") 195 } 196 197 tv := reflect.Indirect(reflect.ValueOf(ts)) 198 for i, n := 0, tv.NumField(); i < n; i++ { 199 typ := tv.Field(i).Type().String() 200 if typ == "[4]int" { 201 typ = "int" // the problem is int, not the [4] 202 } 203 if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil { 204 t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type()) 205 } else if !strings.Contains(err.Error(), typ) { 206 t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ) 207 } 208 } 209 } 210 211 type BlankFields struct { 212 A uint32 213 _ int32 214 B float64 215 _ [4]int16 216 C byte 217 _ [7]byte 218 _ struct { 219 f [8]float32 220 } 221 } 222 223 type BlankFieldsProbe struct { 224 A uint32 225 P0 int32 226 B float64 227 P1 [4]int16 228 C byte 229 P2 [7]byte 230 P3 struct { 231 F [8]float32 232 } 233 } 234 235 func TestBlankFields(t *testing.T) { 236 buf := new(bytes.Buffer) 237 b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42} 238 if err := Write(buf, LittleEndian, &b1); err != nil { 239 t.Error(err) 240 } 241 242 // zero values must have been written for blank fields 243 var p BlankFieldsProbe 244 if err := Read(buf, LittleEndian, &p); err != nil { 245 t.Error(err) 246 } 247 248 // quick test: only check first value of slices 249 if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 { 250 t.Errorf("non-zero values for originally blank fields: %#v", p) 251 } 252 253 // write p and see if we can probe only some fields 254 if err := Write(buf, LittleEndian, &p); err != nil { 255 t.Error(err) 256 } 257 258 // read should ignore blank fields in b2 259 var b2 BlankFields 260 if err := Read(buf, LittleEndian, &b2); err != nil { 261 t.Error(err) 262 } 263 if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C { 264 t.Errorf("%#v != %#v", b1, b2) 265 } 266 } 267 268 // An attempt to read into a struct with an unexported field will 269 // panic. This is probably not the best choice, but at this point 270 // anything else would be an API change. 271 272 type Unexported struct { 273 a int32 274 } 275 276 func TestUnexportedRead(t *testing.T) { 277 var buf bytes.Buffer 278 u1 := Unexported{a: 1} 279 if err := Write(&buf, LittleEndian, &u1); err != nil { 280 t.Fatal(err) 281 } 282 283 defer func() { 284 if recover() == nil { 285 t.Fatal("did not panic") 286 } 287 }() 288 var u2 Unexported 289 Read(&buf, LittleEndian, &u2) 290 } 291 292 func TestReadErrorMsg(t *testing.T) { 293 var buf bytes.Buffer 294 read := func(data interface{}) { 295 err := Read(&buf, LittleEndian, data) 296 want := "binary.Read: invalid type " + reflect.TypeOf(data).String() 297 if err == nil { 298 t.Errorf("%T: got no error; want %q", data, want) 299 return 300 } 301 if got := err.Error(); got != want { 302 t.Errorf("%T: got %q; want %q", data, got, want) 303 } 304 } 305 read(0) 306 s := new(struct{}) 307 read(&s) 308 p := &s 309 read(&p) 310 } 311 312 func TestReadTruncated(t *testing.T) { 313 const data = "0123456789abcdef" 314 315 var b1 = make([]int32, 4) 316 var b2 struct { 317 A, B, C, D byte 318 E int32 319 F float64 320 } 321 322 for i := 0; i <= len(data); i++ { 323 var errWant error 324 switch i { 325 case 0: 326 errWant = io.EOF 327 case len(data): 328 errWant = nil 329 default: 330 errWant = io.ErrUnexpectedEOF 331 } 332 333 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant { 334 t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant) 335 } 336 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant { 337 t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant) 338 } 339 } 340 } 341 342 func testUint64SmallSliceLengthPanics() (panicked bool) { 343 defer func() { 344 panicked = recover() != nil 345 }() 346 b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} 347 LittleEndian.Uint64(b[:4]) 348 return false 349 } 350 351 func testPutUint64SmallSliceLengthPanics() (panicked bool) { 352 defer func() { 353 panicked = recover() != nil 354 }() 355 b := [8]byte{} 356 LittleEndian.PutUint64(b[:4], 0x0102030405060708) 357 return false 358 } 359 360 func TestEarlyBoundsChecks(t *testing.T) { 361 if testUint64SmallSliceLengthPanics() != true { 362 t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't") 363 } 364 if testPutUint64SmallSliceLengthPanics() != true { 365 t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't") 366 } 367 } 368 369 type byteSliceReader struct { 370 remain []byte 371 } 372 373 func (br *byteSliceReader) Read(p []byte) (int, error) { 374 n := copy(p, br.remain) 375 br.remain = br.remain[n:] 376 return n, nil 377 } 378 379 func BenchmarkReadSlice1000Int32s(b *testing.B) { 380 bsr := &byteSliceReader{} 381 slice := make([]int32, 1000) 382 buf := make([]byte, len(slice)*4) 383 b.SetBytes(int64(len(buf))) 384 b.ResetTimer() 385 for i := 0; i < b.N; i++ { 386 bsr.remain = buf 387 Read(bsr, BigEndian, slice) 388 } 389 } 390 391 func BenchmarkReadStruct(b *testing.B) { 392 bsr := &byteSliceReader{} 393 var buf bytes.Buffer 394 Write(&buf, BigEndian, &s) 395 b.SetBytes(int64(dataSize(reflect.ValueOf(s)))) 396 t := s 397 b.ResetTimer() 398 for i := 0; i < b.N; i++ { 399 bsr.remain = buf.Bytes() 400 Read(bsr, BigEndian, &t) 401 } 402 b.StopTimer() 403 if b.N > 0 && !reflect.DeepEqual(s, t) { 404 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s) 405 } 406 } 407 408 func BenchmarkReadInts(b *testing.B) { 409 var ls Struct 410 bsr := &byteSliceReader{} 411 var r io.Reader = bsr 412 b.SetBytes(2 * (1 + 2 + 4 + 8)) 413 b.ResetTimer() 414 for i := 0; i < b.N; i++ { 415 bsr.remain = big 416 Read(r, BigEndian, &ls.Int8) 417 Read(r, BigEndian, &ls.Int16) 418 Read(r, BigEndian, &ls.Int32) 419 Read(r, BigEndian, &ls.Int64) 420 Read(r, BigEndian, &ls.Uint8) 421 Read(r, BigEndian, &ls.Uint16) 422 Read(r, BigEndian, &ls.Uint32) 423 Read(r, BigEndian, &ls.Uint64) 424 } 425 426 want := s 427 want.Float32 = 0 428 want.Float64 = 0 429 want.Complex64 = 0 430 want.Complex128 = 0 431 for i := range want.Array { 432 want.Array[i] = 0 433 } 434 b.StopTimer() 435 if b.N > 0 && !reflect.DeepEqual(ls, want) { 436 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want) 437 } 438 } 439 440 func BenchmarkWriteInts(b *testing.B) { 441 buf := new(bytes.Buffer) 442 var w io.Writer = buf 443 b.SetBytes(2 * (1 + 2 + 4 + 8)) 444 b.ResetTimer() 445 for i := 0; i < b.N; i++ { 446 buf.Reset() 447 Write(w, BigEndian, s.Int8) 448 Write(w, BigEndian, s.Int16) 449 Write(w, BigEndian, s.Int32) 450 Write(w, BigEndian, s.Int64) 451 Write(w, BigEndian, s.Uint8) 452 Write(w, BigEndian, s.Uint16) 453 Write(w, BigEndian, s.Uint32) 454 Write(w, BigEndian, s.Uint64) 455 } 456 b.StopTimer() 457 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) { 458 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30]) 459 } 460 } 461 462 func BenchmarkWriteSlice1000Int32s(b *testing.B) { 463 slice := make([]int32, 1000) 464 buf := new(bytes.Buffer) 465 var w io.Writer = buf 466 b.SetBytes(4 * 1000) 467 b.ResetTimer() 468 for i := 0; i < b.N; i++ { 469 buf.Reset() 470 Write(w, BigEndian, slice) 471 } 472 b.StopTimer() 473 }