🐛 fix(tsl-syntax-reference): route derived rules and bound section size
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import importlib.util
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -275,6 +276,104 @@ class TslSyntaxReferenceTests(unittest.TestCase):
|
||||
|
||||
self.assertTrue(any("assignment" in message for message in messages))
|
||||
|
||||
def test_quickstart_owner_drift_fails_structure_check(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
references = Path(temp_dir)
|
||||
write_reference(
|
||||
references,
|
||||
"01_quickstart.md",
|
||||
"""
|
||||
# Quickstart
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-01-001 -->
|
||||
|
||||
派生摘要。
|
||||
|
||||
## 语言核心事实速查
|
||||
|
||||
<!-- section-id: syntax-01-002 -->
|
||||
|
||||
<!-- quickstart-rule: assignment -->
|
||||
- 普通赋值使用 `:=`。
|
||||
Owner Section:`syntax-02-999`
|
||||
""",
|
||||
)
|
||||
write_reference(
|
||||
references,
|
||||
"02_topic.md",
|
||||
"""
|
||||
# Topic
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-02-001 -->
|
||||
|
||||
完整事实源。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-02-002 -->
|
||||
|
||||
<!-- quickstart-rule: assignment -->
|
||||
- 普通赋值使用 `:=`。
|
||||
""",
|
||||
)
|
||||
|
||||
messages = [item.message for item in lookup.validate_references(references)]
|
||||
|
||||
self.assertTrue(any("Owner Section 不存在" in message for message in messages))
|
||||
|
||||
def test_quickstart_routes_every_derived_rule_to_its_owner_section(self):
|
||||
quickstart = run_lookup("--section", "syntax-01-002")
|
||||
|
||||
self.assertEqual(0, quickstart.returncode, quickstart.stderr)
|
||||
owner_ids = set(
|
||||
re.findall(r"Owner Section:`(syntax-\d{2}-\d{3})`", quickstart.stdout)
|
||||
)
|
||||
self.assertEqual(
|
||||
{
|
||||
"syntax-02-002",
|
||||
"syntax-03-002",
|
||||
"syntax-03-004",
|
||||
"syntax-05-002",
|
||||
"syntax-06-004",
|
||||
"syntax-08-002",
|
||||
"syntax-09-002",
|
||||
},
|
||||
owner_ids,
|
||||
)
|
||||
for owner_id in owner_ids:
|
||||
with self.subTest(owner_id=owner_id):
|
||||
owner = run_lookup("--section", owner_id)
|
||||
self.assertEqual(0, owner.returncode, owner.stderr)
|
||||
|
||||
def test_oversized_leaf_section_fails_structure_check(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
references = Path(temp_dir)
|
||||
long_body = "\n".join(f"事实行 {index}" for index in range(181))
|
||||
write_reference(
|
||||
references,
|
||||
"99_fixture.md",
|
||||
"# Fixture\n\n"
|
||||
"## 本篇职责\n\n"
|
||||
"<!-- section-id: syntax-99-001 -->\n\n"
|
||||
"测试职责。\n\n"
|
||||
"## 过长事实段\n\n"
|
||||
"<!-- section-id: syntax-99-002 -->\n\n"
|
||||
f"{long_body}\n",
|
||||
)
|
||||
|
||||
result = run_lookup(
|
||||
"--check",
|
||||
"--references-dir",
|
||||
str(references),
|
||||
)
|
||||
|
||||
self.assertEqual(1, result.returncode)
|
||||
self.assertIn("叶子 Section 正文超过 180 行", result.stderr)
|
||||
|
||||
def test_missing_references_are_installation_errors_for_every_action(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
missing = Path(temp_dir) / "missing"
|
||||
@@ -317,6 +416,25 @@ class TslSyntaxReferenceTests(unittest.TestCase):
|
||||
self.assertEqual("syntax-05-008", write_result.matches[0].section.id)
|
||||
self.assertEqual("syntax-02-006", diagnose_result.matches[0].section.id)
|
||||
|
||||
def test_object_and_class_queries_return_focused_sections(self):
|
||||
cases = {
|
||||
"成员访问可见性": "syntax-08-013",
|
||||
"类外实现": "syntax-08-014",
|
||||
"固定索引 property": "syntax-08-015",
|
||||
"参数化 property": "syntax-08-016",
|
||||
"方法隐藏 hide": "syntax-08-017",
|
||||
"调用父类 inherited": "syntax-08-018",
|
||||
"析构 destroy": "syntax-08-019",
|
||||
}
|
||||
for query, expected_id in cases.items():
|
||||
with self.subTest(query=query):
|
||||
result = lookup.query_sections(query, "explain", limit=1)
|
||||
self.assertTrue(result.matches, query)
|
||||
self.assertEqual(expected_id, result.matches[0].section.id)
|
||||
section = run_lookup("--section", expected_id)
|
||||
self.assertEqual(0, section.returncode, section.stderr)
|
||||
self.assertLessEqual(len(section.stdout.splitlines()), 186)
|
||||
|
||||
def test_external_call_queries_retrieve_platform_and_abi_boundaries(self):
|
||||
cases = {
|
||||
"动态库常驻": "syntax-17-012",
|
||||
@@ -440,17 +558,40 @@ class TslSyntaxReferenceTests(unittest.TestCase):
|
||||
|
||||
def test_skill_contract_uses_extracted_queries_and_deliverable_api_checks(self):
|
||||
skill = SKILL_PATH.read_text(encoding="utf-8")
|
||||
help_text = lookup._parser().format_help()
|
||||
help_result = run_lookup("--help")
|
||||
self.assertEqual(0, help_result.returncode, help_result.stderr)
|
||||
help_text = help_result.stdout
|
||||
|
||||
self.assertIn("保留这些词在用户原话中", skill)
|
||||
self.assertIn("不传完整句", skill)
|
||||
self.assertNotIn("## 构造查询词", skill)
|
||||
self.assertNotIn("用户怎么说就怎么传", skill)
|
||||
self.assertIn("从用户原话提取", help_text)
|
||||
self.assertIn("保留原写法但不传完整用户句", help_text)
|
||||
self.assertIn("不传完整用户句", help_text)
|
||||
self.assertIn("面向用户交付的 TSL/TSF 代码", skill)
|
||||
self.assertIn("每个 builtin/API", skill)
|
||||
self.assertIn("纯语法说明", skill)
|
||||
self.assertIn("不得声称该占位调用的 API 行为或输出", skill)
|
||||
|
||||
def test_help_owns_cli_details_and_skill_defers_to_it(self):
|
||||
skill = SKILL_PATH.read_text(encoding="utf-8")
|
||||
result = run_lookup("--help")
|
||||
|
||||
self.assertEqual(0, result.returncode, result.stderr)
|
||||
for text in (
|
||||
"一次 --query 只覆盖一个语法要素",
|
||||
"Required: yes",
|
||||
"Owner Section",
|
||||
"混合候选",
|
||||
"180 行粒度上限",
|
||||
"退出码",
|
||||
):
|
||||
with self.subTest(text=text):
|
||||
self.assertIn(text, result.stdout)
|
||||
self.assertIn("构造任一命令前先运行", skill)
|
||||
self.assertIn("scripts/lookup.py --help", skill)
|
||||
self.assertIn("不用于查询 API 签名", skill)
|
||||
self.assertIn("不用于选择解释器或运行方式", skill)
|
||||
|
||||
def test_ci_runs_syntax_structure_and_format_gates(self):
|
||||
workflow = CI_PATH.read_text(encoding="utf-8")
|
||||
prepare = PREPARE_PATH.read_text(encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user