From 946f304bb2b6ed91b90580f8332dc977615ceac2 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 31 Dec 2024 10:53:38 +0800 Subject: [PATCH] compiler: add go test command --- _demo/runtest/bar/bar.go | 5 ++++ _demo/runtest/bar/bar_test.go | 9 +++++++ _demo/runtest/foo/foo.go | 5 ++++ _demo/runtest/foo/foo_test.go | 9 +++++++ _demo/runtest/main.go | 16 ++++++++++++ _demo/runtest/main_test.go | 9 +++++++ compiler/chore/ssadump/ssadump.go | 2 +- compiler/cmd/internal/test/test.go | 33 ++++++++++++++++++++++++ compiler/cmd/llgo/llgo.go | 2 ++ compiler/go.mod | 2 +- compiler/internal/build/build.go | 25 +++++++++++------- compiler/internal/packages/load.go | 14 +++++----- runtime/internal/lib/go/parser/parser.go | 13 ++++++++++ 13 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 _demo/runtest/bar/bar.go create mode 100644 _demo/runtest/bar/bar_test.go create mode 100644 _demo/runtest/foo/foo.go create mode 100644 _demo/runtest/foo/foo_test.go create mode 100644 _demo/runtest/main.go create mode 100644 _demo/runtest/main_test.go create mode 100644 compiler/cmd/internal/test/test.go create mode 100644 runtime/internal/lib/go/parser/parser.go diff --git a/_demo/runtest/bar/bar.go b/_demo/runtest/bar/bar.go new file mode 100644 index 00000000..5730a5c5 --- /dev/null +++ b/_demo/runtest/bar/bar.go @@ -0,0 +1,5 @@ +package bar + +func Bar() int { + return 2 +} diff --git a/_demo/runtest/bar/bar_test.go b/_demo/runtest/bar/bar_test.go new file mode 100644 index 00000000..a5c99912 --- /dev/null +++ b/_demo/runtest/bar/bar_test.go @@ -0,0 +1,9 @@ +package bar + +import "testing" + +func TestBar(t *testing.T) { + if Bar() != 2 { + t.Fatal("Bar() != 2") + } +} diff --git a/_demo/runtest/foo/foo.go b/_demo/runtest/foo/foo.go new file mode 100644 index 00000000..96b79fa4 --- /dev/null +++ b/_demo/runtest/foo/foo.go @@ -0,0 +1,5 @@ +package foo + +func Foo() int { + return 1 +} diff --git a/_demo/runtest/foo/foo_test.go b/_demo/runtest/foo/foo_test.go new file mode 100644 index 00000000..13798beb --- /dev/null +++ b/_demo/runtest/foo/foo_test.go @@ -0,0 +1,9 @@ +package foo + +import "testing" + +func TestFoo(t *testing.T) { + if Foo() != 1 { + t.Fatal("Foo() != 1") + } +} diff --git a/_demo/runtest/main.go b/_demo/runtest/main.go new file mode 100644 index 00000000..b9ad473a --- /dev/null +++ b/_demo/runtest/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "github.com/goplus/llgo/_demo/runtest/bar" + "github.com/goplus/llgo/_demo/runtest/foo" +) + +func Zoo() int { + return 3 +} + +func main() { + println("foo.Foo()", foo.Foo()) + println("bar.Bar()", bar.Bar()) + println("Zoo()", Zoo()) +} diff --git a/_demo/runtest/main_test.go b/_demo/runtest/main_test.go new file mode 100644 index 00000000..3484e083 --- /dev/null +++ b/_demo/runtest/main_test.go @@ -0,0 +1,9 @@ +package main + +import "testing" + +func TestZoo(t *testing.T) { + if Zoo() != 3 { + t.Fatal("Zoo() != 3") + } +} diff --git a/compiler/chore/ssadump/ssadump.go b/compiler/chore/ssadump/ssadump.go index 03fb623a..4c0fa0b3 100644 --- a/compiler/chore/ssadump/ssadump.go +++ b/compiler/chore/ssadump/ssadump.go @@ -148,7 +148,7 @@ func doMain() error { for i, p := range pkgs { if p == nil { - return fmt.Errorf("cannot build SSA for package %s", initial[i]) + return fmt.Errorf("cannot build SSA for package %s", initial[i].ID) } } diff --git a/compiler/cmd/internal/test/test.go b/compiler/cmd/internal/test/test.go new file mode 100644 index 00000000..5e00f6fd --- /dev/null +++ b/compiler/cmd/internal/test/test.go @@ -0,0 +1,33 @@ +package test + +import ( + "fmt" + "os" + + "github.com/goplus/llgo/compiler/cmd/internal/base" + "github.com/goplus/llgo/compiler/internal/build" +) + +// llgo test +var Cmd = &base.Command{ + UsageLine: "llgo test [build flags] package [arguments...]", + Short: "Compile and run Go test", +} + +func init() { + Cmd.Run = runCmd +} + +func runCmd(cmd *base.Command, args []string) { + runCmdEx(cmd, args, build.ModeRun) +} + +func runCmdEx(_ *base.Command, args []string, mode build.Mode) { + conf := build.NewDefaultConf(mode) + conf.Mode = build.ModeTest + _, err := build.Do(args, conf) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/compiler/cmd/llgo/llgo.go b/compiler/cmd/llgo/llgo.go index 77cf35a8..17575ead 100644 --- a/compiler/cmd/llgo/llgo.go +++ b/compiler/cmd/llgo/llgo.go @@ -31,6 +31,7 @@ import ( "github.com/goplus/llgo/compiler/cmd/internal/help" "github.com/goplus/llgo/compiler/cmd/internal/install" "github.com/goplus/llgo/compiler/cmd/internal/run" + "github.com/goplus/llgo/compiler/cmd/internal/test" "github.com/goplus/llgo/compiler/cmd/internal/version" "github.com/goplus/llgo/compiler/internal/mockable" ) @@ -47,6 +48,7 @@ func init() { get.Cmd, run.Cmd, run.CmpTestCmd, + test.Cmd, clean.Cmd, version.Cmd, } diff --git a/compiler/go.mod b/compiler/go.mod index 48ff738a..b95a7873 100644 --- a/compiler/go.mod +++ b/compiler/go.mod @@ -1,6 +1,6 @@ module github.com/goplus/llgo/compiler -go 1.22.0 +go 1.22.4 require ( github.com/goplus/gogen v1.16.6 diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 910a6e13..30eb68c9 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -55,6 +55,7 @@ const ( ModeBuild Mode = iota ModeInstall ModeRun + ModeTest ModeCmpTest ModeGen ) @@ -130,6 +131,10 @@ func Do(args []string, conf *Config) ([]Package, error) { Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile, BuildFlags: flags, Fset: token.NewFileSet(), + Tests: conf.Mode == ModeTest, + } + if conf.Mode == ModeTest { + cfg.Mode |= packages.NeedForTest } if len(overlayFiles) > 0 { @@ -164,15 +169,14 @@ func Do(args []string, conf *Config) ([]Package, error) { initial, err := packages.LoadEx(dedup, sizes, cfg, patterns...) check(err) mode := conf.Mode - if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 { - if mode == ModeBuild { + switch mode { + case ModeBuild: + if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 { mode = ModeInstall } - } else if mode == ModeRun { + case ModeRun: if len(initial) > 1 { return nil, fmt.Errorf("cannot run multiple packages") - } else { - return nil, fmt.Errorf("no Go files in matched packages") } } @@ -205,7 +209,8 @@ func Do(args []string, conf *Config) ([]Package, error) { os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0} - pkgs := buildAllPkgs(ctx, initial, verbose) + pkgs, err := buildAllPkgs(ctx, initial, verbose) + check(err) if mode == ModeGen { for _, pkg := range pkgs { if pkg.Package == initial[0] { @@ -215,7 +220,8 @@ func Do(args []string, conf *Config) ([]Package, error) { return nil, fmt.Errorf("initial package not found") } - dpkg := buildAllPkgs(ctx, altPkgs[noRt:], verbose) + dpkg, err := buildAllPkgs(ctx, altPkgs[noRt:], verbose) + check(err) var linkArgs []string for _, pkg := range dpkg { linkArgs = append(linkArgs, pkg.LinkArgs...) @@ -266,7 +272,7 @@ type context struct { nLibdir int } -func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage) { +func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage, err error) { prog := ctx.prog pkgs, errPkgs := allPkgs(ctx, initial, verbose) for _, errPkg := range errPkgs { @@ -276,7 +282,7 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg) } if len(errPkgs) > 0 { - mockable.Exit(1) + return nil, fmt.Errorf("cannot build SSA for packages") } built := ctx.built for _, aPkg := range pkgs { @@ -862,6 +868,7 @@ var hasAltPkg = map[string]none{ "crypto/sha512": {}, "crypto/subtle": {}, "fmt": {}, + "go/parser": {}, "hash/crc32": {}, "internal/abi": {}, "internal/bytealg": {}, diff --git a/compiler/internal/packages/load.go b/compiler/internal/packages/load.go index 65ddf25e..66f4c29c 100644 --- a/compiler/internal/packages/load.go +++ b/compiler/internal/packages/load.go @@ -58,6 +58,8 @@ const ( NeedTypesSizes = packages.NeedTypesSizes NeedTypesInfo = packages.NeedTypesInfo + NeedForTest = packages.NeedForTest + typecheckCgo = NeedModule - 1 // TODO(xsw): how to check ) @@ -129,18 +131,18 @@ func (p Deduper) SetPkgPath(fn func(path, name string) string) { p.setpath = fn } -func (p Deduper) Check(pkgPath string) *Cached { - if v, ok := p.cache.Load(pkgPath); ok { +func (p Deduper) Check(id string) *Cached { + if v, ok := p.cache.Load(id); ok { return v.(*Cached) } return nil } -func (p Deduper) set(pkgPath string, cp *Cached) { +func (p Deduper) set(id string, cp *Cached) { if DebugPackagesLoad { - log.Println("==> Import", pkgPath) + log.Println("==> Import", id) } - p.cache.Store(pkgPath, cp) + p.cache.Store(id, cp) } //go:linkname defaultDriver golang.org/x/tools/go/packages.defaultDriver @@ -176,7 +178,7 @@ func loadPackageEx(dedup Deduper, ld *loader, lpkg *loaderPackage) { } if dedup != nil { - if cp := dedup.Check(lpkg.PkgPath); cp != nil { + if cp := dedup.Check(lpkg.ID); cp != nil { lpkg.Types = cp.Types lpkg.Fset = ld.Fset lpkg.TypesInfo = cp.TypesInfo diff --git a/runtime/internal/lib/go/parser/parser.go b/runtime/internal/lib/go/parser/parser.go new file mode 100644 index 00000000..4b7b93b9 --- /dev/null +++ b/runtime/internal/lib/go/parser/parser.go @@ -0,0 +1,13 @@ +package parser + +import "go/ast" + +func unparen(e ast.Expr) ast.Expr { + for { + paren, ok := e.(*ast.ParenExpr) + if !ok { + return e + } + e = paren.X + } +}