feature (backend-rs, macro-rs): prittify error outputs for napi export
Co-authored-by: sup39 <dev@sup39.dev>
This commit is contained in:
parent
9ec9c31ab5
commit
1cc24b9c25
3 changed files with 96 additions and 5 deletions
90
packages/backend-rs/src/util/error_chain.rs
Normal file
90
packages/backend-rs/src/util/error_chain.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
//! Error formatter used until backtracing methods are standarized
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
/// Prettifies [`Error`] message (mainly for napi export)
|
||||
pub fn format_error(mut error: &dyn Error) -> String {
|
||||
let mut to_return = String::new();
|
||||
|
||||
to_return.push_str(&format!(
|
||||
concat!(" raw: {0:?}", "\n", " message: {0}"),
|
||||
error,
|
||||
));
|
||||
|
||||
while let Some(source) = error.source() {
|
||||
to_return.push('\n');
|
||||
to_return.push_str(&format!("caused by: {}", source));
|
||||
error = source;
|
||||
}
|
||||
|
||||
to_return
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn format_error() {
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("inner error 1")]
|
||||
struct InnerError1;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("unexpected string '{0}'")]
|
||||
struct InnerError2(String);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
enum ErrorVariants {
|
||||
#[error("error 1 occured")]
|
||||
Error1(#[from] InnerError1),
|
||||
#[error("error 2 occured")]
|
||||
Error2(#[from] InnerError2),
|
||||
}
|
||||
|
||||
fn causes_inner_error_1() -> Result<(), InnerError1> {
|
||||
Err(InnerError1)
|
||||
}
|
||||
fn causes_inner_error_2() -> Result<(), InnerError2> {
|
||||
Err(InnerError2("foo".to_string()))
|
||||
}
|
||||
|
||||
fn causes_error_1() -> Result<(), ErrorVariants> {
|
||||
causes_inner_error_1()?;
|
||||
Ok(())
|
||||
}
|
||||
fn causes_error_2() -> Result<(), ErrorVariants> {
|
||||
causes_inner_error_2()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let error_1 = causes_error_1().unwrap_err();
|
||||
let error_2 = causes_error_2().unwrap_err();
|
||||
|
||||
let error_message_1 = super::format_error(&error_1);
|
||||
let error_message_2 = super::format_error(&error_2);
|
||||
|
||||
// We can't assume consistency in `Debug` output, so the output texts
|
||||
// may need to be updated in the future, and we shouldn't make this kind
|
||||
// of assumption in the actual program.
|
||||
let expected_message_1 = "
|
||||
raw: Error1(InnerError1)
|
||||
message: error 1 occured
|
||||
caused by: inner error 1
|
||||
";
|
||||
let expected_message_2 = r#"
|
||||
raw: Error2(InnerError2("foo"))
|
||||
message: error 2 occured
|
||||
caused by: unexpected string 'foo'
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
error_message_1,
|
||||
expected_message_1[1..expected_message_1.len() - 1]
|
||||
);
|
||||
assert_eq!(
|
||||
error_message_2,
|
||||
expected_message_2[1..expected_message_2.len() - 1]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
//! Basic utilities such as ID generator and HTTP client
|
||||
|
||||
pub mod error_chain;
|
||||
pub mod http_client;
|
||||
pub mod id;
|
||||
pub mod random;
|
||||
|
|
|
@ -212,7 +212,7 @@ pub fn ts_export(
|
|||
/// ```
|
||||
///
|
||||
/// ## Function with `Result<T, E>` return type
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// #[derive(thiserror::Error, Debug)]
|
||||
/// pub enum IntegerDivisionError {
|
||||
/// #[error("Divided by zero")]
|
||||
|
@ -233,7 +233,7 @@ pub fn ts_export(
|
|||
/// }
|
||||
/// ```
|
||||
/// generates
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #[derive(thiserror::Error, Debug)]
|
||||
/// # pub enum IntegerDivisionError {
|
||||
/// # #[error("Divided by zero")]
|
||||
|
@ -252,7 +252,7 @@ pub fn ts_export(
|
|||
/// # }
|
||||
/// #[napi_derive::napi(js_name = "integerDivide",)]
|
||||
/// pub fn integer_divide_napi(dividend: i64, divisor: i64) -> napi::Result<i64> {
|
||||
/// integer_divide(dividend, divisor).map_err(|err| napi::Error::from_reason(err.to_string()))
|
||||
/// integer_divide(dividend, divisor).map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
|
@ -329,7 +329,7 @@ fn napi_impl(macro_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
};
|
||||
// add modifier to function call result
|
||||
function_call_modifiers.push(quote! {
|
||||
.map_err(|err| napi::Error::from_reason(err.to_string()))
|
||||
.map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -539,7 +539,7 @@ mod tests {
|
|||
divisor: i64,
|
||||
) -> napi::Result<i64> {
|
||||
integer_divide(dividend, divisor)
|
||||
.map_err(|err| napi::Error::from_reason(err.to_string()))
|
||||
.map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue