Skip to content

Commit

Permalink
Add InterfaceDirRelative template variable
Browse files Browse the repository at this point in the history
This fixes #623

Also fixed in here was a bug where the template object was being reused. This caused subtle issues where if a templated variable was set to the empty string, the template would simply reuse the last parsed template.

Add docs/fix minor logic flow

Fix bug with test
  • Loading branch information
LandonTClipp committed May 14, 2023
1 parent 05d270e commit 66f7b66
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 18 deletions.
3 changes: 2 additions & 1 deletion docs/configuration.md
Expand Up @@ -96,7 +96,8 @@ These are the config options when using the `packages` config option. Use of the

| name | description |
|------|-------------|
| InterfaceDir | The path of the original interface being mocked. This can be used as <br>`#!yaml dir: "{{.InterfaceDir}}"` to place your mocks adjacent to the original interface. This should not be used for external interfaces. |
| InterfaceDir | The directory path of the original interface being mocked. This can be used as <br>`#!yaml dir: "{{.InterfaceDir}}"` to place your mocks adjacent to the original interface. This should not be used for external interfaces. |
| InterfaceDirRelative | The directory path of the original interface being mocked, relative to the current working directory. If the path cannot be made relative to the current working directory, this variable will be set equal to `PackagePath` |
| InterfaceName | The name of the original interface being mocked |
| InterfaceNameCamel | Converts a string `interface_name` to `InterfaceName` |
| InterfaceNameLowerCamel | Converts `InterfaceName` to `interfaceName` |
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -3,7 +3,7 @@ module github.com/vektra/mockery/v2
go 1.19

