foundry_cheatcodes/
test.rs

1//! Implementations of [`Testing`](spec::Group::Testing) cheatcodes.
2
3use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*};
4use alloy_primitives::Address;
5use alloy_sol_types::SolValue;
6use foundry_common::version::SEMVER_VERSION;
7use foundry_evm_core::constants::MAGIC_SKIP;
8
9pub(crate) mod assert;
10pub(crate) mod assume;
11pub(crate) mod expect;
12pub(crate) mod revert_handlers;
13
14impl Cheatcode for breakpoint_0Call {
15    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
16        let Self { char } = self;
17        breakpoint(ccx.state, &ccx.caller, char, true)
18    }
19}
20
21impl Cheatcode for breakpoint_1Call {
22    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
23        let Self { char, value } = self;
24        breakpoint(ccx.state, &ccx.caller, char, *value)
25    }
26}
27
28impl Cheatcode for getFoundryVersionCall {
29    fn apply(&self, _state: &mut Cheatcodes) -> Result {
30        let Self {} = self;
31        Ok(SEMVER_VERSION.abi_encode())
32    }
33}
34
35impl Cheatcode for rpcUrlCall {
36    fn apply(&self, state: &mut Cheatcodes) -> Result {
37        let Self { rpcAlias } = self;
38        let url = state.config.rpc_endpoint(rpcAlias)?.url()?.abi_encode();
39        Ok(url)
40    }
41}
42
43impl Cheatcode for rpcUrlsCall {
44    fn apply(&self, state: &mut Cheatcodes) -> Result {
45        let Self {} = self;
46        state.config.rpc_urls().map(|urls| urls.abi_encode())
47    }
48}
49
50impl Cheatcode for rpcUrlStructsCall {
51    fn apply(&self, state: &mut Cheatcodes) -> Result {
52        let Self {} = self;
53        state.config.rpc_urls().map(|urls| urls.abi_encode())
54    }
55}
56
57impl Cheatcode for sleepCall {
58    fn apply(&self, _state: &mut Cheatcodes) -> Result {
59        let Self { duration } = self;
60        let sleep_duration = std::time::Duration::from_millis(duration.saturating_to());
61        std::thread::sleep(sleep_duration);
62        Ok(Default::default())
63    }
64}
65
66impl Cheatcode for skip_0Call {
67    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
68        let Self { skipTest } = *self;
69        skip_1Call { skipTest, reason: String::new() }.apply_stateful(ccx)
70    }
71}
72
73impl Cheatcode for skip_1Call {
74    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
75        let Self { skipTest, reason } = self;
76        if *skipTest {
77            // Skip should not work if called deeper than at test level.
78            // Since we're not returning the magic skip bytes, this will cause a test failure.
79            ensure!(ccx.ecx.journaled_state.depth() <= 1, "`skip` can only be used at test level");
80            Err([MAGIC_SKIP, reason.as_bytes()].concat().into())
81        } else {
82            Ok(Default::default())
83        }
84    }
85}
86
87/// Adds or removes the given breakpoint to the state.
88fn breakpoint(state: &mut Cheatcodes, caller: &Address, s: &str, add: bool) -> Result {
89    let mut chars = s.chars();
90    let (Some(point), None) = (chars.next(), chars.next()) else {
91        bail!("breakpoints must be exactly one character");
92    };
93    ensure!(point.is_alphabetic(), "only alphabetic characters are accepted as breakpoints");
94
95    if add {
96        state.breakpoints.insert(point, (*caller, state.pc));
97    } else {
98        state.breakpoints.remove(&point);
99    }
100
101    Ok(Default::default())
102}