|
16 | 16 | from pyrit.converter import ConverterResult, PDFConverter |
17 | 17 | from pyrit.memory import DataTypeSerializer |
18 | 18 | from pyrit.models import SeedPrompt |
| 19 | +from pyrit.registry import ConverterRegistry |
19 | 20 |
|
20 | 21 |
|
21 | 22 | @pytest.mark.usefixtures("patch_central_database") |
@@ -648,6 +649,84 @@ def test_identifier_distinguishes_font_color() -> None: |
648 | 649 | assert len({default.hash, red.hash, white.hash}) == 3 |
649 | 650 |
|
650 | 651 |
|
| 652 | +@pytest.mark.usefixtures("patch_central_database") |
| 653 | +def test_identifier_distinguishes_layout() -> None: |
| 654 | + default = PDFConverter().get_identifier() |
| 655 | + narrow = PDFConverter(column_width=80).get_identifier() |
| 656 | + tall = PDFConverter(row_height=20).get_identifier() |
| 657 | + auto_height = PDFConverter(row_height=0).get_identifier() |
| 658 | + |
| 659 | + assert "column_width" not in default.params |
| 660 | + assert "row_height" not in default.params |
| 661 | + assert narrow.params["column_width"] == 80 |
| 662 | + assert tall.params["row_height"] == 20 |
| 663 | + assert auto_height.params["row_height"] == 0 |
| 664 | + assert len({default.hash, narrow.hash, tall.hash, auto_height.hash}) == 4 |
| 665 | + |
| 666 | + |
| 667 | +@pytest.mark.usefixtures("patch_central_database") |
| 668 | +def test_identifier_distinguishes_injection_items(mock_pdf_path: Path) -> None: |
| 669 | + def injecting(text: str) -> PDFConverter: |
| 670 | + return PDFConverter(existing_pdf=mock_pdf_path, injection_items=[{"page": 0, "x": 50, "y": 700, "text": text}]) |
| 671 | + |
| 672 | + first = injecting("first payload") |
| 673 | + second = injecting("second payload") |
| 674 | + |
| 675 | + assert "injection_items_hash" not in PDFConverter(existing_pdf=mock_pdf_path).get_identifier().params |
| 676 | + assert first.get_identifier().hash != second.get_identifier().hash |
| 677 | + assert injecting("first payload").get_identifier().hash == first.get_identifier().hash |
| 678 | + |
| 679 | + # Both configurations get their own default registry name instead of colliding. |
| 680 | + instances = ConverterRegistry().instances |
| 681 | + instances.register(first) |
| 682 | + instances.register(second) |
| 683 | + assert instances.get(second.get_identifier().unique_name) is second |
| 684 | + |
| 685 | + |
| 686 | +@pytest.mark.usefixtures("patch_central_database") |
| 687 | +@pytest.mark.parametrize("text", ["hello", "caf\u00e9"]) |
| 688 | +async def test_identifier_normalizes_injected_byte_text_async(*, mock_pdf_path: Path, text: str) -> None: |
| 689 | + byte_text = text.encode("utf-8") |
| 690 | + converters = [ |
| 691 | + PDFConverter(existing_pdf=mock_pdf_path, injection_items=[{"text": value}]) |
| 692 | + for value in (byte_text, text, str(byte_text)) |
| 693 | + ] |
| 694 | + identifiers = [converter.get_identifier() for converter in converters] |
| 695 | + |
| 696 | + assert identifiers[0].hash == identifiers[1].hash |
| 697 | + assert identifiers[0].hash != identifiers[2].hash |
| 698 | + |
| 699 | + instances = ConverterRegistry().instances |
| 700 | + instances.register(converters[0]) |
| 701 | + instances.register(converters[2]) |
| 702 | + assert instances.get(identifiers[2].unique_name) is converters[2] |
| 703 | + |
| 704 | + for converter, expected in zip(converters, (text, text, str(byte_text)), strict=True): |
| 705 | + result = await converter.convert_async(prompt="") |
| 706 | + assert PdfReader(result.output_text).pages[0].extract_text() == f"Page 1 content\n{expected}\n" |
| 707 | + |
| 708 | + |
| 709 | +@pytest.mark.usefixtures("patch_central_database") |
| 710 | +def test_identifier_rejects_unsupported_injection_values() -> None: |
| 711 | + converter = PDFConverter(injection_items=[{"text": object()}]) |
| 712 | + |
| 713 | + with pytest.raises(TypeError, match="Unsupported injection item value type: object"): |
| 714 | + converter.get_identifier() |
| 715 | + |
| 716 | + |
| 717 | +@pytest.mark.usefixtures("patch_central_database") |
| 718 | +def test_identifier_rejects_invalid_utf8_injection_text() -> None: |
| 719 | + converter = PDFConverter(injection_items=[{"text": b"\xff"}]) |
| 720 | + |
| 721 | + with pytest.raises(UnicodeDecodeError): |
| 722 | + converter.get_identifier() |
| 723 | + |
| 724 | + |
| 725 | +@pytest.mark.usefixtures("patch_central_database") |
| 726 | +def test_identifier_keeps_default_hash() -> None: |
| 727 | + assert PDFConverter().get_identifier().hash == "a05b4cf1482efac3adbc73fd088af40021f1ec3e8f08da575101410595aacf96" |
| 728 | + |
| 729 | + |
651 | 730 | @pytest.mark.usefixtures("patch_central_database") |
652 | 731 | @pytest.mark.parametrize("font_color", [(256, 0, 0), (0, 0), [0, 0, 0]]) |
653 | 732 | def test_init_rejects_invalid_font_color(font_color: Any) -> None: |
|
0 commit comments