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  }