github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/compress/flate/deflate_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 flate 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "internal/testenv" 12 "io" 13 "io/ioutil" 14 "reflect" 15 "sync" 16 "testing" 17 ) 18 19 type deflateTest struct { 20 in []byte 21 level int 22 out []byte 23 } 24 25 type deflateInflateTest struct { 26 in []byte 27 } 28 29 type reverseBitsTest struct { 30 in uint16 31 bitCount uint8 32 out uint16 33 } 34 35 var deflateTests = []*deflateTest{ 36 {[]byte{}, 0, []byte{1, 0, 0, 255, 255}}, 37 {[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}}, 38 {[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}}, 39 {[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}}, 40 41 {[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}}, 42 {[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}}, 43 {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0, 44 []byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255}, 45 }, 46 {[]byte{}, 2, []byte{1, 0, 0, 255, 255}}, 47 {[]byte{0x11}, 2, []byte{18, 4, 4, 0, 0, 255, 255}}, 48 {[]byte{0x11, 0x12}, 2, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, 49 {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 2, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, 50 {[]byte{}, 9, []byte{1, 0, 0, 255, 255}}, 51 {[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}}, 52 {[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}}, 53 {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}}, 54 } 55 56 var deflateInflateTests = []*deflateInflateTest{ 57 {[]byte{}}, 58 {[]byte{0x11}}, 59 {[]byte{0x11, 0x12}}, 60 {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}}, 61 {[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}}, 62 {largeDataChunk()}, 63 } 64 65 var reverseBitsTests = []*reverseBitsTest{ 66 {1, 1, 1}, 67 {1, 2, 2}, 68 {1, 3, 4}, 69 {1, 4, 8}, 70 {1, 5, 16}, 71 {17, 5, 17}, 72 {257, 9, 257}, 73 {29, 5, 23}, 74 } 75 76 func largeDataChunk() []byte { 77 result := make([]byte, 100000) 78 for i := range result { 79 result[i] = byte(i * i & 0xFF) 80 } 81 return result 82 } 83 84 func TestBulkHash4(t *testing.T) { 85 for _, x := range deflateTests { 86 y := x.out 87 if len(y) < minMatchLength { 88 continue 89 } 90 y = append(y, y...) 91 for j := 4; j < len(y); j++ { 92 y := y[:j] 93 dst := make([]uint32, len(y)-minMatchLength+1) 94 for i := range dst { 95 dst[i] = uint32(i + 100) 96 } 97 bulkHash4(y, dst) 98 for i, got := range dst { 99 want := hash4(y[i:]) 100 if got != want && got == uint32(i)+100 { 101 t.Errorf("Len:%d Index:%d, want 0x%08x but not modified", len(y), i, want) 102 } else if got != want { 103 t.Errorf("Len:%d Index:%d, got 0x%08x want:0x%08x", len(y), i, got, want) 104 } 105 } 106 } 107 } 108 } 109 110 func TestDeflate(t *testing.T) { 111 for _, h := range deflateTests { 112 var buf bytes.Buffer 113 w, err := NewWriter(&buf, h.level) 114 if err != nil { 115 t.Errorf("NewWriter: %v", err) 116 continue 117 } 118 w.Write(h.in) 119 w.Close() 120 if !bytes.Equal(buf.Bytes(), h.out) { 121 t.Errorf("Deflate(%d, %x) = \n%#v, want \n%#v", h.level, h.in, buf.Bytes(), h.out) 122 } 123 } 124 } 125 126 // A sparseReader returns a stream consisting of 0s followed by 1<<16 1s. 127 // This tests missing hash references in a very large input. 128 type sparseReader struct { 129 l int64 130 cur int64 131 } 132 133 func (r *sparseReader) Read(b []byte) (n int, err error) { 134 if r.cur >= r.l { 135 return 0, io.EOF 136 } 137 n = len(b) 138 cur := r.cur + int64(n) 139 if cur > r.l { 140 n -= int(cur - r.l) 141 cur = r.l 142 } 143 for i := range b[0:n] { 144 if r.cur+int64(i) >= r.l-1<<16 { 145 b[i] = 1 146 } else { 147 b[i] = 0 148 } 149 } 150 r.cur = cur 151 return 152 } 153 154 func TestVeryLongSparseChunk(t *testing.T) { 155 if testing.Short() { 156 t.Skip("skipping sparse chunk during short test") 157 } 158 w, err := NewWriter(ioutil.Discard, 1) 159 if err != nil { 160 t.Errorf("NewWriter: %v", err) 161 return 162 } 163 if _, err = io.Copy(w, &sparseReader{l: 23E8}); err != nil { 164 t.Errorf("Compress failed: %v", err) 165 return 166 } 167 } 168 169 type syncBuffer struct { 170 buf bytes.Buffer 171 mu sync.RWMutex 172 closed bool 173 ready chan bool 174 } 175 176 func newSyncBuffer() *syncBuffer { 177 return &syncBuffer{ready: make(chan bool, 1)} 178 } 179 180 func (b *syncBuffer) Read(p []byte) (n int, err error) { 181 for { 182 b.mu.RLock() 183 n, err = b.buf.Read(p) 184 b.mu.RUnlock() 185 if n > 0 || b.closed { 186 return 187 } 188 <-b.ready 189 } 190 } 191 192 func (b *syncBuffer) signal() { 193 select { 194 case b.ready <- true: 195 default: 196 } 197 } 198 199 func (b *syncBuffer) Write(p []byte) (n int, err error) { 200 n, err = b.buf.Write(p) 201 b.signal() 202 return 203 } 204 205 func (b *syncBuffer) WriteMode() { 206 b.mu.Lock() 207 } 208 209 func (b *syncBuffer) ReadMode() { 210 b.mu.Unlock() 211 b.signal() 212 } 213 214 func (b *syncBuffer) Close() error { 215 b.closed = true 216 b.signal() 217 return nil 218 } 219 220 func testSync(t *testing.T, level int, input []byte, name string) { 221 if len(input) == 0 { 222 return 223 } 224 225 t.Logf("--testSync %d, %d, %s", level, len(input), name) 226 buf := newSyncBuffer() 227 buf1 := new(bytes.Buffer) 228 buf.WriteMode() 229 w, err := NewWriter(io.MultiWriter(buf, buf1), level) 230 if err != nil { 231 t.Errorf("NewWriter: %v", err) 232 return 233 } 234 r := NewReader(buf) 235 236 // Write half the input and read back. 237 for i := 0; i < 2; i++ { 238 var lo, hi int 239 if i == 0 { 240 lo, hi = 0, (len(input)+1)/2 241 } else { 242 lo, hi = (len(input)+1)/2, len(input) 243 } 244 t.Logf("#%d: write %d-%d", i, lo, hi) 245 if _, err := w.Write(input[lo:hi]); err != nil { 246 t.Errorf("testSync: write: %v", err) 247 return 248 } 249 if i == 0 { 250 if err := w.Flush(); err != nil { 251 t.Errorf("testSync: flush: %v", err) 252 return 253 } 254 } else { 255 if err := w.Close(); err != nil { 256 t.Errorf("testSync: close: %v", err) 257 } 258 } 259 buf.ReadMode() 260 out := make([]byte, hi-lo+1) 261 m, err := io.ReadAtLeast(r, out, hi-lo) 262 t.Logf("#%d: read %d", i, m) 263 if m != hi-lo || err != nil { 264 t.Errorf("testSync/%d (%d, %d, %s): read %d: %d, %v (%d left)", i, level, len(input), name, hi-lo, m, err, buf.buf.Len()) 265 return 266 } 267 if !bytes.Equal(input[lo:hi], out[:hi-lo]) { 268 t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo]) 269 return 270 } 271 // This test originally checked that after reading 272 // the first half of the input, there was nothing left 273 // in the read buffer (buf.buf.Len() != 0) but that is 274 // not necessarily the case: the write Flush may emit 275 // some extra framing bits that are not necessary 276 // to process to obtain the first half of the uncompressed 277 // data. The test ran correctly most of the time, because 278 // the background goroutine had usually read even 279 // those extra bits by now, but it's not a useful thing to 280 // check. 281 buf.WriteMode() 282 } 283 buf.ReadMode() 284 out := make([]byte, 10) 285 if n, err := r.Read(out); n > 0 || err != io.EOF { 286 t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n]) 287 } 288 if buf.buf.Len() != 0 { 289 t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name) 290 } 291 r.Close() 292 293 // stream should work for ordinary reader too 294 r = NewReader(buf1) 295 out, err = ioutil.ReadAll(r) 296 if err != nil { 297 t.Errorf("testSync: read: %s", err) 298 return 299 } 300 r.Close() 301 if !bytes.Equal(input, out) { 302 t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name) 303 } 304 } 305 306 func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) { 307 var buffer bytes.Buffer 308 w, err := NewWriter(&buffer, level) 309 if err != nil { 310 t.Errorf("NewWriter: %v", err) 311 return 312 } 313 w.Write(input) 314 w.Close() 315 if limit > 0 && buffer.Len() > limit { 316 t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit) 317 return 318 } 319 if limit > 0 { 320 t.Logf("level: %d, size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len()) 321 } 322 r := NewReader(&buffer) 323 out, err := ioutil.ReadAll(r) 324 if err != nil { 325 t.Errorf("read: %s", err) 326 return 327 } 328 r.Close() 329 if !bytes.Equal(input, out) { 330 t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name) 331 return 332 } 333 testSync(t, level, input, name) 334 } 335 336 func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) { 337 for i := 0; i < 10; i++ { 338 testToFromWithLevelAndLimit(t, i, input, name, limit[i]) 339 } 340 // Test HuffmanCompression 341 testToFromWithLevelAndLimit(t, -2, input, name, limit[10]) 342 } 343 344 func TestDeflateInflate(t *testing.T) { 345 for i, h := range deflateInflateTests { 346 testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{}) 347 } 348 } 349 350 func TestReverseBits(t *testing.T) { 351 for _, h := range reverseBitsTests { 352 if v := reverseBits(h.in, h.bitCount); v != h.out { 353 t.Errorf("reverseBits(%v,%v) = %v, want %v", 354 h.in, h.bitCount, v, h.out) 355 } 356 } 357 } 358 359 type deflateInflateStringTest struct { 360 filename string 361 label string 362 limit [11]int 363 } 364 365 var deflateInflateStringTests = []deflateInflateStringTest{ 366 { 367 "../testdata/e.txt", 368 "2.718281828...", 369 [...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683}, 370 }, 371 { 372 "../testdata/Mark.Twain-Tom.Sawyer.txt", 373 "Mark.Twain-Tom.Sawyer", 374 [...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295, 233460}, 375 }, 376 } 377 378 func TestDeflateInflateString(t *testing.T) { 379 if testing.Short() && testenv.Builder() == "" { 380 t.Skip("skipping in short mode") 381 } 382 for _, test := range deflateInflateStringTests { 383 gold, err := ioutil.ReadFile(test.filename) 384 if err != nil { 385 t.Error(err) 386 } 387 testToFromWithLimit(t, gold, test.label, test.limit) 388 if testing.Short() { 389 break 390 } 391 } 392 } 393 394 func TestReaderDict(t *testing.T) { 395 const ( 396 dict = "hello world" 397 text = "hello again world" 398 ) 399 var b bytes.Buffer 400 w, err := NewWriter(&b, 5) 401 if err != nil { 402 t.Fatalf("NewWriter: %v", err) 403 } 404 w.Write([]byte(dict)) 405 w.Flush() 406 b.Reset() 407 w.Write([]byte(text)) 408 w.Close() 409 410 r := NewReaderDict(&b, []byte(dict)) 411 data, err := ioutil.ReadAll(r) 412 if err != nil { 413 t.Fatal(err) 414 } 415 if string(data) != "hello again world" { 416 t.Fatalf("read returned %q want %q", string(data), text) 417 } 418 } 419 420 func TestWriterDict(t *testing.T) { 421 const ( 422 dict = "hello world" 423 text = "hello again world" 424 ) 425 var b bytes.Buffer 426 w, err := NewWriter(&b, 5) 427 if err != nil { 428 t.Fatalf("NewWriter: %v", err) 429 } 430 w.Write([]byte(dict)) 431 w.Flush() 432 b.Reset() 433 w.Write([]byte(text)) 434 w.Close() 435 436 var b1 bytes.Buffer 437 w, _ = NewWriterDict(&b1, 5, []byte(dict)) 438 w.Write([]byte(text)) 439 w.Close() 440 441 if !bytes.Equal(b1.Bytes(), b.Bytes()) { 442 t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes()) 443 } 444 } 445 446 // See https://golang.org/issue/2508 447 func TestRegression2508(t *testing.T) { 448 if testing.Short() { 449 t.Logf("test disabled with -short") 450 return 451 } 452 w, err := NewWriter(ioutil.Discard, 1) 453 if err != nil { 454 t.Fatalf("NewWriter: %v", err) 455 } 456 buf := make([]byte, 1024) 457 for i := 0; i < 131072; i++ { 458 if _, err := w.Write(buf); err != nil { 459 t.Fatalf("writer failed: %v", err) 460 } 461 } 462 w.Close() 463 } 464 465 func TestWriterReset(t *testing.T) { 466 for level := 0; level <= 9; level++ { 467 if testing.Short() && level > 1 { 468 break 469 } 470 w, err := NewWriter(ioutil.Discard, level) 471 if err != nil { 472 t.Fatalf("NewWriter: %v", err) 473 } 474 buf := []byte("hello world") 475 n := 1024 476 if testing.Short() { 477 n = 10 478 } 479 for i := 0; i < n; i++ { 480 w.Write(buf) 481 } 482 w.Reset(ioutil.Discard) 483 484 wref, err := NewWriter(ioutil.Discard, level) 485 if err != nil { 486 t.Fatalf("NewWriter: %v", err) 487 } 488 489 // DeepEqual doesn't compare functions. 490 w.d.fill, wref.d.fill = nil, nil 491 w.d.step, wref.d.step = nil, nil 492 w.d.bulkHasher, wref.d.bulkHasher = nil, nil 493 // hashMatch is always overwritten when used. 494 copy(w.d.hashMatch[:], wref.d.hashMatch[:]) 495 if len(w.d.tokens) != 0 { 496 t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, len(w.d.tokens)) 497 } 498 // As long as the length is 0, we don't care about the content. 499 w.d.tokens = wref.d.tokens 500 501 // We don't care if there are values in the window, as long as it is at d.index is 0 502 w.d.window = wref.d.window 503 if !reflect.DeepEqual(w, wref) { 504 t.Errorf("level %d Writer not reset after Reset", level) 505 } 506 } 507 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, NoCompression) }) 508 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, DefaultCompression) }) 509 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, BestCompression) }) 510 dict := []byte("we are the world") 511 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, NoCompression, dict) }) 512 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, DefaultCompression, dict) }) 513 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, BestCompression, dict) }) 514 } 515 516 func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error)) { 517 buf := new(bytes.Buffer) 518 w, err := newWriter(buf) 519 if err != nil { 520 t.Fatalf("NewWriter: %v", err) 521 } 522 b := []byte("hello world") 523 for i := 0; i < 1024; i++ { 524 w.Write(b) 525 } 526 w.Close() 527 out1 := buf.Bytes() 528 529 buf2 := new(bytes.Buffer) 530 w.Reset(buf2) 531 for i := 0; i < 1024; i++ { 532 w.Write(b) 533 } 534 w.Close() 535 out2 := buf2.Bytes() 536 537 if len(out1) != len(out2) { 538 t.Errorf("got %d, expected %d bytes", len(out2), len(out1)) 539 return 540 } 541 if !bytes.Equal(out1, out2) { 542 mm := 0 543 for i, b := range out1[:len(out2)] { 544 if b != out2[i] { 545 t.Errorf("mismatch index %d: %#02x, expected %#02x", i, out2[i], b) 546 } 547 mm++ 548 if mm == 10 { 549 t.Fatal("Stopping") 550 } 551 } 552 } 553 t.Logf("got %d bytes", len(out1)) 554 } 555 556 // TestBestSpeed tests that round-tripping through deflate and then inflate 557 // recovers the original input. The Write sizes are near the thresholds in the 558 // compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize 559 // (65535). 560 func TestBestSpeed(t *testing.T) { 561 abc := make([]byte, 128) 562 for i := range abc { 563 abc[i] = byte(i) 564 } 565 abcabc := bytes.Repeat(abc, 131072/len(abc)) 566 var want []byte 567 568 testCases := [][]int{ 569 {65536, 0}, 570 {65536, 1}, 571 {65536, 1, 256}, 572 {65536, 1, 65536}, 573 {65536, 14}, 574 {65536, 15}, 575 {65536, 16}, 576 {65536, 16, 256}, 577 {65536, 16, 65536}, 578 {65536, 127}, 579 {65536, 128}, 580 {65536, 128, 256}, 581 {65536, 128, 65536}, 582 {65536, 129}, 583 {65536, 65536, 256}, 584 {65536, 65536, 65536}, 585 } 586 587 for i, tc := range testCases { 588 for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} { 589 tc[0] = firstN 590 outer: 591 for _, flush := range []bool{false, true} { 592 buf := new(bytes.Buffer) 593 want = want[:0] 594 595 w, err := NewWriter(buf, BestSpeed) 596 if err != nil { 597 t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err) 598 continue 599 } 600 for _, n := range tc { 601 want = append(want, abcabc[:n]...) 602 if _, err := w.Write(abcabc[:n]); err != nil { 603 t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err) 604 continue outer 605 } 606 if !flush { 607 continue 608 } 609 if err := w.Flush(); err != nil { 610 t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err) 611 continue outer 612 } 613 } 614 if err := w.Close(); err != nil { 615 t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err) 616 continue 617 } 618 619 r := NewReader(buf) 620 got, err := ioutil.ReadAll(r) 621 if err != nil { 622 t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err) 623 continue 624 } 625 r.Close() 626 627 if !bytes.Equal(got, want) { 628 t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush) 629 continue 630 } 631 } 632 } 633 } 634 } 635 636 var errIO = errors.New("IO error") 637 638 // failWriter fails with errIO exactly at the nth call to Write. 639 type failWriter struct{ n int } 640 641 func (w *failWriter) Write(b []byte) (int, error) { 642 w.n-- 643 if w.n == -1 { 644 return 0, errIO 645 } 646 return len(b), nil 647 } 648 649 func TestWriterPersistentError(t *testing.T) { 650 d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt") 651 if err != nil { 652 t.Fatalf("ReadFile: %v", err) 653 } 654 d = d[:10000] // Keep this test short 655 656 zw, err := NewWriter(nil, DefaultCompression) 657 if err != nil { 658 t.Fatalf("NewWriter: %v", err) 659 } 660 661 // Sweep over the threshold at which an error is returned. 662 // The variable i makes it such that the ith call to failWriter.Write will 663 // return errIO. Since failWriter errors are not persistent, we must ensure 664 // that flate.Writer errors are persistent. 665 for i := 0; i < 1000; i++ { 666 fw := &failWriter{i} 667 zw.Reset(fw) 668 669 _, werr := zw.Write(d) 670 cerr := zw.Close() 671 if werr != errIO && werr != nil { 672 t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO) 673 } 674 if cerr != errIO && fw.n < 0 { 675 t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO) 676 } 677 if fw.n >= 0 { 678 // At this point, the failure threshold was sufficiently high enough 679 // that we wrote the whole stream without any errors. 680 return 681 } 682 } 683 }