func TestLoad_TestFilesInTestPackage(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "foo": { Name: "foo", Files: map[string]*ast.File{ "foo.go": parse(expect, "type Foo interface{}"), }, }, "foo_test": { Name: "foo_test", Files: map[string]*ast.File{ "foo_test.go": parse(expect, "type Bar interface{}"), }, }, } found := types.Load(mockGoDir) expect(found).To.Have.Len(1).Else.FailNow() expect(found[0].Len()).To.Equal(1) expect(found[0].Package()).To.Equal("foo") expect(found[0].TestPackage()).To.Equal("foo_test") }
// TestAnonymousError is testing the only case (as of go 1.7) where // a builtin is an interface type. func TestAnonymousError(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "foo": { Name: "foo", Files: map[string]*ast.File{ "foo.go": parse(expect, ` type Foo interface{ error }`), }, }, } found := types.Load(mockGoDir) expect(found).To.Have.Len(1).Else.FailNow() typs := found[0].ExportedTypes() expect(typs).To.Have.Len(1).Else.FailNow() spec := typs[0] expect(spec).Not.To.Be.Nil().Else.FailNow() inter := spec.Type.(*ast.InterfaceType) expect(inter.Methods.List).To.Have.Len(1).Else.FailNow() err := inter.Methods.List[0] expect(err.Names[0].String()).To.Equal("Error") _, isFunc := err.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok() }
func TestAliasedImportedDependencies(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "bar": { Name: "bar", Files: map[string]*ast.File{ "foo.go": parse(expect, ` import baz "some/path/to/foo" type Bar interface{ Bar(baz.Foo) baz.Bar }`), }, }, } close(mockGoDir.ImportOutput.Err) pkgName := "foo" pkg := &ast.Package{ Name: pkgName, Files: map[string]*ast.File{ "foo.go": parse(expect, ` type Foo interface { Foo() } type Bar interface { Bar() }`), }, } mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName found := types.Load(mockGoDir) expect(mockGoDir.ImportCalled).To.Have.Len(2) expect(<-mockGoDir.ImportInput.Path).To.Equal("some/path/to/foo") expect(found).To.Have.Len(1).Else.FailNow() mockables := found[0].ExportedTypes() expect(mockables).To.Have.Len(1) dependencies := found[0].Dependencies(mockables[0].Type.(*ast.InterfaceType)) expect(dependencies).To.Have.Len(2) names := make(map[string]bool) for _, dependent := range dependencies { expect(dependent.PkgName).To.Equal("baz") expect(dependent.PkgPath).To.Equal("some/path/to/foo") names[dependent.Type.Name.String()] = true } expect(names).To.Equal(map[string]bool{"Foo": true, "Bar": true}) }
func TestFilter(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "foo": { Name: "foo", Files: map[string]*ast.File{ "foo.go": parse(expect, ` type Foo interface {} type Bar interface {} type FooBar interface {} type BarFoo interface {} `), }, }, } found := types.Load(mockGoDir) expect(found).To.Have.Len(1).Else.FailNow() expect(found[0].Len()).To.Equal(4) notFiltered := found.Filter() expect(notFiltered).To.Have.Len(1).Else.FailNow() expect(notFiltered[0].Len()).To.Equal(4) foos := found.Filter("Foo") expect(foos).To.Have.Len(1).Else.FailNow() expect(foos[0].Len()).To.Equal(1) expect(foos[0].ExportedTypes()[0].Name.String()).To.Equal("Foo") fooPrefixes := found.Filter("Foo.*") expect(fooPrefixes).To.Have.Len(1).Else.FailNow() expect(fooPrefixes[0].Len()).To.Equal(2) expectNamesToMatch(expect, fooPrefixes[0].ExportedTypes(), "Foo", "FooBar") fooPostfixes := found.Filter(".*Foo") expect(fooPostfixes).To.Have.Len(1).Else.FailNow() expect(fooPostfixes[0].Len()).To.Equal(2) expectNamesToMatch(expect, fooPostfixes[0].ExportedTypes(), "Foo", "BarFoo") fooContainers := found.Filter("Foo.*", ".*Foo") expect(fooContainers).To.Have.Len(1).Else.FailNow() expect(fooContainers[0].Len()).To.Equal(3) expectNamesToMatch(expect, fooContainers[0].ExportedTypes(), "Foo", "FooBar", "BarFoo") }
func TestLocalDependencies(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "bar": { Name: "bar", Files: map[string]*ast.File{ "bar.go": parse(expect, ` type Bar interface{ Bar(Foo) Foo }`), "foo.go": parse(expect, ` type Foo interface { Foo() }`), }, }, } found := types.Load(mockGoDir) expect(found).To.Have.Len(1).Else.FailNow() mockables := found[0].ExportedTypes() expect(mockables).To.Have.Len(2) var foo, bar *ast.TypeSpec for _, mockable := range mockables { switch mockable.Name.String() { case "Bar": bar = mockable case "Foo": foo = mockable } } expect(bar).Not.To.Be.Nil().Else.FailNow() dependencies := found[0].Dependencies(bar.Type.(*ast.InterfaceType)) expect(dependencies).To.Have.Len(1).Else.FailNow() expect(dependencies[0].Type).To.Equal(foo) expect(dependencies[0].PkgName).To.Equal("") expect(dependencies[0].PkgPath).To.Equal("") }
func TestAnonymousLocalTypes(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.ret0 <- "/some/path" mockGoDir.PackagesOutput.ret0 <- map[string]*ast.Package{ "foo": { Name: "foo", Files: map[string]*ast.File{ "bar.go": parse(expect, ` type Bar interface{ Foo Bar() }`), "foo.go": parse(expect, ` type Foo interface{ Foo() }`), }, }, } found := types.Load(mockGoDir) expect(found).To.Have.Len(1) typs := found[0].ExportedTypes() expect(typs).To.Have.Len(2) spec := find(expect, typs, "Bar") expect(spec).Not.To.Be.Nil() inter := spec.Type.(*ast.InterfaceType) expect(inter.Methods.List).To.Have.Len(2) foo := inter.Methods.List[0] expect(foo.Names[0].String()).To.Equal("Foo") _, isFunc := foo.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok() }
func init() { output, err := exec.Command("which", "goimports").Output() if err != nil { fmt.Println("Could not locate goimports: ", err.Error()) fmt.Println("If goimports is not installed, please install it somewhere in your path. " + "See https://godoc.org/golang.org/x/tools/cmd/goimports.") os.Exit(1) } goimportsPath = strings.TrimSpace(string(output)) cmd = &cobra.Command{ Use: "hel", Short: "A mock generator for Go", Long: "A simple mock generator. The origin of the name is the Norse goddess, Hel, " + "who guards over the souls of those unworthy to enter Valhalla. You can probably " + "guess how much I like mocks.", Run: func(cmd *cobra.Command, args []string) { if len(args) > 0 { fmt.Println("Invalid usage.\n") err := cmd.Help() if err != nil { panic(err) } os.Exit(1) } packagePatterns, err := cmd.Flags().GetStringSlice("package") if err != nil { panic(err) } typePatterns, err := cmd.Flags().GetStringSlice("type") if err != nil { panic(err) } outputName, err := cmd.Flags().GetString("output") if err != nil { panic(err) } chanSize, err := cmd.Flags().GetInt("chan-size") if err != nil { panic(err) } blockingReturn, err := cmd.Flags().GetBool("blocking-return") if err != nil { panic(err) } fmt.Printf("Loading directories matching pattern"+pluralize(packagePatterns, "", "s")+" %v", packagePatterns) var dirList []packages.Dir progress(func() { dirList = packages.Load(packagePatterns...) }) fmt.Print("\n") fmt.Println("Found directories:") for _, dir := range dirList { fmt.Println(" " + dir.Path()) } fmt.Print("\n") fmt.Printf("Loading interface types in matching directories") var typeDirs types.Dirs progress(func() { godirs := make([]types.GoDir, 0, len(dirList)) for _, dir := range dirList { godirs = append(godirs, dir) } typeDirs = types.Load(godirs...).Filter(typePatterns...) }) fmt.Print("\n\n") fmt.Printf("Generating mocks in output file %s", outputName) progress(func() { for _, typeDir := range typeDirs { mockPath, err := makeMocks(typeDir, outputName, chanSize, blockingReturn) if err != nil { panic(err) } if mockPath != "" { if err = exec.Command(goimportsPath, "-w", mockPath).Run(); err != nil { panic(err) } } } }) fmt.Print("\n") }, } cmd.Flags().StringSliceP("package", "p", []string{"."}, "The package(s) to generate mocks for.") cmd.Flags().StringSliceP("type", "t", []string{}, "The type(s) to generate mocks for. If no types "+ "are passed in, all exported interface types will be generated.") cmd.Flags().StringP("output", "o", "helheim_test.go", "The file to write generated mocks to. Since hel does "+ "not generate exported types, this file will be saved directly in all packages with generated mocks. "+ "Also note that, since the types are not exported, you will want the file to end in '_test.go'.") cmd.Flags().IntP("chan-size", "s", 100, "The size of channels used for method calls.") cmd.Flags().BoolP("blocking-return", "b", false, "Always block when returning from mock even if there is no return value.") }
func TestAnonymousImportedTypes_Recursion(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "bar": { Name: "bar", Files: map[string]*ast.File{ "foo.go": parse(expect, ` import "some/path/to/foo" type Bar interface{ foo.Foo Bar() }`), }, }, } close(mockGoDir.ImportOutput.Err) pkgName := "foo" pkg := &ast.Package{ Name: pkgName, Files: map[string]*ast.File{ "foo.go": parse(expect, ` type Foo interface { Foo(func(X) Y) func(Y) X }`), }, } mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName found := types.Load(mockGoDir) // One call for the initial import, four more for dependency checking expect(mockGoDir.ImportCalled).To.Have.Len(5) expect(<-mockGoDir.ImportInput.Path).To.Equal("some/path/to/foo") expect(found).To.Have.Len(1).Else.FailNow() typs := found[0].ExportedTypes() expect(typs).To.Have.Len(1).Else.FailNow() spec := typs[0] expect(spec).Not.To.Be.Nil().Else.FailNow() inter := spec.Type.(*ast.InterfaceType) expect(inter.Methods.List).To.Have.Len(2).Else.FailNow() foo := inter.Methods.List[0] expect(foo.Names[0].String()).To.Equal("Foo") f, isFunc := foo.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok().Else.FailNow() expect(f.Params.List).To.Have.Len(1).Else.FailNow() expect(f.Results.List).To.Have.Len(1).Else.FailNow() input := f.Params.List[0] in, isFunc := input.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok().Else.FailNow() expr, isSelector := in.Params.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok().Else.FailNow() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("X") expr, isSelector = in.Results.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok().Else.FailNow() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("Y") output := f.Params.List[0] out, isFunc := output.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok().Else.FailNow() expr, isSelector = out.Params.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok().Else.FailNow() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("X") expr, isSelector = out.Results.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok().Else.FailNow() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("Y") }
func TestAnonymousAliasedImportedTypes(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.Path <- "/some/path" mockGoDir.PackagesOutput.Packages <- map[string]*ast.Package{ "bar": { Name: "bar", Files: map[string]*ast.File{ "foo.go": parse(expect, ` import baz "some/path/to/foo" type Bar interface{ baz.Foo Bar() }`), }, }, } close(mockGoDir.ImportOutput.Err) pkgName := "foo" pkg := &ast.Package{ Name: pkgName, Files: map[string]*ast.File{ "foo.go": parse(expect, ` type Foo interface { Foo(x X) Y } type X int type Y int`), }, } mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName mockGoDir.ImportOutput.Pkg <- pkg mockGoDir.ImportOutput.Name <- pkgName found := types.Load(mockGoDir) // 3 calls: 1 for the initial import, then deps imports for X and Y expect(mockGoDir.ImportCalled).To.Have.Len(3) expect(<-mockGoDir.ImportInput.Path).To.Equal("some/path/to/foo") expect(found).To.Have.Len(1).Else.FailNow() typs := found[0].ExportedTypes() expect(typs).To.Have.Len(1).Else.FailNow() spec := typs[0] expect(spec).Not.To.Be.Nil().Else.FailNow() inter := spec.Type.(*ast.InterfaceType) expect(inter.Methods.List).To.Have.Len(2).Else.FailNow() foo := inter.Methods.List[0] expect(foo.Names[0].String()).To.Equal("Foo") f, isFunc := foo.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok().Else.FailNow() expect(f.Params.List).To.Have.Len(1).Else.FailNow() expect(f.Results.List).To.Have.Len(1).Else.FailNow() expr, isSelector := f.Params.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok().Else.FailNow() expect(expr.X.(*ast.Ident).String()).To.Equal("baz") expect(expr.Sel.String()).To.Equal("X") expr, isSelector = f.Results.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok().Else.FailNow() expect(expr.X.(*ast.Ident).String()).To.Equal("baz") expect(expr.Sel.String()).To.Equal("Y") }
func TestAnonymousImportedTypes_Recursion(t *testing.T) { expect := expect.New(t) mockGoDir := newMockGoDir() mockGoDir.PathOutput.ret0 <- "/some/path" mockGoDir.PackagesOutput.ret0 <- map[string]*ast.Package{ "bar": { Name: "bar", Files: map[string]*ast.File{ "foo.go": parse(expect, ` import "some/path/to/foo" type Bar interface{ foo.Foo Bar() }`), }, }, } close(mockGoDir.ImportOutput.ret1) mockGoDir.ImportOutput.ret0 <- &ast.Package{ Name: "foo", Files: map[string]*ast.File{ "foo.go": parse(expect, ` type Foo interface { Foo(func(X) Y) func(Y) X }`), }, } found := types.Load(mockGoDir) expect(mockGoDir.ImportCalled).To.Have.Len(1) expect(<-mockGoDir.ImportInput.path).To.Equal("some/path/to/foo") expect(<-mockGoDir.ImportInput.pkg).To.Equal("foo") expect(found).To.Have.Len(1) typs := found[0].ExportedTypes() expect(typs).To.Have.Len(1) spec := typs[0] expect(spec).Not.To.Be.Nil() inter := spec.Type.(*ast.InterfaceType) expect(inter.Methods.List).To.Have.Len(2) foo := inter.Methods.List[0] expect(foo.Names[0].String()).To.Equal("Foo") f, isFunc := foo.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok() expect(f.Params.List).To.Have.Len(1) expect(f.Results.List).To.Have.Len(1) input := f.Params.List[0] in, isFunc := input.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok() expr, isSelector := in.Params.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("X") expr, isSelector = in.Results.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("Y") output := f.Params.List[0] out, isFunc := output.Type.(*ast.FuncType) expect(isFunc).To.Be.Ok() expr, isSelector = out.Params.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("X") expr, isSelector = out.Results.List[0].Type.(*ast.SelectorExpr) expect(isSelector).To.Be.Ok() expect(expr.X.(*ast.Ident).String()).To.Equal("foo") expect(expr.Sel.String()).To.Equal("Y") }