github.com/traefik/yaegi@v0.15.1/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/traefik/yaegi/interp" 16 "github.com/traefik/yaegi/stdlib" 17 "github.com/traefik/yaegi/stdlib/syscall" 18 "github.com/traefik/yaegi/stdlib/unrestricted" 19 "github.com/traefik/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{ 120 GoPath: build.Default.GOPATH, 121 BuildTags: strings.Split(tags, ","), 122 Env: os.Environ(), 123 Unrestricted: useUnrestricted, 124 }) 125 if err := i.Use(stdlib.Symbols); err != nil { 126 return err 127 } 128 if err := i.Use(interp.Symbols); err != nil { 129 return err 130 } 131 if useSyscall { 132 if err := i.Use(syscall.Symbols); err != nil { 133 return err 134 } 135 // Using a environment var allows a nested interpreter to import the syscall package. 136 if err := os.Setenv("YAEGI_SYSCALL", "1"); err != nil { 137 return err 138 } 139 } 140 if useUnrestricted { 141 if err := i.Use(unrestricted.Symbols); err != nil { 142 return err 143 } 144 if err := os.Setenv("YAEGI_UNRESTRICTED", "1"); err != nil { 145 return err 146 } 147 } 148 if useUnsafe { 149 if err := i.Use(unsafe.Symbols); err != nil { 150 return err 151 } 152 if err := os.Setenv("YAEGI_UNSAFE", "1"); err != nil { 153 return err 154 } 155 } 156 if err = i.EvalTest(path); err != nil { 157 return err 158 } 159 160 benchmarks := []testing.InternalBenchmark{} 161 tests := []testing.InternalTest{} 162 syms, ok := i.Symbols(path)[path] 163 if !ok { 164 return errors.New("No tests found") 165 } 166 for name, sym := range syms { 167 switch fun := sym.Interface().(type) { 168 case func(*testing.B): 169 benchmarks = append(benchmarks, testing.InternalBenchmark{name, fun}) 170 case func(*testing.T): 171 tests = append(tests, testing.InternalTest{name, fun}) 172 } 173 } 174 175 testing.Main(regexp.MatchString, tests, benchmarks, nil) 176 return nil 177 }