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
5package flate
6
7import (
8	"bytes"
9	"fmt"
10	"io"
11	"math/rand"
12	"runtime"
13	"testing"
14)
15
16func 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.
44type errorWriter struct {
45	N int
46}
47
48func (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.
57func 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.
115func 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
123func 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
179func 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