//! Oracle conformance — the reference Oracle implementations //! (`AlwaysPassOracle`, `AlwaysFailOracle`, `CompositeOracle`) must //! produce the verdict listed in `conformance/vectors.json` for every //! (oracle_program, candidate) pair, byte-equal under serde_json. use jouleclaw_oracle::{ AlwaysFailOracle, AlwaysPassOracle, Candidate, CompositeOracle, Oracle, Verdict, }; use serde_json::Value; const VECTORS: &str = include_str!("../conformance/vectors.json"); fn parse_candidate(v: &Value) -> Candidate { Candidate { id: v["id"].as_str().unwrap_or("").to_string(), content: v["content"].as_str().unwrap_or("").to_string(), language: v["language"].as_str().unwrap_or("").to_string(), source_tier: v["source_tier"].as_str().unwrap_or("").to_string(), provenance: v["provenance"].as_str().unwrap_or("").to_string(), } } fn build_oracle(program: &[Value]) -> Box { // The first node is either a leaf (always_pass / always_fail) or // a composite header (kind="composite", id=…) followed by its // members. let head = &program[0]; match head["kind"].as_str().expect("kind") { "always_pass" => Box::new(AlwaysPassOracle), "always_fail" => Box::new(AlwaysFailOracle::new( head["reason"].as_str().unwrap_or(""), )), "composite" => { let id = head["id"].as_str().expect("composite id"); let mut comp = CompositeOracle::new(id); for member in &program[1..] { comp = comp.add(build_oracle(std::slice::from_ref(member))); } Box::new(comp) } other => panic!("unknown oracle kind: {other}"), } } 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_verdict"]; let candidate = parse_candidate(&input["candidate"]); let program = input["oracle_program"] .as_array() .expect("oracle_program array"); let oracle = build_oracle(program); // Drive the async verify via a current-thread runtime. let rt = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .expect("tokio runtime"); let verdict: Verdict = rt.block_on(oracle.verify(&candidate)).expect("verify"); let got = serde_json::to_value(&verdict).expect("verdict serialises"); assert_eq!( &got, expected, "vector {n} ({desc}): verdict mismatch.\n got = {got}\n expected = {expected}" ); } #[test] fn every_oracle_vector_matches_the_reference() { 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); } }