import unittest from app.features.memoir.chapter_markdown_compose import ( compose_ordered_stories_to_markdown, compose_ordered_stories_to_pdf_markdown, materialize_chapter_markdown_from_loaded_chapter, ) class ChapterMarkdownComposeTest(unittest.TestCase): def test_joins_bodies_with_hr_only_no_story_headings(self): md = compose_ordered_stories_to_markdown( [("第一章", "正文A"), ("第二章", "正文B")] ) self.assertNotIn("##", md) self.assertIn("正文A", md) self.assertIn("正文B", md) self.assertIn("\n\n---\n\n", md) self.assertTrue(md.index("正文A") < md.index("---")) self.assertTrue(md.index("---") < md.index("正文B")) def test_preserves_asset_refs(self): body = "![x](asset://abc-123)" md = compose_ordered_stories_to_markdown([("S", body)]) self.assertIn("asset://abc-123", md) def test_empty_title_still_composes_body(self): md = compose_ordered_stories_to_markdown([("", "仅正文")]) self.assertEqual(md, "仅正文") self.assertNotIn("##", md) def test_empty_body_skipped(self): md = compose_ordered_stories_to_markdown([("仅标题", "")]) self.assertEqual(md, "") def test_pdf_markdown_includes_story_headings(self): md = compose_ordered_stories_to_pdf_markdown( [("第一章", "正文A"), ("第二章", "正文B")] ) self.assertIn("## 第一章", md) self.assertIn("## 第二章", md) def test_materialize_respects_order_index(self): class _S: def __init__(self, title: str, body: str): self.title = title self.canonical_markdown = body class _L: def __init__(self, o: int, story: _S): self.order_index = o self.story = story ch = type( "Ch", (), { "story_links": [ _L(1, _S("B", "后")), _L(0, _S("A", "先")), ] }, )() md = materialize_chapter_markdown_from_loaded_chapter(ch) self.assertLess(md.index("先"), md.index("后")) self.assertNotIn("##", md)