Skip to content

Commit

Permalink
Handle help and version errors, rather than let clap exit the process
Browse files Browse the repository at this point in the history
  • Loading branch information
gawashburn committed Dec 1, 2024
1 parent 057e9f9 commit f0808bb
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ coverage-helper = "0.2"

[dependencies]
coverage-helper = "0.2"
clap = { version = "4.5", features = ["cargo"] }
clap = { version = "4.5", features = ["color", "cargo"] }
objc = "0.2"
static_assertions = "1.1"
serde = "1.0"
Expand Down
19 changes: 15 additions & 4 deletions src/knoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::valid_config::*;
#[derive(Debug)]
pub enum Error {
// Wrapper errors.
Argument(clap::Error),
Config(valid_config::Error),
Displays(displays::Error),
Io(std::io::Error),
Expand All @@ -48,6 +49,7 @@ impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use crate::knoll::Error::*;
match self {
Argument(e) => Some(e),
Config(e) => Some(e),
Displays(e) => Some(e),
Io(e) => Some(e),
Expand All @@ -60,6 +62,12 @@ impl std::error::Error for Error {
}
}

impl From<clap::Error> for Error {
fn from(e: clap::Error) -> Self {
Error::Argument(e)
}
}

impl From<valid_config::Error> for Error {
fn from(e: valid_config::Error) -> Self {
Error::Config(e)
Expand Down Expand Up @@ -107,6 +115,9 @@ impl std::fmt::Display for Error {
use crate::knoll::Error::*;

match self {
// TODO Detect if the output is a terminal to determine when
// to use ANSI escape codes.
Argument(ce) => write!(f, "{}", ce.render().ansi()),
NoConfigGroups => write!(
f,
"The parsed input contains no configuration groups. \
Expand Down Expand Up @@ -225,7 +236,7 @@ pub fn run<
stderr: ERR,
) -> Result<(), Error> {
// Handle parsing the command-line arguments.
let matches = argument_parse(args);
let matches = argument_parse(args)?;

// Examine the serialization format option.
let format_opt: Option<&str> = matches.get_one::<String>("FORMAT").map(|s| s.as_str());
Expand Down Expand Up @@ -272,7 +283,7 @@ pub fn run<
}

/// Helper for parsing the command-line arguments.
fn argument_parse(args: &Vec<String>) -> ArgMatches {
fn argument_parse(args: &Vec<String>) -> Result<ArgMatches, clap::Error> {
// Clap argument parsing setup.

let in_arg = Arg::new("IN")
Expand Down Expand Up @@ -313,7 +324,7 @@ fn argument_parse(args: &Vec<String>) -> ArgMatches {
.default_value("2s")
.value_parser(clap::builder::NonEmptyStringValueParser::new());

let cmd = Command::new("knoll")
let mut cmd = Command::new("knoll")
.version(clap::crate_version!())
.about("Tool for configuring and arranging displays")
.args(vec![quiet_arg, verbose_arg, format_arg])
Expand All @@ -328,7 +339,7 @@ fn argument_parse(args: &Vec<String>) -> ArgMatches {
.arg(out_arg),
]);

cmd.get_matches_from(args)
cmd.try_get_matches_from(args)
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
20 changes: 13 additions & 7 deletions tests/knoll_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ use tempfile::tempdir;
/// Run the knoll command with the given arguments an optional input and
/// returns whether the invoked resulted in an error and the text output
/// to stdout and stderr.
///
/// The only caveat is that it is currently not possible to override output
/// destinations for the clap argument parser when using `--help` or
/// `--version`. So at present we cannot capture the output of these
/// options.
fn run_knoll<DS: DisplayState>(
args: Vec<&str>,
input: Option<String>,
Expand Down Expand Up @@ -82,13 +77,24 @@ fn run_knoll_fake(args: Vec<&str>, input: Option<String>) -> (Option<Error>, Str
#[test]
/// Test the knoll --help command
fn test_help() {
run_knoll_real(vec!["knoll", "--help"], None);
let (opt_err, _, _) = run_knoll_real(vec!["knoll", "--help"], None);
println!("opt_err: {:?}", opt_err);
// Verify that a help error was produced.
match opt_err {
Some(Error::Argument(e)) => assert_eq!(e.kind(), clap::error::ErrorKind::DisplayHelp),
_ => panic!("Unexpected error: {:?}", opt_err),
}
}

#[test]
/// Test the knoll --version command
fn test_version() {
run_knoll_real(vec!["knoll", "--version"], None);
let (opt_err, _, _) = run_knoll_real(vec!["knoll", "--version"], None);
// Verify that a version error was produced.
match opt_err {
Some(Error::Argument(e)) => assert_eq!(e.kind(), clap::error::ErrorKind::DisplayVersion),
_ => panic!("Unexpected error: {:?}", opt_err),
}
}

#[test]
Expand Down

0 comments on commit f0808bb

Please sign in to comment.