Merge branch 'master' into patch-1

pull/1248/head
Olivier Mengué 2023-10-16 19:23:14 +02:00 committed by GitHub
commit f19cdfc9fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 2306 additions and 1213 deletions

View File

@ -6,14 +6,32 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
go_version: ["1.18.1", "1.17.6", "1.16.5"] go_version:
- "1.19"
- "1.20"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v3.2.0 uses: actions/setup-go@v4.1.0
with: with:
go-version: ${{ matrix.go_version }} go-version: ${{ matrix.go_version }}
- run: ./.ci.gogenerate.sh - run: ./.ci.gogenerate.sh
- run: ./.ci.gofmt.sh - run: ./.ci.gofmt.sh
- run: ./.ci.govet.sh - run: ./.ci.govet.sh
- run: go test -v -race ./... - run: go test -v -race ./...
test:
runs-on: ubuntu-latest
strategy:
matrix:
go_version:
- "1.17"
- "1.18"
- "1.19"
- "1.20"
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v4.1.0
with:
go-version: ${{ matrix.go_version }}
- run: go test -v -race ./...

19
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Create release from new tag
# this flow will be run only when new tags are pushed that match our pattern
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create GitHub release from tag
uses: softprops/action-gh-release@v1

View File

@ -5,5 +5,4 @@ pull requests.
* @glesica * @glesica
* @boyan-soubachov * @boyan-soubachov
* @mvdkleijn

View File

