Skip to content

Commit

Permalink
Add more code to plumb through all the values needed by moq registry …
Browse files Browse the repository at this point in the history
…methods

In this commit, we gather all the template data needed by the moq logic to
generate its template. This is untested as of yet.

TODO: need to start testing this works by calling upon `moq` in `.mockery.yaml`.
  • Loading branch information
LandonTClipp committed Nov 20, 2023
1 parent 313d656 commit f03c906
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 46 deletions.
3 changes: 3 additions & 0 deletions pkg/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package pkg
import (
"go/ast"
"go/types"

"golang.org/x/tools/go/packages"
)

// Interface type represents the target type that we will generate a mock for.
Expand All @@ -14,6 +16,7 @@ type Interface struct {
QualifiedName string // Path to the package of the target type.
FileName string
File *ast.File
PackagesPackage *packages.Package
Pkg TypesPackage
NamedType *types.Named
IsFunction bool // If true, this instance represents a function, otherwise it's an interface.
Expand Down
6 changes: 5 additions & 1 deletion pkg/outputter.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,11 @@ func (o *Outputter) Generate(ctx context.Context, iface *Interface) error {
config := TemplateGeneratorConfig{
Style: interfaceConfig.Style,
}
generator := NewTemplateGenerator(config)
generator, err := NewTemplateGenerator(iface.PackagesPackage, config)
if err != nil {
return fmt.Errorf("creating template generator: %w", err)
}

fmt.Printf("generator: %v\n", generator)

}
Expand Down
22 changes: 10 additions & 12 deletions pkg/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func (p *Parser) Find(name string) (*Interface, error) {
for _, entry := range p.entries {
for _, iface := range entry.interfaces {
if iface == name {
list := p.packageInterfaces(entry.pkg.Types, entry.fileName, []string{name}, nil)
list := p.packageInterfaces(entry, []string{name}, nil)
if len(list) > 0 {
return list[0], nil
}
Expand All @@ -204,19 +204,18 @@ func (p *Parser) Interfaces() []*Interface {
ifaces := make(sortableIFaceList, 0)
for _, entry := range p.entries {
declaredIfaces := entry.interfaces
ifaces = p.packageInterfaces(entry.pkg.Types, entry.fileName, declaredIfaces, ifaces)
ifaces = p.packageInterfaces(entry, declaredIfaces, ifaces)
}

sort.Sort(ifaces)
return ifaces
}

func (p *Parser) packageInterfaces(
pkg *types.Package,
fileName string,
entry *parserEntry,
declaredInterfaces []string,
ifaces []*Interface) []*Interface {
scope := pkg.Scope()
scope := entry.pkg.Types.Scope()
for _, name := range declaredInterfaces {
obj := scope.Lookup(name)
if obj == nil {
Expand All @@ -235,11 +234,12 @@ func (p *Parser) packageInterfaces(
}

elem := &Interface{
Name: name,
Pkg: pkg,
QualifiedName: pkg.Path(),
FileName: fileName,
NamedType: typ,
Name: name,
PackagesPackage: entry.pkg,
Pkg: entry.pkg.Types,
QualifiedName: entry.pkg.Types.Path(),
FileName: entry.fileName,
NamedType: typ,
}

iface, ok := typ.Underlying().(*types.Interface)
Expand All @@ -266,8 +266,6 @@ type TypesPackage interface {
Path() string
}



type sortableIFaceList []*Interface

func (s sortableIFaceList) Len() int {
Expand Down
2 changes: 1 addition & 1 deletion pkg/registry/method_scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ 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)
imports[pkg.Path()] = m.registry.AddImport(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
Expand Down
5 changes: 1 addition & 4 deletions pkg/registry/package.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package registry

import (
"path"
"strings"
)

Expand Down Expand Up @@ -42,7 +41,7 @@ func (p *Package) Path() string {
return ""
}

return stripVendorPath(p.pkg.Path())
return p.pkg.Path()
}

var replacer = strings.NewReplacer(
Expand Down Expand Up @@ -72,8 +71,6 @@ func (p Package) uniqueName(lvl int) string {
return name
}



func min(a, b int) int {
if a < b {
return a
Expand Down
11 changes: 5 additions & 6 deletions pkg/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"sort"
"strings"

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

Expand All @@ -18,19 +17,19 @@ import (
// qualifiers.
type Registry struct {
srcPkgName string
srcPkgPath string
srcPkgTypes *types.Package
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(srcPkg *packages.Package, outputPath *pathlib.Path) (*Registry, error) {
func New(srcPkg *packages.Package) (*Registry, error) {
return &Registry{
srcPkgName: srcPkg.Name,
srcPkgPath: srcPkg.PkgPath,
srcPkgTypes: srcPkg.Types,
outputPath: outputPath,
aliases: parseImportsAliases(srcPkg.Syntax),
imports: make(map[string]*Package),
}, nil
Expand Down Expand Up @@ -79,8 +78,8 @@ func (r *Registry) MethodScope() *MethodScope {
// suitable alias if there are any conflicts with previously imported
// packages.
func (r *Registry) AddImport(pkg *types.Package) *Package {
path := stripVendorPath(pkg.Path())
if pathlib.NewPath(path).Equals(r.outputPath) {
path := pkg.Path()
if pkg.Path() == r.srcPkgPath {
return nil
}

Expand Down
10 changes: 0 additions & 10 deletions pkg/registry/registry_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1 @@
package registry

import (
"testing"
)

func BenchmarkNew(b *testing.B) {
for i := 0; i < b.N; i++ {
New("../../pkg/moq/testpackages/example", "")
}
}
2 changes: 1 addition & 1 deletion pkg/registry/var.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (v Var) TypeString() string {

// packageQualifier is a types.Qualifier.
func (v Var) packageQualifier(pkg *types.Package) string {
path := stripVendorPath(pkg.Path())
path := pkg.Path()
if v.moqPkgPath != "" && v.moqPkgPath == path {
return ""
}
Expand Down
93 changes: 82 additions & 11 deletions pkg/template_generator.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,110 @@
package pkg

import (
"bytes"
"context"
"fmt"
"go/types"

"github.com/chigopher/pathlib"
"github.com/rs/zerolog"
"github.com/vektra/mockery/v2/pkg/config"
"github.com/vektra/mockery/v2/pkg/registry"
"github.com/vektra/mockery/v2/pkg/template"
"golang.org/x/tools/go/packages"
)

type TemplateGeneratorConfig struct {
Style string
}
type TemplateGenerator struct {
config TemplateGeneratorConfig
config TemplateGeneratorConfig
registry *registry.Registry
}

func NewTemplateGenerator(config TemplateGeneratorConfig) *TemplateGenerator {
return &TemplateGenerator{
config: config,
func NewTemplateGenerator(srcPkg *packages.Package, config TemplateGeneratorConfig) (*TemplateGenerator, error) {
reg, err := registry.New(srcPkg)
if err != nil {
return nil, fmt.Errorf("creating new registry: %w", err)
}

return &TemplateGenerator{
config: config,
registry: reg,
}, nil
}

func (g *TemplateGenerator) Generate(iface *Interface, ifaceConfig *config.Config) error {
templ, err := template.New(g.config.Style)
if err != nil {
return err
}
func (g *TemplateGenerator) Generate(ctx context.Context, iface *Interface, ifaceConfig *config.Config) error {
log := zerolog.Ctx(ctx)
log.Info().Msg("generating mock for interface")

imports := Imports{}
for _, method := range iface.Methods() {
method.populateImports(imports)
}
// TODO: Work on getting these imports into the template
methods := make([]template.MethodData, iface.ActualInterface.NumMethods())

for i := 0; i < iface.ActualInterface.NumMethods(); i++ {
method := iface.ActualInterface.Method(i)
methodScope := g.registry.MethodScope()

signature := method.Type().(*types.Signature)
params := make([]template.ParamData, signature.Params().Len())
for j := 0; j < signature.Params().Len(); j++ {
param := signature.Params().At(j)
params[j] = template.ParamData{
Var: methodScope.AddVar(param, ""),
Variadic: signature.Variadic() && j == signature.Params().Len()-1,
}
}

returns := make([]template.ParamData, signature.Results().Len())
for j := 0; j < signature.Results().Len(); j++ {
param := signature.Results().At(j)
returns[j] = template.ParamData{
Var: methodScope.AddVar(param, "Out"),
Variadic: false,
}
}

methods[i] = template.MethodData{
Name: method.Name(),
Params: params,
Returns: returns,
}

}

// For now, mockery only supports one mock per file, which is why we're creating
// a single-element list. moq seems to have supported multiple mocks per file.
mockData := []template.MockData{
{
InterfaceName: iface.Name,
MockName: ifaceConfig.MockName,
Methods: methods,
},
}
data := template.Data{
PkgName: ifaceConfig.Outpkg,
SrcPkgQualifier: iface.Pkg.Name() + ".",
Imports:
Imports: g.registry.Imports(),
Mocks: mockData,
}

templ, err := template.New(g.config.Style)
if err != nil {
return fmt.Errorf("creating new template: %w", err)
}

var buf bytes.Buffer
if err := templ.Execute(&buf, data); err != nil {
return fmt.Errorf("executing template: %w", err)
}

outPath := pathlib.NewPath(ifaceConfig.Dir).Join(ifaceConfig.FileName)
if err := outPath.WriteFile(buf.Bytes()); err != nil {
log.Error().Err(err).Msg("couldn't write to output file")
return fmt.Errorf("writing to output file: %w", err)
}
return nil
}

0 comments on commit f03c906

Please sign in to comment.