github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/internal/zstd/zstd_test.go (about) 1 // Copyright 2023 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 zstd 6 7 import ( 8 "bytes" 9 "fmt" 10 "internal/race" 11 "internal/testenv" 12 "io" 13 "os" 14 "os/exec" 15 "strings" 16 "sync" 17 "testing" 18 ) 19 20 // tests holds some simple test cases, including some found by fuzzing. 21 var tests = []struct { 22 name, uncompressed, compressed string 23 }{ 24 { 25 "hello", 26 "hello, world\n", 27 "\x28\xb5\x2f\xfd\x24\x0d\x69\x00\x00\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x0a\x4c\x1f\xf9\xf1", 28 }, 29 { 30 // a small compressed .debug_ranges section. 31 "ranges", 32 "\xcc\x11\x00\x00\x00\x00\x00\x00\xd5\x13\x00\x00\x00\x00\x00\x00" + 33 "\x1c\x14\x00\x00\x00\x00\x00\x00\x72\x14\x00\x00\x00\x00\x00\x00" + 34 "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00" + 35 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 36 "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00" + 37 "\x0c\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00" + 38 "\x29\x14\x00\x00\x00\x00\x00\x00\x4e\x14\x00\x00\x00\x00\x00\x00" + 39 "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00" + 40 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 41 "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00" + 42 "\x67\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00" + 43 "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00" + 44 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 45 "\x5f\x0b\x00\x00\x00\x00\x00\x00\x6c\x0b\x00\x00\x00\x00\x00\x00" + 46 "\x7d\x0b\x00\x00\x00\x00\x00\x00\x7e\x0c\x00\x00\x00\x00\x00\x00" + 47 "\x38\x0f\x00\x00\x00\x00\x00\x00\x5c\x0f\x00\x00\x00\x00\x00\x00" + 48 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 49 "\x83\x0c\x00\x00\x00\x00\x00\x00\xfa\x0c\x00\x00\x00\x00\x00\x00" + 50 "\xfd\x0d\x00\x00\x00\x00\x00\x00\xef\x0e\x00\x00\x00\x00\x00\x00" + 51 "\x14\x0f\x00\x00\x00\x00\x00\x00\x38\x0f\x00\x00\x00\x00\x00\x00" + 52 "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00" + 53 "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00" + 54 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 55 "\xfd\x0d\x00\x00\x00\x00\x00\x00\xd8\x0e\x00\x00\x00\x00\x00\x00" + 56 "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00" + 57 "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00" + 58 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 59 "\xfa\x0c\x00\x00\x00\x00\x00\x00\xea\x0d\x00\x00\x00\x00\x00\x00" + 60 "\xef\x0e\x00\x00\x00\x00\x00\x00\x14\x0f\x00\x00\x00\x00\x00\x00" + 61 "\x5c\x0f\x00\x00\x00\x00\x00\x00\x9f\x0f\x00\x00\x00\x00\x00\x00" + 62 "\xac\x0f\x00\x00\x00\x00\x00\x00\xdb\x0f\x00\x00\x00\x00\x00\x00" + 63 "\xff\x0f\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00" + 64 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 65 "\x60\x11\x00\x00\x00\x00\x00\x00\xd1\x16\x00\x00\x00\x00\x00\x00" + 66 "\x40\x0b\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00" + 67 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 68 "\x7a\x00\x00\x00\x00\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x00\x00" + 69 "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00" + 70 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 71 "\x7a\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00" + 72 "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00" + 73 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 74 75 "\x28\xb5\x2f\xfd\x64\xa0\x01\x2d\x05\x00\xc4\x04\xcc\x11\x00\xd5" + 76 "\x13\x00\x1c\x14\x00\x72\x9d\xd5\xfb\x12\x00\x09\x0c\x13\xcb\x13" + 77 "\x29\x4e\x67\x5f\x0b\x6c\x0b\x7d\x0b\x7e\x0c\x38\x0f\x5c\x0f\x83" + 78 "\x0c\xfa\x0c\xfd\x0d\xef\x0e\x14\x38\x9f\x0f\xac\x0f\xdb\x0f\xff" + 79 "\x0f\xd8\x9f\xac\xdb\xff\xea\x5c\x2c\x10\x60\xd1\x16\x40\x0b\x7a" + 80 "\x00\xb6\x00\x9f\x01\xa7\x01\xa9\x36\x20\xa0\x83\x14\x34\x63\x4a" + 81 "\x21\x70\x8c\x07\x46\x03\x4e\x10\x62\x3c\x06\x4e\xc8\x8c\xb0\x32" + 82 "\x2a\x59\xad\xb2\xf1\x02\x82\x7c\x33\xcb\x92\x6f\x32\x4f\x9b\xb0" + 83 "\xa2\x30\xf0\xc0\x06\x1e\x98\x99\x2c\x06\x1e\xd8\xc0\x03\x56\xd8" + 84 "\xc0\x03\x0f\x6c\xe0\x01\xf1\xf0\xee\x9a\xc6\xc8\x97\x99\xd1\x6c" + 85 "\xb4\x21\x45\x3b\x10\xe4\x7b\x99\x4d\x8a\x36\x64\x5c\x77\x08\x02" + 86 "\xcb\xe0\xce", 87 }, 88 { 89 "fuzz1", 90 "0\x00\x00\x00\x00\x000\x00\x00\x00\x00\x001\x00\x00\x00\x00\x000000", 91 "(\xb5/\xfd\x04X\x8d\x00\x00P0\x000\x001\x000000\x03T\x02\x00\x01\x01m\xf9\xb7G", 92 }, 93 } 94 95 func TestSamples(t *testing.T) { 96 for _, test := range tests { 97 test := test 98 t.Run(test.name, func(t *testing.T) { 99 r := NewReader(strings.NewReader(test.compressed)) 100 got, err := io.ReadAll(r) 101 if err != nil { 102 t.Fatal(err) 103 } 104 gotstr := string(got) 105 if gotstr != test.uncompressed { 106 t.Errorf("got %q want %q", gotstr, test.uncompressed) 107 } 108 }) 109 } 110 } 111 112 var ( 113 bigDataOnce sync.Once 114 bigDataBytes []byte 115 bigDataErr error 116 ) 117 118 // bigData returns the contents of our large test file. 119 func bigData(t testing.TB) []byte { 120 bigDataOnce.Do(func() { 121 bigDataBytes, bigDataErr = os.ReadFile("../../testdata/Isaac.Newton-Opticks.txt") 122 }) 123 if bigDataErr != nil { 124 t.Fatal(bigDataErr) 125 } 126 return bigDataBytes 127 } 128 129 var ( 130 zstdBigOnce sync.Once 131 zstdBigBytes []byte 132 zstdBigSkip bool 133 zstdBigErr error 134 ) 135 136 // zstdBigData returns the compressed contents of our large test file. 137 // This will only run on Unix systems with zstd installed. 138 // That's OK as the package is GOOS-independent. 139 func zstdBigData(t testing.TB) []byte { 140 input := bigData(t) 141 142 zstdBigOnce.Do(func() { 143 if _, err := os.Stat("/usr/bin/zstd"); err != nil { 144 zstdBigSkip = true 145 return 146 } 147 148 cmd := exec.Command("/usr/bin/zstd", "-z") 149 cmd.Stdin = bytes.NewReader(input) 150 var compressed bytes.Buffer 151 cmd.Stdout = &compressed 152 cmd.Stderr = os.Stderr 153 if err := cmd.Run(); err != nil { 154 zstdBigErr = fmt.Errorf("running zstd failed: %v", err) 155 return 156 } 157 158 zstdBigBytes = compressed.Bytes() 159 }) 160 if zstdBigSkip { 161 t.Skip("skipping because /usr/bin/zstd does not exist") 162 } 163 if zstdBigErr != nil { 164 t.Fatal(zstdBigErr) 165 } 166 return zstdBigBytes 167 } 168 169 // Test decompressing a large file. We don't have a compressor, 170 // so this test only runs on systems with zstd installed. 171 func TestLarge(t *testing.T) { 172 if testing.Short() { 173 t.Skip("skipping expensive test in short mode") 174 } 175 176 data := bigData(t) 177 compressed := zstdBigData(t) 178 179 t.Logf("/usr/bin/zstd compressed %d bytes to %d", len(data), len(compressed)) 180 181 r := NewReader(bytes.NewReader(compressed)) 182 got, err := io.ReadAll(r) 183 if err != nil { 184 t.Fatal(err) 185 } 186 187 if !bytes.Equal(got, data) { 188 showDiffs(t, got, data) 189 } 190 } 191 192 // showDiffs reports the first few differences in two []byte. 193 func showDiffs(t *testing.T, got, want []byte) { 194 t.Error("data mismatch") 195 if len(got) != len(want) { 196 t.Errorf("got data length %d, want %d", len(got), len(want)) 197 } 198 diffs := 0 199 for i, b := range got { 200 if i >= len(want) { 201 break 202 } 203 if b != want[i] { 204 diffs++ 205 if diffs > 20 { 206 break 207 } 208 t.Logf("%d: %#x != %#x", i, b, want[i]) 209 } 210 } 211 } 212 213 func TestAlloc(t *testing.T) { 214 testenv.SkipIfOptimizationOff(t) 215 if race.Enabled { 216 t.Skip("skipping allocation test under race detector") 217 } 218 219 compressed := zstdBigData(t) 220 input := bytes.NewReader(compressed) 221 r := NewReader(input) 222 c := testing.AllocsPerRun(10, func() { 223 input.Reset(compressed) 224 r.Reset(input) 225 io.Copy(io.Discard, r) 226 }) 227 if c != 0 { 228 t.Errorf("got %v allocs, want 0", c) 229 } 230 } 231 232 func BenchmarkLarge(b *testing.B) { 233 b.StopTimer() 234 b.ReportAllocs() 235 236 compressed := zstdBigData(b) 237 238 b.SetBytes(int64(len(compressed))) 239 240 input := bytes.NewReader(compressed) 241 r := NewReader(input) 242 243 b.StartTimer() 244 for i := 0; i < b.N; i++ { 245 input.Reset(compressed) 246 r.Reset(input) 247 io.Copy(io.Discard, r) 248 } 249 }