1use super::utils;
2
3use clap::{arg, error::ErrorKind, Arg, ArgAction, Command};
4
5#[test]
6fn flag_subcommand_normal() {
7    let matches = Command::new("test")
8        .subcommand(
9            Command::new("some").short_flag('S').long_flag("some").arg(
10                Arg::new("test")
11                    .short('t')
12                    .long("test")
13                    .help("testing testing")
14                    .action(ArgAction::SetTrue),
15            ),
16        )
17        .try_get_matches_from(vec!["myprog", "some", "--test"])
18        .unwrap();
19    assert_eq!(matches.subcommand_name().unwrap(), "some");
20    let sub_matches = matches.subcommand_matches("some").unwrap();
21    assert!(*sub_matches
22        .get_one::<bool>("test")
23        .expect("defaulted by clap"));
24}
25
26#[test]
27fn flag_subcommand_normal_with_alias() {
28    let matches = Command::new("test")
29        .subcommand(
30            Command::new("some")
31                .short_flag('S')
32                .long_flag("S")
33                .arg(
34                    Arg::new("test")
35                        .short('t')
36                        .long("test")
37                        .help("testing testing")
38                        .action(ArgAction::SetTrue),
39                )
40                .alias("result"),
41        )
42        .try_get_matches_from(vec!["myprog", "result", "--test"])
43        .unwrap();
44    assert_eq!(matches.subcommand_name().unwrap(), "some");
45    let sub_matches = matches.subcommand_matches("some").unwrap();
46    assert!(*sub_matches
47        .get_one::<bool>("test")
48        .expect("defaulted by clap"));
49}
50
51#[test]
52fn flag_subcommand_short() {
53    let matches = Command::new("test")
54        .subcommand(
55            Command::new("some").short_flag('S').arg(
56                Arg::new("test")
57                    .short('t')
58                    .long("test")
59                    .help("testing testing")
60                    .action(ArgAction::SetTrue),
61            ),
62        )
63        .try_get_matches_from(vec!["myprog", "-S", "--test"])
64        .unwrap();
65    assert_eq!(matches.subcommand_name().unwrap(), "some");
66    let sub_matches = matches.subcommand_matches("some").unwrap();
67    assert!(*sub_matches
68        .get_one::<bool>("test")
69        .expect("defaulted by clap"));
70}
71
72#[test]
73fn flag_subcommand_short_with_args() {
74    let matches = Command::new("test")
75        .subcommand(
76            Command::new("some").short_flag('S').arg(
77                Arg::new("test")
78                    .short('t')
79                    .long("test")
80                    .help("testing testing")
81                    .action(ArgAction::SetTrue),
82            ),
83        )
84        .try_get_matches_from(vec!["myprog", "-St"])
85        .unwrap();
86    assert_eq!(matches.subcommand_name().unwrap(), "some");
87    let sub_matches = matches.subcommand_matches("some").unwrap();
88    assert!(*sub_matches
89        .get_one::<bool>("test")
90        .expect("defaulted by clap"));
91}
92
93#[test]
94fn flag_subcommand_short_with_alias() {
95    let matches = Command::new("test")
96        .subcommand(
97            Command::new("some")
98                .short_flag('S')
99                .arg(
100                    Arg::new("test")
101                        .short('t')
102                        .long("test")
103                        .help("testing testing")
104                        .action(ArgAction::SetTrue),
105                )
106                .short_flag_alias('M')
107                .short_flag_alias('B'),
108        )
109        .try_get_matches_from(vec!["myprog", "-Bt"])
110        .unwrap();
111    assert_eq!(matches.subcommand_name().unwrap(), "some");
112    let sub_matches = matches.subcommand_matches("some").unwrap();
113    assert!(*sub_matches
114        .get_one::<bool>("test")
115        .expect("defaulted by clap"));
116}
117
118#[test]
119fn flag_subcommand_short_with_alias_same_as_short_flag() {
120    let matches = Command::new("test")
121        .subcommand(Command::new("some").short_flag('S').short_flag_alias('S'))
122        .try_get_matches_from(vec!["myprog", "-S"])
123        .unwrap();
124    assert_eq!(matches.subcommand_name().unwrap(), "some");
125}
126
127#[test]
128fn flag_subcommand_long_with_alias_same_as_long_flag() {
129    let matches = Command::new("test")
130        .subcommand(
131            Command::new("some")
132                .long_flag("sync")
133                .long_flag_alias("sync"),
134        )
135        .try_get_matches_from(vec!["myprog", "--sync"])
136        .unwrap();
137    assert_eq!(matches.subcommand_name().unwrap(), "some");
138}
139
140#[test]
141fn flag_subcommand_short_with_aliases_vis_and_hidden() {
142    let cmd = Command::new("test").subcommand(
143        Command::new("some")
144            .short_flag('S')
145            .arg(
146                Arg::new("test")
147                    .short('t')
148                    .long("test")
149                    .help("testing testing"),
150            )
151            .visible_short_flag_aliases(['M', 'B'])
152            .short_flag_alias('C'),
153    );
154    let app1 = cmd.clone();
155    let matches1 = app1.try_get_matches_from(vec!["test", "-M"]).unwrap();
156    assert_eq!(matches1.subcommand_name().unwrap(), "some");
157
158    let app2 = cmd.clone();
159    let matches2 = app2.try_get_matches_from(vec!["test", "-C"]).unwrap();
160    assert_eq!(matches2.subcommand_name().unwrap(), "some");
161
162    let app3 = cmd.clone();
163    let matches3 = app3.try_get_matches_from(vec!["test", "-B"]).unwrap();
164    assert_eq!(matches3.subcommand_name().unwrap(), "some");
165}
166
167#[test]
168fn flag_subcommand_short_with_aliases() {
169    let matches = Command::new("test")
170        .subcommand(
171            Command::new("some")
172                .short_flag('S')
173                .arg(
174                    Arg::new("test")
175                        .short('t')
176                        .long("test")
177                        .help("testing testing")
178                        .action(ArgAction::SetTrue),
179                )
180                .short_flag_aliases(['M', 'B']),
181        )
182        .try_get_matches_from(vec!["myprog", "-Bt"])
183        .unwrap();
184    assert_eq!(matches.subcommand_name().unwrap(), "some");
185    let sub_matches = matches.subcommand_matches("some").unwrap();
186    assert!(*sub_matches
187        .get_one::<bool>("test")
188        .expect("defaulted by clap"));
189}
190
191#[test]
192#[should_panic]
193fn flag_subcommand_short_with_alias_hyphen() {
194    let _ = Command::new("test")
195        .subcommand(
196            Command::new("some")
197                .short_flag('S')
198                .arg(
199                    Arg::new("test")
200                        .short('t')
201                        .long("test")
202                        .help("testing testing"),
203                )
204                .short_flag_alias('-'),
205        )
206        .try_get_matches_from(vec!["myprog", "-Bt"])
207        .unwrap();
208}
209
210#[test]
211#[should_panic]
212fn flag_subcommand_short_with_aliases_hyphen() {
213    let _ = Command::new("test")
214        .subcommand(
215            Command::new("some")
216                .short_flag('S')
217                .arg(
218                    Arg::new("test")
219                        .short('t')
220                        .long("test")
221                        .help("testing testing"),
222                )
223                .short_flag_aliases(['-', '-', '-']),
224        )
225        .try_get_matches_from(vec!["myprog", "-Bt"])
226        .unwrap();
227}
228
229#[test]
230fn flag_subcommand_short_after_long_arg() {
231    let m = Command::new("pacman")
232        .subcommand(
233            Command::new("sync")
234                .short_flag('S')
235                .arg(Arg::new("clean").short('c').action(ArgAction::SetTrue)),
236        )
237        .arg(Arg::new("arg").long("arg").action(ArgAction::Set))
238        .try_get_matches_from(vec!["pacman", "--arg", "foo", "-Sc"])
239        .unwrap();
240    let subm = m.subcommand_matches("sync");
241    assert!(subm.is_some());
242    let subm = subm.unwrap();
243    assert!(*subm.get_one::<bool>("clean").expect("defaulted by clap"));
244}
245
246#[test]
247fn flag_subcommand_long() {
248    let matches = Command::new("test")
249        .subcommand(
250            Command::new("some").long_flag("some").arg(
251                Arg::new("test")
252                    .short('t')
253                    .long("test")
254                    .help("testing testing")
255                    .action(ArgAction::SetTrue),
256            ),
257        )
258        .try_get_matches_from(vec!["myprog", "--some", "--test"])
259        .unwrap();
260    assert_eq!(matches.subcommand_name().unwrap(), "some");
261    let sub_matches = matches.subcommand_matches("some").unwrap();
262    assert!(*sub_matches
263        .get_one::<bool>("test")
264        .expect("defaulted by clap"));
265}
266
267#[test]
268fn flag_subcommand_long_with_alias() {
269    let matches = Command::new("test")
270        .subcommand(
271            Command::new("some")
272                .long_flag("some")
273                .arg(
274                    Arg::new("test")
275                        .short('t')
276                        .long("test")
277                        .help("testing testing")
278                        .action(ArgAction::SetTrue),
279                )
280                .long_flag_alias("result"),
281        )
282        .try_get_matches_from(vec!["myprog", "--result", "--test"])
283        .unwrap();
284    assert_eq!(matches.subcommand_name().unwrap(), "some");
285    let sub_matches = matches.subcommand_matches("some").unwrap();
286    assert!(*sub_matches
287        .get_one::<bool>("test")
288        .expect("defaulted by clap"));
289}
290
291#[test]
292fn flag_subcommand_long_with_aliases() {
293    let matches = Command::new("test")
294        .subcommand(
295            Command::new("some")
296                .long_flag("some")
297                .arg(
298                    Arg::new("test")
299                        .short('t')
300                        .long("test")
301                        .help("testing testing")
302                        .action(ArgAction::SetTrue),
303                )
304                .long_flag_aliases(["result", "someall"]),
305        )
306        .try_get_matches_from(vec!["myprog", "--result", "--test"])
307        .unwrap();
308    assert_eq!(matches.subcommand_name().unwrap(), "some");
309    let sub_matches = matches.subcommand_matches("some").unwrap();
310    assert!(*sub_matches
311        .get_one::<bool>("test")
312        .expect("defaulted by clap"));
313}
314
315#[test]
316fn flag_subcommand_multiple() {
317    let matches = Command::new("test")
318        .subcommand(
319            Command::new("some")
320                .short_flag('S')
321                .long_flag("some")
322                .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue))
323                .arg(arg!(-p --print "print something").action(ArgAction::SetTrue))
324                .subcommand(
325                    Command::new("result")
326                        .short_flag('R')
327                        .long_flag("result")
328                        .arg(arg!(-f --flag "some flag").action(ArgAction::SetTrue))
329                        .arg(arg!(-p --print "print something").action(ArgAction::SetTrue)),
330                ),
331        )
332        .try_get_matches_from(vec!["myprog", "-SfpRfp"])
333        .unwrap();
334    assert_eq!(matches.subcommand_name().unwrap(), "some");
335    let sub_matches = matches.subcommand_matches("some").unwrap();
336    assert!(*sub_matches
337        .get_one::<bool>("flag")
338        .expect("defaulted by clap"));
339    assert!(*sub_matches
340        .get_one::<bool>("print")
341        .expect("defaulted by clap"));
342    assert_eq!(sub_matches.subcommand_name().unwrap(), "result");
343    let result_matches = sub_matches.subcommand_matches("result").unwrap();
344    assert!(*result_matches
345        .get_one::<bool>("flag")
346        .expect("defaulted by clap"));
347    assert!(*result_matches
348        .get_one::<bool>("print")
349        .expect("defaulted by clap"));
350}
351
352#[cfg(debug_assertions)]
353#[test]
354#[should_panic = "the \'-f\' short flag for the \'test\' argument conflicts with the short flag for \'some\' subcommand"]
355fn flag_subcommand_short_conflict_with_arg() {
356    let _ = Command::new("test")
357        .subcommand(Command::new("some").short_flag('f').long_flag("some"))
358        .arg(Arg::new("test").short('f'))
359        .try_get_matches_from(vec!["myprog", "-f"])
360        .unwrap();
361}
362
363#[cfg(debug_assertions)]
364#[test]
365#[should_panic = "the \'-f\' short flag is specified for both \'some\' and \'result\' subcommands"]
366fn flag_subcommand_short_conflict_with_alias() {
367    let _ = Command::new("test")
368        .subcommand(Command::new("some").short_flag('f').long_flag("some"))
369        .subcommand(Command::new("result").short_flag('t').short_flag_alias('f'))
370        .try_get_matches_from(vec!["myprog", "-f"])
371        .unwrap();
372}
373
374#[cfg(debug_assertions)]
375#[test]
376#[should_panic = "the \'--flag\' long flag is specified for both \'some\' and \'result\' subcommands"]
377fn flag_subcommand_long_conflict_with_alias() {
378    let _ = Command::new("test")
379        .subcommand(Command::new("some").long_flag("flag"))
380        .subcommand(
381            Command::new("result")
382                .long_flag("test")
383                .long_flag_alias("flag"),
384        )
385        .try_get_matches_from(vec!["myprog", "--flag"])
386        .unwrap();
387}
388
389#[cfg(debug_assertions)]
390#[test]
391#[should_panic = "the \'-f\' short flag for the \'test\' argument conflicts with the short flag for \'some\' subcommand"]
392fn flag_subcommand_short_conflict_with_arg_alias() {
393    let _ = Command::new("test")
394        .subcommand(Command::new("some").short_flag('f').long_flag("some"))
395        .arg(Arg::new("test").short('t').short_alias('f'))
396        .try_get_matches_from(vec!["myprog", "-f"])
397        .unwrap();
398}
399
400#[cfg(debug_assertions)]
401#[test]
402#[should_panic = "the \'--some\' long flag for the \'test\' argument conflicts with the short flag for \'some\' subcommand"]
403fn flag_subcommand_long_conflict_with_arg_alias() {
404    let _ = Command::new("test")
405        .subcommand(Command::new("some").short_flag('f').long_flag("some"))
406        .arg(Arg::new("test").long("test").alias("some"))
407        .try_get_matches_from(vec!["myprog", "--some"])
408        .unwrap();
409}
410
411#[cfg(debug_assertions)]
412#[test]
413#[should_panic = "the \'--flag\' long flag for the \'flag\' argument conflicts with the short flag for \'some\' subcommand"]
414fn flag_subcommand_long_conflict_with_arg() {
415    let _ = Command::new("test")
416        .subcommand(Command::new("some").short_flag('a').long_flag("flag"))
417        .arg(Arg::new("flag").long("flag"))
418        .try_get_matches_from(vec!["myprog", "--flag"])
419        .unwrap();
420}
421
422#[test]
423#[should_panic = "the '--help' long flag for the 'help' argument conflicts with the short flag for 'help' subcommand"]
424fn flag_subcommand_conflict_with_help() {
425    let _ = Command::new("test")
426        .subcommand(Command::new("help").short_flag('h').long_flag("help"))
427        .try_get_matches_from(vec!["myprog", "--help"])
428        .unwrap();
429}
430
431#[test]
432#[cfg(debug_assertions)]
433#[should_panic = "the '--version' long flag for the 'version' argument conflicts with the short flag for 'ver' subcommand"]
434fn flag_subcommand_conflict_with_version() {
435    let _ = Command::new("test")
436        .version("1.0.0")
437        .subcommand(Command::new("ver").short_flag('V').long_flag("version"))
438        .try_get_matches_from(vec!["myprog", "--version"])
439        .unwrap();
440}
441
442#[test]
443fn flag_subcommand_long_infer_pass() {
444    let m = Command::new("prog")
445        .infer_subcommands(true)
446        .subcommand(Command::new("test").long_flag("test"))
447        .try_get_matches_from(vec!["prog", "--te"])
448        .unwrap();
449    assert_eq!(m.subcommand_name(), Some("test"));
450}
451
452#[cfg(not(feature = "suggestions"))]
453#[test]
454fn flag_subcommand_long_infer_fail() {
455    let m = Command::new("prog")
456        .infer_subcommands(true)
457        .subcommand(Command::new("test").long_flag("test"))
458        .subcommand(Command::new("temp").long_flag("temp"))
459        .try_get_matches_from(vec!["prog", "--te"]);
460    assert!(m.is_err(), "{:#?}", m.unwrap());
461    assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
462}
463
464#[cfg(feature = "suggestions")]
465#[test]
466fn flag_subcommand_long_infer_fail() {
467    let m = Command::new("prog")
468        .infer_subcommands(true)
469        .subcommand(Command::new("test").long_flag("test"))
470        .subcommand(Command::new("temp").long_flag("temp"))
471        .try_get_matches_from(vec!["prog", "--te"]);
472    assert!(m.is_err(), "{:#?}", m.unwrap());
473    assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
474}
475
476#[test]
477fn flag_subcommand_long_infer_pass_close() {
478    let m = Command::new("prog")
479        .infer_subcommands(true)
480        .subcommand(Command::new("test").long_flag("test"))
481        .subcommand(Command::new("temp").long_flag("temp"))
482        .try_get_matches_from(vec!["prog", "--tes"])
483        .unwrap();
484    assert_eq!(m.subcommand_name(), Some("test"));
485}
486
487#[test]
488fn flag_subcommand_long_infer_exact_match() {
489    let m = Command::new("prog")
490        .infer_subcommands(true)
491        .subcommand(Command::new("test").long_flag("test"))
492        .subcommand(Command::new("testa").long_flag("testa"))
493        .subcommand(Command::new("testb").long_flag("testb"))
494        .try_get_matches_from(vec!["prog", "--test"])
495        .unwrap();
496    assert_eq!(m.subcommand_name(), Some("test"));
497}
498
499static FLAG_SUBCOMMAND_HELP: &str = "\
500Query the package database.
501
502Usage: pacman {query|--query|-Q} [OPTIONS]
503
504Options:
505  -s, --search <search>...  search locally installed packages for matching strings
506  -i, --info <info>...      view package information
507  -h, --help                Print help
508";
509
510#[test]
511fn flag_subcommand_long_short_normal_usage_string() {
512    let cmd = Command::new("pacman")
513        .about("package manager utility")
514        .version("5.2.1")
515        .subcommand_required(true)
516        .author("Pacman Development Team")
517        // Query subcommand
518        //
519        // Only a few of its arguments are implemented below.
520        .subcommand(
521            Command::new("query")
522                .short_flag('Q')
523                .long_flag("query")
524                .about("Query the package database.")
525                .arg(
526                    Arg::new("search")
527                        .short('s')
528                        .long("search")
529                        .help("search locally installed packages for matching strings")
530                        .conflicts_with("info")
531                        .action(ArgAction::Set)
532                        .num_args(1..),
533                )
534                .arg(
535                    Arg::new("info")
536                        .long("info")
537                        .short('i')
538                        .conflicts_with("search")
539                        .help("view package information")
540                        .action(ArgAction::Set)
541                        .num_args(1..),
542                ),
543        );
544    utils::assert_output(cmd, "pacman -Qh", FLAG_SUBCOMMAND_HELP, false);
545}
546
547static FLAG_SUBCOMMAND_NO_SHORT_HELP: &str = "\
548Query the package database.
549
550Usage: pacman {query|--query} [OPTIONS]
551
552Options:
553  -s, --search <search>...  search locally installed packages for matching strings
554  -i, --info <info>...      view package information
555  -h, --help                Print help
556";
557
558#[test]
559fn flag_subcommand_long_normal_usage_string() {
560    let cmd = Command::new("pacman")
561        .about("package manager utility")
562        .version("5.2.1")
563        .subcommand_required(true)
564        .author("Pacman Development Team")
565        // Query subcommand
566        //
567        // Only a few of its arguments are implemented below.
568        .subcommand(
569            Command::new("query")
570                .long_flag("query")
571                .about("Query the package database.")
572                .arg(
573                    Arg::new("search")
574                        .short('s')
575                        .long("search")
576                        .help("search locally installed packages for matching strings")
577                        .conflicts_with("info")
578                        .action(ArgAction::Set)
579                        .num_args(1..),
580                )
581                .arg(
582                    Arg::new("info")
583                        .long("info")
584                        .short('i')
585                        .conflicts_with("search")
586                        .help("view package information")
587                        .action(ArgAction::Set)
588                        .num_args(1..),
589                ),
590        );
591    utils::assert_output(
592        cmd,
593        "pacman query --help",
594        FLAG_SUBCOMMAND_NO_SHORT_HELP,
595        false,
596    );
597}
598
599static FLAG_SUBCOMMAND_NO_LONG_HELP: &str = "\
600Query the package database.
601
602Usage: pacman {query|-Q} [OPTIONS]
603
604Options:
605  -s, --search <search>...  search locally installed packages for matching strings
606  -i, --info <info>...      view package information
607  -h, --help                Print help
608";
609
610#[test]
611fn flag_subcommand_short_normal_usage_string() {
612    let cmd = Command::new("pacman")
613        .about("package manager utility")
614        .version("5.2.1")
615        .subcommand_required(true)
616        .author("Pacman Development Team")
617        // Query subcommand
618        //
619        // Only a few of its arguments are implemented below.
620        .subcommand(
621            Command::new("query")
622                .short_flag('Q')
623                .about("Query the package database.")
624                .arg(
625                    Arg::new("search")
626                        .short('s')
627                        .long("search")
628                        .help("search locally installed packages for matching strings")
629                        .conflicts_with("info")
630                        .action(ArgAction::Set)
631                        .num_args(1..),
632                )
633                .arg(
634                    Arg::new("info")
635                        .long("info")
636                        .short('i')
637                        .conflicts_with("search")
638                        .help("view package information")
639                        .action(ArgAction::Set)
640                        .num_args(1..),
641                ),
642        );
643    utils::assert_output(
644        cmd,
645        "pacman query --help",
646        FLAG_SUBCOMMAND_NO_LONG_HELP,
647        false,
648    );
649}
650