Skip to content

Commit

Permalink
Tons of fixes
Browse files Browse the repository at this point in the history
TODO: Isn't handling mocks that contain type aliases very well. Example:

```
type VariadicFunction = func(args1 string, args2 ...interface{}) interface{}
```

The generated mock doesn't have the proper package name qualifier when
referring to this alias.
  • Loading branch information
LandonTClipp committed Dec 26, 2024
1 parent 1f30801 commit b814a32
Show file tree
Hide file tree
Showing 57 changed files with 4,806 additions and 4,985 deletions.
9 changes: 5 additions & 4 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
disable-version-string: True
mockname: "{{.InterfaceName}}Mock"
filename: "{{.InterfaceName}}.go"
filename: "moq_test.go"
template: moq
dir: "mocks/moq/{{.PackagePath}}"
formatter: "goimports"

packages:
github.com/vektra/mockery/v2/pkg/fixtures:
config:
include-regex: '.*'
exclude-regex: 'RequesterGenerics|UnsafeInterface|requester_unexported'
filename: "mocks.go"
template: moq
outpkg: test
template-map:
filename: "moq_fixtures_test.go"
template-data:
with-resets: true
skip-ensure: true
stub-impl: false
Expand Down
134 changes: 121 additions & 13 deletions cmd/mockery.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package cmd

