Skip to content

test(rtl): add generated Arabic fixtures guarding visual-order extraction - #447

Open
mathurshubham wants to merge 1 commit into
firecrawl:mainfrom
mathurshubham:test/rtl-generated-fixtures
Open

test(rtl): add generated Arabic fixtures guarding visual-order extraction#447
mathurshubham wants to merge 1 commit into
firecrawl:mainfrom
mathurshubham:test/rtl-generated-fixtures

Conversation

@mathurshubham

@mathurshubham mathurshubham commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Implements #218: Arabic/RTL regression coverage with fixtures generated at test time — no hosted sample files, no licensing question, and no headless-Chrome dependency in CI.

Why now

#440 just landed geometric visual-order reversal in fix_visual_order_rtl. As #218 points out, RTL bugs are uniquely prone to silent regression: the output looks like text to a reviewer who doesn't read the script, so a revert or refactor that breaks it is invisible in a diff. These tests are the guard.

How the fixtures are generated

Pure Rust, in-test (tests/rtl_generated_tests.rs, no production source touched). make_rtl_pdf(lines, storage) hand-builds a single-page PDF with a byte-accurate xref — the same pattern as the repo's existing make_text_pdf helpers and the same shape as the Hebrew fixtures that landed with #440:

  • A /TrueType font with a /ToUnicode CMap maps single-byte codes to Unicode, so no real Arabic glyph program is embedded.
  • Each token is one Tj with an absolute Tm. Visual-order storage reverses each Arabic run's characters and paints left-to-right (increasing x — the case fix(extract): reverse visual-order RTL text using glyph geometry #440 must reverse). Logical-order storage stores reading order and paints right-to-left (the case fix(extract): reverse visual-order RTL text using glyph geometry #440 must leave alone). Both the geometric vote and restore_embedded_ltr_runs are exercised.
  • Every test word carries a lam-alef pair emitted as a single glyph code mapping to two code points (U+0644 U+0627), covering the multi-character ToUnicode expansion where naive reversal breaks.

Assertions (from #218)

  1. Digit groups survive reordering intact126,248.34 inside an Arabic line must come out unreversed: arabic_visual_order_keeps_digit_group_intact, arabic_logical_order_keeps_digit_group_intact, arabic_digit_group_intact_in_positioned_items.
  2. Multi-char ToUnicode ligature round-triparabic_visual_order_ligature_round_trip, arabic_logical_order_ligature_round_trip.
  3. Negative control — the character-reversed corruptions (مالسلا, مالكلا) must be absent from output: visual_order_negative_control_wrong_output_is_rejected.

Plus visual_and_logical_storage_agree: both storage conventions extract to identical reading order. Both process_pdf_mem (markdown) and extract_text_with_positions_mem (positioned items) are covered.

Revert check

With fix_visual_order_rtl temporarily neutralized (early return), the 4 visual-order tests fail with the expected reversed corruption (e.g. ## لالخ مالسلا مالكلا) while the 3 logical-order/positioned tests still pass — exactly the split the guard should produce. All 7 pass on current main.

Verification

Full cargo test green (1015 lib + 165 integration + 7 new rtl_generated + 3 bin + 2 doc-tests, 0 failures); cargo fmt and cargo clippy -- -D warnings clean.

Out of scope, per the issue discussion: the synthetic wrong-ToUnicode corruption generator (that targets #214's detection feature, not this reversal guard) and Arabic-Indic digit variants (the ASCII digit-group case from the issue is asserted; #440's logic covers both scripts).

Closes #218.


Summary by cubic

Adds generated Arabic/RTL regression tests that synthesize PDFs at test time to guard visual-order text extraction. Prevents silent regressions in fix_visual_order_rtl (#440) without hosting sample files or adding headless browser deps. Closes #218.

  • Review notes
    • Test-only change: new tests/rtl_generated_tests.rs builds single-page PDFs in Rust with a /ToUnicode CMap; exercises both visual and logical storage and restore_embedded_ltr_runs.
    • Assertions per Add RTL/Arabic regression fixtures to CI — generated at test time, nothing to host #218: digit groups (126,248.34) remain unreversed inside RTL lines; lam‑alef (لا) multi-character ToUnicode expansion round-trips; negative control rejects raw reversed forms; both process_pdf_mem and extract_text_with_positions_mem agree; visual and logical storage extract to identical reading order.
    • Guard verified: disabling fix_visual_order_rtl makes visual-order tests fail while logical/positioned tests pass.

Written for commit f856f3f. Summary will update on new commits.

Review in cubic

…tion

There are no Arabic/RTL documents in the test matrix and real ones cannot
be hosted for licensing reasons (issue firecrawl#218). Rather than depend on
headless Chrome in CI, synthesize the PDFs in pure Rust at test time,
reusing the hand-rolled %PDF + ToUnicode CMap approach the repo already
uses for the checked-in Hebrew fixtures from PR firecrawl#440.

The fixtures are the regression guard for firecrawl#440 (visual-order RTL reversal
via glyph geometry): base-alphabet Arabic stored in visual order must
reverse back to logical reading order, while logical-order storage must be
left alone. Both conventions are generated and must extract to the same
logical text. Assertions mirror the three the issue calls out: digit
groups (126,248.34) embedded in an Arabic line survive intact and
unreversed, lam-alef (لا) multi-character ToUnicode expansions round-trip
character-identical, and a negative control rejects the raw stored
(reversed) output so a run of the pipeline without the fix is caught.

Verified the guard fails when fix_visual_order_rtl is neutralized and
passes on current main.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Shadow auto-approve: would auto-approve. Adds generated Arabic/RTL regression tests to guard visual-order text extraction logic. This test-only change synthesizes PDFs in-memory to verify digit preservation and ligature handling without modifying production code.

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant