main (test): add tests to tinygo test
Этот коммит содержится в:
родитель
21b89ef327
коммит
d86dd642b3
6 изменённых файлов: 234 добавлений и 46 удалений
242
main_test.go
242
main_test.go
|
@ -9,12 +9,14 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -27,7 +29,11 @@ const TESTDATA = "testdata"
|
||||||
|
|
||||||
var testTarget = flag.String("target", "", "override test target")
|
var testTarget = flag.String("target", "", "override test target")
|
||||||
|
|
||||||
func TestCompiler(t *testing.T) {
|
var sema = make(chan struct{}, runtime.NumCPU())
|
||||||
|
|
||||||
|
func TestBuild(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
tests := []string{
|
tests := []string{
|
||||||
"alias.go",
|
"alias.go",
|
||||||
"atomic.go",
|
"atomic.go",
|
||||||
|
@ -62,8 +68,6 @@ func TestCompiler(t *testing.T) {
|
||||||
tests = append(tests, "go1.17.go")
|
tests = append(tests, "go1.17.go")
|
||||||
}
|
}
|
||||||
|
|
||||||
sema := make(chan struct{}, runtime.NumCPU())
|
|
||||||
|
|
||||||
if *testTarget != "" {
|
if *testTarget != "" {
|
||||||
// This makes it possible to run one specific test (instead of all),
|
// This makes it possible to run one specific test (instead of all),
|
||||||
// which is especially useful to quickly check whether some changes
|
// which is especially useful to quickly check whether some changes
|
||||||
|
@ -84,41 +88,29 @@ func TestCompiler(t *testing.T) {
|
||||||
// Test with few optimizations enabled (no inlining, etc).
|
// Test with few optimizations enabled (no inlining, etc).
|
||||||
t.Run("opt=1", func(t *testing.T) {
|
t.Run("opt=1", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTestWithConfig("stdlib.go", t, compileopts.Options{
|
opts := optionsFromTarget("", sema)
|
||||||
GOOS: goenv.Get("GOOS"),
|
opts.Opt = "1"
|
||||||
GOARCH: goenv.Get("GOARCH"),
|
runTestWithConfig("stdlib.go", t, opts, nil, nil)
|
||||||
GOARM: goenv.Get("GOARM"),
|
|
||||||
Opt: "1",
|
|
||||||
Semaphore: sema,
|
|
||||||
}, nil, nil)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with only the bare minimum of optimizations enabled.
|
// Test with only the bare minimum of optimizations enabled.
|
||||||
// TODO: fix this for stdlib.go, which currently fails.
|
// TODO: fix this for stdlib.go, which currently fails.
|
||||||
t.Run("opt=0", func(t *testing.T) {
|
t.Run("opt=0", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTestWithConfig("print.go", t, compileopts.Options{
|
opts := optionsFromTarget("", sema)
|
||||||
GOOS: goenv.Get("GOOS"),
|
opts.Opt = "0"
|
||||||
GOARCH: goenv.Get("GOARCH"),
|
runTestWithConfig("print.go", t, opts, nil, nil)
|
||||||
GOARM: goenv.Get("GOARM"),
|
|
||||||
Opt: "0",
|
|
||||||
Semaphore: sema,
|
|
||||||
}, nil, nil)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ldflags", func(t *testing.T) {
|
t.Run("ldflags", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTestWithConfig("ldflags.go", t, compileopts.Options{
|
opts := optionsFromTarget("", sema)
|
||||||
GOOS: goenv.Get("GOOS"),
|
opts.GlobalValues = map[string]map[string]string{
|
||||||
GOARCH: goenv.Get("GOARCH"),
|
"main": {
|
||||||
GOARM: goenv.Get("GOARM"),
|
"someGlobal": "foobar",
|
||||||
GlobalValues: map[string]map[string]string{
|
|
||||||
"main": {
|
|
||||||
"someGlobal": "foobar",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Semaphore: sema,
|
}
|
||||||
}, nil, nil)
|
runTestWithConfig("ldflags.go", t, opts, nil, nil)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -211,22 +203,12 @@ func TestCompiler(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||||
// Check if the emulator is installed.
|
emuCheck(t, options)
|
||||||
|
|
||||||
spec, err := compileopts.LoadTarget(&options)
|
spec, err := compileopts.LoadTarget(&options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("failed to load target spec:", err)
|
t.Fatal("failed to load target spec:", err)
|
||||||
}
|
}
|
||||||
if len(spec.Emulator) != 0 {
|
|
||||||
_, err := exec.LookPath(spec.Emulator[0])
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, exec.ErrNotFound) {
|
|
||||||
t.Skipf("emulator not installed: %q", spec.Emulator[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Errorf("searching for emulator: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, name := range tests {
|
for _, name := range tests {
|
||||||
name := name // redefine to avoid race condition
|
name := name // redefine to avoid race condition
|
||||||
|
@ -263,6 +245,25 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func emuCheck(t *testing.T, options compileopts.Options) {
|
||||||
|
// Check if the emulator is installed.
|
||||||
|
spec, err := compileopts.LoadTarget(&options)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("failed to load target spec:", err)
|
||||||
|
}
|
||||||
|
if len(spec.Emulator) != 0 {
|
||||||
|
_, err := exec.LookPath(spec.Emulator[0])
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, exec.ErrNotFound) {
|
||||||
|
t.Skipf("emulator not installed: %q", spec.Emulator[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Errorf("searching for emulator: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
||||||
return compileopts.Options{
|
return compileopts.Options{
|
||||||
// GOOS/GOARCH are only used if target == ""
|
// GOOS/GOARCH are only used if target == ""
|
||||||
|
@ -271,6 +272,9 @@ func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
||||||
GOARM: goenv.Get("GOARM"),
|
GOARM: goenv.Get("GOARM"),
|
||||||
Target: target,
|
Target: target,
|
||||||
Semaphore: sema,
|
Semaphore: sema,
|
||||||
|
Debug: true,
|
||||||
|
VerifyIR: true,
|
||||||
|
Opt: "z",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +287,9 @@ func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
|
||||||
GOOS: parts[0],
|
GOOS: parts[0],
|
||||||
GOARCH: parts[1],
|
GOARCH: parts[1],
|
||||||
Semaphore: sema,
|
Semaphore: sema,
|
||||||
|
Debug: true,
|
||||||
|
VerifyIR: true,
|
||||||
|
Opt: "z",
|
||||||
}
|
}
|
||||||
if options.GOARCH == "arm" {
|
if options.GOARCH == "arm" {
|
||||||
options.GOARM = parts[2]
|
options.GOARM = parts[2]
|
||||||
|
@ -295,13 +302,6 @@ func runTest(name string, options compileopts.Options, t *testing.T, cmdArgs, en
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
|
func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
|
||||||
// Set default config.
|
|
||||||
options.Debug = true
|
|
||||||
options.VerifyIR = true
|
|
||||||
if options.Opt == "" {
|
|
||||||
options.Opt = "z"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the expected output for this test.
|
// Get the expected output for this test.
|
||||||
// Note: not using filepath.Join as it strips the path separator at the end
|
// Note: not using filepath.Join as it strips the path separator at the end
|
||||||
// of the path.
|
// of the path.
|
||||||
|
@ -466,6 +466,156 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTest(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type targ struct {
|
||||||
|
name string
|
||||||
|
opts compileopts.Options
|
||||||
|
}
|
||||||
|
targs := []targ{
|
||||||
|
// Host
|
||||||
|
{"Host", optionsFromTarget("", sema)},
|
||||||
|
}
|
||||||
|
if !testing.Short() {
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
targs = append(targs,
|
||||||
|
// Linux
|
||||||
|
targ{"X86Linux", optionsFromOSARCH("linux/386", sema)},
|
||||||
|
targ{"ARMLinux", optionsFromOSARCH("linux/arm/6", sema)},
|
||||||
|
targ{"ARM64Linux", optionsFromOSARCH("linux/arm64", sema)},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
targs = append(targs,
|
||||||
|
// QEMU microcontrollers
|
||||||
|
targ{"EmulatedCortexM3", optionsFromTarget("cortex-m-qemu", sema)},
|
||||||
|
targ{"EmulatedRISCV", optionsFromTarget("riscv-qemu", sema)},
|
||||||
|
|
||||||
|
// Node/Wasmtime
|
||||||
|
targ{"WASM", optionsFromTarget("wasm", sema)},
|
||||||
|
targ{"WASI", optionsFromTarget("wasi", sema)},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for _, targ := range targs {
|
||||||
|
targ := targ
|
||||||
|
t.Run(targ.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
emuCheck(t, targ.opts)
|
||||||
|
|
||||||
|
t.Run("Pass", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Test a package which builds and passes normally.
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
|
out := ioLogger(t, &wg)
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
opts := targ.opts
|
||||||
|
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, false, false, false, "", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("test error: %v", err)
|
||||||
|
}
|
||||||
|
if !passed {
|
||||||
|
t.Error("test failed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Fail", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Test a package which builds fine but fails.
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
|
out := ioLogger(t, &wg)
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
opts := targ.opts
|
||||||
|
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, false, false, false, "", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("test error: %v", err)
|
||||||
|
}
|
||||||
|
if passed {
|
||||||
|
t.Error("test passed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if targ.name != "Host" {
|
||||||
|
// Emulated tests are somewhat slow, and these do not need to be run across every platform.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Nothing", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Test a package with no test files.
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
|
out := ioLogger(t, &wg)
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
var output bytes.Buffer
|
||||||
|
opts := targ.opts
|
||||||
|
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, false, false, false, "", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("test error: %v", err)
|
||||||
|
}
|
||||||
|
if !passed {
|
||||||
|
t.Error("test failed")
|
||||||
|
}
|
||||||
|
if !strings.Contains(output.String(), "[no test files]") {
|
||||||
|
t.Error("missing [no test files] in output")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("BuildErr", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Test a package which fails to build.
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
|
out := ioLogger(t, &wg)
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
opts := targ.opts
|
||||||
|
passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, false, false, false, "", "")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("test did not error")
|
||||||
|
}
|
||||||
|
if passed {
|
||||||
|
t.Error("test passed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioLogger(t *testing.T, wg *sync.WaitGroup) io.WriteCloser {
|
||||||
|
r, w := io.Pipe()
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
for scanner.Scan() {
|
||||||
|
t.Log(scanner.Text())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
// This TestMain is necessary because TinyGo may also be invoked to run certain
|
// This TestMain is necessary because TinyGo may also be invoked to run certain
|
||||||
// LLVM tools in a separate process. Not capturing these invocations would lead
|
// LLVM tools in a separate process. Not capturing these invocations would lead
|
||||||
// to recursive tests.
|
// to recursive tests.
|
||||||
|
|
10
tests/testing/builderr/builderr.go
Обычный файл
10
tests/testing/builderr/builderr.go
Обычный файл
|
@ -0,0 +1,10 @@
|
||||||
|
package builderr
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname x notARealFunction
|
||||||
|
func x()
|
||||||
|
|
||||||
|
func Thing() {
|
||||||
|
x()
|
||||||
|
}
|
11
tests/testing/builderr/builderr_test.go
Обычный файл
11
tests/testing/builderr/builderr_test.go
Обычный файл
|
@ -0,0 +1,11 @@
|
||||||
|
package builderr_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinygo/tests/testing/builderr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestThing(t *testing.T) {
|
||||||
|
builderr.Thing()
|
||||||
|
}
|
7
tests/testing/fail/fail_test.go
Обычный файл
7
tests/testing/fail/fail_test.go
Обычный файл
|
@ -0,0 +1,7 @@
|
||||||
|
package fail_test
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestFail(t *testing.T) {
|
||||||
|
t.Error("fail")
|
||||||
|
}
|
3
tests/testing/nothing/nothing.go
Обычный файл
3
tests/testing/nothing/nothing.go
Обычный файл
|
@ -0,0 +1,3 @@
|
||||||
|
package nothing
|
||||||
|
|
||||||
|
// This package has no tests.
|
7
tests/testing/pass/pass_test.go
Обычный файл
7
tests/testing/pass/pass_test.go
Обычный файл
|
@ -0,0 +1,7 @@
|
||||||
|
package pass_test
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestPass(t *testing.T) {
|
||||||
|
// This test passes.
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче