import importlib.util import subprocess import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SCRIPT = ROOT / "skills" / "tsl-syntax-reference" / "scripts" / "lookup.py" spec = importlib.util.spec_from_file_location("tsl_syntax_lookup", SCRIPT) lookup = importlib.util.module_from_spec(spec) spec.loader.exec_module(lookup) class TslSyntaxLookupTests(unittest.TestCase): def test_parser_creates_unique_h2_h3_section_ids(self): sections = lookup.load_sections(lookup.DEFAULT_REFERENCES_DIR) ids = [section.id for section in sections] self.assertEqual(len(ids), len(set(ids))) self.assertTrue(any("05_functions_and_calls" in value for value in ids)) def test_write_mode_includes_file_model_and_direct_example(self): result = lookup.query_sections("写函数 命名参数", "write", limit=4) rendered = lookup.render_result(result) self.assertIn("文件模型", rendered) self.assertIn("代码块身份:可直接照写示例", rendered) def test_diagnose_mode_prioritizes_invalid_statement_pitfall(self): result = lookup.query_sections("invalid statement 声明区", "diagnose", limit=4) self.assertIn("11_pitfalls.md", result.matches[0].section.page.as_posix()) def test_explain_mode_does_not_force_write_prelude(self): result = lookup.query_sections("数组下标", "explain", limit=3) self.assertEqual(result.prelude, []) def test_no_match_returns_exit_code_two_in_every_mode(self): for mode in ("write", "diagnose", "explain"): with self.subTest(mode=mode): completed = subprocess.run( [ sys.executable, str(SCRIPT), "--query", "不存在的孤立语法词xyz", "--mode", mode, ], capture_output=True, text=True, encoding="utf-8", ) self.assertEqual(completed.returncode, 2) def test_missing_section_returns_nearest_section_ids(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) (references / "sample.md").write_text( "# Sample\n\n## Exact Section\n\nDetails.\n\n## Other\n\nMore.\n", encoding="utf-8", newline="\n", ) expected_id = lookup.load_sections(references)[0].id completed = subprocess.run( [ sys.executable, str(SCRIPT), "--section", f"{expected_id}-typo", "--references-dir", str(references), ], capture_output=True, text=True, encoding="utf-8", ) self.assertEqual(completed.returncode, 2) self.assertIn("Nearest section IDs:", completed.stderr) self.assertIn(f"- {expected_id}\n", completed.stderr) def test_write_identifier_query_keeps_required_context(self): result = lookup.query_sections("varByRef 命名参数", "write", limit=5) prelude_pages = {section.page.name for section in result.prelude} self.assertEqual(prelude_pages, {"01_quickstart.md", "02_core_model.md"}) def test_write_prelude_renders_source_for_every_section(self): result = lookup.query_sections("varByRef 命名参数", "write", limit=5) rendered = lookup.render_result(result) required_context = rendered.split("## Match 1", 1)[0] self.assertEqual(required_context.count("Source: `"), len(result.prelude)) for section in result.prelude: self.assertIn(f"Source: `{section.page.as_posix()}`", required_context) def test_check_rejects_unknown_code_block_identity(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) (references / "sample.md").write_text( "# Sample\n\n" "## Example\n\n" "代码块身份:未知身份\n\n" "```tsl\n" "return 1;\n" "```\n", encoding="utf-8", newline="\n", ) problems = lookup.validate_references(references) self.assertTrue( any("未知身份" in problem.message for problem in problems), problems ) def test_parser_and_validator_reject_prose_between_identity_and_fence(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) page = references / "sample.md" page.write_text( "# Sample\n\n" "## Example\n\n" "代码块身份:可直接照写示例\n" "This arbitrary prose breaks the metadata association.\n\n" "```tsl\n" "return 1;\n" "```\n", encoding="utf-8", newline="\n", ) sections = lookup.load_sections(references) problems = lookup.validate_references(references) self.assertEqual(sections[0].identities, ()) self.assertTrue(any("恰好一个代码块身份" in item.message for item in problems)) def test_parser_and_validator_accept_structured_block_description(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) page = references / "sample.md" page.write_text( "# Sample\n\n" "## Example\n\n" "代码块身份:配置片段 / 概念骨架\n" "代码块说明:This is structured metadata.\n\n" "```text\n" "example\n" "```\n", encoding="utf-8", newline="\n", ) sections = lookup.load_sections(references) problems = lookup.validate_references(references) self.assertEqual(sections[0].identities, ("配置片段 / 概念骨架",)) self.assertEqual(problems, []) def test_check_accumulates_fence_identity_and_link_problems(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) (references / "sample.md").write_text( "# Sample\n\n" "## Example\n\n" "[missing](missing.md)\n\n" "代码块身份:输出片段\n" "代码块身份:可直接照写示例\n\n" "```tsl\n" "return 1;\n", encoding="utf-8", newline="\n", ) problems = lookup.validate_references(references) messages = "\n".join(problem.message for problem in problems) self.assertIn("本地链接不存在", messages) self.assertIn("代码围栏未闭合", messages) self.assertIn("恰好一个代码块身份", messages) def test_check_ignores_markdown_link_shapes_inside_inline_code(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) (references / "sample.md").write_text( "# Sample\n\n" "## Operators\n\n" "Use `function operator[](index);`.\n", encoding="utf-8", newline="\n", ) problems = lookup.validate_references(references) self.assertEqual(problems, []) def test_natural_chinese_query_finds_object_creation(self): result = lookup.query_sections("写一个类并创建对象", "write", limit=5) sources = "\n".join(match.section.id for match in result.matches) self.assertIn("08_objects_and_classes", sources) def test_ranking_tiers_beat_adversarial_page_order(self): with tempfile.TemporaryDirectory() as tmp_dir: references = Path(tmp_dir) pages = { "a_body.md": "# Other\n\n## Other\n\nneedle appears as plain prose.\n", "b_title.md": "# needle\n\n## Other\n\nNo body match.\n", "c_identifier.md": "# Other\n\n## Other\n\nUse `needle` here.\n", "z_heading.md": "# Other\n\n## needle\n\nNo body detail.\n", } for name, text in pages.items(): (references / name).write_text( text, encoding="utf-8", newline="\n" ) result = lookup.query_sections( "needle", "explain", limit=4, references_dir=references ) self.assertEqual( [match.section.page.name for match in result.matches], ["z_heading.md", "c_identifier.md", "b_title.md", "a_body.md"], ) def test_tsl_identifier_is_preserved(self): result = lookup.query_sections("varByRef 命名参数", "explain", limit=5) rendered = lookup.render_result(result) self.assertRegex(rendered, r"(?i)varByRef") if __name__ == "__main__": unittest.main()