• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 The Wuffs Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package testcut provides support for testing flatecut and zlibcut.
16package testcut
17
18import (
19	"bytes"
20	"io"
21	"io/ioutil"
22	"testing"
23)
24
25func calculateDecodedLen(b []byte,
26	newReader func(io.Reader) (io.ReadCloser, error)) (int64, error) {
27
28	r, err := newReader(bytes.NewReader(b))
29	if err != nil {
30		return 0, err
31	}
32	n, err := io.Copy(ioutil.Discard, r)
33	if err != nil {
34		r.Close()
35		return 0, err
36	}
37	return n, r.Close()
38}
39
40func clone(b []byte) []byte {
41	return append([]byte(nil), b...)
42}
43
44func Test(t *testing.T,
45	smallestValidMaxEncodedLen int,
46	cut func(io.Writer, []byte, int) (int, int, error),
47	newReader func(io.Reader) (io.ReadCloser, error),
48	filenames []string) {
49
50	for _, filename := range filenames {
51		full, err := ioutil.ReadFile("../../test/data/" + filename)
52		if err != nil {
53			t.Errorf("f=%q: ReadFile: %v", filename, err)
54			continue
55		}
56		fullDecodedLen, err := calculateDecodedLen(full, newReader)
57		if err != nil {
58			t.Errorf("f=%q: calculateDecodedLen: %v", filename, err)
59			continue
60		}
61
62		maxEncodedLens := []int{
63			smallestValidMaxEncodedLen + 0,
64			smallestValidMaxEncodedLen + 1,
65			smallestValidMaxEncodedLen + 2,
66			smallestValidMaxEncodedLen + 3,
67			smallestValidMaxEncodedLen + 4,
68			smallestValidMaxEncodedLen + 5,
69			smallestValidMaxEncodedLen + 6,
70			smallestValidMaxEncodedLen + 7,
71			20,
72			77,
73			234,
74			512,
75			1999,
76			8192,
77			len(full) - 7,
78			len(full) - 6,
79			len(full) - 5,
80			len(full) - 4,
81			len(full) - 3,
82			len(full) - 2,
83			len(full) - 1,
84			len(full) + 0,
85			len(full) + 1,
86			len(full) + 2,
87		}
88
89		for _, maxEncodedLen := range maxEncodedLens {
90			if maxEncodedLen < smallestValidMaxEncodedLen {
91				continue
92			}
93			w0 := &bytes.Buffer{}
94			encoded := clone(full)
95			encLen, decLen, err := cut(w0, encoded, maxEncodedLen)
96			if err != nil {
97				t.Errorf("f=%q, mEL=%d: cut: %v", filename, maxEncodedLen, err)
98				continue
99			}
100			if encLen > maxEncodedLen {
101				t.Errorf("f=%q, mEL=%d: encLen vs max: got %d, want <= %d",
102					filename, maxEncodedLen, encLen, maxEncodedLen)
103				continue
104			}
105			if encLen > len(encoded) {
106				t.Errorf("f=%q, mEL=%d: encLen vs len: got %d, want <= %d",
107					filename, maxEncodedLen, encLen, len(encoded))
108				continue
109			}
110
111			w1 := &bytes.Buffer{}
112			r, err := newReader(bytes.NewReader(encoded[:encLen]))
113			if err != nil {
114				t.Errorf("f=%q, mEL=%d: newReader: %v", filename, maxEncodedLen, err)
115				continue
116			}
117			if n, err := io.Copy(w1, r); err != nil {
118				t.Errorf("f=%q, mEL=%d: io.Copy: %v", filename, maxEncodedLen, err)
119				continue
120			} else if n != int64(decLen) {
121				t.Errorf("f=%q, mEL=%d: io.Copy: got %d, want %d",
122					filename, maxEncodedLen, n, decLen)
123				continue
124			}
125
126			if !bytes.Equal(w0.Bytes(), w1.Bytes()) {
127				t.Errorf("f=%q, mEL=%d: decoded bytes were not equal", filename, maxEncodedLen)
128				continue
129			}
130
131			if (maxEncodedLen == len(encoded)) && (int64(decLen) != fullDecodedLen) {
132				t.Errorf("f=%q, mEL=%d: full decode: got %d, want %d",
133					filename, maxEncodedLen, decLen, fullDecodedLen)
134				continue
135			}
136
137			if err := r.Close(); err != nil {
138				t.Errorf("f=%q, mEL=%d: r.Close: %v", filename, maxEncodedLen, err)
139				continue
140			}
141		}
142	}
143}
144
145func Benchmark(b *testing.B,
146	smallestValidMaxEncodedLen int,
147	cut func(io.Writer, []byte, int) (int, int, error),
148	newReader func(io.Reader) (io.ReadCloser, error),
149	filename string,
150	trimPrefix int,
151	trimSuffix int,
152	decodedLen int64) {
153
154	full, err := ioutil.ReadFile("../../test/data/" + filename)
155	if err != nil {
156		b.Fatalf("ReadFile: %v", err)
157	}
158
159	if len(full) < (trimPrefix + trimSuffix) {
160		b.Fatalf("len(full): got %d, want >= %d", len(full), trimPrefix+trimSuffix)
161	}
162	full = full[trimPrefix : len(full)-trimSuffix]
163
164	if n, err := calculateDecodedLen(full, newReader); err != nil {
165		b.Fatalf("calculateDecodedLen: %v", err)
166	} else if n != decodedLen {
167		b.Fatalf("calculateDecodedLen: got %d, want %d", n, decodedLen)
168	}
169
170	b.ResetTimer()
171	for i := 0; i < b.N; i++ {
172		for maxEncodedLen := 10; ; maxEncodedLen *= 10 {
173			if maxEncodedLen < smallestValidMaxEncodedLen {
174				continue
175			}
176			encoded := clone(full)
177			if _, _, err := cut(nil, encoded, maxEncodedLen); err != nil {
178				b.Fatalf("cut: %v", err)
179			}
180			if maxEncodedLen >= len(full) {
181				break
182			}
183		}
184	}
185}
186