Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134package tests_test
import ( "hash/crc32" "io" "os" "os/exec" "path/filepath" "strings" "testing"
"git.urbach.dev/cli/q/src/compiler" "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/exe" "git.urbach.dev/cli/q/src/linker" "git.urbach.dev/go/assert")
type run struct { Name string Args []string Input string Output string ExitCode int}
// Run compiles a debug and release version and tests both.func (test *run) Run(t *testing.T, build *config.Build) { build.Matrix(func(cross *config.Build) { if cross.OS == build.OS && cross.Arch == build.Arch { cross.Optimize(false) test.RunBuild(t, test.Name+"/"+cross.OS.String()+"/"+cross.Arch.String()+"/debug", cross) cross.Optimize(true) test.RunBuild(t, test.Name+"/"+cross.OS.String()+"/"+cross.Arch.String()+"/release", cross) } else { cross.Optimize(false) test.Compile(t, test.Name+"/"+cross.OS.String()+"/"+cross.Arch.String()+"/debug", cross) cross.Optimize(true) test.Compile(t, test.Name+"/"+cross.OS.String()+"/"+cross.Arch.String()+"/release", cross) } })}
// Compile only tests the compilation without actually running the executable.func (test *run) Compile(t *testing.T, name string, build *config.Build) { t.Run(name, func(t *testing.T) { env, err := compiler.Compile(build) assert.Nil(t, err) discard := &exe.Discard{} linker.Write(discard, env) })}
// RunBuild builds and runs the file to check if the output matches the expected output.func (test *run) RunBuild(t *testing.T, name string, build *config.Build) { t.Run(name, func(t *testing.T) { if test.ExitCode == -1 { env, err := compiler.Compile(build) assert.Nil(t, err) discard := &exe.Discard{} linker.Write(discard, env) return }
originalHash := uint32(0) tmpDir := t.TempDir() executable := build.Executable() executable = filepath.Join(tmpDir, filepath.Base(executable))
for range 3 { env, err := compiler.Compile(build) assert.Nil(t, err)
err = linker.WriteFile(executable, env) assert.Nil(t, err)
stat, err := os.Stat(executable) assert.Nil(t, err) assert.True(t, stat.Size() > 0)
// Run the executable cmd := exec.Command(executable, test.Args...) cmd.Stdin = strings.NewReader(test.Input) output, err := cmd.Output() exitCode := 0
if err != nil { exitError, ok := err.(*exec.ExitError)
if !ok { t.Fatal(exitError) }
exitCode = exitError.ExitCode() }
assert.Equal(t, exitCode, test.ExitCode) assert.DeepEqual(t, string(output), test.Output)
// Fail the test if the machine code is not deterministic newHash, err := checksum(executable) assert.Nil(t, err)
if originalHash == 0 { originalHash = newHash } else { assert.Equal(t, newHash, originalHash) }
// Clean up err = os.Remove(executable) assert.Nil(t, err) } })}
// checksum calculates a checksum for the file contents.func checksum(path string) (uint32, error) { file, err := os.Open(path)
if err != nil { return 0, err }
defer file.Close() sum := crc32.NewIEEE() _, err = io.Copy(sum, file)
if err != nil { return 0, err }
return sum.Sum32(), nil}