| 1 |
747 |
jeremybenn |
// Copyright 2009 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 flag_test
|
| 6 |
|
|
|
| 7 |
|
|
import (
|
| 8 |
|
|
"bytes"
|
| 9 |
|
|
. "flag"
|
| 10 |
|
|
"fmt"
|
| 11 |
|
|
"os"
|
| 12 |
|
|
"sort"
|
| 13 |
|
|
"strings"
|
| 14 |
|
|
"testing"
|
| 15 |
|
|
"time"
|
| 16 |
|
|
)
|
| 17 |
|
|
|
| 18 |
|
|
var (
|
| 19 |
|
|
test_bool = Bool("test_bool", false, "bool value")
|
| 20 |
|
|
test_int = Int("test_int", 0, "int value")
|
| 21 |
|
|
test_int64 = Int64("test_int64", 0, "int64 value")
|
| 22 |
|
|
test_uint = Uint("test_uint", 0, "uint value")
|
| 23 |
|
|
test_uint64 = Uint64("test_uint64", 0, "uint64 value")
|
| 24 |
|
|
test_string = String("test_string", "0", "string value")
|
| 25 |
|
|
test_float64 = Float64("test_float64", 0, "float64 value")
|
| 26 |
|
|
test_duration = Duration("test_duration", 0, "time.Duration value")
|
| 27 |
|
|
)
|
| 28 |
|
|
|
| 29 |
|
|
func boolString(s string) string {
|
| 30 |
|
|
if s == "0" {
|
| 31 |
|
|
return "false"
|
| 32 |
|
|
}
|
| 33 |
|
|
return "true"
|
| 34 |
|
|
}
|
| 35 |
|
|
|
| 36 |
|
|
func TestEverything(t *testing.T) {
|
| 37 |
|
|
m := make(map[string]*Flag)
|
| 38 |
|
|
desired := "0"
|
| 39 |
|
|
visitor := func(f *Flag) {
|
| 40 |
|
|
if len(f.Name) > 5 && f.Name[0:5] == "test_" {
|
| 41 |
|
|
m[f.Name] = f
|
| 42 |
|
|
ok := false
|
| 43 |
|
|
switch {
|
| 44 |
|
|
case f.Value.String() == desired:
|
| 45 |
|
|
ok = true
|
| 46 |
|
|
case f.Name == "test_bool" && f.Value.String() == boolString(desired):
|
| 47 |
|
|
ok = true
|
| 48 |
|
|
case f.Name == "test_duration" && f.Value.String() == desired+"s":
|
| 49 |
|
|
ok = true
|
| 50 |
|
|
}
|
| 51 |
|
|
if !ok {
|
| 52 |
|
|
t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
|
| 53 |
|
|
}
|
| 54 |
|
|
}
|
| 55 |
|
|
}
|
| 56 |
|
|
VisitAll(visitor)
|
| 57 |
|
|
if len(m) != 8 {
|
| 58 |
|
|
t.Error("VisitAll misses some flags")
|
| 59 |
|
|
for k, v := range m {
|
| 60 |
|
|
t.Log(k, *v)
|
| 61 |
|
|
}
|
| 62 |
|
|
}
|
| 63 |
|
|
m = make(map[string]*Flag)
|
| 64 |
|
|
Visit(visitor)
|
| 65 |
|
|
if len(m) != 0 {
|
| 66 |
|
|
t.Errorf("Visit sees unset flags")
|
| 67 |
|
|
for k, v := range m {
|
| 68 |
|
|
t.Log(k, *v)
|
| 69 |
|
|
}
|
| 70 |
|
|
}
|
| 71 |
|
|
// Now set all flags
|
| 72 |
|
|
Set("test_bool", "true")
|
| 73 |
|
|
Set("test_int", "1")
|
| 74 |
|
|
Set("test_int64", "1")
|
| 75 |
|
|
Set("test_uint", "1")
|
| 76 |
|
|
Set("test_uint64", "1")
|
| 77 |
|
|
Set("test_string", "1")
|
| 78 |
|
|
Set("test_float64", "1")
|
| 79 |
|
|
Set("test_duration", "1s")
|
| 80 |
|
|
desired = "1"
|
| 81 |
|
|
Visit(visitor)
|
| 82 |
|
|
if len(m) != 8 {
|
| 83 |
|
|
t.Error("Visit fails after set")
|
| 84 |
|
|
for k, v := range m {
|
| 85 |
|
|
t.Log(k, *v)
|
| 86 |
|
|
}
|
| 87 |
|
|
}
|
| 88 |
|
|
// Now test they're visited in sort order.
|
| 89 |
|
|
var flagNames []string
|
| 90 |
|
|
Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
|
| 91 |
|
|
if !sort.StringsAreSorted(flagNames) {
|
| 92 |
|
|
t.Errorf("flag names not sorted: %v", flagNames)
|
| 93 |
|
|
}
|
| 94 |
|
|
}
|
| 95 |
|
|
|
| 96 |
|
|
func TestUsage(t *testing.T) {
|
| 97 |
|
|
called := false
|
| 98 |
|
|
ResetForTesting(func() { called = true })
|
| 99 |
|
|
if CommandLine().Parse([]string{"-x"}) == nil {
|
| 100 |
|
|
t.Error("parse did not fail for unknown flag")
|
| 101 |
|
|
}
|
| 102 |
|
|
if !called {
|
| 103 |
|
|
t.Error("did not call Usage for unknown flag")
|
| 104 |
|
|
}
|
| 105 |
|
|
}
|
| 106 |
|
|
|
| 107 |
|
|
func testParse(f *FlagSet, t *testing.T) {
|
| 108 |
|
|
if f.Parsed() {
|
| 109 |
|
|
t.Error("f.Parse() = true before Parse")
|
| 110 |
|
|
}
|
| 111 |
|
|
boolFlag := f.Bool("bool", false, "bool value")
|
| 112 |
|
|
bool2Flag := f.Bool("bool2", false, "bool2 value")
|
| 113 |
|
|
intFlag := f.Int("int", 0, "int value")
|
| 114 |
|
|
int64Flag := f.Int64("int64", 0, "int64 value")
|
| 115 |
|
|
uintFlag := f.Uint("uint", 0, "uint value")
|
| 116 |
|
|
uint64Flag := f.Uint64("uint64", 0, "uint64 value")
|
| 117 |
|
|
stringFlag := f.String("string", "0", "string value")
|
| 118 |
|
|
float64Flag := f.Float64("float64", 0, "float64 value")
|
| 119 |
|
|
durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
|
| 120 |
|
|
extra := "one-extra-argument"
|
| 121 |
|
|
args := []string{
|
| 122 |
|
|
"-bool",
|
| 123 |
|
|
"-bool2=true",
|
| 124 |
|
|
"--int", "22",
|
| 125 |
|
|
"--int64", "0x23",
|
| 126 |
|
|
"-uint", "24",
|
| 127 |
|
|
"--uint64", "25",
|
| 128 |
|
|
"-string", "hello",
|
| 129 |
|
|
"-float64", "2718e28",
|
| 130 |
|
|
"-duration", "2m",
|
| 131 |
|
|
extra,
|
| 132 |
|
|
}
|
| 133 |
|
|
if err := f.Parse(args); err != nil {
|
| 134 |
|
|
t.Fatal(err)
|
| 135 |
|
|
}
|
| 136 |
|
|
if !f.Parsed() {
|
| 137 |
|
|
t.Error("f.Parse() = false after Parse")
|
| 138 |
|
|
}
|
| 139 |
|
|
if *boolFlag != true {
|
| 140 |
|
|
t.Error("bool flag should be true, is ", *boolFlag)
|
| 141 |
|
|
}
|
| 142 |
|
|
if *bool2Flag != true {
|
| 143 |
|
|
t.Error("bool2 flag should be true, is ", *bool2Flag)
|
| 144 |
|
|
}
|
| 145 |
|
|
if *intFlag != 22 {
|
| 146 |
|
|
t.Error("int flag should be 22, is ", *intFlag)
|
| 147 |
|
|
}
|
| 148 |
|
|
if *int64Flag != 0x23 {
|
| 149 |
|
|
t.Error("int64 flag should be 0x23, is ", *int64Flag)
|
| 150 |
|
|
}
|
| 151 |
|
|
if *uintFlag != 24 {
|
| 152 |
|
|
t.Error("uint flag should be 24, is ", *uintFlag)
|
| 153 |
|
|
}
|
| 154 |
|
|
if *uint64Flag != 25 {
|
| 155 |
|
|
t.Error("uint64 flag should be 25, is ", *uint64Flag)
|
| 156 |
|
|
}
|
| 157 |
|
|
if *stringFlag != "hello" {
|
| 158 |
|
|
t.Error("string flag should be `hello`, is ", *stringFlag)
|
| 159 |
|
|
}
|
| 160 |
|
|
if *float64Flag != 2718e28 {
|
| 161 |
|
|
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
|
| 162 |
|
|
}
|
| 163 |
|
|
if *durationFlag != 2*time.Minute {
|
| 164 |
|
|
t.Error("duration flag should be 2m, is ", *durationFlag)
|
| 165 |
|
|
}
|
| 166 |
|
|
if len(f.Args()) != 1 {
|
| 167 |
|
|
t.Error("expected one argument, got", len(f.Args()))
|
| 168 |
|
|
} else if f.Args()[0] != extra {
|
| 169 |
|
|
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
| 170 |
|
|
}
|
| 171 |
|
|
}
|
| 172 |
|
|
|
| 173 |
|
|
func TestParse(t *testing.T) {
|
| 174 |
|
|
ResetForTesting(func() { t.Error("bad parse") })
|
| 175 |
|
|
testParse(CommandLine(), t)
|
| 176 |
|
|
}
|
| 177 |
|
|
|
| 178 |
|
|
func TestFlagSetParse(t *testing.T) {
|
| 179 |
|
|
testParse(NewFlagSet("test", ContinueOnError), t)
|
| 180 |
|
|
}
|
| 181 |
|
|
|
| 182 |
|
|
// Declare a user-defined flag type.
|
| 183 |
|
|
type flagVar []string
|
| 184 |
|
|
|
| 185 |
|
|
func (f *flagVar) String() string {
|
| 186 |
|
|
return fmt.Sprint([]string(*f))
|
| 187 |
|
|
}
|
| 188 |
|
|
|
| 189 |
|
|
func (f *flagVar) Set(value string) error {
|
| 190 |
|
|
*f = append(*f, value)
|
| 191 |
|
|
return nil
|
| 192 |
|
|
}
|
| 193 |
|
|
|
| 194 |
|
|
func TestUserDefined(t *testing.T) {
|
| 195 |
|
|
var flags FlagSet
|
| 196 |
|
|
flags.Init("test", ContinueOnError)
|
| 197 |
|
|
var v flagVar
|
| 198 |
|
|
flags.Var(&v, "v", "usage")
|
| 199 |
|
|
if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
|
| 200 |
|
|
t.Error(err)
|
| 201 |
|
|
}
|
| 202 |
|
|
if len(v) != 3 {
|
| 203 |
|
|
t.Fatal("expected 3 args; got ", len(v))
|
| 204 |
|
|
}
|
| 205 |
|
|
expect := "[1 2 3]"
|
| 206 |
|
|
if v.String() != expect {
|
| 207 |
|
|
t.Errorf("expected value %q got %q", expect, v.String())
|
| 208 |
|
|
}
|
| 209 |
|
|
}
|
| 210 |
|
|
|
| 211 |
|
|
func TestSetOutput(t *testing.T) {
|
| 212 |
|
|
var flags FlagSet
|
| 213 |
|
|
var buf bytes.Buffer
|
| 214 |
|
|
flags.SetOutput(&buf)
|
| 215 |
|
|
flags.Init("test", ContinueOnError)
|
| 216 |
|
|
flags.Parse([]string{"-unknown"})
|
| 217 |
|
|
if out := buf.String(); !strings.Contains(out, "-unknown") {
|
| 218 |
|
|
t.Logf("expected output mentioning unknown; got %q", out)
|
| 219 |
|
|
}
|
| 220 |
|
|
}
|
| 221 |
|
|
|
| 222 |
|
|
// This tests that one can reset the flags. This still works but not well, and is
|
| 223 |
|
|
// superseded by FlagSet.
|
| 224 |
|
|
func TestChangingArgs(t *testing.T) {
|
| 225 |
|
|
ResetForTesting(func() { t.Fatal("bad parse") })
|
| 226 |
|
|
oldArgs := os.Args
|
| 227 |
|
|
defer func() { os.Args = oldArgs }()
|
| 228 |
|
|
os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
|
| 229 |
|
|
before := Bool("before", false, "")
|
| 230 |
|
|
if err := CommandLine().Parse(os.Args[1:]); err != nil {
|
| 231 |
|
|
t.Fatal(err)
|
| 232 |
|
|
}
|
| 233 |
|
|
cmd := Arg(0)
|
| 234 |
|
|
os.Args = Args()
|
| 235 |
|
|
after := Bool("after", false, "")
|
| 236 |
|
|
Parse()
|
| 237 |
|
|
args := Args()
|
| 238 |
|
|
|
| 239 |
|
|
if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
|
| 240 |
|
|
t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
|
| 241 |
|
|
}
|
| 242 |
|
|
}
|
| 243 |
|
|
|
| 244 |
|
|
// Test that -help invokes the usage message and returns ErrHelp.
|
| 245 |
|
|
func TestHelp(t *testing.T) {
|
| 246 |
|
|
var helpCalled = false
|
| 247 |
|
|
fs := NewFlagSet("help test", ContinueOnError)
|
| 248 |
|
|
fs.Usage = func() { helpCalled = true }
|
| 249 |
|
|
var flag bool
|
| 250 |
|
|
fs.BoolVar(&flag, "flag", false, "regular flag")
|
| 251 |
|
|
// Regular flag invocation should work
|
| 252 |
|
|
err := fs.Parse([]string{"-flag=true"})
|
| 253 |
|
|
if err != nil {
|
| 254 |
|
|
t.Fatal("expected no error; got ", err)
|
| 255 |
|
|
}
|
| 256 |
|
|
if !flag {
|
| 257 |
|
|
t.Error("flag was not set by -flag")
|
| 258 |
|
|
}
|
| 259 |
|
|
if helpCalled {
|
| 260 |
|
|
t.Error("help called for regular flag")
|
| 261 |
|
|
helpCalled = false // reset for next test
|
| 262 |
|
|
}
|
| 263 |
|
|
// Help flag should work as expected.
|
| 264 |
|
|
err = fs.Parse([]string{"-help"})
|
| 265 |
|
|
if err == nil {
|
| 266 |
|
|
t.Fatal("error expected")
|
| 267 |
|
|
}
|
| 268 |
|
|
if err != ErrHelp {
|
| 269 |
|
|
t.Fatal("expected ErrHelp; got ", err)
|
| 270 |
|
|
}
|
| 271 |
|
|
if !helpCalled {
|
| 272 |
|
|
t.Fatal("help was not called")
|
| 273 |
|
|
}
|
| 274 |
|
|
// If we define a help flag, that should override.
|
| 275 |
|
|
var help bool
|
| 276 |
|
|
fs.BoolVar(&help, "help", false, "help flag")
|
| 277 |
|
|
helpCalled = false
|
| 278 |
|
|
err = fs.Parse([]string{"-help"})
|
| 279 |
|
|
if err != nil {
|
| 280 |
|
|
t.Fatal("expected no error for defined -help; got ", err)
|
| 281 |
|
|
}
|
| 282 |
|
|
if helpCalled {
|
| 283 |
|
|
t.Fatal("help was called; should not have been for defined help flag")
|
| 284 |
|
|
}
|
| 285 |
|
|
}
|