483 lines
11 KiB
Go
483 lines
11 KiB
Go
package huff0
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
)
|
|
|
|
func TestDecompress1X(t *testing.T) {
|
|
for _, test := range testfiles {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
var s = &Scratch{}
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
b, re, err := Compress1X(buf0, s)
|
|
if err != test.err1X {
|
|
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
|
|
}
|
|
if err != nil {
|
|
t.Log(test.name, err.Error())
|
|
return
|
|
}
|
|
if b == nil {
|
|
t.Error("got no output")
|
|
return
|
|
}
|
|
if len(s.OutTable) == 0 {
|
|
t.Error("got no table definition")
|
|
}
|
|
if re {
|
|
t.Error("claimed to have re-used.")
|
|
}
|
|
if len(s.OutData) == 0 {
|
|
t.Error("got no data output")
|
|
}
|
|
|
|
wantRemain := len(s.OutData)
|
|
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
|
|
|
s.Out = nil
|
|
var remain []byte
|
|
s, remain, err = ReadTable(b, s)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
var buf bytes.Buffer
|
|
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
|
t.Error(buf.String())
|
|
}
|
|
if len(remain) != wantRemain {
|
|
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
|
}
|
|
t.Logf("remain: %d bytes, ok", len(remain))
|
|
dc, err := s.Decompress1X(remain)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if len(buf0) != len(dc) {
|
|
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
|
if len(buf0) > len(dc) {
|
|
buf0 = buf0[:len(dc)]
|
|
} else {
|
|
dc = dc[:len(buf0)]
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(dc) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
|
} else {
|
|
t.Log(string(dc))
|
|
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(buf0) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
} else {
|
|
t.Log(string(dc))
|
|
}
|
|
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
|
t.Errorf(test.name + ": decompressed, got delta")
|
|
}
|
|
if !t.Failed() {
|
|
t.Log("... roundtrip ok!")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecompress4X(t *testing.T) {
|
|
for _, test := range testfiles {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
var s = &Scratch{}
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
b, re, err := Compress4X(buf0, s)
|
|
if err != test.err4X {
|
|
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
|
|
}
|
|
if err != nil {
|
|
t.Log(test.name, err.Error())
|
|
return
|
|
}
|
|
if b == nil {
|
|
t.Error("got no output")
|
|
return
|
|
}
|
|
if len(s.OutTable) == 0 {
|
|
t.Error("got no table definition")
|
|
}
|
|
if re {
|
|
t.Error("claimed to have re-used.")
|
|
}
|
|
if len(s.OutData) == 0 {
|
|
t.Error("got no data output")
|
|
}
|
|
|
|
wantRemain := len(s.OutData)
|
|
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
|
|
|
s.Out = nil
|
|
var remain []byte
|
|
s, remain, err = ReadTable(b, s)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
var buf bytes.Buffer
|
|
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
|
t.Error(buf.String())
|
|
}
|
|
if len(remain) != wantRemain {
|
|
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
|
}
|
|
t.Logf("remain: %d bytes, ok", len(remain))
|
|
dc, err := s.Decompress4X(remain, len(buf0))
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if len(buf0) != len(dc) {
|
|
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
|
if len(buf0) > len(dc) {
|
|
buf0 = buf0[:len(dc)]
|
|
} else {
|
|
dc = dc[:len(buf0)]
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(dc) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
|
} else {
|
|
t.Log(string(dc))
|
|
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(buf0) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
} else {
|
|
t.Log(string(dc))
|
|
}
|
|
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
|
t.Errorf(test.name + ": decompressed, got delta")
|
|
}
|
|
if !t.Failed() {
|
|
t.Log("... roundtrip ok!")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecompress1XFuzz(t *testing.T) {
|
|
for _, test := range testfilesExtended {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
var s = &Scratch{}
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
b, re, err := Compress1X(buf0, s)
|
|
if err != nil {
|
|
if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
|
|
t.Log(test.name, err.Error())
|
|
return
|
|
}
|
|
t.Error(test.name, err.Error())
|
|
return
|
|
}
|
|
if b == nil {
|
|
t.Error("got no output")
|
|
return
|
|
}
|
|
if len(s.OutTable) == 0 {
|
|
t.Error("got no table definition")
|
|
}
|
|
if re {
|
|
t.Error("claimed to have re-used.")
|
|
}
|
|
if len(s.OutData) == 0 {
|
|
t.Error("got no data output")
|
|
}
|
|
|
|
wantRemain := len(s.OutData)
|
|
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
|
|
|
s.Out = nil
|
|
var remain []byte
|
|
s, remain, err = ReadTable(b, s)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
var buf bytes.Buffer
|
|
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
|
t.Error(buf.String())
|
|
}
|
|
if len(remain) != wantRemain {
|
|
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
|
}
|
|
t.Logf("remain: %d bytes, ok", len(remain))
|
|
dc, err := s.Decompress1X(remain)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if len(buf0) != len(dc) {
|
|
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
|
if len(buf0) > len(dc) {
|
|
buf0 = buf0[:len(dc)]
|
|
} else {
|
|
dc = dc[:len(buf0)]
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(dc) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
|
} else {
|
|
t.Log(string(dc))
|
|
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(buf0) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
} else {
|
|
t.Log(string(dc))
|
|
}
|
|
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
|
t.Errorf(test.name + ": decompressed, got delta")
|
|
}
|
|
if !t.Failed() {
|
|
t.Log("... roundtrip ok!")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecompress4XFuzz(t *testing.T) {
|
|
for _, test := range testfilesExtended {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
var s = &Scratch{}
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
b, re, err := Compress4X(buf0, s)
|
|
if err != nil {
|
|
if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
|
|
t.Log(test.name, err.Error())
|
|
return
|
|
}
|
|
t.Error(test.name, err.Error())
|
|
return
|
|
}
|
|
if b == nil {
|
|
t.Error("got no output")
|
|
return
|
|
}
|
|
if len(s.OutTable) == 0 {
|
|
t.Error("got no table definition")
|
|
}
|
|
if re {
|
|
t.Error("claimed to have re-used.")
|
|
}
|
|
if len(s.OutData) == 0 {
|
|
t.Error("got no data output")
|
|
}
|
|
|
|
wantRemain := len(s.OutData)
|
|
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
|
|
|
s.Out = nil
|
|
var remain []byte
|
|
s, remain, err = ReadTable(b, s)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
var buf bytes.Buffer
|
|
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
|
t.Error(buf.String())
|
|
}
|
|
if len(remain) != wantRemain {
|
|
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
|
}
|
|
t.Logf("remain: %d bytes, ok", len(remain))
|
|
dc, err := s.Decompress4X(remain, len(buf0))
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if len(buf0) != len(dc) {
|
|
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
|
if len(buf0) > len(dc) {
|
|
buf0 = buf0[:len(dc)]
|
|
} else {
|
|
dc = dc[:len(buf0)]
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(dc) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
|
} else {
|
|
t.Log(string(dc))
|
|
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if !cmp.Equal(buf0, dc) {
|
|
if len(buf0) > 1024 {
|
|
t.Log(string(dc[:1024]))
|
|
} else {
|
|
t.Log(string(dc))
|
|
}
|
|
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
|
t.Errorf(test.name + ": decompressed, got delta")
|
|
}
|
|
if !t.Failed() {
|
|
t.Log("... roundtrip ok!")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecompress1XTable(b *testing.B) {
|
|
for _, tt := range testfiles {
|
|
test := tt
|
|
if test.err1X != nil {
|
|
continue
|
|
}
|
|
b.Run(test.name, func(b *testing.B) {
|
|
var s = &Scratch{}
|
|
s.Reuse = ReusePolicyNone
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
compressed, _, err := Compress1X(buf0, s)
|
|
if err != test.err1X {
|
|
b.Fatal("unexpected error:", err)
|
|
}
|
|
s.Out = nil
|
|
s, remain, _ := ReadTable(compressed, s)
|
|
s.Decompress1X(remain)
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(buf0)))
|
|
for i := 0; i < b.N; i++ {
|
|
s, remain, err := ReadTable(compressed, s)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
_, err = s.Decompress1X(remain)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecompress1XNoTable(b *testing.B) {
|
|
for _, tt := range testfiles {
|
|
test := tt
|
|
if test.err1X != nil {
|
|
continue
|
|
}
|
|
b.Run(test.name, func(b *testing.B) {
|
|
var s = &Scratch{}
|
|
s.Reuse = ReusePolicyNone
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
compressed, _, err := Compress1X(buf0, s)
|
|
if err != test.err1X {
|
|
b.Fatal("unexpected error:", err)
|
|
}
|
|
s.Out = nil
|
|
s, remain, _ := ReadTable(compressed, s)
|
|
s.Decompress1X(remain)
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(buf0)))
|
|
for i := 0; i < b.N; i++ {
|
|
_, err = s.Decompress1X(remain)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecompress4XNoTable(b *testing.B) {
|
|
for _, tt := range testfiles {
|
|
test := tt
|
|
if test.err4X != nil {
|
|
continue
|
|
}
|
|
b.Run(test.name, func(b *testing.B) {
|
|
var s = &Scratch{}
|
|
s.Reuse = ReusePolicyNone
|
|
buf0, err := test.fn()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if len(buf0) > BlockSizeMax {
|
|
buf0 = buf0[:BlockSizeMax]
|
|
}
|
|
compressed, _, err := Compress4X(buf0, s)
|
|
if err != test.err1X {
|
|
b.Fatal("unexpected error:", err)
|
|
}
|
|
s.Out = nil
|
|
s, remain, _ := ReadTable(compressed, s)
|
|
s.Decompress4X(remain, len(buf0))
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(buf0)))
|
|
for i := 0; i < b.N; i++ {
|
|
_, err = s.Decompress4X(remain, len(buf0))
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|