Part of #394: headless tests for Hyphenation › Exceptions UI and layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Fabio William Conceição 2026-10-09 20:23:32 +01:00
parent c9ba5db4fb
commit 4f9b292213
3 changed files with 53 additions and 3 deletions

View File

@ -186,14 +186,20 @@ thread_local! {
static TEST_OVERRIDE: std::cell::RefCell<Option<Exceptions>> = const { std::cell::RefCell::new(None) };
}
/// Run `f` with Preferences › Hyphenation › Exceptions applied on this thread only (tests).
#[cfg(test)]
pub(crate) fn with_hyphenation_exceptions_for_test(source: &str, f: impl FnOnce()) {
TEST_OVERRIDE.with(|c| *c.borrow_mut() = Some(parse_list(source)));
f();
TEST_OVERRIDE.with(|c| *c.borrow_mut() = None);
}
#[cfg(test)]
mod tests {
use super::*;
fn with_exceptions(source: &str, f: impl FnOnce()) {
TEST_OVERRIDE.with(|c| *c.borrow_mut() = Some(parse_list(source)));
f();
TEST_OVERRIDE.with(|c| *c.borrow_mut() = None);
with_hyphenation_exceptions_for_test(source, f);
}
/// #394 Preferences › Hyphenation › Exceptions contract (parse + override).

View File

@ -415,6 +415,26 @@ fn hyphenated_layout_adds_hyphens() {
}
}
/// Preferences › Hyphenation › Exceptions (#394): listing a word stops the layout from breaking it.
#[test]
fn hyphenation_exceptions_keep_listed_words_whole_in_layout() {
// Same copy as `hyphenated_layout_adds_hyphens` (known to produce soft hyphens at 120pt width).
let text = "Extraordinarily comprehensive typographical considerations notwithstanding everything.";
let mut t = area(text, style(14.0), Rect::new(0.0, 0.0, 120.0, 600.0), Justify::Left);
t.para.hyphenate = true;
let with_breaks = layout(db(), &t);
let hyphens = |l: &TextLayout| l.glyphs.iter().filter(|g| g.len == 0).count();
assert!(hyphens(&with_breaks) > 0, "pattern produces soft hyphens");
hyphen::with_hyphenation_exceptions_for_test(
"extraordinarily, comprehensive, typographical, considerations, notwithstanding, everything",
|| {
let blocked = layout(db(), &t);
assert_eq!(hyphens(&blocked), 0, "every long word listed: no soft hyphens");
assert!(blocked.lines.len() >= with_breaks.lines.len());
},
);
}
#[test]
fn soft_hyphen_is_invisible_mid_line() {
let l = layout(db(), &TextObject::point(Point::ZERO, "co\u{00AD}operate", style(20.0)));

View File

@ -577,4 +577,28 @@ mod tests {
assert!(PREF_SPECS.iter().any(|s| s.category == *c));
}
}
/// Preferences › Hyphenation › Exceptions (#394): OK on the dialog pushes the list into the
/// hyphenator the same way `prefs.set` does (no need to drive the live Preferences window).
#[test]
fn hyphenation_exceptions_dialog_ok_reaches_the_hyphenator() {
struct Clear;
impl Drop for Clear {
fn drop(&mut self) {
vectorcraft_text::set_hyphenation_exceptions("");
}
}
let _clear = Clear;
let mut a = app();
open(&mut a, Some("Hyphenation"));
let d = a.ui.dialog.as_mut().unwrap();
assert_eq!(d.str("__category"), "Hyphenation");
d.fields.insert("hyphenationExceptions".into(), json!("typography, hap-pen"));
confirm(&mut a).unwrap();
assert!(a.ui.dialog.is_none());
assert_eq!(a.session.prefs.hyphenation_exceptions, "typography, hap-pen");
assert_eq!(vectorcraft_text::hyphenation_exceptions(), "typography, hap-pen");
assert!(vectorcraft_text::hyphen::hyphen_points("typography").is_empty());
assert_eq!(vectorcraft_text::hyphen::hyphen_points("happen"), vec![3]);
}
}