Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unit test command line flags in Go?

I would like a unit test that verifies a particular command line flag is within an enumeration.

Here is the code I would like to write tests against:

var formatType string

const (
    text = "text"
    json = "json"
    hash = "hash"
)

func init() {
    const (
        defaultFormat = "text"
        formatUsage   = "desired output format"
    )

    flag.StringVar(&formatType, "format", defaultFormat, formatUsage)
    flag.StringVar(&formatType, "f", defaultFormat, formatUsage+" (shorthand)")

}

func main() {
    flag.Parse()
}

The desired test would pass only if -format equalled one of the const values given above. This value would be available in formatType. An example correct call would be: program -format text

What is the best way to test the desired behaviors?

Note: Perhaps I have phrased this poorly, but the displayed code it not the unit test itself, but the code I want to write unit tests against. This is a simple example from the tool I am writing and wanted to ask if there were a good way to test valid inputs to the tool.

like image 890
KevDog Avatar asked Jul 01 '13 20:07

KevDog


People also ask

How do you use the flag package in go?

Using the flag package involves three steps: First, define variables to capture flag values, then define the flags your Go application will use, and finally, parse the flags provided to the application upon execution.

How do I get command line arguments in Golang?

To access all command-line arguments in their raw format, we need to use Args variables imported from the os package . This type of variable is a string ( [] ) slice. Args is an argument that starts with the name of the program in the command-line. The first value in the Args slice is the name of our program, while os.

How do you use the flag command?

Command-line flags Bool() , flag.Int() , etc. After you've defined your flags, you need to call flag. Parse() . This call will execute command-line parsing and will let you use the flags.


1 Answers

Custom testing and processing of flags can be achieved with the flag.Var function in the flag package.

Flag.Var "defines a flag with the specified name and usage string. The type and value of the flag are represented by the first argument, of type Value, which typically holds a user-defined implementation of Value."

A flag.Value is any type that satisfies the Value interface, defined as:

type Value interface {
    String() string
    Set(string) error
}

There is a good example in the example_test.go file in the flag package source

For your use case you could use something like:

package main

import (
    "errors"
    "flag"
    "fmt"
)

type formatType string

func (f *formatType) String() string {
    return fmt.Sprint(*f)
}

func (f *formatType) Set(value string) error {
    if len(*f) > 0 && *f != "text" {
        return errors.New("format flag already set")
    }
    if value != "text" && value != "json" && value != "hash" {
        return errors.New("Invalid Format Type")
    }
    *f = formatType(value)
    return nil
}

var typeFlag formatType

func init() {
    typeFlag = "text"
    usage := `Format type. Must be "text", "json" or "hash". Defaults to "text".`
    flag.Var(&typeFlag, "format", usage)
    flag.Var(&typeFlag, "f", usage+" (shorthand)")
}

func main() {
    flag.Parse()
    fmt.Println("Format type is", typeFlag)
}

This is probably overkill for such a simple example, but may be very useful when defining more complex flag types (The linked example converts a comma separated list of intervals into a slice of a custom type based on time.Duration).

EDIT: In answer to how to run unit tests against flags, the most canonical example is flag_test.go in the flag package source. The section related to testing custom flag variables starts at Line 181.

like image 141
Intermernet Avatar answered Oct 25 '22 06:10

Intermernet