clap/tests/subcommands.rs
Ed Page 7e899cd340 Revert "Deprecate Arg::help in favour of Arg::about"
This reverts commits 24cb8b1..d0abb37 from clap-rs/clap#1840

This is part of #16.  clap-rs/clap#1840 wasn't the right call but we
don't have time to make the decision now, so instead of having one
option and changing it in 4.0, this reverts back to clap2 behavior.
2021-11-18 12:25:49 -06:00

552 lines
15 KiB
Rust

mod utils;
use clap::{App, AppSettings, Arg, ErrorKind};
static VISIBLE_ALIAS_HELP: &str = "clap-test 2.6
USAGE:
clap-test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test Some help [aliases: dongle, done]
";
static INVISIBLE_ALIAS_HELP: &str = "clap-test 2.6
USAGE:
clap-test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test Some help
";
static SUBCMD_ALPHA_ORDER: &str = "test 1
USAGE:
test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
a1 blah a1
b1 blah b1
help Print this message or the help of the given subcommand(s)
";
static SUBCMD_DECL_ORDER: &str = "test 1
USAGE:
test [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
b1 blah b1
a1 blah a1
help Print this message or the help of the given subcommand(s)
";
#[cfg(feature = "suggestions")]
static DYM_SUBCMD: &str = "error: The subcommand 'subcm' wasn't recognized
Did you mean 'subcmd'?
If you believe you received this message in error, try re-running with 'dym -- subcm'
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
#[cfg(feature = "suggestions")]
static DYM_SUBCMD_AMBIGUOUS: &str = "error: The subcommand 'te' wasn't recognized
Did you mean 'test' or 'temp'?
If you believe you received this message in error, try re-running with 'dym -- te'
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
static SUBCMD_AFTER_DOUBLE_DASH: &str =
"error: Found argument 'subcmd' which wasn't expected, or isn't valid in this context
\tIf you tried to supply `subcmd` as a subcommand, remove the '--' before it.
USAGE:
app [SUBCOMMAND]
For more information try --help
";
#[test]
fn subcommand() {
let m = App::new("test")
.subcommand(
App::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
),
)
.arg(Arg::new("other").long("other"))
.get_matches_from(vec!["myprog", "some", "--test", "testing"]);
assert_eq!(m.subcommand_name().unwrap(), "some");
let sub_m = m.subcommand_matches("some").unwrap();
assert!(sub_m.is_present("test"));
assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}
#[test]
fn subcommand_none_given() {
let m = App::new("test")
.subcommand(
App::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
),
)
.arg(Arg::new("other").long("other"))
.get_matches_from(vec![""]);
assert!(m.subcommand_name().is_none());
}
#[test]
fn subcommand_multiple() {
let m = App::new("test")
.subcommands(vec![
App::new("some").arg(
Arg::new("test")
.short('t')
.long("test")
.takes_value(true)
.help("testing testing"),
),
App::new("add").arg(Arg::new("roster").short('r')),
])
.arg(Arg::new("other").long("other"))
.get_matches_from(vec!["myprog", "some", "--test", "testing"]);
assert!(m.subcommand_matches("some").is_some());
assert!(m.subcommand_matches("add").is_none());
assert_eq!(m.subcommand_name().unwrap(), "some");
let sub_m = m.subcommand_matches("some").unwrap();
assert!(sub_m.is_present("test"));
assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}
#[test]
fn subcommand_display_order() {
let app_subcmd_alpha_order = App::new("test").version("1").subcommands(vec![
App::new("b1")
.about("blah b1")
.arg(Arg::new("test").short('t')),
App::new("a1")
.about("blah a1")
.arg(Arg::new("roster").short('r')),
]);
assert!(utils::compare_output(
app_subcmd_alpha_order,
"test --help",
SUBCMD_ALPHA_ORDER,
false,
));
let app_subcmd_decl_order = App::new("test")
.version("1")
.setting(clap::AppSettings::DeriveDisplayOrder)
.subcommands(vec![
App::new("b1")
.about("blah b1")
.arg(Arg::new("test").short('t')),
App::new("a1")
.about("blah a1")
.arg(Arg::new("roster").short('r')),
]);
assert!(utils::compare_output(
app_subcmd_decl_order,
"test --help",
SUBCMD_DECL_ORDER,
false,
));
}
#[test]
fn single_alias() {
let m = App::new("myprog")
.subcommand(App::new("test").alias("do-stuff"))
.get_matches_from(vec!["myprog", "do-stuff"]);
assert_eq!(m.subcommand_name(), Some("test"));
}
#[test]
fn multiple_aliases() {
let m = App::new("myprog")
.subcommand(App::new("test").aliases(&["do-stuff", "test-stuff"]))
.get_matches_from(vec!["myprog", "test-stuff"]);
assert_eq!(m.subcommand_name(), Some("test"));
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output() {
let app = App::new("dym").subcommand(App::new("subcmd"));
assert!(utils::compare_output(app, "dym subcm", DYM_SUBCMD, true));
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_ambiguous() {
let app = App::new("dym")
.subcommand(App::new("test"))
.subcommand(App::new("temp"));
assert!(utils::compare_output(
app,
"dym te",
DYM_SUBCMD_AMBIGUOUS,
true
));
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg() {
static EXPECTED: &str =
"error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
\tIf you tried to supply `--subcmarg` as a value rather than a flag, use `-- --subcmarg`
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
let app = App::new("dym")
.subcommand(App::new("subcmd").arg(Arg::from("-s --subcmdarg [subcmdarg] 'tests'")));
assert!(utils::compare_output(
app,
"dym --subcmarg subcmd",
EXPECTED,
true
));
}
#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg_false_positives() {
static EXPECTED: &str =
"error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
\tIf you tried to supply `--subcmarg` as a value rather than a flag, use `-- --subcmarg`
USAGE:
dym [SUBCOMMAND]
For more information try --help
";
let app = App::new("dym")
.subcommand(App::new("subcmd").arg(Arg::from("-s --subcmdarg [subcmdarg] 'tests'")));
assert!(utils::compare_output(
app,
"dym --subcmarg foo",
EXPECTED,
true
));
}
#[test]
fn alias_help() {
let m = App::new("myprog")
.subcommand(App::new("test").alias("do-stuff"))
.try_get_matches_from(vec!["myprog", "help", "do-stuff"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::DisplayHelp);
}
#[test]
fn visible_aliases_help_output() {
let app = App::new("clap-test").version("2.6").subcommand(
App::new("test")
.about("Some help")
.alias("invisible")
.visible_alias("dongle")
.visible_alias("done"),
);
assert!(utils::compare_output(
app,
"clap-test --help",
VISIBLE_ALIAS_HELP,
false
));
}
#[test]
fn invisible_aliases_help_output() {
let app = App::new("clap-test")
.version("2.6")
.subcommand(App::new("test").about("Some help").alias("invisible"));
assert!(utils::compare_output(
app,
"clap-test --help",
INVISIBLE_ALIAS_HELP,
false
));
}
#[test]
#[cfg(feature = "unstable-replace")]
fn replace() {
let m = App::new("prog")
.subcommand(App::new("module").subcommand(App::new("install").about("Install module")))
.replace("install", &["module", "install"])
.get_matches_from(vec!["prog", "install"]);
assert_eq!(m.subcommand_name(), Some("module"));
assert_eq!(
m.subcommand_matches("module").unwrap().subcommand_name(),
Some("install")
);
}
#[test]
fn issue_1031_args_with_same_name() {
let res = App::new("prog")
.arg(Arg::from("--ui-path=<PATH>"))
.subcommand(App::new("signer"))
.try_get_matches_from(vec!["prog", "--ui-path", "signer"]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
let m = res.unwrap();
assert_eq!(m.value_of("ui-path"), Some("signer"));
}
#[test]
fn issue_1031_args_with_same_name_no_more_vals() {
let res = App::new("prog")
.arg(Arg::from("--ui-path=<PATH>"))
.subcommand(App::new("signer"))
.try_get_matches_from(vec!["prog", "--ui-path", "value", "signer"]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
let m = res.unwrap();
assert_eq!(m.value_of("ui-path"), Some("value"));
assert_eq!(m.subcommand_name(), Some("signer"));
}
#[test]
fn issue_1161_multiple_hyphen_hyphen() {
// from example 22
let res = App::new("myprog")
.arg(Arg::new("eff").short('f'))
.arg(Arg::new("pea").short('p').takes_value(true))
.arg(
Arg::new("slop")
.takes_value(true)
.multiple_values(true)
.last(true),
)
.try_get_matches_from(vec![
"-f",
"-p=bob",
"--",
"sloppy",
"slop",
"-a",
"--",
"subprogram",
"position",
"args",
]);
assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
let m = res.unwrap();
let expected = Some(vec![
"sloppy",
"slop",
"-a",
"--",
"subprogram",
"position",
"args",
]);
let actual = m.values_of("slop").map(|vals| vals.collect::<Vec<_>>());
assert_eq!(expected, actual);
}
#[test]
fn issue_1722_not_emit_error_when_arg_follows_similar_to_a_subcommand() {
let m = App::new("myprog")
.subcommand(App::new("subcommand"))
.arg(Arg::new("argument"))
.try_get_matches_from(vec!["myprog", "--", "subcommand"]);
assert_eq!(m.unwrap().value_of("argument"), Some("subcommand"));
}
#[test]
fn subcommand_placeholder_test() {
let mut app = App::new("myprog")
.subcommand(App::new("subcommand"))
.subcommand_placeholder("TEST_PLACEHOLDER", "TEST_HEADER");
assert_eq!(&app.render_usage(), "USAGE:\n myprog [TEST_PLACEHOLDER]");
let mut help_text = Vec::new();
app.write_help(&mut help_text)
.expect("Failed to write to internal buffer");
assert!(String::from_utf8(help_text)
.unwrap()
.contains("TEST_HEADER:"));
}
#[test]
fn subcommand_used_after_double_dash() {
let app = App::new("app").subcommand(App::new("subcmd"));
assert!(utils::compare_output(
app,
"app -- subcmd",
SUBCMD_AFTER_DOUBLE_DASH,
true
));
}
#[test]
fn subcommand_after_argument() {
let m = App::new("myprog")
.arg(Arg::new("some_text"))
.subcommand(App::new("test"))
.get_matches_from(vec!["myprog", "teat", "test"]);
assert_eq!(m.value_of("some_text"), Some("teat"));
assert_eq!(m.subcommand().unwrap().0, "test");
}
#[test]
fn subcommand_after_argument_looks_like_help() {
let m = App::new("myprog")
.arg(Arg::new("some_text"))
.subcommand(App::new("test"))
.get_matches_from(vec!["myprog", "helt", "test"]);
assert_eq!(m.value_of("some_text"), Some("helt"));
assert_eq!(m.subcommand().unwrap().0, "test");
}
#[test]
fn issue_2494_subcommand_is_present() {
let app = App::new("opt")
.arg(Arg::new("global").long("global"))
.subcommand(App::new("global"));
let m = app.clone().get_matches_from(&["opt", "--global", "global"]);
assert_eq!(m.subcommand_name().unwrap(), "global");
assert!(m.is_present("global"));
let m = app.clone().get_matches_from(&["opt", "--global"]);
assert!(m.subcommand_name().is_none());
assert!(m.is_present("global"));
let m = app.get_matches_from(&["opt", "global"]);
assert_eq!(m.subcommand_name().unwrap(), "global");
assert!(!m.is_present("global"));
}
#[test]
fn subcommand_not_recognized() {
let app = App::new("fake")
.subcommand(App::new("sub"))
.setting(AppSettings::DisableHelpSubcommand)
.setting(AppSettings::InferSubcommands);
assert!(utils::compare_output(
app,
"fake help",
"error: The subcommand 'help' wasn't recognized
USAGE:
fake <subcommands>
For more information try --help
",
true
));
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn busybox_like_multicall() {
let app = App::new("busybox")
.setting(AppSettings::Multicall)
.subcommand(App::new("true"))
.subcommand(App::new("false"));
let m = app.clone().get_matches_from(&["busybox", "true"]);
assert_eq!(m.subcommand_name(), Some("true"));
let m = app.clone().get_matches_from(&["true"]);
assert_eq!(m.subcommand_name(), Some("true"));
let m = app.clone().try_get_matches_from(&["a.out"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}
#[cfg(feature = "unstable-multicall")]
#[test]
fn hostname_like_multicall() {
let mut app = App::new("hostname")
.setting(AppSettings::Multicall)
.subcommand(App::new("hostname"))
.subcommand(App::new("dnsdomainname"));
let m = app.clone().get_matches_from(&["hostname"]);
assert_eq!(m.subcommand_name(), Some("hostname"));
let m = app.clone().get_matches_from(&["dnsdomainname"]);
assert_eq!(m.subcommand_name(), Some("dnsdomainname"));
let m = app.clone().try_get_matches_from(&["a.out"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
let m = app.try_get_matches_from_mut(&["hostname", "hostname"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
let m = app.try_get_matches_from(&["hostname", "dnsdomainname"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
}