use clap::error::ErrorKind;
use thiserror::Error;
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
pub enum Error {
#[error("incomplete data")]
Incomplete,
#[error("connection reset by peer")]
ConnectionResetByPeer,
#[error("There is no valid data directory")]
DataDir,
#[error("There is no valid config directory")]
ConfigDir,
#[error("Unable to build a valid configuration")]
ConfigBuild,
#[error("Unable to load a valid configuration")]
ConfigLoad,
#[error("Unable to deserialize config")]
ConfigDeserialize,
#[error("Unable to initialize tracing")]
TracingInit,
#[error("An invalid IP address was provided")]
InvalidIpAddress,
#[error("An invalid frame was received")]
InvalidFrame,
#[error("A key has not been established")]
KeyNotEstablished,
#[error("Decryption failed")]
DecryptionFailed,
#[error("Invalid IP address for server")]
InvalidServerAddress,
#[error("Invalid Moshpits address")]
InvalidMoshpitsAddress,
#[error("key exchange failed")]
InvalidKexState,
#[error("UUID mismatch")]
UuidMismatch,
#[error("There is no valid home directory")]
HomeDir,
#[error("Invalid public key file format")]
InvalidPublicKeyFormat,
#[error("An invalid key header was found")]
InvalidKeyHeader,
#[error("A public key mismatch occurred")]
PublicKeyMismatch,
#[error("An unsupported AEAD cipher was specified")]
UnsupportedAeadCipher,
#[error("An invalid server destination format was provided")]
InvalidServerDestination,
#[error("Frame too large")]
FrameTooLarge,
#[error("Key file not found")]
KeyFileMissing,
#[error("Key file is corrupt or has an invalid format")]
KeyCorrupt,
#[error("Public key does not match private key")]
KeyPairMismatch,
#[error("Host key rejected by user")]
HostKeyRejected,
#[error("No common algorithm found during key exchange negotiation")]
NoCommonAlgorithm,
}
#[allow(clippy::needless_pass_by_value)]
#[must_use]
pub fn clap_or_error(err: anyhow::Error) -> i32 {
let disp_err = || {
eprintln!("{err:?}");
1
};
match err.downcast_ref::<clap::Error>() {
Some(e) => match e.kind() {
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => {
println!("{e}");
0
}
ErrorKind::InvalidValue
| ErrorKind::UnknownArgument
| ErrorKind::InvalidSubcommand
| ErrorKind::NoEquals
| ErrorKind::ValueValidation
| ErrorKind::TooManyValues
| ErrorKind::TooFewValues
| ErrorKind::WrongNumberOfValues
| ErrorKind::ArgumentConflict
| ErrorKind::MissingRequiredArgument
| ErrorKind::MissingSubcommand
| ErrorKind::InvalidUtf8
| ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
| ErrorKind::Io
| ErrorKind::Format => disp_err(),
_ => unknown_err_kind(),
},
None => disp_err(),
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
fn unknown_err_kind() -> i32 {
eprintln!("Unknown ErrorKind");
1
}
#[must_use]
pub fn success((): ()) -> i32 {
0
}
#[cfg(test)]
mod test {
use super::{clap_or_error, success};
use anyhow::{Error, anyhow};
use clap::{
Command,
error::ErrorKind::{self, DisplayHelp, DisplayVersion},
};
#[test]
fn test_success() {
assert_eq!(success(()), 0);
}
#[test]
fn clap_or_error_is_error() {
assert_eq!(1, clap_or_error(anyhow!("test")));
}
#[test]
fn clap_or_error_is_help() {
let mut cmd = Command::new("libmoshpit");
let error = cmd.error(DisplayHelp, "help");
let clap_error = Error::new(error);
assert_eq!(0, clap_or_error(clap_error));
}
#[test]
fn clap_or_error_is_version() {
let mut cmd = Command::new("libmoshpit");
let error = cmd.error(DisplayVersion, "1.0");
let clap_error = Error::new(error);
assert_eq!(0, clap_or_error(clap_error));
}
#[test]
fn clap_or_error_is_other_clap_error() {
let mut cmd = Command::new("libmoshpit");
let error = cmd.error(ErrorKind::InvalidValue, "Some failure case");
let clap_error = Error::new(error);
assert_eq!(1, clap_or_error(clap_error));
}
}