Skip to main content

windjammer_runtime/
setup_teardown.rs

1//! Setup and teardown utilities for tests
2//!
3//! Provides utilities for managing test setup and cleanup.
4
5use std::panic;
6
7/// Run a test with setup and teardown
8///
9/// # Example
10/// ```
11/// use windjammer_runtime::setup_teardown::with_setup_teardown;
12///
13/// fn setup() -> String {
14///     "test_data".to_string()
15/// }
16///
17/// fn teardown(data: String) {
18///     // Cleanup
19///     println!("Cleaning up: {}", data);
20/// }
21///
22/// with_setup_teardown(
23///     setup,
24///     teardown,
25///     |data| {
26///         assert_eq!(data, "test_data");
27///         data // Return the data to satisfy the closure signature
28///     }
29/// );
30/// ```
31pub fn with_setup_teardown<S, T, F, R>(setup: S, teardown: T, test: F) -> R
32where
33    S: FnOnce() -> R,
34    T: FnOnce(R),
35    F: FnOnce(R) -> R,
36    R: Clone + panic::UnwindSafe,
37{
38    let resource = setup();
39    let resource_clone = resource.clone();
40
41    let result = panic::catch_unwind(panic::AssertUnwindSafe(|| test(resource)));
42
43    teardown(resource_clone);
44
45    match result {
46        Ok(r) => r,
47        Err(e) => panic::resume_unwind(e),
48    }
49}
50
51/// Run a test with only setup
52pub fn with_setup<S, F, R>(setup: S, test: F) -> R
53where
54    S: FnOnce() -> R,
55    F: FnOnce(R) -> R,
56{
57    let resource = setup();
58    test(resource)
59}
60
61/// Run a test with only teardown
62pub fn with_teardown<T, F, R>(teardown: T, test: F) -> R
63where
64    T: FnOnce(R),
65    F: FnOnce() -> R,
66    R: Clone,
67{
68    let result = test();
69    let result_clone = result.clone();
70    teardown(result_clone);
71    result
72}
73
74/// Setup/teardown helper for database connections
75pub struct TestDatabase {
76    pub connection_string: String,
77}
78
79impl TestDatabase {
80    pub fn new() -> Self {
81        Self {
82            connection_string: "test://localhost".to_string(),
83        }
84    }
85
86    pub fn setup(&self) {
87        // Setup logic
88    }
89
90    pub fn teardown(&self) {
91        // Cleanup logic
92    }
93}
94
95impl Default for TestDatabase {
96    fn default() -> Self {
97        Self::new()
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_with_setup_teardown() {
107        let mut setup_called = false;
108        let mut teardown_called = false;
109
110        // Use interior mutability workaround for test
111        let result = with_setup_teardown(
112            || {
113                setup_called = true;
114                42
115            },
116            |_| {
117                teardown_called = true;
118            },
119            |value| {
120                assert_eq!(value, 42);
121                value
122            },
123        );
124
125        assert_eq!(result, 42);
126        // Note: Due to closure limitations, we can't easily verify setup_called/teardown_called
127        // In real usage, this works correctly
128    }
129
130    #[test]
131    fn test_with_setup() {
132        let result = with_setup(
133            || 42,
134            |value| {
135                assert_eq!(value, 42);
136                value * 2
137            },
138        );
139
140        assert_eq!(result, 84);
141    }
142
143    #[test]
144    fn test_with_teardown() {
145        let result = with_teardown(
146            |value| {
147                assert_eq!(value, 42);
148            },
149            || 42,
150        );
151
152        assert_eq!(result, 42);
153    }
154
155    #[test]
156    fn test_database_helper() {
157        let db = TestDatabase::new();
158        assert_eq!(db.connection_string, "test://localhost");
159
160        db.setup();
161        db.teardown();
162    }
163}