refactor(ui-egui): move dialogs_insert tests to dialogs_insert/tests.rs

This commit is contained in:
aiongg
2026-10-26 21:16:48 +00:00
parent 188f379b85
commit ffc631861e
2 changed files with 169 additions and 170 deletions
+1 -170
View File
@@ -1429,173 +1429,4 @@ fn field_options(ui: &mut Ui, f: &mut FieldForm, t: &Tokens) {
}
#[cfg(test)]
mod tests {
use super::*;
fn app() -> WordApp {
WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::from_text("one\ntwo")), Default::default())
}
fn drop_cap_form(a: &mut WordApp) -> Option<DropCapForm> {
a.run("ui.dialog", json!({"name": "dropCap"})).unwrap();
match a.dialog.take() {
Some(crate::dialogs::Dialog::Insert(d)) => match *d {
InsertDialog::DropCap(f) => Some(f),
d => panic!("not drop cap: {d:?}"),
},
_ => None,
}
}
/// #2601: Drop Cap Options… opens on the paragraph's drop cap (the defaults without one:
/// 3 lines, distance 0, the text's font) in the interface unit, and OK runs `insert.dropCap`
/// with the chosen values; it reopens showing them. Choosing the text's own font sends none.
#[test]
fn drop_cap_dialog_prefills_and_applies() {
let mut a = app();
a.run("file.options", json!({"units": "centimeters"})).unwrap();
let mut f = drop_cap_form(&mut a).expect("the dialog");
assert_eq!((f.position.as_str(), f.lines, f.distance), ("none", 3, 0.0));
assert_eq!(f.font, f.text_font, "the text's font");
assert!(!f.font.is_empty());
assert_eq!(f.params(), json!({"position": "none"}));
f.position = "margin".into();
f.lines = 4;
f.distance = 1.0;
a.run("insert.dropCap", f.params()).unwrap();
let props = |a: &WordApp| a.session.doc.body.first().and_then(|b| b.as_para()).map(|p| p.props.clone()).unwrap_or_default();
let p = props(&a);
assert_eq!((p.drop_cap, p.drop_cap_margin, p.drop_cap_font.as_deref()), (Some(4), Some(true), None));
assert!((p.drop_cap_distance.unwrap_or_default() - wordcraft_geom::PT_PER_CM).abs() < 0.01, "1 cm: {:?}", p.drop_cap_distance);
let mut f = drop_cap_form(&mut a).expect("the dialog");
assert_eq!((f.position.as_str(), f.lines), ("margin", 4));
assert!((f.distance - 1.0).abs() < 0.01, "{} cm", f.distance);
f.position = "dropped".into();
f.font = "Liberation Mono".into();
a.run("insert.dropCap", f.params()).unwrap();
let p = props(&a);
assert_eq!((p.drop_cap, p.drop_cap_margin, p.drop_cap_font.as_deref()), (Some(4), None, Some("Liberation Mono")));
assert_eq!(drop_cap_form(&mut a).map(|f| f.font), Some("Liberation Mono".to_string()));
assert_eq!(wordcraft_engine::cmd::insert::drop_cap_state(&a.session).position, "dropped", "the menu checks Dropped");
// Where Word greys Drop Cap out, there is no dialog.
a.run("caret.docEnd", json!({})).unwrap();
a.run("text.newParagraph", json!({})).unwrap();
assert!(drop_cap_form(&mut a).is_none(), "an empty paragraph");
}
/// More Columns: two unequal columns with a line between apply as one undo step.
#[test]
fn columns_dialog_applies_unequal_columns_in_one_step() {
let mut a = app();
a.run("ui.dialog", json!({"name": "columns"})).unwrap();
let Some(crate::dialogs::Dialog::Insert(d)) = a.dialog.take() else { panic!("no dialog") };
let InsertDialog::Columns(mut f) = *d else { panic!("not columns") };
assert_eq!((f.count, f.equal), (1, true));
f.preset("left");
assert_eq!(f.current_preset(), Some("left"));
// Widen the first column: the second gives up the room, the total stays the text width.
if let Some(c) = f.cols.first_mut() {
c.0 += 0.5;
}
f.rebalance(0);
let total: f32 = f.cols.iter().map(|(w, s)| w + s).sum();
assert!((total - f.text_width).abs() < 0.01, "{total} vs {}", f.text_width);
f.separator = true;
let undo_before = a.session.undo_depth();
a.run("layout.columns", f.params()).unwrap();
let c = wordcraft_engine::cmd::page::sect(&a.session).columns;
assert_eq!((c.count, c.separator, c.widths.len()), (2, true, 2));
assert_eq!(a.session.undo_depth(), undo_before + 1, "one undo step");
// The dialog reopens with what was applied.
let again = ColumnsForm::read(&a);
assert!(!again.equal && again.separator && again.cols.len() == 2);
a.run("edit.undo", json!({})).unwrap();
assert_eq!(wordcraft_engine::cmd::page::sect(&a.session).columns.count, 1);
}
/// With text selected, More Columns applies to the selected text by default, as in Word
/// (#2024): the other paragraphs keep one column.
#[test]
fn columns_dialog_applies_to_the_selected_text() {
let mut a = app();
assert!(!ColumnsForm::read(&a).selection, "no selection, no Selected text");
a.run("select.paragraph", json!({})).unwrap();
let mut f = ColumnsForm::read(&a);
assert_eq!((f.selection, f.apply.as_str()), (true, "selection"));
f.preset("two");
a.run("layout.columns", f.params()).unwrap();
let counts: Vec<u32> = a.session.doc.sections().iter().map(|(_, x)| x.columns.count).collect();
assert_eq!(counts, vec![2, 1]);
}
/// The Symbol dialog inserts in the chosen font and remembers the symbol.
#[test]
fn symbol_dialog_inserts_with_its_font() {
let mut a = app();
let mut f = SymbolForm::new(&a, 0);
f.font = "DejaVu Sans".into();
f.selected = Some('\u{2665}');
let p = f.params().unwrap();
assert_eq!(p, json!({"char": "\u{2665}", "font": "DejaVu Sans"}));
a.run("insert.symbol", p).unwrap();
remember_symbol(&mut a, "\u{2665}", "DejaVu Sans");
assert!(a.session.doc.plain_text(wordcraft_doc::StoryRef::Body).starts_with('\u{2665}'));
assert_eq!(a.ui.recent_symbols.first().map(|r| r.font.as_str()), Some("DejaVu Sans"));
assert_eq!(subset_of('\u{2665}'), Some("Miscellaneous Symbols"));
// (normal text) inserts without a font.
f.font.clear();
assert_eq!(f.params().unwrap(), json!({"char": "\u{2665}"}));
}
/// The Field dialog builds the field code from its options.
#[test]
fn field_dialog_builds_the_instruction() {
let a = app();
let mut f = FieldForm::new(&a);
assert_eq!(f.instruction(), r#"DATE \@ "M/d/yyyy" \* MERGEFORMAT"#);
f.date_format = "yyyy-MM-dd".into();
f.preserve = false;
assert_eq!(f.instruction(), r#"DATE \@ "yyyy-MM-dd""#);
f.select("PAGE");
f.number_format = "roman".into();
assert_eq!(f.instruction(), r"PAGE \* roman");
f.select("SEQ");
f.target = "Table".into();
assert_eq!(f.instruction(), r"SEQ Table");
f.select("REF");
f.target = "intro".into();
assert_eq!(f.instruction(), r"REF intro \h");
f.select("STYLEREF");
assert_eq!(f.target, "Heading 1");
f.style_switches = "pl".into();
assert_eq!(f.instruction(), r#"STYLEREF "Heading 1" \l \p"#);
f.select("MERGEFIELD");
f.target = "First Name".into();
assert_eq!(f.params().unwrap(), json!({"instr": r#"MERGEFIELD "First Name""#, "result": "«First Name»"}));
// Field Codes: the typed code wins.
f.codes = true;
f.code = "NUMPAGES \\* Arabic".into();
assert_eq!(f.final_code(), "NUMPAGES \\* Arabic");
f.code = " ".into();
assert!(f.params().is_none());
}
/// The Field dialog lists Word's document information fields, and the counts take a number
/// format.
#[test]
fn field_dialog_lists_the_document_information_fields() {
let listed: Vec<&str> = FIELDS.iter().filter(|(_, cat, _)| *cat == "Document Information").map(|(n, _, _)| *n).collect();
for name in ["COMMENTS", "KEYWORDS", "LASTSAVEDBY", "NUMCHARS", "REVNUM", "SUBJECT"] {
assert!(listed.contains(&name), "{name} in {listed:?}");
}
let a = app();
let mut f = FieldForm::new(&a);
f.select("REVNUM");
f.number_format = "ROMAN".into();
f.preserve = false;
assert_eq!(f.instruction(), r"REVNUM \* ROMAN");
f.select("SUBJECT");
assert_eq!(f.instruction(), "SUBJECT");
}
}
mod tests;
@@ -0,0 +1,168 @@
use super::*;
fn app() -> WordApp {
WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::from_text("one\ntwo")), Default::default())
}
fn drop_cap_form(a: &mut WordApp) -> Option<DropCapForm> {
a.run("ui.dialog", json!({"name": "dropCap"})).unwrap();
match a.dialog.take() {
Some(crate::dialogs::Dialog::Insert(d)) => match *d {
InsertDialog::DropCap(f) => Some(f),
d => panic!("not drop cap: {d:?}"),
},
_ => None,
}
}
/// #2601: Drop Cap Options… opens on the paragraph's drop cap (the defaults without one:
/// 3 lines, distance 0, the text's font) in the interface unit, and OK runs `insert.dropCap`
/// with the chosen values; it reopens showing them. Choosing the text's own font sends none.
#[test]
fn drop_cap_dialog_prefills_and_applies() {
let mut a = app();
a.run("file.options", json!({"units": "centimeters"})).unwrap();
let mut f = drop_cap_form(&mut a).expect("the dialog");
assert_eq!((f.position.as_str(), f.lines, f.distance), ("none", 3, 0.0));
assert_eq!(f.font, f.text_font, "the text's font");
assert!(!f.font.is_empty());
assert_eq!(f.params(), json!({"position": "none"}));
f.position = "margin".into();
f.lines = 4;
f.distance = 1.0;
a.run("insert.dropCap", f.params()).unwrap();
let props = |a: &WordApp| a.session.doc.body.first().and_then(|b| b.as_para()).map(|p| p.props.clone()).unwrap_or_default();
let p = props(&a);
assert_eq!((p.drop_cap, p.drop_cap_margin, p.drop_cap_font.as_deref()), (Some(4), Some(true), None));
assert!((p.drop_cap_distance.unwrap_or_default() - wordcraft_geom::PT_PER_CM).abs() < 0.01, "1 cm: {:?}", p.drop_cap_distance);
let mut f = drop_cap_form(&mut a).expect("the dialog");
assert_eq!((f.position.as_str(), f.lines), ("margin", 4));
assert!((f.distance - 1.0).abs() < 0.01, "{} cm", f.distance);
f.position = "dropped".into();
f.font = "Liberation Mono".into();
a.run("insert.dropCap", f.params()).unwrap();
let p = props(&a);
assert_eq!((p.drop_cap, p.drop_cap_margin, p.drop_cap_font.as_deref()), (Some(4), None, Some("Liberation Mono")));
assert_eq!(drop_cap_form(&mut a).map(|f| f.font), Some("Liberation Mono".to_string()));
assert_eq!(wordcraft_engine::cmd::insert::drop_cap_state(&a.session).position, "dropped", "the menu checks Dropped");
// Where Word greys Drop Cap out, there is no dialog.
a.run("caret.docEnd", json!({})).unwrap();
a.run("text.newParagraph", json!({})).unwrap();
assert!(drop_cap_form(&mut a).is_none(), "an empty paragraph");
}
/// More Columns: two unequal columns with a line between apply as one undo step.
#[test]
fn columns_dialog_applies_unequal_columns_in_one_step() {
let mut a = app();
a.run("ui.dialog", json!({"name": "columns"})).unwrap();
let Some(crate::dialogs::Dialog::Insert(d)) = a.dialog.take() else { panic!("no dialog") };
let InsertDialog::Columns(mut f) = *d else { panic!("not columns") };
assert_eq!((f.count, f.equal), (1, true));
f.preset("left");
assert_eq!(f.current_preset(), Some("left"));
// Widen the first column: the second gives up the room, the total stays the text width.
if let Some(c) = f.cols.first_mut() {
c.0 += 0.5;
}
f.rebalance(0);
let total: f32 = f.cols.iter().map(|(w, s)| w + s).sum();
assert!((total - f.text_width).abs() < 0.01, "{total} vs {}", f.text_width);
f.separator = true;
let undo_before = a.session.undo_depth();
a.run("layout.columns", f.params()).unwrap();
let c = wordcraft_engine::cmd::page::sect(&a.session).columns;
assert_eq!((c.count, c.separator, c.widths.len()), (2, true, 2));
assert_eq!(a.session.undo_depth(), undo_before + 1, "one undo step");
// The dialog reopens with what was applied.
let again = ColumnsForm::read(&a);
assert!(!again.equal && again.separator && again.cols.len() == 2);
a.run("edit.undo", json!({})).unwrap();
assert_eq!(wordcraft_engine::cmd::page::sect(&a.session).columns.count, 1);
}
/// With text selected, More Columns applies to the selected text by default, as in Word
/// (#2024): the other paragraphs keep one column.
#[test]
fn columns_dialog_applies_to_the_selected_text() {
let mut a = app();
assert!(!ColumnsForm::read(&a).selection, "no selection, no Selected text");
a.run("select.paragraph", json!({})).unwrap();
let mut f = ColumnsForm::read(&a);
assert_eq!((f.selection, f.apply.as_str()), (true, "selection"));
f.preset("two");
a.run("layout.columns", f.params()).unwrap();
let counts: Vec<u32> = a.session.doc.sections().iter().map(|(_, x)| x.columns.count).collect();
assert_eq!(counts, vec![2, 1]);
}
/// The Symbol dialog inserts in the chosen font and remembers the symbol.
#[test]
fn symbol_dialog_inserts_with_its_font() {
let mut a = app();
let mut f = SymbolForm::new(&a, 0);
f.font = "DejaVu Sans".into();
f.selected = Some('\u{2665}');
let p = f.params().unwrap();
assert_eq!(p, json!({"char": "\u{2665}", "font": "DejaVu Sans"}));
a.run("insert.symbol", p).unwrap();
remember_symbol(&mut a, "\u{2665}", "DejaVu Sans");
assert!(a.session.doc.plain_text(wordcraft_doc::StoryRef::Body).starts_with('\u{2665}'));
assert_eq!(a.ui.recent_symbols.first().map(|r| r.font.as_str()), Some("DejaVu Sans"));
assert_eq!(subset_of('\u{2665}'), Some("Miscellaneous Symbols"));
// (normal text) inserts without a font.
f.font.clear();
assert_eq!(f.params().unwrap(), json!({"char": "\u{2665}"}));
}
/// The Field dialog builds the field code from its options.
#[test]
fn field_dialog_builds_the_instruction() {
let a = app();
let mut f = FieldForm::new(&a);
assert_eq!(f.instruction(), r#"DATE \@ "M/d/yyyy" \* MERGEFORMAT"#);
f.date_format = "yyyy-MM-dd".into();
f.preserve = false;
assert_eq!(f.instruction(), r#"DATE \@ "yyyy-MM-dd""#);
f.select("PAGE");
f.number_format = "roman".into();
assert_eq!(f.instruction(), r"PAGE \* roman");
f.select("SEQ");
f.target = "Table".into();
assert_eq!(f.instruction(), r"SEQ Table");
f.select("REF");
f.target = "intro".into();
assert_eq!(f.instruction(), r"REF intro \h");
f.select("STYLEREF");
assert_eq!(f.target, "Heading 1");
f.style_switches = "pl".into();
assert_eq!(f.instruction(), r#"STYLEREF "Heading 1" \l \p"#);
f.select("MERGEFIELD");
f.target = "First Name".into();
assert_eq!(f.params().unwrap(), json!({"instr": r#"MERGEFIELD "First Name""#, "result": "«First Name»"}));
// Field Codes: the typed code wins.
f.codes = true;
f.code = "NUMPAGES \\* Arabic".into();
assert_eq!(f.final_code(), "NUMPAGES \\* Arabic");
f.code = " ".into();
assert!(f.params().is_none());
}
/// The Field dialog lists Word's document information fields, and the counts take a number
/// format.
#[test]
fn field_dialog_lists_the_document_information_fields() {
let listed: Vec<&str> = FIELDS.iter().filter(|(_, cat, _)| *cat == "Document Information").map(|(n, _, _)| *n).collect();
for name in ["COMMENTS", "KEYWORDS", "LASTSAVEDBY", "NUMCHARS", "REVNUM", "SUBJECT"] {
assert!(listed.contains(&name), "{name} in {listed:?}");
}
let a = app();
let mut f = FieldForm::new(&a);
f.select("REVNUM");
f.number_format = "ROMAN".into();
f.preserve = false;
assert_eq!(f.instruction(), r"REVNUM \* ROMAN");
f.select("SUBJECT");
assert_eq!(f.instruction(), "SUBJECT");
}