from __future__ import annotations import subprocess import sys import tempfile import unittest from pathlib import Path from unittest.mock import patch sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from tools.office_to_pdf import OfficeToPdfTool from tools import office_to_pdf as office_module _ALL_FORMATS = frozenset({ ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ods", ".ppt", ".pptx", ".odp", }) class TestOfficeToPdfTool(unittest.TestCase): def _tool(self, root: Path, task: Path) -> OfficeToPdfTool: return OfficeToPdfTool(base_dir=task, user_root=root) def test_converts_container_path_on_host_and_publishes_requested_output(self): with tempfile.TemporaryDirectory() as td: root = Path(td) task = root / "task" task.mkdir() (task / "source.docx").write_bytes(b"docx") def fake_run(cmd, **kwargs): outdir = Path(cmd[cmd.index("--outdir") + 1]) (outdir / "source.pdf").write_bytes(b"%PDF-1.4 test") return subprocess.CompletedProcess(cmd, 0, b"", b"") with patch( "tools.office_to_pdf.office_supported_suffixes", return_value=_ALL_FORMATS ), patch("tools.office_to_pdf.find_soffice", return_value="soffice"), patch( "tools.office_to_pdf.subprocess.run", side_effect=fake_run ): result = self._tool(root, task).execute( source="task/source.docx", output="task/converted/final.pdf", ) out = task / "converted" / "final.pdf" self.assertEqual(out.read_bytes(), b"%PDF-1.4 test") self.assertIn("[OK] PDF created: task/converted/final.pdf", result) def test_rejects_source_outside_user_workspace(self): with tempfile.TemporaryDirectory() as td: root = Path(td) / "user" task = root / "task" task.mkdir(parents=True) result = self._tool(root, task).execute(source="../../outside.docx") self.assertIn("[Error] source path out of user workspace", result) def test_rejects_non_office_source(self): with tempfile.TemporaryDirectory() as td: root = Path(td) task = root / "task" task.mkdir() (task / "notes.md").write_text("x", encoding="utf-8") result = self._tool(root, task).execute(source="notes.md") self.assertIn("[Error] unsupported Office format", result) def test_reports_missing_writer_component_before_conversion(self): with tempfile.TemporaryDirectory() as td: root = Path(td) task = root / "task" task.mkdir() (task / "legacy.doc").write_bytes(b"doc") with patch( "tools.office_to_pdf.office_supported_suffixes", return_value=frozenset({".ppt", ".pptx", ".odp"}), ), patch("tools.office_to_pdf.subprocess.run") as run: tool = self._tool(root, task) result = tool.execute(source="legacy.doc") self.assertIn("lacks the Writer component", result) self.assertIn("PPT", tool.description) self.assertNotIn("DOC,", tool.description) run.assert_not_called() def test_debian_component_detection_limits_advertised_formats(self): office_module.office_supported_suffixes.cache_clear() try: with patch("tools.office_to_pdf.find_soffice", return_value="/usr/bin/soffice"), patch( "tools.office_to_pdf._debian_office_families", return_value=frozenset({"Impress"}), ): supported = office_module.office_supported_suffixes() self.assertEqual(supported, frozenset({".ppt", ".pptx", ".odp"})) finally: office_module.office_supported_suffixes.cache_clear() if __name__ == "__main__": unittest.main()