1// Copyright 2014-2017 Ulrich Kunitz. 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
5package lzma
6
7import (
8	"bytes"
9	"io"
10	"io/ioutil"
11	"math/rand"
12	"testing"
13
14	"github.com/ulikunitz/xz/internal/randtxt"
15)
16
17var testString = `LZMA decoder test example
18=========================
19! LZMA ! Decoder ! TEST !
20=========================
21! TEST ! LZMA ! Decoder !
22=========================
23---- Test Line 1 --------
24=========================
25---- Test Line 2 --------
26=========================
27=== End of test file ====
28=========================
29`
30
31func cycle(t *testing.T, n int) {
32	t.Logf("cycle(t,%d)", n)
33	if n > len(testString) {
34		t.Fatalf("cycle: n=%d larger than len(testString)=%d", n,
35			len(testString))
36	}
37	const dictCap = MinDictCap
38	m, err := newHashTable(dictCap, 4)
39	if err != nil {
40		t.Fatal(err)
41	}
42	encoderDict, err := newEncoderDict(dictCap, dictCap+1024, m)
43	if err != nil {
44		t.Fatal(err)
45	}
46	props := Properties{2, 0, 2}
47	if err := props.verify(); err != nil {
48		t.Fatalf("properties error %s", err)
49	}
50	state := newState(props)
51	var buf bytes.Buffer
52	w, err := newEncoder(&buf, state, encoderDict, eosMarker)
53	if err != nil {
54		t.Fatalf("newEncoder error %s", err)
55	}
56	orig := []byte(testString)[:n]
57	t.Logf("len(orig) %d", len(orig))
58	k, err := w.Write(orig)
59	if err != nil {
60		t.Fatalf("w.Write error %s", err)
61	}
62	if k != len(orig) {
63		t.Fatalf("w.Write returned %d; want %d", k, len(orig))
64	}
65	if err = w.Close(); err != nil {
66		t.Fatalf("w.Close error %s", err)
67	}
68	t.Logf("buf.Len() %d len(orig) %d", buf.Len(), len(orig))
69	decoderDict, err := newDecoderDict(dictCap)
70	if err != nil {
71		t.Fatalf("newDecoderDict error %s", err)
72	}
73	state.Reset()
74	r, err := newDecoder(&buf, state, decoderDict, -1)
75	if err != nil {
76		t.Fatalf("newDecoder error %s", err)
77	}
78	decoded, err := ioutil.ReadAll(r)
79	if err != nil {
80		t.Fatalf("ReadAll(lr) error %s", err)
81	}
82	t.Logf("decoded: %s", decoded)
83	if len(orig) != len(decoded) {
84		t.Fatalf("length decoded is %d; want %d", len(decoded),
85			len(orig))
86	}
87	if !bytes.Equal(orig, decoded) {
88		t.Fatalf("decoded file differs from original")
89	}
90}
91
92func TestEncoderCycle1(t *testing.T) {
93	cycle(t, len(testString))
94}
95
96func TestEncoderCycle2(t *testing.T) {
97	buf := new(bytes.Buffer)
98	const txtlen = 50000
99	io.CopyN(buf, randtxt.NewReader(rand.NewSource(42)), txtlen)
100	txt := buf.String()
101	buf.Reset()
102	const dictCap = MinDictCap
103	m, err := newHashTable(dictCap, 4)
104	if err != nil {
105		t.Fatal(err)
106	}
107	encoderDict, err := newEncoderDict(dictCap, dictCap+1024, m)
108	if err != nil {
109		t.Fatal(err)
110	}
111	props := Properties{3, 0, 2}
112	if err := props.verify(); err != nil {
113		t.Fatalf("properties error %s", err)
114	}
115	state := newState(props)
116	lbw := &LimitedByteWriter{BW: buf, N: 100}
117	w, err := newEncoder(lbw, state, encoderDict, 0)
118	if err != nil {
119		t.Fatalf("NewEncoder error %s", err)
120	}
121	_, err = io.WriteString(w, txt)
122	if err != nil && err != ErrLimit {
123		t.Fatalf("WriteString error %s", err)
124	}
125	if err = w.Close(); err != nil {
126		t.Fatalf("w.Close error %s", err)
127	}
128	n := w.Compressed()
129	txt = txt[:n]
130	decoderDict, err := newDecoderDict(dictCap)
131	if err != nil {
132		t.Fatalf("NewDecoderDict error %s", err)
133	}
134	state.Reset()
135	r, err := newDecoder(buf, state, decoderDict, n)
136	if err != nil {
137		t.Fatalf("NewDecoder error %s", err)
138	}
139	out := new(bytes.Buffer)
140	if _, err = io.Copy(out, r); err != nil {
141		t.Fatalf("decompress copy error %s", err)
142	}
143	got := out.String()
144	t.Logf("%s", got)
145	if len(got) != int(n) {
146		t.Fatalf("len(got) %d; want %d", len(got), n)
147	}
148	if got != txt {
149		t.Fatalf("got and txt differ")
150	}
151}
152