wowlab_tidy/languages/rust/rules/style/
whitespace.rs1#[cfg(test)]
2use googletest::prelude::*;
3
4use crate::{Example, FileCtx, Fix, Violation, violation};
5
6#[rustfmt::skip]
7const EXAMPLES: &[Example] = &[
8 Example {
9 label: "clean file",
10 code: "fn main() {}",
11 pass: true,
12 },
13 Example {
14 label: "trailing whitespace",
15 code: "let x = 1; \nlet y = 2;",
16 pass: false,
17 },
18 Example {
19 label: "tab character",
20 code: "\tlet x = 1;",
21 pass: false,
22 },
23];
24
25crate::line_rule!(
26 style,
27 "Enforce no trailing whitespace, no tabs, no CRLF line endings.",
28 "Trailing whitespace, tabs, and CRLF endings cause noisy diffs and merge conflicts.",
29 Low,
30 fix_style,
31);
32
33fn check_style(ctx: &FileCtx<'_>) -> Vec<Violation> {
34 let mut out = Vec::new();
35
36 for (i, line) in ctx.lines.iter().enumerate() {
37 let lineno = i + 1;
38
39 if *line != line.trim_end() {
40 out.push(violation(ctx.rel, lineno, "trailing whitespace"));
41 }
42
43 if line.contains('\t') {
44 out.push(violation(ctx.rel, lineno, "tab character (use spaces)"));
45 }
46
47 if line.contains('\r') {
48 out.push(violation(ctx.rel, lineno, "CR line ending (use LF)"));
49 }
50 }
51
52 out
53}
54
55fn fix_style(ctx: &FileCtx<'_>, v: &Violation) -> Option<Fix> {
56 let line = ctx.line(v.line)?;
57 let fixed = line.replace('\t', " ").replace('\r', "");
58
59 Some(Fix::replace_line(v.line, fixed.trim_end()))
60}
61
62crate::tidy_test!(check_style, {
63 crate::example_tests!(EXAMPLES, check_style);
64 crate::fix_tests!(line, check_style, fix_style);
65
66 #[gtest]
67 fn cr_line_ending() -> Result<()> {
68 let v = run("let x = 1;\r");
69 verify_false!(v.is_empty())?;
70 verify_true!(v.iter().any(|v| v.message.contains("CR line ending")))?;
71
72 Ok(())
73 }
74
75 #[gtest]
76 fn multiple_violations_on_one_line() -> Result<()> {
77 let v = run("\tlet x = 1; ");
78 verify_eq!(v.len(), 2)?;
79
80 Ok(())
81 }
82});