Compare commits

...

283 Commits

Author SHA1 Message Date
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
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 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
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
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
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 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 0b4ff03cda
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
Bracken bb548d0473
Merge pull request #1552 from stretchr/dependabot/go_modules/github.com/stretchr/objx-0.5.2
build(deps): bump github.com/stretchr/objx from 0.5.1 to 0.5.2
2024-02-29 14:36:18 +00:00
dependabot[bot] 814075f391
build(deps): bump github.com/stretchr/objx from 0.5.1 to 0.5.2
Bumps [github.com/stretchr/objx](https://github.com/stretchr/objx) from 0.5.1 to 0.5.2.
- [Release notes](https://github.com/stretchr/objx/releases)
- [Commits](https://github.com/stretchr/objx/compare/v0.5.1...v0.5.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/objx
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-29 11:18:15 +00:00
Bracken e045612245
Merge pull request #1339 from bogdandrutu/uintptr
Add support to compare uintptr
2024-02-28 16:20:56 +00:00
Bracken 5b6926d686
Merge pull request #1385 from hslatman/not-implements
Add `NotImplements` and variants
2024-02-28 16:02:08 +00:00
Bracken 9f97d67703
Merge pull request #1550 from stretchr/release-notes
Include the auto-release notes in releases
2024-02-28 09:53:47 +00:00
Bracken Dawson bcb0d3fe49
Include the auto-release notes in releases 2024-02-27 16:35:20 +00:00
Bracken fb770f8238
Merge pull request #1247 from ccoVeille/typos
fix typos in comments and tests
2024-02-25 11:59:52 +00:00
ccoVeille 85d8bb6eea
fix typos in comments, tests and github templates 2024-02-24 23:48:24 +01:00
Bracken e2741fa4e9
Merge pull request #1548 from arjunmahishi/msgAndArgs
http_assertions: honour the msgAndArgs provided with each assertion
2024-02-23 17:40:20 +00:00
Arjun Mahishi 6e59f20c0d http_assertions: assert that the msgAndArgs actually works in tests
This commit also adds the method `Failed() bool` to the mockTestingT
struct. This is usefull for asserting failure in tests
2024-02-23 22:41:24 +05:30
Arjun Mahishi 840f800f1a http_assertions: Include msgAndArgs is some of the existing tests
A mix of using and not using msgAndArgs will ensure that there is no
regression.
2024-02-23 21:20:50 +05:30
Bracken e65c014fc9
Merge pull request #1248 from guettli/patch-1
README: drop link to gorc
2024-02-23 12:59:46 +00:00
Arjun Mahishi 135b468c5a assert: honour the msgAndArgs provided in InEpsilon 2024-02-23 00:23:39 +05:30
Arjun Mahishi ecdde720b4 http_assertions: honour the msgAndArgs provided with each assertion 2024-02-23 00:16:29 +05:30
Bracken 9f0ad86b78
Merge pull request #1517 from Lucaber/equalExportedValues-ptr
Support Pointer to Struct in EqualExportedValues
2024-02-22 17:16:44 +00:00
Bracken 7c847e2503
Merge pull request #1545 from hendrywiranto/update-setupgo-v5
Update Github workflows setup-go to V5
2024-02-21 23:13:52 +00:00
hendry.wiranto 898b77d0bb try to update to v5 2024-02-21 22:31:33 +07:00
Bracken 7caada5a3b
Merge pull request #1540 from stretchr/build-badge
Update the build status badge
2024-02-20 16:23:09 +00:00
Bracken Dawson e099480d59
Update the build status badge 2024-02-20 12:36:59 +00:00
Bracken 4b9af26649
Merge pull request #1538 from stretchr/issue-templates
[chore] Add issue templates
2024-02-20 10:18:57 +00:00
Arjun Mahishi a5087d7793 [chore] Issue templates: Add link to the discussion page 2024-02-20 11:20:33 +05:30
Arjun Mahishi bd22f81c8f [chore] Issue templates: Switch from bold to H2 headings 2024-02-19 22:53:39 +05:30
Arjun Mahishi 28efcd1170 [chore] Fix typos and improve hints in the issue templates 2024-02-19 22:49:15 +05:30
Bracken fef12e7dc3
Merge pull request #1537 from stretchr/fix-time-equal
Revert "assert: ObjectsAreEqual: use time.Equal for time.Time type"
2024-02-19 12:42:59 +00:00
Arjun Mahishi 5ed61202ae
[chore] Add issue templates 2024-02-19 10:33:44 +05:30
Bracken Dawson 7b3de08425
Revert "assert: ObjectsAreEqual: use time.Equal for time.Time type"
This reverts commit 34763e0df3.

time.Time.Equal only tests that the two instances refer to the same instant, but time.Time also carries zone information, so this caused two non-equal instances to be considered equal.
2024-02-18 20:43:45 +00:00
Bracken 14ffa908e6
Merge pull request #1535 from arjunmahishi/fix-suit-deadlock
suite: fix deadlock in suite.Require()/Assert()
2024-02-18 18:34:49 +00:00
Arjun Mahishi c41592ba5f suite: fix deadlock in suite.Require()/Assert()
As pointed out in issue #1520, if the suite is not initialised properly
(buy calling the Run function), then calling suite.Require() or
suite.Assert() will result in a deadlock.

This commit fixes that by panicking if the suite is not initialised
properly. This is justified because, the suite is intended to be
triggered in the right way. If the user does not do that, this panic will
nudge them in the right direction.

It has to be a panic because, at this point, we don't have access to any
testing.T context to gracefully call a t.Fail(). Also, these two
functions are not expected to return an error.

Fixes #1520
2024-02-18 23:55:01 +05:30
Bracken c719de3088
Merge pull request #1331 from ianrose14/ianrose/assertexpectations-skipped
Ensure AssertExpectations does not fail in skipped tests
2024-02-17 17:50:13 +00:00
Bracken 0e75f9941b
Merge pull request #1485 from kevinburkesegment/len-format
assert: better formatting for Len() error
2024-02-16 15:58:11 +00:00
Kevin Burke 89c0872acd
try to do the whole format string 2024-02-15 11:35:07 -07:00
Kevin Burke f6ed021e60
assert: shorten cases 2024-02-15 11:35:07 -07:00
Kevin Burke f7fedd9f85
assert: better formatting for Len() error
Previously, the use of %s with array objects meant you would get an
error like this:

    "[%!s(int=1) %!s(int=2) %!s(int=3)]\" should have 4 item(s), but has 3

Use %v instead, which provides a much nicer error.

    "[1 2 3]" should have 4 item(s), but has 3

Fixes #1482.
2024-02-15 11:35:07 -07:00
Bracken 5911e38e09
Merge pull request #1531 from arjunmahishi/fix-equal-values
assert: Fix EqualValues to handle overflow/underflow
2024-02-14 15:22:36 +00:00
Arjun Mahishi 4c4d0118a6 assert: Fix EqualValues to handle overflow/underflow
The underlying function ObjectsAreEqualValues did not handle
overflow/underflow of values while converting one type to another
for comparison. For example:

    EqualValues(t, int(270), int8(14))

would return true, even though the values are not equal. Because, when
you convert int(270) to int8, it overflows and becomes 14 (270 % 256 = 14)

This commit fixes that by making sure that the conversion always happens
from the smaller type to the larger type, and then comparing the values.
Additionally, this commit also seperates out the test cases of
ObjectsAreEqualValues from TestObjectsAreEqual.

Fixes #1462
2024-02-14 18:12:21 +05:30
Bracken d25ac14e7d
Merge pull request #1533 from brackendawson/maintainers
Update maintainers
2024-02-14 11:07:13 +00:00
Bracken Dawson d3b6816104
Add emeritus I missed 2024-02-13 23:35:29 +00:00
Bracken Dawson a67cee3a98
Update maintainers
I think I've captured the current list of active committers.
2024-02-13 17:02:43 +00:00
Sean Marciniak c3b0c9b4f5
Merge pull request #1502 from stretchr/suite-fix-reporting-of-panic-location
suite: fix recoverAndFailOnPanic to report test failure at the right location
2024-02-01 08:44:43 +10:30
Olivier Mengué 2be68b5e9e suite: fix recoverAndFailOnPanic to report at the right location
Add calls to t.Helper() to fix the location where the panic is reported
as a test failure.
2024-01-31 16:01:43 +01:00
Olivier Mengué b139300e7e
Merge pull request #1450 from stretchr/CI-go1.21
CI: use 'stable' and 'oldstable' indirections to refers to Go versions
2024-01-31 16:00:29 +01:00
Olivier Mengué c86e139511 CI: add go 1.21 2024-01-31 15:57:41 +01:00
Sean Marciniak 9b9a3b48b1
Merge pull request #1412 from stretchr/fix-flaky-TestEventuallyIssue805
assert: fix TestEventuallyTimeout
2024-01-26 13:58:29 +10:30
Sean Marciniak 0feb1d9baf
Merge branch 'master' into fix-flaky-TestEventuallyIssue805 2024-01-25 09:12:58 +10:30
Sean Marciniak 648a7937c5
Merge pull request #1416 from stretchr/mock-simplify-matcher-check
mock: optimize argument matching checks
2024-01-22 08:48:09 +10:30
Sean Marciniak 24e57f1a77
Merge pull request #1444 from stretchr/mock-refactor-TestIsArgsEqual
mock: refactor TestIsArgsEqual
2024-01-22 08:44:43 +10:30
Sean Marciniak 12f05f76ab
Merge pull request #1453 from stretchr/fix-1292-dep-cycle-with-objx
Fix dependency cycle with objx #1292
2024-01-22 08:44:18 +10:30
Sean Marciniak 14d4b9bcc6
Merge pull request #1483 from stretchr/fix-1231-InEpsilonSlice-expected-actual-order
assert.InEpsilonSlice: fix expected/actual order and other improvements
2024-01-22 08:43:45 +10:30
Sean Marciniak 92533fad9b
Merge pull request #1506 from stretchr/assert-simplify-isNil
assert: simplify isNil implementation
2024-01-22 08:39:01 +10:30
Sean Marciniak 1f53b4e175
Merge pull request #1505 from stretchr/more-unsafe.Pointer-tests
assert: improve unsafe.Pointer tests
2024-01-18 03:08:17 +10:30
Luca Berneking 74a35d55d5 Support Pointer to Struct in EqualExportedValues
This PRs allows to `EqualExportedValues` pointers to structs.
2023-12-08 12:42:36 +01:00
Olivier Mengué cbcc423cdf assert: simplify isNil implementation
Simpler and faster (also less allocations) in internal isNil().
2023-11-09 16:40:41 +01:00
Olivier Mengué 858080fbab assert: more unsafe.Pointer tests
1. Isolate tests that use the "unsafe" package in a separate package
   assert/internal/unsafetests. That way the assert package is not
   tainted with unsafe.
2. Remove one reference to the private assert.isNil() in assert tests.
3. Add more tests of assert.Nil and assert.NotNil with unsafe.Pointer.
2023-11-09 16:32:25 +01:00
Olivier Mengué db8608ed63
suite: fix subtest names (fix #1501) (#1504)
* suite: fix TestSubtestPanic failure (#1501)

The subtest of TestSubtestPanic is expected to fail, but that must not
make the testuite of package 'suite' to fail. So call Skip to make 'go
test' to ignore that expected failure.

* suite: fix subtests names

We are doing dirty things with testing.InternalTest. It looks like test
names should have the same prefix as the parent test, like if they were
true subtests (testing.T.Run).

So until we drop our usage of testing.InternamTest, let's rename the
tests.

Also added a few checks of the testing.RunTests result.
2023-11-09 10:44:27 +10:00
Craig Davison 331c520966 Improve readability 2023-10-31 15:54:18 +01:00
Craig Davison 5f48c62606 address some review comments 2023-10-31 15:54:18 +01:00
Craig Davison b7c378d6bd captureTestingT.checkResultAndErrMsg 2023-10-31 15:54:18 +01:00
Craig Davison 002647e9f8 TestErrorIs/TestNotErrorIs: check error contents 2023-10-31 15:54:18 +01:00
Justin Chadwell 5105b61304 Add map support doc comments to Subset and NotSubset
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-10-31 00:24:17 +01:00
Oleksandr Redko 43b2ef12b3 Change to use godoc 2023-10-31 00:07:12 +01:00
Oleksandr Redko 056e9e6bfa docs: Fix deprecation formatting for http 2023-10-31 00:07:12 +01:00
Ian Rose 1837f62a5f Ensure AssertExpectations does not fail in skipped tests 2023-10-31 00:00:55 +01:00
Olivier Mengué 21ba5d23bb
Merge branch 'master' into uintptr 2023-10-30 23:51:22 +01:00
Linus Barth 7df1a82a31 test: add suite tests for panicking of subtests 2023-10-30 22:51:08 +01:00
Linus Barth a4a54a4597 fix: panic behavior for subtests
This fix adds panic handling for subtests which will achieve:
- subtests will fail for the correct test context when panicking
- the test execution is not stopped; the next subtest will be executed
2023-10-30 22:51:08 +01:00
Linus Barth 65318c364a improve: tests for asserting test names in subtests 2023-10-30 22:51:08 +01:00
Linus Barth 130d340262 improve: move comment to msgAndArgs-param in test 2023-10-30 22:51:08 +01:00
Linus Barth 855d1c6784 test: testing.T correctness in subtests setup/teardown 2023-10-30 22:51:08 +01:00
Linus Barth 82022eeb0d test: call order of setup/teardown for subtests 2023-10-30 22:51:08 +01:00
Linus Barth 4526456fa4 improve: defer-style in Suite.Run() 2023-10-30 22:51:08 +01:00
Linus Barth 737a765d89 fix: SetupSubTest and TearDownSubTest execution order
There were two problems with the order of execution in the Suite.Run() method:
- One could not access the correct testing context ("s.T()") inside the SetupSubTest and TearDownSubTest methods. If the testing context was used for e.g. assertions of mocks in the TearDownSubTest, the results would not be "attached" to the correct test in the test output.
- The behavior was different to the order of execution for "root" tests (see lines 167-201) regarding the SetupTest and TearDownTest methods. This could confuse users of the library.

Also the logic to be deferred was joined together. This was fine beforehand because a panic in the TearDownSubTest would have had no influence on the "suite.SetT(oldT)". Now since a panic in the TearDownSubTest would lead to omitting the "suite.SetT(oldT)" this defer was split into two separate defers.
2023-10-30 22:51:08 +01:00
Oleksandr Redko 351d2776c6 Revert some changes 2023-10-30 22:41:11 +01:00
Oleksandr Redko 375474cd3c suite: refactor test assertions 2023-10-30 22:41:11 +01:00
Harald Nordgren fc1dee9921 Deprecate EqualExportedValues 2023-10-24 09:21:34 +02:00
Kevin Burke 7f962d56e4 .github: use latest Go versions
Also update the runners to their latest versions.
2023-10-24 09:10:36 +02:00
Olivier Mengué f8dcfd6618 assert.InEpsilonSlice: mention index of error in fail message 2023-10-18 18:46:08 +02:00
Olivier Mengué 7d383ba732 assert.InEpsilonSlice: refactor 2023-10-18 18:46:08 +02:00
Olivier Mengué f7fbc7da15 assert.InEpsilonSlice: fix order of expected vs actual (#1231) 2023-10-18 18:46:08 +02:00
Olivier Mengué 8fd5aae061 assert.InEpsilonSlice: remove redundant check
Remove check of actual's kind redundant with Type()'s check.
2023-10-18 18:46:08 +02:00
Olivier Mengué f728d3c50f assert.InEpsilonSlice: refactor
Remove multiple calls to reflect.Value.Len()
2023-10-18 18:46:08 +02:00
Olivier Mengué b5dec80529 assert.InEpsilonSlice: add more slice checks 2023-10-18 18:46:08 +02:00
Olivier Mengué ab3b9743a7 assert.InEpsilonSlice: refactor 2023-10-18 18:46:08 +02:00
Olivier Mengué 5dca985ff4 assert: remove logs in TestEventuallyTimeout 2023-10-16 21:14:11 +02:00
Olivier Mengué e8837d5396 assert: fix TestEventuallyTimeout
Fix TestEventuallyIssue805 which was flaky because of the use of a timer
that has exactly the same duration as the Eventually timout. But time is
not a synchronization primitive.

Now we use channels to ensure that the condition is still running and
Eventually times out before checking its return value.

The test is also renamed to TestEventuallyTimeout to more clearly show
its purpose.
2023-10-16 21:12:04 +02:00
Olivier Mengué f19cdfc9fe
Merge branch 'master' into patch-1 2023-10-16 19:23:14 +02:00
Herman Slatman 4e56e1ee06 Add `NotImplements` and variants 2023-10-16 14:27:51 +02:00
Olivier Mengué 307c9344b8 mock: refactor IsType
Reduce calls to reflect.Type in implementation of mock.IsType by
extracting the type early.

This also avoids to keep alive references to the argument value.
2023-10-16 13:57:23 +02:00
Olivier Mengué 413628c0f4 mock: simplify Arguments.Diff
Use a type switch instead of reflect.TypeOf comparisons.
2023-10-16 13:57:23 +02:00
Zachary Becker 4ae48e988c Combine switch cases, difference wrapped in if statement 2023-10-16 00:55:57 +02:00
Zachary Becker 2f7efa2451 Fix bug where array is treated as slice in EqualExportedValues 2023-10-16 00:55:57 +02:00
hidu ce5c2b684b assert: fix httpCode and HTTPBody occur panic when http.Handler read body 2023-10-15 23:34:32 +02:00
Grzegorz Burzyński 89920137cd collect errors from condition in defer 2023-10-13 08:53:17 +02:00
Grzegorz Burzyński 4ed68e1bca fix: make EventuallyWithT concurrency safe 2023-10-13 08:53:17 +02:00
dependabot[bot] 11a6452626 Bump actions/setup-go from 3.2.0 to 4.1.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3.2.0 to 4.1.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3.2.0...v4.1.0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-10 17:30:50 +02:00
dependabot[bot] c1ca192909 Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-10 17:25:08 +02:00
tscales 34763e0df3 assert: ObjectsAreEqual: use time.Equal for time.Time type 2023-10-10 17:14:01 +02:00
Oleksandr Redko 1ee798c140 Remove canConvert because Go 1.16 is dropped from support 2023-10-10 14:28:34 +02:00
Olivier Mengué 838caeaac1 deps: exclude old testify to break the dependency cycle from objx
In go.mod exclude the old version of testify brought by objx. This
allows to break the dependency cycle and completely remove the
dependency link to old versions of dependencies (some of which had
security issues).

Closes #1292.

go mod edit -exclude=github.com/stretchr/testify@v1.8.2 && go.mod
2023-08-09 16:24:51 +02:00
Olivier Mengué 975128c5e6 deps: upgrade objx to v0.5.1 to fix dep cycle
See https://github.com/stretchr/objx/pull/140

go get github.com/stretchr/objx@v0.5.1
2023-08-09 16:18:00 +02:00
Olivier Mengué 882382d845
Merge pull request #1441 from stretchr/mock-deprecate-AnythingOfTypeArgument
mock: deprecate AnythingOfTypeArgument (#1434)
2023-08-08 11:46:46 +02:00
Olivier Mengué f24f3ba986 mock: deprecate AnythingOfTypeArgument (#1434)
Deprecate mock.AnythingOfTypeArgument which should never have been
publicly exposed.

AnythingOfTypeArgument is now a type alias to the private
anythingOfTypeArgument and is marked as Deprecated in godoc.
The AnythingOfType constructor is still available.

The aim is to completely remove that alias.
2023-08-08 11:05:09 +02:00
Olivier Mengué 0e90845e22
Merge pull request #1445 from stretchr/assert-refactor-getLen
assert: refactor internal func getLen()
2023-08-08 11:04:26 +02:00
Olivier Mengué 9e58631a03 assert: reverse return values of internal getLen()
Reverse order of return values of internal function getLen() to be more
consistent with stdlib (ex: os.LookupEnv).

Old: func (any) (ok bool, length int)
New: func (any) (length int, ok bool)
2023-08-08 11:01:35 +02:00
Olivier Mengué 7a796b8f87 assert: simplify getLen() implementation 2023-08-08 11:01:35 +02:00
Anant Vyas a23f5db224
mock: move regexp compilation outside of Called (#631)
Co-authored-by: Olivier Mengué <dolmen@cpan.org>
2023-08-01 10:07:29 +02:00
Ivan Pesenti a392378178 Fixed typos
"Setup" means an existing arrangeament while "set up" is an action.
2023-07-31 19:15:21 +02:00
Olivier Mengué 81667ad920 assert: fix flaky TestNeverTrue
Fix flaky TestNeverTrue: use a channel to make a synchronized list of
return values to avoid a race condition.
2023-07-31 19:06:57 +02:00
Olivier Mengué c740480fc1 mock: refactor TestIsArgsEqual
Refactor tests to use 'append' to build copies of slices instead of
manual loops.

Thanks golangci-lint.
2023-07-30 20:51:12 +02:00
Olivier Mengué 862e41010c
Merge pull request #1360 from hikyaru-suzuki/feature/update_logging_output
mock: AssertExpectations log reason only on failure
2023-07-29 05:52:15 +02:00
Olivier Mengué 486eb6f08c
Merge pull request #1406 from dolmen-go/use-std-header-for-generated-code
codegen: use standard header for generated files
2023-07-22 08:51:09 +02:00
Olivier Mengué af4d8a66cf
Merge pull request #1320 from lesichkovm/patch-1
Fix adding ? when no values passed
2023-07-11 22:52:16 +02:00
Olivier Mengué 78aedbf433
Merge pull request #1409 from SuperQ/test_old_versions
CI: run tests from go1.17
2023-07-06 13:09:59 +02:00
SuperQ 95683d1a6c
Add tests for old Go versions
Test old Go versions all the way back to 1.17.

Signed-off-by: SuperQ <superq@gmail.com>
2023-07-06 12:59:57 +02:00
Olivier Mengué 0a3163c6c4
Merge pull request #1410 from alexandear/docs-fix-typos
doc: Fix typo in godoc

Also fix typos in tests (assertion messages).
2023-07-06 12:33:18 +02:00
Oleksandr Redko 37814a1755 docs: Fix typos in tests and comments 2023-07-06 13:14:39 +03:00
Olivier Mengué 34b86428f4
Merge pull request #1346 from LandonTClipp/mockery_docs
README: update mockery link to point to doc on Github Pages
2023-07-05 12:52:28 +02:00
Olivier Mengué 4f6e609334
Merge branch 'master' into mockery_docs 2023-07-05 12:49:36 +02:00
Olivier Mengué 204612911e
README: fix link to mockery tool 2023-07-05 12:48:13 +02:00
Olivier Mengué 6bfed73816
Merge pull request #1349 from davidjb/patch-1
README: fix URLs to point to go.dev/pkg.go.dev
2023-07-05 12:39:07 +02:00
Olivier Mengué c6ffad3f5c
Merge pull request #1389 from echarrod/master
Correct spelling/grammar in README and comments
2023-07-05 12:18:24 +02:00
Olivier Mengué b247874fc3
Merge pull request #1367 from stretchr/mvdkleijn-patch-1
Remove mvdkleijn from MAINTAINERS.md on his request
2023-07-05 12:01:22 +02:00
Olivier Mengué 945f91b9b9
Merge pull request #1392 from programmer04/improve-docs
Document that require is not safe to call in created goroutines
2023-07-05 11:59:09 +02:00
Olivier Mengué 68bbf7ae46
Merge pull request #1394 from SuperQ/go_min
Set Go version to 1.19 (oldstable) in go.mod
2023-07-05 11:57:03 +02:00
Olivier Mengué 5ca0755b51 codegen: use standard header for generated files
Use the standard header in generated Go sources.
See https://go.dev/s/generatedcode.
2023-07-02 21:06:15 +02:00
SuperQ b5eddf779a
Fix Go modules version
The `go` directive in go.mod is meant to indicate the minimum supported
version.

See: https://go.dev/doc/modules/gomod-ref#go

Signed-off-by: SuperQ <superq@gmail.com>
2023-06-02 16:11:11 +02:00
Jakub Warczarek e18a70d446
Document that require is not safe to call in created goroutines 2023-05-31 11:34:43 +02:00
Martti T f97607b898
Create GitHub release when new release tag is pushed (#1354) 2023-05-30 19:38:40 +10:00
Ed 9f0f17fe64 Correct spelling/grammar 2023-05-26 10:38:59 +01:00
Harald Nordgren 4c93d8f201
EqualExportedValues: Handle nested pointer, slice and map fields (#1379)
* EqualExportedValues: Handle pointer and slice fields

* Update assert/assertions.go

Co-authored-by: Michael Pu <michael.pu123@gmail.com>

* Reduce redundant calls to 'copyExportedFields'

* Update comments

* Add support for maps

* Update Go version support to 1.19 and onward

* Re-generate after rebasing

---------

Co-authored-by: Michael Pu <michael.pu123@gmail.com>
2023-05-11 07:42:04 +10:00
Tobias Krischer 4b2f4d2bcf
add EventuallyWithT assertion (#1264)
* add EventuallyWithT assertion

* Change "EventuallyWithT" condition acceptance to no-errors raised

This change updates the "EventuallyWithT" assertion variants (regular, formatted,
requirement) to consider a condition as "met" if no assertion errors were raised
in a tick.

This allows to write easier conditions which simply contain assertions, without
needing to return a bool. The equivalent of a condition returning true in the
previous implementation would be a a condition with a single "assert.True(..)" call.

* Declare the "Collect.Copy(T)" method as a testing helper

* run go generate

---------

Co-authored-by: Arik Kfir <arik@kfirs.com>
2023-05-10 06:58:49 +10:00
Nisheeth Barthwal b3106d772c
allow testing for functional options (#1023)
* allow testing for functional options

* add linting docs

* use reflect magic to obtain FunctionalOption name

Co-authored-by: dillonstreator <dillonstreator@gmail.com>

---------

Co-authored-by: dillonstreator <dillonstreator@gmail.com>
2023-05-10 06:55:48 +10:00
wwade 437071b948
assert: fix error message formatting for NotContains (#1362)
* assert: rename and refactor TestContainsFailMessage

I've renamed it to TestContainsNotContains and added a test case
structure so that I can use this test to validate the failure messages
from both Contains and NotContains,

There are no functional changes here, strictly refactoring. A new test
case will be added in a subsequent change.

* assert: fix error message formatting for NotContains

It was using "%s" to format the s and contains arguments, but these
could be any type that supports iteration such as a map. In this case
of NotContains failing against a map, it would print something like:

   "map[one:%!s(int=1)]" should not contain "one"

Fix this using "%#v" as was already done for Contains and added test
cases covering both the "len()" / iterable failure messages as well as
the Contains/NotContains failure case.

The new message for this example map would be something like:

    map[string]int{"one":1} should not contain "one"
2023-05-05 14:05:51 +10:00
Martijn 02647d3471
Remove myself from MAINTAINERS.md
As I am supposed to be a maintainer but have almost zero access to actually manage the project, I've found it difficult to help out. Since then my time has become fragmented and as such I'm removing myself as maintainer.
2023-04-07 08:55:49 +02:00
Michael Pu c5fc9d6b6b
Compare public elements of struct (#1309)
* Implement checking only exported fields

Co-authored-by: Anthony Chang <anthony-chang@users.noreply.github.com>

* Update comment

* Run go generate

* Make compatiable with Go 1.16.5

* Fix go generate files

* Fix white space changes

* Fix whitespace changes

* Fix whitespace changes in gogenerate files

---------

Co-authored-by: Anthony Chang <anthony-chang@users.noreply.github.com>
2023-03-14 22:01:35 +10:00
鈴木 光 75b9b6dfff update: log reason output only if failed 2023-03-09 18:49:15 +09:00
David Beitey d099934742 docs: Update URLs in README 2023-03-05 12:32:34 +10:00
Landon Clipp 0291ba6dc2
https 2023-02-11 01:59:47 -06:00
LandonTClipp d2db48976a Update mockery link to Github Pages 2023-02-11 01:23:36 -06:00
Bogdan Drutu f7b49d3ed7
Add support to compare uintptr
Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
2023-02-04 16:27:21 -08:00
Milan Lesichkov c029f419b8
Fix adding ? when no values passed 2022-12-22 10:45:24 +00:00
Thomas Güttler afd76b48e3
gorc last update is nine years old
I think it makes no sense to link to it.
2022-08-11 21:51:04 +02:00
48 changed files with 4144 additions and 1673 deletions

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

@ -0,0 +1,12 @@
#!/bin/bash
# Verify that the code snippets in README.md are formatted.
# The tool https://github.com/hougesen/mdsf is used.
if [ -n "$(mdsf verify --config .mdsf.json --log-level error README.md 2>&1)" ]; then
echo "Go code in the README.md is not formatted."
echo "Did you forget to run 'mdsf format --config .mdsf.json README.md'?"
mdsf format --config .mdsf.json README.md
git diff
exit 1
fi

23
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,23 @@
---
name: Bug report
about: Format to report a bug
title: ''
labels: bug
assignees: ''
---
<!-- If this is a question, consider using the discussion section of this repo -->
<!-- Here: https://github.com/stretchr/testify/discussions/new?category=q-a -->
## Description
<!-- A detailed description of the bug -->
## Step To Reproduce
<!-- Steps or code snippet to reproduce the behavior -->
## Expected behavior
<!-- A clear and concise description of what you expected to happen -->
## Actual behavior
<!-- What testify does -->

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Propose a new feature
title: ''
labels: enhancement
assignees: ''
---
<!-- If this is a question, consider using the discussion section of this repo -->
<!-- Here: https://github.com/stretchr/testify/discussions/new?category=q-a -->
## Description
<!-- A clear and concise description of what feature you are proposing -->
## Proposed solution
<!-- Optionally a suggested implementation -->
## Use case
<!-- What is the motivation? What workarounds have you used? -->

View File

@ -6,14 +6,36 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go_version: ["1.18.1", "1.17.6", "1.16.5"]
go_version:
- stable
- oldstable
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v3.2.0
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
- run: ./.ci.gogenerate.sh
- 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:
runs-on: ubuntu-latest
strategy:
matrix:
go_version:
- "1.17"
- "1.18"
- "1.19"
- "1.20"
- "1.21"
- "1.22"
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
- run: go test -v -race ./...

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

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

12
EMERITUS.md Normal file
View File

@ -0,0 +1,12 @@
# Emeritus
We would like to acknowledge previous testify maintainers and their huge contributions to our collective success:
* @matryer
* @glesica
* @ernesto-jimenez
* @mvdkleijn
* @georgelesica-wf
* @bencampbell-wf
We thank these members for their service to this community.

View File

@ -3,7 +3,15 @@
The individuals listed below are active in the project and have the ability to approve and merge
pull requests.
* @glesica
* @boyan-soubachov
* @mvdkleijn
* @dolmen
* @MovieStoreGuy
* @brackendawson
## Approvers
The individuals listed below are active in the project and have the ability to approve pull
requests.
* @arjunmahishi
* @ccoVeille

229
README.md
View File

@ -1,9 +1,11 @@
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://travis-ci.org/stretchr/testify.svg)](https://travis-ci.org/stretchr/testify) [![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)
[![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)
Go code (golang) set of packages that provide many tools for testifying that your code will behave as you intend.
@ -16,14 +18,12 @@ Features include:
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 http://golang.org/doc/code.html#Testing
* Check out the API Documentation http://godoc.org/github.com/stretchr/testify
* To make your testing life easier, check out our other project, [gorc](http://github.com/stretchr/gorc)
* A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development)
* 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`](http://godoc.org/github.com/stretchr/testify/assert "API documentation") package
[`assert`](https://pkg.go.dev/github.com/stretchr/testify/assert "API documentation") package
-------------------------------------------------------------------------------------------
The `assert` package provides some helpful methods that allow you to write better test code in Go.
@ -38,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)
}
}
```
@ -74,52 +71,55 @@ 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)
}
}
```
[`require`](http://godoc.org/github.com/stretchr/testify/require "API documentation") package
[`require`](https://pkg.go.dev/github.com/stretchr/testify/require "API documentation") package
---------------------------------------------------------------------------------------------
The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test.
These functions must be called from the goroutine running the test or benchmark function, not from other goroutines created during the test.
Otherwise race conditions may occur.
See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details.
See [t.FailNow](https://pkg.go.dev/testing#T.FailNow) for details.
[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package
[`mock`](https://pkg.go.dev/github.com/stretchr/testify/mock "API documentation") package
----------------------------------------------------------------------------------------
The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code.
An example test function that tests a piece of code that relies on an external object `testObj`, can setup expectations (testify) and assert that they indeed happened:
An example test function that tests a piece of code that relies on an external object `testObj`, can set up expectations (testify) and assert that they indeed happened:
```go
package yours
import (
"testing"
"github.com/stretchr/testify/mock"
"testing"
"github.com/stretchr/testify/mock"
)
/*
@ -128,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
@ -140,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)
}
/*
@ -153,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)
// setup 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
@ -175,130 +170,131 @@ 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)
// setup 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)
// setup 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)
}
```
For more information on how to write mock code, check out the [API documentation for the `mock` package](http://godoc.org/github.com/stretchr/testify/mock).
For more information on how to write mock code, check out the [API documentation for the `mock` package](https://pkg.go.dev/github.com/stretchr/testify/mock).
You can use the [mockery tool](http://github.com/vektra/mockery) to autogenerate the mock code against an interface as well, making using mocks much quicker.
You can use the [mockery tool](https://vektra.github.io/mockery/latest/) to autogenerate the mock code against an interface as well, making using mocks much quicker.
[`suite`](http://godoc.org/github.com/stretchr/testify/suite "API documentation") package
[`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package
-----------------------------------------------------------------------------------------
> [!WARNING]
> The suite package does not support parallel tests. See [#934](https://github.com/stretchr/testify/issues/934).
The `suite` package provides functionality that you might be used to from more common object oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal.
The `suite` package provides functionality that you might be used to from more common object-oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal.
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))
}
```
For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go)
For more information on writing suites, check out the [API documentation for the `suite` package](http://godoc.org/github.com/stretchr/testify/suite).
For more information on writing suites, check out the [API documentation for the `suite` package](https://pkg.go.dev/github.com/stretchr/testify/suite).
`Suite` object has assertion methods:
```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))
}
```
@ -325,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!")
}
```
@ -348,7 +343,7 @@ To update Testify to the latest version, use `go get -u github.com/stretchr/test
Supported go versions
==================
We currently support the most recent major Go versions from 1.13 onward.
We currently support the most recent major Go versions from 1.19 onward.
------
@ -359,7 +354,7 @@ Please feel free to submit issues, fork the repository and send pull requests!
When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it.
Code generation is used. Look for `CODE GENERATED AUTOMATICALLY` at the top of some files. Run `go generate ./...` to update generated files.
Code generation is used. [Look for `Code generated with`](https://github.com/search?q=repo%3Astretchr%2Ftestify%20%22Code%20generated%20with%22&type=code) at the top of some files. Run `go generate ./...` to update generated files.
We also chat on the [Gophers Slack](https://gophers.slack.com) group in the `#testify` and `#testify-dev` channels.

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

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
)
@ -28,6 +31,8 @@ var (
uint32Type = reflect.TypeOf(uint32(1))
uint64Type = reflect.TypeOf(uint64(1))
uintptrType = reflect.TypeOf(uintptr(1))
float32Type = reflect.TypeOf(float32(1))
float64Type = reflect.TypeOf(float64(1))
@ -37,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)
@ -308,11 +313,11 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
case reflect.Struct:
{
// All structs enter here. We're not interested in most types.
if !canConvert(obj1Value, timeType) {
if !obj1Value.CanConvert(timeType) {
break
}
// time.Time can compared!
// time.Time can be compared!
timeObj1, ok := obj1.(time.Time)
if !ok {
timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time)
@ -323,12 +328,18 @@ 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:
{
// We only care about the []byte type.
if !canConvert(obj1Value, bytesType) {
if !obj1Value.CanConvert(bytesType) {
break
}
@ -343,7 +354,27 @@ 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:
{
uintptrObj1, ok := obj1.(uintptr)
if !ok {
uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr)
}
uintptrObj2, ok := obj2.(uintptr)
if !ok {
uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr)
}
if uintptrObj1 > uintptrObj2 {
return compareGreater, true
}
if uintptrObj1 == uintptrObj2 {
return compareEqual, true
}
if uintptrObj1 < uintptrObj2 {
return compareLess, true
}
}
}
@ -352,79 +383,85 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
// Greater asserts that the first element is greater than the second
//
// assert.Greater(t, 2, 1)
// assert.Greater(t, float64(2), float64(1))
// assert.Greater(t, "b", "a")
// assert.Greater(t, 2, 1)
// assert.Greater(t, float64(2), float64(1))
// assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
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
//
// assert.GreaterOrEqual(t, 2, 1)
// assert.GreaterOrEqual(t, 2, 2)
// assert.GreaterOrEqual(t, "b", "a")
// assert.GreaterOrEqual(t, "b", "b")
// assert.GreaterOrEqual(t, 2, 1)
// assert.GreaterOrEqual(t, 2, 2)
// assert.GreaterOrEqual(t, "b", "a")
// assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
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
//
// assert.Less(t, 1, 2)
// assert.Less(t, float64(1), float64(2))
// assert.Less(t, "a", "b")
// assert.Less(t, 1, 2)
// assert.Less(t, float64(1), float64(2))
// assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
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
//
// assert.LessOrEqual(t, 1, 2)
// assert.LessOrEqual(t, 2, 2)
// assert.LessOrEqual(t, "a", "b")
// assert.LessOrEqual(t, "b", "b")
// assert.LessOrEqual(t, 1, 2)
// assert.LessOrEqual(t, 2, 2)
// assert.LessOrEqual(t, "a", "b")
// assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
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
//
// assert.Positive(t, 1)
// assert.Positive(t, 1.23)
// assert.Positive(t, 1)
// assert.Positive(t, 1.23)
func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
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
//
// assert.Negative(t, -1)
// assert.Negative(t, -1.23)
// assert.Negative(t, -1)
// assert.Negative(t, -1.23)
func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
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()
}
@ -437,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

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

View File

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

View File

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

View File

@ -6,9 +6,11 @@ import (
"reflect"
"runtime"
"testing"
"time"
)
func TestCompare(t *testing.T) {
type customString string
type customInt int
type customInt8 int8
type customInt16 int16
@ -21,7 +23,9 @@ func TestCompare(t *testing.T) {
type customUInt64 uint64
type customFloat32 float32
type customFloat64 float64
type customString string
type customUintptr uintptr
type customTime time.Time
type customBytes []byte
for _, currCase := range []struct {
less interface{}
greater interface{}
@ -52,6 +56,13 @@ func TestCompare(t *testing.T) {
{less: customFloat32(1.23), greater: customFloat32(2.23), cType: "float32"},
{less: float64(1.23), greater: float64(2.34), cType: "float64"},
{less: customFloat64(1.23), greater: customFloat64(2.34), cType: "float64"},
{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"},
} {
resLess, isComparable := compare(currCase.less, currCase.greater, reflect.ValueOf(currCase.less).Kind())
if !isComparable {
@ -148,6 +159,9 @@ func TestGreater(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"1" is not greater than "2"`},
{less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than "2.34"`},
{less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than "2.34"`},
{less: uintptr(1), greater: uintptr(2), msg: `"1" is not greater than "2"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than "0001-01-01 01:00:00 +0000 UTC"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than "[1 2]"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, Greater(out, currCase.less, currCase.greater))
@ -189,6 +203,9 @@ func TestGreaterOrEqual(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"1" is not greater than or equal to "2"`},
{less: float32(1.23), greater: float32(2.34), msg: `"1.23" is not greater than or equal to "2.34"`},
{less: float64(1.23), greater: float64(2.34), msg: `"1.23" is not greater than or equal to "2.34"`},
{less: uintptr(1), greater: uintptr(2), msg: `"1" is not greater than or equal to "2"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 00:00:00 +0000 UTC" is not greater than or equal to "0001-01-01 01:00:00 +0000 UTC"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 1]" is not greater than or equal to "[1 2]"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, GreaterOrEqual(out, currCase.less, currCase.greater))
@ -230,6 +247,9 @@ func TestLess(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"2" is not less than "1"`},
{less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than "1.23"`},
{less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than "1.23"`},
{less: uintptr(1), greater: uintptr(2), msg: `"2" is not less than "1"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than "0001-01-01 00:00:00 +0000 UTC"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than "[1 1]"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, Less(out, currCase.greater, currCase.less))
@ -271,6 +291,9 @@ func TestLessOrEqual(t *testing.T) {
{less: uint64(1), greater: uint64(2), msg: `"2" is not less than or equal to "1"`},
{less: float32(1.23), greater: float32(2.34), msg: `"2.34" is not less than or equal to "1.23"`},
{less: float64(1.23), greater: float64(2.34), msg: `"2.34" is not less than or equal to "1.23"`},
{less: uintptr(1), greater: uintptr(2), msg: `"2" is not less than or equal to "1"`},
{less: time.Time{}, greater: time.Time{}.Add(time.Hour), msg: `"0001-01-01 01:00:00 +0000 UTC" is not less than or equal to "0001-01-01 00:00:00 +0000 UTC"`},
{less: []byte{1, 1}, greater: []byte{1, 2}, msg: `"[1 2]" is not less than or equal to "[1 1]"`},
} {
out := &outputT{buf: bytes.NewBuffer(nil)}
False(t, LessOrEqual(out, currCase.greater, currCase.less))
@ -370,8 +393,8 @@ 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)
}
}
@ -389,8 +412,8 @@ 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)
}
}
@ -398,35 +421,35 @@ func Test_compareTwoValuesCorrectCompareResult(t *testing.T) {
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) {
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

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

File diff suppressed because it is too large Load Diff

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) {
@ -46,36 +46,36 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT
// IsIncreasing asserts that the collection is increasing
//
// assert.IsIncreasing(t, []int{1, 2, 3})
// assert.IsIncreasing(t, []float{1, 2})
// assert.IsIncreasing(t, []string{"a", "b"})
// assert.IsIncreasing(t, []int{1, 2, 3})
// 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
//
// assert.IsNonIncreasing(t, []int{2, 1, 1})
// assert.IsNonIncreasing(t, []float{2, 1})
// assert.IsNonIncreasing(t, []string{"b", "a"})
// assert.IsNonIncreasing(t, []int{2, 1, 1})
// 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
//
// assert.IsDecreasing(t, []int{2, 1, 0})
// assert.IsDecreasing(t, []float{2, 1})
// assert.IsDecreasing(t, []string{"b", "a"})
// assert.IsDecreasing(t, []int{2, 1, 0})
// 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
//
// assert.IsNonDecreasing(t, []int{1, 1, 2})
// assert.IsNonDecreasing(t, []float{1, 2})
// assert.IsNonDecreasing(t, []string{"a", "b"})
// assert.IsNonDecreasing(t, []int{1, 1, 2})
// 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...)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -546,7 +546,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))

View File

@ -12,7 +12,7 @@ import (
// an error if building a new request fails.
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
w := httptest.NewRecorder()
req, err := http.NewRequest(method, url, nil)
req, err := http.NewRequest(method, url, http.NoBody)
if err != nil {
return -1, err
}
@ -23,7 +23,7 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
@ -32,12 +32,12 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
if !isSuccessCode {
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code))
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
}
return isSuccessCode
@ -45,7 +45,7 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
@ -54,12 +54,12 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
if !isRedirectCode {
Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code))
Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
}
return isRedirectCode
@ -67,7 +67,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
// HTTPError asserts that a specified handler returns an error status code.
//
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
@ -76,12 +76,12 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
isErrorCode := code >= http.StatusBadRequest
if !isErrorCode {
Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code))
Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
}
return isErrorCode
@ -89,7 +89,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
@ -98,12 +98,12 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
successful := code == statuscode
if !successful {
Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code))
Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...)
}
return successful
@ -113,7 +113,10 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va
// empty string if building a new request fails.
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
w := httptest.NewRecorder()
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
if len(values) > 0 {
url += "?" + values.Encode()
}
req, err := http.NewRequest(method, url, http.NoBody)
if err != nil {
return ""
}
@ -124,7 +127,7 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
@ -135,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))
Fail(t, fmt.Sprintf("Expected response body for %q to contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
}
return contains
@ -144,7 +147,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
@ -155,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))
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

@ -2,6 +2,7 @@ package assert
import (
"fmt"
"io"
"net/http"
"net/url"
"testing"
@ -11,6 +12,12 @@ func httpOK(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func httpReadBody(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(io.Discard, r.Body)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello"))
}
func httpRedirect(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTemporaryRedirect)
}
@ -34,21 +41,33 @@ func TestHTTPSuccess(t *testing.T) {
assert.Equal(HTTPSuccess(mockT2, httpRedirect, "GET", "/", nil), false)
assert.True(mockT2.Failed())
mockT3 := new(testing.T)
assert.Equal(HTTPSuccess(mockT3, httpError, "GET", "/", nil), false)
mockT3 := new(mockTestingT)
assert.Equal(HTTPSuccess(
mockT3, httpError, "GET", "/", nil,
"was not expecting a failure here",
), false)
assert.True(mockT3.Failed())
assert.Contains(mockT3.errorString(), "was not expecting a failure here")
mockT4 := new(testing.T)
assert.Equal(HTTPSuccess(mockT4, httpStatusCode, "GET", "/", nil), false)
assert.True(mockT4.Failed())
mockT5 := new(testing.T)
assert.Equal(HTTPSuccess(mockT5, httpReadBody, "POST", "/", nil), true)
assert.False(mockT5.Failed())
}
func TestHTTPRedirect(t *testing.T) {
assert := New(t)
mockT1 := new(testing.T)
assert.Equal(HTTPRedirect(mockT1, httpOK, "GET", "/", nil), false)
mockT1 := new(mockTestingT)
assert.Equal(HTTPRedirect(
mockT1, httpOK, "GET", "/", nil,
"was expecting a 3xx status code. Got 200.",
), false)
assert.True(mockT1.Failed())
assert.Contains(mockT1.errorString(), "was expecting a 3xx status code. Got 200.")
mockT2 := new(testing.T)
assert.Equal(HTTPRedirect(mockT2, httpRedirect, "GET", "/", nil), true)
@ -70,9 +89,13 @@ func TestHTTPError(t *testing.T) {
assert.Equal(HTTPError(mockT1, httpOK, "GET", "/", nil), false)
assert.True(mockT1.Failed())
mockT2 := new(testing.T)
assert.Equal(HTTPError(mockT2, httpRedirect, "GET", "/", nil), false)
mockT2 := new(mockTestingT)
assert.Equal(HTTPError(
mockT2, httpRedirect, "GET", "/", nil,
"Expected this request to error out. But it didn't",
), false)
assert.True(mockT2.Failed())
assert.Contains(mockT2.errorString(), "Expected this request to error out. But it didn't")
mockT3 := new(testing.T)
assert.Equal(HTTPError(mockT3, httpError, "GET", "/", nil), true)
@ -94,9 +117,13 @@ func TestHTTPStatusCode(t *testing.T) {
assert.Equal(HTTPStatusCode(mockT2, httpRedirect, "GET", "/", nil, http.StatusSwitchingProtocols), false)
assert.True(mockT2.Failed())
mockT3 := new(testing.T)
assert.Equal(HTTPStatusCode(mockT3, httpError, "GET", "/", nil, http.StatusSwitchingProtocols), false)
mockT3 := new(mockTestingT)
assert.Equal(HTTPStatusCode(
mockT3, httpError, "GET", "/", nil, http.StatusSwitchingProtocols,
"Expected the status code to be %d", http.StatusSwitchingProtocols,
), false)
assert.True(mockT3.Failed())
assert.Contains(mockT3.errorString(), "Expected the status code to be 101")
mockT4 := new(testing.T)
assert.Equal(HTTPStatusCode(mockT4, httpStatusCode, "GET", "/", nil, http.StatusSwitchingProtocols), true)
@ -122,7 +149,7 @@ func TestHTTPStatusesWrapper(t *testing.T) {
func httpHelloName(w http.ResponseWriter, r *http.Request) {
name := r.FormValue("name")
_, _ = w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
_, _ = fmt.Fprintf(w, "Hello, %s!", name)
}
func TestHTTPRequestWithNoParams(t *testing.T) {
@ -156,15 +183,21 @@ func TestHTTPRequestWithParams(t *testing.T) {
func TestHttpBody(t *testing.T) {
assert := New(t)
mockT := new(testing.T)
mockT := new(mockTestingT)
assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.False(HTTPBodyNotContains(
mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World",
"Expected the request body to not contain 'World'. But it did.",
))
assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
assert.Contains(mockT.errorString(), "Expected the request body to not contain 'World'. But it did.")
assert.True(HTTPBodyContains(mockT, httpReadBody, "GET", "/", nil, "hello"))
}
func TestHttpBodyWrappers(t *testing.T) {
@ -178,5 +211,4 @@ func TestHttpBodyWrappers(t *testing.T) {
assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
}

View File

@ -0,0 +1,4 @@
// This package exists just to isolate tests that reference the [unsafe] package.
//
// The tests in this package are totally safe.
package unsafetests

View File

@ -0,0 +1,34 @@
package unsafetests_test
import (
"fmt"
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
)
type ignoreTestingT struct{}
var _ assert.TestingT = ignoreTestingT{}
func (ignoreTestingT) Helper() {}
func (ignoreTestingT) Errorf(format string, args ...interface{}) {
// Run the formatting, but ignore the result
msg := fmt.Sprintf(format, args...)
_ = msg
}
func TestUnsafePointers(t *testing.T) {
var ignore ignoreTestingT
assert.True(t, assert.Nil(t, unsafe.Pointer(nil), "unsafe.Pointer(nil) is nil"))
assert.False(t, assert.NotNil(ignore, unsafe.Pointer(nil), "unsafe.Pointer(nil) is nil"))
assert.True(t, assert.Nil(t, unsafe.Pointer((*int)(nil)), "unsafe.Pointer((*int)(nil)) is nil"))
assert.False(t, assert.NotNil(ignore, unsafe.Pointer((*int)(nil)), "unsafe.Pointer((*int)(nil)) is nil"))
assert.False(t, assert.Nil(ignore, unsafe.Pointer(new(int)), "unsafe.Pointer(new(int)) is NOT nil"))
assert.True(t, assert.NotNil(t, unsafe.Pointer(new(int)), "unsafe.Pointer(new(int)) is NOT nil"))
}

View File

@ -0,0 +1,25 @@
//go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default
// +build testify_yaml_custom,!testify_yaml_fail,!testify_yaml_default
// Package yaml is an implementation of YAML functions that calls a pluggable implementation.
//
// This implementation is selected with the testify_yaml_custom build tag.
//
// go test -tags testify_yaml_custom
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3].
//
// In your test package:
//
// import assertYaml "github.com/stretchr/testify/assert/yaml"
//
// func init() {
// assertYaml.Unmarshal = func (in []byte, out interface{}) error {
// // ...
// return nil
// }
// }
package yaml
var Unmarshal func(in []byte, out interface{}) error

View File

@ -0,0 +1,37 @@
//go:build !testify_yaml_fail && !testify_yaml_custom
// +build !testify_yaml_fail,!testify_yaml_custom
// Package yaml is just an indirection to handle YAML deserialization.
//
// This package is just an indirection that allows the builder to override the
// indirection with an alternative implementation of this package that uses
// another implementation of YAML deserialization. This allows to not either not
// use YAML deserialization at all, or to use another implementation than
// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]).
//
// Alternative implementations are selected using build tags:
//
// - testify_yaml_fail: [Unmarshal] always fails with an error
// - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it
// before calling any of [github.com/stretchr/testify/assert.YAMLEq] or
// [github.com/stretchr/testify/assert.YAMLEqf].
//
// Usage:
//
// go test -tags testify_yaml_fail
//
// You can check with "go list" which implementation is linked:
//
// go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
//
// [PR #1120]: https://github.com/stretchr/testify/pull/1120
package yaml
import goyaml "gopkg.in/yaml.v3"
// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal].
func Unmarshal(in []byte, out interface{}) error {
return goyaml.Unmarshal(in, out)
}

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

@ -0,0 +1,18 @@
//go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default
// +build testify_yaml_fail,!testify_yaml_custom,!testify_yaml_default
// Package yaml is an implementation of YAML functions that always fail.
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3]:
//
// go test -tags testify_yaml_fail
package yaml
import "errors"
var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)")
func Unmarshal([]byte, interface{}) error {
return errNotImplemented
}

18
doc.go
View File

@ -1,23 +1,15 @@
// ** 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:
//
// The assert package provides a comprehensive set of assertion functions that tie in to the Go testing system.
//
// The http package contains tools to make it easier to test http activity using the Go testing system.
//
// 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
// blank imports help docs.
import (
// assert package
_ "github.com/stretchr/testify/assert"
// http package
_ "github.com/stretchr/testify/http"
// mock package
_ "github.com/stretchr/testify/mock"
)

10
go.mod
View File

@ -1,10 +1,16 @@
module github.com/stretchr/testify
go 1.13
// This should match the minimum supported version that is tested in
// .github/workflows/main.yml
go 1.17
require (
github.com/davecgh/go-spew v1.1.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.5.0
github.com/stretchr/objx v0.5.2
gopkg.in/yaml.v3 v3.0.1
)
// Break dependency cycle with objx.
// See https://github.com/stretchr/objx/pull/140
exclude github.com/stretchr/testify v1.8.2

4
go.sum
View File

@ -5,10 +5,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,2 +1,2 @@
// Package http DEPRECATED USE net/http/httptest
// Deprecated: Use [net/http/httptest] instead.
package http

View File

@ -4,7 +4,7 @@ import (
"net/http"
)
// TestResponseWriter DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
// Deprecated: Use [net/http/httptest] instead.
type TestResponseWriter struct {
// StatusCode is the last int written by the call to WriteHeader(int)
@ -17,7 +17,7 @@ type TestResponseWriter struct {
header http.Header
}
// Header DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
// Deprecated: Use [net/http/httptest] instead.
func (rw *TestResponseWriter) Header() http.Header {
if rw.header == nil {
@ -27,7 +27,7 @@ func (rw *TestResponseWriter) Header() http.Header {
return rw.header
}
// Write DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
// Deprecated: Use [net/http/httptest] instead.
func (rw *TestResponseWriter) Write(bytes []byte) (int, error) {
// assume 200 success if no header has been set
@ -43,7 +43,7 @@ func (rw *TestResponseWriter) Write(bytes []byte) (int, error) {
}
// WriteHeader DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
// Deprecated: Use [net/http/httptest] instead.
func (rw *TestResponseWriter) WriteHeader(i int) {
rw.StatusCode = i
}

View File

@ -6,12 +6,12 @@ import (
"github.com/stretchr/testify/mock"
)
// TestRoundTripper DEPRECATED USE net/http/httptest
// Deprecated: Use [net/http/httptest] instead.
type TestRoundTripper struct {
mock.Mock
}
// RoundTrip DEPRECATED USE net/http/httptest
// Deprecated: Use [net/http/httptest] instead.
func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
args := t.Called(req)
return args.Get(0).(*http.Response), args.Error(1)

View File

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

View File

@ -3,6 +3,7 @@ package mock
import (
"errors"
"fmt"
"path"
"reflect"
"regexp"
"runtime"
@ -13,9 +14,13 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/objx"
"github.com/stretchr/testify/assert"
)
// regex for GCCGO functions
var gccgoRE = regexp.MustCompile(`\.pN\d+_`)
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Logf(format string, args ...interface{})
@ -75,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,
@ -99,7 +104,7 @@ func (c *Call) unlock() {
// Return specifies the return arguments for the expectation.
//
// Mock.On("DoSomething").Return(errors.New("failed"))
// Mock.On("DoSomething").Return(errors.New("failed"))
func (c *Call) Return(returnArguments ...interface{}) *Call {
c.lock()
defer c.unlock()
@ -109,9 +114,9 @@ func (c *Call) Return(returnArguments ...interface{}) *Call {
return c
}
// Panic specifies if the functon call should fail and the panic message
// Panic specifies if the function call should fail and the panic message
//
// Mock.On("DoSomething").Panic("test panic")
// Mock.On("DoSomething").Panic("test panic")
func (c *Call) Panic(msg string) *Call {
c.lock()
defer c.unlock()
@ -121,24 +126,24 @@ func (c *Call) Panic(msg string) *Call {
return c
}
// Once indicates that that the mock should only return the value once.
// Once indicates that the mock should only return the value once.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
func (c *Call) Once() *Call {
return c.Times(1)
}
// Twice indicates that that the mock should only return the value twice.
// Twice indicates that the mock should only return the value twice.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
func (c *Call) Twice() *Call {
return c.Times(2)
}
// Times indicates that that the mock should only return the indicated number
// Times indicates that the mock should only return the indicated number
// of times.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
func (c *Call) Times(i int) *Call {
c.lock()
defer c.unlock()
@ -149,7 +154,7 @@ func (c *Call) Times(i int) *Call {
// WaitUntil sets the channel that will block the mock's return until its closed
// or a message is received.
//
// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
func (c *Call) WaitUntil(w <-chan time.Time) *Call {
c.lock()
defer c.unlock()
@ -159,7 +164,7 @@ func (c *Call) WaitUntil(w <-chan time.Time) *Call {
// After sets how long to block until the call returns
//
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
func (c *Call) After(d time.Duration) *Call {
c.lock()
defer c.unlock()
@ -171,10 +176,10 @@ func (c *Call) After(d time.Duration) *Call {
// mocking a method (such as an unmarshaler) that takes a pointer to a struct and
// sets properties in such struct
//
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) {
// arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar"
// })
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) {
// arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar"
// })
func (c *Call) Run(fn func(args Arguments)) *Call {
c.lock()
defer c.unlock()
@ -194,16 +199,25 @@ func (c *Call) Maybe() *Call {
// On chains a new expectation description onto the mocked interface. This
// allows syntax like.
//
// Mock.
// On("MyMethod", 1).Return(nil).
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
// Mock.
// On("MyMethod", 1).Return(nil).
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
//
//go:noinline
func (c *Call) On(methodName string, arguments ...interface{}) *Call {
return c.Parent.On(methodName, arguments...)
}
// Unset removes a mock handler from being called.
// test.On("func", mock.Anything).Unset()
// Unset removes all mock handlers that satisfy the call instance arguments from being
// called. Only supported on call instances with static input arguments.
//
// 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
@ -249,9 +263,9 @@ 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("Init").Return(nil)
// )
// Mock.On("Do").Return(nil).NotBefore(
// Mock.On("Init").Return(nil)
// )
func (c *Call) NotBefore(calls ...*Call) *Call {
c.lock()
defer c.unlock()
@ -266,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.
@ -310,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()
@ -334,7 +365,7 @@ func (m *Mock) fail(format string, args ...interface{}) {
// On starts a description of an expectation of the specified method
// being called.
//
// Mock.On("MyMethod", arg1, arg2)
// Mock.On("MyMethod", arg1, arg2)
func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
for _, arg := range arguments {
if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
@ -344,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
}
@ -424,6 +456,10 @@ func callString(method string, arguments Arguments, includeArgumentValues bool)
if includeArgumentValues {
var argVals []string
for argIndex, arg := range arguments {
if _, ok := arg.(*FunctionalOptionsArgument); ok {
argVals = append(argVals, fmt.Sprintf("%d: %s", argIndex, arg))
continue
}
argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg))
}
argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
@ -447,9 +483,8 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
// For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
// uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
// With GCCGO we need to remove interface information starting from pN<dd>.
re := regexp.MustCompile("\\.pN\\d+_")
if re.MatchString(functionPath) {
functionPath = re.Split(functionPath, -1)[0]
if gccgoRE.MatchString(functionPath) {
functionPath = gccgoRE.Split(functionPath, -1)[0]
}
parts := strings.Split(functionPath, ".")
functionName := parts[len(parts)-1]
@ -466,10 +501,10 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
found, call := m.findExpectedCall(methodName, arguments...)
if found < 0 {
// expected call found but it has already been called with repeatable times
// expected call found, but it has already been called with repeatable times
if call != nil {
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:
@ -481,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())
}
}
@ -519,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
@ -555,7 +591,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
Assertions
*/
type assertExpectationser interface {
type assertExpectationiser interface {
AssertExpectations(TestingT) bool
}
@ -572,7 +608,7 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)")
obj = m
}
m := obj.(assertExpectationser)
m := obj.(assertExpectationiser)
if !m.AssertExpectations(t) {
t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m))
return false
@ -584,6 +620,9 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
// AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool {
if s, ok := t.(interface{ Skipped() bool }); ok && s.Skipped() {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
@ -598,8 +637,8 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
satisfied, reason := m.checkExpectation(expectedCall)
if !satisfied {
failedExpectations++
t.Logf(reason)
}
t.Logf(reason)
}
if failedExpectations != 0 {
@ -750,34 +789,80 @@ const (
Anything = "mock.Anything"
)
// AnythingOfTypeArgument is a string that contains the type of an argument
// for use when type checking. Used in Diff and Assert.
type AnythingOfTypeArgument string
// AnythingOfTypeArgument contains the type of an argument
// for use when type checking. Used in [Arguments.Diff] and [Arguments.Assert].
//
// 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
// AnythingOfType returns an AnythingOfTypeArgument object containing the
// name of the type to check for. Used in Diff and Assert.
// anythingOfTypeArgument is a string that contains the type of an argument
// for use when type checking. Used in Diff and Assert.
type anythingOfTypeArgument string
// AnythingOfType returns a special value containing the
// name of the type to check for. The type name will be matched against the type name returned by [reflect.Type.String].
//
// Used in Diff and Assert.
//
// For example:
// Assert(t, AnythingOfType("string"), AnythingOfType("int"))
//
// args.Assert(t, AnythingOfType("string"), AnythingOfType("int"))
func AnythingOfType(t string) AnythingOfTypeArgument {
return AnythingOfTypeArgument(t)
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 interface{}
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: t}
return &IsTypeArgument{t: reflect.TypeOf(t)}
}
// FunctionalOptionsArgument contains a list of functional options arguments
// expected for use when matching a list of arguments.
type FunctionalOptionsArgument struct {
values []interface{}
}
// String returns the string representation of FunctionalOptionsArgument
func (f *FunctionalOptionsArgument) String() string {
var name string
if len(f.values) > 0 {
name = "[]" + reflect.TypeOf(f.values[0]).String()
}
return strings.Replace(fmt.Sprintf("%#v", f.values), "[]interface {}", name, 1)
}
// FunctionalOptions returns an [FunctionalOptionsArgument] object containing
// the expected functional-options to check for.
//
// For example:
//
// args.Assert(t, FunctionalOptions(foo.Opt1("strValue"), foo.Opt2(613)))
func FunctionalOptions(values ...interface{}) *FunctionalOptionsArgument {
return &FunctionalOptionsArgument{
values: values,
}
}
// argumentMatcher performs custom argument matching, returning whether or
@ -823,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)
@ -913,29 +999,51 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
}
} else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
// type checking
if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
}
} else if reflect.TypeOf(expected) == reflect.TypeOf((*IsTypeArgument)(nil)) {
t := expected.(*IsTypeArgument).t
if reflect.TypeOf(t) != reflect.TypeOf(actual) {
differences++
output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt)
}
} else {
// normal checking
switch expected := expected.(type) {
case anythingOfTypeArgument:
// type checking
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)
}
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)
}
case *FunctionalOptionsArgument:
var name string
if len(expected.values) > 0 {
name = "[]" + reflect.TypeOf(expected.values[0]).String()
}
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)
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
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)
} else {
if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" {
// match
output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName)
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef)
}
}
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)
} else {
// not match
differences++
output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
}
}
}
@ -1017,7 +1125,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
}
@ -1102,3 +1210,89 @@ var spewConfig = spew.ConfigState{
type tHelper interface {
Helper()
}
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++ {
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++ {
f := runtimeFunc(actualOpts.Index(i).Interface())
actualFuncs = append(actualFuncs, f)
actualNames = append(actualNames, funcName(f))
}
if expectedOpts.Len() != actualOpts.Len() {
expectedFmt = fmt.Sprintf("%v", expectedNames)
actualFmt = fmt.Sprintf("%v", actualNames)
return
}
for i := 0; i < expectedOpts.Len(); i++ {
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
if ot.NumIn() == 0 {
return
}
for i := 0; i < ot.NumIn(); i++ {
vt := ot.In(i).Elem()
expectedValues = append(expectedValues, reflect.New(vt))
actualValues = append(actualValues, reflect.New(vt))
}
reflect.ValueOf(expectedOpt).Call(expectedValues)
reflect.ValueOf(actualOpt).Call(actualValues)
for i := 0; i < ot.NumIn(); i++ {
if 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
}
}
}
return "", ""
}
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

