Skip to content

Commit

Permalink
Tons of additions and fixes.
Browse files Browse the repository at this point in the history
Most notably, I fixed moq's generation of type constraints expressed as a union inside an interface. For example:

```
TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}
```

This caused lots of probems. Mockery was not generating the `test.` package qualifier. The issue was
that a `*types.Union` type was not checked for in the `populateImports` method. The fix is simple,
just recurse down each term of the union.
  • Loading branch information
LandonTClipp committed Dec 27, 2024
1 parent 918307a commit ed244e4
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 51 deletions.
1 change: 1 addition & 0 deletions .boilerplate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TEST MOCKERY BOILERPLATE
15 changes: 9 additions & 6 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
disable-version-string: True
mockname: "Mock{{.InterfaceName}}"
filename: "mockery_mock.go"
outpkg: mocks
pkgname: mocks
tags: "custom2"
issue-845-fix: True
template: "mockery"
boilerplate-file: "./.boilerplate.txt"
mock-build-tags: test
_anchors: &inpackage_config
all: True
dir: "{{.InterfaceDir}}"
mockname: "Mock{{.InterfaceName}}"
outpkg: "{{.PackageName}}_test"
pkgname: "{{.PackageName}}_test"
filename: "mock_{{.InterfaceNameSnake}}_test.go"
packages:
#github.com/vektra/mockery/v2/pkg/fixtures/buildtag/comment:
Expand All @@ -26,6 +28,7 @@ packages:
all: False
interfaces:
A:
RequesterGenerics:
#RequesterArgSameAsNamedImport:
#RequesterVariadic:
# configs:
Expand All @@ -52,20 +55,20 @@ packages:
# dir: "{{.InterfaceDir}}"
# filename: "{{.InterfaceName}}_mock.go"
# mockname: "Mock{{.InterfaceName}}"
# outpkg: "{{.PackageName}}"
# pkgname: "{{.PackageName}}"
#github.com/vektra/mockery/v2/pkg/fixtures/empty_return:
# config:
# all: True
# dir: "{{.InterfaceDir}}"
# mockname: "{{.InterfaceName}}Mock"
# outpkg: "{{.PackageName}}"
# pkgname: "{{.PackageName}}"
# filename: "mock_{{.InterfaceName}}_test.go"
#github.com/vektra/mockery/v2/pkg/fixtures/method_args/same_name_arg_and_type:
# config:
# all: True
# dir: "{{.InterfaceDir}}"
# mockname: "{{.InterfaceName}}Mock"
# outpkg: "{{.PackageName}}"
# pkgname: "{{.PackageName}}"
# filename: "mock_{{.InterfaceName}}_test.go"
#github.com/vektra/mockery/v2/pkg/fixtures/iface_typed_param:
# config: *inpackage_config
Expand All @@ -91,5 +94,5 @@ packages:
# all: True
# dir: "{{.InterfaceDir}}"
# filename: "mock_{{.MockName}}_test.go"
# outpkg: "{{.PackageName}}_test"
# pkgname: "{{.PackageName}}_test"
#
5 changes: 1 addition & 4 deletions cmd/mockery.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ func NewRootCmd() (*cobra.Command, error) {

pFlags := cmd.PersistentFlags()
pFlags.StringVar(&cfgFile, "config", "", "config file to use")
pFlags.String("outpkg", "mocks", "name of generated package")
pFlags.String("packageprefix", "", "prefix for the generated package name, it is ignored if outpkg is also specified.")
pFlags.String("dir", "", "directory to search for interfaces")
pFlags.BoolP("recursive", "r", false, "recurse search into sub-directories")
pFlags.StringArray("exclude", nil, "prefixes of subdirectories and files to exclude from search")
Expand Down Expand Up @@ -334,9 +332,8 @@ func (r *RootApp) Run() error {
generator, err := pkg.NewTemplateGenerator(
interfacesInFile.interfaces[0].Pkg,
outPkgPath,
interfacesInFile.interfaces[0].Config.Template,
packageConfig.Template,
pkg.Formatter(r.Config.Formatter),
interfacesInFile.interfaces[0].Config.Outpkg,
packageConfig,
)
if err != nil {
Expand Down
57 changes: 56 additions & 1 deletion mocks/github.com/vektra/mockery/v2/pkg/fixtures/mockery_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ type Config struct {
MockName string `mapstructure:"mockname"`
Note string `mapstructure:"note"`
PkgName string `mapstructure:"pkgname"`
Packageprefix string `mapstructure:"packageprefix"`
Packages map[string]interface{} `mapstructure:"packages"`
Profile string `mapstructure:"profile"`
Recursive bool `mapstructure:"recursive"`
Expand All @@ -84,8 +83,9 @@ func NewConfigFromViper(v *viper.Viper) (*Config, error) {

v.SetDefault("dir", "mocks/{{.PackagePath}}")
v.SetDefault("filename", "mock_{{.InterfaceName}}.go")
v.SetDefault("formatter", "goimports")
v.SetDefault("mockname", "Mock{{.InterfaceName}}")
v.SetDefault("outpkg", "{{.PackageName}}")
v.SetDefault("pkgname", "{{.PackageName}}")
v.SetDefault("dry-run", false)
v.SetDefault("log-level", "info")

Expand Down
17 changes: 16 additions & 1 deletion pkg/registry/method_scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package registry

import (
"context"
"fmt"
"go/types"
"strconv"

Expand Down Expand Up @@ -136,15 +137,29 @@ func (m MethodScope) populateImports(ctx context.Context, t types.Type, imports
m.populateImports(ctx, t.Field(i).Type(), imports)
}

case *types.Union:
log.Debug().Int("len", t.Len()).Msg("found union")
for i := 0; i < t.Len(); i++ {
term := t.Term(i)
m.populateImports(ctx, term.Type(), imports)
}
case *types.Interface: // anonymous interface
log.Debug().
Int("num-methods", t.NumMethods()).
Int("num-explicit-methods", t.NumExplicitMethods()).
Int("num-embeddeds", t.NumEmbeddeds()).
Msg("found interface")
for i := 0; i < t.NumExplicitMethods(); i++ {
log.Debug().Msg("populating import from explicit method")
m.populateImports(ctx, t.ExplicitMethod(i).Type(), imports)
}
for i := 0; i < t.NumEmbeddeds(); i++ {
log.Debug().Msg("populating import form embedded type")
m.populateImports(ctx, t.EmbeddedType(i), imports)
}

default:
log.Debug().Msg("unable to determine type of object")
log.Debug().Str("real-type", fmt.Sprintf("%T", t)).Msg("unable to determine type of object")
}
}

Expand Down
1 change: 0 additions & 1 deletion pkg/registry/var.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func (v Var) packageQualifier(pkg *types.Package) string {
if v.moqPkgPath != "" && v.moqPkgPath == path {
return ""
}

return v.imports[path].Qualifier()
}

Expand Down
46 changes: 23 additions & 23 deletions pkg/template/mockery.templ
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{{ .Boilerplate }}
// Code generated by mockery; DO NOT EDIT.
// github.com/vektra/mockery

{{- if .BuildTags }}

//go:build {{ .BuildTags }}
{{- end }}

package {{.PkgName}}

import (
Expand All @@ -13,35 +19,29 @@ import (
{{- range $i, $mock := .Mocks }}
// New{{ .MockName }} creates a new instance of {{ .MockName }}. 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 New{{ .MockName}}
{{- if .TypeParams -}}
[
{{- range $index, $param := .TypeParams}}
{{- if $index}}, {{end}}{{$param.Name | Exported}} {{$param.TypeString}}
{{- end -}}
]
{{- end }} (t interface {
func New{{ .MockName }}{{ $mock | TypeConstraint }} (t interface {
mock.TestingT
Cleanup(func())
}) *{{ .MockName }}
{{- if .TypeParams -}}
[
{{- range $index, $param := .TypeParams}}
{{- if $index}}, {{end}}{{$param.Name | Exported}}
{{- end -}}
]
{{- end }} {
mock := &{{ .MockName }}{{- if .TypeParams -}}
[
{{- range $index, $param := .TypeParams}}
{{- if $index}}, {{end}}{{$param.Name | Exported}}
{{- end -}}
]
{{- end }}{}
}) *{{ .MockName }}{{ $mock | TypeInstantiation }} {
mock := &{{ .MockName }}{{ $mock | TypeInstantiation }}{}
mock.Mock.Test(t)

t.Cleanup(func() { mock.AssertExpectations(t) })

return mock
}

// {{ .MockName }} is an autogenerated mock type for the {{ .InterfaceName }} type
type {{ .MockName }}{{ $mock | TypeConstraint }} struct {
mock.Mock
}

type {{.MockName}}_expecter{{ $mock | TypeConstraint }} struct {
mock *mock.Mock
}

func (_m *{{.MockName}}{{ $mock | TypeInstantiation }}) EXPECT() *{{.MockName}}_expecter{{ $mock | TypeInstantiation }} {
return &{{.MockName}}_expecter{{ $mock | TypeInstantiation }}{mock: &_m.Mock}
}
{{- end }}

49 changes: 41 additions & 8 deletions pkg/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func New(style string) (Template, error) {
return Template{}, stackerr.NewStackErrf(nil, "style %s does not exist", style)
}

tmpl, err := template.New("moq").Funcs(templateFuncs).Parse(templateString)
tmpl, err := template.New(style).Funcs(templateFuncs).Parse(templateString)
if err != nil {
return Template{}, err
}
Expand Down Expand Up @@ -87,7 +87,17 @@ var templateFuncs = template.FuncMap{
return "sync"
},
"Exported": exported,
"TypeInstantiation": func(m MockData) string {

"MocksSomeMethod": func(mocks []MockData) bool {
for _, m := range mocks {
if len(m.Methods) > 0 {
return true
}
}

return false
},
"TypeConstraintTest": func(m MockData) string {
if len(m.TypeParams) == 0 {
return ""
}
Expand All @@ -97,17 +107,40 @@ var templateFuncs = template.FuncMap{
s += ", "
}
s += exported(param.Name())
s += " "
s += param.TypeString()
}
s += "]"
return s
},
"MocksSomeMethod": func(mocks []MockData) bool {
for _, m := range mocks {
if len(m.Methods) > 0 {
return true
"TypeConstraint": func(m MockData) string {
if len(m.TypeParams) == 0 {
return ""
}
s := "["
for idx, param := range m.TypeParams {
if idx != 0 {
s += ", "
}
s += exported(param.Name())
s += " "
s += param.TypeString()
}

return false
s += "]"
return s
},
"TypeInstantiation": func(m MockData) string {
if len(m.TypeParams) == 0 {
return ""
}
s := "["
for idx, param := range m.TypeParams {
if idx != 0 {
s += ", "
}
s += exported(param.Name())
}
s += "]"
return s
},
}
2 changes: 2 additions & 0 deletions pkg/template/template_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

// Data is the template data used to render the Moq template.
type Data struct {
Boilerplate string
BuildTags string
PkgName string
SrcPkgQualifier string
Imports []*registry.Package
Expand Down
Loading

0 comments on commit ed244e4

Please sign in to comment.