use crate::linter::{Diagnostic, Fix, LintResult, Severity, Span};
pub fn check(source: &str) -> LintResult {
let mut result = LintResult::new();
for (line_num, line) in source.lines().enumerate() {
if line.contains("rm ") && !line.contains("rm -") {
if let Some(col) = line.find("rm ") {
let span = Span::new(line_num + 1, col + 1, line_num + 1, col + 3);
let fix = Fix::new_with_assumptions(
"rm -f",
vec!["Missing file is not an error condition".to_string()],
);
let diag = Diagnostic::new(
"IDEM002",
Severity::Warning,
"Non-idempotent rm - add -f flag (SAFE-WITH-ASSUMPTIONS)",
span,
)
.with_fix(fix);
result.add(diag);
}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_IDEM002_detects_rm_without_f() {
let script = "rm /app/current";
let result = check(script);
assert_eq!(result.diagnostics.len(), 1);
let diag = &result.diagnostics[0];
assert_eq!(diag.code, "IDEM002");
assert_eq!(diag.severity, Severity::Warning);
}
#[test]
fn test_IDEM002_no_warning_with_f_flag() {
let script = "rm -f /app/current";
let result = check(script);
assert_eq!(result.diagnostics.len(), 0);
}
#[test]
fn test_IDEM002_no_warning_with_rf() {
let script = "rm -rf /app/releases";
let result = check(script);
assert_eq!(result.diagnostics.len(), 0);
}
#[test]
fn test_IDEM002_provides_fix() {
let script = "rm /tmp/foo";
let result = check(script);
assert!(result.diagnostics[0].fix.is_some());
let fix = result.diagnostics[0].fix.as_ref().unwrap();
assert_eq!(fix.replacement, "rm -f");
}
}