Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
LandonTClipp committed Oct 20, 2023
1 parent bb23a0c commit 75de741
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 82 deletions.
11 changes: 6 additions & 5 deletions cmd/mockery.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,6 @@ func (r *RootApp) Run() error {
return nil
}

var osp pkg.OutputStreamProvider
if r.Config.Print {
osp = &pkg.StdoutStreamProvider{}
}
buildTags := strings.Split(r.Config.BuildTags, " ")

var boilerplate string
Expand Down Expand Up @@ -268,7 +264,7 @@ func (r *RootApp) Run() error {
}
ifaceLog.Debug().Msg("config specifies to generate this interface")

outputter := pkg.NewOutputter(&r.Config, boilerplate, true)
outputter := pkg.NewOutputter(&r.Config, boilerplate)
if err := outputter.Generate(ifaceCtx, iface); err != nil {
return err
}
Expand All @@ -277,6 +273,11 @@ func (r *RootApp) Run() error {
return nil
}

var osp pkg.OutputStreamProvider
if r.Config.Print {
osp = &pkg.StdoutStreamProvider{}
}

if r.Config.Name != "" && r.Config.All {
log.Fatal().Msgf("Specify --name or --all, but not both")
} else if (r.Config.FileName != "" || r.Config.StructName != "") && r.Config.All {
Expand Down
34 changes: 34 additions & 0 deletions pkg/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package pkg

import (
"go/ast"
"go/types"
)

// Interface type represents the target type that we will generate a mock for.
// It could be an interface, or a function type.
// Function type emulates: an interface it has 1 method with the function signature
// and a general name, e.g. "Execute".
type Interface struct {
Name string // Name of the type to be mocked.
QualifiedName string // Path to the package of the target type.
FileName string
File *ast.File
Pkg TypesPackage
NamedType *types.Named
IsFunction bool // If true, this instance represents a function, otherwise it's an interface.
ActualInterface *types.Interface // Holds the actual interface type, in case it's an interface.
SingleFunction *Method // Holds the function type information, in case it's a function type.
}

func (iface *Interface) Methods() []*Method {
if iface.IsFunction {
return []*Method{iface.SingleFunction}
}
methods := make([]*Method, iface.ActualInterface.NumMethods())
for i := 0; i < iface.ActualInterface.NumMethods(); i++ {
fn := iface.ActualInterface.Method(i)
methods[i] = &Method{Name: fn.Name(), Signature: fn.Type().(*types.Signature)}
}
return methods
}
88 changes: 88 additions & 0 deletions pkg/method.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package pkg

import (
"go/types"
"path"
"strings"
)

type Method struct {
Name string
Signature *types.Signature
}

type Imports map[string]*types.Package

func (m Method) populateImports(imports Imports) {
for i := 0; i < m.Signature.Params().Len(); i++ {
m.importsHelper(m.Signature.Params().At(i).Type(), imports)
}
}

// 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:]...), "/")
}

