macro_rules! assert_throws {
( $block:block, $message:literal $(,)? ) => {
let error = std::panic::catch_unwind(move || $block).unwrap_err();
if let Some(s) = error.downcast_ref::<&'static str>() {
assert_eq!(*s, $message);
} else if let Some(s) = error.downcast_ref::<String>() {
assert_eq!(s, $message);
} else {
panic!("unexpected panic payload: {:?}", error);
}
};
( $statement:stmt, $message:literal $(,)? ) => {
assert_throws!({ $statement }, $message);
};
}
#[test]
fn test_assert() {
let x = 1;
assert_throws!(assert!(x == 2), "assertion failed: x == 2",);
}
#[test]
fn test_assert_eq() {
let x = 1;
if rustc_version::version().unwrap() < rustc_version::Version::new(1, 75, 0) {
assert_throws!(
assert_eq!(x, 2),
"assertion failed: `(left == right)`
left: `1`,
right: `2`",
);
} else {
assert_throws!(
assert_eq!(x, 2),
"assertion `left == right` failed
left: 1
right: 2",
);
}
}
#[test]
fn test_assert_message() {
let x = 1;
assert_throws!(
assert!(x == 2, "x={}", x),
"x=1", );
}
#[test]
fn test_assert_eq_message() {
let x = 1;
if rustc_version::version().unwrap() < rustc_version::Version::new(1, 75, 0) {
assert_throws!(
assert_eq!(x, 2, "x={}", x),
"assertion failed: `(left == right)`
left: `1`,
right: `2`: x=1",
);
} else {
assert_throws!(
assert_eq!(x, 2, "x={}", x),
"assertion `left == right` failed: x=1
left: 1
right: 2",
);
}
}
#[test]
fn test_one_assert() {
let x = 1;
assert_throws!(
one_assert::assert!(x == 2),
"assertion `x == 2` failed
left: 1
right: 2",
);
let x = true;
assert_throws!(
one_assert::assert!(x && false),
"assertion `x && false` failed
caused by: left side of `&&` evaluated to true, but right side evaluated to false",
);
}
#[test]
fn test_one_assert_message() {
let x = 1;
assert_throws!(
one_assert::assert!(x == 2, "x={}", x),
"assertion `x == 2` failed: x=1
left: 1
right: 2",
);
let x = true;
assert_throws!(
one_assert::assert!(x && false, "x={}", x),
"assertion `x && false` failed: x=true
caused by: left side of `&&` evaluated to true, but right side evaluated to false",
);
}
#[test]
fn test_misc() {
one_assert::assert!(!"abc123".replace(|c: char| c.is_alphabetic(), "").is_empty());
}
#[test]
fn test_single_evaluation() {
fn create_caller() -> impl FnMut() -> bool {
let mut called = false;
move || {
assert!(!called);
called = true;
true
}
}
let mut caller = create_caller();
one_assert::assert!(caller());
one_assert::assert!(create_caller()());
let mut caller = create_caller();
one_assert::assert!(caller() == true);
let mut caller = create_caller();
assert_throws!(
one_assert::assert!(caller() == false),
"assertion `caller() == false` failed
left: true
right: false",
);
}
#[test]
fn test_borrows_input() {
static mut CALLED_DEBUG: i32 = 0;
struct PanicsOnDebug;
impl std::fmt::Debug for PanicsOnDebug {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unsafe {
CALLED_DEBUG += 1;
}
f.write_str("hi")
}
}
impl PartialEq<i32> for PanicsOnDebug {
fn eq(&self, x: &i32) -> bool {
*x == 1
}
}
let x = PanicsOnDebug;
one_assert::assert!(x == 1); let num_called = unsafe { CALLED_DEBUG };
assert_eq!(num_called, 0);
assert_throws!(
one_assert::assert!(x == 2),
"assertion `x == 2` failed
left: hi
right: 2",
);
let num_called = unsafe { CALLED_DEBUG };
assert_eq!(num_called, 1);
}
#[test]
fn test_crazy_nonsense() {
#[derive(Debug)]
struct AddsToBool(i32);
impl std::ops::Add for AddsToBool {
type Output = bool;
fn add(self, rhs: Self) -> bool {
self.0 == rhs.0
}
}
let x = AddsToBool(1);
one_assert::assert!(x + AddsToBool(1));
let x = AddsToBool(1);
assert_throws!(
one_assert::assert!(x + AddsToBool(2)),
"assertion `x + AddsToBool(2)` failed
left: AddsToBool(1)
right: AddsToBool(2)",
);
}
#[test]
#[ignore]
fn error_message_tests() {
let root = std::path::PathBuf::from("tests/fail");
let base_paths = vec![root.clone(), root.join("expr")];
let nightly = rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly;
let channel = if nightly { "nightly" } else { "stable" };
let mut paths = base_paths.clone();
paths.extend(base_paths.iter().map(|p| p.join(channel)));
let t = trybuild::TestCases::new();
for mut path in paths {
path.push("*.rs");
t.compile_fail(path.display().to_string());
}
}