Add JSON report for WCX detection
This commit is contained in:
@ -1,9 +1,12 @@
|
||||
import contextlib
|
||||
import importlib.util
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
SCRIPT_PATH = (
|
||||
@ -413,12 +416,13 @@ class BatchModeTests(unittest.TestCase):
|
||||
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
exit_code = detect_wcx_title.process_batch(
|
||||
files, summary = detect_wcx_title.process_batch(
|
||||
video_files,
|
||||
lambda path: results[path],
|
||||
)
|
||||
|
||||
self.assertEqual(exit_code, 0)
|
||||
self.assertEqual(len(files), 3)
|
||||
self.assertEqual(summary["errors"], 0)
|
||||
self.assertIn("processed: 3", output.getvalue())
|
||||
self.assertIn("wcx: 1", output.getvalue())
|
||||
self.assertIn("uncertain: 1", output.getvalue())
|
||||
@ -438,16 +442,228 @@ class BatchModeTests(unittest.TestCase):
|
||||
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
exit_code = detect_wcx_title.process_batch(
|
||||
files, summary = detect_wcx_title.process_batch(
|
||||
video_files,
|
||||
analyze,
|
||||
)
|
||||
|
||||
self.assertEqual(exit_code, 1)
|
||||
self.assertEqual(summary["errors"], 1)
|
||||
self.assertEqual(files[1]["classification"], "error")
|
||||
self.assertIn("error", output.getvalue())
|
||||
self.assertIn("processed: 2", output.getvalue())
|
||||
self.assertIn("errors: 1", output.getvalue())
|
||||
|
||||
|
||||
class JsonReportTests(unittest.TestCase):
|
||||
def test_report_contains_results_summary_and_sorted_endings(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||
source_directory = Path(temporary_directory)
|
||||
video_files = (
|
||||
source_directory / "a.mp4",
|
||||
source_directory / "b.avi",
|
||||
source_directory / "c.mp4",
|
||||
)
|
||||
results = {
|
||||
video_files[0]: (8.0, 8, "wcx"),
|
||||
video_files[1]: (10.0, 4, "not_wcx"),
|
||||
video_files[2]: (12.0, 7, "uncertain"),
|
||||
}
|
||||
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
files, summary = detect_wcx_title.process_batch(
|
||||
video_files,
|
||||
lambda path: results[path],
|
||||
)
|
||||
|
||||
report = detect_wcx_title.build_json_report(
|
||||
source_directory=source_directory,
|
||||
recursive=False,
|
||||
endings={"mp4", "avi"},
|
||||
summary=summary,
|
||||
files=files,
|
||||
)
|
||||
report_path = (
|
||||
source_directory
|
||||
/ "new-parent"
|
||||
/ "report.json"
|
||||
)
|
||||
detect_wcx_title.write_json_report(
|
||||
report_path,
|
||||
report,
|
||||
)
|
||||
|
||||
self.assertTrue(report_path.parent.is_dir())
|
||||
self.assertTrue(
|
||||
report_path.read_bytes().endswith(b"\n")
|
||||
)
|
||||
with report_path.open(encoding="utf-8") as report_file:
|
||||
loaded = json.load(report_file)
|
||||
|
||||
self.assertEqual(loaded["endings"], ["avi", "mp4"])
|
||||
self.assertEqual(
|
||||
loaded["source_directory"],
|
||||
str(source_directory.resolve()),
|
||||
)
|
||||
self.assertEqual(
|
||||
[item["classification"] for item in loaded["files"]],
|
||||
["wcx", "not_wcx", "uncertain"],
|
||||
)
|
||||
self.assertTrue(
|
||||
all(
|
||||
Path(item["path"]).is_absolute()
|
||||
for item in loaded["files"]
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
loaded["summary"],
|
||||
{
|
||||
"processed": 3,
|
||||
"wcx": 1,
|
||||
"uncertain": 1,
|
||||
"not_wcx": 1,
|
||||
"errors": 0,
|
||||
},
|
||||
)
|
||||
|
||||
def test_report_contains_error_result(self) -> None:
|
||||
video_file = Path("/videos/broken.mp4")
|
||||
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
files, summary = detect_wcx_title.process_batch(
|
||||
(video_file,),
|
||||
lambda _path: (_ for _ in ()).throw(
|
||||
RuntimeError("mock ffmpeg failure")
|
||||
),
|
||||
)
|
||||
|
||||
report = detect_wcx_title.build_json_report(
|
||||
source_directory=Path("/videos"),
|
||||
recursive=False,
|
||||
endings={"mp4"},
|
||||
summary=summary,
|
||||
files=files,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
report["files"],
|
||||
[
|
||||
{
|
||||
"path": str(video_file.resolve()),
|
||||
"classification": "error",
|
||||
"score": None,
|
||||
"best_timestamp": None,
|
||||
"error": "mock ffmpeg failure",
|
||||
}
|
||||
],
|
||||
)
|
||||
self.assertEqual(report["summary"]["errors"], 1)
|
||||
|
||||
def test_empty_batch_report(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
files, summary = detect_wcx_title.process_batch(
|
||||
(),
|
||||
lambda _path: (8.0, 8, "wcx"),
|
||||
)
|
||||
|
||||
report = detect_wcx_title.build_json_report(
|
||||
source_directory=Path(temporary_directory),
|
||||
recursive=True,
|
||||
endings={"mp4"},
|
||||
summary=summary,
|
||||
files=files,
|
||||
)
|
||||
report_path = (
|
||||
Path(temporary_directory)
|
||||
/ "reports"
|
||||
/ "empty.json"
|
||||
)
|
||||
detect_wcx_title.write_json_report(report_path, report)
|
||||
|
||||
with report_path.open(encoding="utf-8") as report_file:
|
||||
loaded = json.load(report_file)
|
||||
|
||||
self.assertEqual(loaded["files"], [])
|
||||
self.assertEqual(
|
||||
loaded["summary"],
|
||||
{
|
||||
"processed": 0,
|
||||
"wcx": 0,
|
||||
"uncertain": 0,
|
||||
"not_wcx": 0,
|
||||
"errors": 0,
|
||||
},
|
||||
)
|
||||
|
||||
def test_existing_report_is_rejected(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||
report_path = Path(temporary_directory) / "report.json"
|
||||
report_path.write_text("existing", encoding="utf-8")
|
||||
|
||||
with self.assertRaises(FileExistsError):
|
||||
detect_wcx_title.write_json_report(
|
||||
report_path,
|
||||
{"schema_version": 1},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
report_path.read_text(encoding="utf-8"),
|
||||
"existing",
|
||||
)
|
||||
|
||||
def test_report_write_failure_returns_one(self) -> None:
|
||||
def failing_writer(
|
||||
_path: Path,
|
||||
_report: dict[str, object],
|
||||
) -> None:
|
||||
raise OSError("mock write failure")
|
||||
|
||||
with contextlib.redirect_stderr(io.StringIO()):
|
||||
exit_code = detect_wcx_title.write_optional_json_report(
|
||||
Path("/reports/report.json"),
|
||||
{"schema_version": 1},
|
||||
writer=failing_writer,
|
||||
)
|
||||
|
||||
self.assertEqual(exit_code, 1)
|
||||
|
||||
def test_json_report_without_batch_is_rejected(self) -> None:
|
||||
arguments = [
|
||||
"detect_wcx_title.py",
|
||||
"/videos/movie.mp4",
|
||||
"--json-report",
|
||||
"/reports/report.json",
|
||||
]
|
||||
with patch.object(sys, "argv", arguments):
|
||||
with contextlib.redirect_stderr(io.StringIO()):
|
||||
exit_code = detect_wcx_title.main()
|
||||
|
||||
self.assertEqual(exit_code, 2)
|
||||
|
||||
def test_existing_report_stops_before_batch_processing(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as temporary_directory:
|
||||
directory = Path(temporary_directory)
|
||||
report_path = directory / "report.json"
|
||||
report_path.write_text("existing", encoding="utf-8")
|
||||
arguments = [
|
||||
"detect_wcx_title.py",
|
||||
str(directory),
|
||||
"--batch",
|
||||
"--json-report",
|
||||
str(report_path),
|
||||
]
|
||||
|
||||
with patch.object(sys, "argv", arguments):
|
||||
with patch.object(
|
||||
detect_wcx_title,
|
||||
"process_batch",
|
||||
) as process_batch:
|
||||
with contextlib.redirect_stderr(io.StringIO()):
|
||||
exit_code = detect_wcx_title.main()
|
||||
|
||||
self.assertEqual(exit_code, 2)
|
||||
process_batch.assert_not_called()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user