Tests: font menu and menu bar tests allow for fonts and plug-ins other tests change

In a full parallel `cargo test -p vectorcraft-ui-egui` run, other tests
add and remove composite fonts in the process-wide font database and
remove plug-ins from the plug-in registry. Two tests failed when that
happened between their reads, and passed when run alone.

- `font_menu::tests::the_scroll_bar_leaves_the_stars_clear` starred
  `FontDb::global().families()`, but the menu lists the composite fonts
  first, so the top rows had no star. The test now turns on the starred
  filter and counts the rows it listed.
- `tests::nativemenu::the_menu_bar_is_inert_while_a_file_dialog_is_open`
  required every menu row from before the dialog to be back afterwards.
  A row may now be missing only when the composite font or plug-in it
  names is gone from the database or the registry.
- Four font menu tests took the first families from
  `menu_family_list()`, which can be a composite font that is removed
  before the frames run. They take them from the families that stay
  listed. The variable-filter test checks that every family listed
  before the click is listed again, instead of comparing two frames.
This commit is contained in:
dotCooCoo
2026-11-12 04:58:20 -08:00
parent 87c0d5cb5e
commit a5d0fe7963
2 changed files with 43 additions and 10 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:?}");
}
+25 -2
View File
@@ -69,6 +69,25 @@ fn find<'a>(bar: &'a MenuBar, command: &str) -> &'a native_menu::Item {
bar.items().into_iter().find(|it| it.command == Some(command)).unwrap_or_else(|| panic!("no {command} item"))
}
/// Is the font or plug-in that an item runs `command` with `params` for gone from the process-wide
/// font database or plug-in registry? A test running alongside can remove a composite font or a
/// plug-in, and the menus then drop its item.
fn source_gone(command: Option<&str>, params: &Value) -> bool {
use vectorcraft_plugins::{PREFIX, effect, export, registry};
let field = |key| params.get(key).and_then(Value::as_str);
let plugin_gone = |id: Option<&str>| id.is_some_and(|id| registry::get(id).is_none());
match command {
Some("text.setStyle") => field("font").is_some_and(|f| !vectorcraft_text::FontDb::global().menu_family_list_now().iter().any(|x| x == f)),
Some("plugin.dialog") => plugin_gone(field("id")),
Some("file.openWith") => plugin_gone(field("importer").and_then(export::plugin_id)),
Some("effect.apply" | "effect.dialog") => plugin_gone(field("effect").and_then(effect::plugin_id)),
Some(c) if vectorcraft_engine::cmd::plugin::is_command_id(c) => {
plugin_gone(c.strip_prefix(PREFIX).and_then(|rest| rest.rsplit_once('.')).map(|(id, _)| id))
}
_ => false,
}
}
#[test]
fn vectorcraft_gets_a_mac_app_menu() {
let bar = bar(&app(true));
@@ -722,9 +741,13 @@ fn the_menu_bar_is_inert_while_a_file_dialog_is_open() {
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).
// Every row from before is back as it was. Tests running alongside may add rows, and may
// remove the composite font or plug-in a row is for.
let after = rows(&m.fake.last());
assert!(rows(&before).iter().all(|r| after.contains(r)), "the menus are as before");
for r in rows(&before) {
let listed = after.iter().any(|a| (a.0, &a.1) == (r.0, &r.1));
assert!(after.contains(&r) || (!listed && source_gone(r.0, &r.1)), "{r:?} is not as before");
}
m.fake.report(native_menu::Event::Click(rulers.1));
m.frame(vec![]);
assert_eq!(m.app.ui.view.rulers, !rulers.0);