github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/compress/lzw/writer_test.go (about) 1 // Copyright 2011 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 lzw 6 7 import ( 8 "bytes" 9 "fmt" 10 "internal/testenv" 11 "io" 12 "math" 13 "os" 14 "runtime" 15 "testing" 16 ) 17 18 var filenames = []string{ 19 "../testdata/gettysburg.txt", 20 "../testdata/e.txt", 21 "../testdata/pi.txt", 22 } 23 24 // testFile tests that compressing and then decompressing the given file with 25 // the given options yields equivalent bytes to the original file. 26 func testFile(t *testing.T, fn string, order Order, litWidth int) { 27 // Read the file, as golden output. 28 golden, err := os.Open(fn) 29 if err != nil { 30 t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err) 31 return 32 } 33 defer golden.Close() 34 35 // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end. 36 raw, err := os.Open(fn) 37 if err != nil { 38 t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err) 39 return 40 } 41 42 piper, pipew := io.Pipe() 43 defer piper.Close() 44 go func() { 45 defer raw.Close() 46 defer pipew.Close() 47 lzww := NewWriter(pipew, order, litWidth) 48 defer lzww.Close() 49 var b [4096]byte 50 for { 51 n, err0 := raw.Read(b[:]) 52 if err0 != nil && err0 != io.EOF { 53 t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err0) 54 return 55 } 56 _, err1 := lzww.Write(b[:n]) 57 if err1 != nil { 58 t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1) 59 return 60 } 61 if err0 == io.EOF { 62 break 63 } 64 } 65 }() 66 lzwr := NewReader(piper, order, litWidth) 67 defer lzwr.Close() 68 69 // Compare the two. 70 b0, err0 := io.ReadAll(golden) 71 b1, err1 := io.ReadAll(lzwr) 72 if err0 != nil { 73 t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err0) 74 return 75 } 76 if err1 != nil { 77 t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1) 78 return 79 } 80 if len(b1) != len(b0) { 81 t.Errorf("%s (order=%d litWidth=%d): length mismatch %d != %d", fn, order, litWidth, len(b1), len(b0)) 82 return 83 } 84 for i := 0; i < len(b0); i++ { 85 if b1[i] != b0[i] { 86 t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x != 0x%02x\n", fn, order, litWidth, i, b1[i], b0[i]) 87 return 88 } 89 } 90 } 91 92 func TestWriter(t *testing.T) { 93 for _, filename := range filenames { 94 for _, order := range [...]Order{LSB, MSB} { 95 // The test data "2.71828 etcetera" is ASCII text requiring at least 6 bits. 96 for litWidth := 6; litWidth <= 8; litWidth++ { 97 if filename == "../testdata/gettysburg.txt" && litWidth == 6 { 98 continue 99 } 100 testFile(t, filename, order, litWidth) 101 } 102 } 103 if testing.Short() && testenv.Builder() == "" { 104 break 105 } 106 } 107 } 108 109 func TestWriterReset(t *testing.T) { 110 for _, order := range [...]Order{LSB, MSB} { 111 t.Run(fmt.Sprintf("Order %d", order), func(t *testing.T) { 112 for litWidth := 6; litWidth <= 8; litWidth++ { 113 t.Run(fmt.Sprintf("LitWidth %d", litWidth), func(t *testing.T) { 114 var data []byte 115 if litWidth == 6 { 116 data = []byte{1, 2, 3} 117 } else { 118 data = []byte(`lorem ipsum dolor sit amet`) 119 } 120 var buf bytes.Buffer 121 w := NewWriter(&buf, order, litWidth) 122 if _, err := w.Write(data); err != nil { 123 t.Errorf("write: %v: %v", string(data), err) 124 } 125 126 if err := w.Close(); err != nil { 127 t.Errorf("close: %v", err) 128 } 129 130 b1 := buf.Bytes() 131 buf.Reset() 132 133 w.(*Writer).Reset(&buf, order, litWidth) 134 135 if _, err := w.Write(data); err != nil { 136 t.Errorf("write: %v: %v", string(data), err) 137 } 138 139 if err := w.Close(); err != nil { 140 t.Errorf("close: %v", err) 141 } 142 b2 := buf.Bytes() 143 144 if !bytes.Equal(b1, b2) { 145 t.Errorf("bytes written were not same") 146 } 147 }) 148 } 149 }) 150 } 151 } 152 153 func TestWriterReturnValues(t *testing.T) { 154 w := NewWriter(io.Discard, LSB, 8) 155 n, err := w.Write([]byte("asdf")) 156 if n != 4 || err != nil { 157 t.Errorf("got %d, %v, want 4, nil", n, err) 158 } 159 } 160 161 func TestSmallLitWidth(t *testing.T) { 162 w := NewWriter(io.Discard, LSB, 2) 163 if _, err := w.Write([]byte{0x03}); err != nil { 164 t.Fatalf("write a byte < 1<<2: %v", err) 165 } 166 if _, err := w.Write([]byte{0x04}); err == nil { 167 t.Fatal("write a byte >= 1<<2: got nil error, want non-nil") 168 } 169 } 170 171 func TestStartsWithClearCode(t *testing.T) { 172 // A literal width of 7 bits means that the code width starts at 8 bits, 173 // which makes it easier to visually inspect the output (provided that the 174 // output is short so codes don't get longer). Each byte is a code: 175 // - ASCII bytes are literal codes, 176 // - 0x80 is the clear code, 177 // - 0x81 is the end code. 178 // - 0x82 and above are copy codes (unused in this test case). 179 for _, empty := range []bool{false, true} { 180 var buf bytes.Buffer 181 w := NewWriter(&buf, LSB, 7) 182 if !empty { 183 w.Write([]byte("Hi")) 184 } 185 w.Close() 186 got := buf.String() 187 188 want := "\x80\x81" 189 if !empty { 190 want = "\x80Hi\x81" 191 } 192 193 if got != want { 194 t.Errorf("empty=%t: got %q, want %q", empty, got, want) 195 } 196 } 197 } 198 199 func BenchmarkEncoder(b *testing.B) { 200 buf, err := os.ReadFile("../testdata/e.txt") 201 if err != nil { 202 b.Fatal(err) 203 } 204 if len(buf) == 0 { 205 b.Fatalf("test file has no data") 206 } 207 208 for e := 4; e <= 6; e++ { 209 n := int(math.Pow10(e)) 210 buf0 := buf 211 buf1 := make([]byte, n) 212 for i := 0; i < n; i += len(buf0) { 213 if len(buf0) > n-i { 214 buf0 = buf0[:n-i] 215 } 216 copy(buf1[i:], buf0) 217 } 218 buf0 = nil 219 runtime.GC() 220 b.Run(fmt.Sprint("1e", e), func(b *testing.B) { 221 b.SetBytes(int64(n)) 222 for i := 0; i < b.N; i++ { 223 w := NewWriter(io.Discard, LSB, 8) 224 w.Write(buf1) 225 w.Close() 226 } 227 }) 228 b.Run(fmt.Sprint("1e-Reuse", e), func(b *testing.B) { 229 b.SetBytes(int64(n)) 230 w := NewWriter(io.Discard, LSB, 8) 231 for i := 0; i < b.N; i++ { 232 w.Write(buf1) 233 w.Close() 234 w.(*Writer).Reset(io.Discard, LSB, 8) 235 } 236 }) 237 } 238 }