@ -32,6 +32,40 @@ func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
return args.Int(0), errors.New("Whoops")
}
type options struct {
num int
str string
}
type OptionFn func(*options)
func OpNum(n int) OptionFn {
return func(o *options) {
o.num = n
}
}
func OpStr(s string) OptionFn {
return func(o *options) {
o.str = s
}
}
func 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)
@ -113,7 +147,7 @@ func (m *MockTestingT) Errorf(string, ...interface{}) {
// the execution stops.
// When expecting this method, the call that invokes it should use the following code:
//
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
func (m *MockTestingT) FailNow() {
m.failNowCount++
@ -914,6 +948,26 @@ func Test_Mock_Return_NotBefore_In_Order(t *testing.T) {
})
}
func Test_Mock_Return_InOrder_Uses_NotBefore(t *testing.T) {
var mockedService = new(TestExampleImplementation)
InOrder(
mockedService.
On("TheExampleMethod", 1, 2, 3).
Return(4, nil),
mockedService.
On("TheExampleMethod2", true).
Return(),
)
require.NotPanics(t, func() {
mockedService.TheExampleMethod(1, 2, 3)
})
require.NotPanics(t, func() {
mockedService.TheExampleMethod2(true)
})
}
func Test_Mock_Return_NotBefore_Out_Of_Order(t *testing.T) {
var mockedService = new(TestExampleImplementation)
@ -944,6 +998,35 @@ TheExampleMethod(int,int,int)
})
}
func Test_Mock_Return_InOrder_Uses_NotBefore_Out_Of_Order(t *testing.T) {
var mockedService = new(TestExampleImplementation)
InOrder(
mockedService.
On("TheExampleMethod", 1, 2, 3).
Return(4, nil).Twice(),
mockedService.
On("TheExampleMethod2", true).
Return(),
)
expectedPanicString := `mock: Unexpected Method Call
-----------------------------
TheExampleMethod2(bool)
0: true
Must not be called before:
TheExampleMethod(int,int,int)
0: 1
1: 2
2: 3`
require.PanicsWithValue(t, expectedPanicString, func() {
mockedService.TheExampleMethod2(true)
})
}
func Test_Mock_Return_NotBefore_Not_Enough_Times(t *testing.T) {
var mockedService = new(TestExampleImplementation)
@ -999,6 +1082,7 @@ 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) {
var (
mockedService1 = new(TestExampleImplementation)
@ -1183,7 +1267,7 @@ func Test_Mock_Called_blocks(t *testing.T) {
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)
@ -1192,7 +1276,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
@ -1415,6 +1499,85 @@ func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
}
func Test_Mock_AssertExpectationsFunctionalOptionsType(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpNum(1), OpStr("foo"))).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.TheExampleMethodFunctionalOptions("test", OpNum(1), OpStr("foo"))
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Empty(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions()).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
mockedService.TheExampleMethodFunctionalOptions("test")
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Indirectly(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpNum(1), OpStr("foo"))).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
// make the call now
TheExampleMethodFunctionalOptionsIndirect(mockedService)
// now assert expectations
assert.True(t, mockedService.AssertExpectations(tt))
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Func(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
assert.Panics(t, func() {
mockedService.TheExampleMethodFunctionalOptions("test", OpBytes([]byte("this")))
})
}
func Test_Mock_AssertExpectationsFunctionalOptionsType_Diff_Arg(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("TheExampleMethodFunctionalOptions", "test", FunctionalOptions(OpStr("this"))).Return(nil).Once()
tt := new(testing.T)
assert.False(t, mockedService.AssertExpectations(tt))
assert.Panics(t, func() {
mockedService.TheExampleMethodFunctionalOptions("test", OpStr("that"))
})
}
func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
var mockedService = new(TestExampleImplementation)
@ -1436,6 +1599,16 @@ func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
}
func Test_Mock_AssertExpectations_Skipped_Test(t *testing.T) {
var mockedService = new(TestExampleImplementation)
mockedService.On("Test_Mock_AssertExpectations_Skipped_Test", 1, 2, 3).Return(5, 6, 7)
defer mockedService.AssertExpectations(t)
t.Skip("skipping test to ensure AssertExpectations does not fail")
}
func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
var mockedService = new(TestExampleImplementation)
@ -1559,17 +1732,14 @@ func Test_Mock_IsMethodCallable(t *testing.T) {
func TestIsArgsEqual(t *testing.T) {
var expected = Arguments{5, 3, 4, 6, 7, 2}
var args = make([]interface{}, 5)
for i := 1; i < len(expected); i++ {
args[i-1] = expected[i]
}
// Copy elements 1 to 5
args := append(([]interface{})(nil), expected[1:]...)
args[2] = expected[1]
assert.False(t, isArgsEqual(expected, args))
var arr = make([]interface{}, 6)
for i := 0; i < len(expected); i++ {
arr[i] = expected[i]
}
// Clone
arr := append(([]interface{})(nil), expected...)
assert.True(t, isArgsEqual(expected, arr))
}
@ -1599,7 +1769,7 @@ func Test_Mock_AssertOptional(t *testing.T) {
}
/*
Arguments helper methods
Arguments helper methods
*/
func Test_Arguments_Get(t *testing.T) {
@ -1905,7 +2075,7 @@ func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
end := time.Now()
elapsedTime := end.Sub(start)
assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs))
assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be at least greater than %v", elapsedTime, waitMs))
assert.Equal(t, total, len(results))
for i := range results {
assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same")
@ -1916,7 +2086,7 @@ func TestArgumentMatcherToPrintMismatch(t *testing.T) {
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)
}
}()
@ -1933,7 +2103,7 @@ func TestArgumentMatcherToPrintMismatchWithReferenceType(t *testing.T) {
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)
}
}()
@ -1964,7 +2134,7 @@ func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
func TestClosestCallFavorsFirstMock(t *testing.T) {
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)
}
@ -1980,7 +2150,7 @@ func TestClosestCallFavorsFirstMock(t *testing.T) {
func TestClosestCallUsesRepeatabilityToFindClosest(t *testing.T) {
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)
}
@ -2037,7 +2207,7 @@ func Test_isBetterMatchThanReturnsFalseIfRepeatabilityIsLessThanOrEqualToOther(t
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)
}

