use clap::{Arg, ArgAction, ArgMatches};
pub use self::output_mode::OutputMode;
pub use self::verbosity::Verbosity;
mod output_mode;
mod verbosity;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct OutputFlags {
verbosity: Verbosity,
mode: OutputMode,
}
impl OutputFlags {
pub fn new(verbosity: Verbosity, mode: OutputMode) -> Self {
Self { verbosity, mode }
}
pub fn verbosity(&self) -> Verbosity {
self.verbosity
}
pub fn mode(&self) -> OutputMode {
self.mode
}
pub fn augment_command(command: clap::Command) -> clap::Command {
command
.arg(
Arg::new("quiet")
.short('q')
.long("quiet")
.help("Suppress informational messages")
.global(true)
.action(ArgAction::SetTrue)
.conflicts_with("verbose"),
)
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.help("Show additional detail")
.global(true)
.action(ArgAction::SetTrue)
.conflicts_with("quiet"),
)
.arg(
Arg::new("json")
.long("json")
.help("Output results as JSON")
.global(true)
.action(ArgAction::SetTrue),
)
}
pub fn from_arg_matches(matches: &ArgMatches) -> Self {
let quiet = matches.get_flag("quiet");
let verbose = matches.get_flag("verbose");
let json = matches.get_flag("json");
let verbosity = match (quiet, verbose) {
(true, _) => Verbosity::Quiet,
(_, true) => Verbosity::Verbose,
(false, false) => Verbosity::Default,
};
let mode = match json {
true => OutputMode::Json,
false => OutputMode::Text,
};
Self::new(verbosity, mode)
}
}
impl Default for OutputFlags {
fn default() -> Self {
Self::new(Verbosity::default(), OutputMode::default())
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::missing_panics_doc)]
use super::*;
fn test_command() -> clap::Command {
OutputFlags::augment_command(clap::Command::new("test"))
}
#[test]
fn augment_command_adds_three_global_args() {
let command = test_command();
let args: Vec<&str> = command
.get_arguments()
.filter(|a| a.is_global_set())
.map(|a| a.get_id().as_str())
.collect();
assert!(args.contains(&"quiet"));
assert!(args.contains(&"verbose"));
assert!(args.contains(&"json"));
assert_eq!(args.len(), 3);
}
#[test]
fn default_is_text_with_default_verbosity() {
let flags = OutputFlags::default();
assert_eq!(flags.verbosity(), Verbosity::Default);
assert_eq!(flags.mode(), OutputMode::Text);
}
#[test]
fn from_arg_matches_with_defaults() {
let matches = test_command().get_matches_from(vec!["test"]);
let flags = OutputFlags::from_arg_matches(&matches);
assert_eq!(flags.verbosity(), Verbosity::Default);
assert_eq!(flags.mode(), OutputMode::Text);
}
#[test]
fn from_arg_matches_with_json_flag() {
let matches = test_command().get_matches_from(vec!["test", "--json"]);
let flags = OutputFlags::from_arg_matches(&matches);
assert_eq!(flags.mode(), OutputMode::Json);
assert_eq!(flags.verbosity(), Verbosity::Default);
}
#[test]
fn from_arg_matches_with_quiet_flag() {
let matches = test_command().get_matches_from(vec!["test", "--quiet"]);
let flags = OutputFlags::from_arg_matches(&matches);
assert_eq!(flags.verbosity(), Verbosity::Quiet);
assert_eq!(flags.mode(), OutputMode::Text);
}
#[test]
fn from_arg_matches_with_verbose_flag() {
let matches = test_command().get_matches_from(vec!["test", "--verbose"]);
let flags = OutputFlags::from_arg_matches(&matches);
assert_eq!(flags.verbosity(), Verbosity::Verbose);
assert_eq!(flags.mode(), OutputMode::Text);
}
#[test]
fn mode_returns_configured_mode() {
let flags = OutputFlags::new(Verbosity::Default, OutputMode::Json);
assert_eq!(flags.mode(), OutputMode::Json);
}
#[test]
fn trait_send() {
fn assert_send<T: Send>() {}
assert_send::<OutputFlags>();
}
#[test]
fn trait_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<OutputFlags>();
}
#[test]
fn trait_unpin() {
fn assert_unpin<T: Unpin>() {}
assert_unpin::<OutputFlags>();
}
#[test]
fn verbosity_returns_configured_verbosity() {
let flags = OutputFlags::new(Verbosity::Verbose, OutputMode::Text);
assert_eq!(flags.verbosity(), Verbosity::Verbose);
}
}