open-standards/wai/wai-rs/tests/exact_tonemap.rs
Transaction Science 469546018c wai: exact tone mapping — wai.meta.gainmap, wai.meta.st2094_50, wai.media.tonemap
The extension text (extensions/exact-tonemap.md), the exact_tonemap module
of wai-rs (integer log2/exp2, the sRGB table, wai-tonemap:gainmap and
wai-tonemap:st2094-50, the rendition record and its verification), the
registry rows and SPEC §5 / §7.1 text for the two companions, the glossary
entries, and the corpus live-conformance/tonemap/ written by
wai_tonemap_vectors gen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:13:55 -04:00

88 lines
3.9 KiB
Rust

//! Exact tone mapping (extensions/exact-tonemap.md): the committed corpus
//! `live-conformance/tonemap/` regenerates byte for byte, holds no other file, every case and
//! envelope in it gets the outcome it states, the extension's §9 lists exactly the reasons the
//! reference reports, §6 states the corpus's measurement, and `frames.rgb8` is the decode of
//! the int_video clip whose digests the integer video corpus publishes. The generator itself
//! asserts that the corpus gives every reason.
#![cfg(feature = "exact_tonemap")]
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use wai::exact_tonemap::{corpus, Reason};
fn wai_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
}
fn read_tree(dir: &Path, prefix: &str, out: &mut BTreeMap<String, Vec<u8>>) {
for e in std::fs::read_dir(dir).expect("the committed corpus").flatten() {
let name = format!("{prefix}{}", e.file_name().to_string_lossy());
if e.file_type().expect("a type").is_dir() {
read_tree(&e.path(), &format!("{name}/"), out);
} else if name != "README.md" {
out.insert(name, std::fs::read(e.path()).expect("a file"));
}
}
}
fn committed() -> BTreeMap<String, Vec<u8>> {
let mut out = BTreeMap::new();
read_tree(&wai_dir().join("live-conformance/tonemap"), "", &mut out);
out
}
fn section(text: &str, heading: &str) -> String {
let at = text.find(heading).unwrap_or_else(|| panic!("a section {heading}"));
let end = text[at + 1..].find("\n## ").map_or(text.len(), |e| at + 1 + e);
text[at..end].to_string()
}
fn extension() -> String {
std::fs::read_to_string(wai_dir().join("extensions/exact-tonemap.md")).expect("the extension")
}
#[test]
fn the_committed_corpus_regenerates_and_every_case_gets_its_outcome() {
let fails = corpus::verify(&committed());
assert!(fails.is_empty(), "{}\n(run `wai_tonemap_vectors gen`)", fails.join("\n"));
}
/// §9 lists exactly the codes `Reason::ALL` has, each once, in order.
#[test]
fn the_extension_lists_the_reasons() {
let listed: Vec<String> = section(&extension(), "\n## 9. Reasons")
.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");
}
/// §6's table states the measurement the corpus records.
#[test]
fn the_extension_states_the_measurement() {
let s = section(&extension(), "\n## 6. ");
let c = corpus::build();
for (k, (r, n, max, mean)) in corpus::measurement_figures(&c.measurement) {
let term = format!("`wai-tonemap:{k}`");
let row = s.lines().find(|l| l.starts_with(&format!("| {term} "))).unwrap_or_else(|| panic!("§6 has no row for {term}"));
let cells: Vec<&str> = row.split('|').map(str::trim).collect();
assert_eq!(&cells[2..6], &[r.to_string().as_str(), n.to_string().as_str(), max.to_string().as_str(), mean.as_str()], "§6's row for {term}");
}
}
/// `frames.rgb8` is the int_video clip as `wai.video.int_motion` decodes it, and each frame's
/// digest is the one the clip's sidecar publishes.
#[test]
fn the_frames_are_the_int_video_decode() {
let (w, h, frames) = corpus::video_frames();
let committed = committed();
assert_eq!(committed["frames.rgb8"], frames.concat());
let sidecar: serde_json::Value =
serde_json::from_slice(&std::fs::read(wai_dir().join(corpus::SIDECAR_PATH)).expect("the sidecar")).expect("json");
let want: Vec<String> = sidecar["int_video"]["frames_sha256"].as_array().expect("digests").iter().map(|v| v.as_str().expect("hex").to_string()).collect();
let got: Vec<String> = frames.iter().map(|f| wai::exact_tonemap::hex(&wai::exact_tonemap::digest(f))).collect();
assert_eq!(got, want);
assert_eq!((w, h), (48, 48));
}