github.com/andybalholm/brotli@v1.1.0/brotli_test.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     2  //
     3  // Distributed under MIT license.
     4  // See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
     5  
     6  package brotli
     7  
     8  import (
     9  	"bytes"
    10  	"compress/gzip"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"math"
    15  	"math/rand"
    16  	"os"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/andybalholm/brotli/matchfinder"
    21  )
    22  
    23  func checkCompressedData(compressedData, wantOriginalData []byte) error {
    24  	uncompressed, err := Decode(compressedData)
    25  	if err != nil {
    26  		return fmt.Errorf("brotli decompress failed: %v", err)
    27  	}
    28  	if !bytes.Equal(uncompressed, wantOriginalData) {
    29  		if len(wantOriginalData) != len(uncompressed) {
    30  			return fmt.Errorf(""+
    31  				"Data doesn't uncompress to the original value.\n"+
    32  				"Length of original: %v\n"+
    33  				"Length of uncompressed: %v",
    34  				len(wantOriginalData), len(uncompressed))
    35  		}
    36  		for i := range wantOriginalData {
    37  			if wantOriginalData[i] != uncompressed[i] {
    38  				return fmt.Errorf(""+
    39  					"Data doesn't uncompress to the original value.\n"+
    40  					"Original at %v is %v\n"+
    41  					"Uncompressed at %v is %v",
    42  					i, wantOriginalData[i], i, uncompressed[i])
    43  			}
    44  		}
    45  	}
    46  	return nil
    47  }
    48  
    49  func TestEncoderNoWrite(t *testing.T) {
    50  	out := bytes.Buffer{}
    51  	e := NewWriterOptions(&out, WriterOptions{Quality: 5})
    52  	if err := e.Close(); err != nil {
    53  		t.Errorf("Close()=%v, want nil", err)
    54  	}
    55  	// Check Write after close.
    56  	if _, err := e.Write([]byte("hi")); err == nil {
    57  		t.Errorf("No error after Close() + Write()")
    58  	}
    59  }
    60  
    61  func TestEncoderEmptyWrite(t *testing.T) {
    62  	out := bytes.Buffer{}
    63  	e := NewWriterOptions(&out, WriterOptions{Quality: 5})
    64  	n, err := e.Write([]byte(""))
    65  	if n != 0 || err != nil {
    66  		t.Errorf("Write()=%v,%v, want 0, nil", n, err)
    67  	}
    68  	if err := e.Close(); err != nil {
    69  		t.Errorf("Close()=%v, want nil", err)
    70  	}
    71  }
    72  func TestIssue22(t *testing.T) {
    73  	f, err := os.Open("testdata/issue22.gz")
    74  	if err != nil {
    75  		t.Fatalf("Error opening test data file: %v", err)
    76  	}
    77  	defer f.Close()
    78  
    79  	zr, err := gzip.NewReader(f)
    80  	if err != nil {
    81  		t.Fatalf("Error creating gzip reader: %v", err)
    82  	}
    83  
    84  	data, err := io.ReadAll(zr)
    85  	if err != nil {
    86  		t.Fatalf("Error reading test data: %v", err)
    87  	}
    88  
    89  	if len(data) != 2851073 {
    90  		t.Fatalf("Wrong length for test data: got %d, want 2851073", len(data))
    91  	}
    92  
    93  	for level := BestSpeed; level <= BestCompression; level++ {
    94  		out := bytes.Buffer{}
    95  		e := NewWriterOptions(&out, WriterOptions{Quality: level})
    96  		n, err := e.Write(data)
    97  		if err != nil {
    98  			t.Errorf("Error compressing data: %v", err)
    99  		}
   100  		if int(n) != len(data) {
   101  			t.Errorf("Write() n=%v, want %v", n, len(data))
   102  		}
   103  		if err := e.Close(); err != nil {
   104  			t.Errorf("Close Error after writing %d bytes: %v", n, err)
   105  		}
   106  		if err := checkCompressedData(out.Bytes(), data); err != nil {
   107  			t.Errorf("Error decompressing data at level %d: %v", level, err)
   108  		}
   109  	}
   110  }
   111  
   112  func TestWriterV2(t *testing.T) {
   113  	for level := BestSpeed; level <= BestCompression; level++ {
   114  		// Test basic encoder usage.
   115  		input := []byte("<html><body><H1>Hello world</H1></body></html>")
   116  		out := bytes.Buffer{}
   117  		e := NewWriterV2(&out, level)
   118  		in := bytes.NewReader([]byte(input))
   119  		n, err := io.Copy(e, in)
   120  		if err != nil {
   121  			t.Errorf("Copy Error: %v", err)
   122  		}
   123  		if int(n) != len(input) {
   124  			t.Errorf("Copy() n=%v, want %v", n, len(input))
   125  		}
   126  		if err := e.Close(); err != nil {
   127  			t.Errorf("Close Error after copied %d bytes: %v", n, err)
   128  		}
   129  		if err := checkCompressedData(out.Bytes(), input); err != nil {
   130  			t.Error(err)
   131  		}
   132  
   133  		out2 := bytes.Buffer{}
   134  		e.Reset(&out2)
   135  		n2, err := e.Write(input)
   136  		if err != nil {
   137  			t.Errorf("Write error after Reset: %v", err)
   138  		}
   139  		if n2 != len(input) {
   140  			t.Errorf("Write() after Reset n=%d, want %d", n2, len(input))
   141  		}
   142  		if err := e.Close(); err != nil {
   143  			t.Errorf("Close error after Reset (copied %d) bytes: %v", n2, err)
   144  		}
   145  		if !bytes.Equal(out.Bytes(), out2.Bytes()) {
   146  			t.Error("Compressed data after Reset doesn't equal first time")
   147  		}
   148  	}
   149  }
   150  
   151  func TestEncoderStreams(t *testing.T) {
   152  	// Test that output is streamed.
   153  	// Adjust window size to ensure the encoder outputs at least enough bytes
   154  	// to fill the window.
   155  	const lgWin = 16
   156  	windowSize := int(math.Pow(2, lgWin))
   157  	input := make([]byte, 8*windowSize)
   158  	rand.Read(input)
   159  	out := bytes.Buffer{}
   160  	e := NewWriterOptions(&out, WriterOptions{Quality: 11, LGWin: lgWin})
   161  	halfInput := input[:len(input)/2]
   162  	in := bytes.NewReader(halfInput)
   163  
   164  	n, err := io.Copy(e, in)
   165  	if err != nil {
   166  		t.Errorf("Copy Error: %v", err)
   167  	}
   168  
   169  	// We've fed more data than the sliding window size. Check that some
   170  	// compressed data has been output.
   171  	if out.Len() == 0 {
   172  		t.Errorf("Output length is 0 after %d bytes written", n)
   173  	}
   174  	if err := e.Close(); err != nil {
   175  		t.Errorf("Close Error after copied %d bytes: %v", n, err)
   176  	}
   177  	if err := checkCompressedData(out.Bytes(), halfInput); err != nil {
   178  		t.Error(err)
   179  	}
   180  }
   181  
   182  func TestEncoderLargeInput(t *testing.T) {
   183  	for level := BestSpeed; level <= BestCompression; level++ {
   184  		input := make([]byte, 1000000)
   185  		rand.Read(input)
   186  		out := bytes.Buffer{}
   187  		e := NewWriterOptions(&out, WriterOptions{Quality: level})
   188  		in := bytes.NewReader(input)
   189  
   190  		n, err := io.Copy(e, in)
   191  		if err != nil {
   192  			t.Errorf("Copy Error: %v", err)
   193  		}
   194  		if int(n) != len(input) {
   195  			t.Errorf("Copy() n=%v, want %v", n, len(input))
   196  		}
   197  		if err := e.Close(); err != nil {
   198  			t.Errorf("Close Error after copied %d bytes: %v", n, err)
   199  		}
   200  		if err := checkCompressedData(out.Bytes(), input); err != nil {
   201  			t.Error(err)
   202  		}
   203  
   204  		out2 := bytes.Buffer{}
   205  		e.Reset(&out2)
   206  		n2, err := e.Write(input)
   207  		if err != nil {
   208  			t.Errorf("Write error after Reset: %v", err)
   209  		}
   210  		if n2 != len(input) {
   211  			t.Errorf("Write() after Reset n=%d, want %d", n2, len(input))
   212  		}
   213  		if err := e.Close(); err != nil {
   214  			t.Errorf("Close error after Reset (copied %d) bytes: %v", n2, err)
   215  		}
   216  		if !bytes.Equal(out.Bytes(), out2.Bytes()) {
   217  			t.Error("Compressed data after Reset doesn't equal first time")
   218  		}
   219  	}
   220  }
   221  
   222  func TestEncoderFlush(t *testing.T) {
   223  	input := make([]byte, 1000)
   224  	rand.Read(input)
   225  	out := bytes.Buffer{}
   226  	e := NewWriterOptions(&out, WriterOptions{Quality: 5})
   227  	in := bytes.NewReader(input)
   228  	_, err := io.Copy(e, in)
   229  	if err != nil {
   230  		t.Fatalf("Copy Error: %v", err)
   231  	}
   232  	if err := e.Flush(); err != nil {
   233  		t.Fatalf("Flush(): %v", err)
   234  	}
   235  	if out.Len() == 0 {
   236  		t.Fatalf("0 bytes written after Flush()")
   237  	}
   238  	decompressed := make([]byte, 1000)
   239  	reader := NewReader(bytes.NewReader(out.Bytes()))
   240  	n, err := reader.Read(decompressed)
   241  	if n != len(decompressed) || err != nil {
   242  		t.Errorf("Expected <%v, nil>, but <%v, %v>", len(decompressed), n, err)
   243  	}
   244  	if !bytes.Equal(decompressed, input) {
   245  		t.Errorf(""+
   246  			"Decompress after flush: %v\n"+
   247  			"%q\n"+
   248  			"want:\n%q",
   249  			err, decompressed, input)
   250  	}
   251  	if err := e.Close(); err != nil {
   252  		t.Errorf("Close(): %v", err)
   253  	}
   254  }
   255  
   256  type readerWithTimeout struct {
   257  	io.Reader
   258  }
   259  
   260  func (r readerWithTimeout) Read(p []byte) (int, error) {
   261  	type result struct {
   262  		n   int
   263  		err error
   264  	}
   265  	ch := make(chan result)
   266  	go func() {
   267  		n, err := r.Reader.Read(p)
   268  		ch <- result{n, err}
   269  	}()
   270  	select {
   271  	case result := <-ch:
   272  		return result.n, result.err
   273  	case <-time.After(5 * time.Second):
   274  		return 0, fmt.Errorf("read timed out")
   275  	}
   276  }
   277  
   278  func TestDecoderStreaming(t *testing.T) {
   279  	pr, pw := io.Pipe()
   280  	writer := NewWriterOptions(pw, WriterOptions{Quality: 5, LGWin: 20})
   281  	reader := readerWithTimeout{NewReader(pr)}
   282  	defer func() {
   283  		go ioutil.ReadAll(pr) // swallow the "EOF" token from writer.Close
   284  		if err := writer.Close(); err != nil {
   285  			t.Errorf("writer.Close: %v", err)
   286  		}
   287  	}()
   288  
   289  	ch := make(chan []byte)
   290  	errch := make(chan error)
   291  	go func() {
   292  		for {
   293  			segment, ok := <-ch
   294  			if !ok {
   295  				return
   296  			}
   297  			if n, err := writer.Write(segment); err != nil || n != len(segment) {
   298  				errch <- fmt.Errorf("write=%v,%v, want %v,%v", n, err, len(segment), nil)
   299  				return
   300  			}
   301  			if err := writer.Flush(); err != nil {
   302  				errch <- fmt.Errorf("flush: %v", err)
   303  				return
   304  			}
   305  		}
   306  	}()
   307  	defer close(ch)
   308  
   309  	segments := [...][]byte{
   310  		[]byte("first"),
   311  		[]byte("second"),
   312  		[]byte("third"),
   313  	}
   314  	for k, segment := range segments {
   315  		t.Run(fmt.Sprintf("Segment%d", k), func(t *testing.T) {
   316  			select {
   317  			case ch <- segment:
   318  			case err := <-errch:
   319  				t.Fatalf("write: %v", err)
   320  			case <-time.After(5 * time.Second):
   321  				t.Fatalf("timed out")
   322  			}
   323  			wantLen := len(segment)
   324  			got := make([]byte, wantLen)
   325  			if n, err := reader.Read(got); err != nil || n != wantLen || !bytes.Equal(got, segment) {
   326  				t.Fatalf("read[%d]=%q,%v,%v, want %q,%v,%v", k, got, n, err, segment, wantLen, nil)
   327  			}
   328  		})
   329  	}
   330  }
   331  
   332  func TestReader(t *testing.T) {
   333  	content := bytes.Repeat([]byte("hello world!"), 10000)
   334  	encoded, _ := Encode(content, WriterOptions{Quality: 5})
   335  	r := NewReader(bytes.NewReader(encoded))
   336  	var decodedOutput bytes.Buffer
   337  	n, err := io.Copy(&decodedOutput, r)
   338  	if err != nil {
   339  		t.Fatalf("Copy(): n=%v, err=%v", n, err)
   340  	}
   341  	if got := decodedOutput.Bytes(); !bytes.Equal(got, content) {
   342  		t.Errorf(""+
   343  			"Reader output:\n"+
   344  			"%q\n"+
   345  			"want:\n"+
   346  			"<%d bytes>",
   347  			got, len(content))
   348  	}
   349  
   350  	r.Reset(bytes.NewReader(encoded))
   351  	decodedOutput.Reset()
   352  	n, err = io.Copy(&decodedOutput, r)
   353  	if err != nil {
   354  		t.Fatalf("After Reset: Copy(): n=%v, err=%v", n, err)
   355  	}
   356  	if got := decodedOutput.Bytes(); !bytes.Equal(got, content) {
   357  		t.Errorf("After Reset: "+
   358  			"Reader output:\n"+
   359  			"%q\n"+
   360  			"want:\n"+
   361  			"<%d bytes>",
   362  			got, len(content))
   363  	}
   364  
   365  }
   366  
   367  func TestDecode(t *testing.T) {
   368  	content := bytes.Repeat([]byte("hello world!"), 10000)
   369  	encoded, _ := Encode(content, WriterOptions{Quality: 5})
   370  	decoded, err := Decode(encoded)
   371  	if err != nil {
   372  		t.Errorf("Decode: %v", err)
   373  	}
   374  	if !bytes.Equal(decoded, content) {
   375  		t.Errorf(""+
   376  			"Decode content:\n"+
   377  			"%q\n"+
   378  			"want:\n"+
   379  			"<%d bytes>",
   380  			decoded, len(content))
   381  	}
   382  }
   383  
   384  func TestQuality(t *testing.T) {
   385  	content := bytes.Repeat([]byte("hello world!"), 10000)
   386  	for q := 0; q < 12; q++ {
   387  		encoded, _ := Encode(content, WriterOptions{Quality: q})
   388  		decoded, err := Decode(encoded)
   389  		if err != nil {
   390  			t.Errorf("Decode: %v", err)
   391  		}
   392  		if !bytes.Equal(decoded, content) {
   393  			t.Errorf(""+
   394  				"Decode content:\n"+
   395  				"%q\n"+
   396  				"want:\n"+
   397  				"<%d bytes>",
   398  				decoded, len(content))
   399  		}
   400  	}
   401  }
   402  
   403  func TestDecodeFuzz(t *testing.T) {
   404  	// Test that the decoder terminates with corrupted input.
   405  	content := bytes.Repeat([]byte("hello world!"), 100)
   406  	rnd := rand.New(rand.NewSource(0))
   407  	encoded, err := Encode(content, WriterOptions{Quality: 5})
   408  	if err != nil {
   409  		t.Fatalf("Encode(<%d bytes>, _) = _, %s", len(content), err)
   410  	}
   411  	if len(encoded) == 0 {
   412  		t.Fatalf("Encode(<%d bytes>, _) produced empty output", len(content))
   413  	}
   414  	for i := 0; i < 100; i++ {
   415  		enc := append([]byte{}, encoded...)
   416  		for j := 0; j < 5; j++ {
   417  			enc[rnd.Intn(len(enc))] = byte(rnd.Intn(256))
   418  		}
   419  		Decode(enc)
   420  	}
   421  }
   422  
   423  func TestDecodeTrailingData(t *testing.T) {
   424  	content := bytes.Repeat([]byte("hello world!"), 100)
   425  	encoded, _ := Encode(content, WriterOptions{Quality: 5})
   426  	_, err := Decode(append(encoded, 0))
   427  	if err == nil {
   428  		t.Errorf("Expected 'excessive input' error")
   429  	}
   430  }
   431  
   432  func TestEncodeDecode(t *testing.T) {
   433  	for _, test := range []struct {
   434  		data    []byte
   435  		repeats int
   436  	}{
   437  		{nil, 0},
   438  		{[]byte("A"), 1},
   439  		{[]byte("<html><body><H1>Hello world</H1></body></html>"), 10},
   440  		{[]byte("<html><body><H1>Hello world</H1></body></html>"), 1000},
   441  	} {
   442  		t.Logf("case %q x %d", test.data, test.repeats)
   443  		input := bytes.Repeat(test.data, test.repeats)
   444  		encoded, err := Encode(input, WriterOptions{Quality: 5})
   445  		if err != nil {
   446  			t.Errorf("Encode: %v", err)
   447  		}
   448  		// Inputs are compressible, but may be too small to compress.
   449  		if maxSize := len(input)/2 + 20; len(encoded) >= maxSize {
   450  			t.Errorf(""+
   451  				"Encode returned %d bytes, want <%d\n"+
   452  				"Encoded=%q",
   453  				len(encoded), maxSize, encoded)
   454  		}
   455  		decoded, err := Decode(encoded)
   456  		if err != nil {
   457  			t.Errorf("Decode: %v", err)
   458  		}
   459  		if !bytes.Equal(decoded, input) {
   460  			var want string
   461  			if len(input) > 320 {
   462  				want = fmt.Sprintf("<%d bytes>", len(input))
   463  			} else {
   464  				want = fmt.Sprintf("%q", input)
   465  			}
   466  			t.Errorf(""+
   467  				"Decode content:\n"+
   468  				"%q\n"+
   469  				"want:\n"+
   470  				"%s",
   471  				decoded, want)
   472  		}
   473  	}
   474  }
   475  
   476  func TestErrorReset(t *testing.T) {
   477  	compress := func(input []byte) []byte {
   478  		var buf bytes.Buffer
   479  		writer := new(Writer)
   480  		writer.Reset(&buf)
   481  		writer.Write(input)
   482  		writer.Close()
   483  
   484  		return buf.Bytes()
   485  	}
   486  
   487  	corruptReader := func(reader *Reader) {
   488  		buf := bytes.NewBuffer([]byte("trash"))
   489  		reader.Reset(buf)
   490  		_, err := io.ReadAll(reader)
   491  		if err == nil {
   492  			t.Fatalf("successively decompressed invalid input")
   493  		}
   494  	}
   495  
   496  	decompress := func(input []byte, reader *Reader) []byte {
   497  		buf := bytes.NewBuffer(input)
   498  		reader.Reset(buf)
   499  		output, err := io.ReadAll(reader)
   500  		if err != nil {
   501  			t.Fatalf("failed to decompress data %s", err.Error())
   502  		}
   503  
   504  		return output
   505  	}
   506  
   507  	source := []byte("text")
   508  
   509  	compressed := compress(source)
   510  	reader := new(Reader)
   511  	corruptReader(reader)
   512  	decompressed := decompress(compressed, reader)
   513  	if string(source) != string(decompressed) {
   514  		t.Fatalf("decompressed data does not match original state")
   515  	}
   516  }
   517  
   518  // Encode returns content encoded with Brotli.
   519  func Encode(content []byte, options WriterOptions) ([]byte, error) {
   520  	var buf bytes.Buffer
   521  	writer := NewWriterOptions(&buf, options)
   522  	_, err := writer.Write(content)
   523  	if closeErr := writer.Close(); err == nil {
   524  		err = closeErr
   525  	}
   526  	return buf.Bytes(), err
   527  }
   528  
   529  // Decode decodes Brotli encoded data.
   530  func Decode(encodedData []byte) ([]byte, error) {
   531  	r := NewReader(bytes.NewReader(encodedData))
   532  	return ioutil.ReadAll(r)
   533  }
   534  
   535  func BenchmarkEncodeLevels(b *testing.B) {
   536  	opticks, err := ioutil.ReadFile("testdata/Isaac.Newton-Opticks.txt")
   537  	if err != nil {
   538  		b.Fatal(err)
   539  	}
   540  
   541  	for level := BestSpeed; level <= BestCompression; level++ {
   542  		b.Run(fmt.Sprintf("%d", level), func(b *testing.B) {
   543  			b.ReportAllocs()
   544  			b.SetBytes(int64(len(opticks)))
   545  			for i := 0; i < b.N; i++ {
   546  				w := NewWriterLevel(ioutil.Discard, level)
   547  				w.Write(opticks)
   548  				w.Close()
   549  			}
   550  		})
   551  	}
   552  }
   553  
   554  func BenchmarkEncodeLevelsReset(b *testing.B) {
   555  	opticks, err := ioutil.ReadFile("testdata/Isaac.Newton-Opticks.txt")
   556  	if err != nil {
   557  		b.Fatal(err)
   558  	}
   559  
   560  	for level := BestSpeed; level <= BestCompression; level++ {
   561  		buf := new(bytes.Buffer)
   562  		w := NewWriterLevel(buf, level)
   563  		w.Write(opticks)
   564  		w.Close()
   565  		b.Run(fmt.Sprintf("%d", level), func(b *testing.B) {
   566  			b.ReportAllocs()
   567  			b.ReportMetric(float64(len(opticks))/float64(buf.Len()), "ratio")
   568  			b.SetBytes(int64(len(opticks)))
   569  			for i := 0; i < b.N; i++ {
   570  				w.Reset(ioutil.Discard)
   571  				w.Write(opticks)
   572  				w.Close()
   573  			}
   574  		})
   575  	}
   576  }
   577  
   578  func BenchmarkEncodeLevelsResetV2(b *testing.B) {
   579  	opticks, err := ioutil.ReadFile("testdata/Isaac.Newton-Opticks.txt")
   580  	if err != nil {
   581  		b.Fatal(err)
   582  	}
   583  
   584  	for level := BestSpeed; level <= 7; level++ {
   585  		buf := new(bytes.Buffer)
   586  		w := NewWriterV2(buf, level)
   587  		w.Write(opticks)
   588  		w.Close()
   589  		b.Run(fmt.Sprintf("%d", level), func(b *testing.B) {
   590  			b.ReportAllocs()
   591  			b.ReportMetric(float64(len(opticks))/float64(buf.Len()), "ratio")
   592  			b.SetBytes(int64(len(opticks)))
   593  			for i := 0; i < b.N; i++ {
   594  				w.Reset(ioutil.Discard)
   595  				w.Write(opticks)
   596  				w.Close()
   597  			}
   598  		})
   599  	}
   600  }
   601  
   602  func BenchmarkDecodeLevels(b *testing.B) {
   603  	opticks, err := ioutil.ReadFile("testdata/Isaac.Newton-Opticks.txt")
   604  	if err != nil {
   605  		b.Fatal(err)
   606  	}
   607  
   608  	for level := BestSpeed; level <= BestCompression; level++ {
   609  		buf := new(bytes.Buffer)
   610  		w := NewWriterLevel(buf, level)
   611  		w.Write(opticks)
   612  		w.Close()
   613  		compressed := buf.Bytes()
   614  		b.Run(fmt.Sprintf("%d", level), func(b *testing.B) {
   615  			b.ReportAllocs()
   616  			b.SetBytes(int64(len(opticks)))
   617  			for i := 0; i < b.N; i++ {
   618  				io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed)))
   619  			}
   620  		})
   621  	}
   622  }
   623  
   624  func test(t *testing.T, filename string, m matchfinder.MatchFinder, blockSize int) {
   625  	data, err := ioutil.ReadFile(filename)
   626  	if err != nil {
   627  		t.Fatal(err)
   628  	}
   629  	b := new(bytes.Buffer)
   630  	w := &matchfinder.Writer{
   631  		Dest:        b,
   632  		MatchFinder: m,
   633  		Encoder:     &Encoder{},
   634  		BlockSize:   blockSize,
   635  	}
   636  	w.Write(data)
   637  	w.Close()
   638  	compressed := b.Bytes()
   639  	sr := NewReader(bytes.NewReader(compressed))
   640  	decompressed, err := ioutil.ReadAll(sr)
   641  	if err != nil {
   642  		t.Fatal(err)
   643  	}
   644  	if !bytes.Equal(decompressed, data) {
   645  		t.Fatal("decompressed output doesn't match")
   646  	}
   647  }
   648  
   649  func benchmark(b *testing.B, filename string, m matchfinder.MatchFinder, blockSize int) {
   650  	b.StopTimer()
   651  	b.ReportAllocs()
   652  	data, err := ioutil.ReadFile(filename)
   653  	if err != nil {
   654  		b.Fatal(err)
   655  	}
   656  
   657  	b.SetBytes(int64(len(data)))
   658  	buf := new(bytes.Buffer)
   659  	w := &matchfinder.Writer{
   660  		Dest:        buf,
   661  		MatchFinder: m,
   662  		Encoder:     &Encoder{},
   663  		BlockSize:   blockSize,
   664  	}
   665  	w.Write(data)
   666  	w.Close()
   667  	b.ReportMetric(float64(len(data))/float64(buf.Len()), "ratio")
   668  	b.StartTimer()
   669  	for i := 0; i < b.N; i++ {
   670  		w.Reset(ioutil.Discard)
   671  		w.Write(data)
   672  		w.Close()
   673  	}
   674  }
   675  
   676  func TestEncodeM4(t *testing.T) {
   677  	test(t, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 18, DistanceBitCost: 57}, 1<<16)
   678  }
   679  
   680  func BenchmarkEncodeM4(b *testing.B) {
   681  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, DistanceBitCost: 57}, 1<<16)
   682  }
   683  
   684  func TestEncodeM4Chain1(t *testing.T) {
   685  	test(t, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 18, ChainLength: 1, DistanceBitCost: 57}, 1<<16)
   686  }
   687  
   688  func BenchmarkEncodeM4Chain1(b *testing.B) {
   689  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 1, DistanceBitCost: 57}, 1<<16)
   690  }
   691  
   692  func BenchmarkEncodeM4Chain2(b *testing.B) {
   693  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 2, DistanceBitCost: 57}, 1<<16)
   694  }
   695  
   696  func BenchmarkEncodeM4Chain4(b *testing.B) {
   697  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 4, DistanceBitCost: 57}, 1<<16)
   698  }
   699  
   700  func BenchmarkEncodeM4Chain8(b *testing.B) {
   701  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 8, HashLen: 5, DistanceBitCost: 57}, 1<<16)
   702  }
   703  
   704  func BenchmarkEncodeM4Chain16(b *testing.B) {
   705  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 16, HashLen: 5, DistanceBitCost: 57}, 1<<16)
   706  }
   707  
   708  func BenchmarkEncodeM4Chain32(b *testing.B) {
   709  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 32, HashLen: 5, DistanceBitCost: 57}, 1<<16)
   710  }
   711  
   712  func BenchmarkEncodeM4Chain64(b *testing.B) {
   713  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 64, HashLen: 5, DistanceBitCost: 57}, 1<<16)
   714  }
   715  
   716  func BenchmarkEncodeM4Chain128(b *testing.B) {
   717  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 128, HashLen: 5, DistanceBitCost: 57}, 1<<16)
   718  }
   719  
   720  func BenchmarkEncodeM4Chain256(b *testing.B) {
   721  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", &matchfinder.M4{MaxDistance: 1 << 20, ChainLength: 256, HashLen: 5, DistanceBitCost: 57}, 1<<16)
   722  }
   723  
   724  func TestEncodeM0(t *testing.T) {
   725  	test(t, "testdata/Isaac.Newton-Opticks.txt", matchfinder.M0{}, 1<<16)
   726  }
   727  
   728  func BenchmarkEncodeM0(b *testing.B) {
   729  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", matchfinder.M0{}, 1<<16)
   730  }
   731  
   732  func TestEncodeM0Lazy(t *testing.T) {
   733  	test(t, "testdata/Isaac.Newton-Opticks.txt", matchfinder.M0{Lazy: true}, 1<<16)
   734  }
   735  
   736  func BenchmarkEncodeM0Lazy(b *testing.B) {
   737  	benchmark(b, "testdata/Isaac.Newton-Opticks.txt", matchfinder.M0{Lazy: true}, 1<<16)
   738  }