"""Unit tests for the active-section boundary — the authoritative computation the refinement endpoint uses (client mirrors it only for a visual hint).""" from app.authoring.sections import active_section, slice_lines DOC = """## Zweck Dieser Ablauf beschreibt die Rechnungsstellung. ## Ablauf Erst exportieren, dann versenden. ## Fallstricke """ def _span(md: str, cursor_line: int) -> tuple[int, int]: section = active_section(md, cursor_line) return section.start_line, section.end_line def test_cursor_in_a_section_selects_from_its_heading_to_the_next() -> None: # Line 5 is "Erst exportieren, dann versenden." under "## Ablauf" (line 4). assert _span(DOC, 5) == (4, 5) _prefix, section, _suffix = slice_lines(DOC, 4, 5) assert section == "## Ablauf\nErst exportieren, dann versenden." def test_cursor_on_the_heading_selects_that_section() -> None: assert _span(DOC, 1) == (1, 2) def test_trailing_blank_lines_are_excluded() -> None: # "## Ablauf" body is followed by a blank line before "## Fallstricke"; # the blank must not be part of the section. start, end = _span(DOC, 4) assert (start, end) == (4, 5) def test_content_before_the_first_heading_is_its_own_section() -> None: md = "Eine Einleitung ohne Überschrift.\n\n## Danach\nText." assert _span(md, 1) == (1, 1) def test_a_document_without_headings_is_one_section() -> None: md = "Nur Fließtext.\nZweite Zeile." assert _span(md, 2) == (1, 2) def test_nested_headings_stop_at_a_same_or_higher_level() -> None: md = "## A\natext\n### A1\nsub\n## B\nbtext" # Cursor in "## A" (line 1) spans through its subsection "### A1" up to # the line before "## B". assert _span(md, 1) == (1, 4) # Cursor in the subsection spans only the subsection. assert _span(md, 4) == (3, 4) def test_a_heading_inside_a_code_fence_is_not_a_boundary() -> None: md = "## Code\n```\n## nicht echt\n```\nfertig" assert _span(md, 3) == (1, 5) def test_a_large_section_narrows_to_the_paragraph_at_the_cursor() -> None: big = "\n\n".join(f"Absatz {i} " + "x" * 400 for i in range(6)) md = f"## Groß\n{big}" start, end = _span(md, 6) # somewhere deep in the section _prefix, section, _suffix = slice_lines(md, start, end) # Narrowed: a single paragraph, not the whole oversized section. assert "\n\n" not in section assert section.startswith("Absatz")