Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add build tag support #145

Merged
merged 3 commits into from
May 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions mockery/fixtures/buildtag/comment/darwin_iface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// +build darwin

package comment

type IfaceWithBuildTagInComment interface {
Sprintf(format string, a ...interface{}) string
}
7 changes: 7 additions & 0 deletions mockery/fixtures/buildtag/comment/freebsd_iface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// +build freebsd

package comment

type IfaceWithBuildTagInComment interface {
Sprintf(format string, a ...interface{}) string
}
7 changes: 7 additions & 0 deletions mockery/fixtures/buildtag/comment/linux_iface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// +build linux

package comment

type IfaceWithBuildTagInComment interface {
Sprintf(format string, a ...interface{}) string
}
7 changes: 7 additions & 0 deletions mockery/fixtures/buildtag/comment/windows_iface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// +build windows

package comment

type IfaceWithBuildTagInComment interface {
Sprintf(format string, a ...interface{}) string
}
5 changes: 5 additions & 0 deletions mockery/fixtures/buildtag/filename/iface_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package filename

type IfaceWithBuildTagInFilename interface {
Sprintf(format string, a ...interface{}) string
}
5 changes: 5 additions & 0 deletions mockery/fixtures/buildtag/filename/iface_freebsd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package filename

type IfaceWithBuildTagInFilename interface {
Sprintf(format string, a ...interface{}) string
}
5 changes: 5 additions & 0 deletions mockery/fixtures/buildtag/filename/iface_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package filename

type IfaceWithBuildTagInFilename interface {
Sprintf(format string, a ...interface{}) string
}
5 changes: 5 additions & 0 deletions mockery/fixtures/buildtag/filename/iface_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package filename

type IfaceWithBuildTagInFilename interface {
Sprintf(format string, a ...interface{}) string
}
24 changes: 24 additions & 0 deletions mockery/mockery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package mockery
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about doing this the other day 👍


import (
"os"
"path/filepath"
)

var fixturePath string

func init() {
dir, err := os.Getwd()
if err != nil {
panic(err)
}
fixturePath = filepath.Join(dir, "fixtures")
}

// getFixturePath returns an absolute path to a fixture sub-directory or file.
//
// getFixturePath("src.go") returns "/path/to/fixtures/src.go"
// getFixturePath("a", "b", "c", "src.go") returns "/path/to/fixtures/a/b/c/src.go"
func getFixturePath(subdirOrBasename ...string) string {
return filepath.Join(append([]string{fixturePath}, subdirOrBasename...)...)
}
34 changes: 29 additions & 5 deletions mockery/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ package mockery

