diff --git a/assert.go b/assert.go index 791b600..7d5f90e 100644 --- a/assert.go +++ b/assert.go @@ -2,32 +2,28 @@ package assert import ( "reflect" - - "github.com/google/go-cmp/cmp" + "runtime" + "testing" ) // Assert is a helper for tests -type Assert struct { - t T -} - -func (a Assert) f(ok bool, msg []interface{}, format string, extra ...interface{}) { - if !ok { - if format != `` { - msg = prepMsg(msg, format, extra...) - } - if msg == nil { - msg = []interface{}{`Assertion failed`} - } - msg = append(append([]interface{}{shell(1) + shell(97) + shell(41) + `FAIL!` + shell(0) + shell(1)}, msg...), shell(0), "\n") - a.t.Helper() - a.t.Error(msg...) - } -} +type Assert func(bool, ...interface{}) // New returns a new Assert -func New(t T) Assert { - a := Assert{t} +func New(t *testing.T) Assert { + a := func(ok bool, msg ...interface{}) { + if !ok { + if msg == nil { + msg = []interface{}{`Assertion failed`} + } + msg = append(append([]interface{}{shell(1) + shell(97) + shell(41) + `FAIL!` + shell(0) + shell(1)}, msg...), shell(0), "\n") + t.Helper() + t.Error(msg...) + } + } + + f := runtime.FuncForPC(reflect.ValueOf(a).Pointer()) + ts[f] = t return a } @@ -38,14 +34,16 @@ func New(t T) Assert { // True asserts the given value is true func (a Assert) True(actual bool, msg ...interface{}) { - a.t.Helper() - a.f(actual, msg, `Should be true, but it isn't`) + t(a).Helper() + msg = prepMsg(msg, `Should be true, but it isn't`) + a(actual, msg...) } -// False asserts the given value is false +// False sserts the given value is false func (a Assert) False(actual bool, msg ...interface{}) { - a.t.Helper() - a.f(!actual, msg, `Should be false, but it isn't`) + t(a).Helper() + msg = prepMsg(msg, `Should be false, but it isn't`) + a(!actual, msg...) } ///// Nil ///// @@ -66,76 +64,87 @@ func isNil(val interface{}) bool { // Nil asserts the given value is nil func (a Assert) Nil(actual interface{}, msg ...interface{}) { - a.t.Helper() - a.f(isNil(actual), msg, `Should be nil, but got %#v`, actual) + t(a).Helper() + msg = prepMsg(msg, `Should be nil, but got %#v`, actual) + + a(isNil(actual), msg...) } -// NotNil asserts the given value is not nil +// NotNil sserts the given value is not nil func (a Assert) NotNil(actual interface{}, msg ...interface{}) { - a.t.Helper() - a.f(!isNil(actual), msg, `Should not be nil, but it is`) + t(a).Helper() + msg = prepMsg(msg, `Should not be nil, but it is`) + + a(!isNil(actual), msg...) } ///// Errors ///// // Error asserts the given error is not nil func (a Assert) Error(actual error, msg ...interface{}) { - a.t.Helper() - a.f(actual != nil, msg, `Expected an error, but got nil`) + t(a).Helper() + msg = prepMsg(msg, `Expected an error, but got nil`) + a(actual != nil, msg...) } -// NoError asserts the given error is nil +// NoError asserts the given error is not nil func (a Assert) NoError(actual error, msg ...interface{}) { - a.t.Helper() - a.f(actual == nil, msg, `Expected no error, but got %#v`, actual) + t(a).Helper() + msg = prepMsg(msg, `Expected no error, but got %#v`, actual) + a(actual == nil, msg...) } ///// Comparisons ///// // Eq asserts the given values match func (a Assert) Eq(expected, actual interface{}, msg ...interface{}) { - a.t.Helper() + t(a).Helper() if reflect.TypeOf(expected) != reflect.TypeOf(actual) { - a.f(false, msg, `Expected %T(%#v), but got %T(%#v)`, expected, expected, actual, actual) + msg = prepMsg(msg, `Expected %T(%#v), but got %T(%#v)`, expected, expected, actual, actual) + a(false, msg...) return } - a.f(expected == actual, msg, `Expected %#v, but got %#v`, expected, actual) + msg = prepMsg(msg, `Expected %#v, but got %#v`, expected, actual) + a(expected == actual, msg...) } // Ne asserts the given values don't match func (a Assert) Ne(expected, actual interface{}, msg ...interface{}) { - a.t.Helper() - a.f(expected != actual, msg, `Should not be %#v, but it is`, expected) + t(a).Helper() + msg = prepMsg(msg, `Should not be %#v, but it is`, expected) + a(expected != actual, msg...) } ///// Lists ///// // Contains asserts the expected value is in the given list func (a Assert) Contains(expected, list interface{}, msg ...interface{}) { - a.t.Helper() + t(a).Helper() rlist := reflect.ValueOf(list) - a.f(rlist.Kind() == reflect.Slice || rlist.Kind() == reflect.Array, nil, `Can only call assert.Contains on a slice or array`) + a(rlist.Kind() == reflect.Slice || rlist.Kind() == reflect.Array, `Can only call assert.Contains on a slice or array`) for i := 0; i < rlist.Len(); i++ { if rlist.Index(i).Interface() == expected { return } } - a.f(false, msg, `Expected %#v to be in %#v, but it isn't`, expected, list) + msg = prepMsg(msg, `Expected %#v to be in %#v, but it isn't`, expected, list) + a(false, msg...) } // SameElements asserts the values have the same elements. It ignores the order of the elements func (a Assert) SameElements(expected, actual interface{}, msg ...interface{}) { - a.t.Helper() + t(a).Helper() rexpected, ractual := reflect.ValueOf(expected), reflect.ValueOf(actual) - a.f(rexpected.Kind() == reflect.Slice || rexpected.Kind() == reflect.Array, nil, `Can only call assert.SameElements on a slice or array`) - a.f(ractual.Kind() == reflect.Slice || ractual.Kind() == reflect.Array, nil, `Can only call assert.SameElements on a slice or array`) + a(rexpected.Kind() == reflect.Slice || rexpected.Kind() == reflect.Array, `Can only call assert.SameElements on a slice or array`) + a(ractual.Kind() == reflect.Slice || ractual.Kind() == reflect.Array, `Can only call assert.SameElements on a slice or array`) + msg = prepMsg(msg, `Expected elements of %#v to match %#v, but they don't`, expected, actual) if rexpected.Len() != ractual.Len() { - a.f(false, msg, `Expected elements of %#v to match %#v, but they don't`, expected, actual) + a(false, msg...) return } @@ -153,24 +162,5 @@ func (a Assert) SameElements(expected, actual interface{}, msg ...interface{}) { return } - a.f(false, msg, ``) -} - -// Cmp assert wrapper for go-cmp -func (a Assert) Cmp(expected, actual interface{}, opts ...cmp.Option) { - a.t.Helper() - diff := cmp.Diff(expected, actual, opts...) - if diff == `` { - return - } - - a.f(false, nil, "\n"+diff) -} - -// NCmp assert wrapper for go-cmp but fails when !Equal -func (a Assert) NCmp(expected, actual interface{}, opts ...cmp.Option) { - a.t.Helper() - - ok := cmp.Equal(expected, actual, opts...) - a.f(!ok, nil, `Should not be %#v, but it is`, expected) + a(false, msg...) } diff --git a/assert_test.go b/assert_test.go deleted file mode 100644 index 0b31a12..0000000 --- a/assert_test.go +++ /dev/null @@ -1,194 +0,0 @@ -package assert - -import ( - "testing" - "time" -) - -// ----------------------------------------- -// Slices -// ----------------------------------------- - -func TestSameElementsSlices(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - a, b := []int{1, 2}, []int{1, 2} - fa.SameElements(a, a) - assert.False(ft.GotError()) - - fa.SameElements(a, b) - assert.False(ft.GotError()) - - b = []int{2, 1} - fa.SameElements(b, a) // SameElements ignores order - assert.False(ft.GotError()) - - b = []int{1, 2, 3} - fa.SameElements(b, a) - assert.True(ft.GotError()) - - b = []int{2, 3} - fa.SameElements(b, a) - assert.True(ft.GotError()) -} - -func TestCmpSlices(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - a, b := []int{1, 2}, []int{1, 2} - fa.Cmp(a, a) - assert.False(ft.GotError()) - - fa.Cmp(a, b) - assert.False(ft.GotError()) - - b = []int{2, 1} - fa.Cmp(a, b) // Cmp does not accept different order - assert.True(ft.GotError()) - - b = []int{1, 2, 3} - fa.Cmp(a, b) - assert.True(ft.GotError()) - - b = []int{2, 3} - fa.Cmp(a, b) - assert.True(ft.GotError()) -} - -// ----------------------------------------- -// Maps -// ----------------------------------------- - -func TestCmpMaps(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - a, b := map[int]int{1: 2, 3: 4}, map[int]int{1: 2, 3: 4} - fa.Cmp(a, a) - assert.False(ft.GotError()) - - fa.Cmp(a, b) - assert.False(ft.GotError()) - - b = map[int]int{1: 2, 3: 5} - fa.Cmp(a, b) - assert.True(ft.GotError()) - - b = map[int]int{1: 2, 3: 4, 5: 6} - fa.Cmp(a, b) - assert.True(ft.GotError()) - - b = map[int]int{1: 2} - fa.Cmp(a, b) - assert.True(ft.GotError()) -} - -// ----------------------------------------- -// Pointers -// ----------------------------------------- - -func TestEqPointers(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - var a, b int - fa.Eq(&a, &a) - assert.False(ft.GotError()) - - fa.Eq(&a, &b) - assert.True(ft.GotError()) - - fa.Eq(&b, &a) - assert.True(ft.GotError()) -} - -func TestCmpPointers(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - type B struct { - Value int - } - type A struct { - B *B - } - - fa.Cmp(A{B: &B{1}}, A{&B{1}}) - assert.False(ft.GotError()) - - fa.Cmp(A{B: &B{1}}, A{&B{2}}) - assert.True(ft.GotError()) - - fa.Cmp(A{B: &B{1}}, A{nil}) - assert.True(ft.GotError()) -} - -// ----------------------------------------- -// Timezones -// ----------------------------------------- - -func mustLoadLocation(zone string) *time.Location { - loc, err := time.LoadLocation(zone) - if err != nil { - panic(err) - } - - return loc -} - -var locAmsterdam = mustLoadLocation(`Europe/Amsterdam`) -var locTokyo = mustLoadLocation(`Asia/Tokyo`) - -func TestEqTimezones(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - ti := time.Now() - ti, ti2 := ti.In(locAmsterdam), ti.In(locTokyo) - - fa.Eq(ti, ti2) - assert.True(ft.GotError()) -} - -func TestCmpTimezones(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - type A struct { - Time time.Time - } - - ti := time.Now() - ti2 := ti.In(time.UTC) - fa.Cmp(&A{ti}, &A{ti2}) - assert.False(ft.GotError()) - - ti2 = ti.In(locAmsterdam) - fa.Cmp(&A{ti}, &A{ti2}) - assert.False(ft.GotError()) - - ti = ti.In(locTokyo) - fa.Cmp(&A{ti}, &A{ti2}) - assert.False(ft.GotError()) - - ti2 = ti2.Add(time.Second) - fa.Cmp(&A{ti}, &A{ti2}) - assert.True(ft.GotError()) -} - -func TestNCmp(t *testing.T) { - assert := New(t) - ft, fa := newFakeT() - - type A struct { - S string - } - - fa.NCmp(A{"not"}, A{"equal"}) - assert.False(ft.GotError()) - - fa.NCmp(A{"equal"}, A{"equal"}) - assert.True(ft.GotError()) -} diff --git a/faket_test.go b/faket_test.go deleted file mode 100644 index 1a494e0..0000000 --- a/faket_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package assert - -type fakeT struct { - gotError bool -} - -func newFakeT() (*fakeT, Assert) { - var ft fakeT - return &ft, New(&ft) -} - -func (t *fakeT) Error(_ ...interface{}) { - t.gotError = true -} - -func (_ *fakeT) Helper() {} - -func (t *fakeT) GotError() bool { - r := t.gotError - t.gotError = false - - return r -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 55a7857..0000000 --- a/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module git.fuyu.moe/Fuyu/assert - -go 1.14 - -require github.com/google/go-cmp v0.4.0 diff --git a/go.sum b/go.sum deleted file mode 100644 index 4430646..0000000 --- a/go.sum +++ /dev/null @@ -1,3 +0,0 @@ -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/helper.go b/helper.go index d8d5e63..67cc4a9 100644 --- a/helper.go +++ b/helper.go @@ -2,7 +2,10 @@ package assert import ( "fmt" + "reflect" + "runtime" "strconv" + "testing" ) func prepMsg(msg []interface{}, format string, args ...interface{}) []interface{} { @@ -12,3 +15,10 @@ func prepMsg(msg []interface{}, format string, args ...interface{}) []interface{ func shell(i int) string { return "\x1B[" + strconv.Itoa(i) + "m" } + +var ts = map[*runtime.Func]*testing.T{} + +func t(a Assert) *testing.T { + f := runtime.FuncForPC(reflect.ValueOf(a).Pointer()) + return ts[f] +} diff --git a/type.go b/type.go deleted file mode 100644 index 1c9a1fd..0000000 --- a/type.go +++ /dev/null @@ -1,7 +0,0 @@ -package assert - -// T is an interface of what we use from testing.T -type T interface { - Error(...interface{}) - Helper() -}