Commit ebb0e5db authored by Daniel Morsing's avatar Daniel Morsing

test: Add rundir, rundircmpout and errorcheckdir commands to testlib and run.go

rundir will compile each file in the directory in lexicographic order, link the last file as the main package and run the resulting program. rundircmpout is an related command, that will compare the output of the program to an corresponding .out file

errorcheckdir will compile each file in a directory in lexicographic order, running errorcheck on each file as it compiles. All compilations are assumed to be successful except for the last file. However, If a -0 flag is present on the command, the last compilation will also be assumed successful

This CL also includes a small refactoring of run.go. It was getting unwieldy and the meaning of the run commands was hidden behind argument line formatting.

Fixes #4058.

R=rsc, minux.ma, remyoudompheng, iant
CC=golang-dev
https://golang.org/cl/6554071
parent 16bea49e
...@@ -165,6 +165,22 @@ func goFiles(dir string) []string { ...@@ -165,6 +165,22 @@ func goFiles(dir string) []string {
return names return names
} }
type runCmd func(...string) ([]byte, error)
func compileFile(runcmd runCmd, longname string) (out []byte, err error) {
return runcmd("go", "tool", gc, "-e", longname)
}
func compileInDir(runcmd runCmd, dir, name string) (out []byte, err error) {
return runcmd("go", "tool", gc, "-e", "-D.", "-I.", filepath.Join(dir, name))
}
func linkFile(runcmd runCmd, goname string) (err error) {
pfile := strings.Replace(goname, ".go", "."+letter, -1)
_, err = runcmd("go", "tool", ld, "-o", "run.out", "-L", ".", pfile)
return
}
// skipError describes why a test was skipped. // skipError describes why a test was skipped.
type skipError string type skipError string
...@@ -230,6 +246,19 @@ func (t *test) goDirName() string { ...@@ -230,6 +246,19 @@ func (t *test) goDirName() string {
return filepath.Join(t.dir, strings.Replace(t.gofile, ".go", ".dir", -1)) return filepath.Join(t.dir, strings.Replace(t.gofile, ".go", ".dir", -1))
} }
func goDirFiles(longdir string) (filter []os.FileInfo, err error) {
files, dirErr := ioutil.ReadDir(longdir)
if dirErr != nil {
return nil, dirErr
}
for _, gofile := range files {
if filepath.Ext(gofile.Name()) == ".go" {
filter = append(filter, gofile)
}
}
return
}
// run runs a test. // run runs a test.
func (t *test) run() { func (t *test) run() {
defer close(t.donec) defer close(t.donec)
...@@ -263,12 +292,15 @@ func (t *test) run() { ...@@ -263,12 +292,15 @@ func (t *test) run() {
} }
switch action { switch action {
case "rundircmpout":
action = "rundir"
t.action = "rundir"
case "cmpout": case "cmpout":
action = "run" // the run case already looks for <dir>/<test>.out files action = "run" // the run case already looks for <dir>/<test>.out files
fallthrough fallthrough
case "compile", "compiledir", "build", "run", "runoutput": case "compile", "compiledir", "build", "run", "runoutput", "rundir":
t.action = action t.action = action
case "errorcheck": case "errorcheck", "errorcheckdir":
t.action = action t.action = action
wantError = true wantError = true
for len(args) > 0 && strings.HasPrefix(args[0], "-") { for len(args) > 0 && strings.HasPrefix(args[0], "-") {
...@@ -308,6 +340,9 @@ func (t *test) run() { ...@@ -308,6 +340,9 @@ func (t *test) run() {
cmd.Dir = t.tempDir cmd.Dir = t.tempDir
} }
err := cmd.Run() err := cmd.Run()
if err != nil {
err = fmt.Errorf("%s\n%s", err, buf.Bytes())
}
return buf.Bytes(), err return buf.Bytes(), err
} }
...@@ -328,7 +363,7 @@ func (t *test) run() { ...@@ -328,7 +363,7 @@ func (t *test) run() {
} }
} else { } else {
if err != nil { if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out) t.err = err
return return
} }
} }
...@@ -336,42 +371,95 @@ func (t *test) run() { ...@@ -336,42 +371,95 @@ func (t *test) run() {
return return
case "compile": case "compile":
out, err := runcmd("go", "tool", gc, "-e", "-o", "a."+letter, long) _, t.err = compileFile(runcmd, long)
if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out)
}
case "compiledir": case "compiledir":
// Compile all files in the directory in lexicographic order. // Compile all files in the directory in lexicographic order.
longdir := filepath.Join(cwd, t.goDirName()) longdir := filepath.Join(cwd, t.goDirName())
files, dirErr := ioutil.ReadDir(longdir) files, err := goDirFiles(longdir)
if dirErr != nil { if err != nil {
t.err = dirErr t.err = err
return return
} }
for _, gofile := range files { for _, gofile := range files {
if filepath.Ext(gofile.Name()) != ".go" { _, t.err = compileInDir(runcmd, longdir, gofile.Name())
continue if t.err != nil {
return
} }
afile := strings.Replace(gofile.Name(), ".go", "."+letter, -1) }
out, err := runcmd("go", "tool", gc, "-e", "-D.", "-I.", "-o", afile, filepath.Join(longdir, gofile.Name()))
case "errorcheckdir":
// errorcheck all files in lexicographic order
// useful for finding importing errors
longdir := filepath.Join(cwd, t.goDirName())
files, err := goDirFiles(longdir)
if err != nil { if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out) t.err = err
return
}
for i, gofile := range files {
out, err := compileInDir(runcmd, longdir, gofile.Name())
if i == len(files)-1 {
if wantError && err == nil {
t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
return
} else if !wantError && err != nil {
t.err = err
return
}
} else if err != nil {
t.err = err
return
}
longname := filepath.Join(longdir, gofile.Name())
t.err = t.errorCheck(string(out), longname, gofile.Name())
if t.err != nil {
break break
} }
} }
case "rundir":
// Compile all files in the directory in lexicographic order.
// then link as if the last file is the main package and run it
longdir := filepath.Join(cwd, t.goDirName())
files, err := goDirFiles(longdir)
if err != nil {
t.err = err
return
}
var gofile os.FileInfo
for _, gofile = range files {
_, err := compileInDir(runcmd, longdir, gofile.Name())
if err != nil {
t.err = err
return
}
}
err = linkFile(runcmd, gofile.Name())
if err != nil {
t.err = err
return
}
out, err := runcmd(append([]string{filepath.Join(t.tempDir, "run.out")}, args...)...)
if err != nil {
t.err = err
return
}
if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
t.err = fmt.Errorf("incorrect output\n%s", out)
}
case "build": case "build":
out, err := runcmd("go", "build", "-o", "a.exe", long) _, err := runcmd("go", "build", "-o", "a.exe", long)
if err != nil { if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out) t.err = err
} }
case "run": case "run":
useTmp = false useTmp = false
out, err := runcmd(append([]string{"go", "run", t.goFileName()}, args...)...) out, err := runcmd(append([]string{"go", "run", t.goFileName()}, args...)...)
if err != nil { if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out) t.err = err
} }
if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() { if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
t.err = fmt.Errorf("incorrect output\n%s", out) t.err = fmt.Errorf("incorrect output\n%s", out)
...@@ -381,7 +469,7 @@ func (t *test) run() { ...@@ -381,7 +469,7 @@ func (t *test) run() {
useTmp = false useTmp = false
out, err := runcmd("go", "run", t.goFileName()) out, err := runcmd("go", "run", t.goFileName())
if err != nil { if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out) t.err = err
} }
tfile := filepath.Join(t.tempDir, "tmp__.go") tfile := filepath.Join(t.tempDir, "tmp__.go")
err = ioutil.WriteFile(tfile, out, 0666) err = ioutil.WriteFile(tfile, out, 0666)
...@@ -391,7 +479,7 @@ func (t *test) run() { ...@@ -391,7 +479,7 @@ func (t *test) run() {
} }
out, err = runcmd("go", "run", tfile) out, err = runcmd("go", "run", tfile)
if err != nil { if err != nil {
t.err = fmt.Errorf("%s\n%s", err, out) t.err = err
} }
if string(out) != t.expectedOutput() { if string(out) != t.expectedOutput() {
t.err = fmt.Errorf("incorrect output\n%s", out) t.err = fmt.Errorf("incorrect output\n%s", out)
...@@ -444,7 +532,7 @@ func (t *test) errorCheck(outStr string, full, short string) (err error) { ...@@ -444,7 +532,7 @@ func (t *test) errorCheck(outStr string, full, short string) (err error) {
out[i] = strings.Replace(out[i], full, short, -1) out[i] = strings.Replace(out[i], full, short, -1)
} }
for _, we := range t.wantedErrors() { for _, we := range t.wantedErrors(full, short) {
var errmsgs []string var errmsgs []string
errmsgs, out = partitionStrings(we.filterRe, out) errmsgs, out = partitionStrings(we.filterRe, out)
if len(errmsgs) == 0 { if len(errmsgs) == 0 {
...@@ -505,8 +593,9 @@ var ( ...@@ -505,8 +593,9 @@ var (
lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`) lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`)
) )
func (t *test) wantedErrors() (errs []wantedError) { func (t *test) wantedErrors(file, short string) (errs []wantedError) {
for i, line := range strings.Split(t.src, "\n") { src, _ := ioutil.ReadFile(file)
for i, line := range strings.Split(string(src), "\n") {
lineNum := i + 1 lineNum := i + 1
if strings.Contains(line, "////") { if strings.Contains(line, "////") {
// double comment disables ERROR // double comment disables ERROR
...@@ -531,15 +620,15 @@ func (t *test) wantedErrors() (errs []wantedError) { ...@@ -531,15 +620,15 @@ func (t *test) wantedErrors() (errs []wantedError) {
delta, _ := strconv.Atoi(m[5:]) delta, _ := strconv.Atoi(m[5:])
n -= delta n -= delta
} }
return fmt.Sprintf("%s:%d", t.gofile, n) return fmt.Sprintf("%s:%d", short, n)
}) })
filterPattern := fmt.Sprintf(`^(\w+/)?%s:%d[:[]`, t.gofile, lineNum) filterPattern := fmt.Sprintf(`^(\w+/)?%s:%d[:[]`, short, lineNum)
errs = append(errs, wantedError{ errs = append(errs, wantedError{
reStr: rx, reStr: rx,
re: regexp.MustCompile(rx), re: regexp.MustCompile(rx),
filterRe: regexp.MustCompile(filterPattern), filterRe: regexp.MustCompile(filterPattern),
lineNum: lineNum, lineNum: lineNum,
file: t.gofile, file: short,
}) })
} }
} }
......
...@@ -16,6 +16,46 @@ compiledir() { ...@@ -16,6 +16,46 @@ compiledir() {
done done
} }
errorcheckdir() {
lastzero=""
if [ "$1" = "-0" ]; then
lastzero="-0"
fi
files=($D/$F.dir/*.go)
for gofile in ${files[@]}
do
zero="-0"
if [ ${files[${#files[@]}-1]} = $gofile ]; then
zero=$lastzero
fi
errchk $zero $G -D. -I. -e $gofile
done
}
rundir() {
lastfile=""
for gofile in $D/$F.dir/*.go
do
name=$(basename ${gofile/\.go/} )
$G -D. -I. -e "$gofile" || return 1
lastfile=$name
done
$L -o $A.out -L. $lastfile.$A
./$A.out
}
rundircmpout() {
lastfile=""
for gofile in $D/$F.dir/*.go
do
name=$(basename ${gofile/\.go/} )
$G -D. -I. -e "$gofile" || return 1
lastfile=$name
done
$L -o $A.out -L. $lastfile.$A
./$A.out | cmp - $D/$F.out
}
build() { build() {
$G $D/$F.go && $L $F.$A $G $D/$F.go && $L $F.$A
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment