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