#[derive(Debug, clap::Args)]
pub struct KvArgs {
#[command(subcommand)]
pub command: KvCommand,
}
#[derive(Debug, clap::Subcommand)]
pub enum KvCommand {
Get(KvGetArgs),
Set(KvSetArgs),
Unset(KvUnsetArgs),
}
#[derive(Debug, clap::Args)]
pub struct KvSetArgs {
pub key: String,
pub value: String,
}
#[derive(Debug, clap::Args)]
pub struct KvGetArgs {
pub key: Option<String>,
}
#[derive(Debug, clap::Args)]
pub struct KvUnsetArgs {
#[arg(required_unless_present = "all", conflicts_with = "all")]
pub key: Option<String>,
#[arg(long)]
pub all: bool,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{Cli, Commands};
fn kv_command(argv: &[&str]) -> KvCommand {
use clap::Parser as _;
let full: Vec<&str> = ["shep"].into_iter().chain(argv.iter().copied()).collect();
let Commands::Kv(args) = Cli::try_parse_from(&full)
.unwrap_or_else(|err| panic!("{full:?} must parse: {err}"))
.command
else {
panic!("{full:?} is not `shep kv`")
};
args.command
}
#[test]
fn kv_takes_get_set_and_unset() {
assert!(matches!(
kv_command(&["kv", "get"]),
KvCommand::Get(KvGetArgs { key: None })
));
assert!(matches!(
kv_command(&["kv", "get", "a"]),
KvCommand::Get(KvGetArgs { key: Some(_) })
));
assert!(matches!(
kv_command(&["kv", "set", "a", "1"]),
KvCommand::Set(KvSetArgs { key, value }) if key == "a" && value == "1"
));
assert!(matches!(
kv_command(&["kv", "unset", "a"]),
KvCommand::Unset(KvUnsetArgs {
key: Some(_),
all: false
})
));
assert!(matches!(
kv_command(&["kv", "unset", "--all"]),
KvCommand::Unset(KvUnsetArgs {
key: None,
all: true
})
));
}
#[test]
fn bare_kv_is_a_usage_error() {
use clap::Parser;
assert!(Cli::try_parse_from(["shep", "kv"]).is_err());
}
#[test]
fn kv_unset_needs_a_key_or_the_all_flag() {
use clap::Parser;
assert!(Cli::try_parse_from(["shep", "kv", "unset"]).is_err());
assert!(Cli::try_parse_from(["shep", "kv", "unset", "a"]).is_ok());
assert!(Cli::try_parse_from(["shep", "kv", "unset", "--all"]).is_ok());
}
#[test]
fn kv_unset_refuses_a_key_and_all_together() {
use clap::Parser;
assert!(Cli::try_parse_from(["shep", "kv", "unset", "a", "--all"]).is_err());
}
#[test]
fn kv_get_takes_an_optional_key() {
use clap::Parser;
assert!(Cli::try_parse_from(["shep", "kv", "get"]).is_ok());
assert!(Cli::try_parse_from(["shep", "kv", "get", "a"]).is_ok());
}
#[test]
fn kv_set_needs_both_a_key_and_a_value() {
use clap::Parser;
assert!(Cli::try_parse_from(["shep", "kv", "set", "a"]).is_err());
assert!(Cli::try_parse_from(["shep", "kv", "set", "a", "1"]).is_ok());
}
#[test]
fn kv_is_visible_and_the_settings_verbs_are_not_its_aliases() {
use clap::CommandFactory;
let cmd = Cli::command();
assert!(
!cmd.find_subcommand("kv").unwrap().is_hide_set(),
"`kv` must be a verb `--help` lists"
);
for settings in ["get", "set", "unset"] {
assert!(
!cmd.find_subcommand(settings).unwrap().is_hide_set(),
"`{settings}` is a settings verb, not a store alias"
);
}
}
#[test]
fn kv_help_lists_its_three_subcommands() {
use clap::CommandFactory;
let mut cmd = Cli::command();
let help = cmd
.find_subcommand_mut("kv")
.expect("`shep kv` exists")
.render_help()
.to_string();
for verb in ["get", "set", "unset"] {
assert!(help.contains(verb), "{help}");
}
}
}