From 45da21672ad1e4ec53487c373b1b7e2ca8f944a2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 23 Jan 2019 15:36:29 +0300 Subject: generalize marking infrastructure --- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/marks.rs | 83 +------------------------------------- crates/ra_hir/src/module_tree.rs | 1 + crates/ra_hir/src/nameres/tests.rs | 2 +- crates/test_utils/src/lib.rs | 9 ++++- crates/test_utils/src/marks.rs | 80 ++++++++++++++++++++++++++++++++++++ 6 files changed, 91 insertions(+), 86 deletions(-) create mode 100644 crates/test_utils/src/marks.rs diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 361d39f03..33a9ba605 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -8,7 +8,7 @@ pub mod db; #[cfg(test)] mod mock; -#[macro_use] +#[cfg(test)] mod marks; mod query_definitions; mod path; diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 05430b975..6aff2c4e1 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -1,82 +1 @@ -//! This module implements manually tracked test coverage, which useful for -//! quickly finding a test responsible for testing a particular bit of code. -//! -//! See https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html -//! for details, but the TL;DR is that you write your test as -//! -//! ```no-run -//! #[test] -//! fn test_foo() { -//! covers!(test_foo); -//! } -//! ``` -//! -//! and in the code under test you write -//! -//! ```no-run -//! 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`. - -#[macro_export] -macro_rules! tested_by { - ($ident:ident) => { - #[cfg(test)] - { - crate::marks::marks::$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst); - } - }; -} - -#[macro_export] -macro_rules! covers { - ($ident:ident) => { - let _checker = crate::marks::marks::MarkChecker::new(&crate::marks::marks::$ident); - }; -} - -#[cfg(test)] -pub(crate) mod marks { - use std::sync::atomic::{AtomicUsize, Ordering}; - - pub(crate) struct MarkChecker { - mark: &'static AtomicUsize, - value_on_entry: usize, - } - - impl MarkChecker { - pub(crate) 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") - } - } - - macro_rules! mark { - ($ident:ident) => { - #[allow(bad_style)] - pub(crate) static $ident: AtomicUsize = AtomicUsize::new(0); - }; - } - - mark!(name_res_works_for_broken_modules); -} +test_utils::mark!(name_res_works_for_broken_modules); diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs index 0256d7996..47c14af35 100644 --- a/crates/ra_hir/src/module_tree.rs +++ b/crates/ra_hir/src/module_tree.rs @@ -10,6 +10,7 @@ use ra_syntax::{ ast::{self, AstNode, NameOwner}, }; use ra_arena::{Arena, RawId, impl_arena_id}; +use test_utils::tested_by; use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource}; diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 0ec11ec12..e92007453 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use ra_db::{FilesDatabase, CrateGraph, SourceRootId, salsa::Database}; use relative_path::RelativePath; -use test_utils::assert_eq_text; +use test_utils::{assert_eq_text, covers}; use crate::{ ItemMap, Resolution, diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 6489033dd..35a679aea 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -1,5 +1,10 @@ -use std::fs; -use std::path::{Path, PathBuf}; +#[macro_use] +pub mod marks; + +use std::{ + fs, + path::{Path, PathBuf} +}; use text_unit::{TextRange, TextUnit}; use serde_json::Value; diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs new file mode 100644 index 000000000..79ffedf69 --- /dev/null +++ b/crates/test_utils/src/marks.rs @@ -0,0 +1,80 @@ +//! This module implements manually tracked test coverage, which useful for +//! quickly finding a test responsible for testing a particular bit of code. +//! +//! See https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html +//! for details, but the TL;DR is that you write your test as +//! +//! ```no-run +//! #[test] +//! fn test_foo() { +//! covers!(test_foo); +//! } +//! ``` +//! +//! and in the code under test you write +//! +//! ```no-run +//! 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 { + ($ident:ident) => { + // sic! use call-site crate + let _checker = $crate::marks::MarkChecker::new(&crate::marks::$ident); + }; +} + +#[macro_export] +macro_rules! mark { + ($ident:ident) => { + #[allow(bad_style)] + pub(crate) 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