PicoBot/.agents/skills/lark-slides/scripts/template_tool_test.py
ooodc a7883dbed9 refactor(todo): 重构待办事项管理逻辑及更新状态规则
- 移除 TodoItem 中的 priority、created_at 和 updated_at 字段
- 强制每个任务都必须有唯一 id,且由用户负责生成
- 修改合并模式逻辑,merge=true 下保留未提及的旧任务
- 支持已完成和已取消任务重新激活(状态改回 pending 或 in_progress)
- 禁止 in_progress 状态退回到 pending,必须标记为 completed 或 cancelled
- 优化状态转换校验,允许特定状态间合法切换
- 简化任务变更消息,移除详细的新增/更新/移除统计
- 更新文档和示例,明确 id 必须由用户生成和使用
- 修复和补充测试,增强状态转换和合并模式验证
- 调整任务时间戳生成逻辑,统一使用当前时间及索引
- 该变更提供更合理的任务状态机械及管理模式,提升稳定性和易用性
2026-06-13 09:22:33 +08:00

178 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (c) 2026 Lark Technologies Pte. Ltd.
# SPDX-License-Identifier: MIT
from __future__ import annotations
import tempfile
import unittest
from pathlib import Path
import template_tool
class TemplateToolTest(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.index_data = template_tool.build_index_data()
def test_build_index_data_exposes_light_general_metadata(self) -> None:
template = next(
entry for entry in self.index_data["templates"] if entry["template_id"] == "office--light_general"
)
expected_keys = {
"template_id",
"category",
"category_label",
"scene",
"tone",
"formality",
"is_general_template",
"slide_count",
"presentation_title",
"palette",
"structure",
"page_types",
"layout_tags",
"use_cases",
"ranges",
}
self.assertEqual(set(template.keys()), expected_keys)
self.assertEqual(template["tone"], "light")
self.assertEqual(template["formality"], "formal")
self.assertEqual(template["slide_count"], 54)
self.assertEqual(template["presentation_title"], "白底通用模板")
self.assertIsInstance(template["layout_tags"], list)
self.assertNotIn("theme_summary", template)
self.assertNotIn("editable_regions", template)
self.assertNotIn("bbox_summary", template)
def test_search_templates_keeps_work_report_templates_in_top_results(self) -> None:
results = template_tool.search_templates(self.index_data, {"query": "工作汇报", "limit": 3})
self.assertTrue(results)
self.assertTrue(any(entry["template_id"] == "office--work_report" for entry in results))
def test_search_templates_extracts_scene_from_long_chinese_prompt(self) -> None:
results = template_tool.search_templates(
self.index_data,
{"query": "帮我做一个季度工作汇报PPT偏正式", "limit": 3},
)
self.assertTrue(results)
self.assertTrue(any(entry["template_id"] == "office--work_report" for entry in results))
def test_search_templates_maps_chinese_tone_words(self) -> None:
results = template_tool.search_templates(
self.index_data,
{"query": "深色科技感产品发布", "limit": 5},
)
self.assertTrue(results)
self.assertTrue(any(entry["tone"] == "dark" for entry in results))
def test_search_templates_finds_product_launch_and_promotion_defense(self) -> None:
product_results = template_tool.search_templates(
self.index_data,
{"query": "产品发布会新品介绍", "limit": 5},
)
self.assertTrue(product_results)
self.assertTrue(
any(
entry["template_id"]
in {"office--project_kickoff", "product--product_intro", "product--product_promotion"}
for entry in product_results
)
)
defense_results = template_tool.search_templates(
self.index_data,
{"query": "晋升答辩 个人述职", "limit": 5},
)
self.assertTrue(defense_results)
self.assertTrue(any(entry["template_id"] == "personal--promotion_defense" for entry in defense_results))
def test_extract_selection_xml_keeps_only_requested_slides_and_theme(self) -> None:
xml = template_tool.extract_selection_xml(self.index_data, "office--light_general", {"label": "封面"})
self.assertEqual(len(template_tool.re.findall(r"<slide\b", xml)), 2)
self.assertIn("<theme>", xml)
self.assertIn("<title>白底通用模板</title>", xml)
def test_summarize_selection_aggregates_slide_titles_and_counts(self) -> None:
summary = template_tool.summarize_selection(self.index_data, "office--light_general", {"label": "封面"})
self.assertEqual(summary["selection"]["range"], "1-2")
self.assertEqual(summary["summary"]["slide_count"], 2)
self.assertTrue(summary["theme_summary"]["has_theme_node"])
self.assertIn("通用模板", summary["summary"]["title_hints"])
self.assertGreater(summary["summary"]["element_totals"]["shape"], 0)
self.assertIsInstance(summary["slides"][0]["layout_tags"], list)
self.assertIn("bbox_summary", summary["slides"][0])
self.assertIn("editable_regions", summary["slides"][0])
def test_template_selector_accepts_catalog_visible_filename(self) -> None:
entry = template_tool.resolve_template_entry(self.index_data, "work_report.xml")
self.assertEqual(entry["template_id"], "office--work_report")
def test_template_path_uses_user_supplied_file(self) -> None:
source_path = template_tool.TEMPLATES_DIR / "office--work_report.xml"
with tempfile.TemporaryDirectory() as temp_dir:
copied_path = Path(temp_dir) / "work_report.xml"
copied_path.write_text(
source_path.read_text(encoding="utf-8").replace(
"<title>工作汇报</title>",
"<title>Copied Path Template</title>",
1,
),
encoding="utf-8",
)
xml = template_tool.extract_selection_xml(
self.index_data,
str(copied_path),
{"range": "1"},
)
self.assertIn("<title>Copied Path Template</title>", xml)
def test_template_path_accepts_unindexed_xml_with_range(self) -> None:
xml = (
'<presentation xmlns="http://www.larkoffice.com/sml/2.0">'
"<title>Generated Template</title>"
"<slide><data></data></slide>"
"</presentation>"
)
with tempfile.TemporaryDirectory() as temp_dir:
template_path = Path(temp_dir) / "generated.xml"
template_path.write_text(xml, encoding="utf-8")
extracted = template_tool.extract_selection_xml(
self.index_data,
str(template_path),
{"range": "1"},
)
self.assertIn("<title>Generated Template</title>", extracted)
def test_search_templates_supports_layout_tag_filtering(self) -> None:
results = template_tool.search_templates(
self.index_data,
{"query": "", "layout-tag": "full-bleed-image-caption", "limit": 10},
)
self.assertTrue(results)
self.assertTrue(
any("full-bleed-image-caption" in entry["layout_tags"] for entry in results)
)
def test_all_template_files_are_cataloged_and_indexed(self) -> None:
template_files = sorted(path.stem for path in template_tool.TEMPLATES_DIR.glob("*.xml"))
indexed_templates = sorted(entry["template_id"] for entry in self.index_data["templates"])
self.assertEqual(indexed_templates, template_files)
self.assertEqual(self.index_data["template_count"], len(template_files))
self.assertTrue(template_files)
def test_catalog_range_parser_keeps_comma_separated_ranges(self) -> None:
template = next(
entry for entry in self.index_data["templates"] if entry["template_id"] == "operations--product_promotion"
)
content_range = next(item for item in template["ranges"] if item["label"] == "内容")
self.assertEqual(content_range["range"], "3-8, 10-12")
if __name__ == "__main__":
unittest.main()