From d18d1c05949eaa890e7bb75710816a61b09a93dd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 May 2020 00:19:59 +0200 Subject: Significantly more glorious marks --- crates/test_utils/src/lib.rs | 2 ++ crates/test_utils/src/mark.rs | 78 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 crates/test_utils/src/mark.rs (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index b1e3c328f..4e05d464f 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -8,6 +8,8 @@ #[macro_use] pub mod marks; +#[macro_use] +pub mod mark; use std::{ fs, diff --git a/crates/test_utils/src/mark.rs b/crates/test_utils/src/mark.rs new file mode 100644 index 000000000..7c309a894 --- /dev/null +++ b/crates/test_utils/src/mark.rs @@ -0,0 +1,78 @@ +//! This module implements manually tracked test coverage, which is useful for +//! quickly finding a test responsible for testing a particular bit of code. +//! +//! See +//! for details, but the TL;DR is that you write your test as +//! +//! ``` +//! #[test] +//! fn test_foo() { +//! mark::check!(test_foo); +//! } +//! ``` +//! +//! and in the code under test you write +//! +//! ``` +//! # use test_utils::mark; +//! # fn some_condition() -> bool { true } +//! fn foo() { +//! if some_condition() { +//! mark::hit!(test_foo); +//! } +//! } +//! ``` +//! +//! This module then checks that executing the test indeed covers the specified +//! function. This is useful if you come back to the `foo` function ten years +//! later and wonder where the test are: now you can grep for `test_foo`. +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[macro_export] +macro_rules! _hit { + ($ident:ident) => {{ + #[cfg(test)] + { + extern "C" { + #[no_mangle] + static $ident: std::sync::atomic::AtomicUsize; + } + unsafe { + $ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + } + } + }}; +} +pub use _hit as hit; + +#[macro_export] +macro_rules! _check { + ($ident:ident) => { + #[no_mangle] + static $ident: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); + let _checker = $crate::mark::MarkChecker::new(&$ident); + }; +} +pub use _check as check; + +pub struct MarkChecker { + mark: &'static AtomicUsize, + value_on_entry: usize, +} + +impl MarkChecker { + pub fn new(mark: &'static AtomicUsize) -> MarkChecker { + let value_on_entry = mark.load(Ordering::SeqCst); + MarkChecker { mark, value_on_entry } + } +} + +impl Drop for MarkChecker { + fn drop(&mut self) { + if std::thread::panicking() { + return; + } + let value_on_exit = self.mark.load(Ordering::SeqCst); + assert!(value_on_exit > self.value_on_entry, "mark was not hit") + } +} -- cgit v1.2.3 From 5258c817f78ecdfe12d7eec44ab3169134cba71d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 May 2020 11:54:57 +0200 Subject: Remove cross-crate marks They create quite a bit of friction. Really, we should just move the tests to the same crate, rather than paper over existing split. --- crates/test_utils/src/marks.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs index c3185e860..f20fb978e 100644 --- a/crates/test_utils/src/marks.rs +++ b/crates/test_utils/src/marks.rs @@ -30,12 +30,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; #[macro_export] macro_rules! tested_by { - ($ident:ident; force) => {{ - { - // sic! use call-site crate - crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); - } - }}; ($ident:ident) => {{ #[cfg(test)] { @@ -49,10 +43,7 @@ macro_rules! tested_by { macro_rules! covers { // sic! use call-site crate ($ident:ident) => { - $crate::covers!(crate::$ident) - }; - ($krate:ident :: $ident:ident) => { - let _checker = $crate::marks::MarkChecker::new(&$krate::marks::$ident); + let _checker = $crate::marks::MarkChecker::new(&crate::marks::$ident); }; } -- cgit v1.2.3 From ecac5d7de2192873c24b7b06d4964d188d8abe6a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 May 2020 12:59:20 +0200 Subject: Switch to new magic marks --- crates/test_utils/src/lib.rs | 2 -- crates/test_utils/src/marks.rs | 81 ------------------------------------------ 2 files changed, 83 deletions(-) delete mode 100644 crates/test_utils/src/marks.rs (limited to 'crates/test_utils') 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 @@ -6,8 +6,6 @@ //! * Extracting markup (mainly, `<|>` markers) out of fixture strings. //! * marks (see the eponymous module). -#[macro_use] -pub mod marks; #[macro_use] pub mod mark; 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 @@ -//! This module implements manually tracked test coverage, which is useful for -//! quickly finding a test responsible for testing a particular bit of code. -//! -//! See -//! for details, but the TL;DR is that you write your test as -//! -//! ``` -//! #[test] -//! fn test_foo() { -//! covers!(test_foo); -//! } -//! ``` -//! -//! and in the code under test you write -//! -//! ``` -//! # use test_utils::tested_by; -//! # fn some_condition() -> bool { true } -//! fn foo() { -//! if some_condition() { -//! tested_by!(test_foo); -//! } -//! } -//! ``` -//! -//! This module then checks that executing the test indeed covers the specified -//! function. This is useful if you come back to the `foo` function ten years -//! later and wonder where the test are: now you can grep for `test_foo`. -use std::sync::atomic::{AtomicUsize, Ordering}; - -#[macro_export] -macro_rules! tested_by { - ($ident:ident) => {{ - #[cfg(test)] - { - // sic! use call-site crate - crate::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); - } - }}; -} - -#[macro_export] -macro_rules! covers { - // sic! use call-site crate - ($ident:ident) => { - let _checker = $crate::marks::MarkChecker::new(&crate::marks::$ident); - }; -} - -#[macro_export] -macro_rules! marks { - ($($ident:ident)*) => { - $( - #[allow(bad_style)] - pub static $ident: std::sync::atomic::AtomicUsize = - std::sync::atomic::AtomicUsize::new(0); - )* - }; -} - -pub struct MarkChecker { - mark: &'static AtomicUsize, - value_on_entry: usize, -} - -impl MarkChecker { - pub fn new(mark: &'static AtomicUsize) -> MarkChecker { - let value_on_entry = mark.load(Ordering::SeqCst); - MarkChecker { mark, value_on_entry } - } -} - -impl Drop for MarkChecker { - fn drop(&mut self) { - if std::thread::panicking() { - return; - } - let value_on_exit = self.mark.load(Ordering::SeqCst); - assert!(value_on_exit > self.value_on_entry, "mark was not hit") - } -} -- cgit v1.2.3