Internal registry for disambiguated imports, vars (#141)

* Internal registry for disambiguated imports, vars
- Move functionality in the moq package partially into
  internal/{registry,template}.
- Leverage registry to assign unique package and variable/method
  parameter names. Use import aliases if present in interface source
  package.
BREAKING CHANGE: When the interface definition does not mention the
parameter names, the field names in call info anonymous struct will be
different.
The new field names are generated using the type info (string -> s,
int -> n, chan int -> intCh, []MyType -> myTypes, map[string]int ->
stringToInt etc.).
For example, for a string parameter previously if the field name was
'In1', the new field could be 'S' or 'S1' (depends on number of
string method parameters).
* Refactor golden file tests to be table-driven
* Fix sync pkg alias handling for moq generation
* Improve, add tests (increase coverage)
* Use $.Foo in template, avoid declaring variables
$ is set to the data argument passed to Execute, that is, to the
starting value of dot.
Variables were declared to be able to refer to the parent context.
* Consistent template field formatting
* Use tabs in generated Godoc comments' example code
* Minor simplification
* go generate
* Fix conflict for generated param name of pointer type

Excellent work by @sudo-suhas.
This commit is contained in:
Suhas Karanth 2021-02-02 00:50:20 +05:30 committed by GitHub
parent b052143b5a
commit 2ae606f132
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 2078 additions and 683 deletions

View File

@ -0,0 +1,155 @@
package registry
import (
"go/types"
"strconv"
)
// MethodScope is the sub-registry for allocating variables present in
// the method scope.
//
// It should be created using a registry instance.
type MethodScope struct {
registry *Registry
moqPkgPath string
vars []*Var
conflicted map[string]bool
}
// AddVar allocates a variable instance and adds it to the method scope.
//
// Variables names are generated if required and are ensured to be
// without conflict with other variables and imported packages. It also
// adds the relevant imports to the registry for each added variable.
func (m *MethodScope) AddVar(vr *types.Var, suffix string) *Var {
name := vr.Name()
if name == "" || name == "_" {
name = generateVarName(vr.Type())
}
name += suffix
switch name {
case "mock", "callInfo", "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct",
"chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for",
"import", "return", "var":
name += "MoqParam"
}
if _, ok := m.searchVar(name); ok || m.conflicted[name] {
return m.addDisambiguatedVar(vr, name)
}
return m.addVar(vr, name)
}
func (m *MethodScope) addDisambiguatedVar(vr *types.Var, suggested string) *Var {
n := 1
for {
// Keep incrementing the suffix until we find a name which is unused.
if _, ok := m.searchVar(suggested + strconv.Itoa(n)); !ok {
break
}
n++
}
name := suggested + strconv.Itoa(n)
if n == 1 {
conflict, _ := m.searchVar(suggested)
conflict.Name += "1"
name = suggested + "2"
m.conflicted[suggested] = true
}
return m.addVar(vr, name)
}
func (m *MethodScope) addVar(vr *types.Var, name string) *Var {
imports := make(map[string]*Package)
m.populateImports(vr.Type(), imports)
v := Var{
vr: vr,
imports: imports,
moqPkgPath: m.moqPkgPath,
Name: name,
}
m.vars = append(m.vars, &v)
m.resolveImportVarConflicts(&v)
return &v
}
func (m MethodScope) searchVar(name string) (*Var, bool) {
for _, v := range m.vars {
if v.Name == name {
return v, true
}
}
return nil, false
}
// populateImports extracts all the package imports for a given type
// recursively. The imported packages by a single type can be more than
// one (ex: map[a.Type]b.Type).
func (m MethodScope) populateImports(t types.Type, imports map[string]*Package) {
switch t := t.(type) {
case *types.Named:
if pkg := t.Obj().Pkg(); pkg != nil {
imports[stripVendorPath(pkg.Path())] = m.registry.AddImport(pkg)
}
case *types.Array:
m.populateImports(t.Elem(), imports)
case *types.Slice:
m.populateImports(t.Elem(), imports)
case *types.Signature:
for i := 0; i < t.Params().Len(); i++ {
m.populateImports(t.Params().At(i).Type(), imports)
}
for i := 0; i < t.Results().Len(); i++ {
m.populateImports(t.Results().At(i).Type(), imports)
}
case *types.Map:
m.populateImports(t.Key(), imports)
m.populateImports(t.Elem(), imports)
case *types.Chan:
m.populateImports(t.Elem(), imports)
case *types.Pointer:
m.populateImports(t.Elem(), imports)
case *types.Struct: // anonymous struct
for i := 0; i < t.NumFields(); i++ {
m.populateImports(t.Field(i).Type(), imports)
}
case *types.Interface: // anonymous interface
for i := 0; i < t.NumExplicitMethods(); i++ {
m.populateImports(t.ExplicitMethod(i).Type(), imports)
}
for i := 0; i < t.NumEmbeddeds(); i++ {
m.populateImports(t.EmbeddedType(i), imports)
}
}
}
func (m MethodScope) resolveImportVarConflicts(v *Var) {
// Ensure that the newly added var does not conflict with a package import
// which was added earlier.
if _, ok := m.registry.searchImport(v.Name); ok {
v.Name += "MoqParam"
}
// Ensure that all the newly added imports do not conflict with any of the
// existing vars.
for _, imprt := range v.imports {
if v, ok := m.searchVar(imprt.Qualifier()); ok {
v.Name += "MoqParam"
}
}
}

View File

@ -0,0 +1,93 @@
package registry
import (
"go/types"
"path"
"strings"
)
// Package represents an imported package.
type Package struct {
pkg *types.Package
Alias string
}
// NewPackage creates a new instance of Package.
func NewPackage(pkg *types.Package) *Package { return &Package{pkg: pkg} }
// Qualifier returns the qualifier which must be used to refer to types
// declared in the package.
func (p *Package) Qualifier() string {
if p == nil {
return ""
}
if p.Alias != "" {
return p.Alias
}
return p.pkg.Name()
}
// Path is the full package import path (without vendor).
func (p *Package) Path() string {
if p == nil {
return ""
}
return stripVendorPath(p.pkg.Path())
}
var replacer = strings.NewReplacer(
"go-", "",
"-go", "",
"-", "",
"_", "",
".", "",
"@", "",
"+", "",
"~", "",
)
// uniqueName generates a unique name for a package by concatenating
// path components. The generated name is guaranteed to unique with an
// appropriate level because the full package import paths themselves
// are unique.
func (p Package) uniqueName(lvl int) string {
pp := strings.Split(p.Path(), "/")
reverse(pp)
var name string
for i := 0; i < min(len(pp), lvl+1); i++ {
name = strings.ToLower(replacer.Replace(pp[i])) + name
}
return name
}
// stripVendorPath strips the vendor dir prefix from a package path.
// For example we might encounter an absolute path like
// github.com/foo/bar/vendor/github.com/pkg/errors which is resolved
// to github.com/pkg/errors.
func stripVendorPath(p string) string {
parts := strings.Split(p, "/vendor/")
if len(parts) == 1 {
return p
}
return strings.TrimLeft(path.Join(parts[1:]...), "/")
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func reverse(a []string) {
for i := len(a)/2 - 1; i >= 0; i-- {
opp := len(a) - 1 - i
a[i], a[opp] = a[opp], a[i]
}
}

View File

@ -0,0 +1,190 @@
package registry
import (
"errors"
"fmt"
"go/types"
"path/filepath"
"sort"
"strings"
"golang.org/x/tools/go/packages"
)
// Registry encapsulates types information for the source and mock
// destination package. For the mock package, it tracks the list of
// imports and ensures there are no conflicts in the imported package
// qualifiers.
type Registry struct {
srcPkg *packages.Package
moqPkgPath string
aliases map[string]string
imports map[string]*Package
}
// New loads the source package info and returns a new instance of
// Registry.
func New(srcDir, moqPkg string) (*Registry, error) {
srcPkg, err := pkgInfoFromPath(
srcDir, packages.NeedName|packages.NeedSyntax|packages.NeedTypes|packages.NeedTypesInfo,
)
if err != nil {
return nil, fmt.Errorf("couldn't load source package: %s", err)
}
return &Registry{
srcPkg: srcPkg,
moqPkgPath: findPkgPath(moqPkg, srcPkg),
aliases: parseImportsAliases(srcPkg),
imports: make(map[string]*Package),
}, nil
}
// SrcPkg returns the types info for the source package.
func (r Registry) SrcPkg() *types.Package {
return r.srcPkg.Types
}
// SrcPkgName returns the name of the source package.
func (r Registry) SrcPkgName() string {
return r.srcPkg.Name
}
// LookupInterface returns the underlying interface definition of the
// given interface name.
func (r Registry) LookupInterface(name string) (*types.Interface, error) {
obj := r.SrcPkg().Scope().Lookup(name)
if obj == nil {
return nil, fmt.Errorf("interface not found: %s", name)
}
if !types.IsInterface(obj.Type()) {
return nil, fmt.Errorf("%s (%s) is not an interface", name, obj.Type())
}
return obj.Type().Underlying().(*types.Interface).Complete(), nil
}
// MethodScope returns a new MethodScope.
func (r *Registry) MethodScope() *MethodScope {
return &MethodScope{
registry: r,
moqPkgPath: r.moqPkgPath,
conflicted: map[string]bool{},
}
}
// AddImport adds the given package to the set of imports. It generates a
// suitable alias if there are any conflicts with previously imported
// packages.
func (r *Registry) AddImport(pkg *types.Package) *Package {
path := stripVendorPath(pkg.Path())
if path == r.moqPkgPath {
return nil
}
if imprt, ok := r.imports[path]; ok {
return imprt
}
imprt := Package{pkg: pkg, Alias: r.aliases[path]}
if conflict, ok := r.searchImport(imprt.Qualifier()); ok {
resolveImportConflict(&imprt, conflict, 0)
}
r.imports[path] = &imprt
return &imprt
}
// Imports returns the list of imported packages. The list is sorted by
// path.
func (r Registry) Imports() []*Package {
imports := make([]*Package, 0, len(r.imports))
for _, imprt := range r.imports {
imports = append(imports, imprt)
}
sort.Slice(imports, func(i, j int) bool {
return imports[i].Path() < imports[j].Path()
})
return imports
}
func (r Registry) searchImport(name string) (*Package, bool) {
for _, imprt := range r.imports {
if imprt.Qualifier() == name {
return imprt, true
}
}
return nil, false
}
func pkgInfoFromPath(srcDir string, mode packages.LoadMode) (*packages.Package, error) {
pkgs, err := packages.Load(&packages.Config{
Mode: mode,
Dir: srcDir,
})
if err != nil {
return nil, err
}
if len(pkgs) == 0 {
return nil, errors.New("package not found")
}
if len(pkgs) > 1 {
return nil, errors.New("found more than one package")
}
if errs := pkgs[0].Errors; len(errs) != 0 {
if len(errs) == 1 {
return nil, errs[0]
}
return nil, fmt.Errorf("%s (and %d more errors)", errs[0], len(errs)-1)
}
return pkgs[0], nil
}
func findPkgPath(pkgInputVal string, srcPkg *packages.Package) string {
if pkgInputVal == "" {
return srcPkg.PkgPath
}
if pkgInDir(srcPkg.PkgPath, pkgInputVal) {
return srcPkg.PkgPath
}
subdirectoryPath := filepath.Join(srcPkg.PkgPath, pkgInputVal)
if pkgInDir(subdirectoryPath, pkgInputVal) {
return subdirectoryPath
}
return ""
}
func pkgInDir(pkgName, dir string) bool {
currentPkg, err := pkgInfoFromPath(dir, packages.NeedName)
if err != nil {
return false
}
return currentPkg.Name == pkgName || currentPkg.Name+"_test" == pkgName
}
func parseImportsAliases(pkg *packages.Package) map[string]string {
aliases := make(map[string]string)
for _, syntax := range pkg.Syntax {
for _, imprt := range syntax.Imports {
if imprt.Name != nil && imprt.Name.Name != "." {
aliases[strings.Trim(imprt.Path.Value, `"`)] = imprt.Name.Name
}
}
}
return aliases
}
// resolveImportConflict generates and assigns a unique alias for
// packages with conflicting qualifiers.
func resolveImportConflict(a, b *Package, lvl int) {
u1, u2 := a.uniqueName(lvl), b.uniqueName(lvl)
if u1 != u2 {
a.Alias, b.Alias = u1, u2
return
}
resolveImportConflict(a, b, lvl+1)
}

123
internal/registry/var.go Normal file
View File

@ -0,0 +1,123 @@
package registry
import (
"go/types"
"strings"
)
// Var represents a method variable/parameter.
//
// It should be created using a method scope instance.
type Var struct {
vr *types.Var
imports map[string]*Package
moqPkgPath string
Name string
}
// IsSlice returns whether the type (or the underlying type) is a slice.
func (v Var) IsSlice() bool {
_, ok := v.vr.Type().Underlying().(*types.Slice)
return ok
}
// TypeString returns the variable type with the package qualifier in the
// format 'pkg.Type'.
func (v Var) TypeString() string {
return types.TypeString(v.vr.Type(), v.packageQualifier)
}
// packageQualifier is a types.Qualifier.
func (v Var) packageQualifier(pkg *types.Package) string {
path := stripVendorPath(pkg.Path())
if v.moqPkgPath != "" && v.moqPkgPath == path {
return ""
}
return v.imports[path].Qualifier()
}
// generateVarName generates a name for the variable using the type
// information.
//
// Examples:
// - string -> s
// - int -> n
// - chan int -> intCh
// - []a.MyType -> myTypes
// - map[string]int -> stringToInt
// - error -> err
// - a.MyType -> myType
func generateVarName(t types.Type) string {
nestedType := func(t types.Type) string {
if t, ok := t.(*types.Basic); ok {
return deCapitalise(t.String())
}
return generateVarName(t)
}
switch t := t.(type) {
case *types.Named:
if t.Obj().Name() == "error" {
return "err"
}
name := deCapitalise(t.Obj().Name())
if name == t.Obj().Name() {
name += "MoqParam"
}
return name
case *types.Basic:
return basicTypeVarName(t)
case *types.Array:
return nestedType(t.Elem()) + "s"
case *types.Slice:
return nestedType(t.Elem()) + "s"
case *types.Struct: // anonymous struct
return "val"
case *types.Pointer:
return generateVarName(t.Elem())
case *types.Signature:
return "fn"
case *types.Interface: // anonymous interface
return "ifaceVal"
case *types.Map:
return nestedType(t.Key()) + "To" + capitalise(nestedType(t.Elem()))
case *types.Chan:
return nestedType(t.Elem()) + "Ch"
}
return "v"
}
func basicTypeVarName(b *types.Basic) string {
switch b.Info() {
case types.IsBoolean:
return "b"
case types.IsInteger:
return "n"
case types.IsFloat:
return "f"
case types.IsString:
return "s"
}
return "v"
}
func capitalise(s string) string { return strings.ToUpper(s[:1]) + s[1:] }
func deCapitalise(s string) string { return strings.ToLower(s[:1]) + s[1:] }

View File

@ -0,0 +1,190 @@
package template
import (
"io"
"strings"
"text/template"
"github.com/matryer/moq/internal/registry"
)
// Template is the Moq template. It is capable of generating the Moq
// implementation for the given template.Data.
type Template struct {
tmpl *template.Template
}
// New returns a new instance of Template.
func New() (Template, error) {
tmpl, err := template.New("moq").Funcs(templateFuncs).Parse(moqTemplate)
if err != nil {
return Template{}, err
}
return Template{tmpl: tmpl}, nil
}
// Execute generates and writes the Moq implementation for the given
// data.
func (t Template) Execute(w io.Writer, data Data) error {
return t.tmpl.Execute(w, data)
}
// moqTemplate is the template for mocked code.
// language=GoTemplate
var moqTemplate = `// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package {{.PkgName}}
import (
{{- range .Imports}}
{{. | ImportStatement}}
{{- end}}
)
{{range $i, $mock := .Mocks -}}
{{- if not $.SkipEnsure -}}
// Ensure, that {{.MockName}} does implement {{$.SrcPkgQualifier}}{{.InterfaceName}}.
// If this is not the case, regenerate this file with moq.
var _ {{$.SrcPkgQualifier}}{{.InterfaceName}} = &{{.MockName}}{}
{{- end}}
// {{.MockName}} is a mock implementation of {{$.SrcPkgQualifier}}{{.InterfaceName}}.
//
// func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {
//
// // make and configure a mocked {{$.SrcPkgQualifier}}{{.InterfaceName}}
// mocked{{.InterfaceName}} := &{{.MockName}}{
{{- range .Methods}}
// {{.Name}}Func: func({{.ArgList}}) {{.ReturnArgTypeList}} {
// panic("mock out the {{.Name}} method")
// },
{{- end}}
// }
//
// // use mocked{{.InterfaceName}} in code that requires {{$.SrcPkgQualifier}}{{.InterfaceName}}
// // and then make assertions.
//
// }
type {{.MockName}} struct {
{{- range .Methods}}
// {{.Name}}Func mocks the {{.Name}} method.
{{.Name}}Func func({{.ArgList}}) {{.ReturnArgTypeList}}
{{end}}
// calls tracks calls to the methods.
calls struct {
{{- range .Methods}}
// {{.Name}} holds details about calls to the {{.Name}} method.
{{.Name}} []struct {
{{- range .Params}}
// {{.Name | Exported}} is the {{.Name}} argument value.
{{.Name | Exported}} {{.TypeString}}
{{- end}}
}
{{- end}}
}
{{- range .Methods}}
lock{{.Name}} {{$.Imports | SyncPkgQualifier}}.RWMutex
{{- end}}
}
{{range .Methods}}
// {{.Name}} calls {{.Name}}Func.
func (mock *{{$mock.MockName}}) {{.Name}}({{.ArgList}}) {{.ReturnArgTypeList}} {
{{- if not $.StubImpl}}
if mock.{{.Name}}Func == nil {
panic("{{$mock.MockName}}.{{.Name}}Func: method is nil but {{$mock.InterfaceName}}.{{.Name}} was just called")
}
{{- end}}
callInfo := struct {
{{- range .Params}}
{{.Name | Exported}} {{.TypeString}}
{{- end}}
}{
{{- range .Params}}
{{.Name | Exported}}: {{.Name}},
{{- end}}
}
mock.lock{{.Name}}.Lock()
mock.calls.{{.Name}} = append(mock.calls.{{.Name}}, callInfo)
mock.lock{{.Name}}.Unlock()
{{- if .Returns}}
{{- if $.StubImpl}}
if mock.{{.Name}}Func == nil {
var (
{{- range .Returns}}
{{.Name}} {{.TypeString}}
{{- end}}
)
return {{.ReturnArgNameList}}
}
{{- end}}
return mock.{{.Name}}Func({{.ArgCallList}})
{{- else}}
{{- if $.StubImpl}}
if mock.{{.Name}}Func == nil {
return
}
{{- end}}
mock.{{.Name}}Func({{.ArgCallList}})
{{- end}}
}
// {{.Name}}Calls gets all the calls that were made to {{.Name}}.
// Check the length with:
// len(mocked{{$mock.InterfaceName}}.{{.Name}}Calls())
func (mock *{{$mock.MockName}}) {{.Name}}Calls() []struct {
{{- range .Params}}
{{.Name | Exported}} {{.TypeString}}
{{- end}}
} {
var calls []struct {
{{- range .Params}}
{{.Name | Exported}} {{.TypeString}}
{{- end}}
}
mock.lock{{.Name}}.RLock()
calls = mock.calls.{{.Name}}
mock.lock{{.Name}}.RUnlock()
return calls
}
{{end -}}
{{end -}}`
// This list comes from the golint codebase. Golint will complain about any of
// these being mixed-case, like "Id" instead of "ID".
var golintInitialisms = []string{
"ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS",
"QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "UID", "UUID", "URI",
"URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS",
}
var templateFuncs = template.FuncMap{
"ImportStatement": func(imprt *registry.Package) string {
if imprt.Alias == "" {
return `"` + imprt.Path() + `"`
}
return imprt.Alias + ` "` + imprt.Path() + `"`
},
"SyncPkgQualifier": func(imports []*registry.Package) string {
for _, imprt := range imports {
if imprt.Path() == "sync" {
return imprt.Qualifier()
}
}
return "sync"
},
"Exported": func(s string) string {
if s == "" {
return ""
}
for _, initialism := range golintInitialisms {
if strings.ToUpper(s) == initialism {
return initialism
}
}
return strings.ToUpper(s[0:1]) + s[1:]
},
}

View File

@ -0,0 +1,125 @@
package template
import (
"fmt"
"strings"
"github.com/matryer/moq/internal/registry"
)
// Data is the template data used to render the Moq template.
type Data struct {
PkgName string
SrcPkgQualifier string
Imports []*registry.Package
Mocks []MockData
StubImpl bool
SkipEnsure bool
}
// MocksSomeMethod returns true of any one of the Mocks has at least 1
// method.
func (d Data) MocksSomeMethod() bool {
for _, m := range d.Mocks {
if len(m.Methods) > 0 {
return true
}
}
return false
}
// MockData is the data used to generate a mock for some interface.
type MockData struct {
InterfaceName string
MockName string
Methods []MethodData
}
// MethodData is the data which represents a method on some interface.
type MethodData struct {
Name string
Params []ParamData
Returns []ParamData
}
// ArgList is the string representation of method parameters, ex:
// 's string, n int, foo bar.Baz'.
func (m MethodData) ArgList() string {
params := make([]string, len(m.Params))
for i, p := range m.Params {
params[i] = p.MethodArg()
}
return strings.Join(params, ", ")
}
// ArgCallList is the string representation of method call parameters,
// ex: 's, n, foo'. In case of a last variadic parameter, it will be of
// the format 's, n, foos...'
func (m MethodData) ArgCallList() string {
params := make([]string, len(m.Params))
for i, p := range m.Params {
params[i] = p.CallName()
}
return strings.Join(params, ", ")
}
// ReturnArgTypeList is the string representation of method return
// types, ex: 'bar.Baz', '(string, error)'.
func (m MethodData) ReturnArgTypeList() string {
params := make([]string, len(m.Returns))
for i, p := range m.Returns {
params[i] = p.TypeString()
}
if len(m.Returns) > 1 {
return fmt.Sprintf("(%s)", strings.Join(params, ", "))
}
return strings.Join(params, ", ")
}
// ReturnArgNameList is the string representation of values being
// returned from the method, ex: 'foo', 's, err'.
func (m MethodData) ReturnArgNameList() string {
params := make([]string, len(m.Returns))
for i, p := range m.Returns {
params[i] = p.Name()
}
return strings.Join(params, ", ")
}
// ParamData is the data which represents a parameter to some method of
// an interface.
type ParamData struct {
Var *registry.Var
Variadic bool
}
// Name returns the name of the parameter.
func (p ParamData) Name() string {
return p.Var.Name
}
// MethodArg is the representation of the parameter in the function
// signature, ex: 'name a.Type'.
func (p ParamData) MethodArg() string {
if p.Variadic {
return fmt.Sprintf("%s ...%s", p.Name(), p.TypeString()[2:])
}
return fmt.Sprintf("%s %s", p.Name(), p.TypeString())
}
// CallName returns the string representation of the parameter to be
// used for a method call. For a variadic paramter, it will be of the
// format 'foos...'.
func (p ParamData) CallName() string {
if p.Variadic {
return p.Name() + "..."
}
return p.Name()
}
// TypeString returns the string representation of the type of the
// parameter.
func (p ParamData) TypeString() string {
return p.Var.TypeString()
}

View File

@ -0,0 +1,55 @@
package template
import (
"go/types"
"testing"
"github.com/matryer/moq/internal/registry"
)
func TestTemplateFuncs(t *testing.T) {
t.Run("Exported", func(t *testing.T) {
f := templateFuncs["Exported"].(func(string) string)
if f("") != "" {
t.Errorf("Exported(...) want: ``; got: `%s`", f(""))
}
if f("var") != "Var" {
t.Errorf("Exported(...) want: `Var`; got: `%s`", f("var"))
}
})
t.Run("ImportStatement", func(t *testing.T) {
f := templateFuncs["ImportStatement"].(func(*registry.Package) string)
pkg := registry.NewPackage(types.NewPackage("xyz", "xyz"))
if f(pkg) != `"xyz"` {
t.Errorf("ImportStatement(...): want: `\"xyz\"`; got: `%s`", f(pkg))
}
pkg.Alias = "x"
if f(pkg) != `x "xyz"` {
t.Errorf("ImportStatement(...): want: `x \"xyz\"`; got: `%s`", f(pkg))
}
})
t.Run("SyncPkgQualifier", func(t *testing.T) {
f := templateFuncs["SyncPkgQualifier"].(func([]*registry.Package) string)
if f(nil) != "sync" {
t.Errorf("SyncPkgQualifier(...): want: `sync`; got: `%s`", f(nil))
}
imports := []*registry.Package{
registry.NewPackage(types.NewPackage("sync", "sync")),
registry.NewPackage(types.NewPackage("github.com/some/module", "module")),
}
if f(imports) != "sync" {
t.Errorf("SyncPkgQualifier(...): want: `sync`; got: `%s`", f(imports))
}
syncPkg := registry.NewPackage(types.NewPackage("sync", "sync"))
syncPkg.Alias = "stdsync"
otherSyncPkg := registry.NewPackage(types.NewPackage("github.com/someother/sync", "sync"))
imports = []*registry.Package{otherSyncPkg, syncPkg}
if f(imports) != "stdsync" {
t.Errorf("SyncPkgQualifier(...): want: `stdsync`; got: `%s`", f(imports))
}
})
}

View File

@ -29,5 +29,3 @@ func gofmt(src []byte) ([]byte, error) {
return formatted, nil return formatted, nil
} }
func noopFmt(src []byte) ([]byte, error) { return src, nil }

View File

@ -1,44 +0,0 @@
package moq
// This list comes from the golint codebase. Golint will complain about any of
// these being mixed-case, like "Id" instead of "ID".
var golintInitialisms = []string{
"ACL",
"API",
"ASCII",
"CPU",
"CSS",
"DNS",
"EOF",
"GUID",
"HTML",
"HTTP",
"HTTPS",
"ID",
"IP",
"JSON",
"LHS",
"QPS",
"RAM",
"RHS",
"RPC",
"SLA",
"SMTP",
"SQL",
"SSH",
"TCP",
"TLS",
"TTL",
"UDP",
"UI",
"UID",
"UUID",
"URI",
"URL",
"UTF8",
"VM",
"XML",
"XMPP",
"XSRF",
"XSS",
}

View File

@ -3,31 +3,20 @@ package moq
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt"
"go/build"
"go/types" "go/types"
"io" "io"
"os"
"path"
"path/filepath"
"strconv"
"strings" "strings"
"text/template"
"golang.org/x/tools/go/packages" "github.com/matryer/moq/internal/registry"
"github.com/matryer/moq/internal/template"
) )
// Mocker can generate mock structs. // Mocker can generate mock structs.
type Mocker struct { type Mocker struct {
srcPkg *packages.Package cfg Config
tmpl *template.Template
pkgName string
pkgPath string
fmter func(src []byte) ([]byte, error)
stubImpl bool
skipEnsure bool
imports map[string]bool registry *registry.Registry
tmpl template.Template
} }
// Config specifies details about how interfaces should be mocked. // Config specifies details about how interfaces should be mocked.
@ -41,331 +30,142 @@ type Config struct {
} }
// New makes a new Mocker for the specified package directory. // New makes a new Mocker for the specified package directory.
func New(conf Config) (*Mocker, error) { func New(cfg Config) (*Mocker, error) {
srcPkg, err := pkgInfoFromPath(conf.SrcDir, packages.NeedName|packages.NeedTypes|packages.NeedTypesInfo) reg, err := registry.New(cfg.SrcDir, cfg.PkgName)
if err != nil {
return nil, fmt.Errorf("couldn't load source package: %s", err)
}
pkgName := conf.PkgName
if pkgName == "" {
pkgName = srcPkg.Name
}
pkgPath, err := findPkgPath(conf.PkgName, srcPkg)
if err != nil {
return nil, fmt.Errorf("couldn't load mock package: %s", err)
}
tmpl, err := template.New("moq").Funcs(templateFuncs).Parse(moqTemplate)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmter := gofmt tmpl, err := template.New()
switch conf.Formatter { if err != nil {
case "goimports": return nil, err
fmter = goimports
case "noop":
fmter = noopFmt
} }
return &Mocker{ return &Mocker{
cfg: cfg,
registry: reg,
tmpl: tmpl, tmpl: tmpl,
srcPkg: srcPkg,
pkgName: pkgName,
pkgPath: pkgPath,
fmter: fmter,
stubImpl: conf.StubImpl,
skipEnsure: conf.SkipEnsure,
imports: make(map[string]bool),
}, nil }, nil
} }
func findPkgPath(pkgInputVal string, srcPkg *packages.Package) (string, error) {
if pkgInputVal == "" {
return srcPkg.PkgPath, nil
}
if pkgInDir(".", pkgInputVal) {
return ".", nil
}
if pkgInDir(srcPkg.PkgPath, pkgInputVal) {
return srcPkg.PkgPath, nil
}
subdirectoryPath := filepath.Join(srcPkg.PkgPath, pkgInputVal)
if pkgInDir(subdirectoryPath, pkgInputVal) {
return subdirectoryPath, nil
}
return "", nil
}
func pkgInDir(pkgName, dir string) bool {
currentPkg, err := pkgInfoFromPath(dir, packages.NeedName)
if err != nil {
return false
}
return currentPkg.Name == pkgName || currentPkg.Name+"_test" == pkgName
}
// Mock generates a mock for the specified interface name. // Mock generates a mock for the specified interface name.
func (m *Mocker) Mock(w io.Writer, names ...string) error { func (m *Mocker) Mock(w io.Writer, namePairs ...string) error {
if len(names) == 0 { if len(namePairs) == 0 {
return errors.New("must specify one interface") return errors.New("must specify one interface")
} }
doc := doc{ mocks := make([]template.MockData, len(namePairs))
PackageName: m.pkgName, for i, np := range namePairs {
Imports: moqImports, name, mockName := parseInterfaceName(np)
StubImpl: m.stubImpl, iface, err := m.registry.LookupInterface(name)
SkipEnsure: m.skipEnsure, if err != nil {
return err
} }
mocksMethods := false methods := make([]template.MethodData, iface.NumMethods())
for j := 0; j < iface.NumMethods(); j++ {
methods[j] = m.methodData(iface.Method(j))
}
tpkg := m.srcPkg.Types mocks[i] = template.MockData{
for _, name := range names { InterfaceName: name,
n, mockName := parseInterfaceName(name)
iface := tpkg.Scope().Lookup(n)
if iface == nil {
return fmt.Errorf("cannot find interface %s", n)
}
if !types.IsInterface(iface.Type()) {
return fmt.Errorf("%s (%s) not an interface", n, iface.Type().String())
}
iiface := iface.Type().Underlying().(*types.Interface).Complete()
obj := obj{
InterfaceName: n,
MockName: mockName, MockName: mockName,
Methods: methods,
} }
for i := 0; i < iiface.NumMethods(); i++ {
mocksMethods = true
meth := iiface.Method(i)
sig := meth.Type().(*types.Signature)
method := &method{
Name: meth.Name(),
}
obj.Methods = append(obj.Methods, method)
method.Params, method.Returns = m.extractArgs(sig)
}
doc.Objects = append(doc.Objects, obj)
} }
if mocksMethods { data := template.Data{
doc.Imports = append(doc.Imports, "sync") PkgName: m.mockPkgName(),
Mocks: mocks,
StubImpl: m.cfg.StubImpl,
SkipEnsure: m.cfg.SkipEnsure,
} }
for pkgToImport := range m.imports { if data.MocksSomeMethod() {
doc.Imports = append(doc.Imports, stripVendorPath(pkgToImport)) m.registry.AddImport(types.NewPackage("sync", "sync"))
}
if m.registry.SrcPkgName() != m.mockPkgName() {
data.SrcPkgQualifier = m.registry.SrcPkgName() + "."
if !m.cfg.SkipEnsure {
imprt := m.registry.AddImport(m.registry.SrcPkg())
data.SrcPkgQualifier = imprt.Qualifier() + "."
}
} }
if tpkg.Name() != m.pkgName { data.Imports = m.registry.Imports()
doc.SourcePackagePrefix = tpkg.Name() + "."
doc.Imports = append(doc.Imports, stripVendorPath(tpkg.Path()))
}
var buf bytes.Buffer var buf bytes.Buffer
err := m.tmpl.Execute(&buf, doc) if err := m.tmpl.Execute(&buf, data); err != nil {
if err != nil { return err
return err }
}
formatted, err := m.fmter(buf.Bytes()) formatted, err := m.format(buf.Bytes())
if err != nil { if err != nil {
return err return err
} }
if _, err := w.Write(formatted); err != nil { if _, err := w.Write(formatted); err != nil {
return err return err
} }
return nil return nil
} }
func (m *Mocker) packageQualifier(pkg *types.Package) string { func (m *Mocker) methodData(f *types.Func) template.MethodData {
if m.pkgPath != "" && m.pkgPath == pkg.Path() { sig := f.Type().(*types.Signature)
return ""
scope := m.registry.MethodScope()
n := sig.Params().Len()
params := make([]template.ParamData, n)
for i := 0; i < n; i++ {
p := template.ParamData{
Var: scope.AddVar(sig.Params().At(i), ""),
} }
path := pkg.Path() p.Variadic = sig.Variadic() && i == n-1 && p.Var.IsSlice() // check for final variadic argument
if pkg.Path() == "." {
wd, err := os.Getwd() params[i] = p
if err == nil { }
path = stripGopath(wd)
n = sig.Results().Len()
results := make([]template.ParamData, n)
for i := 0; i < n; i++ {
results[i] = template.ParamData{
Var: scope.AddVar(sig.Results().At(i), "Out"),
} }
} }
m.imports[path] = true
return pkg.Name() return template.MethodData{
Name: f.Name(),
Params: params,
Returns: results,
}
} }
func (m *Mocker) extractArgs(sig *types.Signature) (params, results []*param) { func (m *Mocker) mockPkgName() string {
pp := sig.Params() if m.cfg.PkgName != "" {
for i := 0; i < pp.Len(); i++ { return m.cfg.PkgName
p := m.buildParam(pp.At(i), "in"+strconv.Itoa(i+1))
// check for final variadic argument
p.Variadic = sig.Variadic() && i == pp.Len()-1 && p.Type[0:2] == "[]"
params = append(params, p)
} }
rr := sig.Results() return m.registry.SrcPkgName()
for i := 0; i < rr.Len(); i++ {
results = append(results, m.buildParam(rr.At(i), "out"+strconv.Itoa(i+1)))
}
return
} }
func (m *Mocker) buildParam(v *types.Var, fallbackName string) *param { func (m *Mocker) format(src []byte) ([]byte, error) {
name := v.Name() switch m.cfg.Formatter {
if name == "" || name == "_" { case "goimports":
name = fallbackName return goimports(src)
case "noop":
return src, nil
} }
typ := types.TypeString(v.Type(), m.packageQualifier)
return &param{Name: name, Type: typ} return gofmt(src)
} }
func pkgInfoFromPath(srcDir string, mode packages.LoadMode) (*packages.Package, error) { func parseInterfaceName(namePair string) (ifaceName, mockName string) {
pkgs, err := packages.Load(&packages.Config{ parts := strings.SplitN(namePair, ":", 2)
Mode: mode,
Dir: srcDir,
})
if err != nil {
return nil, err
}
if len(pkgs) == 0 {
return nil, errors.New("No packages found")
}
if len(pkgs) > 1 {
return nil, errors.New("More than one package was found")
}
if errs := pkgs[0].Errors; len(errs) != 0 {
if len(errs) == 1 {
return nil, errs[0]
}
return nil, fmt.Errorf("%s (and %d more errors)", errs[0], len(errs)-1)
}
return pkgs[0], nil
}
func parseInterfaceName(name string) (ifaceName, mockName string) {
parts := strings.SplitN(name, ":", 2)
ifaceName = parts[0]
mockName = ifaceName + "Mock"
if len(parts) == 2 { if len(parts) == 2 {
mockName = parts[1] return parts[0], parts[1]
} }
return
}
type doc struct { ifaceName = parts[0]
PackageName string return ifaceName, ifaceName + "Mock"
SourcePackagePrefix string
Objects []obj
Imports []string
StubImpl bool
SkipEnsure bool
}
type obj struct {
InterfaceName string
MockName string
Methods []*method
}
type method struct {
Name string
Params []*param
Returns []*param
}
func (m *method) Arglist() string {
params := make([]string, len(m.Params))
for i, p := range m.Params {
params[i] = p.String()
}
return strings.Join(params, ", ")
}
func (m *method) ArgCallList() string {
params := make([]string, len(m.Params))
for i, p := range m.Params {
params[i] = p.CallName()
}
return strings.Join(params, ", ")
}
func (m *method) ReturnArgTypeList() string {
params := make([]string, len(m.Returns))
for i, p := range m.Returns {
params[i] = p.TypeString()
}
if len(m.Returns) > 1 {
return fmt.Sprintf("(%s)", strings.Join(params, ", "))
}
return strings.Join(params, ", ")
}
func (m *method) ReturnArgNameList() string {
params := make([]string, len(m.Returns))
for i, p := range m.Returns {
params[i] = p.Name
}
return strings.Join(params, ", ")
}
type param struct {
Name string
Type string
Variadic bool
}
func (p param) String() string {
return fmt.Sprintf("%s %s", p.Name, p.TypeString())
}
func (p param) CallName() string {
if p.Variadic {
return p.Name + "..."
}
return p.Name
}
func (p param) TypeString() string {
if p.Variadic {
return "..." + p.Type[2:]
}
return p.Type
}
var templateFuncs = template.FuncMap{
"Exported": func(s string) string {
if s == "" {
return ""
}
for _, initialism := range golintInitialisms {
if strings.ToUpper(s) == initialism {
return initialism
}
}
return strings.ToUpper(s[0:1]) + s[1:]
},
}
// stripVendorPath strips the vendor dir prefix from a package path.
// For example we might encounter an absolute path like
// github.com/foo/bar/vendor/github.com/pkg/errors which is resolved
// to github.com/pkg/errors.
func stripVendorPath(p string) string {
parts := strings.Split(p, "/vendor/")
if len(parts) == 1 {
return p
}
return strings.TrimLeft(path.Join(parts[1:]...), "/")
}
// stripGopath takes the directory to a package and removes the
// $GOPATH/src path to get the canonical package name.
func stripGopath(p string) string {
for _, srcDir := range build.Default.SrcDirs() {
rel, err := filepath.Rel(srcDir, p)
if err != nil || strings.HasPrefix(rel, "..") {
continue
}
return filepath.ToSlash(rel)
}
return p
} }

