#![cfg(feature = "mutation-testing")]
use pmat::services::mutation::{
Mutant, MutantExecutor, MutantStatus, MutationOperatorType, SourceLocation,
};
use std::time::Duration;
use tokio::time::timeout;
#[tokio::test]
async fn red_must_restore_file_on_timeout() {
let test_file = std::env::temp_dir().join("test_timeout_restore.rs");
let original_content = "fn original() { 42 }";
std::fs::write(&test_file, original_content).unwrap();
let mutant = Mutant {
id: "TEST_TIMEOUT".to_string(),
original_file: test_file.clone(),
mutated_source: "fn mutated() { 999 }".to_string(),
location: SourceLocation {
line: 1,
column: 1,
end_line: 1,
end_column: 10,
},
operator: MutationOperatorType::ArithmeticReplacement,
hash: "test".to_string(),
status: MutantStatus::Pending,
};
let executor = MutantExecutor::new(std::env::temp_dir()).with_timeout(1);
let _ = timeout(Duration::from_millis(500), executor.execute_mutant(&mutant)).await;
let final_content = std::fs::read_to_string(&test_file).unwrap();
assert_eq!(
final_content, original_content,
"File was NOT restored after timeout! This is the bug we found."
);
let _ = std::fs::remove_file(&test_file);
}
#[tokio::test]
async fn red_must_restore_file_on_panic() {
let test_file = std::env::temp_dir().join("test_panic_restore.rs");
let original_content = "fn original() { 42 }";
std::fs::write(&test_file, original_content).unwrap();
let mutant = Mutant {
id: "TEST_PANIC".to_string(),
original_file: test_file.clone(),
mutated_source: "fn mutated() { panic!() }".to_string(),
location: SourceLocation {
line: 1,
column: 1,
end_line: 1,
end_column: 10,
},
operator: MutationOperatorType::ArithmeticReplacement,
hash: "test".to_string(),
status: MutantStatus::Pending,
};
let executor = MutantExecutor::new(std::env::temp_dir());
let _ = executor.execute_mutant(&mutant).await;
let final_content = std::fs::read_to_string(&test_file).unwrap();
assert_eq!(
final_content, original_content,
"File was NOT restored after panic!"
);
let _ = std::fs::remove_file(&test_file);
}
#[tokio::test]
async fn red_must_clean_up_backup_files() {
let test_file = std::env::temp_dir().join("test_backup_cleanup.rs");
let original_content = "fn original() { 42 }";
std::fs::write(&test_file, original_content).unwrap();
let mutant = Mutant {
id: "TEST_BACKUP".to_string(),
original_file: test_file.clone(),
mutated_source: "fn mutated() { 0 }".to_string(),
location: SourceLocation {
line: 1,
column: 1,
end_line: 1,
end_column: 10,
},
operator: MutationOperatorType::ArithmeticReplacement,
hash: "test".to_string(),
status: MutantStatus::Pending,
};
let executor = MutantExecutor::new(std::env::temp_dir()).with_timeout(1);
let _ = executor.execute_mutant(&mutant).await;
let backup_file = test_file.with_extension("pmat_backup");
assert!(
!backup_file.exists(),
"Backup file was not cleaned up! Found: {}",
backup_file.display()
);
let _ = std::fs::remove_file(&test_file);
let _ = std::fs::remove_file(&backup_file);
}
#[tokio::test]
async fn red_original_file_must_never_be_modified() {
let test_file = std::env::temp_dir().join("test_never_modified.rs");
let original_content = "fn original() { 42 }";
std::fs::write(&test_file, original_content).unwrap();
let mutant = Mutant {
id: "TEST_NEVER_MODIFY".to_string(),
original_file: test_file.clone(),
mutated_source: "fn mutated() { 999 }".to_string(),
location: SourceLocation {
line: 1,
column: 1,
end_line: 1,
end_column: 10,
},
operator: MutationOperatorType::ArithmeticReplacement,
hash: "test".to_string(),
status: MutantStatus::Pending,
};
let executor = MutantExecutor::new(std::env::temp_dir());
let _ = executor.execute_mutant(&mutant).await;
let final_content = std::fs::read_to_string(&test_file).unwrap();
assert_eq!(
final_content, original_content,
"CRITICAL: Original file was modified! Should use temp files only."
);
let _ = std::fs::remove_file(&test_file);
}