Skip to main content

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

1use ra_ap_syntax::{
2    AstNode,
3    ast::{self, HasAttrs},
4};
5
6use super::macro_name;
7use crate::{AstCtx, Example, Violation};
8
9#[rustfmt::skip]
10const EXAMPLES: &[Example] = &[
11    Example { label: "verify in result test", code: "#[gtest]\nfn works() -> Result<()> { verify_that!(1, eq(1))?; Ok(()) }", pass: true },
12    Example { label: "expect in result test", code: "#[gtest]\nfn works() -> Result<()> { expect_that!(1, eq(1)); Ok(()) }", pass: false },
13    Example { label: "expect in non-result test", code: "#[gtest]\nfn works() { expect_that!(1, eq(1)); }", pass: true },
14];
15
16crate::ast_rule!(
17    expect_in_result_test,
18    "Disallow `expect_that!` in tests returning Result.",
19    "Result tests should propagate `verify_that!(..)?` failures through their explicit return channel.",
20    Low,
21);
22
23fn check_expect_in_result_test(ctx: &AstCtx<'_>) -> Vec<Violation> {
24    let mut violations = Vec::new();
25
26    for function in ctx.nodes::<ast::Fn>().filter(|function| {
27        function.ret_type().is_some()
28            && function
29                .attrs()
30                .any(|attr| matches!(attr.simple_name().as_deref(), Some("gtest" | "test")))
31    }) {
32        for call in function
33            .syntax()
34            .descendants()
35            .filter_map(ast::MacroCall::cast)
36        {
37            if macro_name(&call).as_deref() == Some("expect_that") {
38                violations.push(
39                    ctx.violation(&call, "use `verify_that!(..)?` in Result-returning tests"),
40                );
41            }
42        }
43    }
44
45    violations
46}
47
48crate::tidy_ast_test!(check_expect_in_result_test, {
49    crate::example_tests!(EXAMPLES, check_expect_in_result_test);
50});