foundry_common/
traits.rs
1use alloy_json_abi::Function;
4use alloy_primitives::Bytes;
5use alloy_sol_types::SolError;
6use std::{fmt, path::Path};
7
8pub trait TestFilter: Send + Sync {
10 fn matches_test(&self, test_name: &str) -> bool;
12
13 fn matches_contract(&self, contract_name: &str) -> bool;
15
16 fn matches_path(&self, path: &Path) -> bool;
18}
19
20pub trait TestFunctionExt {
22 fn test_function_kind(&self) -> TestFunctionKind {
24 TestFunctionKind::classify(self.tfe_as_str(), self.tfe_has_inputs())
25 }
26
27 fn is_setup(&self) -> bool {
29 self.test_function_kind().is_setup()
30 }
31
32 fn is_any_test(&self) -> bool {
34 self.test_function_kind().is_any_test()
35 }
36
37 fn is_any_test_fail(&self) -> bool {
39 self.test_function_kind().is_any_test_fail()
40 }
41
42 fn is_unit_test(&self) -> bool {
44 matches!(self.test_function_kind(), TestFunctionKind::UnitTest { .. })
45 }
46
47 fn is_before_test_setup(&self) -> bool {
49 self.tfe_as_str().eq_ignore_ascii_case("beforetestsetup")
50 }
51
52 fn is_fuzz_test(&self) -> bool {
54 self.test_function_kind().is_fuzz_test()
55 }
56
57 fn is_invariant_test(&self) -> bool {
59 self.test_function_kind().is_invariant_test()
60 }
61
62 fn is_after_invariant(&self) -> bool {
64 self.test_function_kind().is_after_invariant()
65 }
66
67 fn is_fixture(&self) -> bool {
69 self.test_function_kind().is_fixture()
70 }
71
72 #[doc(hidden)]
73 fn tfe_as_str(&self) -> &str;
74 #[doc(hidden)]
75 fn tfe_has_inputs(&self) -> bool;
76}
77
78impl TestFunctionExt for Function {
79 fn tfe_as_str(&self) -> &str {
80 self.name.as_str()
81 }
82
83 fn tfe_has_inputs(&self) -> bool {
84 !self.inputs.is_empty()
85 }
86}
87
88impl TestFunctionExt for String {
89 fn tfe_as_str(&self) -> &str {
90 self
91 }
92
93 fn tfe_has_inputs(&self) -> bool {
94 false
95 }
96}
97
98impl TestFunctionExt for str {
99 fn tfe_as_str(&self) -> &str {
100 self
101 }
102
103 fn tfe_has_inputs(&self) -> bool {
104 false
105 }
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
110pub enum TestFunctionKind {
111 Setup,
113 UnitTest { should_fail: bool },
115 FuzzTest { should_fail: bool },
117 InvariantTest,
119 AfterInvariant,
121 Fixture,
123 Unknown,
125}
126
127impl TestFunctionKind {
128 #[inline]
130 pub fn classify(name: &str, has_inputs: bool) -> Self {
131 match () {
132 _ if name.starts_with("test") => {
133 let should_fail = name.starts_with("testFail");
134 if has_inputs {
135 Self::FuzzTest { should_fail }
136 } else {
137 Self::UnitTest { should_fail }
138 }
139 }
140 _ if name.starts_with("invariant") || name.starts_with("statefulFuzz") => {
141 Self::InvariantTest
142 }
143 _ if name.eq_ignore_ascii_case("setup") => Self::Setup,
144 _ if name.eq_ignore_ascii_case("afterinvariant") => Self::AfterInvariant,
145 _ if name.starts_with("fixture") => Self::Fixture,
146 _ => Self::Unknown,
147 }
148 }
149
150 pub const fn name(&self) -> &'static str {
152 match self {
153 Self::Setup => "setUp",
154 Self::UnitTest { should_fail: false } => "test",
155 Self::UnitTest { should_fail: true } => "testFail",
156 Self::FuzzTest { should_fail: false } => "fuzz",
157 Self::FuzzTest { should_fail: true } => "fuzz fail",
158 Self::InvariantTest => "invariant",
159 Self::AfterInvariant => "afterInvariant",
160 Self::Fixture => "fixture",
161 Self::Unknown => "unknown",
162 }
163 }
164
165 #[inline]
167 pub const fn is_setup(&self) -> bool {
168 matches!(self, Self::Setup)
169 }
170
171 #[inline]
173 pub const fn is_any_test(&self) -> bool {
174 matches!(self, Self::UnitTest { .. } | Self::FuzzTest { .. } | Self::InvariantTest)
175 }
176
177 #[inline]
179 pub const fn is_any_test_fail(&self) -> bool {
180 matches!(self, Self::UnitTest { should_fail: true } | Self::FuzzTest { should_fail: true })
181 }
182
183 #[inline]
185 pub fn is_unit_test(&self) -> bool {
186 matches!(self, Self::UnitTest { .. })
187 }
188
189 #[inline]
191 pub const fn is_fuzz_test(&self) -> bool {
192 matches!(self, Self::FuzzTest { .. })
193 }
194
195 #[inline]
197 pub const fn is_invariant_test(&self) -> bool {
198 matches!(self, Self::InvariantTest)
199 }
200
201 #[inline]
203 pub const fn is_after_invariant(&self) -> bool {
204 matches!(self, Self::AfterInvariant)
205 }
206
207 #[inline]
209 pub const fn is_fixture(&self) -> bool {
210 matches!(self, Self::Fixture)
211 }
212
213 #[inline]
215 pub const fn is_known(&self) -> bool {
216 !matches!(self, Self::Unknown)
217 }
218
219 #[inline]
221 pub const fn is_unknown(&self) -> bool {
222 matches!(self, Self::Unknown)
223 }
224}
225
226impl fmt::Display for TestFunctionKind {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 self.name().fmt(f)
229 }
230}
231
232pub trait ErrorExt: std::error::Error {
234 fn abi_encode_revert(&self) -> Bytes;
236}
237
238impl<T: std::error::Error> ErrorExt for T {
239 fn abi_encode_revert(&self) -> Bytes {
240 alloy_sol_types::Revert::from(self.to_string()).abi_encode().into()
241 }
242}