"""Tests for should_produce_archive().""" from __future__ import annotations from pathlib import Path from typing import TYPE_CHECKING from unittest.mock import MagicMock import pytest from documents.consumer import should_produce_archive if TYPE_CHECKING: from pytest_mock import MockerFixture def _parser_instance( *, can_produce: bool = True, requires_rendition: bool = False, ) -> MagicMock: """Return a mock parser instance with the given capability flags.""" instance = MagicMock() instance.can_produce_archive = can_produce instance.requires_pdf_rendition = requires_rendition return instance @pytest.fixture() def null_app_config(mocker) -> MagicMock: """Mock ApplicationConfiguration with all fields None → falls back to Django settings.""" return mocker.MagicMock( output_type=None, pages=None, language=None, mode=None, archive_file_generation=None, image_dpi=None, unpaper_clean=None, deskew=None, rotate_pages=None, rotate_pages_threshold=None, max_image_pixels=None, color_conversion_strategy=None, user_args=None, ) @pytest.fixture(autouse=True) def patch_app_config(mocker, null_app_config): """Patch BaseConfig._get_config_instance for all tests in this module.""" mocker.patch( "paperless.config.BaseConfig._get_config_instance", return_value=null_app_config, ) class TestShouldProduceArchive: @pytest.mark.parametrize( ("generation", "can_produce", "requires_rendition", "mime", "expected"), [ pytest.param( "never", True, False, "application/pdf", False, id="never-returns-false", ), pytest.param( "always", True, False, "application/pdf", True, id="always-returns-true", ), pytest.param( "never", True, True, "application/pdf", True, id="requires-rendition-overrides-never", ), pytest.param( "always", False, False, "text/plain", False, id="cannot-produce-overrides-always", ), pytest.param( "always", False, True, "application/pdf", True, id="requires-rendition-wins-even-if-cannot-produce", ), pytest.param( "auto", True, False, "image/tiff", True, id="auto-image-returns-true", ), pytest.param( "auto", True, False, "message/rfc822", False, id="auto-non-pdf-non-image-returns-false", ), ], ) def test_generation_setting( self, settings, generation: str, can_produce: bool, # noqa: FBT001 requires_rendition: bool, # noqa: FBT001 mime: str, expected: bool, # noqa: FBT001 ) -> None: settings.ARCHIVE_FILE_GENERATION = generation parser = _parser_instance( can_produce=can_produce, requires_rendition=requires_rendition, ) assert should_produce_archive(parser, mime, Path("/tmp/doc")) is expected @pytest.mark.parametrize( ("born_digital", "expected"), [ pytest.param(True, False, id="born-digital-skips-archive"), pytest.param(False, True, id="not-born-digital-produces-archive"), ], ) def test_auto_pdf_archive_decision( self, mocker: MockerFixture, settings, born_digital: bool, # noqa: FBT001 expected: bool, # noqa: FBT001 ) -> None: """Archive decision tracks pdf_born_digital_text()'s verdict exactly. should_produce_archive() defers entirely to pdf_born_digital_text() for the has-real-text decision, so both callers of that predicate (this function and RasterisedDocumentParser.parse()) always agree. """ settings.ARCHIVE_FILE_GENERATION = "auto" mocker.patch( "documents.consumer.pdf_born_digital_text", return_value=("some text", born_digital), ) parser = _parser_instance(can_produce=True, requires_rendition=False) assert ( should_produce_archive(parser, "application/pdf", Path("/tmp/doc.pdf")) is expected )