;;; test-wrap-org-table.el --- ERT tests for wrap-org-table.el -*- lexical-binding: t; -*- ;; ;; Run from the repo root: ;; emacs --batch -q -L .ai/scripts -l ert \ ;; -l .ai/scripts/tests/test-wrap-org-table.el \ ;; -f ert-run-tests-batch-and-exit ;; ;; Covers the pure core (render width, tokenizing, cell wrap, column ;; allocation), the table reformat (exact-output cases at small budgets), and ;; the file layer. (require 'ert) (require 'cl-lib) (defconst wot-test--dir (file-name-directory (or load-file-name buffer-file-name default-directory)) "Directory of this test file, captured at load time.") (add-to-list 'load-path (expand-file-name ".." wot-test--dir)) (require 'wrap-org-table) ;;; --------------------------------------------------------------------------- ;;; render width — links measure at their visible label (ert-deftest wot-render-width-plain-text () (should (= (wot-render-width "hello") 5))) (ert-deftest wot-render-width-empty () (should (= (wot-render-width "") 0))) (ert-deftest wot-render-width-descriptive-link-counts-label-only () (should (= (wot-render-width "[[file:long-target-path.org][label]]") 5))) (ert-deftest wot-render-width-bare-link-counts-target () (should (= (wot-render-width "[[file:x.org]]") 10))) (ert-deftest wot-render-width-mixed-text-and-link () ;; "see doc now" = 11 (should (= (wot-render-width "see [[file:a.org][doc]] now") 11))) ;;; --------------------------------------------------------------------------- ;;; tokenize — links are atomic tokens (ert-deftest wot-tokenize-plain-words () (should (equal (wot-tokenize "a quick fox") '("a" "quick" "fox")))) (ert-deftest wot-tokenize-link-is-one-token () (should (equal (wot-tokenize "see [[file:a.org][the doc]] now") '("see" "[[file:a.org][the doc]]" "now")))) (ert-deftest wot-tokenize-empty-string () (should (equal (wot-tokenize "") nil))) ;;; --------------------------------------------------------------------------- ;;; cell wrap (ert-deftest wot-wrap-cell-fits-on-one-line () (should (equal (wot-wrap-cell "short text" 20) '("short text")))) (ert-deftest wot-wrap-cell-wraps-at-word-boundary () (should (equal (wot-wrap-cell "The quick brown fox jumps over the lazy dog" 28) '("The quick brown fox jumps" "over the lazy dog")))) (ert-deftest wot-wrap-cell-empty-cell () (should (equal (wot-wrap-cell "" 10) '("")))) (ert-deftest wot-wrap-cell-overlong-token-sits-alone-unsplit () (should (equal (wot-wrap-cell "tiny incomprehensibilities end" 10) '("tiny" "incomprehensibilities" "end")))) (ert-deftest wot-wrap-cell-link-never-split () ;; label is 17 chars, wider than the 10 budget — the link stays whole (should (equal (wot-wrap-cell "[[file:a.org][a very wide label x]]" 10) '("[[file:a.org][a very wide label x]]")))) ;;; --------------------------------------------------------------------------- ;;; column allocation (ert-deftest wot-allocate-widths-fits-naturally () ;; cells total 1+1, overhead 3*2+1=7 → 9 ≤ 30: keep natural widths (should (equal (wot-allocate-widths '(("A" "B") ("1" "2")) 30) '(1 1)))) (ert-deftest wot-allocate-widths-shrinks-widest-column () ;; naturals 5 + 44, overhead 7 → 56 > 40; Notes shrinks to 28, floor 5 (should (equal (wot-allocate-widths '(("Name" "Notes") ("alpha" "The quick brown fox jumps over the lazy dog")) 40) '(5 28)))) (ert-deftest wot-allocate-widths-respects-token-floor () ;; the long token (21) floors column 2 even when the budget wants less (should (equal (wot-allocate-widths '(("A" "B") ("x" "incomprehensibilities yes")) 20) '(1 21)))) ;;; --------------------------------------------------------------------------- ;;; table reformat — exact output (defconst wot-test--wide-input "| Name | Notes | |------+-------| | alpha | The quick brown fox jumps over the lazy dog | ") (defconst wot-test--wide-expected "| Name | Notes | |-------+------------------------------| | alpha | The quick brown fox jumps | | | over the lazy dog | |-------+------------------------------| ") (ert-deftest wot-reformat-wraps-wide-cell-with-continuation-rows () (should (equal (wot-reformat-table-string wot-test--wide-input 40) wot-test--wide-expected))) (ert-deftest wot-reformat-narrow-table-gains-rules-between-rows () (should (equal (wot-reformat-table-string "| A | B | |---+---| | 1 | 2 | | 3 | 4 | " 120) "| A | B | |---+---| | 1 | 2 | |---+---| | 3 | 4 | |---+---| "))) (ert-deftest wot-reformat-is-idempotent () (let ((once (wot-reformat-table-string wot-test--wide-input 40))) (should (equal (wot-reformat-table-string once 40) once)))) (ert-deftest wot-reformat-preserves-link-source-verbatim () (let ((out (wot-reformat-table-string "| Doc | Notes | |-----+-------| | [[file:very-long-target-path.org][d1]] | ok | " 120))) (should (string-match-p (regexp-quote "[[file:very-long-target-path.org][d1]]") out)))) (ert-deftest wot-reformat-headerless-table-rules-every-row () (should (equal (wot-reformat-table-string "| 1 | 2 | | 3 | 4 | " 120) "| 1 | 2 | |---+---| | 3 | 4 | |---+---| "))) (ert-deftest wot-reformat-preserves-indentation () (should (equal (wot-reformat-table-string " | A | B | |---+---| | 1 | 2 | " 120) " | A | B | |---+---| | 1 | 2 | |---+---| "))) ;;; --------------------------------------------------------------------------- ;;; file layer (ert-deftest wot-process-file-reformats-tables-in-place () (let ((file (make-temp-file "wot-test" nil ".org"))) (unwind-protect (progn (with-temp-file file (insert "* Heading\n\nProse before.\n\n" wot-test--wide-input "\nProse after.\n")) (wot-process-file file 40) (let ((content (with-temp-buffer (insert-file-contents file) (buffer-string)))) (should (string-match-p (regexp-quote wot-test--wide-expected) content)) (should (string-match-p "Prose before\\." content)) (should (string-match-p "Prose after\\." content)))) (delete-file file))))