-
Notifications
You must be signed in to change notification settings - Fork 412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix invalid code generation when interface method parameter's name is the same as interface name #649
fix invalid code generation when interface method parameter's name is the same as interface name #649
Conversation
b92d507
to
0ad4b77
Compare
…er's name is the same as interface name
0ad4b77
to
2a69b15
Compare
Hi, thank you very much for the PR. This solution appears to me to be incomplete. What if you have a separate interface in your package named |
Hi, thank for notes.
I tried to reproduce generation with names conflicts and got following result: //go:generate mockery --inpackage --dir . --outpkg mockery --testonly --name "interfaceA|interfaceB|interfaceB0"
type (
interfaceA interface {
// the name of the parameter like as interface name
SomeMethod(interfaceB interfaceB) (interfaceA interfaceA)
Do(interfaceB interfaceB0) interfaceB0
Do2(interfaceB0 interfaceB0) interfaceB0
}
interfaceB interface {
GetData() int
}
interfaceB0 interface {
DoB0(interfaceB0 interfaceB0) interfaceB0
}
) // Do provides a mock function with given fields: interfaceB
func (_m *mockInterfaceA) Do(interfaceB interfaceB0) interfaceB0 {
ret := _m.Called(interfaceB) // 👈️ `interfaceB` is the arg name
var r0 interfaceB0
if rf, ok := ret.Get(0).(func(interfaceB0) interfaceB0); ok { // 👈️ `interfaceB0 ` is the type
r0 = rf(interfaceB)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(interfaceB0)
}
}
return r0
}
// Do2 provides a mock function with given fields: interfaceB00
func (_m *mockInterfaceA) Do2(interfaceB00 interfaceB0) interfaceB0 {
ret := _m.Called(interfaceB00)
var r0 interfaceB0
if rf, ok := ret.Get(0).(func(interfaceB0) interfaceB0); ok {
r0 = rf(interfaceB00)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(interfaceB0)
}
}
return r0
}
// SomeMethod provides a mock function with given fields: interfaceB0
func (_m *mockInterfaceA) SomeMethod(interfaceB0 interfaceB) interfaceA {
ret := _m.Called(interfaceB0)
var r0 interfaceA
if rf, ok := ret.Get(0).(func(interfaceB) interfaceA); ok {
r0 = rf(interfaceB0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(interfaceA)
}
}
return r0
} I have not found any conflicts. Test example: import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type testStruct struct {
interfaceA interfaceA
}
func (s *testStruct) Exec() interfaceB0 {
var in interfaceB0 = nil
return s.interfaceA.Do(in)
}
func Test(t *testing.T) {
mockInterfaceB0 := new(mockInterfaceB0)
mockInterfaceA := new(mockInterfaceA)
mockInterfaceA.On("Do", mock.Anything).Return(mockInterfaceB0)
s := testStruct{
interfaceA: mockInterfaceA,
}
res := s.Exec()
assert.Equal(t, mockInterfaceB0, res)
mockInterfaceA.AssertExpectations(t)
} |
I will have to toy around with this myself, I'm surprised the mock for the |
I have tried different combinations of flags and interfaces, but haven't found the problem. |
@kozmod could you create a fixture in https://github.com/vektra/mockery/tree/master/pkg/fixtures using some examples (like what you posted here), add config to generate it in |
@LandonTClipp Some tests was added) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good, let's see if the tests pass.
.mockery.yaml
Outdated
testonly: True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two parameters actually aren't recognized by the packages
feature. Best to remove these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed testonly: True
-> ok.
But after was removed keeptree: False
, mocks generate with invalid package arguments imports (method_argssame_name_arg_and_type
):
// DoB0 provides a mock function with given fields: interfaceB0
func (_m *interfaceB0Mock) DoB0(interfaceB0 method_argssame_name_arg_and_type.interfaceB0) method_argssame_name_arg_and_type.interfaceB0 { // 👈️ the interesting behavior
ret := _m.Called(interfaceB0)
var r0 method_argssame_name_arg_and_type.interfaceB0
if rf, ok := ret.Get(0).(func(method_argssame_name_arg_and_type.interfaceB0) method_argssame_name_arg_and_type.interfaceB0); ok {
r0 = rf(interfaceB0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(method_argssame_name_arg_and_type.interfaceB0)
}
}
return r0
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going to continue research the problem...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's happened because configuration file contains keeptree: True
(.mockery.yaml:2). And in package
block I override it useing keeptree: False
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, that seems to be a mistake, mockery shouldn't be using keeptree
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will have to review the usage of keeptree
in mockery, my intention was for this to not be used anywhere in the packages
config. We can just keep it if it makes the tests pass.
Codecov ReportPatch coverage has no change and project coverage change:
Additional details and impacted files@@ Coverage Diff @@
## master #649 +/- ##
===================================================
- Coverage 76.65601% 76.54039% -0.11562%
===================================================
Files 8 8
Lines 2189 2191 +2
===================================================
- Hits 1678 1677 -1
- Misses 376 378 +2
- Partials 135 136 +1
☔ View full report in Codecov by Sentry. |
00c41c6
to
15a4f69
Compare
What about tests? I will able to write tests like (through all generating algorithm) func (s *GeneratorSuite) TestGeneratorSameMethodArgsNameAndType() {
iface := s.getInterfaceFromFile("method_args/same_name_arg_and_type/entity.go", "interfaceA")
pkg := iface.QualifiedName
gen := NewGenerator(s.ctx, GeneratorConfig{
InPackage: true,
}, iface, pkg)
err := gen.Generate(s.ctx)
s.NoError(err)
generatedData := gen.buf.String()
s.Contains(generatedData,
`func (_m *mockInterfaceA) DoB(interfaceB0 interfaceB) interfaceB {ret := _m.Called(interfaceB0)`,
)
s.Contains(generatedData,
` var r0 interfaceB
if rf, ok := ret.Get(0).(func(interfaceB) interfaceB); ok {
r0 = rf(interfaceB0)
} else {if ret.Get(0) != nil {
r0 = ret.Get(0).(interfaceB)
}}
return r0
}`,
)
} |
I think we can ignore the test coverage failures. I am really against comparing the mock against a string because it tests the wrong thing, and it because really difficult to manage if you have 100 string comparison tests and you ever change what your mock looks like! This is good, I will approve. |
Description
look at #648
Type of change
Version of Golang used when building/testing:
How Has This Been Tested?
Try to generate mocks fot interfaces with the same names of a method argument and an argument's type
Expected result
Checklist