module_lifecycle/
module_lifecycle.rs1use rest::prelude::*;
2use std::cell::RefCell;
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5static BEFORE_ALL_COUNTER: AtomicUsize = AtomicUsize::new(0);
7static SETUP_COUNTER: AtomicUsize = AtomicUsize::new(0);
8static TEST_COUNTER: AtomicUsize = AtomicUsize::new(0);
9static TEARDOWN_COUNTER: AtomicUsize = AtomicUsize::new(0);
10static AFTER_ALL_COUNTER: AtomicUsize = AtomicUsize::new(0);
11
12thread_local! {
14 static TEST_VALUE: RefCell<String> = RefCell::new(String::new());
15}
16
17fn set_test_value(value: &str) {
19 TEST_VALUE.with(|v| {
20 *v.borrow_mut() = value.to_string();
21 });
22}
23
24fn get_test_value() -> String {
26 TEST_VALUE.with(|v| v.borrow().clone())
27}
28
29fn print_module_state(stage: &str) {
31 println!("{}", "-".repeat(50));
32 println!("{}", stage);
33 println!(" Before All count: {}", BEFORE_ALL_COUNTER.load(Ordering::SeqCst));
34 println!(" Setup count : {}", SETUP_COUNTER.load(Ordering::SeqCst));
35 println!(" Test count : {}", TEST_COUNTER.load(Ordering::SeqCst));
36 println!(" Teardown count : {}", TEARDOWN_COUNTER.load(Ordering::SeqCst));
37 println!(" After All count : {}", AFTER_ALL_COUNTER.load(Ordering::SeqCst));
38 println!(" Test value : {}", get_test_value());
39 println!("{}", "-".repeat(50));
40}
41
42#[with_fixtures_module]
44mod lifecycle_test {
45 use super::*;
46
47 #[before_all]
49 fn setup_module() {
50 println!("Running before_all setup...");
51 BEFORE_ALL_COUNTER.fetch_add(1, Ordering::SeqCst);
52 set_test_value("Initialized by before_all");
53 }
54
55 #[setup]
57 fn setup_test() {
58 println!("Running setup for a test...");
59 SETUP_COUNTER.fetch_add(1, Ordering::SeqCst);
60 let current = get_test_value();
62 set_test_value(&format!("{} + setup", current));
63 }
64
65 #[test]
67 pub fn first_test() {
68 println!("Running first test...");
69 TEST_COUNTER.fetch_add(1, Ordering::SeqCst);
70
71 expect!(BEFORE_ALL_COUNTER.load(Ordering::SeqCst)).to_equal(1);
73 expect!(SETUP_COUNTER.load(Ordering::SeqCst)).to_equal(1);
74
75 let current = get_test_value();
77 set_test_value(&format!("{} + first_test", current));
78
79 print_module_state("During first test");
80 }
81
82 #[test]
84 pub fn second_test() {
85 println!("Running second test...");
86 TEST_COUNTER.fetch_add(1, Ordering::SeqCst);
87
88 expect!(BEFORE_ALL_COUNTER.load(Ordering::SeqCst)).to_equal(1); expect!(SETUP_COUNTER.load(Ordering::SeqCst)).to_equal(2); let current = get_test_value();
94 set_test_value(&format!("{} + second_test", current));
95
96 print_module_state("During second test");
97 }
98
99 #[tear_down]
101 fn teardown_test() {
102 println!("Running teardown after a test...");
103 TEARDOWN_COUNTER.fetch_add(1, Ordering::SeqCst);
104
105 let current = get_test_value();
107 set_test_value(&format!("{} + teardown", current));
108 }
109
110 #[after_all]
112 fn teardown_module() {
113 println!("Running after_all teardown...");
114 AFTER_ALL_COUNTER.fetch_add(1, Ordering::SeqCst);
115
116 let current = get_test_value();
118 set_test_value(&format!("{} + after_all", current));
119
120 print_module_state("After all tests completed");
121 }
122}
123
124fn run_simulated_tests() {
126 println!("\nRunning example of module lifecycle fixtures:");
127 println!("This demonstrates the order of execution for fixture types:");
128 println!(" 1. #[before_all] - Runs once before any test in the module");
129 println!(" 2. #[setup] - Runs before each test");
130 println!(" 3. Test function - The actual test");
131 println!(" 4. #[tear_down] - Runs after each test");
132 println!(" 5. #[after_all] - Runs once after all tests in the module\n");
133
134 print_module_state("Initial state");
136
137 println!("\nIn normal test execution, the lifecycle would be:");
139
140 println!("1. Running before_all setup once at the beginning");
142 BEFORE_ALL_COUNTER.fetch_add(1, Ordering::SeqCst);
143 set_test_value("Initialized by before_all");
144
145 println!("2. For test #1: Running setup");
147 SETUP_COUNTER.fetch_add(1, Ordering::SeqCst);
148 let current = get_test_value();
149 set_test_value(&format!("{} + setup", current));
150
151 println!("3. For test #1: Running the test itself");
152 TEST_COUNTER.fetch_add(1, Ordering::SeqCst);
153 let current = get_test_value();
154 set_test_value(&format!("{} + first_test", current));
155
156 println!("4. For test #1: Running teardown");
157 TEARDOWN_COUNTER.fetch_add(1, Ordering::SeqCst);
158 let current = get_test_value();
159 set_test_value(&format!("{} + teardown", current));
160
161 println!("5. For test #2: Running setup again");
163 SETUP_COUNTER.fetch_add(1, Ordering::SeqCst);
164 let current = get_test_value();
165 set_test_value(&format!("{} + setup", current));
166
167 println!("6. For test #2: Running the test itself");
168 TEST_COUNTER.fetch_add(1, Ordering::SeqCst);
169 let current = get_test_value();
170 set_test_value(&format!("{} + second_test", current));
171
172 println!("7. For test #2: Running teardown");
173 TEARDOWN_COUNTER.fetch_add(1, Ordering::SeqCst);
174 let current = get_test_value();
175 set_test_value(&format!("{} + teardown", current));
176
177 println!("8. After all tests: Running after_all cleanup once at the end");
179 AFTER_ALL_COUNTER.fetch_add(1, Ordering::SeqCst);
180 let current = get_test_value();
181 set_test_value(&format!("{} + after_all", current));
182
183 print_module_state("Final state");
185}
186
187fn main() {
188 config().enhanced_output(true).apply();
190
191 run_simulated_tests();
193
194 println!("\nNOTE: In real tests with cargo test:");
196 println!("- #[before_all] will run once before any test in the module");
197 println!("- #[after_all] will run at process exit");
198 println!("\nAll tests passed!");
199}