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 }