123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 |
- ;;; test-org.el --- tests for org.el -*- lexical-binding: t; -*-
- ;; Authors: Ihor Radchenko
- ;; This file is not part of GNU Emacs.
- ;; 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 <https://www.gnu.org/licenses/>.
- ;; Org folding tests.
- ;;; Code:
- (eval-and-compile (require 'cl-lib))
- (ert-deftest test-org-fold/hide-drawer-toggle ()
- "Test `org-fold-hide-drawer-toggle' specifications."
- ;; Error when not at a drawer.
- (should-error
- (org-test-with-temp-text ":fake-drawer:\ncontents"
- (org-fold-hide-drawer-toggle 'off)
- (get-char-property (line-end-position) 'invisible)))
- (should-error
- (org-test-with-temp-text
- "#+begin_example\n<point>:D:\nc\n:END:\n#+end_example"
- (org-fold-hide-drawer-toggle t)))
- ;; Hide drawer.
- (should
- (org-test-with-temp-text ":drawer:\ncontents\n:end:"
- (org-fold-show-all)
- (org-fold-hide-drawer-toggle)
- (get-char-property (line-end-position) 'invisible)))
- ;; Show drawer unconditionally when optional argument is `off'.
- (should-not
- (org-test-with-temp-text ":drawer:\ncontents\n:end:"
- (org-fold-hide-drawer-toggle)
- (org-fold-hide-drawer-toggle 'off)
- (get-char-property (line-end-position) 'invisible)))
- ;; Hide drawer unconditionally when optional argument is non-nil.
- (should
- (org-test-with-temp-text ":drawer:\ncontents\n:end:"
- (org-fold-hide-drawer-toggle t)
- (get-char-property (line-end-position) 'invisible)))
- ;; Do not hide drawer when called from final blank lines.
- (should-not
- (org-test-with-temp-text ":drawer:\ncontents\n:end:\n\n<point>"
- (org-fold-show-all)
- (org-fold-hide-drawer-toggle)
- (goto-char (point-min))
- (get-char-property (line-end-position) 'invisible)))
- ;; Don't leave point in an invisible part of the buffer when hiding
- ;; a drawer away.
- (should-not
- (org-test-with-temp-text ":drawer:\ncontents\n<point>:end:"
- (org-fold-hide-drawer-toggle)
- (get-char-property (point) 'invisible))))
- (ert-deftest test-org/hide-block-toggle ()
- "Test `org-fold-hide-block-toggle' specifications."
- ;; Error when not at a block.
- (should-error
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents"
- (org-fold-hide-block-toggle 'off)
- (get-char-property (line-end-position) 'invisible)))
- ;; Hide block.
- (should
- (org-test-with-temp-text "#+BEGIN_CENTER\ncontents\n#+END_CENTER"
- (org-fold-hide-block-toggle)
- (get-char-property (line-end-position) 'invisible)))
- (should
- (org-test-with-temp-text "#+BEGIN_EXAMPLE\ncontents\n#+END_EXAMPLE"
- (org-fold-hide-block-toggle)
- (get-char-property (line-end-position) 'invisible)))
- ;; Show block unconditionally when optional argument is `off'.
- (should-not
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents\n#+END_QUOTE"
- (org-fold-hide-block-toggle)
- (org-fold-hide-block-toggle 'off)
- (get-char-property (line-end-position) 'invisible)))
- (should-not
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents\n#+END_QUOTE"
- (org-fold-hide-block-toggle 'off)
- (get-char-property (line-end-position) 'invisible)))
- ;; Hide block unconditionally when optional argument is non-nil.
- (should
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents\n#+END_QUOTE"
- (org-fold-hide-block-toggle t)
- (get-char-property (line-end-position) 'invisible)))
- (should
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents\n#+END_QUOTE"
- (org-fold-hide-block-toggle)
- (org-fold-hide-block-toggle t)
- (get-char-property (line-end-position) 'invisible)))
- ;; Do not hide block when called from final blank lines.
- (should-not
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents\n#+END_QUOTE\n\n<point>"
- (org-fold-hide-block-toggle)
- (goto-char (point-min))
- (get-char-property (line-end-position) 'invisible)))
- ;; Don't leave point in an invisible part of the buffer when hiding
- ;; a block away.
- (should-not
- (org-test-with-temp-text "#+BEGIN_QUOTE\ncontents\n<point>#+END_QUOTE"
- (org-fold-hide-block-toggle)
- (get-char-property (point) 'invisible))))
- (ert-deftest test-org-fold/hide-block-toggle-maybe ()
- "Test `org-fold-hide-block-toggle' specifications."
- (should
- (org-test-with-temp-text "#+BEGIN: dynamic\nContents\n#+END:"
- (org-hide-block-toggle)))
- (should-error
- (org-test-with-temp-text "Paragraph" (org-hide-block-toggle))))
- (ert-deftest test-org-fold/show-set-visibility ()
- "Test `org-fold-show-set-visibility' specifications."
- ;; Do not throw an error before first heading.
- (should
- (org-test-with-temp-text "Preamble\n* Headline"
- (org-fold-show-set-visibility 'tree)
- t))
- ;; Test all visibility spans, both on headline and in entry.
- (let ((list-visible-lines
- (lambda (state headerp)
- (org-test-with-temp-text "* Grandmother (0)
- ** Uncle (1)
- *** Heir (2)
- ** Father (3)
- Ancestor text (4)
- *** Sister (5)
- Sibling text (6)
- *** Self (7)
- Match (8)
- **** First born (9)
- Child text (10)
- **** The other child (11)
- *** Brother (12)
- ** Aunt (13)
- "
- (org-cycle t)
- (search-forward (if headerp "Self" "Match"))
- (org-fold-show-set-visibility state)
- (goto-char (point-min))
- (let (result (line 0))
- (while (not (eobp))
- (unless (org-invisible-p2) (push line result))
- (cl-incf line)
- (forward-line))
- (nreverse result))))))
- (should (equal '(0 7) (funcall list-visible-lines 'minimal t)))
- (should (equal '(0 7 8) (funcall list-visible-lines 'minimal nil)))
- (should (equal '(0 7 8 9) (funcall list-visible-lines 'local t)))
- (should (equal '(0 7 8 9) (funcall list-visible-lines 'local nil)))
- (should (equal '(0 3 7) (funcall list-visible-lines 'ancestors t)))
- (should (equal '(0 3 7 8) (funcall list-visible-lines 'ancestors nil)))
- (should (equal '(0 3 7 8 9 10 11)
- (funcall list-visible-lines 'ancestors-full t)))
- (should (equal '(0 3 7 8 9 10 11)
- (funcall list-visible-lines 'ancestors-full nil)))
- (should (equal '(0 3 5 7 12) (funcall list-visible-lines 'lineage t)))
- (should (equal '(0 3 5 7 8 9 12) (funcall list-visible-lines 'lineage nil)))
- (should (equal '(0 1 3 5 7 12 13) (funcall list-visible-lines 'tree t)))
- (should (equal '(0 1 3 5 7 8 9 11 12 13)
- (funcall list-visible-lines 'tree nil)))
- (should (equal '(0 1 3 4 5 7 12 13)
- (funcall list-visible-lines 'canonical t)))
- (should (equal '(0 1 3 4 5 7 8 9 11 12 13)
- (funcall list-visible-lines 'canonical nil))))
- ;; When point is hidden in a drawer or a block, make sure to make it
- ;; visible.
- (should-not
- (org-test-with-temp-text "#+BEGIN_QUOTE\nText\n#+END_QUOTE"
- (org-fold-hide-block-toggle)
- (search-forward "Text")
- (org-fold-show-set-visibility 'minimal)
- (org-invisible-p2)))
- (should-not
- (org-test-with-temp-text ":DRAWER:\nText\n:END:"
- (org-fold-hide-drawer-toggle)
- (search-forward "Text")
- (org-fold-show-set-visibility 'minimal)
- (org-invisible-p2)))
- (should-not
- (org-test-with-temp-text
- "#+BEGIN_QUOTE\n<point>:DRAWER:\nText\n:END:\n#+END_QUOTE"
- (org-fold-hide-drawer-toggle)
- (forward-line -1)
- (org-fold-hide-block-toggle)
- (search-forward "Text")
- (org-fold-show-set-visibility 'minimal)
- (org-invisible-p2))))
- (ert-deftest test-org-fold/copy-visible ()
- "Test `org-copy-visible' specifications."
- ;;`org-unfontify-region', which is wired up to
- ;; `font-lock-unfontify-region-function', removes the invisible text
- ;; property, among other things.
- (cl-letf (((symbol-function 'org-unfontify-region) #'ignore))
- (should
- (equal "Foo"
- (org-test-with-temp-text "Foo"
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- ;; Skip invisible characters by text property.
- (should
- (equal "Foo"
- (org-test-with-temp-text #("F<hidden>oo" 1 9 (invisible t))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- ;; Skip invisible characters by overlay.
- (should
- (equal "Foo"
- (org-test-with-temp-text "F<hidden>oo"
- (let ((o (make-overlay 2 10)))
- (overlay-put o 'invisible t))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- ;; Handle invisible characters at the beginning and the end of the
- ;; buffer.
- (should
- (equal "Foo"
- (org-test-with-temp-text #("<hidden>Foo" 0 8 (invisible t))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- (should
- (equal "Foo"
- (org-test-with-temp-text #("Foo<hidden>" 3 11 (invisible t))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- ;; Handle multiple visible parts.
- (should
- (equal "abc"
- (org-test-with-temp-text
- #("aXbXc" 1 2 (invisible t) 3 4 (invisible t))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- ;; Handle adjacent invisible parts.
- (should
- (equal "ab"
- (org-test-with-temp-text
- #("aXXb" 1 2 (invisible t) 2 3 (invisible org-link))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))
- ;; Copies text based on what's actually visible, as defined by
- ;; `buffer-invisibility-spec'.
- (should
- (equal "aYb"
- (org-test-with-temp-text
- #("aXYb"
- 1 2 (invisible t)
- 2 3 (invisible org-test-copy-visible))
- (let ((kill-ring nil))
- (org-copy-visible (point-min) (point-max))
- (current-kill 0 t)))))))
- (ert-deftest test-org-fold/set-visibility-according-to-property ()
- "Test `org-set-visibility-according-to-property' specifications."
- ;; "folded" state.
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: folded
- :END:
- ** <point>b"
- (org-set-visibility-according-to-property)
- (invisible-p (point))))
- ;; "children" state.
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: children
- :END:
- ** b
- <point>Contents
- ** c"
- (org-set-visibility-according-to-property)
- (invisible-p (point))))
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: children
- :END:
- ** b
- Contents
- *** <point>c"
- (org-set-visibility-according-to-property)
- (invisible-p (point))))
- ;; "content" state.
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: content
- :END:
- ** b
- <point>Contents
- *** c"
- (org-set-visibility-according-to-property)
- (invisible-p (point))))
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: content
- :END:
- ** b
- Contents
- *** <point>c"
- (org-set-visibility-according-to-property)
- (not (invisible-p (point)))))
- ;; "showall" state.
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: showall
- :END:
- ** b
- <point>Contents
- *** c"
- (org-set-visibility-according-to-property)
- (not (invisible-p (point)))))
- (should
- (org-test-with-temp-text
- "
- * a
- :PROPERTIES:
- :VISIBILITY: showall
- :END:
- ** b
- Contents
- *** <point>c"
- (org-set-visibility-according-to-property)
- (not (invisible-p (point)))))
- ;; When VISIBILITY properties are nested, ignore inner ones.
- (should
- (org-test-with-temp-text
- "
- * A
- :PROPERTIES:
- :VISIBILITY: folded
- :END:
- ** <point>B
- :PROPERTIES:
- :VISIBILITY: folded
- :END:"
- (org-set-visibility-according-to-property)
- (invisible-p (point)))))
- (ert-deftest test-org-fold/visibility-show-branches ()
- "Test visibility of inline archived subtrees."
- (org-test-with-temp-text
- "* Foo<point>
- ** Bar :ARCHIVE:
- *** Baz
- "
- (org-kill-note-or-show-branches)
- (should (org-invisible-p (- (point-max) 2)))))
- (ert-deftest test-org-fold/org-cycle-narrowed-subtree ()
- "Test cycling in narrowed buffer."
- (org-test-with-temp-text
- "* Heading 1<point>
- ** Child 1.1
- ** Child 1.2
- some text
- *** Sub-child 1.2.1
- * Heading 2"
- (org-overview)
- (org-narrow-to-subtree)
- (org-cycle)
- (re-search-forward "Sub-child")
- (should (org-invisible-p))))
- (ert-deftest test-org-fold/org-fold-reveal-broken-structure ()
- "Test unfolding broken elements."
- (let ((org-fold-core-style 'text-properties))
- (org-test-with-temp-text
- "<point>* Heading 1
- Text here"
- (org-overview)
- (re-search-forward "Text")
- (should (org-invisible-p))
- (goto-char 1)
- (org-delete-char 1)
- (re-search-forward "Text")
- (should-not (org-invisible-p)))
- (org-test-with-temp-text
- "* Heading 1
- <point>:PROPERTIES:
- :ID: something
- :END:
- Text here"
- (org-cycle)
- (org-fold-hide-drawer-all)
- (re-search-forward "ID")
- (should (org-invisible-p))
- (re-search-backward ":PROPERTIES:")
- (delete-char 1)
- (re-search-forward "ID")
- (should-not (org-invisible-p)))
- (org-test-with-temp-text
- "* Heading 1
- <point>:PROPERTIES:
- :ID: something
- :END:
- Text here"
- (org-cycle)
- (org-fold-hide-drawer-all)
- (re-search-forward "ID")
- (should (org-invisible-p))
- (re-search-forward ":END:")
- (delete-char -1)
- (re-search-backward "ID")
- (should-not (org-invisible-p)))
- (org-test-with-temp-text
- "* Heading 1
- <point>#+begin_src emacs-lisp
- (+ 1 2)
- #+end_src
- Text here"
- (org-cycle)
- (org-fold-hide-drawer-all)
- (re-search-forward "end")
- (should (org-invisible-p))
- (delete-char -1)
- (re-search-backward "2")
- (should-not (org-invisible-p)))))
- (ert-deftest test-org-fold/re-hide-edits-inside-fold ()
- "Test edits inside folded regions."
- (org-test-with-temp-text
- "<point>* Heading 1
- Text here"
- (org-overview)
- (org-set-property "TEST" "1")
- (re-search-forward "TEST")
- (should (org-invisible-p)))
- (org-test-with-temp-text
- "* Heading 1<point>
- Text here"
- (org-overview)
- (insert " and extra heading text")
- (re-search-backward "heading")
- (should-not (org-invisible-p)))
- (org-test-with-temp-text
- "* Heading 1
- Text<point> here"
- (org-overview)
- (insert " and extra text")
- (re-search-backward "extra")
- (should (org-invisible-p))))
- (defmacro test-org-fold-with-default-template (&rest body)
- "Run `org-test-with-temp-text' using default folded template."
- (declare (indent 0))
- `(let ((org-link-descriptive t))
- (org-test-with-temp-text
- "#+STARTUP: showeverything
- * <point>Folded heading
- Folded Paragraph inside heading.
- * Unfolded heading
- :FOLDED-DRAWER:
- Folded Paragraph inside drawer.
- :END:
- Unfolded Paragraph.
- #+begin_src emacs-lisp
- (message \"Folded block\")
- #+end_src
- [[hiddenlink][link]]
- "
- (org-cycle)
- (search-forward "FOLDED-DRAWER")
- (org-hide-drawer-toggle t)
- (search-forward "begin_src")
- (org-hide-block-toggle t)
- (goto-char 1)
- ,@body)))
- (ert-deftest test-org-fold/org-catch-invisible-edits ()
- "Test invisible edits handling."
- ;; Disable delay in `org-fold-check-before-invisible-edit'.
- (cl-letf (((symbol-function 'sit-for) #'ignore))
- (dolist (org-fold-core-style '(text-properties overlays))
- (dolist (org-fold-catch-invisible-edits
- '(nil error smart show show-and-error))
- (dolist (kind '(insert delete-backward delete nil))
- (message "Testing invisible edits: %S:%S:%S"
- org-fold-core-style
- org-fold-catch-invisible-edits
- kind)
- ;; Edits outside invisible.
- (test-org-fold-with-default-template
- (search-forward "Unfolded Paragraph")
- (message "Outside invisible")
- (org-fold-check-before-invisible-edit kind)
- (should-not (org-invisible-p)))
- ;; Edits inside invisible region.
- (test-org-fold-with-default-template
- (dolist (txt '("Folded Paragraph inside heading"
- "Folded Paragraph inside drawer"
- "Folded block"))
- (search-forward txt)
- (message "Inside invisible %S" txt)
- (pcase org-fold-catch-invisible-edits
- (`nil
- (org-fold-check-before-invisible-edit kind)
- (should (org-invisible-p)))
- (`show
- (org-fold-check-before-invisible-edit kind)
- (should-not (org-invisible-p)))
- ((or `smart `show-and-error)
- (should-error (org-fold-check-before-invisible-edit kind))
- (should-not (org-invisible-p)))
- (`error
- (should-error (org-fold-check-before-invisible-edit kind))
- (should (org-invisible-p)))))
- (search-forward "hiddenlink")
- (message "Inside hidden link")
- (org-fold-check-before-invisible-edit kind)
- (should (org-invisible-p)))
- ;; Edits at the left border.
- (test-org-fold-with-default-template
- (dolist (txt '("Folded heading"
- ":FOLDED-DRAWER:"
- "#+begin_src emacs-lisp"))
- (search-forward txt)
- (message "Left of folded %S" txt)
- (pcase org-fold-catch-invisible-edits
- (`nil
- (org-fold-check-before-invisible-edit kind)
- (should (org-invisible-p (1+ (point)))))
- (`show
- (org-fold-check-before-invisible-edit kind)
- (should-not (org-invisible-p (1+ (point)))))
- (`smart
- (if (memq kind '(insert delete-backward))
- (org-fold-check-before-invisible-edit kind)
- (should-error (org-fold-check-before-invisible-edit kind)))
- (should-not (org-invisible-p (1+ (point)))))
- (`show-and-error
- (should-error (org-fold-check-before-invisible-edit kind))
- (should-not (org-invisible-p (1+ (point)))))
- (`error
- (should-error (org-fold-check-before-invisible-edit kind))
- (should (org-invisible-p (1+ (point)))))))
- (search-forward "hiddenlink")
- (search-forward "lin")
- (message "Left border of ]] in link")
- (org-fold-check-before-invisible-edit kind)
- (should (org-invisible-p (1+ (point)))))
- ;; Edits at the right border.
- (test-org-fold-with-default-template
- (dolist (txt '("Folded Paragraph inside heading."
- ":END:"
- "#+end_src"))
- (search-forward txt)
- (message "After %S" txt)
- (pcase org-fold-catch-invisible-edits
- (`nil
- (org-fold-check-before-invisible-edit kind)
- (should (org-invisible-p (1- (point)))))
- (`show
- (org-fold-check-before-invisible-edit kind)
- (should-not (org-invisible-p (1- (point)))))
- ((or `smart `show-and-error)
- (should-error (org-fold-check-before-invisible-edit kind))
- (should-not (org-invisible-p (1- (point)))))
- (`error
- (should-error (org-fold-check-before-invisible-edit kind))
- (should (org-invisible-p (1- (point)))))))
- (search-forward "hiddenlink")
- (search-forward "link]]")
- (message "Right border of ]] in link")
- (org-fold-check-before-invisible-edit kind)
- (should (org-invisible-p (1- (point))))))))))
- (provide 'test-org-fold)
- ;;; test-org-fold.el ends here
|