revm_ee_tests/lib.rs
1//! Common test utilities for REVM crates.
2//!
3//! This crate provides shared test utilities that are used across different REVM crates.
4
5use std::path::PathBuf;
6
7use serde_json::Value;
8
9/// Configuration for the test data comparison utility.
10pub struct TestdataConfig {
11 /// The directory where test data files are stored.
12 pub testdata_dir: PathBuf,
13}
14
15impl Default for TestdataConfig {
16 fn default() -> Self {
17 Self {
18 testdata_dir: PathBuf::from("tests/testdata"),
19 }
20 }
21}
22
23/// Compares or saves the execution output to a testdata file.
24///
25/// This utility helps maintain consistent test behavior by comparing
26/// execution results against known-good outputs stored in JSON files.
27///
28/// # Arguments
29///
30/// * `filename` - The name of the testdata file, relative to tests/testdata/
31/// * `output` - The execution output to compare or save
32///
33/// # Panics
34///
35/// This function panics if:
36/// - The output doesn't match the expected testdata (when testdata file exists)
37/// - There's an error reading/writing files
38/// - JSON serialization/deserialization fails
39///
40/// # Note
41///
42/// Tests using this function require the `serde` feature to be enabled:
43/// ```bash
44/// cargo test --features serde
45/// ```
46pub fn compare_or_save_testdata<T>(filename: &str, output: &T)
47where
48 T: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq + std::fmt::Debug,
49{
50 compare_or_save_testdata_with_config(filename, output, TestdataConfig::default());
51}
52
53/// Compares or saves the execution output to a testdata file with custom configuration.
54///
55/// This is a more flexible version of [`compare_or_save_testdata`] that allows
56/// specifying a custom testdata directory.
57///
58/// # Arguments
59///
60/// * `filename` - The name of the testdata file, relative to the testdata directory
61/// * `output` - The execution output to compare or save
62/// * `config` - Configuration for the test data comparison
63pub fn compare_or_save_testdata_with_config<T>(filename: &str, output: &T, config: TestdataConfig)
64where
65 T: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq + std::fmt::Debug,
66{
67 use std::fs;
68
69 let testdata_file = config.testdata_dir.join(filename);
70
71 // Create directory if it doesn't exist
72 if !config.testdata_dir.exists() {
73 fs::create_dir_all(&config.testdata_dir).unwrap();
74 }
75
76 // Serialize the output to serde Value.
77 let output_json = serde_json::to_string(&output).unwrap();
78
79 // convert to Value and sort all objects.
80 let mut temp: Value = serde_json::from_str(&output_json).unwrap();
81 temp.sort_all_objects();
82
83 // serialize to pretty string
84 let output_json = serde_json::to_string_pretty(&temp).unwrap();
85
86 // If the testdata file doesn't exist, save the output
87 if !testdata_file.exists() {
88 fs::write(&testdata_file, &output_json).unwrap();
89 println!("Saved testdata to {}", testdata_file.display());
90 return;
91 }
92
93 // Read the expected output from the testdata file
94 let expected_json = fs::read_to_string(&testdata_file).unwrap();
95
96 // Deserialize to actual object for proper comparison
97 let expected: T = serde_json::from_str(&expected_json).unwrap();
98
99 // Compare the output objects directly
100 if *output != expected {
101 panic!(
102 "Value does not match testdata.\nExpected:\n{expected_json}\n\nActual:\n{output_json}"
103 );
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
112 struct TestData {
113 value: u32,
114 message: String,
115 }
116
117 #[test]
118 fn test_compare_or_save_testdata() {
119 let test_data = TestData {
120 value: 42,
121 message: "test message".to_string(),
122 };
123
124 // This will save the test data on first run, then compare on subsequent runs
125 compare_or_save_testdata("test_data.json", &test_data);
126 }
127}
128
129#[cfg(test)]
130mod op_revm_tests;
131
132#[cfg(test)]
133mod revm_tests;