// importsHelper 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 Method) importsHelper(elem types.Type, imports map[string]*types.Package) {
switch t := elem.(type) {
case *types.Named:
if pkg := t.Obj().Pkg(); pkg != nil {
imports[stripVendorPath(pkg.Path())] = pkg
}
// The imports of a Type with a TypeList must be added to the imports list
// For example: Foo[otherpackage.Bar] , must have otherpackage imported
if targs := t.TypeArgs(); targs != nil {
for i := 0; i < targs.Len(); i++ {
m.importsHelper(targs.At(i), imports)
}
}

case *types.Array:
m.importsHelper(t.Elem(), imports)

case *types.Slice:
m.importsHelper(t.Elem(), imports)

case *types.Signature:
for i := 0; i < t.Params().Len(); i++ {
m.importsHelper(t.Params().At(i).Type(), imports)
}
for i := 0; i < t.Results().Len(); i++ {
m.importsHelper(t.Results().At(i).Type(), imports)
}

case *types.Map:
m.importsHelper(t.Key(), imports)
m.importsHelper(t.Elem(), imports)

case *types.Chan:
m.importsHelper(t.Elem(), imports)

case *types.Pointer:
m.importsHelper(t.Elem(), imports)

case *types.Struct: // anonymous struct
for i := 0; i < t.NumFields(); i++ {
m.importsHelper(t.Field(i).Type(), imports)
}

case *types.Interface: // anonymous interface
for i := 0; i < t.NumExplicitMethods(); i++ {
m.importsHelper(t.ExplicitMethod(i).Type(), imports)
}
for i := 0; i < t.NumEmbeddeds(); i++ {
m.importsHelper(t.EmbeddedType(i), imports)
}
}
}
2 changes: 0 additions & 2 deletions pkg/outputter.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,10 @@ type Outputter struct {
func NewOutputter(
config *config.Config,
boilerplate string,
dryRun bool,
) *Outputter {
return &Outputter{
boilerplate: boilerplate,
config: config,
dryRun: dryRun,
}
}

Expand Down
31 changes: 0 additions & 31 deletions pkg/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,43 +261,12 @@ func (p *Parser) packageInterfaces(
return ifaces
}

type Method struct {
Name string
Signature *types.Signature
}

type TypesPackage interface {
Name() string
Path() string
}

// Interface type represents the target type that we will generate a mock for.
// It could be an interface, or a function type.
// Function type emulates: an interface it has 1 method with the function signature
// and a general name, e.g. "Execute".
type Interface struct {
Name string // Name of the type to be mocked.
QualifiedName string // Path to the package of the target type.
FileName string
File *ast.File
Pkg TypesPackage
NamedType *types.Named
IsFunction bool // If true, this instance represents a function, otherwise it's an interface.
ActualInterface *types.Interface // Holds the actual interface type, in case it's an interface.
SingleFunction *Method // Holds the function type information, in case it's a function type.
}

func (iface *Interface) Methods() []*Method {
if iface.IsFunction {
return []*Method{iface.SingleFunction}
}
methods := make([]*Method, iface.ActualInterface.NumMethods())
for i := 0; i < iface.ActualInterface.NumMethods(); i++ {
fn := iface.ActualInterface.Method(i)
methods[i] = &Method{Name: fn.Name(), Signature: fn.Type().(*types.Signature)}
}
return methods
}

type sortableIFaceList []*Interface

Expand Down
24 changes: 10 additions & 14 deletions pkg/registry/package.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
package registry

import (
"go/types"
"path"

Check failure on line 4 in pkg/registry/package.go

View workflow job for this annotation

GitHub Actions / lint

imported and not used: "path"
"strings"
)

type TypesPackage interface {
Name() string
Path() string
}

// Package represents an imported package.
type Package struct {
pkg *types.Package
pkg TypesPackage

Alias string
}

// NewPackage creates a new instance of Package.
func NewPackage(pkg *types.Package) *Package { return &Package{pkg: pkg} }
func NewPackage(pkg TypesPackage) *Package {
return &Package{pkg: pkg}
}

// Qualifier returns the qualifier which must be used to refer to types
// declared in the package.
Expand Down Expand Up @@ -66,17 +72,7 @@ func (p Package) uniqueName(lvl int) string {
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 {
Expand Down
32 changes: 5 additions & 27 deletions pkg/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"fmt"
"go/ast"
"go/types"
"path/filepath"
"sort"
"strings"

"github.com/chigopher/pathlib"
"golang.org/x/tools/go/packages"
)

Expand All @@ -19,25 +19,18 @@ import (
type Registry struct {
srcPkgName string
srcPkgTypes *types.Package
moqPkgPath string
outputPath *pathlib.Path
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,
)
if err != nil {
return nil, fmt.Errorf("couldn't load source package: %s", err)
}

func New(srcPkg *packages.Package, outputPath *pathlib.Path) (*Registry, error) {
return &Registry{
srcPkgName: srcPkg.Name,
srcPkgTypes: srcPkg.Types,
moqPkgPath: findPkgPath(moqPkg, srcPkg.PkgPath),
outputPath: outputPath,
aliases: parseImportsAliases(srcPkg.Syntax),
imports: make(map[string]*Package),
}, nil
Expand Down Expand Up @@ -78,7 +71,6 @@ func (r Registry) LookupInterface(name string) (*types.Interface, *types.TypePar
func (r *Registry) MethodScope() *MethodScope {
return &MethodScope{
registry: r,
moqPkgPath: r.moqPkgPath,
conflicted: map[string]bool{},
}
}
Expand All @@ -88,7 +80,7 @@ func (r *Registry) MethodScope() *MethodScope {
// packages.
func (r *Registry) AddImport(pkg *types.Package) *Package {
path := stripVendorPath(pkg.Path())

Check failure on line 82 in pkg/registry/registry.go

View workflow job for this annotation

GitHub Actions / lint

undefined: stripVendorPath
if path == r.moqPkgPath {
if pathlib.NewPath(path).Equals(r.outputPath) {
return nil
}

Expand Down Expand Up @@ -176,20 +168,6 @@ func pkgInfoFromPath(srcDir string, mode packages.LoadMode) (*packages.Package,
return pkgs[0], nil
}

func findPkgPath(pkgInputVal string, srcPkgPath string) string {
if pkgInputVal == "" {
return srcPkgPath
}
if pkgInDir(srcPkgPath, pkgInputVal) {
return srcPkgPath
}
subdirectoryPath := filepath.Join(srcPkgPath, pkgInputVal)
if pkgInDir(subdirectoryPath, pkgInputVal) {
return subdirectoryPath
}
return ""
}

func pkgInDir(pkgName, dir string) bool {
currentPkg, err := pkgInfoFromPath(dir, packages.NeedName)
if err != nil {
Expand Down
16 changes: 13 additions & 3 deletions pkg/template_generator.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package pkg

import (
"github.com/vektra/mockery/v2/pkg/registry"
"github.com/vektra/mockery/v2/pkg/config"
"github.com/vektra/mockery/v2/pkg/template"
)

Expand All @@ -18,12 +18,22 @@ func NewTemplateGenerator(config TemplateGeneratorConfig) *TemplateGenerator {
}
}

func (g *TemplateGenerator) Generate() error {
func (g *TemplateGenerator) Generate(iface *Interface, ifaceConfig *config.Config) error {
templ, err := template.New(g.config.Style)
if err != nil {
return err
}
data := registry.
imports := Imports{}
for _, method := range iface.Methods() {
method.populateImports(imports)
}
// TODO: Work on getting these imports into the template

data := template.Data{
PkgName: ifaceConfig.Outpkg,
SrcPkgQualifier: iface.Pkg.Name() + ".",
Imports:
}

Check failure on line 36 in pkg/template_generator.go

View workflow job for this annotation

GitHub Actions / lint

expected operand, found '}' (typecheck)

Check failure on line 36 in pkg/template_generator.go

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 1.20)

expected operand, found '}'

return nil

Check failure on line 38 in pkg/template_generator.go

View workflow job for this annotation

GitHub Actions / lint

missing ',' in composite literal (typecheck)

Check failure on line 38 in pkg/template_generator.go

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 1.20)

missing ',' in composite literal
}

Check failure on line 39 in pkg/template_generator.go

View workflow job for this annotation

GitHub Actions / lint

expected '}', found 'EOF' (typecheck)

Check failure on line 39 in pkg/template_generator.go

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, 1.20)

expected '}', found 'EOF'

0 comments on commit 75de741

Please sign in to comment.