View File

@ -1,27 +1,30 @@
// Package require implements the same assertions as the `assert` package but
// stops test execution when a test fails.
//
// Example Usage
// # Example Usage
//
// The following is a complete example using require in a standard test function:
// import (
// "testing"
// "github.com/stretchr/testify/require"
// )
//
// func TestSomething(t *testing.T) {
// import (
// "testing"
// "github.com/stretchr/testify/require"
// )
//
// var a string = "Hello"
// var b string = "Hello"
// func TestSomething(t *testing.T) {
//
// require.Equal(t, a, b, "The two words should be the same.")
// var a string = "Hello"
// var b string = "Hello"
//
// }
// require.Equal(t, a, b, "The two words should be the same.")
//
// Assertions
// }
//
// # Assertions
//
// The `require` package have same global functions as in the `assert` package,
// 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.

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 }

File diff suppressed because it is too large Load Diff

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
@ -681,3 +683,30 @@ func TestErrorAssertionFunc(t *testing.T) {
})
}
}
func TestEventuallyWithTFalse(t *testing.T) {
mockT := new(MockT)
condition := func(collect *assert.CollectT) {
True(collect, false)
}
EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)
True(t, mockT.Failed, "Check should fail")
}
func TestEventuallyWithTTrue(t *testing.T) {
mockT := new(MockT)
counter := 0
condition := func(collect *assert.CollectT) {
defer func() {
counter += 1
}()
True(collect, counter == 1)
}
EventuallyWithT(mockT, condition, 100*time.Millisecond, 20*time.Millisecond)
False(t, mockT.Failed, "Check should pass")
Equal(t, 2, counter, "Condition is expected to be called 2 times")
}

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

