Skip to content

Commit

Permalink
Merge branch 'jf-new-generate-directive'
Browse files Browse the repository at this point in the history
  • Loading branch information
joefitzgerald committed Jun 3, 2019
2 parents db49161 + 23a2d5c commit 2529dc3
Show file tree
Hide file tree
Showing 26 changed files with 187 additions and 47 deletions.
41 changes: 38 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import (
// during the development process but not otherwise depended on by built code.
```

#### Step 2 - Add `go:generate` Directives
#### Step 2a - Add `go:generate` Directives

You can add directives right next to your interface definitions (or not), in any `.go` file in your module.

Expand All @@ -64,6 +64,41 @@ $ go generate ./...
Writing `FakeMySpecialInterface` to `foofakes/fake_my_special_interface.go`... Done
```

#### Step 2b - Add `counterfeiter:generate` Directives

If you plan to have many directives in a single package, consider using this
option. You can add directives right next to your interface definitions
(or not), in any `.go` file in your module.

```shell
$ cat myinterface.go
```

```go
package foo

// You only need **one** of these per package!
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate

// You will add lots of directives like these in the same package...
//counterfeiter:generate . MySpecialInterface
type MySpecialInterface interface {
DoThings(string, uint64) (int, error)
}

// Like this...
//counterfeiter:generate . MyOtherInterface
type MyOtherInterface interface {
DoOtherThings(string, uint64) (int, error)
}
```

```shell
$ go generate ./...
Writing `FakeMySpecialInterface` to `foofakes/fake_my_special_interface.go`... Done
Writing `FakeMyOtherInterface` to `foofakes/fake_my_other_interface.go`... Done
```

#### Step 3 - Run `go generate`

You can run `go generate` in the directory with your directive, or in the root of your module (to ensure you generate for all packages in your module):
Expand Down Expand Up @@ -98,7 +133,7 @@ go run github.com/maxbrunsfeld/counterfeiter/v6

USAGE
counterfeiter
[-o <output-path>] [-p] [--fake-name <fake-name>]
[-generate] [-o <output-path>] [-p] [--fake-name <fake-name>]
[<source-path>] <interface> [-]
```

Expand All @@ -112,7 +147,7 @@ $ counterfeiter

USAGE
counterfeiter
[-o <output-path>] [-p] [--fake-name <fake-name>]
[-generate] [-o <output-path>] [-p] [--fake-name <fake-name>]
[<source-path>] <interface> [-]
```

Expand Down
27 changes: 26 additions & 1 deletion arguments/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package arguments
const usage = `
USAGE
counterfeiter
[-o <output-path>] [-p] [--fake-name <fake-name>]
[-generate>] [-o <output-path>] [-p] [--fake-name <fake-name>]
[<source-path>] <interface> [-]
ARGUMENTS
Expand All @@ -26,6 +26,31 @@ ARGUMENTS
Write code to standard out instead of to a file
OPTIONS
-generate
Identify all //counterfeiter:generate directives in .go file in the
current working directory and generate fakes for them. You can pass
arguments as usual.
NOTE: This is not the same as //go:generate directives
(used with the 'go generate' command), but it can be combined with
go generate by adding the following to a .go file:
# runs counterfeiter in generate mode
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
example:
Add the following to a .go file:
//counterfeiter:generate . MyInterface
//counterfeiter:generate . MyOtherInterface
//counterfeiter:generate . MyThirdInterface
# run counterfeiter
counterfeiter -generate
# writes "FakeMyInterface" to ./mypackagefakes/fake_my_interface.go
# writes "FakeMyOtherInterface" to ./mypackagefakes/fake_my_other_interface.go
# writes "FakeMyThirdInterface" to ./mypackagefakes/fake_my_third_interface.go
-o
Path to the file or directory for the generated fakes.
This also determines the package name that will be used.
Expand Down
28 changes: 27 additions & 1 deletion benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,33 @@ import (
"github.com/maxbrunsfeld/counterfeiter/v6/generator"
)

func BenchmarkSingleRun(b *testing.B) {
func BenchmarkWithoutCache(b *testing.B) {
b.StopTimer()
workingDir, err := filepath.Abs(filepath.Join(".", "fixtures"))
if err != nil {
b.Fatal(err)
}
log.SetOutput(ioutil.Discard)

args := &arguments.ParsedArguments{
GenerateInterfaceAndShimFromPackageDirectory: false,
SourcePackageDir: workingDir,
PackagePath: workingDir,
OutputPath: filepath.Join(workingDir, "fixturesfakes", "fake_something.go"),
DestinationPackageName: "fixturesfakes",
InterfaceName: "Something",
FakeImplName: "FakeSomething",
PrintToStdOut: false,
}

cache := &generator.FakeCache{}
b.StartTimer()
for i := 0; i < b.N; i++ {
doGenerate(workingDir, args, cache)
}
}

func BenchmarkWithCache(b *testing.B) {
b.StopTimer()
workingDir, err := filepath.Abs(filepath.Join(".", "fixtures"))
if err != nil {
Expand Down
44 changes: 30 additions & 14 deletions command/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
"strings"
)

func Detect(cwd string, args []string) ([]Invocation, error) {
if invokedByGoGenerate() {
return invocations(cwd, args)
func Detect(cwd string, args []string, generateMode bool) ([]Invocation, error) {
if generateMode || invokedByGoGenerate() {
return invocations(cwd, generateMode)
}
i, err := NewInvocation("", 0, args)
if err != nil {
Expand Down Expand Up @@ -45,7 +45,7 @@ func invokedByGoGenerate() bool {
return os.Getenv("DOLLAR") == "$"
}

func invocations(cwd string, args []string) ([]Invocation, error) {
func invocations(cwd string, generateMode bool) ([]Invocation, error) {
var result []Invocation
// Find all the go files
pkg, err := build.ImportDir(cwd, build.IgnoreVendor)
Expand All @@ -59,17 +59,24 @@ func invocations(cwd string, args []string) ([]Invocation, error) {
gofiles = append(gofiles, pkg.TestGoFiles...)
gofiles = append(gofiles, pkg.XTestGoFiles...)
sort.Strings(gofiles)
// Find all the generate statements
line, err := strconv.Atoi(os.Getenv("GOLINE"))
if err != nil {
return nil, err
var line int
if !generateMode {
// generateMode means counterfeiter:generate, not go:generate
line, err = strconv.Atoi(os.Getenv("GOLINE"))
if err != nil {
return nil, err
}
}

for i := range gofiles {
i, err := open(cwd, gofiles[i])
i, err := open(cwd, gofiles[i], generateMode)
if err != nil {
return nil, err
}
result = append(result, i...)
if generateMode {
continue
}
if len(result) > 0 && result[0].File != os.Getenv("GOFILE") {
return nil, nil
}
Expand All @@ -81,9 +88,9 @@ func invocations(cwd string, args []string) ([]Invocation, error) {
return result, nil
}

var re = regexp.MustCompile(`(?mi)^//go:generate (?:go run github\.com/maxbrunsfeld/counterfeiter/v6|gobin -m -run github\.com/maxbrunsfeld/counterfeiter/v6|counterfeiter|counterfeiter.exe)\s+(.*)?\s*$`)
var re = regexp.MustCompile(`(?mi)^//(go:generate|counterfeiter:generate)\s*(?:go run github\.com/maxbrunsfeld/counterfeiter/v6|gobin -m -run github\.com/maxbrunsfeld/counterfeiter/v6|counterfeiter|counterfeiter.exe)?\s*(.*)?\s*$`)

func open(dir string, file string) ([]Invocation, error) {
func open(dir string, file string, generateMode bool) ([]Invocation, error) {
str, err := ioutil.ReadFile(filepath.Join(dir, file))
if err != nil {
return nil, err
Expand All @@ -98,12 +105,21 @@ func open(dir string, file string) ([]Invocation, error) {
if match == nil {
continue
}

inv, err := NewInvocation(file, line, stringToArgs(match[1]))
inv, err := NewInvocation(file, line, stringToArgs(match[2]))
if err != nil {
return nil, err
}
result = append(result, inv)

if generateMode && match[1] == "counterfeiter:generate" {
result = append(result, inv)
}

if !generateMode && match[1] == "go:generate" {
if len(inv.Args) == 2 && strings.EqualFold(strings.TrimSpace(inv.Args[1]), "-generate") {
continue
}
result = append(result, inv)
}
}

return result, nil
Expand Down
34 changes: 28 additions & 6 deletions command/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func testRunner(t *testing.T, when spec.G, it spec.S) {
})

it("creates an invocation", func() {
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"})
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"}, false)
Expect(err).NotTo(HaveOccurred())
Expect(i).NotTo(BeNil())
Expect(i).To(HaveLen(1))
Expand All @@ -49,6 +49,28 @@ func testRunner(t *testing.T, when spec.G, it spec.S) {
})
})

when("counterfeiter is invoked in generate mode", func() {
it.Before(func() {
os.Unsetenv("DOLLAR")
os.Unsetenv("GOFILE")
os.Unsetenv("GOLINE")
os.Unsetenv("GOPACKAGE")
})

it("creates invocations", func() {
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"}, true)
Expect(err).NotTo(HaveOccurred())
Expect(i).NotTo(BeNil())
Expect(len(i)).To(Equal(17))
Expect(i[0].File).To(Equal("aliased_interfaces.go"))
Expect(i[0].Line).To(Equal(7))
Expect(i[0].Args).To(HaveLen(3))
Expect(i[0].Args[0]).To(Equal("counterfeiter"))
Expect(i[0].Args[1]).To(Equal("."))
Expect(i[0].Args[2]).To(Equal("AliasedInterface"))
})
})

when("counterfeiter has been invoked by go generate", func() {
it.Before(func() {
os.Setenv("DOLLAR", "$")
Expand All @@ -57,11 +79,11 @@ func testRunner(t *testing.T, when spec.G, it spec.S) {
os.Setenv("GOPACKAGE", "fixtures")
})

it("creates invocations", func() {
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"})
it("creates invocations but does not include generate mode as an invocation", func() {
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"}, false)
Expect(err).NotTo(HaveOccurred())
Expect(i).NotTo(BeNil())
Expect(len(i)).To(BeNumerically(">", 10))
Expect(len(i)).To(Equal(1))
Expect(i[0].File).To(Equal("aliased_interfaces.go"))
Expect(i[0].Line).To(Equal(5))
Expect(i[0].Args).To(HaveLen(3))
Expand All @@ -76,7 +98,7 @@ func testRunner(t *testing.T, when spec.G, it spec.S) {
})

it("has no invocations", func() {
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "SomeOtherInterface"})
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"}, false)
Expect(err).NotTo(HaveOccurred())
Expect(i).To(HaveLen(0))
})
Expand All @@ -88,7 +110,7 @@ func testRunner(t *testing.T, when spec.G, it spec.S) {
})

it("has no invocations", func() {
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "SomeOtherInterface"})
i, err := command.Detect(filepath.Join(".", "..", "fixtures"), []string{"counterfeiter", ".", "AliasedInterface"}, false)
Expect(err).NotTo(HaveOccurred())
Expect(i).To(HaveLen(0))
})
Expand Down
2 changes: 2 additions & 0 deletions fixtures/aliased_interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package fixtures
import alias "github.com/maxbrunsfeld/counterfeiter/v6/fixtures/another_package"

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . AliasedInterface
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
//counterfeiter:generate . AliasedInterface

// AliasedInterface is an interface that embeds an interface in an aliased package.
type AliasedInterface interface {
Expand Down
2 changes: 1 addition & 1 deletion fixtures/compound_return.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package fixtures

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . SomethingElse
//counterfeiter:generate . SomethingElse
type SomethingElse interface {
ReturnStuff() (a, b int)
}
2 changes: 1 addition & 1 deletion fixtures/dot_imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
. "os"
)

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . DotImports
//counterfeiter:generate . DotImports
type DotImports interface {
DoThings(io.Writer, *File) *http.Client
}
3 changes: 2 additions & 1 deletion fixtures/dup_packages/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"github.com/maxbrunsfeld/counterfeiter/v6/fixtures/dup_packages/b/foo"
)

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . AliasV1
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
//counterfeiter:generate . AliasV1
type AliasV1 interface {
a.A
afoo.I
Expand Down
2 changes: 1 addition & 1 deletion fixtures/dup_packages/dupA.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dup_packages // import "github.com/maxbrunsfeld/counterfeiter/v6/fixture

import "github.com/maxbrunsfeld/counterfeiter/v6/fixtures/dup_packages/a/foo"

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . DupA
//counterfeiter:generate . DupA
type DupA interface {
A() foo.S
}
2 changes: 1 addition & 1 deletion fixtures/dup_packages/dupAB.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dup_packages // import "github.com/maxbrunsfeld/counterfeiter/v6/fixtures/dup_packages"

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . DupAB
//counterfeiter:generate . DupAB
type DupAB interface {
DupA
DupB
Expand Down
2 changes: 1 addition & 1 deletion fixtures/dup_packages/dupB.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dup_packages // import "github.com/maxbrunsfeld/counterfeiter/v6/fixture

import "github.com/maxbrunsfeld/counterfeiter/v6/fixtures/dup_packages/b/foo"

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . DupB
//counterfeiter:generate . DupB
type DupB interface {
B() foo.S
}
2 changes: 1 addition & 1 deletion fixtures/dup_packages/dup_packagenames.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
bfoo "github.com/maxbrunsfeld/counterfeiter/v6/fixtures/dup_packages/b/foo"
)

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . AB
//counterfeiter:generate . AB
type AB interface {
A() foo.S
foo.I
Expand Down
2 changes: 2 additions & 0 deletions fixtures/dup_packages/go.mod
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
module github.com/maxbrunsfeld/counterfeiter/v6/fixtures/dup_packages

go 1.12
2 changes: 1 addition & 1 deletion fixtures/embeds_interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/maxbrunsfeld/counterfeiter/v6/fixtures/another_package"
)

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . EmbedsInterfaces
//counterfeiter:generate . EmbedsInterfaces
type EmbedsInterfaces interface {
http.Handler
another_package.AnotherInterface
Expand Down
2 changes: 1 addition & 1 deletion fixtures/has_imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
some_alias "os"
)

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . HasImports
//counterfeiter:generate . HasImports
type HasImports interface {
DoThings(io.Writer, *some_alias.File) *http.Client
}
Loading

0 comments on commit 2529dc3

Please sign in to comment.