Merge pull request #6867 from dotCooCoo/fix/ui-egui-parallel-test-races

Tests: font menu and menu bar tests allow for fonts and plug-ins other tests change
This commit is contained in:
BFlat
2026-11-12 22:00:42 +07:00
committed by GitHub
2 changed files with 62 additions and 49 deletions
+18 -8
View File
@@ -21,12 +21,13 @@ fn the_thai_filter_lists_fonts_with_thai() {
/// stay clear of it.
#[test]
fn the_scroll_bar_leaves_the_stars_clear() {
// Every family starred, so each row draws its star.
// Every family starred, so each row draws its star. Tests running alongside add fonts and
// composite fonts to the process-wide database, which the menu lists too: the ★ filter keeps
// the rows to the families starred here.
let all = vectorcraft_text::FontDb::global().families();
let families = all.len();
let ctx = egui::Context::default();
let area = egui::Rect::from_min_size(egui::pos2(0.0, 0.0), egui::vec2(300.0, 160.0));
let mut st = super::MenuState::default();
let mut st = super::MenuState { favorites_only: true, ..Default::default() };
let look = super::MenuLook { samples: false, favorites: &all, ..Default::default() };
let mut stars = vec![];
for _ in 0..3 {
@@ -45,6 +46,7 @@ fn the_scroll_bar_leaves_the_stars_clear() {
})
.collect();
}
let families = st.rows.len();
assert!(!stars.is_empty() || families == 0, "{families} families, no row stars drawn");
// The rows don't fill the list without enough families to scroll, and then there is no bar.
if families as f32 * look.row > area.height() {
@@ -62,6 +64,13 @@ fn family(name: &str) -> Row {
Row::Family(name.to_string())
}
/// The families the font menu lists that stay listed, in its order: the menu's list without the
/// composite fonts at its top, which tests running alongside define and remove in the process-wide
/// database.
fn lasting_families() -> Vec<String> {
vectorcraft_text::FontDb::global().family_list().iter().filter(|f| !f.starts_with('.')).cloned().collect()
}
#[test]
fn recent_fonts_are_first_available_unique_and_expandable() {
let names: Vec<_> = ["Alpha", "Bravo", "Charlie"].map(str::to_string).into();
@@ -86,7 +95,7 @@ fn recent_fonts_are_first_available_unique_and_expandable() {
#[test]
fn recent_section_rebuilds_and_arrows_skip_its_headings() {
let names = vectorcraft_text::FontDb::global().menu_family_list();
let names = lasting_families();
if names.len() < 3 {
return;
}
@@ -135,7 +144,7 @@ fn recent_section_rebuilds_and_arrows_skip_its_headings() {
#[test]
fn recent_fonts_obey_search_and_favorite_filters() {
let names = vectorcraft_text::FontDb::global().menu_family_list();
let names = lasting_families();
if names.len() < 3 {
return;
}
@@ -176,7 +185,7 @@ fn recent_fonts_obey_search_and_favorite_filters() {
#[test]
fn opening_on_another_font_keeps_the_recent_section_visible() {
let names = vectorcraft_text::FontDb::global().menu_family_list();
let names = lasting_families();
let Some(current) = names.last() else { return };
let recent = vec![names[0].clone()];
let ctx = egui::Context::default();
@@ -244,7 +253,7 @@ fn the_wheel_steps_one_family_per_notch_and_stops_at_the_ends() {
/// others in the database's order, under the favourites (and other) filters.
#[test]
fn the_wheel_follows_the_menus_order_and_filters() {
let names = vectorcraft_text::FontDb::global().menu_family_list();
let names = lasting_families();
if names.len() < 3 {
return;
}
@@ -770,8 +779,9 @@ fn the_variable_filter_lists_only_variable_families() {
assert_eq!(frame(&mut st, vec![], &favorites).0, [TWO_AXIS_FAMILY]);
st.favorites_only = false;
// Off again: every family is listed.
let lasting = lasting_families();
let again = click(&mut st, &favorites);
assert!(!st.variable_only);
assert_eq!(again, frame(&mut st, vec![], &[]).0);
assert!(lasting.iter().all(|f| has(&again, f)), "{again:?}");
assert!(has(&again, TWO_AXIS_FAMILY) && has(&again, "Source Sans 3") && has(&again, "JetBrains Mono"), "{again:?}");
}
+44 -41
View File
@@ -683,48 +683,51 @@ fn the_app_bar_hides_its_menus_with_the_mac_menu_bar() {
/// answers, the menus are as before and work again.
#[test]
fn the_menu_bar_is_inert_while_a_file_dialog_is_open() {
let mut m = Mac::new(true);
m.app.services.dialogs_are_sheets = true;
let (shown, _) = crate::tests_picks::off_the_ui_thread(&mut m.app.services);
m.app.run("shape.rectangle", json!({"x": 200, "y": 150, "width": 20, "height": 20})).unwrap();
m.app.run("select.none", json!({})).unwrap();
m.frame(vec![]);
let rows = |bar: &MenuBar| bar.items().iter().map(|it| (it.command, it.params.clone(), it.enabled)).collect::<Vec<_>>();
let before = m.fake.last();
let system = [native_menu::HIDE, native_menu::HIDE_OTHERS, native_menu::MINIMIZE];
assert!(system.iter().all(|c| find(&before, c).enabled));
assert!(m.app.run("file.open", json!({})).is_err());
assert!(m.app.file_dialog_open());
m.frame(vec![]);
let inert = m.fake.last();
for it in inert.items() {
let kept = it.command.is_some_and(|c| system.contains(&c));
assert_eq!(it.enabled, kept, "{:?} {} while the dialog is open", it.command, it.label);
}
// A click that raced the menu going inert isn't run; Minimize is.
let rulers = (m.app.ui.view.rulers, find(&before, "view.rulers").clone());
m.fake.report(native_menu::Event::Click(rulers.1.clone()));
m.frame(vec![]);
assert_eq!(m.app.ui.view.rulers, rulers.0);
m.fake.report(native_menu::Event::Click(find(&inert, native_menu::MINIMIZE).clone()));
assert!(m.frame(vec![]).viewport_output[&egui::ViewportId::ROOT].commands.contains(&egui::ViewportCommand::Minimized(true)));
// A key equivalent that raced it doesn't reach egui.
let mut k = crate::shortcuts::parse("Cmd+A").unwrap();
k.modifiers.mac_cmd = k.modifiers.command;
m.fake.report(native_menu::Event::Key(k));
let mut raw = egui::RawInput::default();
m.app.raw_input_hook(&m.ctx, &mut raw);
assert!(!raw.events.iter().any(|e| matches!(e, Event::Key { .. })), "{:?}", raw.events);
m.key_equivalent("Cmd+A");
assert_eq!(m.selected(), 0, "⌘A selected nothing");
// Cancelled: the menus are as before, and work again.
shown.answer(&[]);
m.frame(vec![]);
m.frame(vec![]);
assert!(!m.app.file_dialog_open());
// Every row from before is back as it was (tests running alongside may add plug-in rows).
let after = rows(&m.fake.last());
assert!(rows(&before).iter().all(|r| after.contains(r)), "the menus are as before");
// The menus read before the dialog and after it are compared, so the whole run is undisturbed:
// a test running alongside can add or remove a composite font or a plug-in in between.
let (mut m, (before, after, rulers)) = undisturbed(|m| {
m.app.services.dialogs_are_sheets = true;
let (shown, _) = crate::tests_picks::off_the_ui_thread(&mut m.app.services);
m.app.run("shape.rectangle", json!({"x": 200, "y": 150, "width": 20, "height": 20})).unwrap();
m.app.run("select.none", json!({})).unwrap();
m.frame(vec![]);
let before = m.fake.last();
let system = [native_menu::HIDE, native_menu::HIDE_OTHERS, native_menu::MINIMIZE];
assert!(system.iter().all(|c| find(&before, c).enabled));
assert!(m.app.run("file.open", json!({})).is_err());
assert!(m.app.file_dialog_open());
m.frame(vec![]);
let inert = m.fake.last();
for it in inert.items() {
let kept = it.command.is_some_and(|c| system.contains(&c));
assert_eq!(it.enabled, kept, "{:?} {} while the dialog is open", it.command, it.label);
}
// A click that raced the menu going inert isn't run; Minimize is.
let rulers = (m.app.ui.view.rulers, find(&before, "view.rulers").clone());
m.fake.report(native_menu::Event::Click(rulers.1.clone()));
m.frame(vec![]);
assert_eq!(m.app.ui.view.rulers, rulers.0);
m.fake.report(native_menu::Event::Click(find(&inert, native_menu::MINIMIZE).clone()));
assert!(m.frame(vec![]).viewport_output[&egui::ViewportId::ROOT].commands.contains(&egui::ViewportCommand::Minimized(true)));
// A key equivalent that raced it doesn't reach egui.
let mut k = crate::shortcuts::parse("Cmd+A").unwrap();
k.modifiers.mac_cmd = k.modifiers.command;
m.fake.report(native_menu::Event::Key(k));
let mut raw = egui::RawInput::default();
m.app.raw_input_hook(&m.ctx, &mut raw);
assert!(!raw.events.iter().any(|e| matches!(e, Event::Key { .. })), "{:?}", raw.events);
m.key_equivalent("Cmd+A");
assert_eq!(m.selected(), 0, "⌘A selected nothing");
// Cancelled: the menus are as before, and work again.
shown.answer(&[]);
m.frame(vec![]);
m.frame(vec![]);
assert!(!m.app.file_dialog_open());
(rows(&before), rows(&m.fake.last()), rulers)
});
// Every row from before is back as it was.
assert!(before.iter().all(|r| after.contains(r)), "the menus are as before");
m.fake.report(native_menu::Event::Click(rulers.1));
m.frame(vec![]);
assert_eq!(m.app.ui.view.rulers, !rulers.0);