View File

@ -58,7 +58,7 @@ func (suite *Suite) Require() *require.Assertions {
suite.mu.Lock()
defer suite.mu.Unlock()
if suite.require == nil {
suite.require = require.New(suite.T())
panic("'Require' must not be called before 'Run' or 'SetT'")
}
return suite.require
}
@ -72,17 +72,19 @@ func (suite *Suite) Assert() *assert.Assertions {
suite.mu.Lock()
defer suite.mu.Unlock()
if suite.Assertions == nil {
suite.Assertions = assert.New(suite.T())
panic("'Assert' must not be called before 'Run' or 'SetT'")
}
return suite.Assertions
}
func recoverAndFailOnPanic(t *testing.T) {
t.Helper()
r := recover()
failOnPanic(t, r)
}
func failOnPanic(t *testing.T, r interface{}) {
t.Helper()
if r != nil {
t.Errorf("test panicked: %v\n%s", r, debug.Stack())
t.FailNow()
@ -96,19 +98,20 @@ func failOnPanic(t *testing.T, r interface{}) {
func (suite *Suite) Run(name string, subtest func()) bool {
oldT := suite.T()
if setupSubTest, ok := suite.s.(SetupSubTest); ok {
setupSubTest.SetupSubTest()
}
defer func() {
suite.SetT(oldT)
if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
tearDownSubTest.TearDownSubTest()
}
}()
return oldT.Run(name, func(t *testing.T) {
suite.SetT(t)
defer suite.SetT(oldT)
defer recoverAndFailOnPanic(t)
if setupSubTest, ok := suite.s.(SetupSubTest); ok {
setupSubTest.SetupSubTest()
}
if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok {
defer tearDownSubTest.TearDownSubTest()
}
subtest()
})
}
@ -164,6 +167,8 @@ func Run(t *testing.T, suite TestingSuite) {
suite.SetT(t)
defer recoverAndFailOnPanic(t)
defer func() {
t.Helper()
r := recover()
if stats != nil {

View File

@ -4,7 +4,7 @@ import (
"bytes"
"errors"
"flag"
"io/ioutil"
"io"
"math/rand"
"os"
"os/exec"
@ -21,20 +21,20 @@ import (
type SuiteRequireTwice struct{ Suite }
// TestSuiteRequireTwice checks for regressions of issue #149 where
// suite.requirements was not initialised in suite.SetT()
// suite.requirements was not initialized in suite.SetT()
// A regression would result on these tests panicking rather than failing.
func TestSuiteRequireTwice(t *testing.T) {
ok := testing.RunTests(
allTestsFilter,
[]testing.InternalTest{{
Name: "TestSuiteRequireTwice",
Name: t.Name() + "/SuiteRequireTwice",
F: func(t *testing.T) {
suite := new(SuiteRequireTwice)
Run(t, suite)
},
}},
)
assert.Equal(t, false, ok)
assert.False(t, ok)
}
func (s *SuiteRequireTwice) TestRequireOne() {
@ -104,31 +104,31 @@ func TestSuiteRecoverPanic(t *testing.T) {
ok := true
panickingTests := []testing.InternalTest{
{
Name: "TestPanicInSetupSuite",
Name: t.Name() + "/InSetupSuite",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupSuite: true}) },
},
{
Name: "TestPanicInSetupTest",
Name: t.Name() + "/InSetupTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupTest: true}) },
},
{
Name: "TestPanicInBeforeTest",
Name: t.Name() + "InBeforeTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInBeforeTest: true}) },
},
{
Name: "TestPanicInTest",
Name: t.Name() + "/InTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTest: true}) },
},
{
Name: "TestPanicInAfterTest",
Name: t.Name() + "/InAfterTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInAfterTest: true}) },
},
{
Name: "TestPanicInTearDownTest",
Name: t.Name() + "/InTearDownTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownTest: true}) },
},
{
Name: "TestPanicInTearDownSuite",
Name: t.Name() + "/InTearDownSuite",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownSuite: true}) },
},
}
@ -162,6 +162,9 @@ type SuiteTester struct {
SetupSubTestRunCount int
TearDownSubTestRunCount int
SetupSubTestNames []string
TearDownSubTestNames []string
SuiteNameBefore []string
TestNameBefore []string
@ -258,10 +261,12 @@ func (suite *SuiteTester) TestSubtest() {
}
func (suite *SuiteTester) TearDownSubTest() {
suite.TearDownSubTestNames = append(suite.TearDownSubTestNames, suite.T().Name())
suite.TearDownSubTestRunCount++
}
func (suite *SuiteTester) SetupSubTest() {
suite.SetupSubTestNames = append(suite.SetupSubTestNames, suite.T().Name())
suite.SetupSubTestRunCount++
}
@ -301,13 +306,13 @@ func TestRunSuite(t *testing.T) {
// The suite was only run once, so the SetupSuite and TearDownSuite
// methods should have each been run only once.
assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
assert.Equal(t, 1, suiteTester.SetupSuiteRunCount)
assert.Equal(t, 1, suiteTester.TearDownSuiteRunCount)
assert.Equal(t, len(suiteTester.SuiteNameAfter), 4)
assert.Equal(t, len(suiteTester.SuiteNameBefore), 4)
assert.Equal(t, len(suiteTester.TestNameAfter), 4)
assert.Equal(t, len(suiteTester.TestNameBefore), 4)
assert.Len(t, suiteTester.SuiteNameAfter, 4)
assert.Len(t, suiteTester.SuiteNameBefore, 4)
assert.Len(t, suiteTester.TestNameAfter, 4)
assert.Len(t, suiteTester.TestNameBefore, 4)
assert.Contains(t, suiteTester.TestNameAfter, "TestOne")
assert.Contains(t, suiteTester.TestNameAfter, "TestTwo")
@ -319,6 +324,12 @@ func TestRunSuite(t *testing.T) {
assert.Contains(t, suiteTester.TestNameBefore, "TestSkip")
assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest")
assert.Contains(t, suiteTester.SetupSubTestNames, "TestRunSuite/TestSubtest/first")
assert.Contains(t, suiteTester.SetupSubTestNames, "TestRunSuite/TestSubtest/second")
assert.Contains(t, suiteTester.TearDownSubTestNames, "TestRunSuite/TestSubtest/first")
assert.Contains(t, suiteTester.TearDownSubTestNames, "TestRunSuite/TestSubtest/second")
for _, suiteName := range suiteTester.SuiteNameAfter {
assert.Equal(t, "SuiteTester", suiteName)
}
@ -338,20 +349,20 @@ func TestRunSuite(t *testing.T) {
// There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so
// the SetupTest and TearDownTest methods (which should be run once for
// each test) should have been run four times.
assert.Equal(t, suiteTester.SetupTestRunCount, 4)
assert.Equal(t, suiteTester.TearDownTestRunCount, 4)
assert.Equal(t, 4, suiteTester.SetupTestRunCount)
assert.Equal(t, 4, suiteTester.TearDownTestRunCount)
// Each test should have been run once.
assert.Equal(t, suiteTester.TestOneRunCount, 1)
assert.Equal(t, suiteTester.TestTwoRunCount, 1)
assert.Equal(t, suiteTester.TestSubtestRunCount, 1)
assert.Equal(t, 1, suiteTester.TestOneRunCount)
assert.Equal(t, 1, suiteTester.TestTwoRunCount)
assert.Equal(t, 1, suiteTester.TestSubtestRunCount)
assert.Equal(t, suiteTester.TearDownSubTestRunCount, 2)
assert.Equal(t, suiteTester.SetupSubTestRunCount, 2)
assert.Equal(t, 2, suiteTester.TearDownSubTestRunCount)
assert.Equal(t, 2, suiteTester.SetupSubTestRunCount)
// Methods that don't match the test method identifier shouldn't
// have been run at all.
assert.Equal(t, suiteTester.NonTestMethodRunCount, 0)
assert.Equal(t, 0, suiteTester.NonTestMethodRunCount)
suiteSkipTester := new(SuiteSkipTester)
Run(t, suiteSkipTester)
@ -359,8 +370,8 @@ func TestRunSuite(t *testing.T) {
// The suite was only run once, so the SetupSuite and TearDownSuite
// methods should have each been run only once, even though SetupSuite
// called Skip()
assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1)
assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1)
assert.Equal(t, 1, suiteSkipTester.SetupSuiteRunCount)
assert.Equal(t, 1, suiteSkipTester.TearDownSuiteRunCount)
}
@ -429,7 +440,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
}
@ -440,7 +451,7 @@ func TestSuiteLogging(t *testing.T) {
suiteLoggingTester := new(SuiteLoggingTester)
capture := StdoutCapture{}
internalTest := testing.InternalTest{
Name: "SomeTest",
Name: t.Name() + "/SuiteLoggingTester",
F: func(subT *testing.T) {
Run(subT, suiteLoggingTester)
},
@ -481,7 +492,7 @@ func (s *CallOrderSuite) SetupSuite() {
func (s *CallOrderSuite) TearDownSuite() {
s.call("TearDownSuite")
assert.Equal(s.T(), "SetupSuite;SetupTest;Test A;TearDownTest;SetupTest;Test B;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
assert.Equal(s.T(), "SetupSuite;SetupTest;Test A;SetupSubTest;SubTest A1;TearDownSubTest;SetupSubTest;SubTest A2;TearDownSubTest;TearDownTest;SetupTest;Test B;SetupSubTest;SubTest B1;TearDownSubTest;SetupSubTest;SubTest B2;TearDownSubTest;TearDownTest;TearDownSuite", strings.Join(s.callOrder, ";"))
}
func (s *CallOrderSuite) SetupTest() {
s.call("SetupTest")
@ -491,12 +502,32 @@ func (s *CallOrderSuite) TearDownTest() {
s.call("TearDownTest")
}
func (s *CallOrderSuite) SetupSubTest() {
s.call("SetupSubTest")
}
func (s *CallOrderSuite) TearDownSubTest() {
s.call("TearDownSubTest")
}
func (s *CallOrderSuite) Test_A() {
s.call("Test A")
s.Run("SubTest A1", func() {
s.call("SubTest A1")
})
s.Run("SubTest A2", func() {
s.call("SubTest A2")
})
}
func (s *CallOrderSuite) Test_B() {
s.call("Test B")
s.Run("SubTest B1", func() {
s.call("SubTest B1")
})
s.Run("SubTest B2", func() {
s.call("SubTest B2")
})
}
type suiteWithStats struct {
@ -521,14 +552,15 @@ func (s *suiteWithStats) TestPanic() {
func TestSuiteWithStats(t *testing.T) {
suiteWithStats := new(suiteWithStats)
testing.RunTests(allTestsFilter, []testing.InternalTest{
suiteSuccess := testing.RunTests(allTestsFilter, []testing.InternalTest{
{
Name: "WithStats",
Name: t.Name() + "/suiteWithStats",
F: func(t *testing.T) {
Run(t, suiteWithStats)
},
},
})
require.False(t, suiteSuccess, "suiteWithStats should report test failure because of panic in TestPanic")
assert.True(t, suiteWithStats.wasCalled)
assert.NotZero(t, suiteWithStats.stats.Start)
@ -565,21 +597,51 @@ func TestFailfastSuite(t *testing.T) {
ok := testing.RunTests(
allTestsFilter,
[]testing.InternalTest{{
Name: "TestFailfastSuite",
Name: t.Name() + "/FailfastSuite",
F: func(t *testing.T) {
Run(t, s)
},
}},
)
assert.Equal(t, false, ok)
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")
@ -617,3 +679,70 @@ func (s *FailfastSuite) Test_B_Passes() {
s.call("Test B Passes")
s.Require().True(true)
}
type subtestPanicSuite struct {
Suite
inTearDownSuite bool
inTearDownTest bool
inTearDownSubTest bool
}
func (s *subtestPanicSuite) TearDownSuite() {
s.inTearDownSuite = true
}
func (s *subtestPanicSuite) TearDownTest() {
s.inTearDownTest = true
}
func (s *subtestPanicSuite) TearDownSubTest() {
s.inTearDownSubTest = true
}
func (s *subtestPanicSuite) TestSubtestPanic() {
ok := s.Run("subtest", func() {
panic("panic")
})
s.False(ok, "subtest failure is expected")
}
func TestSubtestPanic(t *testing.T) {
suite := new(subtestPanicSuite)
ok := testing.RunTests(
allTestsFilter,
[]testing.InternalTest{{
Name: t.Name() + "/subtestPanicSuite",
F: func(t *testing.T) {
Run(t, suite)
},
}},
)
assert.False(t, ok, "TestSubtestPanic/subtest should make the testsuite fail")
assert.True(t, suite.inTearDownSubTest)
assert.True(t, suite.inTearDownTest)
assert.True(t, suite.inTearDownSuite)
}
type unInitializedSuite struct {
Suite
}
// TestUnInitializedSuites asserts the behavior of the suite methods when the
// suite is not initialized
func TestUnInitializedSuites(t *testing.T) {
t.Run("should panic on Require", func(t *testing.T) {
suite := new(unInitializedSuite)
assert.Panics(t, func() {
suite.Require().True(true)
})
})
t.Run("should panic on Assert", func(t *testing.T) {
suite := new(unInitializedSuite)
assert.Panics(t, func() {
suite.Assert().True(true)
})
})
}