testing: add support for the -test.v flag
This flag is passed automatically with the (new) -v flag for TinyGo. For example, this prints all the test outputs: $ tinygo test -v crypto/md5 === RUN TestGolden --- PASS: TestGolden === RUN TestGoldenMarshal --- PASS: TestGoldenMarshal === RUN TestLarge --- PASS: TestLarge === RUN TestBlockGeneric --- PASS: TestBlockGeneric === RUN TestLargeHashes --- PASS: TestLargeHashes PASS ok crypto/md5 0.002s This prints just a summary: $ tinygo test crypto/md5 PASS ok crypto/md5 0.002s (The superfluous 'PASS' message may be removed in the future). This is especially useful when testing a large number of packages: $ tinygo test crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 PASS ok crypto/md5 0.002s PASS ok crypto/sha1 0.043s PASS ok crypto/sha256 0.002s PASS ok crypto/sha512 0.003s At the moment, the -test.v flag is not supplied to binaries running in emulation. I intend to fix this after https://github.com/tinygo-org/tinygo/pull/2038 lands by refactoring runPackageTest, Run, and runTestWithConfig in the main package which all do something similar.
Этот коммит содержится в:
родитель
f57e9622fd
коммит
04f520040e
5 изменённых файлов: 133 добавлений и 22 удалений
18
main.go
18
main.go
|
@ -158,7 +158,7 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
|
||||||
|
|
||||||
// Test runs the tests in the given package. Returns whether the test passed and
|
// Test runs the tests in the given package. Returns whether the test passed and
|
||||||
// possibly an error if the test failed to run.
|
// possibly an error if the test failed to run.
|
||||||
func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, outpath string) (bool, error) {
|
func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVerbose bool, outpath string) (bool, error) {
|
||||||
options.TestConfig.CompileTestBinary = true
|
options.TestConfig.CompileTestBinary = true
|
||||||
config, err := builder.NewConfig(options)
|
config, err := builder.NewConfig(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -184,7 +184,7 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, ou
|
||||||
// Run the test.
|
// Run the test.
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
var err error
|
var err error
|
||||||
passed, err = runPackageTest(config, result)
|
passed, err = runPackageTest(config, result, testVerbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -210,10 +210,14 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, ou
|
||||||
// runPackageTest runs a test binary that was previously built. The return
|
// runPackageTest runs a test binary that was previously built. The return
|
||||||
// values are whether the test passed and any errors encountered while trying to
|
// values are whether the test passed and any errors encountered while trying to
|
||||||
// run the binary.
|
// run the binary.
|
||||||
func runPackageTest(config *compileopts.Config, result builder.BuildResult) (bool, error) {
|
func runPackageTest(config *compileopts.Config, result builder.BuildResult, testVerbose bool) (bool, error) {
|
||||||
if len(config.Target.Emulator) == 0 {
|
if len(config.Target.Emulator) == 0 {
|
||||||
// Run directly.
|
// Run directly.
|
||||||
cmd := executeCommand(config.Options, result.Binary)
|
var flags []string
|
||||||
|
if testVerbose {
|
||||||
|
flags = append(flags, "-test.v")
|
||||||
|
}
|
||||||
|
cmd := executeCommand(config.Options, result.Binary, flags...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Dir = result.MainDir
|
cmd.Dir = result.MainDir
|
||||||
|
@ -229,6 +233,7 @@ func runPackageTest(config *compileopts.Config, result builder.BuildResult) (boo
|
||||||
return true, nil
|
return true, nil
|
||||||
} else {
|
} else {
|
||||||
// Run in an emulator.
|
// Run in an emulator.
|
||||||
|
// TODO: pass the -test.v flag if needed.
|
||||||
args := append(config.Target.Emulator[1:], result.Binary)
|
args := append(config.Target.Emulator[1:], result.Binary)
|
||||||
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
|
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
@ -1038,9 +1043,10 @@ func main() {
|
||||||
if command == "help" || command == "build" || command == "build-library" || command == "test" {
|
if command == "help" || command == "build" || command == "build-library" || command == "test" {
|
||||||
flag.StringVar(&outpath, "o", "", "output filename")
|
flag.StringVar(&outpath, "o", "", "output filename")
|
||||||
}
|
}
|
||||||
var testCompileOnlyFlag *bool
|
var testCompileOnlyFlag, testVerboseFlag *bool
|
||||||
if command == "help" || command == "test" {
|
if command == "help" || command == "test" {
|
||||||
testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it")
|
testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it")
|
||||||
|
testVerboseFlag = flag.Bool("v", false, "verbose: print additional output")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Early command processing, before commands are interpreted by the Go flag
|
// Early command processing, before commands are interpreted by the Go flag
|
||||||
|
@ -1201,7 +1207,7 @@ func main() {
|
||||||
allTestsPassed := true
|
allTestsPassed := true
|
||||||
for _, pkgName := range pkgNames {
|
for _, pkgName := range pkgNames {
|
||||||
// TODO: parallelize building the test binaries
|
// TODO: parallelize building the test binaries
|
||||||
passed, err := Test(pkgName, options, *testCompileOnlyFlag, outpath)
|
passed, err := Test(pkgName, options, *testCompileOnlyFlag, *testVerboseFlag, outpath)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
if !passed {
|
if !passed {
|
||||||
allTestsPassed = false
|
allTestsPassed = false
|
||||||
|
|
|
@ -51,6 +51,7 @@ func TestCompiler(t *testing.T) {
|
||||||
"stdlib.go",
|
"stdlib.go",
|
||||||
"string.go",
|
"string.go",
|
||||||
"structs.go",
|
"structs.go",
|
||||||
|
"testing.go",
|
||||||
"zeroalloc.go",
|
"zeroalloc.go",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,34 @@ package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Testing flags.
|
||||||
|
var (
|
||||||
|
flagVerbose bool
|
||||||
|
)
|
||||||
|
|
||||||
|
var initRan bool
|
||||||
|
|
||||||
|
// Init registers testing flags. It has no effect if it has already run.
|
||||||
|
func Init() {
|
||||||
|
if initRan {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
initRan = true
|
||||||
|
|
||||||
|
flag.BoolVar(&flagVerbose, "test.v", false, "verbose: print additional output")
|
||||||
|
}
|
||||||
|
|
||||||
// common holds the elements common between T and B and
|
// common holds the elements common between T and B and
|
||||||
// captures common methods such as Errorf.
|
// captures common methods such as Errorf.
|
||||||
type common struct {
|
type common struct {
|
||||||
output io.Writer
|
output bytes.Buffer
|
||||||
|
indent string
|
||||||
|
|
||||||
failed bool // Test or benchmark has failed.
|
failed bool // Test or benchmark has failed.
|
||||||
skipped bool // Test of benchmark has been skipped.
|
skipped bool // Test of benchmark has been skipped.
|
||||||
|
@ -53,7 +72,6 @@ var _ TB = (*B)(nil)
|
||||||
//
|
//
|
||||||
type T struct {
|
type T struct {
|
||||||
common
|
common
|
||||||
indent string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the running test or benchmark.
|
// Name returns the name of the running test or benchmark.
|
||||||
|
@ -85,8 +103,22 @@ func (c *common) FailNow() {
|
||||||
// log generates the output.
|
// log generates the output.
|
||||||
func (c *common) log(s string) {
|
func (c *common) log(s string) {
|
||||||
// This doesn't print the same as in upstream go, but works for now.
|
// This doesn't print the same as in upstream go, but works for now.
|
||||||
fmt.Fprintf(c.output, "\t")
|
if len(s) != 0 && s[len(s)-1] == '\n' {
|
||||||
fmt.Fprintln(c.output, s)
|
s = s[:len(s)-1]
|
||||||
|
}
|
||||||
|
lines := strings.Split(s, "\n")
|
||||||
|
// First line.
|
||||||
|
c.output.WriteString(c.indent)
|
||||||
|
c.output.WriteString(" ") // 4 spaces
|
||||||
|
c.output.WriteString(lines[0])
|
||||||
|
c.output.WriteByte('\n')
|
||||||
|
// More lines.
|
||||||
|
for _, line := range lines[1:] {
|
||||||
|
c.output.WriteString(c.indent)
|
||||||
|
c.output.WriteString(" ") // 8 spaces
|
||||||
|
c.output.WriteString(line)
|
||||||
|
c.output.WriteByte('\n')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log formats its arguments using default formatting, analogous to Println,
|
// Log formats its arguments using default formatting, analogous to Println,
|
||||||
|
@ -165,25 +197,30 @@ func (c *common) Helper() {
|
||||||
func (t *T) Run(name string, f func(t *T)) bool {
|
func (t *T) Run(name string, f func(t *T)) bool {
|
||||||
// Create a subtest.
|
// Create a subtest.
|
||||||
sub := T{
|
sub := T{
|
||||||
indent: t.indent + " ",
|
|
||||||
common: common{
|
common: common{
|
||||||
name: t.name + "/" + name,
|
name: t.name + "/" + name,
|
||||||
output: &bytes.Buffer{},
|
indent: t.indent + " ",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the test.
|
// Run the test.
|
||||||
fmt.Printf("=== RUN %s\n", sub.name)
|
if flagVerbose {
|
||||||
|
fmt.Fprintf(&t.output, "=== RUN %s\n", sub.name)
|
||||||
|
|
||||||
|
}
|
||||||
f(&sub)
|
f(&sub)
|
||||||
|
|
||||||
// Process the result (pass or fail).
|
// Process the result (pass or fail).
|
||||||
if sub.failed {
|
if sub.failed {
|
||||||
t.failed = true
|
t.failed = true
|
||||||
fmt.Printf(sub.indent+"--- FAIL: %s\n", sub.name)
|
fmt.Fprintf(&t.output, sub.indent+"--- FAIL: %s\n", sub.name)
|
||||||
|
t.output.Write(sub.output.Bytes())
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(sub.indent+"--- PASS: %s\n", sub.name)
|
if flagVerbose {
|
||||||
|
fmt.Fprintf(&t.output, sub.indent+"--- PASS: %s\n", sub.name)
|
||||||
|
t.output.Write(sub.output.Bytes())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Print(sub.output)
|
|
||||||
return !sub.failed
|
return !sub.failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,24 +242,32 @@ func (m *M) Run() int {
|
||||||
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
|
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !flag.Parsed() {
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
failures := 0
|
failures := 0
|
||||||
for _, test := range m.Tests {
|
for _, test := range m.Tests {
|
||||||
t := &T{
|
t := &T{
|
||||||
common: common{
|
common: common{
|
||||||
name: test.Name,
|
name: test.Name,
|
||||||
output: &bytes.Buffer{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("=== RUN %s\n", test.Name)
|
if flagVerbose {
|
||||||
|
fmt.Printf("=== RUN %s\n", test.Name)
|
||||||
|
}
|
||||||
test.F(t)
|
test.F(t)
|
||||||
|
|
||||||
if t.failed {
|
if t.failed {
|
||||||
fmt.Printf("--- FAIL: %s\n", test.Name)
|
fmt.Printf("--- FAIL: %s\n", test.Name)
|
||||||
|
os.Stdout.Write(t.output.Bytes())
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("--- PASS: %s\n", test.Name)
|
if flagVerbose {
|
||||||
|
fmt.Printf("--- PASS: %s\n", test.Name)
|
||||||
|
os.Stdout.Write(t.output.Bytes())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Print(t.output)
|
|
||||||
|
|
||||||
if t.failed {
|
if t.failed {
|
||||||
failures++
|
failures++
|
||||||
|
@ -242,6 +287,7 @@ func TestMain(m *M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
||||||
|
Init()
|
||||||
return &M{
|
return &M{
|
||||||
Tests: tests,
|
Tests: tests,
|
||||||
}
|
}
|
||||||
|
|
42
testdata/testing.go
предоставленный
Обычный файл
42
testdata/testing.go
предоставленный
Обычный файл
|
@ -0,0 +1,42 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// TODO: also test the verbose version.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFoo(t *testing.T) {
|
||||||
|
t.Log("log Foo.a")
|
||||||
|
t.Log("log Foo.b")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBar(t *testing.T) {
|
||||||
|
t.Log("log Bar")
|
||||||
|
t.Log("log g\nh\ni\n")
|
||||||
|
t.Run("Bar1", func(t *testing.T) {})
|
||||||
|
t.Run("Bar2", func(t *testing.T) {
|
||||||
|
t.Log("log Bar2\na\nb\nc")
|
||||||
|
t.Error("failed")
|
||||||
|
t.Log("after failed")
|
||||||
|
})
|
||||||
|
t.Run("Bar3", func(t *testing.T) {})
|
||||||
|
t.Log("log Bar end")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []testing.InternalTest{
|
||||||
|
{"TestFoo", TestFoo},
|
||||||
|
{"TestBar", TestBar},
|
||||||
|
}
|
||||||
|
|
||||||
|
var benchmarks = []testing.InternalBenchmark{}
|
||||||
|
|
||||||
|
var examples = []testing.InternalExample{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
m := testing.MainStart(nil, tests, benchmarks, examples)
|
||||||
|
exitcode := m.Run()
|
||||||
|
if exitcode != 0 {
|
||||||
|
println("exitcode:", exitcode)
|
||||||
|
}
|
||||||
|
}
|
16
testdata/testing.txt
предоставленный
Обычный файл
16
testdata/testing.txt
предоставленный
Обычный файл
|
@ -0,0 +1,16 @@
|
||||||
|
--- FAIL: TestBar
|
||||||
|
log Bar
|
||||||
|
log g
|
||||||
|
h
|
||||||
|
i
|
||||||
|
|
||||||
|
--- FAIL: TestBar/Bar2
|
||||||
|
log Bar2
|
||||||
|
a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
failed
|
||||||
|
after failed
|
||||||
|
log Bar end
|
||||||
|
FAIL
|
||||||
|
exitcode: 1
|
Загрузка…
Создание таблицы
Сослаться в новой задаче