1package cli
2
3import (
4	"flag"
5	"os"
6	"testing"
7	"time"
8)
9
10func TestNewContext(t *testing.T) {
11	set := flag.NewFlagSet("test", 0)
12	set.Int("myflag", 12, "doc")
13	set.Int64("myflagInt64", int64(12), "doc")
14	set.Uint("myflagUint", uint(93), "doc")
15	set.Uint64("myflagUint64", uint64(93), "doc")
16	set.Float64("myflag64", float64(17), "doc")
17	globalSet := flag.NewFlagSet("test", 0)
18	globalSet.Int("myflag", 42, "doc")
19	globalSet.Int64("myflagInt64", int64(42), "doc")
20	globalSet.Uint("myflagUint", uint(33), "doc")
21	globalSet.Uint64("myflagUint64", uint64(33), "doc")
22	globalSet.Float64("myflag64", float64(47), "doc")
23	globalCtx := NewContext(nil, globalSet, nil)
24	command := Command{Name: "mycommand"}
25	c := NewContext(nil, set, globalCtx)
26	c.Command = command
27	expect(t, c.Int("myflag"), 12)
28	expect(t, c.Int64("myflagInt64"), int64(12))
29	expect(t, c.Uint("myflagUint"), uint(93))
30	expect(t, c.Uint64("myflagUint64"), uint64(93))
31	expect(t, c.Float64("myflag64"), float64(17))
32	expect(t, c.GlobalInt("myflag"), 42)
33	expect(t, c.GlobalInt64("myflagInt64"), int64(42))
34	expect(t, c.GlobalUint("myflagUint"), uint(33))
35	expect(t, c.GlobalUint64("myflagUint64"), uint64(33))
36	expect(t, c.GlobalFloat64("myflag64"), float64(47))
37	expect(t, c.Command.Name, "mycommand")
38}
39
40func TestContext_Int(t *testing.T) {
41	set := flag.NewFlagSet("test", 0)
42	set.Int("myflag", 12, "doc")
43	c := NewContext(nil, set, nil)
44	expect(t, c.Int("myflag"), 12)
45}
46
47func TestContext_Int64(t *testing.T) {
48	set := flag.NewFlagSet("test", 0)
49	set.Int64("myflagInt64", 12, "doc")
50	c := NewContext(nil, set, nil)
51	expect(t, c.Int64("myflagInt64"), int64(12))
52}
53
54func TestContext_Uint(t *testing.T) {
55	set := flag.NewFlagSet("test", 0)
56	set.Uint("myflagUint", uint(13), "doc")
57	c := NewContext(nil, set, nil)
58	expect(t, c.Uint("myflagUint"), uint(13))
59}
60
61func TestContext_Uint64(t *testing.T) {
62	set := flag.NewFlagSet("test", 0)
63	set.Uint64("myflagUint64", uint64(9), "doc")
64	c := NewContext(nil, set, nil)
65	expect(t, c.Uint64("myflagUint64"), uint64(9))
66}
67
68func TestContext_GlobalInt(t *testing.T) {
69	set := flag.NewFlagSet("test", 0)
70	set.Int("myflag", 12, "doc")
71	c := NewContext(nil, set, nil)
72	expect(t, c.GlobalInt("myflag"), 12)
73	expect(t, c.GlobalInt("nope"), 0)
74}
75
76func TestContext_GlobalInt64(t *testing.T) {
77	set := flag.NewFlagSet("test", 0)
78	set.Int64("myflagInt64", 12, "doc")
79	c := NewContext(nil, set, nil)
80	expect(t, c.GlobalInt64("myflagInt64"), int64(12))
81	expect(t, c.GlobalInt64("nope"), int64(0))
82}
83
84func TestContext_Float64(t *testing.T) {
85	set := flag.NewFlagSet("test", 0)
86	set.Float64("myflag", float64(17), "doc")
87	c := NewContext(nil, set, nil)
88	expect(t, c.Float64("myflag"), float64(17))
89}
90
91func TestContext_GlobalFloat64(t *testing.T) {
92	set := flag.NewFlagSet("test", 0)
93	set.Float64("myflag", float64(17), "doc")
94	c := NewContext(nil, set, nil)
95	expect(t, c.GlobalFloat64("myflag"), float64(17))
96	expect(t, c.GlobalFloat64("nope"), float64(0))
97}
98
99func TestContext_Duration(t *testing.T) {
100	set := flag.NewFlagSet("test", 0)
101	set.Duration("myflag", time.Duration(12*time.Second), "doc")
102	c := NewContext(nil, set, nil)
103	expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
104}
105
106func TestContext_String(t *testing.T) {
107	set := flag.NewFlagSet("test", 0)
108	set.String("myflag", "hello world", "doc")
109	c := NewContext(nil, set, nil)
110	expect(t, c.String("myflag"), "hello world")
111}
112
113func TestContext_Bool(t *testing.T) {
114	set := flag.NewFlagSet("test", 0)
115	set.Bool("myflag", false, "doc")
116	c := NewContext(nil, set, nil)
117	expect(t, c.Bool("myflag"), false)
118}
119
120func TestContext_BoolT(t *testing.T) {
121	set := flag.NewFlagSet("test", 0)
122	set.Bool("myflag", true, "doc")
123	c := NewContext(nil, set, nil)
124	expect(t, c.BoolT("myflag"), true)
125}
126
127func TestContext_GlobalBool(t *testing.T) {
128	set := flag.NewFlagSet("test", 0)
129
130	globalSet := flag.NewFlagSet("test-global", 0)
131	globalSet.Bool("myflag", false, "doc")
132	globalCtx := NewContext(nil, globalSet, nil)
133
134	c := NewContext(nil, set, globalCtx)
135	expect(t, c.GlobalBool("myflag"), false)
136	expect(t, c.GlobalBool("nope"), false)
137}
138
139func TestContext_GlobalBoolT(t *testing.T) {
140	set := flag.NewFlagSet("test", 0)
141
142	globalSet := flag.NewFlagSet("test-global", 0)
143	globalSet.Bool("myflag", true, "doc")
144	globalCtx := NewContext(nil, globalSet, nil)
145
146	c := NewContext(nil, set, globalCtx)
147	expect(t, c.GlobalBoolT("myflag"), true)
148	expect(t, c.GlobalBoolT("nope"), false)
149}
150
151func TestContext_Args(t *testing.T) {
152	set := flag.NewFlagSet("test", 0)
153	set.Bool("myflag", false, "doc")
154	c := NewContext(nil, set, nil)
155	set.Parse([]string{"--myflag", "bat", "baz"})
156	expect(t, len(c.Args()), 2)
157	expect(t, c.Bool("myflag"), true)
158}
159
160func TestContext_NArg(t *testing.T) {
161	set := flag.NewFlagSet("test", 0)
162	set.Bool("myflag", false, "doc")
163	c := NewContext(nil, set, nil)
164	set.Parse([]string{"--myflag", "bat", "baz"})
165	expect(t, c.NArg(), 2)
166}
167
168func TestContext_IsSet(t *testing.T) {
169	set := flag.NewFlagSet("test", 0)
170	set.Bool("myflag", false, "doc")
171	set.String("otherflag", "hello world", "doc")
172	globalSet := flag.NewFlagSet("test", 0)
173	globalSet.Bool("myflagGlobal", true, "doc")
174	globalCtx := NewContext(nil, globalSet, nil)
175	c := NewContext(nil, set, globalCtx)
176	set.Parse([]string{"--myflag", "bat", "baz"})
177	globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
178	expect(t, c.IsSet("myflag"), true)
179	expect(t, c.IsSet("otherflag"), false)
180	expect(t, c.IsSet("bogusflag"), false)
181	expect(t, c.IsSet("myflagGlobal"), false)
182}
183
184// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
185// Should be moved to `flag_test` in v2
186func TestContext_IsSet_fromEnv(t *testing.T) {
187	var (
188		timeoutIsSet, tIsSet    bool
189		noEnvVarIsSet, nIsSet   bool
190		passwordIsSet, pIsSet   bool
191		unparsableIsSet, uIsSet bool
192	)
193
194	clearenv()
195	os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
196	os.Setenv("APP_PASSWORD", "")
197	a := App{
198		Flags: []Flag{
199			Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
200			StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
201			Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
202			Float64Flag{Name: "no-env-var, n"},
203		},
204		Action: func(ctx *Context) error {
205			timeoutIsSet = ctx.IsSet("timeout")
206			tIsSet = ctx.IsSet("t")
207			passwordIsSet = ctx.IsSet("password")
208			pIsSet = ctx.IsSet("p")
209			unparsableIsSet = ctx.IsSet("unparsable")
210			uIsSet = ctx.IsSet("u")
211			noEnvVarIsSet = ctx.IsSet("no-env-var")
212			nIsSet = ctx.IsSet("n")
213			return nil
214		},
215	}
216	a.Run([]string{"run"})
217	expect(t, timeoutIsSet, true)
218	expect(t, tIsSet, true)
219	expect(t, passwordIsSet, true)
220	expect(t, pIsSet, true)
221	expect(t, noEnvVarIsSet, false)
222	expect(t, nIsSet, false)
223
224	os.Setenv("APP_UNPARSABLE", "foobar")
225	a.Run([]string{"run"})
226	expect(t, unparsableIsSet, false)
227	expect(t, uIsSet, false)
228}
229
230func TestContext_GlobalIsSet(t *testing.T) {
231	set := flag.NewFlagSet("test", 0)
232	set.Bool("myflag", false, "doc")
233	set.String("otherflag", "hello world", "doc")
234	globalSet := flag.NewFlagSet("test", 0)
235	globalSet.Bool("myflagGlobal", true, "doc")
236	globalSet.Bool("myflagGlobalUnset", true, "doc")
237	globalCtx := NewContext(nil, globalSet, nil)
238	c := NewContext(nil, set, globalCtx)
239	set.Parse([]string{"--myflag", "bat", "baz"})
240	globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
241	expect(t, c.GlobalIsSet("myflag"), false)
242	expect(t, c.GlobalIsSet("otherflag"), false)
243	expect(t, c.GlobalIsSet("bogusflag"), false)
244	expect(t, c.GlobalIsSet("myflagGlobal"), true)
245	expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
246	expect(t, c.GlobalIsSet("bogusGlobal"), false)
247}
248
249// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
250// Should be moved to `flag_test` in v2
251func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
252	var (
253		timeoutIsSet, tIsSet    bool
254		noEnvVarIsSet, nIsSet   bool
255		passwordIsSet, pIsSet   bool
256		unparsableIsSet, uIsSet bool
257	)
258
259	clearenv()
260	os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
261	os.Setenv("APP_PASSWORD", "")
262	a := App{
263		Flags: []Flag{
264			Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
265			StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
266			Float64Flag{Name: "no-env-var, n"},
267			Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
268		},
269		Commands: []Command{
270			{
271				Name: "hello",
272				Action: func(ctx *Context) error {
273					timeoutIsSet = ctx.GlobalIsSet("timeout")
274					tIsSet = ctx.GlobalIsSet("t")
275					passwordIsSet = ctx.GlobalIsSet("password")
276					pIsSet = ctx.GlobalIsSet("p")
277					unparsableIsSet = ctx.GlobalIsSet("unparsable")
278					uIsSet = ctx.GlobalIsSet("u")
279					noEnvVarIsSet = ctx.GlobalIsSet("no-env-var")
280					nIsSet = ctx.GlobalIsSet("n")
281					return nil
282				},
283			},
284		},
285	}
286	if err := a.Run([]string{"run", "hello"}); err != nil {
287		t.Logf("error running Run(): %+v", err)
288	}
289	expect(t, timeoutIsSet, true)
290	expect(t, tIsSet, true)
291	expect(t, passwordIsSet, true)
292	expect(t, pIsSet, true)
293	expect(t, noEnvVarIsSet, false)
294	expect(t, nIsSet, false)
295
296	os.Setenv("APP_UNPARSABLE", "foobar")
297	if err := a.Run([]string{"run"}); err != nil {
298		t.Logf("error running Run(): %+v", err)
299	}
300	expect(t, unparsableIsSet, false)
301	expect(t, uIsSet, false)
302}
303
304func TestContext_NumFlags(t *testing.T) {
305	set := flag.NewFlagSet("test", 0)
306	set.Bool("myflag", false, "doc")
307	set.String("otherflag", "hello world", "doc")
308	globalSet := flag.NewFlagSet("test", 0)
309	globalSet.Bool("myflagGlobal", true, "doc")
310	globalCtx := NewContext(nil, globalSet, nil)
311	c := NewContext(nil, set, globalCtx)
312	set.Parse([]string{"--myflag", "--otherflag=foo"})
313	globalSet.Parse([]string{"--myflagGlobal"})
314	expect(t, c.NumFlags(), 2)
315}
316
317func TestContext_GlobalFlag(t *testing.T) {
318	var globalFlag string
319	var globalFlagSet bool
320	app := NewApp()
321	app.Flags = []Flag{
322		StringFlag{Name: "global, g", Usage: "global"},
323	}
324	app.Action = func(c *Context) error {
325		globalFlag = c.GlobalString("global")
326		globalFlagSet = c.GlobalIsSet("global")
327		return nil
328	}
329	app.Run([]string{"command", "-g", "foo"})
330	expect(t, globalFlag, "foo")
331	expect(t, globalFlagSet, true)
332
333}
334
335func TestContext_GlobalFlagsInSubcommands(t *testing.T) {
336	subcommandRun := false
337	parentFlag := false
338	app := NewApp()
339
340	app.Flags = []Flag{
341		BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
342	}
343
344	app.Commands = []Command{
345		{
346			Name: "foo",
347			Flags: []Flag{
348				BoolFlag{Name: "parent, p", Usage: "Parent flag"},
349			},
350			Subcommands: []Command{
351				{
352					Name: "bar",
353					Action: func(c *Context) error {
354						if c.GlobalBool("debug") {
355							subcommandRun = true
356						}
357						if c.GlobalBool("parent") {
358							parentFlag = true
359						}
360						return nil
361					},
362				},
363			},
364		},
365	}
366
367	app.Run([]string{"command", "-d", "foo", "-p", "bar"})
368
369	expect(t, subcommandRun, true)
370	expect(t, parentFlag, true)
371}
372
373func TestContext_Set(t *testing.T) {
374	set := flag.NewFlagSet("test", 0)
375	set.Int("int", 5, "an int")
376	c := NewContext(nil, set, nil)
377
378	expect(t, c.IsSet("int"), false)
379	c.Set("int", "1")
380	expect(t, c.Int("int"), 1)
381	expect(t, c.IsSet("int"), true)
382}
383
384func TestContext_GlobalSet(t *testing.T) {
385	gSet := flag.NewFlagSet("test", 0)
386	gSet.Int("int", 5, "an int")
387
388	set := flag.NewFlagSet("sub", 0)
389	set.Int("int", 3, "an int")
390
391	pc := NewContext(nil, gSet, nil)
392	c := NewContext(nil, set, pc)
393
394	c.Set("int", "1")
395	expect(t, c.Int("int"), 1)
396	expect(t, c.GlobalInt("int"), 5)
397
398	expect(t, c.GlobalIsSet("int"), false)
399	c.GlobalSet("int", "1")
400	expect(t, c.Int("int"), 1)
401	expect(t, c.GlobalInt("int"), 1)
402	expect(t, c.GlobalIsSet("int"), true)
403}
404