PyOrgPatcher/code/test_orgpatch.py

131 lines
4.2 KiB
Python
Executable File

import sys
from pathlib import Path
# Import module from same folder
sys.path.insert(0, str(Path(__file__).parent))
import orgpatch as op
EXAMPLE_ORG = """* Main Title
** Introduction
Some intro text.
#+NAME: intro-para
This is a named paragraph that will be replaced.
It continues until the first blank line.
** Data
#+NAME: mytable
| Item | Value |
|------+-------|
| A | 1 |
| B | 2 |
** Code
#+NAME: code-snippet
#+BEGIN_SRC python
print("hello world")
#+END_SRC
** My Section
This section body will be replaced.
It ends at the next heading of level ** or *.
** Another Section
Content of another section.
"""
def write(p: Path, text: str):
p.write_text(text, encoding="utf-8")
def test_parse_headings_and_sections(tmp_path: Path):
org = tmp_path / "example.org"
write(org, EXAMPLE_ORG)
lines = op.read_lines(str(org))
heads = op.parse_headings(lines)
titles = [h['title'] for h in heads]
assert "Introduction" in titles
assert "My Section" in titles
b = op.section_bounds(lines, heads, "** My Section")
assert b is not None
s, e = b
body = ''.join(lines[s:e])
assert "This section body will be replaced." in body
def test_parse_named_elements(tmp_path: Path):
org = tmp_path / "example.org"
write(org, EXAMPLE_ORG)
lines = op.read_lines(str(org))
elems = op.parse_named_elements(lines)
names = {e['name']: e for e in elems}
assert names['intro-para']['type'] == 'para'
assert names['mytable']['type'] == 'table'
assert names['code-snippet']['type'] == 'block'
def test_replace_section(tmp_path: Path):
org = tmp_path / "example.org"
write(org, EXAMPLE_ORG)
lines = op.read_lines(str(org))
out = op.replace_section(lines, "** My Section", "New body\nMore\n")
joined = ''.join(out)
assert "New body" in joined
assert "This section body will be replaced." not in joined
def test_replace_named_block_table_para(tmp_path: Path):
org = tmp_path / "example.org"
write(org, EXAMPLE_ORG)
lines = op.read_lines(str(org))
out = op.replace_named(lines, "code-snippet", "print('updated')\n")
assert "print('updated')" in ''.join(out)
out2 = op.replace_named(out, "mytable", "| X | 9 |\n")
assert "| X | 9 |" in ''.join(out2)
out3 = op.replace_named(out2, "intro-para", "New intro\nSecond\n")
j3 = ''.join(out3)
assert "New intro" in j3
assert "named paragraph that will be replaced" not in j3
def test_sync_in_and_out(tmp_path: Path):
org = tmp_path / "example.org"
write(org, EXAMPLE_ORG)
code_src = tmp_path / "code.py"
tbl_src = tmp_path / "tbl.org"
sec_src = tmp_path / "section.txt"
para_src = tmp_path / "intro.txt"
write(code_src, "print('via in')\n")
write(tbl_src, "| Col | Val |\n|-----+-----|\n| A | 1 |\n")
write(sec_src, "Replaced via sync in.\nSecond line.\n")
write(para_src, "Intro via sync in.\n\n")
mapping = [
{"name": "code-snippet", "file": str(code_src)},
{"name": "mytable", "file": str(tbl_src)},
{"section": "** My Section", "file": str(sec_src)},
{"name": "intro-para", "file": str(para_src)},
]
lines = op.read_lines(str(org))
new_lines = op.sync_apply_in(lines, mapping)
out = ''.join(new_lines)
assert "print('via in')" in out
assert "| Col | Val |" in out
assert "Replaced via sync in." in out
assert "Intro via sync in." in out
export_dir = tmp_path / "exported"
export_dir.mkdir()
m_out = [
{"name": "code-snippet", "file": str(export_dir / "code.py")},
{"name": "mytable", "file": str(export_dir / "table.org")},
{"section": "** My Section", "file": str(export_dir / "section.txt")},
{"name": "intro-para", "file": str(export_dir / "intro.txt")},
]
op.sync_apply_out(new_lines, m_out, mkdirs=True, overwrite=True)
assert (export_dir / "code.py").read_text(encoding="utf-8").strip() == "print('via in')"
assert "| Col | Val |" in (export_dir / "table.org").read_text(encoding="utf-8")
assert "Replaced via sync in." in (export_dir / "section.txt").read_text(encoding="utf-8")
assert "Intro via sync in." in (export_dir / "intro.txt").read_text(encoding="utf-8")