blob: fa4ef60e8205b695686a0d12b76f439d282c83db [file] [log] [blame]
// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cgozstd
import (
"bytes"
"io"
"strings"
"testing"
)
const (
// compressedMoreN is 15 bytes of zstd frame:
//
// There are two forms, depending on the zstd-the-library version used for
// compression. They differ only in the WD byte.
//
// \x28\xb5\x2f\xfd \x00 \x50 \x31\x00\x00 \x4d\x6f\x72\x65\x21\x0a
// \x28\xb5\x2f\xfd \x00 \x58 \x31\x00\x00 \x4d\x6f\x72\x65\x21\x0a
// Magic----------- FHD- WD-- BH---------- BlockData---------------
//
// Frame Header Descriptor: no flags set.
// Window Descriptor: Exponent=10, Mantissa=0, Window_Size=1MiB.
// or: Exponent=11, Mantissa=0, Window_Size=2MiB.
// Block Header: Last_Block=1, Block_Type=0 (Raw_Block), Block_Size=6.
// Block Data: the literal bytes "More!\n".
compressedMore0 = "\x28\xb5\x2f\xfd\x00\x50\x31\x00\x00\x4d\x6f\x72\x65\x21\x0a"
compressedMore1 = "\x28\xb5\x2f\xfd\x00\x58\x31\x00\x00\x4d\x6f\x72\x65\x21\x0a"
uncompressedMore = "More!\n"
)
func TestRoundTrip(tt *testing.T) {
if !cgoEnabled {
tt.Skip("cgo is not enabled")
}
wr := &WriterRecycler{}
defer wr.Close()
w := &Writer{}
wr.Bind(w)
rr := &ReaderRecycler{}
defer rr.Close()
r := &Reader{}
rr.Bind(r)
for i := 0; i < 3; i++ {
buf := &bytes.Buffer{}
// Compress.
{
if err := w.Reset(buf, nil, 0); err != nil {
w.Close()
tt.Fatalf("i=%d: Reset: %v", i, err)
}
if _, err := w.Write([]byte(uncompressedMore)); err != nil {
w.Close()
tt.Fatalf("i=%d: Write: %v", i, err)
}
if err := w.Close(); err != nil {
tt.Fatalf("i=%d: Close: %v", i, err)
}
}
compressed := buf.String()
if (compressed != compressedMore0) && (compressed != compressedMore1) {
tt.Fatalf("i=%d: compressed\ngot % 02x\nwant % 02x\nor % 02x",
i, compressed, compressedMore0, compressedMore1)
}
// Uncompress.
{
if err := r.Reset(strings.NewReader(compressed), nil); err != nil {
r.Close()
tt.Fatalf("i=%d: Reset: %v", i, err)
}
gotBytes, err := io.ReadAll(r)
if err != nil {
r.Close()
tt.Fatalf("i=%d: ReadAll: %v", i, err)
}
if got, want := string(gotBytes), uncompressedMore; got != want {
r.Close()
tt.Fatalf("i=%d:\ngot %q\nwant %q", i, got, want)
}
if err := r.Close(); err != nil {
tt.Fatalf("i=%d: Close: %v", i, err)
}
}
}
}
func TestDictionary(tt *testing.T) {
if !cgoEnabled {
tt.Skip("cgo is not enabled")
}
const (
abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
uncompressed = abc + "123"
)
for _, withDict := range []bool{false, true} {
buf := &bytes.Buffer{}
dictionary, name := []byte(nil), "sans dictionary"
if withDict {
dictionary, name = []byte(abc), "with dictionary"
}
w := &Writer{}
if err := w.Reset(buf, dictionary, 0); err != nil {
w.Close()
tt.Fatalf("%s: Reset: %v", name, err)
}
if _, err := w.Write([]byte(uncompressed)); err != nil {
w.Close()
tt.Fatalf("%s: Write: %v", name, err)
}
if err := w.Close(); err != nil {
tt.Fatalf("%s: Close: %v", name, err)
}
compressed := buf.String()
if withDict {
if n := buf.Len(); n >= 30 {
tt.Fatalf("%s: compressed length: got %d, want < 30", name, n)
}
} else {
if n := buf.Len(); n < 50 {
tt.Fatalf("%s: compressed length: got %d, want >= 50", name, n)
}
}
r := &Reader{}
if err := r.Reset(strings.NewReader(compressed), dictionary); err != nil {
r.Close()
tt.Fatalf("%s: Reset: %v", name, err)
}
gotBytes, err := io.ReadAll(r)
if err != nil {
r.Close()
tt.Fatalf("%s: ReadAll: %v", name, err)
}
if got, want := string(gotBytes), uncompressed; got != want {
r.Close()
tt.Fatalf("%s:\ngot %q\nwant %q", name, got, want)
}
if err := r.Close(); err != nil {
tt.Fatalf("%s: Close: %v", name, err)
}
}
}