""" tests/test_emoji_markup_parser.py EmojiMarkupParser 단위 테스트 """ import pytest from ctstruct import NodeType from ctstruct.parsers import EmojiMarkupParser SAMPLE = """\ ✅예시 양식 🔹1번 항목 홍길동 홍길순 홍길영 홍길준 홍길호 홍길윤 🔹2번 항목 🔸2-1 항목 (건강) 홍길찬 홍길만 🔸2-2 항목 (직장) 홍길주 """ @pytest.fixture def tree(): return EmojiMarkupParser().parse(SAMPLE) # ── 문서 제목 ───────────────────────────────────────────────────────────────── class TestTitle: def test_title_set(self, tree): assert tree.root.attr("title") == "예시 양식" # ── 섹션 구조 ───────────────────────────────────────────────────────────────── class TestSections: def test_two_top_sections(self, tree): secs = [n for n in tree.root.children if n.node_type == NodeType.SECTION] assert len(secs) == 2 def test_section1_name(self, tree): sec = tree.root.children[0] assert sec.content == "1번 항목" assert sec.attr("level") == 1 def test_section2_name(self, tree): sec = tree.root.children[1] assert sec.content == "2번 항목" assert sec.attr("level") == 1 def test_subsections_under_section2(self, tree): sec2 = tree.root.children[1] subsecs = [n for n in sec2.children if n.node_type == NodeType.SECTION] assert len(subsecs) == 2 assert subsecs[0].content == "2-1 항목" assert subsecs[1].content == "2-2 항목" def test_subsection_level(self, tree): sec2 = tree.root.children[1] for sub in sec2.children: assert sub.attr("level") == 2 # ── 명단 ───────────────────────────────────────────────────────────────────── class TestNameLists: def test_section1_has_one_list(self, tree): sec1 = tree.root.children[0] lists = [n for n in sec1.children if n.node_type == NodeType.LIST] assert len(lists) == 1 def test_section1_names_across_lines(self, tree): sec1 = tree.root.children[0] lst = next(n for n in sec1.children if n.node_type == NodeType.LIST) names = [item.content for item in lst.children] assert names == ["홍길동", "홍길순", "홍길영", "홍길준", "홍길호", "홍길윤"] def test_section1_no_category(self, tree): sec1 = tree.root.children[0] lst = next(n for n in sec1.children if n.node_type == NodeType.LIST) assert lst.attr("category") is None def test_subsec_21_category(self, tree): sub21 = tree.root.children[1].children[0] lst = next(n for n in sub21.children if n.node_type == NodeType.LIST) assert lst.attr("category") == "건강" def test_subsec_21_names(self, tree): sub21 = tree.root.children[1].children[0] lst = next(n for n in sub21.children if n.node_type == NodeType.LIST) names = [item.content for item in lst.children] assert names == ["홍길찬", "홍길만"] def test_subsec_22_category(self, tree): sub22 = tree.root.children[1].children[1] lst = next(n for n in sub22.children if n.node_type == NodeType.LIST) assert lst.attr("category") == "직장" def test_subsec_22_names(self, tree): sub22 = tree.root.children[1].children[1] lst = next(n for n in sub22.children if n.node_type == NodeType.LIST) names = [item.content for item in lst.children] assert names == ["홍길주"] def test_all_list_items_are_leaf(self, tree): for item in tree.find(NodeType.LIST_ITEM): assert item.is_leaf # ── 전체 통계 ───────────────────────────────────────────────────────────────── class TestStats: def test_total_names(self, tree): assert len(tree.find(NodeType.LIST_ITEM)) == 9 def test_total_lists(self, tree): assert len(tree.find(NodeType.LIST)) == 3 def test_total_sections(self, tree): secs = tree.find(NodeType.SECTION) assert len(secs) == 4 # 🔹2 + 🔸2 # ── 엣지 케이스 ─────────────────────────────────────────────────────────────── class TestEdgeCases: def test_empty_string(self): tree = EmojiMarkupParser().parse("") assert tree.root.attr("title") is None assert len(tree.root.children) == 0 def test_title_only(self): tree = EmojiMarkupParser().parse("✅제목만") assert tree.root.attr("title") == "제목만" assert len(tree.root.children) == 0 def test_multiple_categories_in_section(self): text = "🔹항목\n(A) 홍길동\n\n(B) 홍길순\n" tree = EmojiMarkupParser().parse(text) sec = tree.root.children[0] lists = [n for n in sec.children if n.node_type == NodeType.LIST] assert len(lists) == 2 assert lists[0].attr("category") == "A" assert lists[1].attr("category") == "B" def test_names_without_section(self): tree = EmojiMarkupParser().parse("홍길동 홍길순\n홍길영\n") lst = tree.find(NodeType.LIST) assert len(lst) == 1 assert len(lst[0].children) == 3 def test_category_names_on_separate_line(self): # 카테고리 줄 다음에 이름이 없고 다음 줄에 이름이 있는 경우 text = "🔹항목\n(건강)\n홍길동 홍길순\n" tree = EmojiMarkupParser().parse(text) sec = tree.root.children[0] lst = next(n for n in sec.children if n.node_type == NodeType.LIST) assert lst.attr("category") == "건강" assert len(lst.children) == 2