Some checks failed
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m13s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m58s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 50s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 34s
standards workspaces build + test / map-rs (pull_request) Successful in 31s
standards workspaces build + test / mesh-rs (pull_request) Successful in 31s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / jouledesk-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI section references / cited sections exist (pull_request) Has been cancelled
wai-vector vector graphics / linux-aarch64 (pull_request) Has been cancelled
wai-vector vector graphics / linux-x86_64 (pull_request) Has been cancelled
wai-vector vector graphics / macos-arm64 (pull_request) Has been cancelled
wai-vector vector graphics / wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
wai-vector vector graphics / wasm32 under Node (pull_request) Has been cancelled
wai-vector vector graphics / fuzz, peak allocation, comparison count (pull_request) Has been cancelled
workflow hygiene / every workflow supersedes its own queue (pull_request) Has been cancelled
standards workspaces build + test / openpay (pull_request) Has been cancelled
The reference crate of wai.graphics.vector (no_std + alloc, no dependencies; SHA-256 is wai-ops's, by #[path]): - WOS1 parsed with §2.1's load checks in order, and written; - WVG1 split (steps 1-3, nothing allocated before the exact length), the record pass (step 4), the cross-record checks (step 5(a)-(h)), the sets by digest with at most length + 1 bytes read (step 6), the glyphs (7), the interval check (8) and the per-frame cost (9); - the clock with the frame range by division, track evaluation, and placement; - the JSON authoring form, one member per field, packing back to the same bytes; - the CLI: check, cost, pack, unpack, vectors gen and verify; - a wasm32 module and verify.mjs for Node. The corpus wai/vector-conformance/ (arith, canonical, refusals, geometry, cost) with its README's provenance line and a sha256.json sidecar naming the div255 table; wai-vector.yml with native, wasip2, node and fuzz jobs. Co-Authored-By: Claude Opus 5.5 <[email protected]>
135 lines
5.8 KiB
Rust
135 lines
5.8 KiB
Rust
//! §2.7 and §2.1: each code, and the order of the checks, pinned by pairs of faults.
|
|
|
|
use wai_vector::refuse::Code;
|
|
use wai_vector::vectors::{all_vectors, corpus_store, find};
|
|
use wai_vector::{wos1, wvg1};
|
|
|
|
fn code_of(group: &str, name: &str) -> (Code, &'static str) {
|
|
let v = find(group, name).unwrap_or_else(|| panic!("no vector {group}/{name}"));
|
|
let r = match v.ext {
|
|
"wos1" => wos1::parse(&v.bytes).err(),
|
|
_ => wvg1::load(&v.bytes, &mut corpus_store()).err(),
|
|
};
|
|
let r = r.unwrap_or_else(|| panic!("{group}/{name} was accepted"));
|
|
(r.code, r.step)
|
|
}
|
|
|
|
fn accepted(group: &str, name: &str) -> bool {
|
|
let v = find(group, name).unwrap();
|
|
match v.ext {
|
|
"wos1" => wos1::parse(&v.bytes).is_ok(),
|
|
_ => wvg1::load(&v.bytes, &mut corpus_store()).is_ok(),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn wos1_load_check_order() {
|
|
let g = "refusals";
|
|
for (name, code) in [
|
|
("wos1-short", Code::OutlineMalformed),
|
|
("wos1-magic", Code::OutlineMalformed),
|
|
("wos1-flags", Code::OutlineMalformed),
|
|
("wos1-n-glyphs-cap", Code::TooLarge),
|
|
("wos1-notes-zero", Code::OutlineMalformed),
|
|
("wos1-length", Code::OutlineMalformed),
|
|
("wos1-points-limit", Code::PointsLimit),
|
|
("wos1-gid-order", Code::OutlineMalformed),
|
|
("wos1-sums", Code::OutlineMalformed),
|
|
("wos1-ends-order", Code::OutlineMalformed),
|
|
("wos1-tag", Code::OutlineMalformed),
|
|
("wos1-grammar", Code::OutlineMalformed),
|
|
("wos1-grammar-one-point-control", Code::OutlineMalformed),
|
|
("wos1-box", Code::OutlineMalformed),
|
|
("wos1-notes-utf8", Code::OutlineMalformed),
|
|
("wos1-points-16384", Code::PointsLimit),
|
|
] {
|
|
assert_eq!(code_of(g, name).0, code, "{name}");
|
|
}
|
|
// The pairs: each fault alone has another code, so the first check wins.
|
|
assert_eq!(code_of(g, "wos1-points-limit-before-gid-order"), (Code::PointsLimit, "wos1.4"), "check 4 before check 5");
|
|
assert_eq!(code_of(g, "wos1-zero-before-points-limit"), (Code::OutlineMalformed, "wos1.4"), "records in order");
|
|
assert_eq!(code_of(g, "wos1-points-limit-before-zero"), (Code::PointsLimit, "wos1.4"), "n_points first within a record");
|
|
assert_eq!(code_of(g, "wos1-cap-before-length"), (Code::TooLarge, "wos1.2"), "check 2 before check 3");
|
|
assert_eq!(code_of(g, "wos1-zero-glyphs-before-points-cap"), (Code::OutlineMalformed, "wos1.2"), "field order in check 2");
|
|
assert!(accepted(g, "wos1-set-a"));
|
|
assert!(accepted(g, "wos1-points-16383"));
|
|
}
|
|
|
|
#[test]
|
|
fn record_pass_reports_field_range_before_any_cross_table_check() {
|
|
// ITEM.kind = 4 with ref = 0, beside an inline set marked held (a step 5(a) sum).
|
|
assert_eq!(code_of("refusals", "s4-item-kind-four"), (Code::FieldRange, "4"));
|
|
// KEY.interp = 2 + j with j >= n_tables, beside the same sum fault.
|
|
assert_eq!(code_of("refusals", "s4-key-interp-before-sum"), (Code::FieldRange, "4"));
|
|
// Each fault alone.
|
|
assert_eq!(code_of("refusals", "s4-key-interp"), (Code::FieldRange, "4"));
|
|
assert_eq!(code_of("refusals", "s5a-inline-sum"), (Code::PayloadMalformed, "5a"));
|
|
}
|
|
|
|
#[test]
|
|
fn the_four_new_sum_rules() {
|
|
for name in ["s5a-path-contours-sum", "s5a-path-points-sum", "s5a-strings-sum", "s5a-glyphs-sum", "s5a-clusters-sum"] {
|
|
assert_eq!(code_of("refusals", name), (Code::PayloadMalformed, "5a"), "{name}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn exact_length_and_trailing_bytes() {
|
|
let min = find("canonical", "minimal").unwrap().bytes;
|
|
assert!(wvg1::load(&min, &mut corpus_store()).is_ok());
|
|
let mut long = min.clone();
|
|
long.push(0);
|
|
let e = wvg1::parse(&long).unwrap_err();
|
|
assert_eq!((e.code, e.step), (Code::PayloadMalformed, "3"), "one trailing byte");
|
|
let e = wvg1::parse(&min[..min.len() - 1]).unwrap_err();
|
|
assert_eq!((e.code, e.step), (Code::PayloadMalformed, "3"), "one byte short");
|
|
let e = wvg1::parse(&min[..79]).unwrap_err();
|
|
assert_eq!((e.code, e.step), (Code::PayloadMalformed, "1"), "a short header");
|
|
}
|
|
|
|
#[test]
|
|
fn steps_in_order() {
|
|
let g = "refusals";
|
|
for (name, code, step) in [
|
|
("s1-magic-before-cap", Code::PayloadMalformed, "1"),
|
|
("s2-cap-before-range", Code::TooLarge, "2"),
|
|
("s2-cap-before-length", Code::TooLarge, "2"),
|
|
("s4-header-before-record", Code::FieldRange, "4"),
|
|
("s4-set-carriage-before-zero", Code::FieldRange, "4"),
|
|
("s4-set-zero-before-length", Code::PayloadMalformed, "4"),
|
|
("s4-item-zero2-before-ref", Code::PayloadMalformed, "4"),
|
|
("s4-item-rule-before-zero2", Code::FieldRange, "4"),
|
|
("s4-path-points-limit-before-zero", Code::PointsLimit, "4"),
|
|
("s5a-sum-before-typing", Code::PayloadMalformed, "5a"),
|
|
("s5c-typing-before-groups", Code::FieldRange, "5c"),
|
|
("s6-order-held-first", Code::OutlineNotHeld, "6"),
|
|
("s6-order-inline-first", Code::OutlineMalformed, "6"),
|
|
("s7-before-geometry", Code::GlyphMissing, "7"),
|
|
] {
|
|
assert_eq!(code_of(g, name), (code, step), "{name}");
|
|
}
|
|
}
|
|
|
|
/// Every vector's code is the one its note names.
|
|
#[test]
|
|
fn every_vector_has_the_code_its_note_names() {
|
|
let mut store = corpus_store();
|
|
let mut n = 0;
|
|
for v in all_vectors() {
|
|
let got = match v.ext {
|
|
"wos1" => wos1::parse(&v.bytes).err().map(|e| e.code.name()),
|
|
"wvg1" => wvg1::load(&v.bytes, &mut store).err().map(|e| e.code.name()),
|
|
_ => continue,
|
|
};
|
|
let want = match v.note.rsplit_once("-> ") {
|
|
Some((_, rest)) => Some(rest.split(|c: char| !(c.is_ascii_lowercase() || c == '_')).next().unwrap()),
|
|
None => {
|
|
assert!(v.note.ends_with("accepted"), "{}: the note names no outcome", v.name);
|
|
None
|
|
}
|
|
};
|
|
assert_eq!(got, want, "{}/{}: {}", v.group, v.name, v.note);
|
|
n += 1;
|
|
}
|
|
assert!(n > 200, "{n} vectors");
|
|
}
|