pax_global_header00006660000000000000000000000064145461225360014522gustar00rootroot0000000000000052 comment=7de5f7df4739135870ba936d835e809aea96a481 tdewolff-test-7de5f7d/000077500000000000000000000000001454612253600150205ustar00rootroot00000000000000tdewolff-test-7de5f7d/LICENSE.md000066400000000000000000000020621454612253600164240ustar00rootroot00000000000000Copyright (c) 2015 Taco de Wolff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.tdewolff-test-7de5f7d/README.md000066400000000000000000000006101454612253600162740ustar00rootroot00000000000000# Test [![GoDoc](http://godoc.org/github.com/tdewolff/test?status.svg)](http://godoc.org/github.com/tdewolff/test) Test is a helper package written in [Go][1]. It implements a few functions that are useful for io testing, such as readers and writers that fail after N consecutive reads/writes. ## License Released under the [MIT license](LICENSE.md). [1]: http://golang.org/ "Go Language" tdewolff-test-7de5f7d/go.mod000066400000000000000000000000511454612253600161220ustar00rootroot00000000000000module github.com/tdewolff/test go 1.18 tdewolff-test-7de5f7d/readers.go000066400000000000000000000034361454612253600170020ustar00rootroot00000000000000package test import "io" // PlainReader implements an io.Reader and wraps over an existing io.Reader to hide other functions it implements. type PlainReader struct { r io.Reader } // NewPlainReader returns a new PlainReader. func NewPlainReader(r io.Reader) *PlainReader { return &PlainReader{r} } // Read implements the io.Reader interface. func (r *PlainReader) Read(p []byte) (int, error) { return r.r.Read(p) } //////////////////////////////////////////////////////////////// // ErrorReader implements an io.Reader that will do N successive reads before it returns ErrPlain. type ErrorReader struct { n int } // NewErrorReader returns a new ErrorReader. func NewErrorReader(n int) *ErrorReader { return &ErrorReader{n} } // Read implements the io.Reader interface. func (r *ErrorReader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil } if r.n == 0 { return 0, ErrPlain } r.n-- b[0] = '.' return 1, nil } //////////////////////////////////////////////////////////////// // InfiniteReader implements an io.Reader that will always read-in one character. type InfiniteReader struct{} // NewInfiniteReader returns a new InfiniteReader. func NewInfiniteReader() *InfiniteReader { return &InfiniteReader{} } // Read implements the io.Reader interface. func (r *InfiniteReader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil } b[0] = '.' return 1, nil } //////////////////////////////////////////////////////////////// // EmptyReader implements an io.Reader that will always return 0, nil. type EmptyReader struct { } // NewEmptyReader returns a new EmptyReader. func NewEmptyReader() *EmptyReader { return &EmptyReader{} } // Read implements the io.Reader interface. func (r *EmptyReader) Read(b []byte) (n int, err error) { return 0, io.EOF } tdewolff-test-7de5f7d/test.go000066400000000000000000000135401454612253600163310ustar00rootroot00000000000000package test import ( "bytes" "errors" "fmt" "math" "reflect" "runtime" "strings" "testing" "unicode" ) // ErrPlain is the default error that is returned for functions in this package. var ErrPlain = errors.New("error") // Epsilon is used for floating point comparison. var Epsilon = 1e-10 //////////////////////////////////////////////////////////////// func fileline(i int) string { _, file, line, ok := runtime.Caller(i) if !ok { return "" } parts := strings.Split(file, "/") file = parts[len(parts)-1] return fmt.Sprintf("%s:%d", file, line) } func trace() string { trace2 := fileline(2) trace3 := fileline(3) return "\r " + strings.Repeat(" ", len(fmt.Sprintf("%s:", trace2))) + "\r " + trace3 } func message(msgs ...any) string { if len(msgs) == 0 { return "" } s := fmt.Sprintln(msgs...) s = s[:len(s)-1] // remove newline return ": " + s } func printable(s string) string { s2 := "" for _, r := range s { if !unicode.IsPrint(r) { if r == '\n' { s2 += fmt.Sprintf(Dark + "\\n" + UndoDark) } else if r == '\r' { s2 += fmt.Sprintf(Dark + "\\r" + UndoDark) } else if r == '\t' { s2 += fmt.Sprintf(Dark + "\\t" + UndoDark) } else if r == 0 { s2 += fmt.Sprintf(Dark + "\\0" + UndoDark) } else if r <= 0xFF { s2 += fmt.Sprintf(Dark+"\\x%02X"+UndoDark, r) } else if r <= 0xFFFF { s2 += fmt.Sprintf(Dark+"\\u%04X"+UndoDark, r) } else { s2 += fmt.Sprintf(Dark+"\\U%08X"+UndoDark, r) } } else { s2 += string(r) } } return s2 } const ( Red = "\x1B[31m" Green = "\x1B[32m" Dark = "\x1B[2m" UndoDark = "\x1B[22m" Reset = "\x1B[0m" ) func color(color string, s any) string { return fmt.Sprintf("%s%v%s", color, s, Reset) } func floatEqual(a, b, epsilon float64) bool { // use mix of relative and absolute difference for large and small numbers respectively // see: https://stackoverflow.com/a/32334103 if a == b { return true } diff := math.Abs(a - b) norm := math.Min(math.Abs(a)+math.Abs(b), math.MaxFloat64) return diff < epsilon*math.Max(1.0, norm) } ///////////////////////////////////////////////////////////////// func Fail(t *testing.T, msgs ...any) { t.Helper() t.Fatalf("%s%s", trace(), message(msgs...)) } func Error(t *testing.T, err error, msgs ...any) { t.Helper() if err != nil { t.Fatalf("%s%s: %s", trace(), message(msgs...), color(Red, err.Error())) } } func That(t *testing.T, condition bool, msgs ...any) { t.Helper() if !condition { t.Fatalf("%s%s: false", trace(), message(msgs...)) } } func equalsInterface(got, wanted reflect.Value) (bool, bool) { if equals, ok := wanted.Type().MethodByName("Equals"); ok && equals.Type.NumIn() == 2 && equals.Type.NumOut() == 1 && equals.Type.In(0) == wanted.Type() && equals.Type.In(1) == got.Type() && equals.Type.Out(0).Kind() == reflect.Bool { return equals.Func.Call([]reflect.Value{wanted, got})[0].Bool(), true } return false, false } func T(t *testing.T, got, wanted any, msgs ...any) { t.Helper() gotType := reflect.TypeOf(got) wantedType := reflect.TypeOf(wanted) if gotType != wantedType { t.Fatalf("%s%s: type %v != %v", trace(), message(msgs...), color(Red, gotType), color(Green, wantedType)) return } if reflect.DeepEqual(got, wanted) { return } if wantedType != nil { gotValue := reflect.ValueOf(got) wantedValue := reflect.ValueOf(wanted) if equals, ok := equalsInterface(gotValue, wantedValue); ok && equals { return } else if wantedValue.Kind() == reflect.Slice { if gotValue.Len() == wantedValue.Len() { i := 0 for ; i < wantedValue.Len(); i++ { if equals, ok := equalsInterface(gotValue.Index(i), wantedValue.Index(i)); !ok { break } else if !equals { break } } if i == wantedValue.Len() { return } } } } t.Fatalf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted)) } func Bytes(t *testing.T, got, wanted []byte, msgs ...any) { t.Helper() if !bytes.Equal(got, wanted) { gotString := printable(string(got)) wantedString := printable(string(wanted)) t.Fatalf("%s%s:\n%s\n%s", trace(), message(msgs...), color(Red, gotString), color(Green, wantedString)) } } func String(t *testing.T, got, wanted string, msgs ...any) { t.Helper() if got != wanted { gotString := printable(got) wantedString := printable(wanted) t.Fatalf("%s%s:\n%s\n%s", trace(), message(msgs...), color(Red, gotString), color(Green, wantedString)) } } func Float(t *testing.T, got, wanted float64, msgs ...any) { t.Helper() if math.IsNaN(wanted) != math.IsNaN(got) || !math.IsNaN(wanted) && !floatEqual(got, wanted, Epsilon) { t.Fatalf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted)) } } func Floats(t *testing.T, got, wanted []float64, msgs ...any) { t.Helper() equal := len(got) == len(wanted) if equal { for i := range got { if math.IsNaN(wanted[i]) != math.IsNaN(got[i]) || !math.IsNaN(wanted[i]) && !floatEqual(got[i], wanted[i], Epsilon) { equal = false break } } } if !equal { t.Fatalf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, wanted)) } } func FloatDiff(t *testing.T, got, wanted, epsilon float64, msgs ...any) { t.Helper() if math.IsNaN(wanted) != math.IsNaN(got) || !math.IsNaN(wanted) && !floatEqual(got, wanted, epsilon) { t.Fatalf("%s%s: %v != %v", trace(), message(msgs...), color(Red, got), color(Green, fmt.Sprintf("%v ± %v", wanted, epsilon))) } } func Minify(t *testing.T, input string, err error, got, wanted string, msgs ...any) { t.Helper() inputString := printable(input) if err != nil { t.Fatalf("%s%s:\n%s\n%s", trace(), message(msgs...), inputString, color(Red, err.Error())) return } if got != wanted { gotString := printable(got) wantedString := printable(wanted) t.Fatalf("%s%s:\n%s\n%s\n%s", trace(), message(msgs...), inputString, color(Red, gotString), color(Green, wantedString)) } } tdewolff-test-7de5f7d/writers.go000066400000000000000000000006641454612253600170540ustar00rootroot00000000000000package test // ErrorWriter implements an io.Writer that will do N successive writes before it returns ErrPlain. type ErrorWriter struct { n int } // NewErrorWriter returns a new ErrorWriter. func NewErrorWriter(n int) *ErrorWriter { return &ErrorWriter{n} } // Write implements the io.Writer interface. func (w *ErrorWriter) Write(b []byte) (n int, err error) { if w.n == 0 { return 0, ErrPlain } w.n-- return len(b), nil }