repeated_assert/
macros.rs

1#![allow(deprecated)]
2
3/// An assertion macro that tries to assert expressions multiple times
4///
5/// ## Examples
6///
7/// Wait for a file to appear, calculate the checksum and then assert the checksum is to equal to `1234` (re-try up to 10 times, wait 50 ms between tries)
8///
9/// ```rust,ignore
10/// repeated_assert!{ 10, Duration::from_millis(50);
11///     if Path::new("should_appear_soon.txt").exists();
12///     let checksum = crc("should_appear_soon.txt");
13///     eq checksum, 1234;
14/// };
15/// ```
16#[deprecated(
17    since = "0.2.0",
18    note = "Use `repeated_assert::that` or `repeated_assert::with_catch` instead."
19)]
20#[macro_export]
21macro_rules! repeated_assert {
22    ($repetitions:expr, $delay:expr; $($tt:tt)*) => {
23        for i in 0..$repetitions {
24            if i == $repetitions - 1 {
25                __repeated_assert!{ @final, $($tt)* }
26            } else {
27                if __repeated_assert!{ $($tt)* } {
28                    break;
29                }
30                ::std::thread::sleep($delay);
31            }
32        }
33    };
34    ($repetitions:expr, $delay:expr, $repetitions_catch:expr, $catch:block; $($tt:tt)*) => {
35        for i in 0..$repetitions {
36            if i == $repetitions - 1 {
37                __repeated_assert!{ @final, $($tt)* }
38            } else if i == $repetitions_catch {
39                let thread_name = ::std::thread::current().name().unwrap_or("unnamed thread").to_owned();
40                println!("{}: executing repeated-assert catch block", thread_name);
41                $catch
42                ::std::thread::sleep($delay);
43            } else {
44                if __repeated_assert!{ $($tt)* } {
45                    break;
46                }
47                ::std::thread::sleep($delay);
48            }
49        }
50    };
51}
52
53#[doc(hidden)]
54#[macro_export]
55macro_rules! __repeated_assert {
56    (@final, if $expr:expr;) => {
57        assert!($expr);
58    };
59    (@final, eq $left:expr, $right:expr;) => {
60        assert_eq!($left, $right, stringify!($left != $right));
61    };
62    (@final, if $expr:expr; $($tt:tt)+) => {
63        assert!($expr);
64        __repeated_assert!{ @final, $($tt)+ }
65    };
66    (@final, eq $left:expr, $right:expr; $($tt:tt)+) => {
67        assert_eq!($left, $right, stringify!($left != $right));
68        __repeated_assert!{ @final, $($tt)+ }
69    };
70    (@final, let $($pat:pat)|+ = $expr:expr; $($tt:tt)+) => {
71        match $expr {
72            $($pat)|+ => { __repeated_assert!{ @final, $($tt)+ } }
73        }
74    };
75    (if $expr:expr;) => {
76        $expr
77    };
78    (eq $left:expr, $right:expr;) => {
79        $left == $right
80    };
81    (if $expr:expr; $($tt:tt)+) => {
82        if $expr {
83            __repeated_assert!{ $($tt)+ }
84        } else {
85            false
86        }
87    };
88    (eq $left:expr, $right:expr; $($tt:tt)+) => {
89        if $left == $right {
90            __repeated_assert!{ $($tt)+ }
91        } else {
92            false
93        }
94    };
95    (let $($pat:pat)|+ = $expr:expr; $($tt:tt)+) => {
96        match $expr {
97            $($pat)|+ => { __repeated_assert!{ $($tt)+ } }
98        }
99    };
100}
101
102#[cfg(test)]
103mod tests {
104    use std::sync::{Arc, Mutex};
105    use std::thread;
106    use std::time::Duration;
107
108    static STEP_MS: u64 = 100;
109
110    fn spawn_thread(x: Arc<Mutex<i32>>) {
111        thread::spawn(move || loop {
112            thread::sleep(Duration::from_millis(10 * STEP_MS));
113            if let Ok(mut x) = x.lock() {
114                *x += 1;
115            }
116        });
117    }
118
119    #[test]
120    fn single_success() {
121        let x = Arc::new(Mutex::new(0));
122
123        spawn_thread(x.clone());
124
125        repeated_assert! { 5, Duration::from_millis(5 * STEP_MS);
126            if *x.lock().unwrap() > 0;
127        };
128    }
129
130    #[test]
131    #[should_panic(expected = "assertion failed: *x.lock().unwrap() > 0")]
132    fn single_failure() {
133        let x = Arc::new(Mutex::new(0));
134
135        spawn_thread(x.clone());
136
137        repeated_assert! { 3, Duration::from_millis(STEP_MS);
138            if *x.lock().unwrap() > 0;
139        };
140    }
141
142    #[test]
143    fn multiple_success() {
144        let x = Arc::new(Mutex::new(0));
145        let a = 11;
146        let b = 11;
147
148        spawn_thread(x.clone());
149
150        repeated_assert! { 5, Duration::from_millis(5 * STEP_MS);
151            if *x.lock().unwrap() > 0;
152            eq a, b;
153        };
154    }
155
156    #[test]
157    #[should_panic(expected = "assertion failed: *x.lock().unwrap() > 0")]
158    fn multiple_failure_1() {
159        let x = Arc::new(Mutex::new(0));
160        let a = 11;
161        let b = 11;
162
163        spawn_thread(x.clone());
164
165        repeated_assert! { 3, Duration::from_millis(STEP_MS);
166            if *x.lock().unwrap() > 0;
167            eq a, b;
168        };
169    }
170
171    #[test]
172    #[should_panic(expected = "a != b")]
173    fn multiple_failure_2() {
174        let x = Arc::new(Mutex::new(0));
175        let a = 11;
176        let b = 12;
177
178        spawn_thread(x.clone());
179
180        repeated_assert! { 5, Duration::from_millis(5 * STEP_MS);
181            if *x.lock().unwrap() > 0;
182            eq a, b;
183        };
184    }
185
186    #[test]
187    fn let_success() {
188        let x = Arc::new(Mutex::new(0));
189
190        spawn_thread(x.clone());
191
192        repeated_assert! { 5, Duration::from_millis(5 * STEP_MS);
193            let y = *x.lock().unwrap();
194            if y > 0;
195        };
196    }
197
198    #[test]
199    #[should_panic(expected = "assertion failed: y > 0")]
200    fn let_failure() {
201        let x = Arc::new(Mutex::new(0));
202
203        spawn_thread(x.clone());
204
205        repeated_assert! { 3, Duration::from_millis(STEP_MS);
206            let y = *x.lock().unwrap();
207            if y > 0;
208        };
209    }
210
211    #[test]
212    fn catch() {
213        let x = Arc::new(Mutex::new(-1_000));
214
215        spawn_thread(x.clone());
216
217        repeated_assert! { 10, Duration::from_millis(5 * STEP_MS), 5, {
218                *x.lock().unwrap() = 0;
219            };
220            if *x.lock().unwrap() > 0;
221        };
222    }
223}