github.com/aykevl/tinygo@v0.5.0/main_test.go (about) 1 package main 2 3 // This file tests the compiler by running Go files in testdata/*.go and 4 // comparing their output with the expected output in testdata/*.txt. 5 6 import ( 7 "bufio" 8 "bytes" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "runtime" 14 "sort" 15 "testing" 16 ) 17 18 const TESTDATA = "testdata" 19 20 func TestCompiler(t *testing.T) { 21 matches, err := filepath.Glob(TESTDATA + "/*.go") 22 if err != nil { 23 t.Fatal("could not read test files:", err) 24 } 25 26 dirMatches, err := filepath.Glob(TESTDATA + "/*/main.go") 27 if err != nil { 28 t.Fatal("could not read test packages:", err) 29 } 30 if len(matches) == 0 || len(dirMatches) == 0 { 31 t.Fatal("no test files found") 32 } 33 for _, m := range dirMatches { 34 matches = append(matches, filepath.Dir(m)+string(filepath.Separator)) 35 } 36 37 sort.Strings(matches) 38 39 // Create a temporary directory for test output files. 40 tmpdir, err := ioutil.TempDir("", "tinygo-test") 41 if err != nil { 42 t.Fatal("could not create temporary directory:", err) 43 } 44 defer os.RemoveAll(tmpdir) 45 46 t.Log("running tests on host...") 47 for _, path := range matches { 48 t.Run(path, func(t *testing.T) { 49 runTest(path, tmpdir, "", t) 50 }) 51 } 52 53 if testing.Short() { 54 return 55 } 56 57 t.Log("running tests for emulated cortex-m3...") 58 for _, path := range matches { 59 t.Run(path, func(t *testing.T) { 60 runTest(path, tmpdir, "qemu", t) 61 }) 62 } 63 64 if runtime.GOOS == "linux" { 65 t.Log("running tests for linux/arm...") 66 for _, path := range matches { 67 if path == "testdata/cgo/" { 68 continue // TODO: improve CGo 69 } 70 t.Run(path, func(t *testing.T) { 71 runTest(path, tmpdir, "arm--linux-gnueabihf", t) 72 }) 73 } 74 75 t.Log("running tests for linux/arm64...") 76 for _, path := range matches { 77 if path == "testdata/cgo/" { 78 continue // TODO: improve CGo 79 } 80 t.Run(path, func(t *testing.T) { 81 runTest(path, tmpdir, "aarch64--linux-gnu", t) 82 }) 83 } 84 85 t.Log("running tests for WebAssembly...") 86 for _, path := range matches { 87 if path == "testdata/gc.go" { 88 continue // known to fail 89 } 90 t.Run(path, func(t *testing.T) { 91 runTest(path, tmpdir, "wasm", t) 92 }) 93 } 94 } 95 } 96 97 func runTest(path, tmpdir string, target string, t *testing.T) { 98 // Get the expected output for this test. 99 txtpath := path[:len(path)-3] + ".txt" 100 if path[len(path)-1] == '/' { 101 txtpath = path + "out.txt" 102 } 103 f, err := os.Open(txtpath) 104 if err != nil { 105 t.Fatal("could not open expected output file:", err) 106 } 107 expected, err := ioutil.ReadAll(f) 108 if err != nil { 109 t.Fatal("could not read expected output file:", err) 110 } 111 112 // Build the test binary. 113 config := &BuildConfig{ 114 opt: "z", 115 printIR: false, 116 dumpSSA: false, 117 debug: false, 118 printSizes: "", 119 wasmAbi: "js", 120 } 121 binary := filepath.Join(tmpdir, "test") 122 err = Build("./"+path, binary, target, config) 123 if err != nil { 124 t.Log("failed to build:", err) 125 t.Fail() 126 return 127 } 128 129 // Run the test. 130 var cmd *exec.Cmd 131 if target == "" { 132 cmd = exec.Command(binary) 133 } else { 134 spec, err := LoadTarget(target) 135 if err != nil { 136 t.Fatal("failed to load target spec:", err) 137 } 138 if len(spec.Emulator) == 0 { 139 t.Fatal("no emulator available for target:", target) 140 } 141 args := append(spec.Emulator[1:], binary) 142 cmd = exec.Command(spec.Emulator[0], args...) 143 } 144 stdout := &bytes.Buffer{} 145 cmd.Stdout = stdout 146 if target != "" { 147 cmd.Stderr = os.Stderr 148 } 149 err = cmd.Run() 150 if _, ok := err.(*exec.ExitError); ok && target != "" { 151 err = nil // workaround for QEMU 152 } 153 154 // putchar() prints CRLF, convert it to LF. 155 actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1) 156 157 // Check whether the command ran successfully. 158 fail := false 159 if err != nil { 160 t.Log("failed to run:", err) 161 fail = true 162 } else if !bytes.Equal(expected, actual) { 163 t.Log("output did not match") 164 fail = true 165 } 166 167 if fail { 168 r := bufio.NewReader(bytes.NewReader(actual)) 169 for { 170 line, err := r.ReadString('\n') 171 if err != nil { 172 break 173 } 174 t.Log("stdout:", line[:len(line)-1]) 175 } 176 t.Fail() 177 } 178 }