diff options
Diffstat (limited to 'clap/tests')
35 files changed, 10247 insertions, 0 deletions
diff --git a/clap/tests/app.yml b/clap/tests/app.yml new file mode 100644 index 0000000..850bb82 --- /dev/null +++ b/clap/tests/app.yml @@ -0,0 +1,121 @@ +name: claptests +version: "1.0" +about: tests clap library +author: Kevin K. <kbknapp@gmail.com> +settings: + - ArgRequiredElseHelp +help_message: prints help with a nonstandard description +args: + - opt: + short: o + long: option + multiple: true + help: tests options + - positional: + help: tests positionals + index: 1 + - positional2: + help: tests positionals with exclusions + index: 2 + default_value_if: + - [flag, Null, some] + - [postional, other, something] + - flag: + short: f + long: flag + multiple: true + help: tests flags + global: true + - flag2: + short: F + help: tests flags with exclusions + conflicts_with: + - flag + requires: + - option2 + - option2: + long: long-option-2 + help: tests long options with exclusions + conflicts_with: + - option + requires: + - positional2 + - option3: + short: O + long: Option + help: tests options with specific value sets + takes_value: true + possible_values: + - fast + - slow + requires_if: + - [fast, flag] + - positional3: + index: 3 + help: tests positionals with specific values + possible_values: [ vi, emacs ] + - multvals: + long: multvals + help: Tests multiple values, not mult occs + value_names: + - one + - two + - multvalsmo: + long: multvalsmo + multiple: true + help: Tests multiple values, not mult occs + value_names: [one, two] + - multvalsdelim: + long: multvalsdelim + help: Tests multiple values with required delimiter + multiple: true + require_delimiter: true + - singlealias: + long: singlealias + help: Tests single alias + aliases: [alias] + required_if: + - [multvalsmo, two] + - multaliases: + long: multaliases + help: Tests multiple aliases + aliases: [als1, als2, als3] + - minvals2: + long: minvals2 + multiple: true + help: Tests 2 min vals + min_values: 2 + - maxvals3: + long: maxvals3 + multiple: true + help: Tests 3 max vals + max_values: 3 + - case_insensitive: + help: Test case_insensitive + possible_values: [test123, test321] + case_insensitive: true + +arg_groups: + - test: + args: + - maxvals3 + - minmals2 + conflicts_with: + - option3 + requires: + - multvals +subcommands: + - subcmd: + about: tests subcommands + version: "0.1" + author: Kevin K. <kbknapp@gmail.com> + args: + - scoption: + short: o + long: option + multiple: true + help: tests options + takes_value: true + - scpositional: + help: tests positionals + index: 1 diff --git a/clap/tests/app_settings.rs b/clap/tests/app_settings.rs new file mode 100644 index 0000000..3d72a3b --- /dev/null +++ b/clap/tests/app_settings.rs @@ -0,0 +1,965 @@ +extern crate clap; +extern crate regex; + +use clap::{App, Arg, SubCommand, AppSettings, ErrorKind}; + +include!("../clap-test.rs"); + +static ALLOW_EXT_SC: &'static str = "clap-test v1.4.8 + +USAGE: + clap-test [SUBCOMMAND] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information"; + +static DONT_COLLAPSE_ARGS: &'static str = "clap-test v1.4.8 + +USAGE: + clap-test [arg1] [arg2] [arg3] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <arg1> some + <arg2> some + <arg3> some"; + +static REQUIRE_EQUALS: &'static str = "clap-test v1.4.8 + +USAGE: + clap-test --opt=<FILE> + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt=<FILE> some"; + +static UNIFIED_HELP: &'static str = "test 1.3 +Kevin K. +tests stuff + +USAGE: + test [OPTIONS] [arg1] + +OPTIONS: + -f, --flag some flag + -h, --help Prints help information + --option <opt> some option + -V, --version Prints version information + +ARGS: + <arg1> some pos arg"; + +static SKIP_POS_VALS: &'static str = "test 1.3 +Kevin K. +tests stuff + +USAGE: + test [OPTIONS] [arg1] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <opt> some option + +ARGS: + <arg1> some pos arg"; + +#[test] +fn sub_command_negate_required() { + App::new("sub_command_negate") + .setting(AppSettings::SubcommandsNegateReqs) + .arg(Arg::with_name("test") + .required(true) + .index(1)) + .subcommand(SubCommand::with_name("sub1")) + .get_matches_from(vec!["myprog", "sub1"]); +} + +#[test] +fn global_version() { + let mut app = App::new("global_version") + .setting(AppSettings::GlobalVersion) + .version("1.1") + .subcommand(SubCommand::with_name("sub1")); + app.p.propagate_settings(); + assert_eq!(app.p.subcommands[0].p.meta.version, Some("1.1")); +} + +#[test] +fn sub_command_negate_required_2() { + let result = App::new("sub_command_negate") + .setting(AppSettings::SubcommandsNegateReqs) + .arg(Arg::with_name("test") + .required(true) + .index(1)) + .subcommand(SubCommand::with_name("sub1")) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn sub_command_required() { + let result = App::new("sc_required") + .setting(AppSettings::SubcommandRequired) + .subcommand(SubCommand::with_name("sub1")) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingSubcommand); +} + +#[test] +fn arg_required_else_help() { + let result = App::new("arg_required") + .setting(AppSettings::ArgRequiredElseHelp) + .arg(Arg::with_name("test") + .index(1)) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingArgumentOrSubcommand); +} + +#[test] +fn arg_required_else_help_over_reqs() { + let result = App::new("arg_required") + .setting(AppSettings::ArgRequiredElseHelp) + .arg(Arg::with_name("test") + .index(1).required(true)) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingArgumentOrSubcommand); +} + +#[cfg(not(feature = "suggestions"))] +#[test] +fn infer_subcommands_fail_no_args() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from_safe(vec![ + "prog", "te" + ]); + assert!(m.is_err(), "{:#?}", m.unwrap()); + assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand); +} + +#[cfg(feature = "suggestions")] +#[test] +fn infer_subcommands_fail_no_args() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from_safe(vec![ + "prog", "te" + ]); + assert!(m.is_err(), "{:#?}", m.unwrap()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand); +} + +#[test] +fn infer_subcommands_fail_with_args() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .arg(Arg::with_name("some")) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from_safe(vec![ + "prog", "t" + ]); + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + assert_eq!(m.unwrap().value_of("some"), Some("t")); +} + +#[test] +fn infer_subcommands_fail_with_args2() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .arg(Arg::with_name("some")) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from_safe(vec![ + "prog", "te" + ]); + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + assert_eq!(m.unwrap().value_of("some"), Some("te")); +} + +#[test] +fn infer_subcommands_pass() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .get_matches_from(vec![ + "prog", "te" + ]); + assert_eq!(m.subcommand_name(), Some("test")); +} + +#[test] +fn infer_subcommands_pass_close() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from(vec![ + "prog", "tes" + ]); + assert_eq!(m.subcommand_name(), Some("test")); +} + +#[test] +fn infer_subcommands_pass_exact_match() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("testa")) + .subcommand(SubCommand::with_name("testb")) + .get_matches_from(vec![ + "prog", "test" + ]); + assert_eq!(m.subcommand_name(), Some("test")); +} + +#[cfg(feature = "suggestions")] +#[test] +fn infer_subcommands_fail_suggestions() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from_safe(vec![ + "prog", "temps" + ]); + assert!(m.is_err(), "{:#?}", m.unwrap()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand); +} + +#[cfg(not(feature = "suggestions"))] +#[test] +fn infer_subcommands_fail_suggestions() { + let m = App::new("prog") + .setting(AppSettings::InferSubcommands) + .subcommand(SubCommand::with_name("test")) + .subcommand(SubCommand::with_name("temp")) + .get_matches_from_safe(vec![ + "prog", "temps" + ]); + assert!(m.is_err(), "{:#?}", m.unwrap()); + assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand); +} + +#[test] +fn no_bin_name() { + let result = App::new("arg_required") + .setting(AppSettings::NoBinaryName) + .arg(Arg::with_name("test") + .required(true) + .index(1)) + .get_matches_from_safe(vec!["testing"]); + assert!(result.is_ok()); + let matches = result.unwrap(); + assert_eq!(matches.value_of("test").unwrap(), "testing"); +} + +#[test] +fn unified_help() { + let app = App::new("myTest") + .name("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .setting(AppSettings::UnifiedHelpMessage) + .args_from_usage("-f, --flag 'some flag' + [arg1] 'some pos arg' + --option [opt] 'some option'"); + + assert!(test::compare_output(app, "test --help", UNIFIED_HELP, false)); +} + +#[test] +fn skip_possible_values() { + let app = App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .setting(AppSettings::HidePossibleValuesInHelp) + .args(&[Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]), + Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"])]); + + assert!(test::compare_output(app, "test --help", SKIP_POS_VALS, false)); +} + +#[test] +fn global_setting() { + let mut app = App::new("test") + .global_setting(AppSettings::ColoredHelp) + .subcommand(SubCommand::with_name("subcmd")); + app.p.propagate_settings(); + assert!(app.p + .subcommands + .iter() + .filter(|s| s.p + .meta + .name == "subcmd") + .next() + .unwrap() + .p + .is_set(AppSettings::ColoredHelp)); +} + +#[test] +fn global_settings() { + let mut app = App::new("test") + .global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg]) + .subcommand(SubCommand::with_name("subcmd")); + app.p.propagate_settings(); + assert!(app.p + .subcommands + .iter() + .filter(|s| s.p + .meta + .name == "subcmd") + .next() + .unwrap() + .p + .is_set(AppSettings::ColoredHelp)); + assert!(app.p + .subcommands + .iter() + .filter(|s| s.p + .meta + .name == "subcmd") + .next() + .unwrap() + .p + .is_set(AppSettings::TrailingVarArg)); + +} + +#[test] +fn stop_delim_values_only_pos_follows() { + let r = App::new("onlypos") + .setting(AppSettings::DontDelimitTrailingValues) + .args(&[Arg::from_usage("-f [flag] 'some opt'"), + Arg::from_usage("[arg]... 'some arg'")]) + .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert!(!m.is_present("f")); + assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]); +} + +#[test] +fn dont_delim_values_trailingvararg() { + let m = App::new("positional") + .setting(AppSettings::TrailingVarArg) + .setting(AppSettings::DontDelimitTrailingValues) + .arg( + Arg::from_usage("[opt]... 'some pos'"), + ) + .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]); + assert!(m.is_present("opt")); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]); +} + +#[test] +fn delim_values_only_pos_follows() { + let r = App::new("onlypos") + .args(&[Arg::from_usage("-f [flag] 'some opt'"), + Arg::from_usage("[arg]... 'some arg'")]) + .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert!(!m.is_present("f")); + assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]); +} + +#[test] +fn delim_values_trailingvararg() { + let m = App::new("positional") + .setting(AppSettings::TrailingVarArg) + .arg( + Arg::from_usage("[opt]... 'some pos'"), + ) + .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]); + assert!(m.is_present("opt")); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]); +} + +#[test] +fn delim_values_only_pos_follows_with_delim() { + let r = App::new("onlypos") + .args(&[Arg::from_usage("-f [flag] 'some opt'"), + Arg::from_usage("[arg]... 'some arg'").use_delimiter(true)]) + .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert!(!m.is_present("f")); + assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g", "x"]); +} + +#[test] +fn delim_values_trailingvararg_with_delim() { + let m = App::new("positional") + .setting(AppSettings::TrailingVarArg) + .arg( + Arg::from_usage("[opt]... 'some pos'").use_delimiter(true), + ) + .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]); + assert!(m.is_present("opt")); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl", "-bar"]); +} + +#[test] +fn leading_hyphen_short() { + let res = App::new("leadhy") + .setting(AppSettings::AllowLeadingHyphen) + .arg(Arg::with_name("some")) + .arg(Arg::with_name("other") + .short("o")) + .get_matches_from_safe(vec!["", "-bar", "-o"]); + assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); + let m = res.unwrap(); + assert!(m.is_present("some")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("some").unwrap(), "-bar"); +} + +#[test] +fn leading_hyphen_long() { + let res = App::new("leadhy") + .setting(AppSettings::AllowLeadingHyphen) + .arg(Arg::with_name("some")) + .arg(Arg::with_name("other") + .short("o")) + .get_matches_from_safe(vec!["", "--bar", "-o"]); + assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); + let m = res.unwrap(); + assert!(m.is_present("some")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("some").unwrap(), "--bar"); +} + +#[test] +fn leading_hyphen_opt() { + let res = App::new("leadhy") + .setting(AppSettings::AllowLeadingHyphen) + .arg(Arg::with_name("some") + .takes_value(true) + .long("opt")) + .arg(Arg::with_name("other") + .short("o")) + .get_matches_from_safe(vec!["", "--opt", "--bar", "-o"]); + assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); + let m = res.unwrap(); + assert!(m.is_present("some")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("some").unwrap(), "--bar"); +} + +#[test] +fn allow_negative_numbers() { + let res = App::new("negnum") + .setting(AppSettings::AllowNegativeNumbers) + .arg(Arg::with_name("panum")) + .arg(Arg::with_name("onum") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec!["negnum", "-20", "-o", "-1.2"]); + assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind); + let m = res.unwrap(); + assert_eq!(m.value_of("panum").unwrap(), "-20"); + assert_eq!(m.value_of("onum").unwrap(), "-1.2"); +} + +#[test] +fn allow_negative_numbers_fail() { + let res = App::new("negnum") + .setting(AppSettings::AllowNegativeNumbers) + .arg(Arg::with_name("panum")) + .arg(Arg::with_name("onum") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec!["negnum", "--foo", "-o", "-1.2"]); + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument) +} + +#[test] +fn leading_double_hyphen_trailingvararg() { + let m = App::new("positional") + .setting(AppSettings::TrailingVarArg) + .setting(AppSettings::AllowLeadingHyphen) + .arg( + Arg::from_usage("[opt]... 'some pos'"), + ) + .get_matches_from(vec!["", "--foo", "-Wl", "bar"]); + assert!(m.is_present("opt")); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["--foo", "-Wl", "bar"]); +} + +#[test] +fn test_unset_setting() { + let m = App::new("unset_setting"); + assert!(m.p.is_set(AppSettings::AllowInvalidUtf8)); + + let m = m.unset_setting(AppSettings::AllowInvalidUtf8); + assert!(!m.p.is_set(AppSettings::AllowInvalidUtf8)); +} + +#[test] +fn test_unset_settings() { + let m = App::new("unset_settings"); + assert!(&m.p.is_set(AppSettings::AllowInvalidUtf8)); + assert!(&m.p.is_set(AppSettings::ColorAuto)); + + let m = m.unset_settings(&[AppSettings::AllowInvalidUtf8, + AppSettings::ColorAuto]); + assert!(!m.p.is_set(AppSettings::AllowInvalidUtf8)); + assert!(!m.p.is_set(AppSettings::ColorAuto)); +} + +#[test] +fn disable_help_subcommand() { + let result = App::new("disablehelp") + .setting(AppSettings::DisableHelpSubcommand) + .subcommand(SubCommand::with_name("sub1")) + .get_matches_from_safe(vec!["", "help"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::UnknownArgument); +} + +#[test] +fn dont_collapse_args() { + let app = App::new("clap-test") + .version("v1.4.8") + .setting(AppSettings::DontCollapseArgsInUsage) + .args(&[ + Arg::with_name("arg1").help("some"), + Arg::with_name("arg2").help("some"), + Arg::with_name("arg3").help("some"), + ]); + assert!(test::compare_output(app, "clap-test --help", DONT_COLLAPSE_ARGS, false)); +} + +#[test] +fn require_eq() { + let app = App::new("clap-test") + .version("v1.4.8") + .arg( + Arg::with_name("opt") + .long("opt") + .short("o") + .required(true) + .require_equals(true) + .value_name("FILE") + .help("some"), + ); + assert!(test::compare_output(app, "clap-test --help", REQUIRE_EQUALS, false)); +} + +#[test] +fn args_negate_subcommands_one_level() { + let res = App::new("disablehelp") + .setting(AppSettings::ArgsNegateSubcommands) + .setting(AppSettings::SubcommandsNegateReqs) + .arg_from_usage("<arg1> 'some arg'") + .arg_from_usage("<arg2> 'some arg'") + .subcommand(SubCommand::with_name("sub1") + .subcommand(SubCommand::with_name("sub2") + .subcommand(SubCommand::with_name("sub3")) + ) + ) + .get_matches_from_safe(vec!["", "pickles", "sub1"]); + assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind); + let m = res.unwrap(); + assert_eq!(m.value_of("arg2"), Some("sub1")); +} + +#[test] +fn args_negate_subcommands_two_levels() { + let res = App::new("disablehelp") + .global_setting(AppSettings::ArgsNegateSubcommands) + .global_setting(AppSettings::SubcommandsNegateReqs) + .arg_from_usage("<arg1> 'some arg'") + .arg_from_usage("<arg2> 'some arg'") + .subcommand(SubCommand::with_name("sub1") + .arg_from_usage("<arg> 'some'") + .arg_from_usage("<arg2> 'some'") + .subcommand(SubCommand::with_name("sub2") + .subcommand(SubCommand::with_name("sub3")) + ) + ) + .get_matches_from_safe(vec!["", "sub1", "arg", "sub2"]); + assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind); + let m = res.unwrap(); + assert_eq!(m.subcommand_matches("sub1").unwrap().value_of("arg2"), Some("sub2")); +} + + +#[test] +fn propagate_vals_down() { + let m = App::new("myprog") + .arg(Arg::from_usage("[cmd] 'command to run'").global(true)) + .subcommand(SubCommand::with_name("foo")) + .get_matches_from_safe(vec!["myprog", "set", "foo"]); + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + assert_eq!(m.value_of("cmd"), Some("set")); + let sub_m = m.subcommand_matches("foo").unwrap(); + assert_eq!(sub_m.value_of("cmd"), Some("set")); +} + +#[test] +fn allow_missing_positional() { + let m = App::new("test") + .setting(AppSettings::AllowMissingPositional) + .arg(Arg::from_usage("[src] 'some file'").default_value("src")) + .arg_from_usage("<dest> 'some file'") + .get_matches_from_safe(vec!["test", "file"]); + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + assert_eq!(m.value_of("src"), Some("src")); + assert_eq!(m.value_of("dest"), Some("file")); +} + +#[test] +fn allow_missing_positional_no_default() { + let m = App::new("test") + .setting(AppSettings::AllowMissingPositional) + .arg(Arg::from_usage("[src] 'some file'")) + .arg_from_usage("<dest> 'some file'") + .get_matches_from_safe(vec!["test", "file"]); + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + assert_eq!(m.value_of("src"), None); + assert_eq!(m.value_of("dest"), Some("file")); +} + +#[test] +fn missing_positional_no_hyphen() { + let r = App::new("bench") + .setting(AppSettings::AllowMissingPositional) + .arg(Arg::from_usage("[BENCH] 'some bench'")) + .arg(Arg::from_usage("[ARGS]... 'some args'")) + .get_matches_from_safe(vec!["bench", "foo", "arg1", "arg2", "arg3"]); + assert!(r.is_ok(), "{:?}", r.unwrap_err().kind); + + let m = r.unwrap(); + + let expected_bench = Some("foo"); + let expected_args = vec!["arg1", "arg2", "arg3"]; + + assert_eq!(m.value_of("BENCH"), expected_bench); + assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args); +} + +#[test] +fn missing_positional_hyphen() { + let r = App::new("bench") + .setting(AppSettings::AllowMissingPositional) + .arg(Arg::from_usage("[BENCH] 'some bench'")) + .arg(Arg::from_usage("[ARGS]... 'some args'")) + .get_matches_from_safe(vec!["bench", "--", "arg1", "arg2", "arg3"]); + assert!(r.is_ok(), "{:?}", r.unwrap_err().kind); + + let m = r.unwrap(); + + let expected_bench = None; + let expected_args = vec!["arg1", "arg2", "arg3"]; + + assert_eq!(m.value_of("BENCH"), expected_bench); + assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args); +} + +#[test] +fn missing_positional_hyphen_far_back() { + let r = App::new("bench") + .setting(AppSettings::AllowMissingPositional) + .arg(Arg::from_usage("[BENCH1] 'some bench'")) + .arg(Arg::from_usage("[BENCH2] 'some bench'")) + .arg(Arg::from_usage("[BENCH3] 'some bench'")) + .arg(Arg::from_usage("[ARGS]... 'some args'")) + .get_matches_from_safe(vec!["bench", "foo", "--", "arg1", "arg2", "arg3"]); + assert!(r.is_ok(), "{:?}", r.unwrap_err().kind); + + let m = r.unwrap(); + + let expected_bench1 = Some("foo"); + let expected_bench2 = None; + let expected_bench3 = None; + let expected_args = vec!["arg1", "arg2", "arg3"]; + + assert_eq!(m.value_of("BENCH1"), expected_bench1); + assert_eq!(m.value_of("BENCH2"), expected_bench2); + assert_eq!(m.value_of("BENCH3"), expected_bench3); + assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args); +} + +#[test] +fn missing_positional_hyphen_req_error() { + let r = App::new("bench") + .setting(AppSettings::AllowMissingPositional) + .arg(Arg::from_usage("[BENCH1] 'some bench'")) + .arg(Arg::from_usage("<BENCH2> 'some bench'")) + .arg(Arg::from_usage("[ARGS]... 'some args'")) + .get_matches_from_safe(vec!["bench", "foo", "--", "arg1", "arg2", "arg3"]); + assert!(r.is_err()); + assert_eq!(r.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn issue_1066_allow_leading_hyphen_and_unknown_args() { + let res = App::new("prog") + .global_setting(AppSettings::AllowLeadingHyphen) + .arg(Arg::from_usage("--some-argument")) + .get_matches_from_safe(vec!["prog", "hello"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); +} + +#[test] +fn issue_1066_allow_leading_hyphen_and_unknown_args_no_vals() { + let res = App::new("prog") + .global_setting(AppSettings::AllowLeadingHyphen) + .arg(Arg::from_usage("--some-argument")) + .get_matches_from_safe(vec!["prog", "--hello"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); +} + +#[test] +fn issue_1066_allow_leading_hyphen_and_unknown_args_option() { + let res = App::new("prog") + .global_setting(AppSettings::AllowLeadingHyphen) + .arg(Arg::from_usage("--some-argument=[val]")) + .get_matches_from_safe(vec!["prog", "-hello"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); +} + +#[test] +fn issue_1093_allow_ext_sc() { + let app = App::new("clap-test") + .version("v1.4.8") + .setting(AppSettings::AllowExternalSubcommands); + assert!(test::compare_output(app, "clap-test --help", ALLOW_EXT_SC, false)); +} + + +#[test] +fn allow_ext_sc_when_sc_required() { + let res = App::new("clap-test") + .version("v1.4.8") + .setting(AppSettings::AllowExternalSubcommands) + .setting(AppSettings::SubcommandRequiredElseHelp) + .get_matches_from_safe(vec!["clap-test", "external-cmd", "foo"]); + assert!(res.is_ok()); + let m = res.unwrap(); + match m.subcommand() { + (name, Some(args)) => { + assert_eq!(name, "external-cmd"); + assert_eq!(args.values_of_lossy(""), Some(vec!["foo".to_string()])); + } + _ => assert!(false), + } +} + +#[test] +fn external_subcommand_looks_like_built_in() { + let res = App::new("cargo") + .version("1.26.0") + .setting(AppSettings::AllowExternalSubcommands) + .subcommand(SubCommand::with_name("install")) + .get_matches_from_safe(vec!["cargo", "install-update", "foo"]); + assert!(res.is_ok()); + let m = res.unwrap(); + match m.subcommand() { + (name, Some(args)) => { + assert_eq!(name, "install-update"); + assert_eq!(args.values_of_lossy(""), Some(vec!["foo".to_string()])); + } + _ => assert!(false), + } +} + +#[test] +fn aaos_flags() { + // flags + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--flag 'some flag'")) + .get_matches_from_safe(vec!["", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1); +} + +#[test] +fn aaos_flags_mult() { + // flags with multiple + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--flag... 'some flag'")) + .get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 4); +} + +#[test] +fn aaos_opts() { + // opts + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn aaos_opts_w_other_overrides() { + // opts with other overrides + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'")) + .arg(Arg::from_usage("--other [val] 'some other option'").overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt=some", "--other=test", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert!(!m.is_present("other")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn aaos_opts_w_other_overrides_rev() { + // opts with other overrides, rev + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'")) + .arg(Arg::from_usage("--other [val] 'some other option'").overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--other=val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(!m.is_present("opt")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("other"), Some("val")); +} + +#[test] +fn aaos_opts_w_other_overrides_2() { + // opts with other overrides + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("other")) + .arg(Arg::from_usage("--other [val] 'some other option'")) + .get_matches_from_safe(vec!["", "--opt=some", "--other=test", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert!(!m.is_present("other")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn aaos_opts_w_other_overrides_rev_2() { + // opts with other overrides, rev + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("other")) + .arg(Arg::from_usage("--other [val] 'some other option'")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--other=val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(!m.is_present("opt")); + assert!(m.is_present("other")); + assert_eq!(m.value_of("other"), Some("val")); +} + +#[test] +fn aaos_opts_mult() { + // opts with multiple + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val]... 'some option'") + .number_of_values(1) + .require_delimiter(true)) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 3); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["some", "other", "one", "two"]); +} + +#[test] +fn aaos_opts_mult_req_delims() { + // opts with multiple and require delims + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val]... 'some option'")) + .get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 2); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "overides", "some", "other", "val"]); +} + +#[test] +fn aaos_pos_mult() { + // opts with multiple + let res = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("[val]... 'some pos'")) + .get_matches_from_safe(vec!["", "some", "other", "value"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("val")); + assert_eq!(m.occurrences_of("val"), 3); + assert_eq!(m.values_of("val").unwrap().collect::<Vec<_>>(), &["some", "other", "value"]); +} + +#[test] +fn aaos_option_use_delim_false() { + + let m = App::new("posix") + .setting(AppSettings::AllArgsOverrideSelf) + .arg(Arg::from_usage("--opt [val] 'some option'") + .use_delimiter(false)) + .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["one,two"]); +} diff --git a/clap/tests/arg_aliases.rs b/clap/tests/arg_aliases.rs new file mode 100644 index 0000000..77bcd17 --- /dev/null +++ b/clap/tests/arg_aliases.rs @@ -0,0 +1,200 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg, SubCommand}; + +static SC_VISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2 +Some help + +USAGE: + ct test [FLAGS] [OPTIONS] + +FLAGS: + -f, --flag [aliases: v_flg, flag2, flg3] + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <opt> [aliases: visible]"; + +static SC_INVISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2 +Some help + +USAGE: + ct test [FLAGS] [OPTIONS] + +FLAGS: + -f, --flag + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <opt> "; + +#[test] +fn single_alias_of_option() { + let a = App::new("single_alias") + .arg(Arg::with_name("alias") + .long("alias") + .takes_value(true) + .help("single alias") + .alias("new-opt")) + .get_matches_from_safe(vec![ + "", "--new-opt", "cool" + ]); + assert!(a.is_ok()); + let a = a.unwrap(); + assert!(a.is_present("alias")); + assert_eq!(a.value_of("alias").unwrap(), "cool"); +} + +#[test] +fn multiple_aliases_of_option() { + let a = App::new("multiple_aliases") + .arg(Arg::with_name("aliases") + .long("aliases") + .takes_value(true) + .help("multiple aliases") + .aliases(&[ + "alias1", + "alias2", + "alias3" + ])); + let long = a.clone().get_matches_from_safe(vec![ + "", "--aliases", "value" + ]); + assert!(long.is_ok()); + let long = long.unwrap(); + + let als1 = a.clone().get_matches_from_safe(vec![ + "", "--alias1", "value" + ]); + assert!(als1.is_ok()); + let als1 = als1.unwrap(); + + let als2 = a.clone().get_matches_from_safe(vec![ + "", "--alias2", "value" + ]); + assert!(als2.is_ok()); + let als2 = als2.unwrap(); + + let als3 = a.clone().get_matches_from_safe(vec![ + "", "--alias3", "value" + ]); + assert!(als3.is_ok()); + let als3 = als3.unwrap(); + + assert!(long.is_present("aliases")); + assert!(als1.is_present("aliases")); + assert!(als2.is_present("aliases")); + assert!(als3.is_present("aliases")); + assert_eq!(long.value_of("aliases").unwrap(), "value"); + assert_eq!(als1.value_of("aliases").unwrap(), "value"); + assert_eq!(als2.value_of("aliases").unwrap(), "value"); + assert_eq!(als3.value_of("aliases").unwrap(), "value"); +} + +#[test] +fn single_alias_of_flag() { + let a = App::new("test") + .arg(Arg::with_name("flag") + .long("flag") + .alias("alias")) + .get_matches_from_safe(vec!["", "--alias"]); + assert!(a.is_ok()); + let a = a.unwrap(); + assert!(a.is_present("flag")); +} + +#[test] +fn multiple_aliases_of_flag() { + let a = App::new("test") + .arg(Arg::with_name("flag") + .long("flag") + .aliases(&["invisible", + "set", "of", + "cool", "aliases"])); + + let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]); + assert!(flag.is_ok()); + let flag = flag.unwrap(); + + let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]); + assert!(inv.is_ok()); + let inv = inv.unwrap(); + + let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]); + assert!(cool.is_ok()); + let cool = cool.unwrap(); + + let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]); + assert!(als.is_ok()); + let als = als.unwrap(); + + assert!(flag.is_present("flag")); + assert!(inv.is_present("flag")); + assert!(cool.is_present("flag")); + assert!(als.is_present("flag")); +} + +#[test] +fn alias_on_a_subcommand_option() { + let m = App::new("test") + .subcommand(SubCommand::with_name("some") + .arg(Arg::with_name("test") + .short("t") + .long("test") + .takes_value(true) + .alias("opt") + .help("testing testing"))) + .arg(Arg::with_name("other") + .long("other") + .aliases(&["o1", "o2", "o3"])) + .get_matches_from(vec![ + "test", "some", "--opt", "awesome" + ]); + + assert!(m.subcommand_matches("some").is_some()); + let sub_m = m.subcommand_matches("some").unwrap(); + assert!(sub_m.is_present("test")); + assert_eq!(sub_m.value_of("test").unwrap(), "awesome"); +} + +#[test] +fn invisible_arg_aliases_help_output() { + let app = App::new("ct") + .author("Salim Afiune") + .subcommand(SubCommand::with_name("test") + .about("Some help") + .version("1.2") + .arg(Arg::with_name("opt") + .long("opt") + .short("o") + .takes_value(true) + .aliases(&["invisible", "als1", "more"])) + .arg(Arg::from_usage("-f, --flag") + .aliases(&["invisible", "flg1", "anyway"]))); + assert!(test::compare_output(app, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false)); +} + +#[test] +fn visible_arg_aliases_help_output() { + let app = App::new("ct") + .author("Salim Afiune") + .subcommand(SubCommand::with_name("test") + .about("Some help") + .version("1.2") + .arg(Arg::with_name("opt") + .long("opt") + .short("o") + .takes_value(true) + .alias("invisible") + .visible_alias("visible")) + .arg(Arg::with_name("flg") + .long("flag") + .short("f") + .visible_aliases(&["v_flg", "flag2", "flg3"]))); + assert!(test::compare_output(app, "ct test --help", SC_VISIBLE_ALIAS_HELP, false)); +} diff --git a/clap/tests/borrowed.rs b/clap/tests/borrowed.rs new file mode 100644 index 0000000..e7a184b --- /dev/null +++ b/clap/tests/borrowed.rs @@ -0,0 +1,19 @@ +extern crate clap; +extern crate regex; + +use clap::{App, Arg, SubCommand}; + +include!("../clap-test.rs"); + +#[test] +fn borrowed_args() { + let arg = Arg::with_name("some").short("s").long("some").help("other help"); + let arg2 = Arg::with_name("some2").short("S").long("some-thing").help("other help"); + let result = App::new("sub_command_negate") + .arg(Arg::with_name("test").index(1)) + .arg(&arg) + .arg(&arg2) + .subcommand(SubCommand::with_name("sub1").arg(&arg)) + .get_matches_from_safe(vec!["prog"]); + assert!(result.is_ok()); +} diff --git a/clap/tests/completions.rs b/clap/tests/completions.rs new file mode 100644 index 0000000..24409ad --- /dev/null +++ b/clap/tests/completions.rs @@ -0,0 +1,883 @@ +extern crate regex; +extern crate clap; + +use clap::{App, Arg, SubCommand, Shell}; +use regex::Regex; + +static BASH: &'static str = r#"_myapp() { + local i cur prev opts cmds + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${i}" in + myapp) + cmd="myapp" + ;; + + help) + cmd+="__help" + ;; + test) + cmd+="__test" + ;; + *) + ;; + esac + done + + case "${cmd}" in + myapp) + opts=" -h -V --help --version <file> test help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + + myapp__help) + opts=" -h -V --help --version " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + myapp__test) + opts=" -h -V --help --version --case " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --case) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +complete -F _myapp -o bashdefault -o default myapp +"#; + +static ZSH: &'static str = r#"#compdef myapp + +autoload -U is-at-least + +_myapp() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +'::file -- some input file:_files' \ +":: :_myapp_commands" \ +"*::: :->myapp" \ +&& ret=0 + case $state in + (myapp) + words=($line[2] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:myapp-command-$line[2]:" + case $line[2] in + (test) +_arguments "${_arguments_options[@]}" \ +'--case=[the case to test]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 +;; + esac + ;; +esac +} + +(( $+functions[_myapp_commands] )) || +_myapp_commands() { + local commands; commands=( + "test:tests things" \ +"help:Prints this message or the help of the given subcommand(s)" \ + ) + _describe -t commands 'myapp commands' commands "$@" +} +(( $+functions[_myapp__help_commands] )) || +_myapp__help_commands() { + local commands; commands=( + + ) + _describe -t commands 'myapp help commands' commands "$@" +} +(( $+functions[_myapp__test_commands] )) || +_myapp__test_commands() { + local commands; commands=( + + ) + _describe -t commands 'myapp test commands' commands "$@" +} + +_myapp "$@""#; + +static FISH: &'static str = r#"complete -c myapp -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' +complete -c myapp -n "__fish_use_subcommand" -s V -l version -d 'Prints version information' +complete -c myapp -n "__fish_use_subcommand" -f -a "test" -d 'tests things' +complete -c myapp -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)' +complete -c myapp -n "__fish_seen_subcommand_from test" -l case -d 'the case to test' +complete -c myapp -n "__fish_seen_subcommand_from test" -s h -l help -d 'Prints help information' +complete -c myapp -n "__fish_seen_subcommand_from test" -s V -l version -d 'Prints version information' +complete -c myapp -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information' +complete -c myapp -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information' +"#; + +static POWERSHELL: &'static str = r#" +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + 'my_app' + for ($i = 1; $i -lt $commandElements.Count; $i++) { + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-')) { + break + } + $element.Value + }) -join ';' + + $completions = @(switch ($command) { + 'my_app' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things') + [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Prints this message or the help of the given subcommand(s)') + break + } + 'my_app;test' { + [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + break + } + 'my_app;help' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + break + } + }) + + $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + Sort-Object -Property ListItemText +} +"#; + +static ELVISH: &'static str = r#" +edit:completion:arg-completer[my_app] = [@words]{ + fn spaces [n]{ + repeat $n ' ' | joins '' + } + fn cand [text desc]{ + edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc + } + command = 'my_app' + for word $words[1:-1] { + if (has-prefix $word '-') { + break + } + command = $command';'$word + } + completions = [ + &'my_app'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + cand test 'tests things' + cand help 'Prints this message or the help of the given subcommand(s)' + } + &'my_app;test'= { + cand --case 'the case to test' + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + } + &'my_app;help'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + } + ] + $completions[$command] +} +"#; + +static ELVISH_SPECIAL_CMDS: &'static str = r#" +edit:completion:arg-completer[my_app] = [@words]{ + fn spaces [n]{ + repeat $n ' ' | joins '' + } + fn cand [text desc]{ + edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc + } + command = 'my_app' + for word $words[1:-1] { + if (has-prefix $word '-') { + break + } + command = $command';'$word + } + completions = [ + &'my_app'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + cand test 'tests things' + cand some_cmd 'tests other things' + cand some-cmd-with-hypens 'some-cmd-with-hypens' + cand help 'Prints this message or the help of the given subcommand(s)' + } + &'my_app;test'= { + cand --case 'the case to test' + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + } + &'my_app;some_cmd'= { + cand --config 'the other case to test' + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + } + &'my_app;some-cmd-with-hypens'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + } + &'my_app;help'= { + cand -h 'Prints help information' + cand --help 'Prints help information' + cand -V 'Prints version information' + cand --version 'Prints version information' + } + ] + $completions[$command] +} +"#; + +static POWERSHELL_SPECIAL_CMDS: &'static str = r#" +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + 'my_app' + for ($i = 1; $i -lt $commandElements.Count; $i++) { + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-')) { + break + } + $element.Value + }) -join ';' + + $completions = @(switch ($command) { + 'my_app' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things') + [CompletionResult]::new('some_cmd', 'some_cmd', [CompletionResultType]::ParameterValue, 'tests other things') + [CompletionResult]::new('some-cmd-with-hypens', 'some-cmd-with-hypens', [CompletionResultType]::ParameterValue, 'some-cmd-with-hypens') + [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Prints this message or the help of the given subcommand(s)') + break + } + 'my_app;test' { + [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + break + } + 'my_app;some_cmd' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'the other case to test') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + break + } + 'my_app;some-cmd-with-hypens' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + break + } + 'my_app;help' { + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information') + [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information') + break + } + }) + + $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + Sort-Object -Property ListItemText +} +"#; + +static ZSH_SPECIAL_CMDS: &'static str = r#"#compdef my_app + +autoload -U is-at-least + +_my_app() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +'::file -- some input file:_files' \ +":: :_my_app_commands" \ +"*::: :->my_app" \ +&& ret=0 + case $state in + (my_app) + words=($line[2] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:my_app-command-$line[2]:" + case $line[2] in + (test) +_arguments "${_arguments_options[@]}" \ +'--case=[the case to test]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 +;; +(some_cmd) +_arguments "${_arguments_options[@]}" \ +'--config=[the other case to test]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 +;; +(some-cmd-with-hypens) +_arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 +;; + esac + ;; +esac +} + +(( $+functions[_my_app_commands] )) || +_my_app_commands() { + local commands; commands=( + "test:tests things" \ +"some_cmd:tests other things" \ +"some-cmd-with-hypens:" \ +"help:Prints this message or the help of the given subcommand(s)" \ + ) + _describe -t commands 'my_app commands' commands "$@" +} +(( $+functions[_my_app__help_commands] )) || +_my_app__help_commands() { + local commands; commands=( + + ) + _describe -t commands 'my_app help commands' commands "$@" +} +(( $+functions[_my_app__some-cmd-with-hypens_commands] )) || +_my_app__some-cmd-with-hypens_commands() { + local commands; commands=( + + ) + _describe -t commands 'my_app some-cmd-with-hypens commands' commands "$@" +} +(( $+functions[_my_app__some_cmd_commands] )) || +_my_app__some_cmd_commands() { + local commands; commands=( + + ) + _describe -t commands 'my_app some_cmd commands' commands "$@" +} +(( $+functions[_my_app__test_commands] )) || +_my_app__test_commands() { + local commands; commands=( + + ) + _describe -t commands 'my_app test commands' commands "$@" +} + +_my_app "$@""#; + +static FISH_SPECIAL_CMDS: &'static str = r#"complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' +complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information' +complete -c my_app -n "__fish_use_subcommand" -f -a "test" -d 'tests things' +complete -c my_app -n "__fish_use_subcommand" -f -a "some_cmd" -d 'tests other things' +complete -c my_app -n "__fish_use_subcommand" -f -a "some-cmd-with-hypens" +complete -c my_app -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)' +complete -c my_app -n "__fish_seen_subcommand_from test" -l case -d 'the case to test' +complete -c my_app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Prints help information' +complete -c my_app -n "__fish_seen_subcommand_from test" -s V -l version -d 'Prints version information' +complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -l config -d 'the other case to test' +complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -s h -l help -d 'Prints help information' +complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -s V -l version -d 'Prints version information' +complete -c my_app -n "__fish_seen_subcommand_from some-cmd-with-hypens" -s h -l help -d 'Prints help information' +complete -c my_app -n "__fish_seen_subcommand_from some-cmd-with-hypens" -s V -l version -d 'Prints version information' +complete -c my_app -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information' +complete -c my_app -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information' +"#; + +static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() { + local i cur prev opts cmds + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${i}" in + my_app) + cmd="my_app" + ;; + + help) + cmd+="__help" + ;; + some-cmd-with-hypens) + cmd+="__some__cmd__with__hypens" + ;; + some_cmd) + cmd+="__some_cmd" + ;; + test) + cmd+="__test" + ;; + *) + ;; + esac + done + + case "${cmd}" in + my_app) + opts=" -h -V --help --version <file> test some_cmd some-cmd-with-hypens help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + + my_app__help) + opts=" -h -V --help --version " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + my_app__some__cmd__with__hypens) + opts=" -h -V --help --version " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + my_app__some_cmd) + opts=" -h -V --help --version --config " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + my_app__test) + opts=" -h -V --help --version --case " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + + --case) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +complete -F _my_app -o bashdefault -o default my_app +"#; + +static FISH_SPECIAL_HELP: &'static str = r#"complete -c my_app -n "__fish_use_subcommand" -l single-quotes -d 'Can be \'always\', \'auto\', or \'never\'' +complete -c my_app -n "__fish_use_subcommand" -l double-quotes -d 'Can be "always", "auto", or "never"' +complete -c my_app -n "__fish_use_subcommand" -l backticks -d 'For more information see `echo test`' +complete -c my_app -n "__fish_use_subcommand" -l backslash -d 'Avoid \'\\n\'' +complete -c my_app -n "__fish_use_subcommand" -l brackets -d 'List packages [filter]' +complete -c my_app -n "__fish_use_subcommand" -l expansions -d 'Execute the shell command with $SHELL' +complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' +complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information' +"#; + +static ZSH_SPECIAL_HELP: &'static str = r#"#compdef my_app + +autoload -U is-at-least + +_my_app() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'--single-quotes[Can be '\''always'\'', '\''auto'\'', or '\''never'\'']' \ +'--double-quotes[Can be "always", "auto", or "never"]' \ +'--backticks[For more information see `echo test`]' \ +'--backslash[Avoid '\''\\n'\'']' \ +'--brackets[List packages \[filter\]]' \ +'--expansions[Execute the shell command with $SHELL]' \ +'-h[Prints help information]' \ +'--help[Prints help information]' \ +'-V[Prints version information]' \ +'--version[Prints version information]' \ +&& ret=0 + +} + +(( $+functions[_my_app_commands] )) || +_my_app_commands() { + local commands; commands=( + + ) + _describe -t commands 'my_app commands' commands "$@" +} + +_my_app "$@""#; + +fn compare(left: &str, right: &str) -> bool { + let b = left == right; + if !b { + let re = Regex::new(" ").unwrap(); + println!(); + println!("--> left"); + // println!("{}", left); + println!("{}", re.replace_all(left, "\u{2022}")); + println!("--> right"); + println!("{}", re.replace_all(right, "\u{2022}")); + // println!("{}", right); + println!("--") + } + b +} + +fn build_app() -> App<'static, 'static> { build_app_with_name("myapp") } + +fn build_app_with_name(s: &'static str) -> App<'static, 'static> { + App::new(s) + .about("Tests completions") + .arg(Arg::with_name("file").help("some input file")) + .subcommand(SubCommand::with_name("test") + .about("tests things") + .arg(Arg::with_name("case") + .long("case") + .takes_value(true) + .help("the case to test"))) +} + +fn build_app_special_commands() -> App<'static, 'static> { + build_app_with_name("my_app") + .subcommand(SubCommand::with_name("some_cmd") + .about("tests other things") + .arg(Arg::with_name("config") + .long("--config") + .takes_value(true) + .help("the other case to test"))) + .subcommand(SubCommand::with_name("some-cmd-with-hypens")) +} + +fn build_app_special_help() -> App<'static, 'static> { + App::new("my_app") + .arg(Arg::with_name("single-quotes") + .long("single-quotes") + .help("Can be 'always', 'auto', or 'never'")) + .arg(Arg::with_name("double-quotes") + .long("double-quotes") + .help("Can be \"always\", \"auto\", or \"never\"")) + .arg(Arg::with_name("backticks") + .long("backticks") + .help("For more information see `echo test`")) + .arg(Arg::with_name("backslash") + .long("backslash") + .help("Avoid '\\n'")) + .arg(Arg::with_name("brackets") + .long("brackets") + .help("List packages [filter]")) + .arg(Arg::with_name("expansions") + .long("expansions") + .help("Execute the shell command with $SHELL")) +} + +#[test] +fn bash() { + let mut app = build_app(); + let mut buf = vec![]; + app.gen_completions_to("myapp", Shell::Bash, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, BASH)); +} + +#[test] +fn zsh() { + let mut app = build_app(); + let mut buf = vec![]; + app.gen_completions_to("myapp", Shell::Zsh, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, ZSH)); +} + +#[test] +fn fish() { + let mut app = build_app(); + let mut buf = vec![]; + app.gen_completions_to("myapp", Shell::Fish, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, FISH)); +} + +#[test] +fn powershell() { + let mut app = build_app(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::PowerShell, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, POWERSHELL)); +} + +#[test] +fn elvish() { + let mut app = build_app(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Elvish, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, ELVISH)); +} + +#[test] +fn elvish_with_special_commands() { + let mut app = build_app_special_commands(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Elvish, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, ELVISH_SPECIAL_CMDS)); +} + +#[test] +fn powershell_with_special_commands() { + let mut app = build_app_special_commands(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::PowerShell, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, POWERSHELL_SPECIAL_CMDS)); +} + +#[test] +fn bash_with_special_commands() { + let mut app = build_app_special_commands(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Bash, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, BASH_SPECIAL_CMDS)); +} + +#[test] +fn fish_with_special_commands() { + let mut app = build_app_special_commands(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Fish, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, FISH_SPECIAL_CMDS)); +} + +#[test] +fn zsh_with_special_commands() { + let mut app = build_app_special_commands(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Zsh, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, ZSH_SPECIAL_CMDS)); +} + +#[test] +fn fish_with_special_help() { + let mut app = build_app_special_help(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Fish, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, FISH_SPECIAL_HELP)); +} + +#[test] +fn zsh_with_special_help() { + let mut app = build_app_special_help(); + let mut buf = vec![]; + app.gen_completions_to("my_app", Shell::Zsh, &mut buf); + let string = String::from_utf8(buf).unwrap(); + + assert!(compare(&*string, ZSH_SPECIAL_HELP)); +} diff --git a/clap/tests/conflicts.rs b/clap/tests/conflicts.rs new file mode 100644 index 0000000..72a9e05 --- /dev/null +++ b/clap/tests/conflicts.rs @@ -0,0 +1,102 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg, ErrorKind, ArgGroup}; + +static CONFLICT_ERR: &'static str = "error: The argument '-F' cannot be used with '--flag' + +USAGE: + clap-test <positional> <positional2> --flag --long-option-2 <option2> + +For more information try --help"; + +static CONFLICT_ERR_REV: &'static str = "error: The argument '--flag' cannot be used with '-F' + +USAGE: + clap-test <positional> <positional2> -F --long-option-2 <option2> + +For more information try --help"; + +#[test] +fn flag_conflict() { + let result = App::new("flag_conflict") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("other")) + .arg(Arg::from_usage("-o, --other 'some flag'")) + .get_matches_from_safe(vec!["myprog", "-f", "-o"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} + +#[test] +fn flag_conflict_2() { + let result = App::new("flag_conflict") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("other")) + .arg(Arg::from_usage("-o, --other 'some flag'")) + .get_matches_from_safe(vec!["myprog", "-o", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} + +#[test] +fn group_conflict() { + let result = App::new("group_conflict") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("gr")) + .group(ArgGroup::with_name("gr") + .required(true) + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from_safe(vec!["myprog", "--other", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} + +#[test] +fn group_conflict_2() { + let result = App::new("group_conflict") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("gr")) + .group(ArgGroup::with_name("gr") + .required(true) + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from_safe(vec!["myprog", "-f", "--some"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} + +#[test] +fn conflict_output() { + test::compare_output(test::complex_app(), "clap-test val1 --flag --long-option-2 val2 -F", CONFLICT_ERR, true); +} + +#[test] +fn conflict_output_rev() { + test::compare_output(test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true); +} + +#[test] +fn conflict_with_unused_default_value() { + let result = App::new("conflict") + .arg(Arg::from_usage("-o, --opt=[opt] 'some opt'") + .default_value("default")) + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("opt")) + .get_matches_from_safe(vec!["myprog", "-f"]); + assert!(result.is_ok()); + let m = result.unwrap(); + assert_eq!(m.value_of("opt"), Some("default")); + assert!(m.is_present("flag")); +} diff --git a/clap/tests/default_vals.rs b/clap/tests/default_vals.rs new file mode 100644 index 0000000..0dfd3c8 --- /dev/null +++ b/clap/tests/default_vals.rs @@ -0,0 +1,498 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg, ErrorKind}; + +#[test] +fn opts() { + let r = App::new("df") + .arg( + Arg::from_usage("-o [opt] 'some opt'").default_value("default"), + ) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.value_of("o").unwrap(), "default"); +} + +#[test] +fn opt_user_override() { + let r = App::new("df") + .arg( + Arg::from_usage("--opt [FILE] 'some arg'").default_value("default"), + ) + .get_matches_from_safe(vec!["", "--opt", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.value_of("opt").unwrap(), "value"); +} + +#[test] +fn positionals() { + let r = App::new("df") + .arg(Arg::from_usage("[arg] 'some opt'").default_value("default")) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn positional_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("[arg] 'some arg'").default_value("default")) + .get_matches_from_safe(vec!["", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "value"); +} + +// OsStr Default Values + +#[test] +fn osstr_opts() { + use std::ffi::OsStr; + let expected = OsStr::new("default"); + + let r = App::new("df") + .arg( + Arg::from_usage("-o [opt] 'some opt'").default_value_os(expected), + ) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.value_of("o").unwrap(), expected); +} + +#[test] +fn osstr_opt_user_override() { + use std::ffi::OsStr; + let default = OsStr::new("default"); + + let r = App::new("df") + .arg( + Arg::from_usage("--opt [FILE] 'some arg'").default_value_os(default), + ) + .get_matches_from_safe(vec!["", "--opt", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.value_of("opt").unwrap(), "value"); +} + +#[test] +fn osstr_positionals() { + use std::ffi::OsStr; + let expected = OsStr::new("default"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'").default_value_os(expected), + ) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), expected); +} + +#[test] +fn osstr_positional_user_override() { + use std::ffi::OsStr; + let default = OsStr::new("default"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some arg'").default_value_os(default), + ) + .get_matches_from_safe(vec!["", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "value"); +} + +// --- Default if arg is present + +#[test] +fn default_if_arg_present_no_default() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("[arg] 'some arg'").default_value_if( + "opt", + None, + "default", + )) + .get_matches_from_safe(vec!["", "--opt", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn default_if_arg_present_no_default_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("[arg] 'some arg'").default_value_if( + "opt", + None, + "default", + )) + .get_matches_from_safe(vec!["", "--opt", "some", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +#[test] +fn default_if_arg_present_no_arg_with_default() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", None, "default"), + ) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "first"); +} + +#[test] +fn default_if_arg_present_with_default() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", None, "default"), + ) + .get_matches_from_safe(vec!["", "--opt", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn default_if_arg_present_with_default_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", None, "default"), + ) + .get_matches_from_safe(vec!["", "--opt", "some", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +#[test] +fn default_if_arg_present_no_arg_with_default_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", None, "default"), + ) + .get_matches_from_safe(vec!["", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +// Conditional Default Values + +#[test] +fn default_if_arg_present_with_value_no_default() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("[arg] 'some arg'").default_value_if( + "opt", + Some("value"), + "default", + )) + .get_matches_from_safe(vec!["", "--opt", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn default_if_arg_present_with_value_no_default_fail() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("[arg] 'some arg'").default_value_if( + "opt", + Some("value"), + "default", + )) + .get_matches_from_safe(vec!["", "--opt", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(!m.is_present("arg")); + //assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn default_if_arg_present_with_value_no_default_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("[arg] 'some arg'").default_value_if( + "opt", + Some("some"), + "default", + )) + .get_matches_from_safe(vec!["", "--opt", "some", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +#[test] +fn default_if_arg_present_with_value_no_arg_with_default() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", Some("some"), "default"), + ) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "first"); +} + +#[test] +fn default_if_arg_present_with_value_no_arg_with_default_fail() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", Some("some"), "default"), + ) + .get_matches_from_safe(vec!["", "--opt", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "first"); +} + +#[test] +fn default_if_arg_present_with_value_with_default() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", Some("some"), "default"), + ) + .get_matches_from_safe(vec!["", "--opt", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn default_if_arg_present_with_value_with_default_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", Some("some"), "default"), + ) + .get_matches_from_safe(vec!["", "--opt", "some", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +#[test] +fn default_if_arg_present_no_arg_with_value_with_default_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", Some("some"), "default"), + ) + .get_matches_from_safe(vec!["", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +#[test] +fn default_if_arg_present_no_arg_with_value_with_default_user_override_fail() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_if("opt", Some("some"), "default"), + ) + .get_matches_from_safe(vec!["", "--opt", "value", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "other"); +} + +// Multiple conditions + +#[test] +fn default_ifs_arg_present() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("--flag 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]), + ) + .get_matches_from_safe(vec!["", "--flag"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "flg"); +} + +#[test] +fn default_ifs_arg_present_user_override() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("--flag 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]), + ) + .get_matches_from_safe(vec!["", "--flag", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "value"); +} + +#[test] +fn default_ifs_arg_present_order() { + let r = App::new("df") + .arg(Arg::from_usage("--opt [FILE] 'some arg'")) + .arg(Arg::from_usage("--flag 'some arg'")) + .arg( + Arg::from_usage("[arg] 'some arg'") + .default_value("first") + .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]), + ) + .get_matches_from_safe(vec!["", "--opt=some", "--flag"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.value_of("arg").unwrap(), "default"); +} + +#[test] +fn conditional_reqs_fail() { + let m = App::new("Test app") + .version("1.0") + .author("F0x06") + .about("Arg test") + .arg( + Arg::with_name("target") + .takes_value(true) + .default_value("file") + .possible_values(&["file", "stdout"]) + .long("target"), + ) + .arg( + Arg::with_name("input") + .takes_value(true) + .required(true) + .long("input"), + ) + .arg( + Arg::with_name("output") + .takes_value(true) + .required_if("target", "file") + .long("output"), + ) + .get_matches_from_safe(vec!["test", "--input", "some"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn conditional_reqs_pass() { + let m = App::new("Test app") + .version("1.0") + .author("F0x06") + .about("Arg test") + .arg( + Arg::with_name("target") + .takes_value(true) + .default_value("file") + .possible_values(&["file", "stdout"]) + .long("target"), + ) + .arg( + Arg::with_name("input") + .takes_value(true) + .required(true) + .long("input"), + ) + .arg( + Arg::with_name("output") + .takes_value(true) + .required_if("target", "file") + .long("output"), + ) + .get_matches_from_safe(vec!["test", "--input", "some", "--output", "other"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + assert_eq!(m.value_of("output"), Some("other")); + assert_eq!(m.value_of("input"), Some("some")); +} + +#[test] +fn issue_1050_num_vals_and_defaults() { + let res = App::new("hello") + .arg( + Arg::with_name("exit-code") + .long("exit-code") + .required(true) + .takes_value(true) + .number_of_values(1) + .default_value("0"), + ) + .get_matches_from_safe(vec!["hello", "--exit-code=1"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert_eq!(m.value_of("exit-code"), Some("1")); +} diff --git a/clap/tests/delimiters.rs b/clap/tests/delimiters.rs new file mode 100644 index 0000000..d5b60b9 --- /dev/null +++ b/clap/tests/delimiters.rs @@ -0,0 +1,139 @@ +extern crate clap; + +use clap::{App, Arg}; + +#[test] +fn opt_default_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .long("option") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "--option", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_eq_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .long("option") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "--option=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_eq_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o=val1,val2,val3", + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_default_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1,val2,val3", + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_no_space_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_no_space_mult_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .multiple(true) + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_eq_mult_def_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .long("opt") + .multiple(true) + .use_delimiter(true) + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "--opt=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1", "val2", "val3"]); +} diff --git a/clap/tests/derive_order.rs b/clap/tests/derive_order.rs new file mode 100644 index 0000000..b30c8ad --- /dev/null +++ b/clap/tests/derive_order.rs @@ -0,0 +1,245 @@ +extern crate clap; +extern crate regex; + +use std::str; + +use clap::{App, Arg, SubCommand, AppSettings}; + +include!("../clap-test.rs"); + +static NO_DERIVE_ORDER: &'static str = "test 1.2 + +USAGE: + test [FLAGS] [OPTIONS] + +FLAGS: + --flag_a second flag + --flag_b first flag + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --option_a <option_a> second option + --option_b <option_b> first option"; + +static DERIVE_ORDER: &'static str = "test 1.2 + +USAGE: + test [FLAGS] [OPTIONS] + +FLAGS: + --flag_b first flag + --flag_a second flag + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --option_b <option_b> first option + --option_a <option_a> second option"; + +static UNIFIED_HELP: &'static str = "test 1.2 + +USAGE: + test [OPTIONS] + +OPTIONS: + --flag_a second flag + --flag_b first flag + -h, --help Prints help information + --option_a <option_a> second option + --option_b <option_b> first option + -V, --version Prints version information"; + +static UNIFIED_HELP_AND_DERIVE: &'static str = "test 1.2 + +USAGE: + test [OPTIONS] + +OPTIONS: + --flag_b first flag + --option_b <option_b> first option + --flag_a second flag + --option_a <option_a> second option + -h, --help Prints help information + -V, --version Prints version information"; + +static DERIVE_ORDER_SC_PROP: &'static str = "test-sub 1.2 + +USAGE: + test sub [FLAGS] [OPTIONS] + +FLAGS: + --flag_b first flag + --flag_a second flag + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --option_b <option_b> first option + --option_a <option_a> second option"; + +static UNIFIED_SC_PROP: &'static str = "test-sub 1.2 + +USAGE: + test sub [OPTIONS] + +OPTIONS: + --flag_a second flag + --flag_b first flag + -h, --help Prints help information + --option_a <option_a> second option + --option_b <option_b> first option + -V, --version Prints version information"; + +static UNIFIED_DERIVE_SC_PROP: &'static str = "test-sub 1.2 + +USAGE: + test sub [OPTIONS] + +OPTIONS: + --flag_b first flag + --option_b <option_b> first option + --flag_a second flag + --option_a <option_a> second option + -h, --help Prints help information + -V, --version Prints version information"; + +static UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER: &'static str = "test-sub 1.2 + +USAGE: + test sub [OPTIONS] + +OPTIONS: + --flag_a second flag + --flag_b first flag + --option_b <option_b> first option + --option_a <option_a> second option + -h, --help Prints help information + -V, --version Prints version information"; + +#[test] +fn no_derive_order() { + let app = App::new("test") + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ]); + + assert!(test::compare_output(app, "test --help", NO_DERIVE_ORDER, false)); +} + +#[test] +fn derive_order() { + let app = App::new("test") + .setting(AppSettings::DeriveDisplayOrder) + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ]); + + assert!(test::compare_output(app, "test --help", DERIVE_ORDER, false)); +} + +#[test] +fn unified_help() { + let app = App::new("test") + .setting(AppSettings::UnifiedHelpMessage) + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ]); + + assert!(test::compare_output(app, "test --help", UNIFIED_HELP, false)); +} + +#[test] +fn unified_help_and_derive_order() { + let app = App::new("test") + .setting(AppSettings::DeriveDisplayOrder) + .setting(AppSettings::UnifiedHelpMessage) + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ]); + + assert!(test::compare_output(app, "test --help", UNIFIED_HELP_AND_DERIVE, false)); +} + +#[test] +fn derive_order_subcommand_propagate() { + let app = App::new("test") + .global_setting(AppSettings::DeriveDisplayOrder) + .version("1.2") + .subcommand(SubCommand::with_name("sub") + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ])); + + assert!(test::compare_output(app, "test sub --help", DERIVE_ORDER_SC_PROP, false)); +} + +#[test] +fn unified_help_subcommand_propagate() { + let app = App::new("test") + .global_setting(AppSettings::UnifiedHelpMessage) + .subcommand(SubCommand::with_name("sub") + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ])); + + assert!(test::compare_output(app, "test sub --help", UNIFIED_SC_PROP, false)); +} + +#[test] +fn unified_help_and_derive_order_subcommand_propagate() { + let app = App::new("test") + .global_setting(AppSettings::DeriveDisplayOrder) + .global_setting(AppSettings::UnifiedHelpMessage) + .subcommand(SubCommand::with_name("sub") + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag"), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ])); + + assert!(test::compare_output(app, "test sub --help", UNIFIED_DERIVE_SC_PROP, false)); +} + +#[test] +fn unified_help_and_derive_order_subcommand_propagate_with_explicit_display_order() { + let app = App::new("test") + .global_setting(AppSettings::DeriveDisplayOrder) + .global_setting(AppSettings::UnifiedHelpMessage) + .subcommand(SubCommand::with_name("sub") + .version("1.2") + .args(&[ + Arg::with_name("flag_b").long("flag_b").help("first flag"), + Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"), + Arg::with_name("flag_a").long("flag_a").help("second flag").display_order(0), + Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"), + ])); + + assert!(test::compare_output(app, "test sub --help", UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER, false)); +} diff --git a/clap/tests/env.rs b/clap/tests/env.rs new file mode 100644 index 0000000..62833ba --- /dev/null +++ b/clap/tests/env.rs @@ -0,0 +1,263 @@ +extern crate clap; + +use std::env; +use std::ffi::OsStr; + +use clap::{App, Arg}; + +#[test] +fn env() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV")) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg").unwrap(), "env"); +} + +#[test] +fn env_os() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'").env_os(OsStr::new("CLP_TEST_ENV")), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg").unwrap(), "env"); +} + +#[test] +fn no_env() { + // All the other tests use the presence of the Environment variable... + // we need another variable just in case one of the others is running at the same time... + env::remove_var("CLP_TEST_ENV_NONE"); + + let r = App::new("df") + .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV_NONE")) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(!m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg"), None); +} + +#[test] +fn with_default() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV") + .default_value("default"), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg").unwrap(), "env"); +} + +#[test] +fn opt_user_override() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("--arg [FILE] 'some arg'").env("CLP_TEST_ENV"), + ) + .get_matches_from_safe(vec!["", "--arg", "opt"]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 1); + assert_eq!(m.value_of("arg").unwrap(), "opt"); +} + +#[test] +fn positionals() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV")) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg").unwrap(), "env"); +} + +#[test] +fn positionals_user_override() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV")) + .get_matches_from_safe(vec!["", "opt"]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 1); + assert_eq!(m.value_of("arg").unwrap(), "opt"); +} + +#[test] +fn multiple_one() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV") + .use_delimiter(true) + .multiple(true), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), vec!["env"]); +} + +#[test] +fn multiple_three() { + env::set_var("CLP_TEST_ENV_MULTI1", "env1,env2,env3"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV_MULTI1") + .use_delimiter(true) + .multiple(true), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!( + m.values_of("arg").unwrap().collect::<Vec<_>>(), + vec!["env1", "env2", "env3"] + ); +} + +#[test] +fn multiple_no_delimiter() { + env::set_var("CLP_TEST_ENV_MULTI2", "env1 env2 env3"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV_MULTI2") + .multiple(true), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!( + m.values_of("arg").unwrap().collect::<Vec<_>>(), + vec!["env1 env2 env3"] + ); +} + +#[test] +fn possible_value() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV") + .possible_value("env"), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg").unwrap(), "env"); +} + + +#[test] +fn not_possible_value() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV") + .possible_value("never"), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_err()); +} + +#[test] +fn validator() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV") + .validator(|s| if s == "env" { + Ok(()) + } else { + Err("not equal".to_string()) + }), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("arg"), 0); + assert_eq!(m.value_of("arg").unwrap(), "env"); +} + +#[test] +fn validator_invalid() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'") + .env("CLP_TEST_ENV") + .validator(|s| if s != "env" { + Ok(()) + } else { + Err("is equal".to_string()) + }), + ) + .get_matches_from_safe(vec![""]); + + assert!(r.is_err()); +} diff --git a/clap/tests/example1_tmpl_full.txt b/clap/tests/example1_tmpl_full.txt new file mode 100644 index 0000000..6ae57fa --- /dev/null +++ b/clap/tests/example1_tmpl_full.txt @@ -0,0 +1,15 @@ +{bin} {version} +{author} +{about} + +USAGE: + {usage} + +FLAGS: +{flags} +OPTIONS: +{options} +ARGS: +{positionals} +SUBCOMMANDS: +{subcommands} diff --git a/clap/tests/example1_tmpl_simple.txt b/clap/tests/example1_tmpl_simple.txt new file mode 100644 index 0000000..af6c4b0 --- /dev/null +++ b/clap/tests/example1_tmpl_simple.txt @@ -0,0 +1,8 @@ +{bin} {version} +{author} +{about} + +USAGE: + {usage} + +{all-args} diff --git a/clap/tests/flags.rs b/clap/tests/flags.rs new file mode 100644 index 0000000..143404e --- /dev/null +++ b/clap/tests/flags.rs @@ -0,0 +1,147 @@ +extern crate clap; + +use clap::{App, Arg, ArgSettings}; + +#[test] +fn flag_using_short() { + let m = App::new("flag") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::from_usage("-c, --color 'some other flag'") + ]) + .get_matches_from(vec!["", "-f", "-c"]); + assert!(m.is_present("flag")); + assert!(m.is_present("color")); +} + +#[test] +fn lots_o_flags_sep() { + let r = App::new("opts") + .arg( + Arg::from_usage("-o... 'some flag'"), + ) + .get_matches_from_safe(vec!["", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", + ]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8 +} + +#[test] +fn lots_o_flags_combined() { + let r = App::new("opts") + .arg( + Arg::from_usage("-o... 'some flag'"), + ) + .get_matches_from_safe(vec!["", + "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", + "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", + "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", + "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", + "-ooooooooooooooooooooooooooooooooooooooooo", + ]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8 +} + +#[test] +fn flag_using_long() { + let m = App::new("flag") + .args(&[ + Arg::from_usage("--flag 'some flag'"), + Arg::from_usage("--color 'some other flag'") + ]) + .get_matches_from(vec!["", "--flag", "--color"]); + assert!(m.is_present("flag")); + assert!(m.is_present("color")); +} + +#[test] +fn flag_using_mixed() { + let m = App::new("flag") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::from_usage("-c, --color 'some other flag'") + ]) + .get_matches_from(vec!["", "-f", "--color"]); + assert!(m.is_present("flag")); + assert!(m.is_present("color")); + + let m = App::new("flag") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::from_usage("-c, --color 'some other flag'") + ]) + .get_matches_from(vec!["", "--flag", "-c"]); + assert!(m.is_present("flag")); + assert!(m.is_present("color")); +} + +#[test] +fn multiple_flags_in_single() { + let m = App::new("multe_flags") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::from_usage("-c, --color 'some other flag'"), + Arg::from_usage("-d, --debug 'another other flag'") + ]) + .get_matches_from(vec!["", "-fcd"]); + assert!(m.is_present("flag")); + assert!(m.is_present("color")); + assert!(m.is_present("debug")); +} + +#[test] +fn short_flag_misspel() { + let a = Arg::from_usage("-f1, --flag 'some flag'"); + assert_eq!(a.b.name, "flag"); + assert_eq!(a.s.short.unwrap(), 'f'); + assert_eq!(a.s.long.unwrap(), "flag"); + assert_eq!(a.b.help.unwrap(), "some flag"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); +} + +#[test] +fn short_flag_name_missing() { + let a = Arg::from_usage("-f 'some flag'"); + assert_eq!(a.b.name, "f"); + assert_eq!(a.s.short.unwrap(), 'f'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some flag"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + +} diff --git a/clap/tests/global_args.rs b/clap/tests/global_args.rs new file mode 100644 index 0000000..4adc685 --- /dev/null +++ b/clap/tests/global_args.rs @@ -0,0 +1,37 @@ +extern crate clap; +extern crate regex; + +#[cfg(test)] +mod tests { + include!("../clap-test.rs"); + use clap::{App, Arg, SubCommand}; + + fn get_app() -> App<'static, 'static> { + App::new("myprog") + .arg(Arg::with_name("GLOBAL_ARG") + .long("global-arg") + .help( + "Specifies something needed by the subcommands", + ) + .global(true) + .takes_value(true) + .default_value("default_value")) + .arg(Arg::with_name("GLOBAL_FLAG") + .long("global-flag") + .help( + "Specifies something needed by the subcommands", + ) + .multiple(true) + .global(true)) + .subcommand(SubCommand::with_name("outer") + .subcommand(SubCommand::with_name("inner"))) + } + + #[test] + fn issue_1076() { + let mut app = get_app(); + let _ = app.get_matches_from_safe_borrow(vec!["myprog"]); + let _ = app.get_matches_from_safe_borrow(vec!["myprog"]); + let _ = app.get_matches_from_safe_borrow(vec!["myprog"]); + } +} diff --git a/clap/tests/groups.rs b/clap/tests/groups.rs new file mode 100644 index 0000000..bb108ea --- /dev/null +++ b/clap/tests/groups.rs @@ -0,0 +1,207 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg, ArgGroup, ErrorKind, SubCommand}; + +static REQ_GROUP_USAGE: &'static str = "error: The following required arguments were not provided: + <base|--delete> + +USAGE: + clap-test <base|--delete> + +For more information try --help"; + +static REQ_GROUP_CONFLICT_USAGE: &'static str = "error: The argument '<base>' cannot be used with '--delete' + +USAGE: + clap-test <base|--delete> + +For more information try --help"; + +static REQ_GROUP_CONFLICT_REV: &'static str = "error: The argument '--delete' cannot be used with 'base' + +USAGE: + clap-test <base|--delete> + +For more information try --help"; + +#[test] +fn required_group_missing_arg() { + let result = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color 'some other flag'") + .group(ArgGroup::with_name("req") + .args(&["flag", "color"]) + .required(true)) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +#[should_panic] +fn non_existing_arg() { + let _ = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color 'some other flag'") + .group(ArgGroup::with_name("req") + .args(&["flg", "color"]) + .required(true)) + .get_matches_from_safe(vec![""]); +} + +#[test] +#[should_panic(expected = "The group 'c' contains the arg 'd' that doesn't actually exist.")] +fn non_existing_arg_in_subcommand_help() { + let _ = App::new("a") + .subcommand( + SubCommand::with_name("b") + .group( + ArgGroup::with_name("c") + .args(&["d"]) + .required(true), + ) + ).get_matches_from_safe(vec!["a", "help", "b"]); +} + +#[test] +fn group_single_value() { + let res = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color [color] 'some option'") + .group(ArgGroup::with_name("grp") + .args(&["flag", "color"])) + .get_matches_from_safe(vec!["", "-c", "blue"]); + assert!(res.is_ok()); + + let m = res.unwrap(); + assert!(m.is_present("grp")); + assert_eq!(m.value_of("grp").unwrap(), "blue"); +} + +#[test] +fn group_single_flag() { + let res = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color [color] 'some option'") + .group(ArgGroup::with_name("grp") + .args(&["flag", "color"])) + .get_matches_from_safe(vec!["", "-f"]); + assert!(res.is_ok()); + + let m = res.unwrap(); + assert!(m.is_present("grp")); + assert!(m.value_of("grp").is_none()); +} + +#[test] +fn group_empty() { + let res = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color [color] 'some option'") + .group(ArgGroup::with_name("grp") + .args(&["flag", "color"])) + .get_matches_from_safe(vec![""]); + assert!(res.is_ok()); + + let m = res.unwrap(); + assert!(!m.is_present("grp")); + assert!(m.value_of("grp").is_none()); +} + +#[test] +fn group_reqired_flags_empty() { + let result = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color 'some option'") + .group(ArgGroup::with_name("grp") + .required(true) + .args(&["flag", "color"])) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn group_multi_value_single_arg() { + let res = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color [color]... 'some option'") + .group(ArgGroup::with_name("grp") + .args(&["flag", "color"])) + .get_matches_from_safe(vec!["", "-c", "blue", "red", "green"]); + assert!(res.is_ok(), "{:?}", res.unwrap_err().kind); + + let m = res.unwrap(); + assert!(m.is_present("grp")); + assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]); +} + +#[test] +fn empty_group() { + let r = App::new("empty_group") + .arg(Arg::from_usage("-f, --flag 'some flag'")) + .group(ArgGroup::with_name("vers") + .required(true)) + .get_matches_from_safe(vec!["empty_prog"]); + assert!(r.is_err()); + let err = r.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn req_group_usage_string() { + let app = App::new("req_group") + .args_from_usage("[base] 'Base commit' + -d, --delete 'Remove the base commit information'") + .group(ArgGroup::with_name("base_or_delete") + .args(&["base", "delete"]) + .required(true)); + + assert!(test::compare_output(app, "clap-test", REQ_GROUP_USAGE, true)); +} + +#[test] +fn req_group_with_conflict_usage_string() { + let app = App::new("req_group") + .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete")) + .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'")) + .group(ArgGroup::with_name("base_or_delete") + .args(&["base", "delete"]) + .required(true)); + + assert!(test::compare_output2(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, REQ_GROUP_CONFLICT_USAGE, true)); +} + +#[test] +fn required_group_multiple_args() { + let result = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color 'some other flag'") + .group(ArgGroup::with_name("req") + .args(&["flag", "color"]) + .required(true) + .multiple(true)) + .get_matches_from_safe(vec!["group", "-f", "-c"]); + assert!(result.is_ok()); + let m = result.unwrap(); + assert!(m.is_present("flag")); + assert!(m.is_present("color")); +} + +#[test] +fn group_multiple_args_error() { + let result = App::new("group") + .args_from_usage("-f, --flag 'some flag' + -c, --color 'some other flag'") + .group(ArgGroup::with_name("req") + .args(&["flag", "color"])) + .get_matches_from_safe(vec!["group", "-f", "-c"]); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} diff --git a/clap/tests/help.rs b/clap/tests/help.rs new file mode 100644 index 0000000..4b15281 --- /dev/null +++ b/clap/tests/help.rs @@ -0,0 +1,1205 @@ +#[macro_use] +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, AppSettings, SubCommand, ErrorKind, Arg}; + +static REQUIRE_DELIM_HELP: &'static str = "test 1.3 +Kevin K. +tests stuff + +USAGE: + test --fake <some>:<val> + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -f, --fake <some>:<val> some help"; + +static HELP: &'static str = "clap-test v1.4.8 +Kevin K. <kbknapp@gmail.com> +tests clap library + +USAGE: + clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] + +FLAGS: + -f, --flag tests flags + -F tests flags with exclusions + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -O, --Option <option3> specific vals [possible values: fast, slow] + --long-option-2 <option2> tests long options with exclusions + --maxvals3 <maxvals>... Tests 3 max vals + --minvals2 <minvals>... Tests 2 min vals + --multvals <one> <two> Tests multiple values, not mult occs + --multvalsmo <one> <two> Tests multiple values, and mult occs + -o, --option <opt>... tests options + +ARGS: + <positional> tests positionals + <positional2> tests positionals with exclusions + <positional3>... tests specific values [possible values: vi, emacs] + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + subcmd tests subcommands"; + +static SC_NEGATES_REQS: &'static str = "prog 1.0 + +USAGE: + prog --opt <FILE> [PATH] + prog [PATH] <SUBCOMMAND> + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <FILE> tests options + +ARGS: + <PATH> help + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test"; + +static ARGS_NEGATE_SC: &'static str = "prog 1.0 + +USAGE: + prog [FLAGS] [OPTIONS] [PATH] + prog <SUBCOMMAND> + +FLAGS: + -f, --flag testing flags + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <FILE> tests options + +ARGS: + <PATH> help + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test"; + +static AFTER_HELP: &'static str = "some text that comes before the help + +clap-test v1.4.8 +tests clap library + +USAGE: + clap-test + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +some text that comes after the help"; + +static HIDDEN_ARGS: &'static str = "prog 1.0 + +USAGE: + prog [FLAGS] [OPTIONS] + +FLAGS: + -f, --flag testing flags + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <FILE> tests options"; + +static SC_HELP: &'static str = "clap-test-subcmd 0.1 +Kevin K. <kbknapp@gmail.com> +tests subcommands + +USAGE: + clap-test subcmd [FLAGS] [OPTIONS] [--] [scpositional] + +FLAGS: + -f, --flag tests flags + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --option <scoption>... tests options + -s, --subcmdarg <subcmdarg> tests other args + +ARGS: + <scpositional> tests positionals"; + +static ISSUE_1046_HIDDEN_SCS: &'static str = "prog 1.0 + +USAGE: + prog [FLAGS] [OPTIONS] [PATH] + +FLAGS: + -f, --flag testing flags + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --opt <FILE> tests options + +ARGS: + <PATH> some"; + +// Using number_of_values(1) with multiple(true) misaligns help message +static ISSUE_760: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -O, --opt <opt> tests options + -o, --option <option>... tests options"; + +static RIPGREP_USAGE: &'static str = "ripgrep 0.5 + +USAGE: + rg [OPTIONS] <pattern> [<path> ...] + rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...] + rg [OPTIONS] --files [<path> ...] + rg [OPTIONS] --type-list + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information"; + + +static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1 +Kevin K. <kbknapp@gmail.com> +tests subcommands + +USAGE: + ctest subcmd multi [FLAGS] [OPTIONS] + +FLAGS: + -f, --flag tests flags + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -o, --option <scoption>... tests options"; + +static ISSUE_626_CUTOFF: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --cafe <FILE> A coffeehouse, coffee shop, or café is an + establishment which primarily serves hot + coffee, related coffee beverages (e.g., café + latte, cappuccino, espresso), tea, and other + hot beverages. Some coffeehouses also serve + cold beverages such as iced coffee and iced + tea. Many cafés also serve some type of food, + such as light snacks, muffins, or pastries."; + +static ISSUE_626_PANIC: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --cafe <FILE> + La culture du café est très développée + dans de nombreux pays à climat chaud + d\'Amérique, d\'Afrique et d\'Asie, dans + des plantations qui sont cultivées pour + les marchés d\'exportation. Le café est + souvent une contribution majeure aux + exportations des régions productrices."; + +static HIDE_POS_VALS: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --cafe <FILE> A coffeehouse, coffee shop, or café. + -p, --pos <VAL> Some vals [possible values: fast, slow]"; + +static FINAL_WORD_WRAPPING: &'static str = "ctest 0.1 + +USAGE: + ctest + +FLAGS: + -h, --help + Prints help + information + -V, --version + Prints + version + information"; + +static OLD_NEWLINE_CHARS: &'static str = "ctest 0.1 + +USAGE: + ctest [FLAGS] + +FLAGS: + -h, --help Prints help information + -m Some help with some wrapping + (Defaults to something) + -V, --version Prints version information"; + +static WRAPPING_NEWLINE_CHARS: &'static str = "ctest 0.1 + +USAGE: + ctest [mode] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <mode> x, max, maximum 20 characters, contains + symbols. + l, long Copy-friendly, 14 + characters, contains symbols. + m, med, medium Copy-friendly, 8 + characters, contains symbols."; + +static ISSUE_688: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --filter <filter> Sets the filter, or sampling method, to use for interpolation when resizing the particle + images. The default is Linear (Bilinear). [possible values: Nearest, Linear, Cubic, + Gaussian, Lanczos3]"; + +static ISSUE_702: &'static str = "myapp 1.0 +foo +bar + +USAGE: + myapp [OPTIONS] [--] [ARGS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -l, --label <label>... a label + -o, --other <other> some other option + -s, --some <some> some option + +ARGS: + <arg1> some option + <arg2>... some option"; + +static ISSUE_777: &'static str = "A app with a crazy very long long +long name hahaha 1.0 +Some Very Long Name and crazy long +email <email@server.com> +Show how the about text is not +wrapped + +USAGE: + ctest + +FLAGS: + -h, --help + Prints help information + + -V, --version + Prints version + information"; + +static CUSTOM_VERSION_AND_HELP: &'static str = "customize 0.1 +Nobody <odysseus@example.com> +You can customize the version and help text + +USAGE: + customize + +FLAGS: + -H, --help Print help information + -v, --version Print version information"; + +static LAST_ARG: &'static str = "last 0.1 + +USAGE: + last <TARGET> [CORPUS] [-- <ARGS>...] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <TARGET> some + <CORPUS> some + <ARGS>... some"; + +static LAST_ARG_SC: &'static str = "last 0.1 + +USAGE: + last <TARGET> [CORPUS] [-- <ARGS>...] + last <SUBCOMMAND> + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <TARGET> some + <CORPUS> some + <ARGS>... some + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test some"; + +static LAST_ARG_REQ: &'static str = "last 0.1 + +USAGE: + last <TARGET> [CORPUS] -- <ARGS>... + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <TARGET> some + <CORPUS> some + <ARGS>... some"; + +static LAST_ARG_REQ_SC: &'static str = "last 0.1 + +USAGE: + last <TARGET> [CORPUS] -- <ARGS>... + last <SUBCOMMAND> + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <TARGET> some + <CORPUS> some + <ARGS>... some + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test some"; + +static HIDE_DEFAULT_VAL: &'static str = "default 0.1 + +USAGE: + default [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --arg <argument> Pass an argument to the program. [default: default-argument]"; + +static LAST_ARG_USAGE: &'static str = "flamegraph 0.1 + +USAGE: + flamegraph [FLAGS] [OPTIONS] [BINFILE] [-- <ARGS>...] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + -v, --verbose Prints out more stuff. + +OPTIONS: + -f, --frequency <HERTZ> The sampling frequency. + -t, --timeout <SECONDS> Timeout in seconds. + +ARGS: + <BINFILE> The path of the binary to be profiled. for a binary. + <ARGS>... Any arguments you wish to pass to the being profiled."; + +static LAST_ARG_REQ_MULT: &'static str = "example 1.0 + +USAGE: + example <FIRST>... [--] <SECOND>... + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + <FIRST>... First + <SECOND>... Second"; + +static DEFAULT_HELP: &'static str = "ctest 1.0 + +USAGE: + ctest + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information"; + +static LONG_ABOUT: &'static str = "myapp 1.0 +foo +something really really long, with +multiple lines of text +that should be displayed + +USAGE: + myapp [arg1] + +FLAGS: + -h, --help + Prints help information + + -V, --version + Prints version information + + +ARGS: + <arg1> + some option"; + +static HIDE_ENV_VALS: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR] + -p, --pos <VAL> Some vals [possible values: fast, slow]"; + +static SHOW_ENV_VALS: &'static str = "ctest 0.1 + +USAGE: + ctest [OPTIONS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL] + -p, --pos <VAL> Some vals [possible values: fast, slow]"; + +fn setup() -> App<'static, 'static> { + App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") +} + +#[test] +fn help_short() { + let m = setup() + .get_matches_from_safe(vec!["myprog", "-h"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn help_long() { + let m = setup() + .get_matches_from_safe(vec!["myprog", "--help"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn help_no_subcommand() { + let m = setup() + .get_matches_from_safe(vec!["myprog", "help"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument); +} + +#[test] +fn help_subcommand() { + let m = setup() + .subcommand(SubCommand::with_name("test") + .about("tests things") + .arg_from_usage("-v --verbose 'with verbosity'")) + .get_matches_from_safe(vec!["myprog", "help"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn req_last_arg_usage() { + let app = clap_app!(example => + (version: "1.0") + (@arg FIRST: ... * "First") + (@arg SECOND: ... * +last "Second") + ); + assert!(test::compare_output(app, "example --help", LAST_ARG_REQ_MULT, false)); +} + +#[test] +fn args_with_last_usage() { + let app = App::new("flamegraph") + .version("0.1") + .setting(AppSettings::TrailingVarArg) + .arg(Arg::with_name("verbose") + .help("Prints out more stuff.") + .short("v") + .long("verbose") + .multiple(true) + ) + .arg(Arg::with_name("timeout") + .help("Timeout in seconds.") + .short("t") + .long("timeout") + .value_name("SECONDS") + .takes_value(true) + ) + .arg(Arg::with_name("frequency") + .help("The sampling frequency.") + .short("f") + .long("frequency") + .value_name("HERTZ") + .takes_value(true) + ) + .arg(Arg::with_name("binary path") + .help("The path of the binary to be profiled. for a binary.") + .takes_value(true) + .value_name("BINFILE") + ) + .arg(Arg::with_name("pass through args") + .help("Any arguments you wish to pass to the being profiled.") + .value_name("ARGS") + .last(true) + .multiple(true) + ); + assert!(test::compare_output(app, "flamegraph --help", LAST_ARG_USAGE, false)); +} + +#[test] +fn subcommand_short_help() { + let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn subcommand_long_help() { + let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn subcommand_help_rev() { + let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "help", "subcmd"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn complex_help_output() { + assert!(test::compare_output(test::complex_app(), "clap-test --help", HELP, false)); +} + +#[test] +fn after_and_before_help_output() { + let app = App::new("clap-test") + .version("v1.4.8") + .about("tests clap library") + .before_help("some text that comes before the help") + .after_help("some text that comes after the help"); + assert!(test::compare_output(app, "clap-test --help", AFTER_HELP, false)); +} + +#[test] +fn multi_level_sc_help() { + let app = App::new("ctest") + .subcommand(SubCommand::with_name("subcmd").subcommand(SubCommand::with_name("multi") + .about("tests subcommands") + .author("Kevin K. <kbknapp@gmail.com>") + .version("0.1") + .args_from_usage(" + -f, --flag 'tests flags' + -o, --option [scoption]... 'tests options' + "))); + assert!(test::compare_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false)); +} + +#[test] +fn no_wrap_help() { + let app = App::new("ctest") + .set_term_width(0) + .help(MULTI_SC_HELP); + assert!(test::compare_output(app, "ctest --help", MULTI_SC_HELP, false)); +} + +#[test] +fn no_wrap_default_help() { + let app = App::new("ctest").version("1.0").set_term_width(0); + assert!(test::compare_output(app, "ctest --help", DEFAULT_HELP, false)); +} + +#[test] +fn complex_subcommand_help_output() { + let a = test::complex_app(); + assert!(test::compare_output(a, "clap-test subcmd --help", SC_HELP, false)); +} + + +#[test] +fn issue_626_unicode_cutoff() { + let app = App::new("ctest") + .version("0.1") + .set_term_width(70) + .arg(Arg::with_name("cafe") + .short("c") + .long("cafe") + .value_name("FILE") + .help("A coffeehouse, coffee shop, or café is an establishment \ + which primarily serves hot coffee, related coffee beverages \ + (e.g., café latte, cappuccino, espresso), tea, and other hot \ + beverages. Some coffeehouses also serve cold beverages such as \ + iced coffee and iced tea. Many cafés also serve some type of \ + food, such as light snacks, muffins, or pastries.") + .takes_value(true)); + assert!(test::compare_output(app, "ctest --help", ISSUE_626_CUTOFF, false)); +} + +#[test] +fn hide_possible_vals() { + let app = App::new("ctest") + .version("0.1") + .arg(Arg::with_name("pos") + .short("p") + .long("pos") + .value_name("VAL") + .possible_values(&["fast", "slow"]) + .help("Some vals") + .takes_value(true)) + .arg(Arg::with_name("cafe") + .short("c") + .long("cafe") + .value_name("FILE") + .hide_possible_values(true) + .possible_values(&["fast", "slow"]) + .help("A coffeehouse, coffee shop, or café.") + .takes_value(true)); + assert!(test::compare_output(app, "ctest --help", HIDE_POS_VALS, false)); +} + +#[test] +fn issue_626_panic() { + let app = App::new("ctest") + .version("0.1") + .set_term_width(52) + .arg(Arg::with_name("cafe") + .short("c") + .long("cafe") + .value_name("FILE") + .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \ + d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \ + Le café est souvent une contribution majeure aux exportations des régions productrices.") + .takes_value(true)); + assert!(test::compare_output(app, "ctest --help", ISSUE_626_PANIC, false)); +} + +#[test] +fn issue_626_variable_panic() { + for i in 10..320 { + let _ = App::new("ctest") + .version("0.1") + .set_term_width(i) + .arg(Arg::with_name("cafe") + .short("c") + .long("cafe") + .value_name("FILE") + .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \ + d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \ + Le café est souvent une contribution majeure aux exportations des régions productrices.") + .takes_value(true)) + .get_matches_from_safe(vec!["ctest", "--help"]); + } +} + +#[test] +fn final_word_wrapping() { + let app = App::new("ctest").version("0.1").set_term_width(24); + assert!(test::compare_output(app, "ctest --help", FINAL_WORD_WRAPPING, false)); +} + +#[test] +fn wrapping_newline_chars() { + let app = App::new("ctest") + .version("0.1") + .set_term_width(60) + .arg(Arg::with_name("mode") + .help("x, max, maximum 20 characters, contains symbols.{n}\ + l, long Copy-friendly, 14 characters, contains symbols.{n}\ + m, med, medium Copy-friendly, 8 characters, contains symbols.{n}")); + assert!(test::compare_output(app, "ctest --help", WRAPPING_NEWLINE_CHARS, false)); +} + +#[test] +fn old_newline_chars() { + let app = App::new("ctest") + .version("0.1") + .arg(Arg::with_name("mode") + .short("m") + .help("Some help with some wrapping{n}(Defaults to something)")); + assert!(test::compare_output(app, "ctest --help", OLD_NEWLINE_CHARS, false)); +} + +#[test] +fn issue_688_hidden_pos_vals() { + let filter_values = ["Nearest", "Linear", "Cubic", "Gaussian", "Lanczos3"]; + + let app1 = App::new("ctest") + .version("0.1") + .set_term_width(120) + .setting(AppSettings::HidePossibleValuesInHelp) + .arg(Arg::with_name("filter") + .help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \ + images. The default is Linear (Bilinear). [possible values: Nearest, Linear, Cubic, Gaussian, Lanczos3]") + .long("filter") + .possible_values(&filter_values) + .takes_value(true)); + assert!(test::compare_output(app1, "ctest --help", ISSUE_688, false)); + + let app2 = App::new("ctest") + .version("0.1") + .set_term_width(120) + .arg(Arg::with_name("filter") + .help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \ + images. The default is Linear (Bilinear).") + .long("filter") + .possible_values(&filter_values) + .takes_value(true)); + assert!(test::compare_output(app2, "ctest --help", ISSUE_688, false)); + + let app3 = App::new("ctest") + .version("0.1") + .set_term_width(120) + .arg(Arg::with_name("filter") + .help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \ + images. The default is Linear (Bilinear). [possible values: Nearest, Linear, Cubic, Gaussian, Lanczos3]") + .long("filter") + .takes_value(true)); + assert!(test::compare_output(app3, "ctest --help", ISSUE_688, false)); +} + +#[test] +fn issue_702_multiple_values() { + let app = App::new("myapp") + .version("1.0") + .author("foo") + .about("bar") + .arg(Arg::with_name("arg1").help("some option")) + .arg(Arg::with_name("arg2") + .multiple(true) + .help("some option")) + .arg(Arg::with_name("some") + .help("some option") + .short("s") + .long("some") + .takes_value(true)) + .arg(Arg::with_name("other") + .help("some other option") + .short("o") + .long("other") + .takes_value(true)) + .arg(Arg::with_name("label") + .help("a label") + .short("l") + .long("label") + .multiple(true) + .takes_value(true)); + assert!(test::compare_output(app, "myapp --help", ISSUE_702, false)); +} + +#[test] +fn long_about() { + let app = App::new("myapp") + .version("1.0") + .author("foo") + .about("bar") + .long_about("something really really long, with\nmultiple lines of text\nthat should be displayed") + .arg(Arg::with_name("arg1").help("some option")); + assert!(test::compare_output(app, "myapp --help", LONG_ABOUT, false)); +} + +#[test] +fn issue_760() { + let app = App::new("ctest") + .version("0.1") + .arg(Arg::with_name("option") + .help("tests options") + .short("o") + .long("option") + .takes_value(true) + .multiple(true) + .number_of_values(1)) + .arg(Arg::with_name("opt") + .help("tests options") + .short("O") + .long("opt") + .takes_value(true)); + assert!(test::compare_output(app, "ctest --help", ISSUE_760, false)); +} + +#[test] +fn ripgrep_usage() { + let app = App::new("ripgrep") + .version("0.5") + .usage("rg [OPTIONS] <pattern> [<path> ...] + rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...] + rg [OPTIONS] --files [<path> ...] + rg [OPTIONS] --type-list"); + + assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false)); +} + +#[test] +fn ripgrep_usage_using_templates() { + let app = App::new("ripgrep") + .version("0.5") + .usage(" + rg [OPTIONS] <pattern> [<path> ...] + rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...] + rg [OPTIONS] --files [<path> ...] + rg [OPTIONS] --type-list") + .template("\ +{bin} {version} + +USAGE:{usage} + +FLAGS: +{flags}"); + + assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false)); +} + +#[test] +fn sc_negates_reqs() { + let app = App::new("prog") + .version("1.0") + .setting(AppSettings::SubcommandsNegateReqs) + .arg_from_usage("-o, --opt <FILE> 'tests options'") + .arg(Arg::with_name("PATH").help("help")) + .subcommand(SubCommand::with_name("test")); + assert!(test::compare_output(app, "prog --help", SC_NEGATES_REQS, false)); +} + +#[test] +fn hidden_args() { + let app = App::new("prog") + .version("1.0") + .args_from_usage("-f, --flag 'testing flags' + -o, --opt [FILE] 'tests options'") + .arg(Arg::with_name("pos").hidden(true)); + assert!(test::compare_output(app, "prog --help", HIDDEN_ARGS, false)); +} + +#[test] +fn args_negate_sc() { + let app = App::new("prog") + .version("1.0") + .setting(AppSettings::ArgsNegateSubcommands) + .args_from_usage("-f, --flag 'testing flags' + -o, --opt [FILE] 'tests options'") + .arg(Arg::with_name("PATH").help("help")) + .subcommand(SubCommand::with_name("test")); + assert!(test::compare_output(app, "prog --help", ARGS_NEGATE_SC, false)); +} + +#[test] +fn issue_1046_hidden_scs() { + let app = App::new("prog") + .version("1.0") + .args_from_usage("-f, --flag 'testing flags' + -o, --opt [FILE] 'tests options'") + .arg(Arg::with_name("PATH").help("some")) + .subcommand(SubCommand::with_name("test").setting(AppSettings::Hidden)); + assert!(test::compare_output(app, "prog --help", ISSUE_1046_HIDDEN_SCS, false)); +} + +#[test] +fn issue_777_wrap_all_things() { + let app = App::new("A app with a crazy very long long long name hahaha") + .version("1.0") + .author("Some Very Long Name and crazy long email <email@server.com>") + .about("Show how the about text is not wrapped") + .set_term_width(35); + assert!(test::compare_output(app, "ctest --help", ISSUE_777, false)); +} + +#[test] +fn customize_version_and_help() { + let app = App::new("customize") + .version("0.1") + .author("Nobody <odysseus@example.com>") + .about("You can customize the version and help text") + .help_short("H") + .help_message("Print help information") + .version_short("v") + .version_message("Print version information"); + assert!(test::compare_output(app, "customize --help", CUSTOM_VERSION_AND_HELP, false)); +} + +#[test] +fn last_arg_mult_usage() { + let app = App::new("last") + .version("0.1") + .arg(Arg::with_name("TARGET").required(true).help("some")) + .arg(Arg::with_name("CORPUS").help("some")) + .arg(Arg::with_name("ARGS").multiple(true).last(true).help("some")); + assert!(test::compare_output(app, "last --help", LAST_ARG, false)); +} + +#[test] +fn last_arg_mult_usage_req() { + let app = App::new("last") + .version("0.1") + .arg(Arg::with_name("TARGET").required(true).help("some")) + .arg(Arg::with_name("CORPUS").help("some")) + .arg(Arg::with_name("ARGS").multiple(true).last(true).required(true).help("some")); + assert!(test::compare_output(app, "last --help", LAST_ARG_REQ, false)); +} + +#[test] +fn last_arg_mult_usage_req_with_sc() { + let app = App::new("last") + .version("0.1") + .setting(AppSettings::SubcommandsNegateReqs) + .arg(Arg::with_name("TARGET").required(true).help("some")) + .arg(Arg::with_name("CORPUS").help("some")) + .arg(Arg::with_name("ARGS").multiple(true).last(true).required(true).help("some")) + .subcommand(SubCommand::with_name("test").about("some")); + assert!(test::compare_output(app, "last --help", LAST_ARG_REQ_SC, false)); +} + +#[test] +fn last_arg_mult_usage_with_sc() { + let app = App::new("last") + .version("0.1") + .setting(AppSettings::ArgsNegateSubcommands) + .arg(Arg::with_name("TARGET").required(true).help("some")) + .arg(Arg::with_name("CORPUS").help("some")) + .arg(Arg::with_name("ARGS").multiple(true).last(true).help("some")) + .subcommand(SubCommand::with_name("test").about("some")); + assert!(test::compare_output(app, "last --help", LAST_ARG_SC, false)); +} + + +#[test] +fn hidden_default_val() { + let app1 = App::new("default") + .version("0.1") + .set_term_width(120) + .arg(Arg::with_name("argument") + .help("Pass an argument to the program. [default: default-argument]") + .long("arg") + .default_value("default-argument") + .hide_default_value(true)); + assert!(test::compare_output(app1, "default --help", HIDE_DEFAULT_VAL, false)); + + let app2 = App::new("default") + .version("0.1") + .set_term_width(120) + .arg(Arg::with_name("argument") + .help("Pass an argument to the program.") + .long("arg") + .default_value("default-argument")); + assert!(test::compare_output(app2, "default --help", HIDE_DEFAULT_VAL, false)); +} + +fn issue_1112_setup() -> App<'static, 'static> { + App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .arg(Arg::from_usage("-h, --help 'some help'")) + .subcommand(SubCommand::with_name("foo") + .arg(Arg::from_usage("-h, --help 'some help'"))) +} + +#[test] +fn issue_1112_override_help_long() { + let m = issue_1112_setup() + .get_matches_from_safe(vec!["test", "--help"]); + + assert!(m.is_ok()); + assert!(m.unwrap().is_present("help")); +} + +#[test] +fn issue_1112_override_help_short() { + let m = issue_1112_setup() + .get_matches_from_safe(vec!["test", "-h"]); + + assert!(m.is_ok()); + assert!(m.unwrap().is_present("help")); +} + +#[test] +fn issue_1112_override_help_subcmd_long() { + let m = issue_1112_setup() + .get_matches_from_safe(vec!["test", "foo", "--help"]); + + assert!(m.is_ok()); + assert!(m.unwrap().subcommand_matches("foo").unwrap().is_present("help")); +} + +#[test] +fn issue_1112_override_help_subcmd_short() { + let m = issue_1112_setup() + .get_matches_from_safe(vec!["test", "foo", "-h"]); + + assert!(m.is_ok()); + assert!(m.unwrap().subcommand_matches("foo").unwrap().is_present("help")); +} + +#[test] +fn issue_1052_require_delim_help() { + let app = App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .arg(Arg::from_usage("-f, --fake <some> <val> 'some help'").require_delimiter(true).value_delimiter(":")); + + assert!(test::compare_output(app, "test --help", REQUIRE_DELIM_HELP, false)); +} + +#[test] +fn hide_env_vals() { + use std::env; + + env::set_var("ENVVAR", "MYVAL"); + let app = App::new("ctest") + .version("0.1") + .arg(Arg::with_name("pos") + .short("p") + .long("pos") + .value_name("VAL") + .possible_values(&["fast", "slow"]) + .help("Some vals") + .takes_value(true)) + .arg(Arg::with_name("cafe") + .short("c") + .long("cafe") + .value_name("FILE") + .hide_env_values(true) + .env("ENVVAR") + .help("A coffeehouse, coffee shop, or café.") + .takes_value(true)); + assert!(test::compare_output(app, "ctest --help", HIDE_ENV_VALS, false)); +} + +#[test] +fn show_env_vals() { + use std::env; + + env::set_var("ENVVAR", "MYVAL"); + let app = App::new("ctest") + .version("0.1") + .arg(Arg::with_name("pos") + .short("p") + .long("pos") + .value_name("VAL") + .possible_values(&["fast", "slow"]) + .help("Some vals") + .takes_value(true)) + .arg(Arg::with_name("cafe") + .short("c") + .long("cafe") + .value_name("FILE") + .hide_possible_values(true) + .env("ENVVAR") + .help("A coffeehouse, coffee shop, or café.") + .takes_value(true)); + assert!(test::compare_output(app, "ctest --help", SHOW_ENV_VALS, false)); +} + +static ISSUE_897: &'static str = "ctest-foo 0.1 +Long about foo + +USAGE: + ctest foo + +FLAGS: + -h, --help + Prints help information + + -V, --version + Prints version information"; + +#[test] +fn show_long_about_issue_897() { + let app = App::new("ctest") + .version("0.1") + .subcommand(SubCommand::with_name("foo") + .version("0.1") + .about("About foo") + .long_about("Long about foo")); + assert!(test::compare_output(app, "ctest foo --help", ISSUE_897, false)); +} + +static ISSUE_897_SHORT: &'static str = "ctest-foo 0.1 +Long about foo + +USAGE: + ctest foo + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information"; + +#[test] +fn show_short_about_issue_897() { + let app = App::new("ctest") + .version("0.1") + .subcommand(SubCommand::with_name("foo") + .version("0.1") + .about("About foo") + .long_about("Long about foo")); + assert!(test::compare_output(app, "ctest foo -h", ISSUE_897_SHORT, false)); +} diff --git a/clap/tests/hidden_args.rs b/clap/tests/hidden_args.rs new file mode 100644 index 0000000..635e25e --- /dev/null +++ b/clap/tests/hidden_args.rs @@ -0,0 +1,178 @@ +extern crate clap; +extern crate regex; + +use clap::{App, Arg}; + +include!("../clap-test.rs"); + +static HIDDEN_ARGS: &'static str = "test 1.4 +Kevin K. +tests stuff + +USAGE: + test [FLAGS] [OPTIONS] + +FLAGS: + -F, --flag2 some other flag + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + --option <opt> some option"; + +#[test] +fn hidden_args() { + let app = App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.4") + .args(&[Arg::from_usage("-f, --flag 'some flag'").hidden(true), + Arg::from_usage("-F, --flag2 'some other flag'"), + Arg::from_usage("--option [opt] 'some option'"), + Arg::with_name("DUMMY").required(false).hidden(true)]); + assert!(test::compare_output(app, "test --help", HIDDEN_ARGS, false)); +} + +static HIDDEN_SHORT_ARGS: &'static str = "test 2.31.2 +Steve P. +hides short args + +USAGE: + test [FLAGS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + -v, --visible This text should be visible"; + +static HIDDEN_SHORT_ARGS_LONG_HELP: &'static str = "test 2.31.2 +Steve P. +hides short args + +USAGE: + test [FLAGS] + +FLAGS: + -c, --config + Some help text describing the --config arg + + -h, --help + Prints help information + + -V, --version + Prints version information + + -v, --visible + This text should be visible"; + +/// Ensure hidden with short option +#[test] +fn hidden_short_args() { + let app = App::new("test") + .about("hides short args") + .author("Steve P.") + .version("2.31.2") + .args(&[ + Arg::with_name("cfg") + .short("c") + .long("config") + .hidden_short_help(true) + .help("Some help text describing the --config arg"), + Arg::with_name("visible") + .short("v") + .long("visible") + .help("This text should be visible")]); + + assert!(test::compare_output(app, "test -h", HIDDEN_SHORT_ARGS, false)); +} + +/// Ensure visible with opposite option +#[test] +fn hidden_short_args_long_help() { + let app = App::new("test") + .about("hides short args") + .author("Steve P.") + .version("2.31.2") + .args(&[ + Arg::with_name("cfg") + .short("c") + .long("config") + .hidden_short_help(true) + .help("Some help text describing the --config arg"), + Arg::with_name("visible") + .short("v") + .long("visible") + .help("This text should be visible")]); + + assert!(test::compare_output(app, "test --help", HIDDEN_SHORT_ARGS_LONG_HELP, false)); +} + +static HIDDEN_LONG_ARGS: &'static str = "test 2.31.2 +Steve P. +hides long args + +USAGE: + test [FLAGS] + +FLAGS: + -h, --help + Prints help information + + -V, --version + Prints version information + + -v, --visible + This text should be visible"; + +#[test] +fn hidden_long_args() { + let app = App::new("test") + .about("hides long args") + .author("Steve P.") + .version("2.31.2") + .args(&[ + Arg::with_name("cfg") + .short("c") + .long("config") + .hidden_long_help(true) + .help("Some help text describing the --config arg"), + Arg::with_name("visible") + .short("v") + .long("visible") + .help("This text should be visible")]); + + assert!(test::compare_output(app, "test --help", HIDDEN_LONG_ARGS, false)); +} + +static HIDDEN_LONG_ARGS_SHORT_HELP: &'static str = "test 2.31.2 +Steve P. +hides long args + +USAGE: + test [FLAGS] + +FLAGS: + -c, --config Some help text describing the --config arg + -h, --help Prints help information + -V, --version Prints version information + -v, --visible This text should be visible"; + +#[test] +fn hidden_long_args_short_help() { + let app = App::new("test") + .about("hides long args") + .author("Steve P.") + .version("2.31.2") + .args(&[ + Arg::with_name("cfg") + .short("c") + .long("config") + .hidden_long_help(true) + .help("Some help text describing the --config arg"), + Arg::with_name("visible") + .short("v") + .long("visible") + .help("This text should be visible")]); + + assert!(test::compare_output(app, "test -h", HIDDEN_LONG_ARGS_SHORT_HELP, false)); +} diff --git a/clap/tests/indices.rs b/clap/tests/indices.rs new file mode 100644 index 0000000..910529e --- /dev/null +++ b/clap/tests/indices.rs @@ -0,0 +1,175 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg}; + +#[test] +fn indices_mult_opts() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .takes_value(true) + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .takes_value(true) + .multiple(true)) + .get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"]); + + assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[2, 3, 8]); + assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[5, 6]); +} + +#[test] +fn index_mult_opts() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .takes_value(true) + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .takes_value(true) + .multiple(true)) + .get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"]); + + assert_eq!(m.index_of("exclude"), Some(2)); + assert_eq!(m.index_of("include"), Some(5)); +} + +#[test] +fn index_flag() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e")) + .arg(Arg::with_name("include") + .short("i")) + .get_matches_from(vec!["ind", "-e", "-i"]); + + assert_eq!(m.index_of("exclude"), Some(1)); + assert_eq!(m.index_of("include"), Some(2)); +} + +#[test] +fn index_flags() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .multiple(true)) + .get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"]); + + assert_eq!(m.index_of("exclude"), Some(1)); + assert_eq!(m.index_of("include"), Some(2)); +} + +#[test] +fn indices_mult_flags() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .multiple(true)) + .get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"]); + + assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]); + assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]); +} + +#[test] +fn indices_mult_flags_combined() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .multiple(true)) + .get_matches_from(vec!["ind", "-eieei"]); + + assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]); + assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]); +} + +#[test] +fn indices_mult_flags_opt_combined() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .multiple(true)) + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from(vec!["ind", "-eieeio", "val"]); + + assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]); + assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]); + assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]); +} + +#[test] +fn indices_mult_flags_opt_combined_eq() { + let m = App::new("ind") + .arg(Arg::with_name("exclude") + .short("e") + .multiple(true)) + .arg(Arg::with_name("include") + .short("i") + .multiple(true)) + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from(vec!["ind", "-eieeio=val"]); + + assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]); + assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]); + assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]); +} + +#[test] +fn indices_mult_opt_value_delim_eq() { + let m = App::new("myapp") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true) + .use_delimiter(true) + .multiple(true)) + .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]); +} + +#[test] +fn indices_mult_opt_value_no_delim_eq() { + let m = App::new("myapp") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true) + .multiple(true)) + .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]); +} + +#[test] +fn indices_mult_opt_mult_flag() { + let m = App::new("myapp") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true) + .multiple(true)) + .arg(Arg::with_name("flag") + .short("f") + .multiple(true)) + .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]); + + assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]); + assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]); +} diff --git a/clap/tests/macros.rs b/clap/tests/macros.rs new file mode 100755 index 0000000..0cdcb52 --- /dev/null +++ b/clap/tests/macros.rs @@ -0,0 +1,391 @@ +#[macro_use] +extern crate clap; + +use clap::ErrorKind; + +#[test] +fn basic() { + clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg opt: -o --option +takes_value ... "tests options") + (@arg positional: index(1) "tests positionals") + (@arg flag: -f --flag ... +global "tests flags") + (@arg flag2: -F conflicts_with[flag] requires[option2] + "tests flags with exclusions") + (@arg option2: --long_option_2 conflicts_with[option] requires[positional2] + "tests long options with exclusions") + (@arg positional2: index(2) "tests positionals with exclusions") + (@arg option3: -O --Option +takes_value possible_value[fast slow] + "tests options with specific value sets") + (@arg positional3: index(3) ... possible_value[vi emacs] + "tests positionals with specific values") + (@arg multvals: --multvals +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals") + (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals") + (@subcommand subcmd => + (about: "tests subcommands") + (version: "0.1") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg scoption: -o --option ... +takes_value "tests options") + (@arg scpositional: index(1) "tests positionals")) + ); +} + +#[test] +fn quoted_app_name() { + let app = clap_app!(("app name with spaces-and-hyphens") => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg opt: -o --option +takes_value ... "tests options") + (@arg positional: index(1) "tests positionals") + (@arg flag: -f --flag ... +global "tests flags") + (@arg flag2: -F conflicts_with[flag] requires[option2] + "tests flags with exclusions") + (@arg option2: --long_option_2 conflicts_with[option] requires[positional2] + "tests long options with exclusions") + (@arg positional2: index(2) "tests positionals with exclusions") + (@arg option3: -O --Option +takes_value possible_value[fast slow] + "tests options with specific value sets") + (@arg positional3: index(3) ... possible_value[vi emacs] + "tests positionals with specific values") + (@arg multvals: --multvals +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals") + (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals") + (@subcommand subcmd => + (about: "tests subcommands") + (version: "0.1") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg scoption: -o --option ... +takes_value "tests options") + (@arg scpositional: index(1) "tests positionals")) + ); + + assert_eq!(app.p.meta.name, "app name with spaces-and-hyphens"); + + let mut help_text = vec![]; + app.write_help(&mut help_text).expect("Could not write help text."); + let help_text = String::from_utf8(help_text).expect("Help text is not valid utf-8"); + assert!(help_text.starts_with("app name with spaces-and-hyphens 0.1\n")); +} + +#[test] +fn quoted_arg_long_name() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg opt: -o --option +takes_value ... "tests options") + (@arg positional: index(1) "tests positionals") + (@arg flag: -f --flag ... +global "tests flags") + (@arg flag2: -F conflicts_with[flag] requires[option2] + "tests flags with exclusions") + (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2] + "tests long options with exclusions") + (@arg positional2: index(2) "tests positionals with exclusions") + (@arg option3: -O --Option +takes_value possible_value[fast slow] + "tests options with specific value sets") + (@arg positional3: index(3) ... possible_value[vi emacs] + "tests positionals with specific values") + (@arg multvals: --multvals +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals") + (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals") + (@subcommand subcmd => + (about: "tests subcommands") + (version: "0.1") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg scoption: -o --option ... +takes_value "tests options") + (@arg scpositional: index(1) "tests positionals")) + ); + + let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"]) + .expect("Expected to successfully match the given args."); + assert!(matches.is_present("option2")); +} + +#[test] +fn quoted_arg_name() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg opt: -o --option +takes_value ... "tests options") + (@arg ("positional-arg"): index(1) "tests positionals") + (@arg flag: -f --flag ... +global "tests flags") + (@arg flag2: -F conflicts_with[flag] requires[option2] + "tests flags with exclusions") + (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2] + "tests long options with exclusions") + (@arg positional2: index(2) "tests positionals with exclusions") + (@arg option3: -O --Option +takes_value possible_value[fast slow] + "tests options with specific value sets") + (@arg ("positional-3"): index(3) ... possible_value[vi emacs] + "tests positionals with specific values") + (@arg multvals: --multvals +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two] + "Tests multiple values, not mult occs") + (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals") + (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals") + (@subcommand subcmd => + (about: "tests subcommands") + (version: "0.1") + (author: "Kevin K. <kbknapp@gmail.com>") + (@arg scoption: -o --option ... +takes_value "tests options") + (@arg scpositional: index(1) "tests positionals")) + ); + + let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"]) + .expect("Expected to successfully match the given args."); + assert!(matches.is_present("option2")); +} + +#[test] +fn group_macro() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@group difficulty => + (@arg hard: -h --hard "Sets hard mode") + (@arg normal: -n --normal "Sets normal mode") + (@arg easy: -e --easy "Sets easy mode") + ) + ); + + let result = app.get_matches_from_safe(vec!["bin_name", "--hard"]); + assert!(result.is_ok()); + let matches = result.expect("Expected to successfully match the given args."); + assert!(matches.is_present("difficulty")); + assert!(matches.is_present("hard")); +} + +#[test] +fn group_macro_set_multiple() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@group difficulty +multiple => + (@arg hard: -h --hard "Sets hard mode") + (@arg normal: -n --normal "Sets normal mode") + (@arg easy: -e --easy "Sets easy mode") + ) + ); + + let result = app.get_matches_from_safe(vec!["bin_name", "--hard", "--easy"]); + assert!(result.is_ok()); + let matches = result.expect("Expected to successfully match the given args."); + assert!(matches.is_present("difficulty")); + assert!(matches.is_present("hard")); + assert!(matches.is_present("easy")); + assert!(!matches.is_present("normal")); +} + +#[test] +fn group_macro_set_not_multiple() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@group difficulty !multiple => + (@arg hard: -h --hard "Sets hard mode") + (@arg normal: -n --normal "Sets normal mode") + (@arg easy: -e --easy "Sets easy mode") + ) + ); + + let result = app.get_matches_from_safe(vec!["bin_name", "--hard", "--easy"]); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} + +#[test] +fn group_macro_set_required() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@group difficulty +required => + (@arg hard: -h --hard "Sets hard mode") + (@arg normal: -n --normal "Sets normal mode") + (@arg easy: -e --easy "Sets easy mode") + ) + ); + + let result = app.get_matches_from_safe(vec!["bin_name"]); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn group_macro_set_not_required() { + let app = clap_app!(claptests => + (version: "0.1") + (about: "tests clap library") + (author: "Kevin K. <kbknapp@gmail.com>") + (@group difficulty !required => + (@arg hard: -h --hard "Sets hard mode") + (@arg normal: -n --normal "Sets normal mode") + (@arg easy: -e --easy "Sets easy mode") + ) + ); + + let result = app.get_matches_from_safe(vec!["bin_name"]); + assert!(result.is_ok()); + let matches = result.expect("Expected to successfully match the given args."); + assert!(!matches.is_present("difficulty")); +} + +#[test] +fn multiarg() { + let app = || clap_app!( + claptests => + (@arg flag: --flag "value") + (@arg multiarg: --multiarg + default_value("flag-unset") default_value_if("flag", None, "flag-set") + "multiarg") + (@arg multiarg2: --multiarg2 + default_value("flag-unset") default_value_if("flag", None, "flag-set",) + "multiarg2") + ); + + let matches = app() + .get_matches_from_safe(vec!["bin_name"]) + .expect("match failed"); + assert_eq!(matches.value_of("multiarg"), Some("flag-unset")); + assert_eq!(matches.value_of("multiarg2"), Some("flag-unset")); + + let matches = app() + .get_matches_from_safe(vec!["bin_name", "--flag"]) + .expect("match failed"); + assert_eq!(matches.value_of("multiarg"), Some("flag-set")); + assert_eq!(matches.value_of("multiarg2"), Some("flag-set")); +} + +#[test] +fn arg_enum() { + // Helper macros to avoid repetition + macro_rules! test_greek { + ($arg_enum:item, $tests:block) => {{ + $arg_enum + // FromStr implementation + assert!("Charlie".parse::<Greek>().is_err()); + // Display implementation + assert_eq!(format!("{}", Greek::Alpha), "Alpha"); + assert_eq!(format!("{}", Greek::Bravo), "Bravo"); + // fn variants() + assert_eq!(Greek::variants(), ["Alpha", "Bravo"]); + // rest of tests + $tests + }}; + } + macro_rules! test_greek_no_meta { + {$arg_enum:item} => { + test_greek!($arg_enum, { + // FromStr implementation + assert!("Alpha".parse::<Greek>().is_ok()); + assert!("Bravo".parse::<Greek>().is_ok()); + }) + }; + } + macro_rules! test_greek_meta { + {$arg_enum:item} => { + test_greek!($arg_enum, { + // FromStr implementation + assert_eq!("Alpha".parse::<Greek>(), Ok(Greek::Alpha)); + assert_eq!("Bravo".parse::<Greek>(), Ok(Greek::Bravo)); + }) + }; + } + + // Tests for each pattern + // meta NO, pub NO, trailing comma NO + test_greek_no_meta!{ + arg_enum!{ + enum Greek { + Alpha, + Bravo + } + } + }; + // meta NO, pub NO, trailing comma YES + test_greek_no_meta!{ + arg_enum!{ + enum Greek { + Alpha, + Bravo, + } + } + }; + // meta NO, pub YES, trailing comma NO + test_greek_no_meta!{ + arg_enum!{ + pub enum Greek { + Alpha, + Bravo + } + } + }; + // meta NO, pub YES, trailing comma YES + test_greek_no_meta!{ + arg_enum!{ + pub enum Greek { + Alpha, + Bravo, + } + } + }; + // meta YES, pub NO, trailing comma NO + test_greek_meta!{ + arg_enum!{ + #[derive(Debug, PartialEq, Copy, Clone)] + enum Greek { + Alpha, + Bravo + } + } + }; + // meta YES, pub NO, trailing comma YES + test_greek_meta!{ + arg_enum!{ + #[derive(Debug, PartialEq, Copy, Clone)] + enum Greek { + Alpha, + Bravo, + } + } + }; + // meta YES, pub YES, trailing comma NO + test_greek_meta!{ + arg_enum!{ + #[derive(Debug, PartialEq, Copy, Clone)] + pub enum Greek { + Alpha, + Bravo + } + } + }; + // meta YES, pub YES, trailing comma YES + test_greek_meta!{ + arg_enum!{ + #[derive(Debug, PartialEq, Copy, Clone)] + pub enum Greek { + Alpha, + Bravo, + } + } + }; +} diff --git a/clap/tests/multiple_occurrences.rs b/clap/tests/multiple_occurrences.rs new file mode 100644 index 0000000..2f92fb1 --- /dev/null +++ b/clap/tests/multiple_occurrences.rs @@ -0,0 +1,75 @@ +extern crate clap; + +use clap::{App, Arg}; + +#[test] +fn multiple_occurrences_of_flags_long() { + let m = App::new("mo_flags_long") + .arg(Arg::from_usage("--multflag 'allowed multiple flag'") + .multiple(true)) + .arg(Arg::from_usage("--flag 'disallowed multiple flag'")) + .get_matches_from(vec![ + "", + "--multflag", + "--flag", + "--multflag" + ]); + assert!(m.is_present("multflag")); + assert_eq!(m.occurrences_of("multflag"), 2); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1) +} + +#[test] +fn multiple_occurrences_of_flags_short() { + let m = App::new("mo_flags_short") + .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'") + .multiple(true)) + .arg(Arg::from_usage("-f --flag 'disallowed multiple flag'")) + .get_matches_from(vec![ + "", + "-m", + "-f", + "-m" + ]); + assert!(m.is_present("multflag")); + assert_eq!(m.occurrences_of("multflag"), 2); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1); +} + +#[test] +fn multiple_occurrences_of_flags_mixed() { + let m = App::new("mo_flags_mixed") + .arg(Arg::from_usage("-m, --multflag1 'allowed multiple flag'") + .multiple(true)) + .arg(Arg::from_usage("-n, --multflag2 'another allowed multiple flag'") + .multiple(true)) + .arg(Arg::from_usage("-f, --flag 'disallowed multiple flag'")) + .get_matches_from(vec![ + "", + "-m", + "-f", + "-n", + "--multflag1", + "-m", + "--multflag2" + ]); + assert!(m.is_present("multflag1")); + assert_eq!(m.occurrences_of("multflag1"), 3); + assert!(m.is_present("multflag2")); + assert_eq!(m.occurrences_of("multflag2"), 2); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1); +} + +#[test] +fn multiple_occurrences_of_flags_large_quantity() { + let args : Vec<&str> = vec![""].into_iter().chain(vec!["-m"; 1024].into_iter()).collect(); + let m = App::new("mo_flags_larg_qty") + .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'") + .multiple(true)) + .get_matches_from(args); + assert!(m.is_present("multflag")); + assert_eq!(m.occurrences_of("multflag"), 1024); +} diff --git a/clap/tests/multiple_values.rs b/clap/tests/multiple_values.rs new file mode 100644 index 0000000..551aff1 --- /dev/null +++ b/clap/tests/multiple_values.rs @@ -0,0 +1,1122 @@ +extern crate clap; + +use clap::{App, Arg, ErrorKind, SubCommand}; + +#[test] +fn option_long() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .help("multiple options") + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "--option", "val1", + "--option", "val2", + "--option", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 3); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn option_short() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + "-o", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 3); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn option_mixed() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "--option", "val2", + "--option", "val3", + "-o", "val4", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 4); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]); +} + +#[test] +fn option_exact_exact() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .number_of_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + "-o", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 3); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn option_exact_exact_not_mult() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .number_of_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", "val2", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn option_exact_exact_mult() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .number_of_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", "val2", "val3", + "-o", "val4", "val5", "val6", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 2); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4", "val5", "val6"]); +} + +#[test] +fn option_exact_less() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .number_of_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + ]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); +} + +#[test] +fn option_exact_more() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .number_of_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + "-o", "val3", + "-o", "val4", + ]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); +} + +#[test] +fn option_min_exact() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .min_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + "-o", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 3); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn option_min_less() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .min_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + ]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::TooFewValues); +} + +#[test] +fn option_short_min_more_mult_occurs() { + let m = App::new("multiple_values") + .arg(Arg::with_name("arg") + .required(true)) + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .min_values(3)) + .get_matches_from_safe(vec![ + "", + "pos", + "-o", "val1", + "-o", "val2", + "-o", "val3", + "-o", "val4", + ]); + + let m = m.map_err(|e| println!("failed to unwrap err with error kind {:?}", e.kind)).unwrap(); + + assert!(m.is_present("option")); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("option"), 4); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]); + assert_eq!(m.value_of("arg"), Some("pos")); +} + +#[test] +fn option_short_min_more_single_occur() { + let m = App::new("multiple_values") + .arg(Arg::with_name("arg") + .required(true)) + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .min_values(3)) + .get_matches_from_safe(vec![ + "", + "pos", + "-o", "val1", + "val2", + "val3", + "val4", + ]); + + let m = m.map_err(|e| println!("failed to unwrap err with error kind {:#?}", e)).unwrap(); + + assert!(m.is_present("option")); + assert!(m.is_present("arg")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]); + assert_eq!(m.value_of("arg"), Some("pos")); +} + +#[test] +fn option_max_exact() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .max_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + "-o", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 3); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn option_max_less() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .max_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 2); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2"]); +} + +#[test] +fn option_max_more() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .takes_value(true) + .multiple(true) + .max_values(3)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", + "-o", "val2", + "-o", "val3", + "-o", "val4", + ]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::TooManyValues); +} + +#[test] +fn positional() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .multiple(true)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("pos")); + assert_eq!(m.occurrences_of("pos"), 3); + assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn positional_exact_exact() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .number_of_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("pos")); + assert_eq!(m.occurrences_of("pos"), 3); + assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn positional_exact_less() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .number_of_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); +} + +#[test] +fn positional_exact_more() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .number_of_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues); +} + +#[test] +fn positional_min_exact() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .min_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("pos")); + assert_eq!(m.occurrences_of("pos"), 3); + assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn positional_min_less() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .min_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::TooFewValues); +} + +#[test] +fn positional_min_more() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .min_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("pos")); + assert_eq!(m.occurrences_of("pos"), 4); + assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]); +} + +#[test] +fn positional_max_exact() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .max_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("pos")); + assert_eq!(m.occurrences_of("pos"), 3); + assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn positional_max_less() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .max_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("pos")); + assert_eq!(m.occurrences_of("pos"), 2); + assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2"]); +} + +#[test] +fn positional_max_more() { + let m = App::new("multiple_values") + .arg(Arg::with_name("pos") + .help("multiple positionals") + .max_values(3)) + .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::TooManyValues); +} + +#[test] +fn sep_long_equals() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .use_delimiter(true) + .help("multiple options") + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "--option=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn sep_long_space() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .use_delimiter(true) + .help("multiple options") + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "--option", + "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn sep_short_equals() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .use_delimiter(true) + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "-o=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn sep_short_space() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .use_delimiter(true) + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "-o", + "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn sep_short_no_space() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .help("multiple options") + .use_delimiter(true) + .takes_value(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "-oval1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn sep_positional() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .help("multiple options") + .use_delimiter(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "", + "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn different_sep() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .help("multiple options") + .takes_value(true) + .value_delimiter(";")) + .get_matches_from_safe(vec![ + "", + "--option=val1;val2;val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn different_sep_positional() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .help("multiple options") + .value_delimiter(";")) + .get_matches_from_safe(vec![ + "", + "val1;val2;val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]); +} + +#[test] +fn no_sep() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .help("multiple options") + .takes_value(true) + .use_delimiter(false)) + .get_matches_from_safe(vec![ + "", + "--option=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn no_sep_positional() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .help("multiple options") + .use_delimiter(false)) + .get_matches_from_safe(vec![ + "", + "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn req_delimiter_long() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .multiple(true) + .use_delimiter(true) + .require_delimiter(true) + .takes_value(true)) + .arg(Arg::with_name("args") + .multiple(true) + .index(1)) + .get_matches_from_safe(vec![ + "", + "--option", "val1", "val2", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]); + assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]); +} + +#[test] +fn req_delimiter_long_with_equal() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .multiple(true) + .use_delimiter(true) + .require_delimiter(true) + .takes_value(true)) + .arg(Arg::with_name("args") + .multiple(true) + .index(1)) + .get_matches_from_safe(vec![ + "", + "--option=val1", "val2", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]); + assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]); +} + +#[test] +fn req_delimiter_short_with_space() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .multiple(true) + .use_delimiter(true) + .require_delimiter(true) + .takes_value(true)) + .arg(Arg::with_name("args") + .multiple(true) + .index(1)) + .get_matches_from_safe(vec![ + "", + "-o", "val1", "val2", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]); + assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]); +} + +#[test] +fn req_delimiter_short_with_no_space() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("o") + .multiple(true) + .use_delimiter(true) + .require_delimiter(true) + .takes_value(true)) + .arg(Arg::with_name("args") + .multiple(true) + .index(1)) + .get_matches_from_safe(vec![ + "", + "-oval1", "val2", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]); + assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]); +} + +#[test] +fn req_delimiter_short_with_equal() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .short("option") + .multiple(true) + .use_delimiter(true) + .require_delimiter(true) + .takes_value(true)) + .arg(Arg::with_name("args") + .multiple(true) + .index(1)) + .get_matches_from_safe(vec![ + "", + "-o=val1", "val2", "val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]); + assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]); +} + +#[test] +fn req_delimiter_complex() { + let m = App::new("multiple_values") + .arg(Arg::with_name("option") + .long("option") + .short("o") + .multiple(true) + .use_delimiter(true) + .require_delimiter(true) + .takes_value(true)) + .arg(Arg::with_name("args") + .multiple(true) + .index(1)) + .get_matches_from_safe(vec![ + "", + "val1", + "-oval2", "val3", + "-o", "val4", "val5", + "-o=val6", "val7", + "--option=val8", "val9", + "--option", "val10", "val11", + "-oval12,val13", "val14", + "-o", "val15,val16", "val17", + "-o=val18,val19", "val20", + "--option=val21,val22", "val23", + "--option", "val24,val25", "val26" + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 10); + assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), + &["val2", "val4", "val6", "val8", "val10", "val12", "val13", "val15", + "val16", "val18", "val19", "val21", "val22", "val24", "val25"]); + assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), + &["val1", "val3", "val5", "val7", "val9", "val11", "val14", "val17", + "val20", "val23", "val26"]); +} + +#[test] +#[should_panic] +fn low_index_positional_not_required() { + let _ = App::new("lip") + .arg(Arg::with_name("files") + .index(1) + .required(true) + .multiple(true)) + .arg(Arg::with_name("target") + .index(2)) + .get_matches_from_safe(vec![ + "lip", + "file1", "file2", + "file3", "target", + ]); +} + +#[test] +#[should_panic] +fn low_index_positional_last_multiple_too() { + let _ = App::new("lip") + .arg(Arg::with_name("files") + .index(1) + .required(true) + .multiple(true)) + .arg(Arg::with_name("target") + .index(2) + .required(true) + .multiple(true)) + .get_matches_from_safe(vec![ + "lip", + "file1", "file2", + "file3", "target", + ]); +} + +#[test] +#[should_panic] +fn low_index_positional_too_far_back() { + let _ = App::new("lip") + .arg(Arg::with_name("files") + .index(1) + .required(true) + .multiple(true)) + .arg(Arg::with_name("target") + .required(true) + .index(2)) + .arg(Arg::with_name("target2") + .required(true) + .index(3)) + .get_matches_from_safe(vec![ + "lip", + "file1", "file2", + "file3", "target", + ]); +} + +#[test] +fn low_index_positional() { + let m = App::new("lip") + .arg(Arg::with_name("files") + .index(1) + .required(true) + .multiple(true)) + .arg(Arg::with_name("target") + .index(2) + .required(true)) + .get_matches_from_safe(vec![ + "lip", + "file1", "file2", + "file3", "target", + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + + assert!(m.is_present("files")); + assert_eq!(m.occurrences_of("files"), 3); + assert!(m.is_present("target")); + assert_eq!(m.occurrences_of("target"), 1); + assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]); + assert_eq!(m.value_of("target").unwrap(), "target"); +} + +#[test] +fn low_index_positional_in_subcmd() { + let m = App::new("lip") + .subcommand(SubCommand::with_name("test") + .arg(Arg::with_name("files") + .index(1) + .required(true) + .multiple(true)) + .arg(Arg::with_name("target") + .index(2) + .required(true))) + .get_matches_from_safe(vec![ + "lip", "test", + "file1", "file2", + "file3", "target" + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + let sm = m.subcommand_matches("test").unwrap(); + + assert!(sm.is_present("files")); + assert_eq!(sm.occurrences_of("files"), 3); + assert!(sm.is_present("target")); + assert_eq!(sm.occurrences_of("target"), 1); + assert_eq!(sm.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]); + assert_eq!(sm.value_of("target").unwrap(), "target"); +} + +#[test] +fn low_index_positional_with_option() { + let m = App::new("lip") + .arg(Arg::with_name("files") + .required(true) + .index(1) + .multiple(true)) + .arg(Arg::with_name("target") + .index(2) + .required(true)) + .arg(Arg::with_name("opt") + .long("option") + .takes_value(true)) + .get_matches_from_safe(vec![ + "lip", + "file1", "file2", + "file3", "target", + "--option", "test" + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + + assert!(m.is_present("files")); + assert_eq!(m.occurrences_of("files"), 3); + assert!(m.is_present("target")); + assert_eq!(m.occurrences_of("target"), 1); + assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]); + assert_eq!(m.value_of("target").unwrap(), "target"); + assert_eq!(m.value_of("opt").unwrap(), "test"); +} + +#[test] +fn low_index_positional_with_flag() { + let m = App::new("lip") + .arg(Arg::with_name("files") + .index(1) + .required(true) + .multiple(true)) + .arg(Arg::with_name("target") + .index(2) + .required(true)) + .arg(Arg::with_name("flg") + .long("flag")) + .get_matches_from_safe(vec![ + "lip", + "file1", "file2", + "file3", "target", + "--flag" + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + + assert!(m.is_present("files")); + assert_eq!(m.occurrences_of("files"), 3); + assert!(m.is_present("target")); + assert_eq!(m.occurrences_of("target"), 1); + assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]); + assert_eq!(m.value_of("target").unwrap(), "target"); + assert!(m.is_present("flg")); +} + +#[test] +fn multiple_value_terminator_option() { + let m = App::new("lip") + .arg(Arg::with_name("files") + .short("f") + .value_terminator(";") + .multiple(true)) + .arg(Arg::with_name("other")) + .get_matches_from_safe(vec![ + "lip", + "-f", "val1", "val2", ";", + "otherval" + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + + assert!(m.is_present("other")); + assert_eq!(m.occurrences_of("other"), 1); + assert!(m.is_present("files")); + assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["val1", "val2"]); + assert_eq!(m.value_of("other"), Some("otherval")); +} + +#[test] +fn multiple_value_terminator_option_other_arg() { + let m = App::new("lip") + .arg(Arg::with_name("files") + .short("f") + .value_terminator(";") + .multiple(true)) + .arg(Arg::with_name("other")) + .arg(Arg::with_name("flag") + .short("-F")) + .get_matches_from_safe(vec![ + "lip", + "-f", "val1", "val2", + "-F", + "otherval" + ]); + + assert!(m.is_ok(), "{:?}", m.unwrap_err().kind); + let m = m.unwrap(); + + assert!(m.is_present("other")); + assert!(m.is_present("files")); + assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["val1", "val2"]); + assert_eq!(m.value_of("other"), Some("otherval")); + assert!(m.is_present("flag")); +} + +#[test] +fn multiple_vals_with_hyphen() { + let res = App::new("do") + .arg(Arg::with_name("cmds") + .multiple(true) + .allow_hyphen_values(true) + .value_terminator(";")) + .arg(Arg::with_name("location")) + .get_matches_from_safe(vec!["do", "find", "-type", "f", "-name", "special", ";", "/home/clap"]); + assert!(res.is_ok(), "{:?}", res.unwrap_err().kind); + + let m = res.unwrap(); + let cmds: Vec<_> = m.values_of("cmds").unwrap().collect(); + assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]); + assert_eq!(m.value_of("location"), Some("/home/clap")); +} diff --git a/clap/tests/opts.rs b/clap/tests/opts.rs new file mode 100644 index 0000000..a9029ac --- /dev/null +++ b/clap/tests/opts.rs @@ -0,0 +1,461 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, ArgMatches, Arg, ErrorKind}; + +#[cfg(feature = "suggestions")] +static DYM: &'static str = "error: Found argument '--optio' which wasn't expected, or isn't valid in this context +\tDid you mean --option? + +USAGE: + clap-test --option <opt>... + +For more information try --help"; + +#[test] +fn require_equals_fail() { + let res = App::new("prog") + .arg(Arg::with_name("cfg") + .require_equals(true) + .takes_value(true) + .long("config")) + .get_matches_from_safe(vec![ + "prog", "--config", "file.conf" + ]); + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); +} + +#[test] +fn require_equals_min_values_zero() { + let res = App::new("prog") + .arg(Arg::with_name("cfg") + .require_equals(true) + .takes_value(true) + .min_values(0) + .long("config")) + .arg(Arg::with_name("cmd")) + .get_matches_from_safe(vec![ + "prog", "--config", "cmd" + ]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("cfg")); + assert_eq!(m.value_of("cmd"), Some("cmd")); +} + +#[test] +fn double_hyphen_as_value() { + let res = App::new("prog") + .arg(Arg::with_name("cfg") + .takes_value(true) + .allow_hyphen_values(true) + .long("config")) + .get_matches_from_safe(vec![ + "prog", "--config", "--" + ]); + assert!(res.is_ok(), "{:?}", res); + assert_eq!(res.unwrap().value_of("cfg"), Some("--")); +} + +#[test] +fn require_equals_no_empty_values_fail() { + let res = App::new("prog") + .arg(Arg::with_name("cfg") + .require_equals(true) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("some")) + .get_matches_from_safe(vec![ + "prog", "--config=", "file.conf" + ]); + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); +} + +#[test] +fn require_equals_empty_vals_pass() { + let res = App::new("prog") + .arg(Arg::with_name("cfg") + .require_equals(true) + .takes_value(true) + .empty_values(true) + .long("config")) + .get_matches_from_safe(vec![ + "prog", "--config=" + ]); + assert!(res.is_ok()); +} + +#[test] +fn require_equals_pass() { + let res = App::new("prog") + .arg(Arg::with_name("cfg") + .require_equals(true) + .takes_value(true) + .long("config")) + .get_matches_from_safe(vec![ + "prog", "--config=file.conf" + ]); + assert!(res.is_ok()); +} + +#[test] +fn stdin_char() { + let r = App::new("opts") + .arg(Arg::from_usage("-f [flag] 'some flag'")) + .get_matches_from_safe(vec!["", "-f", "-"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("f")); + assert_eq!(m.value_of("f").unwrap(), "-"); +} + +#[test] +fn opts_using_short() { + let r = App::new("opts") + .args(&[Arg::from_usage("-f [flag] 'some flag'"), + Arg::from_usage("-c [color] 'some other flag'")]) + .get_matches_from_safe(vec!["", "-f", "some", "-c", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("f")); + assert_eq!(m.value_of("f").unwrap(), "some"); + assert!(m.is_present("c")); + assert_eq!(m.value_of("c").unwrap(), "other"); +} + +#[test] +fn lots_o_vals() { + let r = App::new("opts") + .arg(Arg::from_usage("-o [opt]... 'some opt'")) + .get_matches_from_safe(vec!["", "-o", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>().len(), 297); // i.e. more than u8 +} + +#[test] +fn opts_using_long_space() { + let r = App::new("opts") + .args(&[Arg::from_usage("--flag [flag] 'some flag'"), + Arg::from_usage("--color [color] 'some other flag'")]) + .get_matches_from_safe(vec!["", "--flag", "some", "--color", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "some"); + assert!(m.is_present("color")); + assert_eq!(m.value_of("color").unwrap(), "other"); +} + +#[test] +fn opts_using_long_equals() { + let r = App::new("opts") + .args(&[Arg::from_usage("--flag [flag] 'some flag'"), + Arg::from_usage("--color [color] 'some other flag'")]) + .get_matches_from_safe(vec!["", "--flag=some", "--color=other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "some"); + assert!(m.is_present("color")); + assert_eq!(m.value_of("color").unwrap(), "other"); +} + +#[test] +fn opts_using_mixed() { + let r = App::new("opts") + .args(&[Arg::from_usage("-f, --flag [flag] 'some flag'"), + Arg::from_usage("-c, --color [color] 'some other flag'")]) + .get_matches_from_safe(vec!["", "-f", "some", "--color", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "some"); + assert!(m.is_present("color")); + assert_eq!(m.value_of("color").unwrap(), "other"); +} + +#[test] +fn opts_using_mixed2() { + let r = App::new("opts") + .args(&[Arg::from_usage("-f, --flag [flag] 'some flag'"), + Arg::from_usage("-c, --color [color] 'some other flag'")]) + .get_matches_from_safe(vec!["", "--flag=some", "-c", "other"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "some"); + assert!(m.is_present("color")); + assert_eq!(m.value_of("color").unwrap(), "other"); +} + +#[test] +fn default_values_user_value() { + let r = App::new("df") + .arg(Arg::from_usage("-o [opt] 'some opt'").default_value("default")) + .get_matches_from_safe(vec!["", "-o", "value"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.value_of("o").unwrap(), "value"); +} + +#[test] +fn multiple_vals_pos_arg_equals() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'")) + .arg(Arg::from_usage("[file] 'some file'")) + .get_matches_from_safe(vec!["", "-o=1", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.value_of("o").unwrap(), "1"); + assert!(m.is_present("file")); + assert_eq!(m.value_of("file").unwrap(), "some"); +} + +#[test] +fn multiple_vals_pos_arg_delim() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'")) + .arg(Arg::from_usage("[file] 'some file'")) + .get_matches_from_safe(vec!["", "-o", "1,2", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["1", "2"]); + assert!(m.is_present("file")); + assert_eq!(m.value_of("file").unwrap(), "some"); +} + +#[test] +fn require_delims_no_delim() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'").require_delimiter(true)) + .arg(Arg::from_usage("[file] 'some file'")) + .get_matches_from_safe(vec!["mvae", "-o", "1", "2", "some"]); + assert!(r.is_err()); + let err = r.unwrap_err(); + assert_eq!(err.kind, ErrorKind::UnknownArgument); +} + +#[test] +fn require_delims() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'").require_delimiter(true)) + .arg(Arg::from_usage("[file] 'some file'")) + .get_matches_from_safe(vec!["", "-o", "1,2", "some"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["1", "2"]); + assert!(m.is_present("file")); + assert_eq!(m.value_of("file").unwrap(), "some"); +} + +#[test] +fn leading_hyphen_pass() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'").allow_hyphen_values(true)) + .get_matches_from_safe(vec!["", "-o", "-2", "3"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2", "3"]); +} + +#[test] +fn leading_hyphen_fail() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt] 'some opt'")) + .get_matches_from_safe(vec!["", "-o", "-2"]); + assert!(r.is_err()); + let m = r.unwrap_err(); + assert_eq!(m.kind, ErrorKind::UnknownArgument); +} + +#[test] +fn leading_hyphen_with_flag_after() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'").allow_hyphen_values(true)) + .arg_from_usage("-f 'some flag'") + .get_matches_from_safe(vec!["", "-o", "-2", "-f"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2", "-f"]); + assert!(!m.is_present("f")); +} + +#[test] +fn leading_hyphen_with_flag_before() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'").allow_hyphen_values(true)) + .arg_from_usage("-f 'some flag'") + .get_matches_from_safe(vec!["", "-f", "-o", "-2"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2"]); + assert!(m.is_present("f")); +} + +#[test] +fn leading_hyphen_with_only_pos_follows() { + let r = App::new("mvae") + .arg(Arg::from_usage("-o [opt]... 'some opt'").number_of_values(1).allow_hyphen_values(true)) + .arg_from_usage("[arg] 'some arg'") + .get_matches_from_safe(vec!["", "-o", "-2", "--", "val"]); + assert!(r.is_ok(), "{:?}", r); + let m = r.unwrap(); + assert!(m.is_present("o")); + assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2"]); + assert_eq!(m.value_of("arg"), Some("val")); +} + +#[test] +#[cfg(feature="suggestions")] +fn did_you_mean() { + assert!(test::compare_output(test::complex_app(), + "clap-test --optio=foo", + DYM, + true)); +} + +#[test] +fn issue_665() { + let res = App::new("tester") + .arg_from_usage("-v, --reroll-count=[N] 'Mark the patch series as PATCH vN'") + .arg(Arg::from_usage( +"--subject-prefix [Subject-Prefix] 'Use [Subject-Prefix] instead of the standard [PATCH] prefix'") + .empty_values(false)) + .get_matches_from_safe(vec!["test", "--subject-prefix", "-v", "2"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); +} + +#[test] +fn issue_1047_min_zero_vals_default_val() { + let m = App::new("foo") + .arg( + Arg::with_name("del") + .short("d") + .long("del") + .takes_value(true) + .require_equals(true) + .min_values(0) + .default_value("default"), + ) + .get_matches_from(vec!["foo", "-d"]); + assert_eq!(m.occurrences_of("del"), 1); + assert_eq!(m.value_of("del"), Some("default")); +} + +fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches<'static>, clap::Error> { + App::new("opts") + .arg_from_usage("-o, --option [opt] 'some option'") + .arg_from_usage("--flag 'some flag'") + .get_matches_from_safe(argv) +} + +#[test] +fn issue_1105_empty_value_long_fail() { + let r = issue_1105_setup(vec!["app", "--option", "--flag"]); + assert!(r.is_err()); + assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue); +} + +#[test] +fn issue_1105_empty_value_long_explicit() { + let r = issue_1105_setup(vec!["app", "--option", ""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert_eq!(m.value_of("option"), Some("")); +} + +#[test] +fn issue_1105_empty_value_long_equals() { + let r = issue_1105_setup(vec!["app", "--option="]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert_eq!(m.value_of("option"), Some("")); +} + +#[test] +fn issue_1105_empty_value_short_fail() { + let r = issue_1105_setup(vec!["app", "-o", "--flag"]); + assert!(r.is_err()); + assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue); +} + +#[test] +fn issue_1105_empty_value_short_explicit() { + let r = issue_1105_setup(vec!["app", "-o", ""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert_eq!(m.value_of("option"), Some("")); +} + +#[test] +fn issue_1105_empty_value_short_equals() { + let r = issue_1105_setup(vec!["app", "-o="]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert_eq!(m.value_of("option"), Some("")); +} + +#[test] +fn issue_1105_empty_value_short_explicit_no_space() { + let r = issue_1105_setup(vec!["app", "-o", ""]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert_eq!(m.value_of("option"), Some("")); +} diff --git a/clap/tests/positionals.rs b/clap/tests/positionals.rs new file mode 100644 index 0000000..bf0f79f --- /dev/null +++ b/clap/tests/positionals.rs @@ -0,0 +1,274 @@ +extern crate clap; + +use clap::{App, Arg, ErrorKind}; + +#[test] +fn only_pos_follow() { + let r = App::new("onlypos") + .args(&[Arg::from_usage("-f [flag] 'some opt'"), + Arg::from_usage("[arg] 'some arg'")]) + .get_matches_from_safe(vec!["", "--", "-f"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert!(!m.is_present("f")); + assert_eq!(m.value_of("arg").unwrap(), "-f"); +} + +#[test] +fn issue_946() { + let r = App::new("compiletest") + .setting(clap::AppSettings::AllowLeadingHyphen) + .args_from_usage("--exact 'filters match exactly'") + .arg(clap::Arg::with_name("filter") + .index(1) + .takes_value(true) + .help("filters to apply to output")) + .get_matches_from_safe(vec!["compiletest", "--exact"]); + assert!(r.is_ok(), "{:#?}", r); + let matches = r.unwrap(); + + assert!(matches.is_present("exact")); + assert!(matches.value_of("filter").is_none()); +} + +#[test] +fn positional() { + let r = App::new("positional") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::with_name("positional") + .index(1) + ]) + .get_matches_from_safe(vec!["", "-f", "test"]); + assert!(r.is_ok(), "{:#?}", r); + let m = r.unwrap(); + assert!(m.is_present("positional")); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("positional").unwrap(), "test"); + + let m = App::new("positional") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::with_name("positional") + .index(1) + ]) + .get_matches_from(vec!["", "test", "--flag"]); + assert!(m.is_present("positional")); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("positional").unwrap(), "test"); +} + +#[test] +fn lots_o_vals() { + let r = App::new("opts") + .arg( + Arg::from_usage("[opt]... 'some pos'"), + ) + .get_matches_from_safe(vec!["", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", + ]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>().len(), 297); // i.e. more than u8 +} + +#[test] +fn positional_multiple() { + let r = App::new("positional_multiple") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::with_name("positional") + .index(1) + .multiple(true) + ]) + .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]); + assert!(r.is_ok(), "{:#?}", r); + let m = r.unwrap(); + assert!(m.is_present("positional")); + assert!(m.is_present("flag")); + assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test1", "test2", "test3"]); +} + +#[test] +fn positional_multiple_3() { + let r = App::new("positional_multiple") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::with_name("positional") + .index(1) + .multiple(true) + ]) + .get_matches_from_safe(vec!["", "test1", "test2", "test3", "--flag"]); + assert!(r.is_ok(), "{:#?}", r); + let m = r.unwrap(); + assert!(m.is_present("positional")); + assert!(m.is_present("flag")); + assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test1", "test2", "test3"]); +} + +#[test] +fn positional_multiple_2() { + let result = App::new("positional_multiple") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::with_name("positional") + .index(1) + ]) + .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::UnknownArgument); +} + +#[test] +fn positional_possible_values() { + let r = App::new("positional_possible_values") + .args(&[ + Arg::from_usage("-f, --flag 'some flag'"), + Arg::with_name("positional") + .index(1) + .possible_value("test123") + ]) + .get_matches_from_safe(vec!["", "-f", "test123"]); + assert!(r.is_ok(), "{:#?}", r); + let m = r.unwrap(); + assert!(m.is_present("positional")); + assert!(m.is_present("flag")); + assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test123"]); +} + +#[test] +fn create_positional() { + let _ = App::new("test") + .arg(Arg::with_name("test") + .index(1) + .help("testing testing")) + .get_matches_from(vec![""]); +} + +#[test] +fn positional_hyphen_does_not_panic() { + let _ = App::new("test") + .arg(Arg::with_name("dummy")) + .get_matches_from(vec!["test", "-"]); +} + +#[test] +fn single_positional_usage_string() { + let m = App::new("test").arg_from_usage("[FILE] 'some file'").get_matches_from(vec!["test"]); + assert_eq!(m.usage(), "USAGE:\n test [FILE]"); +} + +#[test] +fn single_positional_multiple_usage_string() { + let m = App::new("test").arg_from_usage("[FILE]... 'some file'").get_matches_from(vec!["test"]); + assert_eq!(m.usage(), "USAGE:\n test [FILE]..."); +} + +#[test] +fn multiple_positional_usage_string() { + let m = App::new("test") + .arg_from_usage("[FILE] 'some file'") + .arg_from_usage("[FILES]... 'some file'") + .get_matches_from(vec!["test"]); + assert_eq!(m.usage(), "USAGE:\n test [ARGS]"); +} + +#[test] +fn multiple_positional_one_required_usage_string() { + let m = App::new("test") + .arg_from_usage("<FILE> 'some file'") + .arg_from_usage("[FILES]... 'some file'") + .get_matches_from(vec!["test", "file"]); + assert_eq!(m.usage(), "USAGE:\n test <FILE> [FILES]..."); +} + +#[test] +fn single_positional_required_usage_string() { + let m = App::new("test") + .arg_from_usage("<FILE> 'some file'") + .get_matches_from(vec!["test", "file"]); + assert_eq!(m.usage(), "USAGE:\n test <FILE>"); +} + +#[test] +#[should_panic] +fn missing_required() { + let r = App::new("test") + .arg_from_usage("[FILE1] 'some file'") + .arg_from_usage("<FILE2> 'some file'") + .get_matches_from_safe(vec!["test", "file"]); + assert!(r.is_err()); + assert_eq!(r.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn missing_required_2() { + let r = App::new("test") + .arg_from_usage("<FILE1> 'some file'") + .arg_from_usage("<FILE2> 'some file'") + .get_matches_from_safe(vec!["test", "file"]); + assert!(r.is_err()); + assert_eq!(r.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn last_positional() { + let r = App::new("test") + .arg_from_usage("<TARGET> 'some target'") + .arg_from_usage("[CORPUS] 'some corpus'") + .arg(Arg::from_usage("[ARGS]... 'some file'").last(true)) + .get_matches_from_safe(vec!["test", "tgt", "--", "arg"]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &["arg"]); +} + +#[test] +fn last_positional_no_double_dash() { + let r = App::new("test") + .arg_from_usage("<TARGET> 'some target'") + .arg_from_usage("[CORPUS] 'some corpus'") + .arg(Arg::from_usage("[ARGS]... 'some file'").last(true)) + .get_matches_from_safe(vec!["test", "tgt", "crp", "arg"]); + assert!(r.is_err()); + assert_eq!(r.unwrap_err().kind, ErrorKind::UnknownArgument); +} + +#[test] +fn last_positional_second_to_last_mult() { + let r = App::new("test") + .arg_from_usage("<TARGET> 'some target'") + .arg_from_usage("[CORPUS]... 'some corpus'") + .arg(Arg::from_usage("[ARGS]... 'some file'").last(true)) + .get_matches_from_safe(vec!["test", "tgt", "crp1", "crp2", "--", "arg"]); + assert!(r.is_ok(), "{:?}", r.unwrap_err().kind); +} diff --git a/clap/tests/posix_compatible.rs b/clap/tests/posix_compatible.rs new file mode 100644 index 0000000..26d9f71 --- /dev/null +++ b/clap/tests/posix_compatible.rs @@ -0,0 +1,292 @@ +extern crate clap; + +use clap::{App, Arg, ErrorKind}; + +#[test] +fn flag_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag")) + .get_matches_from_safe(vec!["", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 1); +} + +#[test] +fn mult_flag_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag")) + .get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("flag")); + assert_eq!(m.occurrences_of("flag"), 4); +} + +#[test] +fn option_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.value_of("opt"), Some("other")); +} + +#[test] +fn mult_option_require_delim_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--opt [val]... 'some option'") + .overrides_with("opt") + .number_of_values(1) + .require_delimiter(true)) + .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 3); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["some", "other", "one", "two"]); +} + +#[test] +fn mult_option_overrides_itself() { + let res = App::new("posix") + .arg(Arg::from_usage("--opt [val]... 'some option'") + .overrides_with("opt")) + .get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 2); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "overides", "some", "other", "val"]); +} + +#[test] +fn option_use_delim_false_override_itself() { + + let m = App::new("posix") + .arg(Arg::from_usage("--opt [val] 'some option'") + .overrides_with("opt") + .use_delimiter(false)) + .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]); + assert!(m.is_present("opt")); + assert_eq!(m.occurrences_of("opt"), 1); + assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["one,two"]); +} + +#[test] +fn pos_mult_overrides_itself() { + // opts with multiple + let res = App::new("posix") + .arg(Arg::from_usage("[val]... 'some pos'").overrides_with("val")) + .get_matches_from_safe(vec!["", "some", "other", "value"]); + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("val")); + assert_eq!(m.occurrences_of("val"), 3); + assert_eq!(m.values_of("val").unwrap().collect::<Vec<_>>(), &["some", "other", "value"]); +} + +#[test] +fn posix_compatible_flags_long() { + let m = App::new("posix") + .arg(Arg::from_usage("--flag 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("--color 'some other flag'")) + .get_matches_from(vec!["", "--flag", "--color"]); + assert!(m.is_present("color")); + assert!(!m.is_present("flag")); + + let m = App::new("posix") + .arg(Arg::from_usage("--flag 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("--color 'some other flag'")) + .get_matches_from(vec!["", "--color", "--flag"]); + assert!(!m.is_present("color")); + assert!(m.is_present("flag")); +} + +#[test] +fn posix_compatible_flags_short() { + let m = App::new("posix") + .arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("-c, --color 'some other flag'")) + .get_matches_from(vec!["", "-f", "-c"]); + assert!(m.is_present("color")); + assert!(!m.is_present("flag")); + + let m = App::new("posix") + .arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("-c, --color 'some other flag'")) + .get_matches_from(vec!["", "-c", "-f"]); + assert!(!m.is_present("color")); + assert!(m.is_present("flag")); +} + +#[test] +fn posix_compatible_opts_long() { + let m = App::new("posix") + .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("--color [color] 'some other flag'")) + .get_matches_from(vec!["", "--flag", "some" ,"--color", "other"]); + assert!(m.is_present("color")); + assert_eq!(m.value_of("color").unwrap(), "other"); + assert!(!m.is_present("flag")); + + let m = App::new("posix") + .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("--color [color] 'some other flag'")) + .get_matches_from(vec!["", "--color", "some" ,"--flag", "other"]); + assert!(!m.is_present("color")); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "other"); +} + +#[test] +fn posix_compatible_opts_long_equals() { + let m = App::new("posix") + .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("--color [color] 'some other flag'")) + .get_matches_from(vec!["", "--flag=some" ,"--color=other"]); + assert!(m.is_present("color")); + assert_eq!(m.value_of("color").unwrap(), "other"); + assert!(!m.is_present("flag")); + + let m = App::new("posix") + .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color")) + .arg(Arg::from_usage("--color [color] 'some other flag'")) + .get_matches_from(vec!["", "--color=some" ,"--flag=other"]); + assert!(!m.is_present("color")); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "other"); +} + +#[test] +fn posix_compatible_opts_short() { + let m = App::new("posix") + .arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c")) + .arg(Arg::from_usage("-c [color] 'some other flag'")) + .get_matches_from(vec!["", "-f", "some", "-c", "other"]); + assert!(m.is_present("c")); + assert_eq!(m.value_of("c").unwrap(), "other"); + assert!(!m.is_present("f")); + + let m = App::new("posix") + .arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c")) + .arg(Arg::from_usage("-c [color] 'some other flag'")) + .get_matches_from(vec!["", "-c", "some", "-f", "other"]); + assert!(!m.is_present("c")); + assert!(m.is_present("f")); + assert_eq!(m.value_of("f").unwrap(), "other"); +} + +#[test] +fn conflict_overriden() { + let m = App::new("conflict_overriden") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("debug")) + .arg(Arg::from_usage("-d, --debug 'other flag'")) + .arg(Arg::from_usage("-c, --color 'third flag'") + .overrides_with("flag")) + .get_matches_from(vec!["", "-f", "-c", "-d"]); + assert!(m.is_present("color")); + assert!(!m.is_present("flag")); + assert!(m.is_present("debug")); +} + +#[test] +fn conflict_overriden_2() { + let result = App::new("conflict_overriden") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("debug")) + .arg(Arg::from_usage("-d, --debug 'other flag'")) + .arg(Arg::from_usage("-c, --color 'third flag'") + .overrides_with("flag")) + .get_matches_from_safe(vec!["", "-f", "-d", "-c"]); + assert!(result.is_ok()); + let m = result.unwrap(); + assert!(m.is_present("color")); + assert!(m.is_present("debug")); + assert!(!m.is_present("flag")); +} + +#[test] +fn conflict_overriden_3() { + let result = App::new("conflict_overriden") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("debug")) + .arg(Arg::from_usage("-d, --debug 'other flag'")) + .arg(Arg::from_usage("-c, --color 'third flag'") + .overrides_with("flag")) + .get_matches_from_safe(vec!["", "-d", "-c", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::ArgumentConflict); +} + +#[test] +fn conflict_overriden_4() { + let m = App::new("conflict_overriden") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .conflicts_with("debug")) + .arg(Arg::from_usage("-d, --debug 'other flag'")) + .arg(Arg::from_usage("-c, --color 'third flag'") + .overrides_with("flag")) + .get_matches_from(vec!["", "-d", "-f", "-c"]); + assert!(m.is_present("color")); + assert!(!m.is_present("flag")); + assert!(m.is_present("debug")); +} + +#[test] +fn pos_required_overridden_by_flag() { + let result = App::new("require_overriden") + .arg(Arg::with_name("pos") + .index(1) + .required(true)) + .arg(Arg::from_usage("-c, --color 'some flag'") + .overrides_with("pos")) + .get_matches_from_safe(vec!["", "test", "-c"]); + assert!(result.is_ok(), "{:?}", result.unwrap_err()); +} + +#[test] +fn require_overriden_2() { + let m = App::new("require_overriden") + .arg(Arg::with_name("req_pos") + .required(true)) + .arg(Arg::from_usage("-c, --color 'other flag'") + .overrides_with("req_pos")) + .get_matches_from(vec!["", "-c", "req_pos"]); + assert!(!m.is_present("color")); + assert!(m.is_present("req_pos")); +} + +#[test] +fn require_overriden_3() { + let m = App::new("require_overriden") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .requires("debug")) + .arg(Arg::from_usage("-d, --debug 'other flag'")) + .arg(Arg::from_usage("-c, --color 'third flag'") + .overrides_with("flag")) + .get_matches_from(vec!["", "-f", "-c"]); + assert!(m.is_present("color")); + assert!(!m.is_present("flag")); + assert!(!m.is_present("debug")); +} + +#[test] +fn require_overriden_4() { + let result = App::new("require_overriden") + .arg(Arg::from_usage("-f, --flag 'some flag'") + .requires("debug")) + .arg(Arg::from_usage("-d, --debug 'other flag'")) + .arg(Arg::from_usage("-c, --color 'third flag'") + .overrides_with("flag")) + .get_matches_from_safe(vec!["", "-c", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} diff --git a/clap/tests/possible_values.rs b/clap/tests/possible_values.rs new file mode 100644 index 0000000..80772bd --- /dev/null +++ b/clap/tests/possible_values.rs @@ -0,0 +1,266 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; + +use clap::{App, Arg, ErrorKind}; + +#[cfg(feature = "suggestions")] +static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option <option3>' +\t[possible values: fast, slow] + +\tDid you mean 'slow'? + +USAGE: + clap-test --Option <option3> + +For more information try --help"; + +#[cfg(not(feature = "suggestions"))] +static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option <option3>' +\t[possible values: fast, slow] + + +USAGE: + clap-test --Option <option3> + +For more information try --help"; + +#[test] +fn possible_values_of_positional() { + let m = App::new("possible_values") + .arg( + Arg::with_name("positional") + .index(1) + .possible_value("test123"), + ) + .get_matches_from_safe(vec!["myprog", "test123"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("positional")); + assert_eq!(m.value_of("positional"), Some("test123")); +} + +#[test] +fn possible_values_of_positional_fail() { + let m = App::new("possible_values") + .arg( + Arg::with_name("positional") + .index(1) + .possible_value("test123"), + ) + .get_matches_from_safe(vec!["myprog", "notest"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); +} + +#[test] +fn possible_values_of_positional_multiple() { + let m = App::new("possible_values") + .arg( + Arg::with_name("positional") + .index(1) + .possible_value("test123") + .possible_value("test321") + .multiple(true), + ) + .get_matches_from_safe(vec!["myprog", "test123", "test321"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("positional")); + assert_eq!( + m.values_of("positional").unwrap().collect::<Vec<_>>(), + vec!["test123", "test321"] + ); +} + +#[test] +fn possible_values_of_positional_multiple_fail() { + let m = App::new("possible_values") + .arg( + Arg::with_name("positional") + .index(1) + .possible_value("test123") + .possible_value("test321") + .multiple(true), + ) + .get_matches_from_safe(vec!["myprog", "test123", "notest"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); +} + +#[test] +fn possible_values_of_option() { + let m = App::new("possible_values") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123"), + ) + .get_matches_from_safe(vec!["myprog", "--option", "test123"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.value_of("option"), Some("test123")); +} + +#[test] +fn possible_values_of_option_fail() { + let m = App::new("possible_values") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123"), + ) + .get_matches_from_safe(vec!["myprog", "--option", "notest"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); +} + +#[test] +fn possible_values_of_option_multiple() { + let m = App::new("possible_values") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123") + .possible_value("test321") + .multiple(true), + ) + .get_matches_from_safe(vec!["", "--option", "test123", "--option", "test321"]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!( + m.values_of("option").unwrap().collect::<Vec<_>>(), + vec!["test123", "test321"] + ); +} + +#[test] +fn possible_values_of_option_multiple_fail() { + let m = App::new("possible_values") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123") + .possible_value("test321") + .multiple(true), + ) + .get_matches_from_safe(vec!["", "--option", "test123", "--option", "notest"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); +} + +#[test] +fn possible_values_output() { + assert!(test::compare_output( + test::complex_app(), + "clap-test -O slo", + PV_ERROR, + true + )); +} + +#[test] +fn case_insensitive() { + let m = App::new("pv") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123") + .possible_value("test321") + .case_insensitive(true), + ) + .get_matches_from_safe(vec!["pv", "--option", "TeSt123"]); + + assert!(m.is_ok()); + assert!( + m.unwrap() + .value_of("option") + .unwrap() + .eq_ignore_ascii_case("test123") + ); +} + +#[test] +fn case_insensitive_faili() { + let m = App::new("pv") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123") + .possible_value("test321"), + ) + .get_matches_from_safe(vec!["pv", "--option", "TeSt123"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); +} + +#[test] +fn case_insensitive_multiple() { + let m = App::new("pv") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123") + .possible_value("test321") + .multiple(true) + .case_insensitive(true), + ) + .get_matches_from_safe(vec!["pv", "--option", "TeSt123", "teST123", "tESt321"]); + + assert!(m.is_ok()); + assert_eq!( + m.unwrap().values_of("option").unwrap().collect::<Vec<_>>(), + &["TeSt123", "teST123", "tESt321"] + ); +} + +#[test] +fn case_insensitive_multiple_fail() { + let m = App::new("pv") + .arg( + Arg::with_name("option") + .short("-o") + .long("--option") + .takes_value(true) + .possible_value("test123") + .possible_value("test321") + .multiple(true), + ) + .get_matches_from_safe(vec!["pv", "--option", "test123", "teST123", "test321"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); +} diff --git a/clap/tests/propagate_globals.rs b/clap/tests/propagate_globals.rs new file mode 100644 index 0000000..ee77ce0 --- /dev/null +++ b/clap/tests/propagate_globals.rs @@ -0,0 +1,148 @@ +extern crate clap; +extern crate regex; + +#[cfg(test)] +mod tests { + include!("../clap-test.rs"); + use clap::{App, Arg, SubCommand, ArgMatches}; + + fn get_app() -> App<'static, 'static> { + App::new("myprog") + .arg(Arg::with_name("GLOBAL_ARG") + .long("global-arg") + .help( + "Specifies something needed by the subcommands", + ) + .global(true) + .takes_value(true) + .default_value("default_value")) + .arg(Arg::with_name("GLOBAL_FLAG") + .long("global-flag") + .help( + "Specifies something needed by the subcommands", + ) + .multiple(true) + .global(true)) + .subcommand(SubCommand::with_name("outer") + .subcommand(SubCommand::with_name("inner"))) + } + + fn get_matches(app: App<'static, 'static>, argv: &'static str) -> ArgMatches<'static> { + app.get_matches_from(argv.split(' ').collect::<Vec<_>>()) + } + + fn get_outer_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> { + m.subcommand_matches("outer").expect("could not access outer subcommand") + } + + fn get_inner_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> { + get_outer_matches(m).subcommand_matches("inner").expect("could not access inner subcommand") + } + + fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool { + m.value_of("GLOBAL_ARG") == val.into() + } + + fn inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool { + get_inner_matches(m).value_of("GLOBAL_ARG") == val.into() + } + + fn outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool { + get_outer_matches(m).value_of("GLOBAL_ARG") == val.into() + } + + fn top_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool { + (m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences) + } + + fn inner_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool { + let m = get_inner_matches(m); + (m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences) + } + + fn outer_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool { + let m = get_outer_matches(m); + (m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences) + } + + #[test] + fn global_arg_used_top_level() { + let m = get_matches(get_app(), "myprog --global-arg=some_value outer inner"); + + assert!(top_can_access_arg(&m, "some_value")); + assert!(inner_can_access_arg(&m, "some_value")); + assert!(outer_can_access_arg(&m, "some_value")); + } + + #[test] + fn global_arg_used_outer() { + let m = get_matches(get_app(), "myprog outer --global-arg=some_value inner"); + + assert!(top_can_access_arg(&m, "some_value")); + assert!(inner_can_access_arg(&m, "some_value")); + assert!(outer_can_access_arg(&m, "some_value")); + } + + #[test] + fn global_arg_used_inner() { + let m = get_matches(get_app(), "myprog outer inner --global-arg=some_value"); + + assert!(top_can_access_arg(&m, "some_value")); + assert!(inner_can_access_arg(&m, "some_value")); + assert!(outer_can_access_arg(&m, "some_value")); + } + + #[test] + fn global_arg_default_value() { + let m = get_matches(get_app(), "myprog outer inner"); + + assert!(top_can_access_arg(&m, "default_value")); + assert!(inner_can_access_arg(&m, "default_value")); + assert!(outer_can_access_arg(&m, "default_value")); + } + + #[test] + fn global_flag_used_top_level() { + let m = get_matches(get_app(), "myprog --global-flag outer inner"); + + assert!(top_can_access_flag(&m, true, 1)); + assert!(inner_can_access_flag(&m, true, 1)); + assert!(outer_can_access_flag(&m, true, 1)); + } + + #[test] + fn global_flag_used_outer() { + let m = get_matches(get_app(), "myprog outer --global-flag inner"); + + assert!(top_can_access_flag(&m, true, 1)); + assert!(inner_can_access_flag(&m, true, 1)); + assert!(outer_can_access_flag(&m, true, 1)); + } + + #[test] + fn global_flag_used_inner() { + let m = get_matches(get_app(), "myprog outer inner --global-flag"); + + assert!(top_can_access_flag(&m, true, 1)); + assert!(inner_can_access_flag(&m, true, 1)); + assert!(outer_can_access_flag(&m, true, 1)); + } + + #[test] + fn global_flag_2x_used_top_level() { + let m = get_matches(get_app(), "myprog --global-flag --global-flag outer inner"); + + assert!(top_can_access_flag(&m, true, 2)); + assert!(inner_can_access_flag(&m, true, 2)); + assert!(outer_can_access_flag(&m, true, 2)); + } + + #[test] + fn global_flag_2x_used_inner() { + let m = get_matches(get_app(), "myprog outer inner --global-flag --global-flag"); + + assert!(top_can_access_flag(&m, true, 2)); + assert!(inner_can_access_flag(&m, true, 2)); + assert!(outer_can_access_flag(&m, true, 2)); + } +} diff --git a/clap/tests/require.rs b/clap/tests/require.rs new file mode 100644 index 0000000..7121aa5 --- /dev/null +++ b/clap/tests/require.rs @@ -0,0 +1,688 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg, ErrorKind, ArgGroup}; + +static REQUIRE_EQUALS: &'static str = "error: The following required arguments were not provided: + --opt=<FILE> + +USAGE: + clap-test --opt=<FILE> + +For more information try --help"; + +static MISSING_REQ: &'static str = "error: The following required arguments were not provided: + <positional2> + --long-option-2 <option2> + +USAGE: + clap-test <positional2> -F --long-option-2 <option2> + +For more information try --help"; + +static COND_REQ_IN_USAGE: &'static str = "error: The following required arguments were not provided: + --output <output> + +USAGE: + test --input <input> --output <output> --target <target> + +For more information try --help"; + +static ISSUE_1158: &'static str = "error: The following required arguments were not provided: + -x <X> + -y <Y> + -z <Z> + +USAGE: + example [OPTIONS] <ID> -x <X> -y <Y> -z <Z> + +For more information try --help"; + +#[test] +fn issue_1158_conflicting_requirements() { + let app = App::new("example") + .arg(Arg::from_usage("-c, --config [FILE] 'Custom config file.'") + .required_unless("ID") + .conflicts_with("ID")) + .arg(Arg::from_usage("[ID] 'ID'") + .required_unless("config") + .conflicts_with("config") + .requires_all(&["x", "y", "z"])) + .arg(Arg::from_usage("-x [X] 'X'")) + .arg(Arg::from_usage("-y [Y] 'Y'")) + .arg(Arg::from_usage("-z [Z] 'Z'")); + + assert!(test::compare_output(app, "example id", ISSUE_1158, true)); +} + +#[test] +fn issue_1158_conflicting_requirements_rev() { + let res = App::new("example") + .arg(Arg::from_usage("-c, --config [FILE] 'Custom config file.'") + .required_unless("ID") + .conflicts_with("ID")) + .arg(Arg::from_usage("[ID] 'ID'") + .required_unless("config") + .conflicts_with("config") + .requires_all(&["x", "y", "z"])) + .arg(Arg::from_usage("-x [X] 'X'")) + .arg(Arg::from_usage("-y [Y] 'Y'")) + .arg(Arg::from_usage("-z [Z] 'Z'")) + .get_matches_from_safe(vec!["example", "--config", "some"]); + + assert!(res.is_ok()); +} + +#[test] +fn flag_required() { + let result = App::new("flag_required") + .arg(Arg::from_usage("-f, --flag 'some flag'").requires("color")) + .arg(Arg::from_usage("-c, --color 'third flag'")) + .get_matches_from_safe(vec!["", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn flag_required_2() { + let m = App::new("flag_required") + .arg(Arg::from_usage("-f, --flag 'some flag'").requires("color")) + .arg(Arg::from_usage("-c, --color 'third flag'")) + .get_matches_from(vec!["", "-f", "-c"]); + assert!(m.is_present("color")); + assert!(m.is_present("flag")); +} + +#[test] +fn option_required() { + let result = App::new("option_required") + .arg(Arg::from_usage("-f [flag] 'some flag'").requires("c")) + .arg(Arg::from_usage("-c [color] 'third flag'")) + .get_matches_from_safe(vec!["", "-f", "val"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn option_required_2() { + let m = App::new("option_required") + .arg(Arg::from_usage("-f [flag] 'some flag'").requires("c")) + .arg(Arg::from_usage("-c [color] 'third flag'")) + .get_matches_from(vec!["", "-f", "val", "-c", "other_val"]); + assert!(m.is_present("c")); + assert_eq!(m.value_of("c").unwrap(), "other_val"); + assert!(m.is_present("f")); + assert_eq!(m.value_of("f").unwrap(), "val"); +} + +#[test] +fn positional_required() { + let result = App::new("positional_required") + .arg(Arg::with_name("flag") + .index(1) + .required(true)) + .get_matches_from_safe(vec![""]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn positional_required_2() { + let m = App::new("positional_required") + .arg(Arg::with_name("flag") + .index(1) + .required(true)) + .get_matches_from(vec!["", "someval"]); + assert!(m.is_present("flag")); + assert_eq!(m.value_of("flag").unwrap(), "someval"); +} + +#[test] +fn group_required() { + let result = App::new("group_required") + .arg(Arg::from_usage("-f, --flag 'some flag'")) + .group(ArgGroup::with_name("gr") + .required(true) + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from_safe(vec!["", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn group_required_2() { + let m = App::new("group_required") + .arg(Arg::from_usage("-f, --flag 'some flag'")) + .group(ArgGroup::with_name("gr") + .required(true) + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from(vec!["", "-f", "--some"]); + assert!(m.is_present("some")); + assert!(!m.is_present("other")); + assert!(m.is_present("flag")); +} + +#[test] +fn group_required_3() { + let m = App::new("group_required") + .arg(Arg::from_usage("-f, --flag 'some flag'")) + .group(ArgGroup::with_name("gr") + .required(true) + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from(vec!["", "-f", "--other"]); + assert!(!m.is_present("some")); + assert!(m.is_present("other")); + assert!(m.is_present("flag")); +} + +#[test] +fn arg_require_group() { + let result = App::new("arg_require_group") + .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr")) + .group(ArgGroup::with_name("gr") + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from_safe(vec!["", "-f"]); + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn arg_require_group_2() { + let m = App::new("arg_require_group") + .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr")) + .group(ArgGroup::with_name("gr") + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from(vec!["", "-f", "--some"]); + assert!(m.is_present("some")); + assert!(!m.is_present("other")); + assert!(m.is_present("flag")); +} + +#[test] +fn arg_require_group_3() { + let m = App::new("arg_require_group") + .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr")) + .group(ArgGroup::with_name("gr") + .arg("some") + .arg("other")) + .arg(Arg::from_usage("--some 'some arg'")) + .arg(Arg::from_usage("--other 'other arg'")) + .get_matches_from(vec!["", "-f", "--other"]); + assert!(!m.is_present("some")); + assert!(m.is_present("other")); + assert!(m.is_present("flag")); +} + +// REQUIRED_UNLESS + +#[test] +fn issue_753() { + let m = App::new("test") + .arg(Arg::from_usage("-l, --list 'List available interfaces (and stop there)'")) + .arg(Arg::from_usage("-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'") + .required_unless("list")) + .arg(Arg::from_usage("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'") + .conflicts_with("iface") + .required_unless("list")) + .arg(Arg::from_usage("-s, --server=[SERVER_IP] 'NTP server IP address'") + .required_unless("list")) + .arg(Arg::from_usage("-p, --port=[SERVER_PORT] 'NTP server port'") + .default_value("123")) + .get_matches_from_safe(vec!["test", "--list"]); + assert!(m.is_ok()); +} + +#[test] +fn required_unless() { + let res = App::new("unlesstest") + .arg(Arg::with_name("cfg") + .required_unless("dbg") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .get_matches_from_safe(vec!["unlesstest", "--debug"]); + + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("dbg")); + assert!(!m.is_present("cfg")); +} + +#[test] +fn required_unless_err() { + let res = App::new("unlesstest") + .arg(Arg::with_name("cfg") + .required_unless("dbg") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .get_matches_from_safe(vec!["unlesstest"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +// REQUIRED_UNLESS_ALL + +#[test] +fn required_unless_all() { + let res = App::new("unlessall") + .arg(Arg::with_name("cfg") + .required_unless_all(&["dbg", "infile"]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .arg(Arg::with_name("infile") + .short("i") + .takes_value(true)) + .get_matches_from_safe(vec!["unlessall", "--debug", "-i", "file"]); + + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("dbg")); + assert!(m.is_present("infile")); + assert!(!m.is_present("cfg")); +} + +#[test] +fn required_unless_all_err() { + let res = App::new("unlessall") + .arg(Arg::with_name("cfg") + .required_unless_all(&["dbg", "infile"]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .arg(Arg::with_name("infile") + .short("i") + .takes_value(true)) + .get_matches_from_safe(vec!["unlessall", "--debug"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +// REQUIRED_UNLESS_ONE + +#[test] +fn required_unless_one() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .required_unless_one(&["dbg", "infile"]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .arg(Arg::with_name("infile") + .short("i") + .takes_value(true)) + .get_matches_from_safe(vec!["unlessone", "--debug"]); + + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("dbg")); + assert!(!m.is_present("cfg")); +} + +#[test] +fn required_unless_one_2() { + // This tests that the required_unless_one works when the second arg in the array is used + // instead of the first. + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .required_unless_one(&["dbg", "infile"]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .arg(Arg::with_name("infile") + .short("i") + .takes_value(true)) + .get_matches_from_safe(vec!["unlessone", "-i", "file"]); + + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(m.is_present("infile")); + assert!(!m.is_present("cfg")); +} + +#[test] +fn required_unless_one_works_with_short() { + // GitHub issue: https://github.com/clap-rs/clap/issues/1135 + let res = App::new("unlessone") + .arg(Arg::with_name("a").conflicts_with("b").short("a")) + .arg(Arg::with_name("b").short("b")) + .arg( + Arg::with_name("x") + .short("x") + .required_unless_one(&["a", "b"]) + ).get_matches_from_safe(vec!["unlessone", "-a"]); + + assert!(res.is_ok()); +} + +#[test] +fn required_unless_one_works_with_short_err() { + let res = App::new("unlessone") + .arg(Arg::with_name("a").conflicts_with("b").short("a")) + .arg(Arg::with_name("b").short("b")) + .arg( + Arg::with_name("x") + .short("x") + .required_unless_one(&["a", "b"]) + ).get_matches_from_safe(vec!["unlessone"]); + + assert!(!res.is_ok()); +} + +#[test] +fn required_unless_one_works_without() { + let res = App::new("unlessone") + .arg(Arg::with_name("a").conflicts_with("b").short("a")) + .arg(Arg::with_name("b").short("b")) + .arg( + Arg::with_name("x") + .required_unless_one(&["a", "b"]) + ).get_matches_from_safe(vec!["unlessone", "-a"]); + + assert!(res.is_ok()); +} + +#[test] +fn required_unless_one_works_with_long() { + let res = App::new("unlessone") + .arg(Arg::with_name("a").conflicts_with("b").short("a")) + .arg(Arg::with_name("b").short("b")) + .arg( + Arg::with_name("x") + .long("x_is_the_option") + .required_unless_one(&["a", "b"]) + ).get_matches_from_safe(vec!["unlessone", "-a"]); + + assert!(res.is_ok()); +} + +#[test] +fn required_unless_one_1() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .required_unless_one(&["dbg", "infile"]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .arg(Arg::with_name("infile") + .short("i") + .takes_value(true)) + .get_matches_from_safe(vec!["unlessone", "--debug"]); + + assert!(res.is_ok()); + let m = res.unwrap(); + assert!(!m.is_present("infile")); + assert!(!m.is_present("cfg")); + assert!(m.is_present("dbg")); +} + +#[test] +fn required_unless_one_err() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .required_unless_one(&["dbg", "infile"]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("dbg").long("debug")) + .arg(Arg::with_name("infile") + .short("i") + .takes_value(true)) + .get_matches_from_safe(vec!["unlessone"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn missing_required_output() { + assert!(test::compare_output(test::complex_app(), "clap-test -F", MISSING_REQ, true)); +} + +// Conditional external requirements + +#[test] +fn requires_if_present_val() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .requires_if("my.cfg", "extra") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra").long("extra")) + .get_matches_from_safe(vec!["unlessone", "--config=my.cfg"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn requires_if_present_mult() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra").long("extra")) + .arg(Arg::with_name("other").long("other")) + .get_matches_from_safe(vec!["unlessone", "--config=other.cfg"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn requires_if_present_mult_pass() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra").long("extra")) + .arg(Arg::with_name("other").long("other")) + .get_matches_from_safe(vec!["unlessone", "--config=some.cfg"]); + + assert!(res.is_ok()); + // assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn requires_if_present_val_no_present_pass() { + let res = App::new("unlessone") + .arg(Arg::with_name("cfg") + .requires_if("my.cfg", "extra") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra").long("extra")) + .get_matches_from_safe(vec!["unlessone"]); + + assert!(res.is_ok()); +} + +// Conditionally required + +#[test] +fn required_if_val_present_pass() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_if("extra", "val") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .get_matches_from_safe(vec!["ri", "--extra", "val", "--config", "my.cfg"]); + + assert!(res.is_ok()); +} + +#[test] +fn required_if_val_present_fail() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_if("extra", "val") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .get_matches_from_safe(vec!["ri", "--extra", "val"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn required_if_val_present_fail_error_output() { + let app = App::new("Test app") + .version("1.0") + .author("F0x06") + .about("Arg test") + .arg(Arg::with_name("target") + .takes_value(true) + .required(true) + .possible_values(&["file", "stdout"]) + .long("target")) + .arg(Arg::with_name("input") + .takes_value(true) + .required(true) + .long("input")) + .arg(Arg::with_name("output") + .takes_value(true) + .required_if("target", "file") + .long("output")); + + assert!(test::compare_output(app, + "test --input somepath --target file", + COND_REQ_IN_USAGE, + true)); +} + +#[test] +fn required_if_wrong_val() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_if("extra", "val") + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .get_matches_from_safe(vec!["ri", "--extra", "other"]); + + assert!(res.is_ok()); +} + +#[test] +fn required_ifs_val_present_pass() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_ifs(&[("extra", "val"), ("option", "spec")]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("option") + .takes_value(true) + .long("option")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .get_matches_from_safe(vec!["ri", "--option", "spec", "--config", "my.cfg"]); + + assert!(res.is_ok()); + // assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn required_ifs_val_present_fail() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_ifs(&[("extra", "val"), ("option", "spec")]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .arg(Arg::with_name("option") + .takes_value(true) + .long("option")) + .get_matches_from_safe(vec!["ri", "--option", "spec"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn required_ifs_wrong_val() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_ifs(&[("extra", "val"), ("option", "spec")]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .arg(Arg::with_name("option") + .takes_value(true) + .long("option")) + .get_matches_from_safe(vec!["ri", "--option", "other"]); + + assert!(res.is_ok()); +} + +#[test] +fn required_ifs_wrong_val_mult_fail() { + let res = App::new("ri") + .arg(Arg::with_name("cfg") + .required_ifs(&[("extra", "val"), ("option", "spec")]) + .takes_value(true) + .long("config")) + .arg(Arg::with_name("extra") + .takes_value(true) + .long("extra")) + .arg(Arg::with_name("option") + .takes_value(true) + .long("option")) + .get_matches_from_safe(vec!["ri", "--extra", "other", "--option", "spec"]); + + assert!(res.is_err()); + assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); +} + +#[test] +fn require_eq() { + let app = App::new("clap-test") + .version("v1.4.8") + .arg( + Arg::with_name("opt") + .long("opt") + .short("o") + .required(true) + .require_equals(true) + .value_name("FILE") + .help("some") + ); + assert!(test::compare_output(app, "clap-test", REQUIRE_EQUALS, true)); +} diff --git a/clap/tests/subcommands.rs b/clap/tests/subcommands.rs new file mode 100644 index 0000000..6257aaf --- /dev/null +++ b/clap/tests/subcommands.rs @@ -0,0 +1,216 @@ +extern crate clap; +extern crate regex; + +include!("../clap-test.rs"); + +use clap::{App, Arg, SubCommand, ErrorKind}; + +static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6 + +USAGE: + clap-test [SUBCOMMAND] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test Some help [aliases: dongle, done]"; + +static INVISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6 + +USAGE: + clap-test [SUBCOMMAND] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test Some help"; + +#[cfg(feature = "suggestions")] +static DYM_SUBCMD: &'static 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"; + +#[test] +fn subcommand() { + let m = App::new("test") + .subcommand(SubCommand::with_name("some") + .arg(Arg::with_name("test") + .short("t") + .long("test") + .takes_value(true) + .help("testing testing"))) + .arg(Arg::with_name("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(SubCommand::with_name("some") + .arg(Arg::with_name("test") + .short("t") + .long("test") + .takes_value(true) + .help("testing testing"))) + .arg(Arg::with_name("other").long("other")) + .get_matches_from(vec![""]); + + assert!(m.subcommand_name().is_none()); +} + +#[test] +fn subcommand_multiple() { + let m = App::new("test") + .subcommands(vec![ + SubCommand::with_name("some") + .arg(Arg::with_name("test") + .short("t") + .long("test") + .takes_value(true) + .help("testing testing")), + SubCommand::with_name("add") + .arg(Arg::with_name("roster").short("r")) + ]) + .arg(Arg::with_name("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 single_alias() { + let m = App::new("myprog") + .subcommand(SubCommand::with_name("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(SubCommand::with_name("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(SubCommand::with_name("subcmd")); + assert!(test::compare_output(app, "dym subcm", DYM_SUBCMD, true)); +} + +#[test] +#[cfg(feature="suggestions")] +fn subcmd_did_you_mean_output_arg() { + static EXPECTED: &'static 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'? + +USAGE: + dym [SUBCOMMAND] + +For more information try --help"; + + let app = App::new("dym") + .subcommand(SubCommand::with_name("subcmd") + .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'") ); + assert!(test::compare_output(app, "dym --subcmarg subcmd", EXPECTED, true)); +} + +#[test] +#[cfg(feature="suggestions")] +fn subcmd_did_you_mean_output_arg_false_positives() { + static EXPECTED: &'static str = "error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context + +USAGE: + dym [SUBCOMMAND] + +For more information try --help"; + + let app = App::new("dym") + .subcommand(SubCommand::with_name("subcmd") + .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'") ); + assert!(test::compare_output(app, "dym --subcmarg foo", EXPECTED, true)); +} + +#[test] +fn alias_help() { + let m = App::new("myprog") + .subcommand(SubCommand::with_name("test") + .alias("do-stuff")) + .get_matches_from_safe(vec!["myprog", "help", "do-stuff"]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn visible_aliases_help_output() { + let app = App::new("clap-test") + .version("2.6") + .subcommand(SubCommand::with_name("test") + .about("Some help") + .alias("invisible") + .visible_alias("dongle") + .visible_alias("done")); + assert!(test::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(SubCommand::with_name("test") + .about("Some help") + .alias("invisible")); + assert!(test::compare_output(app, "clap-test --help", INVISIBLE_ALIAS_HELP, false)); +} + +#[test] +fn issue_1031_args_with_same_name() { + let res = App::new("prog") + .arg(Arg::from_usage("--ui-path=<PATH>")) + .subcommand(SubCommand::with_name("signer")) + .get_matches_from_safe(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_usage("--ui-path=<PATH>")) + .subcommand(SubCommand::with_name("signer")) + .get_matches_from_safe(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")); +} diff --git a/clap/tests/template_help.rs b/clap/tests/template_help.rs new file mode 100644 index 0000000..b1a546a --- /dev/null +++ b/clap/tests/template_help.rs @@ -0,0 +1,117 @@ +extern crate clap; +extern crate regex; + +use clap::{App, SubCommand}; + +include!("../clap-test.rs"); + +static EXAMPLE1_TMPL_S : &'static str = include_str!("example1_tmpl_simple.txt"); +static EXAMPLE1_TMPS_F : &'static str = include_str!("example1_tmpl_full.txt"); + +static CUSTOM_TEMPL_HELP: &'static str = "MyApp 1.0 +Kevin K. <kbknapp@gmail.com> +Does awesome things + +USAGE: + MyApp [FLAGS] [OPTIONS] <output> [SUBCOMMAND] + +FLAGS: + -d Turn debugging information on + -h, --help Prints help information + -V, --version Prints version information +OPTIONS: + -c, --config <FILE> Sets a custom config file +ARGS: + <output> Sets an optional output file +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test does testing things"; + +static SIMPLE_TEMPLATE: &'static str = "MyApp 1.0 +Kevin K. <kbknapp@gmail.com> +Does awesome things + +USAGE: + MyApp [FLAGS] [OPTIONS] <output> [SUBCOMMAND] + +FLAGS: + -d Turn debugging information on + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -c, --config <FILE> Sets a custom config file + +ARGS: + <output> Sets an optional output file + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test does testing things"; + +#[test] +fn with_template() { + let app = app_example1().template(EXAMPLE1_TMPL_S); + assert!(test::compare_output(app, "MyApp --help", SIMPLE_TEMPLATE, false)); +} + +#[test] +fn custom_template() { + let app = app_example1().template(EXAMPLE1_TMPS_F); + assert!(test::compare_output(app, "MyApp --help", CUSTOM_TEMPL_HELP, false)); +} + +#[test] +fn template_empty() { + let app = App::new("MyApp") + .version("1.0") + .author("Kevin K. <kbknapp@gmail.com>") + .about("Does awesome things") + .template(""); + assert!(test::compare_output(app, "MyApp --help", "", false)); +} + +#[test] +fn template_notag() { + let app = App::new("MyApp") + .version("1.0") + .author("Kevin K. <kbknapp@gmail.com>") + .about("Does awesome things") + .template("test no tag test"); + assert!(test::compare_output(app, "MyApp --help", "test no tag test", false)); +} + +#[test] +fn template_unknowntag() { + let app = App::new("MyApp") + .version("1.0") + .author("Kevin K. <kbknapp@gmail.com>") + .about("Does awesome things") + .template("test {unknown_tag} test"); + assert!(test::compare_output(app, "MyApp --help", "test {unknown_tag} test", false)); +} + +#[test] +fn template_author_version() { + let app = App::new("MyApp") + .version("1.0") + .author("Kevin K. <kbknapp@gmail.com>") + .about("Does awesome things") + .template("{author}\n{version}\n{about}\n{bin}"); + assert!(test::compare_output(app, "MyApp --help", "Kevin K. <kbknapp@gmail.com>\n1.0\nDoes awesome things\nMyApp", false)); +} + +// ---------- + +fn app_example1<'b, 'c>() -> App<'b, 'c> { + App::new("MyApp") + .version("1.0") + .author("Kevin K. <kbknapp@gmail.com>") + .about("Does awesome things") + .args_from_usage("-c, --config=[FILE] 'Sets a custom config file' + <output> 'Sets an optional output file' + -d... 'Turn debugging information on'") + .subcommand(SubCommand::with_name("test") + .about("does testing things") + .arg_from_usage("-l, --list 'lists test values'")) +} diff --git a/clap/tests/tests.rs b/clap/tests/tests.rs new file mode 100644 index 0000000..0ad825a --- /dev/null +++ b/clap/tests/tests.rs @@ -0,0 +1,435 @@ +#[macro_use] +extern crate clap; +extern crate regex; + +use std::io::Write; +use std::str; + +include!("../clap-test.rs"); + +use clap::{App, Arg}; + +static SCF2OP: &'static str = "flag present 2 times +option NOT present +positional NOT present +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option NOT present +positional NOT present +subcmd present +flag present 2 times +scoption present with value: some +An scoption: some +scpositional present with value: value +"; + +static SCFOP: &'static str = "flag present 1 times +option NOT present +positional NOT present +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option NOT present +positional NOT present +subcmd present +flag present 1 times +scoption present with value: some +An scoption: some +scpositional present with value: value +"; + +static O2P: &'static str = "flag NOT present +option present 2 times with value: some +An option: some +An option: other +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 2 times with value: some +An option: some +An option: other +positional present with value: value +subcmd NOT present +"; + +static F2OP: &'static str = "flag present 2 times +option present 1 times with value: some +An option: some +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 1 times with value: some +An option: some +positional present with value: value +subcmd NOT present +"; + +static FOP: &'static str = "flag present 1 times +option present 1 times with value: some +An option: some +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 1 times with value: some +An option: some +positional present with value: value +subcmd NOT present +"; + +pub fn check_complex_output(args: &str, out: &str) { + let mut w = vec![]; + let matches = test::complex_app().get_matches_from(args.split(' ').collect::<Vec<_>>()); + if matches.is_present("flag") { + writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap(); + } else { + writeln!(w, "flag NOT present").unwrap(); + } + + if matches.is_present("option") { + if let Some(v) = matches.value_of("option") { + writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap(); + } + if let Some(ov) = matches.values_of("option") { + for o in ov { + writeln!(w, "An option: {}", o).unwrap(); + } + } + } else { + writeln!(w, "option NOT present").unwrap(); + } + + if let Some(p) = matches.value_of("positional") { + writeln!(w, "positional present with value: {}", p).unwrap(); + } else { + writeln!(w, "positional NOT present").unwrap(); + } + + if matches.is_present("flag2") { + writeln!(w, "flag2 present").unwrap(); + writeln!(w, "option2 present with value of: {}", matches.value_of("long-option-2").unwrap()).unwrap(); + writeln!(w, "positional2 present with value of: {}", matches.value_of("positional2").unwrap()).unwrap(); + } else { + writeln!(w, "flag2 NOT present").unwrap(); + writeln!(w, "option2 maybe present with value of: {}", matches.value_of("long-option-2").unwrap_or("Nothing")).unwrap(); + writeln!(w, "positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing")).unwrap(); + } + + let _ = match matches.value_of("Option3").unwrap_or("") { + "fast" => writeln!(w, "option3 present quickly"), + "slow" => writeln!(w, "option3 present slowly"), + _ => writeln!(w, "option3 NOT present") + }; + + let _ = match matches.value_of("positional3").unwrap_or("") { + "vi" => writeln!(w, "positional3 present in vi mode"), + "emacs" => writeln!(w, "positional3 present in emacs mode"), + _ => writeln!(w, "positional3 NOT present") + }; + + if matches.is_present("option") { + if let Some(v) = matches.value_of("option") { + writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap(); + } + if let Some(ov) = matches.values_of("option") { + for o in ov { + writeln!(w, "An option: {}", o).unwrap(); + } + } + } else { + writeln!(w, "option NOT present").unwrap(); + } + + if let Some(p) = matches.value_of("positional") { + writeln!(w, "positional present with value: {}", p).unwrap(); + } else { + writeln!(w, "positional NOT present").unwrap(); + } + if matches.is_present("subcmd") { + writeln!(w, "subcmd present").unwrap(); + if let Some(matches) = matches.subcommand_matches("subcmd") { + if matches.is_present("flag") { + writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap(); + } else { + writeln!(w, "flag NOT present").unwrap(); + } + + if matches.is_present("option") { + if let Some(v) = matches.value_of("option") { + writeln!(w, "scoption present with value: {}", v).unwrap(); + } + if let Some(ov) = matches.values_of("option") { + for o in ov { + writeln!(w, "An scoption: {}", o).unwrap(); + } + } + } else { + writeln!(w, "scoption NOT present").unwrap(); + } + + if let Some(p) = matches.value_of("scpositional") { + writeln!(w, "scpositional present with value: {}", p).unwrap(); + } + } + } else { + writeln!(w, "subcmd NOT present").unwrap(); + } + + let res = str::from_utf8(&w).unwrap(); + assert_eq!(res, out); +} + +arg_enum!{ + #[derive(Debug)] + enum Val1 { + ValOne, + ValTwo + } +} +arg_enum!{ + #[derive(Debug)] + pub enum Val2 { + ValOne, + ValTwo + } +} +arg_enum!{ + enum Val3 { + ValOne, + ValTwo + } +} +arg_enum!{ + pub enum Val4 { + ValOne, + ValTwo + } +} + +#[test] +fn test_enums() { + let v1_lower = "valone"; + let v1_camel = "ValOne"; + + let v1_lp = v1_lower.parse::<Val1>().unwrap(); + let v1_cp = v1_camel.parse::<Val1>().unwrap(); + match v1_lp { + Val1::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + match v1_cp { + Val1::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + let v1_lp = v1_lower.parse::<Val2>().unwrap(); + let v1_cp = v1_camel.parse::<Val2>().unwrap(); + match v1_lp { + Val2::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + match v1_cp { + Val2::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + let v1_lp = v1_lower.parse::<Val3>().unwrap(); + let v1_cp = v1_camel.parse::<Val3>().unwrap(); + match v1_lp { + Val3::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + match v1_cp { + Val3::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + let v1_lp = v1_lower.parse::<Val4>().unwrap(); + let v1_cp = v1_camel.parse::<Val4>().unwrap(); + match v1_lp { + Val4::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } + match v1_cp { + Val4::ValOne => (), + _ => panic!("Val1 didn't parse correctly"), + } +} + +#[test] +fn create_app() { + let _ = + App::new("test").version("1.0").author("kevin").about("does awesome things").get_matches_from(vec![""]); +} + +#[test] +fn add_multiple_arg() { + let _ = App::new("test") + .args(&[ + Arg::with_name("test").short("s"), + Arg::with_name("test2").short("l")]) + .get_matches_from(vec![""]); +} +#[test] +fn flag_x2_opt() { + check_complex_output("clap-test value -f -f -o some", +"flag present 2 times +option present 1 times with value: some +An option: some +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 1 times with value: some +An option: some +positional present with value: value +subcmd NOT present +"); +} + +#[test] +fn long_opt_x2_pos() { + check_complex_output("clap-test value --option some --option other", O2P); +} + +#[test] +fn long_opt_eq_x2_pos() { + check_complex_output("clap-test value --option=some --option=other", O2P); +} + +#[test] +fn short_opt_x2_pos() { + check_complex_output("clap-test value -o some -o other", O2P); +} + +#[test] +fn short_opt_eq_x2_pos() { + check_complex_output("clap-test value -o=some -o=other", O2P); +} + +#[test] +fn short_flag_x2_comb_short_opt_pos() { + check_complex_output("clap-test value -ff -o some", F2OP); +} + +#[test] +fn short_flag_short_opt_pos() { + check_complex_output("clap-test value -f -o some", FOP); +} + +#[test] +fn long_flag_long_opt_pos() { + check_complex_output("clap-test value --flag --option some", FOP); +} + +#[test] +fn long_flag_long_opt_eq_pos() { + check_complex_output("clap-test value --flag --option=some", FOP); +} + +#[test] +fn sc_long_flag_long_opt() { + check_complex_output("clap-test subcmd value --flag --option some", SCFOP); +} + +#[test] +fn sc_long_flag_short_opt_pos() { + check_complex_output("clap-test subcmd value --flag -o some", SCFOP); +} + +#[test] +fn sc_long_flag_long_opt_eq_pos() { + check_complex_output("clap-test subcmd value --flag --option=some", SCFOP); +} + +#[test] +fn sc_short_flag_long_opt_pos() { + check_complex_output("clap-test subcmd value -f --option some", SCFOP); +} + +#[test] +fn sc_short_flag_short_opt_pos() { + check_complex_output("clap-test subcmd value -f -o some", SCFOP); +} + +#[test] +fn sc_short_flag_short_opt_eq_pos() { + check_complex_output("clap-test subcmd value -f -o=some", SCFOP); +} + +#[test] +fn sc_short_flag_long_opt_eq_pos() { + check_complex_output("clap-test subcmd value -f --option=some", SCFOP); +} + +#[test] +fn sc_short_flag_x2_comb_long_opt_pos() { + check_complex_output("clap-test subcmd value -ff --option some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_comb_short_opt_pos() { + check_complex_output("clap-test subcmd value -ff -o some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_comb_long_opt_eq_pos() { + check_complex_output("clap-test subcmd value -ff --option=some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_comb_short_opt_eq_pos() { + check_complex_output("clap-test subcmd value -ff -o=some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_long_opt_pos() { + check_complex_output("clap-test subcmd value --flag --flag --option some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_short_opt_pos() { + check_complex_output("clap-test subcmd value --flag --flag -o some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_short_opt_eq_pos() { + check_complex_output("clap-test subcmd value --flag --flag -o=some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_long_opt_eq_pos() { + check_complex_output("clap-test subcmd value --flag --flag --option=some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_long_opt_pos() { + check_complex_output("clap-test subcmd value -f -f --option some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_short_opt_pos() { + check_complex_output("clap-test subcmd value -f -f -o some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_short_opt_eq_pos() { + check_complex_output("clap-test subcmd value -f -f -o=some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_long_opt_eq_pos() { + check_complex_output("clap-test subcmd value -f -f --option=some", SCF2OP); +} diff --git a/clap/tests/unique_args.rs b/clap/tests/unique_args.rs new file mode 100644 index 0000000..8710248 --- /dev/null +++ b/clap/tests/unique_args.rs @@ -0,0 +1,22 @@ +extern crate clap; + +use clap::{App, Arg}; + +#[test] +#[should_panic] +fn unique_arg_names() { + App::new("some").args(&[Arg::with_name("arg").short("a"), Arg::with_name("arg").short("b")]); +} + +#[test] +#[should_panic] +fn unique_arg_shorts() { + App::new("some").args(&[Arg::with_name("arg1").short("a"), Arg::with_name("arg2").short("a")]); +} + +#[test] +#[should_panic] +fn unique_arg_longs() { + App::new("some") + .args(&[Arg::with_name("arg1").long("long"), Arg::with_name("arg2").long("long")]); +} diff --git a/clap/tests/utf8.rs b/clap/tests/utf8.rs new file mode 100644 index 0000000..dfa382e --- /dev/null +++ b/clap/tests/utf8.rs @@ -0,0 +1,223 @@ +#![cfg(not(windows))] + +extern crate clap; + +use std::ffi::OsString; +use std::os::unix::ffi::OsStringExt; +use clap::{App, Arg, AppSettings, ErrorKind}; + +#[test] +fn invalid_utf8_strict_positional() { + let m = App::new("bad_utf8") + .arg(Arg::from_usage("<arg> 'some arg'")) + .setting(AppSettings::StrictUtf8) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0xe9])]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); +} + +#[test] +fn invalid_utf8_strict_option_short_space() { + let m = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .setting(AppSettings::StrictUtf8) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from("-a"), + OsString::from_vec(vec![0xe9])]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); +} + +#[test] +fn invalid_utf8_strict_option_short_equals() { + let m = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .setting(AppSettings::StrictUtf8) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); +} + +#[test] +fn invalid_utf8_strict_option_short_no_space() { + let m = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .setting(AppSettings::StrictUtf8) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x61, 0xe9])]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); +} + +#[test] +fn invalid_utf8_strict_option_long_space() { + let m = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .setting(AppSettings::StrictUtf8) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from("--arg"), + OsString::from_vec(vec![0xe9])]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); +} + +#[test] +fn invalid_utf8_strict_option_long_equals() { + let m = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .setting(AppSettings::StrictUtf8) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); +} + +#[test] +fn invalid_utf8_lossy_positional() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("<arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}"); +} + +#[test] +fn invalid_utf8_lossy_option_short_space() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from("-a"), + OsString::from_vec(vec![0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}"); +} + +#[test] +fn invalid_utf8_lossy_option_short_equals() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}"); +} + +#[test] +fn invalid_utf8_lossy_option_short_no_space() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x61, 0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}"); +} + +#[test] +fn invalid_utf8_lossy_option_long_space() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from("--arg"), + OsString::from_vec(vec![0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}"); +} + +#[test] +fn invalid_utf8_lossy_option_long_equals() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}"); +} + +#[test] +fn invalid_utf8_positional() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("<arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); +} + +#[test] +fn invalid_utf8_option_short_space() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from("-a"), + OsString::from_vec(vec![0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); +} + +#[test] +fn invalid_utf8_option_short_equals() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); +} + +#[test] +fn invalid_utf8_option_short_no_space() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x61, 0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); +} + +#[test] +fn invalid_utf8_option_long_space() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from("--arg"), + OsString::from_vec(vec![0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); +} + +#[test] +fn invalid_utf8_option_long_equals() { + let r = App::new("bad_utf8") + .arg(Arg::from_usage("-a, --arg <arg> 'some arg'")) + .get_matches_from_safe(vec![OsString::from(""), + OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]); + assert!(r.is_ok()); + let m = r.unwrap(); + assert!(m.is_present("arg")); + assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9])); +} diff --git a/clap/tests/version-numbers.rs b/clap/tests/version-numbers.rs new file mode 100644 index 0000000..411eea5 --- /dev/null +++ b/clap/tests/version-numbers.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate version_sync; + +#[test] +fn test_readme_deps() { + assert_markdown_deps_updated!("README.md"); +} + +#[test] +fn test_html_root_url() { + assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/clap/tests/version.rs b/clap/tests/version.rs new file mode 100644 index 0000000..8bbd474 --- /dev/null +++ b/clap/tests/version.rs @@ -0,0 +1,58 @@ +extern crate clap; +extern crate regex; + +use std::str; + +use clap::{App, Arg, ErrorKind}; + +include!("../clap-test.rs"); + +static VERSION: &'static str = "clap-test v1.4.8"; + +#[test] +fn version_short() { + let m = App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .get_matches_from_safe(vec!["myprog", "-V"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::VersionDisplayed); +} + +#[test] +fn version_long() { + let m = App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .get_matches_from_safe(vec!["myprog", "--version"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::VersionDisplayed); +} + +#[test] +fn complex_version_output() { + let mut a = App::new("clap-test").version("v1.4.8"); + let _ = a.get_matches_from_safe_borrow(vec![""]); + + // Now we check the output of print_version() + let mut ver = vec![]; + a.write_version(&mut ver).unwrap(); + assert_eq!(str::from_utf8(&ver).unwrap(), VERSION); +} + +#[test] +fn override_ver() { + let m = App::new("test") + .author("Kevin K.") + .about("tests stuff") + .version("1.3") + .arg(Arg::from_usage("-v, --version 'some version'")) + .get_matches_from_safe(vec!["test", "--version"]); + + assert!(m.is_ok()); + assert!(m.unwrap().is_present("version")); +} diff --git a/clap/tests/yaml.rs b/clap/tests/yaml.rs new file mode 100644 index 0000000..279b987 --- /dev/null +++ b/clap/tests/yaml.rs @@ -0,0 +1,40 @@ +#![cfg(feature="yaml")] + +#[macro_use] +extern crate clap; + +use clap::App; + +#[test] +fn create_app_from_yaml() { + let yml = load_yaml!("app.yml"); + App::from_yaml(yml); +} + +#[test] +fn help_message() { + let yml = load_yaml!("app.yml"); + let mut app = App::from_yaml(yml); + // Generate the full help message! + let _ = app.get_matches_from_safe_borrow(Vec::<String>::new()); + + let mut help_buffer = Vec::new(); + app.write_help(&mut help_buffer).unwrap(); + let help_string = String::from_utf8(help_buffer).unwrap(); + assert!(help_string.contains( + "-h, --help prints help with a nonstandard description\n")); +} + +#[test] +fn author() { + let yml = load_yaml!("app.yml"); + let mut app = App::from_yaml(yml); + // Generate the full help message! + let _ = app.get_matches_from_safe_borrow(Vec::<String>::new()); + + let mut help_buffer = Vec::new(); + app.write_help(&mut help_buffer).unwrap(); + let help_string = String::from_utf8(help_buffer).unwrap(); + assert!(help_string.contains( + "Kevin K. <kbknapp@gmail.com>")); +} |