fluent_test/backend/fixtures/
mod.rs1use once_cell::sync::Lazy;
8use std::cell::RefCell;
9use std::collections::{HashMap, HashSet};
10use std::panic::{self, AssertUnwindSafe};
11use std::sync::Mutex;
12
13pub type FixtureFunc = Box<dyn Fn() + Send + Sync + 'static>;
15
16static SETUP_FIXTURES: Lazy<Mutex<HashMap<&'static str, Vec<FixtureFunc>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
17
18static TEARDOWN_FIXTURES: Lazy<Mutex<HashMap<&'static str, Vec<FixtureFunc>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
19
20static BEFORE_ALL_FIXTURES: Lazy<Mutex<HashMap<&'static str, Vec<FixtureFunc>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
21
22static AFTER_ALL_FIXTURES: Lazy<Mutex<HashMap<&'static str, Vec<FixtureFunc>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
23
24static EXECUTED_MODULES: Lazy<Mutex<HashSet<&'static str>>> = Lazy::new(|| Mutex::new(HashSet::new()));
25
26pub fn register_setup(module_path: &'static str, func: FixtureFunc) {
30 let mut fixtures = SETUP_FIXTURES.lock().unwrap();
31 fixtures.entry(module_path).or_default().push(func);
32}
33
34pub fn register_teardown(module_path: &'static str, func: FixtureFunc) {
38 let mut fixtures = TEARDOWN_FIXTURES.lock().unwrap();
39 fixtures.entry(module_path).or_default().push(func);
40}
41
42pub fn register_before_all(module_path: &'static str, func: FixtureFunc) {
47 let mut fixtures = BEFORE_ALL_FIXTURES.lock().unwrap();
48 fixtures.entry(module_path).or_default().push(func);
49}
50
51pub fn register_after_all(module_path: &'static str, func: FixtureFunc) {
58 let mut fixtures = AFTER_ALL_FIXTURES.lock().unwrap();
59 fixtures.entry(module_path).or_default().push(func);
60}
61
62thread_local! {
63 static IN_FIXTURE_TEST: RefCell<bool> = const { RefCell::new(false) };
65}
66
67pub fn run_test_with_fixtures<F>(module_path: &'static str, test_fn: AssertUnwindSafe<F>)
71where
72 F: FnOnce(),
73{
74 IN_FIXTURE_TEST.with(|flag| {
76 *flag.borrow_mut() = true;
77 });
78
79 run_before_all_if_needed(module_path);
82
83 if let Ok(fixtures) = SETUP_FIXTURES.lock() {
85 if let Some(setup_funcs) = fixtures.get(module_path) {
86 for setup_fn in setup_funcs {
87 setup_fn();
88 }
89 }
90 }
91
92 let result = panic::catch_unwind(test_fn);
94
95 if let Ok(fixtures) = TEARDOWN_FIXTURES.lock() {
97 if let Some(teardown_funcs) = fixtures.get(module_path) {
98 for teardown_fn in teardown_funcs {
99 teardown_fn();
100 }
101 }
102 }
103
104 IN_FIXTURE_TEST.with(|flag| {
106 *flag.borrow_mut() = false;
107 });
108
109 register_after_all_handler(module_path);
112
113 if let Err(err) = result {
115 panic::resume_unwind(err);
116 }
117}
118
119fn run_before_all_if_needed(module_path: &'static str) {
121 let mut executed = EXECUTED_MODULES.lock().unwrap();
123 if !executed.contains(module_path) {
124 executed.insert(module_path);
126
127 if let Ok(fixtures) = BEFORE_ALL_FIXTURES.lock() {
129 if let Some(before_all_funcs) = fixtures.get(module_path) {
130 for before_fn in before_all_funcs {
131 before_fn();
132 }
133 }
134 }
135 }
136}
137
138fn register_after_all_handler(module_path: &'static str) {
140 let mut executed = EXECUTED_MODULES.lock().unwrap();
146 executed.insert(module_path);
147}
148
149#[doc(hidden)]
152pub fn run_after_all_fixtures() {
153 let executed = EXECUTED_MODULES.lock().unwrap();
155
156 if let Ok(fixtures) = AFTER_ALL_FIXTURES.lock() {
158 for module_path in executed.iter() {
159 if let Some(after_all_funcs) = fixtures.get(module_path) {
160 for after_fn in after_all_funcs {
161 after_fn();
162 }
163 }
164 }
165 }
166}
167
168pub fn is_in_fixture_test() -> bool {
170 return IN_FIXTURE_TEST.with(|flag| *flag.borrow());
171}