github.com/switchupcb/yaegi@v0.10.2/cmd/yaegi/test.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"flag"
     6  	"fmt"
     7  	"go/build"
     8  	"os"
     9  	"path/filepath"
    10  	"regexp"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/switchupcb/yaegi/interp"
    16  	"github.com/switchupcb/yaegi/stdlib"
    17  	"github.com/switchupcb/yaegi/stdlib/syscall"
    18  	"github.com/switchupcb/yaegi/stdlib/unrestricted"
    19  	"github.com/switchupcb/yaegi/stdlib/unsafe"
    20  )
    21  
    22  func test(arg []string) (err error) {
    23  	var (
    24  		bench     string
    25  		benchmem  bool
    26  		benchtime string
    27  		count     string
    28  		cpu       string
    29  		failfast  bool
    30  		run       string
    31  		short     bool
    32  		tags      string
    33  		timeout   string
    34  		verbose   bool
    35  	)
    36  
    37  	// The following flags are initialized from environment.
    38  	useSyscall, _ := strconv.ParseBool(os.Getenv("YAEGI_SYSCALL"))
    39  	useUnrestricted, _ := strconv.ParseBool(os.Getenv("YAEGI_UNRESTRICTED"))
    40  	useUnsafe, _ := strconv.ParseBool(os.Getenv("YAEGI_UNSAFE"))
    41  
    42  	tflag := flag.NewFlagSet("test", flag.ContinueOnError)
    43  	tflag.StringVar(&bench, "bench", "", "Run only those benchmarks matching a regular expression.")
    44  	tflag.BoolVar(&benchmem, "benchmem", false, "Print memory allocation statistics for benchmarks.")
    45  	tflag.StringVar(&benchtime, "benchtime", "", "Run enough iterations of each benchmark to take t.")
    46  	tflag.StringVar(&count, "count", "", "Run each test and benchmark n times (default 1).")
    47  	tflag.StringVar(&cpu, "cpu", "", "Specify a list of GOMAXPROCS values for which the tests or benchmarks should be executed.")
    48  	tflag.BoolVar(&failfast, "failfast", false, "Do not start new tests after the first test failure.")
    49  	tflag.StringVar(&run, "run", "", "Run only those tests matching a regular expression.")
    50  	tflag.BoolVar(&short, "short", false, "Tell long-running tests to shorten their run time.")
    51  	tflag.StringVar(&tags, "tags", "", "Set a list of build tags.")
    52  	tflag.StringVar(&timeout, "timeout", "", "If a test binary runs longer than duration d, panic.")
    53  	tflag.BoolVar(&useUnrestricted, "unrestricted", useUnrestricted, "Include unrestricted symbols.")
    54  	tflag.BoolVar(&useUnsafe, "unsafe", useUnsafe, "Include usafe symbols.")
    55  	tflag.BoolVar(&useSyscall, "syscall", useSyscall, "Include syscall symbols.")
    56  	tflag.BoolVar(&verbose, "v", false, "Verbose output: log all tests as they are run.")
    57  	tflag.Usage = func() {
    58  		fmt.Println("Usage: yaegi test [options] [path]")
    59  		fmt.Println("Options:")
    60  		tflag.PrintDefaults()
    61  	}
    62  	if err = tflag.Parse(arg); err != nil {
    63  		return err
    64  	}
    65  	args := tflag.Args()
    66  	path := "."
    67  	if len(args) > 0 {
    68  		path = args[0]
    69  	}
    70  
    71  	// Overwrite os.Args with correct flags to setup testing.Init.
    72  	tf := []string{""}
    73  	if bench != "" {
    74  		tf = append(tf, "-test.bench", bench)
    75  	}
    76  	if benchmem {
    77  		tf = append(tf, "-test.benchmem")
    78  	}
    79  	if benchtime != "" {
    80  		tf = append(tf, "-test.benchtime", benchtime)
    81  	}
    82  	if count != "" {
    83  		tf = append(tf, "-test.count", count)
    84  	}
    85  	if cpu != "" {
    86  		tf = append(tf, "-test.cpu", cpu)
    87  	}
    88  	if failfast {
    89  		tf = append(tf, "-test.failfast")
    90  	}
    91  	if run != "" {
    92  		tf = append(tf, "-test.run", run)
    93  	}
    94  	if short {
    95  		tf = append(tf, "-test.short")
    96  	}
    97  	if timeout != "" {
    98  		tf = append(tf, "-test.timeout", timeout)
    99  	}
   100  	if verbose {
   101  		tf = append(tf, "-test.v")
   102  	}
   103  	testing.Init()
   104  	os.Args = tf
   105  	flag.Parse()
   106  	path += string(filepath.Separator)
   107  	var dir string
   108  
   109  	switch strings.Split(path, string(filepath.Separator))[0] {
   110  	case ".", "..", string(filepath.Separator):
   111  		dir = path
   112  	default:
   113  		dir = filepath.Join(build.Default.GOPATH, "src", path)
   114  	}
   115  	if err = os.Chdir(dir); err != nil {
   116  		return err
   117  	}
   118  
   119  	i := interp.New(interp.Options{GoPath: build.Default.GOPATH, BuildTags: strings.Split(tags, ",")})
   120  	if err := i.Use(stdlib.Symbols); err != nil {
   121  		return err
   122  	}
   123  	if err := i.Use(interp.Symbols); err != nil {
   124  		return err
   125  	}
   126  	if useSyscall {
   127  		if err := i.Use(syscall.Symbols); err != nil {
   128  			return err
   129  		}
   130  		// Using a environment var allows a nested interpreter to import the syscall package.
   131  		if err := os.Setenv("YAEGI_SYSCALL", "1"); err != nil {
   132  			return err
   133  		}
   134  	}
   135  	if useUnrestricted {
   136  		if err := i.Use(unrestricted.Symbols); err != nil {
   137  			return err
   138  		}
   139  		if err := os.Setenv("YAEGI_UNRESTRICTED", "1"); err != nil {
   140  			return err
   141  		}
   142  	}
   143  	if useUnsafe {
   144  		if err := i.Use(unsafe.Symbols); err != nil {
   145  			return err
   146  		}
   147  		if err := os.Setenv("YAEGI_UNSAFE", "1"); err != nil {
   148  			return err
   149  		}
   150  	}
   151  	if err = i.EvalTest(path); err != nil {
   152  		return err
   153  	}
   154  
   155  	benchmarks := []testing.InternalBenchmark{}
   156  	tests := []testing.InternalTest{}
   157  	syms, ok := i.Symbols(path)[path]
   158  	if !ok {
   159  		return errors.New("No tests found")
   160  	}
   161  	for name, sym := range syms {
   162  		switch fun := sym.Interface().(type) {
   163  		case func(*testing.B):
   164  			benchmarks = append(benchmarks, testing.InternalBenchmark{name, fun})
   165  		case func(*testing.T):
   166  			tests = append(tests, testing.InternalTest{name, fun})
   167  		}
   168  	}
   169  
   170  	testing.Main(regexp.MatchString, tests, benchmarks, nil)
   171  	return nil
   172  }