Compare commits

...

200 Commits

Author SHA1 Message Date
Olivier Mengué
0ff4bb43de
Merge pull request #1751 from stretchr/dolmen/suite-fix-use-of-testing-internals
suite: cleanup use of 'testing' internals at runtime
2025-05-30 17:22:03 +02:00
Olivier Mengué
82767aed18 suite: cleanup use of 'testing' internals at runtime
Cleanup runtime use of stdlib's testing internals which was required for older
Go versions.

Note: we are still using testing.RunTests in the suite's test suite for
now.
2025-05-30 17:17:21 +02:00
Olivier Mengué
186f1654cc
Merge pull request #1756 from stretchr/dolmen/mock-Parallel-testing
mock: enable parallel testing on internal testsuite
2025-05-30 17:15:38 +02:00
Olivier Mengué
8b3dc18b37 mock: enable parallel testing on internal testsuite
Add t.Parallel() to all package-level tests of the 'mock' package.
Result: faster tests results.

Before:
  $ go test -count=10 ./mock
  ok  	github.com/stretchr/testify/mock	0.631s
After:
  $ go test -count=10 ./mock
  ok  	github.com/stretchr/testify/mock	0.426s
2025-05-30 17:12:36 +02:00
Olivier Mengué
4f71159ca8 assert.YAMLEq: shortcut if same strings
Shortcut in assert.YAMLEq once we have validated that 'expected' is
valid YAML, and 'actual' is the exact same string.
2025-05-30 16:08:10 +02:00
Olivier Mengué
4eb688ba0c assert.JSONEq: shortcut if same strings
Shortcut in assert.JSONEq once we have validated that 'expected' is
valid JSON, and 'actual' is the exact same string.
2025-05-30 16:05:08 +02:00
ccoVeille
3c1541a3b4 Improve usage of Sprintf with Same/NotSame
Co-authored-by: Olivier Mengué <dolmen@cpan.org>
2025-05-27 23:42:48 +02:00
Bracken
c98ef6eb29
Merge pull request #1423 from stretchr/add-Helper-method-in-tests
Add Helper() method in internal mocks and assert.CollectT
2025-05-27 08:22:18 +02:00
Olivier Mengué
8f73f15d69 assert.CollectT: add Helper() method
Add Helper() method to CollectT like testing.T as we intend to add
Helper() to the assert.TestingT interface.
2025-05-25 21:56:50 +02:00
Olivier Mengué
e2ad95950e mock/tests: add method Helper() to all mock of *testing.T 2025-05-25 21:56:50 +02:00
Olivier Mengué
b534400d17 require/tests: add Helper() method to all mocks of *testing.T 2025-05-25 21:56:50 +02:00
Olivier Mengué
bf47cc8868 assert/tests: add Helper() in all testing.T mocks
Add an Helper() method to all mocks in tests of package 'assert'.
2025-05-25 21:56:50 +02:00
Ararsa
d2ddb5da5d
suite.Passed: add one more status test report (#1706)
## Summary
This test case verifies that the Passed method returns false when all
tests in the suite fail

## Changes
Added a test case to check the scenario where all tests fail.

## Motivation
This test is important to ensure that the Passed method correctly
identifies the overall failure state of a test suite when none of the
individual tests pass.

 ## Example usage 
This test can be used as a part of the test suite to validate the
behavior of the Passed method under failure conditions.

## Related issues
None
2025-05-25 10:10:11 +02:00
Olivier Mengué
83d32a3d33
Merge pull request #1747 from stretchr/dolmen/assert,require-enable-parallel-testing
assert,require: enable parallel testing on (almost) all top tests
2025-05-25 05:39:27 +02:00
Olivier Mengué
603c2a0348 assert,require: enable parallel testing on (almost) all top tests
Enable parallel testing for almost all tests in packages 'assert' and
'require' by calling t.Parallel() as the first line of the test.

A few tests are incompatible and will be fixed separately. They are
marked with a FIXME.
Incompatible tests: TestFileExists, TestNoFileExists, TestDirExists,
TestNoDirExists.

Before:
  $ go test -count=10 ./assert ./require
  ok  	github.com/stretchr/testify/assert	7.575s
  ok  	github.com/stretchr/testify/require	1.501s

After:
  $ go test -count=10 ./assert ./require
  ok  	github.com/stretchr/testify/assert	1.703s
  ok  	github.com/stretchr/testify/require	1.245s
2025-05-23 16:17:12 +02:00
Bracken
11522a0d15
Merge pull request #1746 from stretchr/dolmen/fix-CI-script-shebang
CI: fix shebang in .ci.*.sh scripts
2025-05-23 16:01:51 +02:00
Olivier Mengué
af716f8bff CI: fix shebang in .ci.*.sh scripts
Fix shebang in .ci.*.sh scripts to ease running on platforms where bash
is not in /bin/bash (ex: MacOS).
2025-05-22 11:53:03 +02:00
Bart Venter
9fc264e324
assert: add IsNotType (#1730)
Add the `IsNotType` assertion, which is the inverse
of the existing `IsType` assertion. It allows users to assert that an
object is not of a specific type.

Additionally, minor documentation improvements were made.

## Summary
This PR adds a new assertion function, `IsNotType`, to the
`testify/assert` package. It complements the existing `IsType` function
by providing a way to assert that an object is not of a specific type.

## Changes
* Added the `IsNotType` function to the `assert` package.
* Wrote unit tests for `IsNotType` to ensure correctness.
* Updated documentation to include examples and usage for `IsNotType`.

## Motivation
The `testify/assert` package already provides an `IsType` function to
check if an object is of a specific type. However, there was no built-in
way to assert that an object is **not** of a specific type. This PR
addresses that gap by introducing the `IsNotType` function, improving
the library's completeness and usability.

## Example usage
```go
assert.IsNotType(t, &MyStruct{}, actualObject)
```

## Related issues
_N/A_
2025-05-22 11:45:11 +02:00
Olivier Mengué
2035e7d7a7
Merge pull request #1739 from ccoveille-forks/asserter-gofumpt
Format assertions files with gofumpt
2025-05-22 10:38:23 +02:00
ccoVeille
9bcca2f950
Format assertions files with gofumpt 2025-05-13 14:17:27 +02:00
Bracken
016e2e9c26
Merge pull request #1671 from alexandear-org/chore/remove-deprecated-build-constraints
assert: remove deprecated build constraints
2025-05-12 15:34:44 +01:00
Bracken
296df14257
Merge pull request #1734 from stretchr/errors-asserter
Improve ErrorAs failure message when error is nil
2025-05-12 15:30:04 +01:00
ccoVeille
c2116b4194
Improve ErrorAs failure message when error is nil
Before:

    Should be in error chain:
    expected: *assert.customError
    in chain:

After:
    An error is expected but got nil.
    expected: *assert.customError

The message `An error is expected but got nil.` is the one already
reported by `assert.Error`
2025-05-08 20:48:57 +02:00
Bracken
111716d6f9
Merge pull request #1729 from siliconbrain/fix-subset-notsubset-mixed-type
fix Subset/NotSubset when calling with mixed input types
2025-05-08 13:42:27 +01:00
Dudás Ádám
121ddb9b0e clarify behavior of Subset/NotSubset when passing maps 2025-05-08 11:16:40 +00:00
Bracken
d338e951cf
Merge pull request #1681 from tsioftas/tsioftas/erroris-improve
Improve ErrorIs message when error is nil but an error was expected
2025-05-08 11:40:41 +01:00
Bracken
520d02e627
Merge pull request #1675 from architagr/doc-update-for-error-fn
Update documentation for the Error function in assert or require package
2025-05-07 13:56:33 +01:00
Archit Agarwal
01b9a87c30
Merge branch 'master' into doc-update-for-error-fn 2025-05-07 17:26:11 +05:30
Archit Agarwal
d0c350a872
Update assert/doc.go
Co-authored-by: Bracken <abdawson@gmail.com>
2025-05-07 17:25:57 +05:30
Bracken
f4244f1680
Merge pull request #1427 from cszczepaniak/cs/quicker_eventually
assert: check early in Eventually, EventuallyWithT, and Never
2025-05-06 14:28:41 +01:00
Bracken
a31a53e5b4
Merge pull request #1615 from DevotedHealth/mauclair-mock-match-sprintf
Lazily render mock diff output on successful match
2025-05-06 11:20:15 +01:00
Archit Agarwal
0c9a9e02f8
Update assert/doc.go
Co-authored-by: ccoVeille <3875889+ccoVeille@users.noreply.github.com>
2025-05-02 13:01:29 +05:30
Archit Agarwal
992db2b883 upadte doc 2025-04-29 17:10:00 +05:30
Archit Agarwal
e32ceae4ea
Update assert/doc.go
Co-authored-by: ccoVeille <3875889+ccoVeille@users.noreply.github.com>
2025-04-29 17:08:34 +05:30
Dudás Ádám
2a9c44b1d8 fix Subset/NotSubset when calling with mixed input types (array/slice list with map subset) 2025-04-23 14:31:40 +00:00
Archit Agarwal
d5cd75acec update documentation of assert package to mention that all function return a bool value 2025-04-22 23:33:01 +05:30
tsioftas
e7b1880349 update error message based on suggestion 2025-04-03 14:20:14 +03:00
tsioftas
5ed1b90367
Update assert/assertions_test.go
Co-authored-by: Bracken <abdawson@gmail.com>
2025-04-03 14:17:58 +03:00
Oleksandr Redko
0b6039ed54 assert: remove deprecated build constraints 2025-04-02 12:37:14 +03:00
Archit Agarwal
500cb17e16
Merge branch 'master' into doc-update-for-error-fn 2025-03-26 00:05:52 +05:30
Mike Auclair
e6575e05ed
Update mock.go 2025-03-24 14:24:41 -04:00
Bracken
5ac6528bff
Merge pull request #1716 from brackendawson/update-maintainers
Propose Christophe Colombier (ccoVeille) as approver
2025-03-24 18:30:37 +01:00
Bracken Dawson
d0e0f4961b
Propose Christophe Colombier (ccoVeille) as approver 2025-03-23 18:36:20 +01:00
Bracken Dawson
b561f16e87
Correct maintainers list
arjunmahishi is actually only an approver, at the moment.
2025-03-23 18:33:47 +01:00
Bracken
a948a8c402
Merge pull request #1674 from alexandear/refactor/simplify-with-sprintf-q
refactor: use %q and %T to simplify fmt.Sprintf
2025-03-23 14:23:15 +01:00
Bracken
c3915e850a
Merge branch 'master' into refactor/simplify-with-sprintf-q 2025-03-23 14:22:18 +01:00
Bracken
16020e8cbc
Merge pull request #1687 from alexandear/docs-format-go-examples
README: apply gofmt to examples
2025-03-23 12:09:57 +01:00
Oleksandr Redko
75df9d50d4 Update mdsf 2025-03-23 12:40:01 +02:00
Oleksandr Redko
33be8f984a Move to jobs.build 2025-03-23 12:20:44 +02:00
Oleksandr Redko
a9e8aed155 Remove mistakenly added .ci.gofmt.sh 2025-03-23 12:18:52 +02:00
Bracken
3b8bd9bf7d
Merge pull request #1614 from DevotedHealth/mauclair-call-stack-perf
Call stack perf change for CallerInfo
2025-03-22 23:13:13 +01:00
Bracken
1e7fb5865a
Merge pull request #1709 from techfg/chore/issue-1621-update-docs
chore: update docs for Unset #1621
2025-03-22 12:44:25 +01:00
techfg
c6ac9bb91d chore: update per PR feedback 2025-03-21 06:25:01 -07:00
Bracken
65f73866c0
Merge pull request #1710 from greg0ire/doc-goroutine-restriction
Document consequences of calling t.FailNow()
2025-03-21 13:27:31 +01:00
Grégoire Paris
b1c9368f81
Improve existing docs 2025-03-21 13:21:25 +01:00
Bracken
5a5ac85551
Merge pull request #1062 from lambdanis/fix-fail-message-formatting
Fix failure message formatting for Positive and Negative asserts
2025-03-21 10:15:07 +01:00
Bracken
53e0c918d4
Merge branch 'master' into fix-fail-message-formatting 2025-03-21 10:10:08 +01:00
Grégoire Paris
89086b0757
Document consequences of calling t.FailNow()
These comments are adapted from t.FailNow()'s own documentation.

Closes #1701
2025-03-19 20:50:44 +01:00
techfg
098128fd10 chore: update docs for Unset #1621 2025-03-18 12:48:09 -07:00
Bracken
f784abc221
Merge pull request #1345 from craig65535/fix-assert-erroras
assert.ErrorAs: log target type
2025-03-18 18:04:00 +00:00
Oleksandr Redko
dfda68b86f Verify formatting of code snippets in CI 2025-01-20 19:49:35 +02:00
Oleksandr Redko
3cf0926564 docs: Format examples in README 2025-01-07 11:35:15 +01:00
Craig Davison
c60c3bd7fb dereference target 2025-01-03 14:34:16 -07:00
Archit Agarwal
0c935ad39e
Merge branch 'master' into doc-update-for-error-fn 2025-01-03 21:59:11 +05:30
Craig Davison
1c717c00c1 Add return 2024-12-31 15:35:31 -07:00
Craig Davison
ccb5e7f656 Remove redundant returns 2024-12-31 15:26:24 -07:00
Craig Davison
ca6698b8a1 assert.ErrorAs: log target type 2024-12-31 15:09:40 -07:00
Bracken
7c367bb7bc
Merge pull request #1684 from alexandear/refactor-replace-deprecated-ioutil
Replace deprecated io/ioutil with io and os
2024-12-21 13:10:41 +00:00
Bracken
e6a990c21d
Merge pull request #1688 from alexandear/docs-fix-typo
docs: Fix typo in README
2024-12-21 13:09:58 +00:00
Mike Auclair
cbf6e73c7e simplified renderers 2024-12-17 18:30:48 +00:00
Mike Auclair
3d98e693c7 cleanup 2024-12-17 18:25:59 +00:00
Mike Auclair
cfee2346d7 review feedback 2024-12-17 18:18:56 +00:00
Oleksandr Redko
f8c628e5a1 docs: Fix typo in README 2024-12-16 23:14:16 +02:00
Oleksandr Redko
014ae9a7a4 Replace deprecated io/ioutil with io and os 2024-12-10 14:21:03 +02:00
Oleksandr Redko
30f3cef5ad Apply suggestions from code review
Co-authored-by: Olivier Mengué <dolmen@cpan.org>
2024-12-10 14:08:46 +02:00
Oleksandr Redko
d57bac8721 refactor: use %q to simplify fmt.Sprintf 2024-11-24 18:28:03 +02:00
tsioftas
19ddcbb61a go fmt 2024-11-18 12:20:16 +00:00
tsioftas
7434b149f3 Improve ErrorIs message when error is nil but an error was expected 2024-11-18 11:48:33 +00:00
Archit Agarwal
fc69fea19d
Merge branch 'master' into doc-update-for-error-fn 2024-11-17 14:34:51 +05:30
Bracken
89cbdd9e7b
Merge pull request #1626 from arjun-1/fix-functional-options-diff-indirect-calls
fix: compare functional option names for indirect calls
2024-11-12 22:58:45 +00:00
Archit Agarwal
d27af4e3f5 update documentation for auto require package 2024-11-03 02:51:16 +05:30
Archit Agarwal
2eca2b1976 update documentation for the Error function in assert or require package #1609 2024-11-03 02:19:05 +05:30
Bracken
07bac606be
Merge pull request #1667 from sikehish/flaky
Increase timeouts in Test_Mock_Called_blocks to reduce flakiness in CI
2024-10-28 20:19:38 +00:00
sikehish
716de8dff4 Increase timeouts in Test_Mock_Called_blocks to reduce flakiness in CI 2024-10-29 00:00:56 +05:30
Hisham Akmal
118fb83466
NotSame should fail if args are not pointers #1661 (#1664)
## Summary
Reduces the confusion assosciated with NotSame that previously would
check nothing if any of the values is not a pointer. The changes made
were tested using TestSame, TestNotSame, and Test_samePointers tests,
and the changes did clear the tests.

## Changes
1. Modified samePointers to return another bool value(ok) that would
determine if the 2 values are of pointer type or not, while the returned
"same" bool value would determine if the 2 pointers are same.
2. Modified assert.NotSame to call Fail() if the 2 values are either
i)pointers pointing to the same address or ii)either/both of the values
are not pointers.
3. Modified assert.Same to call Fail() if the 2 values are either
i)pointers not pointing to the same address or ii)either/both of the
values are not pointers.
4. Modified Test_samePointers to handle the new behavior of samePointers
by checking both if the inputs are pointers (ok) and if they point to
the same object (same).

## Motivation
Ensure NotSame accurately verifies pointer sameness by handling
non-pointer inputs explicitly, improving clarity and reducing potential
misuse.

## Related issues
Closes #1661

---------

