diff --git a/clap_complete/tests/testsuite/dynamic.rs b/clap_complete/tests/testsuite/dynamic.rs index 8a2d9e466b43..ae73482ad1a8 100644 --- a/clap_complete/tests/testsuite/dynamic.rs +++ b/clap_complete/tests/testsuite/dynamic.rs @@ -1,34 +1,69 @@ #![cfg(feature = "unstable-dynamic")] +macro_rules! assert_completion { + ($cmd:expr, $input:expr, $(current_dir = $current_dir:expr,)? [$($comp:expr $(=> $help:expr)?),+]) => { + let mut args = vec![std::ffi::OsString::from($cmd.get_name())]; + let arg_index; + + if let Some((prior, after)) = $input.split_once("[TAB]") { + args.extend(prior.split_whitespace().map(From::from)); + if prior.ends_with(char::is_whitespace) { + args.push(std::ffi::OsString::default()) + } + arg_index = args.len() - 1; + // TODO when we can handle [TAB] inside of tokens, we need to update this + args.extend(after.split_whitespace().map(From::from)); + } else { + args.extend($input.split_whitespace().map(From::from)); + if $input.ends_with(char::is_whitespace) { + args.push(std::ffi::OsString::default()) + } + arg_index = args.len() - 1; + } + + let current_dir = None; + $(let current_dir = $current_dir;)? + + let mut completions = + clap_complete::dynamic::complete(&mut $cmd, args, arg_index, current_dir).unwrap(); + + $( + #[allow(unused)] + 'block: { + let (comp, help) = completions.remove(0); + assert_eq!(comp.to_string_lossy(), $comp); + $( + assert_eq!(help.unwrap().to_string(), $help, "Expected `{}` to have help message `{}`.", $comp, $help); + break 'block; + )? + assert!( + help.is_none(), + "Expected `{}` to not have help message `{}`.", + $comp, + help.unwrap() + ); + } + )+ + assert!(completions.is_empty(), "{completions:?}") + }; +} + +const HELP: &str = "Print this message or the help of the given subcommand(s)"; +const HELP_SHORT: &str = "Print help"; + #[test] fn suggest_subcommand_subset() { - let name = "exhaustive"; - let mut cmd = clap::Command::new(name) + let mut cmd = clap::Command::new("exhaustive") .subcommand(clap::Command::new("hello-world")) .subcommand(clap::Command::new("hello-moon")) .subcommand(clap::Command::new("goodbye-world")); - let args = [name, "he"]; - let arg_index = 1; - let args = IntoIterator::into_iter(args) - .map(std::ffi::OsString::from) - .collect::>(); - let current_dir = None; - - let completions = - clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); - let completions = completions - .into_iter() - .map(|s| s.0.to_string_lossy().into_owned()) - .collect::>(); - - assert_eq!(completions, ["hello-moon", "hello-world", "help"]); + assert_completion!(cmd, "he", ["hello-moon", "hello-world", "help" => HELP]); } #[test] fn suggest_long_flag_subset() { - let name = "exhaustive"; - let mut cmd = clap::Command::new(name) + let mut cmd = clap::Command::new("exhaustive") .arg( clap::Arg::new("hello-world") .long("hello-world") @@ -45,21 +80,7 @@ fn suggest_long_flag_subset() { .action(clap::ArgAction::Count), ); - let args = [name, "--he"]; - let arg_index = 1; - let args = IntoIterator::into_iter(args) - .map(std::ffi::OsString::from) - .collect::>(); - let current_dir = None; - - let completions = - clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); - let completions = completions - .into_iter() - .map(|s| s.0.to_string_lossy().into_owned()) - .collect::>(); - - assert_eq!(completions, ["--hello-world", "--hello-moon", "--help"]); + assert_completion!(cmd, "--he", ["--hello-world", "--hello-moon", "--help" => HELP_SHORT]); } #[test] @@ -71,27 +92,12 @@ fn suggest_possible_value_subset() { "goodbye-world", ])); - let args = [name, "hello"]; - let arg_index = 1; - let args = IntoIterator::into_iter(args) - .map(std::ffi::OsString::from) - .collect::>(); - let current_dir = None; - - let completions = - clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); - let completions = completions - .into_iter() - .map(|s| s.0.to_string_lossy().into_owned()) - .collect::>(); - - assert_eq!(completions, ["hello-world", "hello-moon"]); + assert_completion!(cmd, "hello", ["hello-world", "hello-moon"]); } #[test] fn suggest_additional_short_flags() { - let name = "exhaustive"; - let mut cmd = clap::Command::new(name) + let mut cmd = clap::Command::new("exhaustive") .arg( clap::Arg::new("a") .short('a') @@ -108,19 +114,5 @@ fn suggest_additional_short_flags() { .action(clap::ArgAction::Count), ); - let args = [name, "-a"]; - let arg_index = 1; - let args = IntoIterator::into_iter(args) - .map(std::ffi::OsString::from) - .collect::>(); - let current_dir = None; - - let completions = - clap_complete::dynamic::complete(&mut cmd, args, arg_index, current_dir).unwrap(); - let completions = completions - .into_iter() - .map(|s| s.0.to_string_lossy().into_owned()) - .collect::>(); - - assert_eq!(completions, ["-aa", "-ab", "-ac", "-ah"]); + assert_completion!(cmd, "-a", ["-aa", "-ab", "-ac", "-ah" => HELP_SHORT]); }