Files
moxa/cmd/yaegi/test.go
Marc Vertes a876bb3673 interp: virtualize environment in restricted mode
In restricted mode, replace environment related symbols in
stdlib os package by a version which operates on a private copy
per interpreter context.

It allows to have concurrent interpreters in the same process
operating each in their own environment without affecting each
other or the host.

If unrestricted opt is set, this behaviour is disabled, and the
default symbols from stdlib are used.

Note also that no modification is done for syscall package, as it
should be not used in restricted mode.
2021-11-08 09:58:10 +01:00

178 lines
4.8 KiB
Go

package main
import (
"errors"
"flag"
"fmt"
"go/build"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
"github.com/traefik/yaegi/interp"
"github.com/traefik/yaegi/stdlib"
"github.com/traefik/yaegi/stdlib/syscall"
"github.com/traefik/yaegi/stdlib/unrestricted"
"github.com/traefik/yaegi/stdlib/unsafe"
)
func test(arg []string) (err error) {
var (
bench string
benchmem bool
benchtime string
count string
cpu string
failfast bool
run string
short bool
tags string
timeout string
verbose bool
)
// The following flags are initialized from environment.
useSyscall, _ := strconv.ParseBool(os.Getenv("YAEGI_SYSCALL"))
useUnrestricted, _ := strconv.ParseBool(os.Getenv("YAEGI_UNRESTRICTED"))
useUnsafe, _ := strconv.ParseBool(os.Getenv("YAEGI_UNSAFE"))
tflag := flag.NewFlagSet("test", flag.ContinueOnError)
tflag.StringVar(&bench, "bench", "", "Run only those benchmarks matching a regular expression.")
tflag.BoolVar(&benchmem, "benchmem", false, "Print memory allocation statistics for benchmarks.")
tflag.StringVar(&benchtime, "benchtime", "", "Run enough iterations of each benchmark to take t.")
tflag.StringVar(&count, "count", "", "Run each test and benchmark n times (default 1).")
tflag.StringVar(&cpu, "cpu", "", "Specify a list of GOMAXPROCS values for which the tests or benchmarks should be executed.")
tflag.BoolVar(&failfast, "failfast", false, "Do not start new tests after the first test failure.")
tflag.StringVar(&run, "run", "", "Run only those tests matching a regular expression.")
tflag.BoolVar(&short, "short", false, "Tell long-running tests to shorten their run time.")
tflag.StringVar(&tags, "tags", "", "Set a list of build tags.")
tflag.StringVar(&timeout, "timeout", "", "If a test binary runs longer than duration d, panic.")
tflag.BoolVar(&useUnrestricted, "unrestricted", useUnrestricted, "Include unrestricted symbols.")
tflag.BoolVar(&useUnsafe, "unsafe", useUnsafe, "Include usafe symbols.")
tflag.BoolVar(&useSyscall, "syscall", useSyscall, "Include syscall symbols.")
tflag.BoolVar(&verbose, "v", false, "Verbose output: log all tests as they are run.")
tflag.Usage = func() {
fmt.Println("Usage: yaegi test [options] [path]")
fmt.Println("Options:")
tflag.PrintDefaults()
}
if err = tflag.Parse(arg); err != nil {
return err
}
args := tflag.Args()
path := "."
if len(args) > 0 {
path = args[0]
}
// Overwrite os.Args with correct flags to setup testing.Init.
tf := []string{""}
if bench != "" {
tf = append(tf, "-test.bench", bench)
}
if benchmem {
tf = append(tf, "-test.benchmem")
}
if benchtime != "" {
tf = append(tf, "-test.benchtime", benchtime)
}
if count != "" {
tf = append(tf, "-test.count", count)
}
if cpu != "" {
tf = append(tf, "-test.cpu", cpu)
}
if failfast {
tf = append(tf, "-test.failfast")
}
if run != "" {
tf = append(tf, "-test.run", run)
}
if short {
tf = append(tf, "-test.short")
}
if timeout != "" {
tf = append(tf, "-test.timeout", timeout)
}
if verbose {
tf = append(tf, "-test.v")
}
testing.Init()
os.Args = tf
flag.Parse()
path += string(filepath.Separator)
var dir string
switch strings.Split(path, string(filepath.Separator))[0] {
case ".", "..", string(filepath.Separator):
dir = path
default:
dir = filepath.Join(build.Default.GOPATH, "src", path)
}
if err = os.Chdir(dir); err != nil {
return err
}
i := interp.New(interp.Options{
GoPath: build.Default.GOPATH,
BuildTags: strings.Split(tags, ","),
Env: os.Environ(),
Unrestricted: useUnrestricted,
})
if err := i.Use(stdlib.Symbols); err != nil {
return err
}
if err := i.Use(interp.Symbols); err != nil {
return err
}
if useSyscall {
if err := i.Use(syscall.Symbols); err != nil {
return err
}
// Using a environment var allows a nested interpreter to import the syscall package.
if err := os.Setenv("YAEGI_SYSCALL", "1"); err != nil {
return err
}
}
if useUnrestricted {
if err := i.Use(unrestricted.Symbols); err != nil {
return err
}
if err := os.Setenv("YAEGI_UNRESTRICTED", "1"); err != nil {
return err
}
}
if useUnsafe {
if err := i.Use(unsafe.Symbols); err != nil {
return err
}
if err := os.Setenv("YAEGI_UNSAFE", "1"); err != nil {
return err
}
}
if err = i.EvalTest(path); err != nil {
return err
}
benchmarks := []testing.InternalBenchmark{}
tests := []testing.InternalTest{}
syms, ok := i.Symbols(path)[path]
if !ok {
return errors.New("No tests found")
}
for name, sym := range syms {
switch fun := sym.Interface().(type) {
case func(*testing.B):
benchmarks = append(benchmarks, testing.InternalBenchmark{name, fun})
case func(*testing.T):
tests = append(tests, testing.InternalTest{name, fun})
}
}
testing.Main(regexp.MatchString, tests, benchmarks, nil)
return nil
}