diff --git a/cl/_testgo/runextest/bar/bar.go b/cl/_testgo/runextest/bar/bar.go new file mode 100644 index 00000000..5730a5c5 --- /dev/null +++ b/cl/_testgo/runextest/bar/bar.go @@ -0,0 +1,5 @@ +package bar + +func Bar() int { + return 2 +} diff --git a/cl/_testgo/runextest/bar/bar_test.go b/cl/_testgo/runextest/bar/bar_test.go new file mode 100644 index 00000000..8d4c0438 --- /dev/null +++ b/cl/_testgo/runextest/bar/bar_test.go @@ -0,0 +1,13 @@ +package bar_test + +import ( + "testing" + + "github.com/goplus/llgo/cl/_testgo/runextest/bar" +) + +func TestBar(t *testing.T) { + if bar.Bar() != 2 { + t.Fatal("Bar() != 2") + } +} diff --git a/cl/_testgo/runextest/bar/barinner/barinner.go b/cl/_testgo/runextest/bar/barinner/barinner.go new file mode 100644 index 00000000..b37a5d6d --- /dev/null +++ b/cl/_testgo/runextest/bar/barinner/barinner.go @@ -0,0 +1,5 @@ +package barinner + +func BarInner() int { + return 2 +} diff --git a/cl/_testgo/runextest/bar/barinner/barinner_test.go b/cl/_testgo/runextest/bar/barinner/barinner_test.go new file mode 100644 index 00000000..12c543cd --- /dev/null +++ b/cl/_testgo/runextest/bar/barinner/barinner_test.go @@ -0,0 +1,13 @@ +package barinner_test + +import ( + "testing" + + "github.com/goplus/llgo/cl/_testgo/runextest/bar/barinner" +) + +func TestBarInner(t *testing.T) { + if barinner.BarInner() != 2 { + t.Fatal("BarInner() != 2") + } +} diff --git a/cl/_testgo/runextest/foo/foo.go b/cl/_testgo/runextest/foo/foo.go new file mode 100644 index 00000000..96b79fa4 --- /dev/null +++ b/cl/_testgo/runextest/foo/foo.go @@ -0,0 +1,5 @@ +package foo + +func Foo() int { + return 1 +} diff --git a/cl/_testgo/runextest/foo/foo_test.go b/cl/_testgo/runextest/foo/foo_test.go new file mode 100644 index 00000000..5c2125e7 --- /dev/null +++ b/cl/_testgo/runextest/foo/foo_test.go @@ -0,0 +1,13 @@ +package foo_test + +import ( + "testing" + + "github.com/goplus/llgo/cl/_testgo/runextest/foo" +) + +func TestFoo(t *testing.T) { + if foo.Foo() != 1 { + t.Fatal("Foo() != 1") + } +} diff --git a/cl/_testgo/runextest/main.go b/cl/_testgo/runextest/main.go new file mode 100644 index 00000000..b3fd473c --- /dev/null +++ b/cl/_testgo/runextest/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "github.com/goplus/llgo/cl/_testgo/runextest/bar" + "github.com/goplus/llgo/cl/_testgo/runextest/foo" +) + +func Zoo() int { + return 3 +} + +func main() { + println("foo.Foo()", foo.Foo()) + println("bar.Bar()", bar.Bar()) + println("Zoo()", Zoo()) +} diff --git a/cl/_testgo/runextest/main_test.go b/cl/_testgo/runextest/main_test.go new file mode 100644 index 00000000..385de527 --- /dev/null +++ b/cl/_testgo/runextest/main_test.go @@ -0,0 +1,11 @@ +package main + +import ( + "testing" +) + +func TestZoo(t *testing.T) { + if Zoo() != 3 { + t.Fatal("Zoo() != 3") + } +} diff --git a/cl/_testgo/runextest/out.ll b/cl/_testgo/runextest/out.ll new file mode 100644 index 00000000..1c8a0e79 --- /dev/null +++ b/cl/_testgo/runextest/out.ll @@ -0,0 +1 @@ +; \ No newline at end of file diff --git a/internal/build/build.go b/internal/build/build.go index 3c45dac1..1c480b25 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -252,7 +252,7 @@ func Do(args []string, conf *Config) ([]Package, error) { output := conf.OutFile != "" export, err := crosscompile.Use(conf.Goos, conf.Goarch, IsWasiThreadsEnabled(), IsRpathChangeEnabled()) check(err) - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), conf, export} + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), conf, export, false} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -282,6 +282,10 @@ func Do(args []string, conf *Config) ([]Package, error) { } } + if mode == ModeTest && ctx.testFail { + mockable.Exit(1) + } + return dpkg, nil } @@ -342,6 +346,8 @@ type context struct { buildConf *Config crossCompile crosscompile.Export + + testFail bool } func (c *context) compiler() *clang.Cmd { @@ -587,7 +593,9 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l if s := cmd.ProcessState; s != nil { exitCode := s.ExitCode() fmt.Fprintf(os.Stderr, "%s: exit code %d\n", app, exitCode) - mockable.Exit(exitCode) + if !ctx.testFail && exitCode != 0 { + ctx.testFail = true + } } case ModeRun: args := make([]string, 0, len(conf.RunArgs)+1) diff --git a/internal/build/build_test.go b/internal/build/build_test.go index e7e599fd..f2f8730f 100644 --- a/internal/build/build_test.go +++ b/internal/build/build_test.go @@ -4,7 +4,9 @@ package build import ( + "bytes" "fmt" + "io" "os" "testing" @@ -58,9 +60,36 @@ func TestRun(t *testing.T) { } func TestTest(t *testing.T) { + // FIXME(zzy): with builtin package test in a llgo test ./... will cause duplicate symbol error mockRun([]string{"../../cl/_testgo/runtest"}, &Config{Mode: ModeTest}) } +func TestExtest(t *testing.T) { + originalStdout := os.Stdout + defer func() { os.Stdout = originalStdout }() + + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("os.Pipe failed: %v", err) + } + os.Stdout = w + outputChan := make(chan string) + go func() { + var data bytes.Buffer + io.Copy(&data, r) + outputChan <- data.String() + }() + + mockRun([]string{"../../cl/_testgo/runextest/..."}, &Config{Mode: ModeTest}) + + w.Close() + got := <-outputChan + expected := "PASS\nPASS\nPASS\nPASS\n" + if got != expected { + t.Errorf("Expected output %q, but got %q", expected, got) + } +} + func TestCmpTest(t *testing.T) { mockRun([]string{"../../cl/_testgo/runtest"}, &Config{Mode: ModeCmpTest}) }