161 lines
4.2 KiB
Go
161 lines
4.2 KiB
Go
package compiler
|
|
|
|
import "time"
|
|
import "io/fs"
|
|
import "embed"
|
|
import "strings"
|
|
import "testing"
|
|
import "context"
|
|
import "os/exec"
|
|
import "path/filepath"
|
|
import "git.tebibyte.media/fspl/fspl/entity"
|
|
import "git.tebibyte.media/fspl/fspl/errors"
|
|
import "git.tebibyte.media/fspl/fspl/testcommon"
|
|
import "git.tebibyte.media/fspl/fspl/generator/native"
|
|
|
|
//go:embed all:test-data/*
|
|
var testData embed.FS
|
|
|
|
func defaultCompiler () *Compiler {
|
|
// instantiate and configure the compiler
|
|
comp := new(Compiler)
|
|
comp.Prefix = "compiler"
|
|
comp.Resolver = NewResolver (
|
|
"/test-data/usr/local/src/fspl",
|
|
"/test-data/usr/src/fspl",
|
|
"/test-data/usr/local/incude/fspl",
|
|
"/test-data/usr/include/fspl")
|
|
comp.Resolver.FS = testData
|
|
comp.Filetype = FiletypeObject
|
|
comp.Debug = true
|
|
nativeTarget := native.NativeTarget()
|
|
comp.Target = &nativeTarget
|
|
return comp
|
|
}
|
|
|
|
func compileDependency (
|
|
test *testing.T,
|
|
address entity.Address,
|
|
) string {
|
|
// create temporary directory
|
|
temp := test.TempDir()
|
|
|
|
// instantiate and configure the compiler
|
|
compOutputBuilder := new(strings.Builder)
|
|
comp := defaultCompiler()
|
|
defer func () {
|
|
test.Logf (
|
|
"COMPILER LOG (dependency %s):\n%s",
|
|
address, compOutputBuilder)
|
|
} ()
|
|
comp.Writer = compOutputBuilder
|
|
nickname, ok := address.Nickname()
|
|
if !ok {
|
|
test.Fatal("could not generate nickname for", address)
|
|
}
|
|
comp.Output = filepath.Join(temp, FiletypeObject.Extend(*comp.Target, nickname))
|
|
|
|
// compile to object file
|
|
err := comp.CompileUnit(address)
|
|
if err != nil {
|
|
test.Fatal("compiler returned error:", errors.Format(err))
|
|
}
|
|
|
|
return comp.Output
|
|
}
|
|
|
|
func testUnit (
|
|
test *testing.T,
|
|
address entity.Address,
|
|
clangArgs []string,
|
|
stdin, stdout string,
|
|
exit int,
|
|
args ...string,
|
|
) {
|
|
// create temporary directory
|
|
temp := test.TempDir()
|
|
|
|
// instantiate and configure the compiler
|
|
compOutputBuilder := new(strings.Builder)
|
|
comp := defaultCompiler()
|
|
outputCompilerLog := func () {
|
|
test.Log("COMPILER LOG (main unit):\n" + compOutputBuilder.String())
|
|
}
|
|
comp.Writer = compOutputBuilder
|
|
comp.Output = filepath.Join(temp, FiletypeObject.Extend(*comp.Target, "output"))
|
|
|
|
// compile to object file
|
|
err := comp.CompileUnit(address)
|
|
if err != nil {
|
|
outputCompilerLog()
|
|
test.Fatal("compiler returned error:", errors.Format(err))
|
|
}
|
|
outputCompilerLog()
|
|
|
|
// link the object file into an executable
|
|
linkOutputBuilder := new(strings.Builder)
|
|
executablePath := FiletypeExecutable.Extend(*comp.Target, filepath.Join(temp, "output"))
|
|
linkCommand := exec.Command("clang", append (
|
|
clangArgs,
|
|
comp.Output,
|
|
"-v",
|
|
"-o",
|
|
executablePath)...)
|
|
linkCommand.Stdout = linkOutputBuilder
|
|
linkCommand.Stderr = linkOutputBuilder
|
|
test.Log("running link command: ", linkCommand)
|
|
err = linkCommand.Run()
|
|
test.Log("LINKER LOG (main unit):\n" + linkOutputBuilder.String())
|
|
if err != nil {
|
|
test.Fatal("error linking executable:", err)
|
|
}
|
|
|
|
// run the executable file (with timeout) and check its output
|
|
timeoutDuration := 4000 * time.Millisecond
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
|
|
defer cancel()
|
|
executableCommand := exec.CommandContext(ctx, executablePath, args...)
|
|
stdoutBuilder := new(strings.Builder)
|
|
executableCommand.Stdin = strings.NewReader(stdin)
|
|
executableCommand.Stdout = stdoutBuilder
|
|
test.Log("running executable command: ", executableCommand)
|
|
err = executableCommand.Run()
|
|
|
|
if ctx.Err() == context.DeadlineExceeded {
|
|
test.Errorf("timeout of %v exceeded!", timeoutDuration)
|
|
}
|
|
|
|
// check error, compare exit code
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
code := exitErr.ExitCode()
|
|
if code != exit {
|
|
test.Errorf (
|
|
"expecting exit code %d, got %d",
|
|
exit, code)
|
|
}
|
|
} else if err != nil {
|
|
test.Fatalf("error running %s: %v", executablePath, err)
|
|
} else {
|
|
if 0 != exit {
|
|
test.Errorf("expecting exit code %d, got 0", exit)
|
|
}
|
|
}
|
|
|
|
// compare stdout
|
|
gotStdout := stdoutBuilder.String()
|
|
if gotStdout != stdout {
|
|
testcommon.CompareHex(test, stdout, gotStdout)
|
|
test.Fail()
|
|
}
|
|
}
|
|
|
|
func TestEmbedOk (test *testing.T) {
|
|
err := fs.WalkDir(testData, ".", func (path string, d fs.DirEntry, err error) error {
|
|
test.Log("file:", path)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
test.Error("walk dir failed: ", err)
|
|
}
|
|
}
|