diff options
Diffstat (limited to 'test/run.go')
-rw-r--r-- | test/run.go | 139 |
1 files changed, 107 insertions, 32 deletions
diff --git a/test/run.go b/test/run.go index f1f1ec034..a8d4baa3a 100644 --- a/test/run.go +++ b/test/run.go @@ -27,6 +27,7 @@ import ( "sort" "strconv" "strings" + "time" "unicode" ) @@ -44,6 +45,8 @@ var ( // letter is the build.ArchChar letter string + + goos, goarch string // dirs are the directories to look for *.go files in. // TODO(bradfitz): just use all directories? @@ -68,8 +71,12 @@ const maxTests = 5000 func main() { flag.Parse() - // Disable parallelism if printing - if *verbose { + goos = os.Getenv("GOOS") + goarch = os.Getenv("GOARCH") + findExecCmd() + + // Disable parallelism if printing or if using a simulator. + if *verbose || len(findExecCmd()) > 0 { *numParallel = 1 } @@ -114,28 +121,39 @@ func main() { failed := false resCount := map[string]int{} for _, test := range tests { - <-test.donec - _, isSkip := test.err.(skipError) - errStr := "pass" + <-test.donec + status := "ok " + errStr := "" + if _, isSkip := test.err.(skipError); isSkip { + status = "skip" + test.err = nil + if !skipOkay[path.Join(test.dir, test.gofile)] { + errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr + status = "FAIL" + } + } if test.err != nil { + status = "FAIL" errStr = test.err.Error() - if !isSkip { - failed = true - } } - if isSkip && !skipOkay[path.Join(test.dir, test.gofile)] { - errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr - isSkip = false + if status == "FAIL" { failed = true } - resCount[errStr]++ - if isSkip && !*verbose && !*showSkips { + resCount[status]++ + if status == "skip" && !*verbose && !*showSkips { continue } - if !*verbose && test.err == nil { + dt := fmt.Sprintf("%.3fs", test.dt.Seconds()) + if status == "FAIL" { + fmt.Printf("# go run run.go -- %s\n%s\nFAIL\t%s\t%s\n", + path.Join(test.dir, test.gofile), + errStr, test.goFileName(), dt) continue } - fmt.Printf("# go run run.go -- %s\n%-20s %-20s: %s\n", path.Join(test.dir, test.gofile), test.action, test.goFileName(), errStr) + if !*verbose { + continue + } + fmt.Printf("%s\t%s\t%s\n", status, test.goFileName(), dt) } if *summary { @@ -188,7 +206,7 @@ func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err e func linkFile(runcmd runCmd, goname string) (err error) { pfile := strings.Replace(goname, ".go", "."+letter, -1) - _, err = runcmd("go", "tool", ld, "-o", "a.exe", "-L", ".", pfile) + _, err = runcmd("go", "tool", ld, "-w", "-o", "a.exe", "-L", ".", pfile) return } @@ -207,7 +225,8 @@ func check(err error) { type test struct { dir, gofile string donec chan bool // closed when done - + dt time.Duration + src string action string // "compile", "build", etc. @@ -379,7 +398,11 @@ func init() { checkShouldTest() } // run runs a test. func (t *test) run() { - defer close(t.donec) + start := time.Now() + defer func() { + t.dt = time.Since(start) + close(t.donec) + }() srcBytes, err := ioutil.ReadFile(t.goFileName()) if err != nil { @@ -396,7 +419,7 @@ func (t *test) run() { t.err = errors.New("double newline not found") return } - if ok, why := shouldTest(t.src, runtime.GOOS, runtime.GOARCH); !ok { + if ok, why := shouldTest(t.src, goos, goarch); !ok { t.action = "skip" if *showSkips { fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why) @@ -456,8 +479,12 @@ func (t *test) run() { check(err) // A few tests (of things like the environment) require these to be set. - os.Setenv("GOOS", runtime.GOOS) - os.Setenv("GOARCH", runtime.GOARCH) + if os.Getenv("GOOS") == "" { + os.Setenv("GOOS", runtime.GOOS) + } + if os.Getenv("GOARCH") == "" { + os.Setenv("GOARCH", runtime.GOARCH) + } useTmp := true runcmd := func(args ...string) ([]byte, error) { @@ -572,7 +599,11 @@ func (t *test) run() { t.err = err return } - out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...) + var cmd []string + cmd = append(cmd, findExecCmd()...) + cmd = append(cmd, filepath.Join(t.tempDir, "a.exe")) + cmd = append(cmd, args...) + out, err := runcmd(cmd...) if err != nil { t.err = err return @@ -654,6 +685,23 @@ func (t *test) run() { } } +var execCmd []string + +func findExecCmd() []string { + if execCmd != nil { + return execCmd + } + execCmd = []string{} // avoid work the second time + if goos == runtime.GOOS && goarch == runtime.GOARCH { + return execCmd + } + path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch)) + if err == nil { + execCmd = []string{path} + } + return execCmd +} + func (t *test) String() string { return filepath.Join(t.dir, t.gofile) } @@ -712,7 +760,7 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) { for _, we := range want { var errmsgs []string - errmsgs, out = partitionStrings(we.filterRe, out) + errmsgs, out = partitionStrings(we.prefix, out) if len(errmsgs) == 0 { errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr)) continue @@ -754,9 +802,29 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) { } -func partitionStrings(rx *regexp.Regexp, strs []string) (matched, unmatched []string) { +// matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[), +// That is, it needs the file name prefix followed by a : or a [, +// and possibly preceded by a directory name. +func matchPrefix(s, prefix string) bool { + i := strings.Index(s, ":") + if i < 0 { + return false + } + j := strings.LastIndex(s[:i], "/") + s = s[j+1:] + if len(s) <= len(prefix) || s[:len(prefix)] != prefix { + return false + } + switch s[len(prefix)] { + case '[', ':': + return true + } + return false +} + +func partitionStrings(prefix string, strs []string) (matched, unmatched []string) { for _, s := range strs { - if rx.MatchString(s) { + if matchPrefix(s, prefix) { matched = append(matched, s) } else { unmatched = append(unmatched, s) @@ -770,7 +838,7 @@ type wantedError struct { re *regexp.Regexp lineNum int file string - filterRe *regexp.Regexp // /^file:linenum\b/m + prefix string } var ( @@ -780,6 +848,8 @@ var ( ) func (t *test) wantedErrors(file, short string) (errs []wantedError) { + cache := make(map[string]*regexp.Regexp) + src, _ := ioutil.ReadFile(file) for i, line := range strings.Split(string(src), "\n") { lineNum := i + 1 @@ -808,15 +878,20 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) { } return fmt.Sprintf("%s:%d", short, n) }) - re, err := regexp.Compile(rx) - if err != nil { - log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err) + re := cache[rx] + if re == nil { + var err error + re, err = regexp.Compile(rx) + if err != nil { + log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err) + } + cache[rx] = re } - filterPattern := fmt.Sprintf(`^(\w+/)?%s:%d[:[]`, regexp.QuoteMeta(short), lineNum) + prefix := fmt.Sprintf("%s:%d", short, lineNum) errs = append(errs, wantedError{ reStr: rx, re: re, - filterRe: regexp.MustCompile(filterPattern), + prefix: prefix, lineNum: lineNum, file: short, }) @@ -869,7 +944,7 @@ func checkShouldTest() { // Build tags separated by a space are OR-ed together. assertNot(shouldTest("// +build arm 386", "linux", "amd64")) - // Build tags seperated by a comma are AND-ed together. + // Build tags separated by a comma are AND-ed together. assertNot(shouldTest("// +build !windows,!plan9", "windows", "amd64")) assertNot(shouldTest("// +build !windows,!plan9", "plan9", "386")) |