Skip to content

Commit d18d1c0

Browse files
committed
Significantly more glorious marks
1 parent 4d3fd62 commit d18d1c0

File tree

4 files changed

+86
-8
lines changed

4 files changed

+86
-8
lines changed

crates/ra_assists/src/handlers/add_turbo_fish.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass};
22
use ra_syntax::{ast, AstNode, SyntaxKind, T};
3+
use test_utils::mark;
34

45
use crate::{
56
assist_context::{AssistContext, Assists},
67
AssistId,
78
};
8-
use test_utils::tested_by;
99

1010
// Assist: add_turbo_fish
1111
//
@@ -28,7 +28,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
2828
let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?;
2929
let next_token = ident.next_token()?;
3030
if next_token.kind() == T![::] {
31-
tested_by!(add_turbo_fish_one_fish_is_enough);
31+
mark::hit!(add_turbo_fish_one_fish_is_enough);
3232
return None;
3333
}
3434
let name_ref = ast::NameRef::cast(ident.parent())?;
@@ -42,7 +42,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
4242
};
4343
let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
4444
if generics.is_empty() {
45-
tested_by!(add_turbo_fish_non_generic);
45+
mark::hit!(add_turbo_fish_non_generic);
4646
return None;
4747
}
4848
acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| {
@@ -58,7 +58,7 @@ mod tests {
5858
use crate::tests::{check_assist, check_assist_not_applicable};
5959

6060
use super::*;
61-
use test_utils::covers;
61+
use test_utils::mark;
6262

6363
#[test]
6464
fn add_turbo_fish_function() {
@@ -106,7 +106,7 @@ fn main() {
106106

107107
#[test]
108108
fn add_turbo_fish_one_fish_is_enough() {
109-
covers!(add_turbo_fish_one_fish_is_enough);
109+
mark::check!(add_turbo_fish_one_fish_is_enough);
110110
check_assist_not_applicable(
111111
add_turbo_fish,
112112
r#"
@@ -120,7 +120,7 @@ fn main() {
120120

121121
#[test]
122122
fn add_turbo_fish_non_generic() {
123-
covers!(add_turbo_fish_non_generic);
123+
mark::check!(add_turbo_fish_non_generic);
124124
check_assist_not_applicable(
125125
add_turbo_fish,
126126
r#"

crates/ra_assists/src/marks.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,4 @@ test_utils::marks![
1010
test_not_applicable_if_variable_unused
1111
change_visibility_field_false_positive
1212
test_add_from_impl_already_exists
13-
add_turbo_fish_one_fish_is_enough
14-
add_turbo_fish_non_generic
1513
];

crates/test_utils/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
99
#[macro_use]
1010
pub mod marks;
11+
#[macro_use]
12+
pub mod mark;
1113

1214
use std::{
1315
fs,

crates/test_utils/src/mark.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
//! mark::check!(test_foo);
11+
//! }
12+
//! ```
13+
//!
14+
//! and in the code under test you write
15+
//!
16+
//! ```
17+
//! # use test_utils::mark;
18+
//! # fn some_condition() -> bool { true }
19+
//! fn foo() {
20+
//! if some_condition() {
21+
//! mark::hit!(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`.
29+
use std::sync::atomic::{AtomicUsize, Ordering};
30+
31+
#[macro_export]
32+
macro_rules! _hit {
33+
($ident:ident) => {{
34+
#[cfg(test)]
35+
{
36+
extern "C" {
37+
#[no_mangle]
38+
static $ident: std::sync::atomic::AtomicUsize;
39+
}
40+
unsafe {
41+
$ident.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
42+
}
43+
}
44+
}};
45+
}
46+
pub use _hit as hit;
47+
48+
#[macro_export]
49+
macro_rules! _check {
50+
($ident:ident) => {
51+
#[no_mangle]
52+
static $ident: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
53+
let _checker = $crate::mark::MarkChecker::new(&$ident);
54+
};
55+
}
56+
pub use _check as check;
57+
58+
pub struct MarkChecker {
59+
mark: &'static AtomicUsize,
60+
value_on_entry: usize,
61+
}
62+
63+
impl MarkChecker {
64+
pub fn new(mark: &'static AtomicUsize) -> MarkChecker {
65+
let value_on_entry = mark.load(Ordering::SeqCst);
66+
MarkChecker { mark, value_on_entry }
67+
}
68+
}
69+
70+
impl Drop for MarkChecker {
71+
fn drop(&mut self) {
72+
if std::thread::panicking() {
73+
return;
74+
}
75+
let value_on_exit = self.mark.load(Ordering::SeqCst);
76+
assert!(value_on_exit > self.value_on_entry, "mark was not hit")
77+
}
78+
}

0 commit comments

Comments
 (0)