1// 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
5package pflag
6
7import (
8	"bytes"
9	"strconv"
10	"testing"
11)
12
13// This value can be a boolean ("true", "false") or "maybe"
14type triStateValue int
15
16const (
17	triStateFalse triStateValue = 0
18	triStateTrue  triStateValue = 1
19	triStateMaybe triStateValue = 2
20)
21
22const strTriStateMaybe = "maybe"
23
24func (v *triStateValue) IsBoolFlag() bool {
25	return true
26}
27
28func (v *triStateValue) Get() interface{} {
29	return triStateValue(*v)
30}
31
32func (v *triStateValue) Set(s string) error {
33	if s == strTriStateMaybe {
34		*v = triStateMaybe
35		return nil
36	}
37	boolVal, err := strconv.ParseBool(s)
38	if boolVal {
39		*v = triStateTrue
40	} else {
41		*v = triStateFalse
42	}
43	return err
44}
45
46func (v *triStateValue) String() string {
47	if *v == triStateMaybe {
48		return strTriStateMaybe
49	}
50	return strconv.FormatBool(*v == triStateTrue)
51}
52
53// The type of the flag as required by the pflag.Value interface
54func (v *triStateValue) Type() string {
55	return "version"
56}
57
58func setUpFlagSet(tristate *triStateValue) *FlagSet {
59	f := NewFlagSet("test", ContinueOnError)
60	*tristate = triStateFalse
61	flag := f.VarPF(tristate, "tristate", "t", "tristate value (true, maybe or false)")
62	flag.NoOptDefVal = "true"
63	return f
64}
65
66func TestExplicitTrue(t *testing.T) {
67	var tristate triStateValue
68	f := setUpFlagSet(&tristate)
69	err := f.Parse([]string{"--tristate=true"})
70	if err != nil {
71		t.Fatal("expected no error; got", err)
72	}
73	if tristate != triStateTrue {
74		t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
75	}
76}
77
78func TestImplicitTrue(t *testing.T) {
79	var tristate triStateValue
80	f := setUpFlagSet(&tristate)
81	err := f.Parse([]string{"--tristate"})
82	if err != nil {
83		t.Fatal("expected no error; got", err)
84	}
85	if tristate != triStateTrue {
86		t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
87	}
88}
89
90func TestShortFlag(t *testing.T) {
91	var tristate triStateValue
92	f := setUpFlagSet(&tristate)
93	err := f.Parse([]string{"-t"})
94	if err != nil {
95		t.Fatal("expected no error; got", err)
96	}
97	if tristate != triStateTrue {
98		t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
99	}
100}
101
102func TestShortFlagExtraArgument(t *testing.T) {
103	var tristate triStateValue
104	f := setUpFlagSet(&tristate)
105	// The"maybe"turns into an arg, since short boolean options will only do true/false
106	err := f.Parse([]string{"-t", "maybe"})
107	if err != nil {
108		t.Fatal("expected no error; got", err)
109	}
110	if tristate != triStateTrue {
111		t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
112	}
113	args := f.Args()
114	if len(args) != 1 || args[0] != "maybe" {
115		t.Fatal("expected an extra 'maybe' argument to stick around")
116	}
117}
118
119func TestExplicitMaybe(t *testing.T) {
120	var tristate triStateValue
121	f := setUpFlagSet(&tristate)
122	err := f.Parse([]string{"--tristate=maybe"})
123	if err != nil {
124		t.Fatal("expected no error; got", err)
125	}
126	if tristate != triStateMaybe {
127		t.Fatal("expected", triStateMaybe, "(triStateMaybe) but got", tristate, "instead")
128	}
129}
130
131func TestExplicitFalse(t *testing.T) {
132	var tristate triStateValue
133	f := setUpFlagSet(&tristate)
134	err := f.Parse([]string{"--tristate=false"})
135	if err != nil {
136		t.Fatal("expected no error; got", err)
137	}
138	if tristate != triStateFalse {
139		t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead")
140	}
141}
142
143func TestImplicitFalse(t *testing.T) {
144	var tristate triStateValue
145	f := setUpFlagSet(&tristate)
146	err := f.Parse([]string{})
147	if err != nil {
148		t.Fatal("expected no error; got", err)
149	}
150	if tristate != triStateFalse {
151		t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead")
152	}
153}
154
155func TestInvalidValue(t *testing.T) {
156	var tristate triStateValue
157	f := setUpFlagSet(&tristate)
158	var buf bytes.Buffer
159	f.SetOutput(&buf)
160	err := f.Parse([]string{"--tristate=invalid"})
161	if err == nil {
162		t.Fatal("expected an error but did not get any, tristate has value", tristate)
163	}
164}
165
166func TestBoolP(t *testing.T) {
167	b := BoolP("bool", "b", false, "bool value in CommandLine")
168	c := BoolP("c", "c", false, "other bool value")
169	args := []string{"--bool"}
170	if err := CommandLine.Parse(args); err != nil {
171		t.Error("expected no error, got ", err)
172	}
173	if *b != true {
174		t.Errorf("expected b=true got b=%v", *b)
175	}
176	if *c != false {
177		t.Errorf("expect c=false got c=%v", *c)
178	}
179}
180