View File

@ -246,45 +246,6 @@ func TestVariadicArguments(t *testing.T) {
} }
} }
// TestSliceResult tests to ensure slice return data type works as
// expected.
// see https://github.com/matryer/moq/issues/124
func TestSliceResult(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/variadic"})
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
if err = m.Mock(&buf, "Echoer"); err != nil {
t.Errorf("m.Mock: %s", err)
}
golden := filepath.Join("testpackages/variadic", "echoer.golden.go")
if err := matchGoldenFile(golden, buf.Bytes()); err != nil {
t.Errorf("check golden file: %s", err)
}
}
// TestBlankID tests generation of mock where a method on the interface
// uses a blank identifier.
// See https://github.com/matryer/moq/issues/70
func TestBlankID(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/blankid"})
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
if err = m.Mock(&buf, "Swallower"); err != nil {
t.Errorf("m.Mock: %s", err)
}
golden := filepath.Join("testpackages/blankid", "swallower.golden.go")
if err := matchGoldenFile(golden, buf.Bytes()); err != nil {
t.Errorf("check golden file: %s", err)
}
}
func TestNothingToReturn(t *testing.T) { func TestNothingToReturn(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/example"}) m, err := New(Config{SrcDir: "testpackages/example"})
if err != nil { if err != nil {
@ -310,23 +271,6 @@ func TestNothingToReturn(t *testing.T) {
} }
} }
func TestChannelNames(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/channels", StubImpl: true})
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
if err = m.Mock(&buf, "Queuer"); err != nil {
t.Errorf("m.Mock: %s", err)
}
golden := filepath.Join("testpackages/channels", "queuer_moq.golden.go")
if err := matchGoldenFile(golden, buf.Bytes()); err != nil {
t.Errorf("check golden file: %s", err)
}
}
func TestImports(t *testing.T) { func TestImports(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/imports/two"}) m, err := New(Config{SrcDir: "testpackages/imports/two"})
if err != nil { if err != nil {
@ -352,6 +296,101 @@ func TestImports(t *testing.T) {
} }
} }
func TestMockGolden(t *testing.T) {
cases := []struct {
name string
cfg Config
interfaces []string
goldenFile string
}{
{
// Tests to ensure slice return data type works as expected.
// See https://github.com/matryer/moq/issues/124
name: "SliceResult",
cfg: Config{SrcDir: "testpackages/variadic"},
interfaces: []string{"Echoer"},
goldenFile: filepath.Join("testpackages/variadic", "echoer.golden.go"),
},
{
// Tests generation of mock where a method on the interface uses a
// blank identifier.
// See https://github.com/matryer/moq/issues/70
name: "BlankID",
cfg: Config{SrcDir: "testpackages/blankid"},
interfaces: []string{"Swallower"},
goldenFile: filepath.Join("testpackages/blankid", "swallower.golden.go"),
},
{
name: "ChannelNames",
cfg: Config{SrcDir: "testpackages/channels", StubImpl: true},
interfaces: []string{"Queuer"},
goldenFile: filepath.Join("testpackages/channels", "queuer_moq.golden.go"),
},
{
// Tests generation of mock when the interface imports a different
// package by the same name as it's own.
// See https://github.com/matryer/moq/issues/94
name: "PkgShadow",
cfg: Config{SrcDir: "testpackages/shadow/http", PkgName: "mock"},
interfaces: []string{"Thing"},
goldenFile: filepath.Join("testpackages/shadow/mock", "thing_moq.golden.go"),
},
{
// Tests generation of mock when a method parameter shadows an
// imported package name.
name: "ParamShadow",
cfg: Config{SrcDir: "testpackages/shadow"},
interfaces: []string{"Shadower"},
goldenFile: filepath.Join("testpackages/shadow", "shadower_moq.golden.go"),
},
{
name: "ImportAlias",
cfg: Config{SrcDir: "testpackages/importalias"},
interfaces: []string{"MiddleMan"},
goldenFile: filepath.Join("testpackages/importalias", "middleman_moq.golden.go"),
},
{
// Tests conflict resolution for generated names of method
// parameters.
name: "ParamNameConflict",
cfg: Config{SrcDir: "testpackages/paramconflict"},
interfaces: []string{"Interface"},
goldenFile: filepath.Join("testpackages/paramconflict", "iface_moq.golden.go"),
},
{
// Tests generation of names for unnamed method parameters.
name: "GenerateParamNames",
cfg: Config{SrcDir: "testpackages/genparamname"},
interfaces: []string{"Interface"},
goldenFile: filepath.Join("testpackages/genparamname", "iface_moq.golden.go"),
},
{
name: "SyncImport",
cfg: Config{SrcDir: "testpackages/syncimport"},
interfaces: []string{"Syncer"},
goldenFile: filepath.Join("testpackages/syncimport", "syncer_moq.golden.go"),
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
m, err := New(tc.cfg)
if err != nil {
t.Fatalf("moq.New: %s", err)
}
var buf bytes.Buffer
if err = m.Mock(&buf, tc.interfaces...); err != nil {
t.Errorf("m.Mock: %s", err)
return
}
if err := matchGoldenFile(tc.goldenFile, buf.Bytes()); err != nil {
t.Errorf("check golden file: %s", err)
}
})
}
}
func TestFormatter(t *testing.T) { func TestFormatter(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
@ -419,13 +458,6 @@ func matchGoldenFile(goldenFile string, actual []byte) error {
return nil return nil
} }
func TestTemplateFuncs(t *testing.T) {
fn := templateFuncs["Exported"].(func(string) string)
if fn("var") != "Var" {
t.Errorf("exported didn't work: %s", fn("var"))
}
}
func TestVendoredPackages(t *testing.T) { func TestVendoredPackages(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/vendoring/user"}) m, err := New(Config{SrcDir: "testpackages/vendoring/user"})
if err != nil { if err != nil {
@ -601,6 +633,41 @@ func TestParseError(t *testing.T) {
} }
} }
func TestMockError(t *testing.T) {
m, err := New(Config{SrcDir: "testpackages/example"})
if err != nil {
t.Fatalf("moq.New: %s", err)
}
cases := []struct {
name string
namePair string
wantErr string
}{
{
name: "TypeNotFound",
namePair: "DoesNotExist",
wantErr: "interface not found: DoesNotExist",
},
{
name: "UnexpectedType",
namePair: "Person",
wantErr: "Person (github.com/matryer/moq/pkg/moq/testpackages/example.Person) is not an interface",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := m.Mock(ioutil.Discard, tc.namePair)
if err == nil {
t.Errorf("expected error but got nil")
return
}
if !strings.Contains(err.Error(), tc.wantErr) {
t.Errorf("unexpected error: %s", err.Error())
}
})
}
}
// normalize normalizes \r\n (windows) and \r (mac) // normalize normalizes \r\n (windows) and \r (mac)
// into \n (unix) // into \n (unix)
func normalize(d []byte) []byte { func normalize(d []byte) []byte {

View File

@ -1,127 +0,0 @@
package moq
// moqImports are the imports all moq files get.
var moqImports = []string{}
// moqTemplate is the template for mocked code.
// language=GoTemplate
var moqTemplate = `// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package {{.PackageName}}
{{- $sourcePackagePrefix := .SourcePackagePrefix}}
{{- $stubImpl := .StubImpl}}
{{- $skipEnsure := .SkipEnsure}}
import (
{{- range .Imports }}
"{{.}}"
{{- end }}
)
{{ range $i, $obj := .Objects -}}
{{- if not $skipEnsure -}}
// Ensure, that {{.MockName}} does implement {{$sourcePackagePrefix}}{{.InterfaceName}}.
// If this is not the case, regenerate this file with moq.
var _ {{$sourcePackagePrefix}}{{.InterfaceName}} = &{{.MockName}}{}
{{- end }}
// {{.MockName}} is a mock implementation of {{$sourcePackagePrefix}}{{.InterfaceName}}.
//
// func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {
//
// // make and configure a mocked {{$sourcePackagePrefix}}{{.InterfaceName}}
// mocked{{.InterfaceName}} := &{{.MockName}}{ {{ range .Methods }}
// {{.Name}}Func: func({{ .Arglist }}) {{.ReturnArgTypeList}} {
// panic("mock out the {{.Name}} method")
// },{{- end }}
// }
//
// // use mocked{{.InterfaceName}} in code that requires {{$sourcePackagePrefix}}{{.InterfaceName}}
// // and then make assertions.
//
// }
type {{.MockName}} struct {
{{- range .Methods }}
// {{.Name}}Func mocks the {{.Name}} method.
{{.Name}}Func func({{ .Arglist }}) {{.ReturnArgTypeList}}
{{ end }}
// calls tracks calls to the methods.
calls struct {
{{- range .Methods }}
// {{ .Name }} holds details about calls to the {{.Name}} method.
{{ .Name }} []struct {
{{- range .Params }}
// {{ .Name | Exported }} is the {{ .Name }} argument value.
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}
{{- end }}
}
{{- range .Methods }}
lock{{.Name}} sync.RWMutex
{{- end }}
}
{{ range .Methods }}
// {{.Name}} calls {{.Name}}Func.
func (mock *{{$obj.MockName}}) {{.Name}}({{.Arglist}}) {{.ReturnArgTypeList}} {
{{- if not $stubImpl }}
if mock.{{.Name}}Func == nil {
panic("{{$obj.MockName}}.{{.Name}}Func: method is nil but {{$obj.InterfaceName}}.{{.Name}} was just called")
}
{{- end }}
callInfo := struct {
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}{
{{- range .Params }}
{{ .Name | Exported }}: {{ .Name }},
{{- end }}
}
mock.lock{{.Name}}.Lock()
mock.calls.{{.Name}} = append(mock.calls.{{.Name}}, callInfo)
mock.lock{{.Name}}.Unlock()
{{- if .Returns }}
{{- if $stubImpl }}
if mock.{{.Name}}Func == nil {
var (
{{- range .Returns }}
{{.Name}} {{.Type}}
{{- end }}
)
return {{.ReturnArgNameList}}
}
{{- end }}
return mock.{{.Name}}Func({{.ArgCallList}})
{{- else }}
{{- if $stubImpl }}
if mock.{{.Name}}Func == nil {
return
}
{{- end }}
mock.{{.Name}}Func({{.ArgCallList}})
{{- end }}
}
// {{.Name}}Calls gets all the calls that were made to {{.Name}}.
// Check the length with:
// len(mocked{{$obj.InterfaceName}}.{{.Name}}Calls())
func (mock *{{$obj.MockName}}) {{.Name}}Calls() []struct {
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
} {
var calls []struct {
{{- range .Params }}
{{ .Name | Exported }} {{ .Type }}
{{- end }}
}
mock.lock{{.Name}}.RLock()
calls = mock.calls.{{.Name}}
mock.lock{{.Name}}.RUnlock()
return calls
}
{{ end -}}
{{ end -}}`

View File

@ -17,7 +17,7 @@ var _ Swallower = &SwallowerMock{}
// //
// // make and configure a mocked Swallower // // make and configure a mocked Swallower
// mockedSwallower := &SwallowerMock{ // mockedSwallower := &SwallowerMock{
// SwallowFunc: func(in1 string) { // SwallowFunc: func(s string) {
// panic("mock out the Swallow method") // panic("mock out the Swallow method")
// }, // },
// } // }
@ -28,43 +28,43 @@ var _ Swallower = &SwallowerMock{}
// } // }
type SwallowerMock struct { type SwallowerMock struct {
// SwallowFunc mocks the Swallow method. // SwallowFunc mocks the Swallow method.
SwallowFunc func(in1 string) SwallowFunc func(s string)
// calls tracks calls to the methods. // calls tracks calls to the methods.
calls struct { calls struct {
// Swallow holds details about calls to the Swallow method. // Swallow holds details about calls to the Swallow method.
Swallow []struct { Swallow []struct {
// In1 is the in1 argument value. // S is the s argument value.
In1 string S string
} }
} }
lockSwallow sync.RWMutex lockSwallow sync.RWMutex
} }
// Swallow calls SwallowFunc. // Swallow calls SwallowFunc.
func (mock *SwallowerMock) Swallow(in1 string) { func (mock *SwallowerMock) Swallow(s string) {
if mock.SwallowFunc == nil { if mock.SwallowFunc == nil {
panic("SwallowerMock.SwallowFunc: method is nil but Swallower.Swallow was just called") panic("SwallowerMock.SwallowFunc: method is nil but Swallower.Swallow was just called")
} }
callInfo := struct { callInfo := struct {
In1 string S string
}{ }{
In1: in1, S: s,
} }
mock.lockSwallow.Lock() mock.lockSwallow.Lock()
mock.calls.Swallow = append(mock.calls.Swallow, callInfo) mock.calls.Swallow = append(mock.calls.Swallow, callInfo)
mock.lockSwallow.Unlock() mock.lockSwallow.Unlock()
mock.SwallowFunc(in1) mock.SwallowFunc(s)
} }
// SwallowCalls gets all the calls that were made to Swallow. // SwallowCalls gets all the calls that were made to Swallow.
// Check the length with: // Check the length with:
// len(mockedSwallower.SwallowCalls()) // len(mockedSwallower.SwallowCalls())
func (mock *SwallowerMock) SwallowCalls() []struct { func (mock *SwallowerMock) SwallowCalls() []struct {
In1 string S string
} { } {
var calls []struct { var calls []struct {
In1 string S string
} }
mock.lockSwallow.RLock() mock.lockSwallow.RLock()
calls = mock.calls.Swallow calls = mock.calls.Swallow

View File

@ -65,10 +65,10 @@ func (mock *QueuerMock) Sub(topic string) (<-chan Queue, error) {
mock.lockSub.Unlock() mock.lockSub.Unlock()
if mock.SubFunc == nil { if mock.SubFunc == nil {
var ( var (
out1 <-chan Queue queueChOut <-chan Queue
out2 error errOut error
) )
return out1, out2 return queueChOut, errOut
} }
return mock.SubFunc(topic) return mock.SubFunc(topic)
} }

View File

@ -8,10 +8,6 @@ import (
"sync" "sync"
) )
var (
lockServiceMockUser sync.RWMutex
)
// Ensure, that ServiceMock does implement dotimport.Service. // Ensure, that ServiceMock does implement dotimport.Service.
// If this is not the case, regenerate this file with moq. // If this is not the case, regenerate this file with moq.
var _ dotimport.Service = &ServiceMock{} var _ dotimport.Service = &ServiceMock{}
@ -43,6 +39,7 @@ type ServiceMock struct {
ID string ID string
} }
} }
lockUser sync.RWMutex
} }
// User calls UserFunc. // User calls UserFunc.
@ -55,9 +52,9 @@ func (mock *ServiceMock) User(ID string) (dotimport.User, error) {
}{ }{
ID: ID, ID: ID,
} }
lockServiceMockUser.Lock() mock.lockUser.Lock()
mock.calls.User = append(mock.calls.User, callInfo) mock.calls.User = append(mock.calls.User, callInfo)
lockServiceMockUser.Unlock() mock.lockUser.Unlock()
return mock.UserFunc(ID) return mock.UserFunc(ID)
} }
@ -70,8 +67,8 @@ func (mock *ServiceMock) UserCalls() []struct {
var calls []struct { var calls []struct {
ID string ID string
} }
lockServiceMockUser.RLock() mock.lockUser.RLock()
calls = mock.calls.User calls = mock.calls.User
lockServiceMockUser.RUnlock() mock.lockUser.RUnlock()
return calls return calls
} }

