diff --git a/.mockery.yaml b/.mockery.yaml index 6cb49058..ffeed52b 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -46,7 +46,7 @@ packages: config: replace-type: - github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[-TImport]=github.com/vektra/mockery/v2/pkg/fixtures/redefined_type_b.B - - github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[TConstraint]=github.com/vektra/mockery/v2/pkg/fixtures/constraints.Integer + - github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[TConstraint]=github.com/vektra/mockery/v2/pkg/fixtures/constraints.String # Replace a generic param with the parent type ReplaceGenericSelf: config: diff --git a/docs/features.md b/docs/features.md index 5ed0838a..bb6e9d94 100644 --- a/docs/features.md +++ b/docs/features.md @@ -93,19 +93,58 @@ func (_m *Handler) HandleMessage(m pubsub.Message) error { Generic type constraints can also be replaced by targeting the changed parameter with the square bracket notation on the left hand side. ```shell -mockery --replace-type github.com/vektra/mockery/v2/baz/internal/foo.InternalBaz[T]=baz:github.com/vektra/mockery/v2/baz.Baz +mockery --replace-type github.com/vektra/mockery/v2/baz/internal/foo.InternalBaz[T]=github.com/vektra/mockery/v2/baz.Baz +``` + +For example: + +```go +type InternalBaz[T any] struct{} + +func (*InternalBaz[T]) Foo() T {} + +// Becomes +type InternalBaz[T baz.Baz] struct{} + +func (*InternalBaz[T]) Foo() T {} ``` If a type constraint needs to be removed and replaced with a type, target the constraint with square brackets and include a '-' in front to have it removed. ```shell -mockery --replace-type github.com/vektra/mockery/v2/baz/internal/foo.InternalBaz[-T]=baz:github.com/vektra/mockery/v2/baz.Baz +mockery --replace-type github.com/vektra/mockery/v2/baz/internal/foo.InternalBaz[-T]=github.com/vektra/mockery/v2/baz.Baz +``` + +For example: + +```go +type InternalBaz[T any] struct{} + +func (*InternalBaz[T]) Foo() T {} + +// Becomes +type InternalBaz struct{} + +func (*InternalBaz) Foo() baz.Baz {} ``` When replacing a generic constraint, you can replace the type with a pointer by adding a '*' before the output type name. ```shell -mockery --replace-type github.com/vektra/mockery/v2/baz/internal/foo.InternalBaz[-T]=baz:github.com/vektra/mockery/v2/baz.*Baz +mockery --replace-type github.com/vektra/mockery/v2/baz/internal/foo.InternalBaz[-T]=github.com/vektra/mockery/v2/baz.*Baz +``` + +For example: + +```go +type InternalBaz[T any] struct{} + +func (*InternalBaz[T]) Foo() T {} + +// Becomes +type InternalBaz struct{} + +func (*InternalBaz) Foo() *baz.Baz {} ``` `packages` configuration diff --git a/mocks/github.com/vektra/mockery/v2/pkg/fixtures/ReplaceGeneric.go b/mocks/github.com/vektra/mockery/v2/pkg/fixtures/ReplaceGeneric.go index 1721e2fd..0727b975 100644 --- a/mocks/github.com/vektra/mockery/v2/pkg/fixtures/ReplaceGeneric.go +++ b/mocks/github.com/vektra/mockery/v2/pkg/fixtures/ReplaceGeneric.go @@ -10,11 +10,11 @@ import ( ) // ReplaceGeneric is an autogenerated mock type for the ReplaceGeneric type -type ReplaceGeneric[TConstraint constraints.Integer, TKeep interface{}] struct { +type ReplaceGeneric[TConstraint constraints.String, TKeep interface{}] struct { mock.Mock } -type ReplaceGeneric_Expecter[TConstraint constraints.Integer, TKeep interface{}] struct { +type ReplaceGeneric_Expecter[TConstraint constraints.String, TKeep interface{}] struct { mock *mock.Mock } @@ -41,7 +41,7 @@ func (_m *ReplaceGeneric[TConstraint, TKeep]) A(t1 test.B) TKeep { } // ReplaceGeneric_A_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'A' -type ReplaceGeneric_A_Call[TConstraint constraints.Integer, TKeep interface{}] struct { +type ReplaceGeneric_A_Call[TConstraint constraints.String, TKeep interface{}] struct { *mock.Call } @@ -87,7 +87,7 @@ func (_m *ReplaceGeneric[TConstraint, TKeep]) B() test.B { } // ReplaceGeneric_B_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'B' -type ReplaceGeneric_B_Call[TConstraint constraints.Integer, TKeep interface{}] struct { +type ReplaceGeneric_B_Call[TConstraint constraints.String, TKeep interface{}] struct { *mock.Call } @@ -132,7 +132,7 @@ func (_m *ReplaceGeneric[TConstraint, TKeep]) C() TConstraint { } // ReplaceGeneric_C_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'C' -type ReplaceGeneric_C_Call[TConstraint constraints.Integer, TKeep interface{}] struct { +type ReplaceGeneric_C_Call[TConstraint constraints.String, TKeep interface{}] struct { *mock.Call } @@ -160,7 +160,7 @@ func (_c *ReplaceGeneric_C_Call[TConstraint, TKeep]) RunAndReturn(run func() TCo // NewReplaceGeneric creates a new instance of ReplaceGeneric. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewReplaceGeneric[TConstraint constraints.Integer, TKeep interface{}](t interface { +func NewReplaceGeneric[TConstraint constraints.String, TKeep interface{}](t interface { mock.TestingT Cleanup(func()) }) *ReplaceGeneric[TConstraint, TKeep] { diff --git a/pkg/fixtures/constraints/constraints.go b/pkg/fixtures/constraints/constraints.go index a17dc2e0..b73c7bb7 100644 --- a/pkg/fixtures/constraints/constraints.go +++ b/pkg/fixtures/constraints/constraints.go @@ -7,3 +7,7 @@ type Signed interface { type Integer interface { ~int } + +type String interface { + ~string +} diff --git a/pkg/fixtures/test/generic_test.go b/pkg/fixtures/test/generic_test.go new file mode 100644 index 00000000..66365a97 --- /dev/null +++ b/pkg/fixtures/test/generic_test.go @@ -0,0 +1,30 @@ +package test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + mocks "github.com/vektra/mockery/v2/mocks/github.com/vektra/mockery/v2/pkg/fixtures" + rtb "github.com/vektra/mockery/v2/pkg/fixtures/redefined_type_b" +) + +func TestReplaceGeneric(t *testing.T) { + type str string + + m := mocks.NewReplaceGeneric[str, str](t) + + m.EXPECT().A(rtb.B(1)).Return("") + assert.Equal(t, m.A(rtb.B(1)), str("")) + + m.EXPECT().B().Return(2) + assert.Equal(t, m.B(), rtb.B(2)) + + m.EXPECT().C().Return("") + assert.Equal(t, m.C(), str("")) +} + +func TestReplaceGenericSelf(t *testing.T) { + m := mocks.NewReplaceGenericSelf(t) + m.EXPECT().A().Return(m) + assert.Equal(t, m.A(), m) +} diff --git a/pkg/generator.go b/pkg/generator.go index cdda3c39..26622271 100644 --- a/pkg/generator.go +++ b/pkg/generator.go @@ -1164,12 +1164,7 @@ func parseReplaceType(t string) *replaceType { // Match type parameter substitution match := regexp.MustCompile(`\[(.*?)\]$`).FindStringSubmatch(t) if len(match) >= 2 { - if match[1][:1] == "-" { - ret.param = match[1][1:] - ret.rmvParam = true - } else { - ret.param = match[1] - } + ret.param, ret.rmvParam = strings.CutPrefix(match[1], "-") t = strings.ReplaceAll(t, match[0], "") } diff --git a/pkg/generator_test.go b/pkg/generator_test.go index 69d197bb..012a9856 100644 --- a/pkg/generator_test.go +++ b/pkg/generator_test.go @@ -760,32 +760,6 @@ func (s *GeneratorSuite) TestReplaceTypePackageMultiple() { }) } -func (s *GeneratorSuite) TestReplaceTypeGeneric() { - cfg := GeneratorConfig{InPackage: false, ReplaceType: []string{ - "github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[-TImport]=github.com/vektra/mockery/v2/pkg/fixtures/redefined_type_b.B", - "github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGeneric[TConstraint]=github.com/vektra/mockery/v2/pkg/fixtures/constraints.Integer", - "github.com/vektra/mockery/v2/pkg/fixtures.ReplaceGenericSelf[-T]=github.com/vektra/mockery/v2/pkg/fixtures.*ReplaceGenericSelf", - }} - - s.checkGenerationRegexWithConfig("generic.go", "ReplaceGeneric", cfg, []regexpExpected{ - // type ReplaceGeneric[TConstraint constraints.Integer, TKeep interface{}] struct - {true, regexp.MustCompile(`type ReplaceGeneric\[TConstraint constraints.Integer\, TKeep interface\{\}] struct`)}, - // func (_m *ReplaceGeneric[TConstraint, TKeep]) A(t1 test.B) TKeep - {true, regexp.MustCompile(`func \(_m \*ReplaceGeneric\[TConstraint, TKeep\]\) A\(t1 test\.B\) TKeep`)}, - // func (_m *ReplaceGeneric[TConstraint, TKeep]) B() test.B - {true, regexp.MustCompile(`func \(_m \*ReplaceGeneric\[TConstraint, TKeep\]\) B\(\) test\.B`)}, - // func (_m *ReplaceGeneric[TConstraint, TKeep]) C() TConstraint - {true, regexp.MustCompile(`func \(_m \*ReplaceGeneric\[TConstraint, TKeep\]\) C\(\) TConstraint`)}, - }) - - s.checkGenerationRegexWithConfig("generic.go", "ReplaceGenericSelf", cfg, []regexpExpected{ - // type ReplaceGenericSelf struct - {true, regexp.MustCompile(`type ReplaceGenericSelf struct`)}, - // func (_m *ReplaceGenericSelf) A() *ReplaceGenericSelf - {true, regexp.MustCompile(`func \(_m \*ReplaceGenericSelf\) A\(\) \*ReplaceGenericSelf`)}, - }) -} - func (s *GeneratorSuite) TestGenericGenerator() { s.checkGeneration("generic.go", "RequesterGenerics", false, "", "") }