pax_global_header00006660000000000000000000000064142312471510014512gustar00rootroot0000000000000052 comment=df62958a1fc106a4c9c9e0093aba3b5d2296307e test-1.0.0/000077500000000000000000000000001423124715100124675ustar00rootroot00000000000000test-1.0.0/LICENSE000066400000000000000000000020611423124715100134730ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 chzyer 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. test-1.0.0/README.md000066400000000000000000000000061423124715100137420ustar00rootroot00000000000000# testtest-1.0.0/disk.go000066400000000000000000000034331423124715100137530ustar00rootroot00000000000000package test import ( "encoding/hex" "io" ) type MemDisk struct { data [][]byte size int64 woff, roff int } func NewMemDisk() *MemDisk { return &MemDisk{} } func (w *MemDisk) Write(b []byte) (int, error) { n, err := w.WriteAt(b, int64(w.woff)) w.woff += n return n, err } func (w *MemDisk) getData(off int64) []byte { idx := int(off >> 20) if idx >= cap(w.data) { newdata := make([][]byte, idx+1) copy(newdata, w.data) w.data = newdata } if len(w.data[idx]) == 0 { w.data[idx] = make([]byte, 1<<20) } return w.data[idx][off&((1<<20)-1):] } func (w *MemDisk) WriteAt(b []byte, off int64) (int, error) { n := len(b) for len(b) > 0 { buf := w.getData(off) m := copy(buf, b) if off+int64(m) > w.size { w.size = off + int64(m) } b = b[m:] off += int64(m) } return n, nil } func (w *MemDisk) ReadAt(b []byte, off int64) (int, error) { byteRead := 0 for byteRead < len(b) { if off >= w.size { return 0, io.EOF } buf := w.getData(off) if int64(len(buf))+off > w.size { buf = buf[:w.size-off] } if len(buf) == 0 { return byteRead, io.EOF } n := copy(b[byteRead:], buf) off += int64(n) byteRead += n } return byteRead, nil } func (w *MemDisk) Dump() string { return hex.Dump(w.getData(0)) } func (w *MemDisk) SeekRead(offset int64, whence int) (ret int64) { switch whence { case 0: w.roff += int(offset) case 1: w.roff = int(offset) default: } return int64(w.roff) } func (w *MemDisk) SeekWrite(offset int64, whence int) (ret int64) { switch whence { case 0: w.woff += int(offset) case 1: w.woff = int(offset) default: } return int64(w.woff) } func (w *MemDisk) Read(b []byte) (int, error) { n, err := w.ReadAt(b, int64(w.roff)) w.roff += n return n, err } func (w *MemDisk) Close() error { return nil } test-1.0.0/disk_test.go000066400000000000000000000004611423124715100150100ustar00rootroot00000000000000package test import ( "io" "testing" ) func TestMemDisk(t *testing.T) { defer New(t) md := NewMemDisk() WriteAt(md, []byte("hello"), 4) h := make([]byte, 5) n, err := md.ReadAt(h, 3) Equals(n, 5, err, nil, h, []byte("\x00hell")) { n, err := md.ReadAt(h, 10) Equals(n, 0, err, io.EOF) } } test-1.0.0/go.mod000066400000000000000000000001171423124715100135740ustar00rootroot00000000000000module github.com/chzyer/test go 1.15 require github.com/chzyer/logex v1.2.1 test-1.0.0/go.sum000066400000000000000000000002451423124715100136230ustar00rootroot00000000000000github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= test-1.0.0/test.go000066400000000000000000000202151423124715100137750ustar00rootroot00000000000000package test import ( "bytes" "crypto/rand" "fmt" "io" "io/ioutil" "os" "path/filepath" "reflect" "runtime" "strconv" "strings" "github.com/chzyer/logex" ) var ( mainRoot = "" RootPath = os.TempDir() ErrNotExcept = logex.Define("result not expect") ErrNotEqual = logex.Define("result not equals") ErrRequireNotEqual = logex.Define("result require not equals") StrNotSuchFile = "no such file or directory" ) func init() { println("tmpdir:", RootPath) } type testException struct { depth int info string } func (t *testException) String() string { return t.info } func getMainRoot() string { if mainRoot != "" { return mainRoot } cwd, err := os.Getwd() if err != nil { return "" } for len(cwd) > 1 { _, err := os.Stat(filepath.Join(cwd, ".git")) if err == nil { mainRoot = cwd + string([]rune{filepath.Separator}) break } cwd = filepath.Dir(cwd) } return mainRoot } func Skip() { panic(nil) } type Failer interface { FailNow() } func New(t Failer) { err := recover() if err == nil { return } te, ok := err.(*testException) if !ok { panic(err) } idx := -1 for i := 0; ; i++ { _, file, _, ok := runtime.Caller(i) if !ok { break } if strings.HasPrefix(file, getMainRoot()) { idx = i break } } _, file, line, _ := runtime.Caller(idx) if strings.HasPrefix(file, getMainRoot()) { file = file[len(getMainRoot()):] } println(fmt.Sprintf("%s:%d: %s", file, line, te.info)) t.FailNow() } func getErr(def error, e []error) error { if len(e) == 0 { return def } return e[0] } func ReadAt(r io.ReaderAt, b []byte, at int64) { n, err := r.ReadAt(b, at) if err != nil { Panic(0, fmt.Errorf("ReadAt error: %v", err)) } if n != len(b) { Panic(0, fmt.Errorf("ReadAt short read: %v, want: %v", n, len(b))) } } func ReadAndCheck(r io.Reader, b []byte) { buf := make([]byte, len(b)) Read(r, buf) equalBytes(1, buf, b) } func Read(r io.Reader, b []byte) { n, err := r.Read(b) if err != nil && !logex.Equal(err, io.EOF) { Panic(0, fmt.Errorf("Read error: %v", err)) } if n != len(b) { Panic(0, fmt.Errorf("Read: %v, want: %v", n, len(b))) } } func ReadStringAt(r io.ReaderAt, off int64, s string) { buf := make([]byte, len(s)) n, err := r.ReadAt(buf, off) buf = buf[:n] if err != nil { Panic(0, fmt.Errorf("ReadStringAt: %v", err)) } if string(buf) != s { Panic(0, fmt.Errorf( "ReadStringAt not match: %v, got: %v", strconv.Quote(s), strconv.Quote(string(buf)), )) } } func ReadString(r io.Reader, s string) { buf := make([]byte, len(s)) n, err := r.Read(buf) if err != nil && !logex.Equal(err, io.EOF) { Panic(0, fmt.Errorf("ReadString: %v, got: %v", strconv.Quote(s), err)) } if n != len(buf) { Panic(0, fmt.Errorf("ReadString: %v, got: %v", strconv.Quote(s), n)) } if string(buf) != s { Panic(0, fmt.Errorf( "ReadString not match: %v, got: %v", strconv.Quote(s), strconv.Quote(string(buf)), )) } } func WriteAt(w io.WriterAt, b []byte, at int64) { n, err := w.WriteAt(b, at) if err != nil { Panic(0, err) } if n != len(b) { Panic(0, "short write") } } func Write(w io.Writer, b []byte) { n, err := w.Write(b) if err != nil { Panic(0, err) } if n != len(b) { Panic(0, "short write") } } func WriteString(w io.Writer, s string) { n, err := w.Write([]byte(s)) if err != nil { Panic(0, err) } if n != len(s) { Panic(0, "short write") } } func Equals(o ...interface{}) { if len(o)%2 != 0 { Panic(0, "invalid Equals arguments") } for i := 0; i < len(o); i += 2 { equal(1, o[i], o[i+1], nil) } } func NotEqual(a, b interface{}, e ...error) { notEqual(1, a, b, e) } func toInt(a interface{}) (int64, bool) { switch n := a.(type) { case int: return int64(n), true case int8: return int64(n), true case int16: return int64(n), true case int32: return int64(n), true case int64: return int64(n), true case uintptr: return int64(n), true default: return -1, false } } func MarkLine() { r := strings.Repeat("-", 20) println(r) } var globalMarkInfo string func Mark(obj ...interface{}) { globalMarkInfo = fmt.Sprint(obj...) } func EqualBytes(got, want []byte) { equalBytes(0, got, want) } func equalBytes(n int, got, want []byte) { a := got b := want size := 16 if len(a) != len(b) { Panic(n, fmt.Sprintf("equal bytes, %v != %v", len(a), len(b))) } if bytes.Equal(a, b) { return } for off := 0; off < len(a); off += size { end := off + size if end > len(a) { end = len(a) } if !bytes.Equal(a[off:end], b[off:end]) { Panic(n, fmt.Sprintf( "equal [%v]byte in [%v, %v]:\n\tgot: %v\n\twant: %v", len(a), off, off+size, a[off:end], b[off:end], )) } } } func Equal(a, b interface{}, e ...error) { if ai, ok := toInt(a); ok { if bi, ok := toInt(b); ok { equal(1, ai, bi, e) return } } equal(1, a, b, e) } func CheckError(e error, s string) { if e == nil { Panic(0, ErrNotExcept) } if !strings.Contains(e.Error(), s) { Panic(0, fmt.Errorf( "want: %s, got %s", strconv.Quote(s), strconv.Quote(e.Error()), )) } } func formatMax(o interface{}, max int) string { aStr := fmt.Sprint(o) if len(aStr) > max { aStr = aStr[:max] + " ..." } return aStr } func notEqual(d int, a, b interface{}, e []error) { _, oka := a.(error) _, okb := b.(error) if oka && okb { if logex.Equal(a.(error), b.(error)) { Panic(d, fmt.Sprintf("%v: %v", getErr(ErrRequireNotEqual, e), a, )) } return } if reflect.DeepEqual(a, b) { Panic(d, fmt.Sprintf("%v: (%v, %v)", getErr(ErrRequireNotEqual, e), formatMax(a, 100), formatMax(b, 100), )) } } func equal(d int, a, b interface{}, e []error) { _, oka := a.(error) _, okb := b.(error) if oka && okb { if !logex.Equal(a.(error), b.(error)) { Panic(d, fmt.Sprintf("%v: (%v, %v)", getErr(ErrNotEqual, e), formatMax(a, 100), formatMax(b, 100), )) } return } result, ok := customEqual(a, b) if !ok { result = reflect.DeepEqual(a, b) } if !result { Panic(d, fmt.Sprintf("%v: (%+v, %+v)", getErr(ErrNotEqual, e), a, b)) } } func customEqual(a, b interface{}) (bool, bool) { typeA := reflect.TypeOf(a) typeB := reflect.TypeOf(b) if typeA != typeB { return false, false } method, ok := typeA.MethodByName("Equal") if !ok { return false, false } if method.Type.NumIn() != 2 || method.Type.In(0) != method.Type.In(1) || method.Type.NumOut() != 1 || method.Type.Out(0).Kind() != reflect.Bool { return false, false } result := method.Func.Call([]reflect.Value{reflect.ValueOf(a), reflect.ValueOf(b)}) return result[0].Bool(), true } func Should(b bool, e ...error) { if !b { Panic(0, getErr(ErrNotExcept, e)) } } func NotNil(obj interface{}) { if obj == nil { Panic(0, "should not nil") } } func False(obj bool) { if obj { Panic(0, "should false") } } func True(obj bool) { if !obj { Panic(0, "should true") } } func Nil(obj interface{}) { if obj != nil { // double check, incase different type with nil value if !reflect.ValueOf(obj).IsNil() { str := fmt.Sprint(obj) if err, ok := obj.(error); ok { str = logex.DecodeError(err) } Panic(0, fmt.Sprintf("should nil: %v", str)) } } } func Panic(depth int, obj interface{}) { t := &testException{ depth: depth, } if err, ok := obj.(error); ok { t.info = logex.DecodeError(err) } else { t.info = fmt.Sprint(obj) } if globalMarkInfo != "" { t.info = "[info:" + globalMarkInfo + "] " + t.info } panic(t) } func CleanTmp() { os.RemoveAll(root(2)) } func TmpFile() (*os.File, error) { dir := root(2) if err := os.MkdirAll(dir, 0744); err != nil { return nil, err } return ioutil.TempFile(dir, "") } func Root() string { p := root(2) os.RemoveAll(root(2)) return p } func root(n int) string { pc, _, _, _ := runtime.Caller(n) name := runtime.FuncForPC(pc).Name() if idx := strings.LastIndex(name, "."); idx > 0 { name = name[:idx] + "/" + name[idx+1:] } root := os.Getenv("TEST_ROOT") if root == "" { root = RootPath } return filepath.Join(root, name) } func RandBytes(n int) []byte { buf := make([]byte, n) rand.Read(buf) return buf } func SeqBytes(n int) []byte { buf := make([]byte, n) for idx := range buf { buf[idx] = byte(idx) } return buf }