View File

@ -0,0 +1,34 @@
package genparamname
import (
"database/sql"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
)
type (
Go func()
myType struct{}
)
type Interface interface {
Method(
*myType,
[3]json.Number,
[]byte,
map[sql.NullString]io.Reader,
func(conn net.Conn),
Go,
chan *httputil.BufferPool,
struct{ URL *url.URL },
interface {
fmt.Stringer
CookieJar() http.CookieJar
},
)
}

View File

@ -0,0 +1,147 @@
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package genparamname
import (
"database/sql"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
"sync"
)
// Ensure, that InterfaceMock does implement Interface.
// If this is not the case, regenerate this file with moq.
var _ Interface = &InterfaceMock{}
// InterfaceMock is a mock implementation of Interface.
//
// func TestSomethingThatUsesInterface(t *testing.T) {
//
// // make and configure a mocked Interface
// mockedInterface := &InterfaceMock{
// MethodFunc: func(myTypeMoqParam *myType, numbers [3]json.Number, bytes []byte, nullStringToReader map[sql.NullString]io.Reader, fn func(conn net.Conn), goMoqParam Go, bufferPoolCh chan *httputil.BufferPool, val struct{URL *url.URL}, ifaceVal interface{CookieJar() http.CookieJar; fmt.Stringer}) {
// panic("mock out the Method method")
// },
// }
//
// // use mockedInterface in code that requires Interface
// // and then make assertions.
//
// }
type InterfaceMock struct {
// MethodFunc mocks the Method method.
MethodFunc func(myTypeMoqParam *myType, numbers [3]json.Number, bytes []byte, nullStringToReader map[sql.NullString]io.Reader, fn func(conn net.Conn), goMoqParam Go, bufferPoolCh chan *httputil.BufferPool, val struct{ URL *url.URL }, ifaceVal interface {
CookieJar() http.CookieJar
fmt.Stringer
})
// calls tracks calls to the methods.
calls struct {
// Method holds details about calls to the Method method.
Method []struct {
// MyTypeMoqParam is the myTypeMoqParam argument value.
MyTypeMoqParam *myType
// Numbers is the numbers argument value.
Numbers [3]json.Number
// Bytes is the bytes argument value.
Bytes []byte
// NullStringToReader is the nullStringToReader argument value.
NullStringToReader map[sql.NullString]io.Reader
// Fn is the fn argument value.
Fn func(conn net.Conn)
// GoMoqParam is the goMoqParam argument value.
GoMoqParam Go
// BufferPoolCh is the bufferPoolCh argument value.
BufferPoolCh chan *httputil.BufferPool
// Val is the val argument value.
Val struct{ URL *url.URL }
// IfaceVal is the ifaceVal argument value.
IfaceVal interface {
CookieJar() http.CookieJar
fmt.Stringer
}
}
}
lockMethod sync.RWMutex
}
// Method calls MethodFunc.
func (mock *InterfaceMock) Method(myTypeMoqParam *myType, numbers [3]json.Number, bytes []byte, nullStringToReader map[sql.NullString]io.Reader, fn func(conn net.Conn), goMoqParam Go, bufferPoolCh chan *httputil.BufferPool, val struct{ URL *url.URL }, ifaceVal interface {
CookieJar() http.CookieJar
fmt.Stringer
}) {
if mock.MethodFunc == nil {
panic("InterfaceMock.MethodFunc: method is nil but Interface.Method was just called")
}
callInfo := struct {
MyTypeMoqParam *myType
Numbers [3]json.Number
Bytes []byte
NullStringToReader map[sql.NullString]io.Reader
Fn func(conn net.Conn)
GoMoqParam Go
BufferPoolCh chan *httputil.BufferPool
Val struct{ URL *url.URL }
IfaceVal interface {
CookieJar() http.CookieJar
fmt.Stringer
}
}{
MyTypeMoqParam: myTypeMoqParam,
Numbers: numbers,
Bytes: bytes,
NullStringToReader: nullStringToReader,
Fn: fn,
GoMoqParam: goMoqParam,
BufferPoolCh: bufferPoolCh,
Val: val,
IfaceVal: ifaceVal,
}
mock.lockMethod.Lock()
mock.calls.Method = append(mock.calls.Method, callInfo)
mock.lockMethod.Unlock()
mock.MethodFunc(myTypeMoqParam, numbers, bytes, nullStringToReader, fn, goMoqParam, bufferPoolCh, val, ifaceVal)
}
// MethodCalls gets all the calls that were made to Method.
// Check the length with:
// len(mockedInterface.MethodCalls())
func (mock *InterfaceMock) MethodCalls() []struct {
MyTypeMoqParam *myType
Numbers [3]json.Number
Bytes []byte
NullStringToReader map[sql.NullString]io.Reader
Fn func(conn net.Conn)
GoMoqParam Go
BufferPoolCh chan *httputil.BufferPool
Val struct{ URL *url.URL }
IfaceVal interface {
CookieJar() http.CookieJar
fmt.Stringer
}
} {
var calls []struct {
MyTypeMoqParam *myType
Numbers [3]json.Number
Bytes []byte
NullStringToReader map[sql.NullString]io.Reader
Fn func(conn net.Conn)
GoMoqParam Go
BufferPoolCh chan *httputil.BufferPool
Val struct{ URL *url.URL }
IfaceVal interface {
CookieJar() http.CookieJar
fmt.Stringer
}
}
mock.lockMethod.RLock()
calls = mock.calls.Method
mock.lockMethod.RUnlock()
return calls
}

