diff --git a/packages/backend-rs/src/util/error_chain.rs b/packages/backend-rs/src/util/error_chain.rs new file mode 100644 index 0000000000..086e5449f2 --- /dev/null +++ b/packages/backend-rs/src/util/error_chain.rs @@ -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] + ); + } +} diff --git a/packages/backend-rs/src/util/mod.rs b/packages/backend-rs/src/util/mod.rs index 761527c4ae..3df33831e8 100644 --- a/packages/backend-rs/src/util/mod.rs +++ b/packages/backend-rs/src/util/mod.rs @@ -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; diff --git a/packages/macro-rs/src/lib.rs b/packages/macro-rs/src/lib.rs index eebbe198cc..65ad817e05 100644 --- a/packages/macro-rs/src/lib.rs +++ b/packages/macro-rs/src/lib.rs @@ -212,7 +212,7 @@ pub fn ts_export( /// ``` /// /// ## Function with `Result` 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 { -/// 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 { 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))) } } );