compiler: add go test command

This commit is contained in:
Li Jie
2024-12-31 10:53:38 +08:00
parent 6b11c100ba
commit 946f304bb2
13 changed files with 127 additions and 17 deletions

5
_demo/runtest/bar/bar.go Normal file
View File

@@ -0,0 +1,5 @@
package bar
func Bar() int {
return 2
}

View File

@@ -0,0 +1,9 @@
package bar
import "testing"
func TestBar(t *testing.T) {
if Bar() != 2 {
t.Fatal("Bar() != 2")
}
}

5
_demo/runtest/foo/foo.go Normal file
View File

@@ -0,0 +1,5 @@
package foo
func Foo() int {
return 1
}

View File

@@ -0,0 +1,9 @@
package foo
import "testing"
func TestFoo(t *testing.T) {
if Foo() != 1 {
t.Fatal("Foo() != 1")
}
}

16
_demo/runtest/main.go Normal file
View File

@@ -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())
}

View File

@@ -0,0 +1,9 @@
package main
import "testing"
func TestZoo(t *testing.T) {
if Zoo() != 3 {
t.Fatal("Zoo() != 3")
}
}

View File

@@ -148,7 +148,7 @@ func doMain() error {
for i, p := range pkgs { for i, p := range pkgs {
if p == nil { 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)
} }
} }

View File

@@ -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)
}
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/goplus/llgo/compiler/cmd/internal/help" "github.com/goplus/llgo/compiler/cmd/internal/help"
"github.com/goplus/llgo/compiler/cmd/internal/install" "github.com/goplus/llgo/compiler/cmd/internal/install"
"github.com/goplus/llgo/compiler/cmd/internal/run" "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/cmd/internal/version"
"github.com/goplus/llgo/compiler/internal/mockable" "github.com/goplus/llgo/compiler/internal/mockable"
) )
@@ -47,6 +48,7 @@ func init() {
get.Cmd, get.Cmd,
run.Cmd, run.Cmd,
run.CmpTestCmd, run.CmpTestCmd,
test.Cmd,
clean.Cmd, clean.Cmd,
version.Cmd, version.Cmd,
} }

View File

@@ -1,6 +1,6 @@
module github.com/goplus/llgo/compiler module github.com/goplus/llgo/compiler
go 1.22.0 go 1.22.4
require ( require (
github.com/goplus/gogen v1.16.6 github.com/goplus/gogen v1.16.6

View File

@@ -55,6 +55,7 @@ const (
ModeBuild Mode = iota ModeBuild Mode = iota
ModeInstall ModeInstall
ModeRun ModeRun
ModeTest
ModeCmpTest ModeCmpTest
ModeGen ModeGen
) )
@@ -130,6 +131,10 @@ func Do(args []string, conf *Config) ([]Package, error) {
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile, Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
BuildFlags: flags, BuildFlags: flags,
Fset: token.NewFileSet(), Fset: token.NewFileSet(),
Tests: conf.Mode == ModeTest,
}
if conf.Mode == ModeTest {
cfg.Mode |= packages.NeedForTest
} }
if len(overlayFiles) > 0 { if len(overlayFiles) > 0 {
@@ -164,15 +169,14 @@ func Do(args []string, conf *Config) ([]Package, error) {
initial, err := packages.LoadEx(dedup, sizes, cfg, patterns...) initial, err := packages.LoadEx(dedup, sizes, cfg, patterns...)
check(err) check(err)
mode := conf.Mode mode := conf.Mode
switch mode {
case ModeBuild:
if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 { if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 {
if mode == ModeBuild {
mode = ModeInstall mode = ModeInstall
} }
} else if mode == ModeRun { case ModeRun:
if len(initial) > 1 { if len(initial) > 1 {
return nil, fmt.Errorf("cannot run multiple packages") 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 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} 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 { if mode == ModeGen {
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Package == initial[0] { 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") 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 var linkArgs []string
for _, pkg := range dpkg { for _, pkg := range dpkg {
linkArgs = append(linkArgs, pkg.LinkArgs...) linkArgs = append(linkArgs, pkg.LinkArgs...)
@@ -266,7 +272,7 @@ type context struct {
nLibdir int 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 prog := ctx.prog
pkgs, errPkgs := allPkgs(ctx, initial, verbose) pkgs, errPkgs := allPkgs(ctx, initial, verbose)
for _, errPkg := range errPkgs { 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) fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg)
} }
if len(errPkgs) > 0 { if len(errPkgs) > 0 {
mockable.Exit(1) return nil, fmt.Errorf("cannot build SSA for packages")
} }
built := ctx.built built := ctx.built
for _, aPkg := range pkgs { for _, aPkg := range pkgs {
@@ -862,6 +868,7 @@ var hasAltPkg = map[string]none{
"crypto/sha512": {}, "crypto/sha512": {},
"crypto/subtle": {}, "crypto/subtle": {},
"fmt": {}, "fmt": {},
"go/parser": {},
"hash/crc32": {}, "hash/crc32": {},
"internal/abi": {}, "internal/abi": {},
"internal/bytealg": {}, "internal/bytealg": {},

View File

@@ -58,6 +58,8 @@ const (
NeedTypesSizes = packages.NeedTypesSizes NeedTypesSizes = packages.NeedTypesSizes
NeedTypesInfo = packages.NeedTypesInfo NeedTypesInfo = packages.NeedTypesInfo
NeedForTest = packages.NeedForTest
typecheckCgo = NeedModule - 1 // TODO(xsw): how to check 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 p.setpath = fn
} }
func (p Deduper) Check(pkgPath string) *Cached { func (p Deduper) Check(id string) *Cached {
if v, ok := p.cache.Load(pkgPath); ok { if v, ok := p.cache.Load(id); ok {
return v.(*Cached) return v.(*Cached)
} }
return nil return nil
} }
func (p Deduper) set(pkgPath string, cp *Cached) { func (p Deduper) set(id string, cp *Cached) {
if DebugPackagesLoad { 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 //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 dedup != nil {
if cp := dedup.Check(lpkg.PkgPath); cp != nil { if cp := dedup.Check(lpkg.ID); cp != nil {
lpkg.Types = cp.Types lpkg.Types = cp.Types
lpkg.Fset = ld.Fset lpkg.Fset = ld.Fset
lpkg.TypesInfo = cp.TypesInfo lpkg.TypesInfo = cp.TypesInfo

View File

@@ -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
}
}