import (
"go/ast"
"go/build"
"go/importer"
"go/types"
"io/ioutil"
"path/filepath"
"strings"

"golang.org/x/tools/go/loader"
"sort"
"sync"

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

type Parser struct {
Expand All @@ -27,6 +29,12 @@ func NewParser() *Parser {
conf.TypeCheckFuncBodies = func(_ string) bool { return false }
conf.TypeChecker.DisableUnusedImportCheck = true
conf.TypeChecker.Importer = importer.Default()

// Initialize the build context (e.g. GOARCH/GOOS fields) so we can use it for respecting
// build tags during Parse.
defaultBuildCtx := build.Default
conf.Build = &defaultBuildCtx

return &Parser{
parserPackages: make([]*types.Package, 0),
configMapping: make(map[string][]*ast.File),
Expand All @@ -37,6 +45,7 @@ func NewParser() *Parser {
}

func (p *Parser) Parse(path string) error {

// To support relative paths to mock targets w/ vendor deps, we need to provide eventual
// calls to build.Context.Import with an absolute path. It needs to be absolute because
// Import will only find the vendor directory if our target path for parsing is under
Expand All @@ -61,10 +70,25 @@ func (p *Parser) Parse(path string) error {
continue
}

fpath := filepath.Join(dir, fi.Name())
f, err := p.conf.ParseFile(fpath, nil)
if err != nil {
return err
fname := fi.Name()
fpath := filepath.Join(dir, fname)

// If go/build would ignore this file, e.g. based on build tags, also ignore it here.
//
// (Further coupling with go internals and x/tools may of course bear a cost eventually
// e.g. https://github.com/vektra/mockery/pull/117#issue-199337071, but should add
// worthwhile consistency in this tool's behavior in the meantime.)
match, matchErr := p.conf.Build.MatchFile(dir, fname)
if matchErr != nil {
return matchErr
}
if !match {
continue
}

f, parseErr := p.conf.ParseFile(fpath, nil)
if parseErr != nil {
return parseErr
}

p.configMapping[path] = append(p.configMapping[path], f)
Expand Down
58 changes: 46 additions & 12 deletions mockery/parse_test.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
package mockery

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

var fixturePath string
var testFile string
var testFile2 string

func init() {
dir, err := os.Getwd()
if err != nil {
panic(err)
}

fixturePath = filepath.Join(dir, "fixtures")

testFile = filepath.Join(dir, "fixtures", "requester.go")
testFile2 = filepath.Join(dir, "fixtures", "requester2.go")
testFile = getFixturePath("requester.go")
testFile2 = getFixturePath("requester2.go")
}

func TestFileParse(t *testing.T) {
Expand Down Expand Up @@ -51,3 +41,47 @@ func noTestFileInterfaces(t *testing.T) {
assert.Equal(t, 1, len(nodes))
assert.Equal(t, "Requester", nodes[0].Name)
}

func TestBuildTagInFilename(t *testing.T) {
parser := NewParser()

// Include the major OS values found on https://golang.org/dl/ so we're likely to match
// anywhere the test is executed.
err := parser.Parse(getFixturePath("buildtag", "filename", "iface_windows.go"))
assert.NoError(t, err)
err = parser.Parse(getFixturePath("buildtag", "filename", "iface_linux.go"))
assert.NoError(t, err)
err = parser.Parse(getFixturePath("buildtag", "filename", "iface_darwin.go"))
assert.NoError(t, err)
err = parser.Parse(getFixturePath("buildtag", "filename", "iface_freebsd.go"))
assert.NoError(t, err)

err = parser.Load()
assert.NoError(t, err) // Expect "redeclared in this block" if tags aren't respected

nodes := parser.Interfaces()
assert.Equal(t, 1, len(nodes))
assert.Equal(t, "IfaceWithBuildTagInFilename", nodes[0].Name)
}

func TestBuildTagInComment(t *testing.T) {
parser := NewParser()

// Include the major OS values found on https://golang.org/dl/ so we're likely to match
// anywhere the test is executed.
err := parser.Parse(getFixturePath("buildtag", "comment", "windows_iface.go"))
assert.NoError(t, err)
err = parser.Parse(getFixturePath("buildtag", "comment", "linux_iface.go"))
assert.NoError(t, err)
err = parser.Parse(getFixturePath("buildtag", "comment", "darwin_iface.go"))
assert.NoError(t, err)
err = parser.Parse(getFixturePath("buildtag", "comment", "freebsd_iface.go"))
assert.NoError(t, err)

err = parser.Load()
assert.NoError(t, err) // Expect "redeclared in this block" if tags aren't respected

nodes := parser.Interfaces()
assert.Equal(t, 1, len(nodes))
assert.Equal(t, "IfaceWithBuildTagInComment", nodes[0].Name)
}
5 changes: 2 additions & 3 deletions mockery/walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package mockery

import (
"os"
"path/filepath"
"regexp"
"testing"

Expand Down Expand Up @@ -45,7 +44,7 @@ func TestWalkerHere(t *testing.T) {
assert.True(t, len(gv.Interfaces) > 10)
first := gv.Interfaces[0]
assert.Equal(t, "AsyncProducer", first.Name)
assert.Equal(t, filepath.Join(wd, "fixtures", "async.go"), first.Path)
assert.Equal(t, getFixturePath("async.go"), first.Path)
}

func TestWalkerRegexp(t *testing.T) {
Expand All @@ -69,5 +68,5 @@ func TestWalkerRegexp(t *testing.T) {
assert.True(t, len(gv.Interfaces) >= 1)
first := gv.Interfaces[0]
assert.Equal(t, "AsyncProducer", first.Name)
assert.Equal(t, filepath.Join(wd, "fixtures", "async.go"), first.Path)
assert.Equal(t, getFixturePath("async.go"), first.Path)
}