feat(net): don't use panic to signal test should fail
All checks were successful
Test / build (map[name:nightly]) (push) Successful in 4m43s
Test / build (map[name:stable]) (push) Successful in 5m3s
Release Please / Release-plz (push) Successful in 40s

This commit is contained in:
Paul Campbell 2024-12-07 20:37:05 +00:00
parent b6a236ab74
commit 8534eca219
2 changed files with 80 additions and 21 deletions

View file

@ -611,36 +611,95 @@ impl From<MockNet> for Net {
}
impl Drop for MockNet {
#[cfg_attr(test, mutants::skip)]
#[tracing::instrument]
fn drop(&mut self) {
let unused = self.plans.take();
if unused.is_empty() {
tracing::trace!("no unused expected requests");
return; // all good
// Don't assert during panic to avoid double panic
if std::thread::panicking() {
return;
}
let unused = self.plans.take();
if !unused.is_empty() {
log_unused_plans(&unused);
assert!(
unused.is_empty(),
"{} expected requests were not made",
unused.len()
);
}
panic_with_unused_plans(unused);
}
}
impl Drop for Net {
#[cfg_attr(test, mutants::skip)]
#[tracing::instrument]
fn drop(&mut self) {
// Don't assert during panic to avoid double panic
if std::thread::panicking() {
return;
}
if let Some(plans) = &self.plans {
let unused = plans.try_lock().expect("lock plans").take();
if unused.is_empty() {
tracing::trace!("no unused expected requests");
return; // all good
if !unused.is_empty() {
log_unused_plans(&unused);
assert!(
unused.is_empty(),
"{} expected requests were not made",
unused.len()
);
}
panic_with_unused_plans(unused);
}
}
}
fn panic_with_unused_plans(unused: Vec<Plan>) {
eprintln!("These requests were expected, but not made:");
for plan in unused {
eprintln!("- {plan}");
#[cfg_attr(test, mutants::skip)]
fn log_unused_plans(unused: &[Plan]) {
if !unused.is_empty() {
eprintln!(
"Net::drop(): {} expected requests were not made:\n{}",
unused.len(),
unused
.iter()
.map(|p| format!(" - {}", p))
.collect::<Vec<_>>()
.join("\n")
);
}
}
impl Net {
/// Assert that all expected requests were made.
/// This will fail the test if there are any unused plans.
#[cfg_attr(test, mutants::skip)]
pub fn assert_no_unused_plans(&self) {
if let Some(plans) = &self.plans {
let unused = plans.try_lock().expect("lock plans").take();
if !unused.is_empty() {
log_unused_plans(&unused);
assert!(
unused.is_empty(),
"{} expected requests were not made",
unused.len()
);
}
}
}
}
impl MockNet {
/// Assert that all expected requests were made.
/// This will fail the test if there are any unused plans.
#[cfg_attr(test, mutants::skip)]
pub fn assert_no_unused_plans(&self) {
let unused = self.plans.take();
if !unused.is_empty() {
log_unused_plans(&unused);
assert!(
unused.is_empty(),
"{} expected requests were not made",
unused.len()
);
}
}
panic!("There were expected requests that were not made.");
}
#[derive(Debug, Clone, PartialEq, Eq)]

View file

@ -335,7 +335,7 @@ async fn test_post_by_header_wrong_value() {
}
#[tokio::test]
#[should_panic]
#[should_panic(expected = "1 expected requests were not made")]
async fn test_unused_post_as_net() {
//given
let mock_net = kxio::net::mock();
@ -349,18 +349,18 @@ async fn test_unused_post_as_net() {
.body("Post OK")
.expect("mock");
let _net = Net::from(mock_net);
let net = Net::from(mock_net);
//when
// don't send the planned request
// let _response = Net::from(net).send(client.post(url)).await.expect("send");
// let _response = net.send(client.post(url)).await.expect("send");
//then
// Drop implementation for net should panic
net.assert_no_unused_plans();
}
#[tokio::test]
#[should_panic]
#[should_panic(expected = "1 expected requests were not made")]
async fn test_unused_post_as_mocknet() {
//given
let mock_net = kxio::net::mock();
@ -376,10 +376,10 @@ async fn test_unused_post_as_mocknet() {
//when
// don't send the planned request
// let _response = Net::from(net).send(client.post(url)).await.expect("send");
// let _response = mock_net.send(client.post(url)).await.expect("send");
//then
// Drop implementation for mock_net should panic
mock_net.assert_no_unused_plans();
}
#[tokio::test]