use std::fmt::Debug;
use std::time::Instant;
use crate::core::{TestCase, TestStatus};
pub fn parametrize<Input, Test>(
name: &str,
cases: impl IntoIterator<Item = Input>,
test: Test,
) -> Vec<TestCase>
where
Input: Debug,
Test: Fn(&Input),
{
let mut results = Vec::new();
for (index, input) in cases.into_iter().enumerate() {
let test_name = format!("{}[{}]", name, index);
let start = Instant::now();
let status = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
test(&input);
}));
let duration = start.elapsed();
let status = match status {
Ok(_) => TestStatus::Passed,
Err(panic_info) => {
let reason = extract_panic_message(&panic_info);
TestStatus::Failed { reason, location: None }
}
};
results.push(TestCase {
name: test_name,
suite: Some(name.to_owned()),
tags: Vec::new(),
status,
duration,
assertions: 0,
location: None,
parameters: vec![("input".to_owned(), format!("{input:?}"))],
});
}
results
}
pub fn parametrize_named<'a, Input, Test>(
suite_name: &str,
cases: impl IntoIterator<Item = (&'a str, Input)>,
test: Test,
) -> Vec<TestCase>
where
Input: Debug,
Test: Fn(&Input),
{
let mut results = Vec::new();
for (label, input) in cases.into_iter() {
let test_name = format!("{} :: {}", suite_name, label);
let start = Instant::now();
let status = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
test(&input);
}));
let duration = start.elapsed();
let status = match status {
Ok(_) => TestStatus::Passed,
Err(panic_info) => {
let reason = extract_panic_message(&panic_info);
TestStatus::Failed { reason, location: None }
}
};
results.push(TestCase {
name: test_name,
suite: Some(suite_name.to_owned()),
tags: Vec::new(),
status,
duration,
assertions: 0,
location: None,
parameters: vec![("input".to_owned(), format!("{input:?}"))],
});
}
results
}
fn extract_panic_message(panic_info: &Box<dyn std::any::Any + Send>) -> String {
if let Some(s) = panic_info.downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = panic_info.downcast_ref::<String>() {
s.clone()
} else {
"test panicked".to_owned()
}
}