Skip to content

Commit a8b8acf

Browse files
tests/live: Enhance PDF signing tests with additional cases
- Added tests for new and existing signature type literals to ensure consistent behavior across sync and async API clients. - Introduced logo opacity bounds tests to validate edge case constraints for this field. - Implemented invalid configuration tests for unsupported signature types and logo opacity values. - Refactored reusable components: - `SIGNATURE_TYPES`, `LOGO_OPACITY_BOUNDS`, and `INVALID_LOGO_OPACITY_VALUES` for parametrized test cases. - `_to_json_string` utility function for consistent JSON encoding. Assisted-by: Codex
1 parent 0c9f076 commit a8b8acf

2 files changed

Lines changed: 597 additions & 0 deletions

File tree

tests/live/test_live_sign_pdf.py

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
from __future__ import annotations
22

33
import pytest
4+
from pydantic_core import to_json
45

56
from pdfrest import AsyncPdfRestClient, PdfRestApiError, PdfRestClient
67
from pdfrest.models import PdfRestFile
78

89
from ..resources import get_test_resource_path
910

11+
SIGNATURE_TYPES = (
12+
pytest.param("new", id="new"),
13+
pytest.param("existing", id="existing"),
14+
)
15+
16+
LOGO_OPACITY_BOUNDS = (
17+
pytest.param((0.01, "min"), id="min"),
18+
pytest.param((1.0, "max"), id="max"),
19+
)
20+
21+
INVALID_LOGO_OPACITY_VALUES = (
22+
pytest.param(0.0, id="zero"),
23+
pytest.param(1.1, id="above-max"),
24+
)
25+
26+
27+
def _to_json_string(value: object) -> str:
28+
return to_json(value).decode("utf-8")
29+
1030

