родитель
a3d1f1a514
коммит
208e1719ad
9 изменённых файлов: 288 добавлений и 13 удалений
4
Makefile
4
Makefile
|
@ -38,6 +38,7 @@ fmt:
|
||||||
fmt-check:
|
fmt-check:
|
||||||
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
||||||
|
|
||||||
|
|
||||||
gen-device: gen-device-avr gen-device-nrf gen-device-sam gen-device-stm32
|
gen-device: gen-device-avr gen-device-nrf gen-device-sam gen-device-stm32
|
||||||
|
|
||||||
gen-device-avr:
|
gen-device-avr:
|
||||||
|
@ -85,6 +86,9 @@ build/tinygo:
|
||||||
test:
|
test:
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go test -v -tags byollvm .
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go test -v -tags byollvm .
|
||||||
|
|
||||||
|
tinygo-test:
|
||||||
|
cd tests/tinygotest && tinygo test
|
||||||
|
|
||||||
.PHONY: smoketest smoketest-no-avr
|
.PHONY: smoketest smoketest-no-avr
|
||||||
smoketest: smoketest-no-avr
|
smoketest: smoketest-no-avr
|
||||||
tinygo build -size short -o test.elf -target=arduino examples/blinky1
|
tinygo build -size short -o test.elf -target=arduino examples/blinky1
|
||||||
|
|
|
@ -48,6 +48,12 @@ type Config struct {
|
||||||
TINYGOROOT string // GOROOT for TinyGo
|
TINYGOROOT string // GOROOT for TinyGo
|
||||||
GOPATH string // GOPATH, like `go env GOPATH`
|
GOPATH string // GOPATH, like `go env GOPATH`
|
||||||
BuildTags []string // build tags for TinyGo (empty means {Config.GOOS/Config.GOARCH})
|
BuildTags []string // build tags for TinyGo (empty means {Config.GOOS/Config.GOARCH})
|
||||||
|
TestConfig TestConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestConfig struct {
|
||||||
|
CompileTestBinary bool
|
||||||
|
// TODO: Filter the test functions to run, include verbose flag, etc
|
||||||
}
|
}
|
||||||
|
|
||||||
type Compiler struct {
|
type Compiler struct {
|
||||||
|
@ -214,7 +220,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
path = path[len(tinygoPath+"/src/"):]
|
path = path[len(tinygoPath+"/src/"):]
|
||||||
}
|
}
|
||||||
switch path {
|
switch path {
|
||||||
case "machine", "os", "reflect", "runtime", "runtime/volatile", "sync":
|
case "machine", "os", "reflect", "runtime", "runtime/volatile", "sync", "testing":
|
||||||
return path
|
return path
|
||||||
default:
|
default:
|
||||||
if strings.HasPrefix(path, "device/") || strings.HasPrefix(path, "examples/") {
|
if strings.HasPrefix(path, "device/") || strings.HasPrefix(path, "examples/") {
|
||||||
|
@ -241,6 +247,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
CFlags: c.CFlags,
|
CFlags: c.CFlags,
|
||||||
ClangHeaders: c.ClangHeaders,
|
ClangHeaders: c.ClangHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(mainPath, ".go") {
|
if strings.HasSuffix(mainPath, ".go") {
|
||||||
_, err = lprogram.ImportFile(mainPath)
|
_, err = lprogram.ImportFile(mainPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -252,12 +259,13 @@ func (c *Compiler) Compile(mainPath string) []error {
|
||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = lprogram.Import("runtime", "")
|
_, err = lprogram.Import("runtime", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lprogram.Parse()
|
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
|
|
137
loader/loader.go
137
loader/loader.go
|
@ -1,6 +1,7 @@
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
@ -10,12 +11,15 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/cgo"
|
"github.com/tinygo-org/tinygo/cgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Program holds all packages and some metadata about the program as a whole.
|
// Program holds all packages and some metadata about the program as a whole.
|
||||||
type Program struct {
|
type Program struct {
|
||||||
|
mainPkg string
|
||||||
Build *build.Context
|
Build *build.Context
|
||||||
OverlayBuild *build.Context
|
OverlayBuild *build.Context
|
||||||
OverlayPath func(path string) string
|
OverlayPath func(path string) string
|
||||||
|
@ -64,6 +68,11 @@ func (p *Program) Import(path, srcDir string) (*Package, error) {
|
||||||
p.sorted = nil // invalidate the sorted order of packages
|
p.sorted = nil // invalidate the sorted order of packages
|
||||||
pkg := p.newPackage(buildPkg)
|
pkg := p.newPackage(buildPkg)
|
||||||
p.Packages[buildPkg.ImportPath] = pkg
|
p.Packages[buildPkg.ImportPath] = pkg
|
||||||
|
|
||||||
|
if p.mainPkg == "" {
|
||||||
|
p.mainPkg = buildPkg.ImportPath
|
||||||
|
}
|
||||||
|
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +102,11 @@ func (p *Program) ImportFile(path string) (*Package, error) {
|
||||||
p.sorted = nil // invalidate the sorted order of packages
|
p.sorted = nil // invalidate the sorted order of packages
|
||||||
pkg := p.newPackage(buildPkg)
|
pkg := p.newPackage(buildPkg)
|
||||||
p.Packages[buildPkg.ImportPath] = pkg
|
p.Packages[buildPkg.ImportPath] = pkg
|
||||||
|
|
||||||
|
if p.mainPkg == "" {
|
||||||
|
p.mainPkg = buildPkg.ImportPath
|
||||||
|
}
|
||||||
|
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,10 +185,12 @@ func (p *Program) sort() {
|
||||||
// The returned error may be an Errors error, which contains a list of errors.
|
// The returned error may be an Errors error, which contains a list of errors.
|
||||||
//
|
//
|
||||||
// Idempotent.
|
// Idempotent.
|
||||||
func (p *Program) Parse() error {
|
func (p *Program) Parse(compileTestBinary bool) error {
|
||||||
|
includeTests := compileTestBinary
|
||||||
|
|
||||||
// Load all imports
|
// Load all imports
|
||||||
for _, pkg := range p.Sorted() {
|
for _, pkg := range p.Sorted() {
|
||||||
err := pkg.importRecursively()
|
err := pkg.importRecursively(includeTests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err, ok := err.(*ImportCycleError); ok {
|
if err, ok := err.(*ImportCycleError); ok {
|
||||||
if pkg.ImportPath != err.Packages[0] {
|
if pkg.ImportPath != err.Packages[0] {
|
||||||
|
@ -187,7 +203,14 @@ func (p *Program) Parse() error {
|
||||||
|
|
||||||
// Parse all packages.
|
// Parse all packages.
|
||||||
for _, pkg := range p.Sorted() {
|
for _, pkg := range p.Sorted() {
|
||||||
err := pkg.Parse()
|
err := pkg.Parse(includeTests)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if compileTestBinary {
|
||||||
|
err := p.SwapTestMain()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -204,6 +227,83 @@ func (p *Program) Parse() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Program) SwapTestMain() error {
|
||||||
|
var tests []string
|
||||||
|
|
||||||
|
isTestFunc := func(f *ast.FuncDecl) bool {
|
||||||
|
// TODO: improve signature check
|
||||||
|
if strings.HasPrefix(f.Name.Name, "Test") && f.Name.Name != "TestMain" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
mainPkg := p.Packages[p.mainPkg]
|
||||||
|
for _, f := range mainPkg.Files {
|
||||||
|
for i, d := range f.Decls {
|
||||||
|
switch v := d.(type) {
|
||||||
|
case *ast.FuncDecl:
|
||||||
|
if isTestFunc(v) {
|
||||||
|
tests = append(tests, v.Name.Name)
|
||||||
|
}
|
||||||
|
if v.Name.Name == "main" {
|
||||||
|
// Remove main
|
||||||
|
if len(f.Decls) == 1 {
|
||||||
|
f.Decls = make([]ast.Decl, 0)
|
||||||
|
} else {
|
||||||
|
f.Decls[i] = f.Decls[len(f.Decls)-1]
|
||||||
|
f.Decls = f.Decls[:len(f.Decls)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if they defined a TestMain and call it instead of testing.TestMain
|
||||||
|
const mainBody = `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main () {
|
||||||
|
m := &testing.M{
|
||||||
|
Tests: []testing.TestToCall{
|
||||||
|
{{range .TestFunctions}}
|
||||||
|
{Name: "{{.}}", Func: {{.}}},
|
||||||
|
{{end}}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testing.TestMain(m)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
tmpl := template.Must(template.New("testmain").Parse(mainBody))
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
tmplData := struct {
|
||||||
|
TestFunctions []string
|
||||||
|
}{
|
||||||
|
TestFunctions: tests,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := tmpl.Execute(&b, tmplData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
path := filepath.Join(p.mainPkg, "$testmain.go")
|
||||||
|
|
||||||
|
if p.fset == nil {
|
||||||
|
p.fset = token.NewFileSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
newMain, err := parser.ParseFile(p.fset, path, b.Bytes(), parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mainPkg.Files = append(mainPkg.Files, newMain)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// parseFile is a wrapper around parser.ParseFile.
|
// parseFile is a wrapper around parser.ParseFile.
|
||||||
func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
|
func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
|
||||||
if p.fset == nil {
|
if p.fset == nil {
|
||||||
|
@ -228,7 +328,7 @@ func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
|
||||||
// Parse parses and typechecks this package.
|
// Parse parses and typechecks this package.
|
||||||
//
|
//
|
||||||
// Idempotent.
|
// Idempotent.
|
||||||
func (p *Package) Parse() error {
|
func (p *Package) Parse(includeTests bool) error {
|
||||||
if len(p.Files) != 0 {
|
if len(p.Files) != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -242,7 +342,7 @@ func (p *Package) Parse() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := p.parseFiles()
|
files, err := p.parseFiles(includeTests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -281,11 +381,21 @@ func (p *Package) Check() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseFiles parses the loaded list of files and returns this list.
|
// parseFiles parses the loaded list of files and returns this list.
|
||||||
func (p *Package) parseFiles() ([]*ast.File, error) {
|
func (p *Package) parseFiles(includeTests bool) ([]*ast.File, error) {
|
||||||
// TODO: do this concurrently.
|
// TODO: do this concurrently.
|
||||||
var files []*ast.File
|
var files []*ast.File
|
||||||
var fileErrs []error
|
var fileErrs []error
|
||||||
for _, file := range p.GoFiles {
|
|
||||||
|
var gofiles []string
|
||||||
|
if includeTests {
|
||||||
|
gofiles = make([]string, 0, len(p.GoFiles)+len(p.TestGoFiles))
|
||||||
|
gofiles = append(gofiles, p.GoFiles...)
|
||||||
|
gofiles = append(gofiles, p.TestGoFiles...)
|
||||||
|
} else {
|
||||||
|
gofiles = p.GoFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range gofiles {
|
||||||
f, err := p.parseFile(filepath.Join(p.Package.Dir, file), parser.ParseComments)
|
f, err := p.parseFile(filepath.Join(p.Package.Dir, file), parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fileErrs = append(fileErrs, err)
|
fileErrs = append(fileErrs, err)
|
||||||
|
@ -320,6 +430,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||||
if len(fileErrs) != 0 {
|
if len(fileErrs) != 0 {
|
||||||
return nil, Errors{p, fileErrs}
|
return nil, Errors{p, fileErrs}
|
||||||
}
|
}
|
||||||
|
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,9 +451,15 @@ func (p *Package) Import(to string) (*types.Package, error) {
|
||||||
// importRecursively() on the imported packages as well.
|
// importRecursively() on the imported packages as well.
|
||||||
//
|
//
|
||||||
// Idempotent.
|
// Idempotent.
|
||||||
func (p *Package) importRecursively() error {
|
func (p *Package) importRecursively(includeTests bool) error {
|
||||||
p.Importing = true
|
p.Importing = true
|
||||||
for _, to := range p.Package.Imports {
|
|
||||||
|
imports := p.Package.Imports
|
||||||
|
if includeTests {
|
||||||
|
imports = append(imports, p.Package.TestImports...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, to := range imports {
|
||||||
if to == "C" {
|
if to == "C" {
|
||||||
// Do CGo processing in a later stage.
|
// Do CGo processing in a later stage.
|
||||||
continue
|
continue
|
||||||
|
@ -360,7 +477,7 @@ func (p *Package) importRecursively() error {
|
||||||
if importedPkg.Importing {
|
if importedPkg.Importing {
|
||||||
return &ImportCycleError{[]string{p.ImportPath, importedPkg.ImportPath}, p.ImportPos[to]}
|
return &ImportCycleError{[]string{p.ImportPath, importedPkg.ImportPath}, p.ImportPos[to]}
|
||||||
}
|
}
|
||||||
err = importedPkg.importRecursively()
|
err = importedPkg.importRecursively(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err, ok := err.(*ImportCycleError); ok {
|
if err, ok := err.(*ImportCycleError); ok {
|
||||||
err.Packages = append([]string{p.ImportPath}, err.Packages...)
|
err.Packages = append([]string{p.ImportPath}, err.Packages...)
|
||||||
|
|
33
main.go
33
main.go
|
@ -54,6 +54,7 @@ type BuildConfig struct {
|
||||||
cFlags []string
|
cFlags []string
|
||||||
ldFlags []string
|
ldFlags []string
|
||||||
wasmAbi string
|
wasmAbi string
|
||||||
|
testConfig compiler.TestConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for Compiler object.
|
// Helper function for Compiler object.
|
||||||
|
@ -108,6 +109,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
|
||||||
GOROOT: goroot,
|
GOROOT: goroot,
|
||||||
GOPATH: getGopath(),
|
GOPATH: getGopath(),
|
||||||
BuildTags: tags,
|
BuildTags: tags,
|
||||||
|
TestConfig: config.testConfig,
|
||||||
}
|
}
|
||||||
c, err := compiler.NewCompiler(pkgName, compilerConfig)
|
c, err := compiler.NewCompiler(pkgName, compilerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -349,6 +351,30 @@ func Build(pkgName, outpath, target string, config *BuildConfig) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test(pkgName, target string, config *BuildConfig) error {
|
||||||
|
spec, err := LoadTarget(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.BuildTags = append(spec.BuildTags, "test")
|
||||||
|
config.testConfig.CompileTestBinary = true
|
||||||
|
return Compile(pkgName, ".elf", spec, config, func(tmppath string) error {
|
||||||
|
cmd := exec.Command(tmppath)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
// Propagate the exit code
|
||||||
|
if err, ok := err.(*exec.ExitError); ok {
|
||||||
|
os.Exit(err.ExitCode())
|
||||||
|
}
|
||||||
|
return &commandError{"failed to run compiled binary", tmppath, err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func Flash(pkgName, target, port string, config *BuildConfig) error {
|
func Flash(pkgName, target, port string, config *BuildConfig) error {
|
||||||
spec, err := LoadTarget(target)
|
spec, err := LoadTarget(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -656,6 +682,13 @@ func main() {
|
||||||
}
|
}
|
||||||
err := Run(flag.Arg(0), *target, config)
|
err := Run(flag.Arg(0), *target, config)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
|
case "test":
|
||||||
|
pkgRoot := "."
|
||||||
|
if flag.NArg() == 1 {
|
||||||
|
pkgRoot = flag.Arg(0)
|
||||||
|
}
|
||||||
|
err := Test(pkgRoot, *target, config)
|
||||||
|
handleCompilerError(err)
|
||||||
case "clean":
|
case "clean":
|
||||||
// remove cache directory
|
// remove cache directory
|
||||||
dir := cacheDir()
|
dir := cacheDir()
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (v Value) Pointer() uintptr {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Value) IsValid() bool {
|
func (v Value) IsValid() bool {
|
||||||
panic("unimplemented: (reflect.Value).IsValid()")
|
return v.typecode != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Value) CanInterface() bool {
|
func (v Value) CanInterface() bool {
|
||||||
|
|
6
src/testing/doc.go
Обычный файл
6
src/testing/doc.go
Обычный файл
|
@ -0,0 +1,6 @@
|
||||||
|
package testing
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a sad stub of the upstream testing package because it doesn't compile
|
||||||
|
with tinygo right now.
|
||||||
|
*/
|
77
src/testing/testing.go
Обычный файл
77
src/testing/testing.go
Обычный файл
|
@ -0,0 +1,77 @@
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// T is a test helper.
|
||||||
|
type T struct {
|
||||||
|
name string
|
||||||
|
output io.Writer
|
||||||
|
|
||||||
|
// flags the test as having failed when non-zero
|
||||||
|
failed int
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestToCall is a reference to a test that should be called during a test suite run.
|
||||||
|
type TestToCall struct {
|
||||||
|
// Name of the test to call.
|
||||||
|
Name string
|
||||||
|
// Function reference to the test.
|
||||||
|
Func func(*T)
|
||||||
|
}
|
||||||
|
|
||||||
|
// M is a test suite.
|
||||||
|
type M struct {
|
||||||
|
// tests is a list of the test names to execute
|
||||||
|
Tests []TestToCall
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the test suite.
|
||||||
|
func (m *M) Run() int {
|
||||||
|
failures := 0
|
||||||
|
for _, test := range m.Tests {
|
||||||
|
t := &T{
|
||||||
|
name: test.Name,
|
||||||
|
output: &bytes.Buffer{},
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("=== RUN %s\n", test.Name)
|
||||||
|
test.Func(t)
|
||||||
|
|
||||||
|
if t.failed == 0 {
|
||||||
|
fmt.Printf("--- PASS: %s\n", test.Name)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("--- FAIL: %s\n", test.Name)
|
||||||
|
}
|
||||||
|
fmt.Println(t.output)
|
||||||
|
|
||||||
|
failures += t.failed
|
||||||
|
}
|
||||||
|
|
||||||
|
if failures > 0 {
|
||||||
|
fmt.Printf("exit status %d\n", failures)
|
||||||
|
fmt.Println("FAIL")
|
||||||
|
}
|
||||||
|
return failures
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *M) {
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error is equivalent to Log followed by Fail
|
||||||
|
func (t *T) Error(args ...interface{}) {
|
||||||
|
// This doesn't print the same as in upstream go, but works good enough
|
||||||
|
// TODO: buffer test output like go does
|
||||||
|
fmt.Fprintf(t.output, "\t")
|
||||||
|
fmt.Fprintln(t.output, args...)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) Fail() {
|
||||||
|
t.failed = 1
|
||||||
|
}
|
14
tests/tinygotest/main.go
Обычный файл
14
tests/tinygotest/main.go
Обычный файл
|
@ -0,0 +1,14 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
Thing()
|
||||||
|
fmt.Println("normal main")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Thing() {
|
||||||
|
fmt.Println("THING")
|
||||||
|
}
|
16
tests/tinygotest/main_test.go
Обычный файл
16
tests/tinygotest/main_test.go
Обычный файл
|
@ -0,0 +1,16 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing" // This is the tinygo testing package
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFail1(t *testing.T) {
|
||||||
|
t.Error("TestFail1 failed because of stuff and things")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFail2(t *testing.T) {
|
||||||
|
t.Error("TestFail2 failed for reasons")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPass(t *testing.T) {
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче