1//! Test results and errors
23use crate::Case;
4use reth_db::DatabaseError;
5use reth_provider::ProviderError;
6use std::path::{Path, PathBuf};
7use thiserror::Error;
89/// Test errors
10///
11/// # Note
12///
13/// `Error::Skipped` should not be treated as a test failure.
14#[derive(Debug, Error)]
15#[non_exhaustive]
16pub enum Error {
17/// The test was skipped
18#[error("test was skipped")]
19Skipped,
20/// No post state found in test
21#[error("no post state found for validation")]
22MissingPostState,
23/// An IO error occurred
24#[error("an error occurred interacting with the file system at {path}: {error}")]
25Io {
26/// The path to the file or directory
27path: PathBuf,
28/// The specific error
29#[source]
30error: std::io::Error,
31 },
32/// A deserialization error occurred
33#[error("an error occurred deserializing the test at {path}: {error}")]
34CouldNotDeserialize {
35/// The path to the file we wanted to deserialize
36path: PathBuf,
37/// The specific error
38#[source]
39error: serde_json::Error,
40 },
41/// A database error occurred.
42#[error(transparent)]
43Database(#[from] DatabaseError),
44/// A test assertion failed.
45#[error("test failed: {0}")]
46Assertion(String),
47/// An error internally in reth occurred.
48#[error("test failed: {0}")]
49Provider(#[from] ProviderError),
50/// An error occurred while decoding RLP.
51#[error("an error occurred deserializing RLP: {0}")]
52RlpDecodeError(#[from] alloy_rlp::Error),
53}
5455/// The result of running a test.
56#[derive(Debug)]
57pub struct CaseResult {
58/// A description of the test.
59pub desc: String,
60/// The full path to the test.
61pub path: PathBuf,
62/// The result of the test.
63pub result: Result<(), Error>,
64}
6566impl CaseResult {
67/// Create a new test result.
68pub fn new(path: &Path, case: &impl Case, result: Result<(), Error>) -> Self {
69Self { desc: case.description(), path: path.into(), result }
70 }
71}
7273/// Assert that all the given tests passed and print the results to stdout.
74pub(crate) fn assert_tests_pass(suite_name: &str, path: &Path, results: &[CaseResult]) {
75let (passed, failed, skipped) = categorize_results(results);
7677print_results(suite_name, path, &passed, &failed, &skipped);
7879assert!(failed.is_empty(), "Some tests failed (see above)");
80}
8182/// Categorize test results into `(passed, failed, skipped)`.
83pub(crate) fn categorize_results(
84 results: &[CaseResult],
85) -> (Vec<&CaseResult>, Vec<&CaseResult>, Vec<&CaseResult>) {
86let mut passed = Vec::new();
87let mut failed = Vec::new();
88let mut skipped = Vec::new();
8990for case in results {
91match case.result.as_ref().err() {
92Some(Error::Skipped) => skipped.push(case),
93Some(_) => failed.push(case),
94None => passed.push(case),
95 }
96 }
9798 (passed, failed, skipped)
99}
100101/// Display the given test results to stdout.
102pub(crate) fn print_results(
103 suite_name: &str,
104 path: &Path,
105 passed: &[&CaseResult],
106 failed: &[&CaseResult],
107 skipped: &[&CaseResult],
108) {
109println!("Suite: {suite_name} (at {})", path.display());
110println!(
111"Ran {} tests ({} passed, {} failed, {} skipped)",
112 passed.len() + failed.len() + skipped.len(),
113 passed.len(),
114 failed.len(),
115 skipped.len()
116 );
117118for case in skipped {
119println!("[S] Case {} skipped", case.path.display());
120 }
121122for case in failed {
123let error = case.result.as_ref().unwrap_err();
124println!("[!] Case {} failed (description: {}): {}", case.path.display(), case.desc, error);
125 }
126}