tests/test_check_public_text.py
Rama master · réplica de lectura del repositorio original.
import io
import json
import sqlite3
import subprocess
import tempfile
import unittest
from contextlib import redirect_stderr
from pathlib import Path
from unittest import mock
from scripts import check_public_text
from scripts.check_public_text import Library, insider_terms, problems, publish_text
def ledger(path: Path) -> Path:
"""只有判据读到的那几列;内容全是虚构的。"""
connection = sqlite3.connect(path)
connection.executescript("""
CREATE TABLE asset(code TEXT, catalog_title TEXT, original_title TEXT, name TEXT);
CREATE TABLE feed_item(code TEXT);
CREATE TABLE entity(kind TEXT, canonical_name TEXT);
CREATE TABLE follow_source(label TEXT);
INSERT INTO asset VALUES ('ZZQ-101', '架空作品のための長い題名です', '', 'ZZQ-101.mp4'),
('zzq102', '', '', ''), ('ZZQ-103', '', '', ''), ('', '', '', '');
INSERT INTO feed_item VALUES ('YYW-007');
INSERT INTO entity VALUES ('performer', '虚构女优甲'), ('performer', '虚构女优乙'), ('tag', '虚构标签名'),
('creator', 'Fictional Maker');
INSERT INTO follow_source VALUES ('fictional_account'), (NULL);
""")
connection.commit()
connection.close()
return path
class LibraryTests(unittest.TestCase):
def setUp(self):
directory = tempfile.TemporaryDirectory()
self.addCleanup(directory.cleanup)
self.library = Library.load(ledger(Path(directory.name) / "ledger.db"))
def test_the_ledger_is_read_into_codes_names_and_title_fragments(self):
self.assertEqual(self.library.codes, {"ZZQ-101", "ZZQ-102", "ZZQ-103", "YYW-007"})
self.assertEqual(self.library.names, {"虚构女优甲", "虚构女优乙", "Fictional Maker", "fictional_account"})
self.assertIn("架空作品のため", self.library.grams)
def test_a_list_of_owned_codes_names_or_titles_is_a_problem(self):
cases = {"ZZQ-101、zzq-102、ZZQ103 都要人判": "番号 3 个",
"虚构女优甲 对 虚构女优乙": "人物 2 个",
"系列名:架空作品のための長い題名 对 題名です長い架空作品のため": "标题片段 2 个"}
for text, expected in cases.items():
with self.subTest(text=text):
self.assertTrue(problems(text, self.library)[0].startswith(expected))
def test_the_example_a_fix_needs_and_unrelated_text_pass(self):
for text in ("只修 ZZQ-101 的前缀,YYW-007 是反例。", "虚构女优甲 的别名修好了。",
"ABC-123、DEF-456、GHI-789 都不在账本里。", "Fictional 与 Maker 分开写不算。"):
with self.subTest(text=text):
self.assertEqual(problems(text, self.library), [])
def test_a_stated_reason_or_a_machine_without_a_ledger_passes(self):
listed = "ZZQ-101、ZZQ-102、ZZQ-103"
self.assertEqual(problems(listed + "\n<!-- peach-public-text: 三个番号就是这次修的前缀 -->", self.library), [])
self.assertNotEqual(problems(listed + "\npeach-public-text:", self.library), [])
self.assertEqual(problems(listed, None), [])
class InsiderTermsTests(unittest.TestCase):
"""PR、issue 与评论写给外部读者:派单的编号、批次与本机交付流程的说法他们看不懂。"""
def test_feedback_codes_batches_and_delivery_steps_are_named_by_kind(self):
found = insider_terms("修复反馈 N01,本轮 R0–R2;全库排查第 3 批,合批后第一轮 auto 在集成工作树里跑,"
"ready:ok;门槛已改。")
self.assertEqual([line.split(":", 1)[0] for line in found],
["反馈条目编号", "批次与轮次", "本机交付流程", "自造用语"])
self.assertIn("N01", found[0])
self.assertIn("合批", found[1])
def test_code_spans_ordinary_words_and_a_stated_reason_pass(self):
for text in ("Windows 11:`& .\\scripts\\test.ps1`(按改动自动选范围)通过。",
"命令是 `agent_worktree.py ready`,H264 与 N1 芯片不受影响。",
"分批派发补全任务;这批文件已核对。",
"第一轮反馈\npeach-public-text: 讨论的就是批次命名本身"):
with self.subTest(text=text):
self.assertEqual(insider_terms(text), [])
class PublishCommandTests(unittest.TestCase):
def setUp(self):
directory = tempfile.TemporaryDirectory()
self.addCleanup(directory.cleanup)
self.cwd = Path(directory.name)
(self.cwd / "body.md").write_text("正文文件里的内容", encoding="utf-8")
def test_gh_commands_that_publish_carry_their_text_and_body_files(self):
for command in ("gh pr create --title t --body-file body.md", "gh pr edit 3 -F body.md",
"cd x && gh issue comment 5 --body-file=body.md",
f"gh api -X PATCH repos/o/r/issues/comments/9 -F body=@{self.cwd / 'body.md'}"):
with self.subTest(command=command):
text = publish_text(command, self.cwd)
self.assertIn(command, text)
self.assertIn("正文文件里的内容", text)
heredoc = "gh pr create --body \"$(cat <<'EOF'\n正文直接写在命令里\nEOF\n)\""
self.assertIn("正文直接写在命令里", publish_text(heredoc, self.cwd))
def test_commands_that_only_read_are_not_publishing(self):
for command in ("gh pr view 3 --json body", "gh pr list", "gh api repos/o/r/pulls/3", "echo hello"):
with self.subTest(command=command):
self.assertIsNone(publish_text(command, self.cwd))
def test_the_hook_blocks_with_a_reason_and_lets_everything_else_through(self):
library = Library(codes={"ZZQ-101", "ZZQ-102", "ZZQ-103"})
listed = {"cwd": str(self.cwd), "tool_input": {"command": "gh pr create --body 'ZZQ-101 ZZQ-102 ZZQ-103'"}}
with mock.patch.object(check_public_text, "load_library", return_value=library) as load:
error = io.StringIO()
with redirect_stderr(error):
self.assertEqual(check_public_text.hook(listed), 2)
self.assertIn("番号 3 个", error.getvalue())
self.assertIn("peach-public-text", error.getvalue())
self.assertEqual(check_public_text.hook({"tool_input": {"command": "gh pr create --body 'ZZQ-101'"}}), 0)
load.reset_mock()
self.assertEqual(check_public_text.hook({"tool_input": {"command": "git status"}}), 0)
load.assert_not_called()
def test_a_delivery_script_chained_after_the_publish_command_is_not_its_text(self):
command = ("gh pr create --title t --body-file body.md && "
"python scripts/agent_worktree.py integrate --branch agent/claude/x")
with mock.patch.object(check_public_text, "load_library", return_value=None):
self.assertEqual(check_public_text.hook({"cwd": str(self.cwd), "tool_input": {"command": command}}), 0)
def test_the_hook_blocks_insider_terms_even_without_a_ledger(self):
(self.cwd / "notes.md").write_text("合批验证,见批次 0570。", encoding="utf-8")
for command in ("gh pr edit 3 --body '修复 N01'", "gh release edit v1.0.0 --notes-file notes.md"):
with self.subTest(command=command), mock.patch.object(check_public_text, "load_library", return_value=None):
error = io.StringIO()
with redirect_stderr(error):
self.assertEqual(check_public_text.hook({"cwd": str(self.cwd), "tool_input": {"command": command}}), 2)
self.assertIn("内部用语", error.getvalue())
self.assertIn("peach-public-text", error.getvalue())
def test_the_hook_reads_a_missing_cwd_as_this_checkout(self):
payload = {"cwd": "/no/such/place", "tool_input": {"command": "gh pr create --body x"}}
with mock.patch.object(check_public_text, "load_library", return_value=None) as load:
self.assertEqual(check_public_text.hook(payload), 0)
load.assert_called_once_with(check_public_text.ROOT)
def test_the_configured_claude_hook_runs_as_written(self):
"""配置里的命令原样跑一遍:PATH 上没有 uv 就是测试红,不是钩子静默;`--no-project` 不建 venv。"""
settings = json.loads((check_public_text.ROOT / ".claude" / "settings.json").read_text(encoding="utf-8"))
[matcher] = settings["hooks"]["PreToolUse"]
self.assertEqual(matcher["matcher"], "Bash|PowerShell")
[hook] = matcher["hooks"]
argv = [hook["command"], *(arg.replace("${CLAUDE_PROJECT_DIR}", str(check_public_text.ROOT))
for arg in hook["args"])]
venv = (self.cwd / ".venv").exists()
result = subprocess.run(argv, input=json.dumps({"cwd": str(self.cwd), "tool_input": {"command": "git status"}}),
capture_output=True, text=True, encoding="utf-8", cwd=self.cwd, timeout=120)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn(result.stderr, ("", "WARN `--no-project` was provided, but no project was found\n"))
self.assertEqual((self.cwd / ".venv").exists(), venv)
def test_unreadable_hook_input_never_blocks(self):
with mock.patch("sys.stdin", io.StringIO("not json")):
self.assertEqual(check_public_text.main(["--hook-event"]), 0)
with mock.patch("sys.stdin", io.StringIO(json.dumps([1]))):
self.assertEqual(check_public_text.main(["--hook-event"]), 0)
if __name__ == "__main__":
unittest.main()