Co-authored-by: Bracken <abdawson@gmail.com>
2024-10-28 11:08:04 +00:00
Arjun Dhawan
7d99b2b43d attempt 2 2024-10-27 08:07:57 +01:00
Arjun Dhawan
05f87c0160 more similar 2024-10-27 08:05:00 +01:00
Arjun Dhawan
ea7129e006 better fmt 2024-10-27 08:02:53 +01:00
Bracken
a1b9c9efe3
Merge pull request #1663 from ybrustin/master
Fix issue #1662 (comparing infs should fail)
2024-10-26 19:43:05 +01:00
Bracken
8302de98b1
Merge branch 'master' into master 2024-10-26 19:41:18 +01:00
Bracken
89352f7958
Merge pull request #1518 from hendrywiranto/adjust-readme-remove-v2
README: replace Testify V2 notice with @dolmen's V2 manifesto
2024-10-26 19:33:39 +01:00
hendry.wiranto
2780579e15 review: use proper github md 2024-10-26 23:18:03 +07:00
hendry.wiranto
8f049b0122 link maintainer manifesto on readme instead of v2 notice 2024-10-26 23:18:03 +07:00
Arjun Dhawan
be992afabf trial 2024-10-24 13:28:30 +02:00
Arjun Dhawan
fb67df6392 no regression 2024-10-24 11:40:45 +02:00
Arjun Dhawan
55bac84354 reword tests 2024-10-24 11:30:00 +02:00
Arjun Dhawan
822223ec34 fix name regression 2024-10-24 11:30:00 +02:00
Arjun Dhawan
22d3bd5def in order to remain compatible with go1..19, don't compare function names (but do include them in the diff output) 2024-10-24 11:30:00 +02:00
Arjun Dhawan
9c174eb41c fix: compare functional option names for indirect calls
Closes Functional Options testing broken for indirect calls #1380
2024-10-24 11:30:00 +02:00
Bracken
7efaf15f33
Merge pull request #1586 from redachl/fix/equal-exported-values-accepts-everything
assert.EqualExportedValues: accepts everything
2024-10-23 23:39:08 +01:00
Bracken
dce9e58ee3
Merge branch 'master' into fix/equal-exported-values-accepts-everything 2024-10-23 23:37:57 +01:00
Bracken
75a239b2fd
Merge pull request #1610 from Neokil/generate-better-comments-for-require-package
Generate better comments for require package
2024-10-23 23:37:20 +01:00
Bracken
f9ccf14f6f
Merge branch 'master' into generate-better-comments-for-require-package 2024-10-23 23:36:08 +01:00
Yaroslav Brustinov
6555fd4da6 Fix issue #1662 (comparing infs should fail) 2024-10-16 17:25:23 +03:00
Bracken
a012e45d18
Merge pull request #1636 from rainhq/jayd3e.fix_return_arguments
Record Return Arguments of a Call
2024-10-16 14:07:58 +01:00
Simon Schulte
3b2754b72f remove failure note on require-comments 2024-10-15 13:54:51 +02:00
Bracken
2fc4e39394
Merge pull request #1421 from stevenh/fix/suite-test-failures
suite: fix test failures
2024-10-06 16:49:23 +01:00
Bracken
f2227519d6
Merge branch 'master' into fix/suite-test-failures 2024-10-06 16:48:07 +01:00
Bracken
50d5b7e695
Merge pull request #1651 from alexandear/mock-fix-not-before-comment
mock: fix doc comment for NotBefore
2024-10-04 16:15:03 +01:00
Bracken
55ebaca027
Merge pull request #1650 from alexandear/assert-fix-comment-typos
assert: fix typos in comments
2024-10-04 16:12:39 +01:00
Oleksandr Redko
ba3e7c34d5 mock: fix doc comment for NotBefore 2024-10-04 18:06:40 +03:00
Oleksandr Redko
2063e81696 assert: fix typos in comments 2024-10-04 18:02:45 +03:00
Bracken
7f489726a5
Merge pull request #1129 from palsivertsen/not-error-as
Add assertion for NotErrorAs
2024-10-04 13:38:32 +01:00
Pål Sivertsen
f844b269df Review: Expand NotErrorAs func docs
https://github.com/stretchr/testify/pull/1129#discussion_r1787490770
2024-10-04 12:43:45 +02:00
Pål Sivertsen
dc100b1be3 Review: Drop doc line and fix typo
Review feedback:
https://github.com/stretchr/testify/pull/1129#discussion_r1786495803
2024-10-04 12:43:45 +02:00
Pal Sivertsen
aade8450b3 Improve tests for ErrorIs/ErrorAs
Checks that the assertion result matches what's set in `testing.T`.
2024-10-04 12:43:45 +02:00
Pal Sivertsen
3380867632 Add NotErrorAs assertion
The library already had assertions for `ErrorIs`, `NotErrorIs` and
`ErrorAs`. This commit adds the `NotErrorAs` assertion which is the
inverse of `ErrorAs`.
2024-10-04 12:43:45 +02:00
Olivier Mengué
95d1f9c2ad
Merge pull request #1645 from brackendawson/no-parallel-suite
Document suite's lack of support for t.Parallel
2024-10-04 12:26:06 +02:00
Bracken Dawson
fed9ee68dc Document suite's lack of support for t.Parallel 2024-10-04 12:24:15 +02:00
Bracken
5dc934f9aa
Merge pull request #1629 from HaraldNordgren/patch-1
.github/workflows: Run tests for Go 1.22
2024-10-03 17:22:59 +01:00
Bracken
c4b8421a1f
Merge pull request #1637 from ReyOrtiz/master
mock: in order mock calls
2024-10-02 17:23:18 +01:00
Bracken
85a526818c
Merge branch 'master' into master 2024-10-02 17:21:55 +01:00
Bracken
16a09b7086
Merge pull request #1644 from spirin/unexpected-method-caller-info
mock: caller information for unexpected method call
2024-10-01 10:31:37 +01:00
Spirin
f3f7181b01
Merge branch 'master' into unexpected-method-caller-info 2024-10-01 02:22:07 +03:00
spirin
d62ca68bf5 tests 2024-10-01 02:21:38 +03:00
Bracken
428847e363
Merge pull request #1571 from stretchr/mock-simplify-FunctionalOptions-impl
mock: simplify implementation of FunctionalOptions
2024-09-30 23:30:50 +01:00
Bracken
72e3b61028
Merge branch 'master' into mock-simplify-FunctionalOptions-impl 2024-09-30 23:28:38 +01:00
spirin
ea6964c2e9 mock: caller information for unexpected method call 2024-09-30 21:33:46 +03:00
Reynier Ortiz
f17409f81f mock: in order mock calls
(requested changes applied)
2024-09-25 12:03:55 -04:00
Reynier Ortiz
bdb1271ed8 mock: in order mock calls 2024-09-25 11:26:01 -04:00
Steven Hartland
e943930404 fix(suite): test failures
Fix TestFailfastSuite when run with go test flag -count=X where X
greater than 1.
2024-09-09 10:09:18 +01:00
Reynier Ortiz
7268a5bc0b mock: in order mock calls 2024-09-06 09:18:07 -04:00
Joseph Dallago
da63673a11
Now properly record the ReturnArguments as part of the call. 2024-08-29 22:05:04 +03:00
Harald Nordgren
52df55490e
.github/workflows: Run tests for Go 1.22 2024-07-24 13:39:26 +02:00
Connor Szczepaniak
bae586f140
colocate never/eventually tests 2024-07-09 08:44:49 -05:00
Connor Szczepaniak
bf2c747cca
simplify tests 2024-07-09 08:44:03 -05:00
Connor Szczepaniak
ab114f88b1
test never when it fails quickly 2024-07-09 08:44:03 -05:00
Connor Szczepaniak
e4e93dd77c
update Never to also check the condition initially 2024-07-09 08:44:03 -05:00
cszczepaniak
f96316432b
test that we succeed quickly 2024-07-09 08:31:19 -05:00
cszczepaniak
cd4dc2864c
respect the timeout on the initial condition check 2024-07-09 08:31:19 -05:00
cszczepaniak
68f35d2640
return early in Eventually and EventuallyWithT 2024-07-09 08:29:08 -05:00
Mike Auclair
2b53603313 wip 2024-06-25 14:59:20 +00:00
Mike Auclair
7f10816c93 review feedback 2024-06-25 11:50:49 +00:00
Mike Auclair
176474a4c9 cleanup 2024-06-24 20:42:26 +00:00
Mike Auclair
dd725333f3 wip 2024-06-24 20:29:26 +00:00
Mike Auclair
28e0be5092 refill stack frame buffer after it's exhausted 2024-06-24 18:11:07 +00:00
Mike Auclair
4a90eff4ae fix 2024-06-24 16:50:27 +00:00
Mike Auclair
3ca01f4bc3 Stop querying for stack frames multiple times on CallerInfo() 2024-06-24 16:39:18 +00:00
Simon Schulte
bc04bb85a2
Merge branch 'master' into generate-better-comments-for-require-package 2024-06-17 09:16:44 +02:00
Vladimir Kochnev
b074924938
assert: collect.FailNow() should not panic (#1481)
## Summary
`collect.FailNow()` should exit goroutine without a panic to be usable
with `require` package.

## Changes
`collect.FailNow()` just does `runtime.Goexit()` instead of `panic()`.
For example `FailNow()` from `testing` package [behaves
similarly](https://cs.opensource.google/go/go/+/refs/tags/go1.21.2:src/testing/testing.go;l=973).

## Motivation

I just want `require` package to be usable with `EventuallyWithT` e.g. I
want this example to pass but it panics:

```go
package main

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestRequireEventuallyWithT(t *testing.T) {
	state := 0
	require.EventuallyWithT(t, func(c *assert.CollectT) {
		defer func() { state += 1 }()
		require.True(c, state == 2)
	}, 100*time.Millisecond, 10*time.Millisecond)
}
```

See https://go.dev/play/p/Oqd95IT7qxQ

## Related issues
Fixes https://github.com/stretchr/testify/issues/1396
Fixes https://github.com/stretchr/testify/issues/1457
2024-06-13 22:09:51 +02:00
Simon Schulte
f71de4a756 updated message 2024-06-13 18:02:19 +02:00
Simon Schulte
592e4e3c00
Merge branch 'stretchr:master' into generate-better-comments-for-require-package 2024-06-13 18:01:22 +02:00
Simon Schulte
044c46a89f
Update require.go.tmpl
Co-authored-by: Olivier Mengué <dolmen@cpan.org>
2024-06-13 15:40:29 +02:00
Maria Ines Parnisari
84619f5c3c
fix: grammar in godoc for NotErrorIs(f) functions (#1607)
Grammar fixes in doc: _asserts that at none_ -> _asserts that none_

$ grep 'that at none' */*.go
assert/assertion_format.go:// NotErrorIsf asserts that at none of the errors in err's chain matches target.
assert/assertion_forward.go:// NotErrorIs asserts that at none of the errors in err's chain matches target.
assert/assertion_forward.go:// NotErrorIsf asserts that at none of the errors in err's chain matches target.
assert/assertions.go:// NotErrorIs asserts that at none of the errors in err's chain matches target.
require/require.go:// NotErrorIs asserts that at none of the errors in err's chain matches target.
require/require.go:// NotErrorIsf asserts that at none of the errors in err's chain matches target.
require/require_forward.go:// NotErrorIs asserts that at none of the errors in err's chain matches target.
require/require_forward.go:// NotErrorIsf asserts that at none of the errors in err's chain matches target.
2024-06-13 14:57:39 +02:00
Simon Schulte
9326036bf5 Generate better comments for require package
The comments for the require package were just copied over
from the assert package when generating the functions.
This could lead to confusion because
1. The code-examples were showing examples using the
assert package instead of the require package
2. The function-documentation was not mentioning that
the functions were calling `t.FailNow()` which is some
critical information when using this package.
2024-06-13 06:52:14 +02:00
Bracken
1b4fca7679
Merge pull request #1600 from hendrywiranto/not-element-match
assert: new assertion NotElementsMatch
2024-05-29 01:08:10 +01:00
hendry.wiranto
cb4e70cf8d review: match fail msg with params 2024-05-28 21:36:34 +07:00
hendry.wiranto
7af3ed34c2 feat: new assertion NotElementsMatch 2024-05-28 21:36:34 +07:00
Reda Chlieh
df81388b27
Merge branch 'master' into fix/equal-exported-values-accepts-everything 2024-05-23 10:26:47 +02:00
Sean Marciniak
6b275adbf7
Merge pull request #1579 from stretchr/pluggable-yaml-package
assert: make YAML dependency pluggable via build tags
2024-05-23 15:19:21 +09:30
Sean Marciniak
b661f0ade2
Merge pull request #1587 from kevinburkesegment/regex-bytes
assert.Regexp: handle []byte array properly
2024-05-22 11:19:21 +09:30
Reda Chlieh
109f4286cf
Merge branch 'master' into fix/equal-exported-values-accepts-everything 2024-05-20 11:32:27 +02:00
Olivier Mengué
3c0c0e6443
Merge pull request #1593 from brackendawson/EqualValuesDoc
Correctly document EqualValues behavior
2024-05-16 13:55:04 +02:00
Bracken Dawson
32766084e4
Correctly document EqualValues behavior 2024-04-29 13:49:40 +01:00
Bracken
8d4dcbbccb
Merge pull request #1569 from stretchr/mock-more-AnythingOfTypeArgument-alternatives
mock: document more alternatives to deprecated AnythingOfTypeArgument
2024-04-23 16:15:28 +00:00
Olivier Mengué
8c324a0bbd
mock: simpler deprecation doc for AnythingOfTypeArgument
Co-authored-by: Bracken <abdawson@gmail.com>
2024-04-23 15:23:21 +02:00
Olivier Mengué
f32ff5b3cb
Merge pull request #1575 from stretchr/dependabot/github_actions/softprops/action-gh-release-2
CI: bump softprops/action-gh-release from 1 to 2
2024-04-23 14:56:52 +02:00
dependabot[bot]
e33bd6fdd1
build(deps): bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-23 12:37:40 +00:00
Olivier Mengué
d4a63f5b89 mock: simplify implementation of FunctionalOptions
Remove unnecessary use of reflect in the implementation of
mock.FunctionalOptions().
2024-04-22 23:10:37 +02:00
Kevin Burke
a9e6121b1c
assert: handle []byte array properly
The regexp package works more efficiently on bytes; if you have bytes,
it is easier to pass these directly to assert.Regexp than to convert
them to a string first.

In addition, FindIndex/FindStringIndex are unnecessary here because we
immediately throw away the result - let's just call Match() instead.
2024-04-17 12:18:13 -07:00
Olivier Mengué
a61e9e59d6
Merge pull request #1588 from JonCrowther/fix-eventuallywithtf-example
assert: fix example for EventuallyWithT, EventuallyWithTf
2024-04-17 08:33:52 +02:00
Jonathan Crowther
4ec7678c61 Correct the EventuallyWithT and EventuallyWithTf example 2024-04-12 14:19:10 -04:00
Reda Chlieh
42d887f28b
Remove type validation in EqualExportedValues 2024-04-11 22:54:14 +02:00
Ania Kapuścińska
0e5b59666a Fix failure message formatting for Positive and Negative asserts 2024-04-11 17:41:38 +02:00
Bracken
352d2438b9
Merge pull request #1580 from JohnEndson/master
assert: fix typo in comment
2024-04-02 09:13:05 +00:00
Bracken
726249eca2
Merge pull request #1582 from myxo/master
Fix time.Time compare
2024-04-01 15:42:55 +00:00
Olivier Mengué
d3dbb19355 assert: make YAML dependency pluggable via build tags
Make the YAML dependency required for {assert,require}.YAMLEq{,f} pluggable.

The implementation can be selected using build tags:
- testify_yaml_default (default): gopkg.in/yaml.v3 is used, like before
- testify_yaml_fail: YAML deserialization is not implemented and always
  fails. So assert.YAMLEq always fails. This is useful if the test suite
  package doesn't use assert.YAMLEq (very common case).
- testify_yaml_custom: the github.com/stretchr/testify/assert/yaml
  package exposes an Unmarshal variable of type func([]byte, any) error
  (same as gopkg.in/yaml.v3) that allows to plug any alternate
  implementation. For example github.com/goccy/go-yaml.Unmarshal.
  This allows to avoid the link constraints of the license of
  gopkg.in/yaml.v3 (see PR stretchr/testify#1120).

Usage: go test -tags testify_yaml_fail

To install the alternate implementation with testify_yaml_custom:

	//go:build testify_yaml_custom

	package my_pkg_test

	import (
		goyaml "github.com/goccy/go-yaml"
		"github.com/stretchr/testify/assert/yaml"
	)

	func init() {
		yaml.Unmarshal = goyaml.Unmarshal
	}
2024-03-31 22:37:21 +02:00
myxo
17b83c52e4 Fix time.Time compare 2024-03-29 08:40:17 +03:00
JohnEndson
a2fbbfe71b assert: fix typo in comment
Signed-off-by: JohnEndson <jiayuzhen@outlook.com>
2024-03-29 11:39:16 +08:00
Olivier Mengué
be3fbeb943
Merge pull request #1568 from stretchr/doc-testifylint
README: link out to the excellent testifylint
2024-03-28 23:14:32 +01:00
Olivier Mengué
edd74b24a1
Merge pull request #1433 from snirye/master
mock: fix FunctionalOptions docs
2024-03-22 14:01:47 +01:00
Bracken
740a5e83fa
Suggest golangci-lint in README.md as well as doc.go
Co-authored-by: Olivier Mengué <dolmen@cpan.org>
2024-03-20 12:51:19 +00:00
Olivier Mengué
404159f5fa
Merge pull request #1566 from stretchr/assert-deprecate-CompareType
assert: deprecate CompareType
2024-03-20 00:49:17 +01:00
Olivier Mengué
a155d2a49d assert: restore CompareType, but mark it as deprecated
Reinstate CompareType for full backward compatibility, but mark it as
deprecated.
2024-03-20 00:47:39 +01:00
Olivier Mengué
39442a4e4e assert: drop CompareType
Rename CompareType to compareResult to make it private. This type is
used only in internal functions and is of no use for external users and
should never have been made public.

CompareType has been introduced by 0b4ff03cda5c8eb0150a14ffbaaa088fd777d6ba
and appeared in releases since v1.6.0.

Note: strictly speaking, this is a breaking change, but no external user
should have ever used assert.CompareType as it made no sense in the assert
API. A search on GitHub has revealed no use of it.
https://github.com/search?q=assert.CompareType+language%3AGo&type=Repositories&ref=advsearch&l=Go&l=
2024-03-20 00:47:39 +01:00
Olivier Mengué
74e1cbebab assert: minor refactor of compareTwoValues tests
Refactor compareTwoValues tests to free the 'compareResult' symbol name
(for incoming use of this name in next commit).
2024-03-20 00:47:39 +01:00
Olivier Mengué
a71299064b assert: refactor Test_compareTwoValuesCorrectCompareResult
Refactor Test_compareTwoValuesCorrectCompareResult table test to be more
explicit: "compareTypes" renamed to "allowedResults".
2024-03-20 00:47:39 +01:00
Snir Yehuda
da1e1476cb
Merge branch 'master' into master 2024-03-18 09:47:57 +02:00
Olivier Mengué
3c302f75ae
mock: improve doc (#1570)
## Summary
Improve API doc of package
[`mock`](https://pkg.go.dev/github.com/stretchr/testify/mock):
- add godoc links
- indent example code

## Motivation
Readability.
2024-03-10 11:42:04 +01:00
Bracken Dawson
1dedc83b8f
Add testifylint to godocs too
I checked the render locally.
2024-03-07 15:09:29 +00:00
Olivier Mengué
aca1890ec1 mock: document more alternatives to deprecated AnythingOfTypeArgument 2024-03-07 11:59:12 +01:00
Bracken Dawson
bfa3ee96e3
Link out to the excellent testifylint 2024-03-07 00:13:49 +00:00
Snir Yehuda
f1b5324b90 assert.FunctionalOptions: fix go doc 2024-03-06 11:28:50 +03:00
Olivier Mengué
632a26080f
Merge pull request #820 from TomWright/master
Do not get argument again unnecessarily in Arguments.Error()
2024-03-06 03:05:06 +01:00
Tom Wright
cab2acc70f Do not get argument again unnecessarily in Arguments.Error() 2024-03-06 03:03:10 +01:00
Olivier Mengué
edb801534f
Merge pull request #1565 from stretchr/gitignore-test-binaries
.gitignore: ignore "go test -c" binaries
2024-03-05 12:09:22 +01:00
Olivier Mengué
89ffab03a5
Merge pull request #1562 from stretchr/make-tHelper-a-type-alias
assert: make tHelper a type alias
2024-03-05 10:48:10 +01:00
Fahim Bagar
8585d8de96
Add PanicAssertionFunc (#1337, #730)
Add a `PanicAssertionFunc` to ease writing table-driven tests for panic
assertion.

Closes #730
2024-03-05 10:13:30 +01:00
Olivier Mengué
e5e71998af gitignore: ignore "go test -c" binaries
Ignore binaries produced by "go test -c".
2024-03-04 22:37:21 +01:00
Olivier Mengué
85fabe7c5c assert: make tHelper a type alias
The tHelper interface is defined only for internal usage. We don't need
a "hard" type for it as we don't define methods on it. Let's make is
just a alias to the anonymous interface it represents.

Note: we are already using type aliases elswhere, and type aliases were
introduced a long time ago in Go 1.9.
2024-03-03 18:29:24 +01:00
40 changed files with 2641 additions and 771 deletions

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
if [ -n "$(gofmt -l .)" ]; then
echo "Go code is not formatted:"

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# If GOMOD is defined we are running with Go Modules enabled, either
# automatically or via the GO111MODULE=on environment variable. Codegen only

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -e

12
.ci.readme.fmt.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env 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

View File

@ -15,8 +15,10 @@ jobs:
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
- run: npm install -g mdsf-cli
- run: ./.ci.gogenerate.sh
- run: ./.ci.gofmt.sh
- run: ./.ci.readme.fmt.sh
- run: ./.ci.govet.sh
- run: go test -v -race ./...
test:
@ -29,6 +31,7 @@ jobs:
- "1.19"
- "1.20"
- "1.21"
- "1.22"
steps:
- uses: actions/checkout@v4
- name: Setup Go

View File

@ -16,6 +16,6 @@ jobs:
uses: actions/checkout@v4
- name: Create GitHub release from tag
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true

6
.gitignore vendored
View File

@ -22,3 +22,9 @@ _testmain.go
*.exe
.DS_Store
# Output of "go test -c"
/assert/assert.test
/require/require.test
/suite/suite.test
/mock/mock.test

12
.mdsf.json Normal file
View File

@ -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"
]
]
}
}

View File

@ -6,5 +6,12 @@ pull requests.
* @boyan-soubachov
* @dolmen
* @MovieStoreGuy
* @arjunmahishi
* @brackendawson
## Approvers
The individuals listed below are active in the project and have the ability to approve pull
requests.
* @arjunmahishi
* @ccoVeille

194
README.md
View File

@ -1,7 +1,9 @@
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).
[![Build Status](https://github.com/stretchr/testify/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/stretchr/testify/actions/workflows/main.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/testify)](https://goreportcard.com/report/github.com/stretchr/testify) [![PkgGoDev](https://pkg.go.dev/badge/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)
* 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
* 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)
[`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") package
-------------------------------------------------------------------------------------------
@ -37,30 +38,27 @@ See it in action:
package yours
import (
"testing"
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
// assert equality
assert.Equal(t, 123, 123, "they should be equal")
// assert equality
assert.Equal(t, 123, 123, "they should be equal")
// assert inequality
assert.NotEqual(t, 123, 456, "they should not be equal")
// assert inequality
assert.NotEqual(t, 123, 456, "they should not be equal")
// assert for nil (good for errors)
assert.Nil(t, object)
// assert for not nil (good when you expect something)
if assert.NotNil(t, object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal(t, "Something", object.Value)
}
// assert for nil (good for errors)
assert.Nil(t, object)
// assert for not nil (good when you expect something)
if assert.NotNil(t, object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal(t, "Something", object.Value)
}
}
```
@ -73,29 +71,29 @@ if you assert many times, use the below:
package yours
import (
"testing"
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
assert := assert.New(t)
assert := assert.New(t)
// assert equality
assert.Equal(123, 123, "they should be equal")
// assert equality
assert.Equal(123, 123, "they should be equal")
// assert inequality
assert.NotEqual(123, 456, "they should not be equal")
// assert inequality
assert.NotEqual(123, 456, "they should not be equal")
// assert for nil (good for errors)
assert.Nil(object)
// assert for nil (good for errors)
assert.Nil(object)
// assert for not nil (good when you expect something)
if assert.NotNil(object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal("Something", object.Value)
}
// assert for not nil (good when you expect something)
if assert.NotNil(object) {
// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal("Something", object.Value)
}
}
```
@ -119,8 +117,9 @@ An example test function that tests a piece of code that relies on an external o
package yours
import (
"testing"
"github.com/stretchr/testify/mock"
"testing"
"github.com/stretchr/testify/mock"
)
/*
@ -129,8 +128,8 @@ import (
// MyMockedObject is a mocked object that implements an interface
// that describes an object that the code I am testing relies on.
type MyMockedObject struct{
mock.Mock
type MyMockedObject struct {
mock.Mock
}
// DoSomething is a method on MyMockedObject that implements some interface
@ -141,10 +140,8 @@ type MyMockedObject struct{
//
// NOTE: This method is not being tested here, code that uses this object is.
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
args := m.Called(number)
return args.Bool(0), args.Error(1)
args := m.Called(number)
return args.Bool(0), args.Error(1)
}
/*
@ -154,20 +151,17 @@ func (m *MyMockedObject) DoSomething(number int) (bool, error) {
// TestSomething is an example of how to use our test object to
// make assertions about some target code we are testing.
func TestSomething(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// create an instance of our test object
testObj := new(MyMockedObject)
// set up expectations
testObj.On("DoSomething", 123).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
// set up expectations
testObj.On("DoSomething", 123).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
}
// TestSomethingWithPlaceholder is a second example of how to use our test object to
@ -176,45 +170,42 @@ func TestSomething(t *testing.T) {
// data being passed in is normally dynamically generated and cannot be
// predicted beforehand (eg. containing hashes that are time sensitive)
func TestSomethingWithPlaceholder(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// create an instance of our test object
testObj := new(MyMockedObject)
// set up expectations with a placeholder in the argument list
testObj.On("DoSomething", mock.Anything).Return(true, nil)
// set up expectations with a placeholder in the argument list
testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
}
// TestSomethingElse2 is a third example that shows how you can use
// the Unset method to cleanup handlers and then add new ones.
func TestSomethingElse2(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// create an instance of our test object
testObj := new(MyMockedObject)
// set up expectations with a placeholder in the argument list
mockCall := testObj.On("DoSomething", mock.Anything).Return(true, nil)
// set up expectations with a placeholder in the argument list
mockCall := testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
// assert that the expectations were met
testObj.AssertExpectations(t)
// remove the handler now so we can add another one that takes precedence
mockCall.Unset()
// remove the handler now so we can add another one that takes precedence
mockCall.Unset()
// return false now instead of true
testObj.On("DoSomething", mock.Anything).Return(false, nil)
// return false now instead of true
testObj.On("DoSomething", mock.Anything).Return(false, nil)
testObj.AssertExpectations(t)
testObj.AssertExpectations(t)
}
```
@ -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
-----------------------------------------------------------------------------------------
> [!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.
@ -232,35 +225,36 @@ An example suite is shown below:
```go
// Basic imports
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
// Define the suite, and absorb the built-in basic suite
// functionality from testify - including a T() method which
// returns the current testing context
type ExampleTestSuite struct {
suite.Suite
VariableThatShouldStartAtFive int
suite.Suite
VariableThatShouldStartAtFive int
}
// Make sure that VariableThatShouldStartAtFive is set to five
// before each test
func (suite *ExampleTestSuite) SetupTest() {
suite.VariableThatShouldStartAtFive = 5
suite.VariableThatShouldStartAtFive = 5
}
// All methods that begin with "Test" are run as tests within a
// suite.
func (suite *ExampleTestSuite) TestExample() {
assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
}
// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, new(ExampleTestSuite))
suite.Run(t, new(ExampleTestSuite))
}
```
@ -273,33 +267,34 @@ For more information on writing suites, check out the [API documentation for the
```go
// Basic imports
import (
"testing"
"github.com/stretchr/testify/suite"
"testing"
"github.com/stretchr/testify/suite"
)
// Define the suite, and absorb the built-in basic suite
// functionality from testify - including assertion methods.
type ExampleTestSuite struct {
suite.Suite
VariableThatShouldStartAtFive int
suite.Suite
VariableThatShouldStartAtFive int
}
// Make sure that VariableThatShouldStartAtFive is set to five
// before each test
func (suite *ExampleTestSuite) SetupTest() {
suite.VariableThatShouldStartAtFive = 5
suite.VariableThatShouldStartAtFive = 5
}
// All methods that begin with "Test" are run as tests within a
// suite.
func (suite *ExampleTestSuite) TestExample() {
suite.Equal(suite.VariableThatShouldStartAtFive, 5)
suite.Equal(suite.VariableThatShouldStartAtFive, 5)
}
// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, new(ExampleTestSuite))
suite.Run(t, new(ExampleTestSuite))
}
```
@ -326,14 +321,13 @@ Import the `testify/assert` package into your code using this template:
package yours
import (
"testing"
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSomething(t *testing.T) {
assert.True(t, true, "True is true!")
assert.True(t, true, "True is true!")
}
```

View File

@ -16,7 +16,6 @@ import (
"go/token"
"go/types"
"io"
"io/ioutil"
"log"
"os"
"path"
@ -101,13 +100,15 @@ func parseTemplates() (*template.Template, *template.Template, error) {
return nil, nil, err
}
if *tmplFile != "" {
f, err := ioutil.ReadFile(*tmplFile)
f, err := os.ReadFile(*tmplFile)
if err != nil {
return nil, nil, err
}
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 {
return nil, nil, err
}
@ -181,7 +182,7 @@ func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) {
files := make(map[string]*ast.File)
fileList := make([]*ast.File, len(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 {
return nil, nil, err
}

View File

@ -7,10 +7,13 @@ import (
"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 (
compareLess CompareType = iota - 1
compareLess compareResult = iota - 1
compareEqual
compareGreater
)
@ -39,7 +42,7 @@ var (
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)
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)
}
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:
{
@ -345,7 +354,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
}
return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true
return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true
}
case reflect.Uintptr:
{
@ -381,7 +390,8 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface
if h, ok := t.(tHelper); ok {
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
@ -394,7 +404,8 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in
if h, ok := t.(tHelper); ok {
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
@ -406,7 +417,8 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{})
if h, ok := t.(tHelper); ok {
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
@ -419,7 +431,8 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter
if h, ok := t.(tHelper); ok {
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
@ -431,7 +444,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
h.Helper()
}
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
@ -443,10 +457,11 @@ func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
h.Helper()
}
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 {
h.Helper()
}
@ -459,17 +474,17 @@ func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedCompare
compareResult, isComparable := compare(e1, e2, e1Kind)
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) {
return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
return Fail(t, failMessage, msgAndArgs...)
}
return true
}
func containsValue(values []CompareType, value CompareType) bool {
func containsValue(values []compareResult, value compareResult) bool {
for _, v := range values {
if v == value {
return true

View File

@ -10,6 +10,8 @@ import (
)
func TestCompare(t *testing.T) {
t.Parallel()
type customString string
type customInt int
type customInt8 int8
@ -59,6 +61,7 @@ func TestCompare(t *testing.T) {
{less: uintptr(1), greater: uintptr(2), cType: "uintptr"},
{less: customUintptr(1), greater: customUintptr(2), cType: "uint64"},
{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: []byte{1, 1}, greater: []byte{1, 2}, cType: "[]byte"},
{less: customBytes([]byte{1, 1}), greater: customBytes([]byte{1, 2}), cType: "[]byte"},
@ -126,6 +129,8 @@ func callerName(skip int) string {
}
func TestGreater(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !Greater(mockT, 2, 1) {
@ -170,6 +175,8 @@ func TestGreater(t *testing.T) {
}
func TestGreaterOrEqual(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !GreaterOrEqual(mockT, 2, 1) {
@ -214,6 +221,8 @@ func TestGreaterOrEqual(t *testing.T) {
}
func TestLess(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !Less(mockT, 1, 2) {
@ -258,6 +267,8 @@ func TestLess(t *testing.T) {
}
func TestLessOrEqual(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !LessOrEqual(mockT, 1, 2) {
@ -302,6 +313,8 @@ func TestLessOrEqual(t *testing.T) {
}
func TestPositive(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !Positive(mockT, 1) {
@ -341,6 +354,8 @@ func TestPositive(t *testing.T) {
}
func TestNegative(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !Negative(mockT, -1) {
@ -380,6 +395,8 @@ func TestNegative(t *testing.T) {
}
func Test_compareTwoValuesDifferentValuesTypes(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
for _, currCase := range []struct {
@ -392,12 +409,14 @@ func Test_compareTwoValuesDifferentValuesTypes(t *testing.T) {
{v1: float64(12), v2: "123"},
{v1: "float(12)", v2: float64(1)},
} {
compareResult := compareTwoValues(mockT, currCase.v1, currCase.v2, []CompareType{compareLess, compareEqual, compareGreater}, "testFailMessage")
False(t, compareResult)
result := compareTwoValues(mockT, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage")
False(t, result)
}
}
func Test_compareTwoValuesNotComparableValues(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
type CompareStruct struct {
@ -411,44 +430,48 @@ func Test_compareTwoValuesNotComparableValues(t *testing.T) {
{v1: map[string]int{}, v2: map[string]int{}},
{v1: make([]int, 5), v2: make([]int, 5)},
} {
compareResult := compareTwoValues(mockT, currCase.v1, currCase.v2, []CompareType{compareLess, compareEqual, compareGreater}, "testFailMessage")
False(t, compareResult)
result := compareTwoValues(mockT, currCase.v1, currCase.v2, []compareResult{compareLess, compareEqual, compareGreater}, "testFailMessage")
False(t, result)
}
}
func Test_compareTwoValuesCorrectCompareResult(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
for _, currCase := range []struct {
v1 interface{}
v2 interface{}
compareTypes []CompareType
v1 interface{}
v2 interface{}
allowedResults []compareResult
}{
{v1: 1, v2: 2, compareTypes: []CompareType{compareLess}},
{v1: 1, v2: 2, compareTypes: []CompareType{compareLess, compareEqual}},
{v1: 2, v2: 2, compareTypes: []CompareType{compareGreater, compareEqual}},
{v1: 2, v2: 2, compareTypes: []CompareType{compareEqual}},
{v1: 2, v2: 1, compareTypes: []CompareType{compareEqual, compareGreater}},
{v1: 2, v2: 1, compareTypes: []CompareType{compareGreater}},
{v1: 1, v2: 2, allowedResults: []compareResult{compareLess}},
{v1: 1, v2: 2, allowedResults: []compareResult{compareLess, compareEqual}},
{v1: 2, v2: 2, allowedResults: []compareResult{compareGreater, compareEqual}},
{v1: 2, v2: 2, allowedResults: []compareResult{compareEqual}},
{v1: 2, v2: 1, allowedResults: []compareResult{compareEqual, compareGreater}},
{v1: 2, v2: 1, allowedResults: []compareResult{compareGreater}},
} {
compareResult := compareTwoValues(mockT, currCase.v1, currCase.v2, currCase.compareTypes, "testFailMessage")
True(t, compareResult)
result := compareTwoValues(mockT, currCase.v1, currCase.v2, currCase.allowedResults, "testFailMessage")
True(t, result)
}
}
func Test_containsValue(t *testing.T) {
t.Parallel()
for _, currCase := range []struct {
values []CompareType
value CompareType
values []compareResult
value compareResult
result bool
}{
{values: []CompareType{compareGreater}, value: compareGreater, result: true},
{values: []CompareType{compareGreater, compareLess}, value: compareGreater, result: true},
{values: []CompareType{compareGreater, compareLess}, value: compareLess, result: true},
{values: []CompareType{compareGreater, compareLess}, value: compareEqual, result: false},
{values: []compareResult{compareGreater}, value: compareGreater, result: true},
{values: []compareResult{compareGreater, compareLess}, value: compareGreater, result: true},
{values: []compareResult{compareGreater, compareLess}, value: compareLess, result: true},
{values: []compareResult{compareGreater, compareLess}, value: compareEqual, result: false},
} {
compareResult := containsValue(currCase.values, currCase.value)
Equal(t, currCase.result, compareResult)
result := containsValue(currCase.values, currCase.value)
Equal(t, currCase.result, result)
}
}

View File

@ -104,8 +104,8 @@ func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{},
return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// EqualValuesf asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
@ -117,10 +117,8 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if assert.Errorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err)
// }
// actualObj, err := SomeFunction()
// assert.Errorf(t, err, "error message %s", "formatted")
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -186,7 +184,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 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 {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -438,7 +436,19 @@ func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interf
return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...)
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// assert.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsNotType(t, theType, object, append([]interface{}{msg}, args...)...)
}
// IsTypef asserts that the specified objects are of the same type.
//
// assert.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -568,6 +578,23 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
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
// a slice or a channel with len == 0.
//
@ -604,7 +631,16 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s
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.
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
@ -667,12 +703,15 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string,
return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
// contain all elements given in the specified subset list(array, slice...) or
// map.
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// assert.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// assert.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -756,11 +795,15 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg
return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Subsetf asserts that the specified list(array, slice...) or map contains all
// elements given in the specified subset list(array, slice...) or map.
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// assert.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// assert.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()

View File

@ -186,8 +186,8 @@ func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface
return EqualExportedValuesf(a.t, expected, actual, msg, args...)
}
// EqualValues asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValues(uint32(123), int32(123))
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...)
}
// EqualValuesf asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
@ -224,10 +224,8 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if a.Error(err) {
// assert.Equal(t, expectedError, err)
// }
// actualObj, err := SomeFunction()
// a.Error(err)
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -297,10 +295,8 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if a.Errorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err)
// }
// actualObj, err := SomeFunction()
// a.Errorf(err, "error message %s", "formatted")
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -336,7 +332,7 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
// a.EventuallyWithT(func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 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 {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -361,7 +357,7 @@ func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 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 {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -868,7 +864,29 @@ func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...in
return IsNonIncreasingf(a.t, object, msg, args...)
}
// IsNotType asserts that the specified objects are not of the same type.
//
// a.IsNotType(&NotMyStruct{}, &MyStruct{})
func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNotType(a.t, theType, object, msgAndArgs...)
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNotTypef(a.t, theType, object, msg, args...)
}
// IsType asserts that the specified objects are of the same type.
//
// a.IsType(&MyStruct{}, &MyStruct{})
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -877,6 +895,8 @@ func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAnd
}
// IsTypef asserts that the specified objects are of the same type.
//
// a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1128,6 +1148,40 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
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
// a slice or a channel with len == 0.
//
@ -1200,7 +1254,25 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
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.
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
@ -1209,7 +1281,7 @@ func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface
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.
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
@ -1326,12 +1398,15 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri
return NotSamef(a.t, expected, actual, msg, args...)
}
// NotSubset asserts that the specified list(array, slice...) or map does NOT
// contain all elements given in the specified subset list(array, slice...) or
// map.
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubset([1, 3, 4], [1, 2])
// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
// a.NotSubset([1, 3, 4], {1: "one", 2: "two"})
// a.NotSubset({"x": 1, "y": 2}, ["z"])
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1339,12 +1414,15 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
return NotSubset(a.t, list, subset, msgAndArgs...)
}
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
// contain all elements given in the specified subset list(array, slice...) or
// map.
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1504,11 +1582,15 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string,
return Samef(a.t, expected, actual, msg, args...)
}
// Subset asserts that the specified list(array, slice...) or map contains all
// elements given in the specified subset list(array, slice...) or map.
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subset([1, 2, 3], [1, 2])
// a.Subset({"x": 1, "y": 2}, {"x": 1})
// a.Subset([1, 2, 3], {1: "one", 2: "two"})
// a.Subset({"x": 1, "y": 2}, ["x"])
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1516,11 +1598,15 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
return Subset(a.t, list, subset, msgAndArgs...)
}
// Subsetf asserts that the specified list(array, slice...) or map contains all
// elements given in the specified subset list(array, slice...) or map.
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()

View File

@ -6,7 +6,7 @@ import (
)
// 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()
if objKind != reflect.Slice && objKind != reflect.Array {
return false
@ -33,7 +33,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind)
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) {
@ -50,7 +50,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
// assert.IsIncreasing(t, []float{1, 2})
// assert.IsIncreasing(t, []string{"a", "b"})
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
@ -59,7 +59,7 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
// assert.IsNonIncreasing(t, []float{2, 1})
// assert.IsNonIncreasing(t, []string{"b", "a"})
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
@ -68,7 +68,7 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{})
// assert.IsDecreasing(t, []float{2, 1})
// assert.IsDecreasing(t, []string{"b", "a"})
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
@ -77,5 +77,5 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
// assert.IsNonDecreasing(t, []float{1, 2})
// assert.IsNonDecreasing(t, []string{"a", "b"})
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...)
}

View File

@ -6,6 +6,8 @@ import (
)
func TestIsIncreasing(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !IsIncreasing(mockT, []int{1, 2}) {
@ -51,6 +53,8 @@ func TestIsIncreasing(t *testing.T) {
}
func TestIsNonIncreasing(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !IsNonIncreasing(mockT, []int{2, 1}) {
@ -96,6 +100,8 @@ func TestIsNonIncreasing(t *testing.T) {
}
func TestIsDecreasing(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !IsDecreasing(mockT, []int{2, 1}) {
@ -141,6 +147,8 @@ func TestIsDecreasing(t *testing.T) {
}
func TestIsNonDecreasing(t *testing.T) {
t.Parallel()
mockT := new(testing.T)
if !IsNonDecreasing(mockT, []int{1, 2}) {
@ -186,6 +194,8 @@ func TestIsNonDecreasing(t *testing.T) {
}
func TestOrderingMsgAndArgsForwarding(t *testing.T) {
t.Parallel()
msgAndArgs := []interface{}{"format %s %x", "this", 0xc001}
expectedOutput := "format this c001\n"
collection := []int{1, 2, 1}

View File

@ -19,9 +19,13 @@ import (
"github.com/davecgh/go-spew/spew"
"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"
// TestingT is an interface wrapper around *testing.T
@ -45,6 +49,10 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
// for table driven tests.
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
type Comparison func() (success bool)
@ -204,59 +212,74 @@ the problem actually occurred in calling code.*/
// of each stack frame leading from the current test to the assert call that
// failed.
func CallerInfo() []string {
var pc uintptr
var ok bool
var file string
var line int
var name string
callers := []string{}
for i := 0; ; i++ {
pc, file, line, ok = runtime.Caller(i)
if !ok {
// The breaks below failed to terminate the loop, and we ran off the
// end of the call stack.
pcs := make([]uintptr, stackFrameBufferSize)
offset := 1
for {
n := runtime.Callers(offset, pcs)
if n == 0 {
break
}
// This is a huge edge case, but it will panic if this is the case, see #180
if file == "<autogenerated>" {
break
}
frames := runtime.CallersFrames(pcs[:n])
f := runtime.FuncForPC(pc)
if f == nil {
break
}
name = f.Name()
for {
frame, more := frames.Next()
pc = frame.PC
file = frame.File
line = frame.Line
// testing.tRunner is the standard library function that calls
// tests. Subtests are called directly by tRunner, without going through
// the Test/Benchmark/Example function that contains the t.Run calls, so
// with subtests we should break when we hit tRunner, without adding it
// to the list of callers.
if name == "testing.tRunner" {
break
}
// This is a huge edge case, but it will panic if this is the case, see #180
if file == "<autogenerated>" {
break
}
parts := strings.Split(file, "/")
if len(parts) > 1 {
filename := parts[len(parts)-1]
dir := parts[len(parts)-2]
if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" {
callers = append(callers, fmt.Sprintf("%s:%d", file, line))
f := runtime.FuncForPC(pc)
if f == nil {
break
}
name = f.Name()
// testing.tRunner is the standard library function that calls
// tests. Subtests are called directly by tRunner, without going through
// the Test/Benchmark/Example function that contains the t.Run calls, so
// with subtests we should break when we hit tRunner, without adding it
// to the list of callers.
if name == "testing.tRunner" {
break
}
parts := strings.Split(file, "/")
if len(parts) > 1 {
filename := parts[len(parts)-1]
dir := parts[len(parts)-2]
if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" {
callers = append(callers, fmt.Sprintf("%s:%d", file, line))
}
}
// Drop the package
segments := strings.Split(name, ".")
name = segments[len(segments)-1]
if isTest(name, "Test") ||
isTest(name, "Benchmark") ||
isTest(name, "Example") {
break
}
if !more {
break
}
}
// We know we already have less than a buffer's worth of frames
offset += stackFrameBufferSize
// Drop the package
segments := strings.Split(name, ".")
name = segments[len(segments)-1]
if isTest(name, "Test") ||
isTest(name, "Benchmark") ||
isTest(name, "Example") {
break
}
}
return callers
@ -431,17 +454,34 @@ func NotImplements(t TestingT, interfaceObject interface{}, object interface{},
return true
}
func isType(expectedType, object interface{}) bool {
return ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType))
}
// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
//
// assert.IsType(t, &MyStruct{}, &MyStruct{})
func IsType(t TestingT, expectedType, object interface{}, msgAndArgs ...interface{}) bool {
if isType(expectedType, object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Object expected to be of type %T, but was %T", expectedType, object), msgAndArgs...)
}
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...)
// IsNotType asserts that the specified objects are not of the same type.
//
// assert.IsNotType(t, &NotMyStruct{}, &MyStruct{})
func IsNotType(t TestingT, theType, object interface{}, msgAndArgs ...interface{}) bool {
if !isType(theType, object) {
return true
}
return true
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Object type expected to be different than %T", theType), msgAndArgs...)
}
// Equal asserts that two objects are equal.
@ -469,7 +509,6 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
}
return true
}
// validateEqualArgs checks whether provided arguments can be safely used in the
@ -496,10 +535,17 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
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"+
"expected: %p %#v\n"+
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
"expected: %p %#[1]v\n"+
"actual : %p %#[2]v",
expected, actual), msgAndArgs...)
}
return true
@ -516,29 +562,37 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
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(
"Expected and actual point to the same object: %p %#v",
expected, expected), msgAndArgs...)
"Expected and actual point to the same object: %p %#[1]v",
expected), msgAndArgs...)
}
return true
}
// samePointers compares two generic interface objects and returns whether
// they point to the same object
func samePointers(first, second interface{}) bool {
// samePointers checks if two generic interface objects are pointers of the same
// type pointing to the same object. It returns two values: same indicating if
// 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)
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)
if firstType != secondType {
return false
return false, true // both are pointers, but of different types
}
// compare pointer addresses
return first == second
return first == second, true
}
// formatUnequalValues takes two values of arbitrary types and returns string
@ -572,8 +626,8 @@ func truncatingFormat(data interface{}) string {
return value
}
// EqualValues asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
@ -590,7 +644,6 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa
}
return true
}
// EqualExportedValues asserts that the types of two objects are equal and their public
@ -615,21 +668,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...)
}
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)
actual = copyExportedFields(actual)
@ -660,7 +698,6 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
}
return Equal(t, expected, actual, msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
@ -710,7 +747,6 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
// isEmpty gets whether the specified object is considered empty or not.
func isEmpty(object interface{}) bool {
// get nil case out of the way
if object == nil {
return true
@ -751,7 +787,6 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
}
return pass
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
@ -770,7 +805,6 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
}
return pass
}
// getLen tries to get the length of an object.
@ -814,7 +848,6 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
}
return true
}
// False asserts that the specified value is false.
@ -829,7 +862,6 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
}
return true
}
// NotEqual asserts that the specified values are NOT equal.
@ -852,7 +884,6 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
}
return true
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
@ -875,7 +906,6 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte
// return (true, false) if element was not found.
// return (true, true) if element was found.
func containsElement(list interface{}, element interface{}) (ok, found bool) {
listValue := reflect.ValueOf(list)
listType := reflect.TypeOf(list)
if listType == nil {
@ -910,7 +940,6 @@ func containsElement(list interface{}, element interface{}) (ok, found bool) {
}
}
return true, false
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
@ -933,7 +962,6 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
}
return true
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
@ -956,14 +984,17 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
}
return true
}
// Subset asserts that the specified list(array, slice...) or map contains all
// elements given in the specified subset list(array, slice...) or map.
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.Subset(t, [1, 2, 3], [1, 2])
// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
// assert.Subset(t, [1, 2, 3], {1: "one", 2: "two"})
// assert.Subset(t, {"x": 1, "y": 2}, ["x"])
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -978,7 +1009,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
}
subsetKind := reflect.TypeOf(subset).Kind()
if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map {
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
}
@ -1002,6 +1033,13 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
}
subsetList := reflect.ValueOf(subset)
if subsetKind == reflect.Map {
keys := make([]interface{}, subsetList.Len())
for idx, key := range subsetList.MapKeys() {
keys[idx] = key.Interface()
}
subsetList = reflect.ValueOf(keys)
}
for i := 0; i < subsetList.Len(); i++ {
element := subsetList.Index(i).Interface()
ok, found := containsElement(list, element)
@ -1016,12 +1054,15 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
return true
}
// NotSubset asserts that the specified list(array, slice...) or map does NOT
// contain all elements given in the specified subset list(array, slice...) or
// map.
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.NotSubset(t, [1, 3, 4], [1, 2])
// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
// assert.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"})
// assert.NotSubset(t, {"x": 1, "y": 2}, ["z"])
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -1036,7 +1077,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
}
subsetKind := reflect.TypeOf(subset).Kind()
if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map {
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
}
@ -1060,11 +1101,18 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
}
subsetList := reflect.ValueOf(subset)
if subsetKind == reflect.Map {
keys := make([]interface{}, subsetList.Len())
for idx, key := range subsetList.MapKeys() {
keys[idx] = key.Interface()
}
subsetList = reflect.ValueOf(keys)
}
for i := 0; i < subsetList.Len(); i++ {
element := subsetList.Index(i).Interface()
ok, found := containsElement(list, element)
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 {
return true
@ -1170,6 +1218,39 @@ func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) stri
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.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
@ -1488,6 +1569,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
if err != nil {
return Fail(t, err.Error(), msgAndArgs...)
}
if math.IsNaN(actualEpsilon) {
return Fail(t, "relative error is NaN", msgAndArgs...)
}
if actualEpsilon > epsilon {
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
" < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
@ -1550,10 +1634,8 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if assert.Error(t, err) {
// assert.Equal(t, expectedError, err)
// }
// actualObj, err := SomeFunction()
// assert.Error(t, err)
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
if err == nil {
if h, ok := t.(tHelper); ok {
@ -1611,7 +1693,6 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in
// matchRegexp return true if a specified regexp matches a string.
func matchRegexp(rx interface{}, str interface{}) bool {
var r *regexp.Regexp
if rr, ok := rx.(*regexp.Regexp); ok {
r = rr
@ -1619,8 +1700,14 @@ func matchRegexp(rx interface{}, str interface{}) bool {
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))
}
}
// Regexp asserts that a specified regexp matches a string.
@ -1656,7 +1743,6 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
}
return !match
}
// Zero asserts that i is the zero value for its type.
@ -1767,6 +1853,11 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
// Shortcut if same bytes
if actual == expected {
return true
}
if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
}
@ -1785,6 +1876,11 @@ func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
// Shortcut if same bytes
if actual == expected {
return true
}
if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
}
@ -1872,7 +1968,7 @@ var spewConfigStringerEnabled = spew.ConfigState{
MaxDepth: 10,
}
type tHelper interface {
type tHelper = interface {
Helper()
}
@ -1886,6 +1982,7 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
}
ch := make(chan bool, 1)
checkCond := func() { ch <- condition() }
timer := time.NewTimer(waitFor)
defer timer.Stop()
@ -1893,35 +1990,47 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
ticker := time.NewTicker(tick)
defer ticker.Stop()
for tick := ticker.C; ; {
var tickC <-chan time.Time
// Check the condition once first on the initial call.
go checkCond()
for {
select {
case <-timer.C:
return Fail(t, "Condition never satisfied", msgAndArgs...)
case <-tick:
tick = nil
go func() { ch <- condition() }()
case <-tickC:
tickC = nil
go checkCond()
case v := <-ch:
if v {
return true
}
tick = ticker.C
tickC = ticker.C
}
}
}
// CollectT implements the TestingT interface and collects all errors.
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
}
// Helper is like [testing.T.Helper] but does nothing.
func (CollectT) Helper() {}
// Errorf collects the error.
func (c *CollectT) Errorf(format string, args ...interface{}) {
c.errors = append(c.errors, fmt.Errorf(format, args...))
}
// FailNow panics.
func (*CollectT) FailNow() {
panic("Assertion failed")
// FailNow stops execution by calling runtime.Goexit.
func (c *CollectT) FailNow() {
c.fail()
runtime.Goexit()
}
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
@ -1934,6 +2043,16 @@ func (*CollectT) Copy(TestingT) {
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,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
@ -1951,14 +2070,22 @@ func (*CollectT) Copy(TestingT) {
// assert.EventuallyWithT(t, func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 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 {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var lastFinishedTickErrs []error
ch := make(chan []error, 1)
ch := make(chan *CollectT, 1)
checkCond := func() {
collect := new(CollectT)
defer func() {
ch <- collect
}()
condition(collect)
}
timer := time.NewTimer(waitFor)
defer timer.Stop()
@ -1966,29 +2093,28 @@ func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time
ticker := time.NewTicker(tick)
defer ticker.Stop()
for tick := ticker.C; ; {
var tickC <-chan time.Time
// Check the condition once first on the initial call.
go checkCond()
for {
select {
case <-timer.C:
for _, err := range lastFinishedTickErrs {
t.Errorf("%v", err)
}
return Fail(t, "Condition never satisfied", msgAndArgs...)
case <-tick:
tick = nil
go func() {
collect := new(CollectT)
defer func() {
ch <- collect.errors
}()
condition(collect)
}()
case errs := <-ch:
if len(errs) == 0 {
case <-tickC:
tickC = nil
go checkCond()
case collect := <-ch:
if !collect.failed() {
return true
}
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
lastFinishedTickErrs = errs
tick = ticker.C
lastFinishedTickErrs = collect.errors
tickC = ticker.C
}
}
}
@ -2003,6 +2129,7 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D
}
ch := make(chan bool, 1)
checkCond := func() { ch <- condition() }
timer := time.NewTimer(waitFor)
defer timer.Stop()
@ -2010,18 +2137,23 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D
ticker := time.NewTicker(tick)
defer ticker.Stop()
for tick := ticker.C; ; {
var tickC <-chan time.Time
// Check the condition once first on the initial call.
go checkCond()
for {
select {
case <-timer.C:
return true
case <-tick:
tick = nil
go func() { ch <- condition() }()
case <-tickC:
tickC = nil
go checkCond()
case v := <-ch:
if v {
return Fail(t, "Condition satisfied", msgAndArgs...)
}
tick = ticker.C
tickC = ticker.C
}
}
}
@ -2039,9 +2171,12 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
var expectedText string
if target != nil {
expectedText = target.Error()
if err == nil {
return Fail(t, fmt.Sprintf("Expected error with %q in chain but got nil.", expectedText), msgAndArgs...)
}
}
chain := buildErrorChainString(err)
chain := buildErrorChainString(err, false)
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
"expected: %q\n"+
@ -2049,7 +2184,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
), 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.
func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
@ -2064,7 +2199,7 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
expectedText = target.Error()
}
chain := buildErrorChainString(err)
chain := buildErrorChainString(err, false)
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
"found: %q\n"+
@ -2082,24 +2217,70 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
return true
}
chain := buildErrorChainString(err)
expectedText := reflect.ValueOf(target).Elem().Type().String()
if err == nil {
return Fail(t, fmt.Sprintf("An error is expected but got nil.\n"+
"expected: %s", expectedText), msgAndArgs...)
}
chain := buildErrorChainString(err, true)
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
"expected: %q\n"+
"in chain: %s", target, chain,
"expected: %s\n"+
"in chain: %s", expectedText, chain,
), 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 {
return ""
}
e := errors.Unwrap(err)
chain := fmt.Sprintf("%q", err.Error())
for e != nil {
chain += fmt.Sprintf("\n\t%q", e.Error())
e = errors.Unwrap(e)
var chain string
errs := unwrapAll(err)
for i := range errs {
if i != 0 {
chain += "\n\t"
}
chain += fmt.Sprintf("%q", errs[i].Error())
if withType {
chain += fmt.Sprintf(" (%T)", errs[i])
}
}
return chain
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,9 @@
// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
//
// # Note
//
// All functions in this package return a bool value indicating whether the assertion has passed.
//
// # Example Usage
//
// The following is a complete example using assert in a standard test function:

View File

@ -8,6 +8,8 @@ import (
)
func TestImplementsWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
@ -19,6 +21,8 @@ func TestImplementsWrapper(t *testing.T) {
}
func TestIsTypeWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
@ -31,6 +35,8 @@ func TestIsTypeWrapper(t *testing.T) {
}
func TestEqualWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.Equal("Hello World", "Hello World") {
@ -51,6 +57,8 @@ func TestEqualWrapper(t *testing.T) {
}
func TestEqualValuesWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.EqualValues(uint32(10), int32(10)) {
@ -59,6 +67,8 @@ func TestEqualValuesWrapper(t *testing.T) {
}
func TestNotNilWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.NotNil(new(AssertionTesterConformingObject)) {
@ -71,6 +81,8 @@ func TestNotNilWrapper(t *testing.T) {
}
func TestNilWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.Nil(nil) {
@ -83,6 +95,8 @@ func TestNilWrapper(t *testing.T) {
}
func TestTrueWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.True(true) {
@ -95,6 +109,8 @@ func TestTrueWrapper(t *testing.T) {
}
func TestFalseWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.False(false) {
@ -107,6 +123,8 @@ func TestFalseWrapper(t *testing.T) {
}
func TestExactlyWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
a := float32(1)
@ -134,6 +152,7 @@ func TestExactlyWrapper(t *testing.T) {
}
func TestNotEqualWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
@ -155,6 +174,7 @@ func TestNotEqualWrapper(t *testing.T) {
}
func TestNotEqualValuesWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
@ -179,6 +199,7 @@ func TestNotEqualValuesWrapper(t *testing.T) {
}
func TestContainsWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
list := []string{"Foo", "Bar"}
@ -200,6 +221,7 @@ func TestContainsWrapper(t *testing.T) {
}
func TestNotContainsWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
list := []string{"Foo", "Bar"}
@ -221,6 +243,7 @@ func TestNotContainsWrapper(t *testing.T) {
}
func TestConditionWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
@ -235,6 +258,7 @@ func TestConditionWrapper(t *testing.T) {
}
func TestDidPanicWrapper(t *testing.T) {
t.Parallel()
if funcDidPanic, _, _ := didPanic(func() {
panic("Panic!")
@ -250,6 +274,7 @@ func TestDidPanicWrapper(t *testing.T) {
}
func TestPanicsWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
@ -267,6 +292,7 @@ func TestPanicsWrapper(t *testing.T) {
}
func TestNotPanicsWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
@ -284,6 +310,8 @@ func TestNotPanicsWrapper(t *testing.T) {
}
func TestNoErrorWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -300,6 +328,8 @@ func TestNoErrorWrapper(t *testing.T) {
}
func TestErrorWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -316,6 +346,8 @@ func TestErrorWrapper(t *testing.T) {
}
func TestErrorContainsWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -335,6 +367,8 @@ func TestErrorContainsWrapper(t *testing.T) {
}
func TestEqualErrorWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -352,6 +386,8 @@ func TestEqualErrorWrapper(t *testing.T) {
}
func TestEmptyWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -370,6 +406,8 @@ func TestEmptyWrapper(t *testing.T) {
}
func TestNotEmptyWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -388,6 +426,8 @@ func TestNotEmptyWrapper(t *testing.T) {
}
func TestLenWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -428,6 +468,8 @@ func TestLenWrapper(t *testing.T) {
}
func TestWithinDurationWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
a := time.Now()
@ -447,6 +489,8 @@ func TestWithinDurationWrapper(t *testing.T) {
}
func TestInDeltaWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
@ -481,6 +525,8 @@ func TestInDeltaWrapper(t *testing.T) {
}
func TestInEpsilonWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
cases := []struct {
@ -519,6 +565,7 @@ func TestInEpsilonWrapper(t *testing.T) {
}
func TestRegexpWrapper(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
@ -546,7 +593,7 @@ func TestRegexpWrapper(t *testing.T) {
}
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))
True(t, assert.NotRegexp(tc.rx, tc.str))
True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
@ -554,6 +601,8 @@ func TestRegexpWrapper(t *testing.T) {
}
func TestZeroWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -567,6 +616,8 @@ func TestZeroWrapper(t *testing.T) {
}
func TestNotZeroWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -580,6 +631,8 @@ func TestNotZeroWrapper(t *testing.T) {
}
func TestJSONEqWrapper_EqualSONString(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) {
t.Error("JSONEq should return true")
@ -588,6 +641,8 @@ func TestJSONEqWrapper_EqualSONString(t *testing.T) {
}
func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return true")
@ -596,6 +651,8 @@ func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
}
func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") {
@ -604,6 +661,8 @@ func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
}
func TestJSONEqWrapper_Array(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) {
t.Error("JSONEq should return true")
@ -612,6 +671,8 @@ func TestJSONEqWrapper_Array(t *testing.T) {
}
func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) {
t.Error("JSONEq should return false")
@ -619,6 +680,8 @@ func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
}
func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return false")
@ -626,6 +689,8 @@ func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
}
func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") {
t.Error("JSONEq should return false")
@ -633,6 +698,8 @@ func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
}
func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return false")
@ -640,6 +707,8 @@ func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
}
func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.JSONEq("Not JSON", "Not JSON") {
t.Error("JSONEq should return false")
@ -647,6 +716,8 @@ func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
}
func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) {
t.Error("JSONEq should return false")
@ -654,6 +725,8 @@ func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
}
func TestYAMLEqWrapper_EqualYAMLString(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.YAMLEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) {
t.Error("YAMLEq should return true")
@ -662,6 +735,8 @@ func TestYAMLEqWrapper_EqualYAMLString(t *testing.T) {
}
func TestYAMLEqWrapper_EquivalentButNotEqual(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.YAMLEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("YAMLEq should return true")
@ -670,6 +745,8 @@ func TestYAMLEqWrapper_EquivalentButNotEqual(t *testing.T) {
}
func TestYAMLEqWrapper_HashOfArraysAndHashes(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
expected := `
numeric: 1.5
@ -702,6 +779,8 @@ array:
}
func TestYAMLEqWrapper_Array(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) {
t.Error("YAMLEq should return true")
@ -710,6 +789,8 @@ func TestYAMLEqWrapper_Array(t *testing.T) {
}
func TestYAMLEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) {
t.Error("YAMLEq should return false")
@ -717,6 +798,8 @@ func TestYAMLEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
}
func TestYAMLEqWrapper_HashesNotEquivalent(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.YAMLEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("YAMLEq should return false")
@ -724,6 +807,8 @@ func TestYAMLEqWrapper_HashesNotEquivalent(t *testing.T) {
}
func TestYAMLEqWrapper_ActualIsSimpleString(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.YAMLEq(`{"foo": "bar"}`, "Simple String") {
t.Error("YAMLEq should return false")
@ -731,6 +816,8 @@ func TestYAMLEqWrapper_ActualIsSimpleString(t *testing.T) {
}
func TestYAMLEqWrapper_ExpectedIsSimpleString(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.YAMLEq("Simple String", `{"foo": "bar", "hello": "world"}`) {
t.Error("YAMLEq should return false")
@ -738,6 +825,8 @@ func TestYAMLEqWrapper_ExpectedIsSimpleString(t *testing.T) {
}
func TestYAMLEqWrapper_ExpectedAndActualSimpleString(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if !assert.YAMLEq("Simple String", "Simple String") {
t.Error("YAMLEq should return true")
@ -745,6 +834,8 @@ func TestYAMLEqWrapper_ExpectedAndActualSimpleString(t *testing.T) {
}
func TestYAMLEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
t.Parallel()
assert := New(new(testing.T))
if assert.YAMLEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) {
t.Error("YAMLEq should return false")

View File

@ -138,7 +138,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
contains := strings.Contains(body, fmt.Sprint(str))
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
@ -158,7 +158,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin
contains := strings.Contains(body, fmt.Sprint(str))
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

View File

@ -31,6 +31,8 @@ func httpStatusCode(w http.ResponseWriter, r *http.Request) {
}
func TestHTTPSuccess(t *testing.T) {
t.Parallel()
assert := New(t)
mockT1 := new(testing.T)
@ -59,6 +61,8 @@ func TestHTTPSuccess(t *testing.T) {
}
func TestHTTPRedirect(t *testing.T) {
t.Parallel()
assert := New(t)
mockT1 := new(mockTestingT)
@ -83,6 +87,8 @@ func TestHTTPRedirect(t *testing.T) {
}
func TestHTTPError(t *testing.T) {
t.Parallel()
assert := New(t)
mockT1 := new(testing.T)
@ -107,6 +113,8 @@ func TestHTTPError(t *testing.T) {
}
func TestHTTPStatusCode(t *testing.T) {
t.Parallel()
assert := New(t)
mockT1 := new(testing.T)
@ -131,6 +139,8 @@ func TestHTTPStatusCode(t *testing.T) {
}
func TestHTTPStatusesWrapper(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))
@ -153,6 +163,8 @@ func httpHelloName(w http.ResponseWriter, r *http.Request) {
}
func TestHTTPRequestWithNoParams(t *testing.T) {
t.Parallel()
var got *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
got = r
@ -166,6 +178,8 @@ func TestHTTPRequestWithNoParams(t *testing.T) {
}
func TestHTTPRequestWithParams(t *testing.T) {
t.Parallel()
var got *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
got = r
@ -182,6 +196,8 @@ func TestHTTPRequestWithParams(t *testing.T) {
}
func TestHttpBody(t *testing.T) {
t.Parallel()
assert := New(t)
mockT := new(mockTestingT)
@ -201,6 +217,8 @@ func TestHttpBody(t *testing.T) {
}
func TestHttpBodyWrappers(t *testing.T) {
t.Parallel()
assert := New(t)
mockAssert := New(new(testing.T))

View File

@ -0,0 +1,24 @@
//go: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

View File

@ -0,0 +1,36 @@
//go: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)
}

17
assert/yaml/yaml_fail.go Normal file
View File

@ -0,0 +1,17 @@
//go: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
View File

@ -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.
//
// 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 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

View File

@ -80,12 +80,12 @@ type Call struct {
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{
Parent: parent,
Method: methodName,
Arguments: methodArguments,
ReturnArguments: make([]interface{}, 0),
ReturnArguments: returnArguments,
callerInfo: callerInfo,
Repeatability: 0,
WaitFor: nil,
@ -208,9 +208,16 @@ func (c *Call) On(methodName string, arguments ...interface{}) *Call {
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 {
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
// 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)
// )
func (c *Call) NotBefore(calls ...*Call) *Call {
@ -273,6 +280,20 @@ func (c *Call) NotBefore(calls ...*Call) *Call {
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.
// For an example of its usage, refer to the "Example Usage" section at the top
// of this document.
@ -317,7 +338,10 @@ func (m *Mock) TestData() objx.Map {
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) {
m.mutex.Lock()
defer m.mutex.Unlock()
@ -351,7 +375,8 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
m.mutex.Lock()
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)
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
if call != nil {
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
// as the return arguments. This is because:
@ -491,14 +516,15 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
m.mutex.Unlock()
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, closestCall.Arguments, true),
diffArguments(closestCall.Arguments, arguments),
strings.TrimSpace(mismatch),
assert.CallerInfo(),
)
} 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++
// 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()
// block if specified
@ -764,9 +790,17 @@ const (
)
// 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
// anythingOfTypeArgument is a string that contains the type of an argument
@ -780,53 +814,54 @@ type anythingOfTypeArgument string
//
// For example:
//
// Assert(t, AnythingOfType("string"), AnythingOfType("int"))
// args.Assert(t, AnythingOfType("string"), AnythingOfType("int"))
func AnythingOfType(t string) AnythingOfTypeArgument {
return anythingOfTypeArgument(t)
}
// IsTypeArgument is a struct that contains the type of an argument
// for use when type checking. This is an alternative to AnythingOfType.
// Used in Diff and Assert.
// for use when type checking. This is an alternative to [AnythingOfType].
// Used in [Arguments.Diff] and [Arguments.Assert].
type IsTypeArgument struct {
t reflect.Type
}
// 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
// alternative to AnythingOfType. Used in Diff and Assert.
// alternative to [AnythingOfType]. Used in [Arguments.Diff] and [Arguments.Assert].
//
// For example:
// Assert(t, IsType(""), IsType(0))
//
// args.Assert(t, IsType(""), IsType(0))
func IsType(t interface{}) *IsTypeArgument {
return &IsTypeArgument{t: reflect.TypeOf(t)}
}
// FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument
// for use when type checking.
// FunctionalOptionsArgument contains a list of functional options arguments
// expected for use when matching a list of arguments.
type FunctionalOptionsArgument struct {
value interface{}
values []interface{}
}
// String returns the string representation of FunctionalOptionsArgument
func (f *FunctionalOptionsArgument) String() string {
var name string
tValue := reflect.ValueOf(f.value)
if tValue.Len() > 0 {
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
if len(f.values) > 0 {
name = "[]" + reflect.TypeOf(f.values[0]).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
// and the values to check of
// FunctionalOptions returns an [FunctionalOptionsArgument] object containing
// the expected functional-options to check for.
//
// 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{
value: value,
values: values,
}
}
@ -873,10 +908,11 @@ func (f argumentMatcher) String() string {
// and false otherwise.
//
// Example:
// 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)
// which returns a bool. If |fn| doesn't match the required signature,
// 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)
// which returns a bool. If fn doesn't match the required signature,
// MatchedBy() panics.
func MatchedBy(fn interface{}) argumentMatcher {
fnType := reflect.TypeOf(fn)
@ -912,6 +948,8 @@ func (args Arguments) Is(objects ...interface{}) bool {
return true
}
type outputRenderer func() string
// Diff gets a string describing the differences between the arguments
// and the specified objects.
//
@ -919,7 +957,7 @@ func (args Arguments) Is(objects ...interface{}) bool {
func (args Arguments) Diff(objects []interface{}) (string, int) {
// TODO: could return string as error and nil for No difference
output := "\n"
var outputBuilder strings.Builder
var differences int
maxArgCount := len(args)
@ -927,24 +965,35 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
maxArgCount = len(objects)
}
outputRenderers := []outputRenderer{}
for i := 0; i < maxArgCount; i++ {
i := i
var actual, expected interface{}
var actualFmt, expectedFmt string
var actualFmt, expectedFmt func() string
if len(objects) <= i {
actual = "(Missing)"
actualFmt = "(Missing)"
actualFmt = func() string {
return "(Missing)"
}
} else {
actual = objects[i]
actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual)
actualFmt = func() string {
return fmt.Sprintf("(%[1]T=%[1]v)", actual)
}
}
if len(args) <= i {
expected = "(Missing)"
expectedFmt = "(Missing)"
expectedFmt = func() string {
return "(Missing)"
}
} else {
expected = args[i]
expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected)
expectedFmt = func() string {
return fmt.Sprintf("(%[1]T=%[1]v)", expected)
}
}
if matcher, ok := expected.(argumentMatcher); ok {
@ -952,16 +1001,22 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
func() {
defer func() {
if r := recover(); r != nil {
actualFmt = fmt.Sprintf("panic in argument matcher: %v", r)
actualFmt = func() string {
return fmt.Sprintf("panic in argument matcher: %v", r)
}
}
}()
matches = matcher.Matches(actual)
}()
if matches {
output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: PASS: %s matched by %s\n", i, actualFmt(), matcher)
})
} else {
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: FAIL: %s not matched by %s\n", i, actualFmt(), matcher)
})
}
} else {
switch expected := expected.(type) {
@ -970,46 +1025,57 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
if reflect.TypeOf(actual).Name() != string(expected) && reflect.TypeOf(actual).String() != string(expected) {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: FAIL: type %s != type %s - %s\n", i, expected, reflect.TypeOf(actual).Name(), actualFmt())
})
}
case *IsTypeArgument:
actualT := reflect.TypeOf(actual)
if actualT != expected.t {
differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: FAIL: type %s != type %s - %s\n", i, expected.t.Name(), actualT.Name(), actualFmt())
})
}
case *FunctionalOptionsArgument:
t := expected.value
var name string
tValue := reflect.ValueOf(t)
if tValue.Len() > 0 {
name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String()
if len(expected.values) > 0 {
name = "[]" + reflect.TypeOf(expected.values[0]).String()
}
tName := reflect.TypeOf(t).Name()
if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 {
const tName = "[]interface{}"
if name != reflect.TypeOf(actual).String() && len(expected.values) != 0 {
differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: FAIL: type %s != type %s - %s\n", i, tName, reflect.TypeOf(actual).Name(), actualFmt())
})
} else {
if ef, af := assertOpts(t, actual); ef == "" && af == "" {
if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" {
// match
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: PASS: %s == %s\n", i, tName, tName)
})
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: FAIL: %s != %s\n", i, af, ef)
})
}
}
default:
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
// match
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: PASS: %s == %s\n", i, actualFmt(), expectedFmt())
})
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
outputRenderers = append(outputRenderers, func() string {
return fmt.Sprintf("\t%d: FAIL: %s != %s\n", i, actualFmt(), expectedFmt())
})
}
}
}
@ -1020,7 +1086,12 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
return "No differences.", differences
}
return output, differences
outputBuilder.WriteString("\n")
for _, r := range outputRenderers {
outputBuilder.WriteString(r())
}
return outputBuilder.String(), differences
}
// Assert compares the arguments with the specified objects and fails if
@ -1092,7 +1163,7 @@ func (args Arguments) Error(index int) error {
return nil
}
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
}
@ -1181,32 +1252,38 @@ type tHelper interface {
func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
expectedOpts := reflect.ValueOf(expected)
actualOpts := reflect.ValueOf(actual)
var expectedFuncs []*runtime.Func
var expectedNames []string
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
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)
actualFmt = fmt.Sprintf("%v", actualNames)
return
}
for i := 0; i < expectedOpts.Len(); i++ {
expectedOpt := expectedOpts.Index(i).Interface()
actualOpt := actualOpts.Index(i).Interface()
expectedFunc := expectedNames[i]
actualFunc := actualNames[i]
if expectedFunc != actualFunc {
expectedFmt = expectedFunc
actualFmt = actualFunc
if !isFuncSame(expectedFuncs[i], actualFuncs[i]) {
expectedFmt = expectedNames[i]
actualFmt = actualNames[i]
return
}
expectedOpt := expectedOpts.Index(i).Interface()
actualOpt := actualOpts.Index(i).Interface()
ot := reflect.TypeOf(expectedOpt)
var expectedValues []reflect.Value
var actualValues []reflect.Value
@ -1224,9 +1301,9 @@ func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
reflect.ValueOf(actualOpt).Call(actualValues)
for i := 0; i < ot.NumIn(); i++ {
if !assert.ObjectsAreEqual(expectedValues[i].Interface(), actualValues[i].Interface()) {
expectedFmt = fmt.Sprintf("%s %+v", expectedNames[i], expectedValues[i].Interface())
actualFmt = fmt.Sprintf("%s %+v", expectedNames[i], actualValues[i].Interface())
if expectedArg, actualArg := expectedValues[i].Interface(), actualValues[i].Interface(); !assert.ObjectsAreEqual(expectedArg, actualArg) {
expectedFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], expectedArg, expectedArg)
actualFmt = fmt.Sprintf("%s(%T) -> %#v", expectedNames[i], actualArg, actualArg)
return
}
}
@ -1235,7 +1312,25 @@ func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) {
return "", ""
}
func funcName(opt interface{}) string {
n := runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name()
return strings.TrimSuffix(path.Base(n), path.Ext(n))
func runtimeFunc(opt interface{}) *runtime.Func {
return runtime.FuncForPC(reflect.ValueOf(opt).Pointer())
}
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
}

View File

@ -50,11 +50,22 @@ func OpStr(s string) OptionFn {
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 {
args := i.Called(x, opts)
return args.Error(0)
}
func TheExampleMethodFunctionalOptionsIndirect(i *TestExampleImplementation) {
i.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo"))
}
//go:noinline
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
i.Called(yesorno)
@ -121,6 +132,9 @@ type MockTestingT struct {
logfCount, errorfCount, failNowCount int
}
// Helper is like [testing.T.Helper] but does nothing.
func (MockTestingT) Helper() {}
const mockTestingTFailNowCalled = "FailNow was called"
func (m *MockTestingT) Logf(string, ...interface{}) {
@ -149,6 +163,7 @@ func (m *MockTestingT) FailNow() {
*/
func Test_Mock_TestData(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -160,6 +175,7 @@ func Test_Mock_TestData(t *testing.T) {
}
func Test_Mock_On(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -170,6 +186,8 @@ func Test_Mock_On(t *testing.T) {
}
func Test_Mock_Chained_On(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -201,6 +219,7 @@ func Test_Mock_Chained_On(t *testing.T) {
}
func Test_Mock_On_WithArgs(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -213,6 +232,7 @@ func Test_Mock_On_WithArgs(t *testing.T) {
}
func Test_Mock_On_WithFuncArg(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -234,6 +254,8 @@ func Test_Mock_On_WithFuncArg(t *testing.T) {
}
func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod",
@ -257,6 +279,8 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithArgMatcherThatPanics(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod2", MatchedBy(func(_ interface{}) bool {
@ -283,6 +307,8 @@ func Test_Mock_On_WithArgMatcherThatPanics(t *testing.T) {
}
func TestMock_WithTest(t *testing.T) {
t.Parallel()
var (
mockedService TestExampleImplementation
mockedTest MockTestingT
@ -311,6 +337,8 @@ func TestMock_WithTest(t *testing.T) {
}
func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod3",
@ -331,6 +359,8 @@ func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2")
@ -355,6 +385,8 @@ func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithInterfaceArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod4",
@ -365,6 +397,8 @@ func Test_Mock_On_WithInterfaceArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithChannelArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod5",
@ -375,6 +409,8 @@ func Test_Mock_On_WithChannelArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithMapArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod6",
@ -385,6 +421,8 @@ func Test_Mock_On_WithMapArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithSliceArgMatcher(t *testing.T) {
t.Parallel()
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod7",
@ -395,6 +433,7 @@ func Test_Mock_On_WithSliceArgMatcher(t *testing.T) {
}
func Test_Mock_On_WithVariadicFunc(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -417,6 +456,7 @@ func Test_Mock_On_WithVariadicFunc(t *testing.T) {
}
func Test_Mock_On_WithMixedVariadicFunc(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -440,6 +480,7 @@ func Test_Mock_On_WithMixedVariadicFunc(t *testing.T) {
}
func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -461,6 +502,7 @@ func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) {
}
func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -484,6 +526,8 @@ func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) {
}
func Test_Mock_On_WithFuncPanics(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -493,6 +537,7 @@ func Test_Mock_On_WithFuncPanics(t *testing.T) {
}
func Test_Mock_On_WithFuncTypeArg(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -512,6 +557,8 @@ func Test_Mock_On_WithFuncTypeArg(t *testing.T) {
}
func Test_Mock_Unset(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -540,6 +587,8 @@ func Test_Mock_Unset(t *testing.T) {
// Since every time you call On it creates a new object
// the last time you call Unset it will only unset the last call
func Test_Mock_Chained_UnsetOnlyUnsetsLastCall(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -574,6 +623,8 @@ func Test_Mock_Chained_UnsetOnlyUnsetsLastCall(t *testing.T) {
}
func Test_Mock_UnsetIfAlreadyUnsetFails(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -593,6 +644,8 @@ func Test_Mock_UnsetIfAlreadyUnsetFails(t *testing.T) {
}
func Test_Mock_UnsetByOnMethodSpec(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -614,6 +667,8 @@ func Test_Mock_UnsetByOnMethodSpec(t *testing.T) {
}
func Test_Mock_UnsetByOnMethodSpecAmongOthers(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -656,6 +711,8 @@ func Test_Mock_UnsetByOnMethodSpecAmongOthers(t *testing.T) {
}
func Test_Mock_Unset_WithFuncPanics(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
mock1 := mockedService.On("TheExampleMethod", 1)
@ -667,6 +724,7 @@ func Test_Mock_Unset_WithFuncPanics(t *testing.T) {
}
func Test_Mock_Return(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -691,6 +749,7 @@ func Test_Mock_Return(t *testing.T) {
}
func Test_Mock_Panic(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -714,6 +773,7 @@ func Test_Mock_Panic(t *testing.T) {
}
func Test_Mock_Return_WaitUntil(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -741,6 +801,7 @@ func Test_Mock_Return_WaitUntil(t *testing.T) {
}
func Test_Mock_Return_After(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -767,6 +828,7 @@ func Test_Mock_Return_After(t *testing.T) {
}
func Test_Mock_Return_Run(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -799,6 +861,8 @@ func Test_Mock_Return_Run(t *testing.T) {
}
func Test_Mock_Return_Run_Out_Of_Order(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
f := func(args Arguments) {
@ -824,6 +888,7 @@ func Test_Mock_Return_Run_Out_Of_Order(t *testing.T) {
}
func Test_Mock_Return_Once(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -848,6 +913,7 @@ func Test_Mock_Return_Once(t *testing.T) {
}
func Test_Mock_Return_Twice(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -873,6 +939,7 @@ func Test_Mock_Return_Twice(t *testing.T) {
}
func Test_Mock_Return_Times(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -898,6 +965,7 @@ func Test_Mock_Return_Times(t *testing.T) {
}
func Test_Mock_Return_Nothing(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -918,6 +986,8 @@ func Test_Mock_Return_Nothing(t *testing.T) {
}
func Test_Mock_Return_NotBefore_In_Order(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
b := mockedService.
@ -937,7 +1007,31 @@ func Test_Mock_Return_NotBefore_In_Order(t *testing.T) {
})
}
func Test_Mock_Return_InOrder_Uses_NotBefore(t *testing.T) {
t.Parallel()
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) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
b := mockedService.
@ -967,7 +1061,40 @@ TheExampleMethod(int,int,int)
})
}
func Test_Mock_Return_InOrder_Uses_NotBefore_Out_Of_Order(t *testing.T) {
t.Parallel()
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) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
b := mockedService.
@ -1001,6 +1128,8 @@ TheExampleMethod(int,int,int)
}
func Test_Mock_Return_NotBefore_Different_Mock_In_Order(t *testing.T) {
t.Parallel()
var (
mockedService1 = new(TestExampleImplementation)
mockedService2 = new(TestExampleImplementation)
@ -1022,7 +1151,10 @@ func Test_Mock_Return_NotBefore_Different_Mock_In_Order(t *testing.T) {
mockedService2.TheExampleMethod2(true)
})
}
func Test_Mock_Return_NotBefore_Different_Mock_Out_Of_Order(t *testing.T) {
t.Parallel()
var (
mockedService1 = new(TestExampleImplementation)
mockedService2 = new(TestExampleImplementation)
@ -1056,6 +1188,8 @@ TheExampleMethod(int,int,int)
}
func Test_Mock_Return_NotBefore_In_Order_With_Non_Dependant(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
a := mockedService.
@ -1096,6 +1230,8 @@ func Test_Mock_Return_NotBefore_In_Order_With_Non_Dependant(t *testing.T) {
}
func Test_Mock_Return_NotBefore_Orphan_Call(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
require.PanicsWithValue(t, "not before calls must be created with Mock.On()", func() {
@ -1107,6 +1243,7 @@ func Test_Mock_Return_NotBefore_Orphan_Call(t *testing.T) {
}
func Test_Mock_findExpectedCall(t *testing.T) {
t.Parallel()
m := new(Mock)
m.On("One", 1).Return("one")
@ -1126,6 +1263,7 @@ func Test_Mock_findExpectedCall(t *testing.T) {
}
func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) {
t.Parallel()
m := new(Mock)
m.On("One", 1).Return("one")
@ -1139,6 +1277,7 @@ func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) {
}
func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
t.Parallel()
m := new(Mock)
m.On("One", 1).Return("one")
@ -1169,6 +1308,7 @@ func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
}
func Test_callString(t *testing.T) {
t.Parallel()
assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false))
assert.Equal(t, `Method(<nil>)`, callString("Method", []interface{}{nil}, false))
@ -1176,6 +1316,7 @@ func Test_callString(t *testing.T) {
}
func Test_Mock_Called(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1203,10 +1344,11 @@ func asyncCall(m *Mock, ch chan Arguments) {
}
func Test_Mock_Called_blocks(t *testing.T) {
t.Parallel()
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)
@ -1215,7 +1357,7 @@ func Test_Mock_Called_blocks(t *testing.T) {
select {
case <-ch:
t.Fatal("should have waited")
case <-time.After(1 * time.Millisecond):
case <-time.After(10 * time.Millisecond):
}
returnArguments := <-ch
@ -1236,6 +1378,7 @@ func Test_Mock_Called_blocks(t *testing.T) {
}
func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1277,6 +1420,7 @@ func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
}
func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1293,6 +1437,7 @@ func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) {
}
func Test_Mock_Called_Unexpected(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1304,6 +1449,7 @@ func Test_Mock_Called_Unexpected(t *testing.T) {
}
func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
t.Parallel()
var mockedService1 = new(TestExampleImplementation)
var mockedService2 = new(TestExampleImplementation)
@ -1324,6 +1470,7 @@ func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
}
func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
t.Parallel()
var mockedService1 = new(TestExampleImplementation)
var mockedService2 = new(TestExampleImplementation)
@ -1343,6 +1490,7 @@ func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
}
func Test_Mock_AssertExpectations(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1360,6 +1508,7 @@ func Test_Mock_AssertExpectations(t *testing.T) {
}
func Test_Mock_AssertExpectations_Placeholder_NoArgs(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1378,6 +1527,7 @@ func Test_Mock_AssertExpectations_Placeholder_NoArgs(t *testing.T) {
}
func Test_Mock_AssertExpectations_Placeholder(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1401,6 +1551,7 @@ func Test_Mock_AssertExpectations_Placeholder(t *testing.T) {
}
func Test_Mock_AssertExpectations_With_Pointers(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1422,6 +1573,7 @@ func Test_Mock_AssertExpectations_With_Pointers(t *testing.T) {
}
func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1439,6 +1591,7 @@ func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
}
func Test_Mock_AssertExpectationsFunctionalOptionsType(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1456,6 +1609,7 @@ func Test_Mock_AssertExpectationsFunctionalOptionsType(t *testing.T) {
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1472,7 +1626,56 @@ func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) {
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Indirectly(t *testing.T) {
t.Parallel()
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) {
t.Parallel()
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) {
t.Parallel()
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) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1494,6 +1697,7 @@ func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
}
func Test_Mock_AssertExpectations_Skipped_Test(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1504,6 +1708,7 @@ func Test_Mock_AssertExpectations_Skipped_Test(t *testing.T) {
}
func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1523,6 +1728,7 @@ func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
}
func Test_Mock_AssertNumberOfCalls(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1537,6 +1743,7 @@ func Test_Mock_AssertNumberOfCalls(t *testing.T) {
}
func Test_Mock_AssertCalled(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1549,6 +1756,7 @@ func Test_Mock_AssertCalled(t *testing.T) {
}
func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1563,6 +1771,7 @@ func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
}
func Test_Mock_AssertCalled_WithArguments(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1577,6 +1786,7 @@ func Test_Mock_AssertCalled_WithArguments(t *testing.T) {
}
func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1594,6 +1804,7 @@ func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) {
}
func Test_Mock_AssertNotCalled(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
@ -1606,6 +1817,8 @@ func Test_Mock_AssertNotCalled(t *testing.T) {
}
func Test_Mock_IsMethodCallable(t *testing.T) {
t.Parallel()
var mockedService = new(TestExampleImplementation)
arg := []Call{{Repeatability: 1}, {Repeatability: 2}}
@ -1625,6 +1838,8 @@ func Test_Mock_IsMethodCallable(t *testing.T) {
}
func TestIsArgsEqual(t *testing.T) {
t.Parallel()
var expected = Arguments{5, 3, 4, 6, 7, 2}
// Copy elements 1 to 5
@ -1638,6 +1853,8 @@ func TestIsArgsEqual(t *testing.T) {
}
func Test_Mock_AssertOptional(t *testing.T) {
t.Parallel()
// Optional called
var ms1 = new(TestExampleImplementation)
ms1.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil)
@ -1666,6 +1883,7 @@ func Test_Mock_AssertOptional(t *testing.T) {
Arguments helper methods
*/
func Test_Arguments_Get(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
@ -1676,6 +1894,7 @@ func Test_Arguments_Get(t *testing.T) {
}
func Test_Arguments_Is(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
@ -1685,6 +1904,7 @@ func Test_Arguments_Is(t *testing.T) {
}
func Test_Arguments_Diff(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"Hello World", 123, true})
var diff string
@ -1698,6 +1918,7 @@ func Test_Arguments_Diff(t *testing.T) {
}
func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
var diff string
@ -1710,6 +1931,7 @@ func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
}
func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
var count int
@ -1720,6 +1942,7 @@ func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) {
}
func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", Anything, true})
var count int
@ -1730,6 +1953,7 @@ func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) {
}
func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", AnythingOfType("int"), true})
var count int
@ -1740,6 +1964,7 @@ func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) {
}
func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", AnythingOfType("string"), true})
var count int
@ -1752,6 +1977,8 @@ func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
}
func Test_Arguments_Diff_WithIsTypeArgument(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", IsType(0), true})
var count int
_, count = args.Diff([]interface{}{"string", 123, true})
@ -1760,6 +1987,8 @@ func Test_Arguments_Diff_WithIsTypeArgument(t *testing.T) {
}
func Test_Arguments_Diff_WithIsTypeArgument_Failing(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", IsType(""), true})
var count int
var diff string
@ -1770,6 +1999,8 @@ func Test_Arguments_Diff_WithIsTypeArgument_Failing(t *testing.T) {
}
func Test_Arguments_Diff_WithArgMatcher(t *testing.T) {
t.Parallel()
matchFn := func(a int) bool {
return a == 123
}
@ -1793,6 +2024,7 @@ func Test_Arguments_Diff_WithArgMatcher(t *testing.T) {
}
func Test_Arguments_Assert(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
@ -1801,6 +2033,7 @@ func Test_Arguments_Assert(t *testing.T) {
}
func Test_Arguments_String_Representation(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
assert.Equal(t, `string,int,bool`, args.String())
@ -1808,6 +2041,7 @@ func Test_Arguments_String_Representation(t *testing.T) {
}
func Test_Arguments_String(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
assert.Equal(t, "string", args.String(0))
@ -1815,6 +2049,7 @@ func Test_Arguments_String(t *testing.T) {
}
func Test_Arguments_Error(t *testing.T) {
t.Parallel()
var err = errors.New("An Error")
var args = Arguments([]interface{}{"string", 123, true, err})
@ -1823,6 +2058,7 @@ func Test_Arguments_Error(t *testing.T) {
}
func Test_Arguments_Error_Nil(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true, nil})
assert.Equal(t, nil, args.Error(3))
@ -1830,6 +2066,7 @@ func Test_Arguments_Error_Nil(t *testing.T) {
}
func Test_Arguments_Int(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
assert.Equal(t, 123, args.Int(1))
@ -1837,6 +2074,7 @@ func Test_Arguments_Int(t *testing.T) {
}
func Test_Arguments_Bool(t *testing.T) {
t.Parallel()
var args = Arguments([]interface{}{"string", 123, true})
assert.Equal(t, true, args.Bool(2))
@ -1844,6 +2082,7 @@ func Test_Arguments_Bool(t *testing.T) {
}
func Test_WaitUntil_Parallel(t *testing.T) {
t.Parallel()
// make a test impl object
var mockedService = new(TestExampleImplementation)
@ -1870,6 +2109,8 @@ func Test_WaitUntil_Parallel(t *testing.T) {
}
func Test_MockMethodCalled(t *testing.T) {
t.Parallel()
m := new(Mock)
m.On("foo", "hello").Return("world")
@ -1880,6 +2121,8 @@ func Test_MockMethodCalled(t *testing.T) {
}
func Test_MockMethodCalled_Panic(t *testing.T) {
t.Parallel()
m := new(Mock)
m.On("foo", "hello").Panic("world panics")
@ -1889,6 +2132,8 @@ func Test_MockMethodCalled_Panic(t *testing.T) {
// Test to validate fix for racy concurrent call access in MethodCalled()
func Test_MockReturnAndCalledConcurrent(t *testing.T) {
t.Parallel()
iterations := 1000
m := &Mock{}
call := m.On("ConcurrencyTestMethod")
@ -1939,6 +2184,8 @@ func (tc *tCustomLogger) Errorf(format string, args ...interface{}) {
func (tc *tCustomLogger) FailNow() {}
func TestLoggingAssertExpectations(t *testing.T) {
t.Parallel()
m := new(timer)
m.On("GetTime", 0).Return("")
tcl := &tCustomLogger{t, []string{}, []string{}}
@ -1953,6 +2200,8 @@ func TestLoggingAssertExpectations(t *testing.T) {
}
func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
t.Parallel()
waitDuration := 1
total, waitMs := 5, time.Millisecond*time.Duration(waitDuration)
aTimer := new(timer)
@ -1977,10 +2226,12 @@ func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
}
func TestArgumentMatcherToPrintMismatch(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r != nil {
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)
}
}()
@ -1994,10 +2245,12 @@ func TestArgumentMatcherToPrintMismatch(t *testing.T) {
}
func TestArgumentMatcherToPrintMismatchWithReferenceType(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r != nil {
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)
}
}()
@ -2011,6 +2264,8 @@ func TestArgumentMatcherToPrintMismatchWithReferenceType(t *testing.T) {
}
func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod(int,int,int)`, `0: 1\s+1: 1\s+2: 2`, `0: 1\s+1: 1\s+2: 1`, `Diff: 0: PASS: \(int=1\) == \(int=1\)\s+1: PASS: \(int=1\) == \(int=1\)\s+2: FAIL: \(int=2\) != \(int=1\)`))
@ -2026,9 +2281,11 @@ func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
}
func TestClosestCallFavorsFirstMock(t *testing.T) {
t.Parallel()
defer func() {
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))
assert.Regexp(t, matchingExp, r)
}
@ -2042,9 +2299,11 @@ func TestClosestCallFavorsFirstMock(t *testing.T) {
}
func TestClosestCallUsesRepeatabilityToFindClosest(t *testing.T) {
t.Parallel()
defer func() {
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))
assert.Regexp(t, matchingExp, r)
}
@ -2062,6 +2321,8 @@ func TestClosestCallUsesRepeatabilityToFindClosest(t *testing.T) {
}
func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`GetTime(int)`, "0: 1", "0: 999", `Diff: 0: FAIL: \(int=1\) != \(int=999\)`))
@ -2076,32 +2337,44 @@ func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) {
}
func Test_isBetterMatchThanReturnsFalseIfCandidateCallIsNil(t *testing.T) {
t.Parallel()
assert.False(t, matchCandidate{}.isBetterMatchThan(matchCandidate{}))
}
func Test_isBetterMatchThanReturnsTrueIfOtherCandidateCallIsNil(t *testing.T) {
t.Parallel()
assert.True(t, matchCandidate{call: &Call{}}.isBetterMatchThan(matchCandidate{}))
}
func Test_isBetterMatchThanReturnsFalseIfDiffCountIsGreaterThanOther(t *testing.T) {
t.Parallel()
assert.False(t, matchCandidate{call: &Call{}, diffCount: 2}.isBetterMatchThan(matchCandidate{call: &Call{}, diffCount: 1}))
}
func Test_isBetterMatchThanReturnsTrueIfDiffCountIsLessThanOther(t *testing.T) {
t.Parallel()
assert.True(t, matchCandidate{call: &Call{}, diffCount: 1}.isBetterMatchThan(matchCandidate{call: &Call{}, diffCount: 2}))
}
func Test_isBetterMatchThanReturnsTrueIfRepeatabilityIsGreaterThanOther(t *testing.T) {
t.Parallel()
assert.True(t, matchCandidate{call: &Call{Repeatability: 1}, diffCount: 1}.isBetterMatchThan(matchCandidate{call: &Call{Repeatability: -1}, diffCount: 1}))
}
func Test_isBetterMatchThanReturnsFalseIfRepeatabilityIsLessThanOrEqualToOther(t *testing.T) {
t.Parallel()
assert.False(t, matchCandidate{call: &Call{Repeatability: 1}, diffCount: 1}.isBetterMatchThan(matchCandidate{call: &Call{Repeatability: 1}, diffCount: 1}))
}
func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string {
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)
}
@ -2111,6 +2384,8 @@ func ConcurrencyTestMethod(m *Mock) {
}
func TestConcurrentArgumentRead(t *testing.T) {
t.Parallel()
methodUnderTest := func(c caller, u user) {
go u.Use(c)
c.Call()

View File

@ -23,6 +23,8 @@
//
// The `require` package have same global functions as in the `assert` package,
// 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,
// allowing custom error messages to be appended to the message the assertion method outputs.

View File

@ -7,6 +7,8 @@ import (
)
func TestImplementsWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
@ -19,7 +21,23 @@ func TestImplementsWrapper(t *testing.T) {
}
}
func TestIsNotTypeWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.IsNotType(new(AssertionTesterNonConformingObject), new(AssertionTesterConformingObject))
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.IsNotType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestIsTypeWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
@ -32,6 +50,8 @@ func TestIsTypeWrapper(t *testing.T) {
}
func TestEqualWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Equal(1, 1)
@ -44,6 +64,8 @@ func TestEqualWrapper(t *testing.T) {
}
func TestNotEqualWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NotEqual(1, 2)
@ -56,6 +78,8 @@ func TestNotEqualWrapper(t *testing.T) {
}
func TestExactlyWrapper(t *testing.T) {
t.Parallel()
require := New(t)
a := float32(1)
@ -73,6 +97,8 @@ func TestExactlyWrapper(t *testing.T) {
}
func TestNotNilWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NotNil(t, new(AssertionTesterConformingObject))
@ -85,6 +111,8 @@ func TestNotNilWrapper(t *testing.T) {
}
func TestNilWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Nil(nil)
@ -97,6 +125,8 @@ func TestNilWrapper(t *testing.T) {
}
func TestTrueWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.True(true)
@ -109,6 +139,8 @@ func TestTrueWrapper(t *testing.T) {
}
func TestFalseWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.False(false)
@ -121,6 +153,8 @@ func TestFalseWrapper(t *testing.T) {
}
func TestContainsWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Contains("Hello World", "Hello")
@ -133,6 +167,8 @@ func TestContainsWrapper(t *testing.T) {
}
func TestNotContainsWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NotContains("Hello World", "Hello!")
@ -145,6 +181,8 @@ func TestNotContainsWrapper(t *testing.T) {
}
func TestPanicsWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Panics(func() {
panic("Panic!")
@ -159,6 +197,8 @@ func TestPanicsWrapper(t *testing.T) {
}
func TestNotPanicsWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NotPanics(func() {})
@ -173,6 +213,8 @@ func TestNotPanicsWrapper(t *testing.T) {
}
func TestNoErrorWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NoError(nil)
@ -185,6 +227,8 @@ func TestNoErrorWrapper(t *testing.T) {
}
func TestErrorWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Error(errors.New("some error"))
@ -197,6 +241,8 @@ func TestErrorWrapper(t *testing.T) {
}
func TestErrorContainsWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.ErrorContains(errors.New("some error: another error"), "some error")
@ -209,6 +255,8 @@ func TestErrorContainsWrapper(t *testing.T) {
}
func TestEqualErrorWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.EqualError(errors.New("some error"), "some error")
@ -221,6 +269,8 @@ func TestEqualErrorWrapper(t *testing.T) {
}
func TestEmptyWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Empty("")
@ -233,6 +283,8 @@ func TestEmptyWrapper(t *testing.T) {
}
func TestNotEmptyWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NotEmpty("x")
@ -245,6 +297,8 @@ func TestNotEmptyWrapper(t *testing.T) {
}
func TestWithinDurationWrapper(t *testing.T) {
t.Parallel()
require := New(t)
a := time.Now()
b := a.Add(10 * time.Second)
@ -260,6 +314,8 @@ func TestWithinDurationWrapper(t *testing.T) {
}
func TestInDeltaWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.InDelta(1.001, 1, 0.01)
@ -272,6 +328,8 @@ func TestInDeltaWrapper(t *testing.T) {
}
func TestZeroWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.Zero(0)
@ -284,6 +342,8 @@ func TestZeroWrapper(t *testing.T) {
}
func TestNotZeroWrapper(t *testing.T) {
t.Parallel()
require := New(t)
require.NotZero(1)
@ -296,6 +356,8 @@ func TestNotZeroWrapper(t *testing.T) {
}
func TestJSONEqWrapper_EqualSONString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -306,6 +368,8 @@ func TestJSONEqWrapper_EqualSONString(t *testing.T) {
}
func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -316,6 +380,8 @@ func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
}
func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -327,6 +393,8 @@ func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
}
func TestJSONEqWrapper_Array(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -337,6 +405,8 @@ func TestJSONEqWrapper_Array(t *testing.T) {
}
func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -347,6 +417,8 @@ func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
}
func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -357,6 +429,8 @@ func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
}
func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -367,6 +441,8 @@ func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
}
func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -377,6 +453,8 @@ func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
}
func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -387,6 +465,8 @@ func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
}
func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -397,6 +477,8 @@ func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
}
func TestYAMLEqWrapper_EqualYAMLString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -407,6 +489,8 @@ func TestYAMLEqWrapper_EqualYAMLString(t *testing.T) {
}
func TestYAMLEqWrapper_EquivalentButNotEqual(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -417,6 +501,8 @@ func TestYAMLEqWrapper_EquivalentButNotEqual(t *testing.T) {
}
func TestYAMLEqWrapper_HashOfArraysAndHashes(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -453,6 +539,8 @@ array:
}
func TestYAMLEqWrapper_Array(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -463,6 +551,8 @@ func TestYAMLEqWrapper_Array(t *testing.T) {
}
func TestYAMLEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -473,6 +563,8 @@ func TestYAMLEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
}
func TestYAMLEqWrapper_HashesNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -483,6 +575,8 @@ func TestYAMLEqWrapper_HashesNotEquivalent(t *testing.T) {
}
func TestYAMLEqWrapper_ActualIsSimpleString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -493,6 +587,8 @@ func TestYAMLEqWrapper_ActualIsSimpleString(t *testing.T) {
}
func TestYAMLEqWrapper_ExpectedIsSimpleString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -503,6 +599,8 @@ func TestYAMLEqWrapper_ExpectedIsSimpleString(t *testing.T) {
}
func TestYAMLEqWrapper_ExpectedAndActualSimpleString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)
@ -513,6 +611,8 @@ func TestYAMLEqWrapper_ExpectedAndActualSimpleString(t *testing.T) {
}
func TestYAMLEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
t.Parallel()
mockT := new(MockT)
mockRequire := New(mockT)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
{{.Comment}}
{{ replace .Comment "assert." "require."}}
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
if h, ok := t.(tHelper); ok { h.Helper() }
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }

