From 5e20a29b4fdc8a2d442d1093681b396dcb4b816b Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 7 Jan 2020 11:18:04 +0000 Subject: Add structopt dependency in version 0.3.7 This patch series replaces argparse with structopt in the argument handling code. As a first step, we need structopt as a dependency. Import subrepo structopt/:structopt at efbdda4753592e27bc430fb01f7b9650b2f3174d Import subrepo bitflags/:bitflags at 30668016aca6bd3b02c766e8347e0b4080d4c296 Import subrepo clap/:clap at 784524f7eb193e35f81082cc69454c8c21b948f7 Import subrepo heck/:heck at 093d56fbf001e1506e56dbfa38631d99b1066df1 Import subrepo proc-macro-error/:proc-macro-error at 6c4cfe79a622c5de8ae68557993542be46eacae2 Import subrepo proc-macro2/:proc-macro2 at d5d48eddca4566e5438e8a2cbed4a74e049544de Import subrepo quote/:quote at 727436c6c137b20f0f34dde5d8fda2679b9747ad Import subrepo rustversion/:rustversion at 0c5663313516263059ce9059ef81fc7a1cf655ca Import subrepo syn-mid/:syn-mid at 5d3d85414a9e6674e1857ec22a87b96e04a6851a Import subrepo syn/:syn at e87c27e87f6f4ef8919d0372bdb056d53ef0d8f3 Import subrepo textwrap/:textwrap at abcd618beae3f74841032aa5b53c1086b0a57ca2 Import subrepo unicode-segmentation/:unicode-segmentation at 637c9874c4fe0c205ff27787faf150a40295c6c3 Import subrepo unicode-width/:unicode-width at 3033826f8bf05e82724140a981d5941e48fce393 Import subrepo unicode-xid/:unicode-xid at 4baae9fffb156ba229665b972a9cd5991787ceb7 --- clap/tests/require.rs | 688 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) create mode 100644 clap/tests/require.rs (limited to 'clap/tests/require.rs') 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= + +USAGE: + clap-test --opt= + +For more information try --help"; + +static MISSING_REQ: &'static str = "error: The following required arguments were not provided: + + --long-option-2 + +USAGE: + clap-test -F --long-option-2 + +For more information try --help"; + +static COND_REQ_IN_USAGE: &'static str = "error: The following required arguments were not provided: + --output + +USAGE: + test --input --output --target + +For more information try --help"; + +static ISSUE_1158: &'static str = "error: The following required arguments were not provided: + -x + -y + -z + +USAGE: + example [OPTIONS] -x -y -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)); +} -- cgit v1.2.1