ken_nogi/PythonProj/ScanOCR/スクリプト/tests/test_extract_and_rename.py
Kenichiro NOGI 0a0bb057e2 feat: キュー処理メインループ(run_queue)を追加
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 10:13:12 +09:00

219 lines
6.4 KiB
Python

from pathlib import Path
from extract_and_rename import (
check_dependencies,
check_external_tools,
run_queue,
select_template_file,
)
def test_select_template_file_picks_first_by_name(tmp_path):
(tmp_path / "b_template.png").write_bytes(b"x")
(tmp_path / "a_template.png").write_bytes(b"x")
(tmp_path / "note.txt").write_bytes(b"x") # 対象外拡張子
result = select_template_file(tmp_path)
assert result == tmp_path / "a_template.png"
def test_select_template_file_no_candidates_raises(tmp_path):
(tmp_path / "note.txt").write_bytes(b"x")
try:
select_template_file(tmp_path)
assert False, "FileNotFoundErrorが送出されるべき"
except FileNotFoundError:
pass
def test_check_dependencies_detects_missing_module():
result = check_dependencies(("this_module_does_not_exist_xyz",))
assert result == ["this_module_does_not_exist_xyz"]
def test_check_dependencies_detects_installed_module():
result = check_dependencies(("os",))
assert result == []
def test_check_external_tools_detects_missing(tmp_path):
tesseract = tmp_path / "tools" / "tesseract" / "tesseract.exe"
poppler = tmp_path / "tools" / "poppler" / "pdftoppm.exe"
result = check_external_tools(tesseract, poppler)
assert str(tesseract) in result
assert str(poppler) in result
def test_check_external_tools_all_present(tmp_path):
tesseract = tmp_path / "tesseract.exe"
poppler = tmp_path / "pdftoppm.exe"
tesseract.write_bytes(b"x")
poppler.write_bytes(b"x")
result = check_external_tools(tesseract, poppler)
assert result == []
def _make_dirs(tmp_path):
dirs = {
"scan": tmp_path / "スキャン",
"output": tmp_path / "アウトプット",
"success": tmp_path / "成功",
"failed": tmp_path / "失敗",
"log": tmp_path / "ログ",
}
dirs["scan"].mkdir()
return dirs
def test_run_queue_success_moves_and_copies(tmp_path):
dirs = _make_dirs(tmp_path)
pdf = dirs["scan"] / "scan001.pdf"
pdf.write_bytes(b"dummy")
def fake_process_pdf(path, boxes, margin):
return ("氏名A", "20260802")
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=fake_process_pdf,
key_check=lambda: False,
sleep_func=lambda s: None,
)
assert (dirs["output"] / "氏名A" / "氏名A_20260802.pdf").exists()
assert (dirs["success"] / "scan001.pdf").exists()
assert not pdf.exists()
from datetime import datetime
log_content = (dirs["log"] / f"{datetime.now().strftime('%Y-%m-%d')}.log").read_text(encoding="utf-8-sig")
assert "結果=成功" in log_content
def test_run_queue_missing_name_moves_to_failed(tmp_path):
dirs = _make_dirs(tmp_path)
pdf = dirs["scan"] / "scan002.pdf"
pdf.write_bytes(b"dummy")
def fake_process_pdf(path, boxes, margin):
return (None, "20260802")
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=fake_process_pdf,
key_check=lambda: False,
sleep_func=lambda s: None,
)
assert (dirs["failed"] / "scan002.pdf").exists()
assert not pdf.exists()
def test_run_queue_exception_moves_to_failed(tmp_path):
dirs = _make_dirs(tmp_path)
pdf = dirs["scan"] / "scan003.pdf"
pdf.write_bytes(b"dummy")
def fake_process_pdf(path, boxes, margin):
raise RuntimeError("OCRエラー")
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=fake_process_pdf,
key_check=lambda: False,
sleep_func=lambda s: None,
)
assert (dirs["failed"] / "scan003.pdf").exists()
def test_run_queue_stops_on_key_press(tmp_path):
dirs = _make_dirs(tmp_path)
pdf = dirs["scan"] / "scan004.pdf"
pdf.write_bytes(b"dummy")
calls = []
def fake_process_pdf(path, boxes, margin):
calls.append(path)
return ("氏名A", "20260802")
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=fake_process_pdf,
key_check=lambda: True, # 常に押下扱い
sleep_func=lambda s: None,
)
assert calls == []
assert pdf.exists() # 処理されず残る
def test_run_queue_skips_file_deleted_before_processing(tmp_path):
dirs = _make_dirs(tmp_path)
pdf = dirs["scan"] / "scan005.pdf"
pdf.write_bytes(b"dummy")
calls = []
def fake_process_pdf(path, boxes, margin):
calls.append(path)
return ("氏名A", "20260802")
def key_check_and_delete():
if pdf.exists():
pdf.unlink()
return False
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=fake_process_pdf,
key_check=key_check_and_delete,
sleep_func=lambda s: None,
)
assert calls == []
def test_run_queue_empty_scan_dir_returns_immediately(tmp_path):
dirs = _make_dirs(tmp_path)
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=lambda p, b, m: ("氏名A", "20260802"),
key_check=lambda: False,
sleep_func=lambda s: None,
)
# 例外が出ずに戻ることのみ確認
def test_run_queue_name_collision_gets_suffix(tmp_path):
dirs = _make_dirs(tmp_path)
existing_output_dir = dirs["output"] / "氏名A"
existing_output_dir.mkdir(parents=True)
(existing_output_dir / "氏名A_20260802.pdf").write_bytes(b"old")
pdf = dirs["scan"] / "scan006.pdf"
pdf.write_bytes(b"dummy")
run_queue(
dirs["scan"], dirs["output"], dirs["success"], dirs["failed"], dirs["log"],
boxes=[], margin=0.1, stable_wait_sec=0, stable_retries=1,
process_pdf_func=lambda p, b, m: ("氏名A", "20260802"),
key_check=lambda: False,
sleep_func=lambda s: None,
)
assert (existing_output_dir / "氏名A_20260802(2).pdf").exists()