165 lines
6.0 KiB
Python
165 lines
6.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""Cell / Grid Presentation 契约:schema + 文档 + 示例。"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
import unittest
|
||
|
||
from util.runtime_paths import get_skill_root
|
||
|
||
|
||
def _skill_path(*parts: str) -> str:
|
||
return os.path.join(get_skill_root(), *parts)
|
||
|
||
|
||
def _load_json(*parts: str) -> dict:
|
||
with open(_skill_path(*parts), encoding="utf-8") as f:
|
||
return json.load(f)
|
||
|
||
|
||
def _load_cell_schema() -> dict:
|
||
return _load_json("assets", "schemas", "skill-cell-presentation.schema.json")
|
||
|
||
|
||
def _load_cell_example() -> dict:
|
||
return _load_json("assets", "examples", "skill-cell-presentation.example.json")
|
||
|
||
|
||
def _load_grid_schema() -> dict:
|
||
return _load_json("assets", "schemas", "skill-grid-presentation.schema.json")
|
||
|
||
|
||
def _load_grid_example() -> dict:
|
||
return _load_json("assets", "examples", "skill-grid-presentation.example.json")
|
||
|
||
|
||
class TestCellPresentationContract(unittest.TestCase):
|
||
def test_schema_file_exists_and_parses(self) -> None:
|
||
schema = _load_cell_schema()
|
||
self.assertEqual(schema.get("title"), "SkillCellPresentationDocument")
|
||
self.assertIs(schema.get("additionalProperties"), False)
|
||
self.assertEqual(schema["properties"]["schemaVersion"].get("const"), 1)
|
||
tones = set(schema["$defs"]["tone"].get("enum") or [])
|
||
self.assertEqual(tones, {"danger", "warning", "info", "success", "muted"})
|
||
|
||
def test_example_validates_against_schema(self) -> None:
|
||
try:
|
||
import jsonschema
|
||
except ImportError:
|
||
self.skipTest("jsonschema not installed")
|
||
jsonschema.validate(instance=_load_cell_example(), schema=_load_cell_schema())
|
||
|
||
def test_actions_schema_defines_cell_presentation_enable_block(self) -> None:
|
||
actions_schema = _load_json("assets", "schemas", "skill-actions.schema.json")
|
||
self.assertIn("cellPresentation", actions_schema["properties"])
|
||
self.assertIn("cellPresentationDeclaration", actions_schema["$defs"])
|
||
|
||
def test_docs_and_example_exist(self) -> None:
|
||
self.assertTrue(os.path.isfile(_skill_path("references", "CELL_PRESENTATION.md")))
|
||
self.assertTrue(
|
||
os.path.isfile(
|
||
_skill_path("assets", "schemas", "skill-cell-presentation.schema.json")
|
||
)
|
||
)
|
||
self.assertTrue(
|
||
os.path.isfile(
|
||
_skill_path("assets", "examples", "skill-cell-presentation.example.json")
|
||
)
|
||
)
|
||
self.assertTrue(
|
||
os.path.isfile(
|
||
_skill_path("assets", "schemas", "skill-grid-presentation.schema.json")
|
||
)
|
||
)
|
||
self.assertTrue(
|
||
os.path.isfile(
|
||
_skill_path("assets", "examples", "skill-grid-presentation.example.json")
|
||
)
|
||
)
|
||
|
||
def test_cell_presentation_md_covers_contract(self) -> None:
|
||
path = _skill_path("references", "CELL_PRESENTATION.md")
|
||
with open(path, encoding="utf-8") as f:
|
||
text = f.read()
|
||
for marker in (
|
||
"tone",
|
||
"danger",
|
||
"warning",
|
||
"alert",
|
||
"_jiangchang_cell_presentation",
|
||
"_jiangchang_grid_presentation",
|
||
"cellPresentation",
|
||
"派生",
|
||
"任意 CSS",
|
||
"用途不限",
|
||
"schemaVersion",
|
||
"整行",
|
||
"整列",
|
||
"all",
|
||
"格子 > 区域 > 行 > 列",
|
||
"详情",
|
||
):
|
||
self.assertIn(marker, text, msg=f"CELL_PRESENTATION.md missing {marker!r}")
|
||
|
||
def test_grid_schema_file_exists_and_parses(self) -> None:
|
||
schema = _load_grid_schema()
|
||
self.assertEqual(schema.get("title"), "SkillGridPresentationDocument")
|
||
self.assertIs(schema.get("additionalProperties"), False)
|
||
self.assertEqual(schema["properties"]["schemaVersion"].get("const"), 1)
|
||
tones = set(schema["$defs"]["tone"].get("enum") or [])
|
||
self.assertEqual(tones, {"danger", "warning", "info", "success", "muted"})
|
||
self.assertIn("not", schema["$defs"]["ruleItem"])
|
||
|
||
def test_grid_example_validates_against_schema(self) -> None:
|
||
try:
|
||
import jsonschema
|
||
except ImportError:
|
||
self.skipTest("jsonschema not installed")
|
||
jsonschema.validate(instance=_load_grid_example(), schema=_load_grid_schema())
|
||
|
||
def test_grid_schema_rejects_all_by_all(self) -> None:
|
||
try:
|
||
import jsonschema
|
||
except ImportError:
|
||
self.skipTest("jsonschema not installed")
|
||
payload = {
|
||
"schemaVersion": 1,
|
||
"skill": "your-skill-slug",
|
||
"table": "business_records",
|
||
"rowKey": "id",
|
||
"rules": [
|
||
{
|
||
"ruleKey": "paint-everything",
|
||
"rows": "all",
|
||
"columns": "all",
|
||
"tone": "danger",
|
||
}
|
||
],
|
||
}
|
||
with self.assertRaises(jsonschema.ValidationError):
|
||
jsonschema.validate(instance=payload, schema=_load_grid_schema())
|
||
|
||
def test_internal_metadata_hides_presentation_tables(self) -> None:
|
||
from db.display_metadata import INTERNAL_METADATA_TABLES, METADATA_TABLES
|
||
|
||
self.assertIn("_jiangchang_cell_presentation", INTERNAL_METADATA_TABLES)
|
||
self.assertIn("_jiangchang_grid_presentation", INTERNAL_METADATA_TABLES)
|
||
self.assertTrue(INTERNAL_METADATA_TABLES <= METADATA_TABLES)
|
||
|
||
def test_template_actions_do_not_enable_presentation_by_default(self) -> None:
|
||
manifest = _load_json("assets", "actions.json")
|
||
self.assertNotEqual(manifest.get("cellPresentation", {}).get("enabled"), True)
|
||
|
||
def test_checklist_covers_grid_presentation(self) -> None:
|
||
path = _skill_path("development", "CHECKLIST.md")
|
||
with open(path, encoding="utf-8") as f:
|
||
text = f.read()
|
||
self.assertIn("A6-15", text)
|
||
self.assertIn("cellPresentation", text)
|
||
self.assertIn("CELL_PRESENTATION.md", text)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|