Skip to content

Commit c206b2e

Browse files
Mock can be deadlocked by a panic (#1157)
If an argumentMatcher function panics and AssertExpectations is deferred then the test would deadlock.
1 parent 1b73601 commit c206b2e

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

mock/mock.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,16 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
858858
}
859859

860860
if matcher, ok := expected.(argumentMatcher); ok {
861-
if matcher.Matches(actual) {
861+
var matches bool
862+
func() {
863+
defer func() {
864+
if r := recover(); r != nil {
865+
actualFmt = fmt.Sprintf("panic in argument matcher: %v", r)
866+
}
867+
}()
868+
matches = matcher.Matches(actual)
869+
}()
870+
if matches {
862871
output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
863872
} else {
864873
differences++

mock/mock_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,32 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
233233
})
234234
}
235235

236+
func Test_Mock_On_WithArgMatcherThatPanics(t *testing.T) {
237+
var mockedService TestExampleImplementation
238+
239+
mockedService.On("TheExampleMethod2", MatchedBy(func(_ interface{}) bool {
240+
panic("try to lock mockedService")
241+
})).Return()
242+
243+
defer func() {
244+
assertedExpectations := make(chan struct{})
245+
go func() {
246+
tt := new(testing.T)
247+
mockedService.AssertExpectations(tt)
248+
close(assertedExpectations)
249+
}()
250+
select {
251+
case <-assertedExpectations:
252+
case <-time.After(time.Second):
253+
t.Fatal("AssertExpectations() deadlocked, did the panic leave mockedService locked?")
254+
}
255+
}()
256+
257+
assert.Panics(t, func() {
258+
mockedService.TheExampleMethod2(false)
259+
})
260+
}
261+
236262
func TestMock_WithTest(t *testing.T) {
237263
var (
238264
mockedService TestExampleImplementation

0 commit comments

Comments
 (0)