1use std::{
16 any::{Any, TypeId},
17 collections::HashMap,
18 ops::{Deref, DerefMut},
19 sync::{Mutex, OnceLock},
20};
21
22pub trait Fixture: Sized {
35 fn set_up() -> crate::Result<Self>;
42
43 fn tear_down(self) -> crate::Result<()>;
50}
51
52pub trait ConsumableFixture: Sized {
65 fn set_up() -> crate::Result<Self>;
72}
73
74pub struct FixtureOf<T>(T);
77
78impl<T: Default> ConsumableFixture for FixtureOf<T> {
79 fn set_up() -> crate::Result<Self> {
80 Ok(Self(T::default()))
81 }
82}
83
84impl<T> Deref for FixtureOf<T> {
85 type Target = T;
86
87 fn deref(&self) -> &Self::Target {
88 &self.0
89 }
90}
91
92impl<T> DerefMut for FixtureOf<T> {
93 fn deref_mut(&mut self) -> &mut Self::Target {
94 &mut self.0
95 }
96}
97
98pub trait StaticFixture: Sized + Sync + Send {
111 fn set_up_once() -> crate::Result<Self>;
117}
118
119impl<F: StaticFixture + 'static> Fixture for &'static F {
120 fn set_up() -> crate::Result<Self> {
121 static ONCE_FIXTURE_REPO: OnceLock<
122 Mutex<HashMap<TypeId, &'static (dyn Any + Sync + Send)>>,
123 > = OnceLock::new();
124 let mut map = ONCE_FIXTURE_REPO.get_or_init(|| Mutex::new(HashMap::new())).lock()?;
125 let any =
126 map.entry(TypeId::of::<F>()).or_insert_with(|| Box::leak(Box::new(F::set_up_once())));
127 match any.downcast_ref::<crate::Result<F>>() {
128 Some(Ok(fixture)) => Ok(fixture),
129 Some(Err(e)) => Err(e.clone()),
130 None => panic!("Downcast failed. This is a bug in GoogleTest Rust"),
131 }
132 }
133
134 fn tear_down(self) -> crate::Result<()> {
136 Ok(())
137 }
138}
139
140#[cfg(test)]
141mod tests {
142
143 use std::sync::Once;
144
145 use super::FixtureOf;
146 use super::StaticFixture;
147 use crate as googletest;
148 use crate::prelude::*;
149 use crate::test;
150 use crate::Result;
151
152 #[test]
153 fn fixture_no_fixture() -> Result<()> {
154 Ok(())
155 }
156
157 struct AlwaysSucceed;
158
159 impl Fixture for AlwaysSucceed {
160 fn set_up() -> crate::Result<Self> {
161 Ok(Self)
162 }
163
164 fn tear_down(self) -> crate::Result<()> {
165 Ok(())
166 }
167 }
168
169 #[test]
170 fn fixture_one_fixture(_: &AlwaysSucceed) -> Result<()> {
171 Ok(())
172 }
173
174 #[test]
175 fn fixture_three_fixtures(
176 _: &AlwaysSucceed,
177 _: &AlwaysSucceed,
178 _: &AlwaysSucceed,
179 ) -> Result<()> {
180 Ok(())
181 }
182
183 struct NotAFixture {
184 a_field: i32,
185 }
186
187 impl Default for NotAFixture {
188 fn default() -> Self {
189 Self { a_field: 33 }
190 }
191 }
192
193 #[test]
194 fn fixture_of_non_fixture(not_a_fixture: FixtureOf<NotAFixture>) -> Result<()> {
195 verify_that!(not_a_fixture.a_field, eq(33))
196 }
197
198 #[test]
199 fn fixture_of_non_fixture_mut(mut not_a_fixture: FixtureOf<NotAFixture>) -> Result<()> {
200 not_a_fixture.a_field += 10;
201 verify_that!(not_a_fixture.a_field, eq(43))
202 }
203 struct PanickyFixture;
204
205 impl Fixture for PanickyFixture {
206 fn set_up() -> crate::Result<Self> {
207 Ok(Self)
208 }
209
210 fn tear_down(self) -> crate::Result<()> {
211 panic!("Whoooops");
212 }
213 }
214
215 #[test]
216 #[should_panic(expected = "Whoooops")]
217 fn fixture_teardown_called_even_if_test_fail(_: &PanickyFixture) -> Result<()> {
218 Err(googletest::TestAssertionFailure::create("It must fail!".into()))
219 }
220
221 struct AbortIfNotTornDownFixture {
222 has_been_torn_down: bool,
223 }
224
225 impl Fixture for AbortIfNotTornDownFixture {
226 fn set_up() -> crate::Result<Self> {
227 Ok(Self { has_been_torn_down: false })
228 }
229 fn tear_down(mut self) -> crate::Result<()> {
230 self.has_been_torn_down = true;
231 Ok(())
232 }
233 }
234
235 impl Drop for AbortIfNotTornDownFixture {
236 fn drop(&mut self) {
237 if !self.has_been_torn_down {
238 eprintln!("AbortIfNotTornDownFixture was not torn down");
239 std::process::abort();
240 }
241 }
242 }
243
244 #[test]
245 #[should_panic(expected = "simple_fail")]
246 fn fixture_torn_down_after_test_panics(f: &AbortIfNotTornDownFixture) {
247 expect_that!(f.has_been_torn_down, eq(false));
248 panic!("simple_fail");
249 }
250
251 struct OnlyOnce;
252
253 impl StaticFixture for OnlyOnce {
254 fn set_up_once() -> crate::Result<Self> {
255 static ONCE: Once = Once::new();
256 assert!(!ONCE.is_completed());
257 ONCE.call_once(|| {});
258 Ok(Self)
259 }
260 }
261
262 #[test]
263 fn static_fixture_works(_: &&OnlyOnce) {}
264
265 #[test]
266 fn static_fixture_same_static_fixture_twice(once: &&OnlyOnce, twice: &&OnlyOnce) {
267 let once: *const OnlyOnce = *once;
269 let twice: *const OnlyOnce = *twice;
270 expect_eq!(once, twice);
271 }
272
273 struct AnotherStaticFixture;
274
275 impl StaticFixture for AnotherStaticFixture {
276 fn set_up_once() -> crate::Result<Self> {
277 Ok(Self)
278 }
279 }
280
281 #[test]
282 fn static_fixture_two_different_static_fixtures(_: &&OnlyOnce, _: &&AnotherStaticFixture) {}
283
284 struct FailingSetUp;
285
286 impl Fixture for FailingSetUp {
287 fn set_up() -> crate::Result<Self> {
288 Err(googletest::TestAssertionFailure::create("sad fixture".into()))
289 }
290
291 fn tear_down(self) -> crate::Result<()> {
292 unreachable!();
293 }
294 }
295
296 #[test]
297 #[should_panic(expected = "See failure output above")]
298 fn failing_fixture_causes_test_failure(_: &FailingSetUp) {
299 unreachable!()
300 }
301
302 struct FailingTearDown;
303
304 impl Fixture for FailingTearDown {
305 fn set_up() -> crate::Result<Self> {
306 Ok(Self)
307 }
308
309 fn tear_down(self) -> crate::Result<()> {
310 Err(googletest::TestAssertionFailure::create("It must fail!".into()))
311 }
312 }
313
314 #[test]
315 #[should_panic(expected = "See failure output above")]
316 fn failing_teardown_causes_test_failure(_: &FailingTearDown) {}
317}