| // 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 testcut provides support for testing flatecut and zlibcut. |
| package testcut |
| |
| import ( |
| "bytes" |
| "io" |
| "io/ioutil" |
| "testing" |
| ) |
| |
| func calculateDecodedLen(b []byte, |
| newReader func(io.Reader) (io.ReadCloser, error)) (int64, error) { |
| |
| r, err := newReader(bytes.NewReader(b)) |
| if err != nil { |
| return 0, err |
| } |
| n, err := io.Copy(ioutil.Discard, r) |
| if err != nil { |
| r.Close() |
| return 0, err |
| } |
| return n, r.Close() |
| } |
| |
| func clone(b []byte) []byte { |
| return append([]byte(nil), b...) |
| } |
| |
| func Test(tt *testing.T, |
| smallestValidMaxEncodedLen int, |
| cut func(io.Writer, []byte, int) (int, int, error), |
| newReader func(io.Reader) (io.ReadCloser, error), |
| filenames []string) { |
| |
| for _, filename := range filenames { |
| full, err := ioutil.ReadFile("../../test/data/" + filename) |
| if err != nil { |
| tt.Errorf("f=%q: ReadFile: %v", filename, err) |
| continue |
| } |
| fullDecodedLen, err := calculateDecodedLen(full, newReader) |
| if err != nil { |
| tt.Errorf("f=%q: calculateDecodedLen: %v", filename, err) |
| continue |
| } |
| |
| maxEncodedLens := []int{ |
| smallestValidMaxEncodedLen + 0, |
| smallestValidMaxEncodedLen + 1, |
| smallestValidMaxEncodedLen + 2, |
| smallestValidMaxEncodedLen + 3, |
| smallestValidMaxEncodedLen + 4, |
| smallestValidMaxEncodedLen + 5, |
| smallestValidMaxEncodedLen + 6, |
| smallestValidMaxEncodedLen + 7, |
| 20, |
| 77, |
| 234, |
| 512, |
| 1999, |
| 8192, |
| len(full) - 7, |
| len(full) - 6, |
| len(full) - 5, |
| len(full) - 4, |
| len(full) - 3, |
| len(full) - 2, |
| len(full) - 1, |
| len(full) + 0, |
| len(full) + 1, |
| len(full) + 2, |
| } |
| |
| for _, maxEncodedLen := range maxEncodedLens { |
| if maxEncodedLen < smallestValidMaxEncodedLen { |
| continue |
| } |
| w0 := &bytes.Buffer{} |
| encoded := clone(full) |
| encLen, decLen, err := cut(w0, encoded, maxEncodedLen) |
| if err != nil { |
| tt.Errorf("f=%q, mEL=%d: cut: %v", filename, maxEncodedLen, err) |
| continue |
| } |
| if encLen > maxEncodedLen { |
| tt.Errorf("f=%q, mEL=%d: encLen vs max: got %d, want <= %d", |
| filename, maxEncodedLen, encLen, maxEncodedLen) |
| continue |
| } |
| if encLen > len(encoded) { |
| tt.Errorf("f=%q, mEL=%d: encLen vs len: got %d, want <= %d", |
| filename, maxEncodedLen, encLen, len(encoded)) |
| continue |
| } |
| |
| w1 := &bytes.Buffer{} |
| r, err := newReader(bytes.NewReader(encoded[:encLen])) |
| if err != nil { |
| tt.Errorf("f=%q, mEL=%d: newReader: %v", filename, maxEncodedLen, err) |
| continue |
| } |
| if n, err := io.Copy(w1, r); err != nil { |
| tt.Errorf("f=%q, mEL=%d: io.Copy: %v", filename, maxEncodedLen, err) |
| continue |
| } else if n != int64(decLen) { |
| tt.Errorf("f=%q, mEL=%d: io.Copy: got %d, want %d", |
| filename, maxEncodedLen, n, decLen) |
| continue |
| } |
| |
| if !bytes.Equal(w0.Bytes(), w1.Bytes()) { |
| tt.Errorf("f=%q, mEL=%d: decoded bytes were not equal", filename, maxEncodedLen) |
| continue |
| } |
| |
| if (maxEncodedLen == len(encoded)) && (int64(decLen) != fullDecodedLen) { |
| tt.Errorf("f=%q, mEL=%d: full decode: got %d, want %d", |
| filename, maxEncodedLen, decLen, fullDecodedLen) |
| continue |
| } |
| |
| if err := r.Close(); err != nil { |
| tt.Errorf("f=%q, mEL=%d: r.Close: %v", filename, maxEncodedLen, err) |
| continue |
| } |
| } |
| } |
| } |
| |
| func Benchmark(b *testing.B, |
| smallestValidMaxEncodedLen int, |
| cut func(io.Writer, []byte, int) (int, int, error), |
| newReader func(io.Reader) (io.ReadCloser, error), |
| filename string, |
| trimPrefix int, |
| trimSuffix int, |
| decodedLen int64) { |
| |
| full, err := ioutil.ReadFile("../../test/data/" + filename) |
| if err != nil { |
| b.Fatalf("ReadFile: %v", err) |
| } |
| |
| if len(full) < (trimPrefix + trimSuffix) { |
| b.Fatalf("len(full): got %d, want >= %d", len(full), trimPrefix+trimSuffix) |
| } |
| full = full[trimPrefix : len(full)-trimSuffix] |
| |
| if n, err := calculateDecodedLen(full, newReader); err != nil { |
| b.Fatalf("calculateDecodedLen: %v", err) |
| } else if n != decodedLen { |
| b.Fatalf("calculateDecodedLen: got %d, want %d", n, decodedLen) |
| } |
| |
| b.ResetTimer() |
| for i := 0; i < b.N; i++ { |
| for maxEncodedLen := 10; ; maxEncodedLen *= 10 { |
| if maxEncodedLen < smallestValidMaxEncodedLen { |
| continue |
| } |
| encoded := clone(full) |
| if _, _, err := cut(nil, encoded, maxEncodedLen); err != nil { |
| b.Fatalf("cut: %v", err) |
| } |
| if maxEncodedLen >= len(full) { |
| break |
| } |
| } |
| } |
| } |