summaryrefslogtreecommitdiffstats
path: root/src/internal/zstd/zstd_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/zstd/zstd_test.go')
-rw-r--r--src/internal/zstd/zstd_test.go249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/internal/zstd/zstd_test.go b/src/internal/zstd/zstd_test.go
new file mode 100644
index 0000000..bc75e0f
--- /dev/null
+++ b/src/internal/zstd/zstd_test.go
@@ -0,0 +1,249 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zstd
+
+import (
+ "bytes"
+ "fmt"
+ "internal/race"
+ "internal/testenv"
+ "io"
+ "os"
+ "os/exec"
+ "strings"
+ "sync"
+ "testing"
+)
+
+// tests holds some simple test cases, including some found by fuzzing.
+var tests = []struct {
+ name, uncompressed, compressed string
+}{
+ {
+ "hello",
+ "hello, world\n",
+ "\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",
+ },
+ {
+ // a small compressed .debug_ranges section.
+ "ranges",
+ "\xcc\x11\x00\x00\x00\x00\x00\x00\xd5\x13\x00\x00\x00\x00\x00\x00" +
+ "\x1c\x14\x00\x00\x00\x00\x00\x00\x72\x14\x00\x00\x00\x00\x00\x00" +
+ "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00" +
+ "\x0c\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00" +
+ "\x29\x14\x00\x00\x00\x00\x00\x00\x4e\x14\x00\x00\x00\x00\x00\x00" +
+ "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00" +
+ "\x67\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00" +
+ "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\x5f\x0b\x00\x00\x00\x00\x00\x00\x6c\x0b\x00\x00\x00\x00\x00\x00" +
+ "\x7d\x0b\x00\x00\x00\x00\x00\x00\x7e\x0c\x00\x00\x00\x00\x00\x00" +
+ "\x38\x0f\x00\x00\x00\x00\x00\x00\x5c\x0f\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\x83\x0c\x00\x00\x00\x00\x00\x00\xfa\x0c\x00\x00\x00\x00\x00\x00" +
+ "\xfd\x0d\x00\x00\x00\x00\x00\x00\xef\x0e\x00\x00\x00\x00\x00\x00" +
+ "\x14\x0f\x00\x00\x00\x00\x00\x00\x38\x0f\x00\x00\x00\x00\x00\x00" +
+ "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00" +
+ "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\xfd\x0d\x00\x00\x00\x00\x00\x00\xd8\x0e\x00\x00\x00\x00\x00\x00" +
+ "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00" +
+ "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\xfa\x0c\x00\x00\x00\x00\x00\x00\xea\x0d\x00\x00\x00\x00\x00\x00" +
+ "\xef\x0e\x00\x00\x00\x00\x00\x00\x14\x0f\x00\x00\x00\x00\x00\x00" +
+ "\x5c\x0f\x00\x00\x00\x00\x00\x00\x9f\x0f\x00\x00\x00\x00\x00\x00" +
+ "\xac\x0f\x00\x00\x00\x00\x00\x00\xdb\x0f\x00\x00\x00\x00\x00\x00" +
+ "\xff\x0f\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\x60\x11\x00\x00\x00\x00\x00\x00\xd1\x16\x00\x00\x00\x00\x00\x00" +
+ "\x40\x0b\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\x7a\x00\x00\x00\x00\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x00\x00" +
+ "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
+ "\x7a\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00" +
+ "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00" +
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+
+ "\x28\xb5\x2f\xfd\x64\xa0\x01\x2d\x05\x00\xc4\x04\xcc\x11\x00\xd5" +
+ "\x13\x00\x1c\x14\x00\x72\x9d\xd5\xfb\x12\x00\x09\x0c\x13\xcb\x13" +
+ "\x29\x4e\x67\x5f\x0b\x6c\x0b\x7d\x0b\x7e\x0c\x38\x0f\x5c\x0f\x83" +
+ "\x0c\xfa\x0c\xfd\x0d\xef\x0e\x14\x38\x9f\x0f\xac\x0f\xdb\x0f\xff" +
+ "\x0f\xd8\x9f\xac\xdb\xff\xea\x5c\x2c\x10\x60\xd1\x16\x40\x0b\x7a" +
+ "\x00\xb6\x00\x9f\x01\xa7\x01\xa9\x36\x20\xa0\x83\x14\x34\x63\x4a" +
+ "\x21\x70\x8c\x07\x46\x03\x4e\x10\x62\x3c\x06\x4e\xc8\x8c\xb0\x32" +
+ "\x2a\x59\xad\xb2\xf1\x02\x82\x7c\x33\xcb\x92\x6f\x32\x4f\x9b\xb0" +
+ "\xa2\x30\xf0\xc0\x06\x1e\x98\x99\x2c\x06\x1e\xd8\xc0\x03\x56\xd8" +
+ "\xc0\x03\x0f\x6c\xe0\x01\xf1\xf0\xee\x9a\xc6\xc8\x97\x99\xd1\x6c" +
+ "\xb4\x21\x45\x3b\x10\xe4\x7b\x99\x4d\x8a\x36\x64\x5c\x77\x08\x02" +
+ "\xcb\xe0\xce",
+ },
+ {
+ "fuzz1",
+ "0\x00\x00\x00\x00\x000\x00\x00\x00\x00\x001\x00\x00\x00\x00\x000000",
+ "(\xb5/\xfd\x04X\x8d\x00\x00P0\x000\x001\x000000\x03T\x02\x00\x01\x01m\xf9\xb7G",
+ },
+}
+
+func TestSamples(t *testing.T) {
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ r := NewReader(strings.NewReader(test.compressed))
+ got, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+ gotstr := string(got)
+ if gotstr != test.uncompressed {
+ t.Errorf("got %q want %q", gotstr, test.uncompressed)
+ }
+ })
+ }
+}
+
+var (
+ bigDataOnce sync.Once
+ bigDataBytes []byte
+ bigDataErr error
+)
+
+// bigData returns the contents of our large test file.
+func bigData(t testing.TB) []byte {
+ bigDataOnce.Do(func() {
+ bigDataBytes, bigDataErr = os.ReadFile("../../testdata/Isaac.Newton-Opticks.txt")
+ })
+ if bigDataErr != nil {
+ t.Fatal(bigDataErr)
+ }
+ return bigDataBytes
+}
+
+var (
+ zstdBigOnce sync.Once
+ zstdBigBytes []byte
+ zstdBigSkip bool
+ zstdBigErr error
+)
+
+// zstdBigData returns the compressed contents of our large test file.
+// This will only run on Unix systems with zstd installed.
+// That's OK as the package is GOOS-independent.
+func zstdBigData(t testing.TB) []byte {
+ input := bigData(t)
+
+ zstdBigOnce.Do(func() {
+ if _, err := os.Stat("/usr/bin/zstd"); err != nil {
+ zstdBigSkip = true
+ return
+ }
+
+ cmd := exec.Command("/usr/bin/zstd", "-z")
+ cmd.Stdin = bytes.NewReader(input)
+ var compressed bytes.Buffer
+ cmd.Stdout = &compressed
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ zstdBigErr = fmt.Errorf("running zstd failed: %v", err)
+ return
+ }
+
+ zstdBigBytes = compressed.Bytes()
+ })
+ if zstdBigSkip {
+ t.Skip("skipping because /usr/bin/zstd does not exist")
+ }
+ if zstdBigErr != nil {
+ t.Fatal(zstdBigErr)
+ }
+ return zstdBigBytes
+}
+
+// Test decompressing a large file. We don't have a compressor,
+// so this test only runs on systems with zstd installed.
+func TestLarge(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping expensive test in short mode")
+ }
+
+ data := bigData(t)
+ compressed := zstdBigData(t)
+
+ t.Logf("/usr/bin/zstd compressed %d bytes to %d", len(data), len(compressed))
+
+ r := NewReader(bytes.NewReader(compressed))
+ got, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(got, data) {
+ showDiffs(t, got, data)
+ }
+}
+
+// showDiffs reports the first few differences in two []byte.
+func showDiffs(t *testing.T, got, want []byte) {
+ t.Error("data mismatch")
+ if len(got) != len(want) {
+ t.Errorf("got data length %d, want %d", len(got), len(want))
+ }
+ diffs := 0
+ for i, b := range got {
+ if i >= len(want) {
+ break
+ }
+ if b != want[i] {
+ diffs++
+ if diffs > 20 {
+ break
+ }
+ t.Logf("%d: %#x != %#x", i, b, want[i])
+ }
+ }
+}
+
+func TestAlloc(t *testing.T) {
+ testenv.SkipIfOptimizationOff(t)
+ if race.Enabled {
+ t.Skip("skipping allocation test under race detector")
+ }
+
+ compressed := zstdBigData(t)
+ input := bytes.NewReader(compressed)
+ r := NewReader(input)
+ c := testing.AllocsPerRun(10, func() {
+ input.Reset(compressed)
+ r.Reset(input)
+ io.Copy(io.Discard, r)
+ })
+ if c != 0 {
+ t.Errorf("got %v allocs, want 0", c)
+ }
+}
+
+func BenchmarkLarge(b *testing.B) {
+ b.StopTimer()
+ b.ReportAllocs()
+
+ compressed := zstdBigData(b)
+
+ b.SetBytes(int64(len(compressed)))
+
+ input := bytes.NewReader(compressed)
+ r := NewReader(input)
+
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ input.Reset(compressed)
+ r.Reset(input)
+ io.Copy(io.Discard, r)
+ }
+}