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