#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use std::fs;
use std::path::PathBuf;
#[test]
fn test_coherence_gate_admits_full_coherence_with_ontology_and_artifacts() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
let ontology_bytes = fs::read(&ontology_path).expect("read ontology");
let mut generated: Vec<(PathBuf, String)> = vec![];
generated.push((
PathBuf::from("src/lib.rs"),
"pub mod generated { pub fn hello() {} }\n".to_string(),
));
generated.push((
PathBuf::from("src/main.rs"),
"fn main() { println!(\"Hello, world!\"); }\n".to_string(),
));
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
let config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: true, expectations: None,
};
let gate = CoherenceGate::new(config);
let generated_with_string: Vec<(String, String)> = generated
.iter()
.map(|(p, c)| (p.to_string_lossy().to_string(), c.clone()))
.collect();
let result = gate.validate(&ontology_bytes, &generated_with_string, &[]);
assert!(
result.is_err(),
"expected CoherenceViolation when event-log pole is required but empty"
);
if let Err(e) = result {
let error_msg = format!("{}", e);
assert!(
error_msg.contains("coherence"),
"error should mention coherence; got: {}",
error_msg
);
}
}
#[test]
fn test_coherence_gate_allows_empty_event_log_in_dry_run_mode() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
let ontology_bytes = fs::read(&ontology_path).expect("read ontology");
let generated = vec![
("src/lib.rs".to_string(), "pub fn hello() {}".to_string()),
("src/main.rs".to_string(), "fn main() {}".to_string()),
];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
let config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: false, expectations: None,
};
let gate = CoherenceGate::new(config);
let result = gate.validate(&ontology_bytes, &generated, &[]);
assert!(
result.is_ok(),
"dry-run mode should skip event-log pole requirement"
);
let report = result.unwrap();
assert!(
!report.admitted,
"event-log pole is still missing, so admitted should be false"
);
assert!(
report.poles.len() == 2,
"should only have O and A poles in dry-run; got {} poles",
report.poles.len()
);
}
#[test]
fn test_coherence_gate_rejects_empty_artifacts_with_non_empty_ontology() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
let ontology_bytes = fs::read(&ontology_path).expect("read ontology");
let generated: Vec<(String, String)> = vec![];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
let config = CoherenceGateConfig {
allow_count_discrepancy: false, check_event_log: false,
expectations: None,
};
let gate = CoherenceGate::new(config);
let result = gate.validate(&ontology_bytes, &generated, &[]);
assert!(
result.is_err(),
"gate should reject empty artifacts when ontology is non-empty"
);
if let Err(e) = result {
let error_msg = format!("{}", e);
assert!(
error_msg.contains("coherence"),
"error should mention coherence; got: {}",
error_msg
);
}
}
#[test]
fn test_coherence_gate_detects_hash_drift_against_expectations() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
let ontology_bytes = fs::read(&ontology_path).expect("read ontology");
let generated = vec![("src/lib.rs".to_string(), "pub fn hello() {}".to_string())];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
use ggen_graph::coherence::Pole;
use std::collections::HashMap;
let baseline_config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: false,
expectations: None,
};
let baseline_gate = CoherenceGate::new(baseline_config);
let baseline_report = baseline_gate
.validate(&ontology_bytes, &generated, &[])
.expect("baseline check should pass");
let baseline_ontology_hash = baseline_report
.poles
.iter()
.find(|p| p.pole == Pole::Ontology)
.map(|p| p.hash.clone())
.expect("ontology pole must be present");
let modified_ontology = format!("{}\n# Modified\n", String::from_utf8_lossy(&ontology_bytes));
let modified_ontology_bytes = modified_ontology.into_bytes();
let mut expectations = HashMap::new();
expectations.insert(Pole::Ontology, baseline_ontology_hash);
let drift_config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: false,
expectations: Some(expectations),
};
let drift_gate = CoherenceGate::new(drift_config);
let result = drift_gate.validate(&modified_ontology_bytes, &generated, &[]);
assert!(
result.is_err(),
"gate should reject modified ontology when expectations are provided"
);
if let Err(e) = result {
let error_msg = format!("{}", e);
assert!(
error_msg.contains("coherence") || error_msg.contains("CoherenceViolation"),
"error should mention coherence; got: {}",
error_msg
);
}
}
#[test]
fn test_coherence_gate_detects_artifact_size_drift() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
let ontology_bytes = fs::read(&ontology_path).expect("read ontology");
let generated_v1 = vec![("src/lib.rs".to_string(), "pub fn hello() {}".to_string())];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
use ggen_graph::coherence::Pole;
use std::collections::HashMap;
let baseline_config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: false,
expectations: None,
};
let baseline_gate = CoherenceGate::new(baseline_config);
let baseline_report = baseline_gate
.validate(&ontology_bytes, &generated_v1, &[])
.expect("baseline check should pass");
let baseline_artifact_hash = baseline_report
.poles
.iter()
.find(|p| p.pole == Pole::Artifact)
.map(|p| p.hash.clone())
.expect("artifact pole must be present");
let generated_v2 = vec![(
"src/lib.rs".to_string(),
"pub fn hello() {}\n\n// Modified\n".to_string(),
)];
let drift_config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: false,
expectations: Some({
let mut m = HashMap::new();
m.insert(Pole::Artifact, baseline_artifact_hash);
m
}),
};
let drift_gate = CoherenceGate::new(drift_config);
let result = drift_gate.validate(&ontology_bytes, &generated_v2, &[]);
assert!(
result.is_err(),
"gate should reject modified artifact when expectations are provided"
);
}
#[test]
fn test_coherence_gate_rejects_empty_event_log_with_artifacts() {
let ontology_bytes =
b"<https://example.org/s> <https://example.org/p> <https://example.org/o> .";
let generated = vec![("src/lib.rs".to_string(), "pub fn hello() {}".to_string())];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
let config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: true, expectations: None,
};
let gate = CoherenceGate::new(config);
let result = gate.validate(ontology_bytes, &generated, &[]);
assert!(
result.is_err(),
"gate should reject empty event log when artifacts exist"
);
}
#[test]
fn test_coherence_gate_emits_otel_spans() {
let ontology_bytes =
b"<https://example.org/s> <https://example.org/p> <https://example.org/o> .";
let generated = vec![("src/lib.rs".to_string(), "pub fn hello() {}".to_string())];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
let config = CoherenceGateConfig {
allow_count_discrepancy: false,
check_event_log: false, expectations: None,
};
let gate = CoherenceGate::new(config);
let _ = gate.validate(ontology_bytes, &generated, &[]);
}
#[test]
fn test_coherence_gate_allows_count_discrepancy_when_configured() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
let ontology_bytes = fs::read(&ontology_path).expect("read ontology");
let generated: Vec<(String, String)> = vec![];
use ggen_core::sync::{CoherenceGate, CoherenceGateConfig};
let config = CoherenceGateConfig {
allow_count_discrepancy: true, check_event_log: false,
expectations: None,
};
let gate = CoherenceGate::new(config);
let result = gate.validate(&ontology_bytes, &generated, &[]);
assert!(
result.is_ok(),
"gate should allow CountDiscrepancy when configured"
);
let report = result.unwrap();
assert!(
!report.drifts.is_empty(),
"report should document the CountDiscrepancy drift"
);
}
#[test]
fn test_coherence_gate_integration_with_sync_config() {
let ontology_path = PathBuf::from(".specify/chatmangpt-sprint-ontology.ttl");
if !ontology_path.exists() {
eprintln!(
"Skipping test: real ontology not found at {}",
ontology_path.display()
);
return;
}
use ggen_core::sync::SyncError;
use ggen_graph::coherence::CoherenceChecker;
let empty_report = CoherenceChecker::check(&[]);
let error = SyncError::CoherenceViolation {
detail: "test drift".to_string(),
report: empty_report,
};
let error_msg = format!("{}", error);
assert!(
error_msg.contains("coherence violation"),
"SyncError::CoherenceViolation should format correctly"
);
}