use std::path::Path;
use chronicle::graph::Chronicle;
use chronicle::validation::{ValidationError, ValidationWarning};
fn data_path(scenario: &str) -> std::path::PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/data/invalid")
.join(scenario)
}
#[test]
fn catches_dangling_reference() {
let c = Chronicle::from_directory(&data_path("dangling_ref")).unwrap();
let report = c.validate();
let dangling: Vec<_> = report.errors.iter().filter(|e| {
matches!(e, ValidationError::DanglingReference { target_id, .. } if target_id == "nonexistent_actor")
}).collect();
assert!(!dangling.is_empty(), "should catch dangling reference to nonexistent_actor");
}
#[test]
fn catches_state_violation_dead_actor() {
let c = Chronicle::from_directory(&data_path("temporal_violation")).unwrap();
let report = c.validate();
let violations: Vec<_> = report.errors.iter().filter(|e| {
matches!(e, ValidationError::StateViolation { entity_id, event_id, .. }
if entity_id == "doomed_soldier" && event_id == "later_battle")
}).collect();
assert!(!violations.is_empty(), "should catch dead actor participating in later event");
}
#[test]
fn catches_state_violation_destroyed_place() {
let c = Chronicle::from_directory(&data_path("state_violation")).unwrap();
let report = c.validate();
let violations: Vec<_> = report.errors.iter().filter(|e| {
matches!(e, ValidationError::StateViolation { entity_id, event_id, .. }
if entity_id == "ruined_city" && event_id == "impossible_market")
}).collect();
assert!(!violations.is_empty(), "should catch event at destroyed location");
}
#[test]
fn catches_orphan_entity() {
let c = Chronicle::from_directory(&data_path("orphan")).unwrap();
let report = c.validate();
let orphans: Vec<_> = report.warnings.iter().filter(|w| {
matches!(w, ValidationWarning::OrphanEntity { entity_id } if entity_id == "forgotten_hermit")
}).collect();
assert!(!orphans.is_empty(), "should warn about orphaned forgotten_hermit");
let false_orphans: Vec<_> = report.warnings.iter().filter(|w| {
matches!(w, ValidationWarning::OrphanEntity { entity_id } if entity_id == "connected_faction")
}).collect();
assert!(false_orphans.is_empty(), "connected_faction should not be orphaned");
}
#[test]
fn catches_duplicate_id() {
let result = Chronicle::from_directory(&data_path("duplicate_id"));
let err = match result {
Err(e) => e,
Ok(_) => panic!("should fail to load duplicate IDs"),
};
let msg = err.to_string();
assert!(msg.contains("duplicate_id"), "error should mention the duplicate ID: {msg}");
}