//! Elicitor conformance — the reference [`SlotWalker`] must produce //! the final [`ElicitorStep`] listed in `conformance/vectors.json` //! after processing the submit sequence for every fixture, byte-equal //! under serde_json. use jouleclaw_elicitor::{Answer, Elicitor, ElicitorStep, RawRequest, Slot, SlotWalker}; use serde_json::Value; const VECTORS: &str = include_str!("../conformance/vectors.json"); fn check_vector(v: &Value) { let n = v["n"].as_i64().expect("n"); let desc = v["description"].as_str().expect("description"); let input = &v["input"]; let expected = &v["expected_final_step"]; let request = RawRequest::new( input["request_text"] .as_str() .expect("request_text is string"), ); let slots: Vec = serde_json::from_value(input["slots"].clone()).expect("slots parse"); let mut walker = SlotWalker::new(&request, slots); let mut step = walker.next(); for sub in input["submits"].as_array().expect("submits array") { let answer: Answer = serde_json::from_value(sub.clone()).expect("answer parse"); step = walker.submit(answer).expect("submit succeeds for valid vectors"); } let got: Value = serde_json::to_value(&step).expect("step serialises"); assert_eq!( &got, expected, "vector {n} ({desc}): final step mismatch.\n got = {got}\n expected = {expected}" ); // Round-trip the step through ElicitorStep to confirm it parses // back identically — the conformance contract is bidirectional. let _back: ElicitorStep = serde_json::from_value(got).expect("step parses back"); } #[test] fn every_elicitor_vector_matches_the_reference_walker() { let suite: Value = serde_json::from_str(VECTORS).expect("vectors.json parses"); let count = suite["vector_count"].as_u64().expect("vector_count") as usize; let vectors = suite["vectors"].as_array().expect("vectors array"); assert_eq!(vectors.len(), count, "vector_count mismatch"); for v in vectors { check_vector(v); } }