chore: import upstream snapshot with attribution
CI - Python Bindings / sdist (push) Failing after 1s
CI - Python Bindings / Build x86_64-unknown-linux-musl (push) Failing after 1s
CI / fmt (push) Failing after 1s
E2E Output Validation / compare-outputs (push) Failing after 1s
Sync Docs to Developer Hub / sync-docs (push) Failing after 1s
CI - Python Bindings / Build x86_64-unknown-linux-gnu (push) Failing after 1s
CI - WASM Bindings / Build WASM (push) Failing after 0s
CI / clippy (push) Failing after 1s
CI / build-and-test (ubuntu-latest) (push) Failing after 0s
CI - WASM Bindings / Edge runtime PDF parse test (push) Has been skipped
CI - WASM Bindings / Browser PDF parse test (push) Has been skipped
Deploy Demo to GitHub Pages / deploy (push) Failing after 1s
CI / build-docker-image (push) Failing after 3s
CI - Node Bindings / Build darwin-x64 (push) Has been cancelled
CI - Node Bindings / Test win32-x64-msvc (push) Has been cancelled
CI - Node Bindings / Build linux-arm64-gnu (push) Has been cancelled
CI - Node Bindings / Build linux-x64-gnu (push) Has been cancelled
CI - Node Bindings / Build linux-x64-musl (push) Has been cancelled
CI - Node Bindings / Build win32-arm64-msvc (push) Has been cancelled
CI - Node Bindings / Build win32-x64-msvc (push) Has been cancelled
CI - Node Bindings / Test darwin-arm64 (push) Has been cancelled
CI - Node Bindings / Test darwin-x64 (push) Has been cancelled
CI - Node Bindings / Test linux-x64-gnu (push) Has been cancelled
CI - Node Bindings / Test linux-x64-musl (push) Has been cancelled
CI - Node Bindings / Test win32-arm64-msvc (push) Has been cancelled
CI - Python Bindings / Build aarch64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Build x86_64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Build x86_64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Build aarch64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Build aarch64-unknown-linux-gnu (push) Has been cancelled
CI - Node Bindings / Build darwin-arm64 (push) Has been cancelled
CI - Python Bindings / Test x86_64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Test aarch64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Test x86_64-unknown-linux-gnu (push) Has been cancelled
CI - Python Bindings / Test x86_64-unknown-linux-musl (push) Has been cancelled
CI - Python Bindings / Test aarch64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Test x86_64-pc-windows-msvc (push) Has been cancelled
CI / build-and-test (macos-26-intel) (push) Has been cancelled
CI / build-and-test (macos-latest) (push) Has been cancelled
CI / build-and-test (windows-11-arm) (push) Has been cancelled
CI / build-and-test (windows-latest) (push) Has been cancelled
E2E Output Validation / upload-dataset (push) Has been cancelled
CI - Python Bindings / sdist (push) Failing after 1s
CI - Python Bindings / Build x86_64-unknown-linux-musl (push) Failing after 1s
CI / fmt (push) Failing after 1s
E2E Output Validation / compare-outputs (push) Failing after 1s
Sync Docs to Developer Hub / sync-docs (push) Failing after 1s
CI - Python Bindings / Build x86_64-unknown-linux-gnu (push) Failing after 1s
CI - WASM Bindings / Build WASM (push) Failing after 0s
CI / clippy (push) Failing after 1s
CI / build-and-test (ubuntu-latest) (push) Failing after 0s
CI - WASM Bindings / Edge runtime PDF parse test (push) Has been skipped
CI - WASM Bindings / Browser PDF parse test (push) Has been skipped
Deploy Demo to GitHub Pages / deploy (push) Failing after 1s
CI / build-docker-image (push) Failing after 3s
CI - Node Bindings / Build darwin-x64 (push) Has been cancelled
CI - Node Bindings / Test win32-x64-msvc (push) Has been cancelled
CI - Node Bindings / Build linux-arm64-gnu (push) Has been cancelled
CI - Node Bindings / Build linux-x64-gnu (push) Has been cancelled
CI - Node Bindings / Build linux-x64-musl (push) Has been cancelled
CI - Node Bindings / Build win32-arm64-msvc (push) Has been cancelled
CI - Node Bindings / Build win32-x64-msvc (push) Has been cancelled
CI - Node Bindings / Test darwin-arm64 (push) Has been cancelled
CI - Node Bindings / Test darwin-x64 (push) Has been cancelled
CI - Node Bindings / Test linux-x64-gnu (push) Has been cancelled
CI - Node Bindings / Test linux-x64-musl (push) Has been cancelled
CI - Node Bindings / Test win32-arm64-msvc (push) Has been cancelled
CI - Python Bindings / Build aarch64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Build x86_64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Build x86_64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Build aarch64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Build aarch64-unknown-linux-gnu (push) Has been cancelled
CI - Node Bindings / Build darwin-arm64 (push) Has been cancelled
CI - Python Bindings / Test x86_64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Test aarch64-apple-darwin (push) Has been cancelled
CI - Python Bindings / Test x86_64-unknown-linux-gnu (push) Has been cancelled
CI - Python Bindings / Test x86_64-unknown-linux-musl (push) Has been cancelled
CI - Python Bindings / Test aarch64-pc-windows-msvc (push) Has been cancelled
CI - Python Bindings / Test x86_64-pc-windows-msvc (push) Has been cancelled
CI / build-and-test (macos-26-intel) (push) Has been cancelled
CI / build-and-test (macos-latest) (push) Has been cancelled
CI / build-and-test (windows-11-arm) (push) Has been cancelled
CI / build-and-test (windows-latest) (push) Has been cancelled
E2E Output Validation / upload-dataset (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""Shared fixtures for e2e tests."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from liteparse import LiteParse
|
||||
|
||||
# Resolve test-docs relative to the repo root
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
TEST_DOCS = REPO_ROOT / "test-docs"
|
||||
EXPECTED_DATASET = REPO_ROOT / "expected-dataset" / "data"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def parser() -> LiteParse:
|
||||
"""LiteParse instance (auto-detects CLI)."""
|
||||
return LiteParse()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def invoice_pdf() -> Path:
|
||||
"""Path to a small single-page invoice PDF."""
|
||||
p = TEST_DOCS / "invoice.pdf"
|
||||
if not p.exists():
|
||||
pytest.skip(f"Test document not found: {p}")
|
||||
return p
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def two_page_pdf() -> Path:
|
||||
"""Path to a 2-page PDF."""
|
||||
p = EXPECTED_DATASET / "2pages.pdf"
|
||||
if not p.exists():
|
||||
pytest.skip(f"Test document not found: {p}")
|
||||
return p
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def empty_pdf() -> Path:
|
||||
"""Path to an empty PDF."""
|
||||
p = EXPECTED_DATASET / "empty.pdf"
|
||||
if not p.exists():
|
||||
pytest.skip(f"Test document not found: {p}")
|
||||
return p
|
||||
@@ -0,0 +1,88 @@
|
||||
"""E2E tests for LiteParse.batch_parse() — validates Python types match CLI output."""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from liteparse import (
|
||||
BatchResult,
|
||||
LiteParse,
|
||||
OutputFormat,
|
||||
)
|
||||
|
||||
|
||||
class TestBatchParseBasic:
|
||||
"""Basic batch parsing functionality."""
|
||||
|
||||
def test_batch_parse_returns_batch_result(
|
||||
self, parser: LiteParse, invoice_pdf: Path
|
||||
):
|
||||
input_dir = invoice_pdf.parent
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
result = parser.batch_parse(
|
||||
input_dir,
|
||||
tmpdir,
|
||||
ocr_enabled=False,
|
||||
extension_filter=".pdf",
|
||||
)
|
||||
assert isinstance(result, BatchResult)
|
||||
assert result.output_dir == tmpdir
|
||||
|
||||
def test_batch_parse_creates_output_files(
|
||||
self, parser: LiteParse, invoice_pdf: Path
|
||||
):
|
||||
input_dir = invoice_pdf.parent
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
parser.batch_parse(
|
||||
input_dir,
|
||||
tmpdir,
|
||||
output_format=OutputFormat.TEXT,
|
||||
ocr_enabled=False,
|
||||
extension_filter=".pdf",
|
||||
)
|
||||
output_files = list(Path(tmpdir).rglob("*"))
|
||||
# Should have produced at least one output file
|
||||
assert len(output_files) > 0
|
||||
|
||||
def test_batch_parse_json_format(self, parser: LiteParse, invoice_pdf: Path):
|
||||
input_dir = invoice_pdf.parent
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
parser.batch_parse(
|
||||
input_dir,
|
||||
tmpdir,
|
||||
output_format="json",
|
||||
ocr_enabled=False,
|
||||
extension_filter=".pdf",
|
||||
)
|
||||
json_files = list(Path(tmpdir).rglob("*.json"))
|
||||
assert len(json_files) > 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_batch_parse_async(self, parser: LiteParse, invoice_pdf: Path):
|
||||
input_dir = invoice_pdf.parent
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
result = await parser.batch_parse_async(
|
||||
input_dir,
|
||||
tmpdir,
|
||||
output_format="json",
|
||||
ocr_enabled=False,
|
||||
extension_filter=".pdf",
|
||||
)
|
||||
assert isinstance(result, BatchResult)
|
||||
assert result.output_dir == tmpdir
|
||||
|
||||
|
||||
class TestBatchParseErrors:
|
||||
"""Test error handling."""
|
||||
|
||||
def test_input_dir_not_found(self, parser: LiteParse):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
with pytest.raises(FileNotFoundError):
|
||||
parser.batch_parse("/nonexistent/dir", tmpdir)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_input_dir_not_found_async(self, parser: LiteParse):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
with pytest.raises(FileNotFoundError):
|
||||
await parser.batch_parse_async("/nonexistent/dir", tmpdir)
|
||||
@@ -0,0 +1,176 @@
|
||||
"""E2E tests for LiteParse.parse() — validates Python types match CLI output."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from liteparse import (
|
||||
BoundingBox,
|
||||
LiteParse,
|
||||
ParsedPage,
|
||||
ParseError,
|
||||
ParseResult,
|
||||
TextItem,
|
||||
)
|
||||
|
||||
|
||||
class TestParseBasic:
|
||||
"""Basic parse functionality and output structure."""
|
||||
|
||||
def test_parse_returns_parse_result(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
assert isinstance(result, ParseResult)
|
||||
|
||||
def test_parse_result_has_pages(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
assert len(result.pages) > 0
|
||||
assert result.num_pages == len(result.pages)
|
||||
|
||||
def test_parse_result_has_text(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
assert isinstance(result.text, str)
|
||||
assert len(result.text) > 0
|
||||
|
||||
def test_parse_result_has_json(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
assert result.json is not None
|
||||
assert "pages" in result.json
|
||||
|
||||
def test_parse_bytest_input(self, parser: LiteParse, invoice_pdf: Path):
|
||||
file_bytes = invoice_pdf.read_bytes()
|
||||
result = parser.parse(file_bytes)
|
||||
assert result.json is not None
|
||||
assert "pages" in result.json
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_async(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = await parser.parse_async(invoice_pdf)
|
||||
assert result.json is not None
|
||||
assert "pages" in result.json
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_async_bytes_input(self, parser: LiteParse, invoice_pdf: Path):
|
||||
file_bytes = invoice_pdf.read_bytes()
|
||||
result = await parser.parse_async(file_bytes)
|
||||
assert result.json is not None
|
||||
assert "pages" in result.json
|
||||
|
||||
|
||||
class TestParsedPageStructure:
|
||||
"""Validate ParsedPage fields match CLI output."""
|
||||
|
||||
def test_page_fields(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
page = result.pages[0]
|
||||
assert isinstance(page, ParsedPage)
|
||||
assert isinstance(page.pageNum, int)
|
||||
assert page.pageNum >= 1
|
||||
assert isinstance(page.width, (int, float))
|
||||
assert isinstance(page.height, (int, float))
|
||||
assert page.width > 0
|
||||
assert page.height > 0
|
||||
assert isinstance(page.text, str)
|
||||
|
||||
def test_page_has_text_items(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
page = result.pages[0]
|
||||
assert len(page.textItems) > 0
|
||||
|
||||
def test_text_item_fields(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
item = result.pages[0].textItems[0]
|
||||
assert isinstance(item, TextItem)
|
||||
assert isinstance(item.text, str)
|
||||
assert isinstance(item.x, (int, float))
|
||||
assert isinstance(item.y, (int, float))
|
||||
assert isinstance(item.width, (int, float))
|
||||
assert isinstance(item.height, (int, float))
|
||||
# fontName and fontSize may be None or present
|
||||
if item.fontName is not None:
|
||||
assert isinstance(item.fontName, str)
|
||||
if item.fontSize is not None:
|
||||
assert isinstance(item.fontSize, (int, float))
|
||||
|
||||
def test_bounding_box_fields(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False, precise_bounding_box=True)
|
||||
page = result.pages[0]
|
||||
assert len(page.boundingBoxes) > 0
|
||||
bbox = page.boundingBoxes[0]
|
||||
assert isinstance(bbox, BoundingBox)
|
||||
assert isinstance(bbox.x1, (int, float))
|
||||
assert isinstance(bbox.y1, (int, float))
|
||||
assert isinstance(bbox.x2, (int, float))
|
||||
assert isinstance(bbox.y2, (int, float))
|
||||
|
||||
|
||||
class TestParseOptions:
|
||||
"""Test that CLI options are correctly forwarded."""
|
||||
|
||||
def test_target_pages(self, parser: LiteParse, invoice_pdf: Path):
|
||||
# invoice.pdf has 2 pages — parse only page 1
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False, target_pages="1")
|
||||
assert result.num_pages == 1
|
||||
assert result.pages[0].pageNum == 1
|
||||
|
||||
def test_max_pages(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False, max_pages=1)
|
||||
assert result.num_pages == 1
|
||||
|
||||
def test_no_precise_bbox(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(
|
||||
invoice_pdf, ocr_enabled=False, precise_bounding_box=False
|
||||
)
|
||||
assert isinstance(result, ParseResult)
|
||||
# With no precise bbox, boundingBoxes should be empty
|
||||
for page in result.pages:
|
||||
assert len(page.boundingBoxes) == 0
|
||||
|
||||
def test_get_page_helper(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
page1 = result.get_page(1)
|
||||
assert page1 is not None
|
||||
assert page1.pageNum == 1
|
||||
assert result.get_page(999) is None
|
||||
|
||||
def test_multi_page_text_joined(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.parse(invoice_pdf, ocr_enabled=False)
|
||||
assert result.num_pages == 2
|
||||
# result.text should be the join of all page texts
|
||||
expected = "\n\n".join(p.text for p in result.pages)
|
||||
assert result.text == expected
|
||||
|
||||
|
||||
class TestParseErrors:
|
||||
"""Test error handling."""
|
||||
|
||||
def test_file_not_found(self, parser: LiteParse):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
parser.parse("/nonexistent/file.pdf")
|
||||
|
||||
def test_cli_not_found(self):
|
||||
parser = LiteParse(cli_path="/nonexistent/liteparse")
|
||||
# subprocess raises FileNotFoundError when the binary doesn't exist
|
||||
with pytest.raises((ParseError, FileNotFoundError, OSError)):
|
||||
parser.parse(Path(__file__)) # any existing file
|
||||
|
||||
def test_timeout(self, parser: LiteParse, invoice_pdf: Path):
|
||||
# Extremely short timeout should fail
|
||||
with pytest.raises(TimeoutError):
|
||||
parser.parse(invoice_pdf, timeout=0.001)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_file_not_found_async(self, parser: LiteParse):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
await parser.parse_async("/nonexistent/file.pdf")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cli_not_found_async(self):
|
||||
parser = LiteParse(cli_path="/nonexistent/liteparse")
|
||||
# subprocess raises FileNotFoundError when the binary doesn't exist
|
||||
with pytest.raises((ParseError, FileNotFoundError, OSError)):
|
||||
parser.parse(Path(__file__)) # any existing file
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_timeout_async(self, parser: LiteParse, invoice_pdf: Path):
|
||||
with pytest.raises(TimeoutError):
|
||||
await parser.parse_async(invoice_pdf, timeout=0.001)
|
||||
@@ -0,0 +1,102 @@
|
||||
"""E2E tests for LiteParse.screenshot() — validates Python types match CLI output."""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from liteparse import (
|
||||
ImageFormat,
|
||||
LiteParse,
|
||||
ScreenshotBatchResult,
|
||||
ScreenshotResult,
|
||||
)
|
||||
|
||||
|
||||
class TestScreenshotBasic:
|
||||
"""Basic screenshot functionality."""
|
||||
|
||||
def test_screenshot_returns_batch_result(
|
||||
self, parser: LiteParse, invoice_pdf: Path
|
||||
):
|
||||
result = parser.screenshot(invoice_pdf)
|
||||
assert isinstance(result, ScreenshotBatchResult)
|
||||
|
||||
def test_screenshot_has_screenshots(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf)
|
||||
assert len(result) > 0
|
||||
assert len(result.screenshots) > 0
|
||||
|
||||
def test_screenshot_result_fields(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf)
|
||||
ss = result.screenshots[0]
|
||||
assert isinstance(ss, ScreenshotResult)
|
||||
assert isinstance(ss.page_num, int)
|
||||
assert ss.page_num >= 1
|
||||
assert isinstance(ss.image_path, str)
|
||||
assert Path(ss.image_path).exists()
|
||||
|
||||
def test_screenshot_output_dir(self, parser: LiteParse, invoice_pdf: Path):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
result = parser.screenshot(invoice_pdf, output_dir=tmpdir)
|
||||
assert result.output_dir == tmpdir
|
||||
# Files should be in the specified directory
|
||||
for ss in result.screenshots:
|
||||
assert ss.image_path.startswith(tmpdir)
|
||||
|
||||
def test_screenshot_png_format(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf, image_format=ImageFormat.PNG)
|
||||
for ss in result.screenshots:
|
||||
assert ss.image_path.endswith(".png")
|
||||
|
||||
def test_screenshot_jpg_format(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf, image_format="jpg")
|
||||
for ss in result.screenshots:
|
||||
assert ss.image_path.endswith(".jpg")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_screensho_async_basic(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = await parser.screenshot_async(invoice_pdf, image_format="png")
|
||||
assert isinstance(result, ScreenshotBatchResult)
|
||||
assert len(result.screenshots) > 0
|
||||
|
||||
|
||||
class TestScreenshotOptions:
|
||||
"""Test screenshot options are forwarded correctly."""
|
||||
|
||||
def test_target_pages(self, parser: LiteParse, invoice_pdf: Path):
|
||||
# invoice.pdf has 2 pages — screenshot only page 1
|
||||
result = parser.screenshot(invoice_pdf, target_pages="1")
|
||||
assert len(result) == 1
|
||||
assert result.screenshots[0].page_num == 1
|
||||
|
||||
def test_load_bytes(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf, load_bytes=True)
|
||||
for ss in result.screenshots:
|
||||
assert ss.image_bytes is not None
|
||||
assert len(ss.image_bytes) > 0
|
||||
|
||||
def test_no_load_bytes(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf, load_bytes=False)
|
||||
for ss in result.screenshots:
|
||||
assert ss.image_bytes is None
|
||||
|
||||
def test_get_page_helper(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf)
|
||||
page1 = result.get_page(1)
|
||||
assert page1 is not None
|
||||
assert page1.page_num == 1
|
||||
assert result.get_page(999) is None
|
||||
|
||||
def test_iterable(self, parser: LiteParse, invoice_pdf: Path):
|
||||
result = parser.screenshot(invoice_pdf)
|
||||
pages = list(result)
|
||||
assert len(pages) == len(result)
|
||||
|
||||
|
||||
class TestScreenshotErrors:
|
||||
"""Test error handling."""
|
||||
|
||||
def test_file_not_found(self, parser: LiteParse):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
parser.screenshot("/nonexistent/file.pdf")
|
||||
Reference in New Issue
Block a user