extern crate self as error_path;
use error_path_macros::{error_path, error_path_impl};
use std::future::Future;
use std::pin::pin;
use std::sync::Arc;
use std::task::{Context, Poll, Wake, Waker};
trait WithErrorPath: Sized {
fn with_error_path(self, path: &str) -> Self;
}
#[derive(Debug, PartialEq)]
struct TestError(Vec<String>);
impl WithErrorPath for TestError {
fn with_error_path(mut self, path: &str) -> Self {
self.0.insert(0, path.to_owned());
self
}
}
type TestResult<T> = Result<T, TestError>;
#[error_path]
fn sync_failure() -> TestResult<()> {
Err(TestError(vec![]))
}
#[error_path("custom.path")]
async fn async_failure() -> TestResult<()> {
Err(TestError(vec![]))
}
struct Service;
#[error_path_impl]
impl Service {
fn failure(&self) -> TestResult<()> {
Err(TestError(vec![]))
}
async fn async_failure(&self) -> TestResult<()> {
Err(TestError(vec![]))
}
#[error_path_skip]
fn skipped(&self) -> TestResult<()> {
Err(TestError(vec![]))
}
fn value(&self) -> usize {
42
}
}
struct DelimitedService;
#[error_path_impl("login::api")]
impl DelimitedService {
fn failure(&self) -> TestResult<()> {
Err(TestError(vec![]))
}
}
struct NoopWake;
impl Wake for NoopWake {
fn wake(self: Arc<Self>) {}
}
fn block_on<F: Future>(future: F) -> F::Output {
let waker = Waker::from(Arc::new(NoopWake));
let mut context = Context::from_waker(&waker);
let mut future = pin!(future);
loop {
if let Poll::Ready(output) = future.as_mut().poll(&mut context) {
return output;
}
}
}
#[test]
fn wraps_sync_function_with_default_path() {
assert_eq!(sync_failure(), Err(TestError(vec!["sync_failure".into()])));
}
#[test]
fn wraps_async_function_with_custom_path() {
assert_eq!(
block_on(async_failure()),
Err(TestError(vec!["custom.path".into()]))
);
}
#[test]
fn wraps_sync_impl_method() {
assert_eq!(
Service.failure(),
Err(TestError(vec!["Service".into(), "failure".into()]))
);
}
#[test]
fn wraps_async_impl_method() {
assert_eq!(
block_on(Service.async_failure()),
Err(TestError(vec!["Service".into(), "async_failure".into()]))
);
}
#[test]
fn preserves_explicit_base_as_a_separate_literal() {
assert_eq!(
DelimitedService.failure(),
Err(TestError(vec!["login::api".into(), "failure".into()]))
);
}
#[test]
fn leaves_skipped_method_unwrapped() {
assert_eq!(Service.skipped(), Err(TestError(vec![])));
}
#[test]
fn leaves_non_result_method_unwrapped() {
assert_eq!(Service.value(), 42);
}