#[cfg(test)]
mod purifier_coverage {
use crate::linter::{Diagnostic, LintResult, Severity};
use crate::repl::purifier::{
explain_purification_changes, explain_purification_changes_detailed, format_alternatives,
format_purified_lint_result, format_purified_lint_result_with_context,
format_safety_rationale, purify_and_lint, Alternative, PurificationError,
PurifiedLintResult, SafetyRationale, SafetySeverity,
};
use crate::repl::purifier_transforms::{
generate_determinism_alternatives, generate_determinism_rationale,
generate_idempotency_alternatives, generate_idempotency_rationale,
generate_safety_rationale, TransformationCategory, TransformationExplanation,
};
use crate::repl::purifier_transforms_gen::{
format_transformation_report, generate_safety_alternatives,
};
fn make_lint_result_with(codes: &[&str]) -> LintResult {
let mut lr = LintResult::new();
for &code in codes {
lr.diagnostics.push(Diagnostic::new(
code,
Severity::Warning,
format!("test violation {code}"),
crate::linter::Span::new(1, 1, 1, 10),
));
}
lr
}
#[test]
fn test_format_with_context_det_violation() {
let lr = make_lint_result_with(&["DET001"]);
let result = PurifiedLintResult::new("echo $RANDOM".to_string(), lr);
let formatted = format_purified_lint_result_with_context(&result, "echo $RANDOM");
assert!(formatted.contains("Purified"));
assert!(formatted.contains("critical violation"));
assert!(formatted.contains("DET"));
}
#[test]
fn test_format_with_context_idem_violation() {
let lr = make_lint_result_with(&["IDEM001"]);
let result = PurifiedLintResult::new("rm /tmp/x".to_string(), lr);
let formatted = format_purified_lint_result_with_context(&result, "rm /tmp/x");
assert!(formatted.contains("IDEM"));
assert!(!result.is_clean);
}
#[test]
fn test_format_with_context_sec_violation() {
let lr = make_lint_result_with(&["SEC001"]);
let result = PurifiedLintResult::new("eval $cmd".to_string(), lr);
let formatted = format_purified_lint_result_with_context(&result, "eval $cmd");
assert!(formatted.contains("SEC"));
}
#[test]
fn test_format_with_context_multiple_violations() {
let lr = make_lint_result_with(&["DET001", "IDEM001", "SEC001"]);
let result = PurifiedLintResult::new("code".to_string(), lr);
let formatted = format_purified_lint_result_with_context(&result, "code");
assert!(formatted.contains("3"));
assert!(formatted.contains("DET"));
assert!(formatted.contains("IDEM"));
assert!(formatted.contains("SEC"));
}
#[test]
fn test_format_with_context_clean() {
let lr = LintResult::new();
let result = PurifiedLintResult::new("echo hello".to_string(), lr);
let formatted = format_purified_lint_result_with_context(&result, "echo hello");
assert!(formatted.contains("CLEAN"));
assert!(result.is_clean);
}
#[test]
fn test_collect_rm_to_rm_f_via_explain() {
let result = explain_purification_changes("rm /tmp/test_file");
assert!(result.is_ok());
}
#[test]
fn test_collect_variable_quoting_via_explain() {
let result = explain_purification_changes("echo $HOME");
assert!(result.is_ok());
}
#[test]
fn test_collect_ln_sf_via_explain() {
let result = explain_purification_changes("ln -s /target /link");
assert!(result.is_ok());
let text = result.unwrap();
assert!(!text.is_empty());
}
#[test]
fn test_collect_random_removal_via_explain() {
let result = explain_purification_changes("echo $RANDOM");
assert!(result.is_ok());
let text = result.unwrap();
assert!(!text.is_empty());
}
#[test]
fn test_collect_date_via_explain() {
let result = explain_purification_changes("echo $(date +%s)");
assert!(result.is_ok());
}
#[test]
fn test_collect_no_changes_via_explain() {
let result = explain_purification_changes("echo hello");
assert!(result.is_ok());
assert!(!result.unwrap().is_empty());
}
#[test]
fn test_explain_detailed_rm_f() {
let original = "rm /tmp/test_file";
let result = explain_purification_changes_detailed(original);
assert!(result.is_ok(), "should not fail: {:?}", result);
let explanations = result.unwrap();
if !explanations.is_empty() {
let has_rm = explanations
.iter()
.any(|e| e.category == TransformationCategory::Idempotency);
assert!(has_rm, "rm -f is an idempotency fix");
}
}
#[test]
fn test_explain_detailed_variable_quoting() {
let original = "echo $HOME";
let result = explain_purification_changes_detailed(original);
assert!(result.is_ok());
}
#[test]
fn test_explain_detailed_ln_sf() {
let original = "ln -s /target /link";
let result = explain_purification_changes_detailed(original);
assert!(result.is_ok());
let explanations = result.unwrap();
for e in &explanations {
if e.title.contains("ln") {
assert_eq!(e.category, TransformationCategory::Idempotency);
}
}
}
#[test]
fn test_explain_detailed_random() {
let original = "echo $RANDOM";
let result = explain_purification_changes_detailed(original);
assert!(result.is_ok());
let explanations = result.unwrap();
for e in &explanations {
if e.title.contains("RANDOM") {
assert_eq!(e.category, TransformationCategory::Determinism);
}
}
}
#[test]
fn test_explain_detailed_no_change_returns_empty() {
let original = "echo hello";
let result = explain_purification_changes_detailed(original);
assert!(result.is_ok());
}
include!("purifier_coverage_tests_tests_extracted_idempotency.rs");
}