github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/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 "fmt" 10 "io" 11 "io/ioutil" 12 "math" 13 "reflect" 14 "strings" 15 "sync" 16 "testing" 17 ) 18 19 type Struct struct { 20 Int8 int8 21 Int16 int16 22 Int32 int32 23 Int64 int64 24 Uint8 uint8 25 Uint16 uint16 26 Uint32 uint32 27 Uint64 uint64 28 Float32 float32 29 Float64 float64 30 Complex64 complex64 31 Complex128 complex128 32 Array [4]uint8 33 Bool bool 34 BoolArray [4]bool 35 } 36 37 type T struct { 38 Int int 39 Uint uint 40 Uintptr uintptr 41 Array [4]int 42 } 43 44 var s = Struct{ 45 0x01, 46 0x0203, 47 0x04050607, 48 0x08090a0b0c0d0e0f, 49 0x10, 50 0x1112, 51 0x13141516, 52 0x1718191a1b1c1d1e, 53 54 math.Float32frombits(0x1f202122), 55 math.Float64frombits(0x232425262728292a), 56 complex( 57 math.Float32frombits(0x2b2c2d2e), 58 math.Float32frombits(0x2f303132), 59 ), 60 complex( 61 math.Float64frombits(0x333435363738393a), 62 math.Float64frombits(0x3b3c3d3e3f404142), 63 ), 64 65 [4]uint8{0x43, 0x44, 0x45, 0x46}, 66 67 true, 68 [4]bool{true, false, true, false}, 69 } 70 71 var big = []byte{ 72 1, 73 2, 3, 74 4, 5, 6, 7, 75 8, 9, 10, 11, 12, 13, 14, 15, 76 16, 77 17, 18, 78 19, 20, 21, 22, 79 23, 24, 25, 26, 27, 28, 29, 30, 80 81 31, 32, 33, 34, 82 35, 36, 37, 38, 39, 40, 41, 42, 83 43, 44, 45, 46, 47, 48, 49, 50, 84 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 85 86 67, 68, 69, 70, 87 88 1, 89 1, 0, 1, 0, 90 } 91 92 var little = []byte{ 93 1, 94 3, 2, 95 7, 6, 5, 4, 96 15, 14, 13, 12, 11, 10, 9, 8, 97 16, 98 18, 17, 99 22, 21, 20, 19, 100 30, 29, 28, 27, 26, 25, 24, 23, 101 102 34, 33, 32, 31, 103 42, 41, 40, 39, 38, 37, 36, 35, 104 46, 45, 44, 43, 50, 49, 48, 47, 105 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59, 106 107 67, 68, 69, 70, 108 109 1, 110 1, 0, 1, 0, 111 } 112 113 var src = []byte{1, 2, 3, 4, 5, 6, 7, 8} 114 var res = []int32{0x01020304, 0x05060708} 115 var putbuf = []byte{0, 0, 0, 0, 0, 0, 0, 0} 116 117 func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) { 118 if err != nil { 119 t.Errorf("%v %v: %v", dir, order, err) 120 return 121 } 122 if !reflect.DeepEqual(have, want) { 123 t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want) 124 } 125 } 126 127 func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) { 128 var s2 Struct 129 err := Read(bytes.NewReader(b), order, &s2) 130 checkResult(t, "Read", order, err, s2, s1) 131 } 132 133 func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) { 134 buf := new(bytes.Buffer) 135 err := Write(buf, order, s1) 136 checkResult(t, "Write", order, err, buf.Bytes(), b) 137 } 138 139 func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) } 140 func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) } 141 func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) } 142 143 func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) } 144 func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) } 145 func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) } 146 147 func TestReadSlice(t *testing.T) { 148 slice := make([]int32, 2) 149 err := Read(bytes.NewReader(src), BigEndian, slice) 150 checkResult(t, "ReadSlice", BigEndian, err, slice, res) 151 } 152 153 func TestWriteSlice(t *testing.T) { 154 buf := new(bytes.Buffer) 155 err := Write(buf, BigEndian, res) 156 checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src) 157 } 158 159 func TestReadBool(t *testing.T) { 160 var res bool 161 var err error 162 err = Read(bytes.NewReader([]byte{0}), BigEndian, &res) 163 checkResult(t, "ReadBool", BigEndian, err, res, false) 164 res = false 165 err = Read(bytes.NewReader([]byte{1}), BigEndian, &res) 166 checkResult(t, "ReadBool", BigEndian, err, res, true) 167 res = false 168 err = Read(bytes.NewReader([]byte{2}), BigEndian, &res) 169 checkResult(t, "ReadBool", BigEndian, err, res, true) 170 } 171 172 func TestReadBoolSlice(t *testing.T) { 173 slice := make([]bool, 4) 174 err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice) 175 checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true}) 176 } 177 178 // Addresses of arrays are easier to manipulate with reflection than are slices. 179 var intArrays = []interface{}{ 180 &[100]int8{}, 181 &[100]int16{}, 182 &[100]int32{}, 183 &[100]int64{}, 184 &[100]uint8{}, 185 &[100]uint16{}, 186 &[100]uint32{}, 187 &[100]uint64{}, 188 } 189 190 func TestSliceRoundTrip(t *testing.T) { 191 buf := new(bytes.Buffer) 192 for _, array := range intArrays { 193 src := reflect.ValueOf(array).Elem() 194 unsigned := false 195 switch src.Index(0).Kind() { 196 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 197 unsigned = true 198 } 199 for i := 0; i < src.Len(); i++ { 200 if unsigned { 201 src.Index(i).SetUint(uint64(i * 0x07654321)) 202 } else { 203 src.Index(i).SetInt(int64(i * 0x07654321)) 204 } 205 } 206 buf.Reset() 207 srcSlice := src.Slice(0, src.Len()) 208 err := Write(buf, BigEndian, srcSlice.Interface()) 209 if err != nil { 210 t.Fatal(err) 211 } 212 dst := reflect.New(src.Type()).Elem() 213 dstSlice := dst.Slice(0, dst.Len()) 214 err = Read(buf, BigEndian, dstSlice.Interface()) 215 if err != nil { 216 t.Fatal(err) 217 } 218 if !reflect.DeepEqual(src.Interface(), dst.Interface()) { 219 t.Fatal(src) 220 } 221 } 222 } 223 224 func TestWriteT(t *testing.T) { 225 buf := new(bytes.Buffer) 226 ts := T{} 227 if err := Write(buf, BigEndian, ts); err == nil { 228 t.Errorf("WriteT: have err == nil, want non-nil") 229 } 230 231 tv := reflect.Indirect(reflect.ValueOf(ts)) 232 for i, n := 0, tv.NumField(); i < n; i++ { 233 typ := tv.Field(i).Type().String() 234 if typ == "[4]int" { 235 typ = "int" // the problem is int, not the [4] 236 } 237 if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil { 238 t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type()) 239 } else if !strings.Contains(err.Error(), typ) { 240 t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ) 241 } 242 } 243 } 244 245 type BlankFields struct { 246 A uint32 247 _ int32 248 B float64 249 _ [4]int16 250 C byte 251 _ [7]byte 252 _ struct { 253 f [8]float32 254 } 255 } 256 257 type BlankFieldsProbe struct { 258 A uint32 259 P0 int32 260 B float64 261 P1 [4]int16 262 C byte 263 P2 [7]byte 264 P3 struct { 265 F [8]float32 266 } 267 } 268 269 func TestBlankFields(t *testing.T) { 270 buf := new(bytes.Buffer) 271 b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42} 272 if err := Write(buf, LittleEndian, &b1); err != nil { 273 t.Error(err) 274 } 275 276 // zero values must have been written for blank fields 277 var p BlankFieldsProbe 278 if err := Read(buf, LittleEndian, &p); err != nil { 279 t.Error(err) 280 } 281 282 // quick test: only check first value of slices 283 if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 { 284 t.Errorf("non-zero values for originally blank fields: %#v", p) 285 } 286 287 // write p and see if we can probe only some fields 288 if err := Write(buf, LittleEndian, &p); err != nil { 289 t.Error(err) 290 } 291 292 // read should ignore blank fields in b2 293 var b2 BlankFields 294 if err := Read(buf, LittleEndian, &b2); err != nil { 295 t.Error(err) 296 } 297 if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C { 298 t.Errorf("%#v != %#v", b1, b2) 299 } 300 } 301 302 func TestSizeStructCache(t *testing.T) { 303 // Reset the cache, otherwise multiple test runs fail. 304 structSize = sync.Map{} 305 306 count := func() int { 307 var i int 308 structSize.Range(func(_, _ interface{}) bool { 309 i++ 310 return true 311 }) 312 return i 313 } 314 315 var total int 316 added := func() int { 317 delta := count() - total 318 total += delta 319 return delta 320 } 321 322 type foo struct { 323 A uint32 324 } 325 326 type bar struct { 327 A Struct 328 B foo 329 C Struct 330 } 331 332 testcases := []struct { 333 val interface{} 334 want int 335 }{ 336 {new(foo), 1}, 337 {new(bar), 1}, 338 {new(bar), 0}, 339 {new(struct{ A Struct }), 1}, 340 {new(struct{ A Struct }), 0}, 341 } 342 343 for _, tc := range testcases { 344 if Size(tc.val) == -1 { 345 t.Fatalf("Can't get the size of %T", tc.val) 346 } 347 348 if n := added(); n != tc.want { 349 t.Errorf("Sizing %T added %d entries to the cache, want %d", tc.val, n, tc.want) 350 } 351 } 352 } 353 354 // An attempt to read into a struct with an unexported field will 355 // panic. This is probably not the best choice, but at this point 356 // anything else would be an API change. 357 358 type Unexported struct { 359 a int32 360 } 361 362 func TestUnexportedRead(t *testing.T) { 363 var buf bytes.Buffer 364 u1 := Unexported{a: 1} 365 if err := Write(&buf, LittleEndian, &u1); err != nil { 366 t.Fatal(err) 367 } 368 369 defer func() { 370 if recover() == nil { 371 t.Fatal("did not panic") 372 } 373 }() 374 var u2 Unexported 375 Read(&buf, LittleEndian, &u2) 376 } 377 378 func TestReadErrorMsg(t *testing.T) { 379 var buf bytes.Buffer 380 read := func(data interface{}) { 381 err := Read(&buf, LittleEndian, data) 382 want := "binary.Read: invalid type " + reflect.TypeOf(data).String() 383 if err == nil { 384 t.Errorf("%T: got no error; want %q", data, want) 385 return 386 } 387 if got := err.Error(); got != want { 388 t.Errorf("%T: got %q; want %q", data, got, want) 389 } 390 } 391 read(0) 392 s := new(struct{}) 393 read(&s) 394 p := &s 395 read(&p) 396 } 397 398 func TestReadTruncated(t *testing.T) { 399 const data = "0123456789abcdef" 400 401 var b1 = make([]int32, 4) 402 var b2 struct { 403 A, B, C, D byte 404 E int32 405 F float64 406 } 407 408 for i := 0; i <= len(data); i++ { 409 var errWant error 410 switch i { 411 case 0: 412 errWant = io.EOF 413 case len(data): 414 errWant = nil 415 default: 416 errWant = io.ErrUnexpectedEOF 417 } 418 419 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant { 420 t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant) 421 } 422 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant { 423 t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant) 424 } 425 } 426 } 427 428 func testUint64SmallSliceLengthPanics() (panicked bool) { 429 defer func() { 430 panicked = recover() != nil 431 }() 432 b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} 433 LittleEndian.Uint64(b[:4]) 434 return false 435 } 436 437 func testPutUint64SmallSliceLengthPanics() (panicked bool) { 438 defer func() { 439 panicked = recover() != nil 440 }() 441 b := [8]byte{} 442 LittleEndian.PutUint64(b[:4], 0x0102030405060708) 443 return false 444 } 445 446 func TestEarlyBoundsChecks(t *testing.T) { 447 if testUint64SmallSliceLengthPanics() != true { 448 t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't") 449 } 450 if testPutUint64SmallSliceLengthPanics() != true { 451 t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't") 452 } 453 } 454 455 func TestReadInvalidDestination(t *testing.T) { 456 testReadInvalidDestination(t, BigEndian) 457 testReadInvalidDestination(t, LittleEndian) 458 } 459 460 func testReadInvalidDestination(t *testing.T, order ByteOrder) { 461 destinations := []interface{}{ 462 int8(0), 463 int16(0), 464 int32(0), 465 int64(0), 466 467 uint8(0), 468 uint16(0), 469 uint32(0), 470 uint64(0), 471 472 bool(false), 473 } 474 475 for _, dst := range destinations { 476 err := Read(bytes.NewReader([]byte{1, 2, 3, 4, 5, 6, 7, 8}), order, dst) 477 want := fmt.Sprintf("binary.Read: invalid type %T", dst) 478 if err == nil || err.Error() != want { 479 t.Fatalf("for type %T: got %q; want %q", dst, err, want) 480 } 481 } 482 } 483 484 type byteSliceReader struct { 485 remain []byte 486 } 487 488 func (br *byteSliceReader) Read(p []byte) (int, error) { 489 n := copy(p, br.remain) 490 br.remain = br.remain[n:] 491 return n, nil 492 } 493 494 func BenchmarkReadSlice1000Int32s(b *testing.B) { 495 bsr := &byteSliceReader{} 496 slice := make([]int32, 1000) 497 buf := make([]byte, len(slice)*4) 498 b.SetBytes(int64(len(buf))) 499 b.ResetTimer() 500 for i := 0; i < b.N; i++ { 501 bsr.remain = buf 502 Read(bsr, BigEndian, slice) 503 } 504 } 505 506 func BenchmarkReadStruct(b *testing.B) { 507 bsr := &byteSliceReader{} 508 var buf bytes.Buffer 509 Write(&buf, BigEndian, &s) 510 b.SetBytes(int64(dataSize(reflect.ValueOf(s)))) 511 t := s 512 b.ResetTimer() 513 for i := 0; i < b.N; i++ { 514 bsr.remain = buf.Bytes() 515 Read(bsr, BigEndian, &t) 516 } 517 b.StopTimer() 518 if b.N > 0 && !reflect.DeepEqual(s, t) { 519 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s) 520 } 521 } 522 523 func BenchmarkWriteStruct(b *testing.B) { 524 b.SetBytes(int64(Size(&s))) 525 b.ResetTimer() 526 for i := 0; i < b.N; i++ { 527 Write(ioutil.Discard, BigEndian, &s) 528 } 529 } 530 531 func BenchmarkReadInts(b *testing.B) { 532 var ls Struct 533 bsr := &byteSliceReader{} 534 var r io.Reader = bsr 535 b.SetBytes(2 * (1 + 2 + 4 + 8)) 536 b.ResetTimer() 537 for i := 0; i < b.N; i++ { 538 bsr.remain = big 539 Read(r, BigEndian, &ls.Int8) 540 Read(r, BigEndian, &ls.Int16) 541 Read(r, BigEndian, &ls.Int32) 542 Read(r, BigEndian, &ls.Int64) 543 Read(r, BigEndian, &ls.Uint8) 544 Read(r, BigEndian, &ls.Uint16) 545 Read(r, BigEndian, &ls.Uint32) 546 Read(r, BigEndian, &ls.Uint64) 547 } 548 b.StopTimer() 549 want := s 550 want.Float32 = 0 551 want.Float64 = 0 552 want.Complex64 = 0 553 want.Complex128 = 0 554 want.Array = [4]uint8{0, 0, 0, 0} 555 want.Bool = false 556 want.BoolArray = [4]bool{false, false, false, false} 557 if b.N > 0 && !reflect.DeepEqual(ls, want) { 558 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want) 559 } 560 } 561 562 func BenchmarkWriteInts(b *testing.B) { 563 buf := new(bytes.Buffer) 564 var w io.Writer = buf 565 b.SetBytes(2 * (1 + 2 + 4 + 8)) 566 b.ResetTimer() 567 for i := 0; i < b.N; i++ { 568 buf.Reset() 569 Write(w, BigEndian, s.Int8) 570 Write(w, BigEndian, s.Int16) 571 Write(w, BigEndian, s.Int32) 572 Write(w, BigEndian, s.Int64) 573 Write(w, BigEndian, s.Uint8) 574 Write(w, BigEndian, s.Uint16) 575 Write(w, BigEndian, s.Uint32) 576 Write(w, BigEndian, s.Uint64) 577 } 578 b.StopTimer() 579 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) { 580 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30]) 581 } 582 } 583 584 func BenchmarkWriteSlice1000Int32s(b *testing.B) { 585 slice := make([]int32, 1000) 586 buf := new(bytes.Buffer) 587 var w io.Writer = buf 588 b.SetBytes(4 * 1000) 589 b.ResetTimer() 590 for i := 0; i < b.N; i++ { 591 buf.Reset() 592 Write(w, BigEndian, slice) 593 } 594 b.StopTimer() 595 } 596 597 func BenchmarkPutUint16(b *testing.B) { 598 b.SetBytes(2) 599 for i := 0; i < b.N; i++ { 600 BigEndian.PutUint16(putbuf[:], uint16(i)) 601 } 602 } 603 604 func BenchmarkPutUint32(b *testing.B) { 605 b.SetBytes(4) 606 for i := 0; i < b.N; i++ { 607 BigEndian.PutUint32(putbuf[:], uint32(i)) 608 } 609 } 610 611 func BenchmarkPutUint64(b *testing.B) { 612 b.SetBytes(8) 613 for i := 0; i < b.N; i++ { 614 BigEndian.PutUint64(putbuf[:], uint64(i)) 615 } 616 } 617 func BenchmarkLittleEndianPutUint16(b *testing.B) { 618 b.SetBytes(2) 619 for i := 0; i < b.N; i++ { 620 LittleEndian.PutUint16(putbuf[:], uint16(i)) 621 } 622 } 623 624 func BenchmarkLittleEndianPutUint32(b *testing.B) { 625 b.SetBytes(4) 626 for i := 0; i < b.N; i++ { 627 LittleEndian.PutUint32(putbuf[:], uint32(i)) 628 } 629 } 630 631 func BenchmarkLittleEndianPutUint64(b *testing.B) { 632 b.SetBytes(8) 633 for i := 0; i < b.N; i++ { 634 LittleEndian.PutUint64(putbuf[:], uint64(i)) 635 } 636 } 637 638 func BenchmarkReadFloats(b *testing.B) { 639 var ls Struct 640 bsr := &byteSliceReader{} 641 var r io.Reader = bsr 642 b.SetBytes(4 + 8) 643 b.ResetTimer() 644 for i := 0; i < b.N; i++ { 645 bsr.remain = big[30:] 646 Read(r, BigEndian, &ls.Float32) 647 Read(r, BigEndian, &ls.Float64) 648 } 649 b.StopTimer() 650 want := s 651 want.Int8 = 0 652 want.Int16 = 0 653 want.Int32 = 0 654 want.Int64 = 0 655 want.Uint8 = 0 656 want.Uint16 = 0 657 want.Uint32 = 0 658 want.Uint64 = 0 659 want.Complex64 = 0 660 want.Complex128 = 0 661 want.Array = [4]uint8{0, 0, 0, 0} 662 want.Bool = false 663 want.BoolArray = [4]bool{false, false, false, false} 664 if b.N > 0 && !reflect.DeepEqual(ls, want) { 665 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want) 666 } 667 } 668 669 func BenchmarkWriteFloats(b *testing.B) { 670 buf := new(bytes.Buffer) 671 var w io.Writer = buf 672 b.SetBytes(4 + 8) 673 b.ResetTimer() 674 for i := 0; i < b.N; i++ { 675 buf.Reset() 676 Write(w, BigEndian, s.Float32) 677 Write(w, BigEndian, s.Float64) 678 } 679 b.StopTimer() 680 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[30:30+4+8]) { 681 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[30:30+4+8]) 682 } 683 } 684 685 func BenchmarkReadSlice1000Float32s(b *testing.B) { 686 bsr := &byteSliceReader{} 687 slice := make([]float32, 1000) 688 buf := make([]byte, len(slice)*4) 689 b.SetBytes(int64(len(buf))) 690 b.ResetTimer() 691 for i := 0; i < b.N; i++ { 692 bsr.remain = buf 693 Read(bsr, BigEndian, slice) 694 } 695 } 696 697 func BenchmarkWriteSlice1000Float32s(b *testing.B) { 698 slice := make([]float32, 1000) 699 buf := new(bytes.Buffer) 700 var w io.Writer = buf 701 b.SetBytes(4 * 1000) 702 b.ResetTimer() 703 for i := 0; i < b.N; i++ { 704 buf.Reset() 705 Write(w, BigEndian, slice) 706 } 707 b.StopTimer() 708 }