Skip to content
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

Option to replace a generic type parameter with a specific type #747

Closed
1 of 5 tasks
DustinJSilk opened this issue Jan 11, 2024 · 3 comments · Fixed by #750
Closed
1 of 5 tasks

Option to replace a generic type parameter with a specific type #747

DustinJSilk opened this issue Jan 11, 2024 · 3 comments · Fixed by #750
Labels
approved feature Feature request approved for development

Comments

@DustinJSilk
Copy link
Contributor

Description

When using an interface that describes a method that returns a clone of the struct, the generated mocks cannot be used.

Take this interface for example:

type Repository[T any] interface {
  Clone() T
}

This can be implemented and used normally with this struct (note, no generics used here):

type repository struct {}

func (r *repository) Clone() *repository {
  return &repository{}
}

This struct can successfully be injected into a function that expects the Repository[T] interface:

func Foo[R Repository[R]](repo R) {
  // ...
}

func main() {
  repository := &repository{}
  Foo(repository)
}

However, the generated mocks generate a struct that follows the interface (as expected):

type MockRepository[T interface{}] struct {
  mock.Mock
}

func (_m *MockRepository[T]) Clone() T {
  // ...
}

The problem is that these generated structs now cannot be used in the Foo function because their clone methods cannot infer T.

For an example with a little bit more added, please see this repository: https://github.com/DustinJSilk/mockery-cloneable/tree/main

Mockery Version

v2.39.2

Golang Version

1.21.6

Installation Method

  • Binary Distribution
  • Docker
  • brew
  • go install
  • Other: [specify]

Steps to Reproduce

  1. Clone the repository
  2. See the errors in your IDE

Expected Behavior

There is no way to have an interface that clones itself without using generics.
It would help if there was a way to tell Mockery to replace the generics with a specific type, in this case, itself.

Actual Behavior

Is correct, but also doesnt work. It generates the mocks usings the interface definition but it needs more flexibility to work correctly.

@LandonTClipp
Copy link
Collaborator

@DustinJSilk

It took me a minute to wrap my head around the question but I think I understand. This is basically a self-referential problem coming from the fact that .Clone() is returning the same generic type that was used when instantiating the mocks.MockClient type. This loop is generated when providing concrete types to the generic constraints:

mockRepository :=mocks.NewMockRepository[*testing.T, *mocks.MockClient[*mocks.MockClient[*mocks.MockClient[etc. forever and ever]]](t)

I forked your example and manually modified the mocks to provide a completely working example of what we would ultimately want mockery to generate: LandonTClipp/mockery-cloneable@d18f1dd

The proposal is to add new config parameters that allow mockery to replace the generic constraints with concrete types. The changes I made to the mock implementation should be what mockery would generate.

My questions for you:

  1. Does my fork of your reproducer seem to actually fix your problem?
  2. Would you be willing to submit a PR for this, assuming we both agree on the solution I proposed?

@DustinJSilk
Copy link
Contributor Author

Hi @LandonTClipp ,

Thanks for taking the time to look into this!

  1. Yes it does, I ended up manually editing the mocks in the same way in my project and it works as expected.
  2. I'm happy to have a crack at it over the next few days when i get a moment

@LandonTClipp
Copy link
Collaborator

Okay great. It would be much appreciated if you could try for an implementation here. Otherwise, I can probably do it myself sometime in the next few weeks. Although, this is such a rare situation that it might get thrown behind some other high priority tasks.

@LandonTClipp LandonTClipp added the approved feature Feature request approved for development label Jan 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved feature Feature request approved for development
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants