Skip to main content

wowlab_tidy/languages/rust/rules/tests/
gtest_required.rs

1use ra_ap_syntax::{
2    AstNode,
3    ast::{self, HasAttrs},
4};
5
6use crate::{AstCtx, Example, Violation};
7
8#[rustfmt::skip]
9const EXAMPLES: &[Example] = &[
10    Example { label: "gtest", code: "#[gtest]\nfn works() {}", pass: true },
11    Example { label: "plain test", code: "#[test]\nfn works() {}", pass: false },
12    Example { label: "gtest before tokio", code: "#[gtest]\n#[tokio::test]\nasync fn works() {}", pass: true },
13    Example { label: "tokio without gtest", code: "#[tokio::test]\nasync fn works() {}", pass: false },
14    Example { label: "ordinary function", code: "fn works() {}", pass: true },
15];
16
17crate::ast_rule!(
18    gtest_required,
19    "Require every native Rust test to use the googletest test attribute.",
20    "A single test framework keeps matcher behavior and failure reporting consistent.",
21    Medium,
22);
23
24fn check_gtest_required(ctx: &AstCtx<'_>) -> Vec<Violation> {
25    ctx.nodes::<ast::Fn>()
26        .filter(|function| {
27            let attrs: Vec<String> = function
28                .attrs()
29                .map(|attr| attr.syntax().text().to_string())
30                .collect();
31            let native_test = attrs
32                .iter()
33                .any(|attr| attr == "#[test]" || attr == "#[tokio::test]");
34
35            native_test && !attrs.iter().any(|attr| attr == "#[gtest]")
36        })
37        .map(|function| ctx.violation(&function, "native test function must carry `#[gtest]`"))
38        .collect()
39}
40
41crate::tidy_ast_test!(check_gtest_required, {
42    crate::example_tests!(EXAMPLES, check_gtest_required);
43});