Files
audiobookshelf/tests/test_apply_abs_mock_report.py
2026-04-26 18:40:09 +02:00

231 lines
8.0 KiB
Python

import csv
import io
import tempfile
import unittest
from pathlib import Path
from unittest import mock
import apply_abs_mock_report as apply_report
class ApplyAbsMockReportTests(unittest.TestCase):
def write_report(self, path: Path, rows: list[dict[str, str]]) -> None:
fieldnames = [
"verification_status",
"verification_source",
"verification_note",
"status",
"current_path",
"audio_file_count",
"sample_audio_file",
"author",
"author_confidence",
"author_source",
"series",
"sequence",
"publish_year",
"title",
"title_source",
"narrator",
"proposed_abs_path",
"notes",
]
with path.open("w", encoding="utf-8", newline="") as handle:
writer = csv.DictWriter(handle, fieldnames=fieldnames, delimiter="\t")
writer.writeheader()
writer.writerows(rows)
def create_book(self, root: Path, relative_path: str) -> Path:
book_root = root / relative_path
(book_root / "Disc 1").mkdir(parents=True)
(book_root / "Disc 1" / "01.mp3").write_bytes(b"audio")
(book_root / "cover.jpg").write_bytes(b"cover")
return book_root
def test_copy_mode_recreates_report_structure(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
source_root = tmp / "source"
destination_root = tmp / "destination"
report_path = tmp / "report.tsv"
book_root = self.create_book(source_root, "Old Author/Old Book")
self.write_report(
report_path,
[
{
"status": "ready",
"current_path": str(book_root),
"proposed_abs_path": "New Author/New Series/Vol. 01 - New Book",
}
],
)
exit_code = apply_report.main(
[
"--report",
str(report_path),
"--destination-root",
str(destination_root),
"--mode",
"copy",
]
)
self.assertEqual(exit_code, 0)
copied_root = destination_root / "New Author" / "New Series" / "Vol. 01 - New Book"
self.assertTrue((copied_root / "Disc 1" / "01.mp3").exists())
self.assertTrue((copied_root / "cover.jpg").exists())
self.assertTrue((book_root / "Disc 1" / "01.mp3").exists())
def test_move_mode_removes_source_tree(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
source_root = tmp / "source"
destination_root = tmp / "destination"
report_path = tmp / "report.tsv"
book_root = self.create_book(source_root, "Old Author/Old Book")
self.write_report(
report_path,
[
{
"status": "ready",
"current_path": str(book_root),
"proposed_abs_path": "Author/Book",
}
],
)
exit_code = apply_report.main(
[
"--report",
str(report_path),
"--destination-root",
str(destination_root),
"--mode",
"move",
]
)
self.assertEqual(exit_code, 0)
moved_root = destination_root / "Author" / "Book"
self.assertTrue((moved_root / "Disc 1" / "01.mp3").exists())
self.assertFalse(book_root.exists())
def test_dry_run_prints_plan_without_creating_destination(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
source_root = tmp / "source"
destination_root = tmp / "destination"
report_path = tmp / "report.tsv"
book_root = self.create_book(source_root, "Old Author/Old Book")
self.write_report(
report_path,
[
{
"status": "ready",
"current_path": str(book_root),
"proposed_abs_path": "Author/Book",
}
],
)
stdout = io.StringIO()
with mock.patch("sys.stdout", stdout):
exit_code = apply_report.main(
[
"--report",
str(report_path),
"--destination-root",
str(destination_root),
"--dry-run",
]
)
self.assertEqual(exit_code, 0)
self.assertIn("plan\t", stdout.getvalue())
self.assertFalse(destination_root.exists())
def test_duplicate_targets_fail_validation(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
source_root = tmp / "source"
report_path = tmp / "report.tsv"
first_book = self.create_book(source_root, "Author A/Book One")
second_book = self.create_book(source_root, "Author B/Book Two")
self.write_report(
report_path,
[
{
"status": "ready",
"current_path": str(first_book),
"proposed_abs_path": "Author/Shared",
},
{
"status": "ready",
"current_path": str(second_book),
"proposed_abs_path": "Author/Shared",
},
],
)
stderr = io.StringIO()
with mock.patch("sys.stderr", stderr):
exit_code = apply_report.main(
[
"--report",
str(report_path),
"--destination-root",
str(tmp / "destination"),
]
)
self.assertEqual(exit_code, 1)
self.assertIn("duplicate proposed_abs_path", stderr.getvalue())
def test_default_status_only_applies_ready_rows(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
tmp = Path(tmpdir)
source_root = tmp / "source"
destination_root = tmp / "destination"
report_path = tmp / "report.tsv"
ready_book = self.create_book(source_root, "Ready Author/Ready Book")
review_book = self.create_book(source_root, "Review Author/Review Book")
self.write_report(
report_path,
[
{
"status": "ready",
"current_path": str(ready_book),
"proposed_abs_path": "Ready Author/Ready Book",
},
{
"status": "review",
"current_path": str(review_book),
"proposed_abs_path": "Review Author/Review Book",
},
],
)
exit_code = apply_report.main(
[
"--report",
str(report_path),
"--destination-root",
str(destination_root),
]
)
self.assertEqual(exit_code, 0)
self.assertTrue((destination_root / "Ready Author" / "Ready Book").exists())
self.assertFalse((destination_root / "Review Author" / "Review Book").exists())
self.assertTrue(review_book.exists())
if __name__ == "__main__":
unittest.main()