From d4a63f5b89ec8c392fe4066e3a91b48dc10fe92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Mengu=C3=A9?= Date: Thu, 7 Mar 2024 00:23:10 +0100 Subject: [PATCH 01/14] mock: simplify implementation of FunctionalOptions Remove unnecessary use of reflect in the implementation of mock.FunctionalOptions(). --- mock/mock.go | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/mock/mock.go b/mock/mock.go index 876371d..9062f01 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -803,21 +803,20 @@ func IsType(t interface{}) *IsTypeArgument { return &IsTypeArgument{t: reflect.TypeOf(t)} } -// FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument -// for use when type checking. +// FunctionalOptionsArgument contains a list of functional options arguments +// expected for use when matching a list of arguments. type FunctionalOptionsArgument struct { - value interface{} + values []interface{} } // String returns the string representation of FunctionalOptionsArgument func (f *FunctionalOptionsArgument) String() string { var name string - tValue := reflect.ValueOf(f.value) - if tValue.Len() > 0 { - name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String() + if len(f.values) > 0 { + name = "[]" + reflect.TypeOf(f.values[0]).String() } - return strings.Replace(fmt.Sprintf("%#v", f.value), "[]interface {}", name, 1) + return strings.Replace(fmt.Sprintf("%#v", f.values), "[]interface {}", name, 1) } // FunctionalOptions returns an [FunctionalOptionsArgument] object containing @@ -825,10 +824,10 @@ func (f *FunctionalOptionsArgument) String() string { // // For example: // -// Assert(t, FunctionalOptions(foo.Opt1("strValue"), foo.Opt2(613))) -func FunctionalOptions(value ...interface{}) *FunctionalOptionsArgument { +// args.Assert(t, FunctionalOptions(foo.Opt1("strValue"), foo.Opt2(613))) +func FunctionalOptions(values ...interface{}) *FunctionalOptionsArgument { return &FunctionalOptionsArgument{ - value: value, + values: values, } } @@ -982,20 +981,17 @@ func (args Arguments) Diff(objects []interface{}) (string, int) { output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt) } case *FunctionalOptionsArgument: - t := expected.value - var name string - tValue := reflect.ValueOf(t) - if tValue.Len() > 0 { - name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String() + if len(expected.values) > 0 { + name = "[]" + reflect.TypeOf(expected.values[0]).String() } - tName := reflect.TypeOf(t).Name() - if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 { + const tName = "[]interface{}" + if name != reflect.TypeOf(actual).String() && len(expected.values) != 0 { differences++ output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt) } else { - if ef, af := assertOpts(t, actual); ef == "" && af == "" { + if ef, af := assertOpts(expected.values, actual); ef == "" && af == "" { // match output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName) } else { From 52df55490e922b9229bf066cd8f28664cf84de33 Mon Sep 17 00:00:00 2001 From: Harald Nordgren Date: Wed, 24 Jul 2024 13:39:26 +0200 Subject: [PATCH 02/14] .github/workflows: Run tests for Go 1.22 --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9458c39..1dd4e65 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,6 +29,7 @@ jobs: - "1.19" - "1.20" - "1.21" + - "1.22" steps: - uses: actions/checkout@v4 - name: Setup Go From 7268a5bc0bb240a58a3f85d04076ad9ae13e2cb2 Mon Sep 17 00:00:00 2001 From: Reynier Ortiz Date: Fri, 6 Sep 2024 09:18:07 -0400 Subject: [PATCH 03/14] mock: in order mock calls --- mock/mock.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mock/mock.go b/mock/mock.go index d5eb1ef..6446445 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -273,6 +273,13 @@ func (c *Call) NotBefore(calls ...*Call) *Call { return c } +// InOrder defines the order in which the calls should be made +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. From bdb1271ed89c8de6881bc02cfe700bb91bc9a990 Mon Sep 17 00:00:00 2001 From: Reynier Ortiz Date: Fri, 6 Sep 2024 09:18:07 -0400 Subject: [PATCH 04/14] mock: in order mock calls --- mock/mock_test.go | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/mock/mock_test.go b/mock/mock_test.go index b80a8a7..bc3c5ad 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -937,6 +937,30 @@ func Test_Mock_Return_NotBefore_In_Order(t *testing.T) { }) } +func Test_Mock_Return_InOrder_Uses_NotBefore(t *testing.T) { + var mockedService = new(TestExampleImplementation) + + b := mockedService. + On("TheExampleMethod", 1, 2, 3). + Return(4, nil) + c := mockedService. + On("TheExampleMethod2", true). + Return() + + InOrder( + b, + c, + ) + + require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) + 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) @@ -967,6 +991,40 @@ TheExampleMethod(int,int,int) }) } +func Test_Mock_Return_InOrder_Uses_NotBefore_Out_Of_Order(t *testing.T) { + var mockedService = new(TestExampleImplementation) + + b := mockedService. + On("TheExampleMethod", 1, 2, 3). + Return(4, nil).Twice() + c := mockedService. + On("TheExampleMethod2", true). + Return() + + InOrder( + b, + c, + ) + + require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) + + 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) @@ -1022,6 +1080,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) From f17409f81f93ebd964caa7a36793134d68e23fdb Mon Sep 17 00:00:00 2001 From: Reynier Ortiz Date: Fri, 6 Sep 2024 09:18:07 -0400 Subject: [PATCH 05/14] mock: in order mock calls (requested changes applied) --- mock/mock.go | 7 +++++++ mock/mock_test.go | 33 ++++++++++++--------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/mock/mock.go b/mock/mock.go index 6446445..920a87a 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -274,6 +274,13 @@ func (c *Call) NotBefore(calls ...*Call) *Call { } // 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]) diff --git a/mock/mock_test.go b/mock/mock_test.go index bc3c5ad..4878b67 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -940,19 +940,15 @@ func Test_Mock_Return_NotBefore_In_Order(t *testing.T) { func Test_Mock_Return_InOrder_Uses_NotBefore(t *testing.T) { var mockedService = new(TestExampleImplementation) - b := mockedService. - On("TheExampleMethod", 1, 2, 3). - Return(4, nil) - c := mockedService. - On("TheExampleMethod2", true). - Return() - InOrder( - b, - c, + mockedService. + On("TheExampleMethod", 1, 2, 3). + Return(4, nil), + mockedService. + On("TheExampleMethod2", true). + Return(), ) - require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) require.NotPanics(t, func() { mockedService.TheExampleMethod(1, 2, 3) }) @@ -994,20 +990,15 @@ TheExampleMethod(int,int,int) func Test_Mock_Return_InOrder_Uses_NotBefore_Out_Of_Order(t *testing.T) { var mockedService = new(TestExampleImplementation) - b := mockedService. - On("TheExampleMethod", 1, 2, 3). - Return(4, nil).Twice() - c := mockedService. - On("TheExampleMethod2", true). - Return() - InOrder( - b, - c, + mockedService. + On("TheExampleMethod", 1, 2, 3). + Return(4, nil).Twice(), + mockedService. + On("TheExampleMethod2", true). + Return(), ) - require.Equal(t, []*Call{b, c}, mockedService.ExpectedCalls) - expectedPanicString := `mock: Unexpected Method Call ----------------------------- From ea6964c2e96c2c682acc94781c71d861e21c94fc Mon Sep 17 00:00:00 2001 From: spirin Date: Mon, 30 Sep 2024 21:33:46 +0300 Subject: [PATCH 06/14] mock: caller information for unexpected method call --- mock/mock.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mock/mock.go b/mock/mock.go index d5eb1ef..a4b7b08 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -491,11 +491,12 @@ 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()) From d62ca68bf5d930468044ce3b7286c12a63079c22 Mon Sep 17 00:00:00 2001 From: spirin Date: Tue, 1 Oct 2024 02:21:38 +0300 Subject: [PATCH 07/14] tests --- mock/mock_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mock/mock_test.go b/mock/mock_test.go index b80a8a7..95159d8 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -1980,7 +1980,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) } }() @@ -1997,7 +1997,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) } }() @@ -2028,7 +2028,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) } @@ -2044,7 +2044,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) } @@ -2101,7 +2101,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) } From fed9ee68dc942c41c77a9b2c2431f3c2967c00ae Mon Sep 17 00:00:00 2001 From: Bracken Dawson Date: Tue, 1 Oct 2024 23:55:16 +0100 Subject: [PATCH 08/14] Document suite's lack of support for t.Parallel --- README.md | 2 ++ suite/doc.go | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 0250c3e..ccaa758 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,8 @@ You can use the [mockery tool](https://vektra.github.io/mockery/latest/) to auto [`suite`](https://pkg.go.dev/github.com/stretchr/testify/suite "API documentation") package ----------------------------------------------------------------------------------------- +> [!WARNING] +> The suite package does not support parallel tests. See [#934](https://github.com/stretchr/testify/issues/934). The `suite` package provides functionality that you might be used to from more common object-oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal. diff --git a/suite/doc.go b/suite/doc.go index 8d55a3a..05a562f 100644 --- a/suite/doc.go +++ b/suite/doc.go @@ -5,6 +5,8 @@ // or individual tests (depending on which interface(s) you // implement). // +// The suite package does not support parallel tests. See [issue 934]. +// // A testing suite is usually built by first extending the built-in // suite functionality from suite.Suite in testify. Alternatively, // you could reproduce that logic on your own if you wanted (you @@ -63,4 +65,6 @@ // func TestExampleTestSuite(t *testing.T) { // suite.Run(t, new(ExampleTestSuite)) // } +// +// [issue 934]: https://github.com/stretchr/testify/issues/934 package suite From 3380867632684d2023eeeb0d5d1d45a7b89e6972 Mon Sep 17 00:00:00 2001 From: Pal Sivertsen Date: Tue, 30 Nov 2021 14:26:04 +0100 Subject: [PATCH 09/14] 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`. --- assert/assertion_format.go | 9 +++++++++ assert/assertion_forward.go | 18 ++++++++++++++++++ assert/assertions.go | 18 ++++++++++++++++++ assert/assertions_test.go | 27 ++++++++++++++++++++++++++- require/require.go | 24 ++++++++++++++++++++++++ require/require_forward.go | 18 ++++++++++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) diff --git a/assert/assertion_format.go b/assert/assertion_format.go index 546fe1f..1db3955 100644 --- a/assert/assertion_format.go +++ b/assert/assertion_format.go @@ -621,6 +621,15 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } +// NotErrorAsf asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +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 { diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go index 8504dca..a658b4d 100644 --- a/assert/assertion_forward.go +++ b/assert/assertion_forward.go @@ -1234,6 +1234,24 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str return NotEqualf(a.t, expected, actual, msg, args...) } +// NotErrorAs asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorAs(a.t, err, target, msgAndArgs...) +} + +// NotErrorAsf asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorAsf(a.t, err, target, msg, args...) +} + // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { diff --git a/assert/assertions.go b/assert/assertions.go index 104a0c9..5ace3d4 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -2149,6 +2149,24 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{ ), msgAndArgs...) } +// NotErrorAs asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !errors.As(err, target) { + return true + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ + "found: %q\n"+ + "in chain: %s", target, chain, + ), msgAndArgs...) +} + func buildErrorChainString(err error) string { if err == nil { return "" diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 064b92f..228f20a 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -3284,7 +3284,32 @@ func TestErrorAs(t *testing.T) { t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) { res := ErrorAs(mockT, tt.err, &target) if res != tt.result { - t.Errorf("ErrorAs(%#v,%#v) should return %t)", tt.err, target, tt.result) + t.Errorf("ErrorAs(%#v,%#v) should return %t", tt.err, target, tt.result) + } + }) + } +} + +func TestNotErrorAs(t *testing.T) { + tests := []struct { + err error + result bool + }{ + {fmt.Errorf("wrap: %w", &customError{}), false}, + {io.EOF, true}, + {nil, true}, + } + for _, tt := range tests { + tt := tt + var target *customError + t.Run(fmt.Sprintf("NotErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) { + mockT := new(testing.T) + res := NotErrorAs(mockT, tt.err, &target) + if res != tt.result { + t.Errorf("NotErrorAs(%#v,%#v) should not return %t", tt.err, target, tt.result) + } + if res == mockT.Failed() { + t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !mockT.Failed()) } }) } diff --git a/require/require.go b/require/require.go index d0c73ff..bf9877c 100644 --- a/require/require.go +++ b/require/require.go @@ -1559,6 +1559,30 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } +// NotErrorAs asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorAs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotErrorAsf asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorAsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { diff --git a/require/require_forward.go b/require/require_forward.go index 3c15ca3..521daaf 100644 --- a/require/require_forward.go +++ b/require/require_forward.go @@ -1235,6 +1235,24 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str NotEqualf(a.t, expected, actual, msg, args...) } +// NotErrorAs asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorAs(a.t, err, target, msgAndArgs...) +} + +// NotErrorAsf asserts that at none of the errors in err's chain matches target. +// This is the inverse of the ErrorAs function. +func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorAsf(a.t, err, target, msg, args...) +} + // NotErrorIs asserts that none of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { From aade8450b3812d4f2e5d4cb65769b264c4604328 Mon Sep 17 00:00:00 2001 From: Pal Sivertsen Date: Tue, 30 Nov 2021 14:29:39 +0100 Subject: [PATCH 10/14] Improve tests for ErrorIs/ErrorAs Checks that the assertion result matches what's set in `testing.T`. --- assert/assertions_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 228f20a..20d63b1 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -3269,7 +3269,6 @@ func TestNotErrorIs(t *testing.T) { } func TestErrorAs(t *testing.T) { - mockT := new(testing.T) tests := []struct { err error result bool @@ -3282,10 +3281,14 @@ func TestErrorAs(t *testing.T) { tt := tt var target *customError t.Run(fmt.Sprintf("ErrorAs(%#v,%#v)", tt.err, target), func(t *testing.T) { + mockT := new(testing.T) res := ErrorAs(mockT, tt.err, &target) if res != tt.result { t.Errorf("ErrorAs(%#v,%#v) should return %t", tt.err, target, tt.result) } + if res == mockT.Failed() { + t.Errorf("The test result (%t) should be reflected in the testing.T type (%t)", res, !mockT.Failed()) + } }) } } From dc100b1be3ac644d59bccf1f4b9b00261eb10f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Sivertsen?= Date: Fri, 4 Oct 2024 09:52:45 +0200 Subject: [PATCH 11/14] Review: Drop doc line and fix typo Review feedback: https://github.com/stretchr/testify/pull/1129#discussion_r1786495803 --- assert/assertion_format.go | 3 +-- assert/assertion_forward.go | 6 ++---- assert/assertions.go | 3 +-- require/require.go | 6 ++---- require/require_forward.go | 6 ++---- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/assert/assertion_format.go b/assert/assertion_format.go index 1db3955..2dff9e4 100644 --- a/assert/assertion_format.go +++ b/assert/assertion_format.go @@ -621,8 +621,7 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } -// NotErrorAsf asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAsf asserts that none of the errors in err's chain matches target. func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go index a658b4d..7bcc9f0 100644 --- a/assert/assertion_forward.go +++ b/assert/assertion_forward.go @@ -1234,8 +1234,7 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str return NotEqualf(a.t, expected, actual, msg, args...) } -// NotErrorAs asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAs asserts that none of the errors in err's chain matches target. func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1243,8 +1242,7 @@ func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...int return NotErrorAs(a.t, err, target, msgAndArgs...) } -// NotErrorAsf asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAsf asserts that none of the errors in err's chain matches target. func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/assert/assertions.go b/assert/assertions.go index 5ace3d4..4ebe302 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -2149,8 +2149,7 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{ ), msgAndArgs...) } -// NotErrorAs asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAs asserts that none of the errors in err's chain matches target. func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/require/require.go b/require/require.go index bf9877c..9871d08 100644 --- a/require/require.go +++ b/require/require.go @@ -1559,8 +1559,7 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } -// NotErrorAs asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAs asserts that none of the errors in err's chain matches target. func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1571,8 +1570,7 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa t.FailNow() } -// NotErrorAsf asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAsf asserts that none of the errors in err's chain matches target. func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/require/require_forward.go b/require/require_forward.go index 521daaf..34ac533 100644 --- a/require/require_forward.go +++ b/require/require_forward.go @@ -1235,8 +1235,7 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str NotEqualf(a.t, expected, actual, msg, args...) } -// NotErrorAs asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAs asserts that none of the errors in err's chain matches target. func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1244,8 +1243,7 @@ func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...int NotErrorAs(a.t, err, target, msgAndArgs...) } -// NotErrorAsf asserts that at none of the errors in err's chain matches target. -// This is the inverse of the ErrorAs function. +// NotErrorAsf asserts that none of the errors in err's chain matches target. func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() From f844b269dfdaed00db57ff08e2ff601daa349e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Sivertsen?= Date: Fri, 4 Oct 2024 12:37:24 +0200 Subject: [PATCH 12/14] Review: Expand NotErrorAs func docs https://github.com/stretchr/testify/pull/1129#discussion_r1787490770 --- assert/assertion_format.go | 3 ++- assert/assertion_forward.go | 6 ++++-- assert/assertions.go | 3 ++- require/require.go | 6 ++++-- require/require_forward.go | 6 ++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/assert/assertion_format.go b/assert/assertion_format.go index 2dff9e4..1906341 100644 --- a/assert/assertion_format.go +++ b/assert/assertion_format.go @@ -621,7 +621,8 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } -// NotErrorAsf asserts that 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() diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go index 7bcc9f0..2162908 100644 --- a/assert/assertion_forward.go +++ b/assert/assertion_forward.go @@ -1234,7 +1234,8 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str return NotEqualf(a.t, expected, actual, msg, args...) } -// NotErrorAs asserts that none of the errors in err's chain matches target. +// NotErrorAs asserts that none of the errors in err's chain matches target, +// but if so, sets target to that error value. func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1242,7 +1243,8 @@ func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...int return NotErrorAs(a.t, err, target, msgAndArgs...) } -// NotErrorAsf asserts that 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 (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/assert/assertions.go b/assert/assertions.go index 4ebe302..44b854d 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -2149,7 +2149,8 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{ ), msgAndArgs...) } -// NotErrorAs asserts that none of the errors in err's chain matches target. +// NotErrorAs asserts that none of the errors in err's chain matches target, +// but if so, sets target to that error value. func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/require/require.go b/require/require.go index 9871d08..50ec19e 100644 --- a/require/require.go +++ b/require/require.go @@ -1559,7 +1559,8 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } -// NotErrorAs asserts that none of the errors in err's chain matches target. +// NotErrorAs asserts that none of the errors in err's chain matches target, +// but if so, sets target to that error value. func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1570,7 +1571,8 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa t.FailNow() } -// NotErrorAsf asserts that 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{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/require/require_forward.go b/require/require_forward.go index 34ac533..1bd8730 100644 --- a/require/require_forward.go +++ b/require/require_forward.go @@ -1235,7 +1235,8 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str NotEqualf(a.t, expected, actual, msg, args...) } -// NotErrorAs asserts that none of the errors in err's chain matches target. +// NotErrorAs asserts that none of the errors in err's chain matches target, +// but if so, sets target to that error value. func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1243,7 +1244,8 @@ func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...int NotErrorAs(a.t, err, target, msgAndArgs...) } -// NotErrorAsf asserts that 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 (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() From 2063e816961eecfd3a9f80e13fa69f7ef66a4c54 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Fri, 4 Oct 2024 18:02:45 +0300 Subject: [PATCH 13/14] assert: fix typos in comments --- assert/assertions_test.go | 2 +- assert/yaml/yaml_custom.go | 2 +- assert/yaml/yaml_default.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index 20d63b1..e158688 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -1327,7 +1327,7 @@ func TestNotElementsMatch(t *testing.T) { actual interface{} result bool }{ - // not mathing + // not matching {[]int{1}, []int{}, true}, {[]int{}, []int{2}, true}, {[]int{1}, []int{2}, true}, diff --git a/assert/yaml/yaml_custom.go b/assert/yaml/yaml_custom.go index bc32dc9..baa0cc7 100644 --- a/assert/yaml/yaml_custom.go +++ b/assert/yaml/yaml_custom.go @@ -15,7 +15,7 @@ // import assertYaml "github.com/stretchr/testify/assert/yaml" // // func init() { -// assertYaml.Unmarshall = func (in []byte, out interface{}) error { +// assertYaml.Unmarshal = func (in []byte, out interface{}) error { // // ... // return nil // } diff --git a/assert/yaml/yaml_default.go b/assert/yaml/yaml_default.go index 9a92eed..b83c6cf 100644 --- a/assert/yaml/yaml_default.go +++ b/assert/yaml/yaml_default.go @@ -5,7 +5,7 @@ // // This package is just an indirection that allows the builder to override the // indirection with an alternative implementation of this package that uses -// another implemantation of YAML deserialization. This allows to not either not +// 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]). // From ba3e7c34d5ee33bd1dd7d6835daafeaa093525ca Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Fri, 4 Oct 2024 18:06:40 +0300 Subject: [PATCH 14/14] mock: fix doc comment for NotBefore --- mock/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mock/mock.go b/mock/mock.go index 41257fb..0c30941 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -256,7 +256,7 @@ func (c *Call) Unset() *Call { // calls have been called as expected. The referenced calls may be from the // same mock instance and/or other mock instances. // -// Mock.On("Do").Return(nil).Notbefore( +// Mock.On("Do").Return(nil).NotBefore( // Mock.On("Init").Return(nil) // ) func (c *Call) NotBefore(calls ...*Call) *Call {