-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the Location struct and register it as implicitly generated data
We had to inline usages of `map_err` because those combinators don't have `#[track_caller]`. Other combinators, such as those in futures, are more difficult to fix, so we offer some workarounds. This requires Rust 1.46, so added a new feature flag.
- Loading branch information
1 parent
4b5ebfc
commit 7739ac2
Showing
13 changed files
with
824 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
#![cfg(test)] | ||
|
||
mod location; | ||
|
||
mod api { | ||
use futures::{stream, StreamExt, TryStream}; | ||
use snafu::prelude::*; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
use futures::{executor::block_on, prelude::*}; | ||
use snafu::{location, prelude::*, Location}; | ||
|
||
#[derive(Debug, Copy, Clone, Snafu)] | ||
struct InnerError { | ||
location: Location, | ||
} | ||
|
||
#[derive(Debug, Copy, Clone, Snafu)] | ||
struct WrappedError { | ||
source: InnerError, | ||
location: Location, | ||
} | ||
|
||
#[derive(Debug, Snafu)] | ||
struct ManuallyWrappedError { | ||
source: InnerError, | ||
#[snafu(implicit(false))] | ||
location: Location, | ||
} | ||
|
||
#[derive(Debug, Snafu)] | ||
#[snafu(display("{}", message))] | ||
#[snafu(whatever)] | ||
pub struct MyWhatever { | ||
#[snafu(source(from(Box<dyn std::error::Error>, Some)))] | ||
source: Option<Box<dyn std::error::Error>>, | ||
message: String, | ||
location: Location, | ||
} | ||
|
||
mod try_future { | ||
use super::*; | ||
|
||
#[test] | ||
fn location_macro_uses_creation_location() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_future = async { InnerSnafu.fail::<()>() }; | ||
let wrapped_error_future = error_future.with_context(|| ManuallyWrappedSnafu { | ||
location: location!(), | ||
}); | ||
let wrapped_error = wrapped_error_future.await.unwrap_err(); | ||
|
||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 3, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn async_block_uses_creation_location() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_future = async { InnerSnafu.fail::<()>() }; | ||
let wrapped_error_future = async { error_future.await.context(WrappedSnafu) }; | ||
let wrapped_error = wrapped_error_future.await.unwrap_err(); | ||
|
||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 2, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_context_poll() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_future = async { InnerSnafu.fail::<()>() }; | ||
let wrapped_error_future = error_future.context(WrappedSnafu); | ||
let wrapped_error = wrapped_error_future.await.unwrap_err(); | ||
|
||
// `.await` calls our implementation of `poll`, so the | ||
// location corresponds to that line. | ||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 3, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_with_context_poll() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_future = async { InnerSnafu.fail::<()>() }; | ||
let wrapped_error_future = error_future.with_context(|| WrappedSnafu); | ||
let wrapped_error = wrapped_error_future.await.unwrap_err(); | ||
|
||
// `.await` calls our implementation of `poll`, so the | ||
// location corresponds to that line. | ||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 3, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_whatever_context_poll() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_future = async { InnerSnafu.fail::<()>() }; | ||
let wrapped_error_future = error_future.whatever_context("bang"); | ||
let wrapped_error: MyWhatever = wrapped_error_future.await.unwrap_err(); | ||
|
||
// `.await` calls our implementation of `poll`, so the | ||
// location corresponds to that line. | ||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 3, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_with_whatever_context_poll() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_future = async { InnerSnafu.fail::<()>() }; | ||
let wrapped_error_future = error_future.with_whatever_context(|_| "bang"); | ||
let wrapped_error: MyWhatever = wrapped_error_future.await.unwrap_err(); | ||
|
||
// `.await` calls our implementation of `poll`, so the | ||
// location corresponds to that line. | ||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 3, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
} | ||
|
||
mod try_stream { | ||
use super::*; | ||
|
||
#[test] | ||
fn location_macro_uses_creation_location() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_stream = stream::repeat(InnerSnafu.fail::<()>()); | ||
let mut wrapped_error_stream = error_stream.with_context(|| ManuallyWrappedSnafu { | ||
location: location!(), | ||
}); | ||
let wrapped_error = wrapped_error_stream.next().await.unwrap().unwrap_err(); | ||
|
||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 3, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn async_block_uses_creation_location() { | ||
block_on(async { | ||
let base_line = line!(); | ||
let error_stream = stream::repeat(InnerSnafu.fail::<()>()); | ||
let mut wrapped_error_stream = error_stream.map(|r| r.context(WrappedSnafu)); | ||
let wrapped_error = wrapped_error_stream.next().await.unwrap().unwrap_err(); | ||
|
||
assert_eq!( | ||
wrapped_error.location.line, | ||
base_line + 2, | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_context_poll() { | ||
block_on(async { | ||
let error_stream = stream::repeat(InnerSnafu.fail::<()>()); | ||
let mut wrapped_error_stream = error_stream.context(WrappedSnafu); | ||
let wrapped_error = wrapped_error_stream.next().await.unwrap().unwrap_err(); | ||
|
||
// `StreamExt::next` doesn't have `[track_caller]`, so the | ||
// location is inside the futures library. | ||
assert!( | ||
wrapped_error.location.file.contains("/futures-util-"), | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_with_context_poll() { | ||
block_on(async { | ||
let error_stream = stream::repeat(InnerSnafu.fail::<()>()); | ||
let mut wrapped_error_stream = error_stream.with_context(|| WrappedSnafu); | ||
let wrapped_error = wrapped_error_stream.next().await.unwrap().unwrap_err(); | ||
|
||
// `StreamExt::next` doesn't have `[track_caller]`, so the | ||
// location is inside the futures library. | ||
assert!( | ||
wrapped_error.location.file.contains("/futures-util-"), | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_whatever_context_poll() { | ||
block_on(async { | ||
let error_stream = stream::repeat(InnerSnafu.fail::<()>()); | ||
let mut wrapped_error_stream = error_stream.whatever_context("bang"); | ||
let wrapped_error: MyWhatever = wrapped_error_stream.next().await.unwrap().unwrap_err(); | ||
|
||
// `StreamExt::next` doesn't have `[track_caller]`, so the | ||
// location is inside the futures library. | ||
assert!( | ||
wrapped_error.location.file.contains("/futures-util-"), | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
|
||
#[test] | ||
fn track_caller_is_applied_on_with_whatever_context_poll() { | ||
block_on(async { | ||
let error_stream = stream::repeat(InnerSnafu.fail::<()>()); | ||
let mut wrapped_error_stream = error_stream.with_whatever_context(|_| "bang"); | ||
let wrapped_error: MyWhatever = wrapped_error_stream.next().await.unwrap().unwrap_err(); | ||
|
||
// `StreamExt::next` doesn't have `[track_caller]`, so the | ||
// location is inside the futures library. | ||
assert!( | ||
wrapped_error.location.file.contains("/futures-util-"), | ||
"Actual location: {}", | ||
wrapped_error.location, | ||
); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.