github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-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  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/base"
    13  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg"
    14  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/cmdflag"
    15  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/str"
    16  	"github.com/gagliardetto/golang-go/cmd/go/not-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  	{Name: "json", BoolVar: &testJSON},
    37  	{Name: "vet"},
    38  
    39  	// Passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
    40  	{Name: "bench", PassToTest: true},
    41  	{Name: "benchmem", BoolVar: new(bool), PassToTest: true},
    42  	{Name: "benchtime", PassToTest: true},
    43  	{Name: "blockprofile", PassToTest: true},
    44  	{Name: "blockprofilerate", PassToTest: true},
    45  	{Name: "count", PassToTest: true},
    46  	{Name: "coverprofile", PassToTest: true},
    47  	{Name: "cpu", PassToTest: true},
    48  	{Name: "cpuprofile", PassToTest: true},
    49  	{Name: "failfast", BoolVar: new(bool), PassToTest: true},
    50  	{Name: "list", PassToTest: true},
    51  	{Name: "memprofile", PassToTest: true},
    52  	{Name: "memprofilerate", PassToTest: true},
    53  	{Name: "mutexprofile", PassToTest: true},
    54  	{Name: "mutexprofilefraction", PassToTest: true},
    55  	{Name: "outputdir", PassToTest: true},
    56  	{Name: "parallel", PassToTest: true},
    57  	{Name: "run", PassToTest: true},
    58  	{Name: "short", BoolVar: new(bool), PassToTest: true},
    59  	{Name: "timeout", PassToTest: true},
    60  	{Name: "trace", PassToTest: true},
    61  	{Name: "v", BoolVar: &testV, PassToTest: true},
    62  }
    63  
    64  // add build flags to testFlagDefn
    65  func init() {
    66  	cmdflag.AddKnownFlags("test", testFlagDefn)
    67  	var cmd base.Command
    68  	work.AddBuildFlags(&cmd, work.DefaultBuildFlags)
    69  	cmd.Flag.VisitAll(func(f *flag.Flag) {
    70  		if f.Name == "v" {
    71  			// test overrides the build -v flag
    72  			return
    73  		}
    74  		testFlagDefn = append(testFlagDefn, &cmdflag.Defn{
    75  			Name:  f.Name,
    76  			Value: f.Value,
    77  		})
    78  	})
    79  }
    80  
    81  // testFlags processes the command line, grabbing -x and -c, rewriting known flags
    82  // to have "test" before them, and reading the command line for the 6.out.
    83  // Unfortunately for us, we need to do our own flag processing because go test
    84  // grabs some flags but otherwise its command line is just a holding place for
    85  // pkg.test's arguments.
    86  // We allow known flags both before and after the package name list,
    87  // to allow both
    88  //	go test fmt -custom-flag-for-fmt-test
    89  //	go test -x math
    90  func testFlags(usage func(), args []string) (packageNames, passToTest []string) {
    91  	goflags := cmdflag.FindGOFLAGS(testFlagDefn)
    92  	args = str.StringList(goflags, args)
    93  	inPkg := false
    94  	var explicitArgs []string
    95  	for i := 0; i < len(args); i++ {
    96  		if !strings.HasPrefix(args[i], "-") {
    97  			if !inPkg && packageNames == nil {
    98  				// First package name we've seen.
    99  				inPkg = true
   100  			}
   101  			if inPkg {
   102  				packageNames = append(packageNames, args[i])
   103  				continue
   104  			}
   105  		}
   106  
   107  		if inPkg {
   108  			// Found an argument beginning with "-"; end of package list.
   109  			inPkg = false
   110  		}
   111  
   112  		f, value, extraWord := cmdflag.Parse(cmd, usage, testFlagDefn, args, i)
   113  		if f == nil {
   114  			// This is a flag we do not know; we must assume
   115  			// that any args we see after this might be flag
   116  			// arguments, not package names.
   117  			inPkg = false
   118  			if packageNames == nil {
   119  				// make non-nil: we have seen the empty package list
   120  				packageNames = []string{}
   121  			}
   122  			if args[i] == "-args" || args[i] == "--args" {
   123  				// -args or --args signals that everything that follows
   124  				// should be passed to the test.
   125  				explicitArgs = args[i+1:]
   126  				break
   127  			}
   128  			passToTest = append(passToTest, args[i])
   129  			continue
   130  		}
   131  		if i < len(goflags) {
   132  			f.Present = false // Not actually present on the command line.
   133  		}
   134  		if f.Value != nil {
   135  			if err := f.Value.Set(value); err != nil {
   136  				base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
   137  			}
   138  		} else {
   139  			// Test-only flags.
   140  			// Arguably should be handled by f.Value, but aren't.
   141  			switch f.Name {
   142  			// bool flags.
   143  			case "c", "i", "v", "cover", "json":
   144  				cmdflag.SetBool(cmd, f.BoolVar, value)
   145  				if f.Name == "json" && testJSON {
   146  					passToTest = append(passToTest, "-test.v=true")
   147  				}
   148  			case "o":
   149  				testO = value
   150  				testNeedBinary = true
   151  			case "exec":
   152  				xcmd, err := str.SplitQuotedFields(value)
   153  				if err != nil {
   154  					base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
   155  				}
   156  				work.ExecCmd = xcmd
   157  			case "bench":
   158  				// record that we saw the flag; don't care about the value
   159  				testBench = true
   160  			case "list":
   161  				testList = true
   162  			case "timeout":
   163  				testTimeout = value
   164  			case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
   165  				testProfile = "-" + f.Name
   166  				testNeedBinary = true
   167  			case "trace":
   168  				testProfile = "-trace"
   169  			case "coverpkg":
   170  				testCover = true
   171  				if value == "" {
   172  					testCoverPaths = nil
   173  				} else {
   174  					testCoverPaths = strings.Split(value, ",")
   175  				}
   176  			case "coverprofile":
   177  				testCover = true
   178  				testCoverProfile = value
   179  			case "covermode":
   180  				switch value {
   181  				case "set", "count", "atomic":
   182  					testCoverMode = value
   183  				default:
   184  					base.Fatalf("invalid flag argument for -covermode: %q", value)
   185  				}
   186  				testCover = true
   187  			case "outputdir":
   188  				testOutputDir = value
   189  			case "vet":
   190  				testVetList = value
   191  			}
   192  		}
   193  		if extraWord {
   194  			i++
   195  		}
   196  		if f.PassToTest {
   197  			passToTest = append(passToTest, "-test."+f.Name+"="+value)
   198  		}
   199  	}
   200  
   201  	if testCoverMode == "" {
   202  		testCoverMode = "set"
   203  		if cfg.BuildRace {
   204  			// Default coverage mode is atomic when -race is set.
   205  			testCoverMode = "atomic"
   206  		}
   207  	}
   208  
   209  	testVetExplicit = testVetList != ""
   210  	if testVetList != "" && testVetList != "off" {
   211  		if strings.Contains(testVetList, "=") {
   212  			base.Fatalf("-vet argument cannot contain equal signs")
   213  		}
   214  		if strings.Contains(testVetList, " ") {
   215  			base.Fatalf("-vet argument is comma-separated list, cannot contain spaces")
   216  		}
   217  		list := strings.Split(testVetList, ",")
   218  		for i, arg := range list {
   219  			list[i] = "-" + arg
   220  		}
   221  		testVetFlags = list
   222  	}
   223  
   224  	if cfg.BuildRace && testCoverMode != "atomic" {
   225  		base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode)
   226  	}
   227  
   228  	// Tell the test what directory we're running in, so it can write the profiles there.
   229  	if testProfile != "" && testOutputDir == "" {
   230  		dir, err := os.Getwd()
   231  		if err != nil {
   232  			base.Fatalf("error from os.Getwd: %s", err)
   233  		}
   234  		passToTest = append(passToTest, "-test.outputdir", dir)
   235  	}
   236  
   237  	passToTest = append(passToTest, explicitArgs...)
   238  	return
   239  }