Files
markitect-tool/tests/test_ops_transform_compose_include.py

160 lines
4.5 KiB
Python

from pathlib import Path
import pytest
from click.testing import CliRunner
from markitect_tool.cli import main
from markitect_tool.ops import (
IncludeError,
compose_files,
resolve_includes,
transform_markdown,
)
def test_transform_sets_frontmatter_and_shifts_headings():
markdown = """---
title: Original
---
# Intro
## Detail
"""
result = transform_markdown(
markdown,
set_frontmatter={"status": "draft", "nested": {"owner": "Docs"}},
heading_delta=1,
)
assert "title: Original" in result.markdown
assert "status: draft" in result.markdown
assert "owner: Docs" in result.markdown
assert "## Intro" in result.markdown
assert "### Detail" in result.markdown
assert result.operations == ["set_frontmatter", "shift_headings:1"]
def test_transform_extracts_selector_text():
markdown = """# Doc
## Keep
This section should remain.
## Drop
This section should not remain.
"""
result = transform_markdown(markdown, extract_selector="sections[heading=Keep]")
assert result.markdown == "## Keep\n\nThis section should remain."
assert "Drop" not in result.markdown
def test_compose_files_adds_title_and_separators(tmp_path: Path):
one = tmp_path / "one.md"
two = tmp_path / "two.md"
one.write_text("# One\n\nText one.", encoding="utf-8")
two.write_text("---\ntitle: Two\n---\n\n# Two\n\nText two.", encoding="utf-8")
result = compose_files([one, two], title="Combined", heading_delta=1)
assert result.sources == [str(one), str(two)]
assert result.markdown.startswith("# Combined")
assert "## One" in result.markdown
assert "## Two" in result.markdown
assert "title: Two" not in result.markdown
assert "\n\n---\n\n" in result.markdown
def test_resolve_includes_supports_comment_marker_selector_and_heading_shift(tmp_path: Path):
partial = tmp_path / "partial.md"
partial.write_text(
"""# Partial
## Keep
Selected text.
## Drop
Nope.
""",
encoding="utf-8",
)
markdown = '<!-- mkt:include path="partial.md" selector="sections[heading=Keep]" heading_delta="1" -->'
result = resolve_includes(markdown, base_dir=tmp_path)
assert result.included_paths == [str(partial.resolve())]
assert "### Keep" in result.markdown
assert "Selected text" in result.markdown
assert "Drop" not in result.markdown
def test_resolve_includes_supports_brace_shorthand(tmp_path: Path):
partial = tmp_path / "partial.md"
partial.write_text("Included body.", encoding="utf-8")
result = resolve_includes("Before\n\n{{include:partial.md}}\n\nAfter", base_dir=tmp_path)
assert "Before" in result.markdown
assert "Included body." in result.markdown
assert "After" in result.markdown
def test_resolve_includes_rejects_cycles(tmp_path: Path):
one = tmp_path / "one.md"
two = tmp_path / "two.md"
one.write_text("{{include:two.md}}", encoding="utf-8")
two.write_text("{{include:one.md}}", encoding="utf-8")
with pytest.raises(IncludeError, match="Circular include"):
resolve_includes(one.read_text(encoding="utf-8"), base_dir=tmp_path, current_path=one)
def test_resolve_includes_rejects_paths_outside_base_dir(tmp_path: Path):
outside = tmp_path.parent / "outside.md"
outside.write_text("Nope", encoding="utf-8")
with pytest.raises(IncludeError, match="escapes base directory"):
resolve_includes("{{include:../outside.md}}", base_dir=tmp_path)
def test_mkt_transform_writes_markdown(tmp_path: Path):
source = tmp_path / "doc.md"
source.write_text("# One\n", encoding="utf-8")
result = CliRunner().invoke(
main, ["transform", str(source), "--heading-delta", "1", "--set", "status=draft"]
)
assert result.exit_code == 0
assert "status: draft" in result.output
assert "## One" in result.output
def test_mkt_compose_writes_output_file(tmp_path: Path):
one = tmp_path / "one.md"
output = tmp_path / "out.md"
one.write_text("# One\n", encoding="utf-8")
result = CliRunner().invoke(main, ["compose", str(one), "--title", "Combined", "--output", str(output)])
assert result.exit_code == 0
assert result.output == ""
assert output.read_text(encoding="utf-8").startswith("# Combined")
def test_mkt_include_reports_errors(tmp_path: Path):
source = tmp_path / "doc.md"
source.write_text("{{include:missing.md}}", encoding="utf-8")
result = CliRunner().invoke(main, ["include", str(source)])
assert result.exit_code == 1
assert "Included file not found" in result.output