@ -16,13 +16,13 @@ Features include:
Get started: Get started:
* Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date) * Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date)
* For an introduction to writing test code in Go, see http://golang.org/doc/code.html#Testing * For an introduction to writing test code in Go, see https://go.dev/doc/code#Testing
* Check out the API Documentation http://godoc.org/github.com/stretchr/testify * Check out the API Documentation https://pkg.go.dev/github.com/stretchr/testify
* A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development) * A little about [Test-Driven Development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development)
[`assert`](http://godoc.org/github.com/stretchr/testify/assert "API documentation") package [`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") package
------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------
The `assert` package provides some helpful methods that allow you to write better test code in Go. The `assert` package provides some helpful methods that allow you to write better test code in Go.
@ -99,19 +99,21 @@ func TestSomething(t *testing.T) {
} }
``` ```
[`require`](http://godoc.org/github.com/stretchr/testify/require "API documentation") package [`require`](https://pkg.go.dev/github.com/stretchr/testify/require "API documentation") package
--------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------
The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test. The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test.
These functions must be called from the goroutine running the test or benchmark function, not from other goroutines created during the test.
Otherwise race conditions may occur.
See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details. See [t.FailNow](https://pkg.go.dev/testing#T.FailNow) for details.
[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package [`mock`](https://pkg.go.dev/github.com/stretchr/testify/mock "API documentation") package
---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------
The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code. The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code.
An example test function that tests a piece of code that relies on an external object `testObj`, can setup expectations (testify) and assert that they indeed happened: An example test function that tests a piece of code that relies on an external object `testObj`, can set up expectations (testify) and assert that they indeed happened:
```go ```go
package yours package yours
@ -156,7 +158,7 @@ func TestSomething(t *testing.T) {
// create an instance of our test object // create an instance of our test object
testObj := new(MyMockedObject) testObj := new(MyMockedObject)
// setup expectations // set up expectations
testObj.On("DoSomething", 123).Return(true, nil) testObj.On("DoSomething", 123).Return(true, nil)
// call the code we are testing // call the code we are testing
@ -178,7 +180,7 @@ func TestSomethingWithPlaceholder(t *testing.T) {
// create an instance of our test object // create an instance of our test object
testObj := new(MyMockedObject) testObj := new(MyMockedObject)
// setup expectations with a placeholder in the argument list // set up expectations with a placeholder in the argument list
testObj.On("DoSomething", mock.Anything).Return(true, nil) testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing // call the code we are testing
@ -197,7 +199,7 @@ func TestSomethingElse2(t *testing.T) {
// create an instance of our test object // create an instance of our test object
testObj := new(MyMockedObject) testObj := new(MyMockedObject)
// setup expectations with a placeholder in the argument list // set up expectations with a placeholder in the argument list
mockCall := testObj.On("DoSomething", mock.Anything).Return(true, nil) mockCall := testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing // call the code we are testing
@ -216,14 +218,14 @@ func TestSomethingElse2(t *testing.T) {
} }
``` ```
For more information on how to write mock code, check out the [API documentation for the `mock` package](http://godoc.org/github.com/stretchr/testify/mock). For more information on how to write mock code, check out the [API documentation for the `mock` package](https://pkg.go.dev/github.com/stretchr/testify/mock).
You can use the [mockery tool](http://github.com/vektra/mockery) to autogenerate the mock code against an interface as well, making using mocks much quicker. You can use the [mockery tool](https://vektra.github.io/mockery/latest/) to autogenerate the mock code against an interface as well, making using mocks much quicker.
[`suite`](http://godoc.org/github.com/stretchr/testify/suite "API documentation") package [`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package
----------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------
The `suite` package provides functionality that you might be used to from more common object oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal. The `suite` package provides functionality that you might be used to from more common object-oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal.
An example suite is shown below: An example suite is shown below:
@ -264,7 +266,7 @@ func TestExampleTestSuite(t *testing.T) {
For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go) For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go)
For more information on writing suites, check out the [API documentation for the `suite` package](http://godoc.org/github.com/stretchr/testify/suite). For more information on writing suites, check out the [API documentation for the `suite` package](https://pkg.go.dev/github.com/stretchr/testify/suite).
`Suite` object has assertion methods: `Suite` object has assertion methods:
@ -347,7 +349,7 @@ To update Testify to the latest version, use `go get -u github.com/stretchr/test
Supported go versions Supported go versions
================== ==================
We currently support the most recent major Go versions from 1.13 onward. We currently support the most recent major Go versions from 1.19 onward.
------ ------
@ -358,7 +360,7 @@ Please feel free to submit issues, fork the repository and send pull requests!
When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it. When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it.
Code generation is used. Look for `CODE GENERATED AUTOMATICALLY` at the top of some files. Run `go generate ./...` to update generated files. Code generation is used. [Look for `Code generated with`](https://github.com/search?q=repo%3Astretchr%2Ftestify%20%22Code%20generated%20with%22&type=code) at the top of some files. Run `go generate ./...` to update generated files.
We also chat on the [Gophers Slack](https://gophers.slack.com) group in the `#testify` and `#testify-dev` channels. We also chat on the [Gophers Slack](https://gophers.slack.com) group in the `#testify` and `#testify-dev` channels.

View File

@ -297,10 +297,8 @@ func (f *testFunc) CommentWithoutT(receiver string) string {
return strings.Replace(f.Comment(), search, replace, -1) return strings.Replace(f.Comment(), search, replace, -1)
} }
var headerTemplate = `/* // Standard header https://go.dev/s/generatedcode.
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen var headerTemplate = `// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
* THIS FILE MUST NOT BE EDITED BY HAND
*/
package {{.Name}} package {{.Name}}

View File

@ -308,11 +308,11 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
case reflect.Struct: case reflect.Struct:
{ {
// All structs enter here. We're not interested in most types. // All structs enter here. We're not interested in most types.
if !canConvert(obj1Value, timeType) { if !obj1Value.CanConvert(timeType) {
break break
} }
// time.Time can compared! // time.Time can be compared!
timeObj1, ok := obj1.(time.Time) timeObj1, ok := obj1.(time.Time)
if !ok { if !ok {
timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time)
@ -328,7 +328,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
case reflect.Slice: case reflect.Slice:
{ {
// We only care about the []byte type. // We only care about the []byte type.
if !canConvert(obj1Value, bytesType) { if !obj1Value.CanConvert(bytesType) {
break break
} }
@ -352,9 +352,9 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
// Greater asserts that the first element is greater than the second // Greater asserts that the first element is greater than the second
// //
// assert.Greater(t, 2, 1) // assert.Greater(t, 2, 1)
// assert.Greater(t, float64(2), float64(1)) // assert.Greater(t, float64(2), float64(1))
// assert.Greater(t, "b", "a") // assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -364,10 +364,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface
// GreaterOrEqual asserts that the first element is greater than or equal to the second // GreaterOrEqual asserts that the first element is greater than or equal to the second
// //
// assert.GreaterOrEqual(t, 2, 1) // assert.GreaterOrEqual(t, 2, 1)
// assert.GreaterOrEqual(t, 2, 2) // assert.GreaterOrEqual(t, 2, 2)
// assert.GreaterOrEqual(t, "b", "a") // assert.GreaterOrEqual(t, "b", "a")
// assert.GreaterOrEqual(t, "b", "b") // assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -377,9 +377,9 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in
// Less asserts that the first element is less than the second // Less asserts that the first element is less than the second
// //
// assert.Less(t, 1, 2) // assert.Less(t, 1, 2)
// assert.Less(t, float64(1), float64(2)) // assert.Less(t, float64(1), float64(2))
// assert.Less(t, "a", "b") // assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -389,10 +389,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{})
// LessOrEqual asserts that the first element is less than or equal to the second // LessOrEqual asserts that the first element is less than or equal to the second
// //
// assert.LessOrEqual(t, 1, 2) // assert.LessOrEqual(t, 1, 2)
// assert.LessOrEqual(t, 2, 2) // assert.LessOrEqual(t, 2, 2)
// assert.LessOrEqual(t, "a", "b") // assert.LessOrEqual(t, "a", "b")
// assert.LessOrEqual(t, "b", "b") // assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -402,8 +402,8 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter
// Positive asserts that the specified element is positive // Positive asserts that the specified element is positive
// //
// assert.Positive(t, 1) // assert.Positive(t, 1)
// assert.Positive(t, 1.23) // assert.Positive(t, 1.23)
func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -414,8 +414,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
// Negative asserts that the specified element is negative // Negative asserts that the specified element is negative
// //
// assert.Negative(t, -1) // assert.Negative(t, -1)
// assert.Negative(t, -1.23) // assert.Negative(t, -1.23)
func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()

View File

@ -1,16 +0,0 @@
//go:build go1.17
// +build go1.17
// TODO: once support for Go 1.16 is dropped, this file can be
// merged/removed with assertion_compare_go1.17_test.go and
// assertion_compare_legacy.go
package assert
import "reflect"
// Wrapper around reflect.Value.CanConvert, for compatibility
// reasons.
func canConvert(value reflect.Value, to reflect.Type) bool {
return value.CanConvert(to)
}

View File

@ -1,182 +0,0 @@
//go:build go1.17
// +build go1.17
// TODO: once support for Go 1.16 is dropped, this file can be
// merged/removed with assertion_compare_can_convert.go and
// assertion_compare_legacy.go
package assert
import (
"bytes"
"reflect"
"testing"
"time"
)
func TestCompare17(t *testing.T) {
type customTime time.Time
type customBytes []byte
for _, currCase := range []struct {
less interface{}
greater interface{}
cType string
}{
{less: time.Now(), greater: time.Now().Add(time.Hour), cType: "time.Time"},
{less: customTime(time.Now()), greater: customTime(time.Now().Add(time.Hour)), cType: "time.Time"},
{less: []byte{1, 1}, greater: []byte{1, 2}, cType: "[]byte"},
{less: customBytes([]byte{1, 1}), greater: customBytes([]byte{1, 2}), cType: "[]byte"},
} {
resLess, isComparable := compare(currCase.less, currCase.greater, reflect.ValueOf(currCase.less).Kind())
if !isComparable {
t.Error("object should be comparable for type " + currCase.cType)
}
if resLess != compareLess {
t.Errorf("object less (%v) should be less than greater (%v) for type "+currCase.cType,
currCase.less, currCase.greater)
}
resGreater, isComparable := compare(currCase.greater, currCase.less, reflect.ValueOf(currCase.less).Kind())
if !isComparable {
t.Error("object are comparable for type " + currCase.cType)
}
if resGreater != compareGreater {
t.Errorf("object greater should be greater than less for type " + currCase.cType)
}
resEqual, isComparable := compare(currCase.less, currCase.less, reflect.ValueOf(currCase.less).Kind())
if !isComparable {
t.Error("object are comparable for type " + currCase.cType)
}
if resEqual != 0 {
t.Errorf("objects should be equal for type " + currCase.cType)
}
}
}
func TestGreater17(t *testing.T) {
mockT := new(testing.T)
if !Greater(mockT, 2, 1) {
t.Error("Greater should return true")
}
if Greater(mockT, 1, 1) {
t.Error("Greater should return false")
}
if Greater(mockT, 1, 2) {
t.Error("Greater should return false")
}
// Check error report
for _, currCase := range []struct {
less interface{}
greater interface{}
msg string
}{
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than "[1 2]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than "0001-01-01 01:00:00 +0000 UTC"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, Greater(out, currCase.less, currCase.greater))
Contains(t, out.buf.String(), currCase.msg)
Contains(t, out.helpers, "github.com/stretchr/testify/assert.Greater")
}
}
func TestGreaterOrEqual17(t *testing.T) {
mockT := new(testing.T)
if !GreaterOrEqual(mockT, 2, 1) {
t.Error("GreaterOrEqual should return true")
}
if !GreaterOrEqual(mockT, 1, 1) {
t.Error("GreaterOrEqual should return true")
}
if GreaterOrEqual(mockT, 1, 2) {
t.Error("GreaterOrEqual should return false")
}
// Check error report
for _, currCase := range []struct {
less interface{}
greater interface{}
msg string
}{
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than or equal to "[1 2]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than or equal to "0001-01-01 01:00:00 +0000 UTC"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, GreaterOrEqual(out, currCase.less, currCase.greater))
Contains(t, out.buf.String(), currCase.msg)
Contains(t, out.helpers, "github.com/stretchr/testify/assert.GreaterOrEqual")
}
}
func TestLess17(t *testing.T) {
mockT := new(testing.T)
if !Less(mockT, 1, 2) {
t.Error("Less should return true")
}
if Less(mockT, 1, 1) {
t.Error("Less should return false")
}
if Less(mockT, 2, 1) {
t.Error("Less should return false")
}
// Check error report
for _, currCase := range []struct {
less interface{}
greater interface{}
msg string
}{
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than "[1 1]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than "0001-01-01 00:00:00 +0000 UTC"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, Less(out, currCase.greater, currCase.less))
Contains(t, out.buf.String(), currCase.msg)
Contains(t, out.helpers, "github.com/stretchr/testify/assert.Less")
}
}
func TestLessOrEqual17(t *testing.T) {
mockT := new(testing.T)
if !LessOrEqual(mockT, 1, 2) {
t.Error("LessOrEqual should return true")
}
if !LessOrEqual(mockT, 1, 1) {
t.Error("LessOrEqual should return true")
}
if LessOrEqual(mockT, 2, 1) {
t.Error("LessOrEqual should return false")
}
// Check error report
for _, currCase := range []struct {
less interface{}
greater interface{}
msg string
}{
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than or equal to "[1 1]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than or equal to "0001-01-01 00:00:00 +0000 UTC"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, LessOrEqual(out, currCase.greater, currCase.less))
Contains(t, out.buf.String(), currCase.msg)
Contains(t, out.helpers, "github.com/stretchr/testify/assert.LessOrEqual")
}
}

View File

@ -1,16 +0,0 @@
//go:build !go1.17
// +build !go1.17
// TODO: once support for Go 1.16 is dropped, this file can be
// merged/removed with assertion_compare_go1.17_test.go and
// assertion_compare_can_convert.go
package assert
import "reflect"
// Older versions of Go does not have the reflect.Value.CanConvert
// method.
func canConvert(value reflect.Value, to reflect.Type) bool {
return false
}

View File

@ -6,6 +6,7 @@ import (
"reflect" "reflect"
"runtime" "runtime"
"testing" "testing"
"time"
) )
func TestCompare(t *testing.T) { func TestCompare(t *testing.T) {
@ -22,6 +23,8 @@ func TestCompare(t *testing.T) {
type customFloat32 float32 type customFloat32 float32
type customFloat64 float64 type customFloat64 float64
type customString string type customString string
type customTime time.Time
type customBytes []byte
for _, currCase := range []struct { for _, currCase := range []struct {
less interface{} less interface{}
greater interface{} greater interface{}
@ -52,6 +55,10 @@ func TestCompare(t *testing.T) {
{less: customFloat32(1.23), greater: customFloat32(2.23), cType: "float32"}, {less: customFloat32(1.23), greater: customFloat32(2.23), cType: "float32"},
{less: float64(1.23), greater: float64(2.34), cType: "float64"}, {less: float64(1.23), greater: float64(2.34), cType: "float64"},
{less: customFloat64(1.23), greater: customFloat64(2.34), cType: "float64"}, {less: customFloat64(1.23), greater: customFloat64(2.34), cType: "float64"},
{less: time.Now(), greater: time.Now().Add(time.Hour), cType: "time.Time"},
{less: customTime(time.Now()), greater: customTime(time.Now().Add(time.Hour)), cType: "time.Time"},
{less: []byte{1, 1}, greater: []byte{1, 2}, cType: "[]byte"},
{less: customBytes([]byte{1, 1}), greater: customBytes([]byte{1, 2}), cType: "[]byte"},
} { } {
resLess, isComparable := compare(currCase.less, currCase.greater, reflect.ValueOf(currCase.less).Kind()) resLess, isComparable := compare(currCase.less, currCase.greater, reflect.ValueOf(currCase.less).Kind())
if !isComparable { if !isComparable {
@ -148,6 +155,8 @@ func TestGreater(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"1" is not greater than "2"`}, {less: uint64(1), greater: uint64(2), msg: `"1" is not greater than "2"`},
{less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than "2.34"`}, {less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than "2.34"`},
{less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than "2.34"`}, {less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than "2.34"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than "[1 2]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than "0001-01-01 01:00:00 +0000 UTC"`},
} { } {
out := &outputT{buf: bytes.NewBuffer(nil)} out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, Greater(out, currCase.less, currCase.greater)) False(t, Greater(out, currCase.less, currCase.greater))
@ -189,6 +198,8 @@ func TestGreaterOrEqual(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"1" is not greater than or equal to "2"`}, {less: uint64(1), greater: uint64(2), msg: `"1" is not greater than or equal to "2"`},
{less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than or equal to "2.34"`}, {less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than or equal to "2.34"`},
{less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than or equal to "2.34"`}, {less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than or equal to "2.34"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than or equal to "[1 2]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than or equal to "0001-01-01 01:00:00 +0000 UTC"`},
} { } {
out := &outputT{buf: bytes.NewBuffer(nil)} out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, GreaterOrEqual(out, currCase.less, currCase.greater)) False(t, GreaterOrEqual(out, currCase.less, currCase.greater))
@ -230,6 +241,8 @@ func TestLess(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"2" is not less than "1"`}, {less: uint64(1), greater: uint64(2), msg: `"2" is not less than "1"`},
{less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than "1.23"`}, {less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than "1.23"`},
{less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than "1.23"`}, {less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than "1.23"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than "[1 1]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than "0001-01-01 00:00:00 +0000 UTC"`},
} { } {
out := &outputT{buf: bytes.NewBuffer(nil)} out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, Less(out, currCase.greater, currCase.less)) False(t, Less(out, currCase.greater, currCase.less))
@ -271,6 +284,8 @@ func TestLessOrEqual(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"2" is not less than or equal to "1"`}, {less: uint64(1), greater: uint64(2), msg: `"2" is not less than or equal to "1"`},
{less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than or equal to "1.23"`}, {less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than or equal to "1.23"`},
{less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than or equal to "1.23"`}, {less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than or equal to "1.23"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than or equal to "[1 1]"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than or equal to "0001-01-01 00:00:00 +0000 UTC"`},
} { } {
out := &outputT{buf: bytes.NewBuffer(nil)} out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, LessOrEqual(out, currCase.greater, currCase.less)) False(t, LessOrEqual(out, currCase.greater, currCase.less))

View File

@ -1,7 +1,4 @@
/* // Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
* THIS FILE MUST NOT BE EDITED BY HAND
*/
package assert package assert
@ -22,9 +19,9 @@ func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bo
// Containsf asserts that the specified string, list(array, slice...) or map contains the // Containsf asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element. // specified substring or element.
// //
// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") // assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") // assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") // assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -56,7 +53,7 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// assert.Emptyf(t, obj, "error message %s", "formatted") // assert.Emptyf(t, obj, "error message %s", "formatted")
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -66,7 +63,7 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) boo
// Equalf asserts that two objects are equal. // Equalf asserts that two objects are equal.
// //
// assert.Equalf(t, 123, 123, "error message %s", "formatted") // assert.Equalf(t, 123, 123, "error message %s", "formatted")
// //
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
@ -81,8 +78,8 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar
// EqualErrorf asserts that a function returned an error (i.e. not `nil`) // EqualErrorf asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error. // and that it is equal to the provided error.
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") // assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -90,10 +87,27 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
} }
// EqualValuesf asserts that two objects are equal or convertable to the same types // EqualExportedValuesf asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// EqualValuesf asserts that two objects are equal or convertible to the same types
// and equal. // and equal.
// //
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") // assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -103,10 +117,10 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
// Errorf asserts that a function returned an error (i.e. not `nil`). // Errorf asserts that a function returned an error (i.e. not `nil`).
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// if assert.Errorf(t, err, "error message %s", "formatted") { // if assert.Errorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err) // assert.Equal(t, expectedErrorf, err)
// } // }
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -126,8 +140,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring. // and that the error contains the specified substring.
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") // assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted")
func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -147,7 +161,7 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface
// Eventuallyf asserts that given condition will be met in waitFor time, // Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. // periodically checking target function each tick.
// //
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") // assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -155,9 +169,34 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
} }
// EventuallyWithTf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
}
// Exactlyf asserts that two objects are equal in value and type. // Exactlyf asserts that two objects are equal in value and type.
// //
// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") // assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -183,7 +222,7 @@ func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}
// Falsef asserts that the specified value is false. // Falsef asserts that the specified value is false.
// //
// assert.Falsef(t, myBool, "error message %s", "formatted") // assert.Falsef(t, myBool, "error message %s", "formatted")
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -202,9 +241,9 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool
// Greaterf asserts that the first element is greater than the second // Greaterf asserts that the first element is greater than the second
// //
// assert.Greaterf(t, 2, 1, "error message %s", "formatted") // assert.Greaterf(t, 2, 1, "error message %s", "formatted")
// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") // assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
// assert.Greaterf(t, "b", "a", "error message %s", "formatted") // assert.Greaterf(t, "b", "a", "error message %s", "formatted")
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -214,10 +253,10 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in
// GreaterOrEqualf asserts that the first element is greater than or equal to the second // GreaterOrEqualf asserts that the first element is greater than or equal to the second
// //
// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") // assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") // assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") // assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") // assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -228,7 +267,7 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg
// HTTPBodyContainsf asserts that a specified handler returns a // HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
@ -241,7 +280,7 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url
// HTTPBodyNotContainsf asserts that a specified handler returns a // HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
@ -253,7 +292,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u
// HTTPErrorf asserts that a specified handler returns an error status code. // HTTPErrorf asserts that a specified handler returns an error status code.
// //
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
@ -265,7 +304,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string,
// HTTPRedirectf asserts that a specified handler returns a redirect status code. // HTTPRedirectf asserts that a specified handler returns a redirect status code.
// //
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
@ -277,7 +316,7 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
// HTTPStatusCodef asserts that a specified handler returns a specified status code. // HTTPStatusCodef asserts that a specified handler returns a specified status code.
// //
// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
@ -289,7 +328,7 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st
// HTTPSuccessf asserts that a specified handler returns a success status code. // HTTPSuccessf asserts that a specified handler returns a success status code.
// //
// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
@ -301,7 +340,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin
// Implementsf asserts that an object is implemented by the specified interface. // Implementsf asserts that an object is implemented by the specified interface.
// //
// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") // assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -311,7 +350,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
// InDeltaf asserts that the two numerals are within delta of each other. // InDeltaf asserts that the two numerals are within delta of each other.
// //
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") // assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -353,9 +392,9 @@ func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsil
// IsDecreasingf asserts that the collection is decreasing // IsDecreasingf asserts that the collection is decreasing
// //
// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") // assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") // assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") // assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -365,9 +404,9 @@ func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface
// IsIncreasingf asserts that the collection is increasing // IsIncreasingf asserts that the collection is increasing
// //
// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") // assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") // assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") // assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -377,9 +416,9 @@ func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface
// IsNonDecreasingf asserts that the collection is not decreasing // IsNonDecreasingf asserts that the collection is not decreasing
// //
// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") // assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") // assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") // assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -389,9 +428,9 @@ func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interf
// IsNonIncreasingf asserts that the collection is not increasing // IsNonIncreasingf asserts that the collection is not increasing
// //
// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") // assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") // assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") // assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -409,7 +448,7 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin
// JSONEqf asserts that two JSON strings are equivalent. // JSONEqf asserts that two JSON strings are equivalent.
// //
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") // assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -420,7 +459,7 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
// Lenf asserts that the specified object has specific length. // Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept. // Lenf also fails if the object has a type that len() not accept.
// //
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") // assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -430,9 +469,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
// Lessf asserts that the first element is less than the second // Lessf asserts that the first element is less than the second
// //
// assert.Lessf(t, 1, 2, "error message %s", "formatted") // assert.Lessf(t, 1, 2, "error message %s", "formatted")
// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") // assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
// assert.Lessf(t, "a", "b", "error message %s", "formatted") // assert.Lessf(t, "a", "b", "error message %s", "formatted")
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -442,10 +481,10 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter
// LessOrEqualf asserts that the first element is less than or equal to the second // LessOrEqualf asserts that the first element is less than or equal to the second
// //
// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") // assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") // assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") // assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") // assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -455,8 +494,8 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args .
// Negativef asserts that the specified element is negative // Negativef asserts that the specified element is negative
// //
// assert.Negativef(t, -1, "error message %s", "formatted") // assert.Negativef(t, -1, "error message %s", "formatted")
// assert.Negativef(t, -1.23, "error message %s", "formatted") // assert.Negativef(t, -1.23, "error message %s", "formatted")
func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -467,7 +506,7 @@ func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool
// Neverf asserts that the given condition doesn't satisfy in waitFor time, // Neverf asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick. // periodically checking the target function each tick.
// //
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") // assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -477,7 +516,7 @@ func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.
// Nilf asserts that the specified object is nil. // Nilf asserts that the specified object is nil.
// //
// assert.Nilf(t, err, "error message %s", "formatted") // assert.Nilf(t, err, "error message %s", "formatted")
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -496,10 +535,10 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool
// NoErrorf asserts that a function returned no error (i.e. `nil`). // NoErrorf asserts that a function returned no error (i.e. `nil`).
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// if assert.NoErrorf(t, err, "error message %s", "formatted") { // if assert.NoErrorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -519,9 +558,9 @@ func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) boo
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element. // specified substring or element.
// //
// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") // assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") // assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") // assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -532,9 +571,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { // if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -544,7 +583,7 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{})
// NotEqualf asserts that the specified values are NOT equal. // NotEqualf asserts that the specified values are NOT equal.
// //
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
// //
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
@ -557,7 +596,7 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string,
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type // NotEqualValuesf asserts that two objects are not equal even when converted to the same type
// //
// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") // assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -576,7 +615,7 @@ func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interf
// NotNilf asserts that the specified object is not nil. // NotNilf asserts that the specified object is not nil.
// //
// assert.NotNilf(t, err, "error message %s", "formatted") // assert.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -586,7 +625,7 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bo
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") // assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -596,8 +635,8 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo
// NotRegexpf asserts that a specified regexp does not match a string. // NotRegexpf asserts that a specified regexp does not match a string.
// //
// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") // assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -607,7 +646,7 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
// NotSamef asserts that two pointers do not reference the same object. // NotSamef asserts that two pointers do not reference the same object.
// //
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
// //
// Both arguments must be pointer variables. Pointer variable sameness is // Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value. // determined based on the equality of both type and value.
@ -621,7 +660,7 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string,
// NotSubsetf asserts that the specified list(array, slice...) contains not all // NotSubsetf asserts that the specified list(array, slice...) contains not all
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") // assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -639,7 +678,7 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
// Panicsf asserts that the code inside the specified PanicTestFunc panics. // Panicsf asserts that the code inside the specified PanicTestFunc panics.
// //
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") // assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -651,7 +690,7 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool
// panics, and that the recovered panic value is an error that satisfies the // panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison. // EqualError comparison.
// //
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") // assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -662,7 +701,7 @@ func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string,
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") // assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -672,8 +711,8 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str
// Positivef asserts that the specified element is positive // Positivef asserts that the specified element is positive
// //
// assert.Positivef(t, 1, "error message %s", "formatted") // assert.Positivef(t, 1, "error message %s", "formatted")
// assert.Positivef(t, 1.23, "error message %s", "formatted") // assert.Positivef(t, 1.23, "error message %s", "formatted")
func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -683,8 +722,8 @@ func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool
// Regexpf asserts that a specified regexp matches a string. // Regexpf asserts that a specified regexp matches a string.
// //
// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") // assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -694,7 +733,7 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
// Samef asserts that two pointers reference the same object. // Samef asserts that two pointers reference the same object.
// //
// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") // assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
// //
// Both arguments must be pointer variables. Pointer variable sameness is // Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value. // determined based on the equality of both type and value.
@ -708,7 +747,7 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg
// Subsetf asserts that the specified list(array, slice...) contains all // Subsetf asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") // assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -718,7 +757,7 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args
// Truef asserts that the specified value is true. // Truef asserts that the specified value is true.
// //
// assert.Truef(t, myBool, "error message %s", "formatted") // assert.Truef(t, myBool, "error message %s", "formatted")
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -728,7 +767,7 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
// WithinDurationf asserts that the two times are within duration delta of each other. // WithinDurationf asserts that the two times are within duration delta of each other.
// //
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") // assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -738,7 +777,7 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim
// WithinRangef asserts that a time is within a time range (inclusive). // WithinRangef asserts that a time is within a time range (inclusive).
// //
// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") // assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()

File diff suppressed because it is too large Load Diff

View File

@ -46,36 +46,36 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
// IsIncreasing asserts that the collection is increasing // IsIncreasing asserts that the collection is increasing
// //
// assert.IsIncreasing(t, []int{1, 2, 3}) // assert.IsIncreasing(t, []int{1, 2, 3})
// assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []float{1, 2})
// assert.IsIncreasing(t, []string{"a", "b"}) // assert.IsIncreasing(t, []string{"a", "b"})
func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
} }
// IsNonIncreasing asserts that the collection is not increasing // IsNonIncreasing asserts that the collection is not increasing
// //
// assert.IsNonIncreasing(t, []int{2, 1, 1}) // assert.IsNonIncreasing(t, []int{2, 1, 1})
// assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []float{2, 1})
// assert.IsNonIncreasing(t, []string{"b", "a"}) // assert.IsNonIncreasing(t, []string{"b", "a"})
func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
} }
// IsDecreasing asserts that the collection is decreasing // IsDecreasing asserts that the collection is decreasing
// //
// assert.IsDecreasing(t, []int{2, 1, 0}) // assert.IsDecreasing(t, []int{2, 1, 0})
// assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []float{2, 1})
// assert.IsDecreasing(t, []string{"b", "a"}) // assert.IsDecreasing(t, []string{"b", "a"})
func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
} }
// IsNonDecreasing asserts that the collection is not decreasing // IsNonDecreasing asserts that the collection is not decreasing
// //
// assert.IsNonDecreasing(t, []int{1, 1, 2}) // assert.IsNonDecreasing(t, []int{1, 1, 2})
// assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []float{1, 2})
// assert.IsNonDecreasing(t, []string{"a", "b"}) // assert.IsNonDecreasing(t, []string{"a", "b"})
func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
} }

View File

@ -8,7 +8,6 @@ import (
"fmt" "fmt"
"math" "math"
"os" "os"
"path/filepath"
"reflect" "reflect"
"regexp" "regexp"
"runtime" "runtime"
@ -20,7 +19,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib" "github.com/pmezard/go-difflib/difflib"
yaml "gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
@ -60,20 +59,101 @@ func ObjectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil { if expected == nil || actual == nil {
return expected == actual return expected == actual
} }
switch exp := expected.(type) {
exp, ok := expected.([]byte) case []byte:
if !ok { act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
case time.Time:
act, ok := actual.(time.Time)
if !ok {
return false
}
return exp.Equal(act)
default:
return reflect.DeepEqual(expected, actual) return reflect.DeepEqual(expected, actual)
} }
}
act, ok := actual.([]byte) // copyExportedFields iterates downward through nested data structures and creates a copy
if !ok { // that only contains the exported struct fields.
return false func copyExportedFields(expected interface{}) interface{} {
if isNil(expected) {
return expected
} }
if exp == nil || act == nil {
return exp == nil && act == nil expectedType := reflect.TypeOf(expected)
expectedKind := expectedType.Kind()
expectedValue := reflect.ValueOf(expected)
switch expectedKind {
case reflect.Struct:
result := reflect.New(expectedType).Elem()
for i := 0; i < expectedType.NumField(); i++ {
field := expectedType.Field(i)
isExported := field.IsExported()
if isExported {
fieldValue := expectedValue.Field(i)
if isNil(fieldValue) || isNil(fieldValue.Interface()) {
continue
}
newValue := copyExportedFields(fieldValue.Interface())
result.Field(i).Set(reflect.ValueOf(newValue))
}
}
return result.Interface()
case reflect.Ptr:
result := reflect.New(expectedType.Elem())
unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface())
result.Elem().Set(reflect.ValueOf(unexportedRemoved))
return result.Interface()
case reflect.Array, reflect.Slice:
var result reflect.Value
if expectedKind == reflect.Array {
result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem()
} else {
result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len())
}
for i := 0; i < expectedValue.Len(); i++ {
index := expectedValue.Index(i)
if isNil(index) {
continue
}
unexportedRemoved := copyExportedFields(index.Interface())
result.Index(i).Set(reflect.ValueOf(unexportedRemoved))
}
return result.Interface()
case reflect.Map:
result := reflect.MakeMap(expectedType)
for _, k := range expectedValue.MapKeys() {
index := expectedValue.MapIndex(k)
unexportedRemoved := copyExportedFields(index.Interface())
result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved))
}
return result.Interface()
default:
return expected
} }
return bytes.Equal(exp, act) }
// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are
// considered equal. This comparison of only exported fields is applied recursively to nested data
// structures.
//
// This function does no assertion of any kind.
func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
expectedCleaned := copyExportedFields(expected)
actualCleaned := copyExportedFields(actual)
return ObjectsAreEqualValues(expectedCleaned, actualCleaned)
} }
// ObjectsAreEqualValues gets whether two objects are equal, or if their // ObjectsAreEqualValues gets whether two objects are equal, or if their
@ -141,12 +221,11 @@ func CallerInfo() []string {
} }
parts := strings.Split(file, "/") parts := strings.Split(file, "/")
file = parts[len(parts)-1]
if len(parts) > 1 { if len(parts) > 1 {
filename := parts[len(parts)-1]
dir := parts[len(parts)-2] dir := parts[len(parts)-2]
if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" {
path, _ := filepath.Abs(file) callers = append(callers, fmt.Sprintf("%s:%d", file, line))
callers = append(callers, fmt.Sprintf("%s:%d", path, line))
} }
} }
@ -197,7 +276,7 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
// Aligns the provided message so that all lines after the first line start at the same location as the first line. // Aligns the provided message so that all lines after the first line start at the same location as the first line.
// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). // Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).
// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the // The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the
// basis on which the alignment occurs). // basis on which the alignment occurs).
func indentMessageLines(message string, longestLabelLen int) string { func indentMessageLines(message string, longestLabelLen int) string {
outBuf := new(bytes.Buffer) outBuf := new(bytes.Buffer)
@ -273,7 +352,7 @@ type labeledContent struct {
// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
// //
// \t{{label}}:{{align_spaces}}\t{{content}}\n // \t{{label}}:{{align_spaces}}\t{{content}}\n
// //
// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
@ -296,7 +375,7 @@ func labeledOutput(content ...labeledContent) string {
// Implements asserts that an object is implemented by the specified interface. // Implements asserts that an object is implemented by the specified interface.
// //
// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) // assert.Implements(t, (*MyInterface)(nil), new(MyObject))
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -328,7 +407,7 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
// Equal asserts that two objects are equal. // Equal asserts that two objects are equal.
// //
// assert.Equal(t, 123, 123) // assert.Equal(t, 123, 123)
// //
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
@ -369,7 +448,7 @@ func validateEqualArgs(expected, actual interface{}) error {
// Same asserts that two pointers reference the same object. // Same asserts that two pointers reference the same object.
// //
// assert.Same(t, ptr1, ptr2) // assert.Same(t, ptr1, ptr2)
// //
// Both arguments must be pointer variables. Pointer variable sameness is // Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value. // determined based on the equality of both type and value.
@ -389,7 +468,7 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
// NotSame asserts that two pointers do not reference the same object. // NotSame asserts that two pointers do not reference the same object.
// //
// assert.NotSame(t, ptr1, ptr2) // assert.NotSame(t, ptr1, ptr2)
// //
// Both arguments must be pointer variables. Pointer variable sameness is // Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value. // determined based on the equality of both type and value.
@ -427,7 +506,7 @@ func samePointers(first, second interface{}) bool {
// representations appropriate to be presented to the user. // representations appropriate to be presented to the user.
// //
// If the values are not of like type, the returned strings will be prefixed // If the values are not of like type, the returned strings will be prefixed
// with the type name, and the value will be enclosed in parenthesis similar // with the type name, and the value will be enclosed in parentheses similar
// to a type conversion in the Go grammar. // to a type conversion in the Go grammar.
func formatUnequalValues(expected, actual interface{}) (e string, a string) { func formatUnequalValues(expected, actual interface{}) (e string, a string) {
if reflect.TypeOf(expected) != reflect.TypeOf(actual) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
@ -454,10 +533,10 @@ func truncatingFormat(data interface{}) string {
return value return value
} }
// EqualValues asserts that two objects are equal or convertable to the same types // EqualValues asserts that two objects are equal or convertible to the same types
// and equal. // and equal.
// //
// assert.EqualValues(t, uint32(123), int32(123)) // assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -475,9 +554,53 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa
} }
// EqualExportedValues asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
aType := reflect.TypeOf(expected)
bType := reflect.TypeOf(actual)
if aType != bType {
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
}
if aType.Kind() != reflect.Struct {
return Fail(t, fmt.Sprintf("Types expected to both be struct \n\t%v != %v", aType.Kind(), reflect.Struct), msgAndArgs...)
}
if bType.Kind() != reflect.Struct {
return Fail(t, fmt.Sprintf("Types expected to both be struct \n\t%v != %v", bType.Kind(), reflect.Struct), msgAndArgs...)
}
expected = copyExportedFields(expected)
actual = copyExportedFields(actual)
if !ObjectsAreEqualValues(expected, actual) {
diff := diff(expected, actual)
expected, actual = formatUnequalValues(expected, actual)
return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+
"expected: %s\n"+
"actual : %s%s", expected, actual, diff), msgAndArgs...)
}
return true
}
// Exactly asserts that two objects are equal in value and type. // Exactly asserts that two objects are equal in value and type.
// //
// assert.Exactly(t, int32(123), int64(123)) // assert.Exactly(t, int32(123), int64(123))
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -496,7 +619,7 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
// NotNil asserts that the specified object is not nil. // NotNil asserts that the specified object is not nil.
// //
// assert.NotNil(t, err) // assert.NotNil(t, err)
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if !isNil(object) { if !isNil(object) {
return true return true
@ -530,7 +653,7 @@ func isNil(object interface{}) bool {
[]reflect.Kind{ []reflect.Kind{
reflect.Chan, reflect.Func, reflect.Chan, reflect.Func,
reflect.Interface, reflect.Map, reflect.Interface, reflect.Map,
reflect.Ptr, reflect.Slice}, reflect.Ptr, reflect.Slice, reflect.UnsafePointer},
kind) kind)
if isNilableKind && value.IsNil() { if isNilableKind && value.IsNil() {
@ -542,7 +665,7 @@ func isNil(object interface{}) bool {
// Nil asserts that the specified object is nil. // Nil asserts that the specified object is nil.
// //
// assert.Nil(t, err) // assert.Nil(t, err)
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if isNil(object) { if isNil(object) {
return true return true
@ -585,7 +708,7 @@ func isEmpty(object interface{}) bool {
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// assert.Empty(t, obj) // assert.Empty(t, obj)
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
pass := isEmpty(object) pass := isEmpty(object)
if !pass { if !pass {
@ -602,9 +725,9 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// if assert.NotEmpty(t, obj) { // if assert.NotEmpty(t, obj) {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
pass := !isEmpty(object) pass := !isEmpty(object)
if !pass { if !pass {
@ -618,27 +741,25 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
} }
// getLen try to get length of object. // getLen tries to get the length of an object.
// return (false, 0) if impossible. // It returns (0, false) if impossible.
func getLen(x interface{}) (ok bool, length int) { func getLen(x interface{}) (length int, ok bool) {
v := reflect.ValueOf(x) v := reflect.ValueOf(x)
defer func() { defer func() {
if e := recover(); e != nil { ok = recover() == nil
ok = false
}
}() }()
return true, v.Len() return v.Len(), true
} }
// Len asserts that the specified object has specific length. // Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept. // Len also fails if the object has a type that len() not accept.
// //
// assert.Len(t, mySlice, 3) // assert.Len(t, mySlice, 3)
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
} }
ok, l := getLen(object) l, ok := getLen(object)
if !ok { if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
} }
@ -651,7 +772,7 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
// True asserts that the specified value is true. // True asserts that the specified value is true.
// //
// assert.True(t, myBool) // assert.True(t, myBool)
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if !value { if !value {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
@ -666,7 +787,7 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
// False asserts that the specified value is false. // False asserts that the specified value is false.
// //
// assert.False(t, myBool) // assert.False(t, myBool)
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if value { if value {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
@ -681,7 +802,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
// NotEqual asserts that the specified values are NOT equal. // NotEqual asserts that the specified values are NOT equal.
// //
// assert.NotEqual(t, obj1, obj2) // assert.NotEqual(t, obj1, obj2)
// //
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
@ -704,7 +825,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
// NotEqualValues asserts that two objects are not equal even when converted to the same type // NotEqualValues asserts that two objects are not equal even when converted to the same type
// //
// assert.NotEqualValues(t, obj1, obj2) // assert.NotEqualValues(t, obj1, obj2)
func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -763,9 +884,9 @@ func containsElement(list interface{}, element interface{}) (ok, found bool) {
// Contains asserts that the specified string, list(array, slice...) or map contains the // Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element. // specified substring or element.
// //
// assert.Contains(t, "Hello World", "World") // assert.Contains(t, "Hello World", "World")
// assert.Contains(t, ["Hello", "World"], "World") // assert.Contains(t, ["Hello", "World"], "World")
// assert.Contains(t, {"Hello": "World"}, "Hello") // assert.Contains(t, {"Hello": "World"}, "Hello")
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -786,9 +907,9 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element. // specified substring or element.
// //
// assert.NotContains(t, "Hello World", "Earth") // assert.NotContains(t, "Hello World", "Earth")
// assert.NotContains(t, ["Hello", "World"], "Earth") // assert.NotContains(t, ["Hello", "World"], "Earth")
// assert.NotContains(t, {"Hello": "World"}, "Earth") // assert.NotContains(t, {"Hello": "World"}, "Earth")
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -796,10 +917,10 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
ok, found := containsElement(s, contains) ok, found := containsElement(s, contains)
if !ok { if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
} }
if found { if found {
return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...) return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...)
} }
return true return true
@ -809,7 +930,7 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
// Subset asserts that the specified list(array, slice...) contains all // Subset asserts that the specified list(array, slice...) contains all
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") // assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -818,49 +939,44 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
return true // we consider nil to be equal to the nil set return true // we consider nil to be equal to the nil set
} }
defer func() {
if e := recover(); e != nil {
ok = false
}
}()
listKind := reflect.TypeOf(list).Kind() listKind := reflect.TypeOf(list).Kind()
subsetKind := reflect.TypeOf(subset).Kind()
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
} }
subsetKind := reflect.TypeOf(subset).Kind()
if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
} }
subsetValue := reflect.ValueOf(subset)
if subsetKind == reflect.Map && listKind == reflect.Map { if subsetKind == reflect.Map && listKind == reflect.Map {
listValue := reflect.ValueOf(list) subsetMap := reflect.ValueOf(subset)
subsetKeys := subsetValue.MapKeys() actualMap := reflect.ValueOf(list)
for i := 0; i < len(subsetKeys); i++ { for _, k := range subsetMap.MapKeys() {
subsetKey := subsetKeys[i] ev := subsetMap.MapIndex(k)
subsetElement := subsetValue.MapIndex(subsetKey).Interface() av := actualMap.MapIndex(k)
listElement := listValue.MapIndex(subsetKey).Interface()
if !ObjectsAreEqual(subsetElement, listElement) { if !av.IsValid() {
return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, subsetElement), msgAndArgs...) return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
}
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
} }
} }
return true return true
} }
for i := 0; i < subsetValue.Len(); i++ { subsetList := reflect.ValueOf(subset)
element := subsetValue.Index(i).Interface() for i := 0; i < subsetList.Len(); i++ {
element := subsetList.Index(i).Interface()
ok, found := containsElement(list, element) ok, found := containsElement(list, element)
if !ok { if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
} }
if !found { if !found {
return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...) return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...)
} }
} }
@ -870,7 +986,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
// NotSubset asserts that the specified list(array, slice...) contains not all // NotSubset asserts that the specified list(array, slice...) contains not all
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") // assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -879,34 +995,28 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...)
} }
defer func() {
if e := recover(); e != nil {
ok = false
}
}()
listKind := reflect.TypeOf(list).Kind() listKind := reflect.TypeOf(list).Kind()
subsetKind := reflect.TypeOf(subset).Kind()
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
} }
subsetKind := reflect.TypeOf(subset).Kind()
if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
} }
subsetValue := reflect.ValueOf(subset)
if subsetKind == reflect.Map && listKind == reflect.Map { if subsetKind == reflect.Map && listKind == reflect.Map {
listValue := reflect.ValueOf(list) subsetMap := reflect.ValueOf(subset)
subsetKeys := subsetValue.MapKeys() actualMap := reflect.ValueOf(list)
for i := 0; i < len(subsetKeys); i++ { for _, k := range subsetMap.MapKeys() {
subsetKey := subsetKeys[i] ev := subsetMap.MapIndex(k)
subsetElement := subsetValue.MapIndex(subsetKey).Interface() av := actualMap.MapIndex(k)
listElement := listValue.MapIndex(subsetKey).Interface()
if !ObjectsAreEqual(subsetElement, listElement) { if !av.IsValid() {
return true
}
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
return true return true
} }
} }
@ -914,8 +1024,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
} }
for i := 0; i < subsetValue.Len(); i++ { subsetList := reflect.ValueOf(subset)
element := subsetValue.Index(i).Interface() for i := 0; i < subsetList.Len(); i++ {
element := subsetList.Index(i).Interface()
ok, found := containsElement(list, element) ok, found := containsElement(list, element)
if !ok { if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...)
@ -1060,7 +1171,7 @@ func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string
// Panics asserts that the code inside the specified PanicTestFunc panics. // Panics asserts that the code inside the specified PanicTestFunc panics.
// //
// assert.Panics(t, func(){ GoCrazy() }) // assert.Panics(t, func(){ GoCrazy() })
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1076,7 +1187,7 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) // assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1097,7 +1208,7 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr
// panics, and that the recovered panic value is an error that satisfies the // panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison. // EqualError comparison.
// //
// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) // assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1117,7 +1228,7 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs .
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// assert.NotPanics(t, func(){ RemainCalm() }) // assert.NotPanics(t, func(){ RemainCalm() })
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1132,7 +1243,7 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
// WithinDuration asserts that the two times are within duration delta of each other. // WithinDuration asserts that the two times are within duration delta of each other.
// //
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) // assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1148,7 +1259,7 @@ func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration,
// WithinRange asserts that a time is within a time range (inclusive). // WithinRange asserts that a time is within a time range (inclusive).
// //
// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) // assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool { func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1207,7 +1318,7 @@ func toFloat(x interface{}) (float64, bool) {
// InDelta asserts that the two numerals are within delta of each other. // InDelta asserts that the two numerals are within delta of each other.
// //
// assert.InDelta(t, math.Pi, 22/7.0, 0.01) // assert.InDelta(t, math.Pi, 22/7.0, 0.01)
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1380,10 +1491,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
// NoError asserts that a function returned no error (i.e. `nil`). // NoError asserts that a function returned no error (i.e. `nil`).
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// if assert.NoError(t, err) { // if assert.NoError(t, err) {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
if err != nil { if err != nil {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
@ -1397,10 +1508,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
// Error asserts that a function returned an error (i.e. not `nil`). // Error asserts that a function returned an error (i.e. not `nil`).
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// if assert.Error(t, err) { // if assert.Error(t, err) {
// assert.Equal(t, expectedError, err) // assert.Equal(t, expectedError, err)
// } // }
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
if err == nil { if err == nil {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
@ -1415,8 +1526,8 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
// EqualError asserts that a function returned an error (i.e. not `nil`) // EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error. // and that it is equal to the provided error.
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// assert.EqualError(t, err, expectedErrorString) // assert.EqualError(t, err, expectedErrorString)
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1438,8 +1549,8 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
// ErrorContains asserts that a function returned an error (i.e. not `nil`) // ErrorContains asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring. // and that the error contains the specified substring.
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// assert.ErrorContains(t, err, expectedErrorSubString) // assert.ErrorContains(t, err, expectedErrorSubString)
func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1472,8 +1583,8 @@ func matchRegexp(rx interface{}, str interface{}) bool {
// Regexp asserts that a specified regexp matches a string. // Regexp asserts that a specified regexp matches a string.
// //
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") // assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting") // assert.Regexp(t, "start...$", "it's not starting")
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1490,8 +1601,8 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface
// NotRegexp asserts that a specified regexp does not match a string. // NotRegexp asserts that a specified regexp does not match a string.
// //
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") // assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting") // assert.NotRegexp(t, "^start", "it's not starting")
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1603,7 +1714,7 @@ func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
// JSONEq asserts that two JSON strings are equivalent. // JSONEq asserts that two JSON strings are equivalent.
// //
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) // assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1726,7 +1837,7 @@ type tHelper interface {
// Eventually asserts that given condition will be met in waitFor time, // Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. // periodically checking target function each tick.
// //
// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) // assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()
@ -1756,10 +1867,94 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
} }
} }
// CollectT implements the TestingT interface and collects all errors.
type CollectT struct {
errors []error
}
// Errorf collects the error.
func (c *CollectT) Errorf(format string, args ...interface{}) {
c.errors = append(c.errors, fmt.Errorf(format, args...))
}
// FailNow panics.
func (*CollectT) FailNow() {
panic("Assertion failed")
}
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
func (*CollectT) Reset() {
panic("Reset() is deprecated")
}
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
func (*CollectT) Copy(TestingT) {
panic("Copy() is deprecated")
}
// EventuallyWithT asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// assert.EventuallyWithT(t, func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var lastFinishedTickErrs []error
ch := make(chan []error, 1)
timer := time.NewTimer(waitFor)
defer timer.Stop()
ticker := time.NewTicker(tick)
defer ticker.Stop()
for tick := ticker.C; ; {
select {
case <-timer.C:
for _, err := range lastFinishedTickErrs {
t.Errorf("%v", err)
}
return Fail(t, "Condition never satisfied", msgAndArgs...)
case <-tick:
tick = nil
go func() {
collect := new(CollectT)
defer func() {
ch <- collect.errors
}()
condition(collect)
}()
case errs := <-ch:
if len(errs) == 0 {
return true
}
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
lastFinishedTickErrs = errs
tick = ticker.C
}
}
}
// Never asserts that the given condition doesn't satisfy in waitFor time, // Never asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick. // periodically checking the target function each tick.
// //
// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) // assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok { if h, ok := t.(tHelper); ok {
h.Helper() h.Helper()

View File

@ -9,12 +9,14 @@ import (
"io" "io"
"math" "math"
"os" "os"
"path/filepath"
"reflect" "reflect"
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"testing" "testing"
"time" "time"
"unsafe"
) )
var ( var (
@ -146,6 +148,289 @@ func TestObjectsAreEqual(t *testing.T) {
t.Fail() t.Fail()
} }
tm := time.Now()
tz := tm.In(time.Local)
if !ObjectsAreEqualValues(tm, tz) {
t.Error("ObjectsAreEqualValues should return true for time.Time objects with different time zones")
}
}
type Nested struct {
Exported interface{}
notExported interface{}
}
type S struct {
Exported1 interface{}
Exported2 Nested
notExported1 interface{}
notExported2 Nested
}
type S2 struct {
foo interface{}
}
type S3 struct {
Exported1 *Nested
Exported2 *Nested
}
type S4 struct {
Exported1 []*Nested
}
type S5 struct {
Exported Nested
}
type S6 struct {
Exported string
unexported string
}
func TestObjectsExportedFieldsAreEqual(t *testing.T) {
intValue := 1
cases := []struct {
expected interface{}
actual interface{}
result bool
}{
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, 4, Nested{5, 6}}, true},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, "a", Nested{5, 6}}, true},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, 4, Nested{5, "a"}}, true},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, 3}, 4, Nested{"a", "a"}}, true},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{2, "a"}, 4, Nested{5, 6}}, true},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{"a", Nested{2, 3}, 4, Nested{5, 6}}, false},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S{1, Nested{"a", 3}, 4, Nested{5, 6}}, false},
{S{1, Nested{2, 3}, 4, Nested{5, 6}}, S2{1}, false},
{1, S{1, Nested{2, 3}, 4, Nested{5, 6}}, false},
{S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{1, 2}, &Nested{3, 4}}, true},
{S3{nil, &Nested{3, 4}}, S3{nil, &Nested{3, 4}}, true},
{S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{1, 2}, &Nested{3, "b"}}, true},
{S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{1, "a"}, &Nested{3, "b"}}, true},
{S3{&Nested{1, 2}, &Nested{3, 4}}, S3{&Nested{"a", 2}, &Nested{3, 4}}, false},
{S3{&Nested{1, 2}, &Nested{3, 4}}, S3{}, false},
{S3{}, S3{}, true},
{S4{[]*Nested{{1, 2}}}, S4{[]*Nested{{1, 2}}}, true},
{S4{[]*Nested{{1, 2}}}, S4{[]*Nested{{1, 3}}}, true},
{S4{[]*Nested{{1, 2}, {3, 4}}}, S4{[]*Nested{{1, "a"}, {3, "b"}}}, true},
{S4{[]*Nested{{1, 2}, {3, 4}}}, S4{[]*Nested{{1, "a"}, {2, "b"}}}, false},
{Nested{&intValue, 2}, Nested{&intValue, 2}, true},
{Nested{&Nested{1, 2}, 3}, Nested{&Nested{1, "b"}, 3}, true},
{Nested{&Nested{1, 2}, 3}, Nested{nil, 3}, false},
{
Nested{map[interface{}]*Nested{nil: nil}, 2},
Nested{map[interface{}]*Nested{nil: nil}, 2},
true,
},
{
Nested{map[interface{}]*Nested{"a": nil}, 2},
Nested{map[interface{}]*Nested{"a": nil}, 2},
true,
},
{
Nested{map[interface{}]*Nested{"a": nil}, 2},
Nested{map[interface{}]*Nested{"a": {1, 2}}, 2},
false,
},
{
Nested{map[interface{}]Nested{"a": {1, 2}, "b": {3, 4}}, 2},
Nested{map[interface{}]Nested{"a": {1, 5}, "b": {3, 7}}, 2},
true,
},
{
Nested{map[interface{}]Nested{"a": {1, 2}, "b": {3, 4}}, 2},
Nested{map[interface{}]Nested{"a": {2, 2}, "b": {3, 4}}, 2},
false,
},
}
for _, c := range cases {
t.Run(fmt.Sprintf("ObjectsExportedFieldsAreEqual(%#v, %#v)", c.expected, c.actual), func(t *testing.T) {
res := ObjectsExportedFieldsAreEqual(c.expected, c.actual)
if res != c.result {
t.Errorf("ObjectsExportedFieldsAreEqual(%#v, %#v) should return %#v", c.expected, c.actual, c.result)
}
})
}
}
func TestCopyExportedFields(t *testing.T) {
intValue := 1
cases := []struct {
input interface{}
expected interface{}
}{
{
input: Nested{"a", "b"},
expected: Nested{"a", nil},
},
{
input: Nested{&intValue, 2},
expected: Nested{&intValue, nil},
},
{
input: Nested{nil, 3},
expected: Nested{nil, nil},
},
{
input: S{1, Nested{2, 3}, 4, Nested{5, 6}},
expected: S{1, Nested{2, nil}, nil, Nested{}},
},
{
input: S3{},
expected: S3{},
},
{
input: S3{&Nested{1, 2}, &Nested{3, 4}},
expected: S3{&Nested{1, nil}, &Nested{3, nil}},
},
{
input: S3{Exported1: &Nested{"a", "b"}},
expected: S3{Exported1: &Nested{"a", nil}},
},
{
input: S4{[]*Nested{
nil,
{1, 2},
}},
expected: S4{[]*Nested{
nil,
{1, nil},
}},
},
{
input: S4{[]*Nested{
{1, 2}},
},
expected: S4{[]*Nested{
{1, nil}},
},
},
{
input: S4{[]*Nested{
{1, 2},
{3, 4},
}},
expected: S4{[]*Nested{
{1, nil},
{3, nil},
}},
},
{
input: S5{Exported: Nested{"a", "b"}},
expected: S5{Exported: Nested{"a", nil}},
},
{
input: S6{"a", "b"},
expected: S6{"a", ""},
},
}
for _, c := range cases {
t.Run("", func(t *testing.T) {
output := copyExportedFields(c.input)
if !ObjectsAreEqualValues(c.expected, output) {
t.Errorf("%#v, %#v should be equal", c.expected, output)
}
})
}
}
func TestEqualExportedValues(t *testing.T) {
cases := []struct {
value1 interface{}
value2 interface{}
expectedEqual bool
expectedFail string
}{
{
value1: S{1, Nested{2, 3}, 4, Nested{5, 6}},
value2: S{1, Nested{2, nil}, nil, Nested{}},
expectedEqual: true,
},
{
value1: S{1, Nested{2, 3}, 4, Nested{5, 6}},
value2: S{1, Nested{1, nil}, nil, Nested{}},
expectedEqual: false,
expectedFail: `
Diff:
--- Expected
+++ Actual
@@ -3,3 +3,3 @@
Exported2: (assert.Nested) {
- Exported: (int) 2,
+ Exported: (int) 1,
notExported: (interface {}) <nil>`,
},
{
value1: S3{&Nested{1, 2}, &Nested{3, 4}},
value2: S3{&Nested{"a", 2}, &Nested{3, 4}},
expectedEqual: false,
expectedFail: `
Diff:
--- Expected
+++ Actual
@@ -2,3 +2,3 @@
Exported1: (*assert.Nested)({
- Exported: (int) 1,
+ Exported: (string) (len=1) "a",
notExported: (interface {}) <nil>`,
},
{
value1: S4{[]*Nested{
{1, 2},
{3, 4},
}},
value2: S4{[]*Nested{
{1, "a"},
{2, "b"},
}},
expectedEqual: false,
expectedFail: `
Diff:
--- Expected
+++ Actual
@@ -7,3 +7,3 @@
(*assert.Nested)({
- Exported: (int) 3,
+ Exported: (int) 2,
notExported: (interface {}) <nil>`,
},
{
value1: S{[2]int{1, 2}, Nested{2, 3}, 4, Nested{5, 6}},
value2: S{[2]int{1, 2}, Nested{2, nil}, nil, Nested{}},
expectedEqual: true,
},
}
for _, c := range cases {
t.Run("", func(t *testing.T) {
mockT := new(mockTestingT)
actual := EqualExportedValues(mockT, c.value1, c.value2)
if actual != c.expectedEqual {
t.Errorf("Expected EqualExportedValues to be %t, but was %t", c.expectedEqual, actual)
}
actualFail := mockT.errorString()
if !strings.Contains(actualFail, c.expectedFail) {
t.Errorf("Contains failure should include %q but was %q", c.expectedFail, actualFail)
}
})
}
} }
func TestImplements(t *testing.T) { func TestImplements(t *testing.T) {
@ -642,15 +927,59 @@ func TestContainsNotContains(t *testing.T) {
} }
} }
func TestContainsFailMessage(t *testing.T) { func TestContainsNotContainsFailMessage(t *testing.T) {
mockT := new(mockTestingT) mockT := new(mockTestingT)
Contains(mockT, "Hello World", errors.New("Hello")) type nonContainer struct {
expectedFail := "\"Hello World\" does not contain &errors.errorString{s:\"Hello\"}" Value string
actualFail := mockT.errorString() }
if !strings.Contains(actualFail, expectedFail) {
t.Errorf("Contains failure should include %q but was %q", expectedFail, actualFail) cases := []struct {
assertion func(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool
container interface{}
instance interface{}
expected string
}{
{
assertion: Contains,
container: "Hello World",
instance: errors.New("Hello"),
expected: "\"Hello World\" does not contain &errors.errorString{s:\"Hello\"}",
},
{
assertion: Contains,
container: map[string]int{"one": 1},
instance: "two",
expected: "map[string]int{\"one\":1} does not contain \"two\"\n",
},
{
assertion: NotContains,
container: map[string]int{"one": 1},
instance: "one",
expected: "map[string]int{\"one\":1} should not contain \"one\"",
},
{
assertion: Contains,
container: nonContainer{Value: "Hello"},
instance: "Hello",
expected: "assert.nonContainer{Value:\"Hello\"} could not be applied builtin len()\n",
},
{
assertion: NotContains,
container: nonContainer{Value: "Hello"},
instance: "Hello",
expected: "assert.nonContainer{Value:\"Hello\"} could not be applied builtin len()\n",
},
}
for _, c := range cases {
name := filepath.Base(runtime.FuncForPC(reflect.ValueOf(c.assertion).Pointer()).Name())
t.Run(fmt.Sprintf("%v(%T, %T)", name, c.container, c.instance), func(t *testing.T) {
c.assertion(mockT, c.container, c.instance)
actualFail := mockT.errorString()
if !strings.Contains(actualFail, c.expected) {
t.Errorf("Contains failure should include %q but was %q", c.expected, actualFail)
}
})
} }
} }
@ -671,20 +1000,18 @@ func TestContainsNotContainsOnNilValue(t *testing.T) {
} }
func TestSubsetNotSubset(t *testing.T) { func TestSubsetNotSubset(t *testing.T) {
// MTestCase adds a custom message to the case
cases := []struct { cases := []struct {
expected interface{} list interface{}
actual interface{} subset interface{}
result bool result bool
message string message string
}{ }{
// cases that are expected to contain // cases that are expected to contain
{[]int{1, 2, 3}, nil, true, "given subset is nil"}, {[]int{1, 2, 3}, nil, true, `nil is the empty set which is a subset of every set`},
{[]int{1, 2, 3}, []int{}, true, "any set contains the nil set"}, {[]int{1, 2, 3}, []int{}, true, `[] is a subset of ['\x01' '\x02' '\x03']`},
{[]int{1, 2, 3}, []int{1, 2}, true, "[1, 2, 3] contains [1, 2]"}, {[]int{1, 2, 3}, []int{1, 2}, true, `['\x01' '\x02'] is a subset of ['\x01' '\x02' '\x03']`},
{[]int{1, 2, 3}, []int{1, 2, 3}, true, "[1, 2, 3] contains [1, 2, 3"}, {[]int{1, 2, 3}, []int{1, 2, 3}, true, `['\x01' '\x02' '\x03'] is a subset of ['\x01' '\x02' '\x03']`},
{[]string{"hello", "world"}, []string{"hello"}, true, "[\"hello\", \"world\"] contains [\"hello\"]"}, {[]string{"hello", "world"}, []string{"hello"}, true, `["hello"] is a subset of ["hello" "world"]`},
{map[string]string{ {map[string]string{
"a": "x", "a": "x",
"c": "z", "c": "z",
@ -692,12 +1019,12 @@ func TestSubsetNotSubset(t *testing.T) {
}, map[string]string{ }, map[string]string{
"a": "x", "a": "x",
"b": "y", "b": "y",
}, true, `{ "a": "x", "b": "y", "c": "z"} contains { "a": "x", "b": "y"}`}, }, true, `map["a":"x" "b":"y"] is a subset of map["a":"x" "b":"y" "c":"z"]`},
// cases that are expected not to contain // cases that are expected not to contain
{[]string{"hello", "world"}, []string{"hello", "testify"}, false, "[\"hello\", \"world\"] does not contain [\"hello\", \"testify\"]"}, {[]string{"hello", "world"}, []string{"hello", "testify"}, false, `[]string{"hello", "world"} does not contain "testify"`},
{[]int{1, 2, 3}, []int{4, 5}, false, "[1, 2, 3] does not contain [4, 5"}, {[]int{1, 2, 3}, []int{4, 5}, false, `[]int{1, 2, 3} does not contain 4`},
{[]int{1, 2, 3}, []int{1, 5}, false, "[1, 2, 3] does not contain [1, 5]"}, {[]int{1, 2, 3}, []int{1, 5}, false, `[]int{1, 2, 3} does not contain 5`},
{map[string]string{ {map[string]string{
"a": "x", "a": "x",
"c": "z", "c": "z",
@ -705,35 +1032,51 @@ func TestSubsetNotSubset(t *testing.T) {
}, map[string]string{ }, map[string]string{
"a": "x", "a": "x",
"b": "z", "b": "z",
}, false, `{ "a": "x", "b": "y", "c": "z"} does not contain { "a": "x", "b": "z"}`}, }, false, `map[string]string{"a":"x", "b":"y", "c":"z"} does not contain map[string]string{"a":"x", "b":"z"}`},
{map[string]string{
"a": "x",
"b": "y",
}, map[string]string{
"a": "x",
"b": "y",
"c": "z",
}, false, `map[string]string{"a":"x", "b":"y"} does not contain map[string]string{"a":"x", "b":"y", "c":"z"}`},
} }
for _, c := range cases { for _, c := range cases {
t.Run("SubSet: "+c.message, func(t *testing.T) { t.Run("SubSet: "+c.message, func(t *testing.T) {
mockT := new(testing.T) mockT := new(mockTestingT)
res := Subset(mockT, c.expected, c.actual) res := Subset(mockT, c.list, c.subset)
if res != c.result { if res != c.result {
if res { t.Errorf("Subset should return %t: %s", c.result, c.message)
t.Errorf("Subset should return true: %s", c.message) }
} else { if !c.result {
t.Errorf("Subset should return false: %s", c.message) expectedFail := c.message
actualFail := mockT.errorString()
if !strings.Contains(actualFail, expectedFail) {
t.Log(actualFail)
t.Errorf("Subset failure should contain %q but was %q", expectedFail, actualFail)
} }
} }
}) })
} }
for _, c := range cases { for _, c := range cases {
t.Run("NotSubSet: "+c.message, func(t *testing.T) { t.Run("NotSubSet: "+c.message, func(t *testing.T) {
mockT := new(testing.T) mockT := new(mockTestingT)
res := NotSubset(mockT, c.expected, c.actual) res := NotSubset(mockT, c.list, c.subset)
// NotSubset should match the inverse of Subset. If it doesn't, something is wrong // NotSubset should match the inverse of Subset. If it doesn't, something is wrong
if res == Subset(mockT, c.expected, c.actual) { if res == Subset(mockT, c.list, c.subset) {
if res { t.Errorf("NotSubset should return %t: %s", !c.result, c.message)
t.Errorf("NotSubset should return true: %s", c.message) }
} else { if c.result {
t.Errorf("NotSubset should return false: %s", c.message) expectedFail := c.message
actualFail := mockT.errorString()
if !strings.Contains(actualFail, expectedFail) {
t.Log(actualFail)
t.Errorf("NotSubset failure should contain %q but was %q", expectedFail, actualFail)
} }
} }
}) })
@ -1096,7 +1439,7 @@ func TestError(t *testing.T) {
True(t, Error(mockT, err), "Error with error should return True") True(t, Error(mockT, err), "Error with error should return True")
// go vet check // go vet check
True(t, Errorf(mockT, err, "example with %s", "formatted message"), "Errorf with error should rturn True") True(t, Errorf(mockT, err, "example with %s", "formatted message"), "Errorf with error should return True")
// returning an empty error interface // returning an empty error interface
err = func() error { err = func() error {
@ -1250,7 +1593,7 @@ func Test_getLen(t *testing.T) {
struct{}{}, struct{}{},
} }
for _, v := range falseCases { for _, v := range falseCases {
ok, l := getLen(v) l, ok := getLen(v)
False(t, ok, "Expected getLen fail to get length of %#v", v) False(t, ok, "Expected getLen fail to get length of %#v", v)
Equal(t, 0, l, "getLen should return 0 for %#v", v) Equal(t, 0, l, "getLen should return 0 for %#v", v)
} }
@ -1279,7 +1622,7 @@ func Test_getLen(t *testing.T) {
} }
for _, c := range trueCases { for _, c := range trueCases {
ok, l := getLen(c.v) l, ok := getLen(c.v)
True(t, ok, "Expected getLen success to get length of %#v", c.v) True(t, ok, "Expected getLen success to get length of %#v", c.v)
Equal(t, c.l, l) Equal(t, c.l, l)
} }
@ -1575,12 +1918,12 @@ func TestInEpsilonSlice(t *testing.T) {
True(t, InEpsilonSlice(mockT, True(t, InEpsilonSlice(mockT,
[]float64{2.2, math.NaN(), 2.0}, []float64{2.2, math.NaN(), 2.0},
[]float64{2.1, math.NaN(), 2.1}, []float64{2.1, math.NaN(), 2.1},
0.06), "{2.2, NaN, 2.0} is element-wise close to {2.1, NaN, 2.1} in espilon=0.06") 0.06), "{2.2, NaN, 2.0} is element-wise close to {2.1, NaN, 2.1} in epsilon=0.06")
False(t, InEpsilonSlice(mockT, False(t, InEpsilonSlice(mockT,
[]float64{2.2, 2.0}, []float64{2.2, 2.0},
[]float64{2.1, 2.1}, []float64{2.1, 2.1},
0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04") 0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in epsilon=0.04")
False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
} }
@ -2428,6 +2771,78 @@ func TestEventuallyTrue(t *testing.T) {
True(t, Eventually(t, condition, 100*time.Millisecond, 20*time.Millisecond)) True(t, Eventually(t, condition, 100*time.Millisecond, 20*time.Millisecond))
} }
// errorsCapturingT is a mock implementation of TestingT that captures errors reported with Errorf.
type errorsCapturingT struct {
errors []error
}
func (t *errorsCapturingT) Errorf(format string, args ...interface{}) {
t.errors = append(t.errors, fmt.Errorf(format, args...))
}
func (t *errorsCapturingT) Helper() {}
func TestEventuallyWithTFalse(t *testing.T) {
mockT := new(errorsCapturingT)
condition := func(collect *CollectT) {
Fail(collect, "condition fixed failure")
}
False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
Len(t, mockT.errors, 2)
}
func TestEventuallyWithTTrue(t *testing.T) {
mockT := new(errorsCapturingT)
state := 0
condition := func(collect *CollectT) {
defer func() {
state += 1
}()
True(collect, state == 2)
}
True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
Len(t, mockT.errors, 0)
}
func TestEventuallyWithT_ConcurrencySafe(t *testing.T) {
mockT := new(errorsCapturingT)
condition := func(collect *CollectT) {
Fail(collect, "condition fixed failure")
}
// To trigger race conditions, we run EventuallyWithT with a nanosecond tick.
False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, time.Nanosecond))
Len(t, mockT.errors, 2)
}
func TestEventuallyWithT_ReturnsTheLatestFinishedConditionErrors(t *testing.T) {
// We'll use a channel to control whether a condition should sleep or not.
mustSleep := make(chan bool, 2)
mustSleep <- false
mustSleep <- true
close(mustSleep)
condition := func(collect *CollectT) {
if <-mustSleep {
// Sleep to ensure that the second condition runs longer than timeout.
time.Sleep(time.Second)
return
}
// The first condition will fail. We expect to get this error as a result.
Fail(collect, "condition fixed failure")
}
mockT := new(errorsCapturingT)
False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
Len(t, mockT.errors, 2)
}
func TestNeverFalse(t *testing.T) { func TestNeverFalse(t *testing.T) {
condition := func() bool { condition := func() bool {
return false return false
@ -2436,14 +2851,20 @@ func TestNeverFalse(t *testing.T) {
True(t, Never(t, condition, 100*time.Millisecond, 20*time.Millisecond)) True(t, Never(t, condition, 100*time.Millisecond, 20*time.Millisecond))
} }
// TestNeverTrue checks Never with a condition that returns true on second call.
func TestNeverTrue(t *testing.T) { func TestNeverTrue(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
state := 0
// A list of values returned by condition.
// Channel protects against concurrent access.
returns := make(chan bool, 2)
returns <- false
returns <- true
defer close(returns)
// Will return true on second call.
condition := func() bool { condition := func() bool {
defer func() { return <-returns
state = state + 1
}()
return state == 2
} }
False(t, Never(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)) False(t, Never(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
@ -2558,3 +2979,10 @@ func TestErrorAs(t *testing.T) {
}) })
} }
} }
func TestIsNil(t *testing.T) {
var n unsafe.Pointer = nil
if !isNil(n) {
t.Fatal("fail")
}
}

View File

@ -1,39 +1,40 @@
// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
// //
// Example Usage // # Example Usage
// //
// The following is a complete example using assert in a standard test function: // The following is a complete example using assert in a standard test function:
// import (
// "testing"
// "github.com/stretchr/testify/assert"
// )
// //
// func TestSomething(t *testing.T) { // import (
// "testing"
// "github.com/stretchr/testify/assert"
// )
// //
// var a string = "Hello" // func TestSomething(t *testing.T) {
// var b string = "Hello"
// //
// assert.Equal(t, a, b, "The two words should be the same.") // var a string = "Hello"
// var b string = "Hello"
// //
// } // assert.Equal(t, a, b, "The two words should be the same.")
//
// }
// //
// if you assert many times, use the format below: // if you assert many times, use the format below:
// //
// import ( // import (
// "testing" // "testing"
// "github.com/stretchr/testify/assert" // "github.com/stretchr/testify/assert"
// ) // )
// //
// func TestSomething(t *testing.T) { // func TestSomething(t *testing.T) {
// assert := assert.New(t) // assert := assert.New(t)
// //
// var a string = "Hello" // var a string = "Hello"
// var b string = "Hello" // var b string = "Hello"
// //
// assert.Equal(a, b, "The two words should be the same.") // assert.Equal(a, b, "The two words should be the same.")
// } // }
// //
// Assertions // # Assertions
// //
// Assertions allow you to easily write test code, and are global funcs in the `assert` package. // Assertions allow you to easily write test code, and are global funcs in the `assert` package.
// All assertion functions take, as the first argument, the `*testing.T` object provided by the // All assertion functions take, as the first argument, the `*testing.T` object provided by the

View File

@ -12,7 +12,7 @@ import (
// an error if building a new request fails. // an error if building a new request fails.
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest(method, url, nil) req, err := http.NewRequest(method, url, http.NoBody)
if err != nil { if err != nil {
return -1, err return -1, err
} }
@ -23,7 +23,7 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (
// HTTPSuccess asserts that a specified handler returns a success status code. // HTTPSuccess asserts that a specified handler returns a success status code.
// //
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
@ -45,7 +45,7 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
// HTTPRedirect asserts that a specified handler returns a redirect status code. // HTTPRedirect asserts that a specified handler returns a redirect status code.
// //
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
@ -67,7 +67,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
// HTTPError asserts that a specified handler returns an error status code. // HTTPError asserts that a specified handler returns an error status code.
// //
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
@ -89,7 +89,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values
// HTTPStatusCode asserts that a specified handler returns a specified status code. // HTTPStatusCode asserts that a specified handler returns a specified status code.
// //
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) // assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
@ -113,7 +113,10 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va
// empty string if building a new request fails. // empty string if building a new request fails.
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) if len(values) > 0 {
url += "?" + values.Encode()
}
req, err := http.NewRequest(method, url, http.NoBody)
if err != nil { if err != nil {
return "" return ""
} }
@ -124,7 +127,7 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
// HTTPBodyContains asserts that a specified handler returns a // HTTPBodyContains asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
@ -144,7 +147,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
// HTTPBodyNotContains asserts that a specified handler returns a // HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {

View File

@ -2,6 +2,7 @@ package assert
import ( import (
"fmt" "fmt"
"io"
"net/http" "net/http"
"net/url" "net/url"
"testing" "testing"
@ -11,6 +12,12 @@ func httpOK(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func httpReadBody(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(io.Discard, r.Body)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello"))
}
func httpRedirect(w http.ResponseWriter, r *http.Request) { func httpRedirect(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTemporaryRedirect) w.WriteHeader(http.StatusTemporaryRedirect)
} }
@ -41,6 +48,10 @@ func TestHTTPSuccess(t *testing.T) {
mockT4 := new(testing.T) mockT4 := new(testing.T)
assert.Equal(HTTPSuccess(mockT4, httpStatusCode, "GET", "/", nil), false) assert.Equal(HTTPSuccess(mockT4, httpStatusCode, "GET", "/", nil), false)
assert.True(mockT4.Failed()) assert.True(mockT4.Failed())
mockT5 := new(testing.T)
assert.Equal(HTTPSuccess(mockT5, httpReadBody, "POST", "/", nil), true)
assert.False(mockT5.Failed())
} }
func TestHTTPRedirect(t *testing.T) { func TestHTTPRedirect(t *testing.T) {
@ -122,7 +133,7 @@ func TestHTTPStatusesWrapper(t *testing.T) {
func httpHelloName(w http.ResponseWriter, r *http.Request) { func httpHelloName(w http.ResponseWriter, r *http.Request) {
name := r.FormValue("name") name := r.FormValue("name")
_, _ = w.Write([]byte(fmt.Sprintf("Hello, %s!", name))) _, _ = fmt.Fprintf(w, "Hello, %s!", name)
} }
func TestHTTPRequestWithNoParams(t *testing.T) { func TestHTTPRequestWithNoParams(t *testing.T) {
@ -165,6 +176,8 @@ func TestHttpBody(t *testing.T) {
assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
assert.True(HTTPBodyContains(mockT, httpReadBody, "GET", "/", nil, "hello"))
} }
func TestHttpBodyWrappers(t *testing.T) { func TestHttpBodyWrappers(t *testing.T) {
@ -178,5 +191,4 @@ func TestHttpBodyWrappers(t *testing.T) {
assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
} }

6
go.mod
View File

@ -1,10 +1,12 @@
module github.com/stretchr/testify module github.com/stretchr/testify
go 1.13 // This should match the minimum supported version that is tested in
// .github/workflows/main.yml
go 1.17
require ( require (
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.4.0 github.com/stretchr/objx v0.5.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )

4
go.sum
View File

@ -4,9 +4,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,17 +1,17 @@
// Package mock provides a system by which it is possible to mock your objects // Package mock provides a system by which it is possible to mock your objects
// and verify calls are happening as expected. // and verify calls are happening as expected.
// //
// Example Usage // # Example Usage
// //
// The mock package provides an object, Mock, that tracks activity on another object. It is usually // The mock package provides an object, Mock, that tracks activity on another object. It is usually
// embedded into a test object as shown below: // embedded into a test object as shown below:
// //
// type MyTestObject struct { // type MyTestObject struct {
// // add a Mock object instance // // add a Mock object instance
// mock.Mock // mock.Mock
// //
// // other fields go here as normal // // other fields go here as normal
// } // }
// //
// When implementing the methods of an interface, you wire your functions up // When implementing the methods of an interface, you wire your functions up
// to call the Mock.Called(args...) method, and return the appropriate values. // to call the Mock.Called(args...) method, and return the appropriate values.
@ -19,25 +19,25 @@
// For example, to mock a method that saves the name and age of a person and returns // For example, to mock a method that saves the name and age of a person and returns
// the year of their birth or an error, you might write this: // the year of their birth or an error, you might write this:
// //
// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { // func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
// args := o.Called(firstname, lastname, age) // args := o.Called(firstname, lastname, age)
// return args.Int(0), args.Error(1) // return args.Int(0), args.Error(1)
// } // }
// //
// The Int, Error and Bool methods are examples of strongly typed getters that take the argument // The Int, Error and Bool methods are examples of strongly typed getters that take the argument
// index position. Given this argument list: // index position. Given this argument list:
// //
// (12, true, "Something") // (12, true, "Something")
// //
// You could read them out strongly typed like this: // You could read them out strongly typed like this:
// //
// args.Int(0) // args.Int(0)
// args.Bool(1) // args.Bool(1)
// args.String(2) // args.String(2)
// //
// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: // For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
// //
// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) // return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
// //
// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those // This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
// cases you should check for nil first. // cases you should check for nil first.

View File

@ -3,6 +3,7 @@ package mock
import ( import (
"errors" "errors"
"fmt" "fmt"
"path"
"reflect" "reflect"
"regexp" "regexp"
"runtime" "runtime"
@ -13,9 +14,13 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib" "github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/objx" "github.com/stretchr/objx"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// regex for GCCGO functions
var gccgoRE = regexp.MustCompile(`\.pN\d+_`)
// TestingT is an interface wrapper around *testing.T // TestingT is an interface wrapper around *testing.T
type TestingT interface { type TestingT interface {
Logf(format string, args ...interface{}) Logf(format string, args ...interface{})
@ -99,7 +104,7 @@ func (c *Call) unlock() {
// Return specifies the return arguments for the expectation. // Return specifies the return arguments for the expectation.
// //
// Mock.On("DoSomething").Return(errors.New("failed")) // Mock.On("DoSomething").Return(errors.New("failed"))
func (c *Call) Return(returnArguments ...interface{}) *Call { func (c *Call) Return(returnArguments ...interface{}) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -109,9 +114,9 @@ func (c *Call) Return(returnArguments ...interface{}) *Call {
return c return c
} }
// Panic specifies if the functon call should fail and the panic message // Panic specifies if the function call should fail and the panic message
// //
// Mock.On("DoSomething").Panic("test panic") // Mock.On("DoSomething").Panic("test panic")
func (c *Call) Panic(msg string) *Call { func (c *Call) Panic(msg string) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -121,24 +126,24 @@ func (c *Call) Panic(msg string) *Call {
return c return c
} }
// Once indicates that that the mock should only return the value once. // Once indicates that the mock should only return the value once.
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
func (c *Call) Once() *Call { func (c *Call) Once() *Call {
return c.Times(1) return c.Times(1)
} }
// Twice indicates that that the mock should only return the value twice. // Twice indicates that the mock should only return the value twice.
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
func (c *Call) Twice() *Call { func (c *Call) Twice() *Call {
return c.Times(2) return c.Times(2)
} }
// Times indicates that that the mock should only return the indicated number // Times indicates that the mock should only return the indicated number
// of times. // of times.
// //
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
func (c *Call) Times(i int) *Call { func (c *Call) Times(i int) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -149,7 +154,7 @@ func (c *Call) Times(i int) *Call {
// WaitUntil sets the channel that will block the mock's return until its closed // WaitUntil sets the channel that will block the mock's return until its closed
// or a message is received. // or a message is received.
// //
// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) // Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
func (c *Call) WaitUntil(w <-chan time.Time) *Call { func (c *Call) WaitUntil(w <-chan time.Time) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -159,7 +164,7 @@ func (c *Call) WaitUntil(w <-chan time.Time) *Call {
// After sets how long to block until the call returns // After sets how long to block until the call returns
// //
// Mock.On("MyMethod", arg1, arg2).After(time.Second) // Mock.On("MyMethod", arg1, arg2).After(time.Second)
func (c *Call) After(d time.Duration) *Call { func (c *Call) After(d time.Duration) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -171,10 +176,10 @@ func (c *Call) After(d time.Duration) *Call {
// mocking a method (such as an unmarshaler) that takes a pointer to a struct and // mocking a method (such as an unmarshaler) that takes a pointer to a struct and
// sets properties in such struct // sets properties in such struct
// //
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) { // Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) {
// arg := args.Get(0).(*map[string]interface{}) // arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar" // arg["foo"] = "bar"
// }) // })
func (c *Call) Run(fn func(args Arguments)) *Call { func (c *Call) Run(fn func(args Arguments)) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -194,16 +199,18 @@ func (c *Call) Maybe() *Call {
// On chains a new expectation description onto the mocked interface. This // On chains a new expectation description onto the mocked interface. This
// allows syntax like. // allows syntax like.
// //
// Mock. // Mock.
// On("MyMethod", 1).Return(nil). // On("MyMethod", 1).Return(nil).
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) // On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
//
//go:noinline //go:noinline
func (c *Call) On(methodName string, arguments ...interface{}) *Call { func (c *Call) On(methodName string, arguments ...interface{}) *Call {
return c.Parent.On(methodName, arguments...) return c.Parent.On(methodName, arguments...)
} }
// Unset removes a mock handler from being called. // Unset removes a mock handler from being called.
// test.On("func", mock.Anything).Unset() //
// test.On("func", mock.Anything).Unset()
func (c *Call) Unset() *Call { func (c *Call) Unset() *Call {
var unlockOnce sync.Once var unlockOnce sync.Once
@ -218,16 +225,22 @@ func (c *Call) Unset() *Call {
foundMatchingCall := false foundMatchingCall := false
for i, call := range c.Parent.ExpectedCalls { // in-place filter slice for calls to be removed - iterate from 0'th to last skipping unnecessary ones
var index int // write index
for _, call := range c.Parent.ExpectedCalls {
if call.Method == c.Method { if call.Method == c.Method {
_, diffCount := call.Arguments.Diff(c.Arguments) _, diffCount := call.Arguments.Diff(c.Arguments)
if diffCount == 0 { if diffCount == 0 {
foundMatchingCall = true foundMatchingCall = true
// Remove from ExpectedCalls // Remove from ExpectedCalls - just skip it
c.Parent.ExpectedCalls = append(c.Parent.ExpectedCalls[:i], c.Parent.ExpectedCalls[i+1:]...) continue
} }
} }
c.Parent.ExpectedCalls[index] = call
index++
} }
// trim slice up to last copied index
c.Parent.ExpectedCalls = c.Parent.ExpectedCalls[:index]
if !foundMatchingCall { if !foundMatchingCall {
unlockOnce.Do(c.unlock) unlockOnce.Do(c.unlock)
@ -243,9 +256,9 @@ func (c *Call) Unset() *Call {
// calls have been called as expected. The referenced calls may be from the // calls have been called as expected. The referenced calls may be from the
// same mock instance and/or other mock instances. // same mock instance and/or other mock instances.
// //
// Mock.On("Do").Return(nil).Notbefore( // Mock.On("Do").Return(nil).Notbefore(
// Mock.On("Init").Return(nil) // Mock.On("Init").Return(nil)
// ) // )
func (c *Call) NotBefore(calls ...*Call) *Call { func (c *Call) NotBefore(calls ...*Call) *Call {
c.lock() c.lock()
defer c.unlock() defer c.unlock()
@ -328,7 +341,7 @@ func (m *Mock) fail(format string, args ...interface{}) {
// On starts a description of an expectation of the specified method // On starts a description of an expectation of the specified method
// being called. // being called.
// //
// Mock.On("MyMethod", arg1, arg2) // Mock.On("MyMethod", arg1, arg2)
func (m *Mock) On(methodName string, arguments ...interface{}) *Call { func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
for _, arg := range arguments { for _, arg := range arguments {
if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
@ -418,6 +431,10 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
if includeArgumentValues { if includeArgumentValues {
var argVals []string var argVals []string
for argIndex, arg := range arguments { for argIndex, arg := range arguments {
if _, ok := arg.(*FunctionalOptionsArgument); ok {
argVals = append(argVals, fmt.Sprintf("%d: %s", argIndex, arg))
continue
}
argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg))
} }
argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
@ -441,9 +458,8 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
// For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock // For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
// uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree // uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
// With GCCGO we need to remove interface information starting from pN<dd>. // With GCCGO we need to remove interface information starting from pN<dd>.
re := regexp.MustCompile("\\.pN\\d+_") if gccgoRE.MatchString(functionPath) {
if re.MatchString(functionPath) { functionPath = gccgoRE.Split(functionPath, -1)[0]
functionPath = re.Split(functionPath, -1)[0]
} }
parts := strings.Split(functionPath, ".") parts := strings.Split(functionPath, ".")
functionName := parts[len(parts)-1] functionName := parts[len(parts)-1]
@ -460,7 +476,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
found, call := m.findExpectedCall(methodName, arguments...) found, call := m.findExpectedCall(methodName, arguments...)
if found < 0 { if found < 0 {
// expected call found but it has already been called with repeatable times // expected call found, but it has already been called with repeatable times
if call != nil { if call != nil {
m.mutex.Unlock() m.mutex.Unlock()
m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(\"%s\").Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo()) m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(\"%s\").Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo())
@ -549,7 +565,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
Assertions Assertions
*/ */
type assertExpectationser interface { type assertExpectationiser interface {
AssertExpectations(TestingT) bool AssertExpectations(TestingT) bool
} }
@ -566,7 +582,7 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)")
obj = m obj = m
} }
m := obj.(assertExpectationser) m := obj.(assertExpectationiser)
if !m.AssertExpectations(t) { if !m.AssertExpectations(t) {
t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m))
return false return false
@ -592,8 +608,8 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
satisfied, reason := m.checkExpectation(expectedCall) satisfied, reason := m.checkExpectation(expectedCall)
if !satisfied { if !satisfied {
failedExpectations++ failedExpectations++
t.Logf(reason)
} }
t.Logf(reason)
} }
if failedExpectations != 0 { if failedExpectations != 0 {
@ -744,17 +760,26 @@ const (
Anything = "mock.Anything" Anything = "mock.Anything"
) )
// AnythingOfTypeArgument is a string that contains the type of an argument // AnythingOfTypeArgument contains the type of an argument
// for use when type checking. Used in Diff and Assert. // for use when type checking. Used in Diff and Assert.
type AnythingOfTypeArgument string //
// Deprecated: this is an implementation detail that must not be used. Use [AnythingOfType] instead.
type AnythingOfTypeArgument = anythingOfTypeArgument
// AnythingOfType returns an AnythingOfTypeArgument object containing the // anythingOfTypeArgument is a string that contains the type of an argument
// name of the type to check for. Used in Diff and Assert. // for use when type checking. Used in Diff and Assert.
type anythingOfTypeArgument string
// AnythingOfType returns a special value containing the
// name of the type to check for. The type name will be matched against the type name returned by [reflect.Type.String].
//
// Used in Diff and Assert.
// //
// For example: // For example:
//
// Assert(t, AnythingOfType("string"), AnythingOfType("int")) // Assert(t, AnythingOfType("string"), AnythingOfType("int"))
func AnythingOfType(t string) AnythingOfTypeArgument { func AnythingOfType(t string) AnythingOfTypeArgument {
return AnythingOfTypeArgument(t) return anythingOfTypeArgument(t)
} }
// IsTypeArgument is a struct that contains the type of an argument // IsTypeArgument is a struct that contains the type of an argument
@ -774,6 +799,34 @@ func IsType(t interface{}) *IsTypeArgument {
return &IsTypeArgument{t: t} return &IsTypeArgument{t: t}
} }
// FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument
// for use when type checking.
type FunctionalOptionsArgument struct {
value interface{}
}
// String returns the string representation of FunctionalOptionsArgument
func (f *FunctionalOptionsArgument) String() string {
var name string
tValue := reflect.ValueOf(f.value)
if tValue.Len() > 0 {
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
}
return strings.Replace(fmt.Sprintf("%#v", f.value), "[]interface {}", name, 1)
}
// FunctionalOptions returns an FunctionalOptionsArgument object containing the functional option type
// and the values to check of
//
// For example:
// Assert(t, FunctionalOptions("[]foo.FunctionalOption", foo.Opt1(), foo.Opt2()))
func FunctionalOptions(value ...interface{}) *FunctionalOptionsArgument {
return &FunctionalOptionsArgument{
value: value,
}
}
// argumentMatcher performs custom argument matching, returning whether or // argumentMatcher performs custom argument matching, returning whether or
// not the argument is matched by the expectation fixture function. // not the argument is matched by the expectation fixture function.
type argumentMatcher struct { type argumentMatcher struct {
@ -907,9 +960,9 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
differences++ differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher) output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
} }
} else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { } else if reflect.TypeOf(expected) == reflect.TypeOf((*anythingOfTypeArgument)(nil)).Elem() {
// type checking // type checking
if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { if reflect.TypeOf(actual).Name() != string(expected.(anythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(anythingOfTypeArgument)) {
// not match // not match
differences++ differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
@ -920,6 +973,29 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
differences++ differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt) output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt)
} }
} else if reflect.TypeOf(expected) == reflect.TypeOf((*FunctionalOptionsArgument)(nil)) {
t := expected.(*FunctionalOptionsArgument).value
var name string
tValue := reflect.ValueOf(t)
if tValue.Len() > 0 {
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
}
tName := reflect.TypeOf(t).Name()
if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 {
differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
} else {
if ef, af := assertOpts(t, actual); ef == "" && af == "" {
// match
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef)
}
}
} else { } else {
// normal checking // normal checking
@ -1096,3 +1172,65 @@ var spewConfig = spew.ConfigState{
type tHelper interface { type tHelper interface {
Helper() Helper()
} }
func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
expectedOpts := reflect.ValueOf(expected)
actualOpts := reflect.ValueOf(actual)
var expectedNames []string
for i := 0; i < expectedOpts.Len(); i++ {
expectedNames = append(expectedNames, funcName(expectedOpts.Index(i).Interface()))
}
var actualNames []string
for i := 0; i < actualOpts.Len(); i++ {
actualNames = append(actualNames, funcName(actualOpts.Index(i).Interface()))
}
if !assert.ObjectsAreEqual(expectedNames, actualNames) {
expectedFmt = fmt.Sprintf("%v", expectedNames)
actualFmt = fmt.Sprintf("%v", actualNames)
return
}
for i := 0; i < expectedOpts.Len(); i++ {
expectedOpt := expectedOpts.Index(i).Interface()
actualOpt := actualOpts.Index(i).Interface()
expectedFunc := expectedNames[i]
actualFunc := actualNames[i]
if expectedFunc != actualFunc {
expectedFmt = expectedFunc
actualFmt = actualFunc
return
}
ot := reflect.TypeOf(expectedOpt)
var expectedValues []reflect.Value
var actualValues []reflect.Value
if ot.NumIn() == 0 {
return
}
for i := 0; i < ot.NumIn(); i++ {
vt := ot.In(i).Elem()
expectedValues = append(expectedValues, reflect.New(vt))
actualValues = append(actualValues, reflect.New(vt))
}
reflect.ValueOf(expectedOpt).Call(expectedValues)
reflect.ValueOf(actualOpt).Call(actualValues)
for i := 0; i < ot.NumIn(); i++ {
if !assert.ObjectsAreEqual(expectedValues[i].Interface(), actualValues[i].Interface()) {
expectedFmt = fmt.Sprintf("%s %+v", expectedNames[i], expectedValues[i].Interface())
actualFmt = fmt.Sprintf("%s %+v", expectedNames[i], actualValues[i].Interface())
return
}
}
}
return "", ""
}
func funcName(opt interface{}) string {
n := runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name()
return strings.TrimSuffix(path.Base(n), path.Ext(n))
}

View File

@ -32,6 +32,29 @@ func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
return args.Int(0), errors.New("Whoops") return args.Int(0), errors.New("Whoops")
} }
type options struct {
num int
str string
}
type OptionFn func(*options)
func OpNum(n int) OptionFn {
return func(o *options) {
o.num = n
}
}
func OpStr(s string) OptionFn {
return func(o *options) {
o.str = s
}
}
func (i *TestExampleImplementation) TheExampleMethodFunctionalOptions(x string, opts ...OptionFn) error {
args := i.Called(x, opts)
return args.Error(0)
}
//go:noinline //go:noinline
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) { func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
i.Called(yesorno) i.Called(yesorno)
@ -113,7 +136,7 @@ func (m *MockTestingT) Errorf(string, ...interface{}) {
// the execution stops. // the execution stops.
// When expecting this method, the call that invokes it should use the following code: // When expecting this method, the call that invokes it should use the following code:
// //
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...}) // assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
func (m *MockTestingT) FailNow() { func (m *MockTestingT) FailNow() {
m.failNowCount++ m.failNowCount++
@ -569,6 +592,80 @@ func Test_Mock_UnsetIfAlreadyUnsetFails(t *testing.T) {
assert.Equal(t, 0, len(mockedService.ExpectedCalls)) assert.Equal(t, 0, len(mockedService.ExpectedCalls))
} }
func Test_Mock_UnsetByOnMethodSpec(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
mock1 := mockedService.
On("TheExampleMethod", 1, 2, 3).
Return(0, nil)
assert.Equal(t, 1, len(mockedService.ExpectedCalls))
mock1.On("TheExampleMethod", 1, 2, 3).
Return(0, nil).Unset()
assert.Equal(t, 0, len(mockedService.ExpectedCalls))
assert.Panics(t, func() {
mock1.Unset()
})
assert.Equal(t, 0, len(mockedService.ExpectedCalls))
}
func Test_Mock_UnsetByOnMethodSpecAmongOthers(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
_, filename, line, _ := runtime.Caller(0)
mock1 := mockedService.
On("TheExampleMethod", 1, 2, 3).
Return(0, nil).
On("TheExampleMethodVariadic", 1, 2, 3, 4, 5).Once().
Return(nil)
mock1.
On("TheExampleMethodFuncType", Anything).
Return(nil)
assert.Equal(t, 3, len(mockedService.ExpectedCalls))
mock1.On("TheExampleMethod", 1, 2, 3).
Return(0, nil).Unset()
assert.Equal(t, 2, len(mockedService.ExpectedCalls))
expectedCalls := []*Call{
{
Parent: &mockedService.Mock,
Method: "TheExampleMethodVariadic",
Repeatability: 1,
Arguments: []interface{}{1, 2, 3, 4, 5},
ReturnArguments: []interface{}{nil},
callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+4)},
},
{
Parent: &mockedService.Mock,
Method: "TheExampleMethodFuncType",
Arguments: []interface{}{Anything},
ReturnArguments: []interface{}{nil},
callerInfo: []string{fmt.Sprintf("%s:%d", filename, line+7)},
},
}
assert.Equal(t, 2, len(mockedService.ExpectedCalls))
assert.Equal(t, expectedCalls, mockedService.ExpectedCalls)
}
func Test_Mock_Unset_WithFuncPanics(t *testing.T) {
// make a test impl object
var mockedService = new(TestExampleImplementation)
mock1 := mockedService.On("TheExampleMethod", 1)
mock1.Arguments = append(mock1.Arguments, func(string) error { return nil })
assert.Panics(t, func() {
mock1.Unset()
})
}
func Test_Mock_Return(t *testing.T) { func Test_Mock_Return(t *testing.T) {
// make a test impl object // make a test impl object
@ -1341,6 +1438,40 @@ func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
} }
func Test_Mock_AssertExpectationsFunctionalOptionsType(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpNum(1), OpStr("foo"))).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo"))
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions()).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.TheExampleMethodFunctionalOptions("test")
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) { func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
var mockedService = new(TestExampleImplementation) var mockedService = new(TestExampleImplementation)
@ -1525,7 +1656,7 @@ func Test_Mock_AssertOptional(t *testing.T) {
} }
/* /*
Arguments helper methods Arguments helper methods
*/ */
func Test_Arguments_Get(t *testing.T) { func Test_Arguments_Get(t *testing.T) {
@ -1831,7 +1962,7 @@ func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
end := time.Now() end := time.Now()
elapsedTime := end.Sub(start) elapsedTime := end.Sub(start)
assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs)) assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be at least greater than %v", elapsedTime, waitMs))
assert.Equal(t, total, len(results)) assert.Equal(t, total, len(results))
for i := range results { for i := range results {
assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same") assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same")

View File

@ -1,24 +1,25 @@
// Package require implements the same assertions as the `assert` package but // Package require implements the same assertions as the `assert` package but
// stops test execution when a test fails. // stops test execution when a test fails.
// //
// Example Usage // # Example Usage
// //
// The following is a complete example using require in a standard test function: // The following is a complete example using require in a standard test function:
// import (
// "testing"
// "github.com/stretchr/testify/require"
// )
// //
// func TestSomething(t *testing.T) { // import (
// "testing"
// "github.com/stretchr/testify/require"
// )
// //
// var a string = "Hello" // func TestSomething(t *testing.T) {
// var b string = "Hello"
// //
// require.Equal(t, a, b, "The two words should be the same.") // var a string = "Hello"
// var b string = "Hello"
// //
// } // require.Equal(t, a, b, "The two words should be the same.")
// //
// Assertions // }
//
// # Assertions
// //
// The `require` package have same global functions as in the `assert` package, // The `require` package have same global functions as in the `assert` package,
// but instead of returning a boolean result they call `t.FailNow()`. // but instead of returning a boolean result they call `t.FailNow()`.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -29,37 +29,38 @@
// Suite object has assertion methods. // Suite object has assertion methods.
// //
// A crude example: // A crude example:
// // Basic imports
// import (
// "testing"
// "github.com/stretchr/testify/assert"
// "github.com/stretchr/testify/suite"
// )
// //
// // Define the suite, and absorb the built-in basic suite // // Basic imports
// // functionality from testify - including a T() method which // import (
// // returns the current testing context // "testing"
// type ExampleTestSuite struct { // "github.com/stretchr/testify/assert"
// suite.Suite // "github.com/stretchr/testify/suite"
// VariableThatShouldStartAtFive int // )
// }
// //
// // Make sure that VariableThatShouldStartAtFive is set to five // // Define the suite, and absorb the built-in basic suite
// // before each test // // functionality from testify - including a T() method which
// func (suite *ExampleTestSuite) SetupTest() { // // returns the current testing context
// suite.VariableThatShouldStartAtFive = 5 // type ExampleTestSuite struct {
// } // suite.Suite
// VariableThatShouldStartAtFive int
// }
// //
// // All methods that begin with "Test" are run as tests within a // // Make sure that VariableThatShouldStartAtFive is set to five
// // suite. // // before each test
// func (suite *ExampleTestSuite) TestExample() { // func (suite *ExampleTestSuite) SetupTest() {
// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) // suite.VariableThatShouldStartAtFive = 5
// suite.Equal(5, suite.VariableThatShouldStartAtFive) // }
// }
// //
// // In order for 'go test' to run this suite, we need to create // // All methods that begin with "Test" are run as tests within a
// // a normal test function and pass our suite to suite.Run // // suite.
// func TestExampleTestSuite(t *testing.T) { // func (suite *ExampleTestSuite) TestExample() {
// suite.Run(t, new(ExampleTestSuite)) // assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
// } // suite.Equal(5, suite.VariableThatShouldStartAtFive)
// }
//
// // In order for 'go test' to run this suite, we need to create
// // a normal test function and pass our suite to suite.Run
// func TestExampleTestSuite(t *testing.T) {
// suite.Run(t, new(ExampleTestSuite))
// }
package suite package suite

View File

@ -7,6 +7,7 @@ import "testing"
type TestingSuite interface { type TestingSuite interface {
T() *testing.T T() *testing.T
SetT(*testing.T) SetT(*testing.T)
SetS(suite TestingSuite)
} }
// SetupAllSuite has a SetupSuite method, which will run before the // SetupAllSuite has a SetupSuite method, which will run before the
@ -51,3 +52,15 @@ type AfterTest interface {
type WithStats interface { type WithStats interface {
HandleStats(suiteName string, stats *SuiteInformation) HandleStats(suiteName string, stats *SuiteInformation)
} }
// SetupSubTest has a SetupSubTest method, which will run before each
// subtest in the suite.
type SetupSubTest interface {
SetupSubTest()
}
// TearDownSubTest has a TearDownSubTest method, which will run after
// each subtest in the suite have been run.
type TearDownSubTest interface {
TearDownSubTest()
}

View File

@ -22,9 +22,13 @@ var matchMethod = flag.String("testify.m", "", "regular expression to select tes
// retrieving the current *testing.T context. // retrieving the current *testing.T context.
type Suite struct { type Suite struct {
*assert.Assertions *assert.Assertions
mu sync.RWMutex mu sync.RWMutex
require *require.Assertions require *require.Assertions
t *testing.T t *testing.T
// Parent suite to have access to the implemented methods of parent struct
s TestingSuite
} }
// T retrieves the current *testing.T context. // T retrieves the current *testing.T context.
@ -43,6 +47,12 @@ func (suite *Suite) SetT(t *testing.T) {
suite.require = require.New(t) suite.require = require.New(t)
} }
// SetS needs to set the current test suite as parent
// to get access to the parent methods
func (suite *Suite) SetS(s TestingSuite) {
suite.s = s
}
// Require returns a require context for suite. // Require returns a require context for suite.
func (suite *Suite) Require() *require.Assertions { func (suite *Suite) Require() *require.Assertions {
suite.mu.Lock() suite.mu.Lock()
@ -85,7 +95,18 @@ func failOnPanic(t *testing.T, r interface{}) {
// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName. // Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName.
func (suite *Suite) Run(name string, subtest func()) bool { func (suite *Suite) Run(name string, subtest func()) bool {
oldT := suite.T() oldT := suite.T()
defer suite.SetT(oldT)
if setupSubTest, ok := suite.s.(SetupSubTest); ok {
setupSubTest.SetupSubTest()
}
defer func() {
suite.SetT(oldT)
if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
tearDownSubTest.TearDownSubTest()
}
}()
return oldT.Run(name, func(t *testing.T) { return oldT.Run(name, func(t *testing.T) {
suite.SetT(t) suite.SetT(t)
subtest() subtest()
@ -98,6 +119,7 @@ func Run(t *testing.T, suite TestingSuite) {
defer recoverAndFailOnPanic(t) defer recoverAndFailOnPanic(t)
suite.SetT(t) suite.SetT(t)
suite.SetS(suite)
var suiteSetupDone bool var suiteSetupDone bool

View File

@ -151,14 +151,16 @@ type SuiteTester struct {
Suite Suite
// Keep counts of how many times each method is run. // Keep counts of how many times each method is run.
SetupSuiteRunCount int SetupSuiteRunCount int
TearDownSuiteRunCount int TearDownSuiteRunCount int
SetupTestRunCount int SetupTestRunCount int
TearDownTestRunCount int TearDownTestRunCount int
TestOneRunCount int TestOneRunCount int
TestTwoRunCount int TestTwoRunCount int
TestSubtestRunCount int TestSubtestRunCount int
NonTestMethodRunCount int NonTestMethodRunCount int
SetupSubTestRunCount int
TearDownSubTestRunCount int
SuiteNameBefore []string SuiteNameBefore []string
TestNameBefore []string TestNameBefore []string
@ -255,6 +257,14 @@ func (suite *SuiteTester) TestSubtest() {
} }
} }
func (suite *SuiteTester) TearDownSubTest() {
suite.TearDownSubTestRunCount++
}
func (suite *SuiteTester) SetupSubTest() {
suite.SetupSubTestRunCount++
}
type SuiteSkipTester struct { type SuiteSkipTester struct {
// Include our basic suite logic. // Include our basic suite logic.
Suite Suite
@ -336,6 +346,9 @@ func TestRunSuite(t *testing.T) {
assert.Equal(t, suiteTester.TestTwoRunCount, 1) assert.Equal(t, suiteTester.TestTwoRunCount, 1)
assert.Equal(t, suiteTester.TestSubtestRunCount, 1) assert.Equal(t, suiteTester.TestSubtestRunCount, 1)
assert.Equal(t, suiteTester.TearDownSubTestRunCount, 2)
assert.Equal(t, suiteTester.SetupSubTestRunCount, 2)
// Methods that don't match the test method identifier shouldn't // Methods that don't match the test method identifier shouldn't
// have been run at all. // have been run at all.
assert.Equal(t, suiteTester.NonTestMethodRunCount, 0) assert.Equal(t, suiteTester.NonTestMethodRunCount, 0)