From 0f126b75c3d2e1973972716af94c5174ea5bfe3c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 6 Jul 2026 07:54:57 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95:=20SUMM?= =?UTF-8?q?ARY=20=EC=A4=84=EC=9D=B4=20skipped=5Fexisting=EC=9D=84=20conver?= =?UTF-8?q?ted=EB=A1=9C=20=EC=98=A4=EC=A7=91=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit main()의 실행 요약 줄은 converted 개수를 `len(results) - len(failed)`로 계산해, 이미 존재하는 출력을 재사용한 `skipped_existing` 결과까지 "converted"에 포함시켰다. 재실행 시 실제 변환이 0건이어도 모든 파일이 변환된 것처럼 보고되는 오집계다. converted / skipped_existing / failed_or_too_large를 각 상태별로 분리 집계하도록 수정했다. 종료 코드 로직(실패가 있으면 1)은 변경 없음. failing 테스트를 먼저 추가해 오집계(converted=2)를 증명한 뒤 수정했다. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CJRVbDrp1vGYkJgNHMGPpG --- media_shrinker.py | 5 ++++- tests/test_media_shrinker.py | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/media_shrinker.py b/media_shrinker.py index d72a8d5..aad901b 100644 --- a/media_shrinker.py +++ b/media_shrinker.py @@ -1349,6 +1349,8 @@ def main(argv: list[str] | None = None) -> int: ) ) write_report(results, report_path) + converted = [result for result in results if result.status == "converted"] + skipped = [result for result in results if result.status == "skipped_existing"] failed = [ result for result in results @@ -1356,7 +1358,8 @@ def main(argv: list[str] | None = None) -> int: ] print(f"REPORT\t{report_path}") print( - f"SUMMARY\tconverted={len(results) - len(failed)}\tfailed_or_too_large={len(failed)}" + f"SUMMARY\tconverted={len(converted)}\tskipped_existing={len(skipped)}" + f"\tfailed_or_too_large={len(failed)}" ) return 1 if failed else 0 diff --git a/tests/test_media_shrinker.py b/tests/test_media_shrinker.py index 0ab2397..a3f9abd 100644 --- a/tests/test_media_shrinker.py +++ b/tests/test_media_shrinker.py @@ -1303,6 +1303,49 @@ def test_main_execute_returns_failure_when_any_result_failed(self) -> None: self.assertEqual(rc, 1) + def test_main_summary_does_not_count_skipped_existing_as_converted(self) -> None: + import contextlib + import io + + converted = media_shrinker.ConversionResult( + source_path=Path("/scan/a.wav"), + output_path=Path("/scan/out/a.flac"), + status="converted", + original_size_bytes=4, + output_size_bytes=2, + strategy="flac-lossless", + ) + skipped = media_shrinker.ConversionResult( + source_path=Path("/scan/b.wav"), + output_path=Path("/scan/out/b.flac"), + status="skipped_existing", + original_size_bytes=4, + output_size_bytes=2, + strategy="existing", + ) + + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) + (root / "a.wav").write_bytes(b"1234") + (root / "b.wav").write_bytes(b"1234") + buffer = io.StringIO() + with patch( + "media_shrinker._execute_conversions", + return_value=[converted, skipped], + ), contextlib.redirect_stdout(buffer): + rc = media_shrinker.main([str(root), "--execute"]) + + summary_line = next( + line + for line in buffer.getvalue().splitlines() + if line.startswith("SUMMARY") + ) + self.assertEqual(rc, 0) + # Only one file was actually converted; the other reused an existing + # output, so it must not inflate the converted count. + self.assertIn("converted=1", summary_line) + self.assertIn("skipped_existing=1", summary_line) + def test_execute_conversions_records_success_and_failure(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: root = Path(temp_dir)