import textwrap from lib import markdown_parser def make_empty_state(): return { 'page': {'title': None, 'sections': []}, 'current_section': None, 'current_card': None, 'current_detail': None, 'content_buffer': [], 'detail_buffer': [], } def test_flush_detail_buffer(): state = make_empty_state() state['current_detail'] = {'title': 'D', 'content': ''} state['detail_buffer'] = ['Line 1', 'Line 2'] markdown_parser.flush_detail_buffer(state) assert 'Line 1' in state['current_detail']['content'] assert state['detail_buffer'] == [] def test_flush_content_buffer_to_card(): state = make_empty_state() state['current_card'] = {'title': 'C', 'content': ''} state['content_buffer'] = ['para 1', 'para 2'] markdown_parser.flush_content_buffer_to_card(state) assert 'para 1' in state['current_card']['content'] def test_flush_content_buffer_to_section(): state = make_empty_state() state['current_section'] = {'title': 'S', 'content': '', 'cards': []} state['content_buffer'] = ['a', 'b'] markdown_parser.flush_content_buffer_to_section(state) assert 'a' in state['current_section']['content'] def test_start_section_and_card_and_detail_and_process_line(): state = make_empty_state() # start a section markdown_parser.start_section('Sec1', state) assert state['current_section']['title'] == 'Sec1' assert state['page']['sections'][0]['title'] == 'Sec1' # start a card markdown_parser.start_card('Card1', state) assert state['current_card']['title'] == 'Card1' assert state['page']['sections'][0]['cards'][0]['title'] == 'Card1' # start a detail markdown_parser.start_detail('Det1', state) assert state['current_detail']['title'] == 'Det1' # process a normal content line into detail_buffer markdown_parser.process_line_with_state('Detail line 1', state) assert 'Detail line 1' in state['detail_buffer'][0] # process an H3 to start a new card markdown_parser.process_line_with_state('### NewCard', state) assert state['current_card']['title'] == 'NewCard' # process an H2 to start a new section markdown_parser.process_line_with_state('## NewSection', state) assert state['current_section']['title'] == 'NewSection' def test_start_card_without_section_is_noop(): state = make_empty_state() markdown_parser.start_card('Orphan', state) assert state['current_card'] is None assert state['page']['sections'] == [] def test_start_detail_without_card_is_noop(): state = make_empty_state() markdown_parser.start_detail('Detail', state) assert state['current_detail'] is None assert state['detail_buffer'] == [] def test_process_h4_without_card_is_treated_as_content(): state = make_empty_state() markdown_parser.process_line_with_state('#### Heading without card', state) assert '#### Heading without card' in state['content_buffer'] def test_process_new_h1_flushes_section_content(): state = make_empty_state() markdown_parser.start_section('First', state) state['content_buffer'].append('Paragraph text') markdown_parser.process_line_with_state('# New Page', state) assert 'Paragraph text' in state['page']['sections'][0]['content'] assert state['page']['title'] == 'New Page' def test_build_component_structure_matches_integration(): md = textwrap.dedent(""" # Title ## Section A ### Card A Intro A #### Detail X Line X """) page = markdown_parser.build_component_structure(md, 'f.md') assert page['title'] == 'Title' assert page['sections'][0]['title'] == 'Section A' card = page['sections'][0]['cards'][0] assert card['title'] == 'Card A' assert 'Intro A' in card['content'] assert 'Detail X' in card['details'][0]['title']