cleanup and fix locating for godog dependency
Этот коммит содержится в:
родитель
d0f68b3fe1
коммит
2772b1df34
4 изменённых файлов: 43 добавлений и 316 удалений
108
ast.go
108
ast.go
|
@ -1,12 +1,6 @@
|
||||||
package godog
|
package godog
|
||||||
|
|
||||||
import (
|
import "go/ast"
|
||||||
"go/ast"
|
|
||||||
"go/build"
|
|
||||||
"go/token"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func astContexts(f *ast.File) []string {
|
func astContexts(f *ast.File) []string {
|
||||||
var contexts []string
|
var contexts []string
|
||||||
|
@ -35,103 +29,3 @@ func astContexts(f *ast.File) []string {
|
||||||
}
|
}
|
||||||
return contexts
|
return contexts
|
||||||
}
|
}
|
||||||
|
|
||||||
func astRemoveUnusedImports(f *ast.File) {
|
|
||||||
used := astUsedPackages(f)
|
|
||||||
isUsed := func(p string) bool {
|
|
||||||
for _, ref := range used {
|
|
||||||
if p == ref {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p == "_"
|
|
||||||
}
|
|
||||||
var decls []ast.Decl
|
|
||||||
for _, d := range f.Decls {
|
|
||||||
gen, ok := d.(*ast.GenDecl)
|
|
||||||
if ok && gen.Tok == token.IMPORT {
|
|
||||||
var specs []ast.Spec
|
|
||||||
for _, spec := range gen.Specs {
|
|
||||||
impspec := spec.(*ast.ImportSpec)
|
|
||||||
ipath := strings.Trim(impspec.Path.Value, `\"`)
|
|
||||||
check := astImportPathToName(ipath)
|
|
||||||
if impspec.Name != nil {
|
|
||||||
check = impspec.Name.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
if isUsed(check) {
|
|
||||||
specs = append(specs, spec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(specs) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
gen.Specs = specs
|
|
||||||
}
|
|
||||||
decls = append(decls, d)
|
|
||||||
}
|
|
||||||
f.Decls = decls
|
|
||||||
}
|
|
||||||
|
|
||||||
func astDeleteTestMainFunc(f *ast.File) {
|
|
||||||
var decls []ast.Decl
|
|
||||||
var hadTestMain bool
|
|
||||||
for _, d := range f.Decls {
|
|
||||||
fun, ok := d.(*ast.FuncDecl)
|
|
||||||
if !ok {
|
|
||||||
decls = append(decls, d)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if fun.Name.Name != "TestMain" {
|
|
||||||
decls = append(decls, fun)
|
|
||||||
} else {
|
|
||||||
hadTestMain = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Decls = decls
|
|
||||||
|
|
||||||
if hadTestMain {
|
|
||||||
astRemoveUnusedImports(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type visitFn func(node ast.Node) ast.Visitor
|
|
||||||
|
|
||||||
func (fn visitFn) Visit(node ast.Node) ast.Visitor {
|
|
||||||
return fn(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func astUsedPackages(f *ast.File) []string {
|
|
||||||
var refs []string
|
|
||||||
var visitor visitFn
|
|
||||||
visitor = visitFn(func(node ast.Node) ast.Visitor {
|
|
||||||
if node == nil {
|
|
||||||
return visitor
|
|
||||||
}
|
|
||||||
switch v := node.(type) {
|
|
||||||
case *ast.SelectorExpr:
|
|
||||||
xident, ok := v.X.(*ast.Ident)
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if xident.Obj != nil {
|
|
||||||
// if the parser can resolve it, it's not a package ref
|
|
||||||
break
|
|
||||||
}
|
|
||||||
refs = append(refs, xident.Name)
|
|
||||||
}
|
|
||||||
return visitor
|
|
||||||
})
|
|
||||||
ast.Walk(visitor, f)
|
|
||||||
return refs
|
|
||||||
}
|
|
||||||
|
|
||||||
// importPathToName finds out the actual package name, as declared in its .go files.
|
|
||||||
// If there's a problem, it falls back to using importPathToNameBasic.
|
|
||||||
func astImportPathToName(importPath string) (packageName string) {
|
|
||||||
if buildPkg, err := build.Import(importPath, "", 0); err == nil {
|
|
||||||
return buildPkg.Name
|
|
||||||
}
|
|
||||||
return path.Base(importPath)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
package godog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var astContextSrc = `package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/DATA-DOG/godog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func myContext(s *godog.Suite) {
|
|
||||||
}`
|
|
||||||
|
|
||||||
var astTwoContextSrc = `package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/DATA-DOG/godog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func apiContext(s *godog.Suite) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbContext(s *godog.Suite) {
|
|
||||||
}`
|
|
||||||
|
|
||||||
func astContextParse(src string, t *testing.T) []string {
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
f, err := parser.ParseFile(fset, "", []byte(src), 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error while parsing ast: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return astContexts(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldGetSingleContextFromSource(t *testing.T) {
|
|
||||||
actual := astContextParse(astContextSrc, t)
|
|
||||||
expect := []string{"myContext"}
|
|
||||||
|
|
||||||
if len(actual) != len(expect) {
|
|
||||||
t.Fatalf("number of found contexts do not match, expected %d, but got %d", len(expect), len(actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, c := range expect {
|
|
||||||
if c != actual[i] {
|
|
||||||
t.Fatalf("expected context '%s' at pos %d, but got: '%s'", c, i, actual[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldGetTwoContextsFromSource(t *testing.T) {
|
|
||||||
actual := astContextParse(astTwoContextSrc, t)
|
|
||||||
expect := []string{"apiContext", "dbContext"}
|
|
||||||
|
|
||||||
if len(actual) != len(expect) {
|
|
||||||
t.Fatalf("number of found contexts do not match, expected %d, but got %d", len(expect), len(actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, c := range expect {
|
|
||||||
if c != actual[i] {
|
|
||||||
t.Fatalf("expected context '%s' at pos %d, but got: '%s'", c, i, actual[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldNotFindAnyContextsInEmptyFile(t *testing.T) {
|
|
||||||
actual := astContextParse(`package main`, t)
|
|
||||||
|
|
||||||
if len(actual) != 0 {
|
|
||||||
t.Fatalf("expected no contexts to be found, but there was some: %v", actual)
|
|
||||||
}
|
|
||||||
}
|
|
160
ast_test.go
160
ast_test.go
|
@ -1,162 +1,76 @@
|
||||||
package godog
|
package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"go/format"
|
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var astMainFile = `package main
|
var astContextSrc = `package main
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("hello")
|
|
||||||
}`
|
|
||||||
|
|
||||||
var astNormalFile = `package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func hello() {
|
|
||||||
fmt.Println("hello")
|
|
||||||
}`
|
|
||||||
|
|
||||||
var astTestMainFile = `package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/DATA-DOG/godog"
|
||||||
"testing"
|
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func MyContext(s *godog.Suite) {
|
||||||
fmt.Println("hello")
|
|
||||||
os.Exit(0)
|
|
||||||
}`
|
}`
|
||||||
|
|
||||||
var astPackAliases = `package main
|
var astTwoContextSrc = `package lib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"github.com/DATA-DOG/godog"
|
||||||
a "fmt"
|
|
||||||
b "fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func ApiContext(s *godog.Suite) {
|
||||||
a.Println("a")
|
}
|
||||||
b.Println("b")
|
|
||||||
|
func DBContext(s *godog.Suite) {
|
||||||
}`
|
}`
|
||||||
|
|
||||||
var astAnonymousImport = `package main
|
func astContextParse(src string, t *testing.T) []string {
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
}`
|
|
||||||
|
|
||||||
var astLibrarySrc = `package lib
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func test() {
|
|
||||||
fmt.Println("hello")
|
|
||||||
}`
|
|
||||||
|
|
||||||
var astInternalPackageSrc = `package godog
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func test() {
|
|
||||||
fmt.Println("hello")
|
|
||||||
}`
|
|
||||||
|
|
||||||
func astProcess(src string, t *testing.T) string {
|
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
f, err := parser.ParseFile(fset, "", []byte(src), 0)
|
f, err := parser.ParseFile(fset, "", []byte(src), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error while parsing ast: %v", err)
|
t.Fatalf("unexpected error while parsing ast: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
astDeleteTestMainFunc(f)
|
return astContexts(f)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := format.Node(&buf, fset, f); err != nil {
|
|
||||||
t.Fatalf("failed to build source file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldCleanTestMainFromSimpleTestFile(t *testing.T) {
|
func TestShouldGetSingleContextFromSource(t *testing.T) {
|
||||||
actual := strings.TrimSpace(astProcess(astTestMainFile, t))
|
actual := astContextParse(astContextSrc, t)
|
||||||
expect := `package main`
|
expect := []string{"MyContext"}
|
||||||
|
|
||||||
if actual != expect {
|
if len(actual) != len(expect) {
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
t.Fatalf("number of found contexts do not match, expected %d, but got %d", len(expect), len(actual))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range expect {
|
||||||
|
if c != actual[i] {
|
||||||
|
t.Fatalf("expected context '%s' at pos %d, but got: '%s'", c, i, actual[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldCleanTestMainFromFileWithPackageAliases(t *testing.T) {
|
func TestShouldGetTwoContextsFromSource(t *testing.T) {
|
||||||
actual := strings.TrimSpace(astProcess(astPackAliases, t))
|
actual := astContextParse(astTwoContextSrc, t)
|
||||||
expect := `package main`
|
expect := []string{"ApiContext", "DBContext"}
|
||||||
|
|
||||||
if actual != expect {
|
if len(actual) != len(expect) {
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
t.Fatalf("number of found contexts do not match, expected %d, but got %d", len(expect), len(actual))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range expect {
|
||||||
|
if c != actual[i] {
|
||||||
|
t.Fatalf("expected context '%s' at pos %d, but got: '%s'", c, i, actual[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldNotModifyNormalFile(t *testing.T) {
|
func TestShouldNotFindAnyContextsInEmptyFile(t *testing.T) {
|
||||||
actual := strings.TrimSpace(astProcess(astNormalFile, t))
|
actual := astContextParse(`package main`, t)
|
||||||
expect := astNormalFile
|
|
||||||
|
|
||||||
if actual != expect {
|
if len(actual) != 0 {
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
t.Fatalf("expected no contexts to be found, but there was some: %v", actual)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldNotModifyMainFile(t *testing.T) {
|
|
||||||
actual := strings.TrimSpace(astProcess(astMainFile, t))
|
|
||||||
expect := astMainFile
|
|
||||||
|
|
||||||
if actual != expect {
|
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldMaintainAnonymousImport(t *testing.T) {
|
|
||||||
actual := strings.TrimSpace(astProcess(astAnonymousImport, t))
|
|
||||||
expect := `package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
|
||||||
)`
|
|
||||||
|
|
||||||
if actual != expect {
|
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldNotModifyLibraryPackageSource(t *testing.T) {
|
|
||||||
actual := strings.TrimSpace(astProcess(astLibrarySrc, t))
|
|
||||||
expect := astLibrarySrc
|
|
||||||
|
|
||||||
if actual != expect {
|
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldNotModifyGodogPackageSource(t *testing.T) {
|
|
||||||
actual := strings.TrimSpace(astProcess(astInternalPackageSrc, t))
|
|
||||||
expect := astInternalPackageSrc
|
|
||||||
|
|
||||||
if actual != expect {
|
|
||||||
t.Fatalf("expected output does not match: %s", actual)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
builder.go
15
builder.go
|
@ -2,7 +2,6 @@ package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
|
@ -165,7 +164,11 @@ func locatePackage(try []string) (*build.Package, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return build.ImportDir(abs, 0)
|
pkg, err := build.ImportDir(abs, 0)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return pkg, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("failed to find godog package in any of:\n%s", strings.Join(try, "\n"))
|
return nil, fmt.Errorf("failed to find godog package in any of:\n%s", strings.Join(try, "\n"))
|
||||||
}
|
}
|
||||||
|
@ -214,11 +217,3 @@ func processPackageTestFiles(packs ...[]string) ([]string, error) {
|
||||||
}
|
}
|
||||||
return ctxs, nil
|
return ctxs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func debug(i interface{}) {
|
|
||||||
dat, err := json.MarshalIndent(i, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(os.Stdout, string(dat))
|
|
||||||
}
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче