xref: /aosp_15_r20/external/brotli/go/cbrotli/cbrotli_test.go (revision f4ee7fba7774faf2a30f13154332c0a06550dbc4)
1*f4ee7fbaSAndroid Build Coastguard Worker// Copyright 2016 Google Inc. All Rights Reserved.
2*f4ee7fbaSAndroid Build Coastguard Worker//
3*f4ee7fbaSAndroid Build Coastguard Worker// Distributed under MIT license.
4*f4ee7fbaSAndroid Build Coastguard Worker// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5*f4ee7fbaSAndroid Build Coastguard Worker
6*f4ee7fbaSAndroid Build Coastguard Workerpackage cbrotli
7*f4ee7fbaSAndroid Build Coastguard Worker
8*f4ee7fbaSAndroid Build Coastguard Workerimport (
9*f4ee7fbaSAndroid Build Coastguard Worker	"bytes"
10*f4ee7fbaSAndroid Build Coastguard Worker	"fmt"
11*f4ee7fbaSAndroid Build Coastguard Worker	"io"
12*f4ee7fbaSAndroid Build Coastguard Worker	"io/ioutil"
13*f4ee7fbaSAndroid Build Coastguard Worker	"math"
14*f4ee7fbaSAndroid Build Coastguard Worker	"math/rand"
15*f4ee7fbaSAndroid Build Coastguard Worker	"testing"
16*f4ee7fbaSAndroid Build Coastguard Worker	"time"
17*f4ee7fbaSAndroid Build Coastguard Worker)
18*f4ee7fbaSAndroid Build Coastguard Worker
19*f4ee7fbaSAndroid Build Coastguard Workerfunc checkCompressedData(compressedData, wantOriginalData []byte) error {
20*f4ee7fbaSAndroid Build Coastguard Worker	uncompressed, err := Decode(compressedData)
21*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
22*f4ee7fbaSAndroid Build Coastguard Worker		return fmt.Errorf("brotli decompress failed: %v", err)
23*f4ee7fbaSAndroid Build Coastguard Worker	}
24*f4ee7fbaSAndroid Build Coastguard Worker	if !bytes.Equal(uncompressed, wantOriginalData) {
25*f4ee7fbaSAndroid Build Coastguard Worker		if len(wantOriginalData) != len(uncompressed) {
26*f4ee7fbaSAndroid Build Coastguard Worker			return fmt.Errorf(""+
27*f4ee7fbaSAndroid Build Coastguard Worker				"Data doesn't uncompress to the original value.\n"+
28*f4ee7fbaSAndroid Build Coastguard Worker				"Length of original: %v\n"+
29*f4ee7fbaSAndroid Build Coastguard Worker				"Length of uncompressed: %v",
30*f4ee7fbaSAndroid Build Coastguard Worker				len(wantOriginalData), len(uncompressed))
31*f4ee7fbaSAndroid Build Coastguard Worker		}
32*f4ee7fbaSAndroid Build Coastguard Worker		for i := range wantOriginalData {
33*f4ee7fbaSAndroid Build Coastguard Worker			if wantOriginalData[i] != uncompressed[i] {
34*f4ee7fbaSAndroid Build Coastguard Worker				return fmt.Errorf(""+
35*f4ee7fbaSAndroid Build Coastguard Worker					"Data doesn't uncompress to the original value.\n"+
36*f4ee7fbaSAndroid Build Coastguard Worker					"Original at %v is %v\n"+
37*f4ee7fbaSAndroid Build Coastguard Worker					"Uncompressed at %v is %v",
38*f4ee7fbaSAndroid Build Coastguard Worker					i, wantOriginalData[i], i, uncompressed[i])
39*f4ee7fbaSAndroid Build Coastguard Worker			}
40*f4ee7fbaSAndroid Build Coastguard Worker		}
41*f4ee7fbaSAndroid Build Coastguard Worker	}
42*f4ee7fbaSAndroid Build Coastguard Worker	return nil
43*f4ee7fbaSAndroid Build Coastguard Worker}
44*f4ee7fbaSAndroid Build Coastguard Worker
45*f4ee7fbaSAndroid Build Coastguard Workerfunc TestEncoderNoWrite(t *testing.T) {
46*f4ee7fbaSAndroid Build Coastguard Worker	out := bytes.Buffer{}
47*f4ee7fbaSAndroid Build Coastguard Worker	e := NewWriter(&out, WriterOptions{Quality: 5})
48*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Close(); err != nil {
49*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close()=%v, want nil", err)
50*f4ee7fbaSAndroid Build Coastguard Worker	}
51*f4ee7fbaSAndroid Build Coastguard Worker	// Check Write after close.
52*f4ee7fbaSAndroid Build Coastguard Worker	if _, err := e.Write([]byte("hi")); err == nil {
53*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("No error after Close() + Write()")
54*f4ee7fbaSAndroid Build Coastguard Worker	}
55*f4ee7fbaSAndroid Build Coastguard Worker}
56*f4ee7fbaSAndroid Build Coastguard Worker
57*f4ee7fbaSAndroid Build Coastguard Workerfunc TestEncoderEmptyWrite(t *testing.T) {
58*f4ee7fbaSAndroid Build Coastguard Worker	out := bytes.Buffer{}
59*f4ee7fbaSAndroid Build Coastguard Worker	e := NewWriter(&out, WriterOptions{Quality: 5})
60*f4ee7fbaSAndroid Build Coastguard Worker	n, err := e.Write([]byte(""))
61*f4ee7fbaSAndroid Build Coastguard Worker	if n != 0 || err != nil {
62*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Write()=%v,%v, want 0, nil", n, err)
63*f4ee7fbaSAndroid Build Coastguard Worker	}
64*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Close(); err != nil {
65*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close()=%v, want nil", err)
66*f4ee7fbaSAndroid Build Coastguard Worker	}
67*f4ee7fbaSAndroid Build Coastguard Worker}
68*f4ee7fbaSAndroid Build Coastguard Worker
69*f4ee7fbaSAndroid Build Coastguard Workerfunc TestWriter(t *testing.T) {
70*f4ee7fbaSAndroid Build Coastguard Worker	// Test basic encoder usage.
71*f4ee7fbaSAndroid Build Coastguard Worker	input := []byte("<html><body><H1>Hello world</H1></body></html>")
72*f4ee7fbaSAndroid Build Coastguard Worker	out := bytes.Buffer{}
73*f4ee7fbaSAndroid Build Coastguard Worker	e := NewWriter(&out, WriterOptions{Quality: 1})
74*f4ee7fbaSAndroid Build Coastguard Worker	in := bytes.NewReader([]byte(input))
75*f4ee7fbaSAndroid Build Coastguard Worker	n, err := io.Copy(e, in)
76*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
77*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Copy Error: %v", err)
78*f4ee7fbaSAndroid Build Coastguard Worker	}
79*f4ee7fbaSAndroid Build Coastguard Worker	if int(n) != len(input) {
80*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Copy() n=%v, want %v", n, len(input))
81*f4ee7fbaSAndroid Build Coastguard Worker	}
82*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Close(); err != nil {
83*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close Error after copied %d bytes: %v", n, err)
84*f4ee7fbaSAndroid Build Coastguard Worker	}
85*f4ee7fbaSAndroid Build Coastguard Worker	if err := checkCompressedData(out.Bytes(), input); err != nil {
86*f4ee7fbaSAndroid Build Coastguard Worker		t.Error(err)
87*f4ee7fbaSAndroid Build Coastguard Worker	}
88*f4ee7fbaSAndroid Build Coastguard Worker}
89*f4ee7fbaSAndroid Build Coastguard Worker
90*f4ee7fbaSAndroid Build Coastguard Workerfunc TestEncoderStreams(t *testing.T) {
91*f4ee7fbaSAndroid Build Coastguard Worker	// Test that output is streamed.
92*f4ee7fbaSAndroid Build Coastguard Worker	// Adjust window size to ensure the encoder outputs at least enough bytes
93*f4ee7fbaSAndroid Build Coastguard Worker	// to fill the window.
94*f4ee7fbaSAndroid Build Coastguard Worker	const lgWin = 16
95*f4ee7fbaSAndroid Build Coastguard Worker	windowSize := int(math.Pow(2, lgWin))
96*f4ee7fbaSAndroid Build Coastguard Worker	input := make([]byte, 8*windowSize)
97*f4ee7fbaSAndroid Build Coastguard Worker	rand.Read(input)
98*f4ee7fbaSAndroid Build Coastguard Worker	out := bytes.Buffer{}
99*f4ee7fbaSAndroid Build Coastguard Worker	e := NewWriter(&out, WriterOptions{Quality: 11, LGWin: lgWin})
100*f4ee7fbaSAndroid Build Coastguard Worker	halfInput := input[:len(input)/2]
101*f4ee7fbaSAndroid Build Coastguard Worker	in := bytes.NewReader(halfInput)
102*f4ee7fbaSAndroid Build Coastguard Worker
103*f4ee7fbaSAndroid Build Coastguard Worker	n, err := io.Copy(e, in)
104*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
105*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Copy Error: %v", err)
106*f4ee7fbaSAndroid Build Coastguard Worker	}
107*f4ee7fbaSAndroid Build Coastguard Worker
108*f4ee7fbaSAndroid Build Coastguard Worker	// We've fed more data than the sliding window size. Check that some
109*f4ee7fbaSAndroid Build Coastguard Worker	// compressed data has been output.
110*f4ee7fbaSAndroid Build Coastguard Worker	if out.Len() == 0 {
111*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Output length is 0 after %d bytes written", n)
112*f4ee7fbaSAndroid Build Coastguard Worker	}
113*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Close(); err != nil {
114*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close Error after copied %d bytes: %v", n, err)
115*f4ee7fbaSAndroid Build Coastguard Worker	}
116*f4ee7fbaSAndroid Build Coastguard Worker	if err := checkCompressedData(out.Bytes(), halfInput); err != nil {
117*f4ee7fbaSAndroid Build Coastguard Worker		t.Error(err)
118*f4ee7fbaSAndroid Build Coastguard Worker	}
119*f4ee7fbaSAndroid Build Coastguard Worker}
120*f4ee7fbaSAndroid Build Coastguard Worker
121*f4ee7fbaSAndroid Build Coastguard Workerfunc TestEncoderLargeInput(t *testing.T) {
122*f4ee7fbaSAndroid Build Coastguard Worker	input := make([]byte, 1000000)
123*f4ee7fbaSAndroid Build Coastguard Worker	rand.Read(input)
124*f4ee7fbaSAndroid Build Coastguard Worker	out := bytes.Buffer{}
125*f4ee7fbaSAndroid Build Coastguard Worker	e := NewWriter(&out, WriterOptions{Quality: 5})
126*f4ee7fbaSAndroid Build Coastguard Worker	in := bytes.NewReader(input)
127*f4ee7fbaSAndroid Build Coastguard Worker
128*f4ee7fbaSAndroid Build Coastguard Worker	n, err := io.Copy(e, in)
129*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
130*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Copy Error: %v", err)
131*f4ee7fbaSAndroid Build Coastguard Worker	}
132*f4ee7fbaSAndroid Build Coastguard Worker	if int(n) != len(input) {
133*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Copy() n=%v, want %v", n, len(input))
134*f4ee7fbaSAndroid Build Coastguard Worker	}
135*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Close(); err != nil {
136*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close Error after copied %d bytes: %v", n, err)
137*f4ee7fbaSAndroid Build Coastguard Worker	}
138*f4ee7fbaSAndroid Build Coastguard Worker	if err := checkCompressedData(out.Bytes(), input); err != nil {
139*f4ee7fbaSAndroid Build Coastguard Worker		t.Error(err)
140*f4ee7fbaSAndroid Build Coastguard Worker	}
141*f4ee7fbaSAndroid Build Coastguard Worker}
142*f4ee7fbaSAndroid Build Coastguard Worker
143*f4ee7fbaSAndroid Build Coastguard Workerfunc TestEncoderFlush(t *testing.T) {
144*f4ee7fbaSAndroid Build Coastguard Worker	input := make([]byte, 1000)
145*f4ee7fbaSAndroid Build Coastguard Worker	rand.Read(input)
146*f4ee7fbaSAndroid Build Coastguard Worker	out := bytes.Buffer{}
147*f4ee7fbaSAndroid Build Coastguard Worker	e := NewWriter(&out, WriterOptions{Quality: 5})
148*f4ee7fbaSAndroid Build Coastguard Worker	in := bytes.NewReader(input)
149*f4ee7fbaSAndroid Build Coastguard Worker	_, err := io.Copy(e, in)
150*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
151*f4ee7fbaSAndroid Build Coastguard Worker		t.Fatalf("Copy Error: %v", err)
152*f4ee7fbaSAndroid Build Coastguard Worker	}
153*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Flush(); err != nil {
154*f4ee7fbaSAndroid Build Coastguard Worker		t.Fatalf("Flush(): %v", err)
155*f4ee7fbaSAndroid Build Coastguard Worker	}
156*f4ee7fbaSAndroid Build Coastguard Worker	if out.Len() == 0 {
157*f4ee7fbaSAndroid Build Coastguard Worker		t.Fatalf("0 bytes written after Flush()")
158*f4ee7fbaSAndroid Build Coastguard Worker	}
159*f4ee7fbaSAndroid Build Coastguard Worker	decompressed := make([]byte, 1000)
160*f4ee7fbaSAndroid Build Coastguard Worker	reader := NewReader(bytes.NewReader(out.Bytes()))
161*f4ee7fbaSAndroid Build Coastguard Worker	n, err := reader.Read(decompressed)
162*f4ee7fbaSAndroid Build Coastguard Worker	if n != len(decompressed) || err != nil {
163*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Expected <%v, nil>, but <%v, %v>", len(decompressed), n, err)
164*f4ee7fbaSAndroid Build Coastguard Worker	}
165*f4ee7fbaSAndroid Build Coastguard Worker	reader.Close()
166*f4ee7fbaSAndroid Build Coastguard Worker	if !bytes.Equal(decompressed, input) {
167*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf(""+
168*f4ee7fbaSAndroid Build Coastguard Worker			"Decompress after flush: %v\n"+
169*f4ee7fbaSAndroid Build Coastguard Worker			"%q\n"+
170*f4ee7fbaSAndroid Build Coastguard Worker			"want:\n%q",
171*f4ee7fbaSAndroid Build Coastguard Worker			err, decompressed, input)
172*f4ee7fbaSAndroid Build Coastguard Worker	}
173*f4ee7fbaSAndroid Build Coastguard Worker	if err := e.Close(); err != nil {
174*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close(): %v", err)
175*f4ee7fbaSAndroid Build Coastguard Worker	}
176*f4ee7fbaSAndroid Build Coastguard Worker}
177*f4ee7fbaSAndroid Build Coastguard Worker
178*f4ee7fbaSAndroid Build Coastguard Workertype readerWithTimeout struct {
179*f4ee7fbaSAndroid Build Coastguard Worker	io.ReadCloser
180*f4ee7fbaSAndroid Build Coastguard Worker}
181*f4ee7fbaSAndroid Build Coastguard Worker
182*f4ee7fbaSAndroid Build Coastguard Workerfunc (r readerWithTimeout) Read(p []byte) (int, error) {
183*f4ee7fbaSAndroid Build Coastguard Worker	type result struct {
184*f4ee7fbaSAndroid Build Coastguard Worker		n   int
185*f4ee7fbaSAndroid Build Coastguard Worker		err error
186*f4ee7fbaSAndroid Build Coastguard Worker	}
187*f4ee7fbaSAndroid Build Coastguard Worker	ch := make(chan result)
188*f4ee7fbaSAndroid Build Coastguard Worker	go func() {
189*f4ee7fbaSAndroid Build Coastguard Worker		n, err := r.ReadCloser.Read(p)
190*f4ee7fbaSAndroid Build Coastguard Worker		ch <- result{n, err}
191*f4ee7fbaSAndroid Build Coastguard Worker	}()
192*f4ee7fbaSAndroid Build Coastguard Worker	select {
193*f4ee7fbaSAndroid Build Coastguard Worker	case result := <-ch:
194*f4ee7fbaSAndroid Build Coastguard Worker		return result.n, result.err
195*f4ee7fbaSAndroid Build Coastguard Worker	case <-time.After(5 * time.Second):
196*f4ee7fbaSAndroid Build Coastguard Worker		return 0, fmt.Errorf("read timed out")
197*f4ee7fbaSAndroid Build Coastguard Worker	}
198*f4ee7fbaSAndroid Build Coastguard Worker}
199*f4ee7fbaSAndroid Build Coastguard Worker
200*f4ee7fbaSAndroid Build Coastguard Workerfunc TestDecoderStreaming(t *testing.T) {
201*f4ee7fbaSAndroid Build Coastguard Worker	pr, pw := io.Pipe()
202*f4ee7fbaSAndroid Build Coastguard Worker	writer := NewWriter(pw, WriterOptions{Quality: 5, LGWin: 20})
203*f4ee7fbaSAndroid Build Coastguard Worker	reader := readerWithTimeout{NewReader(pr)}
204*f4ee7fbaSAndroid Build Coastguard Worker	defer func() {
205*f4ee7fbaSAndroid Build Coastguard Worker		if err := reader.Close(); err != nil {
206*f4ee7fbaSAndroid Build Coastguard Worker			t.Errorf("reader.Close: %v", err)
207*f4ee7fbaSAndroid Build Coastguard Worker		}
208*f4ee7fbaSAndroid Build Coastguard Worker		go ioutil.ReadAll(pr) // swallow the "EOF" token from writer.Close
209*f4ee7fbaSAndroid Build Coastguard Worker		if err := writer.Close(); err != nil {
210*f4ee7fbaSAndroid Build Coastguard Worker			t.Errorf("writer.Close: %v", err)
211*f4ee7fbaSAndroid Build Coastguard Worker		}
212*f4ee7fbaSAndroid Build Coastguard Worker	}()
213*f4ee7fbaSAndroid Build Coastguard Worker
214*f4ee7fbaSAndroid Build Coastguard Worker	ch := make(chan []byte)
215*f4ee7fbaSAndroid Build Coastguard Worker	errch := make(chan error)
216*f4ee7fbaSAndroid Build Coastguard Worker	go func() {
217*f4ee7fbaSAndroid Build Coastguard Worker		for {
218*f4ee7fbaSAndroid Build Coastguard Worker			segment, ok := <-ch
219*f4ee7fbaSAndroid Build Coastguard Worker			if !ok {
220*f4ee7fbaSAndroid Build Coastguard Worker				return
221*f4ee7fbaSAndroid Build Coastguard Worker			}
222*f4ee7fbaSAndroid Build Coastguard Worker			if n, err := writer.Write(segment); err != nil || n != len(segment) {
223*f4ee7fbaSAndroid Build Coastguard Worker				errch <- fmt.Errorf("write=%v,%v, want %v,%v", n, err, len(segment), nil)
224*f4ee7fbaSAndroid Build Coastguard Worker				return
225*f4ee7fbaSAndroid Build Coastguard Worker			}
226*f4ee7fbaSAndroid Build Coastguard Worker			if err := writer.Flush(); err != nil {
227*f4ee7fbaSAndroid Build Coastguard Worker				errch <- fmt.Errorf("flush: %v", err)
228*f4ee7fbaSAndroid Build Coastguard Worker				return
229*f4ee7fbaSAndroid Build Coastguard Worker			}
230*f4ee7fbaSAndroid Build Coastguard Worker		}
231*f4ee7fbaSAndroid Build Coastguard Worker	}()
232*f4ee7fbaSAndroid Build Coastguard Worker	defer close(ch)
233*f4ee7fbaSAndroid Build Coastguard Worker
234*f4ee7fbaSAndroid Build Coastguard Worker	segments := [...][]byte{
235*f4ee7fbaSAndroid Build Coastguard Worker		[]byte("first"),
236*f4ee7fbaSAndroid Build Coastguard Worker		[]byte("second"),
237*f4ee7fbaSAndroid Build Coastguard Worker		[]byte("third"),
238*f4ee7fbaSAndroid Build Coastguard Worker	}
239*f4ee7fbaSAndroid Build Coastguard Worker	for k, segment := range segments {
240*f4ee7fbaSAndroid Build Coastguard Worker		t.Run(fmt.Sprintf("Segment%d", k), func(t *testing.T) {
241*f4ee7fbaSAndroid Build Coastguard Worker			select {
242*f4ee7fbaSAndroid Build Coastguard Worker			case ch <- segment:
243*f4ee7fbaSAndroid Build Coastguard Worker			case err := <-errch:
244*f4ee7fbaSAndroid Build Coastguard Worker				t.Fatalf("write: %v", err)
245*f4ee7fbaSAndroid Build Coastguard Worker			case <-time.After(5 * time.Second):
246*f4ee7fbaSAndroid Build Coastguard Worker				t.Fatalf("timed out")
247*f4ee7fbaSAndroid Build Coastguard Worker			}
248*f4ee7fbaSAndroid Build Coastguard Worker			wantLen := len(segment)
249*f4ee7fbaSAndroid Build Coastguard Worker			got := make([]byte, wantLen)
250*f4ee7fbaSAndroid Build Coastguard Worker			if n, err := reader.Read(got); err != nil || n != wantLen || !bytes.Equal(got, segment) {
251*f4ee7fbaSAndroid Build Coastguard Worker				t.Fatalf("read[%d]=%q,%v,%v, want %q,%v,%v", k, got, n, err, segment, wantLen, nil)
252*f4ee7fbaSAndroid Build Coastguard Worker			}
253*f4ee7fbaSAndroid Build Coastguard Worker		})
254*f4ee7fbaSAndroid Build Coastguard Worker	}
255*f4ee7fbaSAndroid Build Coastguard Worker}
256*f4ee7fbaSAndroid Build Coastguard Worker
257*f4ee7fbaSAndroid Build Coastguard Workerfunc TestReader(t *testing.T) {
258*f4ee7fbaSAndroid Build Coastguard Worker	content := bytes.Repeat([]byte("hello world!"), 10000)
259*f4ee7fbaSAndroid Build Coastguard Worker	encoded, _ := Encode(content, WriterOptions{Quality: 5})
260*f4ee7fbaSAndroid Build Coastguard Worker	r := NewReader(bytes.NewReader(encoded))
261*f4ee7fbaSAndroid Build Coastguard Worker	var decodedOutput bytes.Buffer
262*f4ee7fbaSAndroid Build Coastguard Worker	n, err := io.Copy(&decodedOutput, r)
263*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
264*f4ee7fbaSAndroid Build Coastguard Worker		t.Fatalf("Copy(): n=%v, err=%v", n, err)
265*f4ee7fbaSAndroid Build Coastguard Worker	}
266*f4ee7fbaSAndroid Build Coastguard Worker	if err := r.Close(); err != nil {
267*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Close(): %v", err)
268*f4ee7fbaSAndroid Build Coastguard Worker	}
269*f4ee7fbaSAndroid Build Coastguard Worker	if got := decodedOutput.Bytes(); !bytes.Equal(got, content) {
270*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf(""+
271*f4ee7fbaSAndroid Build Coastguard Worker			"Reader output:\n"+
272*f4ee7fbaSAndroid Build Coastguard Worker			"%q\n"+
273*f4ee7fbaSAndroid Build Coastguard Worker			"want:\n"+
274*f4ee7fbaSAndroid Build Coastguard Worker			"<%d bytes>",
275*f4ee7fbaSAndroid Build Coastguard Worker			got, len(content))
276*f4ee7fbaSAndroid Build Coastguard Worker	}
277*f4ee7fbaSAndroid Build Coastguard Worker	buf := make([]byte, 4)
278*f4ee7fbaSAndroid Build Coastguard Worker	if _, err := r.Read(buf); err != errReaderClosed {
279*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Read-after-Close returned %v, expected %v", err, errReaderClosed)
280*f4ee7fbaSAndroid Build Coastguard Worker	}
281*f4ee7fbaSAndroid Build Coastguard Worker}
282*f4ee7fbaSAndroid Build Coastguard Worker
283*f4ee7fbaSAndroid Build Coastguard Workerfunc TestDecode(t *testing.T) {
284*f4ee7fbaSAndroid Build Coastguard Worker	content := bytes.Repeat([]byte("hello world!"), 10000)
285*f4ee7fbaSAndroid Build Coastguard Worker	encoded, _ := Encode(content, WriterOptions{Quality: 5})
286*f4ee7fbaSAndroid Build Coastguard Worker	decoded, err := Decode(encoded)
287*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
288*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Decode: %v", err)
289*f4ee7fbaSAndroid Build Coastguard Worker	}
290*f4ee7fbaSAndroid Build Coastguard Worker	if !bytes.Equal(decoded, content) {
291*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf(""+
292*f4ee7fbaSAndroid Build Coastguard Worker			"Decode content:\n"+
293*f4ee7fbaSAndroid Build Coastguard Worker			"%q\n"+
294*f4ee7fbaSAndroid Build Coastguard Worker			"want:\n"+
295*f4ee7fbaSAndroid Build Coastguard Worker			"<%d bytes>",
296*f4ee7fbaSAndroid Build Coastguard Worker			decoded, len(content))
297*f4ee7fbaSAndroid Build Coastguard Worker	}
298*f4ee7fbaSAndroid Build Coastguard Worker}
299*f4ee7fbaSAndroid Build Coastguard Worker
300*f4ee7fbaSAndroid Build Coastguard Workerfunc TestDecodeFuzz(t *testing.T) {
301*f4ee7fbaSAndroid Build Coastguard Worker	// Test that the decoder terminates with corrupted input.
302*f4ee7fbaSAndroid Build Coastguard Worker	content := bytes.Repeat([]byte("hello world!"), 100)
303*f4ee7fbaSAndroid Build Coastguard Worker	src := rand.NewSource(0)
304*f4ee7fbaSAndroid Build Coastguard Worker	encoded, err := Encode(content, WriterOptions{Quality: 5})
305*f4ee7fbaSAndroid Build Coastguard Worker	if err != nil {
306*f4ee7fbaSAndroid Build Coastguard Worker		t.Fatalf("Encode(<%d bytes>, _) = _, %s", len(content), err)
307*f4ee7fbaSAndroid Build Coastguard Worker	}
308*f4ee7fbaSAndroid Build Coastguard Worker	if len(encoded) == 0 {
309*f4ee7fbaSAndroid Build Coastguard Worker		t.Fatalf("Encode(<%d bytes>, _) produced empty output", len(content))
310*f4ee7fbaSAndroid Build Coastguard Worker	}
311*f4ee7fbaSAndroid Build Coastguard Worker	for i := 0; i < 100; i++ {
312*f4ee7fbaSAndroid Build Coastguard Worker		enc := append([]byte{}, encoded...)
313*f4ee7fbaSAndroid Build Coastguard Worker		for j := 0; j < 5; j++ {
314*f4ee7fbaSAndroid Build Coastguard Worker			enc[int(src.Int63())%len(enc)] = byte(src.Int63() % 256)
315*f4ee7fbaSAndroid Build Coastguard Worker		}
316*f4ee7fbaSAndroid Build Coastguard Worker		Decode(enc)
317*f4ee7fbaSAndroid Build Coastguard Worker	}
318*f4ee7fbaSAndroid Build Coastguard Worker}
319*f4ee7fbaSAndroid Build Coastguard Worker
320*f4ee7fbaSAndroid Build Coastguard Workerfunc TestDecodeTrailingData(t *testing.T) {
321*f4ee7fbaSAndroid Build Coastguard Worker	content := bytes.Repeat([]byte("hello world!"), 100)
322*f4ee7fbaSAndroid Build Coastguard Worker	encoded, _ := Encode(content, WriterOptions{Quality: 5})
323*f4ee7fbaSAndroid Build Coastguard Worker	_, err := Decode(append(encoded, 0))
324*f4ee7fbaSAndroid Build Coastguard Worker	if err == nil {
325*f4ee7fbaSAndroid Build Coastguard Worker		t.Errorf("Expected 'excessive input' error")
326*f4ee7fbaSAndroid Build Coastguard Worker	}
327*f4ee7fbaSAndroid Build Coastguard Worker}
328*f4ee7fbaSAndroid Build Coastguard Worker
329*f4ee7fbaSAndroid Build Coastguard Workerfunc TestEncodeDecode(t *testing.T) {
330*f4ee7fbaSAndroid Build Coastguard Worker	for _, test := range []struct {
331*f4ee7fbaSAndroid Build Coastguard Worker		data    []byte
332*f4ee7fbaSAndroid Build Coastguard Worker		repeats int
333*f4ee7fbaSAndroid Build Coastguard Worker	}{
334*f4ee7fbaSAndroid Build Coastguard Worker		{nil, 0},
335*f4ee7fbaSAndroid Build Coastguard Worker		{[]byte("A"), 1},
336*f4ee7fbaSAndroid Build Coastguard Worker		{[]byte("<html><body><H1>Hello world</H1></body></html>"), 10},
337*f4ee7fbaSAndroid Build Coastguard Worker		{[]byte("<html><body><H1>Hello world</H1></body></html>"), 1000},
338*f4ee7fbaSAndroid Build Coastguard Worker	} {
339*f4ee7fbaSAndroid Build Coastguard Worker		t.Logf("case %q x %d", test.data, test.repeats)
340*f4ee7fbaSAndroid Build Coastguard Worker		input := bytes.Repeat(test.data, test.repeats)
341*f4ee7fbaSAndroid Build Coastguard Worker		encoded, err := Encode(input, WriterOptions{Quality: 5})
342*f4ee7fbaSAndroid Build Coastguard Worker		if err != nil {
343*f4ee7fbaSAndroid Build Coastguard Worker			t.Errorf("Encode: %v", err)
344*f4ee7fbaSAndroid Build Coastguard Worker		}
345*f4ee7fbaSAndroid Build Coastguard Worker		// Inputs are compressible, but may be too small to compress.
346*f4ee7fbaSAndroid Build Coastguard Worker		if maxSize := len(input)/2 + 20; len(encoded) >= maxSize {
347*f4ee7fbaSAndroid Build Coastguard Worker			t.Errorf(""+
348*f4ee7fbaSAndroid Build Coastguard Worker				"Encode returned %d bytes, want <%d\n"+
349*f4ee7fbaSAndroid Build Coastguard Worker				"Encoded=%q",
350*f4ee7fbaSAndroid Build Coastguard Worker				len(encoded), maxSize, encoded)
351*f4ee7fbaSAndroid Build Coastguard Worker		}
352*f4ee7fbaSAndroid Build Coastguard Worker		decoded, err := Decode(encoded)
353*f4ee7fbaSAndroid Build Coastguard Worker		if err != nil {
354*f4ee7fbaSAndroid Build Coastguard Worker			t.Errorf("Decode: %v", err)
355*f4ee7fbaSAndroid Build Coastguard Worker		}
356*f4ee7fbaSAndroid Build Coastguard Worker		if !bytes.Equal(decoded, input) {
357*f4ee7fbaSAndroid Build Coastguard Worker			var want string
358*f4ee7fbaSAndroid Build Coastguard Worker			if len(input) > 320 {
359*f4ee7fbaSAndroid Build Coastguard Worker				want = fmt.Sprintf("<%d bytes>", len(input))
360*f4ee7fbaSAndroid Build Coastguard Worker			} else {
361*f4ee7fbaSAndroid Build Coastguard Worker				want = fmt.Sprintf("%q", input)
362*f4ee7fbaSAndroid Build Coastguard Worker			}
363*f4ee7fbaSAndroid Build Coastguard Worker			t.Errorf(""+
364*f4ee7fbaSAndroid Build Coastguard Worker				"Decode content:\n"+
365*f4ee7fbaSAndroid Build Coastguard Worker				"%q\n"+
366*f4ee7fbaSAndroid Build Coastguard Worker				"want:\n"+
367*f4ee7fbaSAndroid Build Coastguard Worker				"%s",
368*f4ee7fbaSAndroid Build Coastguard Worker				decoded, want)
369*f4ee7fbaSAndroid Build Coastguard Worker		}
370*f4ee7fbaSAndroid Build Coastguard Worker	}
371*f4ee7fbaSAndroid Build Coastguard Worker}
372