Skip to main content

assertr/assertions/std/
mutex.rs

1use core::fmt::Debug;
2use core::fmt::Write;
3use indoc::writedoc;
4use std::sync::Mutex;
5
6use crate::{AssertThat, Mode, tracking::AssertionTracking};
7
8#[allow(clippy::return_self_not_must_use)]
9#[cfg_attr(feature = "fluent", assertr_derive::fluent_aliases)]
10pub trait MutexAssertions {
11    /// Asserts that this mutex is locked.
12    /// Note that implementations may try to acquire the lock in order to check its state.
13    fn is_locked(self) -> Self;
14
15    /// Asserts that this mutex is not locked.
16    /// Note that implementations may try to acquire the lock in order to check its state.
17    #[cfg_attr(feature = "fluent", fluent_alias("not_be_locked"))]
18    fn is_not_locked(self) -> Self;
19
20    /// Asserts that this mutex is not locked.
21    /// Note that implementations may try to acquire the lock in order to check its state.
22    ///
23    /// Synonym for [`Self::is_not_locked`].
24    fn is_free(self) -> Self
25    where
26        Self: Sized,
27    {
28        self.is_not_locked()
29    }
30}
31
32impl<T: Debug, M: Mode> MutexAssertions for AssertThat<'_, Mutex<T>, M> {
33    #[track_caller]
34    fn is_locked(self) -> Self {
35        self.track_assertion();
36        let actual = self.actual();
37        if let Ok(guard) = actual.try_lock() {
38            self.fail(|w: &mut String| {
39                writedoc! {w, r"
40                    Expected: Mutex {{ data: {guard:#?}, poisoned: {poisoned} }}
41
42                    to be locked, but it wasn't!
43                ", poisoned = actual.is_poisoned()}
44            });
45        }
46        self
47    }
48
49    #[track_caller]
50    fn is_not_locked(self) -> Self {
51        self.track_assertion();
52        let actual = self.actual();
53        if let Err(_err) = actual.try_lock() {
54            self.fail(|w: &mut String| {
55                writedoc! {w, r"
56                    Expected: Mutex {{ data: <locked>, poisoned: {poisoned} }}
57
58                    to not be locked, but it was!
59                ", poisoned = actual.is_poisoned()}
60            });
61        }
62        self
63    }
64}
65
66#[cfg(test)]
67mod tests {
68
69    mod is_locked {
70        use crate::prelude::*;
71        use indoc::formatdoc;
72        use std::sync::Mutex;
73
74        #[test]
75        fn succeeds_when_locked() {
76            let mutex = Mutex::new(42);
77            let guard = mutex.lock();
78            assert_that!(&mutex).is_locked();
79            drop(guard);
80        }
81
82        #[test]
83        fn panics_when_not_locked() {
84            let mutex = Mutex::new(42);
85            assert_that_panic_by(|| assert_that!(mutex).with_location(false).is_locked())
86                .has_type::<String>()
87                .is_equal_to(formatdoc! {"
88                    -------- assertr --------
89                    Expected: Mutex {{ data: 42, poisoned: false }}
90
91                    to be locked, but it wasn't!
92                    -------- assertr --------
93                "});
94        }
95    }
96
97    mod is_not_locked {
98        use crate::prelude::*;
99        use indoc::formatdoc;
100        use std::sync::Mutex;
101
102        #[test]
103        fn succeeds_when_not_locked() {
104            let mutex = Mutex::new(42);
105            assert_that!(mutex).is_not_locked();
106        }
107
108        #[test]
109        fn panics_when_locked() {
110            let mutex = Mutex::new(42);
111            let guard = mutex.lock();
112            assert_that_panic_by(|| assert_that!(&mutex).with_location(false).is_not_locked())
113                .has_type::<String>()
114                .is_equal_to(formatdoc! {"
115                    -------- assertr --------
116                    Expected: Mutex {{ data: <locked>, poisoned: false }}
117
118                    to not be locked, but it was!
119                    -------- assertr --------
120                "});
121            drop(guard);
122        }
123    }
124
125    mod is_free {
126        use crate::prelude::*;
127        use std::sync::Mutex;
128
129        #[test]
130        fn succeeds_when_not_locked() {
131            let mutex = Mutex::new(42);
132            assert_that!(mutex).is_free();
133        }
134    }
135}