use super::AppError;
use conc::{RunArgs, Show, shell_executable};
#[derive(Debug)]
pub enum Command {
Help,
Run(RunArgs),
Version,
}
pub fn parse<SI: Iterator<Item = String>>(args: SI) -> Result<Command, AppError> {
let mut executables = vec![];
let mut show = Show::All;
let mut error_on_output = false;
let mut parse_flags = true; for arg in args {
if arg == "--" {
parse_flags = false;
continue;
}
if !arg.starts_with('-') {
parse_flags = false;
}
if parse_flags && arg.starts_with('-') {
match arg.as_ref() {
"--error-on-output" => error_on_output = true,
"--help" | "-h" => return Ok(Command::Help),
"--show=all" | "--show" => show = Show::All,
"--show=names" => show = Show::Names,
"--show=failed" => show = Show::Failed,
"--version" | "-V" => return Ok(Command::Version),
_ => return Err(AppError::UnknownFlag(arg)),
}
continue;
}
executables.push(shell_executable(arg));
}
Ok(Command::Run(RunArgs {
executables,
error_on_output,
show,
}))
}
#[cfg(test)]
mod tests {
mod parse {
use super::super::*;
use big_s::S;
#[test]
fn single_command() {
let give = vec![S("echo hello world")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![shell_executable("echo hello world")],
error_on_output: false,
show: Show::All,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn multiple_commands() {
let give = vec![S("echo hello"), S("ls -la"), S("pwd")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![
shell_executable("echo hello"),
shell_executable("ls -la"),
shell_executable("pwd"),
],
error_on_output: false,
show: Show::All,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn empty() {
let give = vec![].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![],
error_on_output: false,
show: Show::All,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn show_commands() {
let give = vec![S("--show=names"), S("echo hello")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![shell_executable("echo hello")],
error_on_output: false,
show: Show::Names,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn show_all() {
let give = vec![S("--show=all"), S("echo hello")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![shell_executable("echo hello")],
error_on_output: false,
show: Show::All,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn unknown_flag() {
let give = vec![S("--zonk"), S("echo hello")].into_iter();
let have = parse(give);
let want: Result<Command, AppError> = Err(AppError::UnknownFlag(S("--zonk")));
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn manually_end_flags_section() {
let give = vec![S("--show"), S("--"), S("echo hello")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![shell_executable("echo hello")],
error_on_output: false,
show: Show::All,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn help_long() {
let give = vec![S("--help")].into_iter();
let have = parse(give).unwrap();
let want = Command::Help;
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn help_short() {
let give = vec![S("-h")].into_iter();
let have = parse(give).unwrap();
let want = Command::Help;
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn version_short() {
let give = vec![S("-V")].into_iter();
let have = parse(give).unwrap();
let want = Command::Version;
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn version_long() {
let give = vec![S("--version")].into_iter();
let have = parse(give).unwrap();
let want = Command::Version;
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn error_on_output() {
let give = vec![S("--error-on-output"), S("echo hello")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![shell_executable("echo hello")],
error_on_output: true,
show: Show::All,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
#[test]
fn error_on_output_with_show_failed() {
let give = vec![S("--error-on-output"), S("--show=names"), S("echo hello")].into_iter();
let have = parse(give).unwrap();
let want = Command::Run(RunArgs {
executables: vec![shell_executable("echo hello")],
error_on_output: true,
show: Show::Names,
});
assert_eq!(format!("{have:?}"), format!("{want:?}"));
}
}
}