Skip to main content

revmc_statetest/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), warn(unused_extern_crates))]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![allow(
5    clippy::incompatible_msrv,
6    clippy::needless_update,
7    clippy::collapsible_if,
8    unreachable_pub,
9    dead_code,
10    missing_docs,
11    missing_debug_implementations
12)]
13
14pub mod btest;
15pub mod compiled;
16pub mod diagnostic;
17pub mod merkle_trie;
18pub mod runner;
19pub mod utils;
20
21use std::path::{Path, PathBuf};
22use walkdir::{DirEntry, WalkDir};
23
24/// Find all JSON test files in the given path.
25/// If path is a file, returns it in a vector.
26/// If path is a directory, recursively finds all .json files.
27pub fn find_all_json_tests(path: &Path) -> Vec<PathBuf> {
28    if path.is_file() {
29        vec![path.to_path_buf()]
30    } else {
31        WalkDir::new(path)
32            .into_iter()
33            .filter_map(Result::ok)
34            .filter(|e| e.path().extension() == Some("json".as_ref()))
35            .map(DirEntry::into_path)
36            .collect()
37    }
38}
39
40/// Default path to ethereum/tests repository.
41const DEFAULT_ETHTESTS_PATH: &str = "tests/ethereum-tests";
42
43/// Default path to downloaded test fixtures (execution-spec-tests + legacytests).
44const DEFAULT_FIXTURES_PATH: &str = "test-fixtures";
45
46const STATE_TESTS_TARBALL: &str = "fixtures_general_state_tests.tgz";
47
48/// Resolve the workspace root by walking up from `CARGO_MANIFEST_DIR`.
49fn workspace_root() -> PathBuf {
50    let manifest_dir = env!("CARGO_MANIFEST_DIR");
51    Path::new(manifest_dir)
52        .ancestors()
53        .find(|p| p.join("Cargo.lock").exists())
54        .map(Path::to_path_buf)
55        .unwrap_or_else(|| PathBuf::from("."))
56}
57
58/// Get the path to ethereum/tests.
59pub fn get_ethtests_path() -> PathBuf {
60    if let Ok(path) = std::env::var("ETHTESTS") {
61        return PathBuf::from(path);
62    }
63    let root = workspace_root();
64    let path = root.join(DEFAULT_ETHTESTS_PATH);
65    if path.exists() { path } else { PathBuf::from(DEFAULT_ETHTESTS_PATH) }
66}
67
68/// Get the path to downloaded test fixtures (`test-fixtures/`).
69pub fn get_fixtures_path() -> PathBuf {
70    if let Ok(path) = std::env::var("REVMC_TEST_FIXTURES") {
71        return PathBuf::from(path);
72    }
73    workspace_root().join(DEFAULT_FIXTURES_PATH)
74}
75
76/// Get the path to `GeneralStateTests`, extracting the tarball if necessary.
77///
78/// The ethereum/tests repo ships the fixtures as `.tgz` archives.
79/// We extract into the parent of the submodule (`tests/`) rather than inside
80/// the submodule itself, so the root `.gitignore` can cover the extracted
81/// directory and the submodule stays clean.
82pub fn get_general_state_tests_path() -> Option<PathBuf> {
83    let root = get_ethtests_path();
84
85    // Check next to the submodule first (extracted location).
86    if let Some(parent) = root.parent() {
87        let dir = parent.join("GeneralStateTests");
88        if dir.is_dir() {
89            return Some(dir);
90        }
91    }
92
93    // Also check inside the submodule (manual extraction or old layout).
94    let dir = root.join("GeneralStateTests");
95    if dir.is_dir() {
96        return Some(dir);
97    }
98
99    let tarball = root.join(STATE_TESTS_TARBALL);
100    if !tarball.is_file() {
101        return None;
102    }
103
104    // Extract next to the submodule so the root .gitignore covers it.
105    let extract_dir = root.parent()?;
106    let status = std::process::Command::new("tar")
107        .arg("xzf")
108        .arg(&tarball)
109        .arg("-C")
110        .arg(extract_dir)
111        .status()
112        .ok()?;
113    if !status.success() {
114        return None;
115    }
116
117    let dir = extract_dir.join("GeneralStateTests");
118    dir.is_dir().then_some(dir)
119}
120
121/// Get the path to execution-spec-tests stable state tests.
122pub fn get_exec_spec_stable_state_tests_path() -> Option<PathBuf> {
123    let dir = get_fixtures_path().join("main/stable/state_tests");
124    dir.is_dir().then_some(dir)
125}
126
127/// Get the path to execution-spec-tests develop state tests.
128pub fn get_exec_spec_develop_state_tests_path() -> Option<PathBuf> {
129    let dir = get_fixtures_path().join("main/develop/state_tests");
130    dir.is_dir().then_some(dir)
131}
132
133/// Get the path to legacy Cancun GeneralStateTests.
134pub fn get_legacy_cancun_state_tests_path() -> Option<PathBuf> {
135    let dir = get_fixtures_path().join("legacytests/Cancun/GeneralStateTests");
136    dir.is_dir().then_some(dir)
137}
138
139/// Get the path to legacy Constantinople GeneralStateTests.
140pub fn get_legacy_constantinople_state_tests_path() -> Option<PathBuf> {
141    let dir = get_fixtures_path().join("legacytests/Constantinople/GeneralStateTests");
142    dir.is_dir().then_some(dir)
143}
144
145/// Get the path to execution-spec-tests stable blockchain tests.
146pub fn get_exec_spec_stable_blockchain_tests_path() -> Option<PathBuf> {
147    let dir = get_fixtures_path().join("main/stable/blockchain_tests");
148    dir.is_dir().then_some(dir)
149}
150
151/// Get the path to execution-spec-tests develop blockchain tests.
152pub fn get_exec_spec_develop_blockchain_tests_path() -> Option<PathBuf> {
153    let dir = get_fixtures_path().join("main/develop/blockchain_tests");
154    dir.is_dir().then_some(dir)
155}