"""Tests for pure helpers in mytoolkit.md_to_pdf (no pandoc/typst needed).""" import shutil import pytest from mytoolkit.md_to_pdf import ( _consume_balanced, _longest_backtick_run, _odd_fenced_code_before, _typst_raw_fence, preprocess_typst_callouts, resolve_markdown_image_paths, ) class TestResolveMarkdownImagePaths: def test_relative_path_resolved_when_file_exists(self, tmp_path): (tmp_path / "figs").mkdir() (tmp_path / "figs" / "a.png").write_bytes(b"png") out = resolve_markdown_image_paths("![alt](figs/a.png)", tmp_path) assert out == f"![alt]({tmp_path / 'figs' / 'a.png'})" def test_missing_file_left_unchanged(self, tmp_path): md = "![alt](figs/nope.png)" assert resolve_markdown_image_paths(md, tmp_path) == md @pytest.mark.parametrize( "src", ["https://x.com/a.png", "http://x.com/a.png", "data:image/png;base64,AA", "#frag"], ) def test_urls_and_anchors_untouched(self, tmp_path, src): md = f"![alt]({src})" assert resolve_markdown_image_paths(md, tmp_path) == md def test_absolute_path_untouched(self, tmp_path): md = "![alt](/abs/path/a.png)" assert resolve_markdown_image_paths(md, tmp_path) == md def test_html_img_tag_resolved(self, tmp_path): (tmp_path / "a.png").write_bytes(b"png") out = resolve_markdown_image_paths('', tmp_path) assert out == f'' class TestBacktickFenceHelpers: @pytest.mark.parametrize( ("s", "expected"), [("", 0), ("a`b", 1), ("``x```y", 3), ("````", 4)], ) def test_longest_backtick_run(self, s, expected): assert _longest_backtick_run(s) == expected def test_raw_fence_at_least_three(self): assert _typst_raw_fence("plain") == "```" def test_raw_fence_exceeds_inner_run(self): assert _typst_raw_fence("has ``` inside") == "````" class TestBalancedConsume: def test_simple(self): assert _consume_balanced("(a(b)c)", 0, "(", ")") == 7 def test_not_open_char(self): assert _consume_balanced("x()", 0, "(", ")") is None def test_unbalanced(self): assert _consume_balanced("(a(b)", 0, "(", ")") is None def test_quoted_chars_ignored(self): assert _consume_balanced('(")")x', 0, "(", ")") == 5 class TestOddFencedCode: def test_inside_fence(self): md = "```\ncode\n" assert _odd_fenced_code_before(md, len(md)) is True def test_outside_fence(self): md = "```\ncode\n```\n" assert _odd_fenced_code_before(md, len(md)) is False @pytest.mark.skipif(not shutil.which("pandoc"), reason="pandoc not installed") class TestPreprocessTypstCallouts: def test_info_box_wrapped_in_raw_typst(self): md = "#info-box[\nHello **world**\n]\n" out = preprocess_typst_callouts(md) assert "{=typst}" in out assert "#info-box[" in out def test_callout_inside_code_fence_untouched(self): md = "```\n#info-box[\nx\n]\n```\n" assert preprocess_typst_callouts(md) == md