pax_global_header00006660000000000000000000000064136222750240014515gustar00rootroot0000000000000052 comment=b3fa7030120c6cf11c07fd52e8b58b5b1ed98e49 go-assert-1.1.5/000077500000000000000000000000001362227502400134255ustar00rootroot00000000000000go-assert-1.1.5/.gitignore000066400000000000000000000004301362227502400154120ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof .vscode debuggo-assert-1.1.5/.travis.yml000066400000000000000000000000151362227502400155320ustar00rootroot00000000000000language: go go-assert-1.1.5/LICENSE000066400000000000000000000020631362227502400144330ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2017 Huan Du 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. go-assert-1.1.5/README.md000066400000000000000000000072571362227502400147170ustar00rootroot00000000000000# Package `assert` - Magic assert macros for Go # [![Build Status](https://travis-ci.org/huandu/go-assert.svg?branch=master)](https://travis-ci.org/huandu/go-assert) [![GoDoc](https://godoc.org/github.com/huandu/go-assert?status.svg)](https://godoc.org/github.com/huandu/go-assert) Package `assert` provides developer a way to assert expression and output useful contextual information automatically when a case fails. With this package, we can focus on writing test code without worrying about how to print lots of verbose debug information for debug. Here is a quick sample. ```go import "github.com/huandu/go-assert" func TestSomething(t *testing.T) { str := Foo(42) assert.Assert(t, str == "expected") // This case fails with following message. // // Assertion failed: // str == "expected" // Referenced variables are assigned in following statements: // str := Foo(42) } ``` ## Import ## Use `go get` to install this package. go get github.com/huandu/go-assert Current stable version is `v1.*`. Old versions tagged by `v0.*` are obsoleted. ## Usage ## ### Assertion methods ### If we just want to use functions like `Assert`, `Equal` or `NotEqual`, it's recommended to import this package as `.`. ```go import "github.com/huandu/go-assert" func TestSomething(t *testing.T) { a, b := 1, 2 assert.Assert(t, a > b) // This case fails with message: // Assertion failed: // a > b } func TestAssertEquality(t *testing.T) { assert.Equal(t, map[string]int{ "foo": 1, "bar": -2, }, map[string]int{ "bar": -2, "foo": 10000, }) // This case fails with message: // Assertion failed: // The value of following expression should equal. // [1] map[string]int{ // "foo": 1, // "bar": -2, // } // [2] map[string]int{ // "bar": -2, // "foo": 10000, // } // Values: // [1] -> (map[string]int)map[bar:-2 foo:1] // [2] -> (map[string]int)map[bar:-2 foo:10000] } ``` ### Advanced assertion wrapper: type `A` ### If we want more controls on assertion, it's recommended to wrap `t` in an `A`. There are lots of useful assert methods implemented in `A`. * [`Assert`](https://godoc.org/github.com/huandu/go-assert#A.Assert)/[`Eqaul`](https://godoc.org/github.com/huandu/go-assert#A.Equal)/[`NotEqual`](https://godoc.org/github.com/huandu/go-assert#A.NotEqual): Basic assertion methods. * [`NilError`](https://godoc.org/github.com/huandu/go-assert#A.NilError)/[`NonNilError`](https://godoc.org/github.com/huandu/go-assert#A.NonNilError): Test if a func/method returns expected error. * [`Use`](https://godoc.org/github.com/huandu/go-assert#A.Use): Track variables. If any assert method fails, all variables tracked by `A` and related in assert method will be printed out automatically in assertion message. Here is a sample to demonstrate how to use `A#Use` to print related variables in assertion message. ```go import "github.com/huandu/go-assert" func TestSomething(t *testing.T) { a := assert.New(t) v1 := 123 v2 := []string{"wrong", "right"} v3 := v2[0] v4 := "not related" a.Use(&v1, &v2, &v3, &v4) a.Assert(v1 == 123 && v3 == "right") // This case fails with following message. // // Assertion failed: // v1 == 123 && v3 == "right" // Referenced variables are assigned in following statements: // v1 := 123 // v3 := v2[0] // Related variables: // v1 -> (int)123 // v2 -> ([]string)[wrong right] // v3 -> (string)wrong } ```go-assert-1.1.5/a.go000066400000000000000000000127161362227502400142030ustar00rootroot00000000000000// Copyright 2017 Huan Du. All rights reserved. // Licensed under the MIT license that can be found in the LICENSE file. package assert import ( "bytes" "go/ast" "go/printer" "go/token" "reflect" "testing" "github.com/huandu/go-assert/internal/assertion" ) // The A is a wrapper of testing.T with some extra help methods. type A struct { *testing.T vars map[string]interface{} parser *assertion.Parser } // New creates an assertion object wraps t. func New(t *testing.T) *A { return &A{ T: t, vars: make(map[string]interface{}), parser: new(assertion.Parser), } } // Assert tests expr and call `t.Fatalf` to terminate test case if expr is false-equivalent value. // `false`, 0, nil and empty string are false-equivalent values. // // Sample code. // // func TestSomething(t *testing.T) { // a := assert.New(t) // x, y := 1, 2 // a.Assert(x > y) // } // // Output: // // Assertion failed: // x > y // Referenced variables are assigned in following statements: // x, y := 1, 2 func (a *A) Assert(expr interface{}) { assertion.Assert(a.T, expr, &assertion.Trigger{ Parser: a.parser, FuncName: "Assert", Skip: 1, Args: []int{0}, Vars: a.vars, }) } // NilError expects a function return a nil error. // Otherwise, it will terminate the test case using `t.Fatalf`. // // Sample code. // // func TestSomething(t *testing.T) { // a := assert.New(t) // a.NilError(os.Open("path/to/a/file")) // } // // Output: // // Assertion failed: // Following expression should return a nil error. // os.Open("path/to/a/file") // The error is: // open path/to/a/file: no such file or directory func (a *A) NilError(result ...interface{}) { assertion.AssertNilError(a.T, result, &assertion.Trigger{ Parser: a.parser, FuncName: "NilError", Skip: 1, Args: []int{-1}, Vars: a.vars, }) } // NonNilError expects a function return a non-nil error. // Otherwise, it will terminate the test case using `t.Fatalf`. // // Sample code. // // func TestSomething(t *testing.T) { // a := assert.New(t) // f := func() (int, error) { return 0, errors.New("expected") } // a.NilError(f()) // } // // Output: // // Assertion failed: // Following expression should return a nil error. // f() // f := func() (int, error) { return 0, errors.New("expected") } // The error is: // expected func (a *A) NonNilError(result ...interface{}) { assertion.AssertNonNilError(a.T, result, &assertion.Trigger{ Parser: a.parser, FuncName: "NonNilError", Skip: 1, Args: []int{-1}, Vars: a.vars, }) } // Equal uses `reflect.DeepEqual` to test v1 and v2 equality. // // Sample code. // // func TestSomething(t *testing.T) { // a := assert.New(t) // a.Equal([]int{1,2}, []int{1}) // } // // Output: // // Assertion failed: // a.Equal([]int{1, 2}, []int{1}) // The value of following expression should equal. // [1] []int{1, 2} // [2] []int{1} // Values: // [1] -> ([]int)[1 2] // [2] -> ([]int)[1] func (a *A) Equal(v1, v2 interface{}) { assertion.AssertEqual(a.T, v1, v2, &assertion.Trigger{ Parser: a.parser, FuncName: "Equal", Skip: 1, Args: []int{0, 1}, Vars: a.vars, }) } // NotEqual uses `reflect.DeepEqual` to test v1 and v2 equality. // // Sample code. // // func TestSomething(t *testing.T) { // a := assert.New(t) // a.NotEqual(t, []int{1}, []int{1}) // } // // Output: // // Assertion failed: // a.NotEqual(t, []int{1}, []int{1}) // The value of following expression should not equal. // [1] []int{1} // [2] []int{1} func (a *A) NotEqual(v1, v2 interface{}) { assertion.AssertNotEqual(a.T, v1, v2, &assertion.Trigger{ Parser: a.parser, FuncName: "NotEqual", Skip: 1, Args: []int{0, 1}, Vars: a.vars, }) } // Use saves args in context and prints related args automatically in assertion method when referenced. // // Sample code. // // func TestSomething(t *testing.T) { // a := assert.New(t) // v1 := 123 // v2 := []string{"wrong", "right"} // v3 := v2[0] // v4 := "not related" // a.Use(&v1, &v2, &v3, &v4) // } // // Output: // // Assertion failed: // v1 == 123 && v3 == "right" // Referenced variables are assigned in following statements: // v1 := 123 // v3 := v2[0] // Related variables: // v1 = (int)123 // v3 = (string)wrong func (a *A) Use(args ...interface{}) { if len(args) == 0 { return } argIndex := make([]int, 0, len(args)) values := make([]interface{}, 0, len(args)) for i := range args { if args[i] == nil { continue } val := reflect.ValueOf(args[i]) if val.Kind() != reflect.Ptr { continue } val = val.Elem() if !val.IsValid() { continue } argIndex = append(argIndex, i) values = append(values, args[i]) } if len(argIndex) == 0 { return } f, err := a.parser.ParseArgs("Use", 1, argIndex) if err != nil { return } for i, arg := range f.Args { // Arg must be something like `&a` or `&a.b`. // Otherwise, ignore the arg. expr, ok := arg.(*ast.UnaryExpr) if !ok || expr.Op != token.AND { continue } if !assertion.IsVar(expr.X) { continue } buf := &bytes.Buffer{} printer.Fprint(buf, f.FileSet, expr.X) a.vars[buf.String()] = values[i] } a.parser.AddExcluded(f.Caller) } go-assert-1.1.5/assert.go000066400000000000000000000076741362227502400152730ustar00rootroot00000000000000// Copyright 2017 Huan Du. All rights reserved. // Licensed under the MIT license that can be found in the LICENSE file. // Package assert provides developer a way to assert expression and output useful contextual information automatically when a case fails. // With this package, we can focus on writing test code without worrying about how to print lots of verbose debug information for debug. // // See project page for more samples. // https://github.com/huandu/go-assert package assert import ( "testing" "github.com/huandu/go-assert/internal/assertion" ) // Assert tests expr and call `t.Fatalf` to terminate test case if expr is false-equivalent value. // `false`, 0, nil and empty string are false-equivalent values. // // Sample code. // // import "github.com/huandu/go-assert" // // func TestSomething(t *testing.T) { // a, b := 1, 2 // assert.Assert(t, a > b) // } // // Output: // // Assertion failed: // a > b // Referenced variables are assigned in following statements: // a, b := 1, 2 func Assert(t *testing.T, expr interface{}) { assertion.Assert(t, expr, &assertion.Trigger{ FuncName: "Assert", Skip: 1, Args: []int{1}, }) } // Equal uses `reflect.DeepEqual` to test v1 and v2 equality. // // Sample code. // // import "github.com/huandu/go-assert" // // func TestSomething(t *testing.T) { // assert.Equal(t, []int{1,2}, []int{1}) // } // // Output: // // Assertion failed: // assert.Equal(t, []int{1, 2}, []int{1}) // The value of following expression should equal. // [1] []int{1, 2} // [2] []int{1} // Values: // [1] -> ([]int)[1 2] // [2] -> ([]int)[1] func Equal(t *testing.T, v1, v2 interface{}) { assertion.AssertEqual(t, v1, v2, &assertion.Trigger{ FuncName: "Equal", Skip: 1, Args: []int{1, 2}, }) } // NotEqual uses `reflect.DeepEqual` to test v1 and v2 equality. // // Sample code. // // import "github.com/huandu/go-assert" // // func TestSomething(t *testing.T) { // assert.NotEqual(t, []int{1}, []int{1}) // } // // Output: // // Assertion failed: // assert.NotEqual(t, []int{1}, []int{1}) // The value of following expression should not equal. // [1] []int{1} // [2] []int{1} func NotEqual(t *testing.T, v1, v2 interface{}) { assertion.AssertNotEqual(t, v1, v2, &assertion.Trigger{ FuncName: "NotEqual", Skip: 1, Args: []int{1, 2}, }) } // AssertEqual uses `reflect.DeepEqual` to test v1 and v2 equality. // // Note: as golint dislike the name of this function, // it will be removed in the future. Use Equal instead. // // Sample code. // // import "github.com/huandu/go-assert" // // func TestSomething(t *testing.T) { // assert.AssertEqual(t, []int{1,2}, []int{1}) // } // // Output: // // Assertion failed: // assert.AssertEqual(t, []int{1, 2}, []int{1}) // The value of following expression should equal. // [1] []int{1, 2} // [2] []int{1} // Values: // [1] -> ([]int)[1 2] // [2] -> ([]int)[1] func AssertEqual(t *testing.T, v1, v2 interface{}) { assertion.AssertEqual(t, v1, v2, &assertion.Trigger{ FuncName: "AssertEqual", Skip: 1, Args: []int{1, 2}, }) } // AssertNotEqual uses `reflect.DeepEqual` to test v1 and v2 equality. // // Note: as golint dislike the name of this function, // it will be removed in the future. Use NotEqual instead. // // Sample code. // // import "github.com/huandu/go-assert" // // func TestSomething(t *testing.T) { // assert.AssertNotEqual(t, []int{1}, []int{1}) // } // // Output: // // Assertion failed: // assert.AssertNotEqual(t, []int{1}, []int{1}) // The value of following expression should not equal. // [1] []int{1} // [2] []int{1} func AssertNotEqual(t *testing.T, v1, v2 interface{}) { assertion.AssertNotEqual(t, v1, v2, &assertion.Trigger{ FuncName: "AssertNotEqual", Skip: 1, Args: []int{1, 2}, }) } go-assert-1.1.5/assert_test.go000066400000000000000000000062411362227502400163170ustar00rootroot00000000000000// Copyright 2017 Huan Du. All rights reserved. // Licensed under the MIT license that can be found in the LICENSE file. package assert import ( "errors" "os" "strings" "testing" ) // TestMain hacks the testing process and runs cases only if flag -test.run is specified. // Due to the nature of this package, all "successful" cases will always fail. // With this hack, we can run selected case manually without breaking travis-ci system. func TestMain(m *testing.M) { for _, arg := range os.Args[1:] { if strings.HasPrefix(arg, "-test.run") { os.Exit(m.Run()) return } } } func TestAssertCompareExpr(t *testing.T) { a, b := 1, 2 Assert(t, a > b) } func TestAssertIdent(t *testing.T) { a := 0 Assert(t, a) } func TestAssertNilErrorFunctionCall(t *testing.T) { a := New(t) f := func(string, int) (float32, bool, error) { return 12, true, nil } a.NilError(f("should pass", 0)) f = func(string, int) (float32, bool, error) { return 0, false, errors.New("expected") } a.NilError(f("should fail", 42)) } func TestAssertNonNilErrorFunctionCall(t *testing.T) { a := New(t) f := func(string, int) (float32, bool, error) { return 12, true, errors.New("should pass") } a.NonNilError(f("should pass", 0)) f = func(string, int) (float32, bool, error) { return 0, false, nil } a.NonNilError(f("should fail", 42)) } func TestAssertEquality(t *testing.T) { Equal(t, map[string]int{ "foo": 1, "bar": -2, }, map[string]int{ "bar": -2, "foo": 1, }) Equal(t, map[string]int{ "foo": 1, "bar": -2, }, map[string]int{ "bar": -2, "foo": 10000, }) } func TestAssertEqualityTypeMismatch(t *testing.T) { v1 := struct { Foo string Bar int }{"should pass", 1} v2 := struct { Foo string Bar int }{"should pass", 1} Equal(t, v1, v2) v3 := []int{1, 2, 3} v4 := []int64{1, 2, 3} Equal(t, v3, v4) } func TestAssertEqualityWithAssertion(t *testing.T) { a := New(t) a.Equal(map[string]int{ "foo": 1, "bar": -2, }, map[string]int{ "bar": -2, "foo": 1, }) a.Equal(map[string]int{ "foo": 1, "bar": -2, }, map[string]int{ "bar": -2, "foo": 10000, }) } func TestAssertEqualityTypeMismatchWithAssertion(t *testing.T) { a := New(t) v1 := struct { Foo string Bar int }{"should pass", 1} v2 := struct { Foo string Bar int }{"should pass", 1} a.Equal(v1, v2) v3 := []int{1, 2, 3} v4 := []int64{1, 2, 3} a.Equal(v3, v4) } func TestAssertNotEqual(t *testing.T) { v1 := struct { Foo string Bar int }{"should pass", 1} v2 := struct { Bar int Foo string }{1, "should pass"} NotEqual(t, v1, v2) v3 := []int{1, 2, 3} v4 := []int{1, 2, 3} NotEqual(t, v3, v4) } func TestAssertNotEqualWithAssertion(t *testing.T) { a := New(t) v1 := struct { Foo string Bar int }{"should pass", 1} v2 := struct { Bar int Foo string }{1, "should pass"} a.NotEqual(v1, v2) v3 := []int{1, 2, 3} v4 := []int{1, 2, 3} a.NotEqual(v3, v4) } func TestUse(t *testing.T) { a := New(t) v1 := 123 v2 := []string{"foo", "bar"} v3 := v2[0] a.Use(v1, &v2) // v2 is used but v1 is not used due to missing `&`. // Should pass. a.Assert(v1 == 123 && v3 == "foo") // Should fail. v1 = 345 v3 = v2[1] a.Assert(v1 > 123 && v3 != "bar") } go-assert-1.1.5/go.mod000066400000000000000000000002001362227502400145230ustar00rootroot00000000000000module github.com/huandu/go-assert go 1.13 require ( github.com/davecgh/go-spew v1.1.1 github.com/stretchr/testify v1.4.0 ) go-assert-1.1.5/go.sum000066400000000000000000000016741362227502400145700ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= go-assert-1.1.5/internal/000077500000000000000000000000001362227502400152415ustar00rootroot00000000000000go-assert-1.1.5/internal/assertion/000077500000000000000000000000001362227502400172505ustar00rootroot00000000000000go-assert-1.1.5/internal/assertion/assertion.go000066400000000000000000000273421362227502400216160ustar00rootroot00000000000000// Copyright 2017 Huan Du. All rights reserved. // Licensed under the MIT license that can be found in the LICENSE file. // Package assertion is the implementation detail of package assert. // One can use API to create a customized assert function with this package package assertion import ( "reflect" "strings" "testing" "unsafe" "github.com/davecgh/go-spew/spew" ) // Trigger represents the method which triggers assertion. type Trigger struct { Parser *Parser FuncName string Skip int Args []int Vars map[string]interface{} } // P returns a valid parser. func (t *Trigger) P() *Parser { if t.Parser != nil { return t.Parser } return &Parser{} } // Assert tests expr and call `t.Fatalf` to terminate test case if expr is false-equivalent value. func Assert(t *testing.T, expr interface{}, trigger *Trigger) { k := ParseFalseKind(expr) if k == Positive { return } f, err := trigger.P().ParseArgs(trigger.FuncName, trigger.Skip+1, trigger.Args) if err != nil { t.Fatalf("Assertion failed with an internal error: %v", err) return } info := trigger.P().ParseInfo(f) suffix := "" arg := info.Args[0] if !strings.ContainsRune(arg, ' ') { switch k { case Nil: suffix = " != nil" case False: suffix = " != true" case Zero: suffix = " != 0" case EmptyString: suffix = ` != ""` } } assignment := indentAssignments(info.Assignments[0], 4) if assignment != "" { assignment = "\nReferenced variables are assigned in following statements:" + assignment } t.Fatalf("\n%v:%v: Assertion failed:\n %v%v%v%v", f.Filename, f.Line, indentCode(arg, 4), suffix, assignment, formatRelatedVars(info.RelatedVars, trigger.Vars), ) } // AssertEqual uses `reflect.DeepEqual` to test v1 and v2 equality. func AssertEqual(t *testing.T, v1, v2 interface{}, trigger *Trigger) { if reflect.DeepEqual(v1, v2) { return } typeMismatch := false if v1 != nil && v2 != nil { t1 := reflect.TypeOf(v1) t2 := reflect.TypeOf(v2) if !t1.AssignableTo(t2) && !t2.AssignableTo(t1) { typeMismatch = true } } else { v1Val := reflect.ValueOf(v1) v2Val := reflect.ValueOf(v2) // Treat (*T)(nil) as nil. if isNil(v1Val) && isNil(v2Val) { return } } f, err := trigger.P().ParseArgs(trigger.FuncName, trigger.Skip+1, trigger.Args) if err != nil { t.Fatalf("Assertion failed with an internal error: %v", err) return } info := trigger.P().ParseInfo(f) config := &spew.ConfigState{ DisableMethods: true, DisablePointerMethods: true, DisablePointerAddresses: true, DisableCapacities: true, SortKeys: true, SpewKeys: true, } v1Dump := config.Sprintf("%#v", v1) v2Dump := config.Sprintf("%#v", v2) msg := "The value of following expression should equal." if typeMismatch { msg = "The type of following expressions should be the same." } t.Fatalf("\n%v:%v: Assertion failed:\n %v\n%v\n[1] %v%v\n[2] %v%v\nValues:\n[1] -> %v\n[2] -> %v%v", f.Filename, f.Line, indentCode(info.Source, 4), msg, indentCode(info.Args[0], 4), indentAssignments(info.Assignments[0], 4), indentCode(info.Args[1], 4), indentAssignments(info.Assignments[1], 4), v1Dump, v2Dump, formatRelatedVars(info.RelatedVars, trigger.Vars), ) } func isNil(val reflect.Value) bool { switch val.Kind() { case reflect.Invalid: return true case reflect.Interface, reflect.Chan, reflect.Func, reflect.Slice, reflect.Map, reflect.Ptr: return val.IsNil() } return false } // AssertNotEqual uses `reflect.DeepEqual` to test v1 and v2 equality. func AssertNotEqual(t *testing.T, v1, v2 interface{}, trigger *Trigger) { if !reflect.DeepEqual(v1, v2) { return } f, err := trigger.P().ParseArgs(trigger.FuncName, trigger.Skip+1, trigger.Args) if err != nil { t.Fatalf("Assertion failed with an internal error: %v", err) return } info := trigger.P().ParseInfo(f) t.Fatalf("\n%v:%v: Assertion failed:\n %v\nThe value of following expression should not equal.\n[1] %v%v\n[2] %v%v%v", f.Filename, f.Line, indentCode(info.Source, 4), indentCode(info.Args[0], 4), indentAssignments(info.Assignments[0], 4), indentCode(info.Args[1], 4), indentAssignments(info.Assignments[1], 4), formatRelatedVars(info.RelatedVars, trigger.Vars), ) } // AssertNilError expects a function return a nil error. // Otherwise, it will terminate the test case using `t.Fatalf`. func AssertNilError(t *testing.T, result []interface{}, trigger *Trigger) { if len(result) == 0 { return } pos := len(result) - 1 e := result[pos] if ee, ok := e.(error); !ok || ee == nil { return } f, err := trigger.P().ParseArgs(trigger.FuncName, trigger.Skip+1, trigger.Args) if err != nil { t.Fatalf("Assertion failed with an internal error: %v", err) return } info := trigger.P().ParseInfo(f) t.Fatalf("\n%v:%v: Assertion failed:\nFollowing expression should return a nil error.\n %v%v\nThe error is:\n %v%v", f.Filename, f.Line, indentCode(info.Args[0], 4), indentAssignments(info.Assignments[0], 4), e, formatRelatedVars(info.RelatedVars, trigger.Vars), ) } // AssertNonNilError expects a function return a non-nil error. // Otherwise, it will terminate the test case using `t.Fatalf`. func AssertNonNilError(t *testing.T, result []interface{}, trigger *Trigger) { if len(result) == 0 { return } pos := len(result) - 1 e := result[pos] if e != nil { if _, ok := e.(error); !ok { return } if v := reflect.ValueOf(e); !v.IsNil() { return } } f, err := trigger.P().ParseArgs(trigger.FuncName, trigger.Skip+1, trigger.Args) if err != nil { t.Fatalf("Assertion failed with an internal error: %v", err) return } info := trigger.P().ParseInfo(f) t.Fatalf("\n%v:%v: Assertion failed:\nFollowing expression should return an error.\n %v%v%v", f.Filename, f.Line, indentCode(info.Args[0], 4), indentAssignments(info.Assignments[0], 4), formatRelatedVars(info.RelatedVars, trigger.Vars), ) } func indentCode(code string, spaces int) string { if code == "" { return "" } lines := strings.Split(code, "\n") indented := make([]string, 0, len(lines)) space := strings.Repeat(" ", spaces) indented = append(indented, lines[0]) lines = lines[1:] for _, line := range lines { indented = append(indented, space+line) } return strings.Join(indented, "\n") } func indentAssignments(assignments []string, spaces int) string { if len(assignments) == 0 { return "" } space := strings.Repeat(" ", spaces) output := make([]string, 0) output = append(output, "") // Add a newline at the front. for _, code := range assignments { lines := strings.Split(code, "\n") indented := make([]string, 0, len(lines)) indented = append(indented, space+lines[0]) lines = lines[1:] for _, line := range lines { indented = append(indented, space+line) } output = append(output, indented...) } return strings.Join(output, "\n") } func formatRelatedVars(related []string, vars map[string]interface{}) string { if len(related) == 0 || len(vars) == 0 { return "" } values := make([]interface{}, 0, len(related)) names := make([]string, 0, len(related)) fields := make([]string, 0, len(related)) for _, name := range related { if v, ok := vars[name]; ok { values = append(values, v) names = append(names, name) fields = append(fields, "") continue } parts := strings.Split(name, ".") parts = parts[:len(parts)-1] for len(parts) > 0 { n := strings.Join(parts, ".") if v, ok := vars[n]; ok { values = append(values, v) names = append(names, n) fields = append(fields, name[len(n)+1:]) break } parts = parts[:len(parts)-1] } } if len(values) == 0 { return "" } config := &spew.ConfigState{ DisableMethods: true, DisablePointerMethods: true, DisablePointerAddresses: true, DisableCapacities: true, SortKeys: true, SpewKeys: true, } lines := make([]string, 0, len(values)+1) lines = append(lines, "\nRelated variables:") visitedNames := map[string]struct{}{} for i, v := range values { val := reflect.ValueOf(v) if !val.IsValid() || val.Kind() != reflect.Ptr { continue } val = val.Elem() field, v, ok := getValue(fields[i], val) if !ok { continue } name := names[i] if field != "" { name += "." + field } if _, ok := visitedNames[name]; ok { continue } lines = append(lines, config.Sprintf(" "+name+" = %#v", v)) visitedNames[name] = struct{}{} } // No valid related variables. if len(lines) == 1 { return "" } return strings.Join(lines, "\n") } func getValue(field string, v reflect.Value) (actualField string, value interface{}, ok bool) { if field == "" { value = getValueInterface(v) ok = true return } for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { v = v.Elem() } if !v.IsValid() { return } if v.Kind() != reflect.Struct { value = getValueInterface(v) ok = true return } parts := strings.Split(field, ".") f := v.FieldByName(parts[0]) if !f.IsValid() { value = getValueInterface(v) ok = true return } actual, value, ok := getValue(strings.Join(parts[1:], "."), f) if !ok { return } actualField = parts[0] if actual != "" { actualField += "." + actual } return } func getValueInterface(v reflect.Value) interface{} { if v.CanInterface() { return v.Interface() } // src is an unexported field value. Copy its value. switch v.Kind() { case reflect.Bool: return v.Bool() case reflect.Int: return int(v.Int()) case reflect.Int8: return int8(v.Int()) case reflect.Int16: return int16(v.Int()) case reflect.Int32: return int32(v.Int()) case reflect.Int64: return v.Int() case reflect.Uint: return uint(v.Uint()) case reflect.Uint8: return uint8(v.Uint()) case reflect.Uint16: return uint16(v.Uint()) case reflect.Uint32: return uint32(v.Uint()) case reflect.Uint64: return v.Uint() case reflect.Uintptr: return uintptr(v.Uint()) case reflect.Float32: return float32(v.Float()) case reflect.Float64: return v.Float() case reflect.Complex64: return complex64(v.Complex()) case reflect.Complex128: return v.Complex() case reflect.Array: arr := reflect.New(v.Type()).Elem() num := v.Len() for i := 0; i < num; i++ { arr.Index(i).Set(reflect.ValueOf(getValueInterface(v.Index(i)))) } return arr.Interface() case reflect.Chan: ch := reflect.MakeChan(v.Type(), v.Cap()) return ch.Interface() case reflect.Func: // src.Pointer is the PC address of a func. pc := reflect.New(reflect.TypeOf(uintptr(0))) pc.Elem().SetUint(uint64(v.Pointer())) fn := reflect.New(v.Type()) *(*uintptr)(unsafe.Pointer(fn.Pointer())) = pc.Pointer() return fn.Elem().Interface() case reflect.Interface: iface := reflect.New(v.Type()) *(*[2]uintptr)(unsafe.Pointer(iface.Pointer())) = v.InterfaceData() return iface.Elem().Interface() case reflect.Map: m := reflect.MakeMap(v.Type()) keys := v.MapKeys() for _, key := range keys { m.SetMapIndex(key, reflect.ValueOf(getValueInterface(v.MapIndex(key)))) } return m.Interface() case reflect.Ptr: ptr := reflect.New(v.Type()) *(*uintptr)(unsafe.Pointer(ptr.Pointer())) = v.Pointer() return ptr.Elem().Interface() case reflect.Slice: slice := reflect.MakeSlice(v.Type(), v.Len(), v.Cap()) num := v.Len() for i := 0; i < num; i++ { slice.Index(i).Set(reflect.ValueOf(getValueInterface(v.Index(i)))) } return slice.Interface() case reflect.String: return v.String() case reflect.Struct: st := reflect.New(v.Type()).Elem() num := v.NumField() for i := 0; i < num; i++ { st.Field(i).Set(reflect.ValueOf(getValueInterface(v.Field(i)))) } return st.Interface() case reflect.UnsafePointer: ptr := reflect.New(v.Type()) *(*uintptr)(unsafe.Pointer(ptr.Pointer())) = v.Pointer() return ptr.Elem().Interface() } panic("go-assert: never be here") } go-assert-1.1.5/internal/assertion/falsekind.go000066400000000000000000000025201362227502400215360ustar00rootroot00000000000000package assertion import ( "reflect" ) // FalseKind is the kind of a false-equivalent value. type FalseKind int // Valid kinds for all false-equivalent values. const ( Positive FalseKind = iota Nil False Zero EmptyString ) // ParseFalseKind checks expr value and return false when expr is `false`, 0, `nil` and empty string. // Otherwise, return true. func ParseFalseKind(expr interface{}) FalseKind { if expr == nil { return Nil } if v, ok := expr.(bool); ok && !v { return False } v := reflect.ValueOf(expr) for { switch v.Kind() { case reflect.Invalid: return Nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if n := v.Int(); n == 0 { return Zero } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if n := v.Uint(); n == 0 { return Zero } case reflect.Float32, reflect.Float64: if n := v.Float(); n == 0 { return Zero } case reflect.Complex64, reflect.Complex128: if n := v.Complex(); n == 0 { return Zero } case reflect.String: if s := v.String(); s == "" { return EmptyString } case reflect.Interface: if v.IsNil() { return Nil } v = v.Elem() continue case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Slice: if v.IsNil() { return Nil } } return Positive } } go-assert-1.1.5/internal/assertion/parser.go000066400000000000000000000301751362227502400211010ustar00rootroot00000000000000package assertion import ( "bytes" "fmt" "go/ast" "go/parser" "go/printer" "go/token" "os" "path" "runtime" "sort" "strings" "sync" ) // Parser represents a source file parser. type Parser struct { m sync.Mutex // Excluded call exprs should be excluded when finding assignments. excluded []*ast.CallExpr } // Info represents code analysis information of an assertion function. type Info struct { Source string // Source code of the caller. Args []string // Selected arguments. // The last assignments related to Args. // The len(Assignments) is guaranteed to be the same as len(Args). Assignments [][]string // RelatedVars is the list of variables which are referenced in argument expression // or in the assignment statements containing arguments. // For instance, consider following code. // // for i, c := range cases { // a := 1 // Assert(t, a+1 == c.Value) // } // // After parsing `Assert`, RelatedVars contains `a`, `c.Value` and `i`. // Note that, `i` is listed in related vars because of the value of `i` is assigned in // `i, c := range cases` in which `c` is also assigned. RelatedVars []string } // Func represents AST information of an assertion function. type Func struct { FileSet *token.FileSet Func *ast.FuncDecl Caller *ast.CallExpr Args []ast.Expr Filename string Line int } // ParseArgs parses caller's source code, finds out the right call expression by name // and returns the argument source AST. // // Skip is the stack frame calling an assert function. If skip is 0, the stack frame for // ParseArgs is selected. // In most cases, caller should set skip to 1 to skip ParseArgs itself. func (p *Parser) ParseArgs(name string, skip int, argIndex []int) (f *Func, err error) { if len(argIndex) == 0 { err = fmt.Errorf("missing argIndex") return } filename, line, err := findCaller(skip + 1) if err != nil { return } dotIdx := strings.LastIndex(name, ".") if dotIdx >= 0 { name = name[dotIdx+1:] } fset, parsedAst, err := parseFile(filename) filename = path.Base(filename) if err != nil { return } var funcDecl *ast.FuncDecl var caller *ast.CallExpr argExprs := make([]ast.Expr, 0, len(argIndex)) maxArgIdx := 0 for _, idx := range argIndex { if idx > maxArgIdx { maxArgIdx = idx } } // Inspect AST and find target function at target line. done := false ast.Inspect(parsedAst, func(node ast.Node) bool { if node == nil || done { return false } if decl, ok := node.(*ast.FuncDecl); ok { funcDecl = decl return true } call, ok := node.(*ast.CallExpr) if !ok { return true } var fn string switch expr := call.Fun.(type) { case *ast.Ident: fn = expr.Name case *ast.SelectorExpr: fn = expr.Sel.Name } if fn != name { return true } pos := fset.Position(call.Pos()) posEnd := fset.Position(call.End()) if line < pos.Line || line > posEnd.Line { return true } caller = call for _, idx := range argIndex { if idx < 0 { idx += len(call.Args) } if idx < 0 || idx >= len(call.Args) { // Ignore invalid idx. argExprs = append(argExprs, nil) continue } arg := call.Args[idx] argExprs = append(argExprs, arg) } done = true return false }) f = &Func{ FileSet: fset, Func: funcDecl, Caller: caller, Args: argExprs, Filename: filename, Line: line, } return } // ParseInfo returns more context related information about this f. // See document of Info for details. func (p *Parser) ParseInfo(f *Func) (info *Info) { fset := f.FileSet args := make([]string, 0, len(f.Args)) assignments := make([][]string, 0, len(f.Args)) relatedVars := make(map[string]struct{}) // If args contains any arg which is an ident, find out where it's assigned. for _, arg := range f.Args { assigns, related := findAssignments(fset, f.Func, f.Line, arg, p.excluded) args = append(args, formatNode(fset, arg)) assignments = append(assignments, assigns) for v := range related { relatedVars[v] = struct{}{} } } vars := make([]string, 0, len(relatedVars)) for v := range relatedVars { vars = append(vars, v) } sort.Strings(vars) info = &Info{ Source: formatNode(fset, f.Caller), Args: args, Assignments: assignments, RelatedVars: vars, } return } func findCaller(skip int) (filename string, line int, err error) { const minimumSkip = 2 // Skip 2 frames running runtime functions. pc := make([]uintptr, 1) n := runtime.Callers(skip+minimumSkip, pc) if n == 0 { err = fmt.Errorf("fail to read call stack") return } pc = pc[:n] frames := runtime.CallersFrames(pc) frame, _ := frames.Next() filename = frame.File line = frame.Line if filename == "" || line == 0 { err = fmt.Errorf("fail to read source code information") } return } type fileAST struct { FileSet *token.FileSet File *ast.File } var ( fileCacheLock sync.Mutex fileCache = map[string]*fileAST{} ) func parseFile(filename string) (fset *token.FileSet, f *ast.File, err error) { fileCacheLock.Lock() fa, ok := fileCache[filename] fileCacheLock.Unlock() if ok { fset = fa.FileSet f = fa.File return } file, err := os.Open(filename) if err != nil { return } defer file.Close() fset = token.NewFileSet() f, err = parser.ParseFile(fset, filename, file, 0) fileCacheLock.Lock() fileCache[filename] = &fileAST{ FileSet: fset, File: f, } fileCacheLock.Unlock() return } func formatNode(fset *token.FileSet, node ast.Node) string { if node == nil { return "" } buf := &bytes.Buffer{} config := &printer.Config{ Mode: printer.UseSpaces, Tabwidth: 4, } config.Fprint(buf, fset, node) return buf.String() } func findAssignments(fset *token.FileSet, decl *ast.FuncDecl, line int, arg ast.Expr, excluded []*ast.CallExpr) (assignments []string, relatedVars map[string]struct{}) { if decl == nil || arg == nil { return } src := formatNode(fset, arg) exprs := findRelatedExprs(fset, arg) if len(exprs) == 0 { return } assignmentStmts := make(map[ast.Stmt]struct{}) for _, expr := range exprs { // Find the last assignment for ident. var stmt, lastStmt ast.Stmt done := false ast.Inspect(decl, func(n ast.Node) bool { if n == nil || done { return false } if pos := fset.Position(n.Pos()); pos.Line >= line { done = true return false } if node, ok := n.(ast.Stmt); ok { stmt = node } switch node := n.(type) { case *ast.AssignStmt: for _, left := range node.Lhs { switch n := left.(type) { case *ast.Ident: if isRelated(fset, expr, n) { lastStmt = stmt return true } } } case *ast.RangeStmt: if node.Key == nil { return true } switch n := node.Key.(type) { case *ast.Ident: if isRelated(fset, expr, n) { lastStmt = stmt return true } } if node.Value == nil { return true } switch n := node.Value.(type) { case *ast.Ident: if isRelated(fset, expr, n) { lastStmt = stmt return true } } case *ast.CallExpr: for _, call := range excluded { if node.Pos() == call.Pos() { return false } } for _, arg := range node.Args { switch n := arg.(type) { case *ast.UnaryExpr: // Treat `&a` as a kind of assignment to `a`. if n.Op == token.AND && isRelated(fset, expr, n.X) { lastStmt = stmt return true } } } } return true }) if lastStmt != nil { assignmentStmts[lastStmt] = struct{}{} } } // Collect all stmts and exprs to find out related vars. stmts := make([]ast.Stmt, 0, len(assignmentStmts)) relatedExprs := make([]ast.Expr, 0, 4*len(assignmentStmts)) relatedExprs = append(relatedExprs, arg) for s := range assignmentStmts { switch assign := s.(type) { case *ast.AssignStmt: stmts = append(stmts, assign) relatedExprs = append(relatedExprs, assign.Lhs...) relatedExprs = append(relatedExprs, assign.Rhs...) case *ast.RangeStmt: // For RangeStmt, only use the code like `k, v := range arr`. stmt := *assign body := *assign.Body body.List = nil stmt.Body = &body stmts = append(stmts, &stmt) relatedExprs = append(relatedExprs, assign.Key) if assign.Value != nil { relatedExprs = append(relatedExprs, assign.Value) } default: stmts = append(stmts, s) } } // Find out related vars referenced in expr. // If there is a SelectorExpr, use the longest possible selector. // E.g., for expr `a.b.c.d()`, only the longest selector expr `a.b.c` is returned. relatedVars = make(map[string]struct{}) for _, expr := range relatedExprs { related := findRelatedExprs(fset, expr) for _, n := range related { relatedVars[formatNode(fset, n)] = struct{}{} } } // Remove arg itself. delete(relatedVars, src) // Format source code of all assignments. sort.Sort(sortByStmts(stmts)) for _, stmt := range stmts { code := formatNode(fset, stmt) // Remove keyword `for` and `{}` in RangeStmt. if rng, ok := stmt.(*ast.RangeStmt); ok { start := rng.Pos() code = code[rng.Key.Pos()-start : rng.X.End()-start] } assignments = append(assignments, code) } return } type sortByStmts []ast.Stmt func (stmts sortByStmts) Len() int { return len(stmts) } func (stmts sortByStmts) Less(i, j int) bool { return stmts[i].Pos() < stmts[j].Pos() } func (stmts sortByStmts) Swap(i, j int) { stmts[i], stmts[j] = stmts[j], stmts[i] } // findIdents parses arg to find all referenced idents in arg. func findIdents(fset *token.FileSet, arg ast.Expr) (idents []string) { names := make(map[string]struct{}) related := findRelatedExprs(fset, arg) for _, expr := range related { names[formatNode(fset, expr)] = struct{}{} } for name := range names { idents = append(idents, name) } return } type exprVisitor struct { Related map[ast.Expr]struct{} } func newExprVisitor() *exprVisitor { return &exprVisitor{ Related: make(map[ast.Expr]struct{}), } } func (v *exprVisitor) Visit(n ast.Node) (w ast.Visitor) { if n == nil { return nil } switch node := n.(type) { case *ast.SelectorExpr: // Find out the longest selector expr. // For code `a.b.c().d.e.f()`, only `a.b` is considered as related var. if IsVar(node.X) { v.Related[node] = struct{}{} // No need to inspect this node any more. return nil } // Never walk node.Sel. ast.Walk(v, node.X) return nil case *ast.Ident: v.Related[node] = struct{}{} return nil } return v } func findRelatedExprs(fset *token.FileSet, arg ast.Expr) (related []ast.Expr) { v := newExprVisitor() ast.Walk(v, arg) related = make([]ast.Expr, 0, len(v.Related)) for expr := range v.Related { related = append(related, expr) } return } // IsVar returns true if expr is an ident or a selector expr like `a.b`. func IsVar(expr ast.Expr) bool { switch n := expr.(type) { case *ast.Ident: return true case *ast.SelectorExpr: x := n.X for { if sel, ok := x.(*ast.SelectorExpr); ok { x = sel } else { break } } if _, ok := x.(*ast.Ident); ok { return true } } return false } // isRelated returns true, if target is the same as expr or "parent" of expr. func isRelated(fset *token.FileSet, expr, target ast.Expr) bool { if expr == target { return true } if !IsVar(target) { return false } // target must be a selector or ident. switch n := target.(type) { case *ast.SelectorExpr: if _, ok := expr.(*ast.Ident); ok { return false } return IsIncluded(formatNode(fset, n), formatNode(fset, expr)) case *ast.Ident: return IsIncluded(n.Name, formatNode(fset, expr)) } return false } // IsIncluded checks whether child var is a children of parent var. // Regarding the child var `a.b.c`, it's the children of `a`, `a.b` and `a.b.c`. func IsIncluded(parent, child string) bool { if len(child) < len(parent) { return false } if parent == child { return true } if strings.HasPrefix(child, parent) && child[len(parent)] == '.' { return true } return false } // AddExcluded adds an expr to excluded expr list so that // this expr will not be inspected when finding related assignments. func (p *Parser) AddExcluded(expr *ast.CallExpr) { p.m.Lock() defer p.m.Unlock() p.excluded = append(p.excluded, expr) } go-assert-1.1.5/internal/assertion/parser_test.go000066400000000000000000000037711362227502400221420ustar00rootroot00000000000000// Copyright 2017 Huan Du. All rights reserved. // Licensed under the MIT license that can be found in the LICENSE file. package assertion import ( "testing" ) func assertEqual(t *testing.T, v1, v2 interface{}) { AssertEqual(t, v1, v2, &Trigger{ FuncName: "assertEqual", Skip: 1, Args: []int{1, 2}, }) } func TestParseFalseKind(t *testing.T) { cases := []struct { Value interface{} Kind FalseKind }{ { 12, Positive, }, { nil, Nil, }, { 0, Zero, }, { uint(0), Zero, }, { 0.0, Zero, }, { complex(0, 0), Zero, }, { false, False, }, { []int{}, Positive, }, { ([]int)(nil), Nil, }, { "", EmptyString, }, } for i, c := range cases { t.Logf("case %v: %v", i, c) k := ParseFalseKind(c.Value) assertEqual(t, c.Kind, k) } } func TestParseArgs(t *testing.T) { cases := []struct { ArgIndex []int Args []string Assignments [][]string RelatedVars []string }{ { []int{0}, []string{`prefix + args`}, [][]string{ {`f(&args)`, `prefix := s.(type)`}, }, []string{`args`, `prefix`, `s`}, }, { []int{1}, []string{`skip`}, [][]string{ {`skip = 0`}, }, []string{}, }, { []int{-1, 0, -2, 4}, []string{`c.ArgIndex`, `prefix + args`, `skip`, ""}, [][]string{ {`i, c := range cases`}, {`f(&args)`, `prefix := s.(type)`}, {`skip = 0`}, nil, }, []string{`args`, `c`, `i`, `prefix`, `s`}, }, } p := new(Parser) for i, c := range cases { skip := i skip = 0 // The last assignment to `skip` should be chosen. args := "foo" f := func(s *string) { *s = "Args" } f(&args) var s interface{} = "Parse" switch prefix := s.(type) { // Test init stmt in SwitchStmt. case string: f, err := p.ParseArgs(prefix+args, skip, c.ArgIndex) info := p.ParseInfo(f) skip = 2 assertEqual(t, err, nil) assertEqual(t, info.Args, c.Args) assertEqual(t, info.Assignments, c.Assignments) assertEqual(t, info.RelatedVars, c.RelatedVars) } } } go-assert-1.1.5/samples_test.go000066400000000000000000000016121362227502400164570ustar00rootroot00000000000000package assert import ( "errors" "os" "testing" ) func TestSample_Assert(t *testing.T) { a, b := 1, 2 Assert(t, a > b) } func TestSample_AssertEqual(t *testing.T) { Equal(t, []int{1, 2}, []int{1}) } func TestSample_AssertNotEqual(t *testing.T) { NotEqual(t, []int{1}, []int{1}) } func TestSample_A_Assert(t *testing.T) { a := New(t) x, y := 1, 2 a.Assert(x > y) } func TestSample_A_NilError(t *testing.T) { a := New(t) a.NilError(os.Open("path/to/a/file")) } func TestSample_A_NonNilError(t *testing.T) { a := New(t) f := func() (int, error) { return 0, errors.New("expected") } a.NilError(f()) } func TestSample_A_Equal(t *testing.T) { a := New(t) a.Equal([]int{1, 2}, []int{1}) } func TestSample_A_Use(t *testing.T) { a := New(t) v1 := 123 v2 := []string{"wrong", "right"} v3 := v2[0] v4 := "not related" a.Use(&v1, &v2, &v3, &v4) a.Assert(v1 == 123 && v3 == "right") }