main: use emulator exit code instead of parsing test output

This commit changes `tinygo test` to always look at the exit code of the
running test, instead of looking for a "PASS" string at the end of the
output. This is possible now that the binaries running under
qemu-system-arm or qemu-system-riscv32 will signal the correct exit code
when they exit.

As a side effect, this also makes it possible to avoid the "PASS" line
between successful tests. Before:

    $ tinygo test container/heap container/list
    PASS
    ok  	container/heap	0.001s
    PASS
    ok  	container/list	0.001s

After:

    $ tinygo test container/heap container/list
    ok  	container/heap	0.001s
    ok  	container/list	0.001s

The new behavior is more in line with upstream Go:

    go test container/heap container/list
    ok  	container/heap	0.004s
    ok  	container/list	0.004s
Этот коммит содержится в:
Ayke van Laethem 2021-08-14 01:46:40 +02:00 коммит произвёл Ron Evans
родитель 98f84a497d
коммит 4d5ec6c57b
3 изменённых файлов: 16 добавлений и 37 удалений

46
main.go
Просмотреть файл

@ -212,6 +212,7 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVer
// values are whether the test passed and any errors encountered while trying to
// run the binary.
func runPackageTest(config *compileopts.Config, result builder.BuildResult, testVerbose, testShort bool) (bool, error) {
var cmd *exec.Cmd
if len(config.Target.Emulator) == 0 {
// Run directly.
var flags []string
@ -221,47 +222,26 @@ func runPackageTest(config *compileopts.Config, result builder.BuildResult, test
if testShort {
flags = append(flags, "-test.short")
}
cmd := executeCommand(config.Options, result.Binary, flags...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd = executeCommand(config.Options, result.Binary, flags...)
cmd.Dir = result.MainDir
err := cmd.Run()
if err != nil {
if _, ok := err.(*exec.ExitError); ok {
// Binary exited with a non-zero exit code, which means the test
// failed.
return false, nil
}
return false, &commandError{"failed to run compiled binary", result.Binary, err}
}
return true, nil
} else {
// Run in an emulator.
// TODO: pass the -test.v flag if needed.
args := append(config.Target.Emulator[1:], result.Binary)
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
buf := &bytes.Buffer{}
w := io.MultiWriter(os.Stdout, buf)
cmd.Stdout = w
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
if err, ok := err.(*exec.ExitError); !ok || !err.Exited() {
// Workaround for QEMU which always exits with an error.
return false, &commandError{"failed to run emulator with", result.Binary, err}
}
}
testOutput := string(buf.Bytes())
if testOutput == "PASS\n" || strings.HasSuffix(testOutput, "\nPASS\n") {
// Test passed.
return true, nil
} else {
// Test failed, either by ending with the word "FAIL" or with a
// panic of some sort.
cmd = executeCommand(config.Options, config.Target.Emulator[0], args...)
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
if _, ok := err.(*exec.ExitError); ok {
// Binary exited with a non-zero exit code, which means the test
// failed.
return false, nil
}
return false, &commandError{"failed to run compiled binary", result.Binary, err}
}
return true, nil
}
// Flash builds and flashes the built binary to the given serial port.

Просмотреть файл

@ -333,9 +333,6 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
}
}()
err = cmd.Wait()
if _, ok := err.(*exec.ExitError); ok && options.Target != "" {
err = nil // workaround for QEMU
}
close(runComplete)
if ranTooLong {

Просмотреть файл

@ -285,7 +285,9 @@ func (m *M) Run() int {
if failures > 0 {
fmt.Println("FAIL")
} else {
fmt.Println("PASS")
if flagVerbose {
fmt.Println("PASS")
}
}
return failures
}