1use std::sync::Mutex;
8
9#[macro_export]
11macro_rules! assert_lt {
12 ($x:expr, $y:expr) => {
13 assert!(
14 $x < $y,
15 "assertion `{} < {}` failed; actual: {:?} is not less than {:?}",
16 stringify!($x),
17 stringify!($y),
18 $x,
19 $y
20 );
21 };
22}
23
24#[macro_export]
26macro_rules! assert_leq {
27 ($x:expr, $y:expr) => {
28 assert!(
29 $x <= $y,
30 "assertion `{} <= {}` failed; actual: {:?} is not less than or equal to {:?}",
31 stringify!($x),
32 stringify!($y),
33 $x,
34 $y
35 );
36 };
37}
38
39#[macro_export]
41macro_rules! assert_gt {
42 ($x:expr, $y:expr) => {
43 assert!(
44 $x > $y,
45 "assertion `{} > {}` failed; actual: {:?} is not greater than {:?}",
46 stringify!($x),
47 stringify!($y),
48 $x,
49 $y
50 );
51 };
52}
53
54#[macro_export]
56macro_rules! assert_geq {
57 ($x:expr, $y:expr) => {
58 assert!(
59 $x >= $y,
60 "assertion `{} >= {}` failed; actual: {:?} is not greater than or equal to {:?}",
61 stringify!($x),
62 stringify!($y),
63 $x,
64 $y
65 );
66 };
67}
68
69#[macro_export]
76macro_rules! assert_near {
77 ($x: expr, $y: expr, $delta: expr) => {
78 let difference = $x - $y;
79 assert!(
80 (-$delta..=$delta).contains(&difference),
81 "assertion `{} is near {} (within delta {})` failed; actual: |{:?} - {:?}| > {:?}",
82 stringify!($x),
83 stringify!($y),
84 stringify!($delta),
85 $x,
86 $y,
87 $delta
88 );
89 };
90}
91
92pub struct Counter {
144 count: Mutex<usize>,
145}
146
147impl Counter {
148 pub fn new(initial: usize) -> Self {
150 Counter { count: Mutex::new(initial) }
151 }
152
153 pub fn inc(&self) -> usize {
155 let mut count = self.count.lock().unwrap();
156 *count += 1;
157 *count
158 }
159
160 pub fn get(&self) -> usize {
162 *self.count.lock().unwrap()
163 }
164}
165
166impl std::fmt::Debug for Counter {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 f.debug_struct("Counter").field("count", &self.get()).finish()
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175 use std::collections::BTreeSet;
176 use std::sync::mpsc::{Receiver, Sender};
177 use std::sync::{LazyLock, mpsc};
178 use std::thread;
179
180 #[derive(Debug, PartialEq, PartialOrd)]
181 struct NotDisplay {
182 x: i32,
183 }
184
185 impl core::ops::Sub for NotDisplay {
186 type Output = Self;
187
188 fn sub(self, other: Self) -> Self {
189 NotDisplay { x: self.x - other.x }
190 }
191 }
192
193 impl core::ops::Neg for NotDisplay {
194 type Output = Self;
195
196 fn neg(self) -> Self {
197 NotDisplay { x: -self.x }
198 }
199 }
200
201 #[test]
202 fn test_assert_lt_passes() {
203 assert_lt!(1, 2);
204 assert_lt!(1u8, 2u8);
205 assert_lt!(1u16, 2u16);
206 assert_lt!(1u32, 2u32);
207 assert_lt!(1u64, 2u64);
208 assert_lt!(-1, 3);
209 assert_lt!(-1i8, 3i8);
210 assert_lt!(-1i16, 3i16);
211 assert_lt!(-1i32, 3i32);
212 assert_lt!(-1i64, 3i64);
213 assert_lt!(-2.0, 7.0);
214 assert_lt!(-2.0f32, 7.0f32);
215 assert_lt!(-2.0f64, 7.0f64);
216 assert_lt!('a', 'b');
217 assert_lt!(NotDisplay { x: 1 }, NotDisplay { x: 2 });
218 }
219
220 #[test]
221 #[should_panic(expected = "assertion `a < b` failed; actual: 2 is not less than 2")]
222 fn test_assert_lt_fails_a_equals_b() {
223 let a = 2;
224 let b = 2;
225 assert_lt!(a, b);
226 }
227
228 #[test]
229 #[should_panic(expected = "assertion `a < b` failed; actual: 5 is not less than 2")]
230 fn test_assert_lt_fails_a_greater_than_b() {
231 let a = 5;
232 let b = 2;
233 assert_lt!(a, b);
234 }
235
236 #[test]
237 fn test_assert_leq_passes() {
238 assert_leq!(1, 2);
239 assert_leq!(2, 2);
240 assert_leq!(-2.0, 3.0);
241 assert_leq!(3.0, 3.0);
242 assert_leq!('a', 'b');
243 assert_leq!('b', 'b');
244 assert_leq!(NotDisplay { x: 1 }, NotDisplay { x: 2 });
245 assert_leq!(NotDisplay { x: 2 }, NotDisplay { x: 2 });
246 }
247
248 #[test]
249 #[should_panic(
250 expected = "assertion `a <= b` failed; actual: 3 is not less than or equal to 2"
251 )]
252 fn test_assert_leq_fails() {
253 let a = 3;
254 let b = 2;
255 assert_leq!(a, b);
256 }
257
258 #[test]
259 fn test_assert_gt_passes() {
260 assert_gt!(2, 1);
261 assert_gt!(2u8, 1u8);
262 assert_gt!(2u16, 1u16);
263 assert_gt!(2u32, 1u32);
264 assert_gt!(2u64, 1u64);
265 assert_gt!(3, -1);
266 assert_gt!(3i8, -1i8);
267 assert_gt!(3i16, -1i16);
268 assert_gt!(3i32, -1i32);
269 assert_gt!(3i64, -1i64);
270 assert_gt!(7.0, -2.0);
271 assert_gt!(7.0f32, -2.0f32);
272 assert_gt!(7.0f64, -2.0f64);
273 assert_gt!('b', 'a');
274 assert_gt!(NotDisplay { x: 2 }, NotDisplay { x: 1 });
275 }
276
277 #[test]
278 #[should_panic(expected = "assertion `a > b` failed; actual: 2 is not greater than 2")]
279 fn test_assert_gt_fails_a_equals_b() {
280 let a = 2;
281 let b = 2;
282 assert_gt!(a, b);
283 }
284
285 #[test]
286 #[should_panic(expected = "assertion `a > b` failed; actual: -1 is not greater than 2")]
287 fn test_assert_gt_fails_a_less_than_b() {
288 let a = -1;
289 let b = 2;
290 assert_gt!(a, b);
291 }
292
293 #[test]
294 fn test_assert_geq_passes() {
295 assert_geq!(2, 1);
296 assert_geq!(2, 2);
297 assert_geq!(3.0, -2.0);
298 assert_geq!(3.0, 3.0);
299 assert_geq!('b', 'a');
300 assert_geq!('b', 'b');
301 assert_geq!(NotDisplay { x: 2 }, NotDisplay { x: 1 });
302 assert_geq!(NotDisplay { x: 2 }, NotDisplay { x: 2 });
303 }
304
305 #[test]
306 #[should_panic(
307 expected = "assertion `a >= b` failed; actual: 2 is not greater than or equal to 3"
308 )]
309 fn test_assert_geq_fails() {
310 let a = 2;
311 let b = 3;
312 assert_geq!(a, b);
313 }
314
315 #[test]
316 fn test_assert_near_passes() {
317 assert_near!(1.0001, 1.0, 0.01);
319 assert_near!(1.0, 1.0001, 0.01);
320 assert_near!(1.0, 1.0, 0.0);
321
322 assert_near!(1.0001f32, 1.0f32, 0.01f32);
324 assert_near!(1.0001f64, 1.0f64, 0.01f64);
325 assert_near!(7, 5, 2);
326 assert_near!(7i8, 5i8, 2i8);
327 assert_near!(7i16, 5i16, 2i16);
328 assert_near!(7i32, 5i32, 2i32);
329 assert_near!(7i64, 5i64, 2i64);
330
331 assert_near!(NotDisplay { x: 7 }, NotDisplay { x: 5 }, NotDisplay { x: 2 });
332 }
333
334 #[test]
335 #[should_panic]
336 fn test_assert_near_fails() {
337 assert_near!(1.00001, 1.0, 1e-8);
338 }
339
340 #[test]
342 #[should_panic(
343 expected = "assertion `a is near b (within delta d)` failed; actual: |3 - 5| > 1"
344 )]
345 fn test_assert_near_fails_with_message() {
346 let a = 3;
347 let b = 5;
348 let d = 1;
349 assert_near!(a, b, d);
350 }
351
352 #[test]
353 fn test_inc() {
354 static CALL_COUNT: LazyLock<Counter> = LazyLock::new(|| Counter::new(0));
355
356 CALL_COUNT.inc();
357
358 assert_eq!(CALL_COUNT.get(), 1);
359 }
360
361 #[test]
362 fn test_incs_from_10() {
363 static CALL_COUNT: LazyLock<Counter> = LazyLock::new(|| Counter::new(10));
364
365 CALL_COUNT.inc();
366 CALL_COUNT.inc();
367 CALL_COUNT.inc();
368
369 assert_eq!(CALL_COUNT.get(), 13);
370 }
371
372 #[test]
373 fn async_counts() {
374 static CALL_COUNT: LazyLock<Counter> = LazyLock::new(|| Counter::new(0));
375
376 let (tx, rx): (Sender<usize>, Receiver<usize>) = mpsc::channel();
377 let mut children = Vec::new();
378
379 static NTHREADS: usize = 10;
380
381 for _ in 0..NTHREADS {
382 let thread_tx = tx.clone();
383 let child = thread::spawn(move || {
384 let new_value = CALL_COUNT.inc();
385 thread_tx.send(new_value).unwrap();
386 println!("Sent: {} (OK if out of order)", new_value);
387 });
388
389 children.push(child);
390 }
391
392 let mut ordered_ids: BTreeSet<usize> = BTreeSet::new();
393 for _ in 0..NTHREADS {
394 let received_id = rx.recv().unwrap();
395 println!("Received: {} (OK if in yet a different order)", received_id);
396 ordered_ids.insert(received_id);
397 }
398
399 for child in children {
401 child.join().expect("child thread panicked");
402 }
403
404 assert_eq!(CALL_COUNT.get(), NTHREADS);
406
407 let mut expected_id: usize = 1;
410 for id in ordered_ids.iter() {
411 assert_eq!(*id, expected_id);
412 expected_id += 1;
413 }
414 }
415
416 #[test]
417 fn debug_format_counter() {
418 let counter = Counter::new(0);
419 assert_eq!(format!("{:?}", counter), "Counter { count: 0 }");
420 }
421}