summaryrefslogtreecommitdiff
path: root/src/cmd/gotest/gotest.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gotest/gotest.go')
-rw-r--r--src/cmd/gotest/gotest.go435
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)
-}`