aboutsummaryrefslogtreecommitdiff
path: root/crates/test_utils
diff options
context:
space:
mode:
Diffstat (limited to 'crates/test_utils')
-rw-r--r--crates/test_utils/src/lib.rs2
-rw-r--r--crates/test_utils/src/marks.rs81
2 files changed, 0 insertions, 83 deletions
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 4e05d464f..be2cfbaa2 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -7,8 +7,6 @@
7//! * marks (see the eponymous module). 7//! * marks (see the eponymous module).
8 8
9#[macro_use] 9#[macro_use]
10pub mod marks;
11#[macro_use]
12pub mod mark; 10pub mod mark;
13 11
14use std::{ 12use std::{
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs
deleted file mode 100644
index f20fb978e..000000000
--- a/crates/test_utils/src/marks.rs
+++ /dev/null
@@ -1,81 +0,0 @@
1//! This module implements manually tracked test coverage, which is useful for
2//! quickly finding a test responsible for testing a particular bit of code.
3//!
4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
5//! for details, but the TL;DR is that you write your test as
6//!
7//! ```
8//! #[test]
9//! fn test_foo() {
10//! covers!(test_foo);
11//! }
12//! ```
13//!
14//! and in the code under test you write
15//!
16//! ```
17//! # use test_utils::tested_by;
18//! # fn some_condition() -> bool { true }
19//! fn foo() {
20//! if some_condition() {
21//! tested_by!(test_foo);
22//! }
23//! }
24//! ```
25//!
26//! This module then checks that executing the test indeed covers the specified
27//! function. This is useful if you come back to the `foo` function ten years
28//! later and wonder where the test are: now you can grep for `test_foo`.
29use std::sync::atomic::{AtomicUsize, Ordering};
30
31#[macro_export]
32macro_rules! tested_by {
33 ($ident:ident) => {{
34 #[cfg(test)]
35 {
36 // sic! use call-site crate
37 crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
38 }
39 }};
40}
41
42#[macro_export]
43macro_rules! covers {
44 // sic! use call-site crate
45 ($ident:ident) => {
46 let _checker = $crate::marks::MarkChecker::new(&crate::marks::$ident);
47 };
48}
49
50#[macro_export]
51macro_rules! marks {
52 ($($ident:ident)*) => {
53 $(
54 #[allow(bad_style)]
55 pub static $ident: std::sync::atomic::AtomicUsize =
56 std::sync::atomic::AtomicUsize::new(0);
57 )*
58 };
59}
60
61pub struct MarkChecker {
62 mark: &'static AtomicUsize,
63 value_on_entry: usize,
64}
65
66impl MarkChecker {
67 pub fn new(mark: &'static AtomicUsize) -> MarkChecker {
68 let value_on_entry = mark.load(Ordering::SeqCst);
69 MarkChecker { mark, value_on_entry }
70 }
71}
72
73impl Drop for MarkChecker {
74 fn drop(&mut self) {
75 if std::thread::panicking() {
76 return;
77 }
78 let value_on_exit = self.mark.load(Ordering::SeqCst);
79 assert!(value_on_exit > self.value_on_entry, "mark was not hit")
80 }
81}