135 строки
		
	
	
	
		
			2,9 КиБ
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			135 строки
		
	
	
	
		
			2,9 КиБ
		
	
	
	
		
			Go
		
	
	
	
	
	
| package godog
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"go/ast"
 | |
| 	"go/format"
 | |
| 	"go/parser"
 | |
| 	"go/token"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"text/template"
 | |
| )
 | |
| 
 | |
| var runnerTemplate = template.Must(template.New("main").Parse(`package main
 | |
| import (
 | |
| {{ if not .Internal }}	"github.com/DATA-DOG/godog"{{ end }}
 | |
| 	"os"
 | |
| 	"testing"
 | |
| )
 | |
| 
 | |
| const GodogSuiteName = "{{ .SuiteName }}"
 | |
| 
 | |
| func TestMain(m *testing.M) {
 | |
| 	status := {{ if not .Internal }}godog.{{ end }}Run(func (suite *{{ if not .Internal }}godog.{{ end }}Suite) {
 | |
| 		{{range .Contexts}}
 | |
| 			{{ . }}(suite)
 | |
| 		{{end}}
 | |
| 	})
 | |
| 	os.Exit(status)
 | |
| }`))
 | |
| 
 | |
| type builder struct {
 | |
| 	files     map[string]*ast.File
 | |
| 	Contexts  []string
 | |
| 	Internal  bool
 | |
| 	SuiteName string
 | |
| }
 | |
| 
 | |
| func (b *builder) register(f *ast.File, name string) {
 | |
| 	// mark godog package as internal
 | |
| 	if f.Name.Name == "godog" && !b.Internal {
 | |
| 		b.Internal = true
 | |
| 	}
 | |
| 	b.SuiteName = f.Name.Name
 | |
| 	deleteTestMainFunc(f)
 | |
| 	f.Name.Name = "main"
 | |
| 	b.registerContexts(f)
 | |
| 	b.files[name] = f
 | |
| }
 | |
| 
 | |
| func (b *builder) registerContexts(f *ast.File) {
 | |
| 	for _, d := range f.Decls {
 | |
| 		switch fun := d.(type) {
 | |
| 		case *ast.FuncDecl:
 | |
| 			for _, param := range fun.Type.Params.List {
 | |
| 				switch expr := param.Type.(type) {
 | |
| 				case *ast.StarExpr:
 | |
| 					switch x := expr.X.(type) {
 | |
| 					case *ast.Ident:
 | |
| 						if x.Name == "Suite" {
 | |
| 							b.Contexts = append(b.Contexts, fun.Name.Name)
 | |
| 						}
 | |
| 					case *ast.SelectorExpr:
 | |
| 						switch t := x.X.(type) {
 | |
| 						case *ast.Ident:
 | |
| 							if t.Name == "godog" && x.Sel.Name == "Suite" {
 | |
| 								b.Contexts = append(b.Contexts, fun.Name.Name)
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Build scans all go files in current directory,
 | |
| // copies them to temporary build directory.
 | |
| // If there is a TestMain func in any of test.go files
 | |
| // it removes it and all necessary unused imports related
 | |
| // to this function.
 | |
| //
 | |
| // It also looks for any godog suite contexts and registers
 | |
| // them in order to call them on execution.
 | |
| //
 | |
| // The test entry point which uses go1.4 TestMain func
 | |
| // is generated from the template above.
 | |
| func Build(dir string) error {
 | |
| 	fset := token.NewFileSet()
 | |
| 	b := &builder{files: make(map[string]*ast.File)}
 | |
| 
 | |
| 	err := filepath.Walk(".", func(path string, file os.FileInfo, err error) error {
 | |
| 		if file.IsDir() && file.Name() != "." {
 | |
| 			return filepath.SkipDir
 | |
| 		}
 | |
| 		if err == nil && strings.HasSuffix(path, ".go") {
 | |
| 			f, err := parser.ParseFile(fset, path, nil, 0)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			b.register(f, file.Name())
 | |
| 		}
 | |
| 		return err
 | |
| 	})
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	var buf bytes.Buffer
 | |
| 	if err := runnerTemplate.Execute(&buf, b); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	f, err := parser.ParseFile(fset, "", &buf, 0)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	b.files["godog_test.go"] = f
 | |
| 
 | |
| 	os.Mkdir(dir, 0755)
 | |
| 	for name, node := range b.files {
 | |
| 		f, err := os.Create(filepath.Join(dir, name))
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if err := format.Node(f, fset, node); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | 
