Merge pull request #383 from storytold/claude/test-376-masking-layout

Part of #372: painted-text layout tests from #376
This commit is contained in:
BFlat 2026-10-09 03:47:22 +07:00 committed by GitHub
commit 68e0827633
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 94 additions and 0 deletions

View File

@ -39,6 +39,8 @@ mod tests_library_problem;
#[cfg(test)]
mod tests_masking;
#[cfg(test)]
mod tests_masking_layout;
#[cfg(test)]
mod tests_offline;
#[cfg(test)]
mod tests_panels;

View File

@ -0,0 +1,92 @@
//! Check painted text as well as widget rectangles: custom painters can overflow a valid widget.
use egui::{Rect, pos2, vec2};
use serde_json::json;
use crate::{LightcraftApp, Services, headless::HeadlessView, i18n::Locale};
const LONG_NAME: &str = "The person standing beside the very long fence across the background";
fn text_shapes(shape: &egui::Shape, out: &mut Vec<egui::epaint::TextShape>) {
match shape {
egui::Shape::Text(text) => out.push(text.clone()),
egui::Shape::Vec(shapes) => shapes.iter().for_each(|s| text_shapes(s, out)),
_ => {}
}
}
fn panel(width: f32, scale: f32, locale: Locale, describe: bool) -> (Vec<egui::epaint::TextShape>, Vec<(String, Rect)>) {
let mut app = LightcraftApp::new(lightcraft_engine::Session::with_demo(), Services::default());
app.run("mask.add", json!({"kind": "subject", "name": LONG_NAME})).unwrap();
app.ui.describe = describe.then(|| ("new".into(), LONG_NAME.repeat(4)));
app.ui.detail_due = Some((100.0, 1));
let photo = app.session.active().unwrap();
let ctx = egui::Context::default();
crate::i18n::set_language(locale);
crate::theme::install_fonts(&ctx);
crate::theme::apply(&ctx);
let mut texts = Vec::new();
let mut widgets = Vec::new();
for frame in 0..3 {
let raw = HeadlessView::raw_input(vec2(width, 1600.0), scale, frame as f64 / 60.0, vec![]);
let mut out = ctx.run_ui(raw, |ui| {
egui::CentralPanel::default().frame(egui::Frame::NONE).show(ui, |ui| {
crate::panels::masking::show(&mut app, ui, photo);
});
});
out.textures_delta.clear();
texts.clear();
for shape in &out.shapes {
text_shapes(&shape.shape, &mut texts);
}
widgets = crate::widgets::take_registry(&ctx);
}
if describe {
assert_eq!(app.ui.describe.as_ref().unwrap().1, LONG_NAME.repeat(4), "layout must not shorten the actual prompt");
}
crate::i18n::set_language(Locale::En);
(texts, widgets)
}
#[test]
fn masking_tile_labels_fit_without_eliding_at_supported_panel_widths() {
for locale in [Locale::En, Locale::De, Locale::PtBr] {
for width in [250.0, 270.0, 330.0, 520.0] {
for scale in [1.0, 2.0] {
let (texts, widgets) = panel(width, scale, locale, false);
for (kind, label) in [("background", "Background"), ("luminanceRange", "Luminance"), ("prompt", "Describe")] {
crate::i18n::set_language(locale);
let label = crate::i18n::tr(label).to_string();
crate::i18n::set_language(Locale::En);
let tile = widgets.iter().find(|(id, _)| id == &format!("maskNew:{kind}")).unwrap().1;
let text = texts.iter().find(|t| t.galley.job.text == label && t.pos.y < tile.bottom()).unwrap();
assert!(!text.galley.elided, "{locale:?} {width} {label} should be readable in full");
assert!(
tile.shrink2(vec2(2.0, 0.0)).contains_rect(text.visual_bounding_rect()),
"{locale:?} {width} {scale}: {label} exceeds {tile:?}"
);
}
}
}
}
}
#[test]
fn masking_long_names_and_describe_controls_stay_inside_the_panel() {
for locale in [Locale::En, Locale::De, Locale::PtBr] {
for width in [250.0, 270.0, 520.0] {
let (texts, widgets) = panel(width, 2.0, locale, true);
let row = widgets.iter().find(|(id, _)| id == "mask:1").unwrap().1;
let name = texts.iter().find(|t| t.galley.job.text == LONG_NAME).unwrap();
assert!(name.galley.elided, "long mask names should be elided");
assert!(
Rect::from_min_max(pos2(row.left() + 32.0, row.top()), pos2(row.right() - 28.0, row.bottom()))
.contains_rect(name.visual_bounding_rect())
);
let field = widgets.iter().find(|(id, _)| id == "maskDescribe").unwrap().1;
let button = widgets.iter().find(|(id, _)| id == "button:maskDescribeGo").unwrap().1;
assert!(field.right() <= button.left(), "the prompt must not overlap Select");
assert!(field.left() >= 24.0 && button.right() <= width - 22.0, "{locale:?} {width}: {field:?} {button:?}");
}
}
}