github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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  }