123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- // Copyright 2012 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package flate
- import (
- "bytes"
- "fmt"
- "io"
- "math/rand"
- "runtime"
- "testing"
- )
- func BenchmarkEncode(b *testing.B) {
- doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
- b.StopTimer()
- b.SetBytes(int64(n))
- buf1 := make([]byte, n)
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
- }
- copy(buf1[i:], buf0)
- }
- buf0 = nil
- w, err := NewWriter(io.Discard, level)
- if err != nil {
- b.Fatal(err)
- }
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- w.Reset(io.Discard)
- w.Write(buf1)
- w.Close()
- }
- })
- }
- // errorWriter is a writer that fails after N writes.
- type errorWriter struct {
- N int
- }
- func (e *errorWriter) Write(b []byte) (int, error) {
- if e.N <= 0 {
- return 0, io.ErrClosedPipe
- }
- e.N--
- return len(b), nil
- }
- // Test if errors from the underlying writer is passed upwards.
- func TestWriteError(t *testing.T) {
- t.Parallel()
- buf := new(bytes.Buffer)
- n := 65536
- if !testing.Short() {
- n *= 4
- }
- for i := 0; i < n; i++ {
- fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
- }
- in := buf.Bytes()
- // We create our own buffer to control number of writes.
- copyBuffer := make([]byte, 128)
- for l := 0; l < 10; l++ {
- for fail := 1; fail <= 256; fail *= 2 {
- // Fail after 'fail' writes
- ew := &errorWriter{N: fail}
- w, err := NewWriter(ew, l)
- if err != nil {
- t.Fatalf("NewWriter: level %d: %v", l, err)
- }
- n, err := io.CopyBuffer(w, struct{ io.Reader }{bytes.NewBuffer(in)}, copyBuffer)
- if err == nil {
- t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
- }
- n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5})
- if n2 != 0 {
- t.Fatal("Level", l, "Expected 0 length write, got", n)
- }
- if err == nil {
- t.Fatal("Level", l, "Expected an error")
- }
- err = w.Flush()
- if err == nil {
- t.Fatal("Level", l, "Expected an error on flush")
- }
- err = w.Close()
- if err == nil {
- t.Fatal("Level", l, "Expected an error on close")
- }
- w.Reset(io.Discard)
- n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6})
- if err != nil {
- t.Fatal("Level", l, "Got unexpected error after reset:", err)
- }
- if n2 == 0 {
- t.Fatal("Level", l, "Got 0 length write, expected > 0")
- }
- if testing.Short() {
- return
- }
- }
- }
- }
- // Test if two runs produce identical results
- // even when writing different sizes to the Writer.
- func TestDeterministic(t *testing.T) {
- t.Parallel()
- for i := 0; i <= 9; i++ {
- t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
- }
- t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) })
- }
- func testDeterministic(i int, t *testing.T) {
- t.Parallel()
- // Test so much we cross a good number of block boundaries.
- var length = maxStoreBlockSize*30 + 500
- if testing.Short() {
- length /= 10
- }
- // Create a random, but compressible stream.
- rng := rand.New(rand.NewSource(1))
- t1 := make([]byte, length)
- for i := range t1 {
- t1[i] = byte(rng.Int63() & 7)
- }
- // Do our first encode.
- var b1 bytes.Buffer
- br := bytes.NewBuffer(t1)
- w, err := NewWriter(&b1, i)
- if err != nil {
- t.Fatal(err)
- }
- // Use a very small prime sized buffer.
- cbuf := make([]byte, 787)
- _, err = io.CopyBuffer(w, struct{ io.Reader }{br}, cbuf)
- if err != nil {
- t.Fatal(err)
- }
- w.Close()
- // We choose a different buffer size,
- // bigger than a maximum block, and also a prime.
- var b2 bytes.Buffer
- cbuf = make([]byte, 81761)
- br2 := bytes.NewBuffer(t1)
- w2, err := NewWriter(&b2, i)
- if err != nil {
- t.Fatal(err)
- }
- _, err = io.CopyBuffer(w2, struct{ io.Reader }{br2}, cbuf)
- if err != nil {
- t.Fatal(err)
- }
- w2.Close()
- b1b := b1.Bytes()
- b2b := b2.Bytes()
- if !bytes.Equal(b1b, b2b) {
- t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
- }
- }
- // TestDeflateFast_Reset will test that encoding is consistent
- // across a warparound of the table offset.
- // See https://github.com/golang/go/issues/34121
- func TestDeflateFast_Reset(t *testing.T) {
- buf := new(bytes.Buffer)
- n := 65536
- for i := 0; i < n; i++ {
- fmt.Fprintf(buf, "asdfasdfasdfasdf%d%dfghfgujyut%dyutyu\n", i, i, i)
- }
- // This is specific to level 1.
- const level = 1
- in := buf.Bytes()
- offset := 1
- if testing.Short() {
- offset = 256
- }
- // We do an encode with a clean buffer to compare.
- var want bytes.Buffer
- w, err := NewWriter(&want, level)
- if err != nil {
- t.Fatalf("NewWriter: level %d: %v", level, err)
- }
- // Output written 3 times.
- w.Write(in)
- w.Write(in)
- w.Write(in)
- w.Close()
- for ; offset <= 256; offset *= 2 {
- w, err := NewWriter(io.Discard, level)
- if err != nil {
- t.Fatalf("NewWriter: level %d: %v", level, err)
- }
- // Reset until we are right before the wraparound.
- // Each reset adds maxMatchOffset to the offset.
- for i := 0; i < (bufferReset-len(in)-offset-maxMatchOffset)/maxMatchOffset; i++ {
- // skip ahead to where we are close to wrap around...
- w.d.reset(nil)
- }
- var got bytes.Buffer
- w.Reset(&got)
- // Write 3 times, close.
- for i := 0; i < 3; i++ {
- _, err = w.Write(in)
- if err != nil {
- t.Fatal(err)
- }
- }
- err = w.Close()
- if err != nil {
- t.Fatal(err)
- }
- if !bytes.Equal(got.Bytes(), want.Bytes()) {
- t.Fatalf("output did not match at wraparound, len(want) = %d, len(got) = %d", want.Len(), got.Len())
- }
- }
- }
|