codex author changes
This commit is contained in:
BIN
tests/__pycache__/test_apply_abs_mock_report.cpython-311.pyc
Normal file
BIN
tests/__pycache__/test_apply_abs_mock_report.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
230
tests/test_apply_abs_mock_report.py
Normal file
230
tests/test_apply_abs_mock_report.py
Normal file
@@ -0,0 +1,230 @@
|
||||
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()
|
||||
@@ -83,6 +83,69 @@ class InferBookTests(unittest.TestCase):
|
||||
self.assertEqual(row["sequence"], "05")
|
||||
self.assertEqual(row["title"], "Pogrzebany")
|
||||
|
||||
def test_build_proposed_path_omits_author_from_subfolders(self) -> None:
|
||||
proposed_path = report.build_proposed_abs_path(
|
||||
"Jussi Adler-Olsen",
|
||||
"Adler-Olsen Jussi - Departament Q",
|
||||
"04",
|
||||
"",
|
||||
"Kartoteka 64 - Jussi Adler-Olsen",
|
||||
"",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
proposed_path,
|
||||
"Jussi Adler-Olsen/Departament Q/Vol. 04 - Kartoteka 64",
|
||||
)
|
||||
|
||||
def test_build_proposed_path_omits_author_only_series_folder(self) -> None:
|
||||
proposed_path = report.build_proposed_abs_path(
|
||||
"Jeffrey Archer",
|
||||
"Archer",
|
||||
"",
|
||||
"",
|
||||
"Kain I Abel",
|
||||
"",
|
||||
)
|
||||
|
||||
self.assertEqual(proposed_path, "Jeffrey Archer/Kain I Abel")
|
||||
|
||||
def test_strips_nearly_matching_author_prefix_from_title(self) -> None:
|
||||
row = self.infer_row(
|
||||
"Abmercombie Joe/Abercrombie Joe - Czerwona kraina (Audiobooki2.pl)",
|
||||
["Czerwona kraina (01).mp3"],
|
||||
)
|
||||
|
||||
self.assertEqual(row["author"], "Abmercombie Joe")
|
||||
self.assertEqual(row["title"], "Czerwona kraina (Audiobooki2 pl)")
|
||||
self.assertEqual(
|
||||
row["proposed_abs_path"],
|
||||
"Abmercombie Joe/Czerwona kraina (Audiobooki2 pl)",
|
||||
)
|
||||
|
||||
def test_strips_nearly_matching_author_prefix_from_nested_title(self) -> None:
|
||||
row = self.infer_row(
|
||||
"Dan Simons/Dan Simmons - cykl Hyperion (tom 3) Endymion (Audiobooki2.pl)",
|
||||
["001 Endymion.mp3"],
|
||||
)
|
||||
|
||||
self.assertEqual(row["author"], "Dan Simons")
|
||||
self.assertEqual(row["title"], "cykl Hyperion (tom 3) Endymion (Audiobooki2 pl)")
|
||||
self.assertEqual(
|
||||
row["proposed_abs_path"],
|
||||
"Dan Simons/cykl Hyperion (tom 3) Endymion (Audiobooki2 pl)",
|
||||
)
|
||||
|
||||
def test_strips_multi_author_prefix_when_current_author_is_in_root(self) -> None:
|
||||
row = self.infer_row(
|
||||
"Chmielarz Wojciech/Ćwiek Jakub i Chmielarz Wojciech - Skowyt",
|
||||
["1.mp3"],
|
||||
)
|
||||
|
||||
self.assertEqual(row["author"], "Chmielarz Wojciech")
|
||||
self.assertEqual(row["title"], "Skowyt")
|
||||
self.assertEqual(row["proposed_abs_path"], "Chmielarz Wojciech/Skowyt")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user