use std::collections::BTreeSet;
use kui_core::conformance::{self, Coverage, Output, Scene};
use kui_core::schema::{CUSTOM, ELEMENTS};
fn access_rows(out: &Output) -> Vec<String> {
out.nodes
.iter()
.map(|n| {
format!(
"{} {} {}|{}|{}",
n.depth, n.role, n.name, n.description, n.value
)
})
.collect()
}
fn announcements(out: &Output) -> Vec<String> {
out.announcements
.iter()
.map(|a| format!("{} {}", a.live.name(), a.text))
.collect()
}
fn events(out: &Output) -> Vec<String> {
out.events
.iter()
.map(|(kind, tag)| format!("{kind} {tag}"))
.collect()
}
fn commands(out: &Output) -> Vec<String> {
out.commands
.iter()
.map(|c| {
let mut line = String::new();
conformance::write_command(c, &mut line);
line.trim_end().trim_start_matches("cmd ").to_string()
})
.collect()
}
fn audio(out: &Output) -> Vec<String> {
out.audio
.iter()
.map(|c| {
let mut line = String::new();
conformance::write_audio_command(c, &mut line);
line.trim_end().trim_start_matches("audio ").to_string()
})
.collect()
}
fn check(scene: &Scene) {
let out = conformance::run(scene);
let e = &scene.expect;
let name = scene.name;
assert_eq!(out.kinds[0], e.solid, "{name}: solid quads");
assert_eq!(out.kinds[5], e.shadows, "{name}: shadow quads");
assert_eq!(out.kinds[3], e.images, "{name}: image quads");
if e.segments_follow_text {
assert!(
out.kinds[6] >= e.segments,
"{name}: {} segment quads, expected at least {}",
out.kinds[6],
e.segments
);
} else {
assert_eq!(out.kinds[6], e.segments, "{name}: segment quads");
}
assert_eq!(out.kinds[7], e.fragments, "{name}: fragment quads");
assert_eq!(out.kinds[8], e.textures, "{name}: texture quads");
assert_eq!(
out.fragments.len(),
e.fragments,
"{name}: a fragment draw for every fragment quad"
);
let glyphs = out.kinds[1] + out.kinds[2] + out.kinds[4];
assert!(
glyphs >= e.glyphs_min,
"{name}: {glyphs} glyph quads, expected at least {}",
e.glyphs_min
);
assert_eq!(access_rows(&out), e.access, "{name}: access tree");
assert_eq!(events(&out), e.events, "{name}: events");
assert_eq!(
announcements(&out),
e.announcements,
"{name}: announcements"
);
assert_eq!(out.warnings, e.warnings, "{name}: warnings");
assert_eq!(commands(&out), e.commands, "{name}: window commands");
assert_eq!(audio(&out), e.audio, "{name}: audio commands");
assert_eq!(out.title.as_deref(), e.title, "{name}: window title");
assert_eq!(out.always_on_top, e.always_on_top, "{name}: always on top");
assert_eq!(out.secure_input, e.secure_input, "{name}: secure input");
assert_eq!(out.option_as_alt, e.option_as_alt, "{name}: option as alt");
assert_eq!(out.ime_off, e.ime_off, "{name}: ime off");
}
#[test]
fn every_scene_matches_its_expectations() {
for scene in conformance::SCENES {
check(scene);
}
}
#[test]
fn the_clip_access_scene_cuts_its_rects() {
let scene = conformance::SCENES
.iter()
.find(|s| s.name == "clip-access")
.unwrap();
let out = conformance::run(scene);
let rects: Vec<[f32; 4]> = out
.nodes
.iter()
.map(|n| n.rect.map(f32::from_bits))
.collect();
assert_eq!(
rects,
[
[0.0, 0.0, 320.0, 240.0],
[0.0, 0.0, 320.0, 40.0],
[20.0, 40.0, 60.0, 20.0],
[100.0, 40.0, 0.0, 0.0],
[140.0, -20.0, 60.0, 40.0],
[220.0, 40.0, 100.0, 50.0],
[220.0, 40.0, 100.0, 30.0],
[220.0, 70.0, 100.0, 20.0],
[220.0, 90.0, 0.0, 0.0],
]
);
}
#[test]
fn every_scene_draws_and_reports() {
for scene in conformance::SCENES {
let out = conformance::run(scene);
assert!(out.quad_count > 0, "{}: no quads", scene.name);
assert!(!out.nodes.is_empty(), "{}: no access tree", scene.name);
let block = conformance::report(scene.name, scene.env, scene.steps, &out);
assert!(block.starts_with(&format!("scene {}\n", scene.name)));
assert!(block.ends_with("end\n"));
}
}
#[test]
fn scene_names_are_unique() {
let names: BTreeSet<_> = conformance::SCENES.iter().map(|s| s.name).collect();
assert_eq!(names.len(), conformance::SCENES.len());
}
#[test]
fn the_corpus_covers_every_hand_written_row() {
let custom: BTreeSet<&str> = conformance::SCENES
.iter()
.flat_map(|s| s.custom.iter().copied())
.collect();
let elements: BTreeSet<&str> = conformance::SCENES
.iter()
.flat_map(|s| s.elements.iter().copied())
.collect();
let missing: Vec<&str> = CUSTOM
.iter()
.map(|c| c.name)
.filter(|n| !custom.contains(n))
.collect();
assert!(
missing.is_empty(),
"no scene exercises these schema::CUSTOM rows: {missing:?}"
);
let missing: Vec<&str> = ELEMENTS
.iter()
.map(|e| e.name)
.filter(|n| !elements.contains(n))
.collect();
assert!(
missing.is_empty(),
"no scene exercises these schema::ELEMENTS rows: {missing:?}"
);
for name in &custom {
assert!(
CUSTOM.iter().any(|c| &c.name == name),
"scene claims schema::CUSTOM row {name:?}, which does not exist"
);
}
for name in &elements {
assert!(
ELEMENTS.iter().any(|e| &e.name == name),
"scene claims schema::ELEMENTS row {name:?}, which does not exist"
);
}
}
#[test]
fn every_scene_delivers_the_coverage_it_claims() {
let underived: BTreeSet<&str> = conformance::UNDERIVED.iter().map(|(n, _)| *n).collect();
for scene in conformance::SCENES {
let cov = conformance::run(scene).coverage;
let stale: Vec<&str> = scene
.custom
.iter()
.copied()
.filter(|n| !underived.contains(n) && !cov.custom.contains(n))
.collect();
assert!(
stale.is_empty(),
"scene {:?} claims schema::CUSTOM rows its builder does not exercise: {stale:?}",
scene.name
);
let stale: Vec<&str> = scene
.elements
.iter()
.copied()
.filter(|n| !underived.contains(n) && !cov.elements.contains(n))
.collect();
assert!(
stale.is_empty(),
"scene {:?} claims schema::ELEMENTS rows its builder does not exercise: {stale:?}",
scene.name
);
}
}
#[test]
fn the_underived_rows_are_real_and_still_underived() {
let mut derived = Coverage::default();
for scene in conformance::SCENES {
let cov = conformance::run(scene).coverage;
derived.custom.extend(cov.custom);
derived.elements.extend(cov.elements);
}
for (name, why) in conformance::UNDERIVED {
assert!(!why.is_empty(), "{name:?} is exempted without a reason");
let is_custom = CUSTOM.iter().any(|c| c.name == *name);
let is_element = ELEMENTS.iter().any(|e| e.name == *name);
assert!(
is_custom || is_element,
"UNDERIVED names {name:?}, which is neither a schema::CUSTOM nor a \
schema::ELEMENTS row"
);
assert!(
!((is_custom && derived.custom.contains(name))
|| (is_element && derived.elements.contains(name))),
"UNDERIVED still exempts {name:?}, but a scene now exercises it — \
drop the exemption"
);
}
}
#[test]
fn the_reference_report_is_deterministic() {
assert_eq!(
conformance::reference_report(),
conformance::reference_report()
);
let blocks = conformance::blocks(&conformance::reference_report());
assert_eq!(blocks.len(), conformance::SCENES.len());
for (scene, (name, _)) in conformance::SCENES.iter().zip(&blocks) {
assert_eq!(scene.name, name);
}
}