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 113 func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) { 114 if err != nil { 115 t.Errorf("%v %v: %v", dir, order, err) 116 return 117 } 118 if !reflect.DeepEqual(have, want) { 119 t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want) 120 } 121 } 122 123 func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) { 124 var s2 Struct 125 err := Read(bytes.NewReader(b), order, &s2) 126 checkResult(t, "Read", order, err, s2, s1) 127 } 128 129 func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) { 130 buf := new(bytes.Buffer) 131 err := Write(buf, order, s1) 132 checkResult(t, "Write", order, err, buf.Bytes(), b) 133 } 134 135 func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) } 136 func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) } 137 func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) } 138 139 func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) } 140 func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) } 141 func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) } 142 143 func TestReadSlice(t *testing.T) { 144 slice := make([]int32, 2) 145 err := Read(bytes.NewReader(src), BigEndian, slice) 146 checkResult(t, "ReadSlice", BigEndian, err, slice, res) 147 } 148 149 func TestWriteSlice(t *testing.T) { 150 buf := new(bytes.Buffer) 151 err := Write(buf, BigEndian, res) 152 checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src) 153 } 154 155 func TestReadBool(t *testing.T) { 156 var res bool 157 var err error 158 err = Read(bytes.NewReader([]byte{0}), BigEndian, &res) 159 checkResult(t, "ReadBool", BigEndian, err, res, false) 160 res = false 161 err = Read(bytes.NewReader([]byte{1}), BigEndian, &res) 162 checkResult(t, "ReadBool", BigEndian, err, res, true) 163 res = false 164 err = Read(bytes.NewReader([]byte{2}), BigEndian, &res) 165 checkResult(t, "ReadBool", BigEndian, err, res, true) 166 } 167 168 func TestReadBoolSlice(t *testing.T) { 169 slice := make([]bool, 4) 170 err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice) 171 checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true}) 172 } 173 174 // Addresses of arrays are easier to manipulate with reflection than are slices. 175 var intArrays = []interface{}{ 176 &[100]int8{}, 177 &[100]int16{}, 178 &[100]int32{}, 179 &[100]int64{}, 180 &[100]uint8{}, 181 &[100]uint16{}, 182 &[100]uint32{}, 183 &[100]uint64{}, 184 } 185 186 func TestSliceRoundTrip(t *testing.T) { 187 buf := new(bytes.Buffer) 188 for _, array := range intArrays { 189 src := reflect.ValueOf(array).Elem() 190 unsigned := false 191 switch src.Index(0).Kind() { 192 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 193 unsigned = true 194 } 195 for i := 0; i < src.Len(); i++ { 196 if unsigned { 197 src.Index(i).SetUint(uint64(i * 0x07654321)) 198 } else { 199 src.Index(i).SetInt(int64(i * 0x07654321)) 200 } 201 } 202 buf.Reset() 203 srcSlice := src.Slice(0, src.Len()) 204 err := Write(buf, BigEndian, srcSlice.Interface()) 205 if err != nil { 206 t.Fatal(err) 207 } 208 dst := reflect.New(src.Type()).Elem() 209 dstSlice := dst.Slice(0, dst.Len()) 210 err = Read(buf, BigEndian, dstSlice.Interface()) 211 if err != nil { 212 t.Fatal(err) 213 } 214 if !reflect.DeepEqual(src.Interface(), dst.Interface()) { 215 t.Fatal(src) 216 } 217 } 218 } 219 220 func TestWriteT(t *testing.T) { 221 buf := new(bytes.Buffer) 222 ts := T{} 223 if err := Write(buf, BigEndian, ts); err == nil { 224 t.Errorf("WriteT: have err == nil, want non-nil") 225 } 226 227 tv := reflect.Indirect(reflect.ValueOf(ts)) 228 for i, n := 0, tv.NumField(); i < n; i++ { 229 typ := tv.Field(i).Type().String() 230 if typ == "[4]int" { 231 typ = "int" // the problem is int, not the [4] 232 } 233 if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil { 234 t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type()) 235 } else if !strings.Contains(err.Error(), typ) { 236 t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ) 237 } 238 } 239 } 240 241 type BlankFields struct { 242 A uint32 243 _ int32 244 B float64 245 _ [4]int16 246 C byte 247 _ [7]byte 248 _ struct { 249 f [8]float32 250 } 251 } 252 253 type BlankFieldsProbe struct { 254 A uint32 255 P0 int32 256 B float64 257 P1 [4]int16 258 C byte 259 P2 [7]byte 260 P3 struct { 261 F [8]float32 262 } 263 } 264 265 func TestBlankFields(t *testing.T) { 266 buf := new(bytes.Buffer) 267 b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42} 268 if err := Write(buf, LittleEndian, &b1); err != nil { 269 t.Error(err) 270 } 271 272 // zero values must have been written for blank fields 273 var p BlankFieldsProbe 274 if err := Read(buf, LittleEndian, &p); err != nil { 275 t.Error(err) 276 } 277 278 // quick test: only check first value of slices 279 if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 { 280 t.Errorf("non-zero values for originally blank fields: %#v", p) 281 } 282 283 // write p and see if we can probe only some fields 284 if err := Write(buf, LittleEndian, &p); err != nil { 285 t.Error(err) 286 } 287 288 // read should ignore blank fields in b2 289 var b2 BlankFields 290 if err := Read(buf, LittleEndian, &b2); err != nil { 291 t.Error(err) 292 } 293 if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C { 294 t.Errorf("%#v != %#v", b1, b2) 295 } 296 } 297 298 // An attempt to read into a struct with an unexported field will 299 // panic. This is probably not the best choice, but at this point 300 // anything else would be an API change. 301 302 type Unexported struct { 303 a int32 304 } 305 306 func TestUnexportedRead(t *testing.T) { 307 var buf bytes.Buffer 308 u1 := Unexported{a: 1} 309 if err := Write(&buf, LittleEndian, &u1); err != nil { 310 t.Fatal(err) 311 } 312 313 defer func() { 314 if recover() == nil { 315 t.Fatal("did not panic") 316 } 317 }() 318 var u2 Unexported 319 Read(&buf, LittleEndian, &u2) 320 } 321 322 func TestReadErrorMsg(t *testing.T) { 323 var buf bytes.Buffer 324 read := func(data interface{}) { 325 err := Read(&buf, LittleEndian, data) 326 want := "binary.Read: invalid type " + reflect.TypeOf(data).String() 327 if err == nil { 328 t.Errorf("%T: got no error; want %q", data, want) 329 return 330 } 331 if got := err.Error(); got != want { 332 t.Errorf("%T: got %q; want %q", data, got, want) 333 } 334 } 335 read(0) 336 s := new(struct{}) 337 read(&s) 338 p := &s 339 read(&p) 340 } 341 342 func TestReadTruncated(t *testing.T) { 343 const data = "0123456789abcdef" 344 345 var b1 = make([]int32, 4) 346 var b2 struct { 347 A, B, C, D byte 348 E int32 349 F float64 350 } 351 352 for i := 0; i <= len(data); i++ { 353 var errWant error 354 switch i { 355 case 0: 356 errWant = io.EOF 357 case len(data): 358 errWant = nil 359 default: 360 errWant = io.ErrUnexpectedEOF 361 } 362 363 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant { 364 t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant) 365 } 366 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant { 367 t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant) 368 } 369 } 370 } 371 372 func testUint64SmallSliceLengthPanics() (panicked bool) { 373 defer func() { 374 panicked = recover() != nil 375 }() 376 b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} 377 LittleEndian.Uint64(b[:4]) 378 return false 379 } 380 381 func testPutUint64SmallSliceLengthPanics() (panicked bool) { 382 defer func() { 383 panicked = recover() != nil 384 }() 385 b := [8]byte{} 386 LittleEndian.PutUint64(b[:4], 0x0102030405060708) 387 return false 388 } 389 390 func TestEarlyBoundsChecks(t *testing.T) { 391 if testUint64SmallSliceLengthPanics() != true { 392 t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't") 393 } 394 if testPutUint64SmallSliceLengthPanics() != true { 395 t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't") 396 } 397 } 398 399 type byteSliceReader struct { 400 remain []byte 401 } 402 403 func (br *byteSliceReader) Read(p []byte) (int, error) { 404 n := copy(p, br.remain) 405 br.remain = br.remain[n:] 406 return n, nil 407 } 408 409 func BenchmarkReadSlice1000Int32s(b *testing.B) { 410 bsr := &byteSliceReader{} 411 slice := make([]int32, 1000) 412 buf := make([]byte, len(slice)*4) 413 b.SetBytes(int64(len(buf))) 414 b.ResetTimer() 415 for i := 0; i < b.N; i++ { 416 bsr.remain = buf 417 Read(bsr, BigEndian, slice) 418 } 419 } 420 421 func BenchmarkReadStruct(b *testing.B) { 422 bsr := &byteSliceReader{} 423 var buf bytes.Buffer 424 Write(&buf, BigEndian, &s) 425 b.SetBytes(int64(dataSize(reflect.ValueOf(s)))) 426 t := s 427 b.ResetTimer() 428 for i := 0; i < b.N; i++ { 429 bsr.remain = buf.Bytes() 430 Read(bsr, BigEndian, &t) 431 } 432 b.StopTimer() 433 if b.N > 0 && !reflect.DeepEqual(s, t) { 434 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s) 435 } 436 } 437 438 func BenchmarkReadInts(b *testing.B) { 439 var ls Struct 440 bsr := &byteSliceReader{} 441 var r io.Reader = bsr 442 b.SetBytes(2 * (1 + 2 + 4 + 8)) 443 b.ResetTimer() 444 for i := 0; i < b.N; i++ { 445 bsr.remain = big 446 Read(r, BigEndian, &ls.Int8) 447 Read(r, BigEndian, &ls.Int16) 448 Read(r, BigEndian, &ls.Int32) 449 Read(r, BigEndian, &ls.Int64) 450 Read(r, BigEndian, &ls.Uint8) 451 Read(r, BigEndian, &ls.Uint16) 452 Read(r, BigEndian, &ls.Uint32) 453 Read(r, BigEndian, &ls.Uint64) 454 } 455 b.StopTimer() 456 want := s 457 want.Float32 = 0 458 want.Float64 = 0 459 want.Complex64 = 0 460 want.Complex128 = 0 461 want.Array = [4]uint8{0, 0, 0, 0} 462 want.Bool = false 463 want.BoolArray = [4]bool{false, false, false, false} 464 if b.N > 0 && !reflect.DeepEqual(ls, want) { 465 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want) 466 } 467 } 468 469 func BenchmarkWriteInts(b *testing.B) { 470 buf := new(bytes.Buffer) 471 var w io.Writer = buf 472 b.SetBytes(2 * (1 + 2 + 4 + 8)) 473 b.ResetTimer() 474 for i := 0; i < b.N; i++ { 475 buf.Reset() 476 Write(w, BigEndian, s.Int8) 477 Write(w, BigEndian, s.Int16) 478 Write(w, BigEndian, s.Int32) 479 Write(w, BigEndian, s.Int64) 480 Write(w, BigEndian, s.Uint8) 481 Write(w, BigEndian, s.Uint16) 482 Write(w, BigEndian, s.Uint32) 483 Write(w, BigEndian, s.Uint64) 484 } 485 b.StopTimer() 486 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) { 487 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30]) 488 } 489 } 490 491 func BenchmarkWriteSlice1000Int32s(b *testing.B) { 492 slice := make([]int32, 1000) 493 buf := new(bytes.Buffer) 494 var w io.Writer = buf 495 b.SetBytes(4 * 1000) 496 b.ResetTimer() 497 for i := 0; i < b.N; i++ { 498 buf.Reset() 499 Write(w, BigEndian, slice) 500 } 501 b.StopTimer() 502 } 503