View File

@ -187,8 +187,8 @@ func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface
EqualExportedValuesf(a.t, expected, actual, msg, args...)
}
// EqualValues asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValues(uint32(123), int32(123))
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...)
}
// EqualValuesf asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
@ -225,10 +225,8 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if a.Error(err) {
// assert.Equal(t, expectedError, err)
// }
// actualObj, err := SomeFunction()
// a.Error(err)
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -298,10 +296,8 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if a.Errorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err)
// }
// actualObj, err := SomeFunction()
// a.Errorf(err, "error message %s", "formatted")
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -337,7 +333,7 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti
// a.EventuallyWithT(func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 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{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -362,7 +358,7 @@ func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), w
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 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{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -869,7 +865,29 @@ func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...in
IsNonIncreasingf(a.t, object, msg, args...)
}
// IsNotType asserts that the specified objects are not of the same type.
//
// a.IsNotType(&NotMyStruct{}, &MyStruct{})
func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNotType(a.t, theType, object, msgAndArgs...)
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNotTypef(a.t, theType, object, msg, args...)
}
// IsType asserts that the specified objects are of the same type.
//
// a.IsType(&MyStruct{}, &MyStruct{})
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -878,6 +896,8 @@ func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAnd
}
// IsTypef asserts that the specified objects are of the same type.
//
// a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1129,6 +1149,40 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
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
// a slice or a channel with len == 0.
//
@ -1201,7 +1255,25 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
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.
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
@ -1210,7 +1282,7 @@ func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface
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.
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
@ -1327,12 +1399,15 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri
NotSamef(a.t, expected, actual, msg, args...)
}
// NotSubset asserts that the specified list(array, slice...) or map does NOT
// contain all elements given in the specified subset list(array, slice...) or
// map.
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubset([1, 3, 4], [1, 2])
// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
// a.NotSubset([1, 3, 4], {1: "one", 2: "two"})
// a.NotSubset({"x": 1, "y": 2}, ["z"])
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1340,12 +1415,15 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
NotSubset(a.t, list, subset, msgAndArgs...)
}
// NotSubsetf asserts that the specified list(array, slice...) or map does NOT
// contain all elements given in the specified subset list(array, slice...) or
// map.
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1505,11 +1583,15 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string,
Samef(a.t, expected, actual, msg, args...)
}
// Subset asserts that the specified list(array, slice...) or map contains all
// elements given in the specified subset list(array, slice...) or map.
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subset([1, 2, 3], [1, 2])
// a.Subset({"x": 1, "y": 2}, {"x": 1})
// a.Subset([1, 2, 3], {1: "one", 2: "two"})
// a.Subset({"x": 1, "y": 2}, ["x"])
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -1517,11 +1599,15 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
Subset(a.t, list, subset, msgAndArgs...)
}
// Subsetf asserts that the specified list(array, slice...) or map contains all
// elements given in the specified subset list(array, slice...) or map.
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()

