78 lines
3.2 KiB
Rust
78 lines
3.2 KiB
Rust
//! `wai.live.events` (extensions/live-events.md): the committed corpus
|
|
//! `live-conformance/events/vectors.json` regenerates byte for byte from its fixed seeds,
|
|
//! every case in it gets the outcome it states, it covers every kind and every reason,
|
|
//! and the extension's §9 lists exactly the reasons the reference reports.
|
|
#![cfg(feature = "live_events")]
|
|
|
|
use std::collections::BTreeSet;
|
|
use std::path::PathBuf;
|
|
use wai::live_events::{corpus, kind_name, Reason, KINDS};
|
|
|
|
fn wai_dir() -> PathBuf {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
|
|
}
|
|
|
|
fn committed() -> String {
|
|
std::fs::read_to_string(wai_dir().join("live-conformance/events/vectors.json")).expect("the committed corpus")
|
|
}
|
|
|
|
#[test]
|
|
fn the_committed_corpus_regenerates_from_its_seeds() {
|
|
assert!(committed() == corpus::generate(), "live-conformance/events/vectors.json differs from `wai_live_events_vectors gen`");
|
|
}
|
|
|
|
#[test]
|
|
fn every_case_gets_its_stated_outcome() {
|
|
let fails = corpus::verify(&committed());
|
|
assert!(fails.is_empty(), "{}", fails.join("\n"));
|
|
}
|
|
|
|
/// Every kind has an accepted event, every refusal reason a vector, policy case or binding
|
|
/// case refused with it, and the gap outcome a vector.
|
|
#[test]
|
|
fn the_corpus_covers_every_kind_and_reason() {
|
|
let doc: serde_json::Value = serde_json::from_str(&committed()).unwrap();
|
|
let mut kinds = BTreeSet::new();
|
|
let mut reasons = BTreeSet::new();
|
|
for v in doc["vectors"].as_array().unwrap() {
|
|
if let Some(r) = v["reason"].as_str() {
|
|
reasons.insert(r.to_string());
|
|
}
|
|
if v["outcome"] == "accept" {
|
|
for e in v["events"].as_array().unwrap() {
|
|
let h = e.as_str().unwrap();
|
|
let at = 2 * (4 + 1 + 32 + 32 + 8 + 32 + 8);
|
|
let flag = u8::from_str_radix(&h[at..at + 2], 16).unwrap();
|
|
let k = 2 * (4 + 1 + 32 + 32 + 8 + 32 + 8 + 1 + 48 * flag as usize);
|
|
kinds.insert(u8::from_str_radix(&h[k..k + 2], 16).unwrap());
|
|
}
|
|
}
|
|
}
|
|
for c in doc["policy_cases"].as_array().unwrap().iter().chain(doc["binding_cases"].as_array().unwrap()) {
|
|
if let Some(r) = c["reason"].as_str() {
|
|
reasons.insert(r.to_string());
|
|
}
|
|
}
|
|
for (k, name) in KINDS {
|
|
assert!(kinds.contains(&k), "no accepted {name} event");
|
|
}
|
|
for r in Reason::ALL {
|
|
assert!(reasons.contains(r.code()), "nothing in the corpus is refused with {r}");
|
|
}
|
|
assert!(kinds.iter().all(|k| kind_name(*k).is_some()));
|
|
}
|
|
|
|
/// §9 of the extension lists exactly the codes `Reason` has, each once.
|
|
#[test]
|
|
fn the_extension_lists_the_reasons() {
|
|
let text = std::fs::read_to_string(wai_dir().join("extensions/live-events.md")).expect("the extension");
|
|
let at = text.find("\n## 9. Reasons").expect("a §9");
|
|
let end = text[at + 1..].find("\n## ").map_or(text.len(), |e| at + 1 + e);
|
|
let listed: Vec<String> = text[at..end]
|
|
.lines()
|
|
.filter(|l| l.starts_with("| `"))
|
|
.filter_map(|l| l.split('`').nth(1).map(String::from))
|
|
.collect();
|
|
let want: Vec<String> = Reason::ALL.iter().map(|r| r.code().to_string()).collect();
|
|
assert_eq!(listed, want, "§9's table and Reason::ALL differ");
|
|
}
|