Skip to content

Commit 08f4aad

Browse files
Add tests for PNG conversion with page ranges and invalid inputs
- More thoroughly test page ranges in light of new changes. - Introduced new live tests to validate PNG conversion with various page range formats, including valid and invalid cases. - Added coverage for page range parsing and error scenarios. - Updated fixtures to support new tests with a 20-page PDF resource. Assisted-by: Codex
1 parent 65c8c7c commit 08f4aad

3 files changed

Lines changed: 197 additions & 8 deletions

File tree

tests/live/test_live_graphic_conversions.py

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from __future__ import annotations
22

3-
from collections.abc import Iterable
3+
from collections.abc import Iterable, Sequence
44
from typing import Any, NamedTuple, get_args
55

66
import pytest
77

88
from pdfrest import PdfRestApiError, PdfRestClient
9+
from pdfrest.models import PdfRestFile
910
from pdfrest.models._internal import (
1011
BasePdfRestGraphicPayload,
1112
BmpPdfRestPayload,
@@ -107,6 +108,19 @@ def _invalid_smoothing_cases() -> list[Any]:
107108
return cases
108109

109110

111+
@pytest.fixture(scope="module")
112+
def uploaded_20_page_pdf(
113+
pdfrest_api_key: str,
114+
pdfrest_live_base_url: str,
115+
) -> PdfRestFile:
116+
resource = get_test_resource_path("20-pages.pdf")
117+
with PdfRestClient(
118+
api_key=pdfrest_api_key,
119+
base_url=pdfrest_live_base_url,
120+
) as client:
121+
return client.files.create_from_paths([resource])[0]
122+
123+
110124
@pytest.mark.parametrize(
111125
("_endpoint_label", "spec", "color_model"),
112126
_valid_color_cases(),
@@ -253,3 +267,130 @@ def test_live_graphic_invalid_smoothing(
253267
smoothing="none",
254268
extra_body={"smoothing": invalid_smoothing},
255269
)
270+
271+
272+
@pytest.mark.parametrize(
273+
("page_range", "expect_success"),
274+
[
275+
pytest.param("5", True, id="single"),
276+
pytest.param("3-7", True, id="ascending-range"),
277+
pytest.param("last", True, id="last"),
278+
pytest.param("1-last", True, id="entire-document"),
279+
pytest.param(["1", "3", "5-7"], True, id="list-mixed"),
280+
],
281+
)
282+
def test_live_png_page_range_variants(
283+
pdfrest_api_key: str,
284+
pdfrest_live_base_url: str,
285+
uploaded_20_page_pdf: PdfRestFile,
286+
page_range: Any,
287+
expect_success: bool,
288+
request: pytest.FixtureRequest,
289+
) -> None:
290+
case_id = request.node.callspec.id
291+
with PdfRestClient(
292+
api_key=pdfrest_api_key,
293+
base_url=pdfrest_live_base_url,
294+
) as client:
295+
info = client.query_pdf_info(uploaded_20_page_pdf)
296+
297+
assert info.page_count == 20
298+
assert str(info.input_id) == str(uploaded_20_page_pdf.id)
299+
assert info.filename is None or info.filename.endswith(".pdf")
300+
301+
if expect_success:
302+
response = client.convert_to_png(
303+
uploaded_20_page_pdf,
304+
output_prefix=f"live-range-{case_id}",
305+
page_range=page_range,
306+
)
307+
308+
expected_pages = _expand_page_selection(page_range, total_pages=20)
309+
assert len(response.output_files) == len(expected_pages)
310+
assert any(
311+
file_info.name.endswith(".png") for file_info in response.output_files
312+
)
313+
assert all(
314+
file_info.type == "image/png" and file_info.size > 0
315+
for file_info in response.output_files
316+
)
317+
assert str(response.input_id) == str(uploaded_20_page_pdf.id)
318+
else:
319+
with pytest.raises(PdfRestApiError):
320+
client.convert_to_png(
321+
uploaded_20_page_pdf,
322+
output_prefix=f"live-range-{case_id}",
323+
extra_body={"page_range": page_range},
324+
)
325+
326+
327+
@pytest.mark.parametrize(
328+
"page_override",
329+
[
330+
pytest.param("0", id="zero"),
331+
pytest.param("last-0", id="range-with-zero"),
332+
pytest.param("7-3", id="descending-range"),
333+
pytest.param("even", id="even"),
334+
pytest.param("odd", id="odd"),
335+
pytest.param("odd,even", id="odd-even"),
336+
],
337+
)
338+
def test_live_png_page_range_invalid_overrides(
339+
pdfrest_api_key: str,
340+
pdfrest_live_base_url: str,
341+
uploaded_20_page_pdf: PdfRestFile,
342+
page_override: str,
343+
request: pytest.FixtureRequest,
344+
) -> None:
345+
case_id = request.node.callspec.id
346+
with (
347+
PdfRestClient(
348+
api_key=pdfrest_api_key,
349+
base_url=pdfrest_live_base_url,
350+
) as client,
351+
pytest.raises(PdfRestApiError),
352+
):
353+
client.convert_to_png(
354+
uploaded_20_page_pdf,
355+
output_prefix=f"live-range-invalid-{case_id}",
356+
page_range="1",
357+
extra_body={"pages": page_override},
358+
)
359+
360+
361+
def _expand_page_selection(
362+
selection: Any,
363+
*,
364+
total_pages: int,
365+
) -> list[int]:
366+
def expand_entry(entry: Any) -> list[int]:
367+
if isinstance(entry, int):
368+
return [entry]
369+
text = str(entry).strip()
370+
lowered = text.lower()
371+
if lowered == "even":
372+
return list(range(2, total_pages + 1, 2))
373+
if lowered == "odd":
374+
return list(range(1, total_pages + 1, 2))
375+
if lowered == "last":
376+
return [total_pages]
377+
if "-" in lowered:
378+
start_raw, end_raw = (part.strip() for part in lowered.split("-", 1))
379+
380+
def resolve(range_token: str) -> int:
381+
return total_pages if range_token == "last" else int(range_token) # noqa: S105
382+
383+
start = resolve(start_raw)
384+
end = resolve(end_raw)
385+
step = 1 if end >= start else -1
386+
return list(range(start, end + step, step))
387+
return [int(text)]
388+
389+
if isinstance(selection, Sequence) and not isinstance(
390+
selection, (str, bytes, bytearray)
391+
):
392+
expanded: list[int] = []
393+
for segment in selection:
394+
expanded.extend(expand_entry(segment))
395+
return expanded
396+
return expand_entry(selection)

tests/resources/20-pages.pdf

21.3 KB
Binary file not shown.

tests/test_graphic_payload_validation.py

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,39 +92,49 @@ def test_graphic_payload_invalid_output_prefix(
9292
[
9393
pytest.param(
9494
"0",
95-
"Page numbers must be greater than or equal to 1.",
95+
"greater than or equal to 1",
9696
id="scalar-zero",
9797
),
9898
pytest.param(
9999
["0"],
100-
"Page numbers must be greater than or equal to 1.",
100+
"greater than or equal to 1",
101101
id="list-zero-string",
102102
),
103103
pytest.param(
104104
[0],
105-
"Page numbers must be greater than or equal to 1.",
105+
"greater than or equal to 1",
106106
id="list-zero-int",
107107
),
108108
pytest.param(
109109
"last-5",
110-
"Page range start must be a page number greater than or equal to 1.",
110+
"unable to parse string as an integer",
111111
id="range-last-to-number",
112112
),
113113
pytest.param(
114114
"3-2",
115-
"Page range end must be greater than or equal to the start.",
115+
"less than or equal to the end page",
116116
id="range-descending",
117117
),
118118
pytest.param(
119119
"foo",
120-
"Page range entries must be positive integers, 'last', or a range like '1-3' or '6-last'.",
120+
"unable to parse string as an integer",
121121
id="scalar-word",
122122
),
123123
pytest.param(
124124
["1", "foo"],
125-
"Page range entries must be positive integers, 'last', or a range like '1-3' or '6-last'.",
125+
"unable to parse string as an integer",
126126
id="list-mixed",
127127
),
128+
pytest.param(
129+
"even",
130+
"unable to parse string as an integer",
131+
id="even",
132+
),
133+
pytest.param(
134+
"odd",
135+
"unable to parse string as an integer",
136+
id="odd",
137+
),
128138
],
129139
)
130140
def test_graphic_payload_invalid_page_range_value(
@@ -139,3 +149,41 @@ def test_graphic_payload_invalid_page_range_value(
139149
"page_range": bad_page_range,
140150
}
141151
)
152+
153+
154+
@pytest.mark.parametrize("payload_model", PAYLOAD_MODELS)
155+
@pytest.mark.parametrize(
156+
("page_range", "expected_message"),
157+
[
158+
pytest.param(
159+
"even",
160+
"unable to parse string as an integer",
161+
id="even",
162+
),
163+
pytest.param(
164+
"odd",
165+
"unable to parse string as an integer",
166+
id="odd",
167+
),
168+
pytest.param(
169+
"5-3",
170+
"less than or equal to the end page",
171+
id="descending",
172+
),
173+
],
174+
)
175+
def test_graphic_payload_rejects_special_ranges(
176+
payload_model: type[BasePdfRestGraphicPayload[Any]],
177+
page_range: str,
178+
expected_message: str,
179+
) -> None:
180+
with pytest.raises(
181+
ValidationError,
182+
match=expected_message,
183+
):
184+
payload_model.model_validate(
185+
{
186+
"files": [make_pdf_file("12345678-1234-4abc-8def-1234567890ab")],
187+
"page_range": page_range,
188+
}
189+
)

0 commit comments

Comments
 (0)