Skip to content

Mock.MethodCalled should not call methods of arguments #1719

@philflip12

Description

@philflip12

Description

Mock.MethodCalled calls Mock.mutex.Lock.
Then, it calls Mock.findExpectedCall which searches the Mock's list of expected calls.
When it comes across a potential match, it calls Diff on the arguments.
This creates a string from the arguments using the format specifier %v.
If the argument implements the Stringer interface, its String method can be called.
Ultimately, calling any methods on the arguments being compared must be avoided as this can cause unexpected behavior.
My specific example is, if the argument happens to be the same interface which originally triggered Mock.MethodCalled,
Mock.MethodCalled is called again, but now from within the first call and Mock.mutex.Lock is called again causing a deadlock.

This issue could somewhat be avoided by ensuring that Mock.MethodCalled is not called before the previous call returns.
However, having an argument's String method called from within Mock.MethodCalled is not expected behavior and mock generation libraries such as vektra/mockery assume that this will not happen.

Step To Reproduce

package main

import (
	"github.com/stretchr/testify/mock"
)

type TestStruct struct {
	mock.Mock
}

func (t *TestStruct) String() string {
	t.MethodCalled("String")
	return ""
}

func (t *TestStruct) DoAThing(object *TestStruct) {
	t.MethodCalled("DoAThing", object)
}

func main() {
	mockTestStruct := &TestStruct{}
	mockTestStruct.On("DoAThing", mock.Anything)
	mockTestStruct.DoAThing(mockTestStruct)
}

Expected behavior

I expect that Mock.MethodCalled will never call any methods of the arguments being compared

Actual behavior

In my specific example, Mock.MethodCalled calls the String method of one of the arguments which indirectly
leads to a deadlock if the String function also calls Mock.MethodCalled.
However, this is generally unexpected behavior and could lead to any number of undefined behaviors like race conditions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions