
This interpreter currently complements the Go SSA level interpreter. It may stay complementary or may be the only interpreter in the future. This interpreter is experimental and not yet finished (there are known bugs!) so it is disabled by default. It can be enabled by passing the -initinterp flag. The goal is to be able to run all initializations at compile time except for the ones having side effects. This mostly works except perhaps for a few edge cases. In the future, this interpeter may be used to actually run regular Go code, perhaps in a shell.
127 строки
2,8 КиБ
Go
127 строки
2,8 КиБ
Go
package main
|
|
|
|
// This file tests the compiler by running Go files in testdata/*.go and
|
|
// comparing their output with the expected output in testdata/*.txt.
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
const TESTDATA = "testdata"
|
|
|
|
func TestCompiler(t *testing.T) {
|
|
matches, err := filepath.Glob(TESTDATA + "/*.go")
|
|
if err != nil {
|
|
t.Fatal("could not read test files:", err)
|
|
}
|
|
if len(matches) == 0 {
|
|
t.Fatal("no test files found")
|
|
}
|
|
|
|
// Create a temporary directory for test output files.
|
|
tmpdir, err := ioutil.TempDir("", "tinygo-test")
|
|
if err != nil {
|
|
t.Fatal("could not create temporary directory:", err)
|
|
}
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
t.Log("running tests on the host...")
|
|
for _, path := range matches {
|
|
t.Run(path, func(t *testing.T) {
|
|
runTest(path, tmpdir, "", t)
|
|
})
|
|
}
|
|
|
|
t.Log("running tests on the qemu target...")
|
|
for _, path := range matches {
|
|
t.Run(path, func(t *testing.T) {
|
|
runTest(path, tmpdir, "qemu", t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func runTest(path, tmpdir string, target string, t *testing.T) {
|
|
// Get the expected output for this test.
|
|
txtpath := path[:len(path)-3] + ".txt"
|
|
f, err := os.Open(txtpath)
|
|
if err != nil {
|
|
t.Fatal("could not open expected output file:", err)
|
|
}
|
|
expected, err := ioutil.ReadAll(f)
|
|
if err != nil {
|
|
t.Fatal("could not read expected output file:", err)
|
|
}
|
|
|
|
// Build the test binary.
|
|
config := &BuildConfig{
|
|
opt: "z",
|
|
printIR: false,
|
|
dumpSSA: false,
|
|
debug: false,
|
|
printSizes: "",
|
|
initInterp: false,
|
|
}
|
|
binary := filepath.Join(tmpdir, "test")
|
|
err = Build(path, binary, target, config)
|
|
if err != nil {
|
|
t.Log("failed to build:", err)
|
|
t.Fail()
|
|
return
|
|
}
|
|
|
|
// Run the test.
|
|
var cmd *exec.Cmd
|
|
if target == "" {
|
|
cmd = exec.Command(binary)
|
|
} else {
|
|
spec, err := LoadTarget(target)
|
|
if err != nil {
|
|
t.Fatal("failed to load target spec:", err)
|
|
}
|
|
if len(spec.Emulator) == 0 {
|
|
t.Fatal("no emulator available for target:", target)
|
|
}
|
|
args := append(spec.Emulator[1:], binary)
|
|
cmd = exec.Command(spec.Emulator[0], args...)
|
|
}
|
|
stdout := &bytes.Buffer{}
|
|
cmd.Stdout = stdout
|
|
if target != "" {
|
|
cmd.Stderr = os.Stderr
|
|
}
|
|
err = cmd.Run()
|
|
if _, ok := err.(*exec.ExitError); ok && target != "" {
|
|
err = nil // workaround for QEMU
|
|
}
|
|
|
|
// putchar() prints CRLF, convert it to LF.
|
|
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
|
|
|
|
// Check whether the command ran successfully.
|
|
fail := false
|
|
if err != nil {
|
|
t.Log("failed to run:", err)
|
|
fail = true
|
|
} else if !bytes.Equal(expected, actual) {
|
|
t.Log("output did not match")
|
|
fail = true
|
|
}
|
|
|
|
if fail {
|
|
r := bufio.NewReader(bytes.NewReader(actual))
|
|
for {
|
|
line, err := r.ReadString('\n')
|
|
if err != nil {
|
|
break
|
|
}
|
|
t.Log("stdout:", line[:len(line)-1])
|
|
}
|
|
t.Fail()
|
|
}
|
|
}
|