use brainwires_inference::validation_loop::{
ValidationCheck, ValidationConfig, ValidationIssue, ValidationResult, ValidationSeverity,
format_validation_feedback, run_validation,
};
use tempfile::tempdir;
#[test]
fn config_default_has_duplicates_and_syntax_checks() {
let config = ValidationConfig::default();
assert!(config.enabled);
assert_eq!(config.checks.len(), 2);
assert!(config.working_set_files.is_empty());
}
#[test]
fn config_with_build_appends_build_check() {
let config = ValidationConfig::default().with_build("typescript");
assert_eq!(config.checks.len(), 3);
match &config.checks[2] {
ValidationCheck::BuildSuccess { build_type } => {
assert_eq!(build_type, "typescript");
}
_ => panic!("Expected BuildSuccess check"),
}
}
#[test]
fn config_disabled_creates_disabled_config() {
let config = ValidationConfig::disabled();
assert!(!config.enabled);
}
#[test]
fn config_with_working_set_files() {
let config = ValidationConfig::default()
.with_working_set_files(vec!["src/main.rs".into(), "lib.rs".into()]);
assert_eq!(config.working_set_files.len(), 2);
}
#[tokio::test]
async fn disabled_validation_passes_immediately() {
let config = ValidationConfig::disabled();
let result = run_validation(&config).await.unwrap();
assert!(result.passed);
assert!(result.issues.is_empty());
}
#[tokio::test]
async fn validation_catches_missing_working_set_files() {
let dir = tempdir().unwrap();
let config = ValidationConfig {
checks: vec![], working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 3,
enabled: true,
working_set_files: vec!["nonexistent.rs".into()],
intended_writes: None,
};
let result = run_validation(&config).await.unwrap();
assert!(!result.passed);
assert_eq!(result.issues.len(), 1);
assert_eq!(result.issues[0].check, "file_existence");
assert_eq!(result.issues[0].severity, ValidationSeverity::Error);
assert!(result.issues[0].message.contains("does not exist"));
}
#[tokio::test]
async fn validation_passes_when_working_set_files_exist() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("exists.txt");
std::fs::write(&file_path, "content").unwrap();
let config = ValidationConfig {
checks: vec![], working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 3,
enabled: true,
working_set_files: vec!["exists.txt".into()],
intended_writes: None,
};
let result = run_validation(&config).await.unwrap();
assert!(result.passed);
assert!(result.issues.is_empty());
}
#[tokio::test]
async fn validation_mixed_existing_and_missing_files() {
let dir = tempdir().unwrap();
std::fs::write(dir.path().join("real.rs"), "fn main() {}").unwrap();
let config = ValidationConfig {
checks: vec![],
working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 3,
enabled: true,
working_set_files: vec!["real.rs".into(), "ghost.rs".into()],
intended_writes: None,
};
let result = run_validation(&config).await.unwrap();
assert!(!result.passed);
assert_eq!(result.issues.len(), 1);
assert!(result.issues[0].file.as_deref() == Some("ghost.rs"));
}
#[test]
fn format_feedback_for_passed_validation() {
let result = ValidationResult {
passed: true,
issues: vec![],
};
let feedback = format_validation_feedback(&result);
assert!(feedback.contains("passed"));
}
#[test]
fn format_feedback_includes_all_issues() {
let result = ValidationResult {
passed: false,
issues: vec![
ValidationIssue {
check: "duplicate_check".into(),
severity: ValidationSeverity::Error,
message: "Duplicate export 'Foo'".into(),
file: Some("src/lib.rs".into()),
line: Some(42),
},
ValidationIssue {
check: "file_existence".into(),
severity: ValidationSeverity::Error,
message: "File does not exist".into(),
file: Some("missing.rs".into()),
line: None,
},
],
};
let feedback = format_validation_feedback(&result);
assert!(feedback.contains("VALIDATION FAILED"));
assert!(feedback.contains("src/lib.rs:42:"));
assert!(feedback.contains("Duplicate export 'Foo'"));
assert!(feedback.contains("missing.rs:"));
assert!(feedback.contains("File does not exist"));
assert!(feedback.contains("MUST fix ALL"));
}
#[tokio::test]
async fn empty_working_set_no_checks_passes() {
let dir = tempdir().unwrap();
let config = ValidationConfig {
checks: vec![],
working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 3,
enabled: true,
working_set_files: vec![],
intended_writes: None,
};
let result = run_validation(&config).await.unwrap();
assert!(result.passed);
}
#[tokio::test]
async fn validation_catches_post_validation_clobber() {
use brainwires_core::IntendedWrites;
use sha2::{Digest, Sha256};
let dir = tempdir().unwrap();
let target = dir.path().join("contested.txt");
let agent_a_content = b"agent-A content";
std::fs::write(&target, agent_a_content).unwrap();
let agent_a_hash: [u8; 32] = Sha256::digest(agent_a_content).into();
let intended = IntendedWrites::new();
intended.record(target.clone(), agent_a_hash);
let config_ok = ValidationConfig {
checks: vec![],
working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 1,
enabled: true,
working_set_files: vec![],
intended_writes: Some(intended.clone()),
};
let ok = run_validation(&config_ok).await.unwrap();
assert!(
ok.passed,
"expected validation to pass immediately after write; got issues: {:?}",
ok.issues
);
std::fs::write(&target, b"agent-B clobbered this").unwrap();
let config_clobbered = ValidationConfig {
checks: vec![],
working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 1,
enabled: true,
working_set_files: vec![],
intended_writes: Some(intended),
};
let result = run_validation(&config_clobbered).await.unwrap();
assert!(
!result.passed,
"validation MUST fail when a concurrent writer has clobbered \
this agent's content; otherwise two agents can both report Success: true"
);
let content_persisted_issues: Vec<_> = result
.issues
.iter()
.filter(|i| i.check == "content_persisted")
.collect();
assert_eq!(
content_persisted_issues.len(),
1,
"expected exactly one content_persisted issue, got {:?}",
result.issues
);
let issue = content_persisted_issues[0];
assert_eq!(issue.severity, ValidationSeverity::Error);
assert!(
issue.message.contains("overwritten by a concurrent writer"),
"message should explain the clobber clearly, got: {}",
issue.message
);
assert_eq!(
issue.file.as_deref(),
Some(target.display().to_string()).as_deref()
);
}
#[tokio::test]
async fn validation_catches_deleted_written_file() {
use brainwires_core::IntendedWrites;
use sha2::{Digest, Sha256};
let dir = tempdir().unwrap();
let target = dir.path().join("ephemeral.txt");
let content = b"will be deleted";
std::fs::write(&target, content).unwrap();
let hash: [u8; 32] = Sha256::digest(content).into();
let intended = IntendedWrites::new();
intended.record(target.clone(), hash);
std::fs::remove_file(&target).unwrap();
let config = ValidationConfig {
checks: vec![],
working_directory: dir.path().to_str().unwrap().to_string(),
max_retries: 1,
enabled: true,
working_set_files: vec![],
intended_writes: Some(intended),
};
let result = run_validation(&config).await.unwrap();
assert!(!result.passed);
let has_persisted_issue = result.issues.iter().any(|i| i.check == "content_persisted");
assert!(
has_persisted_issue,
"expected content_persisted error when written file disappeared; got {:?}",
result.issues
);
}