use super::super::*;
use super::common::*;
#[test]
fn test_normalize_kangxi_no_radicals() {
let text = "Hello World";
let result = PdfDocument::normalize_kangxi_radicals(text);
assert_eq!(result, text);
}
#[test]
fn test_normalize_kangxi_with_radicals() {
let text = "\u{2F00}";
let result = PdfDocument::normalize_kangxi_radicals(text);
assert_ne!(result, text);
}
#[test]
fn test_normalize_arabic_no_presentation_forms() {
let text = "Hello World";
let result = PdfDocument::normalize_arabic_presentation_forms(text);
assert_eq!(result, text);
}
#[test]
fn test_normalize_arabic_alef_presentation_form() {
let text = "\u{FE8D}";
let result = PdfDocument::normalize_arabic_presentation_forms(text);
assert!(result.contains('\u{0627}'));
}
#[test]
fn test_normalize_arabic_lam_alef_ligature() {
let text = "\u{FEFB}";
let result = PdfDocument::normalize_arabic_presentation_forms(text);
assert!(result.contains('\u{0644}'));
}
#[test]
fn test_reverse_rtl_preshaped_single_span() {
let mut spans = vec![
make_rtl_test_span(
"\u{0629}\u{064A}\u{0628}\u{0631}\u{0639}\u{0644}\u{0627} \
\u{0637}\u{0648}\u{0637}\u{FCCB}\u{0627} \
\u{0639}\u{0627}\u{0648}\u{0646}\u{0627}",
100.0,
700.0,
),
make_rtl_test_span("other content", 100.0, 680.0),
make_rtl_test_span("more content", 100.0, 660.0),
make_rtl_test_span("tail", 100.0, 640.0),
];
PdfDocument::reverse_rtl_visual_order_runs(&mut spans);
assert_eq!(
spans[0].text,
"\u{0627}\u{0646}\u{0648}\u{0627}\u{0639} \
\u{0627}\u{FCCB}\u{0637}\u{0648}\u{0637} \
\u{0627}\u{0644}\u{0639}\u{0631}\u{0628}\u{064A}\u{0629}",
"Pre-shaped Arabic single span must be reversed into reading order"
);
assert_eq!(spans[1].text, "other content");
assert_eq!(spans[2].text, "more content");
assert_eq!(spans[3].text, "tail");
}
#[test]
fn test_reverse_rtl_logical_order_base_arabic_untouched() {
let logical = "\u{0627}\u{0646}\u{0648}\u{0627}\u{0639} \
\u{0627}\u{0644}\u{062E}\u{0637}\u{0648}\u{0637} \
\u{0627}\u{0644}\u{0639}\u{0631}\u{0628}\u{064A}\u{0629}";
let mut spans = vec![
make_rtl_test_span(logical, 100.0, 700.0),
make_rtl_test_span("other content", 100.0, 680.0),
make_rtl_test_span("more content", 100.0, 660.0),
make_rtl_test_span("tail", 100.0, 640.0),
];
PdfDocument::reverse_rtl_visual_order_runs(&mut spans);
assert_eq!(
spans[0].text, logical,
"Logical-order base-Arabic span must NOT be reversed"
);
}
#[test]
fn test_reverse_rtl_short_rtl_span_not_touched_by_pass0() {
let mut spans = vec![
make_rtl_test_span("\u{FB7F}\u{FEB3}", 100.0, 700.0),
make_rtl_test_span("other content", 100.0, 680.0),
make_rtl_test_span("more content", 100.0, 660.0),
make_rtl_test_span("tail", 100.0, 640.0),
];
PdfDocument::reverse_rtl_visual_order_runs(&mut spans);
assert_eq!(spans[0].text, "\u{FB7F}\u{FEB3}");
}
#[test]
fn test_reverse_rtl_pass0_leaves_ltr_alone() {
let mut spans = vec![
make_rtl_test_span("The quick brown fox jumps over", 100.0, 700.0),
make_rtl_test_span("the lazy dog repeatedly.", 100.0, 680.0),
make_rtl_test_span("Latin content here.", 100.0, 660.0),
make_rtl_test_span("Final line.", 100.0, 640.0),
];
let before: Vec<String> = spans.iter().map(|s| s.text.clone()).collect();
PdfDocument::reverse_rtl_visual_order_runs(&mut spans);
let after: Vec<String> = spans.iter().map(|s| s.text.clone()).collect();
assert_eq!(before, after, "Pure-Latin spans must not be reversed by the RTL pass");
}
#[test]
fn test_reverse_rtl_per_word_logical_spans_reorder_not_charflip() {
let mut spans = vec![
make_rtl_test_span("اﻟﻌﺮﺑﻴﺔ", 160.0, 700.0),
make_rtl_test_span(" ", 277.0, 700.0),
make_rtl_test_span("اﳋﻄﻮط", 288.0, 700.0),
make_rtl_test_span(" ", 409.0, 700.0),
make_rtl_test_span("اﻧﻮاع", 420.0, 700.0),
];
PdfDocument::reverse_rtl_visual_order_runs(&mut spans);
let texts: Vec<&str> = spans.iter().map(|s| s.text.as_str()).collect();
assert_eq!(
texts,
vec!["اﻧﻮاع", " ", "اﳋﻄﻮط", " ", "اﻟﻌﺮﺑﻴﺔ"],
"per-word RTL spans must be reordered into logical word order \
without char-flipping (got {texts:?})"
);
}
#[test]
fn test_reverse_rtl_keeping_marks_keeps_diacritics_attached() {
let src = "\u{0642}\u{0650}\u{0637}\u{0651}";
let out = PdfDocument::reverse_rtl_keeping_marks(src);
assert_eq!(out, "\u{0637}\u{0651}\u{0642}\u{0650}");
let chars: Vec<char> = out.chars().collect();
for (i, c) in chars.iter().enumerate() {
if crate::text::rtl_detector::is_rtl_diacritic(*c as u32) {
assert!(
i > 0 && !crate::text::rtl_detector::is_rtl_diacritic(chars[i - 1] as u32),
"diacritic at {i} is detached from its base"
);
}
}
}
#[test]
fn test_push_span_text_bidi_reverses_neutral_span_in_rtl_run() {
let span = make_rtl_test_span(" ,", 270.0, 700.0);
let mut out = String::from("\u{05D4}\u{05D8}\u{05D5}\u{05E8}");
PdfDocument::push_span_text_bidi(&mut out, &span, true);
assert!(out.ends_with(", "), "neutral span not reversed to logical: {out:?}");
assert!(!out.ends_with(" ,"), "visual order leaked into output: {out:?}");
}
#[test]
fn test_push_span_text_bidi_keeps_neutral_span_in_ltr_run() {
let span = make_rtl_test_span(" ,", 270.0, 700.0);
let mut out = String::from("word");
PdfDocument::push_span_text_bidi(&mut out, &span, false);
assert_eq!(out, "word ,", "LTR neutral span must be emitted verbatim");
}
#[test]
fn test_push_span_text_bidi_reverses_neutral_number_keeping_digits() {
let span = make_rtl_test_span("2009,", 270.0, 700.0);
let mut out = String::new();
PdfDocument::push_span_text_bidi(&mut out, &span, true);
assert_eq!(out, ",2009", "neutral+number span: reverse order, keep 2009 forward");
}
#[test]
fn test_push_span_text_bidi_does_not_reverse_multi_number_span() {
let span = make_rtl_test_span("2009-2010", 270.0, 700.0);
let mut out = String::new();
PdfDocument::push_span_text_bidi(&mut out, &span, true);
assert_eq!(out, "2009-2010", "multi-digit-run span must be emitted verbatim");
}
#[test]
fn test_is_reversible_rtl_neutral_span_classification() {
assert!(PdfDocument::is_reversible_rtl_neutral_span(" ,"));
assert!(PdfDocument::is_reversible_rtl_neutral_span(" ."));
assert!(PdfDocument::is_reversible_rtl_neutral_span(". "));
assert!(PdfDocument::is_reversible_rtl_neutral_span(" \u{060C}")); assert!(!PdfDocument::is_reversible_rtl_neutral_span(","));
assert!(!PdfDocument::is_reversible_rtl_neutral_span(" "));
assert!(!PdfDocument::is_reversible_rtl_neutral_span(" 9"));
assert!(!PdfDocument::is_reversible_rtl_neutral_span(" )"));
assert!(!PdfDocument::is_reversible_rtl_neutral_span(" \""));
assert!(!PdfDocument::is_reversible_rtl_neutral_span("a,"));
}
#[test]
fn test_strip_interior_arabic_spaces() {
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{0642}\u{0650} \u{0644}\u{0627}"),
"\u{0642}\u{0650}\u{0644}\u{0627}"
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{0642} \u{0650}\u{0644}"),
"\u{0642}\u{0650}\u{0644}"
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces(" \u{0642}\u{0644} "),
" \u{0642}\u{0644} "
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{05E9} \u{05DC}"),
"\u{05E9} \u{05DC}"
);
assert_eq!(PdfDocument::strip_interior_arabic_spaces("\u{0642} 5"), "\u{0642} 5");
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{0642}\u{0644}"),
"\u{0642}\u{0644}"
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{0628}\u{062D}\u{0631} \u{0645}\u{0627}"),
"\u{0628}\u{062D}\u{0631} \u{0645}\u{0627}"
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{0643}\u{062A}\u{0628} \u{0644}\u{0627}"),
"\u{0643}\u{062A}\u{0628}\u{0644}\u{0627}"
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces("\u{0629} \u{0644}\u{064A} \u{0635} \u{0641}"),
"\u{0629}\u{0644}\u{064A}\u{0635}\u{0641}"
);
assert_eq!(
PdfDocument::strip_interior_arabic_spaces(
"\u{062F}\u{0627}\u{0631} \u{0633}\u{0644}\u{0627}\u{0645} \u{0628}\u{0644}\u{062F}"
),
"\u{062F}\u{0627}\u{0631} \u{0633}\u{0644}\u{0627}\u{0645} \u{0628}\u{0644}\u{062F}"
);
}
#[test]
fn test_mcid_run_is_pure_rtl() {
let pure_rtl = vec![
make_rtl_test_span("\u{05E9}\u{05DC}\u{05D5}\u{05DD}", 100.0, 700.0),
make_rtl_test_span(" ,", 90.0, 700.0),
];
assert!(PdfDocument::mcid_run_is_pure_rtl(&pure_rtl));
let mixed = vec![
make_rtl_test_span("\u{05E9}\u{05DC}\u{05D5}\u{05DD}", 100.0, 700.0),
make_rtl_test_span("World", 200.0, 700.0),
];
assert!(!PdfDocument::mcid_run_is_pure_rtl(&mixed));
let ltr = vec![make_rtl_test_span("Hello", 100.0, 700.0)];
assert!(!PdfDocument::mcid_run_is_pure_rtl(<r));
}
#[test]
fn test_normalize_arabic_hamza() {
let result = PdfDocument::normalize_arabic_presentation_forms("\u{FE80}");
assert!(result.contains('\u{0621}'));
}
#[test]
fn test_normalize_arabic_beh() {
let result = PdfDocument::normalize_arabic_presentation_forms("\u{FE8F}");
assert!(result.contains('\u{0628}'));
}
#[test]
fn test_normalize_arabic_teh_marbuta() {
let result = PdfDocument::normalize_arabic_presentation_forms("\u{FE93}");
assert!(result.contains('\u{0629}'));
}
#[test]
fn test_normalize_arabic_dal_to_yeh_range() {
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEA9}").contains('\u{062F}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEAB}").contains('\u{0630}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEAD}").contains('\u{0631}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEAF}").contains('\u{0632}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEB1}").contains('\u{0633}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEB5}").contains('\u{0634}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEB9}").contains('\u{0635}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEBD}").contains('\u{0636}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEC1}").contains('\u{0637}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEC5}").contains('\u{0638}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEC9}").contains('\u{0639}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FECD}").contains('\u{063A}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FED1}").contains('\u{0641}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FED5}").contains('\u{0642}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FED9}").contains('\u{0643}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEDD}").contains('\u{0644}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEE1}").contains('\u{0645}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEE5}").contains('\u{0646}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEE9}").contains('\u{0647}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEED}").contains('\u{0648}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEEF}").contains('\u{0649}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEF1}").contains('\u{064A}'));
}
#[test]
fn test_normalize_arabic_diacritics() {
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE70}").contains('\u{064B}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE71}").contains('\u{064B}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE72}").contains('\u{064C}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE74}").contains('\u{064D}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE76}").contains('\u{064E}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE77}").contains('\u{064E}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE78}").contains('\u{064F}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE79}").contains('\u{064F}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE7A}").contains('\u{0650}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE7B}").contains('\u{0650}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE7C}").contains('\u{0651}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE7D}").contains('\u{0651}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE7E}").contains('\u{0652}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE7F}").contains('\u{0652}'));
}
#[test]
fn test_normalize_arabic_lam_alef_ligatures() {
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEF5}").contains('\u{0644}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEF7}").contains('\u{0644}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEF9}").contains('\u{0644}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FEFB}").contains('\u{0644}'));
}
#[test]
fn test_normalize_arabic_alef_variants() {
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE81}").contains('\u{0622}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE83}").contains('\u{0623}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE85}").contains('\u{0624}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE87}").contains('\u{0625}'));
assert!(PdfDocument::normalize_arabic_presentation_forms("\u{FE89}").contains('\u{0626}'));
}
#[test]
fn test_normalize_arabic_mixed_text() {
let result = PdfDocument::normalize_arabic_presentation_forms("Hello \u{FE8D} World");
assert!(result.contains("Hello"));
assert!(result.contains("World"));
assert!(result.contains('\u{0627}'));
}