#!/usr/bin/env python3 """ Verify year-based final statistics aggregation in organize.py. Creates test images with different EXIF years (and some without EXIF), runs the organize function, and checks the output summary. """ from __future__ import annotations import sys import tempfile from pathlib import Path from collections import Counter # Make sure we can import organize HERE = Path(__file__).parent.absolute() if str(HERE) not in sys.path: sys.path.insert(0, str(HERE)) from PIL import Image from PIL.ExifTags import Base as ExifBase from organize import organize def _make_image(tmpdir: Path, name: str, year: int | None = None) -> Path: """Create a test image. If *year* is given, embed EXIF DateTimeOriginal.""" img = Image.new("RGB", (16, 16), color="red") path = tmpdir / name if year is not None: exif_data = img.getexif() exif_data[ExifBase.DateTimeOriginal] = f"{year:04d}:06:15 12:00:00" img.save(path, exif=exif_data.tobytes()) else: img.save(path) # no EXIF img.close() return path def test_stats_summary_format() -> None: """Check that the summary section is printed after per-line output.""" import io with tempfile.TemporaryDirectory() as td: tmp = Path(td) # Create images with known years _make_image(tmp, "img_2023.jpg", year=2023) _make_image(tmp, "img_2024a.jpg", year=2024) _make_image(tmp, "img_2024b.jpg", year=2024) _make_image(tmp, "img_2025.jpg", year=2025) _make_image(tmp, "no_exif.jpg", year=None) # skipped in our test # We just check it doesn't crash and returns correct exit # We'll capture stdout to verify the summary old_stdout = sys.stdout captured = io.StringIO() sys.stdout = captured try: organize(tmp, no_color=True) finally: sys.stdout = old_stdout output = captured.getvalue() # Verify the summary section exists assert "=== Year Summary ===" in output, "Year summary header missing" # Verify per-year counts assert "2023: 1 entries" in output, "Year 2023 count wrong" assert "2024: 2 entries" in output, "Year 2024 count wrong" assert "2025: 1 entries" in output, "Year 2025 count wrong" # Verify category counts assert "Total with EXIF date:" in output assert "Total with FS date:" in output assert "Total skipped:" in output # Summary appears after per-line output (no interleaving check via text position) print("test_stats_summary_format: PASS") def test_stats_counts_match() -> None: """Verify that category totals add up correctly.""" with tempfile.TemporaryDirectory() as td: tmp = Path(td) # 3 with EXIF, 1 without (uses FS date via mtime), 1 corrupt (skipped) _make_image(tmp, "a_2022.jpg", year=2022) _make_image(tmp, "b_2023.jpg", year=2023) _make_image(tmp, "c_2024.jpg", year=2024) # Image without EXIF — falls back to FS date img = Image.new("RGB", (8, 8), color="blue") p = tmp / "no_exif.jpg" img.save(p) img.close() # Corrupt file with valid extension — skipped (tmp / "corrupt.jpg").write_text("not an image") old_stdout = sys.stdout captured = io.StringIO() sys.stdout = captured try: organize(tmp, no_color=True) finally: sys.stdout = old_stdout output = captured.getvalue() # Verify counts assert "Total with EXIF date: 3" in output assert "Total with FS date: 1" in output assert "Total skipped: 1" in output assert "Total processed: 5" in output print("test_stats_counts_match: PASS") if __name__ == "__main__": import io test_stats_summary_format() test_stats_counts_match() print("All stats tests passed!")