use clap::{value_parser, Arg, Command};
use clap_complete::Shell;
fn build_cli() -> Command {
Command::new("stama")
.about(env!("CARGO_PKG_DESCRIPTION"))
.version(env!("CARGO_PKG_VERSION"))
.arg(
Arg::new("output-file")
.short('o')
.long("output-file")
.value_name("FILE")
.help("Sets the output file path"),
)
.arg(
Arg::new("completions")
.long("completions")
.value_name("SHELL")
.value_parser(value_parser!(Shell))
.help("Print a shell completion script to stdout and exit"),
)
}
pub fn parse_args() -> Option<String> {
let matches = build_cli().get_matches();
if let Some(shell) = matches.get_one::<Shell>("completions") {
let mut cmd = build_cli();
clap_complete::generate(*shell, &mut cmd, "stama", &mut std::io::stdout());
std::process::exit(0);
}
matches.get_one::<String>("output-file").cloned()
}
pub fn write_output_file(output_file: Option<&str>, content: &str) {
if let Some(output_file) = output_file {
if let Err(err) = std::fs::write(output_file, content) {
eprintln!("Unable to write output file '{}': {}", output_file, err);
}
} else {
println!("It seems that you didn't provide an output file path. The content will be printed to the console instead:");
println!("{}", content);
println!("For more information on how to execute the command automatically, please refer to the documentation:");
println!("GitHub: https://github.com/Gordi42/stama");
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn cli_definition_is_valid() {
build_cli().debug_assert();
}
#[test]
fn parses_output_file_short_flag() {
let matches = build_cli()
.try_get_matches_from(["stama", "-o", "/tmp/out.txt"])
.unwrap();
assert_eq!(
matches.get_one::<String>("output-file").map(String::as_str),
Some("/tmp/out.txt")
);
}
#[test]
fn parses_output_file_long_flag() {
let matches = build_cli()
.try_get_matches_from(["stama", "--output-file=/tmp/out.txt"])
.unwrap();
assert_eq!(
matches.get_one::<String>("output-file").map(String::as_str),
Some("/tmp/out.txt")
);
}
#[test]
fn parses_completions_shells() {
for (name, shell) in [
("bash", Shell::Bash),
("zsh", Shell::Zsh),
("fish", Shell::Fish),
] {
let matches = build_cli()
.try_get_matches_from(["stama", "--completions", name])
.unwrap();
assert_eq!(matches.get_one::<Shell>("completions"), Some(&shell));
}
}
#[test]
fn rejects_unknown_shell() {
assert!(build_cli()
.try_get_matches_from(["stama", "--completions", "tcsh"])
.is_err());
}
#[test]
fn generates_zsh_completion_script() {
let mut cmd = build_cli();
let mut buffer = Vec::new();
clap_complete::generate(Shell::Zsh, &mut cmd, "stama", &mut buffer);
let script = String::from_utf8(buffer).unwrap();
assert!(script.starts_with("#compdef stama"));
assert!(script.contains("--output-file"));
assert!(script.contains("--completions"));
}
#[test]
fn write_output_file_writes_content() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("output.txt");
let path_str = path.to_str().unwrap();
write_output_file(Some(path_str), "cd /some/path");
assert_eq!(std::fs::read_to_string(&path).unwrap(), "cd /some/path");
}
}