from genesis.data_models import ChapterMarker, ParsedTemplate from genesis.writer.models import ChapterSpec from genesis.writer.template_mapper import map_template def _parsed(): sections = [ ChapterMarker(type="heading", name="はじめに", level=1), ChapterMarker(type="placeholder", name="section:introduction", level=0), ChapterMarker(type="heading", name="DB 設計", level=1), ChapterMarker(type="placeholder", name="section:db_design", level=0), ChapterMarker(type="bookmark", name="bm1", level=0), ] return ParsedTemplate(file_name="t.docx", sections=sections, placeholders={"section:introduction": "x"}, styles={}) def test_map_template_ordered_and_assigns_ids(): specs = map_template(_parsed()) assert [s.title for s in specs] == ["はじめに", "DB 設計"] assert specs[0].chapter_id == "introduction" assert specs[0].section_placeholder == "section:introduction" assert specs[1].chapter_id == "db_design" assert specs[1].section_placeholder == "section:db_design" assert all(isinstance(s, ChapterSpec) for s in specs) def test_map_template_falls_back_without_placeholder(): sections = [ChapterMarker(type="heading", name="附録", level=1)] parsed = ParsedTemplate(file_name="t.docx", sections=sections, placeholders={}, styles={}) specs = map_template(parsed) assert specs[0].chapter_id == "chapter_1" assert specs[0].section_placeholder is None def test_map_template_section_re_case_insensitive(): # 宽容:占位符键名大小写不敏感(解析端已归一,防御性双保险) sections = [ ChapterMarker(type="heading", name="画面一覧", level=1), ChapterMarker(type="placeholder", name="Section:2", level=0), ] parsed = ParsedTemplate(file_name="t.docx", sections=sections, placeholders={}, styles={}) specs = map_template(parsed) assert specs[0].chapter_id == "2" assert specs[0].section_placeholder == "Section:2" # ---------- design.md §6.5:H1 起章,H2/H3 归入本章作为子节(不再独立成章被丢弃) ---------- def test_h2_headings_merge_into_parent_chapter(): sections = [ ChapterMarker(type="heading", name="2. 機能一覧", level=1), ChapterMarker(type="placeholder", name="section:function_list", level=0), ChapterMarker(type="heading", name="2.1 機能一覧表", level=2), ChapterMarker(type="heading", name="2.2 機能詳細", level=2), ] parsed = ParsedTemplate(file_name="t.docx", sections=sections, placeholders={}, styles={}) specs = map_template(parsed) assert len(specs) == 1 s = specs[0] assert s.chapter_id == "function_list" assert s.title == "2. 機能一覧" assert s.sub_headings == ["2.1 機能一覧表", "2.2 機能詳細"] def test_h3_headings_also_merge(): sections = [ ChapterMarker(type="heading", name="5. DB設計", level=1), ChapterMarker(type="placeholder", name="section:db_design", level=0), ChapterMarker(type="heading", name="5.1 テーブル一覧", level=2), ChapterMarker(type="heading", name="5.1.1 補足", level=3), ] parsed = ParsedTemplate(file_name="t.docx", sections=sections, placeholders={}, styles={}) specs = map_template(parsed) assert len(specs) == 1 assert specs[0].sub_headings == ["5.1 テーブル一覧", "5.1.1 補足"] def test_leading_h2_without_parent_starts_chapter(): """异常模板防御:任何 H1 之前出现 H2 → 回落为独立章(不崩溃、不静默丢弃)。""" sections = [ ChapterMarker(type="heading", name="孤立节", level=2), ChapterMarker(type="heading", name="1. はじめに", level=1), ] parsed = ParsedTemplate(file_name="t.docx", sections=sections, placeholders={}, styles={}) specs = map_template(parsed) assert [s.title for s in specs] == ["孤立节", "1. はじめに"] assert specs[0].sub_headings == []