foundry_test_utils/
filter.rs
1use foundry_common::TestFilter;
2use regex::Regex;
3use std::path::Path;
4
5#[derive(Clone, Debug)]
6pub struct Filter {
7 test_regex: Regex,
8 contract_regex: Regex,
9 path_regex: Regex,
10 exclude_tests: Option<Regex>,
11 exclude_contracts: Option<Regex>,
12 exclude_paths: Option<Regex>,
13}
14
15impl Filter {
16 pub fn new(test_pattern: &str, contract_pattern: &str, path_pattern: &str) -> Self {
17 Self {
18 test_regex: Regex::new(test_pattern)
19 .unwrap_or_else(|_| panic!("Failed to parse test pattern: `{test_pattern}`")),
20 contract_regex: Regex::new(contract_pattern).unwrap_or_else(|_| {
21 panic!("Failed to parse contract pattern: `{contract_pattern}`")
22 }),
23 path_regex: Regex::new(path_pattern)
24 .unwrap_or_else(|_| panic!("Failed to parse path pattern: `{path_pattern}`")),
25 exclude_tests: None,
26 exclude_contracts: None,
27 exclude_paths: None,
28 }
29 }
30
31 pub fn contract(contract_pattern: &str) -> Self {
32 Self::new(".*", contract_pattern, ".*")
33 }
34
35 pub fn path(path_pattern: &str) -> Self {
36 Self::new(".*", ".*", path_pattern)
37 }
38
39 pub fn exclude_tests(mut self, pattern: &str) -> Self {
43 self.exclude_tests = Some(Regex::new(pattern).unwrap());
44 self
45 }
46
47 pub fn exclude_contracts(mut self, pattern: &str) -> Self {
51 self.exclude_contracts = Some(Regex::new(pattern).unwrap());
52 self
53 }
54
55 pub fn exclude_paths(mut self, pattern: &str) -> Self {
59 self.exclude_paths = Some(Regex::new(pattern).unwrap());
60 self
61 }
62
63 pub fn matches_all() -> Self {
64 Self {
65 test_regex: Regex::new(".*").unwrap(),
66 contract_regex: Regex::new(".*").unwrap(),
67 path_regex: Regex::new(".*").unwrap(),
68 exclude_tests: None,
69 exclude_contracts: None,
70 exclude_paths: None,
71 }
72 }
73}
74
75impl TestFilter for Filter {
76 fn matches_test(&self, test_name: &str) -> bool {
77 if let Some(exclude) = &self.exclude_tests {
78 if exclude.is_match(test_name) {
79 return false;
80 }
81 }
82 self.test_regex.is_match(test_name)
83 }
84
85 fn matches_contract(&self, contract_name: &str) -> bool {
86 if let Some(exclude) = &self.exclude_contracts {
87 if exclude.is_match(contract_name) {
88 return false;
89 }
90 }
91
92 self.contract_regex.is_match(contract_name)
93 }
94
95 fn matches_path(&self, path: &Path) -> bool {
96 let Some(path) = path.to_str() else {
97 return false;
98 };
99
100 if let Some(exclude) = &self.exclude_paths {
101 if exclude.is_match(path) {
102 return false;
103 }
104 }
105 self.path_regex.is_match(path)
106 }
107}