1use clap::{arg, Arg, ArgAction, Command};
2
3#[test]
4fn issue_1076() {
5    let mut cmd = Command::new("myprog")
6        .arg(
7            Arg::new("GLOBAL_ARG")
8                .long("global-arg")
9                .help("Specifies something needed by the subcommands")
10                .global(true)
11                .action(ArgAction::Set)
12                .default_value("default_value"),
13        )
14        .arg(
15            Arg::new("GLOBAL_FLAG")
16                .long("global-flag")
17                .help("Specifies something needed by the subcommands")
18                .global(true)
19                .action(ArgAction::Set),
20        )
21        .subcommand(Command::new("outer").subcommand(Command::new("inner")));
22    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
23    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
24    let _ = cmd.try_get_matches_from_mut(vec!["myprog"]);
25}
26
27#[test]
28fn propagate_global_arg_in_subcommand_to_subsubcommand_1385() {
29    let m1 = Command::new("foo")
30        .subcommand(
31            Command::new("sub1")
32                .arg(
33                    Arg::new("arg1")
34                        .long("arg1")
35                        .action(ArgAction::Set)
36                        .global(true),
37                )
38                .subcommand(Command::new("sub1a")),
39        )
40        .try_get_matches_from(["foo", "sub1", "--arg1", "v1", "sub1a"])
41        .unwrap();
42    assert_eq!(
43        "v1",
44        m1.subcommand_matches("sub1")
45            .unwrap()
46            .subcommand_matches("sub1a")
47            .unwrap()
48            .get_one::<String>("arg1")
49            .map(|v| v.as_str())
50            .unwrap()
51    );
52}
53
54#[test]
55fn propagate_global_arg_to_subcommand_in_subsubcommand_2053() {
56    let m = Command::new("opts")
57        .arg(arg!(--"global-flag").global(true))
58        .arg(arg!(--"global-str" <str>).global(true))
59        .subcommand(
60            Command::new("test")
61                .arg(arg!(--"sub-flag").global(true))
62                .arg(arg!(--"sub-str" <str>).global(true))
63                .subcommand(Command::new("test")),
64        )
65        .try_get_matches_from([
66            "cmd",
67            "test",
68            "test",
69            "--global-flag",
70            "--global-str",
71            "hello",
72            "--sub-flag",
73            "--sub-str",
74            "world",
75        ])
76        .unwrap();
77    assert_eq!(
78        Some("world"),
79        m.subcommand_matches("test")
80            .unwrap()
81            .get_one::<String>("sub-str")
82            .map(|v| v.as_str())
83    );
84}
85
86#[test]
87fn global_arg_available_in_subcommand() {
88    let m = Command::new("opt")
89        .args([
90            Arg::new("global")
91                .global(true)
92                .long("global")
93                .action(ArgAction::SetTrue),
94            Arg::new("not")
95                .global(false)
96                .long("not")
97                .action(ArgAction::SetTrue),
98        ])
99        .subcommand(Command::new("ping"))
100        .try_get_matches_from(["opt", "ping", "--global"])
101        .unwrap();
102
103    assert!(*m.get_one::<bool>("global").expect("defaulted by clap"));
104    assert!(*m
105        .subcommand_matches("ping")
106        .unwrap()
107        .get_one::<bool>("global")
108        .expect("defaulted by clap"));
109}
110
111#[test]
112fn deeply_nested_discovery() {
113    let cmd = Command::new("a")
114        .arg(arg!(--"long-a").global(true).action(ArgAction::SetTrue))
115        .subcommand(
116            Command::new("b")
117                .arg(arg!(--"long-b").global(true).action(ArgAction::SetTrue))
118                .subcommand(
119                    Command::new("c")
120                        .arg(arg!(--"long-c").global(true).action(ArgAction::SetTrue))
121                        .subcommand(Command::new("d")),
122                ),
123        );
124
125    let m = cmd
126        .try_get_matches_from(["a", "b", "c", "d", "--long-a", "--long-b", "--long-c"])
127        .unwrap();
128    assert!(*m.get_one::<bool>("long-a").expect("defaulted by clap"));
129    let m = m.subcommand_matches("b").unwrap();
130    assert!(*m.get_one::<bool>("long-b").expect("defaulted by clap"));
131    let m = m.subcommand_matches("c").unwrap();
132    assert!(*m.get_one::<bool>("long-c").expect("defaulted by clap"));
133}
134
135#[test]
136fn global_overrides_default() {
137    let cmd = Command::new("test")
138        .arg(
139            Arg::new("name")
140                .long("name")
141                .global(true)
142                .action(ArgAction::Set)
143                .default_value("from_default"),
144        )
145        .subcommand(Command::new("sub"));
146
147    let m = cmd.clone().try_get_matches_from(["test"]).unwrap();
148    assert_eq!(
149        m.get_one::<String>("name").unwrap().as_str(),
150        "from_default"
151    );
152
153    let m = cmd
154        .clone()
155        .try_get_matches_from(["test", "--name", "from_arg"])
156        .unwrap();
157    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
158
159    let m = cmd
160        .clone()
161        .try_get_matches_from(["test", "--name", "from_arg", "sub"])
162        .unwrap();
163    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
164
165    let m = cmd
166        .clone()
167        .try_get_matches_from(["test", "sub", "--name", "from_arg"])
168        .unwrap();
169    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
170}
171
172#[test]
173#[cfg(feature = "env")]
174fn global_overrides_env() {
175    std::env::set_var("GLOBAL_OVERRIDES_ENV", "from_env");
176
177    let cmd = Command::new("test")
178        .arg(
179            Arg::new("name")
180                .long("name")
181                .global(true)
182                .action(ArgAction::Set)
183                .env("GLOBAL_OVERRIDES_ENV"),
184        )
185        .subcommand(Command::new("sub"));
186
187    let m = cmd.clone().try_get_matches_from(["test"]).unwrap();
188    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_env");
189
190    let m = cmd
191        .clone()
192        .try_get_matches_from(["test", "--name", "from_arg"])
193        .unwrap();
194    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
195
196    let m = cmd
197        .clone()
198        .try_get_matches_from(["test", "--name", "from_arg", "sub"])
199        .unwrap();
200    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
201
202    let m = cmd
203        .clone()
204        .try_get_matches_from(["test", "sub", "--name", "from_arg"])
205        .unwrap();
206    assert_eq!(m.get_one::<String>("name").unwrap().as_str(), "from_arg");
207}
208