...

Source file src/compress/flate/writer_test.go

Documentation: compress/flate

		 1  // Copyright 2012 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  	"fmt"
		10  	"io"
		11  	"math/rand"
		12  	"runtime"
		13  	"testing"
		14  )
		15  
		16  func BenchmarkEncode(b *testing.B) {
		17  	doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
		18  		b.StopTimer()
		19  		b.SetBytes(int64(n))
		20  
		21  		buf1 := make([]byte, n)
		22  		for i := 0; i < n; i += len(buf0) {
		23  			if len(buf0) > n-i {
		24  				buf0 = buf0[:n-i]
		25  			}
		26  			copy(buf1[i:], buf0)
		27  		}
		28  		buf0 = nil
		29  		w, err := NewWriter(io.Discard, level)
		30  		if err != nil {
		31  			b.Fatal(err)
		32  		}
		33  		runtime.GC()
		34  		b.StartTimer()
		35  		for i := 0; i < b.N; i++ {
		36  			w.Reset(io.Discard)
		37  			w.Write(buf1)
		38  			w.Close()
		39  		}
		40  	})
		41  }
		42  
		43  // errorWriter is a writer that fails after N writes.
		44  type errorWriter struct {
		45  	N int
		46  }
		47  
		48  func (e *errorWriter) Write(b []byte) (int, error) {
		49  	if e.N <= 0 {
		50  		return 0, io.ErrClosedPipe
		51  	}
		52  	e.N--
		53  	return len(b), nil
		54  }
		55  
		56  // Test if errors from the underlying writer is passed upwards.
		57  func TestWriteError(t *testing.T) {
		58  	t.Parallel()
		59  	buf := new(bytes.Buffer)
		60  	n := 65536
		61  	if !testing.Short() {
		62  		n *= 4
		63  	}
		64  	for i := 0; i < n; i++ {
		65  		fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
		66  	}
		67  	in := buf.Bytes()
		68  	// We create our own buffer to control number of writes.
		69  	copyBuffer := make([]byte, 128)
		70  	for l := 0; l < 10; l++ {
		71  		for fail := 1; fail <= 256; fail *= 2 {
		72  			// Fail after 'fail' writes
		73  			ew := &errorWriter{N: fail}
		74  			w, err := NewWriter(ew, l)
		75  			if err != nil {
		76  				t.Fatalf("NewWriter: level %d: %v", l, err)
		77  			}
		78  			n, err := io.CopyBuffer(w, struct{ io.Reader }{bytes.NewBuffer(in)}, copyBuffer)
		79  			if err == nil {
		80  				t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
		81  			}
		82  			n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5})
		83  			if n2 != 0 {
		84  				t.Fatal("Level", l, "Expected 0 length write, got", n)
		85  			}
		86  			if err == nil {
		87  				t.Fatal("Level", l, "Expected an error")
		88  			}
		89  			err = w.Flush()
		90  			if err == nil {
		91  				t.Fatal("Level", l, "Expected an error on flush")
		92  			}
		93  			err = w.Close()
		94  			if err == nil {
		95  				t.Fatal("Level", l, "Expected an error on close")
		96  			}
		97  
		98  			w.Reset(io.Discard)
		99  			n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6})
	 100  			if err != nil {
	 101  				t.Fatal("Level", l, "Got unexpected error after reset:", err)
	 102  			}
	 103  			if n2 == 0 {
	 104  				t.Fatal("Level", l, "Got 0 length write, expected > 0")
	 105  			}
	 106  			if testing.Short() {
	 107  				return
	 108  			}
	 109  		}
	 110  	}
	 111  }
	 112  
	 113  // Test if two runs produce identical results
	 114  // even when writing different sizes to the Writer.
	 115  func TestDeterministic(t *testing.T) {
	 116  	t.Parallel()
	 117  	for i := 0; i <= 9; i++ {
	 118  		t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
	 119  	}
	 120  	t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) })
	 121  }
	 122  
	 123  func testDeterministic(i int, t *testing.T) {
	 124  	t.Parallel()
	 125  	// Test so much we cross a good number of block boundaries.
	 126  	var length = maxStoreBlockSize*30 + 500
	 127  	if testing.Short() {
	 128  		length /= 10
	 129  	}
	 130  
	 131  	// Create a random, but compressible stream.
	 132  	rng := rand.New(rand.NewSource(1))
	 133  	t1 := make([]byte, length)
	 134  	for i := range t1 {
	 135  		t1[i] = byte(rng.Int63() & 7)
	 136  	}
	 137  
	 138  	// Do our first encode.
	 139  	var b1 bytes.Buffer
	 140  	br := bytes.NewBuffer(t1)
	 141  	w, err := NewWriter(&b1, i)
	 142  	if err != nil {
	 143  		t.Fatal(err)
	 144  	}
	 145  	// Use a very small prime sized buffer.
	 146  	cbuf := make([]byte, 787)
	 147  	_, err = io.CopyBuffer(w, struct{ io.Reader }{br}, cbuf)
	 148  	if err != nil {
	 149  		t.Fatal(err)
	 150  	}
	 151  	w.Close()
	 152  
	 153  	// We choose a different buffer size,
	 154  	// bigger than a maximum block, and also a prime.
	 155  	var b2 bytes.Buffer
	 156  	cbuf = make([]byte, 81761)
	 157  	br2 := bytes.NewBuffer(t1)
	 158  	w2, err := NewWriter(&b2, i)
	 159  	if err != nil {
	 160  		t.Fatal(err)
	 161  	}
	 162  	_, err = io.CopyBuffer(w2, struct{ io.Reader }{br2}, cbuf)
	 163  	if err != nil {
	 164  		t.Fatal(err)
	 165  	}
	 166  	w2.Close()
	 167  
	 168  	b1b := b1.Bytes()
	 169  	b2b := b2.Bytes()
	 170  
	 171  	if !bytes.Equal(b1b, b2b) {
	 172  		t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
	 173  	}
	 174  }
	 175  
	 176  // TestDeflateFast_Reset will test that encoding is consistent
	 177  // across a warparound of the table offset.
	 178  // See https://github.com/golang/go/issues/34121
	 179  func TestDeflateFast_Reset(t *testing.T) {
	 180  	buf := new(bytes.Buffer)
	 181  	n := 65536
	 182  
	 183  	for i := 0; i < n; i++ {
	 184  		fmt.Fprintf(buf, "asdfasdfasdfasdf%d%dfghfgujyut%dyutyu\n", i, i, i)
	 185  	}
	 186  	// This is specific to level 1.
	 187  	const level = 1
	 188  	in := buf.Bytes()
	 189  	offset := 1
	 190  	if testing.Short() {
	 191  		offset = 256
	 192  	}
	 193  
	 194  	// We do an encode with a clean buffer to compare.
	 195  	var want bytes.Buffer
	 196  	w, err := NewWriter(&want, level)
	 197  	if err != nil {
	 198  		t.Fatalf("NewWriter: level %d: %v", level, err)
	 199  	}
	 200  
	 201  	// Output written 3 times.
	 202  	w.Write(in)
	 203  	w.Write(in)
	 204  	w.Write(in)
	 205  	w.Close()
	 206  
	 207  	for ; offset <= 256; offset *= 2 {
	 208  		w, err := NewWriter(io.Discard, level)
	 209  		if err != nil {
	 210  			t.Fatalf("NewWriter: level %d: %v", level, err)
	 211  		}
	 212  
	 213  		// Reset until we are right before the wraparound.
	 214  		// Each reset adds maxMatchOffset to the offset.
	 215  		for i := 0; i < (bufferReset-len(in)-offset-maxMatchOffset)/maxMatchOffset; i++ {
	 216  			// skip ahead to where we are close to wrap around...
	 217  			w.d.reset(nil)
	 218  		}
	 219  		var got bytes.Buffer
	 220  		w.Reset(&got)
	 221  
	 222  		// Write 3 times, close.
	 223  		for i := 0; i < 3; i++ {
	 224  			_, err = w.Write(in)
	 225  			if err != nil {
	 226  				t.Fatal(err)
	 227  			}
	 228  		}
	 229  		err = w.Close()
	 230  		if err != nil {
	 231  			t.Fatal(err)
	 232  		}
	 233  		if !bytes.Equal(got.Bytes(), want.Bytes()) {
	 234  			t.Fatalf("output did not match at wraparound, len(want)	= %d, len(got) = %d", want.Len(), got.Len())
	 235  		}
	 236  	}
	 237  }
	 238  

View as plain text