aboutsummaryrefslogtreecommitdiff
path: root/tests/test-pearl-convert.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-pearl-convert.el')
-rw-r--r--tests/test-pearl-convert.el172
1 files changed, 172 insertions, 0 deletions
diff --git a/tests/test-pearl-convert.el b/tests/test-pearl-convert.el
new file mode 100644
index 0000000..4125e22
--- /dev/null
+++ b/tests/test-pearl-convert.el
@@ -0,0 +1,172 @@
+;;; test-pearl-convert.el --- Tests for the markdown->org conversion -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 Craig Jennings
+
+;; Author: Craig Jennings <c@cjennings.net>
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for `pearl--md-to-org' and `pearl--md-line-to-org' --
+;; the pure-elisp markdown->org conversion tier. Cover each supported
+;; construct (links, inline code, bold, underscore italics, headings, bullets,
+;; fenced code), the heading-safety guard, and literal pass-through.
+
+;;; Code:
+
+(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))
+
+;;; inline conversion
+
+(ert-deftest test-pearl-convert-link ()
+ "A markdown link becomes an org link with url and label swapped."
+ (should (string= "see [[https://x.y][the docs]] now"
+ (pearl--md-line-to-org "see [the docs](https://x.y) now"))))
+
+(ert-deftest test-pearl-convert-inline-code ()
+ "Inline code backticks become org verbatim tildes."
+ (should (string= "call ~foo()~ here"
+ (pearl--md-line-to-org "call `foo()` here"))))
+
+(ert-deftest test-pearl-convert-bold ()
+ "Markdown bold becomes org bold."
+ (should (string= "a *strong* word" (pearl--md-line-to-org "a **strong** word"))))
+
+(ert-deftest test-pearl-convert-italic-underscore ()
+ "Underscore italics become org italics, but identifiers are left alone."
+ (should (string= "an /emphatic/ point"
+ (pearl--md-line-to-org "an _emphatic_ point")))
+ (should (string= "the foo_bar_baz name"
+ (pearl--md-line-to-org "the foo_bar_baz name"))))
+
+;;; line / block conversion
+
+(ert-deftest test-pearl-convert-heading-to-bold ()
+ "A markdown heading becomes a bold line, never an org heading."
+ (let ((out (pearl--md-to-org "## Big Heading")))
+ (should (string= "*Big Heading*" out))
+ (should-not (string-match-p "^\\*+ " out))))
+
+(ert-deftest test-pearl-convert-bullets ()
+ "Markdown `*' and `+' bullets become org `-' bullets."
+ (should (string= "- one\n- two"
+ (pearl--md-to-org "* one\n+ two"))))
+
+(ert-deftest test-pearl-convert-fenced-code ()
+ "A fenced code block becomes a src block, verbatim inside."
+ (should (string= "#+begin_src elisp\n(+ 1 2)\n#+end_src"
+ (pearl--md-to-org "```elisp\n(+ 1 2)\n```"))))
+
+(ert-deftest test-pearl-convert-code-block-is-verbatim ()
+ "Inline markup inside a fenced block is not converted."
+ (let ((out (pearl--md-to-org "```\n**not bold** here\n```")))
+ (should (string-match-p "\\*\\*not bold\\*\\*" out))))
+
+(ert-deftest test-pearl-convert-guards-heading-line ()
+ "A non-bullet line that Org would read as a heading is space-guarded."
+ (let ((out (pearl--md-to-org "** looks like a heading")))
+ (should-not (string-match-p "^\\*+ " out))
+ (should (string-prefix-p " " out))))
+
+(ert-deftest test-pearl-convert-passes-through-plain-and-tables ()
+ "Plain text and unsupported constructs (tables) pass through unchanged."
+ (should (string= "just some text" (pearl--md-to-org "just some text")))
+ (should (string= "| a | b |\n|---|---|"
+ (pearl--md-to-org "| a | b |\n|---|---|"))))
+
+(ert-deftest test-pearl-convert-empty ()
+ "An empty or nil description converts to the empty string."
+ (should (string= "" (pearl--md-to-org "")))
+ (should (string= "" (pearl--md-to-org nil))))
+
+;;; org -> markdown (the push direction)
+
+(ert-deftest test-pearl-org-to-md-link ()
+ "An org link becomes a markdown link with label and url swapped back."
+ (should (string= "see [the docs](https://x.y) now"
+ (pearl--org-line-to-md "see [[https://x.y][the docs]] now"))))
+
+(ert-deftest test-pearl-org-to-md-bare-link ()
+ "An org link with no description becomes the bare url."
+ (should (string= "visit https://x.y"
+ (pearl--org-line-to-md "visit [[https://x.y]]"))))
+
+(ert-deftest test-pearl-org-to-md-inline-code ()
+ "Org verbatim tildes become markdown backticks."
+ (should (string= "call `foo()` here"
+ (pearl--org-line-to-md "call ~foo()~ here"))))
+
+(ert-deftest test-pearl-org-to-md-bold ()
+ "Org bold becomes markdown bold."
+ (should (string= "a **strong** word" (pearl--org-line-to-md "a *strong* word"))))
+
+(ert-deftest test-pearl-org-to-md-italic ()
+ "Org italics become underscore italics, but paths are left alone."
+ (should (string= "an _emphatic_ point"
+ (pearl--org-line-to-md "an /emphatic/ point")))
+ (should (string= "the /usr/local/bin path"
+ (pearl--org-line-to-md "the /usr/local/bin path"))))
+
+(ert-deftest test-pearl-org-to-md-fenced-code ()
+ "An org src block becomes a fenced code block, language preserved."
+ (should (string= "```elisp\n(+ 1 2)\n```"
+ (pearl--org-to-md "#+begin_src elisp\n(+ 1 2)\n#+end_src"))))
+
+(ert-deftest test-pearl-org-to-md-code-block-is-verbatim ()
+ "Org markup inside a src block is not converted back."
+ (let ((out (pearl--org-to-md "#+begin_src\n*not bold* here\n#+end_src")))
+ (should (string-match-p "\\*not bold\\* here" out))))
+
+(ert-deftest test-pearl-org-to-md-quote-block ()
+ "An org quote block becomes markdown blockquote lines."
+ (should (string= "> a quote\n> second line"
+ (pearl--org-to-md
+ "#+begin_quote\na quote\nsecond line\n#+end_quote"))))
+
+(ert-deftest test-pearl-org-to-md-checkbox-case ()
+ "Org uppercase checkbox marks normalize to markdown lowercase."
+ (should (string= "- [ ] todo\n- [x] done"
+ (pearl--org-to-md "- [ ] todo\n- [X] done"))))
+
+(ert-deftest test-pearl-org-to-md-empty ()
+ "An empty or nil body converts to the empty string."
+ (should (string= "" (pearl--org-to-md "")))
+ (should (string= "" (pearl--org-to-md nil))))
+
+(ert-deftest test-pearl-org-to-md-passes-through-tables ()
+ "Tables and unsupported constructs pass through unchanged."
+ (should (string= "| a | b |\n|---|---|"
+ (pearl--org-to-md "| a | b |\n|---|---|"))))
+
+;;; round-trip: org-to-md inverts md-to-org for the supported subset
+
+(ert-deftest test-pearl-convert-roundtrip-identity ()
+ "For the cleanly-supported constructs, org->md(md->org(x)) == x.
+Markdown headings and single-asterisk italics are intentionally lossy (see
+the conversion-tier docstring) and are excluded here."
+ (dolist (md '("a **strong** word"
+ "call `foo()` here"
+ "an _emphatic_ point"
+ "see [the docs](https://x.y) now"
+ "- one\n- two\n- three"
+ "1. first\n2. second"
+ "- [ ] todo\n- [x] done"
+ "```elisp\n(+ 1 2)\n```"
+ "just some plain prose"
+ "| a | b |\n|---|---|"))
+ (should (string= md (pearl--org-to-md (pearl--md-to-org md))))))
+
+(provide 'test-pearl-convert)
+;;; test-pearl-convert.el ends here