Tests: spread three format-by-geometry matrices over the days, and build one precheck state per case

The tilt-shift reference tests and tiled_clear_and_fill_match_one_pass_over_the_area cross pixel
formats or channel counts with independent geometry and fill settings. Each run takes a quarter of
the combinations through Sweep, a different quarter each UTC day.

precheck_agrees_with_execute built all five document states for every call and kept one; it now
builds only the state the call needs.
This commit is contained in:
aiongg
2026-10-23 08:30:48 +00:00
parent b87cfb3c6a
commit 18f4b5348c
5 changed files with 63 additions and 31 deletions
+1
View File
@@ -60,6 +60,7 @@ photocraft-ipp = { workspace = true }
photocraft-affinity = { workspace = true, features = ["synth"] }
# Synthetic camera raw files for the open tests.
photocraft-raw = { workspace = true, features = ["testgen"] }
photocraft-testkit = { workspace = true }
# WebAssembly text -> binary for plug-in test modules (Apache-2.0 WITH LLVM-exception).
wat = "1.228"
# Synthetic multi-part EXR fixtures for the parts-commands tests.
+16 -6
View File
@@ -183,19 +183,29 @@ fn tiled_clear_and_fill_match_one_pass_over_the_area() {
let sr = Rect::new(0, 0, 600, 400);
soft.write_region(sr, &(0..sr.height()).flat_map(|_| (0..sr.width()).map(|x| (1.0 - (x as f32 - 256.0).max(0.0) / 300.0).max(0.0))).collect::<Vec<_>>());
let canvas = Rect::new(0, 0, 700, 600);
// Pixel formats and fill settings are independent: a run takes a quarter of their combinations,
// a different quarter each day.
let sweep = photocraft_testkit::Sweep::new(4);
let mut case = 0;
let mut runs = || {
case += 1;
sweep.includes(case)
};
for fmt in formats {
let s = clear_layer(fmt);
for sel in [None, Some(&soft)] {
let area = sel.map_or(canvas, |m| m.content_bounds());
let what = format!("{fmt:?} selection {}", sel.is_some());
let mut got = s.clone();
try_clear_surface(&mut got, area, sel).unwrap();
assert!(same_pixels(&got, &reference_fill_or_clear(&s, area, sel, None)), "clear {what}");
if fmt.alpha {
assert!(!same_pixels(&got, &s), "clear {what} changes the layer");
if runs() {
let mut got = s.clone();
try_clear_surface(&mut got, area, sel).unwrap();
assert!(same_pixels(&got, &reference_fill_or_clear(&s, area, sel, None)), "clear {what}");
if fmt.alpha {
assert!(!same_pixels(&got, &s), "clear {what} changes the layer");
}
}
for color in [[1.0, 1.0, 1.0, 1.0], [0.3, 0.5, 0.9, 1.0], [0.3, 0.5, 0.9, 0.4]] {
for lock in [true, false] {
for lock in [true, false].into_iter().filter(|_| runs()) {
let mut got = s.clone();
try_fill_surface(&mut got, area, color, sel, lock).unwrap();
assert!(same_pixels(&got, &reference_fill_or_clear(&s, area, sel, Some((color, lock)))), "fill {color:?} lock {lock} {what}");
+29 -25
View File
@@ -7,28 +7,32 @@ use serde_json::{Value, json};
/// Documents in different states: a Background only, a pixel layer active, a group active, a
/// selection, no document.
fn states() -> Vec<(&'static str, Session)> {
let mut out = Vec::new();
out.push(("no document", Session::new()));
const STATES: [&str; 5] = ["no document", "background only", "pixel layer", "group, no background", "selection"];
/// A fresh session in `state`.
fn state(state: &str) -> Session {
let mut s = Session::new();
s.execute("file.new", json!({"width": 40, "height": 30, "background": "white"})).unwrap();
out.push(("background only", s));
let mut s = Session::new();
s.execute("file.new", json!({"width": 40, "height": 30, "background": "white"})).unwrap();
s.execute("layer.new.layer", json!({})).unwrap();
s.execute("edit.fill", json!({"color": "#ff0000"})).unwrap();
out.push(("pixel layer", s));
let mut s = Session::new();
s.execute("file.new", json!({"width": 40, "height": 30, "background": "transparent"})).unwrap();
s.execute("layer.new.group", json!({})).unwrap();
out.push(("group, no background", s));
let mut s = Session::new();
s.execute("file.new", json!({"width": 40, "height": 30, "background": "white"})).unwrap();
s.execute("layer.new.layer", json!({})).unwrap();
s.execute("edit.fill", json!({"color": "#00ff00"})).unwrap();
s.execute("select.rect", json!({"x": 2, "y": 2, "width": 10, "height": 10})).unwrap();
out.push(("selection", s));
out
if state == "no document" {
return s;
}
let background = if state == "group, no background" { "transparent" } else { "white" };
s.execute("file.new", json!({"width": 40, "height": 30, "background": background})).unwrap();
match state {
"pixel layer" => {
s.execute("layer.new.layer", json!({})).unwrap();
s.execute("edit.fill", json!({"color": "#ff0000"})).unwrap();
}
"group, no background" => {
s.execute("layer.new.group", json!({})).unwrap();
}
"selection" => {
s.execute("layer.new.layer", json!({})).unwrap();
s.execute("edit.fill", json!({"color": "#00ff00"})).unwrap();
s.execute("select.rect", json!({"x": 2, "y": 2, "width": 10, "height": 10})).unwrap();
}
_ => {}
}
s
}
fn params() -> Vec<Value> {
@@ -63,13 +67,13 @@ fn precheck_agrees_with_execute() {
let mut disagreements = Vec::new();
for id in PRECHECKED {
for p in params() {
for (state, _) in states() {
// A fresh copy of the state for each call: execute changes it.
let mut s = states().into_iter().find(|(n, _)| *n == state).map(|(_, s)| s).unwrap();
for name in STATES {
// A fresh session for each call: execute changes it.
let mut s = state(name);
let pre = s.precheck(id, &p).is_ok();
let ran = s.execute(id, p.clone()).is_ok();
if pre != ran {
disagreements.push(format!("{id} {p} on {state}: precheck {pre}, execute {ran}"));
disagreements.push(format!("{id} {p} on {name}: precheck {pre}, execute {ran}"));
}
}
}