1 use super::utils;
2
3 use std::io::Write;
4 use std::str;
5
6 use clap::{Arg, Command};
7
8 static SCF2OP: &str = "flag present 2 times
9 option NOT present
10 positional NOT present
11 flag2 NOT present
12 option2 maybe present with value of: Nothing
13 positional2 maybe present with value of: Nothing
14 option3 NOT present
15 positional3 NOT present
16 option NOT present
17 positional NOT present
18 subcmd present
19 flag present 2 times
20 scoption present with value: some
21 An scoption: some
22 scpositional present with value: value
23 ";
24
25 static SCFOP: &str = "flag present 1 times
26 option NOT present
27 positional NOT present
28 flag2 NOT present
29 option2 maybe present with value of: Nothing
30 positional2 maybe present with value of: Nothing
31 option3 NOT present
32 positional3 NOT present
33 option NOT present
34 positional NOT present
35 subcmd present
36 flag present 1 times
37 scoption present with value: some
38 An scoption: some
39 scpositional present with value: value
40 ";
41
42 static O2P: &str = "flag NOT present
43 option present with value: some
44 An option: some
45 An option: other
46 positional present with value: value
47 flag2 NOT present
48 option2 maybe present with value of: Nothing
49 positional2 maybe present with value of: Nothing
50 option3 NOT present
51 positional3 NOT present
52 option present with value: some
53 An option: some
54 An option: other
55 positional present with value: value
56 subcmd NOT present
57 ";
58
59 static F2OP: &str = "flag present 2 times
60 option present with value: some
61 An option: some
62 positional present with value: value
63 flag2 NOT present
64 option2 maybe present with value of: Nothing
65 positional2 maybe present with value of: Nothing
66 option3 NOT present
67 positional3 NOT present
68 option present with value: some
69 An option: some
70 positional present with value: value
71 subcmd NOT present
72 ";
73
74 static FOP: &str = "flag present 1 times
75 option present with value: some
76 An option: some
77 positional present with value: value
78 flag2 NOT present
79 option2 maybe present with value of: Nothing
80 positional2 maybe present with value of: Nothing
81 option3 NOT present
82 positional3 NOT present
83 option present with value: some
84 An option: some
85 positional present with value: value
86 subcmd NOT present
87 ";
88
check_complex_output(args: &str, out: &str)89 pub fn check_complex_output(args: &str, out: &str) {
90 let mut w = vec![];
91 let matches = utils::complex_app()
92 .try_get_matches_from(args.split(' ').collect::<Vec<_>>())
93 .unwrap();
94 match matches.get_one::<u8>("flag").unwrap() {
95 0 => {
96 writeln!(w, "flag NOT present").unwrap();
97 }
98 n => {
99 writeln!(w, "flag present {} times", n).unwrap();
100 }
101 }
102
103 if matches.contains_id("option") {
104 if let Some(v) = matches.get_one::<String>("option").map(|v| v.as_str()) {
105 writeln!(w, "option present with value: {}", v).unwrap();
106 }
107 if let Some(ov) = matches.get_many::<String>("option") {
108 for o in ov {
109 writeln!(w, "An option: {}", o).unwrap();
110 }
111 }
112 } else {
113 writeln!(w, "option NOT present").unwrap();
114 }
115
116 if let Some(p) = matches.get_one::<String>("positional").map(|v| v.as_str()) {
117 writeln!(w, "positional present with value: {}", p).unwrap();
118 } else {
119 writeln!(w, "positional NOT present").unwrap();
120 }
121
122 if *matches.get_one::<bool>("flag2").expect("defaulted by clap") {
123 writeln!(w, "flag2 present").unwrap();
124 writeln!(
125 w,
126 "option2 present with value of: {}",
127 matches
128 .get_one::<String>("long-option-2")
129 .map(|v| v.as_str())
130 .unwrap()
131 )
132 .unwrap();
133 writeln!(
134 w,
135 "positional2 present with value of: {}",
136 matches
137 .get_one::<String>("positional2")
138 .map(|v| v.as_str())
139 .unwrap()
140 )
141 .unwrap();
142 } else {
143 writeln!(w, "flag2 NOT present").unwrap();
144 writeln!(
145 w,
146 "option2 maybe present with value of: {}",
147 matches
148 .get_one::<String>("long-option-2")
149 .map(|v| v.as_str())
150 .unwrap_or("Nothing")
151 )
152 .unwrap();
153 writeln!(
154 w,
155 "positional2 maybe present with value of: {}",
156 matches
157 .get_one::<String>("positional2")
158 .map(|v| v.as_str())
159 .unwrap_or("Nothing")
160 )
161 .unwrap();
162 }
163
164 let _ = match matches
165 .get_one::<String>("option3")
166 .map(|v| v.as_str())
167 .unwrap_or("")
168 {
169 "fast" => writeln!(w, "option3 present quickly"),
170 "slow" => writeln!(w, "option3 present slowly"),
171 _ => writeln!(w, "option3 NOT present"),
172 };
173
174 let _ = match matches
175 .get_one::<String>("positional3")
176 .map(|v| v.as_str())
177 .unwrap_or("")
178 {
179 "vi" => writeln!(w, "positional3 present in vi mode"),
180 "emacs" => writeln!(w, "positional3 present in emacs mode"),
181 _ => writeln!(w, "positional3 NOT present"),
182 };
183
184 if matches.contains_id("option") {
185 if let Some(v) = matches.get_one::<String>("option").map(|v| v.as_str()) {
186 writeln!(w, "option present with value: {}", v).unwrap();
187 }
188 if let Some(ov) = matches.get_many::<String>("option") {
189 for o in ov {
190 writeln!(w, "An option: {}", o).unwrap();
191 }
192 }
193 } else {
194 writeln!(w, "option NOT present").unwrap();
195 }
196
197 if let Some(p) = matches.get_one::<String>("positional").map(|v| v.as_str()) {
198 writeln!(w, "positional present with value: {p}").unwrap();
199 } else {
200 writeln!(w, "positional NOT present").unwrap();
201 }
202 if let Some("subcmd") = matches.subcommand_name() {
203 writeln!(w, "subcmd present").unwrap();
204 if let Some(matches) = matches.subcommand_matches("subcmd") {
205 match matches.get_one::<u8>("flag").unwrap() {
206 0 => {
207 writeln!(w, "flag NOT present").unwrap();
208 }
209 n => {
210 writeln!(w, "flag present {n} times").unwrap();
211 }
212 }
213
214 if matches.contains_id("option") {
215 if let Some(v) = matches.get_one::<String>("option").map(|v| v.as_str()) {
216 writeln!(w, "scoption present with value: {v}").unwrap();
217 }
218 if let Some(ov) = matches.get_many::<String>("option") {
219 for o in ov {
220 writeln!(w, "An scoption: {o}").unwrap();
221 }
222 }
223 } else {
224 writeln!(w, "scoption NOT present").unwrap();
225 }
226
227 if let Some(p) = matches
228 .get_one::<String>("scpositional")
229 .map(|v| v.as_str())
230 {
231 writeln!(w, "scpositional present with value: {p}").unwrap();
232 }
233 }
234 } else {
235 writeln!(w, "subcmd NOT present").unwrap();
236 }
237
238 let res = str::from_utf8(&w).unwrap();
239 snapbox::assert_eq(out, res);
240 }
241
242 #[test]
create_app()243 fn create_app() {
244 let _ = Command::new("test")
245 .version("1.0")
246 .author("kevin")
247 .about("does awesome things")
248 .try_get_matches_from(vec![""])
249 .unwrap();
250 }
251
252 #[test]
add_multiple_arg()253 fn add_multiple_arg() {
254 let _ = Command::new("test")
255 .args([Arg::new("test").short('s'), Arg::new("test2").short('l')])
256 .try_get_matches_from(vec![""])
257 .unwrap();
258 }
259 #[test]
flag_x2_opt()260 fn flag_x2_opt() {
261 check_complex_output(
262 "clap-test value -f -f -o some",
263 "flag present 2 times
264 option present with value: some
265 An option: some
266 positional present with value: value
267 flag2 NOT present
268 option2 maybe present with value of: Nothing
269 positional2 maybe present with value of: Nothing
270 option3 NOT present
271 positional3 NOT present
272 option present with value: some
273 An option: some
274 positional present with value: value
275 subcmd NOT present
276 ",
277 );
278 }
279
280 #[test]
long_opt_x2_pos()281 fn long_opt_x2_pos() {
282 check_complex_output("clap-test value --option some --option other", O2P);
283 }
284
285 #[test]
long_opt_eq_x2_pos()286 fn long_opt_eq_x2_pos() {
287 check_complex_output("clap-test value --option=some --option=other", O2P);
288 }
289
290 #[test]
short_opt_x2_pos()291 fn short_opt_x2_pos() {
292 check_complex_output("clap-test value -o some -o other", O2P);
293 }
294
295 #[test]
short_opt_eq_x2_pos()296 fn short_opt_eq_x2_pos() {
297 check_complex_output("clap-test value -o=some -o=other", O2P);
298 }
299
300 #[test]
short_flag_x2_comb_short_opt_pos()301 fn short_flag_x2_comb_short_opt_pos() {
302 check_complex_output("clap-test value -ff -o some", F2OP);
303 }
304
305 #[test]
short_flag_short_opt_pos()306 fn short_flag_short_opt_pos() {
307 check_complex_output("clap-test value -f -o some", FOP);
308 }
309
310 #[test]
long_flag_long_opt_pos()311 fn long_flag_long_opt_pos() {
312 check_complex_output("clap-test value --flag --option some", FOP);
313 }
314
315 #[test]
long_flag_long_opt_eq_pos()316 fn long_flag_long_opt_eq_pos() {
317 check_complex_output("clap-test value --flag --option=some", FOP);
318 }
319
320 #[test]
sc_long_flag_long_opt()321 fn sc_long_flag_long_opt() {
322 check_complex_output("clap-test subcmd value --flag --option some", SCFOP);
323 }
324
325 #[test]
sc_long_flag_short_opt_pos()326 fn sc_long_flag_short_opt_pos() {
327 check_complex_output("clap-test subcmd value --flag -o some", SCFOP);
328 }
329
330 #[test]
sc_long_flag_long_opt_eq_pos()331 fn sc_long_flag_long_opt_eq_pos() {
332 check_complex_output("clap-test subcmd value --flag --option=some", SCFOP);
333 }
334
335 #[test]
sc_short_flag_long_opt_pos()336 fn sc_short_flag_long_opt_pos() {
337 check_complex_output("clap-test subcmd value -f --option some", SCFOP);
338 }
339
340 #[test]
sc_short_flag_short_opt_pos()341 fn sc_short_flag_short_opt_pos() {
342 check_complex_output("clap-test subcmd value -f -o some", SCFOP);
343 }
344
345 #[test]
sc_short_flag_short_opt_eq_pos()346 fn sc_short_flag_short_opt_eq_pos() {
347 check_complex_output("clap-test subcmd value -f -o=some", SCFOP);
348 }
349
350 #[test]
sc_short_flag_long_opt_eq_pos()351 fn sc_short_flag_long_opt_eq_pos() {
352 check_complex_output("clap-test subcmd value -f --option=some", SCFOP);
353 }
354
355 #[test]
sc_short_flag_x2_comb_long_opt_pos()356 fn sc_short_flag_x2_comb_long_opt_pos() {
357 check_complex_output("clap-test subcmd value -ff --option some", SCF2OP);
358 }
359
360 #[test]
sc_short_flag_x2_comb_short_opt_pos()361 fn sc_short_flag_x2_comb_short_opt_pos() {
362 check_complex_output("clap-test subcmd value -ff -o some", SCF2OP);
363 }
364
365 #[test]
sc_short_flag_x2_comb_long_opt_eq_pos()366 fn sc_short_flag_x2_comb_long_opt_eq_pos() {
367 check_complex_output("clap-test subcmd value -ff --option=some", SCF2OP);
368 }
369
370 #[test]
sc_short_flag_x2_comb_short_opt_eq_pos()371 fn sc_short_flag_x2_comb_short_opt_eq_pos() {
372 check_complex_output("clap-test subcmd value -ff -o=some", SCF2OP);
373 }
374
375 #[test]
sc_long_flag_x2_long_opt_pos()376 fn sc_long_flag_x2_long_opt_pos() {
377 check_complex_output("clap-test subcmd value --flag --flag --option some", SCF2OP);
378 }
379
380 #[test]
sc_long_flag_x2_short_opt_pos()381 fn sc_long_flag_x2_short_opt_pos() {
382 check_complex_output("clap-test subcmd value --flag --flag -o some", SCF2OP);
383 }
384
385 #[test]
sc_long_flag_x2_short_opt_eq_pos()386 fn sc_long_flag_x2_short_opt_eq_pos() {
387 check_complex_output("clap-test subcmd value --flag --flag -o=some", SCF2OP);
388 }
389
390 #[test]
sc_long_flag_x2_long_opt_eq_pos()391 fn sc_long_flag_x2_long_opt_eq_pos() {
392 check_complex_output("clap-test subcmd value --flag --flag --option=some", SCF2OP);
393 }
394
395 #[test]
sc_short_flag_x2_long_opt_pos()396 fn sc_short_flag_x2_long_opt_pos() {
397 check_complex_output("clap-test subcmd value -f -f --option some", SCF2OP);
398 }
399
400 #[test]
sc_short_flag_x2_short_opt_pos()401 fn sc_short_flag_x2_short_opt_pos() {
402 check_complex_output("clap-test subcmd value -f -f -o some", SCF2OP);
403 }
404
405 #[test]
sc_short_flag_x2_short_opt_eq_pos()406 fn sc_short_flag_x2_short_opt_eq_pos() {
407 check_complex_output("clap-test subcmd value -f -f -o=some", SCF2OP);
408 }
409
410 #[test]
sc_short_flag_x2_long_opt_eq_pos()411 fn sc_short_flag_x2_long_opt_eq_pos() {
412 check_complex_output("clap-test subcmd value -f -f --option=some", SCF2OP);
413 }
414
415 #[test]
mut_arg_all()416 fn mut_arg_all() {
417 let mut cmd = utils::complex_app();
418 let arg_names = cmd
419 .get_arguments()
420 .map(|a| a.get_id().clone())
421 .filter(|a| a != "version" && a != "help")
422 .collect::<Vec<_>>();
423
424 for arg_name in arg_names {
425 cmd = cmd.mut_arg(arg_name, |arg| arg.hide_possible_values(true));
426 }
427 }
428
429 #[test]
mut_subcommand_all()430 fn mut_subcommand_all() {
431 let cmd = utils::complex_app();
432
433 assert_eq!(
434 cmd.find_subcommand("subcmd")
435 .unwrap()
436 .is_disable_version_flag_set(),
437 false
438 );
439 let cmd = cmd.mut_subcommand("subcmd", |subcmd| subcmd.disable_version_flag(true));
440 assert_eq!(
441 cmd.find_subcommand("subcmd")
442 .unwrap()
443 .is_disable_version_flag_set(),
444 true
445 );
446 }
447
448 #[test]
mut_subcommand_with_alias_resolve()449 fn mut_subcommand_with_alias_resolve() {
450 let mut cmd =
451 Command::new("foo").subcommand(Command::new("bar").alias("baz").about("test subcmd"));
452 assert_eq!(
453 cmd.find_subcommand("baz")
454 .unwrap()
455 .get_about()
456 .unwrap()
457 .to_string(),
458 "test subcmd"
459 );
460
461 let true_name = cmd.find_subcommand("baz").unwrap().get_name().to_string();
462 assert_eq!(true_name, "bar");
463
464 cmd = cmd.mut_subcommand(&*true_name, |subcmd| subcmd.about("modified about"));
465 assert_eq!(
466 cmd.find_subcommand("baz")
467 .unwrap()
468 .get_about()
469 .unwrap()
470 .to_string(),
471 "modified about"
472 );
473 }
474
475 #[test]
issue_3669_command_build_recurses()476 fn issue_3669_command_build_recurses() {
477 let mut cmd = Command::new("ctest").subcommand(
478 Command::new("subcmd").subcommand(
479 Command::new("multi")
480 .about("tests subcommands")
481 .author("Kevin K. <kbknapp@gmail.com>")
482 .version("0.1")
483 .arg(clap::arg!(
484 <FLAG> "tests flags"
485 )),
486 ),
487 );
488 cmd.build();
489 }
490