Proposal: Introducing the `assert_panic!` Macro for Testing Panic Messages in Rust
Nobody has claimed this yet.
- Dominant language
- Markdown
- Stars
- 6.6k
- Forks
- 1.7k
- Avg merge
- 16h 14m
- Merged PRs (30d)
- 1
Description
Introduction
In Rust, the standard library provides macros like assert! and panic! for handling errors and testing code correctness. However, there is no built-in macro for capturing a panic and checking its message. This proposal aims to introduce a new macro, assert_panic!, which will allow developers to test if a specific panic message is triggered in their code.
Motivation
When writing tests in Rust, it is often necessary to ensure that a function or method panics under certain conditions. While the standard library provides macros like assert! and panic!, they do not offer a way to capture the panic message and check if it matches the expected message.
Having a macro like assert_panic! would simplify the process of testing panic messages and make it more convenient for developers to verify that their code behaves as expected in panic scenarios.
Proposed Solution
The assert_panic! macro will be designed to capture a panic and check if its message matches the expected message. Here's an example of how the macro can be used:
#[test]
fn test_permute_panic() {
let data = &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
let shape = &[2, 3];
let tensor = Tensor::new(data, shape);
assert_panic!(
tensor.permute(&[1]),
"The panic message inside permute()"
);
}
The assert_panic! macro will be implemented as follows:
#[macro_export]
macro_rules! assert_panic {
($expr:expr) => {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| $expr)) {
Ok(_) => panic!("Expression did not trigger panic"),
Err(_) => (),
}
};
($expr:expr, $expected_msg:expr) => {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| $expr)) {
Ok(_) => panic!("Expression did not trigger panic"),
Err(err) => {
let expected_msg_str = $expected_msg.to_string();
if let Some(msg) = err.downcast_ref::<&'static str>() {
assert_eq!(*msg, expected_msg_str, "Panic message does not match expected");
} else if let Some(msg) = err.downcast_ref::<String>() {
assert_eq!(*msg, expected_msg_str, "Panic message does not match expected");
} else {
panic!("Expected panic message not found, expected panic message: {}", expected_msg_str);
}
}
}
};
}
Without this, users have to manually write code like this:
let result = std::panic::catch_unwind(|| {
tensor.permute(&[1]);
});
assert!(result.is_err(), "should trigger panic");
let panic_info = result.unwrap_err();
let panic_msg = panic_info
.downcast_ref::<&'static str>()
.expect("Expected panic message not found");
assert_eq!(*panic_msg, "The panic message inside permute()");
Other thoughts
I don't know if this behavior is not encouraged or not, I see the macro assert_ne! is merged from crate assert_ne, while the similar assert-panic didn't.
Conclusion
Introducing the assert_panic! macro will provide a convenient way for Rust developers to test panic messages in their code. This macro will simplify the process of verifying that a function or method panics with the expected message, making it easier for developers to ensure that their code behaves correctly in panic scenarios.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the proposal's assert_panic! examples and implementation, then compare the referenced assert_ne and assert-panic crates. Done means reaching agreement on whether this belongs in Rust and on an accepted design for testing panic messages.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100