Home | History | Annotate | Download | only in flate
      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 	"runtime/debug"
     16 	"sync"
     17 	"testing"
     18 )
     19 
     20 type deflateTest struct {
     21 	in    []byte
     22 	level int
     23 	out   []byte
     24 }
     25 
     26 type deflateInflateTest struct {
     27 	in []byte
     28 }
     29 
     30 type reverseBitsTest struct {
     31 	in       uint16
     32 	bitCount uint8
     33 	out      uint16
     34 }
     35 
     36 var deflateTests = []*deflateTest{
     37 	{[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
     38 	{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
     39 	{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
     40 	{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
     41 
     42 	{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
     43 	{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
     44 	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
     45 		[]byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
     46 	},
     47 	{[]byte{}, 2, []byte{1, 0, 0, 255, 255}},
     48 	{[]byte{0x11}, 2, []byte{18, 4, 4, 0, 0, 255, 255}},
     49 	{[]byte{0x11, 0x12}, 2, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
     50 	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 2, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
     51 	{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
     52 	{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
     53 	{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
     54 	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
     55 }
     56 
     57 var deflateInflateTests = []*deflateInflateTest{
     58 	{[]byte{}},
     59 	{[]byte{0x11}},
     60 	{[]byte{0x11, 0x12}},
     61 	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
     62 	{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
     63 	{largeDataChunk()},
     64 }
     65 
     66 var reverseBitsTests = []*reverseBitsTest{
     67 	{1, 1, 1},
     68 	{1, 2, 2},
     69 	{1, 3, 4},
     70 	{1, 4, 8},
     71 	{1, 5, 16},
     72 	{17, 5, 17},
     73 	{257, 9, 257},
     74 	{29, 5, 23},
     75 }
     76 
     77 func largeDataChunk() []byte {
     78 	result := make([]byte, 100000)
     79 	for i := range result {
     80 		result[i] = byte(i * i & 0xFF)
     81 	}
     82 	return result
     83 }
     84 
     85 func TestBulkHash4(t *testing.T) {
     86 	for _, x := range deflateTests {
     87 		y := x.out
     88 		if len(y) < minMatchLength {
     89 			continue
     90 		}
     91 		y = append(y, y...)
     92 		for j := 4; j < len(y); j++ {
     93 			y := y[:j]
     94 			dst := make([]uint32, len(y)-minMatchLength+1)
     95 			for i := range dst {
     96 				dst[i] = uint32(i + 100)
     97 			}
     98 			bulkHash4(y, dst)
     99 			for i, got := range dst {
    100 				want := hash4(y[i:])
    101 				if got != want && got == uint32(i)+100 {
    102 					t.Errorf("Len:%d Index:%d, want 0x%08x but not modified", len(y), i, want)
    103 				} else if got != want {
    104 					t.Errorf("Len:%d Index:%d, got 0x%08x want:0x%08x", len(y), i, got, want)
    105 				}
    106 			}
    107 		}
    108 	}
    109 }
    110 
    111 func TestDeflate(t *testing.T) {
    112 	for _, h := range deflateTests {
    113 		var buf bytes.Buffer
    114 		w, err := NewWriter(&buf, h.level)
    115 		if err != nil {
    116 			t.Errorf("NewWriter: %v", err)
    117 			continue
    118 		}
    119 		w.Write(h.in)
    120 		w.Close()
    121 		if !bytes.Equal(buf.Bytes(), h.out) {
    122 			t.Errorf("Deflate(%d, %x) = \n%#v, want \n%#v", h.level, h.in, buf.Bytes(), h.out)
    123 		}
    124 	}
    125 }
    126 
    127 // A sparseReader returns a stream consisting of 0s followed by 1<<16 1s.
    128 // This tests missing hash references in a very large input.
    129 type sparseReader struct {
    130 	l   int64
    131 	cur int64
    132 }
    133 
    134 func (r *sparseReader) Read(b []byte) (n int, err error) {
    135 	if r.cur >= r.l {
    136 		return 0, io.EOF
    137 	}
    138 	n = len(b)
    139 	cur := r.cur + int64(n)
    140 	if cur > r.l {
    141 		n -= int(cur - r.l)
    142 		cur = r.l
    143 	}
    144 	for i := range b[0:n] {
    145 		if r.cur+int64(i) >= r.l-1<<16 {
    146 			b[i] = 1
    147 		} else {
    148 			b[i] = 0
    149 		}
    150 	}
    151 	r.cur = cur
    152 	return
    153 }
    154 
    155 func TestVeryLongSparseChunk(t *testing.T) {
    156 	if testing.Short() {
    157 		t.Skip("skipping sparse chunk during short test")
    158 	}
    159 	w, err := NewWriter(ioutil.Discard, 1)
    160 	if err != nil {
    161 		t.Errorf("NewWriter: %v", err)
    162 		return
    163 	}
    164 	if _, err = io.Copy(w, &sparseReader{l: 23E8}); err != nil {
    165 		t.Errorf("Compress failed: %v", err)
    166 		return
    167 	}
    168 }
    169 
    170 type syncBuffer struct {
    171 	buf    bytes.Buffer
    172 	mu     sync.RWMutex
    173 	closed bool
    174 	ready  chan bool
    175 }
    176 
    177 func newSyncBuffer() *syncBuffer {
    178 	return &syncBuffer{ready: make(chan bool, 1)}
    179 }
    180 
    181 func (b *syncBuffer) Read(p []byte) (n int, err error) {
    182 	for {
    183 		b.mu.RLock()
    184 		n, err = b.buf.Read(p)
    185 		b.mu.RUnlock()
    186 		if n > 0 || b.closed {
    187 			return
    188 		}
    189 		<-b.ready
    190 	}
    191 }
    192 
    193 func (b *syncBuffer) signal() {
    194 	select {
    195 	case b.ready <- true:
    196 	default:
    197 	}
    198 }
    199 
    200 func (b *syncBuffer) Write(p []byte) (n int, err error) {
    201 	n, err = b.buf.Write(p)
    202 	b.signal()
    203 	return
    204 }
    205 
    206 func (b *syncBuffer) WriteMode() {
    207 	b.mu.Lock()
    208 }
    209 
    210 func (b *syncBuffer) ReadMode() {
    211 	b.mu.Unlock()
    212 	b.signal()
    213 }
    214 
    215 func (b *syncBuffer) Close() error {
    216 	b.closed = true
    217 	b.signal()
    218 	return nil
    219 }
    220 
    221 func testSync(t *testing.T, level int, input []byte, name string) {
    222 	if len(input) == 0 {
    223 		return
    224 	}
    225 
    226 	t.Logf("--testSync %d, %d, %s", level, len(input), name)
    227 	buf := newSyncBuffer()
    228 	buf1 := new(bytes.Buffer)
    229 	buf.WriteMode()
    230 	w, err := NewWriter(io.MultiWriter(buf, buf1), level)
    231 	if err != nil {
    232 		t.Errorf("NewWriter: %v", err)
    233 		return
    234 	}
    235 	r := NewReader(buf)
    236 
    237 	// Write half the input and read back.
    238 	for i := 0; i < 2; i++ {
    239 		var lo, hi int
    240 		if i == 0 {
    241 			lo, hi = 0, (len(input)+1)/2
    242 		} else {
    243 			lo, hi = (len(input)+1)/2, len(input)
    244 		}
    245 		t.Logf("#%d: write %d-%d", i, lo, hi)
    246 		if _, err := w.Write(input[lo:hi]); err != nil {
    247 			t.Errorf("testSync: write: %v", err)
    248 			return
    249 		}
    250 		if i == 0 {
    251 			if err := w.Flush(); err != nil {
    252 				t.Errorf("testSync: flush: %v", err)
    253 				return
    254 			}
    255 		} else {
    256 			if err := w.Close(); err != nil {
    257 				t.Errorf("testSync: close: %v", err)
    258 			}
    259 		}
    260 		buf.ReadMode()
    261 		out := make([]byte, hi-lo+1)
    262 		m, err := io.ReadAtLeast(r, out, hi-lo)
    263 		t.Logf("#%d: read %d", i, m)
    264 		if m != hi-lo || err != nil {
    265 			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())
    266 			return
    267 		}
    268 		if !bytes.Equal(input[lo:hi], out[:hi-lo]) {
    269 			t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo])
    270 			return
    271 		}
    272 		// This test originally checked that after reading
    273 		// the first half of the input, there was nothing left
    274 		// in the read buffer (buf.buf.Len() != 0) but that is
    275 		// not necessarily the case: the write Flush may emit
    276 		// some extra framing bits that are not necessary
    277 		// to process to obtain the first half of the uncompressed
    278 		// data. The test ran correctly most of the time, because
    279 		// the background goroutine had usually read even
    280 		// those extra bits by now, but it's not a useful thing to
    281 		// check.
    282 		buf.WriteMode()
    283 	}
    284 	buf.ReadMode()
    285 	out := make([]byte, 10)
    286 	if n, err := r.Read(out); n > 0 || err != io.EOF {
    287 		t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n])
    288 	}
    289 	if buf.buf.Len() != 0 {
    290 		t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name)
    291 	}
    292 	r.Close()
    293 
    294 	// stream should work for ordinary reader too
    295 	r = NewReader(buf1)
    296 	out, err = ioutil.ReadAll(r)
    297 	if err != nil {
    298 		t.Errorf("testSync: read: %s", err)
    299 		return
    300 	}
    301 	r.Close()
    302 	if !bytes.Equal(input, out) {
    303 		t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name)
    304 	}
    305 }
    306 
    307 func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) {
    308 	var buffer bytes.Buffer
    309 	w, err := NewWriter(&buffer, level)
    310 	if err != nil {
    311 		t.Errorf("NewWriter: %v", err)
    312 		return
    313 	}
    314 	w.Write(input)
    315 	w.Close()
    316 	if limit > 0 && buffer.Len() > limit {
    317 		t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
    318 		return
    319 	}
    320 	if limit > 0 {
    321 		t.Logf("level: %d, size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len())
    322 	}
    323 	r := NewReader(&buffer)
    324 	out, err := ioutil.ReadAll(r)
    325 	if err != nil {
    326 		t.Errorf("read: %s", err)
    327 		return
    328 	}
    329 	r.Close()
    330 	if !bytes.Equal(input, out) {
    331 		t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
    332 		return
    333 	}
    334 	testSync(t, level, input, name)
    335 }
    336 
    337 func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) {
    338 	for i := 0; i < 10; i++ {
    339 		testToFromWithLevelAndLimit(t, i, input, name, limit[i])
    340 	}
    341 	// Test HuffmanCompression
    342 	testToFromWithLevelAndLimit(t, -2, input, name, limit[10])
    343 }
    344 
    345 func TestDeflateInflate(t *testing.T) {
    346 	t.Parallel()
    347 	for i, h := range deflateInflateTests {
    348 		testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{})
    349 	}
    350 }
    351 
    352 func TestReverseBits(t *testing.T) {
    353 	for _, h := range reverseBitsTests {
    354 		if v := reverseBits(h.in, h.bitCount); v != h.out {
    355 			t.Errorf("reverseBits(%v,%v) = %v, want %v",
    356 				h.in, h.bitCount, v, h.out)
    357 		}
    358 	}
    359 }
    360 
    361 type deflateInflateStringTest struct {
    362 	filename string
    363 	label    string
    364 	limit    [11]int
    365 }
    366 
    367 var deflateInflateStringTests = []deflateInflateStringTest{
    368 	{
    369 		"../testdata/e.txt",
    370 		"2.718281828...",
    371 		[...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683},
    372 	},
    373 	{
    374 		"../testdata/Mark.Twain-Tom.Sawyer.txt",
    375 		"Mark.Twain-Tom.Sawyer",
    376 		[...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295, 233460},
    377 	},
    378 }
    379 
    380 func TestDeflateInflateString(t *testing.T) {
    381 	t.Parallel()
    382 	if testing.Short() && testenv.Builder() == "" {
    383 		t.Skip("skipping in short mode")
    384 	}
    385 	for _, test := range deflateInflateStringTests {
    386 		gold, err := ioutil.ReadFile(test.filename)
    387 		if err != nil {
    388 			t.Error(err)
    389 		}
    390 		testToFromWithLimit(t, gold, test.label, test.limit)
    391 		if testing.Short() {
    392 			break
    393 		}
    394 	}
    395 }
    396 
    397 func TestReaderDict(t *testing.T) {
    398 	const (
    399 		dict = "hello world"
    400 		text = "hello again world"
    401 	)
    402 	var b bytes.Buffer
    403 	w, err := NewWriter(&b, 5)
    404 	if err != nil {
    405 		t.Fatalf("NewWriter: %v", err)
    406 	}
    407 	w.Write([]byte(dict))
    408 	w.Flush()
    409 	b.Reset()
    410 	w.Write([]byte(text))
    411 	w.Close()
    412 
    413 	r := NewReaderDict(&b, []byte(dict))
    414 	data, err := ioutil.ReadAll(r)
    415 	if err != nil {
    416 		t.Fatal(err)
    417 	}
    418 	if string(data) != "hello again world" {
    419 		t.Fatalf("read returned %q want %q", string(data), text)
    420 	}
    421 }
    422 
    423 func TestWriterDict(t *testing.T) {
    424 	const (
    425 		dict = "hello world"
    426 		text = "hello again world"
    427 	)
    428 	var b bytes.Buffer
    429 	w, err := NewWriter(&b, 5)
    430 	if err != nil {
    431 		t.Fatalf("NewWriter: %v", err)
    432 	}
    433 	w.Write([]byte(dict))
    434 	w.Flush()
    435 	b.Reset()
    436 	w.Write([]byte(text))
    437 	w.Close()
    438 
    439 	var b1 bytes.Buffer
    440 	w, _ = NewWriterDict(&b1, 5, []byte(dict))
    441 	w.Write([]byte(text))
    442 	w.Close()
    443 
    444 	if !bytes.Equal(b1.Bytes(), b.Bytes()) {
    445 		t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes())
    446 	}
    447 }
    448 
    449 // See https://golang.org/issue/2508
    450 func TestRegression2508(t *testing.T) {
    451 	if testing.Short() {
    452 		t.Logf("test disabled with -short")
    453 		return
    454 	}
    455 	w, err := NewWriter(ioutil.Discard, 1)
    456 	if err != nil {
    457 		t.Fatalf("NewWriter: %v", err)
    458 	}
    459 	buf := make([]byte, 1024)
    460 	for i := 0; i < 131072; i++ {
    461 		if _, err := w.Write(buf); err != nil {
    462 			t.Fatalf("writer failed: %v", err)
    463 		}
    464 	}
    465 	w.Close()
    466 }
    467 
    468 func TestWriterReset(t *testing.T) {
    469 	t.Parallel()
    470 	for level := 0; level <= 9; level++ {
    471 		if testing.Short() && level > 1 {
    472 			break
    473 		}
    474 		w, err := NewWriter(ioutil.Discard, level)
    475 		if err != nil {
    476 			t.Fatalf("NewWriter: %v", err)
    477 		}
    478 		buf := []byte("hello world")
    479 		n := 1024
    480 		if testing.Short() {
    481 			n = 10
    482 		}
    483 		for i := 0; i < n; i++ {
    484 			w.Write(buf)
    485 		}
    486 		w.Reset(ioutil.Discard)
    487 
    488 		wref, err := NewWriter(ioutil.Discard, level)
    489 		if err != nil {
    490 			t.Fatalf("NewWriter: %v", err)
    491 		}
    492 
    493 		// DeepEqual doesn't compare functions.
    494 		w.d.fill, wref.d.fill = nil, nil
    495 		w.d.step, wref.d.step = nil, nil
    496 		w.d.bulkHasher, wref.d.bulkHasher = nil, nil
    497 		w.d.bestSpeed, wref.d.bestSpeed = nil, nil
    498 		// hashMatch is always overwritten when used.
    499 		copy(w.d.hashMatch[:], wref.d.hashMatch[:])
    500 		if len(w.d.tokens) != 0 {
    501 			t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, len(w.d.tokens))
    502 		}
    503 		// As long as the length is 0, we don't care about the content.
    504 		w.d.tokens = wref.d.tokens
    505 
    506 		// We don't care if there are values in the window, as long as it is at d.index is 0
    507 		w.d.window = wref.d.window
    508 		if !reflect.DeepEqual(w, wref) {
    509 			t.Errorf("level %d Writer not reset after Reset", level)
    510 		}
    511 	}
    512 	testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, NoCompression) })
    513 	testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, DefaultCompression) })
    514 	testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, BestCompression) })
    515 	dict := []byte("we are the world")
    516 	testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, NoCompression, dict) })
    517 	testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, DefaultCompression, dict) })
    518 	testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, BestCompression, dict) })
    519 }
    520 
    521 func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error)) {
    522 	buf := new(bytes.Buffer)
    523 	w, err := newWriter(buf)
    524 	if err != nil {
    525 		t.Fatalf("NewWriter: %v", err)
    526 	}
    527 	b := []byte("hello world")
    528 	for i := 0; i < 1024; i++ {
    529 		w.Write(b)
    530 	}
    531 	w.Close()
    532 	out1 := buf.Bytes()
    533 
    534 	buf2 := new(bytes.Buffer)
    535 	w.Reset(buf2)
    536 	for i := 0; i < 1024; i++ {
    537 		w.Write(b)
    538 	}
    539 	w.Close()
    540 	out2 := buf2.Bytes()
    541 
    542 	if len(out1) != len(out2) {
    543 		t.Errorf("got %d, expected %d bytes", len(out2), len(out1))
    544 		return
    545 	}
    546 	if !bytes.Equal(out1, out2) {
    547 		mm := 0
    548 		for i, b := range out1[:len(out2)] {
    549 			if b != out2[i] {
    550 				t.Errorf("mismatch index %d: %#02x, expected %#02x", i, out2[i], b)
    551 			}
    552 			mm++
    553 			if mm == 10 {
    554 				t.Fatal("Stopping")
    555 			}
    556 		}
    557 	}
    558 	t.Logf("got %d bytes", len(out1))
    559 }
    560 
    561 // TestBestSpeed tests that round-tripping through deflate and then inflate
    562 // recovers the original input. The Write sizes are near the thresholds in the
    563 // compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize
    564 // (65535).
    565 func TestBestSpeed(t *testing.T) {
    566 	t.Parallel()
    567 	abc := make([]byte, 128)
    568 	for i := range abc {
    569 		abc[i] = byte(i)
    570 	}
    571 	abcabc := bytes.Repeat(abc, 131072/len(abc))
    572 	var want []byte
    573 
    574 	testCases := [][]int{
    575 		{65536, 0},
    576 		{65536, 1},
    577 		{65536, 1, 256},
    578 		{65536, 1, 65536},
    579 		{65536, 14},
    580 		{65536, 15},
    581 		{65536, 16},
    582 		{65536, 16, 256},
    583 		{65536, 16, 65536},
    584 		{65536, 127},
    585 		{65536, 128},
    586 		{65536, 128, 256},
    587 		{65536, 128, 65536},
    588 		{65536, 129},
    589 		{65536, 65536, 256},
    590 		{65536, 65536, 65536},
    591 	}
    592 
    593 	for i, tc := range testCases {
    594 		for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} {
    595 			tc[0] = firstN
    596 		outer:
    597 			for _, flush := range []bool{false, true} {
    598 				buf := new(bytes.Buffer)
    599 				want = want[:0]
    600 
    601 				w, err := NewWriter(buf, BestSpeed)
    602 				if err != nil {
    603 					t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err)
    604 					continue
    605 				}
    606 				for _, n := range tc {
    607 					want = append(want, abcabc[:n]...)
    608 					if _, err := w.Write(abcabc[:n]); err != nil {
    609 						t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err)
    610 						continue outer
    611 					}
    612 					if !flush {
    613 						continue
    614 					}
    615 					if err := w.Flush(); err != nil {
    616 						t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err)
    617 						continue outer
    618 					}
    619 				}
    620 				if err := w.Close(); err != nil {
    621 					t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err)
    622 					continue
    623 				}
    624 
    625 				r := NewReader(buf)
    626 				got, err := ioutil.ReadAll(r)
    627 				if err != nil {
    628 					t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err)
    629 					continue
    630 				}
    631 				r.Close()
    632 
    633 				if !bytes.Equal(got, want) {
    634 					t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush)
    635 					continue
    636 				}
    637 			}
    638 		}
    639 	}
    640 }
    641 
    642 var errIO = errors.New("IO error")
    643 
    644 // failWriter fails with errIO exactly at the nth call to Write.
    645 type failWriter struct{ n int }
    646 
    647 func (w *failWriter) Write(b []byte) (int, error) {
    648 	w.n--
    649 	if w.n == -1 {
    650 		return 0, errIO
    651 	}
    652 	return len(b), nil
    653 }
    654 
    655 func TestWriterPersistentError(t *testing.T) {
    656 	t.Parallel()
    657 	d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt")
    658 	if err != nil {
    659 		t.Fatalf("ReadFile: %v", err)
    660 	}
    661 	d = d[:10000] // Keep this test short
    662 
    663 	zw, err := NewWriter(nil, DefaultCompression)
    664 	if err != nil {
    665 		t.Fatalf("NewWriter: %v", err)
    666 	}
    667 
    668 	// Sweep over the threshold at which an error is returned.
    669 	// The variable i makes it such that the ith call to failWriter.Write will
    670 	// return errIO. Since failWriter errors are not persistent, we must ensure
    671 	// that flate.Writer errors are persistent.
    672 	for i := 0; i < 1000; i++ {
    673 		fw := &failWriter{i}
    674 		zw.Reset(fw)
    675 
    676 		_, werr := zw.Write(d)
    677 		cerr := zw.Close()
    678 		if werr != errIO && werr != nil {
    679 			t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO)
    680 		}
    681 		if cerr != errIO && fw.n < 0 {
    682 			t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO)
    683 		}
    684 		if fw.n >= 0 {
    685 			// At this point, the failure threshold was sufficiently high enough
    686 			// that we wrote the whole stream without any errors.
    687 			return
    688 		}
    689 	}
    690 }
    691 
    692 func TestBestSpeedMatch(t *testing.T) {
    693 	t.Parallel()
    694 	cases := []struct {
    695 		previous, current []byte
    696 		t, s, want        int32
    697 	}{{
    698 		previous: []byte{0, 0, 0, 1, 2},
    699 		current:  []byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
    700 		t:        -3,
    701 		s:        3,
    702 		want:     6,
    703 	}, {
    704 		previous: []byte{0, 0, 0, 1, 2},
    705 		current:  []byte{2, 4, 5, 0, 1, 2, 3, 4, 5},
    706 		t:        -3,
    707 		s:        3,
    708 		want:     3,
    709 	}, {
    710 		previous: []byte{0, 0, 0, 1, 1},
    711 		current:  []byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
    712 		t:        -3,
    713 		s:        3,
    714 		want:     2,
    715 	}, {
    716 		previous: []byte{0, 0, 0, 1, 2},
    717 		current:  []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
    718 		t:        -1,
    719 		s:        0,
    720 		want:     4,
    721 	}, {
    722 		previous: []byte{0, 0, 0, 1, 2, 3, 4, 5, 2, 2},
    723 		current:  []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
    724 		t:        -7,
    725 		s:        4,
    726 		want:     5,
    727 	}, {
    728 		previous: []byte{9, 9, 9, 9, 9},
    729 		current:  []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
    730 		t:        -1,
    731 		s:        0,
    732 		want:     0,
    733 	}, {
    734 		previous: []byte{9, 9, 9, 9, 9},
    735 		current:  []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
    736 		t:        0,
    737 		s:        1,
    738 		want:     0,
    739 	}, {
    740 		previous: []byte{},
    741 		current:  []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
    742 		t:        -5,
    743 		s:        1,
    744 		want:     0,
    745 	}, {
    746 		previous: []byte{},
    747 		current:  []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
    748 		t:        -1,
    749 		s:        1,
    750 		want:     0,
    751 	}, {
    752 		previous: []byte{},
    753 		current:  []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
    754 		t:        0,
    755 		s:        1,
    756 		want:     3,
    757 	}, {
    758 		previous: []byte{3, 4, 5},
    759 		current:  []byte{3, 4, 5},
    760 		t:        -3,
    761 		s:        0,
    762 		want:     3,
    763 	}, {
    764 		previous: make([]byte, 1000),
    765 		current:  make([]byte, 1000),
    766 		t:        -1000,
    767 		s:        0,
    768 		want:     maxMatchLength - 4,
    769 	}, {
    770 		previous: make([]byte, 200),
    771 		current:  make([]byte, 500),
    772 		t:        -200,
    773 		s:        0,
    774 		want:     maxMatchLength - 4,
    775 	}, {
    776 		previous: make([]byte, 200),
    777 		current:  make([]byte, 500),
    778 		t:        0,
    779 		s:        1,
    780 		want:     maxMatchLength - 4,
    781 	}, {
    782 		previous: make([]byte, maxMatchLength-4),
    783 		current:  make([]byte, 500),
    784 		t:        -(maxMatchLength - 4),
    785 		s:        0,
    786 		want:     maxMatchLength - 4,
    787 	}, {
    788 		previous: make([]byte, 200),
    789 		current:  make([]byte, 500),
    790 		t:        -200,
    791 		s:        400,
    792 		want:     100,
    793 	}, {
    794 		previous: make([]byte, 10),
    795 		current:  make([]byte, 500),
    796 		t:        200,
    797 		s:        400,
    798 		want:     100,
    799 	}}
    800 	for i, c := range cases {
    801 		e := deflateFast{prev: c.previous}
    802 		got := e.matchLen(c.s, c.t, c.current)
    803 		if got != c.want {
    804 			t.Errorf("Test %d: match length, want %d, got %d", i, c.want, got)
    805 		}
    806 	}
    807 }
    808 
    809 func TestBestSpeedMaxMatchOffset(t *testing.T) {
    810 	t.Parallel()
    811 	const abc, xyz = "abcdefgh", "stuvwxyz"
    812 	for _, matchBefore := range []bool{false, true} {
    813 		for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} {
    814 			for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ {
    815 				report := func(desc string, err error) {
    816 					t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v",
    817 						matchBefore, extra, offsetAdj, desc, err)
    818 				}
    819 
    820 				offset := maxMatchOffset + offsetAdj
    821 
    822 				// Make src to be a []byte of the form
    823 				//	"%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1)
    824 				// where:
    825 				//	zeros0 is approximately maxMatchOffset zeros.
    826 				//	xyzMaybe is either xyz or the empty string.
    827 				//	zeros1 is between 0 and 30 zeros.
    828 				// The difference between the two abc's will be offset, which
    829 				// is maxMatchOffset plus or minus a small adjustment.
    830 				src := make([]byte, offset+len(abc)+extra)
    831 				copy(src, abc)
    832 				if !matchBefore {
    833 					copy(src[offset-len(xyz):], xyz)
    834 				}
    835 				copy(src[offset:], abc)
    836 
    837 				buf := new(bytes.Buffer)
    838 				w, err := NewWriter(buf, BestSpeed)
    839 				if err != nil {
    840 					report("NewWriter: ", err)
    841 					continue
    842 				}
    843 				if _, err := w.Write(src); err != nil {
    844 					report("Write: ", err)
    845 					continue
    846 				}
    847 				if err := w.Close(); err != nil {
    848 					report("Writer.Close: ", err)
    849 					continue
    850 				}
    851 
    852 				r := NewReader(buf)
    853 				dst, err := ioutil.ReadAll(r)
    854 				r.Close()
    855 				if err != nil {
    856 					report("ReadAll: ", err)
    857 					continue
    858 				}
    859 
    860 				if !bytes.Equal(dst, src) {
    861 					report("", fmt.Errorf("bytes differ after round-tripping"))
    862 					continue
    863 				}
    864 			}
    865 		}
    866 	}
    867 }
    868 
    869 func TestMaxStackSize(t *testing.T) {
    870 	// This test must not run in parallel with other tests as debug.SetMaxStack
    871 	// affects all goroutines.
    872 	n := debug.SetMaxStack(1 << 16)
    873 	defer debug.SetMaxStack(n)
    874 
    875 	var wg sync.WaitGroup
    876 	defer wg.Wait()
    877 
    878 	b := make([]byte, 1<<20)
    879 	for level := HuffmanOnly; level <= BestCompression; level++ {
    880 		// Run in separate goroutine to increase probability of stack regrowth.
    881 		wg.Add(1)
    882 		go func(level int) {
    883 			defer wg.Done()
    884 			zw, err := NewWriter(ioutil.Discard, level)
    885 			if err != nil {
    886 				t.Errorf("level %d, NewWriter() = %v, want nil", level, err)
    887 			}
    888 			if n, err := zw.Write(b); n != len(b) || err != nil {
    889 				t.Errorf("level %d, Write() = (%d, %v), want (%d, nil)", level, n, err, len(b))
    890 			}
    891 			if err := zw.Close(); err != nil {
    892 				t.Errorf("level %d, Close() = %v, want nil", level, err)
    893 			}
    894 			zw.Reset(ioutil.Discard)
    895 		}(level)
    896 	}
    897 }
    898