diff options
Diffstat (limited to 'src/cmd/gotest/gotest.go')
-rw-r--r-- | src/cmd/gotest/gotest.go | 435 |
1 files changed, 0 insertions, 435 deletions
diff --git a/src/cmd/gotest/gotest.go b/src/cmd/gotest/gotest.go deleted file mode 100644 index 4cb3da23c..000000000 --- a/src/cmd/gotest/gotest.go +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "bufio" - "exec" - "fmt" - "go/ast" - "go/parser" - "go/token" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "strings" - "time" - "unicode" - "utf8" -) - -// Environment for commands. -var ( - XGC []string // 6g -I _test -o _xtest_.6 - GC []string // 6g -I _test _testmain.go - GL []string // 6l -L _test _testmain.6 - GOARCH string - GOROOT string - GORUN string - O string - args []string // arguments passed to gotest; also passed to the binary - fileNames []string - env = os.Environ() -) - -// These strings are created by getTestNames. -var ( - insideFileNames []string // list of *.go files inside the package. - outsideFileNames []string // list of *.go files outside the package (in package foo_test). -) - -var ( - files []*File - importPath string -) - -// Flags for our own purposes. We do our own flag processing. -var ( - cFlag bool - xFlag bool -) - -// elapsed returns the number of seconds since gotest started. -func elapsed() float64 { - return float64(time.Nanoseconds()-start) / 1e9 -} - -var start = time.Nanoseconds() - -// File represents a file that contains tests. -type File struct { - name string - pkg string - file *os.File - astFile *ast.File - tests []string // The names of the TestXXXs. - benchmarks []string // The names of the BenchmarkXXXs. -} - -func main() { - flags() - needMakefile() - setEnvironment() - getTestFileNames() - parseFiles() - getTestNames() - run("gomake", "testpackage-clean") - run("gomake", "testpackage", fmt.Sprintf("GOTESTFILES=%s", strings.Join(insideFileNames, " "))) - if len(outsideFileNames) > 0 { - run(append(XGC, outsideFileNames...)...) - } - importPath = runWithStdout("gomake", "-s", "importpath") - writeTestmainGo() - run(GC...) - run(GL...) - if !cFlag { - runTestWithArgs("./" + O + ".out") - } - if xFlag { - fmt.Printf("gotest %.2fs: done\n", elapsed()) - } -} - -// needMakefile tests that we have a Makefile in this directory. -func needMakefile() { - if _, err := os.Stat("Makefile"); err != nil { - Fatalf("please create a Makefile for gotest; see http://golang.org/doc/code.html for details") - } -} - -// Fatalf formats its arguments, prints the message with a final newline, and exits. -func Fatalf(s string, args ...interface{}) { - fmt.Fprintf(os.Stderr, "gotest: "+s+"\n", args...) - os.Exit(2) -} - -// theChar is the map from architecture to object character. -var theChar = map[string]string{ - "arm": "5", - "amd64": "6", - "386": "8", -} - -// addEnv adds a name=value pair to the environment passed to subcommands. -// If the item is already in the environment, addEnv replaces the value. -func addEnv(name, value string) { - for i := 0; i < len(env); i++ { - if strings.HasPrefix(env[i], name+"=") { - env[i] = name + "=" + value - return - } - } - env = append(env, name+"="+value) -} - -// setEnvironment assembles the configuration for gotest and its subcommands. -func setEnvironment() { - // Basic environment. - GOROOT = runtime.GOROOT() - addEnv("GOROOT", GOROOT) - GOARCH = os.Getenv("GOARCH") - if GOARCH == "" { - GOARCH = runtime.GOARCH - } - addEnv("GOARCH", GOARCH) - O = theChar[GOARCH] - if O == "" { - Fatalf("unknown architecture %s", GOARCH) - } - - // Commands and their flags. - gc := os.Getenv("GC") - if gc == "" { - gc = O + "g" - } - XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O} - GC = []string{gc, "-I", "_test", "_testmain.go"} - gl := os.Getenv("GL") - if gl == "" { - gl = O + "l" - } - GL = []string{gl, "-L", "_test", "_testmain." + O} - - // Silence make on Linux - addEnv("MAKEFLAGS", "") - addEnv("MAKELEVEL", "") -} - -// getTestFileNames gets the set of files we're looking at. -// If gotest has no arguments, it scans for file names matching "[^.]*_test.go". -func getTestFileNames() { - names := fileNames - if len(names) == 0 { - var err os.Error - names, err = filepath.Glob("[^.]*_test.go") - if err != nil { - Fatalf("Glob pattern error: %s", err) - } - if len(names) == 0 { - Fatalf(`no test files found: no match for "[^.]*_test.go"`) - } - } - for _, n := range names { - fd, err := os.Open(n) - if err != nil { - Fatalf("%s: %s", n, err) - } - f := &File{name: n, file: fd} - files = append(files, f) - } -} - -// parseFiles parses the files and remembers the packages we find. -func parseFiles() { - fileSet := token.NewFileSet() - for _, f := range files { - // Report declaration errors so we can abort if the files are incorrect Go. - file, err := parser.ParseFile(fileSet, f.name, nil, parser.DeclarationErrors) - if err != nil { - Fatalf("parse error: %s", err) - } - f.astFile = file - f.pkg = file.Name.String() - if f.pkg == "" { - Fatalf("cannot happen: no package name in %s", f.name) - } - } -} - -// getTestNames extracts the names of tests and benchmarks. They are all -// top-level functions that are not methods. -func getTestNames() { - for _, f := range files { - for _, d := range f.astFile.Decls { - n, ok := d.(*ast.FuncDecl) - if !ok { - continue - } - if n.Recv != nil { // a method, not a function. - continue - } - name := n.Name.String() - if isTest(name, "Test") { - f.tests = append(f.tests, name) - } else if isTest(name, "Benchmark") { - f.benchmarks = append(f.benchmarks, name) - } - // TODO: worth checking the signature? Probably not. - } - if strings.HasSuffix(f.pkg, "_test") { - outsideFileNames = append(outsideFileNames, f.name) - } else { - insideFileNames = append(insideFileNames, f.name) - } - } -} - -// isTest tells whether name looks like a test (or benchmark, according to prefix). -// It is a Test (say) if there is a character after Test that is not a lower-case letter. -// We don't want TesticularCancer. -func isTest(name, prefix string) bool { - if !strings.HasPrefix(name, prefix) { - return false - } - if len(name) == len(prefix) { // "Test" is ok - return true - } - rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) - return !unicode.IsLower(rune) -} - -func run(args ...string) { - doRun(args, false) -} - -// runWithStdout is like run, but returns the text of standard output with the last newline dropped. -func runWithStdout(argv ...string) string { - s := doRun(argv, true) - if strings.HasSuffix(s, "\r\n") { - s = s[:len(s)-2] - } else if strings.HasSuffix(s, "\n") { - s = s[:len(s)-1] - } - if len(s) == 0 { - Fatalf("no output from command %s", strings.Join(argv, " ")) - } - return s -} - -// runTestWithArgs appends gotest's runs the provided binary with the args passed on the command line. -func runTestWithArgs(binary string) { - doRun(append([]string{binary}, args...), false) -} - -// doRun is the general command runner. The flag says whether we want to -// retrieve standard output. -func doRun(argv []string, returnStdout bool) string { - if xFlag { - fmt.Printf("gotest %.2fs: %s\n", elapsed(), strings.Join(argv, " ")) - t := -time.Nanoseconds() - defer func() { - t += time.Nanoseconds() - fmt.Printf(" [+%.2fs]\n", float64(t)/1e9) - }() - } - command := argv[0] - if runtime.GOOS == "windows" && command == "gomake" { - // gomake is a shell script and it cannot be executed directly on Windows. - cmd := "" - for i, v := range argv { - if i > 0 { - cmd += " " - } - cmd += `"` + v + `"` - } - command = "bash" - argv = []string{"bash", "-c", cmd} - } - var err os.Error - argv[0], err = exec.LookPath(argv[0]) - if err != nil { - Fatalf("can't find %s: %s", command, err) - } - procAttr := &os.ProcAttr{ - Env: env, - Files: []*os.File{ - os.Stdin, - os.Stdout, - os.Stderr, - }, - } - var r, w *os.File - if returnStdout { - r, w, err = os.Pipe() - if err != nil { - Fatalf("can't create pipe: %s", err) - } - procAttr.Files[1] = w - } - proc, err := os.StartProcess(argv[0], argv, procAttr) - if err != nil { - Fatalf("%s failed to start: %s", command, err) - } - if returnStdout { - defer r.Close() - w.Close() - } - waitMsg, err := proc.Wait(0) - if err != nil || waitMsg == nil { - Fatalf("%s failed: %s", command, err) - } - if !waitMsg.Exited() || waitMsg.ExitStatus() != 0 { - Fatalf("%q failed: %s", strings.Join(argv, " "), waitMsg) - } - if returnStdout { - b, err := ioutil.ReadAll(r) - if err != nil { - Fatalf("can't read output from command: %s", err) - } - return string(b) - } - return "" -} - -// writeTestmainGo generates the test program to be compiled, "./_testmain.go". -func writeTestmainGo() { - f, err := os.Create("_testmain.go") - if err != nil { - Fatalf("can't create _testmain.go: %s", err) - } - defer f.Close() - b := bufio.NewWriter(f) - defer b.Flush() - - // Package and imports. - fmt.Fprint(b, "package main\n\n") - // Are there tests from a package other than the one we're testing? - // We can't just use file names because some of the things we compiled - // contain no tests. - outsideTests := false - insideTests := false - for _, f := range files { - //println(f.name, f.pkg) - if len(f.tests) == 0 && len(f.benchmarks) == 0 { - continue - } - if strings.HasSuffix(f.pkg, "_test") { - outsideTests = true - } else { - insideTests = true - } - } - if insideTests { - switch importPath { - case "testing": - case "main": - // Import path main is reserved, so import with - // explicit reference to ./_test/main instead. - // Also, the file we are writing defines a function named main, - // so rename this import to __main__ to avoid name conflict. - fmt.Fprintf(b, "import __main__ %q\n", "./_test/main") - default: - fmt.Fprintf(b, "import %q\n", importPath) - } - } - if outsideTests { - fmt.Fprintf(b, "import %q\n", "./_xtest_") - } - fmt.Fprintf(b, "import %q\n", "testing") - fmt.Fprintf(b, "import __os__ %q\n", "os") // rename in case tested package is called os - fmt.Fprintf(b, "import __regexp__ %q\n", "regexp") // rename in case tested package is called regexp - fmt.Fprintln(b) // for gofmt - - // Tests. - fmt.Fprintln(b, "var tests = []testing.InternalTest{") - for _, f := range files { - for _, t := range f.tests { - fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, t, notMain(f.pkg), t) - } - } - fmt.Fprintln(b, "}") - fmt.Fprintln(b) - - // Benchmarks. - fmt.Fprintf(b, "var benchmarks = []testing.InternalBenchmark{") - for _, f := range files { - for _, bm := range f.benchmarks { - fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, bm, notMain(f.pkg), bm) - } - } - fmt.Fprintln(b, "}") - - // Body. - fmt.Fprintln(b, testBody) -} - -// notMain returns the package, renaming as appropriate if it's "main". -func notMain(pkg string) string { - if pkg == "main" { - return "__main__" - } - return pkg -} - -// testBody is just copied to the output. It's the code that runs the tests. -var testBody = ` -var matchPat string -var matchRe *__regexp__.Regexp - -func matchString(pat, str string) (result bool, err __os__.Error) { - if matchRe == nil || matchPat != pat { - matchPat = pat - matchRe, err = __regexp__.Compile(matchPat) - if err != nil { - return - } - } - return matchRe.MatchString(str), nil -} - -func main() { - testing.Main(matchString, tests, benchmarks) -}` |