shrupl/src/error.rs
Jörn-Michael Miehe 3257a97351 [wip] unit testing
- mock impl for `sharry::Client` and associated IDs
2025-07-08 21:41:38 +00:00

166 lines
4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::fmt;
use crate::sharry;
#[derive(Debug, thiserror::Error)]
pub enum Parameter {
#[error("given URI {0:?}")]
Uri(sharry::Uri),
#[error("given Alias ID {0:?}")]
AliasID(sharry::AliasID),
#[error("stored Share ID {0:?}")]
ShareID(sharry::ShareID),
#[error("stored {0:?}")]
FileID(sharry::FileID),
}
// a helper to generate all the `From<T> for Parameter` impls
macro_rules! impl_param_from {
// $typ: the source type; $var: the enumvariant name
( $( $typ:path => $var:ident ),* $(,)? ) => {
$(
impl From<$typ> for Parameter {
fn from(value: $typ) -> Self {
Self::$var(value)
}
}
)*
};
}
impl_param_from! {
sharry::Uri => Uri,
sharry::AliasID => AliasID,
sharry::ShareID => ShareID,
sharry::FileID => FileID,
}
impl Parameter {
fn is_fatal(&self) -> bool {
matches!(self, Self::Uri(_) | Self::AliasID(_))
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
StdIo(#[from] std::io::Error),
#[error("Response error: {0}")]
Response(String),
#[error("Invalid {0}")]
InvalidParameter(Parameter),
#[error("Mismatch, expected {expected:?} but got {actual:?}")]
Mismatch { expected: String, actual: String },
#[error("Unknown error: {0}")]
Unknown(String),
}
pub type Result<T> = std::result::Result<T, Error>;
// a helper to generate all the `From<T> for Error` impls
macro_rules! impl_error_from {
// $typ: the source type
( $( $typ:path ),* $(,)? ) => {
$(
// // implement for values
// impl From<$typ> for Error {
// fn from(value: $typ) -> Self {
// Self::InvalidParameter(value.into())
// }
// }
// implement for references
impl From<&$typ> for Error {
fn from(value: &$typ) -> Self {
Self::InvalidParameter(value.clone().into())
}
}
)*
};
}
impl_error_from! {
sharry::Uri,
sharry::AliasID,
sharry::ShareID,
sharry::FileID,
}
#[allow(clippy::needless_pass_by_value)]
fn into_string(val: impl ToString) -> String {
val.to_string()
}
impl Error {
pub fn res_status_check<T>(actual: T, expected: T) -> Result<()>
where
T: PartialEq + fmt::Display + Copy,
{
if actual == expected {
Ok(())
} else {
Err(Self::Response(format!(
"unexpected status: {actual} (expected {expected})"
)))
}
}
pub fn response(e: impl ToString) -> Self {
Self::Response(into_string(e))
}
pub fn mismatch<T>(expected: impl ToString, actual: impl ToString) -> Result<T> {
Err(Self::Mismatch {
expected: into_string(expected),
actual: into_string(actual),
})
}
pub fn is_mismatch<E, A>(&self, want_expected: E, want_actual: A) -> bool
where
E: AsRef<str>,
A: AsRef<str>,
{
matches!(
self,
Self::Mismatch { expected, actual }
if expected == want_expected.as_ref()
&& actual == want_actual.as_ref()
)
}
#[must_use]
pub fn get_invalid_param(&self) -> Option<&Parameter> {
if let Self::InvalidParameter(p) = self {
Some(p)
} else {
None
}
}
#[must_use]
pub fn is_fatal(&self) -> bool {
match self {
Self::InvalidParameter(p) => p.is_fatal(),
Self::Mismatch { .. } | Self::Unknown(_) => true,
_ => false,
}
}
}
#[macro_export]
macro_rules! error_response {
// Match a format string plus optional arguments
($fmt:expr $(, $arg:expr )* $(,)?) => {
// Expand to constructing the Error::Response variant,
// wrapping a `format!(...)` call
Error::Response(format!($fmt $(, $arg )*))
};
}