use pmat::services::clippy_fix::{
ClippyDiagnostic, ClippyFixEngine, ConfidenceLevel, DiagnosticLevel,
};
use std::path::PathBuf;
#[tokio::test]
async fn test_parse_clippy_json_output() {
let clippy_json = r#"{
"reason": "compiler-message",
"message": {
"code": {"code": "clippy::needless_return"},
"level": "warning",
"message": "unneeded `return` statement",
"spans": [{
"file_name": "src/main.rs",
"line_start": 10,
"line_end": 10,
"column_start": 5,
"column_end": 15
}]
}
}"#;
let diagnostic = ClippyDiagnostic::from_json(clippy_json).unwrap();
assert_eq!(diagnostic.code, "clippy::needless_return");
assert_eq!(diagnostic.level, DiagnosticLevel::Warning);
assert_eq!(diagnostic.line_start, 10);
}
#[tokio::test]
async fn test_confidence_scoring_for_safe_fixes() {
let diagnostic = ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded `return` statement".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 10,
line_end: 10,
column_start: 5,
column_end: 15,
suggestion: Some("remove `return`".to_string()),
};
let engine = ClippyFixEngine::new();
let confidence = engine.calculate_confidence(&diagnostic);
assert_eq!(confidence, ConfidenceLevel::High);
}
#[tokio::test]
async fn test_confidence_scoring_for_risky_fixes() {
let diagnostic = ClippyDiagnostic {
code: "clippy::needless_lifetimes".to_string(),
level: DiagnosticLevel::Warning,
message: "explicit lifetimes given in parameter types".to_string(),
file: PathBuf::from("src/lib.rs"),
line_start: 50,
line_end: 55,
column_start: 1,
column_end: 80,
suggestion: None,
};
let engine = ClippyFixEngine::new();
let confidence = engine.calculate_confidence(&diagnostic);
assert_eq!(confidence, ConfidenceLevel::Low);
}
#[tokio::test]
async fn test_ast_based_fix_application() {
let source = r#"
fn calculate(x: i32) -> i32 {
return x * 2;
}
"#;
let diagnostic = ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded `return` statement".to_string(),
file: PathBuf::from("test.rs"),
line_start: 3,
line_end: 3,
column_start: 5,
column_end: 17,
suggestion: Some("x * 2".to_string()),
};
let engine = ClippyFixEngine::new();
let result = engine.apply_fix(source, &diagnostic).await.unwrap();
assert!(result.success);
assert!(result.modified_source.contains("x * 2"));
assert!(!result.modified_source.contains("return"));
}
#[tokio::test]
async fn test_batch_fix_with_dependencies() {
let diagnostics = vec![
ClippyDiagnostic {
code: "clippy::redundant_clone".to_string(),
level: DiagnosticLevel::Warning,
message: "redundant clone".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 10,
line_end: 10,
column_start: 5,
column_end: 20,
suggestion: Some("remove .clone()".to_string()),
},
ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded `return` statement".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 15,
line_end: 15,
column_start: 5,
column_end: 25,
suggestion: Some("remove return".to_string()),
},
];
let engine = ClippyFixEngine::new();
let results = engine.apply_batch_fixes(&diagnostics).await.unwrap();
assert_eq!(results.len(), 2);
assert!(results.iter().all(|r| r.success));
}
#[tokio::test]
async fn test_transactional_rollback_on_error() {
let diagnostic = ClippyDiagnostic {
code: "clippy::some_complex_rule".to_string(),
level: DiagnosticLevel::Warning,
message: "complex issue".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 10,
line_end: 10,
column_start: 1,
column_end: 50,
suggestion: Some("invalid syntax {{".to_string()),
};
let engine = ClippyFixEngine::new();
let source = "fn main() { println!(\"hello\"); }";
let result = engine.apply_fix_with_validation(source, &diagnostic).await;
assert!(result.is_err() || !result.unwrap().success);
}
#[tokio::test]
async fn test_caching_layer_performance() {
use std::time::Instant;
let diagnostic = ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded `return` statement".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 10,
line_end: 10,
column_start: 5,
column_end: 15,
suggestion: Some("remove return".to_string()),
};
let engine = ClippyFixEngine::new();
let source = "fn test() { return 42; }";
let start = Instant::now();
let _ = engine.apply_fix(source, &diagnostic).await.unwrap();
let first_duration = start.elapsed();
let start = Instant::now();
let _ = engine.apply_fix(source, &diagnostic).await.unwrap();
let second_duration = start.elapsed();
assert!(second_duration < first_duration / 2);
}
#[tokio::test]
async fn test_fix_filtering_by_confidence() {
let diagnostics = vec![
(
ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded return".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 10,
line_end: 10,
column_start: 1,
column_end: 10,
suggestion: Some("remove".to_string()),
},
ConfidenceLevel::High,
),
(
ClippyDiagnostic {
code: "clippy::complex_lifetime".to_string(),
level: DiagnosticLevel::Warning,
message: "complex lifetime".to_string(),
file: PathBuf::from("src/lib.rs"),
line_start: 20,
line_end: 25,
column_start: 1,
column_end: 80,
suggestion: None,
},
ConfidenceLevel::Low,
),
];
let engine = ClippyFixEngine::new();
let filtered = engine.filter_by_confidence(diagnostics.clone(), ConfidenceLevel::High);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].0.code, "clippy::needless_return");
}
#[tokio::test]
async fn test_parallel_fix_application() {
let diagnostics = vec![
ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded return".to_string(),
file: PathBuf::from("src/module1.rs"),
line_start: 10,
line_end: 10,
column_start: 1,
column_end: 10,
suggestion: Some("remove".to_string()),
},
ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded return".to_string(),
file: PathBuf::from("src/module2.rs"),
line_start: 15,
line_end: 15,
column_start: 1,
column_end: 10,
suggestion: Some("remove".to_string()),
},
];
let engine = ClippyFixEngine::new();
let results = engine.apply_parallel_fixes(&diagnostics).await.unwrap();
assert_eq!(results.len(), 2);
assert!(results.iter().all(|r| r.success));
}
#[tokio::test]
async fn test_comprehensive_fix_report() {
let engine = ClippyFixEngine::new();
let diagnostic = ClippyDiagnostic {
code: "clippy::needless_return".to_string(),
level: DiagnosticLevel::Warning,
message: "unneeded return".to_string(),
file: PathBuf::from("src/main.rs"),
line_start: 10,
line_end: 10,
column_start: 1,
column_end: 10,
suggestion: Some("remove".to_string()),
};
let source = "fn test() { return 42; }";
let result = engine.apply_fix(source, &diagnostic).await.unwrap();
let report = engine.generate_report(vec![result]);
assert!(report.total_diagnostics > 0);
assert!(report.successful_fixes > 0);
assert!(report.success_rate >= 0.0 && report.success_rate <= 100.0);
assert!(!report.fixed_files.is_empty());
}