github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/cmd/go/internal/test/testflag.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package test 6 7 import ( 8 "flag" 9 "os" 10 "strings" 11 12 "cmd/go/internal/base" 13 "cmd/go/internal/cfg" 14 "cmd/go/internal/cmdflag" 15 "cmd/go/internal/str" 16 "cmd/go/internal/work" 17 ) 18 19 const cmd = "test" 20 21 // The flag handling part of go test is large and distracting. 22 // We can't use the flag package because some of the flags from 23 // our command line are for us, and some are for 6.out, and 24 // some are for both. 25 26 // testFlagDefn is the set of flags we process. 27 var testFlagDefn = []*cmdflag.Defn{ 28 // local. 29 {Name: "c", BoolVar: &testC}, 30 {Name: "i", BoolVar: &cfg.BuildI}, 31 {Name: "o"}, 32 {Name: "cover", BoolVar: &testCover}, 33 {Name: "covermode"}, 34 {Name: "coverpkg"}, 35 {Name: "exec"}, 36 37 // Passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v. 38 {Name: "bench", PassToTest: true}, 39 {Name: "benchmem", BoolVar: new(bool), PassToTest: true}, 40 {Name: "benchtime", PassToTest: true}, 41 {Name: "count", PassToTest: true}, 42 {Name: "coverprofile", PassToTest: true}, 43 {Name: "cpu", PassToTest: true}, 44 {Name: "cpuprofile", PassToTest: true}, 45 {Name: "list", PassToTest: true}, 46 {Name: "memprofile", PassToTest: true}, 47 {Name: "memprofilerate", PassToTest: true}, 48 {Name: "blockprofile", PassToTest: true}, 49 {Name: "blockprofilerate", PassToTest: true}, 50 {Name: "mutexprofile", PassToTest: true}, 51 {Name: "mutexprofilefraction", PassToTest: true}, 52 {Name: "outputdir", PassToTest: true}, 53 {Name: "parallel", PassToTest: true}, 54 {Name: "run", PassToTest: true}, 55 {Name: "short", BoolVar: new(bool), PassToTest: true}, 56 {Name: "timeout", PassToTest: true}, 57 {Name: "trace", PassToTest: true}, 58 {Name: "v", BoolVar: &testV, PassToTest: true}, 59 } 60 61 // add build flags to testFlagDefn 62 func init() { 63 var cmd base.Command 64 work.AddBuildFlags(&cmd) 65 cmd.Flag.VisitAll(func(f *flag.Flag) { 66 if f.Name == "v" { 67 // test overrides the build -v flag 68 return 69 } 70 testFlagDefn = append(testFlagDefn, &cmdflag.Defn{ 71 Name: f.Name, 72 Value: f.Value, 73 }) 74 }) 75 } 76 77 // testFlags processes the command line, grabbing -x and -c, rewriting known flags 78 // to have "test" before them, and reading the command line for the 6.out. 79 // Unfortunately for us, we need to do our own flag processing because go test 80 // grabs some flags but otherwise its command line is just a holding place for 81 // pkg.test's arguments. 82 // We allow known flags both before and after the package name list, 83 // to allow both 84 // go test fmt -custom-flag-for-fmt-test 85 // go test -x math 86 func testFlags(args []string) (packageNames, passToTest []string) { 87 inPkg := false 88 outputDir := "" 89 var explicitArgs []string 90 for i := 0; i < len(args); i++ { 91 if !strings.HasPrefix(args[i], "-") { 92 if !inPkg && packageNames == nil { 93 // First package name we've seen. 94 inPkg = true 95 } 96 if inPkg { 97 packageNames = append(packageNames, args[i]) 98 continue 99 } 100 } 101 102 if inPkg { 103 // Found an argument beginning with "-"; end of package list. 104 inPkg = false 105 } 106 107 f, value, extraWord := cmdflag.Parse(cmd, testFlagDefn, args, i) 108 if f == nil { 109 // This is a flag we do not know; we must assume 110 // that any args we see after this might be flag 111 // arguments, not package names. 112 inPkg = false 113 if packageNames == nil { 114 // make non-nil: we have seen the empty package list 115 packageNames = []string{} 116 } 117 if args[i] == "-args" || args[i] == "--args" { 118 // -args or --args signals that everything that follows 119 // should be passed to the test. 120 explicitArgs = args[i+1:] 121 break 122 } 123 passToTest = append(passToTest, args[i]) 124 continue 125 } 126 if f.Value != nil { 127 if err := f.Value.Set(value); err != nil { 128 base.Fatalf("invalid flag argument for -%s: %v", f.Name, err) 129 } 130 } else { 131 // Test-only flags. 132 // Arguably should be handled by f.Value, but aren't. 133 switch f.Name { 134 // bool flags. 135 case "c", "i", "v", "cover": 136 cmdflag.SetBool(cmd, f.BoolVar, value) 137 case "o": 138 testO = value 139 testNeedBinary = true 140 case "exec": 141 xcmd, err := str.SplitQuotedFields(value) 142 if err != nil { 143 base.Fatalf("invalid flag argument for -%s: %v", f.Name, err) 144 } 145 work.ExecCmd = xcmd 146 case "bench": 147 // record that we saw the flag; don't care about the value 148 testBench = true 149 case "list": 150 testList = true 151 case "timeout": 152 testTimeout = value 153 case "blockprofile", "cpuprofile", "memprofile", "mutexprofile": 154 testProfile = true 155 testNeedBinary = true 156 case "trace": 157 testProfile = true 158 case "coverpkg": 159 testCover = true 160 if value == "" { 161 testCoverPaths = nil 162 } else { 163 testCoverPaths = strings.Split(value, ",") 164 } 165 case "coverprofile": 166 testCover = true 167 testProfile = true 168 case "covermode": 169 switch value { 170 case "set", "count", "atomic": 171 testCoverMode = value 172 default: 173 base.Fatalf("invalid flag argument for -covermode: %q", value) 174 } 175 testCover = true 176 case "outputdir": 177 outputDir = value 178 } 179 } 180 if extraWord { 181 i++ 182 } 183 if f.PassToTest { 184 passToTest = append(passToTest, "-test."+f.Name+"="+value) 185 } 186 } 187 188 if testCoverMode == "" { 189 testCoverMode = "set" 190 if cfg.BuildRace { 191 // Default coverage mode is atomic when -race is set. 192 testCoverMode = "atomic" 193 } 194 } 195 196 if cfg.BuildRace && testCoverMode != "atomic" { 197 base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode) 198 } 199 200 // Tell the test what directory we're running in, so it can write the profiles there. 201 if testProfile && outputDir == "" { 202 dir, err := os.Getwd() 203 if err != nil { 204 base.Fatalf("error from os.Getwd: %s", err) 205 } 206 passToTest = append(passToTest, "-test.outputdir", dir) 207 } 208 209 passToTest = append(passToTest, explicitArgs...) 210 return 211 }