View File

@ -18,7 +18,7 @@ var _ Service = &ServiceMock{}
// //
// // make and configure a mocked Service // // make and configure a mocked Service
// mockedService := &ServiceMock{ // mockedService := &ServiceMock{
// DoSomethingFunc: func(in1 somerepo.SomeType) error { // DoSomethingFunc: func(someType somerepo.SomeType) error {
// panic("mock out the DoSomething method") // panic("mock out the DoSomething method")
// }, // },
// } // }
@ -29,43 +29,43 @@ var _ Service = &ServiceMock{}
// } // }
type ServiceMock struct { type ServiceMock struct {
// DoSomethingFunc mocks the DoSomething method. // DoSomethingFunc mocks the DoSomething method.
DoSomethingFunc func(in1 somerepo.SomeType) error DoSomethingFunc func(someType somerepo.SomeType) error
// calls tracks calls to the methods. // calls tracks calls to the methods.
calls struct { calls struct {
// DoSomething holds details about calls to the DoSomething method. // DoSomething holds details about calls to the DoSomething method.
DoSomething []struct { DoSomething []struct {
// In1 is the in1 argument value. // SomeType is the someType argument value.
In1 somerepo.SomeType SomeType somerepo.SomeType
} }
} }
lockDoSomething sync.RWMutex lockDoSomething sync.RWMutex
} }
// DoSomething calls DoSomethingFunc. // DoSomething calls DoSomethingFunc.
func (mock *ServiceMock) DoSomething(in1 somerepo.SomeType) error { func (mock *ServiceMock) DoSomething(someType somerepo.SomeType) error {
if mock.DoSomethingFunc == nil { if mock.DoSomethingFunc == nil {
panic("ServiceMock.DoSomethingFunc: method is nil but Service.DoSomething was just called") panic("ServiceMock.DoSomethingFunc: method is nil but Service.DoSomething was just called")
} }
callInfo := struct { callInfo := struct {
In1 somerepo.SomeType SomeType somerepo.SomeType
}{ }{
In1: in1, SomeType: someType,
} }
mock.lockDoSomething.Lock() mock.lockDoSomething.Lock()
mock.calls.DoSomething = append(mock.calls.DoSomething, callInfo) mock.calls.DoSomething = append(mock.calls.DoSomething, callInfo)
mock.lockDoSomething.Unlock() mock.lockDoSomething.Unlock()
return mock.DoSomethingFunc(in1) return mock.DoSomethingFunc(someType)
} }
// DoSomethingCalls gets all the calls that were made to DoSomething. // DoSomethingCalls gets all the calls that were made to DoSomething.
// Check the length with: // Check the length with:
// len(mockedService.DoSomethingCalls()) // len(mockedService.DoSomethingCalls())
func (mock *ServiceMock) DoSomethingCalls() []struct { func (mock *ServiceMock) DoSomethingCalls() []struct {
In1 somerepo.SomeType SomeType somerepo.SomeType
} { } {
var calls []struct { var calls []struct {
In1 somerepo.SomeType SomeType somerepo.SomeType
} }
mock.lockDoSomething.RLock() mock.lockDoSomething.RLock()
calls = mock.calls.DoSomething calls = mock.calls.DoSomething

View File

@ -0,0 +1,10 @@
package importalias
import (
srcclient "github.com/matryer/moq/pkg/moq/testpackages/importalias/source/client"
tgtclient "github.com/matryer/moq/pkg/moq/testpackages/importalias/target/client"
)
type MiddleMan interface {
Connect(src srcclient.Client, tgt tgtclient.Client)
}

View File

@ -0,0 +1,81 @@
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package importalias
import (
srcclient "github.com/matryer/moq/pkg/moq/testpackages/importalias/source/client"
tgtclient "github.com/matryer/moq/pkg/moq/testpackages/importalias/target/client"
"sync"
)
// Ensure, that MiddleManMock does implement MiddleMan.
// If this is not the case, regenerate this file with moq.
var _ MiddleMan = &MiddleManMock{}
// MiddleManMock is a mock implementation of MiddleMan.
//
// func TestSomethingThatUsesMiddleMan(t *testing.T) {
//
// // make and configure a mocked MiddleMan
// mockedMiddleMan := &MiddleManMock{
// ConnectFunc: func(src srcclient.Client, tgt tgtclient.Client) {
// panic("mock out the Connect method")
// },
// }
//
// // use mockedMiddleMan in code that requires MiddleMan
// // and then make assertions.
//
// }
type MiddleManMock struct {
// ConnectFunc mocks the Connect method.
ConnectFunc func(src srcclient.Client, tgt tgtclient.Client)
// calls tracks calls to the methods.
calls struct {
// Connect holds details about calls to the Connect method.
Connect []struct {
// Src is the src argument value.
Src srcclient.Client
// Tgt is the tgt argument value.
Tgt tgtclient.Client
}
}
lockConnect sync.RWMutex
}
// Connect calls ConnectFunc.
func (mock *MiddleManMock) Connect(src srcclient.Client, tgt tgtclient.Client) {
if mock.ConnectFunc == nil {
panic("MiddleManMock.ConnectFunc: method is nil but MiddleMan.Connect was just called")
}
callInfo := struct {
Src srcclient.Client
Tgt tgtclient.Client
}{
Src: src,
Tgt: tgt,
}
mock.lockConnect.Lock()
mock.calls.Connect = append(mock.calls.Connect, callInfo)
mock.lockConnect.Unlock()
mock.ConnectFunc(src, tgt)
}
// ConnectCalls gets all the calls that were made to Connect.
// Check the length with:
// len(mockedMiddleMan.ConnectCalls())
func (mock *MiddleManMock) ConnectCalls() []struct {
Src srcclient.Client
Tgt tgtclient.Client
} {
var calls []struct {
Src srcclient.Client
Tgt tgtclient.Client
}
mock.lockConnect.RLock()
calls = mock.calls.Connect
mock.lockConnect.RUnlock()
return calls
}

View File

@ -0,0 +1,3 @@
package client
type Client struct{}

View File

@ -0,0 +1,3 @@
package client
type Client struct{}

View File

@ -4,8 +4,8 @@
package two package two
import ( import (
"sync"
"github.com/matryer/moq/pkg/moq/testpackages/imports/one" "github.com/matryer/moq/pkg/moq/testpackages/imports/one"
"sync"
) )
// Ensure, that noopMock does implement DoSomething. // Ensure, that noopMock does implement DoSomething.

View File

@ -0,0 +1,5 @@
package paramconflict
type Interface interface {
Method(string, bool, string, bool, int, int32, int64, float32, float64)
}

View File

@ -0,0 +1,121 @@
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package paramconflict
import (
"sync"
)
// Ensure, that InterfaceMock does implement Interface.
// If this is not the case, regenerate this file with moq.
var _ Interface = &InterfaceMock{}
// InterfaceMock is a mock implementation of Interface.
//
// func TestSomethingThatUsesInterface(t *testing.T) {
//
// // make and configure a mocked Interface
// mockedInterface := &InterfaceMock{
// MethodFunc: func(s1 string, b1 bool, s2 string, b2 bool, n1 int, n2 int32, n3 int64, f1 float32, f2 float64) {
// panic("mock out the Method method")
// },
// }
//
// // use mockedInterface in code that requires Interface
// // and then make assertions.
//
// }
type InterfaceMock struct {
// MethodFunc mocks the Method method.
MethodFunc func(s1 string, b1 bool, s2 string, b2 bool, n1 int, n2 int32, n3 int64, f1 float32, f2 float64)
// calls tracks calls to the methods.
calls struct {
// Method holds details about calls to the Method method.
Method []struct {
// S1 is the s1 argument value.
S1 string
// B1 is the b1 argument value.
B1 bool
// S2 is the s2 argument value.
S2 string
// B2 is the b2 argument value.
B2 bool
// N1 is the n1 argument value.
N1 int
// N2 is the n2 argument value.
N2 int32
// N3 is the n3 argument value.
N3 int64
// F1 is the f1 argument value.
F1 float32
// F2 is the f2 argument value.
F2 float64
}
}
lockMethod sync.RWMutex
}
// Method calls MethodFunc.
func (mock *InterfaceMock) Method(s1 string, b1 bool, s2 string, b2 bool, n1 int, n2 int32, n3 int64, f1 float32, f2 float64) {
if mock.MethodFunc == nil {
panic("InterfaceMock.MethodFunc: method is nil but Interface.Method was just called")
}
callInfo := struct {
S1 string
B1 bool
S2 string
B2 bool
N1 int
N2 int32
N3 int64
F1 float32
F2 float64
}{
S1: s1,
B1: b1,
S2: s2,
B2: b2,
N1: n1,
N2: n2,
N3: n3,
F1: f1,
F2: f2,
}
mock.lockMethod.Lock()
mock.calls.Method = append(mock.calls.Method, callInfo)
mock.lockMethod.Unlock()
mock.MethodFunc(s1, b1, s2, b2, n1, n2, n3, f1, f2)
}
// MethodCalls gets all the calls that were made to Method.
// Check the length with:
// len(mockedInterface.MethodCalls())
func (mock *InterfaceMock) MethodCalls() []struct {
S1 string
B1 bool
S2 string
B2 bool
N1 int
N2 int32
N3 int64
F1 float32
F2 float64
} {
var calls []struct {
S1 string
B1 bool
S2 string
B2 bool
N1 int
N2 int32
N3 int64
F1 float32
F2 float64
}
mock.lockMethod.RLock()
calls = mock.calls.Method
mock.lockMethod.RUnlock()
return calls
}

View File

@ -0,0 +1,7 @@
package http
import "net/http"
type Thing interface {
Blah(w http.ResponseWriter, r *http.Request)
}

View File

@ -0,0 +1,81 @@
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package mock
import (
shadowhttp "github.com/matryer/moq/pkg/moq/testpackages/shadow/http"
nethttp "net/http"
"sync"
)
// Ensure, that ThingMock does implement shadowhttp.Thing.
// If this is not the case, regenerate this file with moq.
var _ shadowhttp.Thing = &ThingMock{}
// ThingMock is a mock implementation of shadowhttp.Thing.
//
// func TestSomethingThatUsesThing(t *testing.T) {
//
// // make and configure a mocked shadowhttp.Thing
// mockedThing := &ThingMock{
// BlahFunc: func(w nethttp.ResponseWriter, r *nethttp.Request) {
// panic("mock out the Blah method")
// },
// }
//
// // use mockedThing in code that requires shadowhttp.Thing
// // and then make assertions.
//
// }
type ThingMock struct {
// BlahFunc mocks the Blah method.
BlahFunc func(w nethttp.ResponseWriter, r *nethttp.Request)
// calls tracks calls to the methods.
calls struct {
// Blah holds details about calls to the Blah method.
Blah []struct {
// W is the w argument value.
W nethttp.ResponseWriter
// R is the r argument value.
R *nethttp.Request
}
}
lockBlah sync.RWMutex
}
// Blah calls BlahFunc.
func (mock *ThingMock) Blah(w nethttp.ResponseWriter, r *nethttp.Request) {
if mock.BlahFunc == nil {
panic("ThingMock.BlahFunc: method is nil but Thing.Blah was just called")
}
callInfo := struct {
W nethttp.ResponseWriter
R *nethttp.Request
}{
W: w,
R: r,
}
mock.lockBlah.Lock()
mock.calls.Blah = append(mock.calls.Blah, callInfo)
mock.lockBlah.Unlock()
mock.BlahFunc(w, r)
}
// BlahCalls gets all the calls that were made to Blah.
// Check the length with:
// len(mockedThing.BlahCalls())
func (mock *ThingMock) BlahCalls() []struct {
W nethttp.ResponseWriter
R *nethttp.Request
} {
var calls []struct {
W nethttp.ResponseWriter
R *nethttp.Request
}
mock.lockBlah.RLock()
calls = mock.calls.Blah
mock.lockBlah.RUnlock()
return calls
}

View File

@ -0,0 +1,14 @@
package shadow
import (
"io"
"net/http"
)
// Shadower is an interface, with a method, with a parameter whose name
// shadows an import name.
type Shadower interface {
Shadow(io io.Reader)
ShadowTwo(r io.Reader, io interface{})
ShadowThree(http interface{}, srv *http.Server)
}

View File

@ -0,0 +1,173 @@
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package shadow
import (
"io"
"net/http"
"sync"
)
// Ensure, that ShadowerMock does implement Shadower.
// If this is not the case, regenerate this file with moq.
var _ Shadower = &ShadowerMock{}
// ShadowerMock is a mock implementation of Shadower.
//
// func TestSomethingThatUsesShadower(t *testing.T) {
//
// // make and configure a mocked Shadower
// mockedShadower := &ShadowerMock{
// ShadowFunc: func(ioMoqParam io.Reader) {
// panic("mock out the Shadow method")
// },
// ShadowThreeFunc: func(httpMoqParam interface{}, srv *http.Server) {
// panic("mock out the ShadowThree method")
// },
// ShadowTwoFunc: func(r io.Reader, ioMoqParam interface{}) {
// panic("mock out the ShadowTwo method")
// },
// }
//
// // use mockedShadower in code that requires Shadower
// // and then make assertions.
//
// }
type ShadowerMock struct {
// ShadowFunc mocks the Shadow method.
ShadowFunc func(ioMoqParam io.Reader)
// ShadowThreeFunc mocks the ShadowThree method.
ShadowThreeFunc func(httpMoqParam interface{}, srv *http.Server)
// ShadowTwoFunc mocks the ShadowTwo method.
ShadowTwoFunc func(r io.Reader, ioMoqParam interface{})
// calls tracks calls to the methods.
calls struct {
// Shadow holds details about calls to the Shadow method.
Shadow []struct {
// IoMoqParam is the ioMoqParam argument value.
IoMoqParam io.Reader
}
// ShadowThree holds details about calls to the ShadowThree method.
ShadowThree []struct {
// HttpMoqParam is the httpMoqParam argument value.
HttpMoqParam interface{}
// Srv is the srv argument value.
Srv *http.Server
}
// ShadowTwo holds details about calls to the ShadowTwo method.
ShadowTwo []struct {
// R is the r argument value.
R io.Reader
// IoMoqParam is the ioMoqParam argument value.
IoMoqParam interface{}
}
}
lockShadow sync.RWMutex
lockShadowThree sync.RWMutex
lockShadowTwo sync.RWMutex
}
// Shadow calls ShadowFunc.
func (mock *ShadowerMock) Shadow(ioMoqParam io.Reader) {
if mock.ShadowFunc == nil {
panic("ShadowerMock.ShadowFunc: method is nil but Shadower.Shadow was just called")
}
callInfo := struct {
IoMoqParam io.Reader
}{
IoMoqParam: ioMoqParam,
}
mock.lockShadow.Lock()
mock.calls.Shadow = append(mock.calls.Shadow, callInfo)
mock.lockShadow.Unlock()
mock.ShadowFunc(ioMoqParam)
}
// ShadowCalls gets all the calls that were made to Shadow.
// Check the length with:
// len(mockedShadower.ShadowCalls())
func (mock *ShadowerMock) ShadowCalls() []struct {
IoMoqParam io.Reader
} {
var calls []struct {
IoMoqParam io.Reader
}
mock.lockShadow.RLock()
calls = mock.calls.Shadow
mock.lockShadow.RUnlock()
return calls
}
// ShadowThree calls ShadowThreeFunc.
func (mock *ShadowerMock) ShadowThree(httpMoqParam interface{}, srv *http.Server) {
if mock.ShadowThreeFunc == nil {
panic("ShadowerMock.ShadowThreeFunc: method is nil but Shadower.ShadowThree was just called")
}
callInfo := struct {
HttpMoqParam interface{}
Srv *http.Server
}{
HttpMoqParam: httpMoqParam,
Srv: srv,
}
mock.lockShadowThree.Lock()
mock.calls.ShadowThree = append(mock.calls.ShadowThree, callInfo)
mock.lockShadowThree.Unlock()
mock.ShadowThreeFunc(httpMoqParam, srv)
}
// ShadowThreeCalls gets all the calls that were made to ShadowThree.
// Check the length with:
// len(mockedShadower.ShadowThreeCalls())
func (mock *ShadowerMock) ShadowThreeCalls() []struct {
HttpMoqParam interface{}
Srv *http.Server
} {
var calls []struct {
HttpMoqParam interface{}
Srv *http.Server
}
mock.lockShadowThree.RLock()
calls = mock.calls.ShadowThree
mock.lockShadowThree.RUnlock()
return calls
}
// ShadowTwo calls ShadowTwoFunc.
func (mock *ShadowerMock) ShadowTwo(r io.Reader, ioMoqParam interface{}) {
if mock.ShadowTwoFunc == nil {
panic("ShadowerMock.ShadowTwoFunc: method is nil but Shadower.ShadowTwo was just called")
}
callInfo := struct {
R io.Reader
IoMoqParam interface{}
}{
R: r,
IoMoqParam: ioMoqParam,
}
mock.lockShadowTwo.Lock()
mock.calls.ShadowTwo = append(mock.calls.ShadowTwo, callInfo)
mock.lockShadowTwo.Unlock()
mock.ShadowTwoFunc(r, ioMoqParam)
}
// ShadowTwoCalls gets all the calls that were made to ShadowTwo.
// Check the length with:
// len(mockedShadower.ShadowTwoCalls())
func (mock *ShadowerMock) ShadowTwoCalls() []struct {
R io.Reader
IoMoqParam interface{}
} {
var calls []struct {
R io.Reader
IoMoqParam interface{}
}
mock.lockShadowTwo.RLock()
calls = mock.calls.ShadowTwo
mock.lockShadowTwo.RUnlock()
return calls
}

View File

@ -0,0 +1,3 @@
package sync
type Thing string

View File

@ -0,0 +1,11 @@
package syncimport
import (
stdsync "sync"
"github.com/matryer/moq/pkg/moq/testpackages/syncimport/sync"
)
type Syncer interface {
Blah(s sync.Thing, wg *stdsync.WaitGroup)
}

View File

@ -0,0 +1,80 @@
// Code generated by moq; DO NOT EDIT.
// github.com/matryer/moq
package syncimport
import (
"github.com/matryer/moq/pkg/moq/testpackages/syncimport/sync"
stdsync "sync"
)
// Ensure, that SyncerMock does implement Syncer.
// If this is not the case, regenerate this file with moq.
var _ Syncer = &SyncerMock{}
// SyncerMock is a mock implementation of Syncer.
//
// func TestSomethingThatUsesSyncer(t *testing.T) {
//
// // make and configure a mocked Syncer
// mockedSyncer := &SyncerMock{
// BlahFunc: func(s sync.Thing, wg *stdsync.WaitGroup) {
// panic("mock out the Blah method")
// },
// }
//
// // use mockedSyncer in code that requires Syncer
// // and then make assertions.
//
// }
type SyncerMock struct {
// BlahFunc mocks the Blah method.
BlahFunc func(s sync.Thing, wg *stdsync.WaitGroup)
// calls tracks calls to the methods.
calls struct {
// Blah holds details about calls to the Blah method.
Blah []struct {
// S is the s argument value.
S sync.Thing
// Wg is the wg argument value.
Wg *stdsync.WaitGroup
}
}
lockBlah stdsync.RWMutex
}
// Blah calls BlahFunc.
func (mock *SyncerMock) Blah(s sync.Thing, wg *stdsync.WaitGroup) {
if mock.BlahFunc == nil {
panic("SyncerMock.BlahFunc: method is nil but Syncer.Blah was just called")
}
callInfo := struct {
S sync.Thing
Wg *stdsync.WaitGroup
}{
S: s,
Wg: wg,
}
mock.lockBlah.Lock()
mock.calls.Blah = append(mock.calls.Blah, callInfo)
mock.lockBlah.Unlock()
mock.BlahFunc(s, wg)
}
// BlahCalls gets all the calls that were made to Blah.
// Check the length with:
// len(mockedSyncer.BlahCalls())
func (mock *SyncerMock) BlahCalls() []struct {
S sync.Thing
Wg *stdsync.WaitGroup
} {
var calls []struct {
S sync.Thing
Wg *stdsync.WaitGroup
}
mock.lockBlah.RLock()
calls = mock.calls.Blah
mock.lockBlah.RUnlock()
return calls
}