95 lines
3.2 KiB
Python
95 lines
3.2 KiB
Python
"""Unit tests for DOCX/XLSX writers and validators."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import zipfile
|
|
|
|
import pytest
|
|
from docx import Document
|
|
from openpyxl import load_workbook
|
|
|
|
from app.services.convert.pdf_bridge import PdfDocumentText, PdfPageText, _heuristic_tables
|
|
from app.services.convert.validate import ValidationError, validate_input
|
|
from app.services.convert.writers.docx_writer import _is_heading, build_docx_from_pdf_text
|
|
from app.services.convert.writers.xlsx_writer import build_xlsx_from_pdf_text
|
|
|
|
|
|
def test_heading_heuristic():
|
|
assert _is_heading("CHAPTER 1 INTRODUCTION")
|
|
assert _is_heading("1. Overview")
|
|
assert not _is_heading("This is a long sentence that should not be treated as a heading at all.")
|
|
|
|
|
|
def test_table_heuristic_pipe():
|
|
tables = _heuristic_tables(["Name | Qty", "A | 1", "B | 2"])
|
|
assert len(tables) == 1
|
|
assert tables[0][0] == ["Name", "Qty"]
|
|
assert len(tables[0]) == 3
|
|
|
|
|
|
def test_docx_writer_paragraphs_and_table():
|
|
doc_text = PdfDocumentText(
|
|
page_count=1,
|
|
pages=[
|
|
PdfPageText(
|
|
index=0,
|
|
width=612,
|
|
height=792,
|
|
paragraphs=["TITLE PAGE", "Body paragraph one."],
|
|
tables=[[["H1", "H2"], ["a", "b"]]],
|
|
raw_text="TITLE PAGE\nBody paragraph one.",
|
|
)
|
|
],
|
|
)
|
|
# ``build_docx_from_pdf_text`` is deprecated in favour of
|
|
# ``formatters.docx_formatter``. The legacy entry point still has callers,
|
|
# so it is still tested — but the deprecation notice is part of the
|
|
# contract, not noise: asserting it here means silently dropping the
|
|
# warning (or the function) fails the suite instead of passing quietly.
|
|
with pytest.warns(DeprecationWarning, match="docx_writer.build_docx_from_pdf_text"):
|
|
data = build_docx_from_pdf_text(doc_text)
|
|
with zipfile.ZipFile(io.BytesIO(data)) as zf:
|
|
assert "[Content_Types].xml" in zf.namelist()
|
|
doc = Document(io.BytesIO(data))
|
|
texts = [p.text for p in doc.paragraphs if p.text.strip()]
|
|
assert any("Body paragraph one." in t for t in texts)
|
|
assert len(doc.tables) >= 1
|
|
|
|
|
|
def test_xlsx_writer_cells():
|
|
doc_text = PdfDocumentText(
|
|
page_count=1,
|
|
pages=[
|
|
PdfPageText(
|
|
index=0,
|
|
width=612,
|
|
height=792,
|
|
paragraphs=[],
|
|
tables=[[["Name", "Qty"], ["Apple", "10"]]],
|
|
raw_text="",
|
|
)
|
|
],
|
|
)
|
|
with pytest.warns(DeprecationWarning, match="xlsx_writer.build_xlsx_from_pdf_text"):
|
|
data, warnings = build_xlsx_from_pdf_text(doc_text)
|
|
assert not any("No table" in w for w in warnings)
|
|
wb = load_workbook(io.BytesIO(data))
|
|
ws = wb.active
|
|
assert ws.cell(1, 1).value == "Name"
|
|
assert ws.cell(2, 1).value == "Apple"
|
|
|
|
|
|
def test_validate_rejects_empty_and_docm():
|
|
try:
|
|
validate_input(b"", "a.pdf", "pdf")
|
|
assert False, "expected ValidationError"
|
|
except ValidationError as exc:
|
|
assert "Empty" in str(exc)
|
|
|
|
try:
|
|
validate_input(b"PK", "macro.docm", "docx")
|
|
assert False, "expected ValidationError"
|
|
except ValidationError as exc:
|
|
assert exc.status_code == 415
|