1use crate::Case;
4use reth_db::DatabaseError;
5use reth_provider::ProviderError;
6use std::path::{Path, PathBuf};
7use thiserror::Error;
8
9#[derive(Debug, Error)]
15#[non_exhaustive]
16pub enum Error {
17 #[error("test was skipped")]
19 Skipped,
20 #[error("no post state found for validation")]
22 MissingPostState,
23 #[error("block {block_number} failed to process: {err}")]
27 BlockProcessingFailed {
28 block_number: u64,
30 #[source]
32 err: Box<dyn std::error::Error + Send + Sync>,
33 },
34 #[error("an error occurred interacting with the file system at {path}: {error}")]
36 Io {
37 path: PathBuf,
39 #[source]
41 error: std::io::Error,
42 },
43 #[error("an error occurred deserializing the test at {path}: {error}")]
45 CouldNotDeserialize {
46 path: PathBuf,
48 #[source]
50 error: serde_json::Error,
51 },
52 #[error(transparent)]
54 Database(#[from] DatabaseError),
55 #[error("test failed: {0}")]
57 Assertion(String),
58 #[error("test failed: {0}")]
60 Provider(#[from] ProviderError),
61 #[error("an error occurred deserializing RLP: {0}")]
63 RlpDecodeError(#[from] alloy_rlp::Error),
64 #[error("an error occurred during consensus checks: {0}")]
66 ConsensusError(#[from] reth_consensus::ConsensusError),
67}
68
69impl Error {
70 pub fn block_failed(
72 block_number: u64,
73 err: impl std::error::Error + Send + Sync + 'static,
74 ) -> Self {
75 Self::BlockProcessingFailed { block_number, err: Box::new(err) }
76 }
77}
78
79#[derive(Debug)]
81pub struct CaseResult {
82 pub desc: String,
84 pub path: PathBuf,
86 pub result: Result<(), Error>,
88}
89
90impl CaseResult {
91 pub fn new(path: &Path, case: &impl Case, result: Result<(), Error>) -> Self {
93 Self { desc: case.description(), path: path.into(), result }
94 }
95}
96
97pub(crate) fn assert_tests_pass(suite_name: &str, path: &Path, results: &[CaseResult]) {
99 let (passed, failed, skipped) = categorize_results(results);
100
101 print_results(suite_name, path, &passed, &failed, &skipped);
102
103 assert!(failed.is_empty(), "Some tests failed (see above)");
104}
105
106pub(crate) fn categorize_results(
108 results: &[CaseResult],
109) -> (Vec<&CaseResult>, Vec<&CaseResult>, Vec<&CaseResult>) {
110 let mut passed = Vec::new();
111 let mut failed = Vec::new();
112 let mut skipped = Vec::new();
113
114 for case in results {
115 match case.result.as_ref().err() {
116 Some(Error::Skipped) => skipped.push(case),
117 Some(_) => failed.push(case),
118 None => passed.push(case),
119 }
120 }
121
122 (passed, failed, skipped)
123}
124
125pub(crate) fn print_results(
127 suite_name: &str,
128 path: &Path,
129 passed: &[&CaseResult],
130 failed: &[&CaseResult],
131 skipped: &[&CaseResult],
132) {
133 println!("Suite: {suite_name} (at {})", path.display());
134 println!(
135 "Ran {} tests ({} passed, {} failed, {} skipped)",
136 passed.len() + failed.len() + skipped.len(),
137 passed.len(),
138 failed.len(),
139 skipped.len()
140 );
141
142 for case in skipped {
143 println!("[S] Case {} skipped", case.path.display());
144 }
145
146 for case in failed {
147 let error = case.result.as_ref().unwrap_err();
148 println!("[!] Case {} failed (description: {}): {}", case.path.display(), case.desc, error);
149 }
150}