View File

@ -6,7 +6,7 @@ type TestingT interface {
FailNow()
}
type tHelper interface {
type tHelper = interface {
Helper()
}

View File

@ -5,6 +5,8 @@ import (
"errors"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
// AssertionTesterInterface defines an interface to be used for testing assertion methods
@ -27,6 +29,9 @@ type MockT struct {
Failed bool
}
// Helper is like [testing.T.Helper] but does nothing.
func (MockT) Helper() {}
func (t *MockT) FailNow() {
t.Failed = true
}
@ -36,6 +41,7 @@ func (t *MockT) Errorf(format string, args ...interface{}) {
}
func TestImplements(t *testing.T) {
t.Parallel()
Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
@ -47,6 +53,7 @@ func TestImplements(t *testing.T) {
}
func TestIsType(t *testing.T) {
t.Parallel()
IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
@ -58,6 +65,7 @@ func TestIsType(t *testing.T) {
}
func TestEqual(t *testing.T) {
t.Parallel()
Equal(t, 1, 1)
@ -70,6 +78,7 @@ func TestEqual(t *testing.T) {
}
func TestNotEqual(t *testing.T) {
t.Parallel()
NotEqual(t, 1, 2)
mockT := new(MockT)
@ -80,6 +89,7 @@ func TestNotEqual(t *testing.T) {
}
func TestExactly(t *testing.T) {
t.Parallel()
a := float32(1)
b := float32(1)
@ -95,6 +105,7 @@ func TestExactly(t *testing.T) {
}
func TestNotNil(t *testing.T) {
t.Parallel()
NotNil(t, new(AssertionTesterConformingObject))
@ -106,6 +117,7 @@ func TestNotNil(t *testing.T) {
}
func TestNil(t *testing.T) {
t.Parallel()
Nil(t, nil)
@ -117,6 +129,7 @@ func TestNil(t *testing.T) {
}
func TestTrue(t *testing.T) {
t.Parallel()
True(t, true)
@ -128,6 +141,7 @@ func TestTrue(t *testing.T) {
}
func TestFalse(t *testing.T) {
t.Parallel()
False(t, false)
@ -139,6 +153,7 @@ func TestFalse(t *testing.T) {
}
func TestContains(t *testing.T) {
t.Parallel()
Contains(t, "Hello World", "Hello")
@ -150,6 +165,7 @@ func TestContains(t *testing.T) {
}
func TestNotContains(t *testing.T) {
t.Parallel()
NotContains(t, "Hello World", "Hello!")
@ -161,6 +177,7 @@ func TestNotContains(t *testing.T) {
}
func TestPanics(t *testing.T) {
t.Parallel()
Panics(t, func() {
panic("Panic!")
@ -174,6 +191,7 @@ func TestPanics(t *testing.T) {
}
func TestNotPanics(t *testing.T) {
t.Parallel()
NotPanics(t, func() {})
@ -187,6 +205,7 @@ func TestNotPanics(t *testing.T) {
}
func TestNoError(t *testing.T) {
t.Parallel()
NoError(t, nil)
@ -198,6 +217,7 @@ func TestNoError(t *testing.T) {
}
func TestError(t *testing.T) {
t.Parallel()
Error(t, errors.New("some error"))
@ -209,6 +229,7 @@ func TestError(t *testing.T) {
}
func TestErrorContains(t *testing.T) {
t.Parallel()
ErrorContains(t, errors.New("some error: another error"), "some error")
@ -220,6 +241,7 @@ func TestErrorContains(t *testing.T) {
}
func TestEqualError(t *testing.T) {
t.Parallel()
EqualError(t, errors.New("some error"), "some error")
@ -231,6 +253,7 @@ func TestEqualError(t *testing.T) {
}
func TestEmpty(t *testing.T) {
t.Parallel()
Empty(t, "")
@ -242,6 +265,7 @@ func TestEmpty(t *testing.T) {
}
func TestNotEmpty(t *testing.T) {
t.Parallel()
NotEmpty(t, "x")
@ -253,6 +277,7 @@ func TestNotEmpty(t *testing.T) {
}
func TestWithinDuration(t *testing.T) {
t.Parallel()
a := time.Now()
b := a.Add(10 * time.Second)
@ -267,6 +292,7 @@ func TestWithinDuration(t *testing.T) {
}
func TestInDelta(t *testing.T) {
t.Parallel()
InDelta(t, 1.001, 1, 0.01)
@ -278,6 +304,7 @@ func TestInDelta(t *testing.T) {
}
func TestZero(t *testing.T) {
t.Parallel()
Zero(t, "")
@ -289,6 +316,7 @@ func TestZero(t *testing.T) {
}
func TestNotZero(t *testing.T) {
t.Parallel()
NotZero(t, "x")
@ -300,6 +328,8 @@ func TestNotZero(t *testing.T) {
}
func TestJSONEq_EqualSONString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
if mockT.Failed {
@ -308,6 +338,8 @@ func TestJSONEq_EqualSONString(t *testing.T) {
}
func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if mockT.Failed {
@ -316,6 +348,8 @@ func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
}
func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
@ -325,6 +359,8 @@ func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
}
func TestJSONEq_Array(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
if mockT.Failed {
@ -333,6 +369,8 @@ func TestJSONEq_Array(t *testing.T) {
}
func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
if !mockT.Failed {
@ -341,6 +379,8 @@ func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
}
func TestJSONEq_HashesNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
@ -349,6 +389,8 @@ func TestJSONEq_HashesNotEquivalent(t *testing.T) {
}
func TestJSONEq_ActualIsNotJSON(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")
if !mockT.Failed {
@ -357,6 +399,8 @@ func TestJSONEq_ActualIsNotJSON(t *testing.T) {
}
func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
@ -365,6 +409,8 @@ func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
}
func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, "Not JSON", "Not JSON")
if !mockT.Failed {
@ -373,6 +419,8 @@ func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
}
func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
t.Parallel()
mockT := new(MockT)
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)
if !mockT.Failed {
@ -381,6 +429,8 @@ func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
}
func TestYAMLEq_EqualYAMLString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
if mockT.Failed {
@ -389,6 +439,8 @@ func TestYAMLEq_EqualYAMLString(t *testing.T) {
}
func TestYAMLEq_EquivalentButNotEqual(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if mockT.Failed {
@ -397,6 +449,8 @@ func TestYAMLEq_EquivalentButNotEqual(t *testing.T) {
}
func TestYAMLEq_HashOfArraysAndHashes(t *testing.T) {
t.Parallel()
mockT := new(MockT)
expected := `
numeric: 1.5
@ -430,6 +484,8 @@ array:
}
func TestYAMLEq_Array(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
if mockT.Failed {
@ -438,6 +494,8 @@ func TestYAMLEq_Array(t *testing.T) {
}
func TestYAMLEq_HashAndArrayNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
if !mockT.Failed {
@ -446,6 +504,8 @@ func TestYAMLEq_HashAndArrayNotEquivalent(t *testing.T) {
}
func TestYAMLEq_HashesNotEquivalent(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
@ -454,6 +514,8 @@ func TestYAMLEq_HashesNotEquivalent(t *testing.T) {
}
func TestYAMLEq_ActualIsSimpleString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `{"foo": "bar"}`, "Simple String")
if !mockT.Failed {
@ -462,6 +524,8 @@ func TestYAMLEq_ActualIsSimpleString(t *testing.T) {
}
func TestYAMLEq_ExpectedIsSimpleString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, "Simple String", `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
@ -470,6 +534,8 @@ func TestYAMLEq_ExpectedIsSimpleString(t *testing.T) {
}
func TestYAMLEq_ExpectedAndActualSimpleString(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, "Simple String", "Simple String")
if mockT.Failed {
@ -478,6 +544,8 @@ func TestYAMLEq_ExpectedAndActualSimpleString(t *testing.T) {
}
func TestYAMLEq_ArraysOfDifferentOrder(t *testing.T) {
t.Parallel()
mockT := new(MockT)
YAMLEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)
if !mockT.Failed {
@ -516,6 +584,8 @@ func ExampleComparisonAssertionFunc() {
}
func TestComparisonAssertionFunc(t *testing.T) {
t.Parallel()
type iface interface {
Name() string
}
@ -577,6 +647,8 @@ func ExampleValueAssertionFunc() {
}
func TestValueAssertionFunc(t *testing.T) {
t.Parallel()
tests := []struct {
name string
value interface{}
@ -623,6 +695,8 @@ func ExampleBoolAssertionFunc() {
}
func TestBoolAssertionFunc(t *testing.T) {
t.Parallel()
tests := []struct {
name string
value bool
@ -666,6 +740,8 @@ func ExampleErrorAssertionFunc() {
}
func TestErrorAssertionFunc(t *testing.T) {
t.Parallel()
tests := []struct {
name string
err error
@ -681,3 +757,34 @@ func TestErrorAssertionFunc(t *testing.T) {
})
}
}
func TestEventuallyWithTFalse(t *testing.T) {
t.Parallel()
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) {
t.Parallel()
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")
}

View File

@ -5,6 +5,8 @@
// or individual tests (depending on which interface(s) you
// implement).
//
// The suite package does not support parallel tests. See [issue 934].
//
// A testing suite is usually built by first extending the built-in
// suite functionality from suite.Suite in testify. Alternatively,
// you could reproduce that logic on your own if you wanted (you
@ -63,4 +65,6 @@
// func TestExampleTestSuite(t *testing.T) {
// suite.Run(t, new(ExampleTestSuite))
// }
//
// [issue 934]: https://github.com/stretchr/testify/issues/934
package suite

View File

@ -27,3 +27,14 @@ func TestPassedReturnsFalseWhenSomeTestFails(t *testing.T) {
assert.False(t, sinfo.Passed())
}
func TestPassedReturnsFalseWhenAllTestsFail(t *testing.T) {
sinfo := newSuiteInformation()
sinfo.TestStats = map[string]*TestInformation{
"Test1": {TestName: "Test1", Passed: false},
"Test2": {TestName: "Test2", Passed: false},
"Test3": {TestName: "Test3", Passed: false},
}
assert.False(t, sinfo.Passed())
}

View File

@ -15,7 +15,6 @@ import (
"github.com/stretchr/testify/require"
)
var allTestsFilter = func(_, _ string) (bool, error) { return true, nil }
var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run")
// Suite is a basic testing suite with methods for storing and
@ -116,6 +115,11 @@ func (suite *Suite) Run(name string, subtest func()) bool {
})
}
type test = struct {
name string
run func(t *testing.T)
}
// Run takes a testing suite and runs all of the tests attached
// to it.
func Run(t *testing.T, suite TestingSuite) {
@ -131,7 +135,7 @@ func Run(t *testing.T, suite TestingSuite) {
stats = newSuiteInformation()
}
tests := []testing.InternalTest{}
var tests []test
methodFinder := reflect.TypeOf(suite)
suiteName := methodFinder.Elem().Name()
@ -160,9 +164,9 @@ func Run(t *testing.T, suite TestingSuite) {
suiteSetupDone = true
}
test := testing.InternalTest{
Name: method.Name,
F: func(t *testing.T) {
test := test{
name: method.Name,
run: func(t *testing.T) {
parentT := suite.T()
suite.SetT(t)
defer recoverAndFailOnPanic(t)
@ -229,25 +233,13 @@ func methodFilter(name string) (bool, error) {
return regexp.MatchString(*matchMethod, name)
}
func runTests(t testing.TB, tests []testing.InternalTest) {
func runTests(t *testing.T, tests []test) {
if len(tests) == 0 {
t.Log("warning: no tests to run")
return
}
r, ok := t.(runner)
if !ok { // backwards compatibility with Go 1.6 and below
if !testing.RunTests(allTestsFilter, tests) {
t.Fail()
}
return
}
for _, test := range tests {
r.Run(test.Name, test.F)
t.Run(test.name, test.run)
}
}
type runner interface {
Run(name string, f func(t *testing.T)) bool
}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"errors"
"flag"
"io/ioutil"
"io"
"math/rand"
"os"
"os/exec"
@ -16,6 +16,11 @@ import (
"github.com/stretchr/testify/require"
)
// allTestsFilter is a yes filter for testing.RunTests
func allTestsFilter(pat, str string) (bool, error) {
return true, nil
}
// SuiteRequireTwice is intended to test the usage of suite.Require in two
// different tests
type SuiteRequireTwice struct{ Suite }
@ -440,7 +445,7 @@ func (sc *StdoutCapture) StopCapture() (string, error) {
}
os.Stdout.Close()
os.Stdout = sc.oldStdout
bytes, err := ioutil.ReadAll(sc.readPipe)
bytes, err := io.ReadAll(sc.readPipe)
if err != nil {
return "", err
}
@ -604,14 +609,44 @@ func TestFailfastSuite(t *testing.T) {
}},
)
assert.False(t, ok)
var expect []string
if failFast {
// 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 {
// 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) {
// 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")