1131
def make_signature_location() -> dict[str, dict[str, int] | int]:
1232
return {
@@ -169,6 +189,97 @@ def test_live_sign_pdf_with_existing_signature_field(
169189
assert str(first_response.output_file.id) in existing_response.input_ids
170190

171191

192+
@pytest.mark.parametrize("signature_type", SIGNATURE_TYPES)
193+
def test_live_sign_pdf_signature_type_literals(
194+
pdfrest_api_key: str,
195+
pdfrest_live_base_url: str,
196+
uploaded_pdf_for_signing: PdfRestFile,
197+
uploaded_pfx_credential: PdfRestFile,
198+
uploaded_passphrase: PdfRestFile,
199+
signature_type: str,
200+
) -> None:
201+
with PdfRestClient(
202+
api_key=pdfrest_api_key,
203+
base_url=pdfrest_live_base_url,
204+
) as client:
205+
if signature_type == "new":
206+
response = client.sign_pdf(
207+
uploaded_pdf_for_signing,
208+
signature_configuration={
209+
"type": "new",
210+
"name": "live-sign-literal-new",
211+
"location": make_signature_location(),
212+
},
213+
credentials={
214+
"pfx": uploaded_pfx_credential,
215+
"passphrase": uploaded_passphrase,
216+
},
217+
output="live-sign-literal-new",
218+
)
219+
else:
220+
signature_name = "live-sign-literal-existing"
221+
prepared = client.sign_pdf(
222+
uploaded_pdf_for_signing,
223+
signature_configuration={
224+
"type": "new",
225+
"name": signature_name,
226+
"location": make_signature_location(),
227+
},
228+
credentials={
229+
"pfx": uploaded_pfx_credential,
230+
"passphrase": uploaded_passphrase,
231+
},
232+
output="live-sign-literal-existing-prep",
233+
)
234+
response = client.sign_pdf(
235+
prepared.output_file,
236+
signature_configuration={"type": "existing", "name": signature_name},
237+
credentials={
238+
"pfx": uploaded_pfx_credential,
239+
"passphrase": uploaded_passphrase,
240+
},
241+
output="live-sign-literal-existing",
242+
)
243+
244+
assert response.output_file.type == "application/pdf"
245+
assert str(response.output_file.id) in str(response.output_file.url)
246+
247+
248+
@pytest.mark.parametrize("logo_opacity_case", LOGO_OPACITY_BOUNDS)
249+
def test_live_sign_pdf_logo_opacity_bounds(
250+
pdfrest_api_key: str,
251+
pdfrest_live_base_url: str,
252+
uploaded_pdf_for_signing: PdfRestFile,
253+
uploaded_certificate: PdfRestFile,
254+
uploaded_private_key: PdfRestFile,
255+
uploaded_logo: PdfRestFile,
256+
logo_opacity_case: tuple[float, str],
257+
) -> None:
258+
logo_opacity, case_label = logo_opacity_case
259+
with PdfRestClient(
260+
api_key=pdfrest_api_key,
261+
base_url=pdfrest_live_base_url,
262+
) as client:
263+
response = client.sign_pdf(
264+
uploaded_pdf_for_signing,
265+
signature_configuration={
266+
"type": "new",
267+
"name": f"live-logo-opacity-{case_label}",
268+
"logo_opacity": logo_opacity,
269+
"location": make_signature_location(),
270+
},
271+
credentials={
272+
"certificate": uploaded_certificate,
273+
"private_key": uploaded_private_key,
274+
},
275+
logo=uploaded_logo,
276+
output=f"live-logo-opacity-{case_label}",
277+
)
278+
279+
assert response.output_file.type == "application/pdf"
280+
assert uploaded_logo.id in response.input_ids
281+
282+
172283
@pytest.mark.asyncio
173284
async def test_live_async_sign_pdf_with_certificate(
174285
pdfrest_api_key: str,
@@ -204,6 +315,99 @@ async def test_live_async_sign_pdf_with_certificate(
204315
assert uploaded_logo.id in response.input_ids
205316

206317

318+
@pytest.mark.asyncio
319+
@pytest.mark.parametrize("signature_type", SIGNATURE_TYPES)
320+
async def test_live_async_sign_pdf_signature_type_literals(
321+
pdfrest_api_key: str,
322+
pdfrest_live_base_url: str,
323+
uploaded_pdf_for_signing: PdfRestFile,
324+
uploaded_pfx_credential: PdfRestFile,
325+
uploaded_passphrase: PdfRestFile,
326+
signature_type: str,
327+
) -> None:
328+
async with AsyncPdfRestClient(
329+
api_key=pdfrest_api_key,
330+
base_url=pdfrest_live_base_url,
331+
) as client:
332+
if signature_type == "new":
333+
response = await client.sign_pdf(
334+
uploaded_pdf_for_signing,
335+
signature_configuration={
336+
"type": "new",
337+
"name": "live-async-sign-literal-new",
338+
"location": make_signature_location(),
339+
},
340+
credentials={
341+
"pfx": uploaded_pfx_credential,
342+
"passphrase": uploaded_passphrase,
343+
},
344+
output="live-async-sign-literal-new",
345+
)
346+
else:
347+
signature_name = "live-async-sign-literal-existing"
348+
prepared = await client.sign_pdf(
349+
uploaded_pdf_for_signing,
350+
signature_configuration={
351+
"type": "new",
352+
"name": signature_name,
353+
"location": make_signature_location(),
354+
},
355+
credentials={
356+
"pfx": uploaded_pfx_credential,
357+
"passphrase": uploaded_passphrase,
358+
},
359+
output="live-async-sign-literal-existing-prep",
360+
)
361+
response = await client.sign_pdf(
362+
prepared.output_file,
363+
signature_configuration={"type": "existing", "name": signature_name},
364+
credentials={
365+
"pfx": uploaded_pfx_credential,
366+
"passphrase": uploaded_passphrase,
367+
},
368+
output="live-async-sign-literal-existing",
369+
)
370+
371+
assert response.output_file.type == "application/pdf"
372+
assert str(response.output_file.id) in str(response.output_file.url)
373+
374+
375+
@pytest.mark.asyncio
376+
@pytest.mark.parametrize("logo_opacity_case", LOGO_OPACITY_BOUNDS)
377+
async def test_live_async_sign_pdf_logo_opacity_bounds(
378+
pdfrest_api_key: str,
379+
pdfrest_live_base_url: str,
380+
uploaded_pdf_for_signing: PdfRestFile,
381+
uploaded_certificate: PdfRestFile,
382+
uploaded_private_key: PdfRestFile,
383+
uploaded_logo: PdfRestFile,
384+
logo_opacity_case: tuple[float, str],
385+
) -> None:
386+
logo_opacity, case_label = logo_opacity_case
387+
async with AsyncPdfRestClient(
388+
api_key=pdfrest_api_key,
389+
base_url=pdfrest_live_base_url,
390+
) as client:
391+
response = await client.sign_pdf(
392+
uploaded_pdf_for_signing,
393+
signature_configuration={
394+
"type": "new",
395+
"name": f"live-async-logo-opacity-{case_label}",
396+
"logo_opacity": logo_opacity,
397+
"location": make_signature_location(),
398+
},
399+
credentials={
400+
"certificate": uploaded_certificate,
401+
"private_key": uploaded_private_key,
402+
},
403+
logo=uploaded_logo,
404+
output=f"live-async-logo-opacity-{case_label}",
405+
)
406+
407+
assert response.output_file.type == "application/pdf"
408+
assert uploaded_logo.id in response.input_ids
409+
410+
207411
def test_live_sign_pdf_invalid_signature_configuration(
208412
pdfrest_api_key: str,
209413
pdfrest_live_base_url: str,
@@ -235,6 +439,76 @@ def test_live_sign_pdf_invalid_signature_configuration(
235439
)
236440

237441

442+
def test_live_sign_pdf_invalid_signature_type_literal(
443+
pdfrest_api_key: str,
444+
pdfrest_live_base_url: str,
445+
uploaded_pdf_for_signing: PdfRestFile,
446+
uploaded_pfx_credential: PdfRestFile,
447+
uploaded_passphrase: PdfRestFile,
448+
) -> None:
449+
with (
450+
PdfRestClient(
451+
api_key=pdfrest_api_key,
452+
base_url=pdfrest_live_base_url,
453+
) as client,
454+
pytest.raises(PdfRestApiError, match=r"(?i)signature|type|formatted"),
455+
):
456+
client.sign_pdf(
457+
uploaded_pdf_for_signing,
458+
signature_configuration={
459+
"type": "new",
460+
"location": make_signature_location(),
461+
},
462+
credentials={
463+
"pfx": uploaded_pfx_credential,
464+
"passphrase": uploaded_passphrase,
465+
},
466+
extra_body={
467+
"signature_configuration": _to_json_string(
468+
{"type": "unexpected", "location": make_signature_location()}
469+
)
470+
},
471+
)
472+
473+
474+
@pytest.mark.parametrize("invalid_logo_opacity", INVALID_LOGO_OPACITY_VALUES)
475+
def test_live_sign_pdf_invalid_logo_opacity(
476+
pdfrest_api_key: str,
477+
pdfrest_live_base_url: str,
478+
uploaded_pdf_for_signing: PdfRestFile,
479+
uploaded_pfx_credential: PdfRestFile,
480+
uploaded_passphrase: PdfRestFile,
481+
invalid_logo_opacity: float,
482+
) -> None:
483+
with (
484+
PdfRestClient(
485+
api_key=pdfrest_api_key,
486+
base_url=pdfrest_live_base_url,
487+
) as client,
488+
pytest.raises(PdfRestApiError, match=r"(?i)logo_opacity|opacity|formatted"),
489+
):
490+
client.sign_pdf(
491+
uploaded_pdf_for_signing,
492+
signature_configuration={
493+
"type": "new",
494+
"location": make_signature_location(),
495+
},
496+
credentials={
497+
"pfx": uploaded_pfx_credential,
498+
"passphrase": uploaded_passphrase,
499+
},
500+
extra_body={
501+
"signature_configuration": _to_json_string(
502+
{
503+
"type": "new",
504+
"location": make_signature_location(),
505+
"logo_opacity": invalid_logo_opacity,
506+
}
507+
)
508+
},
509+
)
510+
511+
238512
@pytest.mark.asyncio
239513
async def test_live_async_sign_pdf_invalid_signature_configuration(
240514
pdfrest_api_key: str,
@@ -263,3 +537,73 @@ async def test_live_async_sign_pdf_invalid_signature_configuration(
263537
},
264538
extra_body={"signature_configuration": "not-json"},
265539
)
540+
541+
542+
@pytest.mark.asyncio
543+
async def test_live_async_sign_pdf_invalid_signature_type_literal(
544+
pdfrest_api_key: str,
545+
pdfrest_live_base_url: str,
546+
uploaded_pdf_for_signing: PdfRestFile,
547+
uploaded_pfx_credential: PdfRestFile,
548+
uploaded_passphrase: PdfRestFile,
549+
) -> None:
550+
async with AsyncPdfRestClient(
551+
api_key=pdfrest_api_key,
552+
base_url=pdfrest_live_base_url,
553+
) as client:
554+
with pytest.raises(PdfRestApiError, match=r"(?i)signature|type|formatted"):
555+
await client.sign_pdf(
556+
uploaded_pdf_for_signing,
557+
signature_configuration={
558+
"type": "new",
559+
"location": make_signature_location(),
560+
},
561+
credentials={
562+
"pfx": uploaded_pfx_credential,
563+
"passphrase": uploaded_passphrase,
564+
},
565+
extra_body={
566+
"signature_configuration": _to_json_string(
567+
{"type": "unexpected", "location": make_signature_location()}
568+
)
569+
},
570+
)
571+
572+
573+
@pytest.mark.asyncio
574+
@pytest.mark.parametrize("invalid_logo_opacity", INVALID_LOGO_OPACITY_VALUES)
575+
async def test_live_async_sign_pdf_invalid_logo_opacity(
576+
pdfrest_api_key: str,
577+
pdfrest_live_base_url: str,
578+
uploaded_pdf_for_signing: PdfRestFile,
579+
uploaded_pfx_credential: PdfRestFile,
580+
uploaded_passphrase: PdfRestFile,
581+
invalid_logo_opacity: float,
582+
) -> None:
583+
async with AsyncPdfRestClient(
584+
api_key=pdfrest_api_key,
585+
base_url=pdfrest_live_base_url,
586+
) as client:
587+
with pytest.raises(
588+
PdfRestApiError, match=r"(?i)logo_opacity|opacity|formatted"
589+
):
590+
await client.sign_pdf(
591+
uploaded_pdf_for_signing,
592+
signature_configuration={
593+
"type": "new",
594+
"location": make_signature_location(),
595+
},
596+
credentials={
597+
"pfx": uploaded_pfx_credential,
598+
"passphrase": uploaded_passphrase,
599+
},
600+
extra_body={
601+
"signature_configuration": _to_json_string(
602+
{
603+
"type": "new",
604+
"location": make_signature_location(),
605+
"logo_opacity": invalid_logo_opacity,
606+
}
607+
)
608+
},
609+
)

0 commit comments

Comments
 (0)