mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-12 05:12:21 +00:00
test(ui-egui): split the crypto-pick viewer matrix into one test per window size
picks_what_the_viewer_shows_across_sizes_scales_zoom_pan_resolution_and_proxies looped over four independent window-size and display-scale cases, each with its own session. As one test it took ~90 s in the gate and ~590 s under coverage, where it alone set the slowest SonarCloud shard. Each case is now its own test, running the same checks, so nextest runs them in parallel and partitions them across shards. The "more than 100 hovers checked" floor becomes more than 25 per case, which still adds up to more than 100. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6aca5e473c
commit
47fc00f85d
1 file changed
+86
-67
@@ -277,84 +277,103 @@ fn eyedropper_arms_hovers_picks_with_modifiers_and_stays_armed_until_esc() {
|
||||
let _ = std::fs::remove_dir_all(&ids.dir);
|
||||
}
|
||||
|
||||
/// Window and panel sizes × display scales × viewer zoom / pan × Resolution (and a proxy): hover
|
||||
/// and click name the ID of the pixel the viewer shows, next to cell edges too. Each hover is
|
||||
/// checked against the rendered matte of the named ID at the point the screen maps back to.
|
||||
// Window and panel sizes × display scales, one test each so they run in parallel. Together they
|
||||
// took ~90 s as one test, and ~10 min under coverage, where that one test set the slowest shard.
|
||||
#[test]
|
||||
fn picks_what_the_viewer_shows_across_sizes_scales_zoom_pan_resolution_and_proxies() {
|
||||
fn picks_what_the_viewer_shows_at_900x640_and_1x() {
|
||||
picks_what_the_viewer_shows(0, vec2(900.0, 640.0), 1.0, 300.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picks_what_the_viewer_shows_at_1280x720_and_1_25x() {
|
||||
picks_what_the_viewer_shows(1, vec2(1280.0, 720.0), 1.25, 420.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picks_what_the_viewer_shows_at_1600x1000_and_1_5x() {
|
||||
picks_what_the_viewer_shows(2, vec2(1600.0, 1000.0), 1.5, 360.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picks_what_the_viewer_shows_at_2400x1400_and_2x() {
|
||||
picks_what_the_viewer_shows(3, vec2(2400.0, 1400.0), 2.0, 600.0);
|
||||
}
|
||||
|
||||
/// Case `i`: a window of `size` at display scale `ppp`, with an Effect Controls panel `ec` wide,
|
||||
/// × viewer zoom / pan × Resolution (and a proxy). Hover and click name the ID of the pixel the
|
||||
/// viewer shows, next to cell edges too. Each hover is checked against the rendered matte of the
|
||||
/// named ID at the point the screen maps back to. Case 0 also checks frames from the idle cache.
|
||||
fn picks_what_the_viewer_shows(i: usize, size: egui::Vec2, ppp: f32, ec: f32) {
|
||||
let mut checked = 0;
|
||||
let mut failures = vec![];
|
||||
let cases = [(vec2(900.0, 640.0), 1.0, 300.0), (vec2(1280.0, 720.0), 1.25, 420.0), (vec2(1600.0, 1000.0), 1.5, 360.0), (vec2(2400.0, 1400.0), 2.0, 600.0)];
|
||||
for (i, (size, ppp, ec)) in cases.into_iter().enumerate() {
|
||||
let (s, ids) = crypto_session(&format!("matrix{i}"), 1919, 1079, false);
|
||||
let mut h = harness(s, size, ppp, ec);
|
||||
h.state_mut().session.execute_checked("prop.set", json!({"path": "effects/#1/matteOnly", "value": true})).unwrap();
|
||||
arm(&mut h, &ids);
|
||||
for proxy in [false, true] {
|
||||
if proxy {
|
||||
let p = ids.dir.join("proxy").join("plate_proxy.exr");
|
||||
h.state_mut().session.execute("file.setProxy", json!({"item": ids.footage, "path": p.to_string_lossy()})).unwrap();
|
||||
}
|
||||
for res in [Resolution::Full, Resolution::Half, Resolution::Third, Resolution::Quarter, Resolution::Custom(6)] {
|
||||
for (zoom, pan) in [(None, [0.0, 0.0]), (Some(0.5), [0.0, 0.0]), (Some(2.0), [-300.0, 120.0])] {
|
||||
let cid = h.state().session.active_comp_id().unwrap();
|
||||
h.state_mut().session.set_resolution(cid, res).unwrap();
|
||||
h.state_mut().ui.viewer.zoom = zoom.map(|z: f32| z / ppp);
|
||||
h.state_mut().ui.viewer.pan = pan;
|
||||
settle(&mut h);
|
||||
let area = h.state().auto.find("viewer.fxPick").unwrap().rect;
|
||||
let scale = shown_scale(&h);
|
||||
// Points next to cell edges, in the middle and at the far corner.
|
||||
// (Cell edges far from the origin: 925, 1044 shows the 1/3 vs 0.333 rounding.)
|
||||
for p in [[36.6, 28.7], [37.4, 29.3], [959.7, 539.2], [1918.4, 1078.6], [74.1, 57.9], [925.4, 1044.4], [1110.6, 1043.6]] {
|
||||
let Some(sp) = comp_to_screen(&h.ctx, [p[0] as f32, p[1] as f32]) else { continue };
|
||||
if sp.x < area[0] + 4.0 || sp.y < area[1] + 40.0 || sp.x > area[0] + area[2] - 4.0 || sp.y > area[1] + area[3] - 4.0 {
|
||||
continue;
|
||||
}
|
||||
let got = hover(&mut h, sp);
|
||||
let got = got.trim_end_matches(" (selected)").to_string();
|
||||
// The comp point under the cursor, as the viewer maps it back.
|
||||
let q = to_comp(&h, sp);
|
||||
checked += 1;
|
||||
// The named ID has the largest coverage of the shown pixel (a blended edge
|
||||
// pixel of a proxy at Quarter has several). No ID named: the frame shows
|
||||
// (almost) no matte there either (an odd size's last half-resolution pixel
|
||||
// samples just outside the layer).
|
||||
let ok = if got.starts_with('c') { largest(&mut h, &got, q, scale) } else { got == HINT && lit(&mut h, "*", q, scale) < 0.5 };
|
||||
if !ok {
|
||||
failures.push(format!(
|
||||
"{size:?} ppp {ppp} proxy {proxy} {res:?} zoom {zoom:?} (scale {scale}): at {q:?} hover {got:?} is not lit there"
|
||||
));
|
||||
}
|
||||
let (s, ids) = crypto_session(&format!("matrix{i}"), 1919, 1079, false);
|
||||
let mut h = harness(s, size, ppp, ec);
|
||||
h.state_mut().session.execute_checked("prop.set", json!({"path": "effects/#1/matteOnly", "value": true})).unwrap();
|
||||
arm(&mut h, &ids);
|
||||
for proxy in [false, true] {
|
||||
if proxy {
|
||||
let p = ids.dir.join("proxy").join("plate_proxy.exr");
|
||||
h.state_mut().session.execute("file.setProxy", json!({"item": ids.footage, "path": p.to_string_lossy()})).unwrap();
|
||||
}
|
||||
for res in [Resolution::Full, Resolution::Half, Resolution::Third, Resolution::Quarter, Resolution::Custom(6)] {
|
||||
for (zoom, pan) in [(None, [0.0, 0.0]), (Some(0.5), [0.0, 0.0]), (Some(2.0), [-300.0, 120.0])] {
|
||||
let cid = h.state().session.active_comp_id().unwrap();
|
||||
h.state_mut().session.set_resolution(cid, res).unwrap();
|
||||
h.state_mut().ui.viewer.zoom = zoom.map(|z: f32| z / ppp);
|
||||
h.state_mut().ui.viewer.pan = pan;
|
||||
settle(&mut h);
|
||||
let area = h.state().auto.find("viewer.fxPick").unwrap().rect;
|
||||
let scale = shown_scale(&h);
|
||||
// Points next to cell edges, in the middle and at the far corner.
|
||||
// (Cell edges far from the origin: 925, 1044 shows the 1/3 vs 0.333 rounding.)
|
||||
for p in [[36.6, 28.7], [37.4, 29.3], [959.7, 539.2], [1918.4, 1078.6], [74.1, 57.9], [925.4, 1044.4], [1110.6, 1043.6]] {
|
||||
let Some(sp) = comp_to_screen(&h.ctx, [p[0] as f32, p[1] as f32]) else { continue };
|
||||
if sp.x < area[0] + 4.0 || sp.y < area[1] + 40.0 || sp.x > area[0] + area[2] - 4.0 || sp.y > area[1] + area[3] - 4.0 {
|
||||
continue;
|
||||
}
|
||||
let got = hover(&mut h, sp);
|
||||
let got = got.trim_end_matches(" (selected)").to_string();
|
||||
// The comp point under the cursor, as the viewer maps it back.
|
||||
let q = to_comp(&h, sp);
|
||||
checked += 1;
|
||||
// The named ID has the largest coverage of the shown pixel (a blended edge
|
||||
// pixel of a proxy at Quarter has several). No ID named: the frame shows
|
||||
// (almost) no matte there either (an odd size's last half-resolution pixel
|
||||
// samples just outside the layer).
|
||||
let ok = if got.starts_with('c') { largest(&mut h, &got, q, scale) } else { got == HINT && lit(&mut h, "*", q, scale) < 0.5 };
|
||||
if !ok {
|
||||
failures
|
||||
.push(format!("{size:?} ppp {ppp} proxy {proxy} {res:?} zoom {zoom:?} (scale {scale}): at {q:?} hover {got:?} is not lit there"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Frames from Cache Frames When Idle (the first case): rendered on the grid the
|
||||
// viewer renders and the pick reads (1/3, not the key's 0.333), so frame 20 from the
|
||||
// idle cache is frame 0 as the viewer rendered it, and hovers there are right too.
|
||||
if i == 0 && !proxy {
|
||||
(h.state_mut().ui.viewer.zoom, h.state_mut().ui.viewer.pan) = (None, [0.0, 0.0]);
|
||||
for res in [Resolution::Third, Resolution::Custom(6)] {
|
||||
let fails = idle_cached_frames_are_shown_frames(&mut h, res);
|
||||
checked += 1;
|
||||
failures.extend(fails);
|
||||
}
|
||||
}
|
||||
// A click picks what the hover named.
|
||||
}
|
||||
// Frames from Cache Frames When Idle (the first case): rendered on the grid the
|
||||
// viewer renders and the pick reads (1/3, not the key's 0.333), so frame 20 from the
|
||||
// idle cache is frame 0 as the viewer rendered it, and hovers there are right too.
|
||||
if i == 0 && !proxy {
|
||||
(h.state_mut().ui.viewer.zoom, h.state_mut().ui.viewer.pan) = (None, [0.0, 0.0]);
|
||||
settle(&mut h);
|
||||
let sp = comp_to_screen(&h.ctx, [959.7, 539.2]).unwrap();
|
||||
let named = hover(&mut h, sp);
|
||||
click(&mut h, sp, Modifiers::NONE);
|
||||
assert_eq!(selection(&h, &ids), named.trim_end_matches(" (selected)"));
|
||||
if proxy {
|
||||
h.state_mut().session.execute("file.setProxy", json!({"item": ids.footage, "path": null})).ok();
|
||||
for res in [Resolution::Third, Resolution::Custom(6)] {
|
||||
let fails = idle_cached_frames_are_shown_frames(&mut h, res);
|
||||
checked += 1;
|
||||
failures.extend(fails);
|
||||
}
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&ids.dir);
|
||||
// A click picks what the hover named.
|
||||
(h.state_mut().ui.viewer.zoom, h.state_mut().ui.viewer.pan) = (None, [0.0, 0.0]);
|
||||
settle(&mut h);
|
||||
let sp = comp_to_screen(&h.ctx, [959.7, 539.2]).unwrap();
|
||||
let named = hover(&mut h, sp);
|
||||
click(&mut h, sp, Modifiers::NONE);
|
||||
assert_eq!(selection(&h, &ids), named.trim_end_matches(" (selected)"));
|
||||
if proxy {
|
||||
h.state_mut().session.execute("file.setProxy", json!({"item": ids.footage, "path": null})).ok();
|
||||
}
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&ids.dir);
|
||||
assert!(failures.is_empty(), "{} of {checked} hovers wrong:\n{}", failures.len(), failures.join("\n"));
|
||||
assert!(checked > 100, "{checked}");
|
||||
// more than 100 over the four cases, as when they were one test
|
||||
assert!(checked > 25, "{checked}");
|
||||
}
|
||||
|
||||
fn set_frame(h: &mut Harness<'_, EffectcraftApp>, f: i64) {
|
||||
|
||||
Reference in new issue
Block a user