add skip-ensure flag to avoid import cycle (#140)

For mocks generated outside of the tested package with tests lives inside the same package as the tested code (i.e. pkg_test not used) --skip-ensure suppresses import of the source pkg

https://github.com/matryer/moq/issues/139

fix typo in readme
This commit is contained in:
Umputun 2020-09-17 03:49:08 -05:00 committed by GitHub
parent a69ca93dec
commit be64288727
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 34 deletions

View File

@ -33,6 +33,9 @@ moq [flags] source-dir interface [interface2 [interface3 [...]]]
package name (default will infer) package name (default will infer)
-stub -stub
return zero values when no mock implementation is provided, do not panic return zero values when no mock implementation is provided, do not panic
-skip-ensure
suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package
Specifying an alias for the mock is also supported with the format 'interface:alias' Specifying an alias for the mock is also supported with the format 'interface:alias'
Ex: moq -pkg different . MyInterface:MyMock Ex: moq -pkg different . MyInterface:MyMock
``` ```

22
main.go
View File

@ -17,11 +17,12 @@ import (
var version string var version string
type userFlags struct { type userFlags struct {
outFile string outFile string
pkgName string pkgName string
formatter string formatter string
stubImpl bool stubImpl bool
args []string skipEnsure bool
args []string
} }
func main() { func main() {
@ -31,6 +32,8 @@ func main() {
flag.StringVar(&flags.formatter, "fmt", "", "go pretty-printer: gofmt, goimports or noop (default gofmt)") flag.StringVar(&flags.formatter, "fmt", "", "go pretty-printer: gofmt, goimports or noop (default gofmt)")
flag.BoolVar(&flags.stubImpl, "stub", false, flag.BoolVar(&flags.stubImpl, "stub", false,
"return zero values when no mock implementation is provided, do not panic") "return zero values when no mock implementation is provided, do not panic")
flag.BoolVar(&flags.skipEnsure, "skip-ensure", false,
"suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package")
flag.Usage = func() { flag.Usage = func() {
fmt.Println(`moq [flags] source-dir interface [interface2 [interface3 [...]]]`) fmt.Println(`moq [flags] source-dir interface [interface2 [interface3 [...]]]`)
@ -62,10 +65,11 @@ func run(flags userFlags) error {
srcDir, args := flags.args[0], flags.args[1:] srcDir, args := flags.args[0], flags.args[1:]
m, err := moq.New(moq.Config{ m, err := moq.New(moq.Config{
SrcDir: srcDir, SrcDir: srcDir,
PkgName: flags.pkgName, PkgName: flags.pkgName,
Formatter: flags.formatter, Formatter: flags.formatter,
StubImpl: flags.stubImpl, StubImpl: flags.stubImpl,
SkipEnsure: flags.skipEnsure,
}) })
if err != nil { if err != nil {
return err return err

View File

@ -19,12 +19,13 @@ import (
// Mocker can generate mock structs. // Mocker can generate mock structs.
type Mocker struct { type Mocker struct {
srcPkg *packages.Package srcPkg *packages.Package
tmpl *template.Template tmpl *template.Template
pkgName string pkgName string
pkgPath string pkgPath string
fmter func(src []byte) ([]byte, error) fmter func(src []byte) ([]byte, error)
stubImpl bool stubImpl bool
skipEnsure bool
imports map[string]bool imports map[string]bool
} }
@ -32,10 +33,11 @@ type Mocker struct {
// Config specifies details about how interfaces should be mocked. // Config specifies details about how interfaces should be mocked.
// SrcDir is the only field which needs be specified. // SrcDir is the only field which needs be specified.
type Config struct { type Config struct {
SrcDir string SrcDir string
PkgName string PkgName string
Formatter string Formatter string
StubImpl bool StubImpl bool
SkipEnsure bool
} }
// New makes a new Mocker for the specified package directory. // New makes a new Mocker for the specified package directory.
@ -69,13 +71,14 @@ func New(conf Config) (*Mocker, error) {
} }
return &Mocker{ return &Mocker{
tmpl: tmpl, tmpl: tmpl,
srcPkg: srcPkg, srcPkg: srcPkg,
pkgName: pkgName, pkgName: pkgName,
pkgPath: pkgPath, pkgPath: pkgPath,
fmter: fmter, fmter: fmter,
stubImpl: conf.StubImpl, stubImpl: conf.StubImpl,
imports: make(map[string]bool), skipEnsure: conf.SkipEnsure,
imports: make(map[string]bool),
}, nil }, nil
} }
@ -114,6 +117,7 @@ func (m *Mocker) Mock(w io.Writer, names ...string) error {
PackageName: m.pkgName, PackageName: m.pkgName,
Imports: moqImports, Imports: moqImports,
StubImpl: m.stubImpl, StubImpl: m.stubImpl,
SkipEnsure: m.skipEnsure,
} }
mocksMethods := false mocksMethods := false
@ -254,6 +258,7 @@ type doc struct {
Objects []obj Objects []obj
Imports []string Imports []string
StubImpl bool StubImpl bool
SkipEnsure bool
} }
type obj struct { type obj struct {

View File

@ -172,6 +172,33 @@ func TestMoqExplicitPackageWithStaticCheck(t *testing.T) {
} }
} }
func TestMoqSkipEnsure(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different", SkipEnsure: true})
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
err = m.Mock(&buf, "PersonStore")
if err != nil {
t.Errorf("m.Mock: %s", err)
}
s := buf.String()
// assertions of things that should be mentioned
var strs = []string{
"package different",
"type PersonStoreMock struct",
"CreateFunc func(ctx context.Context, person *example.Person, confirm bool) error",
"GetFunc func(ctx context.Context, id string) (*example.Person, error)",
"func (mock *PersonStoreMock) Create(ctx context.Context, person *example.Person, confirm bool) error",
"func (mock *PersonStoreMock) Get(ctx context.Context, id string) (*example.Person, error)",
}
for _, str := range strs {
if !strings.Contains(s, str) {
t.Errorf("expected but missing: \"%s\"", str)
}
}
}
func TestNotCreatingEmptyDirWhenPkgIsGiven(t *testing.T) { func TestNotCreatingEmptyDirWhenPkgIsGiven(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"}) m, err := New(Config{SrcDir: "testpackages/example", PkgName: "different"})
if err != nil { if err != nil {

View File

@ -11,6 +11,7 @@ var moqTemplate = `// Code generated by moq; DO NOT EDIT.
package {{.PackageName}} package {{.PackageName}}
{{- $sourcePackagePrefix := .SourcePackagePrefix}} {{- $sourcePackagePrefix := .SourcePackagePrefix}}
{{- $stubImpl := .StubImpl}} {{- $stubImpl := .StubImpl}}
{{- $skipEnsure := .SkipEnsure}}
import ( import (
{{- range .Imports }} {{- range .Imports }}
@ -20,9 +21,11 @@ import (
{{ range $i, $obj := .Objects -}} {{ range $i, $obj := .Objects -}}
{{- if not $skipEnsure -}}
// Ensure, that {{.MockName}} does implement {{$sourcePackagePrefix}}{{.InterfaceName}}. // Ensure, that {{.MockName}} does implement {{$sourcePackagePrefix}}{{.InterfaceName}}.
// If this is not the case, regenerate this file with moq. // If this is not the case, regenerate this file with moq.
var _ {{$sourcePackagePrefix}}{{.InterfaceName}} = &{{.MockName}}{} var _ {{$sourcePackagePrefix}}{{.InterfaceName}} = &{{.MockName}}{}
{{- end }}
// {{.MockName}} is a mock implementation of {{$sourcePackagePrefix}}{{.InterfaceName}}. // {{.MockName}} is a mock implementation of {{$sourcePackagePrefix}}{{.InterfaceName}}.
// //

View File

@ -8,10 +8,6 @@ import (
"sync" "sync"
) )
var (
lockServiceMockDoSomething sync.RWMutex
)
// Ensure, that ServiceMock does implement Service. // Ensure, that ServiceMock does implement Service.
// If this is not the case, regenerate this file with moq. // If this is not the case, regenerate this file with moq.
var _ Service = &ServiceMock{} var _ Service = &ServiceMock{}
@ -43,6 +39,7 @@ type ServiceMock struct {
In1 somerepo.SomeType In1 somerepo.SomeType
} }
} }
lockDoSomething sync.RWMutex
} }
// DoSomething calls DoSomethingFunc. // DoSomething calls DoSomethingFunc.
@ -55,9 +52,9 @@ func (mock *ServiceMock) DoSomething(in1 somerepo.SomeType) error {
}{ }{
In1: in1, In1: in1,
} }
lockServiceMockDoSomething.Lock() mock.lockDoSomething.Lock()
mock.calls.DoSomething = append(mock.calls.DoSomething, callInfo) mock.calls.DoSomething = append(mock.calls.DoSomething, callInfo)
lockServiceMockDoSomething.Unlock() mock.lockDoSomething.Unlock()
return mock.DoSomethingFunc(in1) return mock.DoSomethingFunc(in1)
} }
@ -70,8 +67,8 @@ func (mock *ServiceMock) DoSomethingCalls() []struct {
var calls []struct { var calls []struct {
In1 somerepo.SomeType In1 somerepo.SomeType
} }
lockServiceMockDoSomething.RLock() mock.lockDoSomething.RLock()
calls = mock.calls.DoSomething calls = mock.calls.DoSomething
lockServiceMockDoSomething.RUnlock() mock.lockDoSomething.RUnlock()
return calls return calls
} }