mirror of https://github.com/stretchr/testify.git
Compare commits
142 Commits
Author | SHA1 | Date |
---|---|---|
|
5ac6528bff | |
|
d0e0f4961b | |
|
b561f16e87 | |
|
a948a8c402 | |
|
c3915e850a | |
|
16020e8cbc | |
|
75df9d50d4 | |
|
33be8f984a | |
|
a9e8aed155 | |
|
3b8bd9bf7d | |
|
1e7fb5865a | |
|
c6ac9bb91d | |
|
65f73866c0 | |
|
b1c9368f81 | |
|
5a5ac85551 | |
|
53e0c918d4 | |
|
89086b0757 | |
|
098128fd10 | |
|
f784abc221 | |
|
dfda68b86f | |
|
3cf0926564 | |
|
c60c3bd7fb | |
|
1c717c00c1 | |
|
ccb5e7f656 | |
|
ca6698b8a1 | |
|
7c367bb7bc | |
|
e6a990c21d | |
|
cfee2346d7 | |
|
f8c628e5a1 | |
|
014ae9a7a4 | |
|
30f3cef5ad | |
|
d57bac8721 | |
|
89cbdd9e7b | |
|
07bac606be | |
|
716de8dff4 | |
|
118fb83466 | |
|
7d99b2b43d | |
|
05f87c0160 | |
|
ea7129e006 | |
|
a1b9c9efe3 | |
|
8302de98b1 | |
|
89352f7958 | |
|
2780579e15 | |
|
8f049b0122 | |
|
be992afabf | |
|
fb67df6392 | |
|
55bac84354 | |
|
822223ec34 | |
|
22d3bd5def | |
|
9c174eb41c | |
|
7efaf15f33 | |
|
dce9e58ee3 | |
|
75a239b2fd | |
|
f9ccf14f6f | |
|
6555fd4da6 | |
|
a012e45d18 | |
|
3b2754b72f | |
|
2fc4e39394 | |
|
f2227519d6 | |
|
50d5b7e695 | |
|
55ebaca027 | |
|
ba3e7c34d5 | |
|
2063e81696 | |
|
7f489726a5 | |
|
f844b269df | |
|
dc100b1be3 | |
|
aade8450b3 | |
|
3380867632 | |
|
95d1f9c2ad | |
|
fed9ee68dc | |
|
5dc934f9aa | |
|
c4b8421a1f | |
|
85a526818c | |
|
16a09b7086 | |
|
f3f7181b01 | |
|
d62ca68bf5 | |
|
428847e363 | |
|
72e3b61028 | |
|
ea6964c2e9 | |
|
f17409f81f | |
|
bdb1271ed8 | |
|
e943930404 | |
|
7268a5bc0b | |
|
da63673a11 | |
|
52df55490e | |
|
7f10816c93 | |
|
176474a4c9 | |
|
28e0be5092 | |
|
4a90eff4ae | |
|
3ca01f4bc3 | |
|
bc04bb85a2 | |
|
b074924938 | |
|
f71de4a756 | |
|
592e4e3c00 | |
|
044c46a89f | |
|
84619f5c3c | |
|
9326036bf5 | |
|
1b4fca7679 | |
|
cb4e70cf8d | |
|
7af3ed34c2 | |
|
df81388b27 | |
|
6b275adbf7 | |
|
b661f0ade2 | |
|
109f4286cf | |
|
3c0c0e6443 | |
|
32766084e4 | |
|
8d4dcbbccb | |
|
8c324a0bbd | |
|
f32ff5b3cb | |
|
e33bd6fdd1 | |
|
d4a63f5b89 | |
|
a9e6121b1c | |
|
a61e9e59d6 | |
|
4ec7678c61 | |
|
42d887f28b | |
|
0e5b59666a | |
|
352d2438b9 | |
|
726249eca2 | |
|
d3dbb19355 | |
|
17b83c52e4 | |
|
a2fbbfe71b | |
|
be3fbeb943 | |
|
edd74b24a1 | |
|
740a5e83fa | |
|
404159f5fa | |
|
a155d2a49d | |
|
39442a4e4e | |
|
74e1cbebab | |
|
a71299064b | |
|
da1e1476cb | |
|
3c302f75ae | |
|
1dedc83b8f | |
|
aca1890ec1 | |
|
bfa3ee96e3 | |
|
f1b5324b90 | |
|
632a26080f | |
|
cab2acc70f | |
|
edb801534f | |
|
89ffab03a5 | |
|
8585d8de96 | |
|
e5e71998af | |
|
85fabe7c5c |
.github/workflows
_codegen
suite
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Verify that the code snippets in README.md are formatted.
|
||||||
|
# The tool https://github.com/hougesen/mdsf is used.
|
||||||
|
|
||||||
|
if [ -n "$(mdsf verify --config .mdsf.json --log-level error README.md 2>&1)" ]; then
|
||||||
|
echo "Go code in the README.md is not formatted."
|
||||||
|
echo "Did you forget to run 'mdsf format --config .mdsf.json README.md'?"
|
||||||
|
mdsf format --config .mdsf.json README.md
|
||||||
|
git diff
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -15,8 +15,10 @@ jobs:
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go_version }}
|
go-version: ${{ matrix.go_version }}
|
||||||
|
- run: npm install -g mdsf-cli
|
||||||
- run: ./.ci.gogenerate.sh
|
- run: ./.ci.gogenerate.sh
|
||||||
- run: ./.ci.gofmt.sh
|
- run: ./.ci.gofmt.sh
|
||||||
|
- run: ./.ci.readme.fmt.sh
|
||||||
- run: ./.ci.govet.sh
|
- run: ./.ci.govet.sh
|
||||||
- run: go test -v -race ./...
|
- run: go test -v -race ./...
|
||||||
test:
|
test:
|
||||||
|
@ -29,6 +31,7 @@ jobs:
|
||||||
- "1.19"
|
- "1.19"
|
||||||
- "1.20"
|
- "1.20"
|
||||||
- "1.21"
|
- "1.21"
|
||||||
|
- "1.22"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
|
|
|
@ -16,6 +16,6 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Create GitHub release from tag
|
- name: Create GitHub release from tag
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
|
|
|
@ -22,3 +22,9 @@ _testmain.go
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Output of "go test -c"
|
||||||
|
/assert/assert.test
|
||||||
|
/require/require.test
|
||||||
|
/suite/suite.test
|
||||||
|
/mock/mock.test
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/hougesen/mdsf/main/schemas/v0.8.2/mdsf.schema.json",
|
||||||
|
"format_finished_document": false,
|
||||||
|
"languages": {
|
||||||
|
"go": [
|
||||||
|
[
|
||||||
|
"gofmt",
|
||||||
|
"goimports"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,5 +6,12 @@ pull requests.
|
||||||
* @boyan-soubachov
|
* @boyan-soubachov
|
||||||
* @dolmen
|
* @dolmen
|
||||||
* @MovieStoreGuy
|
* @MovieStoreGuy
|
||||||
* @arjunmahishi
|
|
||||||
* @brackendawson
|
* @brackendawson
|
||||||
|
|
||||||
|
## Approvers
|
||||||
|
|
||||||
|
The individuals listed below are active in the project and have the ability to approve pull
|
||||||
|
requests.
|
||||||
|
|
||||||
|
* @arjunmahishi
|
||||||
|
* @ccoVeille
|
||||||
|
|
32
README.md
32
README.md
|
@ -1,7 +1,9 @@
|
||||||
Testify - Thou Shalt Write Tests
|
Testify - Thou Shalt Write Tests
|
||||||
================================
|
================================
|
||||||
|
|
||||||
ℹ️ We are working on testify v2 and would love to hear what you'd like to see in it, have your say here: https://cutt.ly/testify
|
> [!NOTE]
|
||||||
|
> Testify is being maintained at v1, no breaking changes will be accepted in this repo.
|
||||||
|
> [See discussion about v2](https://github.com/stretchr/testify/discussions/1560).
|
||||||
|
|
||||||
[](https://github.com/stretchr/testify/actions/workflows/main.yml) [](https://goreportcard.com/report/github.com/stretchr/testify) [](https://pkg.go.dev/github.com/stretchr/testify)
|
[](https://github.com/stretchr/testify/actions/workflows/main.yml) [](https://goreportcard.com/report/github.com/stretchr/testify) [](https://pkg.go.dev/github.com/stretchr/testify)
|
||||||
|
|
||||||
|
@ -18,10 +20,9 @@ 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 https://go.dev/doc/code#Testing
|
* For an introduction to writing test code in Go, see https://go.dev/doc/code#Testing
|
||||||
* Check out the API Documentation https://pkg.go.dev/github.com/stretchr/testify
|
* Check out the API Documentation https://pkg.go.dev/github.com/stretchr/testify
|
||||||
|
* Use [testifylint](https://github.com/Antonboom/testifylint) (via [golangci-lint](https://golangci-lint.run/)) to avoid common mistakes
|
||||||
* A little about [Test-Driven Development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development)
|
* A little about [Test-Driven Development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") package
|
[`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") package
|
||||||
-------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -38,11 +39,11 @@ package yours
|
||||||
|
|
||||||
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 equality
|
// assert equality
|
||||||
assert.Equal(t, 123, 123, "they should be equal")
|
assert.Equal(t, 123, 123, "they should be equal")
|
||||||
|
|
||||||
|
@ -54,13 +55,10 @@ func TestSomething(t *testing.T) {
|
||||||
|
|
||||||
// assert for not nil (good when you expect something)
|
// assert for not nil (good when you expect something)
|
||||||
if assert.NotNil(t, object) {
|
if assert.NotNil(t, object) {
|
||||||
|
|
||||||
// now we know that object isn't nil, we are safe to make
|
// now we know that object isn't nil, we are safe to make
|
||||||
// further assertions without causing any errors
|
// further assertions without causing any errors
|
||||||
assert.Equal(t, "Something", object.Value)
|
assert.Equal(t, "Something", object.Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -74,6 +72,7 @@ package yours
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,7 +90,6 @@ func TestSomething(t *testing.T) {
|
||||||
|
|
||||||
// assert for not nil (good when you expect something)
|
// assert for not nil (good when you expect something)
|
||||||
if assert.NotNil(object) {
|
if assert.NotNil(object) {
|
||||||
|
|
||||||
// now we know that object isn't nil, we are safe to make
|
// now we know that object isn't nil, we are safe to make
|
||||||
// further assertions without causing any errors
|
// further assertions without causing any errors
|
||||||
assert.Equal("Something", object.Value)
|
assert.Equal("Something", object.Value)
|
||||||
|
@ -120,6 +118,7 @@ package yours
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -129,7 +128,7 @@ import (
|
||||||
|
|
||||||
// MyMockedObject is a mocked object that implements an interface
|
// MyMockedObject is a mocked object that implements an interface
|
||||||
// that describes an object that the code I am testing relies on.
|
// that describes an object that the code I am testing relies on.
|
||||||
type MyMockedObject struct{
|
type MyMockedObject struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,10 +140,8 @@ type MyMockedObject struct{
|
||||||
//
|
//
|
||||||
// NOTE: This method is not being tested here, code that uses this object is.
|
// NOTE: This method is not being tested here, code that uses this object is.
|
||||||
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
|
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
|
||||||
|
|
||||||
args := m.Called(number)
|
args := m.Called(number)
|
||||||
return args.Bool(0), args.Error(1)
|
return args.Bool(0), args.Error(1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -154,7 +151,6 @@ func (m *MyMockedObject) DoSomething(number int) (bool, error) {
|
||||||
// TestSomething is an example of how to use our test object to
|
// TestSomething is an example of how to use our test object to
|
||||||
// make assertions about some target code we are testing.
|
// make assertions about some target code we are testing.
|
||||||
func TestSomething(t *testing.T) {
|
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)
|
||||||
|
|
||||||
|
@ -166,8 +162,6 @@ func TestSomething(t *testing.T) {
|
||||||
|
|
||||||
// assert that the expectations were met
|
// assert that the expectations were met
|
||||||
testObj.AssertExpectations(t)
|
testObj.AssertExpectations(t)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSomethingWithPlaceholder is a second example of how to use our test object to
|
// TestSomethingWithPlaceholder is a second example of how to use our test object to
|
||||||
|
@ -176,7 +170,6 @@ func TestSomething(t *testing.T) {
|
||||||
// data being passed in is normally dynamically generated and cannot be
|
// data being passed in is normally dynamically generated and cannot be
|
||||||
// predicted beforehand (eg. containing hashes that are time sensitive)
|
// predicted beforehand (eg. containing hashes that are time sensitive)
|
||||||
func TestSomethingWithPlaceholder(t *testing.T) {
|
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)
|
||||||
|
|
||||||
|
@ -189,13 +182,11 @@ func TestSomethingWithPlaceholder(t *testing.T) {
|
||||||
// assert that the expectations were met
|
// assert that the expectations were met
|
||||||
testObj.AssertExpectations(t)
|
testObj.AssertExpectations(t)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSomethingElse2 is a third example that shows how you can use
|
// TestSomethingElse2 is a third example that shows how you can use
|
||||||
// the Unset method to cleanup handlers and then add new ones.
|
// the Unset method to cleanup handlers and then add new ones.
|
||||||
func TestSomethingElse2(t *testing.T) {
|
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)
|
||||||
|
|
||||||
|
@ -224,6 +215,8 @@ You can use the [mockery tool](https://vektra.github.io/mockery/latest/) to auto
|
||||||
|
|
||||||
[`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package
|
[`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package
|
||||||
-----------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------
|
||||||
|
> [!WARNING]
|
||||||
|
> The suite package does not support parallel tests. See [#934](https://github.com/stretchr/testify/issues/934).
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -233,6 +226,7 @@ An example suite is shown below:
|
||||||
// Basic imports
|
// Basic imports
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
@ -274,6 +268,7 @@ For more information on writing suites, check out the [API documentation for the
|
||||||
// Basic imports
|
// Basic imports
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -327,13 +322,12 @@ package yours
|
||||||
|
|
||||||
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.True(t, true, "True is true!")
|
assert.True(t, true, "True is true!")
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -101,13 +100,15 @@ func parseTemplates() (*template.Template, *template.Template, error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if *tmplFile != "" {
|
if *tmplFile != "" {
|
||||||
f, err := ioutil.ReadFile(*tmplFile)
|
f, err := os.ReadFile(*tmplFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
funcTemplate = string(f)
|
funcTemplate = string(f)
|
||||||
}
|
}
|
||||||
tmpl, err := template.New("function").Parse(funcTemplate)
|
tmpl, err := template.New("function").Funcs(template.FuncMap{
|
||||||
|
"replace": strings.ReplaceAll,
|
||||||
|
}).Parse(funcTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) {
|
||||||
files := make(map[string]*ast.File)
|
files := make(map[string]*ast.File)
|
||||||
fileList := make([]*ast.File, len(pd.GoFiles))
|
fileList := make([]*ast.File, len(pd.GoFiles))
|
||||||
for i, fname := range pd.GoFiles {
|
for i, fname := range pd.GoFiles {
|
||||||
src, err := ioutil.ReadFile(path.Join(pd.Dir, fname))
|
src, err := os.ReadFile(path.Join(pd.Dir, fname))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CompareType int
|
// Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it.
|
||||||
|
type CompareType = compareResult
|
||||||
|
|
||||||
|
type compareResult int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
compareLess CompareType = iota - 1
|
compareLess compareResult = iota - 1
|
||||||
compareEqual
|
compareEqual
|
||||||
compareGreater
|
compareGreater
|
||||||
)
|
)
|
||||||
|
@ -39,7 +42,7 @@ var (
|
||||||
bytesType = reflect.TypeOf([]byte{})
|
bytesType = reflect.TypeOf([]byte{})
|
||||||
)
|
)
|
||||||
|
|
||||||
func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
|
func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, bool) {
|
||||||
obj1Value := reflect.ValueOf(obj1)
|
obj1Value := reflect.ValueOf(obj1)
|
||||||
obj2Value := reflect.ValueOf(obj2)
|
obj2Value := reflect.ValueOf(obj2)
|
||||||
|
|
||||||
|
@ -325,7 +328,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
|
||||||
timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time)
|
timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time)
|
||||||
}
|
}
|
||||||
|
|
||||||
return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64)
|
if timeObj1.Before(timeObj2) {
|
||||||
|
return compareLess, true
|
||||||
|
}
|
||||||
|
if timeObj1.Equal(timeObj2) {
|
||||||
|
return compareEqual, true
|
||||||
|
}
|
||||||
|
return compareGreater, true
|
||||||
}
|
}
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
{
|
{
|
||||||
|
@ -345,7 +354,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
|
||||||
bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
|
bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true
|
return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true
|
||||||
}
|
}
|
||||||
case reflect.Uintptr:
|
case reflect.Uintptr:
|
||||||
{
|
{
|
||||||
|
@ -381,7 +390,8 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
|
failMessage := fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2)
|
||||||
|
return compareTwoValues(t, e1, e2, []compareResult{compareGreater}, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -394,7 +404,8 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
|
failMessage := fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2)
|
||||||
|
return compareTwoValues(t, e1, e2, []compareResult{compareGreater, compareEqual}, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less asserts that the first element is less than the second
|
// Less asserts that the first element is less than the second
|
||||||
|
@ -406,7 +417,8 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{})
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
|
failMessage := fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2)
|
||||||
|
return compareTwoValues(t, e1, e2, []compareResult{compareLess}, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -419,7 +431,8 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
|
failMessage := fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2)
|
||||||
|
return compareTwoValues(t, e1, e2, []compareResult{compareLess, compareEqual}, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Positive asserts that the specified element is positive
|
// Positive asserts that the specified element is positive
|
||||||
|
@ -431,7 +444,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
zero := reflect.Zero(reflect.TypeOf(e))
|
zero := reflect.Zero(reflect.TypeOf(e))
|
||||||
return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...)
|
failMessage := fmt.Sprintf("\"%v\" is not positive", e)
|
||||||
|
return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negative asserts that the specified element is negative
|
// Negative asserts that the specified element is negative
|
||||||
|
@ -443,10 +457,11 @@ func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
zero := reflect.Zero(reflect.TypeOf(e))
|
zero := reflect.Zero(reflect.TypeOf(e))
|
||||||
return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...)
|
failMessage := fmt.Sprintf("\"%v\" is not negative", e)
|
||||||
|
return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool {
|
func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
|
@ -459,17 +474,17 @@ func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedCompare
|
||||||
|
|
||||||
compareResult, isComparable := compare(e1, e2, e1Kind)
|
compareResult, isComparable := compare(e1, e2, e1Kind)
|
||||||
if !isComparable {
|
if !isComparable {
|
||||||
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
|
return Fail(t, fmt.Sprintf(`Can not compare type "%T"`, e1), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !containsValue(allowedComparesResults, compareResult) {
|
if !containsValue(allowedComparesResults, compareResult) {
|
||||||
return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
|
return Fail(t, failMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsValue(values []CompareType, value CompareType) bool {
|
func containsValue(values []compareResult, value compareResult) bool {
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
if v == value {
|
if v == value {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -59,6 +59,7 @@ func TestCompare(t *testing.T) {
|
||||||
{less: uintptr(1), greater: uintptr(2), cType: "uintptr"},
|
{less: uintptr(1), greater: uintptr(2), cType: "uintptr"},
|
||||||
{less: customUintptr(1), greater: customUintptr(2), cType: "uint64"},
|
{less: customUintptr(1), greater: customUintptr(2), cType: "uint64"},
|
||||||
{less: time.Now(), greater: time.Now().Add(time.Hour), cType: "time.Time"},
|
{less: time.Now(), greater: time.Now().Add(time.Hour), cType: "time.Time"},
|
||||||
|
{less: time.Date(2024, 0, 0, 0, 0, 0, 0, time.Local), greater: time.Date(2263, 0, 0, 0, 0, 0, 0, time.Local), cType: "time.Time"},
|
||||||
{less: customTime(time.Now()), greater: customTime(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: []byte{1, 1}, greater: []byte{1, 2}, cType: "[]byte"},
|
||||||
{less: customBytes([]byte{1, 1}), greater: customBytes([]byte{1, 2}), cType: "[]byte"},
|
{less: customBytes([]byte{1, 1}), greater: customBytes([]byte{1, 2}), cType: "[]byte"},
|
||||||
|
@ -392,8 +393,8 @@ func Test_compareTwoValuesDifferentValuesTypes(t *testing.T) {
|
||||||
{v1: float64(12), v2: "123"},
|
{v1: float64(12), v2: "123"},
|
||||||
{v1: "float(12)", v2: float64(1)},
|
{v1: "float(12)", v2: float64(1)},
|
||||||
} {
|
} {
|
||||||
compareResult := compareTwoValues(mockT, currCase.v1, currCase.v2, []CompareType{compareLess, compareEqual, compareGreater}, "testFailMessage")
|
result := compareTwoValues(mockT, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage")
|
||||||
False(t, compareResult)
|
False(t, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,8 +412,8 @@ func Test_compareTwoValuesNotComparableValues(t *testing.T) {
|
||||||
{v1: map[string]int{}, v2: map[string]int{}},
|
{v1: map[string]int{}, v2: map[string]int{}},
|
||||||
{v1: make([]int, 5), v2: make([]int, 5)},
|
{v1: make([]int, 5), v2: make([]int, 5)},
|
||||||
} {
|
} {
|
||||||
compareResult := compareTwoValues(mockT, currCase.v1, currCase.v2, []CompareType{compareLess, compareEqual, compareGreater}, "testFailMessage")
|
result := compareTwoValues(mockT, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage")
|
||||||
False(t, compareResult)
|
False(t, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,33 +423,33 @@ func Test_compareTwoValuesCorrectCompareResult(t *testing.T) {
|
||||||
for _, currCase := range []struct {
|
for _, currCase := range []struct {
|
||||||
v1 interface{}
|
v1 interface{}
|
||||||
v2 interface{}
|
v2 interface{}
|
||||||
compareTypes []CompareType
|
allowedResults []compareResult
|
||||||
}{
|
}{
|
||||||
{v1: 1, v2: 2, compareTypes: []CompareType{compareLess}},
|
{v1: 1, v2: 2, allowedResults: []compareResult{compareLess}},
|
||||||
{v1: 1, v2: 2, compareTypes: []CompareType{compareLess, compareEqual}},
|
{v1: 1, v2: 2, allowedResults: []compareResult{compareLess, compareEqual}},
|
||||||
{v1: 2, v2: 2, compareTypes: []CompareType{compareGreater, compareEqual}},
|
{v1: 2, v2: 2, allowedResults: []compareResult{compareGreater, compareEqual}},
|
||||||
{v1: 2, v2: 2, compareTypes: []CompareType{compareEqual}},
|
{v1: 2, v2: 2, allowedResults: []compareResult{compareEqual}},
|
||||||
{v1: 2, v2: 1, compareTypes: []CompareType{compareEqual, compareGreater}},
|
{v1: 2, v2: 1, allowedResults: []compareResult{compareEqual, compareGreater}},
|
||||||
{v1: 2, v2: 1, compareTypes: []CompareType{compareGreater}},
|
{v1: 2, v2: 1, allowedResults: []compareResult{compareGreater}},
|
||||||
} {
|
} {
|
||||||
compareResult := compareTwoValues(mockT, currCase.v1, currCase.v2, currCase.compareTypes, "testFailMessage")
|
result := compareTwoValues(mockT, currCase.v1, currCase.v2, currCase.allowedResults, "testFailMessage")
|
||||||
True(t, compareResult)
|
True(t, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_containsValue(t *testing.T) {
|
func Test_containsValue(t *testing.T) {
|
||||||
for _, currCase := range []struct {
|
for _, currCase := range []struct {
|
||||||
values []CompareType
|
values []compareResult
|
||||||
value CompareType
|
value compareResult
|
||||||
result bool
|
result bool
|
||||||
}{
|
}{
|
||||||
{values: []CompareType{compareGreater}, value: compareGreater, result: true},
|
{values: []compareResult{compareGreater}, value: compareGreater, result: true},
|
||||||
{values: []CompareType{compareGreater, compareLess}, value: compareGreater, result: true},
|
{values: []compareResult{compareGreater, compareLess}, value: compareGreater, result: true},
|
||||||
{values: []CompareType{compareGreater, compareLess}, value: compareLess, result: true},
|
{values: []compareResult{compareGreater, compareLess}, value: compareLess, result: true},
|
||||||
{values: []CompareType{compareGreater, compareLess}, value: compareEqual, result: false},
|
{values: []compareResult{compareGreater, compareLess}, value: compareEqual, result: false},
|
||||||
} {
|
} {
|
||||||
compareResult := containsValue(currCase.values, currCase.value)
|
result := containsValue(currCase.values, currCase.value)
|
||||||
Equal(t, currCase.result, compareResult)
|
Equal(t, currCase.result, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,8 @@ func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{},
|
||||||
return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualValuesf asserts that two objects are equal or convertible to the same types
|
// EqualValuesf asserts that two objects are equal or convertible to the larger
|
||||||
// and equal.
|
// type 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 {
|
||||||
|
@ -186,7 +186,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
|
||||||
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
|
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
|
||||||
// // add assertions as needed; any assertion failure will fail the current tick
|
// // add assertions as needed; any assertion failure will fail the current tick
|
||||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||||
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
|
// }, 10*time.Second, 1*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 {
|
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 {
|
if h, ok := t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
|
@ -568,6 +568,23 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
|
||||||
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
|
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should not match.
|
||||||
|
// This is an inverse of ElementsMatch.
|
||||||
|
//
|
||||||
|
// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
|
||||||
|
//
|
||||||
|
// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
|
||||||
|
//
|
||||||
|
// assert.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
|
||||||
|
func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
|
@ -604,7 +621,16 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s
|
||||||
return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotErrorIsf asserts that at none of the errors in err's chain matches target.
|
// NotErrorAsf asserts that none of the errors in err's chain matches target,
|
||||||
|
// but if so, sets target to that error value.
|
||||||
|
func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotErrorIsf asserts that none of the errors in err's chain matches target.
|
||||||
// This is a wrapper for errors.Is.
|
// This is a wrapper for errors.Is.
|
||||||
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
|
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
|
|
|
@ -186,8 +186,8 @@ func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface
|
||||||
return EqualExportedValuesf(a.t, expected, actual, msg, args...)
|
return EqualExportedValuesf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualValues asserts that two objects are equal or convertible to the same types
|
// EqualValues asserts that two objects are equal or convertible to the larger
|
||||||
// and equal.
|
// type and equal.
|
||||||
//
|
//
|
||||||
// a.EqualValues(uint32(123), int32(123))
|
// a.EqualValues(uint32(123), int32(123))
|
||||||
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
@ -197,8 +197,8 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
|
||||||
return EqualValues(a.t, expected, actual, msgAndArgs...)
|
return EqualValues(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualValuesf asserts that two objects are equal or convertible to the same types
|
// EqualValuesf asserts that two objects are equal or convertible to the larger
|
||||||
// and equal.
|
// type and equal.
|
||||||
//
|
//
|
||||||
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
|
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
|
||||||
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
@ -336,7 +336,7 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
|
||||||
// a.EventuallyWithT(func(c *assert.CollectT) {
|
// a.EventuallyWithT(func(c *assert.CollectT) {
|
||||||
// // add assertions as needed; any assertion failure will fail the current tick
|
// // add assertions as needed; any assertion failure will fail the current tick
|
||||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||||
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
|
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
|
||||||
func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
|
@ -361,7 +361,7 @@ func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor
|
||||||
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
|
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
|
||||||
// // add assertions as needed; any assertion failure will fail the current tick
|
// // add assertions as needed; any assertion failure will fail the current tick
|
||||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||||
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
|
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
|
||||||
func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
|
@ -1128,6 +1128,40 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
|
||||||
return NotContainsf(a.t, s, contains, msg, args...)
|
return NotContainsf(a.t, s, contains, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should not match.
|
||||||
|
// This is an inverse of ElementsMatch.
|
||||||
|
//
|
||||||
|
// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
|
||||||
|
//
|
||||||
|
// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
|
||||||
|
//
|
||||||
|
// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
|
||||||
|
func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotElementsMatch(a.t, listA, listB, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should not match.
|
||||||
|
// This is an inverse of ElementsMatch.
|
||||||
|
//
|
||||||
|
// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
|
||||||
|
//
|
||||||
|
// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
|
||||||
|
//
|
||||||
|
// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
|
||||||
|
func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotElementsMatchf(a.t, listA, listB, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
|
@ -1200,7 +1234,25 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
|
||||||
return NotEqualf(a.t, expected, actual, msg, args...)
|
return NotEqualf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotErrorIs asserts that at none of the errors in err's chain matches target.
|
// NotErrorAs asserts that none of the errors in err's chain matches target,
|
||||||
|
// but if so, sets target to that error value.
|
||||||
|
func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotErrorAs(a.t, err, target, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotErrorAsf asserts that none of the errors in err's chain matches target,
|
||||||
|
// but if so, sets target to that error value.
|
||||||
|
func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
return NotErrorAsf(a.t, err, target, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotErrorIs asserts that none of the errors in err's chain matches target.
|
||||||
// This is a wrapper for errors.Is.
|
// This is a wrapper for errors.Is.
|
||||||
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
@ -1209,7 +1261,7 @@ func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface
|
||||||
return NotErrorIs(a.t, err, target, msgAndArgs...)
|
return NotErrorIs(a.t, err, target, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotErrorIsf asserts that at none of the errors in err's chain matches target.
|
// NotErrorIsf asserts that none of the errors in err's chain matches target.
|
||||||
// This is a wrapper for errors.Is.
|
// This is a wrapper for errors.Is.
|
||||||
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// isOrdered checks that collection contains orderable elements.
|
// isOrdered checks that collection contains orderable elements.
|
||||||
func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool {
|
func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
|
||||||
objKind := reflect.TypeOf(object).Kind()
|
objKind := reflect.TypeOf(object).Kind()
|
||||||
if objKind != reflect.Slice && objKind != reflect.Array {
|
if objKind != reflect.Slice && objKind != reflect.Array {
|
||||||
return false
|
return false
|
||||||
|
@ -33,7 +33,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
|
||||||
compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind)
|
compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind)
|
||||||
|
|
||||||
if !isComparable {
|
if !isComparable {
|
||||||
return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...)
|
return Fail(t, fmt.Sprintf(`Can not compare type "%T" and "%T"`, value, prevValue), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !containsValue(allowedComparesResults, compareResult) {
|
if !containsValue(allowedComparesResults, compareResult) {
|
||||||
|
@ -50,7 +50,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
|
||||||
// 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, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNonIncreasing asserts that the collection is not increasing
|
// IsNonIncreasing asserts that the collection is not increasing
|
||||||
|
@ -59,7 +59,7 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
|
||||||
// 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, []compareResult{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
|
||||||
|
@ -68,7 +68,7 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{})
|
||||||
// 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, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNonDecreasing asserts that the collection is not decreasing
|
// IsNonDecreasing asserts that the collection is not decreasing
|
||||||
|
@ -77,5 +77,5 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
|
||||||
// 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, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,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"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
// Wrapper around gopkg.in/yaml.v3
|
||||||
|
"github.com/stretchr/testify/assert/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const stackFrameBufferSize = 10
|
||||||
|
|
||||||
//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"
|
||||||
|
|
||||||
// TestingT is an interface wrapper around *testing.T
|
// TestingT is an interface wrapper around *testing.T
|
||||||
|
@ -45,6 +49,10 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
|
||||||
// for table driven tests.
|
// for table driven tests.
|
||||||
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
|
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
|
||||||
|
|
||||||
|
// PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type PanicAssertionFunc = func(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool
|
||||||
|
|
||||||
// Comparison is a custom function that returns true on success and false on failure
|
// Comparison is a custom function that returns true on success and false on failure
|
||||||
type Comparison func() (success bool)
|
type Comparison func() (success bool)
|
||||||
|
|
||||||
|
@ -206,20 +214,29 @@ the problem actually occurred in calling code.*/
|
||||||
func CallerInfo() []string {
|
func CallerInfo() []string {
|
||||||
|
|
||||||
var pc uintptr
|
var pc uintptr
|
||||||
var ok bool
|
|
||||||
var file string
|
var file string
|
||||||
var line int
|
var line int
|
||||||
var name string
|
var name string
|
||||||
|
|
||||||
callers := []string{}
|
callers := []string{}
|
||||||
for i := 0; ; i++ {
|
pcs := make([]uintptr, stackFrameBufferSize)
|
||||||
pc, file, line, ok = runtime.Caller(i)
|
offset := 1
|
||||||
if !ok {
|
|
||||||
// The breaks below failed to terminate the loop, and we ran off the
|
for {
|
||||||
// end of the call stack.
|
n := runtime.Callers(offset, pcs)
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frames := runtime.CallersFrames(pcs[:n])
|
||||||
|
|
||||||
|
for {
|
||||||
|
frame, more := frames.Next()
|
||||||
|
pc = frame.PC
|
||||||
|
file = frame.File
|
||||||
|
line = frame.Line
|
||||||
|
|
||||||
// This is a huge edge case, but it will panic if this is the case, see #180
|
// This is a huge edge case, but it will panic if this is the case, see #180
|
||||||
if file == "<autogenerated>" {
|
if file == "<autogenerated>" {
|
||||||
break
|
break
|
||||||
|
@ -257,6 +274,13 @@ func CallerInfo() []string {
|
||||||
isTest(name, "Example") {
|
isTest(name, "Example") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We know we already have less than a buffer's worth of frames
|
||||||
|
offset += stackFrameBufferSize
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return callers
|
return callers
|
||||||
|
@ -438,7 +462,7 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
|
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
|
||||||
return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Object expected to be of type %T, but was %T", expectedType, object), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -496,7 +520,13 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !samePointers(expected, actual) {
|
same, ok := samePointers(expected, actual)
|
||||||
|
if !ok {
|
||||||
|
return Fail(t, "Both arguments must be pointers", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !same {
|
||||||
|
// both are pointers but not the same type & pointing to the same address
|
||||||
return Fail(t, fmt.Sprintf("Not same: \n"+
|
return Fail(t, fmt.Sprintf("Not same: \n"+
|
||||||
"expected: %p %#v\n"+
|
"expected: %p %#v\n"+
|
||||||
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
|
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
|
||||||
|
@ -516,7 +546,13 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
|
||||||
h.Helper()
|
h.Helper()
|
||||||
}
|
}
|
||||||
|
|
||||||
if samePointers(expected, actual) {
|
same, ok := samePointers(expected, actual)
|
||||||
|
if !ok {
|
||||||
|
//fails when the arguments are not pointers
|
||||||
|
return !(Fail(t, "Both arguments must be pointers", msgAndArgs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
if same {
|
||||||
return Fail(t, fmt.Sprintf(
|
return Fail(t, fmt.Sprintf(
|
||||||
"Expected and actual point to the same object: %p %#v",
|
"Expected and actual point to the same object: %p %#v",
|
||||||
expected, expected), msgAndArgs...)
|
expected, expected), msgAndArgs...)
|
||||||
|
@ -524,21 +560,23 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// samePointers compares two generic interface objects and returns whether
|
// samePointers checks if two generic interface objects are pointers of the same
|
||||||
// they point to the same object
|
// type pointing to the same object. It returns two values: same indicating if
|
||||||
func samePointers(first, second interface{}) bool {
|
// they are the same type and point to the same object, and ok indicating that
|
||||||
|
// both inputs are pointers.
|
||||||
|
func samePointers(first, second interface{}) (same bool, ok bool) {
|
||||||
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
|
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
|
||||||
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
|
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
|
||||||
return false
|
return false, false //not both are pointers
|
||||||
}
|
}
|
||||||
|
|
||||||
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
|
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
|
||||||
if firstType != secondType {
|
if firstType != secondType {
|
||||||
return false
|
return false, true // both are pointers, but of different types
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare pointer addresses
|
// compare pointer addresses
|
||||||
return first == second
|
return first == second, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatUnequalValues takes two values of arbitrary types and returns string
|
// formatUnequalValues takes two values of arbitrary types and returns string
|
||||||
|
@ -572,8 +610,8 @@ func truncatingFormat(data interface{}) string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualValues asserts that two objects are equal or convertible to the same types
|
// EqualValues asserts that two objects are equal or convertible to the larger
|
||||||
// and equal.
|
// type 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 {
|
||||||
|
@ -615,21 +653,6 @@ func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ..
|
||||||
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if aType.Kind() == reflect.Ptr {
|
|
||||||
aType = aType.Elem()
|
|
||||||
}
|
|
||||||
if bType.Kind() == reflect.Ptr {
|
|
||||||
bType = bType.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
if aType.Kind() != reflect.Struct {
|
|
||||||
return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to 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 or pointer to struct \n\t%v != %v", bType.Kind(), reflect.Struct), msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = copyExportedFields(expected)
|
expected = copyExportedFields(expected)
|
||||||
actual = copyExportedFields(actual)
|
actual = copyExportedFields(actual)
|
||||||
|
|
||||||
|
@ -1064,7 +1087,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
|
||||||
element := subsetList.Index(i).Interface()
|
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("%q could not be applied builtin len()", list), msgAndArgs...)
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return true
|
return true
|
||||||
|
@ -1170,6 +1193,39 @@ func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) stri
|
||||||
return msg.String()
|
return msg.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should not match.
|
||||||
|
// This is an inverse of ElementsMatch.
|
||||||
|
//
|
||||||
|
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
|
||||||
|
//
|
||||||
|
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
|
||||||
|
//
|
||||||
|
// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
|
||||||
|
func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
if isEmpty(listA) && isEmpty(listB) {
|
||||||
|
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isList(t, listA, msgAndArgs...) {
|
||||||
|
return Fail(t, "listA is not a list type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
if !isList(t, listB, msgAndArgs...) {
|
||||||
|
return Fail(t, "listB is not a list type", msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
extraA, extraB := diffLists(listA, listB)
|
||||||
|
if len(extraA) == 0 && len(extraB) == 0 {
|
||||||
|
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Condition uses a Comparison to assert a complex condition.
|
// Condition uses a Comparison to assert a complex condition.
|
||||||
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
|
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
|
@ -1488,6 +1544,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Fail(t, err.Error(), msgAndArgs...)
|
return Fail(t, err.Error(), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
if math.IsNaN(actualEpsilon) {
|
||||||
|
return Fail(t, "relative error is NaN", msgAndArgs...)
|
||||||
|
}
|
||||||
if actualEpsilon > epsilon {
|
if actualEpsilon > epsilon {
|
||||||
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
|
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
|
||||||
" < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
|
" < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
|
||||||
|
@ -1611,7 +1670,6 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in
|
||||||
|
|
||||||
// matchRegexp return true if a specified regexp matches a string.
|
// matchRegexp return true if a specified regexp matches a string.
|
||||||
func matchRegexp(rx interface{}, str interface{}) bool {
|
func matchRegexp(rx interface{}, str interface{}) bool {
|
||||||
|
|
||||||
var r *regexp.Regexp
|
var r *regexp.Regexp
|
||||||
if rr, ok := rx.(*regexp.Regexp); ok {
|
if rr, ok := rx.(*regexp.Regexp); ok {
|
||||||
r = rr
|
r = rr
|
||||||
|
@ -1619,7 +1677,14 @@ func matchRegexp(rx interface{}, str interface{}) bool {
|
||||||
r = regexp.MustCompile(fmt.Sprint(rx))
|
r = regexp.MustCompile(fmt.Sprint(rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
return (r.FindStringIndex(fmt.Sprint(str)) != nil)
|
switch v := str.(type) {
|
||||||
|
case []byte:
|
||||||
|
return r.Match(v)
|
||||||
|
case string:
|
||||||
|
return r.MatchString(v)
|
||||||
|
default:
|
||||||
|
return r.MatchString(fmt.Sprint(v))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1872,7 +1937,7 @@ var spewConfigStringerEnabled = spew.ConfigState{
|
||||||
MaxDepth: 10,
|
MaxDepth: 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
type tHelper interface {
|
type tHelper = interface {
|
||||||
Helper()
|
Helper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1911,6 +1976,9 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
||||||
|
|
||||||
// CollectT implements the TestingT interface and collects all errors.
|
// CollectT implements the TestingT interface and collects all errors.
|
||||||
type CollectT struct {
|
type CollectT struct {
|
||||||
|
// A slice of errors. Non-nil slice denotes a failure.
|
||||||
|
// If it's non-nil but len(c.errors) == 0, this is also a failure
|
||||||
|
// obtained by direct c.FailNow() call.
|
||||||
errors []error
|
errors []error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1919,9 +1987,10 @@ func (c *CollectT) Errorf(format string, args ...interface{}) {
|
||||||
c.errors = append(c.errors, fmt.Errorf(format, args...))
|
c.errors = append(c.errors, fmt.Errorf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailNow panics.
|
// FailNow stops execution by calling runtime.Goexit.
|
||||||
func (*CollectT) FailNow() {
|
func (c *CollectT) FailNow() {
|
||||||
panic("Assertion failed")
|
c.fail()
|
||||||
|
runtime.Goexit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
|
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
|
||||||
|
@ -1934,6 +2003,16 @@ func (*CollectT) Copy(TestingT) {
|
||||||
panic("Copy() is deprecated")
|
panic("Copy() is deprecated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CollectT) fail() {
|
||||||
|
if !c.failed() {
|
||||||
|
c.errors = []error{} // Make it non-nil to mark a failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CollectT) failed() bool {
|
||||||
|
return c.errors != nil
|
||||||
|
}
|
||||||
|
|
||||||
// EventuallyWithT asserts that given condition will be met in waitFor time,
|
// EventuallyWithT asserts that given condition will be met in waitFor time,
|
||||||
// periodically checking target function each tick. In contrast to Eventually,
|
// periodically checking target function each tick. In contrast to Eventually,
|
||||||
// it supplies a CollectT to the condition function, so that the condition
|
// it supplies a CollectT to the condition function, so that the condition
|
||||||
|
@ -1951,14 +2030,14 @@ func (*CollectT) Copy(TestingT) {
|
||||||
// assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
// assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||||
// // add assertions as needed; any assertion failure will fail the current tick
|
// // add assertions as needed; any assertion failure will fail the current tick
|
||||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||||
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
|
// }, 10*time.Second, 1*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 {
|
func EventuallyWithT(t TestingT, condition func(collect *CollectT), 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastFinishedTickErrs []error
|
var lastFinishedTickErrs []error
|
||||||
ch := make(chan []error, 1)
|
ch := make(chan *CollectT, 1)
|
||||||
|
|
||||||
timer := time.NewTimer(waitFor)
|
timer := time.NewTimer(waitFor)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
|
@ -1978,16 +2057,16 @@ func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time
|
||||||
go func() {
|
go func() {
|
||||||
collect := new(CollectT)
|
collect := new(CollectT)
|
||||||
defer func() {
|
defer func() {
|
||||||
ch <- collect.errors
|
ch <- collect
|
||||||
}()
|
}()
|
||||||
condition(collect)
|
condition(collect)
|
||||||
}()
|
}()
|
||||||
case errs := <-ch:
|
case collect := <-ch:
|
||||||
if len(errs) == 0 {
|
if !collect.failed() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
|
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
|
||||||
lastFinishedTickErrs = errs
|
lastFinishedTickErrs = collect.errors
|
||||||
tick = ticker.C
|
tick = ticker.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2041,7 +2120,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
||||||
expectedText = target.Error()
|
expectedText = target.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, false)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
|
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
|
||||||
"expected: %q\n"+
|
"expected: %q\n"+
|
||||||
|
@ -2049,7 +2128,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
||||||
), msgAndArgs...)
|
), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotErrorIs asserts that at none of the errors in err's chain matches target.
|
// NotErrorIs asserts that none of the errors in err's chain matches target.
|
||||||
// This is a wrapper for errors.Is.
|
// This is a wrapper for errors.Is.
|
||||||
func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
||||||
if h, ok := t.(tHelper); ok {
|
if h, ok := t.(tHelper); ok {
|
||||||
|
@ -2064,7 +2143,7 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
||||||
expectedText = target.Error()
|
expectedText = target.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, false)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
||||||
"found: %q\n"+
|
"found: %q\n"+
|
||||||
|
@ -2082,24 +2161,64 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
chain := buildErrorChainString(err)
|
chain := buildErrorChainString(err, true)
|
||||||
|
|
||||||
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
|
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
|
||||||
"expected: %q\n"+
|
"expected: %s\n"+
|
||||||
"in chain: %s", target, chain,
|
"in chain: %s", reflect.ValueOf(target).Elem().Type(), chain,
|
||||||
), msgAndArgs...)
|
), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildErrorChainString(err error) string {
|
// NotErrorAs asserts that none of the errors in err's chain matches target,
|
||||||
|
// but if so, sets target to that error value.
|
||||||
|
func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
if !errors.As(err, target) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
chain := buildErrorChainString(err, true)
|
||||||
|
|
||||||
|
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
||||||
|
"found: %s\n"+
|
||||||
|
"in chain: %s", reflect.ValueOf(target).Elem().Type(), chain,
|
||||||
|
), msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unwrapAll(err error) (errs []error) {
|
||||||
|
errs = append(errs, err)
|
||||||
|
switch x := err.(type) {
|
||||||
|
case interface{ Unwrap() error }:
|
||||||
|
err = x.Unwrap()
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errs = append(errs, unwrapAll(err)...)
|
||||||
|
case interface{ Unwrap() []error }:
|
||||||
|
for _, err := range x.Unwrap() {
|
||||||
|
errs = append(errs, unwrapAll(err)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildErrorChainString(err error, withType bool) string {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
e := errors.Unwrap(err)
|
var chain string
|
||||||
chain := fmt.Sprintf("%q", err.Error())
|
errs := unwrapAll(err)
|
||||||
for e != nil {
|
for i := range errs {
|
||||||
chain += fmt.Sprintf("\n\t%q", e.Error())
|
if i != 0 {
|
||||||
e = errors.Unwrap(e)
|
chain += "\n\t"
|
||||||
|
}
|
||||||
|
chain += fmt.Sprintf("%q", errs[i].Error())
|
||||||
|
if withType {
|
||||||
|
chain += fmt.Sprintf(" (%T)", errs[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,6 +449,56 @@ func TestEqualExportedValues(t *testing.T) {
|
||||||
+ Exported: (int) 1,
|
+ Exported: (int) 1,
|
||||||
notExported: (interface {}) <nil>`,
|
notExported: (interface {}) <nil>`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value1: []int{1, 2},
|
||||||
|
value2: []int{1, 2},
|
||||||
|
expectedEqual: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: []int{1, 2},
|
||||||
|
value2: []int{1, 3},
|
||||||
|
expectedEqual: false,
|
||||||
|
expectedFail: `
|
||||||
|
Diff:
|
||||||
|
--- Expected
|
||||||
|
+++ Actual
|
||||||
|
@@ -2,3 +2,3 @@
|
||||||
|
(int) 1,
|
||||||
|
- (int) 2
|
||||||
|
+ (int) 3
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: []*Nested{
|
||||||
|
{1, 2},
|
||||||
|
{3, 4},
|
||||||
|
},
|
||||||
|
value2: []*Nested{
|
||||||
|
{1, "a"},
|
||||||
|
{3, "b"},
|
||||||
|
},
|
||||||
|
expectedEqual: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value1: []*Nested{
|
||||||
|
{1, 2},
|
||||||
|
{3, 4},
|
||||||
|
},
|
||||||
|
value2: []*Nested{
|
||||||
|
{1, "a"},
|
||||||
|
{2, "b"},
|
||||||
|
},
|
||||||
|
expectedEqual: false,
|
||||||
|
expectedFail: `
|
||||||
|
Diff:
|
||||||
|
--- Expected
|
||||||
|
+++ Actual
|
||||||
|
@@ -6,3 +6,3 @@
|
||||||
|
(*assert.Nested)({
|
||||||
|
- Exported: (int) 3,
|
||||||
|
+ Exported: (int) 2,
|
||||||
|
notExported: (interface {}) <nil>`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
|
@ -607,37 +657,57 @@ func Test_samePointers(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
assertion BoolAssertionFunc
|
same BoolAssertionFunc
|
||||||
|
ok BoolAssertionFunc
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "1 != 2",
|
name: "1 != 2",
|
||||||
args: args{first: 1, second: 2},
|
args: args{first: 1, second: 2},
|
||||||
assertion: False,
|
same: False,
|
||||||
|
ok: False,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "1 != 1 (not same ptr)",
|
name: "1 != 1 (not same ptr)",
|
||||||
args: args{first: 1, second: 1},
|
args: args{first: 1, second: 1},
|
||||||
assertion: False,
|
same: False,
|
||||||
|
ok: False,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ptr(1) == ptr(1)",
|
name: "ptr(1) == ptr(1)",
|
||||||
args: args{first: p, second: p},
|
args: args{first: p, second: p},
|
||||||
assertion: True,
|
same: True,
|
||||||
|
ok: True,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "int(1) != float32(1)",
|
name: "int(1) != float32(1)",
|
||||||
args: args{first: int(1), second: float32(1)},
|
args: args{first: int(1), second: float32(1)},
|
||||||
assertion: False,
|
same: False,
|
||||||
|
ok: False,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "array != slice",
|
name: "array != slice",
|
||||||
args: args{first: [2]int{1, 2}, second: []int{1, 2}},
|
args: args{first: [2]int{1, 2}, second: []int{1, 2}},
|
||||||
assertion: False,
|
same: False,
|
||||||
|
ok: False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-pointer vs pointer (1 != ptr(2))",
|
||||||
|
args: args{first: 1, second: p},
|
||||||
|
same: False,
|
||||||
|
ok: False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pointer vs non-pointer (ptr(2) != 1)",
|
||||||
|
args: args{first: p, second: 1},
|
||||||
|
same: False,
|
||||||
|
ok: False,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
tt.assertion(t, samePointers(tt.args.first, tt.args.second))
|
same, ok := samePointers(tt.args.first, tt.args.second)
|
||||||
|
tt.same(t, same)
|
||||||
|
tt.ok(t, ok)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1319,6 +1389,52 @@ func TestDiffLists(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNotElementsMatch(t *testing.T) {
|
||||||
|
mockT := new(testing.T)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
expected interface{}
|
||||||
|
actual interface{}
|
||||||
|
result bool
|
||||||
|
}{
|
||||||
|
// not matching
|
||||||
|
{[]int{1}, []int{}, true},
|
||||||
|
{[]int{}, []int{2}, true},
|
||||||
|
{[]int{1}, []int{2}, true},
|
||||||
|
{[]int{1}, []int{1, 1}, true},
|
||||||
|
{[]int{1, 2}, []int{3, 4}, true},
|
||||||
|
{[]int{3, 4}, []int{1, 2}, true},
|
||||||
|
{[]int{1, 1, 2, 3}, []int{1, 2, 3}, true},
|
||||||
|
{[]string{"hello"}, []string{"world"}, true},
|
||||||
|
{[]string{"hello", "hello"}, []string{"world", "world"}, true},
|
||||||
|
{[3]string{"hello", "hello", "hello"}, [3]string{"world", "world", "world"}, true},
|
||||||
|
|
||||||
|
// matching
|
||||||
|
{nil, nil, false},
|
||||||
|
{[]int{}, nil, false},
|
||||||
|
{[]int{}, []int{}, false},
|
||||||
|
{[]int{1}, []int{1}, false},
|
||||||
|
{[]int{1, 1}, []int{1, 1}, false},
|
||||||
|
{[]int{1, 2}, []int{2, 1}, false},
|
||||||
|
{[2]int{1, 2}, [2]int{2, 1}, false},
|
||||||
|
{[]int{1, 1, 2}, []int{1, 2, 1}, false},
|
||||||
|
{[]string{"hello", "world"}, []string{"world", "hello"}, false},
|
||||||
|
{[]string{"hello", "hello"}, []string{"hello", "hello"}, false},
|
||||||
|
{[]string{"hello", "hello", "world"}, []string{"hello", "world", "hello"}, false},
|
||||||
|
{[3]string{"hello", "hello", "world"}, [3]string{"hello", "world", "hello"}, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(fmt.Sprintf("NotElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) {
|
||||||
|
res := NotElementsMatch(mockT, c.actual, c.expected)
|
||||||
|
|
||||||
|
if res != c.result {
|
||||||
|
t.Errorf("NotElementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCondition(t *testing.T) {
|
func TestCondition(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
mockT := new(testing.T)
|
||||||
|
|
||||||
|
@ -1940,6 +2056,14 @@ func TestInEpsilon(t *testing.T) {
|
||||||
{math.NaN(), 0, 1},
|
{math.NaN(), 0, 1},
|
||||||
{0, math.NaN(), 1},
|
{0, math.NaN(), 1},
|
||||||
{0, 0, math.NaN()},
|
{0, 0, math.NaN()},
|
||||||
|
{math.Inf(1), 1, 1},
|
||||||
|
{math.Inf(-1), 1, 1},
|
||||||
|
{1, math.Inf(1), 1},
|
||||||
|
{1, math.Inf(-1), 1},
|
||||||
|
{math.Inf(1), math.Inf(1), 1},
|
||||||
|
{math.Inf(1), math.Inf(-1), 1},
|
||||||
|
{math.Inf(-1), math.Inf(1), 1},
|
||||||
|
{math.Inf(-1), math.Inf(-1), 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
@ -1972,13 +2096,16 @@ func TestRegexp(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"^start", "start of the line"},
|
{"^start", "start of the line"},
|
||||||
{"end$", "in the end"},
|
{"end$", "in the end"},
|
||||||
|
{"end$", "in the end"},
|
||||||
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
|
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
True(t, Regexp(mockT, tc.rx, tc.str))
|
True(t, Regexp(mockT, tc.rx, tc.str))
|
||||||
True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
||||||
|
True(t, Regexp(mockT, regexp.MustCompile(tc.rx), []byte(tc.str)))
|
||||||
False(t, NotRegexp(mockT, tc.rx, tc.str))
|
False(t, NotRegexp(mockT, tc.rx, tc.str))
|
||||||
|
False(t, NotRegexp(mockT, tc.rx, []byte(tc.str)))
|
||||||
False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1991,9 +2118,11 @@ func TestRegexp(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
|
False(t, Regexp(mockT, tc.rx, tc.str), "Expected %q to not match %q", tc.rx, tc.str)
|
||||||
False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
||||||
|
False(t, Regexp(mockT, regexp.MustCompile(tc.rx), []byte(tc.str)))
|
||||||
True(t, NotRegexp(mockT, tc.rx, tc.str))
|
True(t, NotRegexp(mockT, tc.rx, tc.str))
|
||||||
|
True(t, NotRegexp(mockT, tc.rx, []byte(tc.str)))
|
||||||
True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2022,11 +2151,11 @@ func TestZero(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
mockT := new(testing.T)
|
||||||
|
|
||||||
for _, test := range zeros {
|
for _, test := range zeros {
|
||||||
True(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
|
True(t, Zero(mockT, test, "%#v is not the %T zero value", test, test))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range nonZeros {
|
for _, test := range nonZeros {
|
||||||
False(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
|
False(t, Zero(mockT, test, "%#v is not the %T zero value", test, test))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2034,11 +2163,11 @@ func TestNotZero(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
mockT := new(testing.T)
|
||||||
|
|
||||||
for _, test := range zeros {
|
for _, test := range zeros {
|
||||||
False(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
|
False(t, NotZero(mockT, test, "%#v is not the %T zero value", test, test))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range nonZeros {
|
for _, test := range nonZeros {
|
||||||
True(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
|
True(t, NotZero(mockT, test, "%#v is not the %T zero value", test, test))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2789,6 +2918,42 @@ func TestErrorAssertionFunc(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExamplePanicAssertionFunc() {
|
||||||
|
t := &testing.T{} // provided by test
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
panicFn PanicTestFunc
|
||||||
|
assertion PanicAssertionFunc
|
||||||
|
}{
|
||||||
|
{"with panic", func() { panic(nil) }, Panics},
|
||||||
|
{"without panic", func() {}, NotPanics},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tt.assertion(t, tt.panicFn)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPanicAssertionFunc(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
panicFn PanicTestFunc
|
||||||
|
assertion PanicAssertionFunc
|
||||||
|
}{
|
||||||
|
{"not panic", func() {}, NotPanics},
|
||||||
|
{"panic", func() { panic(nil) }, Panics},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tt.assertion(t, tt.panicFn)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEventuallyFalse(t *testing.T) {
|
func TestEventuallyFalse(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
mockT := new(testing.T)
|
||||||
|
|
||||||
|
@ -2836,16 +3001,15 @@ func TestEventuallyWithTFalse(t *testing.T) {
|
||||||
func TestEventuallyWithTTrue(t *testing.T) {
|
func TestEventuallyWithTTrue(t *testing.T) {
|
||||||
mockT := new(errorsCapturingT)
|
mockT := new(errorsCapturingT)
|
||||||
|
|
||||||
state := 0
|
counter := 0
|
||||||
condition := func(collect *CollectT) {
|
condition := func(collect *CollectT) {
|
||||||
defer func() {
|
counter += 1
|
||||||
state += 1
|
True(collect, counter == 2)
|
||||||
}()
|
|
||||||
True(collect, state == 2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
|
True(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
|
||||||
Len(t, mockT.errors, 0)
|
Len(t, mockT.errors, 0)
|
||||||
|
Equal(t, 2, counter, "Condition is expected to be called 2 times")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventuallyWithT_ConcurrencySafe(t *testing.T) {
|
func TestEventuallyWithT_ConcurrencySafe(t *testing.T) {
|
||||||
|
@ -2883,6 +3047,17 @@ func TestEventuallyWithT_ReturnsTheLatestFinishedConditionErrors(t *testing.T) {
|
||||||
Len(t, mockT.errors, 2)
|
Len(t, mockT.errors, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEventuallyWithTFailNow(t *testing.T) {
|
||||||
|
mockT := new(CollectT)
|
||||||
|
|
||||||
|
condition := func(collect *CollectT) {
|
||||||
|
collect.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
False(t, EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond))
|
||||||
|
Len(t, mockT.errors, 1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNeverFalse(t *testing.T) {
|
func TestNeverFalse(t *testing.T) {
|
||||||
condition := func() bool {
|
condition := func() bool {
|
||||||
return false
|
return false
|
||||||
|
@ -3000,11 +3175,13 @@ func parseLabeledOutput(output string) []labeledContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
type captureTestingT struct {
|
type captureTestingT struct {
|
||||||
|
failed bool
|
||||||
msg string
|
msg string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
|
func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
|
||||||
ctt.msg = fmt.Sprintf(format, args...)
|
ctt.msg = fmt.Sprintf(format, args...)
|
||||||
|
ctt.failed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) {
|
func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res bool, expectedErrMsg string) {
|
||||||
|
@ -3013,6 +3190,10 @@ func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expectedRes, res
|
||||||
t.Errorf("Should return %t", expectedRes)
|
t.Errorf("Should return %t", expectedRes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if res == ctt.failed {
|
||||||
|
t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !ctt.failed)
|
||||||
|
return
|
||||||
|
}
|
||||||
contents := parseLabeledOutput(ctt.msg)
|
contents := parseLabeledOutput(ctt.msg)
|
||||||
if res == true {
|
if res == true {
|
||||||
if contents != nil {
|
if contents != nil {
|
||||||
|
@ -3172,23 +3353,83 @@ func TestNotErrorIs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorAs(t *testing.T) {
|
func TestErrorAs(t *testing.T) {
|
||||||
mockT := new(testing.T)
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
err error
|
err error
|
||||||
result bool
|
result bool
|
||||||
|
resultErrMsg string
|
||||||
}{
|
}{
|
||||||
{fmt.Errorf("wrap: %w", &customError{}), true},
|
{
|
||||||
{io.EOF, false},
|
err: fmt.Errorf("wrap: %w", &customError{}),
|
||||||
{nil, false},
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: io.EOF,
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Should be in error chain:\n" +
|
||||||
|
"expected: *assert.customError\n" +
|
||||||
|
"in chain: \"EOF\" (*errors.errorString)\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: nil,
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Should be in error chain:\n" +
|
||||||
|
"expected: *assert.customError\n" +
|
||||||
|
"in chain: \n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: fmt.Errorf("abc: %w", errors.New("def")),
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Should be in error chain:\n" +
|
||||||
|
"expected: *assert.customError\n" +
|
||||||
|
"in chain: \"abc: def\" (*fmt.wrapError)\n" +
|
||||||
|
"\t\"def\" (*errors.errorString)\n",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt
|
tt := tt
|
||||||
var target *customError
|
var target *customError
|
||||||
t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
||||||
|
mockT := new(captureTestingT)
|
||||||
res := ErrorAs(mockT, tt.err, &target)
|
res := ErrorAs(mockT, tt.err, &target)
|
||||||
if res != tt.result {
|
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
|
||||||
t.Errorf("ErrorAs(%#v,%#v) should return %t)", tt.err, target, tt.result)
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotErrorAs(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
result bool
|
||||||
|
resultErrMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
err: fmt.Errorf("wrap: %w", &customError{}),
|
||||||
|
result: false,
|
||||||
|
resultErrMsg: "" +
|
||||||
|
"Target error should not be in err chain:\n" +
|
||||||
|
"found: *assert.customError\n" +
|
||||||
|
"in chain: \"wrap: fail\" (*fmt.wrapError)\n" +
|
||||||
|
"\t\"fail\" (*assert.customError)\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: io.EOF,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
err: nil,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
var target *customError
|
||||||
|
t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) {
|
||||||
|
mockT := new(captureTestingT)
|
||||||
|
res := NotErrorAs(mockT, tt.err, &target)
|
||||||
|
mockT.checkResultAndErrMsg(t, tt.result, res, tt.resultErrMsg)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -546,7 +546,7 @@ func TestRegexpWrapper(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
False(t, assert.Regexp(tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
|
False(t, assert.Regexp(tc.rx, tc.str), "Expected %q to not match %q", tc.rx, tc.str)
|
||||||
False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
|
False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
|
||||||
True(t, assert.NotRegexp(tc.rx, tc.str))
|
True(t, assert.NotRegexp(tc.rx, tc.str))
|
||||||
True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
|
True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
|
||||||
|
|
|
@ -138,7 +138,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
|
||||||
|
|
||||||
contains := strings.Contains(body, fmt.Sprint(str))
|
contains := strings.Contains(body, fmt.Sprint(str))
|
||||||
if !contains {
|
if !contains {
|
||||||
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...)
|
Fail(t, fmt.Sprintf("Expected response body for %q to contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return contains
|
return contains
|
||||||
|
@ -158,7 +158,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin
|
||||||
|
|
||||||
contains := strings.Contains(body, fmt.Sprint(str))
|
contains := strings.Contains(body, fmt.Sprint(str))
|
||||||
if contains {
|
if contains {
|
||||||
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...)
|
Fail(t, fmt.Sprintf("Expected response body for %q to NOT contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return !contains
|
return !contains
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
//go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default
|
||||||
|
// +build testify_yaml_custom,!testify_yaml_fail,!testify_yaml_default
|
||||||
|
|
||||||
|
// Package yaml is an implementation of YAML functions that calls a pluggable implementation.
|
||||||
|
//
|
||||||
|
// This implementation is selected with the testify_yaml_custom build tag.
|
||||||
|
//
|
||||||
|
// go test -tags testify_yaml_custom
|
||||||
|
//
|
||||||
|
// This implementation can be used at build time to replace the default implementation
|
||||||
|
// to avoid linking with [gopkg.in/yaml.v3].
|
||||||
|
//
|
||||||
|
// In your test package:
|
||||||
|
//
|
||||||
|
// import assertYaml "github.com/stretchr/testify/assert/yaml"
|
||||||
|
//
|
||||||
|
// func init() {
|
||||||
|
// assertYaml.Unmarshal = func (in []byte, out interface{}) error {
|
||||||
|
// // ...
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
var Unmarshal func(in []byte, out interface{}) error
|
|
@ -0,0 +1,37 @@
|
||||||
|
//go:build !testify_yaml_fail && !testify_yaml_custom
|
||||||
|
// +build !testify_yaml_fail,!testify_yaml_custom
|
||||||
|
|
||||||
|
// Package yaml is just an indirection to handle YAML deserialization.
|
||||||
|
//
|
||||||
|
// This package is just an indirection that allows the builder to override the
|
||||||
|
// indirection with an alternative implementation of this package that uses
|
||||||
|
// another implementation of YAML deserialization. This allows to not either not
|
||||||
|
// use YAML deserialization at all, or to use another implementation than
|
||||||
|
// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]).
|
||||||
|
//
|
||||||
|
// Alternative implementations are selected using build tags:
|
||||||
|
//
|
||||||
|
// - testify_yaml_fail: [Unmarshal] always fails with an error
|
||||||
|
// - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it
|
||||||
|
// before calling any of [github.com/stretchr/testify/assert.YAMLEq] or
|
||||||
|
// [github.com/stretchr/testify/assert.YAMLEqf].
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// go test -tags testify_yaml_fail
|
||||||
|
//
|
||||||
|
// You can check with "go list" which implementation is linked:
|
||||||
|
//
|
||||||
|
// go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
|
||||||
|
// go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
|
||||||
|
// go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
|
||||||
|
//
|
||||||
|
// [PR #1120]: https://github.com/stretchr/testify/pull/1120
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import goyaml "gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal].
|
||||||
|
func Unmarshal(in []byte, out interface{}) error {
|
||||||
|
return goyaml.Unmarshal(in, out)
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
//go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default
|
||||||
|
// +build testify_yaml_fail,!testify_yaml_custom,!testify_yaml_default
|
||||||
|
|
||||||
|
// Package yaml is an implementation of YAML functions that always fail.
|
||||||
|
//
|
||||||
|
// This implementation can be used at build time to replace the default implementation
|
||||||
|
// to avoid linking with [gopkg.in/yaml.v3]:
|
||||||
|
//
|
||||||
|
// go test -tags testify_yaml_fail
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)")
|
||||||
|
|
||||||
|
func Unmarshal([]byte, interface{}) error {
|
||||||
|
return errNotImplemented
|
||||||
|
}
|
6
doc.go
6
doc.go
|
@ -1,4 +1,3 @@
|
||||||
// ** We are working on testify v2 and would love to hear what you'd like to see in it, have your say here: https://cutt.ly/testify **
|
|
||||||
// Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend.
|
// Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend.
|
||||||
//
|
//
|
||||||
// testify contains the following packages:
|
// testify contains the following packages:
|
||||||
|
@ -8,4 +7,9 @@
|
||||||
// The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected.
|
// The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected.
|
||||||
//
|
//
|
||||||
// The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces.
|
// The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces.
|
||||||
|
//
|
||||||
|
// A [golangci-lint] compatible linter for testify is available called [testifylint].
|
||||||
|
//
|
||||||
|
// [golangci-lint]: https://golangci-lint.run/
|
||||||
|
// [testifylint]: https://github.com/Antonboom/testifylint
|
||||||
package testify
|
package testify
|
||||||
|
|
173
mock/mock.go
173
mock/mock.go
|
@ -80,12 +80,12 @@ type Call struct {
|
||||||
requires []*Call
|
requires []*Call
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call {
|
func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments Arguments, returnArguments Arguments) *Call {
|
||||||
return &Call{
|
return &Call{
|
||||||
Parent: parent,
|
Parent: parent,
|
||||||
Method: methodName,
|
Method: methodName,
|
||||||
Arguments: methodArguments,
|
Arguments: methodArguments,
|
||||||
ReturnArguments: make([]interface{}, 0),
|
ReturnArguments: returnArguments,
|
||||||
callerInfo: callerInfo,
|
callerInfo: callerInfo,
|
||||||
Repeatability: 0,
|
Repeatability: 0,
|
||||||
WaitFor: nil,
|
WaitFor: nil,
|
||||||
|
@ -208,9 +208,16 @@ 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 all mock handlers that satisfy the call instance arguments from being
|
||||||
|
// called. Only supported on call instances with static input arguments.
|
||||||
//
|
//
|
||||||
// test.On("func", mock.Anything).Unset()
|
// For example, the only handler remaining after the following would be "MyMethod(2, 2)":
|
||||||
|
//
|
||||||
|
// Mock.
|
||||||
|
// On("MyMethod", 2, 2).Return(0).
|
||||||
|
// On("MyMethod", 3, 3).Return(0).
|
||||||
|
// On("MyMethod", Anything, Anything).Return(0)
|
||||||
|
// Mock.On("MyMethod", 3, 3).Unset()
|
||||||
func (c *Call) Unset() *Call {
|
func (c *Call) Unset() *Call {
|
||||||
var unlockOnce sync.Once
|
var unlockOnce sync.Once
|
||||||
|
|
||||||
|
@ -256,7 +263,7 @@ 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 {
|
||||||
|
@ -273,6 +280,20 @@ func (c *Call) NotBefore(calls ...*Call) *Call {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InOrder defines the order in which the calls should be made
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// InOrder(
|
||||||
|
// Mock.On("init").Return(nil),
|
||||||
|
// Mock.On("Do").Return(nil),
|
||||||
|
// )
|
||||||
|
func InOrder(calls ...*Call) {
|
||||||
|
for i := 1; i < len(calls); i++ {
|
||||||
|
calls[i].NotBefore(calls[i-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mock is the workhorse used to track activity on another object.
|
// Mock is the workhorse used to track activity on another object.
|
||||||
// For an example of its usage, refer to the "Example Usage" section at the top
|
// For an example of its usage, refer to the "Example Usage" section at the top
|
||||||
// of this document.
|
// of this document.
|
||||||
|
@ -317,7 +338,10 @@ func (m *Mock) TestData() objx.Map {
|
||||||
Setting expectations
|
Setting expectations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Test sets the test struct variable of the mock object
|
// Test sets the [TestingT] on which errors will be reported, otherwise errors
|
||||||
|
// will cause a panic.
|
||||||
|
// Test should not be called on an object that is going to be used in a
|
||||||
|
// goroutine other than the one running the test function.
|
||||||
func (m *Mock) Test(t TestingT) {
|
func (m *Mock) Test(t TestingT) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
@ -351,7 +375,8 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
|
||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
c := newCall(m, methodName, assert.CallerInfo(), arguments...)
|
|
||||||
|
c := newCall(m, methodName, assert.CallerInfo(), arguments, make([]interface{}, 0))
|
||||||
m.ExpectedCalls = append(m.ExpectedCalls, c)
|
m.ExpectedCalls = append(m.ExpectedCalls, c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -479,7 +504,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
|
||||||
// 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(%#v).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())
|
||||||
}
|
}
|
||||||
// we have to fail here - because we don't know what to do
|
// we have to fail here - because we don't know what to do
|
||||||
// as the return arguments. This is because:
|
// as the return arguments. This is because:
|
||||||
|
@ -491,14 +516,15 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
|
||||||
m.mutex.Unlock()
|
m.mutex.Unlock()
|
||||||
|
|
||||||
if closestCall != nil {
|
if closestCall != nil {
|
||||||
m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s",
|
m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s\nat: %s\n",
|
||||||
callString(methodName, arguments, true),
|
callString(methodName, arguments, true),
|
||||||
callString(methodName, closestCall.Arguments, true),
|
callString(methodName, closestCall.Arguments, true),
|
||||||
diffArguments(closestCall.Arguments, arguments),
|
diffArguments(closestCall.Arguments, arguments),
|
||||||
strings.TrimSpace(mismatch),
|
strings.TrimSpace(mismatch),
|
||||||
|
assert.CallerInfo(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo())
|
m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(%#v).Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +555,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
|
||||||
call.totalCalls++
|
call.totalCalls++
|
||||||
|
|
||||||
// add the call
|
// add the call
|
||||||
m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...))
|
m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments, call.ReturnArguments))
|
||||||
m.mutex.Unlock()
|
m.mutex.Unlock()
|
||||||
|
|
||||||
// block if specified
|
// block if specified
|
||||||
|
@ -764,9 +790,17 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// AnythingOfTypeArgument 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 [Arguments.Diff] and [Arguments.Assert].
|
||||||
//
|
//
|
||||||
// Deprecated: this is an implementation detail that must not be used. Use [AnythingOfType] instead.
|
// Deprecated: this is an implementation detail that must not be used. Use the [AnythingOfType] constructor instead, example:
|
||||||
|
//
|
||||||
|
// m.On("Do", mock.AnythingOfType("string"))
|
||||||
|
//
|
||||||
|
// All explicit type declarations can be replaced with interface{} as is expected by [Mock.On], example:
|
||||||
|
//
|
||||||
|
// func anyString interface{} {
|
||||||
|
// return mock.AnythingOfType("string")
|
||||||
|
// }
|
||||||
type AnythingOfTypeArgument = anythingOfTypeArgument
|
type AnythingOfTypeArgument = anythingOfTypeArgument
|
||||||
|
|
||||||
// anythingOfTypeArgument is a string that contains the type of an argument
|
// anythingOfTypeArgument is a string that contains the type of an argument
|
||||||
|
@ -780,53 +814,54 @@ type anythingOfTypeArgument string
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
// Assert(t, AnythingOfType("string"), AnythingOfType("int"))
|
// args.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
|
||||||
// for use when type checking. This is an alternative to AnythingOfType.
|
// for use when type checking. This is an alternative to [AnythingOfType].
|
||||||
// Used in Diff and Assert.
|
// Used in [Arguments.Diff] and [Arguments.Assert].
|
||||||
type IsTypeArgument struct {
|
type IsTypeArgument struct {
|
||||||
t reflect.Type
|
t reflect.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsType returns an IsTypeArgument object containing the type to check for.
|
// IsType returns an IsTypeArgument object containing the type to check for.
|
||||||
// You can provide a zero-value of the type to check. This is an
|
// You can provide a zero-value of the type to check. This is an
|
||||||
// alternative to AnythingOfType. Used in Diff and Assert.
|
// alternative to [AnythingOfType]. Used in [Arguments.Diff] and [Arguments.Assert].
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
// Assert(t, IsType(""), IsType(0))
|
//
|
||||||
|
// args.Assert(t, IsType(""), IsType(0))
|
||||||
func IsType(t interface{}) *IsTypeArgument {
|
func IsType(t interface{}) *IsTypeArgument {
|
||||||
return &IsTypeArgument{t: reflect.TypeOf(t)}
|
return &IsTypeArgument{t: reflect.TypeOf(t)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument
|
// FunctionalOptionsArgument contains a list of functional options arguments
|
||||||
// for use when type checking.
|
// expected for use when matching a list of arguments.
|
||||||
type FunctionalOptionsArgument struct {
|
type FunctionalOptionsArgument struct {
|
||||||
value interface{}
|
values []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of FunctionalOptionsArgument
|
// String returns the string representation of FunctionalOptionsArgument
|
||||||
func (f *FunctionalOptionsArgument) String() string {
|
func (f *FunctionalOptionsArgument) String() string {
|
||||||
var name string
|
var name string
|
||||||
tValue := reflect.ValueOf(f.value)
|
if len(f.values) > 0 {
|
||||||
if tValue.Len() > 0 {
|
name = "[]" + reflect.TypeOf(f.values[0]).String()
|
||||||
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Replace(fmt.Sprintf("%#v", f.value), "[]interface {}", name, 1)
|
return strings.Replace(fmt.Sprintf("%#v", f.values), "[]interface {}", name, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionalOptions returns an FunctionalOptionsArgument object containing the functional option type
|
// FunctionalOptions returns an [FunctionalOptionsArgument] object containing
|
||||||
// and the values to check of
|
// the expected functional-options to check for.
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
// Assert(t, FunctionalOptions("[]foo.FunctionalOption", foo.Opt1(), foo.Opt2()))
|
//
|
||||||
func FunctionalOptions(value ...interface{}) *FunctionalOptionsArgument {
|
// args.Assert(t, FunctionalOptions(foo.Opt1("strValue"), foo.Opt2(613)))
|
||||||
|
func FunctionalOptions(values ...interface{}) *FunctionalOptionsArgument {
|
||||||
return &FunctionalOptionsArgument{
|
return &FunctionalOptionsArgument{
|
||||||
value: value,
|
values: values,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,10 +908,11 @@ func (f argumentMatcher) String() string {
|
||||||
// and false otherwise.
|
// and false otherwise.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" }))
|
// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" }))
|
||||||
//
|
//
|
||||||
// |fn|, must be a function accepting a single argument (of the expected type)
|
// fn must be a function accepting a single argument (of the expected type)
|
||||||
// which returns a bool. If |fn| doesn't match the required signature,
|
// which returns a bool. If fn doesn't match the required signature,
|
||||||
// MatchedBy() panics.
|
// MatchedBy() panics.
|
||||||
func MatchedBy(fn interface{}) argumentMatcher {
|
func MatchedBy(fn interface{}) argumentMatcher {
|
||||||
fnType := reflect.TypeOf(fn)
|
fnType := reflect.TypeOf(fn)
|
||||||
|
@ -979,20 +1015,17 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt)
|
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt)
|
||||||
}
|
}
|
||||||
case *FunctionalOptionsArgument:
|
case *FunctionalOptionsArgument:
|
||||||
t := expected.value
|
|
||||||
|
|
||||||
var name string
|
var name string
|
||||||
tValue := reflect.ValueOf(t)
|
if len(expected.values) > 0 {
|
||||||
if tValue.Len() > 0 {
|
name = "[]" + reflect.TypeOf(expected.values[0]).String()
|
||||||
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tName := reflect.TypeOf(t).Name()
|
const tName = "[]interface{}"
|
||||||
if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 {
|
if name != reflect.TypeOf(actual).String() && len(expected.values) != 0 {
|
||||||
differences++
|
differences++
|
||||||
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
|
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
|
||||||
} else {
|
} else {
|
||||||
if ef, af := assertOpts(t, actual); ef == "" && af == "" {
|
if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" {
|
||||||
// match
|
// match
|
||||||
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
|
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1092,7 +1125,7 @@ func (args Arguments) Error(index int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if s, ok = obj.(error); !ok {
|
if s, ok = obj.(error); !ok {
|
||||||
panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
|
panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, obj))
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -1181,32 +1214,38 @@ type tHelper interface {
|
||||||
func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
|
func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
|
||||||
expectedOpts := reflect.ValueOf(expected)
|
expectedOpts := reflect.ValueOf(expected)
|
||||||
actualOpts := reflect.ValueOf(actual)
|
actualOpts := reflect.ValueOf(actual)
|
||||||
|
|
||||||
|
var expectedFuncs []*runtime.Func
|
||||||
var expectedNames []string
|
var expectedNames []string
|
||||||
for i := 0; i < expectedOpts.Len(); i++ {
|
for i := 0; i < expectedOpts.Len(); i++ {
|
||||||
expectedNames = append(expectedNames, funcName(expectedOpts.Index(i).Interface()))
|
f := runtimeFunc(expectedOpts.Index(i).Interface())
|
||||||
|
expectedFuncs = append(expectedFuncs, f)
|
||||||
|
expectedNames = append(expectedNames, funcName(f))
|
||||||
}
|
}
|
||||||
|
var actualFuncs []*runtime.Func
|
||||||
var actualNames []string
|
var actualNames []string
|
||||||
for i := 0; i < actualOpts.Len(); i++ {
|
for i := 0; i < actualOpts.Len(); i++ {
|
||||||
actualNames = append(actualNames, funcName(actualOpts.Index(i).Interface()))
|
f := runtimeFunc(actualOpts.Index(i).Interface())
|
||||||
|
actualFuncs = append(actualFuncs, f)
|
||||||
|
actualNames = append(actualNames, funcName(f))
|
||||||
}
|
}
|
||||||
if !assert.ObjectsAreEqual(expectedNames, actualNames) {
|
|
||||||
|
if expectedOpts.Len() != actualOpts.Len() {
|
||||||
expectedFmt = fmt.Sprintf("%v", expectedNames)
|
expectedFmt = fmt.Sprintf("%v", expectedNames)
|
||||||
actualFmt = fmt.Sprintf("%v", actualNames)
|
actualFmt = fmt.Sprintf("%v", actualNames)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < expectedOpts.Len(); i++ {
|
for i := 0; i < expectedOpts.Len(); i++ {
|
||||||
expectedOpt := expectedOpts.Index(i).Interface()
|
if !isFuncSame(expectedFuncs[i], actualFuncs[i]) {
|
||||||
actualOpt := actualOpts.Index(i).Interface()
|
expectedFmt = expectedNames[i]
|
||||||
|
actualFmt = actualNames[i]
|
||||||
expectedFunc := expectedNames[i]
|
|
||||||
actualFunc := actualNames[i]
|
|
||||||
if expectedFunc != actualFunc {
|
|
||||||
expectedFmt = expectedFunc
|
|
||||||
actualFmt = actualFunc
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedOpt := expectedOpts.Index(i).Interface()
|
||||||
|
actualOpt := actualOpts.Index(i).Interface()
|
||||||
|
|
||||||
ot := reflect.TypeOf(expectedOpt)
|
ot := reflect.TypeOf(expectedOpt)
|
||||||
var expectedValues []reflect.Value
|
var expectedValues []reflect.Value
|
||||||
var actualValues []reflect.Value
|
var actualValues []reflect.Value
|
||||||
|
@ -1224,9 +1263,9 @@ func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
|
||||||
reflect.ValueOf(actualOpt).Call(actualValues)
|
reflect.ValueOf(actualOpt).Call(actualValues)
|
||||||
|
|
||||||
for i := 0; i < ot.NumIn(); i++ {
|
for i := 0; i < ot.NumIn(); i++ {
|
||||||
if !assert.ObjectsAreEqual(expectedValues[i].Interface(), actualValues[i].Interface()) {
|
if expectedArg, actualArg := expectedValues[i].Interface(), actualValues[i].Interface(); !assert.ObjectsAreEqual(expectedArg, actualArg) {
|
||||||
expectedFmt = fmt.Sprintf("%s %+v", expectedNames[i], expectedValues[i].Interface())
|
expectedFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], expectedArg, expectedArg)
|
||||||
actualFmt = fmt.Sprintf("%s %+v", expectedNames[i], actualValues[i].Interface())
|
actualFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], actualArg, actualArg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1274,25 @@ func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func funcName(opt interface{}) string {
|
func runtimeFunc(opt interface{}) *runtime.Func {
|
||||||
n := runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name()
|
return runtime.FuncForPC(reflect.ValueOf(opt).Pointer())
|
||||||
return strings.TrimSuffix(path.Base(n), path.Ext(n))
|
}
|
||||||
|
|
||||||
|
func funcName(f *runtime.Func) string {
|
||||||
|
name := f.Name()
|
||||||
|
trimmed := strings.TrimSuffix(path.Base(name), path.Ext(name))
|
||||||
|
splitted := strings.Split(trimmed, ".")
|
||||||
|
|
||||||
|
if len(splitted) == 0 {
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitted[len(splitted)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFuncSame(f1, f2 *runtime.Func) bool {
|
||||||
|
f1File, f1Loc := f1.FileLine(f1.Entry())
|
||||||
|
f2File, f2Loc := f2.FileLine(f2.Entry())
|
||||||
|
|
||||||
|
return f1File == f2File && f1Loc == f2Loc
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,11 +50,22 @@ func OpStr(s string) OptionFn {
|
||||||
o.str = s
|
o.str = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func OpBytes(b []byte) OptionFn {
|
||||||
|
return func(m *options) {
|
||||||
|
m.str = string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (i *TestExampleImplementation) TheExampleMethodFunctionalOptions(x string, opts ...OptionFn) error {
|
func (i *TestExampleImplementation) TheExampleMethodFunctionalOptions(x string, opts ...OptionFn) error {
|
||||||
args := i.Called(x, opts)
|
args := i.Called(x, opts)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TheExampleMethodFunctionalOptionsIndirect(i *TestExampleImplementation) {
|
||||||
|
i.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo"))
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
|
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
|
||||||
i.Called(yesorno)
|
i.Called(yesorno)
|
||||||
|
@ -937,6 +948,26 @@ func Test_Mock_Return_NotBefore_In_Order(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Mock_Return_InOrder_Uses_NotBefore(t *testing.T) {
|
||||||
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
|
InOrder(
|
||||||
|
mockedService.
|
||||||
|
On("TheExampleMethod", 1, 2, 3).
|
||||||
|
Return(4, nil),
|
||||||
|
mockedService.
|
||||||
|
On("TheExampleMethod2", true).
|
||||||
|
Return(),
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NotPanics(t, func() {
|
||||||
|
mockedService.TheExampleMethod(1, 2, 3)
|
||||||
|
})
|
||||||
|
require.NotPanics(t, func() {
|
||||||
|
mockedService.TheExampleMethod2(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Mock_Return_NotBefore_Out_Of_Order(t *testing.T) {
|
func Test_Mock_Return_NotBefore_Out_Of_Order(t *testing.T) {
|
||||||
var mockedService = new(TestExampleImplementation)
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
|
@ -967,6 +998,35 @@ TheExampleMethod(int,int,int)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Mock_Return_InOrder_Uses_NotBefore_Out_Of_Order(t *testing.T) {
|
||||||
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
|
InOrder(
|
||||||
|
mockedService.
|
||||||
|
On("TheExampleMethod", 1, 2, 3).
|
||||||
|
Return(4, nil).Twice(),
|
||||||
|
mockedService.
|
||||||
|
On("TheExampleMethod2", true).
|
||||||
|
Return(),
|
||||||
|
)
|
||||||
|
|
||||||
|
expectedPanicString := `mock: Unexpected Method Call
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
TheExampleMethod2(bool)
|
||||||
|
0: true
|
||||||
|
|
||||||
|
Must not be called before:
|
||||||
|
|
||||||
|
TheExampleMethod(int,int,int)
|
||||||
|
0: 1
|
||||||
|
1: 2
|
||||||
|
2: 3`
|
||||||
|
require.PanicsWithValue(t, expectedPanicString, func() {
|
||||||
|
mockedService.TheExampleMethod2(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Test_Mock_Return_NotBefore_Not_Enough_Times(t *testing.T) {
|
func Test_Mock_Return_NotBefore_Not_Enough_Times(t *testing.T) {
|
||||||
var mockedService = new(TestExampleImplementation)
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
|
@ -1022,6 +1082,7 @@ func Test_Mock_Return_NotBefore_Different_Mock_In_Order(t *testing.T) {
|
||||||
mockedService2.TheExampleMethod2(true)
|
mockedService2.TheExampleMethod2(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Mock_Return_NotBefore_Different_Mock_Out_Of_Order(t *testing.T) {
|
func Test_Mock_Return_NotBefore_Different_Mock_Out_Of_Order(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
mockedService1 = new(TestExampleImplementation)
|
mockedService1 = new(TestExampleImplementation)
|
||||||
|
@ -1206,7 +1267,7 @@ func Test_Mock_Called_blocks(t *testing.T) {
|
||||||
|
|
||||||
var mockedService = new(TestExampleImplementation)
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond)
|
mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(20 * time.Millisecond)
|
||||||
|
|
||||||
ch := make(chan Arguments)
|
ch := make(chan Arguments)
|
||||||
|
|
||||||
|
@ -1215,7 +1276,7 @@ func Test_Mock_Called_blocks(t *testing.T) {
|
||||||
select {
|
select {
|
||||||
case <-ch:
|
case <-ch:
|
||||||
t.Fatal("should have waited")
|
t.Fatal("should have waited")
|
||||||
case <-time.After(1 * time.Millisecond):
|
case <-time.After(10 * time.Millisecond):
|
||||||
}
|
}
|
||||||
|
|
||||||
returnArguments := <-ch
|
returnArguments := <-ch
|
||||||
|
@ -1472,6 +1533,51 @@ func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Mock_AssertExpectationsFunctionalOptionsType_Indirectly(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
|
||||||
|
TheExampleMethodFunctionalOptionsIndirect(mockedService)
|
||||||
|
|
||||||
|
// now assert expectations
|
||||||
|
assert.True(t, mockedService.AssertExpectations(tt))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Func(t *testing.T) {
|
||||||
|
|
||||||
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
|
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once()
|
||||||
|
|
||||||
|
tt := new(testing.T)
|
||||||
|
assert.False(t, mockedService.AssertExpectations(tt))
|
||||||
|
|
||||||
|
assert.Panics(t, func() {
|
||||||
|
mockedService.TheExampleMethodFunctionalOptions("test", OpBytes([]byte("this")))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Arg(t *testing.T) {
|
||||||
|
|
||||||
|
var mockedService = new(TestExampleImplementation)
|
||||||
|
|
||||||
|
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once()
|
||||||
|
|
||||||
|
tt := new(testing.T)
|
||||||
|
assert.False(t, mockedService.AssertExpectations(tt))
|
||||||
|
|
||||||
|
assert.Panics(t, func() {
|
||||||
|
mockedService.TheExampleMethodFunctionalOptions("test", OpStr("that"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -1980,7 +2086,7 @@ func TestArgumentMatcherToPrintMismatch(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
matchingExp := regexp.MustCompile(
|
matchingExp := regexp.MustCompile(
|
||||||
`\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool`)
|
`\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool\nat: \[[^\]]+mock\/mock_test.go`)
|
||||||
assert.Regexp(t, matchingExp, r)
|
assert.Regexp(t, matchingExp, r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -1997,7 +2103,7 @@ func TestArgumentMatcherToPrintMismatchWithReferenceType(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
matchingExp := regexp.MustCompile(
|
matchingExp := regexp.MustCompile(
|
||||||
`\s+mock: Unexpected Method Call\s+-*\s+GetTimes\(\[\]int\)\s+0: \[\]int\{1\}\s+The closest call I have is:\s+GetTimes\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(\[\]int=\[1\]\) not matched by func\(\[\]int\) bool`)
|
`\s+mock: Unexpected Method Call\s+-*\s+GetTimes\(\[\]int\)\s+0: \[\]int\{1\}\s+The closest call I have is:\s+GetTimes\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(\[\]int=\[1\]\) not matched by func\(\[\]int\) bool\nat: \[[^\]]+mock\/mock_test.go`)
|
||||||
assert.Regexp(t, matchingExp, r)
|
assert.Regexp(t, matchingExp, r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -2028,7 +2134,7 @@ func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
|
||||||
func TestClosestCallFavorsFirstMock(t *testing.T) {
|
func TestClosestCallFavorsFirstMock(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
diffRegExp := `Difference found in argument 0:\s+--- Expected\s+\+\+\+ Actual\s+@@ -2,4 \+2,4 @@\s+\(bool\) true,\s+- \(bool\) true,\s+- \(bool\) true\s+\+ \(bool\) false,\s+\+ \(bool\) false\s+}\s+`
|
diffRegExp := `Difference found in argument 0:\s+--- Expected\s+\+\+\+ Actual\s+@@ -2,4 \+2,4 @@\s+\(bool\) true,\s+- \(bool\) true,\s+- \(bool\) true\s+\+ \(bool\) false,\s+\+ \(bool\) false\s+}\s+Diff: 0: FAIL: \(\[\]bool=\[(true\s?|false\s?){3}]\) != \(\[\]bool=\[(true\s?|false\s?){3}\]\)`
|
||||||
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod7([]bool)`, `0: \[\]bool{true, false, false}`, `0: \[\]bool{true, true, true}`, diffRegExp))
|
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod7([]bool)`, `0: \[\]bool{true, false, false}`, `0: \[\]bool{true, true, true}`, diffRegExp))
|
||||||
assert.Regexp(t, matchingExp, r)
|
assert.Regexp(t, matchingExp, r)
|
||||||
}
|
}
|
||||||
|
@ -2044,7 +2150,7 @@ func TestClosestCallFavorsFirstMock(t *testing.T) {
|
||||||
func TestClosestCallUsesRepeatabilityToFindClosest(t *testing.T) {
|
func TestClosestCallUsesRepeatabilityToFindClosest(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
diffRegExp := `Difference found in argument 0:\s+--- Expected\s+\+\+\+ Actual\s+@@ -1,4 \+1,4 @@\s+\(\[\]bool\) \(len=3\) {\s+- \(bool\) false,\s+- \(bool\) false,\s+\+ \(bool\) true,\s+\+ \(bool\) true,\s+\(bool\) false\s+`
|
diffRegExp := `Difference found in argument 0:\s+--- Expected\s+\+\+\+ Actual\s+@@ -1,4 \+1,4 @@\s+\(\[\]bool\) \(len=3\) {\s+- \(bool\) false,\s+- \(bool\) false,\s+\+ \(bool\) true,\s+\+ \(bool\) true,\s+\(bool\) false\s+Diff: 0: FAIL: \(\[\]bool=\[(true\s?|false\s?){3}]\) != \(\[\]bool=\[(true\s?|false\s?){3}\]\)`
|
||||||
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod7([]bool)`, `0: \[\]bool{true, true, false}`, `0: \[\]bool{false, false, false}`, diffRegExp))
|
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod7([]bool)`, `0: \[\]bool{true, true, false}`, `0: \[\]bool{false, false, false}`, diffRegExp))
|
||||||
assert.Regexp(t, matchingExp, r)
|
assert.Regexp(t, matchingExp, r)
|
||||||
}
|
}
|
||||||
|
@ -2101,7 +2207,7 @@ func Test_isBetterMatchThanReturnsFalseIfRepeatabilityIsLessThanOrEqualToOther(t
|
||||||
|
|
||||||
func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string {
|
func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string {
|
||||||
rMethod := regexp.QuoteMeta(method)
|
rMethod := regexp.QuoteMeta(method)
|
||||||
return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+%s`,
|
return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+%s\nat: \[[^\]]+mock\/mock_test.go`,
|
||||||
rMethod, calledArg, rMethod, expectedArg, diff)
|
rMethod, calledArg, rMethod, expectedArg, diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
//
|
//
|
||||||
// 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()`.
|
||||||
|
// A consequence of this is that it must be called from the goroutine running
|
||||||
|
// the test function, not from other goroutines created during the test.
|
||||||
//
|
//
|
||||||
// Every assertion function also takes an optional string message as the final argument,
|
// Every assertion function also takes an optional string message as the final argument,
|
||||||
// allowing custom error messages to be appended to the message the assertion method outputs.
|
// allowing custom error messages to be appended to the message the assertion method outputs.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
{{.Comment}}
|
{{ replace .Comment "assert." "require."}}
|
||||||
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
||||||
if h, ok := t.(tHelper); ok { h.Helper() }
|
if h, ok := t.(tHelper); ok { h.Helper() }
|
||||||
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
||||||
|
|
|
@ -187,8 +187,8 @@ func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface
|
||||||
EqualExportedValuesf(a.t, expected, actual, msg, args...)
|
EqualExportedValuesf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualValues asserts that two objects are equal or convertible to the same types
|
// EqualValues asserts that two objects are equal or convertible to the larger
|
||||||
// and equal.
|
// type and equal.
|
||||||
//
|
//
|
||||||
// a.EqualValues(uint32(123), int32(123))
|
// a.EqualValues(uint32(123), int32(123))
|
||||||
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||||
|
@ -198,8 +198,8 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
|
||||||
EqualValues(a.t, expected, actual, msgAndArgs...)
|
EqualValues(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualValuesf asserts that two objects are equal or convertible to the same types
|
// EqualValuesf asserts that two objects are equal or convertible to the larger
|
||||||
// and equal.
|
// type and equal.
|
||||||
//
|
//
|
||||||
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
|
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
|
||||||
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||||
|
@ -337,7 +337,7 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
|
||||||
// a.EventuallyWithT(func(c *assert.CollectT) {
|
// a.EventuallyWithT(func(c *assert.CollectT) {
|
||||||
// // add assertions as needed; any assertion failure will fail the current tick
|
// // add assertions as needed; any assertion failure will fail the current tick
|
||||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||||
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
|
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
|
||||||
func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
|
@ -362,7 +362,7 @@ func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), w
|
||||||
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
|
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
|
||||||
// // add assertions as needed; any assertion failure will fail the current tick
|
// // add assertions as needed; any assertion failure will fail the current tick
|
||||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||||
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
|
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
|
||||||
func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
h.Helper()
|
h.Helper()
|
||||||
|
@ -1129,6 +1129,40 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
|
||||||
NotContainsf(a.t, s, contains, msg, args...)
|
NotContainsf(a.t, s, contains, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should not match.
|
||||||
|
// This is an inverse of ElementsMatch.
|
||||||
|
//
|
||||||
|
// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
|
||||||
|
//
|
||||||
|
// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
|
||||||
|
//
|
||||||
|
// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
|
||||||
|
func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
NotElementsMatch(a.t, listA, listB, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
|
||||||
|
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
|
||||||
|
// the number of appearances of each of them in both lists should not match.
|
||||||
|
// This is an inverse of ElementsMatch.
|
||||||
|
//
|
||||||
|
// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
|
||||||
|
//
|
||||||
|
// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
|
||||||
|
//
|
||||||
|
// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
|
||||||
|
func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
NotElementsMatchf(a.t, listA, listB, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
|
@ -1201,7 +1235,25 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
|
||||||
NotEqualf(a.t, expected, actual, msg, args...)
|
NotEqualf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotErrorIs asserts that at none of the errors in err's chain matches target.
|
// NotErrorAs asserts that none of the errors in err's chain matches target,
|
||||||
|
// but if so, sets target to that error value.
|
||||||
|
func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
NotErrorAs(a.t, err, target, msgAndArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotErrorAsf asserts that none of the errors in err's chain matches target,
|
||||||
|
// but if so, sets target to that error value.
|
||||||
|
func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
NotErrorAsf(a.t, err, target, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotErrorIs asserts that none of the errors in err's chain matches target.
|
||||||
// This is a wrapper for errors.Is.
|
// This is a wrapper for errors.Is.
|
||||||
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
@ -1210,7 +1262,7 @@ func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface
|
||||||
NotErrorIs(a.t, err, target, msgAndArgs...)
|
NotErrorIs(a.t, err, target, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotErrorIsf asserts that at none of the errors in err's chain matches target.
|
// NotErrorIsf asserts that none of the errors in err's chain matches target.
|
||||||
// This is a wrapper for errors.Is.
|
// This is a wrapper for errors.Is.
|
||||||
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
|
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
|
||||||
if h, ok := a.t.(tHelper); ok {
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
|
|
@ -6,7 +6,7 @@ type TestingT interface {
|
||||||
FailNow()
|
FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
type tHelper interface {
|
type tHelper = interface {
|
||||||
Helper()
|
Helper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AssertionTesterInterface defines an interface to be used for testing assertion methods
|
// AssertionTesterInterface defines an interface to be used for testing assertion methods
|
||||||
|
@ -681,3 +683,30 @@ func TestErrorAssertionFunc(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEventuallyWithTFalse(t *testing.T) {
|
||||||
|
mockT := new(MockT)
|
||||||
|
|
||||||
|
condition := func(collect *assert.CollectT) {
|
||||||
|
True(collect, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)
|
||||||
|
True(t, mockT.Failed, "Check should fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventuallyWithTTrue(t *testing.T) {
|
||||||
|
mockT := new(MockT)
|
||||||
|
|
||||||
|
counter := 0
|
||||||
|
condition := func(collect *assert.CollectT) {
|
||||||
|
defer func() {
|
||||||
|
counter += 1
|
||||||
|
}()
|
||||||
|
True(collect, counter == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)
|
||||||
|
False(t, mockT.Failed, "Check should pass")
|
||||||
|
Equal(t, 2, counter, "Condition is expected to be called 2 times")
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
// or individual tests (depending on which interface(s) you
|
// or individual tests (depending on which interface(s) you
|
||||||
// implement).
|
// implement).
|
||||||
//
|
//
|
||||||
|
// The suite package does not support parallel tests. See [issue 934].
|
||||||
|
//
|
||||||
// A testing suite is usually built by first extending the built-in
|
// A testing suite is usually built by first extending the built-in
|
||||||
// suite functionality from suite.Suite in testify. Alternatively,
|
// suite functionality from suite.Suite in testify. Alternatively,
|
||||||
// you could reproduce that logic on your own if you wanted (you
|
// you could reproduce that logic on your own if you wanted (you
|
||||||
|
@ -63,4 +65,6 @@
|
||||||
// func TestExampleTestSuite(t *testing.T) {
|
// func TestExampleTestSuite(t *testing.T) {
|
||||||
// suite.Run(t, new(ExampleTestSuite))
|
// suite.Run(t, new(ExampleTestSuite))
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
// [issue 934]: https://github.com/stretchr/testify/issues/934
|
||||||
package suite
|
package suite
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -440,7 +440,7 @@ func (sc *StdoutCapture) StopCapture() (string, error) {
|
||||||
}
|
}
|
||||||
os.Stdout.Close()
|
os.Stdout.Close()
|
||||||
os.Stdout = sc.oldStdout
|
os.Stdout = sc.oldStdout
|
||||||
bytes, err := ioutil.ReadAll(sc.readPipe)
|
bytes, err := io.ReadAll(sc.readPipe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -604,14 +604,44 @@ func TestFailfastSuite(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
|
var expect []string
|
||||||
if failFast {
|
if failFast {
|
||||||
// Test A Fails and because we are running with failfast Test B never runs and we proceed straight to TearDownSuite
|
// Test A Fails and because we are running with failfast Test B never runs and we proceed straight to TearDownSuite
|
||||||
assert.Equal(t, "SetupSuite;SetupTest;Test A Fails;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
|
expect = []string{"SetupSuite", "SetupTest", "Test A Fails", "TearDownTest", "TearDownSuite"}
|
||||||
} else {
|
} else {
|
||||||
// Test A Fails and because we are running without failfast we continue and run Test B and then proceed to TearDownSuite
|
// Test A Fails and because we are running without failfast we continue and run Test B and then proceed to TearDownSuite
|
||||||
assert.Equal(t, "SetupSuite;SetupTest;Test A Fails;TearDownTest;SetupTest;Test B Passes;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
|
expect = []string{"SetupSuite", "SetupTest", "Test A Fails", "TearDownTest", "SetupTest", "Test B Passes", "TearDownTest", "TearDownSuite"}
|
||||||
}
|
}
|
||||||
|
callOrderAssert(t, expect, s.callOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tHelper interface {
|
||||||
|
Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
// callOrderAssert is a help with confirms that asserts that expect
|
||||||
|
// matches one or more times in callOrder. This makes it compatible
|
||||||
|
// with go test flag -count=X where X > 1.
|
||||||
|
func callOrderAssert(t *testing.T, expect, callOrder []string) {
|
||||||
|
var ti interface{} = t
|
||||||
|
if h, ok := ti.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
callCount := len(callOrder)
|
||||||
|
expectCount := len(expect)
|
||||||
|
if callCount > expectCount && callCount%expectCount == 0 {
|
||||||
|
// Command line flag -count=X where X > 1.
|
||||||
|
for len(callOrder) >= expectCount {
|
||||||
|
assert.Equal(t, expect, callOrder[:expectCount])
|
||||||
|
callOrder = callOrder[expectCount:]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expect, callOrder)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFailfastSuiteFailFastOn(t *testing.T) {
|
func TestFailfastSuiteFailFastOn(t *testing.T) {
|
||||||
// To test this with failfast on (and isolated from other intended test failures in our test suite) we launch it in its own process
|
// To test this with failfast on (and isolated from other intended test failures in our test suite) we launch it in its own process
|
||||||
cmd := exec.Command("go", "test", "-v", "-race", "-run", "TestFailfastSuite", "-failfast")
|
cmd := exec.Command("go", "test", "-v", "-race", "-run", "TestFailfastSuite", "-failfast")
|
||||||
|
|
Loading…
Reference in New Issue