tinygo: support -run for tests

Fixes #2294
Этот коммит содержится в:
Damian Gryski 2021-11-19 14:14:21 -08:00 коммит произвёл Ron Evans
родитель 18242bc26a
коммит a536ddcda8
3 изменённых файлов: 52 добавлений и 10 удалений

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

@ -177,7 +177,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, testVerbose, testShort bool, outpath string) (bool, error) { func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVerbose, testShort bool, testRunRegexp string, 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 {
@ -203,7 +203,7 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVer
// Run the test. // Run the test.
start := time.Now() start := time.Now()
var err error var err error
passed, err = runPackageTest(config, result, testVerbose, testShort) passed, err = runPackageTest(config, result, testVerbose, testShort, testRunRegexp)
if err != nil { if err != nil {
return err return err
} }
@ -229,7 +229,7 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly, testVer
// 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, testVerbose, testShort bool) (bool, error) { func runPackageTest(config *compileopts.Config, result builder.BuildResult, testVerbose, testShort bool, testRunRegexp string) (bool, error) {
var cmd *exec.Cmd var cmd *exec.Cmd
if len(config.Target.Emulator) == 0 { if len(config.Target.Emulator) == 0 {
// Run directly. // Run directly.
@ -240,6 +240,9 @@ func runPackageTest(config *compileopts.Config, result builder.BuildResult, test
if testShort { if testShort {
flags = append(flags, "-test.short") flags = append(flags, "-test.short")
} }
if testRunRegexp != "" {
flags = append(flags, "-test.run="+testRunRegexp)
}
cmd = executeCommand(config.Options, result.Binary, flags...) cmd = executeCommand(config.Options, result.Binary, flags...)
cmd.Dir = result.MainDir cmd.Dir = result.MainDir
} else { } else {
@ -255,6 +258,9 @@ func runPackageTest(config *compileopts.Config, result builder.BuildResult, test
if testShort { if testShort {
args = append(args, "-test.short") args = append(args, "-test.short")
} }
if testRunRegexp != "" {
args = append(args, "-test.run="+testRunRegexp)
}
} }
cmd = executeCommand(config.Options, config.Target.Emulator[0], args...) cmd = executeCommand(config.Options, config.Target.Emulator[0], args...)
} }
@ -1150,10 +1156,12 @@ func main() {
flag.StringVar(&outpath, "o", "", "output filename") flag.StringVar(&outpath, "o", "", "output filename")
} }
var testCompileOnlyFlag, testVerboseFlag, testShortFlag *bool var testCompileOnlyFlag, testVerboseFlag, testShortFlag *bool
var testRunRegexp *string
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") testVerboseFlag = flag.Bool("v", false, "verbose: print additional output")
testShortFlag = flag.Bool("short", false, "short: run smaller test suite to save time") testShortFlag = flag.Bool("short", false, "short: run smaller test suite to save time")
testRunRegexp = flag.String("run", "", "run: regexp of tests to run")
} }
// Early command processing, before commands are interpreted by the Go flag // Early command processing, before commands are interpreted by the Go flag
@ -1336,7 +1344,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, *testVerboseFlag, *testShortFlag, outpath) passed, err := Test(pkgName, options, *testCompileOnlyFlag, *testVerboseFlag, *testShortFlag, *testRunRegexp, outpath)
handleCompilerError(err) handleCompilerError(err)
if !passed { if !passed {
allTestsPassed = false allTestsPassed = false

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

@ -18,8 +18,9 @@ import (
// Testing flags. // Testing flags.
var ( var (
flagVerbose bool flagVerbose bool
flagShort bool flagShort bool
flagRunRegexp string
) )
var initRan bool var initRan bool
@ -33,6 +34,7 @@ func Init() {
flag.BoolVar(&flagVerbose, "test.v", false, "verbose: print additional output") flag.BoolVar(&flagVerbose, "test.v", false, "verbose: print additional output")
flag.BoolVar(&flagShort, "test.short", false, "short: run smaller test suite to save time") flag.BoolVar(&flagShort, "test.short", false, "short: run smaller test suite to save time")
flag.StringVar(&flagRunRegexp, "test.run", "", "run: regexp of tests to run")
} }
// common holds the elements common between T and B and // common holds the elements common between T and B and
@ -242,19 +244,42 @@ type InternalTest struct {
type M struct { type M struct {
// tests is a list of the test names to execute // tests is a list of the test names to execute
Tests []InternalTest Tests []InternalTest
deps testDeps
} }
// Run the test suite. // Run the test suite.
func (m *M) Run() int { func (m *M) Run() int {
if len(m.Tests) == 0 {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}
if !flag.Parsed() { if !flag.Parsed() {
flag.Parse() flag.Parse()
} }
failures := 0 failures := 0
if flagRunRegexp != "" {
var filtered []InternalTest
// pre-test the regexp; we don't want to bother logging one failure for every test name if the regexp is broken
if _, err := m.deps.MatchString(flagRunRegexp, "some-test-name"); err != nil {
fmt.Println("testing: invalid regexp for -test.run:", err.Error())
failures++
}
// filter the list of tests before we try to run them
for _, test := range m.Tests {
// ignore the error; we already tested that the regexp compiles fine above
if match, _ := m.deps.MatchString(flagRunRegexp, test.Name); match {
filtered = append(filtered, test)
}
}
m.Tests = filtered
}
if len(m.Tests) == 0 {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}
for _, test := range m.Tests { for _, test := range m.Tests {
t := &T{ t := &T{
common: common{ common: common{
@ -326,10 +351,15 @@ func TestMain(m *M) {
os.Exit(m.Run()) os.Exit(m.Run())
} }
type testDeps interface {
MatchString(pat, s string) (bool, error)
}
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M { func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
Init() Init()
return &M{ return &M{
Tests: tests, Tests: tests,
deps: deps.(testDeps),
} }
} }

6
testdata/testing.go предоставленный
Просмотреть файл

@ -34,9 +34,13 @@ var benchmarks = []testing.InternalBenchmark{}
var examples = []testing.InternalExample{} var examples = []testing.InternalExample{}
func main() { func main() {
m := testing.MainStart(nil, tests, benchmarks, examples) m := testing.MainStart(testdeps{}, tests, benchmarks, examples)
exitcode := m.Run() exitcode := m.Run()
if exitcode != 0 { if exitcode != 0 {
println("exitcode:", exitcode) println("exitcode:", exitcode)
} }
} }
type testdeps struct{}
func (testdeps) MatchString(pat, str string) (bool, error) { return true, nil }