require (
github.com/chigopher/pathlib v0.13.0
github.com/chigopher/pathlib v1.0.0
github.com/iancoleman/strcase v0.2.0
github.com/jinzhu/copier v0.3.5
github.com/mitchellh/go-homedir v1.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.work.sum
Expand Up @@ -294,6 +294,8 @@ github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnd
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chigopher/pathlib v1.0.0 h1:SbsCrFX4vDf4M2d8mT/RTzuVlKOjTKoPHK0HidsQFak=
github.com/chigopher/pathlib v1.0.0/go.mod h1:3+YPPV21mU9vyw8Mjp+F33CyCfE6iOzinpiqBcccv7I=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
Expand Down
25 changes: 22 additions & 3 deletions pkg/outputter.go
Expand Up @@ -144,9 +144,29 @@ func parseConfigTemplates(ctx context.Context, c *config.Config, iface *Interfac
} else {
mock = "mock"
}

workingDir, err := os.Getwd()
if err != nil {
return fmt.Errorf("get working directory: %w", err)
}

Check warning on line 151 in pkg/outputter.go

View check run for this annotation

Codecov / codecov/patch

pkg/outputter.go#L150-L151

Added lines #L150 - L151 were not covered by tests
var interfaceDirRelative string
interfaceDir := pathlib.NewPath(iface.FileName).Parent()
interfaceDirRelativePath, err := interfaceDir.RelativeToStr(workingDir)
if errors.Is(err, pathlib.ErrRelativeTo) {
log.Debug().
Stringer("interface-dir", interfaceDir).
Str("working-dir", workingDir).
Msg("can't make interfaceDir relative to working dir. Setting InterfaceDirRelative to package path.")

interfaceDirRelative = iface.Pkg.Path()
} else {
interfaceDirRelative = interfaceDirRelativePath.String()
}

// data is the struct sent to the template parser
data := struct {
InterfaceDir string
InterfaceDirRelative string
InterfaceName string
InterfaceNameCamel string
InterfaceNameLowerCamel string
Expand All @@ -157,6 +177,7 @@ func parseConfigTemplates(ctx context.Context, c *config.Config, iface *Interfac
PackagePath string
}{
InterfaceDir: filepath.Dir(iface.FileName),
InterfaceDirRelative: interfaceDirRelative,
InterfaceName: iface.Name,
InterfaceNameCamel: strcase.ToCamel(iface.Name),
InterfaceNameLowerCamel: strcase.ToLowerCamel(iface.Name),
Expand All @@ -166,8 +187,6 @@ func parseConfigTemplates(ctx context.Context, c *config.Config, iface *Interfac
PackageName: iface.Pkg.Name(),
PackagePath: iface.Pkg.Path(),
}
templ := template.New("interface-template")

// These are the config options that we allow
// to be parsed by the templater. The keys are
// just labels we're using for logs/errors
Expand Down Expand Up @@ -197,7 +216,7 @@ func parseConfigTemplates(ctx context.Context, c *config.Config, iface *Interfac
for name, attributePointer := range templateMap {
oldVal := *attributePointer

attributeTempl, err := templ.Parse(*attributePointer)
attributeTempl, err := template.New("interface-template").Parse(*attributePointer)
if err != nil {
return fmt.Errorf("failed to parse %s template: %w", name, err)
}
Expand Down
62 changes: 49 additions & 13 deletions pkg/outputter_test.go
Expand Up @@ -4,10 +4,12 @@ import (
"context"
"errors"
"fmt"
"os"
"reflect"
"testing"

"github.com/chigopher/pathlib"
"github.com/davecgh/go-spew/spew"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
pkgMocks "github.com/vektra/mockery/v2/mocks/github.com/vektra/mockery/v2/pkg"
Expand Down Expand Up @@ -65,6 +67,15 @@ func TestUnderscoreCaseName(t *testing.T) {
}

func Test_parseConfigTemplates(t *testing.T) {
mockPkg := func(t *testing.T) *pkgMocks.TypesPackage {
m := pkgMocks.NewTypesPackage(t)
m.EXPECT().Path().Return("github.com/user/project/package")
m.EXPECT().Name().Return("packageName")
return m
}
cwd, err := os.Getwd()
require.NoError(t, err)

type args struct {
c *config.Config
iface *Interface
Expand Down Expand Up @@ -96,19 +107,48 @@ func Test_parseConfigTemplates(t *testing.T) {
FileName: "path/to/foobar.go",
},
},
pkg: func(t *testing.T) *pkgMocks.TypesPackage {
m := pkgMocks.NewTypesPackage(t)
m.EXPECT().Path().Return("github.com/user/project/package")
m.EXPECT().Name().Return("packageName")
return m
},
pkg: mockPkg,
want: &config.Config{
Dir: "path/to/github.com/user/project/package",
FileName: "FooBar_FooBar_foo_bar.go",
MockName: "fooBar",
Outpkg: "packageName",
},
},
{
name: "InterfaceDirRelative in current working directory",
args: args{
c: &config.Config{
Dir: "{{.InterfaceDirRelative}}",
},

iface: &Interface{
Name: "FooBar",
FileName: cwd + "/path/to/foobar.go",
},
},
pkg: mockPkg,
want: &config.Config{
Dir: "path/to",
},
},
{
name: "InterfaceDirRelative not in current working directory",
args: args{
c: &config.Config{
Dir: "mocks/{{.InterfaceDirRelative}}",
},

iface: &Interface{
Name: "FooBar",
FileName: "/path/to/foobar.go",
},
},
pkg: mockPkg,
want: &config.Config{
Dir: "mocks/github.com/user/project/package",
},
},
{
name: "infinite loop in template variables",
args: args{
Expand All @@ -124,12 +164,7 @@ func Test_parseConfigTemplates(t *testing.T) {
FileName: "path/to/foobar.go",
},
},
pkg: func(t *testing.T) *pkgMocks.TypesPackage {
m := pkgMocks.NewTypesPackage(t)
m.EXPECT().Path().Return("github.com/user/project/package")
m.EXPECT().Name().Return("packageName")
return m
},
pkg: mockPkg,
disableWantCheck: true,
wantErr: ErrInfiniteLoop,
},
Expand All @@ -143,7 +178,7 @@ func Test_parseConfigTemplates(t *testing.T) {
t.Errorf("parseConfigTemplates() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.disableWantCheck && !reflect.DeepEqual(tt.args.c, tt.want) {
t.Errorf("*config.Config = %v, want %v", tt.args.c, tt.want)
t.Errorf("*config.Config = %s\n, want %+v", spew.Sdump(tt.args.c), spew.Sdump(tt.want))
}
})
}
Expand Down Expand Up @@ -173,6 +208,7 @@ func TestOutputter_Generate(t *testing.T) {
tt.fields.config.Dir = t.TempDir()
tt.fields.config.MockName = "Mock{{.InterfaceName}}"
tt.fields.config.FileName = "mock_{{.InterfaceName}}.go"
tt.fields.config.Outpkg = "{{.PackageName}}"

t.Run(tt.name, func(t *testing.T) {
m := &Outputter{
Expand Down

0 comments on commit 66f7b66

Please sign in to comment.