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/// Block processing failed
24 /// Note: This includes but is not limited to execution.
25 /// For example, the header number could be incorrect.
26#[error("block {block_number} failed to process")]
27BlockProcessingFailed {
28/// The block number for the block that failed
29block_number: u64,
30 },
31/// An IO error occurred
32#[error("an error occurred interacting with the file system at {path}: {error}")]
33Io {
34/// The path to the file or directory
35path: PathBuf,
36/// The specific error
37#[source]
38error: std::io::Error,
39 },
40/// A deserialization error occurred
41#[error("an error occurred deserializing the test at {path}: {error}")]
42CouldNotDeserialize {
43/// The path to the file we wanted to deserialize
44path: PathBuf,
45/// The specific error
46#[source]
47error: serde_json::Error,
48 },
49/// A database error occurred.
50#[error(transparent)]
51Database(#[from] DatabaseError),
52/// A test assertion failed.
53#[error("test failed: {0}")]
54Assertion(String),
55/// An error internally in reth occurred.
56#[error("test failed: {0}")]
57Provider(#[from] ProviderError),
58/// An error occurred while decoding RLP.
59#[error("an error occurred deserializing RLP: {0}")]
60RlpDecodeError(#[from] alloy_rlp::Error),
61/// A consensus error occurred.
62#[error("an error occurred during consensus checks: {0}")]
63ConsensusError(#[from] reth_consensus::ConsensusError),
64}
6566/// The result of running a test.
67#[derive(Debug)]
68pub struct CaseResult {
69/// A description of the test.
70pub desc: String,
71/// The full path to the test.
72pub path: PathBuf,
73/// The result of the test.
74pub result: Result<(), Error>,
75}
7677impl CaseResult {
78/// Create a new test result.
79pub fn new(path: &Path, case: &impl Case, result: Result<(), Error>) -> Self {
80Self { desc: case.description(), path: path.into(), result }
81 }
82}
8384/// Assert that all the given tests passed and print the results to stdout.
85pub(crate) fn assert_tests_pass(suite_name: &str, path: &Path, results: &[CaseResult]) {
86let (passed, failed, skipped) = categorize_results(results);
8788print_results(suite_name, path, &passed, &failed, &skipped);
8990assert!(failed.is_empty(), "Some tests failed (see above)");
91}
9293/// Categorize test results into `(passed, failed, skipped)`.
94pub(crate) fn categorize_results(
95 results: &[CaseResult],
96) -> (Vec<&CaseResult>, Vec<&CaseResult>, Vec<&CaseResult>) {
97let mut passed = Vec::new();
98let mut failed = Vec::new();
99let mut skipped = Vec::new();
100101for case in results {
102match case.result.as_ref().err() {
103Some(Error::Skipped) => skipped.push(case),
104Some(_) => failed.push(case),
105None => passed.push(case),
106 }
107 }
108109 (passed, failed, skipped)
110}
111112/// Display the given test results to stdout.
113pub(crate) fn print_results(
114 suite_name: &str,
115 path: &Path,
116 passed: &[&CaseResult],
117 failed: &[&CaseResult],
118 skipped: &[&CaseResult],
119) {
120println!("Suite: {suite_name} (at {})", path.display());
121println!(
122"Ran {} tests ({} passed, {} failed, {} skipped)",
123 passed.len() + failed.len() + skipped.len(),
124 passed.len(),
125 failed.len(),
126 skipped.len()
127 );
128129for case in skipped {
130println!("[S] Case {} skipped", case.path.display());
131 }
132133for case in failed {
134let error = case.result.as_ref().unwrap_err();
135println!("[!] Case {} failed (description: {}): {}", case.path.display(), case.desc, error);
136 }
137}