• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command, Id};
2 
3 use super::utils;
4 
5 #[test]
required_group_missing_arg()6 fn required_group_missing_arg() {
7     let result = Command::new("group")
8         .arg(arg!(-f --flag "some flag"))
9         .arg(arg!( -c --color "some other flag"))
10         .group(ArgGroup::new("req").args(["flag", "color"]).required(true))
11         .try_get_matches_from(vec![""]);
12     assert!(result.is_err());
13     let err = result.err().unwrap();
14     assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
15 }
16 
17 #[cfg(debug_assertions)]
18 #[test]
19 #[should_panic = "Command group: Argument group 'req' contains non-existent argument"]
non_existing_arg()20 fn non_existing_arg() {
21     let _ = Command::new("group")
22         .arg(arg!(-f --flag "some flag"))
23         .arg(arg!(-c --color "some other flag"))
24         .group(ArgGroup::new("req").args(["flg", "color"]).required(true))
25         .try_get_matches_from(vec![""]);
26 }
27 
28 #[cfg(debug_assertions)]
29 #[test]
30 #[should_panic = "Command group: Argument group name must be unique\n\n\t'req' is already in use"]
unique_group_name()31 fn unique_group_name() {
32     let _ = Command::new("group")
33         .arg(arg!(-f --flag "some flag"))
34         .arg(arg!(-c --color "some other flag"))
35         .group(ArgGroup::new("req").args(["flag"]).required(true))
36         .group(ArgGroup::new("req").args(["color"]).required(true))
37         .try_get_matches_from(vec![""]);
38 }
39 
40 #[cfg(debug_assertions)]
41 #[test]
42 #[should_panic = "Command group: Argument group name 'a' must not conflict with argument name"]
groups_new_of_arg_name()43 fn groups_new_of_arg_name() {
44     let _ = Command::new("group")
45         .arg(Arg::new("a").long("a").group("a"))
46         .try_get_matches_from(vec!["", "--a"]);
47 }
48 
49 #[cfg(debug_assertions)]
50 #[test]
51 #[should_panic = "Command group: Argument group name 'a' must not conflict with argument name"]
arg_group_new_of_arg_name()52 fn arg_group_new_of_arg_name() {
53     let _ = Command::new("group")
54         .arg(Arg::new("a").long("a").group("a"))
55         .group(ArgGroup::new("a"))
56         .try_get_matches_from(vec!["", "--a"]);
57 }
58 
59 #[test]
group_single_value()60 fn group_single_value() {
61     let res = Command::new("group")
62         .arg(arg!(-c --color [color] "some option"))
63         .arg(arg!(-n --hostname <name> "another option"))
64         .group(ArgGroup::new("grp").args(["hostname", "color"]))
65         .try_get_matches_from(vec!["", "-c", "blue"]);
66     assert!(res.is_ok(), "{}", res.unwrap_err());
67 
68     let m = res.unwrap();
69     assert!(m.contains_id("grp"));
70     assert_eq!(m.get_one::<Id>("grp").map(|v| v.as_str()).unwrap(), "color");
71 }
72 
73 #[test]
group_empty()74 fn group_empty() {
75     let res = Command::new("group")
76         .arg(arg!(-f --flag "some flag"))
77         .arg(arg!(-c --color [color] "some option"))
78         .arg(arg!(-n --hostname <name> "another option"))
79         .group(ArgGroup::new("grp").args(["hostname", "color", "flag"]))
80         .try_get_matches_from(vec![""]);
81     assert!(res.is_ok(), "{}", res.unwrap_err());
82 
83     let m = res.unwrap();
84     assert!(!m.contains_id("grp"));
85     assert!(m.get_one::<String>("grp").map(|v| v.as_str()).is_none());
86 }
87 
88 #[test]
group_required_flags_empty()89 fn group_required_flags_empty() {
90     let result = Command::new("group")
91         .arg(arg!(-f --flag "some flag"))
92         .arg(arg!(-c --color "some option"))
93         .arg(arg!(-n --hostname <name> "another option"))
94         .group(
95             ArgGroup::new("grp")
96                 .required(true)
97                 .args(["hostname", "color", "flag"]),
98         )
99         .try_get_matches_from(vec![""]);
100     assert!(result.is_err());
101     let err = result.err().unwrap();
102     assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
103 }
104 
105 #[test]
group_multi_value_single_arg()106 fn group_multi_value_single_arg() {
107     let res = Command::new("group")
108         .arg(arg!(-f --flag "some flag"))
109         .arg(arg!(-c --color <color> "some option").num_args(1..))
110         .arg(arg!(-n --hostname <name> "another option"))
111         .group(ArgGroup::new("grp").args(["hostname", "color", "flag"]))
112         .try_get_matches_from(vec!["", "-c", "blue", "red", "green"]);
113     assert!(res.is_ok(), "{:?}", res.unwrap_err().kind());
114 
115     let m = res.unwrap();
116     assert!(m.contains_id("grp"));
117     assert_eq!(m.get_one::<Id>("grp").map(|v| v.as_str()).unwrap(), "color");
118 }
119 
120 #[test]
empty_group()121 fn empty_group() {
122     let r = Command::new("empty_group")
123         .arg(arg!(-f --flag "some flag"))
124         .group(ArgGroup::new("vers").required(true))
125         .try_get_matches_from(vec!["empty_prog"]);
126     assert!(r.is_err());
127     let err = r.err().unwrap();
128     assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
129 }
130 
131 #[test]
132 #[cfg(feature = "error-context")]
req_group_usage_string()133 fn req_group_usage_string() {
134     static REQ_GROUP_USAGE: &str = "error: the following required arguments were not provided:
135   <base|--delete>
136 
137 Usage: clap-test <base|--delete>
138 
139 For more information, try '--help'.
140 ";
141 
142     let cmd = Command::new("req_group")
143         .arg(arg!([base] "Base commit"))
144         .arg(arg!(
145             -d --delete "Remove the base commit information"
146         ))
147         .group(
148             ArgGroup::new("base_or_delete")
149                 .args(["base", "delete"])
150                 .required(true),
151         );
152 
153     utils::assert_output(cmd, "clap-test", REQ_GROUP_USAGE, true);
154 }
155 
156 #[test]
157 #[cfg(feature = "error-context")]
req_group_with_conflict_usage_string()158 fn req_group_with_conflict_usage_string() {
159     static REQ_GROUP_CONFLICT_USAGE: &str = "\
160 error: the argument '--delete' cannot be used with '[base]'
161 
162 Usage: clap-test <base|--delete>
163 
164 For more information, try '--help'.
165 ";
166 
167     let cmd = Command::new("req_group")
168         .arg(arg!([base] "Base commit").conflicts_with("delete"))
169         .arg(arg!(
170             -d --delete "Remove the base commit information"
171         ))
172         .group(
173             ArgGroup::new("base_or_delete")
174                 .args(["base", "delete"])
175                 .required(true),
176         );
177 
178     utils::assert_output(
179         cmd,
180         "clap-test --delete base",
181         REQ_GROUP_CONFLICT_USAGE,
182         true,
183     );
184 }
185 
186 #[test]
187 #[cfg(feature = "error-context")]
req_group_with_conflict_usage_string_only_options()188 fn req_group_with_conflict_usage_string_only_options() {
189     static REQ_GROUP_CONFLICT_ONLY_OPTIONS: &str = "\
190 error: the argument '--delete' cannot be used with '--all'
191 
192 Usage: clap-test <--all|--delete>
193 
194 For more information, try '--help'.
195 ";
196 
197     let cmd = Command::new("req_group")
198         .arg(arg!(-a --all "All").conflicts_with("delete"))
199         .arg(arg!(
200             -d --delete "Remove the base commit information"
201         ))
202         .group(
203             ArgGroup::new("all_or_delete")
204                 .args(["all", "delete"])
205                 .required(true),
206         );
207     utils::assert_output(
208         cmd,
209         "clap-test --delete --all",
210         REQ_GROUP_CONFLICT_ONLY_OPTIONS,
211         true,
212     );
213 }
214 
215 #[test]
required_group_multiple_args()216 fn required_group_multiple_args() {
217     let result = Command::new("group")
218         .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue))
219         .arg(arg!(-c --color "some other flag").action(ArgAction::SetTrue))
220         .group(
221             ArgGroup::new("req")
222                 .args(["flag", "color"])
223                 .required(true)
224                 .multiple(true),
225         )
226         .try_get_matches_from(vec!["group", "-f", "-c"]);
227     assert!(result.is_ok(), "{}", result.unwrap_err());
228     let m = result.unwrap();
229     assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
230     assert!(*m.get_one::<bool>("color").expect("defaulted by clap"));
231     assert_eq!(
232         &*m.get_many::<Id>("req")
233             .unwrap()
234             .map(|v| v.as_str())
235             .collect::<Vec<_>>(),
236         ["flag", "color"]
237     );
238 }
239 
240 #[test]
group_multiple_args_error()241 fn group_multiple_args_error() {
242     let result = Command::new("group")
243         .arg(arg!(-f --flag "some flag"))
244         .arg(arg!(-c --color "some other flag"))
245         .group(ArgGroup::new("req").args(["flag", "color"]))
246         .try_get_matches_from(vec!["group", "-f", "-c"]);
247     assert!(result.is_err());
248     let err = result.unwrap_err();
249     assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
250 }
251 
252 #[test]
group_overrides_required()253 fn group_overrides_required() {
254     let command = Command::new("group")
255         .arg(arg!(--foo <FOO>).required(true))
256         .arg(arg!(--bar <BAR>).required(true))
257         .group(ArgGroup::new("group").args(["foo", "bar"]).required(true));
258     let result = command.try_get_matches_from(vec!["group", "--foo", "value"]);
259     assert!(result.is_ok(), "{}", result.unwrap_err());
260     let m = result.unwrap();
261     assert!(m.contains_id("foo"));
262     assert!(!m.contains_id("bar"));
263 }
264 
265 #[test]
group_usage_use_val_name()266 fn group_usage_use_val_name() {
267     static GROUP_USAGE_USE_VAL_NAME: &str = "\
268 Usage: prog <A>
269 
270 Arguments:
271   [A]
272 
273 Options:
274   -h, --help  Print help
275 ";
276     let cmd = Command::new("prog")
277         .arg(Arg::new("a").value_name("A"))
278         .group(ArgGroup::new("group").arg("a").required(true));
279     utils::assert_output(cmd, "prog --help", GROUP_USAGE_USE_VAL_NAME, false);
280 }
281 
282 #[test]
group_acts_like_arg()283 fn group_acts_like_arg() {
284     let result = Command::new("prog")
285         .arg(
286             Arg::new("debug")
287                 .long("debug")
288                 .group("mode")
289                 .action(ArgAction::SetTrue),
290         )
291         .arg(
292             Arg::new("verbose")
293                 .long("verbose")
294                 .group("mode")
295                 .action(ArgAction::SetTrue),
296         )
297         .try_get_matches_from(vec!["prog", "--debug"]);
298 
299     assert!(result.is_ok(), "{}", result.unwrap_err());
300     let m = result.unwrap();
301     assert!(m.contains_id("mode"));
302     assert_eq!(m.get_one::<clap::Id>("mode").unwrap(), "debug");
303 }
304 
305 #[test]
conflict_with_overlapping_group_in_error()306 fn conflict_with_overlapping_group_in_error() {
307     static ERR: &str = "\
308 error: the argument '--major' cannot be used with '--minor'
309 
310 Usage: prog --major
311 
312 For more information, try '--help'.
313 ";
314 
315     let cmd = Command::new("prog")
316         .group(ArgGroup::new("all").multiple(true))
317         .arg(arg!(--major).group("vers").group("all"))
318         .arg(arg!(--minor).group("vers").group("all"))
319         .arg(arg!(--other).group("all"));
320 
321     utils::assert_output(cmd, "prog --major --minor", ERR, true);
322 }
323 
324 #[test]
requires_group_with_overlapping_group_in_error()325 fn requires_group_with_overlapping_group_in_error() {
326     static ERR: &str = "\
327 error: the following required arguments were not provided:
328   <--in|--spec>
329 
330 Usage: prog --config <--in|--spec>
331 
332 For more information, try '--help'.
333 ";
334 
335     let cmd = Command::new("prog")
336         .group(ArgGroup::new("all").multiple(true))
337         .group(ArgGroup::new("input").required(true))
338         .arg(arg!(--in).group("input").group("all"))
339         .arg(arg!(--spec).group("input").group("all"))
340         .arg(arg!(--config).requires("input").group("all"));
341 
342     utils::assert_output(cmd, "prog --config", ERR, true);
343 }
344 
345 /* This is used to be fixed in a hack, we need to find a better way to fix it.
346 #[test]
347 fn issue_1794() {
348     let cmd = clap::Command::new("hello")
349         .bin_name("deno")
350         .arg(Arg::new("option1").long("option1").action(ArgAction::SetTrue))
351         .arg(Arg::new("pos1").action(ArgAction::Set))
352         .arg(Arg::new("pos2").action(ArgAction::Set))
353         .group(
354             ArgGroup::new("arg1")
355                 .args(["pos1", "option1"])
356                 .required(true),
357         );
358 
359     let m = cmd.clone().try_get_matches_from(["cmd", "pos1", "pos2"]).unwrap();
360     assert_eq!(m.get_one::<String>("pos1").map(|v| v.as_str()), Some("pos1"));
361     assert_eq!(m.get_one::<String>("pos2").map(|v| v.as_str()), Some("pos2"));
362     assert!(!*m.get_one::<bool>("option1").expect("defaulted by clap"));
363 
364     let m = cmd
365         .clone()
366         .try_get_matches_from(["cmd", "--option1", "positional"]).unwrap();
367     assert_eq!(m.get_one::<String>("pos1").map(|v| v.as_str()), None);
368     assert_eq!(m.get_one::<String>("pos2").map(|v| v.as_str()), Some("positional"));
369     assert!(*m.get_one::<bool>("option1").expect("defaulted by clap"));
370 }
371 */
372