Search code examples
gocommand-lineflags

How to unset flags Visited on command line in GoLang for Tests


I'm trying to run tests which call the same function multiple times with different arguments each time. This is an application that accepts different command line flags. If no commandline flag is supplied then the default value is used.

flagset = make(map[string]bool)
flagset["flag1"] = false
flagset["flag2"] = false
flagset["flag3"] = false
flagset["flag4"] = false
func LoadCommandLineArguments(args []string) error{
        err := flag.CommandLine.Parse(args)
        /*Do error handling
         */
       flag.Visit(func(f *flag.Flag) { flagset[f.Name] = true })
       // Iterate through all the flags and set their default values whatever was not passed on the commandline.
}

func resetFlags(){
/* Reset flag variables to their original default values and set map values to false */
flagset["flag1"] = false
flagset["flag2"] = false
flagset["flag3"] = false
flagset["flag4"] = false
}

I have different test functions each of which supply different flags for tests. Eg: This is how my test file looks like

func TestFlag1(t *testing.T) {
   resetFlags()
   err := LoadCommandLineArguments([]string{"-flag1=somevalue1"})
}
func TestFlag2(t *testing.T) {
resetFlags()
err := LoadCommandLineArguments([]string{"-flag2=somevalue2"})
}
func TestFlag3(t *testing.T) {
resetFlags()
err := LoadCommandLineArguments([]string{"-flag3=somevalue3"})
}
func TestFlag4(t *testing.T) {
resetFlags()
err := LoadCommandLineArguments([]string{""})
}

Whenever I run my test file and each unit test separately all of them seem to work fine. But when I run the whole file test file together, by the time it reaches testFlag4, in LoadCommandLineArguments, it Visits all the flags and thinks all of them were passed on the commandline even though I'm resetting them at the beginning of each test function.

In TestFlag1 it thinks flag1 was passed.

In TestFlag2 it thinks flag1 and flag2 were passed.

In TestFlag3, it thinks flag1, flag2, flag3 were passed.

Similarly, in TestFlag4, it thinks flag1 was also passed, flag2 was also passed, flag3 was also passed, when I didn't pass anything. I want this test to have no command line flags passed. The flags.Visit function should not be able to get true for any of the flags.

I know by setting my map values to false, I'm not actually unsetting the command line values passed but then whats the way to do this?

Is there a way to Unvisit / Unset commandline flags in Golang? Any help will be appreciated.

Thanks.


Solution

  • Based on the source code for flag this should work (you'll need to add os to your imports):

    flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) //flags are now reset
    

    Also, a couple things, as a matter of style:

    Maps return the type's zero value when a key is not found. Zero values for types are 0 for int, "" for string, false for bool, etc.

    So all of these init / reset lines can be deleted:

    flagset = make(map[string]bool)
    // the initialization lines are not needed; bool already initalizes to false:
    //flagset["flag1"] = false
    //...
    
    func LoadCommandLineArguments(args []string) error{
       //...
    }
    
    func resetFlags(){
       /* Reset flag variables */
       flagset = make(map[string]bool)//just make a new map
    }