From ffdb1e2f36955e50058cd26c7400d44391ce0acc Mon Sep 17 00:00:00 2001 From: longieirl Date: Thu, 9 Apr 2026 20:09:15 +0100 Subject: [PATCH 1/2] fix: address low-priority coverage and config issues #118-#121 --- packages/parser-core/pyproject.toml | 1 + .../services/test_extraction_orchestrator.py | 12 +++ .../test_processor_refactored_methods.py | 100 ++++++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/packages/parser-core/pyproject.toml b/packages/parser-core/pyproject.toml index f9600a9..422a78f 100644 --- a/packages/parser-core/pyproject.toml +++ b/packages/parser-core/pyproject.toml @@ -117,6 +117,7 @@ exclude_lines = [ "raise AssertionError", "raise NotImplementedError", "if __name__ == .__main__.:", + "if TYPE_CHECKING:", ] [tool.mypy] diff --git a/packages/parser-core/tests/services/test_extraction_orchestrator.py b/packages/parser-core/tests/services/test_extraction_orchestrator.py index ef0c047..5e9e32e 100644 --- a/packages/parser-core/tests/services/test_extraction_orchestrator.py +++ b/packages/parser-core/tests/services/test_extraction_orchestrator.py @@ -247,6 +247,18 @@ def test_extraction_orchestrator_does_not_mutate_registry_templates( assert t_with_iban.enabled is True assert t_no_iban.enabled is True + @patch("bankstatements_core.services.extraction_orchestrator.TemplateRegistry") + def test_template_init_failure_falls_back_to_default(self, mock_registry_class): + """ExtractionOrchestrator still constructs when template init raises (#120).""" + mock_registry_class.from_default_config.side_effect = FileNotFoundError( + "template file missing" + ) + # Should not raise — falls back to default (no-template) configuration + orchestrator = ExtractionOrchestrator( + extraction_config=self.extraction_config + ) + assert orchestrator is not None + if __name__ == "__main__": unittest.main() diff --git a/packages/parser-core/tests/test_processor_refactored_methods.py b/packages/parser-core/tests/test_processor_refactored_methods.py index 3fdf497..d9bbdf4 100644 --- a/packages/parser-core/tests/test_processor_refactored_methods.py +++ b/packages/parser-core/tests/test_processor_refactored_methods.py @@ -383,5 +383,105 @@ def test_run_uses_refactored_methods(self, mock_extract): self.assertTrue(csv_path.exists()) +class TestCoverageGaps(unittest.TestCase): + """Tests for previously uncovered branches (issues #118, #119).""" + + def _make_processor(self, tmpdir, **kwargs): + input_dir = Path(tmpdir) / "input" + output_dir = Path(tmpdir) / "output" + input_dir.mkdir(exist_ok=True) + output_dir.mkdir(exist_ok=True) + config = ProcessorConfig( + input_dir=input_dir, + output_dir=output_dir, + extraction=ExtractionConfig(table_top_y=100, table_bottom_y=700), + ) + return BankStatementProcessor(config=config, **kwargs) + + def test_set_duplicate_strategy_stores_strategy(self): + """set_duplicate_strategy() assigns the strategy to _duplicate_strategy (#118).""" + from unittest.mock import MagicMock + + with tempfile.TemporaryDirectory() as tmpdir: + processor = self._make_processor(tmpdir) + new_strategy = MagicMock() + processor.set_duplicate_strategy(new_strategy) + self.assertIs(processor._duplicate_strategy, new_strategy) + + @patch( + "bankstatements_core.services.extraction_orchestrator.extract_tables_from_pdf" + ) + def test_activity_log_called_after_run(self, mock_extract): + """_activity_log.log_processing() is called once after run() (#119 lines 421-422).""" + from unittest.mock import MagicMock + + with tempfile.TemporaryDirectory() as tmpdir: + input_dir = Path(tmpdir) / "input" + output_dir = Path(tmpdir) / "output" + input_dir.mkdir() + output_dir.mkdir() + (input_dir / "test.pdf").write_text("fake", encoding="utf-8") + + mock_log = MagicMock() + config = ProcessorConfig( + input_dir=input_dir, + output_dir=output_dir, + extraction=ExtractionConfig(table_top_y=100, table_bottom_y=700), + ) + processor = BankStatementProcessor(config=config, activity_log=mock_log) + + mock_extract.return_value = ExtractionResult( + transactions=dicts_to_transactions( + [{"Date": "01/01/23", "Details": "Test", "Debit €": "10"}] + ), + page_count=1, + iban=None, + source_file=Path("test.pdf"), + ) + + processor.run() + mock_log.log_processing.assert_called_once() + + @patch( + "bankstatements_core.services.extraction_orchestrator.extract_tables_from_pdf" + ) + def test_template_registry_lookup_on_transaction_group(self, mock_extract): + """Template registry is queried when transactions carry a template_id (#119 lines 469-472).""" + from unittest.mock import MagicMock + + with tempfile.TemporaryDirectory() as tmpdir: + input_dir = Path(tmpdir) / "input" + output_dir = Path(tmpdir) / "output" + input_dir.mkdir() + output_dir.mkdir() + (input_dir / "test.pdf").write_text("fake", encoding="utf-8") + + mock_registry = MagicMock() + mock_registry.get_template.return_value = None + config = ProcessorConfig( + input_dir=input_dir, + output_dir=output_dir, + extraction=ExtractionConfig(table_top_y=100, table_bottom_y=700), + ) + processor = BankStatementProcessor( + config=config, template_registry=mock_registry + ) + + txns = dicts_to_transactions( + [{"Date": "01/01/23", "Details": "Test", "Debit €": "10"}] + ) + txns[0].additional_fields["template_id"] = "aib_ireland" + + mock_extract.return_value = ExtractionResult( + transactions=txns, + page_count=1, + iban=None, + source_file=Path("test.pdf"), + ) + + processor.run() + mock_registry.get_template.assert_called_once_with("aib_ireland") + + if __name__ == "__main__": unittest.main() From a8010e90bbb264c2cbb7ae61b65d08b12b500c22 Mon Sep 17 00:00:00 2001 From: longieirl Date: Thu, 9 Apr 2026 20:12:53 +0100 Subject: [PATCH 2/2] fix: collapse single-arg ExtractionOrchestrator call to satisfy black --- .../tests/services/test_extraction_orchestrator.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/parser-core/tests/services/test_extraction_orchestrator.py b/packages/parser-core/tests/services/test_extraction_orchestrator.py index 5e9e32e..81dfa95 100644 --- a/packages/parser-core/tests/services/test_extraction_orchestrator.py +++ b/packages/parser-core/tests/services/test_extraction_orchestrator.py @@ -254,9 +254,7 @@ def test_template_init_failure_falls_back_to_default(self, mock_registry_class): "template file missing" ) # Should not raise — falls back to default (no-template) configuration - orchestrator = ExtractionOrchestrator( - extraction_config=self.extraction_config - ) + orchestrator = ExtractionOrchestrator(extraction_config=self.extraction_config) assert orchestrator is not None