tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/image/internal/compress/flate/writer_test.go (about) 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 }