from ingestion.extract.spans import classify_column, _sort_blocks_reading_order def _block(x0, y0, x1, y1): return {"bbox": (x0, y0, x1, y1)} def testclassify_column_left(): assert classify_column((35.0, 100.0, 280.0, 120.0)) == "left" def testclassify_column_right(): assert classify_column((299.0, 100.0, 553.0, 120.0)) == "right" def testclassify_column_full_width_header(): assert classify_column((35.0, 34.0, 552.0, 48.0)) == "full_width" def testclassify_column_none_bbox_is_unknown(): assert classify_column(None) == "unknown" def test_confirmed_real_oxymetazolin_page_reversed_order_is_corrected(): # exact bboxes from physical page 1100 (the OXYBUTYNIN/OXYMETAZOLIN # boundary — see spans.py module docstring): PyMuPDF's raw block order # is [header, right x7, left x8], right column before left. An earlier # version of this module trusted that raw order, silently attributing # OXYMETAZOLIN's "Chống chỉ định" (right column) to the still-open # OXYBUTYNIN monograph. Confirmed via a whole-book cli validate run, # a whole-document cross-tool character-diff, and rendering the page. raw_order = [ _block(34.96, 34.39, 552.10, 47.72), # 0: full_width header _block(299.39, 60.46, 553.72, 121.96), # 1: right _block(299.39, 124.33, 553.72, 368.94), # 2: right _block(299.39, 371.31, 553.72, 408.39), # 3: right _block(35.43, 60.77, 289.77, 330.56), # 4: left (Xử trí: ...) _block(35.43, 379.21, 231.23, 391.87), # 5: left (Tên chung quốc tế) ] sorted_blocks = _sort_blocks_reading_order(raw_order) columns_in_order = [classify_column(b["bbox"]) for b in sorted_blocks] assert columns_in_order == ["full_width", "left", "left", "right", "right", "right"] def test_already_correct_order_is_left_unchanged_in_content(): blocks = [ _block(35.0, 60.0, 280.0, 100.0), # left _block(35.0, 110.0, 280.0, 150.0), # left, further down _block(299.0, 60.0, 553.0, 100.0), # right ] sorted_blocks = _sort_blocks_reading_order(blocks) assert sorted_blocks == blocks def test_a_narrow_box_between_the_columns_belongs_to_the_right_column(): """The two tolerance bands overlap between x=288 and x=319. Testing left first put everything in that strip in the left column. It is invisible for a full-width block and wrong for a narrow one: a single 4pt glyph at x=315 on physical page 714 was classified left, so the 'ổ' missing from "Độ ổn định" could not be matched to its own line and the corruption survived the repair. """ assert classify_column((313.7, 506.2, 317.8, 514.8)) == "right" assert classify_column((35.4, 500.0, 289.7, 510.0)) == "left" # a box that lands in neither range still resolves by tolerance assert classify_column((300.0, 500.0, 305.0, 510.0)) == "left"