import tempfile import unittest import zipfile from pathlib import Path import pptx_image_compress as pic class TestPptxImageCompress(unittest.TestCase): def test_discover_images_filters_extensions(self): with tempfile.TemporaryDirectory() as td: media_dir = Path(td) (media_dir / "a.jpg").write_bytes(b"1") (media_dir / "b.png").write_bytes(b"1") (media_dir / "c.txt").write_bytes(b"1") (media_dir / "d.GIF").write_bytes(b"1") images = pic.discover_images(media_dir) self.assertEqual([p.name for p in images], ["a.jpg", "b.png", "d.GIF"]) def test_image_result_to_log_line(self): image_result = pic.ImageProcessResult( image_name="image1.png", orig_size=1000, chosen_size=800, slide_nr="[1, 2]", ) line = pic.image_result_to_log_line(image_result) self.assertIn("image1.png", line) self.assertIn("[1, 2]", line) self.assertIn("20.0", line) def test_process_image_file_replaces_when_smaller(self): with tempfile.TemporaryDirectory() as td: root = Path(td) img = root / "image1.png" img.write_bytes(b"A" * 100) scratch = root / "scratch" def fake_compressor(original: Path, out_dir: Path, caesium_threads: int | None, quality: int, min_savings: str): out_dir.mkdir(parents=True, exist_ok=True) out = out_dir / original.name out.write_bytes(b"B" * 40) return out result = pic.process_image_file( idx=1, img_path=img, scratch_dir=scratch, image_to_slides={"image1.png": [1]}, caesium_threads=1, quality=90, min_savings="2%", compressor=fake_compressor, ) self.assertEqual(result.chosen_size, 40) self.assertEqual(img.stat().st_size, 40) self.assertEqual(result.slide_nr, "[1]") def test_process_image_file_keeps_original_when_bigger(self): with tempfile.TemporaryDirectory() as td: root = Path(td) img = root / "image1.png" img.write_bytes(b"A" * 100) scratch = root / "scratch" def fake_compressor(original: Path, out_dir: Path, caesium_threads: int | None, quality: int, min_savings: str): out_dir.mkdir(parents=True, exist_ok=True) out = out_dir / original.name out.write_bytes(b"B" * 120) return out result = pic.process_image_file( idx=1, img_path=img, scratch_dir=scratch, image_to_slides={}, caesium_threads=1, quality=90, min_savings="2%", compressor=fake_compressor, ) self.assertEqual(result.chosen_size, 100) self.assertEqual(img.stat().st_size, 100) self.assertEqual(result.slide_nr, "NOT_USED") def test_process_single_deck_with_injected_compressor(self): with tempfile.TemporaryDirectory() as td: root = Path(td) input_pptx = root / "input.pptx" output_pptx = root / "output.pptx" source_tree = root / "src" rels_dir = source_tree / "ppt" / "slides" / "_rels" media_dir = source_tree / "ppt" / "media" rels_dir.mkdir(parents=True, exist_ok=True) media_dir.mkdir(parents=True, exist_ok=True) rels_xml = ( "" "" "" "" ) (rels_dir / "slide1.xml.rels").write_text(rels_xml, encoding="utf-8") (media_dir / "image1.png").write_bytes(b"A" * 100) with zipfile.ZipFile(input_pptx, "w", compression=zipfile.ZIP_DEFLATED) as z: for p in source_tree.rglob("*"): if p.is_file(): z.write(p, arcname=str(p.relative_to(source_tree))) def fake_compressor(original: Path, out_dir: Path, caesium_threads: int | None, quality: int, min_savings: str): out_dir.mkdir(parents=True, exist_ok=True) out = out_dir / original.name out.write_bytes(b"B" * 50) return out result = pic.process_single_deck( input_pptx=input_pptx, output_pptx=output_pptx, threads=2, quality=90, min_savings="2%", compressor=fake_compressor, ) self.assertTrue(result.ok) self.assertEqual(result.error, None) self.assertTrue(output_pptx.exists()) self.assertIsNotNone(result.log_file) with zipfile.ZipFile(output_pptx, "r") as z: out_image = z.read("ppt/media/image1.png") self.assertEqual(len(out_image), 50) log_file = result.log_file if log_file is None: self.fail("log_file should not be None") log_text = Path(log_file).read_text(encoding="utf-8") self.assertIn("image1.png", log_text) self.assertIn("[1]", log_text) if __name__ == "__main__": unittest.main()