github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/go/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 main 6 7 import ( 8 "fmt" 9 "os" 10 "strconv" 11 "strings" 12 ) 13 14 // The flag handling part of go test is large and distracting. 15 // We can't use the flag package because some of the flags from 16 // our command line are for us, and some are for 6.out, and 17 // some are for both. 18 19 var usageMessage = `Usage of go test: 20 -c=false: compile but do not run the test binary 21 -file=file_test.go: specify file to use for tests; 22 use multiple times for multiple files 23 -p=n: build and test up to n packages in parallel 24 -x=false: print command lines as they are executed 25 26 // These flags can be passed with or without a "test." prefix: -v or -test.v. 27 -bench="": passes -test.bench to test 28 -benchmem=false: print memory allocation statistics for benchmarks 29 -benchtime=1s: passes -test.benchtime to test 30 -cpu="": passes -test.cpu to test 31 -cpuprofile="": passes -test.cpuprofile to test 32 -memprofile="": passes -test.memprofile to test 33 -memprofilerate=0: passes -test.memprofilerate to test 34 -blockprofile="": pases -test.blockprofile to test 35 -blockprofilerate=0: passes -test.blockprofilerate to test 36 -parallel=0: passes -test.parallel to test 37 -run="": passes -test.run to test 38 -short=false: passes -test.short to test 39 -timeout=0: passes -test.timeout to test 40 -v=false: passes -test.v to test 41 ` 42 43 // usage prints a usage message and exits. 44 func testUsage() { 45 fmt.Fprint(os.Stderr, usageMessage) 46 setExitStatus(2) 47 exit() 48 } 49 50 // testFlagSpec defines a flag we know about. 51 type testFlagSpec struct { 52 name string 53 boolVar *bool 54 passToTest bool // pass to Test 55 multiOK bool // OK to have multiple instances 56 present bool // flag has been seen 57 } 58 59 // testFlagDefn is the set of flags we process. 60 var testFlagDefn = []*testFlagSpec{ 61 // local. 62 {name: "c", boolVar: &testC}, 63 {name: "file", multiOK: true}, 64 {name: "i", boolVar: &testI}, 65 66 // build flags. 67 {name: "a", boolVar: &buildA}, 68 {name: "n", boolVar: &buildN}, 69 {name: "p"}, 70 {name: "x", boolVar: &buildX}, 71 {name: "work", boolVar: &buildWork}, 72 {name: "gcflags"}, 73 {name: "ldflags"}, 74 {name: "gccgoflags"}, 75 {name: "tags"}, 76 {name: "compiler"}, 77 {name: "race", boolVar: &buildRace}, 78 79 // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v. 80 {name: "bench", passToTest: true}, 81 {name: "benchmem", boolVar: new(bool), passToTest: true}, 82 {name: "benchtime", passToTest: true}, 83 {name: "cpu", passToTest: true}, 84 {name: "cpuprofile", passToTest: true}, 85 {name: "memprofile", passToTest: true}, 86 {name: "memprofilerate", passToTest: true}, 87 {name: "blockprofile", passToTest: true}, 88 {name: "blockprofilerate", passToTest: true}, 89 {name: "parallel", passToTest: true}, 90 {name: "run", passToTest: true}, 91 {name: "short", boolVar: new(bool), passToTest: true}, 92 {name: "timeout", passToTest: true}, 93 {name: "v", boolVar: &testV, passToTest: true}, 94 } 95 96 // testFlags processes the command line, grabbing -x and -c, rewriting known flags 97 // to have "test" before them, and reading the command line for the 6.out. 98 // Unfortunately for us, we need to do our own flag processing because go test 99 // grabs some flags but otherwise its command line is just a holding place for 100 // pkg.test's arguments. 101 // We allow known flags both before and after the package name list, 102 // to allow both 103 // go test fmt -custom-flag-for-fmt-test 104 // go test -x math 105 func testFlags(args []string) (packageNames, passToTest []string) { 106 inPkg := false 107 for i := 0; i < len(args); i++ { 108 if !strings.HasPrefix(args[i], "-") { 109 if !inPkg && packageNames == nil { 110 // First package name we've seen. 111 inPkg = true 112 } 113 if inPkg { 114 packageNames = append(packageNames, args[i]) 115 continue 116 } 117 } 118 119 if inPkg { 120 // Found an argument beginning with "-"; end of package list. 121 inPkg = false 122 } 123 124 f, value, extraWord := testFlag(args, i) 125 if f == nil { 126 // This is a flag we do not know; we must assume 127 // that any args we see after this might be flag 128 // arguments, not package names. 129 inPkg = false 130 if packageNames == nil { 131 // make non-nil: we have seen the empty package list 132 packageNames = []string{} 133 } 134 passToTest = append(passToTest, args[i]) 135 continue 136 } 137 var err error 138 switch f.name { 139 // bool flags. 140 case "a", "c", "i", "n", "x", "v", "work", "race": 141 setBoolFlag(f.boolVar, value) 142 case "p": 143 setIntFlag(&buildP, value) 144 case "gcflags": 145 buildGcflags, err = splitQuotedFields(value) 146 if err != nil { 147 fatalf("invalid flag argument for -%s: %v", f.name, err) 148 } 149 case "ldflags": 150 buildLdflags, err = splitQuotedFields(value) 151 if err != nil { 152 fatalf("invalid flag argument for -%s: %v", f.name, err) 153 } 154 case "gccgoflags": 155 buildGccgoflags, err = splitQuotedFields(value) 156 if err != nil { 157 fatalf("invalid flag argument for -%s: %v", f.name, err) 158 } 159 case "tags": 160 buildContext.BuildTags = strings.Fields(value) 161 case "compiler": 162 buildCompiler{}.Set(value) 163 case "file": 164 testFiles = append(testFiles, value) 165 case "bench": 166 // record that we saw the flag; don't care about the value 167 testBench = true 168 case "timeout": 169 testTimeout = value 170 case "blockprofile", "cpuprofile", "memprofile": 171 testProfile = true 172 } 173 if extraWord { 174 i++ 175 } 176 if f.passToTest { 177 passToTest = append(passToTest, "-test."+f.name+"="+value) 178 } 179 } 180 return 181 } 182 183 // testFlag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word. 184 func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) { 185 arg := args[i] 186 if strings.HasPrefix(arg, "--") { // reduce two minuses to one 187 arg = arg[1:] 188 } 189 switch arg { 190 case "-?", "-h", "-help": 191 usage() 192 } 193 if arg == "" || arg[0] != '-' { 194 return 195 } 196 name := arg[1:] 197 // If there's already "test.", drop it for now. 198 name = strings.TrimPrefix(name, "test.") 199 equals := strings.Index(name, "=") 200 if equals >= 0 { 201 value = name[equals+1:] 202 name = name[:equals] 203 } 204 for _, f = range testFlagDefn { 205 if name == f.name { 206 // Booleans are special because they have modes -x, -x=true, -x=false. 207 if f.boolVar != nil { 208 if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag 209 value = "true" 210 } else { 211 // verify it parses 212 setBoolFlag(new(bool), value) 213 } 214 } else { // Non-booleans must have a value. 215 extra = equals < 0 216 if extra { 217 if i+1 >= len(args) { 218 usage() 219 } 220 value = args[i+1] 221 } 222 } 223 if f.present && !f.multiOK { 224 usage() 225 } 226 f.present = true 227 return 228 } 229 } 230 f = nil 231 return 232 } 233 234 // setBoolFlag sets the addressed boolean to the value. 235 func setBoolFlag(flag *bool, value string) { 236 x, err := strconv.ParseBool(value) 237 if err != nil { 238 fmt.Fprintf(os.Stderr, "go test: illegal bool flag value %s\n", value) 239 usage() 240 } 241 *flag = x 242 } 243 244 // setIntFlag sets the addressed integer to the value. 245 func setIntFlag(flag *int, value string) { 246 x, err := strconv.Atoi(value) 247 if err != nil { 248 fmt.Fprintf(os.Stderr, "go test: illegal int flag value %s\n", value) 249 usage() 250 } 251 *flag = x 252 }