feat(errors): add stable error propagation
This commit is contained in:
1 parent
97acb2a2d7
commit
ba9c97ed3b
34 files changed
+1007
No files matched your search
@@ -0,0 +1,149 @@
|
||||
use kaptan_err_propagate::{ErrorId, ErrorReport, KaptanError};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
|
||||
enum TestError {
|
||||
#[kaptan_error(id = 65001)]
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
|
||||
enum OuterError {
|
||||
#[kaptan_error(id = 65002)]
|
||||
Converted(TestError),
|
||||
}
|
||||
|
||||
impl From<TestError> for OuterError {
|
||||
fn from(error: TestError) -> Self {
|
||||
Self::Converted(error)
|
||||
}
|
||||
}
|
||||
|
||||
fn fail() -> Result<(), TestError> {
|
||||
Err(TestError::Failed)
|
||||
}
|
||||
|
||||
fn middle() -> Result<(), TestError> {
|
||||
fail()
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn succeeds() -> Result<u8, TestError> {
|
||||
Ok(7)
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn annotated_outer() -> Result<(), TestError> {
|
||||
middle()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn annotated_inner() -> Result<(), TestError> {
|
||||
fail()
|
||||
}
|
||||
|
||||
fn unannotated_outer() -> Result<(), TestError> {
|
||||
annotated_inner()
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn handles_inner_error() -> Result<(), TestError> {
|
||||
let _handled = fail().is_err();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn returns_explicit_error(fail_at_boundary: bool) -> Result<(), TestError> {
|
||||
if fail_at_boundary {
|
||||
return Err(TestError::Failed);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type AliasedResult<T> = core::result::Result<T, TestError>;
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn returns_alias() -> AliasedResult<()> {
|
||||
fail()
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn reports_final_converted_error() -> Result<(), OuterError> {
|
||||
fail()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn reports_error_id() -> Result<(), ErrorId> {
|
||||
Err(ErrorId::new(65003))
|
||||
}
|
||||
|
||||
#[kaptan_err_propagate::propagate]
|
||||
async fn async_boundary() -> Result<(), TestError> {
|
||||
fail()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Service;
|
||||
|
||||
impl Service {
|
||||
#[kaptan_err_propagate::propagate]
|
||||
fn method(&self, fail_at_boundary: bool) -> Result<(), TestError> {
|
||||
if fail_at_boundary {
|
||||
fail()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn take_record() -> kaptan_err_propagate::ErrorRecord {
|
||||
kaptan_err_propagate::take().expect("escaping error must be reported")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reports_only_final_errors_leaving_annotated_boundaries() {
|
||||
while kaptan_err_propagate::take().is_some() {}
|
||||
|
||||
assert_eq!(succeeds(), Ok(7));
|
||||
assert!(kaptan_err_propagate::take().is_none());
|
||||
|
||||
assert_eq!(handles_inner_error(), Ok(()));
|
||||
assert!(kaptan_err_propagate::take().is_none());
|
||||
|
||||
assert_eq!(annotated_outer(), Err(TestError::Failed));
|
||||
assert_eq!(take_record().id(), TestError::Failed.error_id().get());
|
||||
|
||||
assert_eq!(unannotated_outer(), Err(TestError::Failed));
|
||||
assert_eq!(take_record().id(), TestError::Failed.error_id().get());
|
||||
|
||||
assert_eq!(returns_explicit_error(true), Err(TestError::Failed));
|
||||
assert_eq!(take_record().id(), TestError::Failed.error_id().get());
|
||||
|
||||
assert_eq!(returns_alias(), Err(TestError::Failed));
|
||||
assert_eq!(take_record().id(), TestError::Failed.error_id().get());
|
||||
|
||||
assert_eq!(
|
||||
reports_final_converted_error(),
|
||||
Err(OuterError::Converted(TestError::Failed))
|
||||
);
|
||||
assert_eq!(
|
||||
take_record().id(),
|
||||
OuterError::Converted(TestError::Failed).error_id().get()
|
||||
);
|
||||
|
||||
assert_eq!(reports_error_id(), Err(ErrorId::new(65003)));
|
||||
assert_eq!(take_record().id(), 65003);
|
||||
|
||||
assert_eq!(Service.method(false), Ok(()));
|
||||
assert!(kaptan_err_propagate::take().is_none());
|
||||
|
||||
let mut future = core::pin::pin!(async_boundary());
|
||||
let mut context = core::task::Context::from_waker(core::task::Waker::noop());
|
||||
assert_eq!(
|
||||
core::future::Future::poll(future.as_mut(), &mut context),
|
||||
core::task::Poll::Ready(Err(TestError::Failed))
|
||||
);
|
||||
let record = take_record();
|
||||
assert_eq!(record.id(), TestError::Failed.error_id().get());
|
||||
assert!(record.raised_at().contains("propagate.rs:"));
|
||||
}
|
||||
Reference in new issue
Block a user