Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1,29 @@
#![allow(dead_code)]
use eyre::{bail, set_hook, DefaultHandler, InstallError, Result};
use once_cell::sync::OnceCell;
use std::io;
pub fn bail_literal() -> Result<()> {
bail!("oh no!");
}
pub fn bail_fmt() -> Result<()> {
bail!("{} {}!", "oh", "no");
}
pub fn bail_error() -> Result<()> {
bail!(io::Error::new(io::ErrorKind::Other, "oh no!"));
}
// Tests are multithreaded- use OnceCell to install hook once if auto-install
// feature is disabled.
pub fn maybe_install_handler() -> Result<(), InstallError> {
static INSTALLER: OnceCell<Result<(), InstallError>> = OnceCell::new();
if cfg!(not(feature = "auto-install")) {
*INSTALLER.get_or_init(|| set_hook(Box::new(DefaultHandler::default_with)))
} else {
Ok(())
}
}

View file

@ -0,0 +1,7 @@
#[rustversion::attr(not(nightly), ignore)]
#[cfg_attr(miri, ignore)]
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/*.rs");
}

View file

@ -0,0 +1,55 @@
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::Arc;
#[derive(Debug)]
pub struct Flag {
atomic: Arc<AtomicBool>,
}
impl Flag {
pub fn new() -> Self {
Flag {
atomic: Arc::new(AtomicBool::new(false)),
}
}
pub fn get(&self) -> bool {
self.atomic.load(SeqCst)
}
}
#[derive(Debug)]
pub struct DetectDrop {
has_dropped: Flag,
label: &'static str,
}
impl DetectDrop {
pub fn new(label: &'static str, has_dropped: &Flag) -> Self {
DetectDrop {
label,
has_dropped: Flag {
atomic: Arc::clone(&has_dropped.atomic),
},
}
}
}
impl StdError for DetectDrop {}
impl Display for DetectDrop {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "oh no!")
}
}
impl Drop for DetectDrop {
fn drop(&mut self) {
eprintln!("Dropping {}", self.label);
let already_dropped = self.has_dropped.atomic.swap(true, SeqCst);
assert!(!already_dropped);
}
}

View file

@ -0,0 +1,13 @@
use eyre::Report;
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Report>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Report>();
}

View file

@ -0,0 +1,66 @@
mod common;
use self::common::maybe_install_handler;
use eyre::{eyre, Report};
use std::error::Error as StdError;
use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
#[error("outer")]
struct MyError {
source: io::Error,
}
#[test]
fn test_boxed_str() {
maybe_install_handler().unwrap();
let error = Box::<dyn StdError + Send + Sync>::from("oh no!");
let error: Report = eyre!(error);
assert_eq!("oh no!", error.to_string());
assert_eq!(
"oh no!",
error
.downcast_ref::<Box<dyn StdError + Send + Sync>>()
.unwrap()
.to_string()
);
}
#[test]
fn test_boxed_thiserror() {
maybe_install_handler().unwrap();
let error = MyError {
source: io::Error::new(io::ErrorKind::Other, "oh no!"),
};
let error: Report = eyre!(error);
assert_eq!("oh no!", error.source().unwrap().to_string());
}
#[test]
fn test_boxed_eyre() {
maybe_install_handler().unwrap();
let error: Report = eyre!("oh no!").wrap_err("it failed");
let error = eyre!(error);
assert_eq!("oh no!", error.source().unwrap().to_string());
}
#[test]
fn test_boxed_sources() {
maybe_install_handler().unwrap();
let error = MyError {
source: io::Error::new(io::ErrorKind::Other, "oh no!"),
};
let error = Box::<dyn StdError + Send + Sync>::from(error);
let error: Report = eyre!(error).wrap_err("it failed");
assert_eq!("it failed", error.to_string());
assert_eq!("outer", error.source().unwrap().to_string());
assert_eq!(
"oh no!",
error.source().unwrap().source().unwrap().to_string()
);
}

View file

@ -0,0 +1,54 @@
mod common;
use self::common::maybe_install_handler;
use eyre::{eyre, Report};
fn error() -> Report {
eyre!({ 0 }).wrap_err(1).wrap_err(2).wrap_err(3)
}
#[test]
fn test_iter() {
maybe_install_handler().unwrap();
let e = error();
let mut chain = e.chain();
assert_eq!("3", chain.next().unwrap().to_string());
assert_eq!("2", chain.next().unwrap().to_string());
assert_eq!("1", chain.next().unwrap().to_string());
assert_eq!("0", chain.next().unwrap().to_string());
assert!(chain.next().is_none());
assert!(chain.next_back().is_none());
}
#[test]
fn test_rev() {
maybe_install_handler().unwrap();
let e = error();
let mut chain = e.chain().rev();
assert_eq!("0", chain.next().unwrap().to_string());
assert_eq!("1", chain.next().unwrap().to_string());
assert_eq!("2", chain.next().unwrap().to_string());
assert_eq!("3", chain.next().unwrap().to_string());
assert!(chain.next().is_none());
assert!(chain.next_back().is_none());
}
#[test]
fn test_len() {
maybe_install_handler().unwrap();
let e = error();
let mut chain = e.chain();
assert_eq!(4, chain.len());
assert_eq!("3", chain.next().unwrap().to_string());
assert_eq!(3, chain.len());
assert_eq!("0", chain.next_back().unwrap().to_string());
assert_eq!(2, chain.len());
assert_eq!("2", chain.next().unwrap().to_string());
assert_eq!(1, chain.len());
assert_eq!("1", chain.next_back().unwrap().to_string());
assert_eq!(0, chain.len());
assert!(chain.next().is_none());
}

View file

@ -0,0 +1,173 @@
mod common;
mod drop;
use crate::common::maybe_install_handler;
use crate::drop::{DetectDrop, Flag};
use eyre::{Report, Result, WrapErr};
use std::fmt::{self, Display};
use thiserror::Error;
// https://github.com/dtolnay/eyre/issues/18
#[test]
fn test_inference() -> Result<()> {
let x = "1";
let y: u32 = x.parse().wrap_err("...")?;
assert_eq!(y, 1);
Ok(())
}
macro_rules! context_type {
($name:ident) => {
#[derive(Debug)]
#[repr(C)]
struct $name {
_drop: DetectDrop,
message: &'static str,
}
impl Display for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.message)
}
}
};
}
context_type!(HighLevel);
context_type!(MidLevel);
#[derive(Error, Debug)]
#[error("{message}")]
#[repr(C)]
struct LowLevel {
message: &'static str,
drop: DetectDrop,
}
struct Dropped {
low: Flag,
mid: Flag,
high: Flag,
}
impl Dropped {
fn none(&self) -> bool {
!self.low.get() && !self.mid.get() && !self.high.get()
}
fn all(&self) -> bool {
self.low.get() && self.mid.get() && self.high.get()
}
}
fn make_chain() -> (Report, Dropped) {
let dropped = Dropped {
low: Flag::new(),
mid: Flag::new(),
high: Flag::new(),
};
let low = LowLevel {
message: "no such file or directory",
drop: DetectDrop::new("LowLevel", &dropped.low),
};
// impl Report for Result<T, E>
let mid = Err::<(), LowLevel>(low)
.wrap_err(MidLevel {
message: "failed to load config",
_drop: DetectDrop::new("MidLevel", &dropped.mid),
})
.unwrap_err();
// impl Report for Result<T, Error>
let high = Err::<(), Report>(mid)
.wrap_err(HighLevel {
message: "failed to start server",
_drop: DetectDrop::new("HighLevel", &dropped.high),
})
.unwrap_err();
(high, dropped)
}
#[test]
fn test_downcast_ref() {
maybe_install_handler().unwrap();
let (err, dropped) = make_chain();
assert!(!err.is::<String>());
assert!(err.downcast_ref::<String>().is_none());
assert!(err.is::<HighLevel>());
let high = err.downcast_ref::<HighLevel>().unwrap();
assert_eq!(high.to_string(), "failed to start server");
assert!(err.is::<MidLevel>());
let mid = err.downcast_ref::<MidLevel>().unwrap();
assert_eq!(mid.to_string(), "failed to load config");
assert!(err.is::<LowLevel>());
let low = err.downcast_ref::<LowLevel>().unwrap();
assert_eq!(low.to_string(), "no such file or directory");
assert!(dropped.none());
drop(err);
assert!(dropped.all());
}
#[test]
fn test_downcast_high() {
maybe_install_handler().unwrap();
let (err, dropped) = make_chain();
let err = err.downcast::<HighLevel>().unwrap();
assert!(!dropped.high.get());
assert!(dropped.low.get() && dropped.mid.get());
drop(err);
assert!(dropped.all());
}
#[test]
fn test_downcast_mid() {
maybe_install_handler().unwrap();
let (err, dropped) = make_chain();
let err = err.downcast::<MidLevel>().unwrap();
assert!(!dropped.mid.get());
assert!(dropped.low.get() && dropped.high.get());
drop(err);
assert!(dropped.all());
}
#[test]
fn test_downcast_low() {
maybe_install_handler().unwrap();
let (err, dropped) = make_chain();
let err = err.downcast::<LowLevel>().unwrap();
assert!(!dropped.low.get());
assert!(dropped.mid.get() && dropped.high.get());
drop(err);
assert!(dropped.all());
}
#[test]
fn test_unsuccessful_downcast() {
maybe_install_handler().unwrap();
let (err, dropped) = make_chain();
let err = err.downcast::<String>().unwrap_err();
assert!(dropped.none());
drop(err);
assert!(dropped.all());
}

View file

@ -0,0 +1,13 @@
mod common;
use crate::common::maybe_install_handler;
#[test]
fn test_context() {
use eyre::{eyre, Report};
maybe_install_handler().unwrap();
let error: Report = eyre!("oh no!");
let _ = error.context();
}

View file

@ -0,0 +1,28 @@
mod common;
mod drop;
use self::common::maybe_install_handler;
use self::drop::{DetectDrop, Flag};
use eyre::{Report, Result};
use std::error::Error as StdError;
#[test]
fn test_convert() {
maybe_install_handler().unwrap();
let has_dropped = Flag::new();
let error: Report = Report::new(DetectDrop::new("TestConvert", &has_dropped));
let box_dyn = Box::<dyn StdError + Send + Sync>::from(error);
assert_eq!("oh no!", box_dyn.to_string());
drop(box_dyn);
assert!(has_dropped.get());
}
#[test]
fn test_question_mark() -> Result<(), Box<dyn StdError>> {
fn f() -> Result<()> {
Ok(())
}
f()?;
Ok(())
}

View file

@ -0,0 +1,148 @@
mod common;
mod drop;
use self::common::*;
use self::drop::{DetectDrop, Flag};
use eyre::Report;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;
#[test]
fn test_downcast() {
maybe_install_handler().unwrap();
#[cfg(not(eyre_no_fmt_arguments_as_str))]
assert_eq!(
"oh no!",
bail_literal().unwrap_err().downcast::<&str>().unwrap(),
);
#[cfg(eyre_no_fmt_arguments_as_str)]
assert_eq!(
"oh no!",
bail_literal().unwrap_err().downcast::<String>().unwrap(),
);
assert_eq!(
"oh no!",
bail_fmt().unwrap_err().downcast::<String>().unwrap(),
);
assert_eq!(
"oh no!",
bail_error()
.unwrap_err()
.downcast::<io::Error>()
.unwrap()
.to_string(),
);
}
#[test]
fn test_downcast_ref() {
maybe_install_handler().unwrap();
#[cfg(not(eyre_no_fmt_arguments_as_str))]
assert_eq!(
"oh no!",
*bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(),
);
#[cfg(eyre_no_fmt_arguments_as_str)]
assert_eq!(
"oh no!",
*bail_literal()
.unwrap_err()
.downcast_ref::<String>()
.unwrap(),
);
assert_eq!(
"oh no!",
bail_fmt().unwrap_err().downcast_ref::<String>().unwrap(),
);
assert_eq!(
"oh no!",
bail_error()
.unwrap_err()
.downcast_ref::<io::Error>()
.unwrap()
.to_string(),
);
}
#[test]
fn test_downcast_mut() {
maybe_install_handler().unwrap();
#[cfg(not(eyre_no_fmt_arguments_as_str))]
assert_eq!(
"oh no!",
*bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(),
);
#[cfg(eyre_no_fmt_arguments_as_str)]
assert_eq!(
"oh no!",
*bail_literal()
.unwrap_err()
.downcast_mut::<String>()
.unwrap(),
);
assert_eq!(
"oh no!",
bail_fmt().unwrap_err().downcast_mut::<String>().unwrap(),
);
assert_eq!(
"oh no!",
bail_error()
.unwrap_err()
.downcast_mut::<io::Error>()
.unwrap()
.to_string(),
);
}
#[test]
fn test_drop() {
maybe_install_handler().unwrap();
let has_dropped = Flag::new();
let error: Report = Report::new(DetectDrop::new("DetectDrop", &has_dropped));
drop(error.downcast::<DetectDrop>().unwrap());
assert!(has_dropped.get());
}
#[test]
fn test_large_alignment() {
maybe_install_handler().unwrap();
#[repr(align(64))]
#[derive(Debug)]
struct LargeAlignedError(&'static str);
impl Display for LargeAlignedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.0)
}
}
impl StdError for LargeAlignedError {}
let error = Report::new(LargeAlignedError("oh no!"));
assert_eq!(
"oh no!",
error.downcast_ref::<LargeAlignedError>().unwrap().0
);
}
#[test]
fn test_unsuccessful_downcast() {
maybe_install_handler().unwrap();
let mut error = bail_error().unwrap_err();
assert!(error.downcast_ref::<&str>().is_none());
assert!(error.downcast_mut::<&str>().is_none());
assert!(error.downcast::<&str>().is_err());
}

View file

@ -0,0 +1,105 @@
mod common;
use self::common::maybe_install_handler;
use eyre::{bail, Result, WrapErr};
use std::io;
fn f() -> Result<()> {
bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!"));
}
fn g() -> Result<()> {
f().wrap_err("f failed")
}
fn h() -> Result<()> {
g().wrap_err("g failed")
}
const EXPECTED_ALTDISPLAY_F: &str = "oh no!";
const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!";
const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!";
const EXPECTED_DEBUG_F: &str = "oh no!";
const EXPECTED_DEBUG_G: &str = "\
f failed
Caused by:
oh no!\
";
const EXPECTED_DEBUG_H: &str = "\
g failed
Caused by:
0: f failed
1: oh no!\
";
const EXPECTED_ALTDEBUG_F: &str = "\
Custom {
kind: PermissionDenied,
error: \"oh no!\",
}\
";
const EXPECTED_ALTDEBUG_G: &str = "\
Error {
msg: \"f failed\",
source: Custom {
kind: PermissionDenied,
error: \"oh no!\",
},
}\
";
const EXPECTED_ALTDEBUG_H: &str = "\
Error {
msg: \"g failed\",
source: Error {
msg: \"f failed\",
source: Custom {
kind: PermissionDenied,
error: \"oh no!\",
},
},
}\
";
#[test]
fn test_display() {
maybe_install_handler().unwrap();
assert_eq!("g failed", h().unwrap_err().to_string());
}
#[test]
fn test_altdisplay() {
maybe_install_handler().unwrap();
assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err()));
assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err()));
assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err()));
}
#[test]
#[cfg_attr(any(backtrace, track_caller), ignore)]
fn test_debug() {
maybe_install_handler().unwrap();
assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err()));
assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err()));
assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err()));
}
#[test]
fn test_altdebug() {
maybe_install_handler().unwrap();
assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err()));
assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err()));
assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err()));
}

View file

@ -0,0 +1,183 @@
use std::panic::Location;
use eyre::{OptionExt as _, WrapErr};
struct LocationHandler {
actual: Option<&'static str>,
expected: &'static str,
}
impl LocationHandler {
fn new(expected: &'static str) -> Self {
LocationHandler {
actual: None,
expected,
}
}
}
impl eyre::EyreHandler for LocationHandler {
fn debug(
&self,
_error: &(dyn std::error::Error + 'static),
_f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
// we assume that if the compiler is new enough to support
// `track_caller` that we will always have `actual` be `Some`, so we can
// safely skip the assertion if the location is `None` which should only
// happen in older rust versions.
if let Some(actual) = self.actual {
assert_eq!(self.expected, actual);
}
Ok(())
}
fn track_caller(&mut self, location: &'static Location<'static>) {
dbg!(location);
self.actual = Some(location.file());
}
}
#[test]
fn test_wrap_err() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
let err = read_path("totally_fake_path")
.wrap_err("oopsie")
.unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[cfg(not(miri))]
fn read_path(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
#[cfg(miri)]
fn read_path(_path: &str) -> Result<String, std::io::Error> {
// Miri doesn't support reading files, so we just return an error
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Miri doesn't support reading files",
))
}
#[test]
fn test_wrap_err_with() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
let err = read_path("totally_fake_path")
.wrap_err_with(|| "oopsie")
.unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_option_ok_or_eyre() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
let err = None::<()>.ok_or_eyre("oopsie").unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_context() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
let err = read_path("totally_fake_path")
.context("oopsie")
.unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_with_context() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
let err = read_path("totally_fake_path")
.with_context(|| "oopsie")
.unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_option_compat_wrap_err() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
use eyre::ContextCompat;
let err = None::<()>.wrap_err("oopsie").unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_option_compat_wrap_err_with() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
use eyre::ContextCompat;
let err = None::<()>.wrap_err_with(|| "oopsie").unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_option_compat_context() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
use eyre::ContextCompat;
let err = None::<()>.context("oopsie").unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}
#[test]
fn test_option_compat_with_context() {
let _ = eyre::set_hook(Box::new(|_e| {
let expected_location = file!();
Box::new(LocationHandler::new(expected_location))
}));
use eyre::ContextCompat;
let err = None::<()>.with_context(|| "oopsie").unwrap_err();
// should panic if the location isn't in our crate
println!("{:?}", err);
}

View file

@ -0,0 +1,102 @@
#![allow(clippy::eq_op)]
mod common;
use self::common::*;
use eyre::{ensure, eyre, Result};
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::task::Poll;
#[test]
fn test_messages() {
maybe_install_handler().unwrap();
assert_eq!("oh no!", bail_literal().unwrap_err().to_string());
assert_eq!("oh no!", bail_fmt().unwrap_err().to_string());
assert_eq!("oh no!", bail_error().unwrap_err().to_string());
}
#[test]
fn test_ensure() {
maybe_install_handler().unwrap();
let f = || -> Result<()> {
ensure!(1 + 1 == 2, "This is correct");
Ok(())
};
assert!(f().is_ok());
let v = 1;
let f = || -> Result<()> {
ensure!(v + v == 2, "This is correct, v: {}", v);
Ok(())
};
assert!(f().is_ok());
let f = || -> Result<()> {
ensure!(v + v == 1, "This is not correct, v: {}", v);
Ok(())
};
assert!(f().is_err());
let f = || {
ensure!(v + v == 1);
Ok(())
};
assert_eq!(
f().unwrap_err().to_string(),
"Condition failed: `v + v == 1`",
);
}
#[test]
fn test_temporaries() {
struct Ready<T>(Option<T>);
impl<T> Unpin for Ready<T> {}
impl<T> Future for Ready<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> Poll<T> {
Poll::Ready(self.0.take().unwrap())
}
}
fn require_send_sync(_: impl Send + Sync) {}
require_send_sync(async {
// If eyre hasn't dropped any temporary format_args it creates by the
// time it's done evaluating, those will stick around until the
// semicolon, which is on the other side of the await point, making the
// enclosing future non-Send.
let _ = Ready(Some(eyre!("..."))).await;
});
fn message(cell: Cell<&str>) -> &str {
cell.get()
}
require_send_sync(async {
let _ = Ready(Some(eyre!(message(Cell::new("..."))))).await;
});
}
#[test]
#[cfg(not(eyre_no_fmt_args_capture))]
fn test_capture_format_args() {
maybe_install_handler().unwrap();
let var = 42;
let err = eyre!("interpolate {var}");
assert_eq!("interpolate 42", err.to_string());
}
#[test]
fn test_brace_escape() {
maybe_install_handler().unwrap();
let err = eyre!("unterminated ${{..}} expression");
assert_eq!("unterminated ${..} expression", err.to_string());
}

View file

@ -0,0 +1,18 @@
#![cfg(not(feature = "auto-install"))]
use eyre::{eyre, set_hook, DefaultHandler, Report};
#[test]
fn test_no_hook_panic() {
let panic_res = std::panic::catch_unwind(|| eyre!("this will never be displayed"));
assert!(panic_res.is_err());
let downcast_res = panic_res.unwrap_err().downcast::<String>();
assert_eq!(
*downcast_res.unwrap(),
"a handler must always be installed if the `auto-install` feature is disabled"
);
assert!(set_hook(Box::new(DefaultHandler::default_with)).is_ok());
let _error: Report = eyre!("this will be displayed if returned");
}

View file

@ -0,0 +1,15 @@
mod common;
use self::common::maybe_install_handler;
use eyre::OptionExt;
#[test]
fn test_option_ok_or_eyre() {
maybe_install_handler().unwrap();
let option: Option<()> = None;
let result = option.ok_or_eyre("static str error");
assert_eq!(result.unwrap_err().to_string(), "static str error");
}

View file

@ -0,0 +1,33 @@
#![cfg(feature = "pyo3")]
use pyo3::prelude::*;
use eyre::{bail, Result, WrapErr};
fn f() -> Result<()> {
use std::io;
bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!"));
}
fn g() -> Result<()> {
f().wrap_err("f failed")
}
fn h() -> Result<()> {
g().wrap_err("g failed")
}
#[test]
fn test_pyo3_exception_contents() {
use pyo3::types::IntoPyDict;
let err = h().unwrap_err();
let expected_contents = format!("{:?}", err);
let pyerr = PyErr::from(err);
Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run("raise err", None, Some(locals)).unwrap_err();
assert_eq!(pyerr.value(py).to_string(), expected_contents);
})
}

View file

@ -0,0 +1,36 @@
mod common;
mod drop;
use self::common::maybe_install_handler;
use self::drop::{DetectDrop, Flag};
use eyre::Report;
use std::marker::Unpin;
use std::mem;
#[test]
fn test_error_size() {
assert_eq!(mem::size_of::<Report>(), mem::size_of::<usize>());
}
#[test]
fn test_null_pointer_optimization() {
assert_eq!(
mem::size_of::<Result<(), Report>>(),
mem::size_of::<usize>()
);
}
#[test]
fn test_autotraits() {
fn assert<E: Unpin + Send + Sync + 'static>() {}
assert::<Report>();
}
#[test]
fn test_drop() {
maybe_install_handler().unwrap();
let has_dropped = Flag::new();
drop(Report::new(DetectDrop::new("TestDrop", &has_dropped)));
assert!(has_dropped.get());
}

View file

@ -0,0 +1,75 @@
mod common;
use self::common::maybe_install_handler;
use eyre::{eyre, Report};
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;
#[derive(Debug)]
enum TestError {
Io(io::Error),
}
impl Display for TestError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
TestError::Io(e) => Display::fmt(e, formatter),
}
}
}
impl StdError for TestError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
TestError::Io(io) => Some(io),
}
}
}
#[test]
fn test_literal_source() {
maybe_install_handler().unwrap();
let error: Report = eyre!("oh no!");
assert!(error.source().is_none());
}
#[test]
fn test_variable_source() {
maybe_install_handler().unwrap();
let msg = "oh no!";
let error = eyre!(msg);
assert!(error.source().is_none());
let msg = msg.to_owned();
let error: Report = eyre!(msg);
assert!(error.source().is_none());
}
#[test]
fn test_fmt_source() {
maybe_install_handler().unwrap();
let error: Report = eyre!("{} {}!", "oh", "no");
assert!(error.source().is_none());
}
#[test]
fn test_io_source() {
maybe_install_handler().unwrap();
let io = io::Error::new(io::ErrorKind::Other, "oh no!");
let error: Report = eyre!(TestError::Io(io));
assert_eq!("oh no!", error.source().unwrap().to_string());
}
#[test]
fn test_eyre_from_eyre() {
maybe_install_handler().unwrap();
let error: Report = eyre!("oh no!").wrap_err("context");
let error = eyre!(error);
assert_eq!("oh no!", error.source().unwrap().to_string());
}

View file

@ -0,0 +1,34 @@
// These tests check our build script against rustversion.
#[rustversion::attr(not(nightly), ignore)]
#[test]
fn nightlytest() {
if !cfg!(nightly) {
panic!("nightly feature isn't set when the toolchain is nightly.");
}
if cfg!(any(beta, stable)) {
panic!("beta, stable, and nightly are mutually exclusive features.")
}
}
#[rustversion::attr(not(beta), ignore)]
#[test]
fn betatest() {
if !cfg!(beta) {
panic!("beta feature is not set when the toolchain is beta.");
}
if cfg!(any(nightly, stable)) {
panic!("beta, stable, and nightly are mutually exclusive features.")
}
}
#[rustversion::attr(not(stable), ignore)]
#[test]
fn stabletest() {
if !cfg!(stable) {
panic!("stable feature is not set when the toolchain is stable.");
}
if cfg!(any(nightly, beta)) {
panic!("beta, stable, and nightly are mutually exclusive features.")
}
}