mod helpers;
use helpers::{NOTO_SANS, Typesetter, make_typesetter};
use text_document::TextDocument;
fn layout_md(md: &str) -> Typesetter {
let doc = TextDocument::new();
let op = doc.set_markdown(md).expect("markdown parses");
op.wait().expect("markdown op completes");
let flow = doc.snapshot_flow();
let mut ts = make_typesetter();
ts.set_viewport(800.0, 600.0);
ts.layout_full(&flow);
ts
}
fn assert_caret_x_strictly_increases(ts: &Typesetter, text: &str, label: &str) {
let mut prev_x = f32::NEG_INFINITY;
let char_count = text.chars().count();
for char_pos in 0..=char_count {
let rect = ts.caret_rect(char_pos);
let x = rect[0];
assert!(
x > prev_x - 0.01,
"[{label}] caret x went BACKWARDS at char {char_pos}: \
prev_x={prev_x:.2}, x={x:.2}; em-dash bridge unit confusion?"
);
prev_x = x;
}
}
fn assert_hit_test_round_trips(ts: &Typesetter, text: &str, label: &str) {
let baseline_y = ts.caret_rect(0)[1] + ts.caret_rect(0)[3] / 2.0;
let char_count = text.chars().count();
for char_pos in 0..char_count {
let here = ts.caret_rect(char_pos);
let probe_x = here[0] + 0.5;
let hit = ts
.hit_test(probe_x, baseline_y)
.unwrap_or_else(|| panic!("[{label}] hit_test returned None at char {char_pos}"));
assert_eq!(
hit.position, char_pos,
"[{label}] hit_test probe inside glyph {char_pos} returned {} \
— em-dash byte/char confusion in the bridge?",
hit.position
);
}
}
#[test]
fn em_dash_in_single_fragment_block_round_trips() {
let text = "abc — xyz";
let ts = layout_md(text);
assert_caret_x_strictly_increases(&ts, text, "single-fragment em-dash");
assert_hit_test_round_trips(&ts, text, "single-fragment em-dash");
}
#[test]
fn em_dash_inside_bold_span_round_trips() {
let rendered = "abc — bold — xyz";
let ts = layout_md("abc **— bold —** xyz");
assert_caret_x_strictly_increases(&ts, rendered, "bold em-dash");
assert_hit_test_round_trips(&ts, rendered, "bold em-dash");
}
#[test]
fn em_dash_after_bold_prefix_round_trips() {
let rendered = "a bcd — efg";
let ts = layout_md("**a** bcd — efg");
assert_caret_x_strictly_increases(&ts, rendered, "em-dash after bold");
assert_hit_test_round_trips(&ts, rendered, "em-dash after bold");
}
#[test]
fn curly_quote_and_accent_round_trip() {
let rendered = "It’s café x";
let ts = layout_md("**It’s** café x");
assert_caret_x_strictly_increases(&ts, rendered, "curly-quote / accent");
assert_hit_test_round_trips(&ts, rendered, "curly-quote / accent");
}
#[allow(dead_code)]
fn _silence_unused() {
let _ = NOTO_SANS;
}