Skip to content

Commit dce9e58

Browse files
Merge branch 'master' into fix/equal-exported-values-accepts-everything
2 parents df81388 + 75a239b commit dce9e58

17 files changed

+707
-234
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jobs:
2929
- "1.19"
3030
- "1.20"
3131
- "1.21"
32+
- "1.22"
3233
steps:
3334
- uses: actions/checkout@v4
3435
- name: Setup Go

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ You can use the [mockery tool](https://vektra.github.io/mockery/latest/) to auto
223223

224224
[`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package
225225
-----------------------------------------------------------------------------------------
226+
> [!WARNING]
227+
> The suite package does not support parallel tests. See [#934](https://github.com/stretchr/testify/issues/934).
226228
227229
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.
228230

_codegen/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ func parseTemplates() (*template.Template, *template.Template, error) {
107107
}
108108
funcTemplate = string(f)
109109
}
110-
tmpl, err := template.New("function").Parse(funcTemplate)
110+
tmpl, err := template.New("function").Funcs(template.FuncMap{
111+
"replace": strings.ReplaceAll,
112+
}).Parse(funcTemplate)
111113
if err != nil {
112114
return nil, nil, err
113115
}

assert/assertion_format.go

Lines changed: 27 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assert/assertion_forward.go

Lines changed: 54 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assert/assertions.go

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,39 @@ func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) stri
11611161
return msg.String()
11621162
}
11631163

1164+
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
1165+
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
1166+
// the number of appearances of each of them in both lists should not match.
1167+
// This is an inverse of ElementsMatch.
1168+
//
1169+
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
1170+
//
1171+
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
1172+
//
1173+
// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
1174+
func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
1175+
if h, ok := t.(tHelper); ok {
1176+
h.Helper()
1177+
}
1178+
if isEmpty(listA) && isEmpty(listB) {
1179+
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
1180+
}
1181+
1182+
if !isList(t, listA, msgAndArgs...) {
1183+
return Fail(t, "listA is not a list type", msgAndArgs...)
1184+
}
1185+
if !isList(t, listB, msgAndArgs...) {
1186+
return Fail(t, "listB is not a list type", msgAndArgs...)
1187+
}
1188+
1189+
extraA, extraB := diffLists(listA, listB)
1190+
if len(extraA) == 0 && len(extraB) == 0 {
1191+
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
1192+
}
1193+
1194+
return true
1195+
}
1196+
11641197
// Condition uses a Comparison to assert a complex condition.
11651198
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
11661199
if h, ok := t.(tHelper); ok {
@@ -1908,6 +1941,9 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
19081941

19091942
// CollectT implements the TestingT interface and collects all errors.
19101943
type CollectT struct {
1944+
// A slice of errors. Non-nil slice denotes a failure.
1945+
// If it's non-nil but len(c.errors) == 0, this is also a failure
1946+
// obtained by direct c.FailNow() call.
19111947
errors []error
19121948
}
19131949

@@ -1916,9 +1952,10 @@ func (c *CollectT) Errorf(format string, args ...interface{}) {
19161952
c.errors = append(c.errors, fmt.Errorf(format, args...))
19171953
}
19181954

1919-
// FailNow panics.
1920-
func (*CollectT) FailNow() {
1921-
panic("Assertion failed")
1955+
// FailNow stops execution by calling runtime.Goexit.
1956+
func (c *CollectT) FailNow() {
1957+
c.fail()
1958+
runtime.Goexit()
19221959
}
19231960

19241961
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
@@ -1931,6 +1968,16 @@ func (*CollectT) Copy(TestingT) {
19311968
panic("Copy() is deprecated")
19321969
}
19331970

1971+
func (c *CollectT) fail() {
1972+
if !c.failed() {
1973+
c.errors = []error{} // Make it non-nil to mark a failure.
1974+
}
1975+
}
1976+
1977+
func (c *CollectT) failed() bool {
1978+
return c.errors != nil
1979+
}
1980+
19341981
// EventuallyWithT asserts that given condition will be met in waitFor time,
19351982
// periodically checking target function each tick. In contrast to Eventually,
19361983
// it supplies a CollectT to the condition function, so that the condition
@@ -1955,7 +2002,7 @@ func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time
19552002
}
19562003

19572004
var lastFinishedTickErrs []error
1958-
ch := make(chan []error, 1)
2005+
ch := make(chan *CollectT, 1)
19592006

19602007
timer := time.NewTimer(waitFor)
19612008
defer timer.Stop()
@@ -1975,16 +2022,16 @@ func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time
19752022
go func() {
19762023
collect := new(CollectT)
19772024
defer func() {
1978-
ch <- collect.errors
2025+
ch <- collect
19792026
}()
19802027
condition(collect)
19812028
}()
1982-
case errs := <-ch:
1983-
if len(errs) == 0 {
2029+
case collect := <-ch:
2030+
if !collect.failed() {
19842031
return true
19852032
}
19862033
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
1987-
lastFinishedTickErrs = errs
2034+
lastFinishedTickErrs = collect.errors
19882035
tick = ticker.C
19892036
}
19902037
}
@@ -2046,7 +2093,7 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
20462093
), msgAndArgs...)
20472094
}
20482095

2049-
// NotErrorIs asserts that at none of the errors in err's chain matches target.
2096+
// NotErrorIs asserts that none of the errors in err's chain matches target.
20502097
// This is a wrapper for errors.Is.
20512098
func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
20522099
if h, ok := t.(tHelper); ok {
@@ -2087,6 +2134,24 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
20872134
), msgAndArgs...)
20882135
}
20892136

2137+
// NotErrorAs asserts that none of the errors in err's chain matches target,
2138+
// but if so, sets target to that error value.
2139+
func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
2140+
if h, ok := t.(tHelper); ok {
2141+
h.Helper()
2142+
}
2143+
if !errors.As(err, target) {
2144+
return true
2145+
}
2146+
2147+
chain := buildErrorChainString(err)
2148+
2149+
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
2150+
"found: %q\n"+
2151+
"in chain: %s", target, chain,
2152+
), msgAndArgs...)
2153+
}
2154+
20902155
func buildErrorChainString(err error) string {
20912156
if err == nil {
20922157
return ""

0 commit comments

Comments
 (0)