github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 w.d.bestSpeed, wref.d.bestSpeed = nil, nil 494 // hashMatch is always overwritten when used. 495 copy(w.d.hashMatch[:], wref.d.hashMatch[:]) 496 if len(w.d.tokens) != 0 { 497 t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, len(w.d.tokens)) 498 } 499 // As long as the length is 0, we don't care about the content. 500 w.d.tokens = wref.d.tokens 501 502 // We don't care if there are values in the window, as long as it is at d.index is 0 503 w.d.window = wref.d.window 504 if !reflect.DeepEqual(w, wref) { 505 t.Errorf("level %d Writer not reset after Reset", level) 506 } 507 } 508 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, NoCompression) }) 509 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, DefaultCompression) }) 510 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, BestCompression) }) 511 dict := []byte("we are the world") 512 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, NoCompression, dict) }) 513 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, DefaultCompression, dict) }) 514 testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, BestCompression, dict) }) 515 } 516 517 func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error)) { 518 buf := new(bytes.Buffer) 519 w, err := newWriter(buf) 520 if err != nil { 521 t.Fatalf("NewWriter: %v", err) 522 } 523 b := []byte("hello world") 524 for i := 0; i < 1024; i++ { 525 w.Write(b) 526 } 527 w.Close() 528 out1 := buf.Bytes() 529 530 buf2 := new(bytes.Buffer) 531 w.Reset(buf2) 532 for i := 0; i < 1024; i++ { 533 w.Write(b) 534 } 535 w.Close() 536 out2 := buf2.Bytes() 537 538 if len(out1) != len(out2) { 539 t.Errorf("got %d, expected %d bytes", len(out2), len(out1)) 540 return 541 } 542 if !bytes.Equal(out1, out2) { 543 mm := 0 544 for i, b := range out1[:len(out2)] { 545 if b != out2[i] { 546 t.Errorf("mismatch index %d: %#02x, expected %#02x", i, out2[i], b) 547 } 548 mm++ 549 if mm == 10 { 550 t.Fatal("Stopping") 551 } 552 } 553 } 554 t.Logf("got %d bytes", len(out1)) 555 } 556 557 // TestBestSpeed tests that round-tripping through deflate and then inflate 558 // recovers the original input. The Write sizes are near the thresholds in the 559 // compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize 560 // (65535). 561 func TestBestSpeed(t *testing.T) { 562 abc := make([]byte, 128) 563 for i := range abc { 564 abc[i] = byte(i) 565 } 566 abcabc := bytes.Repeat(abc, 131072/len(abc)) 567 var want []byte 568 569 testCases := [][]int{ 570 {65536, 0}, 571 {65536, 1}, 572 {65536, 1, 256}, 573 {65536, 1, 65536}, 574 {65536, 14}, 575 {65536, 15}, 576 {65536, 16}, 577 {65536, 16, 256}, 578 {65536, 16, 65536}, 579 {65536, 127}, 580 {65536, 128}, 581 {65536, 128, 256}, 582 {65536, 128, 65536}, 583 {65536, 129}, 584 {65536, 65536, 256}, 585 {65536, 65536, 65536}, 586 } 587 588 for i, tc := range testCases { 589 for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} { 590 tc[0] = firstN 591 outer: 592 for _, flush := range []bool{false, true} { 593 buf := new(bytes.Buffer) 594 want = want[:0] 595 596 w, err := NewWriter(buf, BestSpeed) 597 if err != nil { 598 t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err) 599 continue 600 } 601 for _, n := range tc { 602 want = append(want, abcabc[:n]...) 603 if _, err := w.Write(abcabc[:n]); err != nil { 604 t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err) 605 continue outer 606 } 607 if !flush { 608 continue 609 } 610 if err := w.Flush(); err != nil { 611 t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err) 612 continue outer 613 } 614 } 615 if err := w.Close(); err != nil { 616 t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err) 617 continue 618 } 619 620 r := NewReader(buf) 621 got, err := ioutil.ReadAll(r) 622 if err != nil { 623 t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err) 624 continue 625 } 626 r.Close() 627 628 if !bytes.Equal(got, want) { 629 t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush) 630 continue 631 } 632 } 633 } 634 } 635 } 636 637 var errIO = errors.New("IO error") 638 639 // failWriter fails with errIO exactly at the nth call to Write. 640 type failWriter struct{ n int } 641 642 func (w *failWriter) Write(b []byte) (int, error) { 643 w.n-- 644 if w.n == -1 { 645 return 0, errIO 646 } 647 return len(b), nil 648 } 649 650 func TestWriterPersistentError(t *testing.T) { 651 d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt") 652 if err != nil { 653 t.Fatalf("ReadFile: %v", err) 654 } 655 d = d[:10000] // Keep this test short 656 657 zw, err := NewWriter(nil, DefaultCompression) 658 if err != nil { 659 t.Fatalf("NewWriter: %v", err) 660 } 661 662 // Sweep over the threshold at which an error is returned. 663 // The variable i makes it such that the ith call to failWriter.Write will 664 // return errIO. Since failWriter errors are not persistent, we must ensure 665 // that flate.Writer errors are persistent. 666 for i := 0; i < 1000; i++ { 667 fw := &failWriter{i} 668 zw.Reset(fw) 669 670 _, werr := zw.Write(d) 671 cerr := zw.Close() 672 if werr != errIO && werr != nil { 673 t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO) 674 } 675 if cerr != errIO && fw.n < 0 { 676 t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO) 677 } 678 if fw.n >= 0 { 679 // At this point, the failure threshold was sufficiently high enough 680 // that we wrote the whole stream without any errors. 681 return 682 } 683 } 684 } 685 686 func TestBestSpeedMatch(t *testing.T) { 687 cases := []struct { 688 previous, current []byte 689 t, s, want int32 690 }{{ 691 previous: []byte{0, 0, 0, 1, 2}, 692 current: []byte{3, 4, 5, 0, 1, 2, 3, 4, 5}, 693 t: -3, 694 s: 3, 695 want: 6, 696 }, { 697 previous: []byte{0, 0, 0, 1, 2}, 698 current: []byte{2, 4, 5, 0, 1, 2, 3, 4, 5}, 699 t: -3, 700 s: 3, 701 want: 3, 702 }, { 703 previous: []byte{0, 0, 0, 1, 1}, 704 current: []byte{3, 4, 5, 0, 1, 2, 3, 4, 5}, 705 t: -3, 706 s: 3, 707 want: 2, 708 }, { 709 previous: []byte{0, 0, 0, 1, 2}, 710 current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5}, 711 t: -1, 712 s: 0, 713 want: 4, 714 }, { 715 previous: []byte{0, 0, 0, 1, 2, 3, 4, 5, 2, 2}, 716 current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5}, 717 t: -7, 718 s: 4, 719 want: 5, 720 }, { 721 previous: []byte{9, 9, 9, 9, 9}, 722 current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5}, 723 t: -1, 724 s: 0, 725 want: 0, 726 }, { 727 previous: []byte{9, 9, 9, 9, 9}, 728 current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5}, 729 t: 0, 730 s: 1, 731 want: 0, 732 }, { 733 previous: []byte{}, 734 current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5}, 735 t: -5, 736 s: 1, 737 want: 0, 738 }, { 739 previous: []byte{}, 740 current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5}, 741 t: -1, 742 s: 1, 743 want: 0, 744 }, { 745 previous: []byte{}, 746 current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5}, 747 t: 0, 748 s: 1, 749 want: 3, 750 }, { 751 previous: []byte{3, 4, 5}, 752 current: []byte{3, 4, 5}, 753 t: -3, 754 s: 0, 755 want: 3, 756 }, { 757 previous: make([]byte, 1000), 758 current: make([]byte, 1000), 759 t: -1000, 760 s: 0, 761 want: maxMatchLength - 4, 762 }, { 763 previous: make([]byte, 200), 764 current: make([]byte, 500), 765 t: -200, 766 s: 0, 767 want: maxMatchLength - 4, 768 }, { 769 previous: make([]byte, 200), 770 current: make([]byte, 500), 771 t: 0, 772 s: 1, 773 want: maxMatchLength - 4, 774 }, { 775 previous: make([]byte, maxMatchLength-4), 776 current: make([]byte, 500), 777 t: -(maxMatchLength - 4), 778 s: 0, 779 want: maxMatchLength - 4, 780 }, { 781 previous: make([]byte, 200), 782 current: make([]byte, 500), 783 t: -200, 784 s: 400, 785 want: 100, 786 }, { 787 previous: make([]byte, 10), 788 current: make([]byte, 500), 789 t: 200, 790 s: 400, 791 want: 100, 792 }} 793 for i, c := range cases { 794 e := deflateFast{prev: c.previous} 795 got := e.matchLen(c.s, c.t, c.current) 796 if got != c.want { 797 t.Errorf("Test %d: match length, want %d, got %d", i, c.want, got) 798 } 799 } 800 } 801 802 func TestBestSpeedMaxMatchOffset(t *testing.T) { 803 const abc, xyz = "abcdefgh", "stuvwxyz" 804 for _, matchBefore := range []bool{false, true} { 805 for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} { 806 for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ { 807 report := func(desc string, err error) { 808 t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v", 809 matchBefore, extra, offsetAdj, desc, err) 810 } 811 812 offset := maxMatchOffset + offsetAdj 813 814 // Make src to be a []byte of the form 815 // "%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1) 816 // where: 817 // zeros0 is approximately maxMatchOffset zeros. 818 // xyzMaybe is either xyz or the empty string. 819 // zeros1 is between 0 and 30 zeros. 820 // The difference between the two abc's will be offset, which 821 // is maxMatchOffset plus or minus a small adjustment. 822 src := make([]byte, offset+len(abc)+extra) 823 copy(src, abc) 824 if !matchBefore { 825 copy(src[offset-len(xyz):], xyz) 826 } 827 copy(src[offset:], abc) 828 829 buf := new(bytes.Buffer) 830 w, err := NewWriter(buf, BestSpeed) 831 if err != nil { 832 report("NewWriter: ", err) 833 continue 834 } 835 if _, err := w.Write(src); err != nil { 836 report("Write: ", err) 837 continue 838 } 839 if err := w.Close(); err != nil { 840 report("Writer.Close: ", err) 841 continue 842 } 843 844 r := NewReader(buf) 845 dst, err := ioutil.ReadAll(r) 846 r.Close() 847 if err != nil { 848 report("ReadAll: ", err) 849 continue 850 } 851 852 if !bytes.Equal(dst, src) { 853 report("", fmt.Errorf("bytes differ after round-tripping")) 854 continue 855 } 856 } 857 } 858 } 859 }