use wasm4pm::testing::{ActivityEvidence, ConformanceVerdict, ObjectEvidence, PowlTestHarness};
fn bh(data: &str) -> String {
blake3::hash(data.as_bytes()).to_hex().to_string()
}
fn model(name: &str) -> String {
format!("{}/routes/test-harness/{name}", env!("CARGO_MANIFEST_DIR"))
}
#[test]
fn test_harness_follows_its_own_declared_route() {
let mut harness =
PowlTestHarness::new("test-lifecycle-route").model(model("test-lifecycle.powl.json"));
harness
.complete_activity(ActivityEvidence::new("test.started").with_outputs(vec![
ObjectEvidence::new("test-context", bh("test:context:init")),
]))
.unwrap();
let command_result = simulate_command("discover_dfg", &["concept:name"]);
harness
.complete_activity(
ActivityEvidence::new("command.executed")
.with_inputs(vec![ObjectEvidence::new(
"test-context",
bh("test:context:init"),
)])
.with_outputs(vec![ObjectEvidence::new(
"command-output",
bh(&command_result),
)]),
)
.unwrap();
let captured = capture_output(command_result.clone());
harness
.complete_activity(
ActivityEvidence::new("output.captured")
.with_inputs(vec![ObjectEvidence::new(
"command-output",
bh(&command_result),
)])
.with_outputs(vec![ObjectEvidence::new("captured-output", bh(&captured))]),
)
.unwrap();
assert!(
!captured.is_empty(),
"command should produce non-empty output"
);
harness
.complete_activity(
ActivityEvidence::new("assertion.checked")
.with_inputs(vec![ObjectEvidence::new("captured-output", bh(&captured))])
.with_outputs(vec![ObjectEvidence::new(
"assertion-result",
bh("assertion:passed"),
)]),
)
.unwrap();
harness
.complete_activity(
ActivityEvidence::new("test.completed")
.with_inputs(vec![ObjectEvidence::new(
"assertion-result",
bh("assertion:passed"),
)])
.with_outputs(vec![ObjectEvidence::new(
"completion-record",
bh("test:done"),
)]),
)
.unwrap();
assert_eq!(
harness.finish(),
ConformanceVerdict::Passed,
"test lifecycle route with full evidence chain must return Passed"
);
}
#[test]
fn skipping_output_capture_fires_andon() {
let mut h =
PowlTestHarness::new("incomplete-lifecycle-route").model(model("test-lifecycle.powl.json"));
h.record_activity("test.started");
h.record_activity("command.executed");
h.record_activity("assertion.checked");
h.record_activity("test.completed");
let verdict = h.finish();
assert!(
matches!(verdict, ConformanceVerdict::Andon(_)),
"skipping output.captured must fire AndonPull, got: {verdict:?}"
);
}
#[test]
fn jumping_directly_to_completion_fires_andon() {
let mut h = PowlTestHarness::new("shortcut-route").model(model("test-lifecycle.powl.json"));
h.record_activity("test.started");
h.record_activity("test.completed");
let verdict = h.finish();
assert!(
matches!(verdict, ConformanceVerdict::Andon(_)),
"shortcutting to test.completed must fire AndonPull, got: {verdict:?}"
);
}
#[test]
fn anti_fake_hardcoded_output_without_route_is_rejected() {
let mut h =
PowlTestHarness::new("fake-completion-route").model(model("test-lifecycle.powl.json"));
h.record_activity("test.completed");
let verdict = h.finish();
assert!(
matches!(verdict, ConformanceVerdict::Andon(_)),
"fake completion (just test.completed) must be rejected, got: {verdict:?}"
);
}
#[test]
fn ocel_evidence_survives_andon_pull() {
let mut h =
PowlTestHarness::new("evidence-on-failure").model(model("test-lifecycle.powl.json"));
h.record_activity("test.started");
let ocel = h.export_ocel();
let verdict = h.finish();
assert_eq!(ocel["routeId"], "evidence-on-failure");
assert_eq!(ocel["events"].as_array().unwrap().len(), 1);
assert!(
matches!(verdict, ConformanceVerdict::Andon(_)),
"incomplete route fires AndonPull, got: {verdict:?}"
);
}
fn simulate_command(algorithm: &str, _args: &[&str]) -> String {
format!(r#"{{"algorithm":"{algorithm}","status":"ok","traces":42}}"#)
}
fn capture_output(raw: String) -> String {
raw.trim().to_string()
}