use crate::Case;
use reth_db::DatabaseError;
use reth_provider::ProviderError;
use std::path::{Path, PathBuf};
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("test was skipped")]
Skipped,
#[error("no post state found for validation")]
MissingPostState,
#[error("an error occurred interacting with the file system at {path}: {error}")]
Io {
path: PathBuf,
#[source]
error: std::io::Error,
},
#[error("an error occurred deserializing the test at {path}: {error}")]
CouldNotDeserialize {
path: PathBuf,
#[source]
error: serde_json::Error,
},
#[error(transparent)]
Database(#[from] DatabaseError),
#[error("test failed: {0}")]
Assertion(String),
#[error("test failed: {0}")]
Provider(#[from] ProviderError),
#[error("an error occurred deserializing RLP: {0}")]
RlpDecodeError(#[from] alloy_rlp::Error),
}
#[derive(Debug)]
pub struct CaseResult {
pub desc: String,
pub path: PathBuf,
pub result: Result<(), Error>,
}
impl CaseResult {
pub fn new(path: &Path, case: &impl Case, result: Result<(), Error>) -> Self {
Self { desc: case.description(), path: path.into(), result }
}
}
pub(crate) fn assert_tests_pass(suite_name: &str, path: &Path, results: &[CaseResult]) {
let (passed, failed, skipped) = categorize_results(results);
print_results(suite_name, path, &passed, &failed, &skipped);
assert!(failed.is_empty(), "Some tests failed (see above)");
}
pub(crate) fn categorize_results(
results: &[CaseResult],
) -> (Vec<&CaseResult>, Vec<&CaseResult>, Vec<&CaseResult>) {
let mut passed = Vec::new();
let mut failed = Vec::new();
let mut skipped = Vec::new();
for case in results {
match case.result.as_ref().err() {
Some(Error::Skipped) => skipped.push(case),
Some(_) => failed.push(case),
None => passed.push(case),
}
}
(passed, failed, skipped)
}
pub(crate) fn print_results(
suite_name: &str,
path: &Path,
passed: &[&CaseResult],
failed: &[&CaseResult],
skipped: &[&CaseResult],
) {
println!("Suite: {suite_name} (at {})", path.display());
println!(
"Ran {} tests ({} passed, {} failed, {} skipped)",
passed.len() + failed.len() + skipped.len(),
passed.len(),
failed.len(),
skipped.len()
);
for case in skipped {
println!("[S] Case {} skipped", case.path.display());
}
for case in failed {
let error = case.result.as_ref().unwrap_err();
println!("[!] Case {} failed (description: {}): {}", case.path.display(), case.desc, error);
}
}