diff --git a/assert/assertion_format.go b/assert/assertion_format.go index 7880b8f94..90761d0a4 100644 --- a/assert/assertion_format.go +++ b/assert/assertion_format.go @@ -659,6 +659,18 @@ func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...) } +// PanicsWithErrorIsf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// assert.PanicsWithErrorIsf(t, expectedError, func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorIsf(t TestingT, expectedError error, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return PanicsWithErrorIs(t, expectedError, f, append([]interface{}{msg}, args...)...) +} + // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // diff --git a/assert/assertion_forward.go b/assert/assertion_forward.go index 339515b8b..2a6f3f590 100644 --- a/assert/assertion_forward.go +++ b/assert/assertion_forward.go @@ -1285,6 +1285,30 @@ func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndAr return PanicsWithError(a.t, errString, f, msgAndArgs...) } +// PanicsWithErrorIs asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// a.PanicsWithErrorIs(expectedError, func(){ GoCrazy() }) +func (a *Assertions) PanicsWithErrorIs(expectedError error, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithErrorIs(a.t, expectedError, f, msgAndArgs...) +} + +// PanicsWithErrorIsf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// a.PanicsWithErrorIsf(expectedError, func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorIsf(expectedError error, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithErrorIsf(a.t, expectedError, f, msg, args...) +} + // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. diff --git a/assert/assertions.go b/assert/assertions.go index 2924cf3a1..bdfce797a 100644 --- a/assert/assertions.go +++ b/assert/assertions.go @@ -1103,6 +1103,28 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs . return true } +// PanicsWithErrorIs asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// assert.PanicsWithErrorIs(t, expectedError, func(){ GoCrazy() }) +func PanicsWithErrorIs(t TestingT, expectedError error, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + funcDidPanic, panicValue, panickedStack := didPanic(f) + if !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + panicErr, ok := panicValue.(error) + if !ok || !errors.Is(panicErr, expectedError) { + return Fail(t, fmt.Sprintf("func %#v should panic with error that has this error in its chain:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expectedError, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // // assert.NotPanics(t, func(){ RemainCalm() }) diff --git a/assert/assertions_test.go b/assert/assertions_test.go index cae11f81d..e004e6537 100644 --- a/assert/assertions_test.go +++ b/assert/assertions_test.go @@ -1048,6 +1048,36 @@ func TestPanicsWithError(t *testing.T) { } } +func TestPanicsWithErrorIs(t *testing.T) { + + mockT := new(testing.T) + + expectedError := errors.New("expected error") + anotherError := errors.New("not expected error") + + if !PanicsWithErrorIs(mockT, expectedError, func() { + panic(expectedError) + }) { + t.Error("PanicsWithErrorIs should return true") + } + + if !PanicsWithErrorIs(mockT, expectedError, func() { + panic(fmt.Errorf("Wrapped Error %w", expectedError)) + }) { + t.Error("PanicsWithErrorIs should return true") + } + + if PanicsWithErrorIs(mockT, expectedError, func() { + }) { + t.Error("PanicsWithErrorIs should return false") + } + + if PanicsWithErrorIs(mockT, expectedError, func() { + }) { + t.Error(anotherError) + } +} + func TestNotPanics(t *testing.T) { mockT := new(testing.T) diff --git a/require/require.go b/require/require.go index 880853f5a..e1122aac7 100644 --- a/require/require.go +++ b/require/require.go @@ -1640,6 +1640,36 @@ func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAn t.FailNow() } +// PanicsWithErrorIs asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// assert.PanicsWithErrorIs(t, expectedError, func(){ GoCrazy() }) +func PanicsWithErrorIs(t TestingT, expectedError error, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithErrorIs(t, expectedError, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithErrorIsf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// assert.PanicsWithErrorIsf(t, expectedError, func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorIsf(t TestingT, expectedError error, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithErrorIsf(t, expectedError, f, msg, args...) { + return + } + t.FailNow() +} + // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. diff --git a/require/require_forward.go b/require/require_forward.go index 960bf6f2c..7c8cf009d 100644 --- a/require/require_forward.go +++ b/require/require_forward.go @@ -1286,6 +1286,30 @@ func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, m PanicsWithError(a.t, errString, f, msgAndArgs...) } +// PanicsWithErrorIs asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// a.PanicsWithErrorIs(expectedError, func(){ GoCrazy() }) +func (a *Assertions) PanicsWithErrorIs(expectedError error, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithErrorIs(a.t, expectedError, f, msgAndArgs...) +} + +// PanicsWithErrorIsf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// errors.Is() method +// +// a.PanicsWithErrorIsf(expectedError, func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorIsf(expectedError error, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithErrorIsf(a.t, expectedError, f, msg, args...) +} + // PanicsWithErrorf asserts that the code inside the specified PanicTestFunc // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison.