84 lines
4.5 KiB
Rust
84 lines
4.5 KiB
Rust
//! `wai.delivery.settlement` (extensions/settlement.md): the committed corpus
|
|
//! `live-conformance/settlement/vectors.json` regenerates byte for byte from its fixed seeds and
|
|
//! is the only file there besides its README, every statement and range proof in it gets the
|
|
//! outcome it states, every reason the extension adds refuses a vector, the accepted vectors are
|
|
//! the cases §12 names, and the extension's §11 lists exactly the reasons the reference reports.
|
|
#![cfg(feature = "settlement")]
|
|
|
|
use std::collections::BTreeSet;
|
|
use std::path::PathBuf;
|
|
use wai::settlement::{corpus, Reason};
|
|
|
|
fn wai_dir() -> PathBuf {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
|
|
}
|
|
|
|
fn read(p: &str) -> String {
|
|
std::fs::read_to_string(wai_dir().join(p)).unwrap_or_else(|e| panic!("{p}: {e}"))
|
|
}
|
|
|
|
fn committed() -> String {
|
|
read("live-conformance/settlement/vectors.json")
|
|
}
|
|
|
|
#[test]
|
|
fn the_committed_corpus_regenerates_from_its_seeds() {
|
|
assert!(committed() == corpus::generate(), "live-conformance/settlement/vectors.json differs from `wai_settlement_vectors gen`");
|
|
let mut files: Vec<String> = std::fs::read_dir(wai_dir().join("live-conformance/settlement")).unwrap().flatten().map(|e| e.file_name().to_string_lossy().into_owned()).collect();
|
|
files.sort();
|
|
assert_eq!(files, ["README.md", "vectors.json"]);
|
|
}
|
|
|
|
#[test]
|
|
fn every_statement_and_range_proof_gets_its_stated_outcome() {
|
|
let fails = corpus::verify(&committed());
|
|
assert!(fails.is_empty(), "{}", fails.join("\n"));
|
|
}
|
|
|
|
/// Every reason this extension adds, and every code of another extension it reuses, refuses a
|
|
/// vector; the accepted statements are §12's, with the figures each was written for.
|
|
#[test]
|
|
fn the_corpus_covers_every_reason_and_case() {
|
|
let doc: serde_json::Value = serde_json::from_str(&committed()).unwrap();
|
|
let mut seen: BTreeSet<&str> = BTreeSet::new();
|
|
for section in ["statements", "ranges"] {
|
|
seen.extend(doc[section].as_array().unwrap().iter().filter_map(|v| v["outcome"]["reason"].as_str()));
|
|
}
|
|
for r in Reason::ALL {
|
|
assert!(seen.contains(r.code()), "nothing in the corpus is refused {r}");
|
|
}
|
|
for r in Reason::REUSED {
|
|
assert!(seen.contains(r), "nothing in the corpus is refused {r}");
|
|
}
|
|
let get = |n: &str| doc["statements"].as_array().unwrap().iter().find(|v| v["name"] == n).unwrap_or_else(|| panic!("no vector {n}"))["outcome"].clone();
|
|
for n in ["relay_paid_by_edge_and_viewer", "edge_fetch_granted_and_free", "origin_fills_billed_to_grant", "viewer_forwards_sealed_objects", "relay_unmetered_hop"] {
|
|
assert_eq!(get(n)["outcome"], "accept", "{n}");
|
|
}
|
|
let relay = get("relay_paid_by_edge_and_viewer");
|
|
assert_eq!(relay["coverage"], "whole");
|
|
assert_eq!(relay["totals"].as_array().unwrap().len(), 2, "one total per class, never one across them");
|
|
assert_eq!(relay["unacknowledged"]["declarations"], 2);
|
|
assert!(relay["unacknowledged"]["bytes"].as_u64().unwrap() > 0, "declared delivery is never zero");
|
|
let edge = get("edge_fetch_granted_and_free");
|
|
let lines = edge["lines"].as_array().unwrap();
|
|
assert!(lines.iter().any(|l| l["class"] == "fetch" && l["free"] == true && l["amount"] == 0), "a fetch served free");
|
|
assert!(lines.iter().any(|l| l["class"] == "fetch" && l["free"] == false && l["amount"].as_u64().unwrap() > 0), "a fetch billed to a grant");
|
|
assert_eq!(get("viewer_forwards_sealed_objects")["currency"], serde_json::Value::Null);
|
|
assert_eq!(get("relay_unmetered_hop")["coverage"], "partial");
|
|
let range = |n: &str| doc["ranges"].as_array().unwrap().iter().find(|v| v["name"] == n).unwrap_or_else(|| panic!("no range {n}"))["outcome"].clone();
|
|
assert_eq!(range("tail_establishes_length")["length_established"], true);
|
|
assert_eq!(range("interior")["length_established"], false);
|
|
assert_eq!(range("length_not_established")["outcome"], "accept");
|
|
assert_eq!(range("length_not_established")["length_established"], false);
|
|
}
|
|
|
|
/// §11 of the extension lists exactly the codes `Reason::ALL` has, each once, in order.
|
|
#[test]
|
|
fn the_extension_lists_the_reasons() {
|
|
let text = read("extensions/settlement.md");
|
|
let at = text.find("\n## 11. Reasons").expect("a §11");
|
|
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, "§11's table and Reason::ALL differ");
|
|
}
|