import (
"context"
"errors"
"fmt"
"os"
"strings"

"github.com/chigopher/pathlib"
"github.com/mitchellh/go-homedir"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -162,6 +164,55 @@ func GetRootAppFromViper(v *viper.Viper) (*RootApp, error) {
return r, nil
}

// InterfaceCollection maintains a list of *pkg.Interface and asserts that all
// the interfaces in the collection belong to the same source package. It also
// asserts that various properties of the interfaces added to the collection are
// uniform.
type InterfaceCollection struct {
srcPkgPath string
outPkgPath string
outFilePath *pathlib.Path
interfaces []*pkg.Interface
}

func NewInterfaceCollection(srcPkgPath string, outPkgPath string, outFilePath *pathlib.Path) *InterfaceCollection {
return &InterfaceCollection{
srcPkgPath: srcPkgPath,
outPkgPath: outPkgPath,
outFilePath: outFilePath,
interfaces: make([]*pkg.Interface, 0),
}
}

func (i *InterfaceCollection) Append(ctx context.Context, iface *pkg.Interface) error {
log := zerolog.Ctx(ctx).With().
Str(logging.LogKeyInterface, iface.Name).
Str(logging.LogKeyPackageName, iface.Pkg.Name).
Str(logging.LogKeyPackagePath, iface.Pkg.PkgPath).
Str("expected-package-path", i.srcPkgPath).Logger()
if iface.Pkg.PkgPath != i.srcPkgPath {
msg := "cannot mix interfaces from different packages in the same file."
log.Error().Msg(msg)
return errors.New(msg)
}
if i.outFilePath.String() != pathlib.NewPath(iface.Config.Dir).Join(iface.Config.FileName).String() {
msg := "all mocks within an InterfaceCollection must have the same output file path"
log.Error().Msg(msg)
return errors.New(msg)
}
ifacePkgPath, err := iface.Config.PkgPath()
if err != nil {
return err
}
if ifacePkgPath != i.outPkgPath {
msg := "all mocks within an InterfaceCollection must have the same output package path"
log.Error().Msg(msg)
return errors.New(msg)
}
i.interfaces = append(i.interfaces, iface)
return nil
}

func (r *RootApp) Run() error {
log, err := logging.GetLogger(r.Config.LogLevel)
if err != nil {
Expand All @@ -183,14 +234,15 @@ func (r *RootApp) Run() error {
}
buildTags := strings.Split(r.Config.BuildTags, " ")

var boilerplate string
if r.Config.BoilerplateFile != "" {
data, err := os.ReadFile(r.Config.BoilerplateFile)
if err != nil {
log.Fatal().Msgf("Failed to read boilerplate file %s: %v", r.Config.BoilerplateFile, err)
}
boilerplate = string(data)
}
// TODO: Fix boilerplate
//var boilerplate string
//if r.Config.BoilerplateFile != "" {
// data, err := os.ReadFile(r.Config.BoilerplateFile)
// if err != nil {
// log.Fatal().Msgf("Failed to read boilerplate file %s: %v", r.Config.BoilerplateFile, err)
// }
// boilerplate = string(data)
//}

configuredPackages, err := r.Config.GetPackages(ctx)
if err != nil {
Expand All @@ -207,7 +259,13 @@ func (r *RootApp) Run() error {
log.Error().Err(err).Msg("unable to parse packages")
return err
}
mockFileToInterfaces := map[string][]*pkg.Interface{}
// maps the following:
// outputFilePath|fullyQualifiedInterfaceName|[]*pkg.Interface
// The reason why we need an interior map of fully qualified interface name
// to a slice of *pkg.Interface (which represents all information necessary
// to create the output mock) is because mockery allows multiple mocks to be
// created for each input interface.
mockFileToInterfaces := map[string]*InterfaceCollection{}

for _, iface := range interfaces {
ifaceLog := log.
Expand All @@ -232,11 +290,61 @@ func (r *RootApp) Run() error {
return err
}
for _, ifaceConfig := range ifaceConfigs {
if interfaces, ok := mockFileToInterfaces[ifaceConfig.FilePath(ctx).String()]; !ok {
interfaces = []*pkg.Interface{}
mockFileToInterfaces[ifaceConfig.FilePath(ctx).String()] = interfaces
if err := ifaceConfig.ParseTemplates(ctx, iface); err != nil {
log.Err(err).Msg("Can't parse config templates for interface")
return err
}
interfaces = append(interfaces, iface)
filePath := ifaceConfig.FilePath(ctx).String()
outPkgPath, err := ifaceConfig.PkgPath()
if err != nil {
return err
}

_, ok := mockFileToInterfaces[filePath]
if !ok {
mockFileToInterfaces[filePath] = NewInterfaceCollection(
iface.Pkg.PkgPath,
outPkgPath,
pathlib.NewPath(ifaceConfig.Dir).Join(ifaceConfig.FileName),
)
}
mockFileToInterfaces[filePath].Append(
ctx,
pkg.NewInterface(
iface.Name,
iface.FileName,
iface.File,
iface.Pkg,
ifaceConfig),
)
}
}

for outFilePath, interfacesInFile := range mockFileToInterfaces {
log.Debug().Int("interfaces-in-file-len", len(interfacesInFile.interfaces)).Msgf("%v", interfacesInFile)
outPkgPath := interfacesInFile.outPkgPath

packageConfig, err := r.Config.GetPackageConfig(ctx, interfacesInFile.srcPkgPath)
if err != nil {
return err
}
generator, err := pkg.NewTemplateGenerator(
interfacesInFile.interfaces[0].Pkg,
outPkgPath,
interfacesInFile.interfaces[0].Config.Template,
pkg.Formatter(r.Config.Formatter),
interfacesInFile.interfaces[0].Config.Outpkg,
packageConfig,
)
if err != nil {
return err
}
templateBytes, err := generator.Generate(ctx, interfacesInFile.interfaces)
if err != nil {
return err
}
if err := pathlib.NewPath(outFilePath).WriteFile(templateBytes); err != nil {
return err
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/showconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/vektra/mockery/v2/pkg/config"
"github.com/vektra/mockery/v2/pkg"
"github.com/vektra/mockery/v2/pkg/logging"
"github.com/vektra/mockery/v2/pkg/stackerr"
"gopkg.in/yaml.v3"
Expand All @@ -33,7 +33,7 @@ func showConfig(
v = viperCfg
}
ctx := context.Background()
config, err := config.NewConfigFromViper(v)
config, err := pkg.NewConfigFromViper(v)
if err != nil {
return stackerr.NewStackErrf(err, "failed to unmarshal config")
}
Expand Down
79 changes: 0 additions & 79 deletions mocks/moq/github.com/vektra/mockery/v2/pkg/fixtures/A.go

This file was deleted.

Loading

0 comments on commit b814a32

Please sign in to comment.