313 lines
6.7 KiB
Go
313 lines
6.7 KiB
Go
|
// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package lzma
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"bytes"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"log"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"testing"
|
||
|
"testing/iotest"
|
||
|
)
|
||
|
|
||
|
func TestNewReader(t *testing.T) {
|
||
|
f, err := os.Open("examples/a.lzma")
|
||
|
if err != nil {
|
||
|
t.Fatalf("open examples/a.lzma: %s", err)
|
||
|
}
|
||
|
defer f.Close()
|
||
|
_, err = NewReader(bufio.NewReader(f))
|
||
|
if err != nil {
|
||
|
t.Fatalf("NewReader: %s", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
dirname = "examples"
|
||
|
origname = "a.txt"
|
||
|
)
|
||
|
|
||
|
func readOrigFile(t *testing.T) []byte {
|
||
|
orig, err := ioutil.ReadFile(filepath.Join(dirname, origname))
|
||
|
if err != nil {
|
||
|
t.Fatalf("ReadFile: %s", err)
|
||
|
}
|
||
|
return orig
|
||
|
}
|
||
|
|
||
|
func testDecodeFile(t *testing.T, filename string, orig []byte) {
|
||
|
pathname := filepath.Join(dirname, filename)
|
||
|
f, err := os.Open(pathname)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Open(%q): %s", pathname, err)
|
||
|
}
|
||
|
defer func() {
|
||
|
if err = f.Close(); err != nil {
|
||
|
t.Fatalf("f.Close() error %s", err)
|
||
|
}
|
||
|
}()
|
||
|
t.Logf("file %s opened", filename)
|
||
|
l, err := NewReader(bufio.NewReader(f))
|
||
|
if err != nil {
|
||
|
t.Fatalf("NewReader: %s", err)
|
||
|
}
|
||
|
decoded, err := ioutil.ReadAll(l)
|
||
|
if err != nil {
|
||
|
t.Fatalf("ReadAll: %s", err)
|
||
|
}
|
||
|
t.Logf("%s", decoded)
|
||
|
if len(orig) != len(decoded) {
|
||
|
t.Fatalf("length decoded is %d; want %d",
|
||
|
len(decoded), len(orig))
|
||
|
}
|
||
|
if !bytes.Equal(orig, decoded) {
|
||
|
t.Fatalf("decoded file differs from original")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestReaderSimple(t *testing.T) {
|
||
|
// DebugOn(os.Stderr)
|
||
|
// defer DebugOff()
|
||
|
|
||
|
testDecodeFile(t, "a.lzma", readOrigFile(t))
|
||
|
}
|
||
|
|
||
|
func TestReaderAll(t *testing.T) {
|
||
|
dirname := "examples"
|
||
|
dir, err := os.Open(dirname)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Open: %s", err)
|
||
|
}
|
||
|
defer func() {
|
||
|
if err := dir.Close(); err != nil {
|
||
|
t.Fatalf("dir.Close() error %s", err)
|
||
|
}
|
||
|
}()
|
||
|
all, err := dir.Readdirnames(0)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Readdirnames: %s", err)
|
||
|
}
|
||
|
// filter now all file with the pattern "a*.lzma"
|
||
|
files := make([]string, 0, len(all))
|
||
|
for _, fn := range all {
|
||
|
match, err := filepath.Match("a*.lzma", fn)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Match: %s", err)
|
||
|
}
|
||
|
if match {
|
||
|
files = append(files, fn)
|
||
|
}
|
||
|
}
|
||
|
t.Log("files:", files)
|
||
|
orig := readOrigFile(t)
|
||
|
// actually test the files
|
||
|
for _, fn := range files {
|
||
|
testDecodeFile(t, fn, orig)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
func Example_reader() {
|
||
|
f, err := os.Open("fox.lzma")
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
// no need for defer; Fatal calls os.Exit(1) that doesn't execute deferred functions
|
||
|
r, err := NewReader(bufio.NewReader(f))
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
_, err = io.Copy(os.Stdout, r)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
if err := f.Close(); err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
// Output:
|
||
|
// The quick brown fox jumps over the lazy dog.
|
||
|
}
|
||
|
|
||
|
type wrapTest struct {
|
||
|
name string
|
||
|
wrap func(io.Reader) io.Reader
|
||
|
}
|
||
|
|
||
|
func (w *wrapTest) testFile(t *testing.T, filename string, orig []byte) {
|
||
|
pathname := filepath.Join(dirname, filename)
|
||
|
f, err := os.Open(pathname)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Open(\"%s\"): %s", pathname, err)
|
||
|
}
|
||
|
defer func() {
|
||
|
if err := f.Close(); err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}()
|
||
|
t.Logf("%s file %s opened", w.name, filename)
|
||
|
l, err := NewReader(w.wrap(f))
|
||
|
if err != nil {
|
||
|
t.Fatalf("%s NewReader: %s", w.name, err)
|
||
|
}
|
||
|
decoded, err := ioutil.ReadAll(l)
|
||
|
if err != nil {
|
||
|
t.Fatalf("%s ReadAll: %s", w.name, err)
|
||
|
}
|
||
|
t.Logf("%s", decoded)
|
||
|
if len(orig) != len(decoded) {
|
||
|
t.Fatalf("%s length decoded is %d; want %d",
|
||
|
w.name, len(decoded), len(orig))
|
||
|
}
|
||
|
if !bytes.Equal(orig, decoded) {
|
||
|
t.Fatalf("%s decoded file differs from original", w.name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestReaderWrap(t *testing.T) {
|
||
|
tests := [...]wrapTest{
|
||
|
{"DataErrReader", iotest.DataErrReader},
|
||
|
{"HalfReader", iotest.HalfReader},
|
||
|
{"OneByteReader", iotest.OneByteReader},
|
||
|
// TimeOutReader would require buffer
|
||
|
}
|
||
|
orig := readOrigFile(t)
|
||
|
for _, tst := range tests {
|
||
|
tst.testFile(t, "a.lzma", orig)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestReaderBadFiles(t *testing.T) {
|
||
|
dirname := "examples"
|
||
|
dir, err := os.Open(dirname)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Open: %s", err)
|
||
|
}
|
||
|
defer func() {
|
||
|
if err := dir.Close(); err != nil {
|
||
|
t.Fatalf("dir.Close() error %s", err)
|
||
|
}
|
||
|
}()
|
||
|
all, err := dir.Readdirnames(0)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Readdirnames: %s", err)
|
||
|
}
|
||
|
// filter now all file with the pattern "bad*.lzma"
|
||
|
files := make([]string, 0, len(all))
|
||
|
for _, fn := range all {
|
||
|
match, err := filepath.Match("bad*.lzma", fn)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Match: %s", err)
|
||
|
}
|
||
|
if match {
|
||
|
files = append(files, fn)
|
||
|
}
|
||
|
}
|
||
|
t.Log("files:", files)
|
||
|
for _, filename := range files {
|
||
|
pathname := filepath.Join(dirname, filename)
|
||
|
f, err := os.Open(pathname)
|
||
|
if err != nil {
|
||
|
t.Fatalf("Open(\"%s\"): %s", pathname, err)
|
||
|
}
|
||
|
defer func(f *os.File) {
|
||
|
if err := f.Close(); err != nil {
|
||
|
t.Fatalf("f.Close() error %s", err)
|
||
|
}
|
||
|
}(f)
|
||
|
t.Logf("file %s opened", filename)
|
||
|
l, err := NewReader(f)
|
||
|
if err != nil {
|
||
|
t.Fatalf("NewReader: %s", err)
|
||
|
}
|
||
|
decoded, err := ioutil.ReadAll(l)
|
||
|
if err == nil {
|
||
|
t.Errorf("ReadAll for %s: no error", filename)
|
||
|
t.Logf("%s", decoded)
|
||
|
continue
|
||
|
}
|
||
|
t.Logf("%s: error %s", filename, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type repReader byte
|
||
|
|
||
|
func (r repReader) Read(p []byte) (n int, err error) {
|
||
|
for i := range p {
|
||
|
p[i] = byte(r)
|
||
|
}
|
||
|
return len(p), nil
|
||
|
}
|
||
|
|
||
|
func newRepReader(c byte, n int64) *io.LimitedReader {
|
||
|
return &io.LimitedReader{R: repReader(c), N: n}
|
||
|
}
|
||
|
|
||
|
func newCodeReader(r io.Reader) *io.PipeReader {
|
||
|
pr, pw := io.Pipe()
|
||
|
go func() {
|
||
|
bw := bufio.NewWriter(pw)
|
||
|
lw, err := NewWriter(bw)
|
||
|
if err != nil {
|
||
|
log.Fatalf("NewWriter error %s", err)
|
||
|
}
|
||
|
if _, err = io.Copy(lw, r); err != nil {
|
||
|
log.Fatalf("io.Copy error %s", err)
|
||
|
}
|
||
|
if err = lw.Close(); err != nil {
|
||
|
log.Fatalf("lw.Close error %s", err)
|
||
|
}
|
||
|
if err = bw.Flush(); err != nil {
|
||
|
log.Fatalf("bw.Flush() error %s", err)
|
||
|
}
|
||
|
if err = pw.CloseWithError(io.EOF); err != nil {
|
||
|
log.Fatalf("pw.CloseWithError(io.EOF) error %s", err)
|
||
|
}
|
||
|
}()
|
||
|
return pr
|
||
|
}
|
||
|
|
||
|
func TestReaderErrAgain(t *testing.T) {
|
||
|
lengths := []int64{0, 128, 1024, 4095, 4096, 4097, 8191, 8192, 8193}
|
||
|
buf := make([]byte, 128)
|
||
|
const c = 'A'
|
||
|
for _, n := range lengths {
|
||
|
t.Logf("n: %d", n)
|
||
|
pr := newCodeReader(newRepReader(c, n))
|
||
|
r, err := NewReader(pr)
|
||
|
if err != nil {
|
||
|
t.Fatalf("NewReader(pr) error %s", err)
|
||
|
}
|
||
|
k := int64(0)
|
||
|
for {
|
||
|
m, err := r.Read(buf)
|
||
|
k += int64(m)
|
||
|
if err == io.EOF {
|
||
|
break
|
||
|
}
|
||
|
if err != nil {
|
||
|
t.Errorf("r.Read(buf) error %s", err)
|
||
|
break
|
||
|
}
|
||
|
if m > len(buf) {
|
||
|
t.Fatalf("r.Read(buf) %d; want <= %d", m,
|
||
|
len(buf))
|
||
|
}
|
||
|
for i, b := range buf[:m] {
|
||
|
if b != c {
|
||
|
t.Fatalf("buf[%d]=%c; want %c", i, b,
|
||
|
c)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if k != n {
|
||
|
t.Errorf("Read %d bytes; want %d", k, n)
|
||
|
}
|
||
|
}
|
||
|
}
|