summaryrefslogtreecommitdiff
path: root/test/run.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/run.go')
-rw-r--r--test/run.go139
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"))