use kaptan_err_reportable::{ErrorId, KaptanError, ReportableError}; #[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 for OuterError { fn from(error: TestError) -> Self { Self::Converted(error) } } fn fail() -> Result<(), TestError> { Err(TestError::Failed) } fn middle() -> Result<(), TestError> { fail() } #[kaptan_err_reportable::propagate] fn succeeds() -> Result { Ok(7) } #[kaptan_err_reportable::propagate] fn annotated_outer() -> Result<(), TestError> { middle()?; Ok(()) } #[kaptan_err_reportable::propagate] fn annotated_inner() -> Result<(), TestError> { fail() } fn unannotated_outer() -> Result<(), TestError> { annotated_inner() } #[kaptan_err_reportable::propagate] fn handles_inner_error() -> Result<(), TestError> { let _handled = fail().is_err(); Ok(()) } #[kaptan_err_reportable::propagate] fn returns_explicit_error(report_error: bool) -> Result<(), TestError> { if report_error { return Err(TestError::Failed); } Ok(()) } type AliasedResult = core::result::Result; #[kaptan_err_reportable::propagate] fn returns_alias() -> AliasedResult<()> { fail() } #[kaptan_err_reportable::propagate] fn reports_converted_error() -> Result<(), OuterError> { fail()?; Ok(()) } #[kaptan_err_reportable::propagate] fn reports_error_id() -> Result<(), ErrorId> { Err(ErrorId::new(65003)) } #[kaptan_err_reportable::propagate] async fn async_reporting_point() -> Result<(), TestError> { fail()?; Ok(()) } struct Service; impl Service { #[kaptan_err_reportable::propagate] fn method(&self, report_error: bool) -> Result<(), TestError> { if report_error { fail()?; } Ok(()) } } fn take_record() -> kaptan_err_reportable::ErrorRecord { kaptan_err_reportable::take().expect("escaping error must be reported") } #[test] fn reports_only_errors_leaving_annotated_reporting_points() { while kaptan_err_reportable::take().is_some() {} assert_eq!(succeeds(), Ok(7)); assert!(kaptan_err_reportable::take().is_none()); assert_eq!(handles_inner_error(), Ok(())); assert!(kaptan_err_reportable::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_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_reportable::take().is_none()); let mut future = core::pin::pin!(async_reporting_point()); 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:")); }