wowlab_tidy/languages/rust/rules/tests/
expect_in_result_test.rs1use 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});