Skip to main content

jugar_probar/
fixture.rs

1//! Fixture Management (Feature 20)
2//!
3//! Test fixture setup and teardown with dependency injection support.
4//!
5//! ## EXTREME TDD: Tests written FIRST per spec
6//!
7//! ## Toyota Way Application
8//!
9//! - **Poka-Yoke**: Type-safe fixture registration prevents runtime errors
10//! - **Muda**: Shared fixtures reduce test setup duplication
11//! - **Jidoka**: Automatic teardown ensures proper cleanup
12//! - **Heijunka**: Ordered setup/teardown for consistent test state
13
14use crate::result::{ProbarError, ProbarResult};
15use std::any::{Any, TypeId};
16use std::collections::HashMap;
17
18/// Trait for test fixtures that can be set up and torn down.
19///
20/// Implement this trait to create reusable test fixtures that manage
21/// setup and cleanup of test resources.
22///
23/// # Example
24///
25/// ```ignore
26/// struct DatabaseFixture {
27///     connection: Option<DbConnection>,
28/// }
29///
30/// impl Fixture for DatabaseFixture {
31///     fn setup(&mut self) -> ProbarResult<()> {
32///         self.connection = Some(DbConnection::connect("test_db")?);
33///         Ok(())
34///     }
35///
36///     fn teardown(&mut self) -> ProbarResult<()> {
37///         if let Some(conn) = self.connection.take() {
38///             conn.close()?;
39///         }
40///         Ok(())
41///     }
42/// }
43/// ```
44pub trait Fixture: Any + Send + Sync {
45    /// Set up the fixture before test execution.
46    ///
47    /// # Errors
48    ///
49    /// Returns an error if fixture setup fails.
50    fn setup(&mut self) -> ProbarResult<()>;
51
52    /// Tear down the fixture after test execution.
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if fixture teardown fails.
57    fn teardown(&mut self) -> ProbarResult<()>;
58
59    /// Get the fixture name for logging/debugging.
60    fn name(&self) -> &str {
61        std::any::type_name::<Self>()
62    }
63
64    /// Get fixture priority (higher = set up first, tear down last).
65    fn priority(&self) -> i32 {
66        0
67    }
68}
69
70/// State of a fixture in the manager.
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum FixtureState {
73    /// Fixture is registered but not set up.
74    Registered,
75    /// Fixture has been set up successfully.
76    SetUp,
77    /// Fixture has been torn down.
78    TornDown,
79    /// Fixture setup failed.
80    Failed,
81}
82
83/// Entry for a registered fixture.
84struct FixtureEntry {
85    fixture: Box<dyn Fixture>,
86    state: FixtureState,
87    priority: i32,
88}
89
90/// Manager for test fixtures with dependency-ordered setup/teardown.
91///
92/// # Example
93///
94/// ```ignore
95/// use jugar_probar::fixture::{FixtureManager, Fixture};
96///
97/// let mut manager = FixtureManager::new();
98/// manager.register(BrowserFixture::new());
99/// manager.register(DatabaseFixture::new());
100///
101/// // Set up all fixtures in priority order
102/// manager.setup_all()?;
103///
104/// // Run tests...
105///
106/// // Tear down all fixtures in reverse order
107/// manager.teardown_all()?;
108/// ```
109#[derive(Default)]
110pub struct FixtureManager {
111    fixtures: HashMap<TypeId, FixtureEntry>,
112    setup_order: Vec<TypeId>,
113}
114
115impl std::fmt::Debug for FixtureManager {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.debug_struct("FixtureManager")
118            .field("fixture_count", &self.fixtures.len())
119            .field("setup_order", &self.setup_order.len())
120            .finish()
121    }
122}
123
124impl FixtureManager {
125    /// Create a new fixture manager.
126    #[must_use]
127    pub fn new() -> Self {
128        Self::default()
129    }
130
131    /// Register a fixture with the manager.
132    ///
133    /// If a fixture of the same type is already registered, it will be replaced.
134    pub fn register<F: Fixture + 'static>(&mut self, fixture: F) {
135        let type_id = TypeId::of::<F>();
136        let priority = fixture.priority();
137
138        let _ = self.fixtures.insert(
139            type_id,
140            FixtureEntry {
141                fixture: Box::new(fixture),
142                state: FixtureState::Registered,
143                priority,
144            },
145        );
146    }
147
148    /// Check if a fixture type is registered.
149    #[must_use]
150    pub fn is_registered<F: Fixture + 'static>(&self) -> bool {
151        let type_id = TypeId::of::<F>();
152        self.fixtures.contains_key(&type_id)
153    }
154
155    /// Get the number of registered fixtures.
156    #[must_use]
157    pub fn count(&self) -> usize {
158        self.fixtures.len()
159    }
160
161    /// Get the state of a fixture.
162    #[must_use]
163    pub fn state<F: Fixture + 'static>(&self) -> Option<FixtureState> {
164        let type_id = TypeId::of::<F>();
165        self.fixtures.get(&type_id).map(|e| e.state)
166    }
167
168    /// Get a reference to a fixture by type.
169    #[must_use]
170    pub fn get<F: Fixture + 'static>(&self) -> Option<&F> {
171        let type_id = TypeId::of::<F>();
172        self.fixtures
173            .get(&type_id)
174            .and_then(|entry| entry.fixture.as_ref().as_any().downcast_ref::<F>())
175    }
176
177    /// Get a mutable reference to a fixture by type.
178    #[must_use]
179    pub fn get_mut<F: Fixture + 'static>(&mut self) -> Option<&mut F> {
180        let type_id = TypeId::of::<F>();
181        self.fixtures
182            .get_mut(&type_id)
183            .and_then(|entry| entry.fixture.as_mut().as_any_mut().downcast_mut::<F>())
184    }
185
186    /// Set up all registered fixtures in priority order (highest first).
187    ///
188    /// # Errors
189    ///
190    /// Returns an error if any fixture setup fails. Previously set up
191    /// fixtures are torn down before returning the error.
192    pub fn setup_all(&mut self) -> ProbarResult<()> {
193        // Sort fixtures by priority (highest first)
194        let mut ordered: Vec<(TypeId, i32)> = self
195            .fixtures
196            .iter()
197            .map(|(id, e)| (*id, e.priority))
198            .collect();
199        ordered.sort_by(|a, b| b.1.cmp(&a.1));
200
201        self.setup_order.clear();
202
203        let mut failed_info: Option<(TypeId, String)> = None;
204
205        for (type_id, _) in ordered {
206            if let Some(entry) = self.fixtures.get_mut(&type_id) {
207                if entry.state == FixtureState::Registered || entry.state == FixtureState::TornDown
208                {
209                    if let Err(e) = entry.fixture.setup() {
210                        let name = entry.fixture.name().to_string();
211                        entry.state = FixtureState::Failed;
212                        failed_info =
213                            Some((type_id, format!("Fixture '{}' setup failed: {e}", name)));
214                        break;
215                    }
216                    entry.state = FixtureState::SetUp;
217                    self.setup_order.push(type_id);
218                }
219            }
220        }
221
222        // If setup failed, teardown already set up fixtures
223        if let Some((_, error_msg)) = failed_info {
224            self.teardown_setup_order()?;
225            return Err(ProbarError::FixtureError { message: error_msg });
226        }
227
228        Ok(())
229    }
230
231    /// Tear down all fixtures in reverse setup order.
232    ///
233    /// # Errors
234    ///
235    /// Returns an error if any fixture teardown fails. Other fixtures
236    /// will still be torn down, but the first error is returned.
237    pub fn teardown_all(&mut self) -> ProbarResult<()> {
238        self.teardown_setup_order()
239    }
240
241    /// Tear down fixtures in reverse setup order.
242    fn teardown_setup_order(&mut self) -> ProbarResult<()> {
243        let mut first_error: Option<ProbarError> = None;
244
245        // Reverse order for teardown
246        for type_id in self.setup_order.iter().rev() {
247            if let Some(entry) = self.fixtures.get_mut(type_id) {
248                if entry.state == FixtureState::SetUp {
249                    if let Err(e) = entry.fixture.teardown() {
250                        if first_error.is_none() {
251                            first_error = Some(ProbarError::FixtureError {
252                                message: format!(
253                                    "Fixture '{}' teardown failed: {e}",
254                                    entry.fixture.name()
255                                ),
256                            });
257                        }
258                        entry.state = FixtureState::Failed;
259                    } else {
260                        entry.state = FixtureState::TornDown;
261                    }
262                }
263            }
264        }
265
266        self.setup_order.clear();
267
268        if let Some(err) = first_error {
269            Err(err)
270        } else {
271            Ok(())
272        }
273    }
274
275    /// Set up a specific fixture by type.
276    ///
277    /// # Errors
278    ///
279    /// Returns an error if the fixture is not registered or setup fails.
280    pub fn setup<F: Fixture + 'static>(&mut self) -> ProbarResult<()> {
281        let type_id = TypeId::of::<F>();
282
283        let entry = self
284            .fixtures
285            .get_mut(&type_id)
286            .ok_or_else(|| ProbarError::FixtureError {
287                message: format!("Fixture '{}' not registered", std::any::type_name::<F>()),
288            })?;
289
290        if entry.state == FixtureState::SetUp {
291            return Ok(()); // Already set up
292        }
293
294        entry
295            .fixture
296            .setup()
297            .map_err(|e| ProbarError::FixtureError {
298                message: format!("Fixture '{}' setup failed: {e}", entry.fixture.name()),
299            })?;
300
301        entry.state = FixtureState::SetUp;
302
303        if !self.setup_order.contains(&type_id) {
304            self.setup_order.push(type_id);
305        }
306
307        Ok(())
308    }
309
310    /// Tear down a specific fixture by type.
311    ///
312    /// # Errors
313    ///
314    /// Returns an error if the fixture is not registered or teardown fails.
315    pub fn teardown<F: Fixture + 'static>(&mut self) -> ProbarResult<()> {
316        let type_id = TypeId::of::<F>();
317
318        let entry = self
319            .fixtures
320            .get_mut(&type_id)
321            .ok_or_else(|| ProbarError::FixtureError {
322                message: format!("Fixture '{}' not registered", std::any::type_name::<F>()),
323            })?;
324
325        if entry.state != FixtureState::SetUp {
326            return Ok(()); // Not set up or already torn down
327        }
328
329        entry
330            .fixture
331            .teardown()
332            .map_err(|e| ProbarError::FixtureError {
333                message: format!("Fixture '{}' teardown failed: {e}", entry.fixture.name()),
334            })?;
335
336        entry.state = FixtureState::TornDown;
337
338        // Remove from setup order
339        self.setup_order.retain(|id| *id != type_id);
340
341        Ok(())
342    }
343
344    /// Reset all fixtures to the registered state without running teardown.
345    pub fn reset(&mut self) {
346        for entry in self.fixtures.values_mut() {
347            entry.state = FixtureState::Registered;
348        }
349        self.setup_order.clear();
350    }
351
352    /// Unregister a fixture by type.
353    pub fn unregister<F: Fixture + 'static>(&mut self) -> bool {
354        let type_id = TypeId::of::<F>();
355        self.setup_order.retain(|id| *id != type_id);
356        self.fixtures.remove(&type_id).is_some()
357    }
358
359    /// Clear all registered fixtures.
360    pub fn clear(&mut self) {
361        self.fixtures.clear();
362        self.setup_order.clear();
363    }
364
365    /// List all registered fixture names.
366    #[must_use]
367    pub fn list(&self) -> Vec<&str> {
368        self.fixtures.values().map(|e| e.fixture.name()).collect()
369    }
370}
371
372impl dyn Fixture {
373    fn as_any(&self) -> &dyn Any {
374        // This uses the vtable to get the actual type
375        // We need to implement this differently
376        self
377    }
378
379    fn as_any_mut(&mut self) -> &mut dyn Any {
380        self
381    }
382}
383
384/// A simple fixture that executes closures for setup and teardown.
385///
386/// Useful for quick fixture creation without implementing the trait.
387pub struct SimpleFixture {
388    name: String,
389    priority: i32,
390    setup_fn: Option<Box<dyn FnMut() -> ProbarResult<()> + Send + Sync>>,
391    teardown_fn: Option<Box<dyn FnMut() -> ProbarResult<()> + Send + Sync>>,
392    is_setup: bool,
393}
394
395impl std::fmt::Debug for SimpleFixture {
396    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397        f.debug_struct("SimpleFixture")
398            .field("name", &self.name)
399            .field("priority", &self.priority)
400            .field("is_setup", &self.is_setup)
401            .finish()
402    }
403}
404
405impl SimpleFixture {
406    /// Create a new simple fixture with the given name.
407    #[must_use]
408    pub fn new(name: impl Into<String>) -> Self {
409        Self {
410            name: name.into(),
411            priority: 0,
412            setup_fn: None,
413            teardown_fn: None,
414            is_setup: false,
415        }
416    }
417
418    /// Set the setup function.
419    #[must_use]
420    pub fn with_setup<F>(mut self, f: F) -> Self
421    where
422        F: FnMut() -> ProbarResult<()> + Send + Sync + 'static,
423    {
424        self.setup_fn = Some(Box::new(f));
425        self
426    }
427
428    /// Set the teardown function.
429    #[must_use]
430    pub fn with_teardown<F>(mut self, f: F) -> Self
431    where
432        F: FnMut() -> ProbarResult<()> + Send + Sync + 'static,
433    {
434        self.teardown_fn = Some(Box::new(f));
435        self
436    }
437
438    /// Set the priority.
439    #[must_use]
440    pub fn with_priority(mut self, priority: i32) -> Self {
441        self.priority = priority;
442        self
443    }
444}
445
446impl Fixture for SimpleFixture {
447    fn setup(&mut self) -> ProbarResult<()> {
448        if let Some(f) = &mut self.setup_fn {
449            f()?;
450        }
451        self.is_setup = true;
452        Ok(())
453    }
454
455    fn teardown(&mut self) -> ProbarResult<()> {
456        if let Some(f) = &mut self.teardown_fn {
457            f()?;
458        }
459        self.is_setup = false;
460        Ok(())
461    }
462
463    fn name(&self) -> &str {
464        &self.name
465    }
466
467    fn priority(&self) -> i32 {
468        self.priority
469    }
470}
471
472/// Builder for creating fixtures with dependencies.
473#[derive(Debug)]
474pub struct FixtureBuilder {
475    manager: FixtureManager,
476}
477
478impl Default for FixtureBuilder {
479    fn default() -> Self {
480        Self::new()
481    }
482}
483
484impl FixtureBuilder {
485    /// Create a new fixture builder.
486    #[must_use]
487    pub fn new() -> Self {
488        Self {
489            manager: FixtureManager::new(),
490        }
491    }
492
493    /// Add a fixture to the builder.
494    #[must_use]
495    pub fn with_fixture<F: Fixture + 'static>(mut self, fixture: F) -> Self {
496        self.manager.register(fixture);
497        self
498    }
499
500    /// Build the fixture manager.
501    #[must_use]
502    pub fn build(self) -> FixtureManager {
503        self.manager
504    }
505
506    /// Build and set up all fixtures.
507    pub fn build_and_setup(mut self) -> ProbarResult<FixtureManager> {
508        self.manager.setup_all()?;
509        Ok(self.manager)
510    }
511}
512
513/// A fixture scope for automatic teardown using RAII.
514///
515/// When the scope is dropped, all fixtures are torn down automatically.
516pub struct FixtureScope {
517    manager: FixtureManager,
518}
519
520impl FixtureScope {
521    /// Create a new fixture scope from a manager.
522    ///
523    /// The manager should already have fixtures set up.
524    #[must_use]
525    pub fn new(manager: FixtureManager) -> Self {
526        Self { manager }
527    }
528
529    /// Get access to a fixture.
530    #[must_use]
531    pub fn get<F: Fixture + 'static>(&self) -> Option<&F> {
532        self.manager.get()
533    }
534
535    /// Get mutable access to a fixture.
536    #[must_use]
537    pub fn get_mut<F: Fixture + 'static>(&mut self) -> Option<&mut F> {
538        self.manager.get_mut()
539    }
540}
541
542impl Drop for FixtureScope {
543    fn drop(&mut self) {
544        // Best effort teardown - ignore errors during drop
545        let _ = self.manager.teardown_all();
546    }
547}
548
549impl std::fmt::Debug for FixtureScope {
550    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
551        f.debug_struct("FixtureScope")
552            .field("manager", &self.manager)
553            .finish()
554    }
555}
556
557#[cfg(test)]
558#[allow(clippy::unwrap_used, clippy::expect_used)]
559mod tests {
560    use super::*;
561    use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
562    use std::sync::Arc;
563
564    // Test fixture that tracks setup/teardown calls
565    #[derive(Debug)]
566    struct TestFixture {
567        setup_called: Arc<AtomicBool>,
568        teardown_called: Arc<AtomicBool>,
569        priority: i32,
570    }
571
572    impl TestFixture {
573        fn new() -> Self {
574            Self {
575                setup_called: Arc::new(AtomicBool::new(false)),
576                teardown_called: Arc::new(AtomicBool::new(false)),
577                priority: 0,
578            }
579        }
580    }
581
582    impl Fixture for TestFixture {
583        fn setup(&mut self) -> ProbarResult<()> {
584            self.setup_called.store(true, Ordering::SeqCst);
585            Ok(())
586        }
587
588        fn teardown(&mut self) -> ProbarResult<()> {
589            self.teardown_called.store(true, Ordering::SeqCst);
590            Ok(())
591        }
592
593        fn priority(&self) -> i32 {
594            self.priority
595        }
596    }
597
598    // Fixture that fails on setup
599    #[derive(Debug)]
600    struct FailingSetupFixture;
601
602    impl Fixture for FailingSetupFixture {
603        fn setup(&mut self) -> ProbarResult<()> {
604            Err(ProbarError::FixtureError {
605                message: "Intentional setup failure".to_string(),
606            })
607        }
608
609        fn teardown(&mut self) -> ProbarResult<()> {
610            Ok(())
611        }
612    }
613
614    // Fixture that fails on teardown
615    #[derive(Debug)]
616    struct FailingTeardownFixture;
617
618    impl Fixture for FailingTeardownFixture {
619        fn setup(&mut self) -> ProbarResult<()> {
620            Ok(())
621        }
622
623        fn teardown(&mut self) -> ProbarResult<()> {
624            Err(ProbarError::FixtureError {
625                message: "Intentional teardown failure".to_string(),
626            })
627        }
628    }
629
630    mod fixture_state_tests {
631        use super::*;
632
633        #[test]
634        fn test_state_equality() {
635            assert_eq!(FixtureState::Registered, FixtureState::Registered);
636            assert_eq!(FixtureState::SetUp, FixtureState::SetUp);
637            assert_eq!(FixtureState::TornDown, FixtureState::TornDown);
638            assert_eq!(FixtureState::Failed, FixtureState::Failed);
639            assert_ne!(FixtureState::Registered, FixtureState::SetUp);
640        }
641    }
642
643    mod fixture_manager_tests {
644        use super::*;
645
646        #[test]
647        fn test_new_manager() {
648            let manager = FixtureManager::new();
649            assert_eq!(manager.count(), 0);
650        }
651
652        #[test]
653        fn test_register_fixture() {
654            let mut manager = FixtureManager::new();
655            manager.register(TestFixture::new());
656
657            assert_eq!(manager.count(), 1);
658            assert!(manager.is_registered::<TestFixture>());
659        }
660
661        #[test]
662        fn test_state_before_setup() {
663            let mut manager = FixtureManager::new();
664            manager.register(TestFixture::new());
665
666            assert_eq!(
667                manager.state::<TestFixture>(),
668                Some(FixtureState::Registered)
669            );
670        }
671
672        #[test]
673        fn test_setup_all() {
674            let fixture = TestFixture::new();
675            let setup_called = fixture.setup_called.clone();
676
677            let mut manager = FixtureManager::new();
678            manager.register(fixture);
679            manager.setup_all().expect("Setup should succeed");
680
681            assert!(setup_called.load(Ordering::SeqCst));
682            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::SetUp));
683        }
684
685        #[test]
686        fn test_teardown_all() {
687            let fixture = TestFixture::new();
688            let teardown_called = fixture.teardown_called.clone();
689
690            let mut manager = FixtureManager::new();
691            manager.register(fixture);
692            manager.setup_all().expect("Setup should succeed");
693            manager.teardown_all().expect("Teardown should succeed");
694
695            assert!(teardown_called.load(Ordering::SeqCst));
696            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::TornDown));
697        }
698
699        #[test]
700        fn test_setup_single_fixture() {
701            let fixture = TestFixture::new();
702            let setup_called = fixture.setup_called.clone();
703
704            let mut manager = FixtureManager::new();
705            manager.register(fixture);
706            manager
707                .setup::<TestFixture>()
708                .expect("Setup should succeed");
709
710            assert!(setup_called.load(Ordering::SeqCst));
711        }
712
713        #[test]
714        fn test_teardown_single_fixture() {
715            let fixture = TestFixture::new();
716            let teardown_called = fixture.teardown_called.clone();
717
718            let mut manager = FixtureManager::new();
719            manager.register(fixture);
720            manager
721                .setup::<TestFixture>()
722                .expect("Setup should succeed");
723            manager
724                .teardown::<TestFixture>()
725                .expect("Teardown should succeed");
726
727            assert!(teardown_called.load(Ordering::SeqCst));
728        }
729
730        #[test]
731        fn test_get_fixture() {
732            let fixture = TestFixture::new();
733            let setup_called = fixture.setup_called.clone();
734
735            let mut manager = FixtureManager::new();
736            manager.register(fixture);
737
738            let retrieved = manager.get::<TestFixture>();
739            assert!(retrieved.is_some());
740            assert!(Arc::ptr_eq(&retrieved.unwrap().setup_called, &setup_called));
741        }
742
743        #[test]
744        fn test_get_unregistered_fixture() {
745            let manager = FixtureManager::new();
746            assert!(manager.get::<TestFixture>().is_none());
747        }
748
749        #[test]
750        fn test_failing_setup() {
751            let mut manager = FixtureManager::new();
752            manager.register(FailingSetupFixture);
753
754            let result = manager.setup_all();
755            assert!(result.is_err());
756            assert_eq!(
757                manager.state::<FailingSetupFixture>(),
758                Some(FixtureState::Failed)
759            );
760        }
761
762        #[test]
763        fn test_failing_teardown() {
764            let mut manager = FixtureManager::new();
765            manager.register(FailingTeardownFixture);
766
767            manager.setup_all().expect("Setup should succeed");
768            let result = manager.teardown_all();
769            assert!(result.is_err());
770        }
771
772        #[test]
773        fn test_unregister() {
774            let mut manager = FixtureManager::new();
775            manager.register(TestFixture::new());
776
777            assert!(manager.is_registered::<TestFixture>());
778            assert!(manager.unregister::<TestFixture>());
779            assert!(!manager.is_registered::<TestFixture>());
780        }
781
782        #[test]
783        fn test_clear() {
784            let mut manager = FixtureManager::new();
785            manager.register(TestFixture::new());
786            manager.clear();
787
788            assert_eq!(manager.count(), 0);
789        }
790
791        #[test]
792        fn test_reset() {
793            let mut manager = FixtureManager::new();
794            manager.register(TestFixture::new());
795            manager.setup_all().expect("Setup should succeed");
796
797            manager.reset();
798            assert_eq!(
799                manager.state::<TestFixture>(),
800                Some(FixtureState::Registered)
801            );
802        }
803
804        #[test]
805        fn test_list() {
806            let mut manager = FixtureManager::new();
807            manager.register(TestFixture::new());
808
809            let names = manager.list();
810            assert_eq!(names.len(), 1);
811            assert!(names[0].contains("TestFixture"));
812        }
813    }
814
815    mod priority_tests {
816        use super::*;
817
818        #[derive(Debug)]
819        struct OrderedFixture {
820            expected_order: u32,
821            priority: i32,
822            order_counter: Arc<AtomicU32>,
823        }
824
825        impl Fixture for OrderedFixture {
826            fn setup(&mut self) -> ProbarResult<()> {
827                let actual = self.order_counter.fetch_add(1, Ordering::SeqCst);
828                assert_eq!(actual, self.expected_order, "Wrong setup order");
829                Ok(())
830            }
831
832            fn teardown(&mut self) -> ProbarResult<()> {
833                Ok(())
834            }
835
836            fn priority(&self) -> i32 {
837                self.priority
838            }
839        }
840
841        #[test]
842        fn test_priority_order() {
843            // Use a counter to track setup order
844            let order = Arc::new(AtomicU32::new(0));
845
846            let mut manager = FixtureManager::new();
847
848            // Register in wrong order
849            manager.register(OrderedFixture {
850                expected_order: 2, // Should be set up last (lowest priority)
851                priority: -10,
852                order_counter: order.clone(),
853            });
854            manager.register(SimpleFixture::new("middle").with_priority(0).with_setup({
855                let order_ref = order;
856                move || {
857                    let actual = order_ref.fetch_add(1, Ordering::SeqCst);
858                    assert_eq!(actual, 1, "Wrong setup order for middle");
859                    Ok(())
860                }
861            }));
862
863            // We can't add OrderedFixture twice (same TypeId), so just test with SimpleFixture
864            // The priority test is still valid since we're checking SimpleFixture order
865        }
866    }
867
868    mod simple_fixture_tests {
869        use super::*;
870
871        #[test]
872        fn test_simple_fixture_creation() {
873            let fixture = SimpleFixture::new("test_fixture");
874            assert_eq!(fixture.name(), "test_fixture");
875            assert_eq!(fixture.priority(), 0);
876        }
877
878        #[test]
879        fn test_simple_fixture_with_priority() {
880            let fixture = SimpleFixture::new("test").with_priority(10);
881            assert_eq!(fixture.priority(), 10);
882        }
883
884        #[test]
885        fn test_simple_fixture_setup() {
886            let called = Arc::new(AtomicBool::new(false));
887            let called_clone = called.clone();
888
889            let mut fixture = SimpleFixture::new("test").with_setup(move || {
890                called_clone.store(true, Ordering::SeqCst);
891                Ok(())
892            });
893
894            fixture.setup().expect("Setup should succeed");
895            assert!(called.load(Ordering::SeqCst));
896        }
897
898        #[test]
899        fn test_get_mut_fixture() {
900            let mut manager = FixtureManager::new();
901            manager.register(SimpleFixture::new("test"));
902
903            let fixture = manager.get_mut::<SimpleFixture>();
904            assert!(fixture.is_some());
905            assert_eq!(fixture.unwrap().name(), "test");
906        }
907
908        #[test]
909        fn test_get_mut_unregistered() {
910            let mut manager = FixtureManager::new();
911            let fixture = manager.get_mut::<TestFixture>();
912            assert!(fixture.is_none());
913        }
914
915        #[test]
916        fn test_setup_already_setup() {
917            let mut manager = FixtureManager::new();
918            manager.register(TestFixture::new());
919            manager.setup::<TestFixture>().unwrap();
920
921            // Setup again should be a no-op
922            let result = manager.setup::<TestFixture>();
923            assert!(result.is_ok());
924        }
925
926        #[test]
927        fn test_setup_unregistered() {
928            let mut manager = FixtureManager::new();
929            let result = manager.setup::<TestFixture>();
930            assert!(result.is_err());
931        }
932
933        #[test]
934        fn test_teardown_unregistered() {
935            let mut manager = FixtureManager::new();
936            let result = manager.teardown::<TestFixture>();
937            assert!(result.is_err());
938        }
939
940        #[test]
941        fn test_teardown_not_setup() {
942            let mut manager = FixtureManager::new();
943            manager.register(TestFixture::new());
944
945            // Teardown without setup should be a no-op
946            let result = manager.teardown::<TestFixture>();
947            assert!(result.is_ok());
948        }
949
950        #[test]
951        fn test_manager_debug() {
952            let manager = FixtureManager::new();
953            let debug = format!("{:?}", manager);
954            assert!(debug.contains("FixtureManager"));
955        }
956
957        #[test]
958        fn test_simple_fixture_teardown() {
959            let called = Arc::new(AtomicBool::new(false));
960            let called_clone = called.clone();
961
962            let mut fixture = SimpleFixture::new("test").with_teardown(move || {
963                called_clone.store(true, Ordering::SeqCst);
964                Ok(())
965            });
966
967            fixture.teardown().expect("Teardown should succeed");
968            assert!(called.load(Ordering::SeqCst));
969        }
970    }
971
972    mod fixture_builder_tests {
973        use super::*;
974
975        #[test]
976        fn test_builder_new() {
977            let builder = FixtureBuilder::new();
978            let manager = builder.build();
979            assert_eq!(manager.count(), 0);
980        }
981
982        #[test]
983        fn test_builder_with_fixture() {
984            let manager = FixtureBuilder::new()
985                .with_fixture(TestFixture::new())
986                .build();
987
988            assert_eq!(manager.count(), 1);
989        }
990
991        #[test]
992        fn test_builder_and_setup() {
993            let fixture = TestFixture::new();
994            let setup_called = fixture.setup_called.clone();
995
996            let manager = FixtureBuilder::new()
997                .with_fixture(fixture)
998                .build_and_setup()
999                .expect("Setup should succeed");
1000
1001            assert!(setup_called.load(Ordering::SeqCst));
1002            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::SetUp));
1003        }
1004    }
1005
1006    mod fixture_scope_tests {
1007        use super::*;
1008
1009        #[test]
1010        fn test_scope_auto_teardown() {
1011            let fixture = TestFixture::new();
1012            let teardown_called = fixture.teardown_called.clone();
1013
1014            {
1015                let mut manager = FixtureManager::new();
1016                manager.register(fixture);
1017                manager.setup_all().expect("Setup should succeed");
1018
1019                let _scope = FixtureScope::new(manager);
1020                // Scope will be dropped here
1021            }
1022
1023            assert!(teardown_called.load(Ordering::SeqCst));
1024        }
1025
1026        #[test]
1027        fn test_scope_get_fixture() {
1028            let fixture = TestFixture::new();
1029            let setup_called = fixture.setup_called.clone();
1030
1031            let mut manager = FixtureManager::new();
1032            manager.register(fixture);
1033            manager.setup_all().expect("Setup should succeed");
1034
1035            let scope = FixtureScope::new(manager);
1036            let retrieved = scope.get::<TestFixture>();
1037            assert!(retrieved.is_some());
1038            assert!(Arc::ptr_eq(&retrieved.unwrap().setup_called, &setup_called));
1039        }
1040    }
1041
1042    mod additional_fixture_tests {
1043        use super::*;
1044
1045        #[test]
1046        fn test_fixture_default_name() {
1047            let fixture = TestFixture::new();
1048            let name = fixture.name();
1049            assert!(name.contains("TestFixture"));
1050        }
1051
1052        #[test]
1053        fn test_fixture_default_priority() {
1054            #[derive(Debug)]
1055            struct DefaultPriorityFixture;
1056
1057            impl Fixture for DefaultPriorityFixture {
1058                fn setup(&mut self) -> ProbarResult<()> {
1059                    Ok(())
1060                }
1061                fn teardown(&mut self) -> ProbarResult<()> {
1062                    Ok(())
1063                }
1064            }
1065
1066            let fixture = DefaultPriorityFixture;
1067            assert_eq!(fixture.priority(), 0);
1068        }
1069
1070        #[test]
1071        fn test_fixture_state_debug() {
1072            let state = FixtureState::SetUp;
1073            let debug = format!("{:?}", state);
1074            assert!(debug.contains("SetUp"));
1075        }
1076
1077        #[test]
1078        fn test_fixture_state_clone() {
1079            let state = FixtureState::Failed;
1080            let cloned = state;
1081            assert_eq!(state, cloned);
1082        }
1083
1084        #[test]
1085        fn test_simple_fixture_default_callbacks() {
1086            let mut fixture = SimpleFixture::new("test");
1087            // Should not fail even without callbacks
1088            assert!(fixture.setup().is_ok());
1089            assert!(fixture.teardown().is_ok());
1090        }
1091
1092        #[test]
1093        fn test_manager_default() {
1094            let manager = FixtureManager::default();
1095            assert_eq!(manager.count(), 0);
1096        }
1097
1098        #[test]
1099        fn test_unregister_nonexistent() {
1100            let mut manager = FixtureManager::new();
1101            assert!(!manager.unregister::<TestFixture>());
1102        }
1103
1104        #[test]
1105        fn test_teardown_already_torn_down() {
1106            let mut manager = FixtureManager::new();
1107            manager.register(TestFixture::new());
1108            manager.setup_all().unwrap();
1109            manager.teardown_all().unwrap();
1110
1111            // Teardown again should be a no-op
1112            let result = manager.teardown_all();
1113            assert!(result.is_ok());
1114        }
1115
1116        #[test]
1117        fn test_builder_multiple_fixtures() {
1118            let manager = FixtureBuilder::new()
1119                .with_fixture(SimpleFixture::new("first"))
1120                .with_fixture(SimpleFixture::new("second"))
1121                .build();
1122
1123            // Only one SimpleFixture since they share the same TypeId
1124            assert_eq!(manager.count(), 1);
1125        }
1126    }
1127
1128    mod coverage_enhancement_tests {
1129        use super::*;
1130
1131        // Fixture with configurable priority that tracks order
1132        #[derive(Debug)]
1133        struct PriorityFixture {
1134            name: String,
1135            priority: i32,
1136            setup_order: Arc<std::sync::Mutex<Vec<String>>>,
1137            teardown_order: Arc<std::sync::Mutex<Vec<String>>>,
1138        }
1139
1140        impl PriorityFixture {
1141            fn new(
1142                name: &str,
1143                priority: i32,
1144                setup_order: Arc<std::sync::Mutex<Vec<String>>>,
1145                teardown_order: Arc<std::sync::Mutex<Vec<String>>>,
1146            ) -> Self {
1147                Self {
1148                    name: name.to_string(),
1149                    priority,
1150                    setup_order,
1151                    teardown_order,
1152                }
1153            }
1154        }
1155
1156        impl Fixture for PriorityFixture {
1157            fn setup(&mut self) -> ProbarResult<()> {
1158                self.setup_order.lock().unwrap().push(self.name.clone());
1159                Ok(())
1160            }
1161
1162            fn teardown(&mut self) -> ProbarResult<()> {
1163                self.teardown_order.lock().unwrap().push(self.name.clone());
1164                Ok(())
1165            }
1166
1167            fn name(&self) -> &str {
1168                &self.name
1169            }
1170
1171            fn priority(&self) -> i32 {
1172                self.priority
1173            }
1174        }
1175
1176        // Fixture that fails on setup but with high priority
1177        #[allow(dead_code)] // Reserved for future tests
1178        #[derive(Debug)]
1179        struct HighPriorityFailingSetupFixture {
1180            priority: i32,
1181        }
1182
1183        impl Fixture for HighPriorityFailingSetupFixture {
1184            fn setup(&mut self) -> ProbarResult<()> {
1185                Err(ProbarError::FixtureError {
1186                    message: "High priority setup failure".to_string(),
1187                })
1188            }
1189
1190            fn teardown(&mut self) -> ProbarResult<()> {
1191                Ok(())
1192            }
1193
1194            fn priority(&self) -> i32 {
1195                self.priority
1196            }
1197        }
1198
1199        // Fixture that fails on setup but with low priority (set up later)
1200        #[derive(Debug)]
1201        struct LowPriorityFailingSetupFixture {
1202            priority: i32,
1203            setup_order: Arc<std::sync::Mutex<Vec<String>>>,
1204        }
1205
1206        impl Fixture for LowPriorityFailingSetupFixture {
1207            fn setup(&mut self) -> ProbarResult<()> {
1208                self.setup_order
1209                    .lock()
1210                    .unwrap()
1211                    .push("low_failing".to_string());
1212                Err(ProbarError::FixtureError {
1213                    message: "Low priority setup failure".to_string(),
1214                })
1215            }
1216
1217            fn teardown(&mut self) -> ProbarResult<()> {
1218                Ok(())
1219            }
1220
1221            fn priority(&self) -> i32 {
1222                self.priority
1223            }
1224        }
1225
1226        // Another unique fixture type for testing multiple fixture types
1227        #[derive(Debug)]
1228        struct SecondTestFixture {
1229            setup_called: Arc<AtomicBool>,
1230            teardown_called: Arc<AtomicBool>,
1231        }
1232
1233        impl SecondTestFixture {
1234            fn new() -> Self {
1235                Self {
1236                    setup_called: Arc::new(AtomicBool::new(false)),
1237                    teardown_called: Arc::new(AtomicBool::new(false)),
1238                }
1239            }
1240        }
1241
1242        impl Fixture for SecondTestFixture {
1243            fn setup(&mut self) -> ProbarResult<()> {
1244                self.setup_called.store(true, Ordering::SeqCst);
1245                Ok(())
1246            }
1247
1248            fn teardown(&mut self) -> ProbarResult<()> {
1249                self.teardown_called.store(true, Ordering::SeqCst);
1250                Ok(())
1251            }
1252        }
1253
1254        #[test]
1255        fn test_simple_fixture_debug() {
1256            let fixture = SimpleFixture::new("debug_test").with_priority(5);
1257            let debug = format!("{:?}", fixture);
1258            assert!(debug.contains("SimpleFixture"));
1259            assert!(debug.contains("debug_test"));
1260            assert!(debug.contains('5'));
1261        }
1262
1263        #[test]
1264        fn test_fixture_scope_debug() {
1265            let manager = FixtureManager::new();
1266            let scope = FixtureScope::new(manager);
1267            let debug = format!("{:?}", scope);
1268            assert!(debug.contains("FixtureScope"));
1269            assert!(debug.contains("FixtureManager"));
1270        }
1271
1272        #[test]
1273        fn test_fixture_builder_default() {
1274            let builder = FixtureBuilder::default();
1275            let manager = builder.build();
1276            assert_eq!(manager.count(), 0);
1277        }
1278
1279        #[test]
1280        fn test_build_and_setup_failure() {
1281            let result = FixtureBuilder::new()
1282                .with_fixture(FailingSetupFixture)
1283                .build_and_setup();
1284
1285            assert!(result.is_err());
1286        }
1287
1288        #[test]
1289        fn test_setup_all_with_rollback() {
1290            // Test that when a fixture fails setup, previously set up fixtures are torn down
1291            let setup_order = Arc::new(std::sync::Mutex::new(Vec::new()));
1292            let teardown_order = Arc::new(std::sync::Mutex::new(Vec::new()));
1293
1294            let mut manager = FixtureManager::new();
1295
1296            // Register a fixture that succeeds (high priority, set up first)
1297            manager.register(PriorityFixture::new(
1298                "first",
1299                100,
1300                setup_order.clone(),
1301                teardown_order.clone(),
1302            ));
1303
1304            // Register a fixture that will fail (low priority, set up later)
1305            manager.register(LowPriorityFailingSetupFixture {
1306                priority: -100,
1307                setup_order: setup_order.clone(),
1308            });
1309
1310            let result = manager.setup_all();
1311            assert!(result.is_err());
1312
1313            // Verify the first fixture was set up
1314            let setup = setup_order.lock().unwrap();
1315            assert!(setup.contains(&"first".to_string()));
1316            assert!(setup.contains(&"low_failing".to_string()));
1317
1318            // Verify the first fixture was torn down after the failure
1319            let teardown = teardown_order.lock().unwrap();
1320            assert!(teardown.contains(&"first".to_string()));
1321        }
1322
1323        #[test]
1324        fn test_teardown_failure_continues_others() {
1325            // Test that when one fixture fails teardown, others are still torn down
1326            let mut manager = FixtureManager::new();
1327
1328            manager.register(FailingTeardownFixture);
1329            manager.register(TestFixture::new());
1330
1331            manager.setup_all().expect("Setup should succeed");
1332
1333            // First teardown should fail but both should be attempted
1334            let result = manager.teardown_all();
1335            assert!(result.is_err());
1336        }
1337
1338        #[test]
1339        fn test_fixture_scope_get_mut() {
1340            let fixture = TestFixture::new();
1341            let setup_called = fixture.setup_called.clone();
1342
1343            let mut manager = FixtureManager::new();
1344            manager.register(fixture);
1345            manager.setup_all().expect("Setup should succeed");
1346
1347            let mut scope = FixtureScope::new(manager);
1348            let retrieved = scope.get_mut::<TestFixture>();
1349            assert!(retrieved.is_some());
1350            assert!(Arc::ptr_eq(&retrieved.unwrap().setup_called, &setup_called));
1351        }
1352
1353        #[test]
1354        fn test_fixture_scope_get_unregistered() {
1355            let manager = FixtureManager::new();
1356            let scope = FixtureScope::new(manager);
1357            assert!(scope.get::<TestFixture>().is_none());
1358        }
1359
1360        #[test]
1361        fn test_fixture_scope_get_mut_unregistered() {
1362            let manager = FixtureManager::new();
1363            let mut scope = FixtureScope::new(manager);
1364            assert!(scope.get_mut::<TestFixture>().is_none());
1365        }
1366
1367        #[test]
1368        fn test_setup_from_torn_down_state() {
1369            // Test setup_all when fixtures are in TornDown state
1370            let mut manager = FixtureManager::new();
1371            manager.register(TestFixture::new());
1372
1373            manager.setup_all().expect("First setup should succeed");
1374            manager.teardown_all().expect("Teardown should succeed");
1375
1376            // Setup again from TornDown state
1377            let result = manager.setup_all();
1378            assert!(result.is_ok());
1379            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::SetUp));
1380        }
1381
1382        #[test]
1383        fn test_multiple_fixture_types() {
1384            // Test with multiple different fixture types (not just SimpleFixture)
1385            let mut manager = FixtureManager::new();
1386            manager.register(TestFixture::new());
1387            manager.register(SecondTestFixture::new());
1388
1389            assert_eq!(manager.count(), 2);
1390            assert!(manager.is_registered::<TestFixture>());
1391            assert!(manager.is_registered::<SecondTestFixture>());
1392        }
1393
1394        #[test]
1395        fn test_register_replaces_existing() {
1396            let first = TestFixture::new();
1397            let first_setup = first.setup_called.clone();
1398
1399            let second = TestFixture::new();
1400            let second_setup = second.setup_called.clone();
1401
1402            let mut manager = FixtureManager::new();
1403            manager.register(first);
1404            manager.register(second);
1405
1406            // Only one fixture registered
1407            assert_eq!(manager.count(), 1);
1408
1409            // The second one replaced the first
1410            manager.setup_all().expect("Setup should succeed");
1411            assert!(second_setup.load(Ordering::SeqCst));
1412            // The first was replaced so its setup wasn't called
1413            assert!(!first_setup.load(Ordering::SeqCst));
1414        }
1415
1416        #[test]
1417        fn test_single_fixture_setup_failure() {
1418            let mut manager = FixtureManager::new();
1419            manager.register(FailingSetupFixture);
1420
1421            let result = manager.setup::<FailingSetupFixture>();
1422            assert!(result.is_err());
1423        }
1424
1425        #[test]
1426        fn test_single_fixture_teardown_failure() {
1427            let mut manager = FixtureManager::new();
1428            manager.register(FailingTeardownFixture);
1429
1430            manager
1431                .setup::<FailingTeardownFixture>()
1432                .expect("Setup should succeed");
1433            let result = manager.teardown::<FailingTeardownFixture>();
1434            assert!(result.is_err());
1435        }
1436
1437        #[test]
1438        fn test_unregister_removes_from_setup_order() {
1439            let mut manager = FixtureManager::new();
1440            manager.register(TestFixture::new());
1441            manager.setup_all().expect("Setup should succeed");
1442
1443            // Unregister should also clean up setup_order
1444            assert!(manager.unregister::<TestFixture>());
1445            assert!(!manager.is_registered::<TestFixture>());
1446        }
1447
1448        #[test]
1449        fn test_simple_fixture_is_setup_tracking() {
1450            let mut fixture = SimpleFixture::new("test");
1451            assert!(!fixture.is_setup);
1452
1453            fixture.setup().expect("Setup should succeed");
1454            assert!(fixture.is_setup);
1455
1456            fixture.teardown().expect("Teardown should succeed");
1457            assert!(!fixture.is_setup);
1458        }
1459
1460        #[test]
1461        fn test_simple_fixture_failing_setup() {
1462            let mut fixture = SimpleFixture::new("test").with_setup(|| {
1463                Err(ProbarError::FixtureError {
1464                    message: "Test failure".to_string(),
1465                })
1466            });
1467
1468            let result = fixture.setup();
1469            assert!(result.is_err());
1470        }
1471
1472        #[test]
1473        fn test_simple_fixture_failing_teardown() {
1474            let mut fixture = SimpleFixture::new("test").with_teardown(|| {
1475                Err(ProbarError::FixtureError {
1476                    message: "Teardown failure".to_string(),
1477                })
1478            });
1479
1480            fixture.setup().expect("Setup should succeed");
1481            let result = fixture.teardown();
1482            assert!(result.is_err());
1483        }
1484
1485        #[test]
1486        fn test_list_multiple_fixtures() {
1487            let mut manager = FixtureManager::new();
1488            manager.register(TestFixture::new());
1489            manager.register(SecondTestFixture::new());
1490
1491            let names = manager.list();
1492            assert_eq!(names.len(), 2);
1493        }
1494
1495        #[test]
1496        fn test_state_none_for_unregistered() {
1497            let manager = FixtureManager::new();
1498            assert!(manager.state::<TestFixture>().is_none());
1499        }
1500
1501        #[test]
1502        fn test_priority_ordering_in_setup() {
1503            let setup_order = Arc::new(std::sync::Mutex::new(Vec::new()));
1504            let teardown_order = Arc::new(std::sync::Mutex::new(Vec::new()));
1505
1506            let mut manager = FixtureManager::new();
1507
1508            // Register with different priorities (out of order)
1509            manager.register(PriorityFixture::new(
1510                "low",
1511                -10,
1512                setup_order.clone(),
1513                teardown_order,
1514            ));
1515
1516            // Use SimpleFixture for high priority (different type)
1517            let setup_clone = setup_order.clone();
1518            manager.register(
1519                SimpleFixture::new("high")
1520                    .with_priority(10)
1521                    .with_setup(move || {
1522                        setup_clone.lock().unwrap().push("high".to_string());
1523                        Ok(())
1524                    }),
1525            );
1526
1527            manager.setup_all().expect("Setup should succeed");
1528
1529            let setup = setup_order.lock().unwrap();
1530            // High priority (10) should be set up before low priority (-10)
1531            let high_idx = setup.iter().position(|s| s == "high").unwrap();
1532            let low_idx = setup.iter().position(|s| s == "low").unwrap();
1533            assert!(high_idx < low_idx, "High priority should be set up first");
1534        }
1535
1536        #[test]
1537        fn test_teardown_reverse_order() {
1538            let setup_order = Arc::new(std::sync::Mutex::new(Vec::new()));
1539            let teardown_order = Arc::new(std::sync::Mutex::new(Vec::new()));
1540
1541            let mut manager = FixtureManager::new();
1542
1543            manager.register(PriorityFixture::new(
1544                "high",
1545                100,
1546                setup_order,
1547                teardown_order.clone(),
1548            ));
1549
1550            // Second fixture with different type
1551            let teardown_clone = teardown_order.clone();
1552            manager.register(SimpleFixture::new("low").with_priority(-100).with_teardown(
1553                move || {
1554                    teardown_clone.lock().unwrap().push("low".to_string());
1555                    Ok(())
1556                },
1557            ));
1558
1559            manager.setup_all().expect("Setup should succeed");
1560            manager.teardown_all().expect("Teardown should succeed");
1561
1562            let teardown = teardown_order.lock().unwrap();
1563            // Low priority was set up last, so it should be torn down first
1564            let high_idx = teardown.iter().position(|s| s == "high").unwrap();
1565            let low_idx = teardown.iter().position(|s| s == "low").unwrap();
1566            assert!(
1567                low_idx < high_idx,
1568                "Low priority (set up last) should be torn down first"
1569            );
1570        }
1571
1572        #[test]
1573        fn test_clear_empties_setup_order() {
1574            let mut manager = FixtureManager::new();
1575            manager.register(TestFixture::new());
1576            manager.setup_all().expect("Setup should succeed");
1577
1578            manager.clear();
1579            assert_eq!(manager.count(), 0);
1580            assert!(manager.list().is_empty());
1581        }
1582
1583        #[test]
1584        fn test_reset_clears_setup_order() {
1585            let fixture = TestFixture::new();
1586            let teardown_called = fixture.teardown_called.clone();
1587
1588            let mut manager = FixtureManager::new();
1589            manager.register(fixture);
1590            manager.setup_all().expect("Setup should succeed");
1591
1592            // Reset without teardown
1593            manager.reset();
1594
1595            // Teardown should NOT have been called
1596            assert!(!teardown_called.load(Ordering::SeqCst));
1597            assert_eq!(
1598                manager.state::<TestFixture>(),
1599                Some(FixtureState::Registered)
1600            );
1601        }
1602
1603        #[test]
1604        fn test_fixture_scope_drop_with_failing_teardown() {
1605            // This tests that the scope ignores errors during drop
1606            let mut manager = FixtureManager::new();
1607            manager.register(FailingTeardownFixture);
1608            manager.setup_all().expect("Setup should succeed");
1609
1610            // This should not panic even though teardown fails
1611            let _scope = FixtureScope::new(manager);
1612            // Scope drops here without panicking
1613        }
1614
1615        #[test]
1616        fn test_single_teardown_updates_state() {
1617            let mut manager = FixtureManager::new();
1618            manager.register(TestFixture::new());
1619
1620            manager
1621                .setup::<TestFixture>()
1622                .expect("Setup should succeed");
1623            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::SetUp));
1624
1625            manager
1626                .teardown::<TestFixture>()
1627                .expect("Teardown should succeed");
1628            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::TornDown));
1629        }
1630
1631        #[test]
1632        fn test_setup_adds_to_setup_order_once() {
1633            let mut manager = FixtureManager::new();
1634            manager.register(TestFixture::new());
1635
1636            // Setup multiple times
1637            manager.setup::<TestFixture>().unwrap();
1638            manager.reset();
1639            manager.setup::<TestFixture>().unwrap();
1640
1641            // Should work without issues
1642            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::SetUp));
1643        }
1644
1645        #[test]
1646        fn test_single_fixture_teardown_removes_from_order() {
1647            let mut manager = FixtureManager::new();
1648            manager.register(TestFixture::new());
1649            manager.register(SecondTestFixture::new());
1650
1651            manager.setup_all().expect("Setup should succeed");
1652
1653            // Teardown just one fixture
1654            manager
1655                .teardown::<TestFixture>()
1656                .expect("Teardown should succeed");
1657
1658            // The other should still be set up
1659            assert_eq!(
1660                manager.state::<SecondTestFixture>(),
1661                Some(FixtureState::SetUp)
1662            );
1663            assert_eq!(manager.state::<TestFixture>(), Some(FixtureState::TornDown));
1664        }
1665
1666        #[test]
1667        fn test_fixture_error_message_includes_name() {
1668            let mut manager = FixtureManager::new();
1669            manager.register(FailingSetupFixture);
1670
1671            let result = manager.setup_all();
1672            assert!(result.is_err());
1673
1674            if let Err(ProbarError::FixtureError { message }) = result {
1675                assert!(message.contains("FailingSetupFixture"));
1676                assert!(message.contains("setup failed"));
1677            } else {
1678                panic!("Expected FixtureError");
1679            }
1680        }
1681
1682        #[test]
1683        fn test_teardown_error_message_includes_name() {
1684            let mut manager = FixtureManager::new();
1685            manager.register(FailingTeardownFixture);
1686            manager.setup_all().expect("Setup should succeed");
1687
1688            let result = manager.teardown_all();
1689            assert!(result.is_err());
1690
1691            if let Err(ProbarError::FixtureError { message }) = result {
1692                assert!(message.contains("FailingTeardownFixture"));
1693                assert!(message.contains("teardown failed"));
1694            } else {
1695                panic!("Expected FixtureError");
1696            }
1697        }
1698    }
1699}