codex author changes

This commit is contained in:
MirSob
2026-04-26 00:46:48 +02:00
parent b5c2929062
commit d07c6b033f
9 changed files with 577 additions and 6 deletions

View 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()

View File

@@ -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()