#[derive(Debug, clap::Args)]
pub struct FlushArgs {
#[arg(required_unless_present = "daemon", conflicts_with = "daemon")]
pub selector: Option<String>,
#[arg(long)]
pub daemon: bool,
}
#[derive(Debug, clap::Args)]
pub struct BarksArgs {
#[arg(long)]
pub tail: Option<usize>,
}
const DEFAULT_SELECTOR: &str = "all";
pub const DEFAULT_BLEAT_LINES: usize = 15;
#[derive(Debug, clap::Args)]
pub struct BleatsArgs {
#[arg(default_value = DEFAULT_SELECTOR)]
pub selector: String,
#[arg(long)]
pub no_follow: bool,
#[arg(long, default_value_t = DEFAULT_BLEAT_LINES, value_name = "N")]
pub lines: usize,
#[arg(long, conflicts_with = "out")]
pub err: bool,
#[arg(long, conflicts_with = "err")]
pub out: bool,
}
#[derive(Debug, clap::Args)]
pub struct ReopenArgs {
#[arg(default_value = DEFAULT_SELECTOR)]
pub selector: String,
}
#[cfg(test)]
mod tests {
use crate::cli::{Cli, Commands};
#[test]
fn bleats_and_reopen_default_to_every_sheep() {
use clap::Parser;
let bare = Cli::try_parse_from(["shep", "reopen"]).unwrap().command;
let Commands::Reopen(args) = bare else {
panic!("`shep reopen` must parse with no selector")
};
assert_eq!(args.selector, "all");
let bare = Cli::try_parse_from(["shep", "bleats"]).unwrap().command;
let Commands::Bleats(args) = bare else {
panic!("`shep bleats` must parse with no selector")
};
assert_eq!(args.selector, "all");
let named = Cli::try_parse_from(["shep", "reopen", "web"])
.unwrap()
.command;
let Commands::Reopen(args) = named else {
panic!("expected reopen")
};
assert_eq!(args.selector, "web");
}
#[test]
fn flush_refuses_to_run_without_a_selector() {
use clap::Parser;
assert!(
Cli::try_parse_from(["shep", "flush"]).is_err(),
"`shep flush` with no selector must be a usage error, never the \
whole flock"
);
let named = Cli::try_parse_from(["shep", "flush", "all"])
.unwrap()
.command;
let Commands::Flush(args) = named else {
panic!("expected flush")
};
assert_eq!(args.selector.as_deref(), Some("all"));
assert!(
!args.daemon,
"a plain flush must not reach the shepherd's own logs"
);
}
#[test]
fn the_daemon_flag_replaces_the_selector_rather_than_riding_along_with_it() {
use clap::Parser;
let bare = Cli::try_parse_from(["shep", "flush", "--daemon"])
.expect("`shep flush --daemon` is the only spelling there is")
.command;
let Commands::Flush(args) = bare else {
panic!("expected flush")
};
assert!(args.daemon);
assert_eq!(args.selector, None);
assert!(
Cli::try_parse_from(["shep", "flush", "all", "--daemon"]).is_err(),
"the shepherd's own logs are a separate act, never a rider on a \
flock-wide flush"
);
}
#[test]
fn barks_takes_no_selector_and_tail_defaults_to_everything() {
use clap::Parser;
let bare = Cli::try_parse_from(["shep", "barks"]).unwrap().command;
let Commands::Barks(args) = bare else {
panic!("`shep barks` must parse with no selector")
};
assert_eq!(args.tail, None);
let tailed = Cli::try_parse_from(["shep", "barks", "--tail", "20"])
.unwrap()
.command;
let Commands::Barks(args) = tailed else {
panic!("expected barks")
};
assert_eq!(args.tail, Some(20));
}
}