1 ;;; test-org-element.el --- Tests for org-element.el
3 ;; Copyright (C) 2012 Nicolas Goaziou
5 ;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
7 ;; This program is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
24 (unless (featurep 'org-element
)
25 (signal 'missing-test-dependency
"org-element"))
35 (ert-deftest test-org-element
/headline-quote-keyword
()
36 "Test QUOTE keyword recognition."
38 (org-test-with-temp-text "* Headline"
39 (let ((org-quote-string "QUOTE"))
40 (should-not (org-element-property :quotedp
(org-element-at-point)))))
42 (org-test-with-temp-text "* QUOTE Headline"
43 (let ((org-quote-string "QUOTE"))
44 (let ((headline (org-element-at-point)))
45 (should (org-element-property :quotedp headline
))
46 ;; Test removal from raw value.
47 (should (equal (org-element-property :raw-value headline
) "Headline"))))
49 (let ((org-quote-string "Quote"))
50 (should-not (org-element-property :quotedp
(org-element-at-point)))))
51 ;; With another keyword.
52 (org-test-with-temp-text "* TODO QUOTE Headline"
53 (let ((org-quote-string "QUOTE")
54 (org-todo-keywords '((sequence "TODO" "DONE"))))
55 (should (org-element-property :quotedp
(org-element-at-point))))))
57 (ert-deftest test-org-element
/headline-comment-keyword
()
58 "Test COMMENT keyword recognition."
60 (org-test-with-temp-text "* Headline"
61 (let ((org-comment-string "COMMENT"))
62 (should-not (org-element-property :commentedp
(org-element-at-point)))))
64 (org-test-with-temp-text "* COMMENT Headline"
65 (let ((org-comment-string "COMMENT"))
66 (let ((headline (org-element-at-point)))
67 (should (org-element-property :commentedp headline
))
68 ;; Test removal from raw value.
69 (should (equal (org-element-property :raw-value headline
) "Headline"))))
71 (let ((org-comment-string "Comment"))
72 (should-not (org-element-property :commentedp
(org-element-at-point)))))
73 ;; With another keyword.
74 (org-test-with-temp-text "* TODO COMMENT Headline"
75 (let ((org-comment-string "COMMENT")
76 (org-todo-keywords '((sequence "TODO" "DONE"))))
77 (should (org-element-property :commentedp
(org-element-at-point))))))
79 (ert-deftest test-org-element
/headline-archive-tag
()
80 "Test ARCHIVE tag recognition."
82 (org-test-with-temp-text "* Headline"
83 (let ((org-archive-tag "ARCHIVE"))
84 (should-not (org-element-property :archivedp
(org-element-at-point)))))
86 (org-test-with-temp-text "* Headline :ARCHIVE:"
87 (let ((org-archive-tag "ARCHIVE"))
88 (let ((headline (org-element-at-point)))
89 (should (org-element-property :archivedp headline
))
91 (should-not (org-element-property :tags headline
))))
92 (let ((org-archive-tag "Archive"))
93 (should-not (org-element-property :archivedp
(org-element-at-point)))))
95 (org-test-with-temp-text "* Headline :test:ARCHIVE:"
96 (let ((org-archive-tag "ARCHIVE"))
97 (let ((headline (org-element-at-point)))
98 (should (org-element-property :archivedp headline
))
100 (should (equal (org-element-property :tags headline
) ":test:"))))))
104 ;;;; Example-blocks and Src-blocks
106 (ert-deftest test-org-element
/block-switches
()
107 "Test `example-block' and `src-block' switches parsing."
108 (let ((org-coderef-label-format "(ref:%s)"))
109 ;; 1. Test "-i" switch.
110 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
111 (let ((element (org-element-current-element)))
112 (should-not (org-element-property :preserve-indent element
))))
113 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -i\n(+ 1 1)\n#+END_SRC"
114 (let ((element (org-element-current-element)))
115 (should (org-element-property :preserve-indent element
))))
116 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText.\n#+END_EXAMPLE"
117 (let ((element (org-element-current-element)))
118 (should-not (org-element-property :preserve-indent element
))))
119 (org-test-with-temp-text "#+BEGIN_EXAMPLE -i\nText.\n#+END_EXAMPLE"
120 (let ((element (org-element-current-element)))
121 (should (org-element-property :preserve-indent element
))))
122 ;; 2. "-n -r -k" combination should number lines, retain labels but
123 ;; not use them in coderefs.
124 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n -r -k\nText.\N#+END_EXAMPLE"
125 (let ((element (org-element-current-element)))
126 (should (and (org-element-property :number-lines element
)
127 (org-element-property :retain-labels element
)
128 (not (org-element-property :use-labels element
))))))
129 (org-test-with-temp-text
130 "#+BEGIN_SRC emacs-lisp -n -r -k\n(+ 1 1)\n#+END_SRC"
131 (let ((element (org-element-current-element)))
132 (should (and (org-element-property :number-lines element
)
133 (org-element-property :retain-labels element
)
134 (not (org-element-property :use-labels element
))))))
135 ;; 3. "-n -r" combination should number-lines remove labels and not
136 ;; use them in coderefs.
137 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n -r\nText.\n#+END_EXAMPLE"
138 (let ((element (org-element-current-element)))
139 (should (and (org-element-property :number-lines element
)
140 (not (org-element-property :retain-labels element
))
141 (not (org-element-property :use-labels element
))))))
142 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -n -r\n(+ 1 1)\n#+END_SRC"
143 (let ((element (org-element-current-element)))
144 (should (and (org-element-property :number-lines element
)
145 (not (org-element-property :retain-labels element
))
146 (not (org-element-property :use-labels element
))))))
147 ;; 4. "-n" or "+n" should number lines, retain labels and use them
149 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n\nText.\n#+END_EXAMPLE"
150 (let ((element (org-element-current-element)))
151 (should (and (org-element-property :number-lines element
)
152 (org-element-property :retain-labels element
)
153 (org-element-property :use-labels element
)))))
154 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -n\n(+ 1 1)\n#+END_SRC"
155 (let ((element (org-element-current-element)))
156 (should (and (org-element-property :number-lines element
)
157 (org-element-property :retain-labels element
)
158 (org-element-property :use-labels element
)))))
159 (org-test-with-temp-text "#+BEGIN_EXAMPLE +n\nText.\n#+END_EXAMPLE"
160 (let ((element (org-element-current-element)))
161 (should (and (org-element-property :number-lines element
)
162 (org-element-property :retain-labels element
)
163 (org-element-property :use-labels element
)))))
164 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp +n\n(+ 1 1)\n#+END_SRC"
165 (let ((element (org-element-current-element)))
166 (should (and (org-element-property :number-lines element
)
167 (org-element-property :retain-labels element
)
168 (org-element-property :use-labels element
)))))
169 ;; 5. No switch should not number lines, but retain labels and use
171 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText.\n#+END_EXAMPLE"
172 (let ((element (org-element-current-element)))
173 (should (and (not (org-element-property :number-lines element
))
174 (org-element-property :retain-labels element
)
175 (org-element-property :use-labels element
)))))
176 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
177 (let ((element (org-element-current-element)))
178 (should (and (not (org-element-property :number-lines element
))
179 (org-element-property :retain-labels element
)
180 (org-element-property :use-labels element
)))))
181 ;; 6. "-r" switch only: do not number lines, remove labels, and
182 ;; don't use labels in coderefs.
183 (org-test-with-temp-text "#+BEGIN_EXAMPLE -r\nText.\n#+END_EXAMPLE"
184 (let ((element (org-element-current-element)))
185 (should (and (not (org-element-property :number-lines element
))
186 (not (org-element-property :retain-labels element
))
187 (not (org-element-property :use-labels element
))))))
188 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -r\n(+ 1 1)\n#+END_SRC"
189 (let ((element (org-element-current-element)))
190 (should (and (not (org-element-property :number-lines element
))
191 (not (org-element-property :retain-labels element
))
192 (not (org-element-property :use-labels element
))))))
193 ;; 7. Recognize coderefs with user-defined syntax.
194 (org-test-with-temp-text
195 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText [ref:text]\n#+END_EXAMPLE"
196 (let ((element (org-element-current-element)))
198 (equal (org-element-property :label-fmt element
) "[ref:%s]"))))
199 (org-test-with-temp-text
200 "#+BEGIN_SRC emacs-lisp -l \"[ref:%s]\"\n(+ 1 1) [ref:text]\n#+END_SRC"
201 (let ((element (org-element-current-element)))
203 (equal (org-element-property :label-fmt element
) "[ref:%s]"))))))
207 ;;;; Footnotes references and definitions
209 (ert-deftest test-org-element
/footnote-reference
()
210 "Test footnote-reference parsing."
211 ;; 1. Parse a standard reference.
212 (org-test-with-temp-text "[fn:label]"
213 (should (equal (org-element-footnote-reference-parser)
215 (:label
"fn:label" :type standard
:inline-definition nil
216 :begin
1 :end
11 :post-blank
0)))))
217 ;; 2. Parse a normalized reference.
218 (org-test-with-temp-text "[1]"
219 (should (equal (org-element-footnote-reference-parser)
221 (:label
"1" :type standard
:inline-definition nil
222 :begin
1 :end
4 :post-blank
0)))))
223 ;; 3. Parse an inline reference.
224 (org-test-with-temp-text "[fn:test:def]"
225 (should (equal (org-element-footnote-reference-parser)
227 (:label
"fn:test" :type inline
:inline-definition
("def")
228 :begin
1 :end
14 :post-blank
0)))))
229 ;; 4. Parse an anonymous reference.
230 (org-test-with-temp-text "[fn::def]"
231 (should (equal (org-element-footnote-reference-parser)
233 (:label nil
:type inline
:inline-definition
("def")
234 :begin
1 :end
10 :post-blank
0)))))
235 ;; 5. Parse nested footnotes.
236 (org-test-with-temp-text "[fn::def [fn:label]]"
239 (org-element-footnote-reference-parser)
241 (:label nil
:type inline
245 (:label
"fn:label" :type standard
:inline-definition nil
246 :begin
5 :end
15 :post-blank
0)))
247 :begin
1 :end
21 :post-blank
0)))))
248 ;; 6. Parse adjacent footnotes.
249 (org-test-with-temp-text "[fn:label1][fn:label2]"
252 (org-element-footnote-reference-parser)
254 (:label
"fn:label1" :type standard
:inline-definition nil
:begin
1
255 :end
12 :post-blank
0)))))
256 ;; 7. Only properly closed footnotes are recognized as such.
257 (org-test-with-temp-text "Text [fn:label"
260 (org-element-parse-buffer) 'footnote-reference
'identity
))))
266 (ert-deftest test-org-element
/granularity
()
267 "Test granularity impact on buffer parsing."
268 (org-test-with-temp-text "
275 ;; 1.1. Granularity set to `headline' should parse every headline
276 ;; in buffer, and only them.
277 (let ((tree (org-element-parse-buffer 'headline
)))
278 (should (= 2 (length (org-element-map tree
'headline
'identity
))))
279 (should-not (org-element-map tree
'paragraph
'identity
)))
280 ;; 1.2. Granularity set to `greater-element' should not enter
281 ;; greater elements excepted headlines and sections.
282 (let ((tree (org-element-parse-buffer 'greater-element
)))
283 (should (= 1 (length (org-element-map tree
'center-block
'identity
))))
284 (should (= 1 (length (org-element-map tree
'paragraph
'identity
))))
285 (should-not (org-element-map tree
'entity
'identity
)))
286 ;; 1.3. Granularity set to `element' should enter every
288 (let ((tree (org-element-parse-buffer 'element
)))
289 (should (= 2 (length (org-element-map tree
'paragraph
'identity
))))
290 (should-not (org-element-map tree
'entity
'identity
)))
291 ;; 1.4. Granularity set to `object' can see everything.
292 (let ((tree (org-element-parse-buffer 'object
)))
293 (should (= 1 (length (org-element-map tree
'entity
'identity
)))))))
295 (ert-deftest test-org-element
/secondary-string-parsing
()
296 "Test if granularity correctly toggles secondary strings parsing."
297 ;; 1. With a granularity bigger than `object', no secondary string
300 ;; 1.1. Test with `headline' type.
301 (org-test-with-temp-text "* Headline"
303 (org-element-map (org-element-parse-buffer 'headline
) 'headline
307 (should (stringp (org-element-property :title headline
)))))
308 ;; 1.2. Test with `item' type.
309 (org-test-with-temp-text "* Headline\n- tag :: item"
310 (let ((item (org-element-map (org-element-parse-buffer 'element
)
315 (should (stringp (org-element-property :tag item
)))))
316 ;; 1.3. Test with `verse-block' type.
317 (org-test-with-temp-text "#+BEGIN_VERSE\nTest\n#+END_VERSE"
318 (let ((verse-block (org-element-map (org-element-parse-buffer 'element
)
323 (should (stringp (org-element-property :value verse-block
)))))
324 ;; 1.4. Test with `inlinetask' type, if avalaible.
325 (when (featurep 'org-inlinetask
)
326 (let ((org-inlinetask-min-level 15))
327 (org-test-with-temp-text "*************** Inlinetask"
328 (let ((inlinetask (org-element-map (org-element-parse-buffer 'element
)
333 (should (stringp (org-element-property :title inlinetask
)))))))
334 ;; 2. With a default granularity, secondary strings should be
336 (org-test-with-temp-text "* Headline"
338 (org-element-map (org-element-parse-buffer) 'headline
342 (should (listp (org-element-property :title headline
)))))
343 ;; 3. `org-element-at-point' should never parse a secondary string.
344 (org-test-with-temp-text "* Headline"
345 (should (stringp (org-element-property :title
(org-element-at-point))))))
351 (ert-deftest test-org-element
/interpret-affiliated-keywords
()
352 "Test if affiliated keywords are correctly interpreted."
353 ;; Interpret simple keywords.
356 (org-element-interpret-data
357 '(org-data nil
(paragraph (:name
"para") "Paragraph")))
358 "#+NAME: para\nParagraph\n"))
359 ;; Interpret multiple keywords.
362 (org-element-interpret-data
363 '(org-data nil
(paragraph (:attr_ascii
("line1" "line2")) "Paragraph")))
364 "#+ATTR_ASCII: line1\n#+ATTR_ASCII: line2\nParagraph\n"))
365 ;; Interpret parsed keywords.
368 (org-element-interpret-data
369 '(org-data nil
(paragraph (:caption
("caption")) "Paragraph")))
370 "#+CAPTION: caption\nParagraph\n"))
371 ;; Interpret dual keywords.
374 (org-element-interpret-data
375 '(org-data nil
(paragraph (:caption
(("long") "short")) "Paragraph")))
376 "#+CAPTION[short]: long\nParagraph\n")))
380 ;;;; Navigation tools.
382 (ert-deftest test-org-element
/forward-element
()
383 "Test `org-element-forward' specifications."
384 ;; 1. At EOB: should error.
385 (org-test-with-temp-text "Some text\n"
386 (goto-char (point-max))
387 (should-error (org-element-forward)))
388 ;; 2. Standard move: expected to ignore blank lines.
389 (org-test-with-temp-text "First paragraph.\n\n\nSecond paragraph."
390 (org-element-forward)
391 (should (looking-at "Second paragraph.")))
392 ;; 3. Headline tests.
393 (org-test-with-temp-text "
398 ;; 3.1. At an headline beginning: move to next headline at the
401 (org-element-forward)
402 (should (looking-at "** Head 1.2"))
403 ;; 3.2. At an headline beginning: move to parent headline if no
404 ;; headline at the same level.
406 (org-element-forward)
407 (should (looking-at "** Head 1.2")))
408 ;; 4. Greater element tests.
409 (org-test-with-temp-text
410 "#+BEGIN_CENTER\nInside.\n#+END_CENTER\n\nOutside."
411 ;; 4.1. At a greater element: expected to skip contents.
412 (org-element-forward)
413 (should (looking-at "Outside."))
414 ;; 4.2. At the end of greater element contents: expected to skip
415 ;; to the end of the greater element.
417 (org-element-forward)
418 (should (looking-at "Outside.")))
420 (org-test-with-temp-text "
434 ;; 5.1. At list top point: expected to move to the element after
437 (org-element-forward)
438 (should (looking-at "Outside."))
439 ;; 5.2. Special case: at the first line of a sub-list, but not at
440 ;; beginning of line, move to next item.
443 (org-element-forward)
444 (should (looking-at "- item2"))
447 (org-element-forward)
448 (should (looking-at " - sub2"))
449 ;; 5.3 At sub-list beginning: expected to move after the sub-list.
451 (org-element-forward)
452 (should (looking-at " Inner paragraph."))
453 ;; 5.4. At sub-list end: expected to move outside the sub-list.
455 (org-element-forward)
456 (should (looking-at " Inner paragraph."))
457 ;; 5.5. At an item: expected to move to next item, if any.
459 (org-element-forward)
460 (should (looking-at " - sub3"))))
462 (ert-deftest test-org-element
/backward-element
()
463 "Test `org-element-backward' specifications."
464 ;; 1. At BOB (modulo some white spaces): should error.
465 (org-test-with-temp-text " \nParagraph."
466 (org-skip-whitespace)
467 (should-error (org-element-backward)))
468 ;; 2. Not at the beginning of an element: move at its beginning.
469 (org-test-with-temp-text "Paragraph1.\n\nParagraph2."
472 (org-element-backward)
473 (should (looking-at "Paragraph2.")))
474 ;; 3. Headline tests.
475 (org-test-with-temp-text "
480 ;; 3.1. At an headline beginning: move to previous headline at the
483 (org-element-backward)
484 (should (looking-at "** Head 1.1"))
485 ;; 3.2. At an headline beginning: move to parent headline if no
486 ;; headline at the same level.
488 (org-element-backward)
489 (should (looking-at "* Head 1"))
490 ;; 3.3. At the first top-level headline: should error.
492 (should-error (org-element-backward)))
493 ;; 4. At beginning of first element inside a greater element:
494 ;; expected to move to greater element's beginning.
495 (org-test-with-temp-text "Before.\n#+BEGIN_CENTER\nInside.\n#+END_CENTER."
497 (org-element-backward)
498 (should (looking-at "#\\+BEGIN_CENTER")))
500 (org-test-with-temp-text "
515 ;; 5.1. At beginning of sub-list: expected to move to the
516 ;; paragraph before it.
518 (org-element-backward)
519 (should (looking-at "item1"))
520 ;; 5.2. At an item in a list: expected to move at previous item.
522 (org-element-backward)
523 (should (looking-at " - sub2"))
525 (org-element-backward)
526 (should (looking-at "- item1"))
527 ;; 5.3. At end of list/sub-list: expected to move to list/sub-list
530 (org-element-backward)
531 (should (looking-at " - sub1"))
533 (org-element-backward)
534 (should (looking-at "- item1"))
535 ;; 5.4. At blank-lines before list end: expected to move to top
538 (org-element-backward)
539 (should (looking-at "- item1"))))
541 (ert-deftest test-org-element
/up-element
()
542 "Test `org-element-up' specifications."
543 ;; 1. At BOB or with no surrounding element: should error.
544 (org-test-with-temp-text "Paragraph."
545 (should-error (org-element-up)))
546 (org-test-with-temp-text "* Head1\n* Head2"
548 (should-error (org-element-up)))
549 (org-test-with-temp-text "Paragraph1.\n\nParagraph2."
551 (should-error (org-element-up)))
552 ;; 2. At an headline: move to parent headline.
553 (org-test-with-temp-text "* Head1\n** Sub-Head1\n** Sub-Head2"
556 (should (looking-at "\\* Head1")))
557 ;; 3. Inside a greater element: move to greater element beginning.
558 (org-test-with-temp-text
559 "Before.\n#+BEGIN_CENTER\nParagraph1\nParagraph2\n#+END_CENTER\n"
562 (should (looking-at "#\\+BEGIN_CENTER")))
564 (org-test-with-temp-text "* Top
571 Paragraph within sub2.
574 ;; 4.1. Within an item: move to the item beginning.
577 (should (looking-at " - sub2"))
578 ;; 4.2. At an item in a sub-list: move to parent item.
581 (should (looking-at "- item1"))
582 ;; 4.3. At an item in top list: move to beginning of whole list.
585 (should (looking-at "- item1"))
586 ;; 4.4. Special case. At very top point: should move to parent of
590 (should (looking-at "\\* Top"))))
592 (ert-deftest test-org-element
/down-element
()
593 "Test `org-element-down' specifications."
594 ;; 1. Error when the element hasn't got a recursive type.
595 (org-test-with-temp-text "Paragraph."
596 (should-error (org-element-down)))
597 ;; 2. When at a plain-list, move to first item.
598 (org-test-with-temp-text "- Item 1\n - Item 1.1\n - Item 2.2"
601 (should (looking-at " - Item 1.1")))
602 ;; 3. Otherwise, move inside the greater element.
603 (org-test-with-temp-text "#+BEGIN_CENTER\nParagraph.\n#+END_CENTER"
605 (should (looking-at "Paragraph"))))
607 (ert-deftest test-org-element
/drag-backward
()
608 "Test `org-element-drag-backward' specifications."
609 ;; 1. Error when trying to move first element of buffer.
610 (org-test-with-temp-text "Paragraph 1.\n\nParagraph 2."
611 (should-error (org-element-drag-backward)))
612 ;; 2. Error when trying to swap nested elements.
613 (org-test-with-temp-text "#+BEGIN_CENTER\nTest.\n#+END_CENTER"
615 (should-error (org-element-drag-backward)))
616 ;; 3. Error when trying to swap an headline element and
617 ;; a non-headline element.
618 (org-test-with-temp-text "Test.\n* Head 1"
620 (should-error (org-element-drag-backward)))
621 ;; 4. Otherwise, swap elements, preserving column and blank lines
623 (org-test-with-temp-text "Para1\n\n\nParagraph 2\n\nPara3"
624 (search-forward "graph")
625 (org-element-drag-backward)
626 (should (equal (buffer-string) "Paragraph 2\n\n\nPara1\n\nPara3"))
627 (should (looking-at " 2"))))
629 (ert-deftest test-org-element
/drag-forward
()
630 "Test `org-element-drag-forward' specifications."
631 ;; 1. Error when trying to move first element of buffer.
632 (org-test-with-temp-text "Paragraph 1.\n\nParagraph 2."
634 (should-error (org-element-drag-forward)))
635 ;; 2. Error when trying to swap nested elements.
636 (org-test-with-temp-text "#+BEGIN_CENTER\nTest.\n#+END_CENTER"
638 (should-error (org-element-drag-forward)))
639 ;; 3. Error when trying to swap a non-headline element and an
641 (org-test-with-temp-text "Test.\n* Head 1"
642 (should-error (org-element-drag-forward)))
643 ;; 4. Otherwise, swap elements, preserving column and blank lines
645 (org-test-with-temp-text "Paragraph 1\n\n\nPara2\n\nPara3"
646 (search-forward "graph")
647 (org-element-drag-forward)
648 (should (equal (buffer-string) "Para2\n\n\nParagraph 1\n\nPara3"))
649 (should (looking-at " 1"))))
652 (provide 'test-org-element
)
653 ;;; test-org-element.el ends here