//! Replay the published `energy_trace/1` pack from disk. //! //! SPEC §5.3–5.6 states rules, and `gen_trace_vectors` emits the vectors. This //! reads those bytes back — the same bytes a third party would — and checks the //! reference implementation reproduces every recorded verdict. A pack only its //! own generator can read is not a conformance pack. //! //! The refusals matter more than the acceptances. An implementation that admits //! an unbound outcome, a double-counted activity or a frozen counter has failed //! in the direction that flatters, which is the direction nobody notices. use jcp_efficiency::dynamics::{ DrawShape, EnergyWindow, PhysicalVerdict, PowerEnvelope, }; use jcp_efficiency::trace::{OutcomeTrace, TraceError}; use serde_json::Value; fn pack() -> Value { let p = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .join("../../../conformance/v1/energy_trace.json"); // Assert, not skip. A `return` here would make this test pass green in the // one case it exists to catch — the pack going missing or moving. assert!( p.exists(), "conformance pack missing at {} — it is what this test replays", p.display() ); let bytes = std::fs::read(&p).unwrap_or_else(|e| panic!("read {}: {e}", p.display())); serde_json::from_slice(&bytes).expect("pack parses") } #[test] fn the_pack_declares_its_profile_and_spec() { let v = pack(); assert_eq!(v["profile"], "energy_trace/1"); assert!(v["spec"].as_str().unwrap().contains("5.3-5.6")); } /// Every positive conservation vector reproduces its recorded reconciliation. #[test] fn conservation_positives_reproduce_their_recorded_verdicts() { let v = pack(); let cases = v["conservation"]["positive"].as_array().expect("positives"); assert!(cases.len() >= 2, "expected the published positive cases"); for c in cases { let note = c["note"].as_str().unwrap_or("?"); let t: OutcomeTrace = serde_json::from_value(c["input"].clone()).unwrap_or_else(|e| panic!("{note}: {e}")); let r = t.reconcile().unwrap_or_else(|e| panic!("{note}: must reconcile: {e}")); let exp = &c["expected"]; assert_eq!( serde_json::to_value(r.accounted_uj).unwrap(), exp["accounted_uj"], "{note}: accounted" ); assert_eq!( serde_json::to_value(r.residual_uj).unwrap(), exp["residual_uj"], "{note}: the residual is the whole point" ); assert_eq!( serde_json::to_value(r.provenance_floor).unwrap(), exp["provenance_floor"], "{note}: provenance takes the floor" ); assert_eq!( serde_json::to_value(r.coverage_floor).unwrap(), exp["coverage_floor"], "{note}: coverage takes the floor" ); } } /// Every refusal is actually refused, and for the recorded reason. An /// implementation that accepted these would be wrong in the flattering /// direction. #[test] fn conservation_negatives_are_refused_for_the_recorded_reason() { let v = pack(); let cases = v["conservation"]["negative"].as_array().expect("negatives"); assert!(cases.len() >= 3, "expected the three published refusals"); for c in cases { let note = c["note"].as_str().unwrap_or("?"); let t: OutcomeTrace = serde_json::from_value(c["input"].clone()).unwrap_or_else(|e| panic!("{note}: {e}")); let err = t.reconcile().expect_err(&format!("{note}: must be refused")); let want = c["expected"]["error"].as_str().unwrap(); let got = match err { TraceError::Unbound => "Unbound", TraceError::DuplicateActivity { .. } => "DuplicateActivity", TraceError::OverAccounted { .. } => "OverAccounted", }; assert_eq!(got, want, "{note}: refused, but for the wrong reason"); } } /// The physical bound refutes above the envelope and below the floor — the /// second being the shape a frozen counter takes. #[test] fn physical_bounds_reproduce_their_recorded_verdicts() { let v = pack(); let env: PowerEnvelope = serde_json::from_value(v["physical"]["envelope"].clone()).expect("envelope"); let cases = v["physical"]["cases"].as_array().expect("cases"); assert!(cases.len() >= 4); let mut saw_below = false; for c in cases { let note = c["note"].as_str().unwrap_or("?"); let w: EnergyWindow = serde_json::from_value(c["input"].clone()).unwrap_or_else(|e| panic!("{note}: {e}")); let got = match env.check(&w) { PhysicalVerdict::NotRefuted { .. } => "NotRefuted", PhysicalVerdict::RefutedAbove { .. } => "RefutedAbove", PhysicalVerdict::RefutedBelow { claimed_uj, floor_uj } => { saw_below = true; if let Some(f) = c["expected"]["floor_uj"].as_u64() { assert_eq!(floor_uj, f, "{note}: floor"); assert_eq!(claimed_uj, 0, "{note}: a frozen counter claims nothing"); } "RefutedBelow" } PhysicalVerdict::Unboundable => "Unboundable", }; assert_eq!(got, c["expected"]["verdict"].as_str().unwrap(), "{note}"); } assert!(saw_below, "the frozen-counter refutation must be in the pack"); } /// Character survives a change of scale, and a padded total does not read as /// sustained. These two together are what the shape check is for. #[test] fn draw_character_reproduces_its_recorded_verdicts() { let v = pack(); let floor = v["shape"]["idle_floor_uj"].as_u64().expect("idle floor"); let cases = v["shape"]["cases"].as_array().expect("cases"); assert!(cases.len() >= 6); let mut saw_inconsistent = false; for c in cases { let note = c["note"].as_str().unwrap_or("?"); let declared: DrawShape = serde_json::from_value(c["input"]["declared"].clone()).expect("declared"); let windows: Vec = serde_json::from_value(c["input"]["windows"].clone()).expect("windows"); let got = jcp_efficiency::dynamics::check_shape(declared, &windows, floor); let want = c["expected"]["verdict"].as_str().unwrap(); let name = match &got { jcp_efficiency::dynamics::ShapeVerdict::Consistent { shape } => { if let Some(s) = c["expected"]["shape"].as_str() { assert_eq!( serde_json::to_value(shape).unwrap().as_str().unwrap(), s, "{note}: shape" ); } "Consistent" } jcp_efficiency::dynamics::ShapeVerdict::Inconsistent { .. } => { saw_inconsistent = true; "Inconsistent" } jcp_efficiency::dynamics::ShapeVerdict::Unresolvable { windows } => { if let Some(n) = c["expected"]["windows"].as_u64() { assert_eq!(*windows as u64, n, "{note}: window count"); } "Unresolvable" } }; assert_eq!(name, want, "{note}"); } assert!(saw_inconsistent, "the padding refutation must be in the pack"); } /// Anti-vacuity across the whole pack: a wrong path, a renamed key or an empty /// array would otherwise let every test above pass having checked nothing. #[test] fn the_pack_carries_every_section_it_claims() { let v = pack(); for section in ["conservation", "budget", "physical", "shape", "dynamism"] { assert!(!v[section].is_null(), "section {section} missing from the pack"); } let total: usize = v["conservation"]["positive"].as_array().map_or(0, Vec::len) + v["conservation"]["negative"].as_array().map_or(0, Vec::len) + v["physical"]["cases"].as_array().map_or(0, Vec::len) + v["shape"]["cases"].as_array().map_or(0, Vec::len) + v["dynamism"]["cases"].as_array().map_or(0, Vec::len) + v["budget"]["positive"].as_array().map_or(0, Vec::len) + v["budget"]["negative"].as_array().map_or(0, Vec::len); assert!(total >= 20, "expected the full published pack, replayed {total} cases"); }