tests/test_it_does_not_plan_what_it_cannot_write.py
Rama main · réplica de lectura del repositorio original.
"""沒有 frontmatter 就沒有地方寫分類——那要說「做不到」,不是「待辦」。
索引 1,706 列裡有 9 列的檔案沒有 YAML frontmatter(github stars、youtube、抓取
失敗的空殼)。這些檔的分類落在 build_search_index.sh 的預設值,所以它們永遠在
「清單外」那一份名單裡。
第一版把它們照樣排進計畫,於是報告每次都說「要重新分類 3 筆」,--apply 之後那 3
筆還在。這是這個專案反覆出現的同一個形狀:**把「做不到」寫成「待辦」**,看起來像
還沒輪到,實際上永遠不會發生。(記憶 xkb-gate-asked-the-impossible:放行率 0 不是
門檻太嚴,是資料根本無法滿足。)
"""
from __future__ import annotations
import io
import sys
import tempfile
import unittest
from contextlib import redirect_stdout
from pathlib import Path
from unittest import mock
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))
import xkb_recategorize as rc # noqa: E402
class FilesWithoutFrontmatterAreReportedNotPlanned(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.root = Path(self.tmp.name)
def _run(self, files: list[Path]) -> str:
item = {"category": "general", "title": "每次都說要改的那一筆",
"relative_path": str(files[0])}
out = io.StringIO()
with mock.patch.object(rc, "load_items", return_value=[item]), \
mock.patch.object(rc, "off_taxonomy", return_value=[item]), \
mock.patch.object(rc.xkb_index, "files_for_item", return_value=files), \
mock.patch.object(rc.category_classifier, "taxonomy",
return_value=["99-general"]), \
mock.patch.object(rc.category_classifier, "proposals", return_value={}), \
mock.patch.object(rc, "gather_promoted", return_value=[]), \
mock.patch.object(sys, "argv", ["xkb_recategorize.py"]), \
redirect_stdout(out):
rc.main()
return out.getvalue()
def test_a_file_without_frontmatter_is_not_listed_as_work_to_do(self):
path = self.root / "every-app__open-seo.md"
path.write_text("# every-app/open-seo\n\n- **Category:** seo-geo\n",
encoding="utf-8")
output = self._run([path])
self.assertIn("沒有 YAML frontmatter", output)
self.assertNotIn("要重新分類", output,
"寫不進去的不該列成待辦——報告會每次重複一個不會發生的承諾")
def test_it_does_not_call_the_classifier_for_a_file_it_cannot_write(self):
"""連 LLM 都不該花。判斷完也沒有地方寫。"""
path = self.root / "no-frontmatter.md"
path.write_text("# 只有正文\n", encoding="utf-8")
with mock.patch.object(rc.category_classifier, "classify_content") as spy:
self._run([path])
spy.assert_not_called()
def test_a_group_with_one_writable_file_is_still_planned(self):
"""一組裡只要有一個檔寫得進去就算可做——別把整組一起放棄。"""
plain = self.root / "bookmark.md"
plain.write_text("# 沒有 frontmatter\n", encoding="utf-8")
card = self.root / "card.md"
card.write_text("---\ncategory: general\ntitle: t\n---\n# t\n",
encoding="utf-8")
with mock.patch.object(
rc.category_classifier, "classify_content",
return_value={"category": "99-general", "confidence": "high",
"llm": True, "proposed_category": "",
"proposal_count": 0}):
output = self._run([card, plain])
self.assertIn("要重新分類", output)
self.assertNotIn("沒有 YAML frontmatter", output)
if __name__ == "__main__":
unittest.main()