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