Skip to main content

revmc_statetest/
lib.rs

1#![allow(clippy::incompatible_msrv)]
2
3pub mod compiled;
4pub mod diagnostic;
5pub mod merkle_trie;
6pub mod runner;
7pub mod utils;
8
9use std::path::{Path, PathBuf};
10use walkdir::{DirEntry, WalkDir};
11
12/// Find all JSON test files in the given path.
13/// If path is a file, returns it in a vector.
14/// If path is a directory, recursively finds all .json files.
15pub fn find_all_json_tests(path: &Path) -> Vec<PathBuf> {
16    if path.is_file() {
17        vec![path.to_path_buf()]
18    } else {
19        WalkDir::new(path)
20            .into_iter()
21            .filter_map(Result::ok)
22            .filter(|e| e.path().extension() == Some("json".as_ref()))
23            .map(DirEntry::into_path)
24            .collect()
25    }
26}
27
28/// Default path to ethereum/tests repository.
29const DEFAULT_ETHTESTS_PATH: &str = "tests/ethereum-tests";
30
31const STATE_TESTS_TARBALL: &str = "fixtures_general_state_tests.tgz";
32
33/// Get the path to ethereum/tests.
34pub fn get_ethtests_path() -> PathBuf {
35    if let Ok(path) = std::env::var("ETHTESTS") {
36        return PathBuf::from(path);
37    }
38    // Resolve relative to the workspace root via CARGO_MANIFEST_DIR.
39    let manifest_dir = env!("CARGO_MANIFEST_DIR");
40    Path::new(manifest_dir)
41        .ancestors()
42        .find(|p| p.join(DEFAULT_ETHTESTS_PATH).exists())
43        .map(|p| p.join(DEFAULT_ETHTESTS_PATH))
44        .unwrap_or_else(|| PathBuf::from(DEFAULT_ETHTESTS_PATH))
45}
46
47/// Get the path to `GeneralStateTests`, extracting the tarball if necessary.
48///
49/// The ethereum/tests repo ships the fixtures as `.tgz` archives.
50/// We extract into the parent of the submodule (`tests/`) rather than inside
51/// the submodule itself, so the root `.gitignore` can cover the extracted
52/// directory and the submodule stays clean.
53pub fn get_general_state_tests_path() -> Option<PathBuf> {
54    let root = get_ethtests_path();
55
56    // Check next to the submodule first (extracted location).
57    if let Some(parent) = root.parent() {
58        let dir = parent.join("GeneralStateTests");
59        if dir.is_dir() {
60            return Some(dir);
61        }
62    }
63
64    // Also check inside the submodule (manual extraction or old layout).
65    let dir = root.join("GeneralStateTests");
66    if dir.is_dir() {
67        return Some(dir);
68    }
69
70    let tarball = root.join(STATE_TESTS_TARBALL);
71    if !tarball.is_file() {
72        return None;
73    }
74
75    // Extract next to the submodule so the root .gitignore covers it.
76    let extract_dir = root.parent()?;
77    let status = std::process::Command::new("tar")
78        .arg("xzf")
79        .arg(&tarball)
80        .arg("-C")
81        .arg(extract_dir)
82        .status()
83        .ok()?;
84    if !status.success() {
85        return None;
86    }
87
88    let dir = extract_dir.join("GeneralStateTests");
89    dir.is_dir().then_some(dir)
90}