Merge branch 'maint'
[org-mode.git] / testing / lisp / test-org-element.el
blob6a2ce1ff22ffa55a9f54745e7e5353ca7fa1b5a6
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/>.
20 (unless (featurep 'org-element)
21 (signal 'missing-test-dependency "org-element"))
23 (defun org-test-parse-and-interpret (text)
24 "Parse TEXT as Org syntax and interpret it.
25 Return interpreted string."
26 (with-temp-buffer
27 (org-mode)
28 (insert text)
29 (org-element-interpret-data (org-element-parse-buffer))))
33 ;;; Test `org-element-map'
35 (ert-deftest test-org-element/map ()
36 "Test `org-element-map'."
37 ;; Can map to `plain-text' objects.
38 (should
39 (= 2
40 (org-test-with-temp-text "Some text \alpha
41 #+BEGIN_CENTER
42 Some other text
43 #+END_CENTER"
44 (let ((count 0))
45 (org-element-map
46 (org-element-parse-buffer) 'plain-text
47 (lambda (s) (when (string-match "text" s) (incf count))))
48 count))))
49 ;; Applies to secondary strings
50 (should
51 (org-element-map '("some " (bold nil "bold") "text") 'bold 'identity))
52 ;; Enter secondary strings before entering contents.
53 (should
54 (equal
55 "alpha"
56 (org-element-property
57 :name
58 (org-test-with-temp-text "* Some \\alpha headline\n\\beta entity."
59 (org-element-map (org-element-parse-buffer) 'entity 'identity nil t)))))
60 ;; Apply NO-RECURSION argument.
61 (should-not
62 (org-test-with-temp-text "#+BEGIN_CENTER\n\\alpha\n#+END_CENTER"
63 (org-element-map
64 (org-element-parse-buffer) 'entity 'identity nil nil 'center-block))))
68 ;;; Test Setters
70 (ert-deftest test-org-element/put-property ()
71 "Test `org-element-put-property' specifications."
72 (org-test-with-temp-text "* Headline\n *a*"
73 (let ((tree (org-element-parse-buffer)))
74 (org-element-put-property
75 (org-element-map tree 'bold 'identity nil t) :test 1)
76 (should (org-element-property
77 :test (org-element-map tree 'bold 'identity nil t))))))
79 (ert-deftest test-org-element/set-contents ()
80 "Test `org-element-set-contents' specifications."
81 ;; Accept multiple entries.
82 (should
83 (equal '("b" (italic nil "a"))
84 (org-test-with-temp-text "* Headline\n *a*"
85 (let ((tree (org-element-parse-buffer)))
86 (org-element-set-contents
87 (org-element-map tree 'bold 'identity nil t) "b" '(italic nil "a"))
88 (org-element-contents
89 (org-element-map tree 'bold 'identity nil t))))))
90 ;; Accept atoms and elements.
91 (should
92 (equal '("b")
93 (org-test-with-temp-text "* Headline\n *a*"
94 (let ((tree (org-element-parse-buffer)))
95 (org-element-set-contents
96 (org-element-map tree 'bold 'identity nil t) "b")
97 (org-element-contents
98 (org-element-map tree 'bold 'identity nil t))))))
99 (should
100 (equal '((italic nil "b"))
101 (org-test-with-temp-text "* Headline\n *a*"
102 (let ((tree (org-element-parse-buffer)))
103 (org-element-set-contents
104 (org-element-map tree 'bold 'identity nil t) '(italic nil "b"))
105 (org-element-contents
106 (org-element-map tree 'bold 'identity nil t))))))
107 ;; Allow nil contents.
108 (should-not
109 (org-test-with-temp-text "* Headline\n *a*"
110 (let ((tree (org-element-parse-buffer)))
111 (org-element-set-contents (org-element-map tree 'bold 'identity nil t))
112 (org-element-contents (org-element-map tree 'bold 'identity nil t))))))
114 (ert-deftest test-org-element/set-element ()
115 "Test `org-element-set-element' specifications."
116 (org-test-with-temp-text "* Headline\n*a*"
117 (let ((tree (org-element-parse-buffer)))
118 (org-element-set-element
119 (org-element-map tree 'bold 'identity nil t)
120 '(italic nil "b"))
121 ;; Check if object is correctly replaced.
122 (should (org-element-map tree 'italic 'identity))
123 (should-not (org-element-map tree 'bold 'identity))
124 ;; Check if new object's parent is correctly set.
125 (should
127 (org-element-property :parent
128 (org-element-map tree 'italic 'identity nil t))
129 (org-element-map tree 'paragraph 'identity nil t))))))
131 (ert-deftest test-org-element/adopt-elements ()
132 "Test `org-element-adopt-elements' specifications."
133 ;; Adopt an element.
134 (should
135 (equal '(plain-text italic)
136 (org-test-with-temp-text "* Headline\n *a*"
137 (let ((tree (org-element-parse-buffer)))
138 (org-element-adopt-elements
139 (org-element-map tree 'bold 'identity nil t) '(italic nil "a"))
140 (mapcar (lambda (blob) (org-element-type blob))
141 (org-element-contents
142 (org-element-map tree 'bold 'identity nil t)))))))
143 ;; Adopt a string.
144 (should
145 (equal '("a" "b")
146 (org-test-with-temp-text "* Headline\n *a*"
147 (let ((tree (org-element-parse-buffer)))
148 (org-element-adopt-elements
149 (org-element-map tree 'bold 'identity nil t) "b")
150 (org-element-contents
151 (org-element-map tree 'bold 'identity nil t)))))))
155 ;;; Test Parsers
157 ;;;; Affiliated Keywords
159 (ert-deftest test-org-element/affiliated-keywords-parser ()
160 "Test affiliated keywords parsing."
161 ;; Read simple keywords.
162 (should
163 (equal "para"
164 (org-element-property
165 :name
166 (org-test-with-temp-text "#+NAME: para\nParagraph"
167 (org-element-at-point)))))
168 ;; Parse multiple keywords.
169 (should
170 (equal
171 '("line1" "line2")
172 (org-element-property
173 :attr_ascii
174 (org-test-with-temp-text
175 "#+ATTR_ASCII: line1\n#+ATTR_ASCII: line2\nParagraph"
176 (org-element-at-point)))))
177 ;; Parse "parsed" keywords.
178 (should
179 (equal
180 '(("caption"))
181 (org-test-with-temp-text "#+CAPTION: caption\nParagraph"
182 (car (org-element-property :caption (org-element-at-point))))))
183 ;; Parse dual keywords.
184 (should
185 (equal
186 '((("long") "short"))
187 (org-test-with-temp-text "#+CAPTION[short]: long\nParagraph"
188 (org-element-property :caption (org-element-at-point)))))
189 ;; Allow multiple caption keywords.
190 (should
191 (equal
192 '((("l1") "s1") (("l2") "s2"))
193 (org-test-with-temp-text "#+CAPTION[s1]: l1\n#+CAPTION[s2]: l2\nParagraph"
194 (org-element-property :caption (org-element-at-point))))))
197 ;;;; Babel Call
199 (ert-deftest test-org-element/babel-call-parser ()
200 "Test `babel-call' parsing."
201 ;; Standard test.
202 (should
203 (org-test-with-temp-text "#+CALL: test()"
204 (org-element-map (org-element-parse-buffer) 'babel-call 'identity)))
205 ;; Ignore case.
206 (should
207 (org-test-with-temp-text "#+call: test()"
208 (org-element-map (org-element-parse-buffer) 'babel-call 'identity))))
211 ;;;; Bold
213 (ert-deftest test-org-element/bold-parser ()
214 "Test `bold' parser."
215 ;; Standard test.
216 (should
217 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
218 (org-test-with-temp-text "*bold*"
219 (org-element-map (org-element-parse-buffer) 'bold 'identity nil t))))
220 ;; Multi-line markup.
221 (should
222 (equal
223 (org-element-contents
224 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
225 (org-test-with-temp-text "*first line\nsecond line*"
226 (org-element-map (org-element-parse-buffer) 'bold 'identity nil t))))
227 '("first line\nsecond line"))))
230 ;;;; Center Block
232 (ert-deftest test-org-element/center-block-parser ()
233 "Test `center-block' parser."
234 ;; Standard test.
235 (should
236 (org-test-with-temp-text "#+BEGIN_CENTER\nText\n#+END_CENTER"
237 (org-element-map (org-element-parse-buffer) 'center-block 'identity)))
238 ;; Ignore case.
239 (should
240 (org-test-with-temp-text "#+begin_center\nText\n#+end_center"
241 (org-element-map (org-element-parse-buffer) 'center-block 'identity)))
242 ;; Test folded block.
243 (org-test-with-temp-text "#+BEGIN_CENTER\nText\n#+END_CENTER"
244 (org-cycle)
245 (should
246 (org-element-property
247 :hiddenp
248 (org-element-map
249 (org-element-parse-buffer) 'center-block 'identity nil t))))
250 ;; Ignore incomplete block.
251 (should-not
252 (org-test-with-temp-text "#+BEGIN_CENTER"
253 (org-element-map
254 (org-element-parse-buffer) 'center-block 'identity nil t))))
257 ;;;; Clock
259 (ert-deftest test-org-element/clock-parser ()
260 "Test `clock' parser."
261 ;; Running clock.
262 (let* ((org-clock-string "CLOCK:")
263 (clock (org-test-with-temp-text "CLOCK: [2012-01-01 sun. 00:01]"
264 (org-element-map
265 (org-element-parse-buffer) 'clock 'identity nil t))))
266 (should (eq (org-element-property :status clock) 'running))
267 (should (equal (org-element-property :value clock)
268 "[2012-01-01 sun. 00:01]"))
269 (should-not (org-element-property :time clock)))
270 ;; Closed clock.
271 (let* ((org-clock-string "CLOCK:")
272 (clock (org-test-with-temp-text "
273 CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] => 0:01"
274 (org-element-map
275 (org-element-parse-buffer) 'clock 'identity nil t))))
276 (should (eq (org-element-property :status clock) 'closed))
277 (should (equal (org-element-property :value clock)
278 "[2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02]"))
279 (should (equal (org-element-property :time clock) "0:01"))))
282 ;;;; Code
284 (ert-deftest test-org-element/code-parser ()
285 "Test `code' parser."
286 ;; Regular test.
287 (should
288 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
289 (org-test-with-temp-text "~code~"
290 (org-element-map (org-element-parse-buffer) 'code 'identity))))
291 ;; Multi-line markup.
292 (should
293 (equal
294 (org-element-property
295 :value
296 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
297 (org-test-with-temp-text "~first line\nsecond line~"
298 (org-element-map
299 (org-element-parse-buffer) 'code 'identity nil t))))
300 "first line\nsecond line")))
303 ;;;; Comment
305 (ert-deftest test-org-element/comment-parser ()
306 "Test `comment' parser."
307 ;; Regular comment.
308 (should
309 (org-test-with-temp-text "# Comment"
310 (org-element-map (org-element-parse-buffer) 'comment 'identity)))
311 ;; Inline comment.
312 (should
313 (org-test-with-temp-text " # Comment"
314 (org-element-map (org-element-parse-buffer) 'comment 'identity)))
315 ;; Preserve indentation.
316 (should
317 (equal
318 (org-element-property
319 :value
320 (org-test-with-temp-text "# No blank\n# One blank"
321 (org-element-map (org-element-parse-buffer) 'comment 'identity nil t)))
322 "No blank\n One blank"))
323 ;; Comment with blank lines.
324 (should
325 (equal
326 (org-element-property
327 :value
328 (org-test-with-temp-text "# First part\n# \n#\n# Second part"
329 (org-element-map (org-element-parse-buffer) 'comment 'identity nil t)))
330 "First part\n\n\nSecond part"))
331 ;; Do not mix comments and keywords.
332 (should
333 (eq 1
334 (org-test-with-temp-text "#+keyword: value\n# comment\n#+keyword: value"
335 (length (org-element-map
336 (org-element-parse-buffer) 'comment 'identity)))))
337 (should
338 (equal "comment"
339 (org-test-with-temp-text "#+keyword: value\n# comment\n#+keyword: value"
340 (org-element-property
341 :value
342 (org-element-map
343 (org-element-parse-buffer) 'comment 'identity nil t))))))
346 ;;;; Comment Block
348 (ert-deftest test-org-element/comment-block-parser ()
349 "Test `comment-block' parser."
350 ;; Standard test.
351 (should
352 (org-test-with-temp-text "#+BEGIN_COMMENT\nText\n#+END_COMMENT"
353 (org-element-map
354 (org-element-parse-buffer) 'comment-block 'identity)))
355 ;; Ignore case.
356 (should
357 (org-test-with-temp-text "#+begin_comment\nText\n#+end_comment"
358 (org-element-map
359 (org-element-parse-buffer) 'comment-block 'identity)))
360 ;; Test folded block.
361 (org-test-with-temp-text "#+BEGIN_COMMENT\nText\n#+END_COMMENT"
362 (org-cycle)
363 (should
364 (org-element-property
365 :hiddenp
366 (org-element-map
367 (org-element-parse-buffer) 'comment-block 'identity nil t))))
368 ;; Ignore incomplete block.
369 (should-not
370 (org-test-with-temp-text "#+BEGIN_COMMENT"
371 (org-element-map
372 (org-element-parse-buffer) 'comment-block 'identity nil t))))
375 ;;;; Drawer
377 (ert-deftest test-org-element/drawer-parser ()
378 "Test `drawer' parser."
379 ;; Standard test.
380 (should
381 (let ((org-drawers '("TEST")))
382 (org-test-with-temp-text ":TEST:\nText\n:END:"
383 (org-element-map (org-element-parse-buffer) 'drawer 'identity))))
384 ;; Do not mix regular drawers and property drawers.
385 (should-not
386 (let ((org-drawers '("PROPERTIES")))
387 (org-test-with-temp-text ":PROPERTIES:\n:prop: value\n:END:"
388 (org-element-map
389 (org-element-parse-buffer) 'drawer 'identity nil t))))
390 ;; Ignore incomplete drawer.
391 (should-not
392 (let ((org-drawers '("TEST")))
393 (org-test-with-temp-text ":TEST:"
394 (org-element-map
395 (org-element-parse-buffer) 'drawer 'identity nil t)))))
398 ;;;; Dynamic Block
400 (ert-deftest test-org-element/dynamic-block-parser ()
401 "Test `dynamic-block' parser."
402 ;; Standard test.
403 (should
404 (org-test-with-temp-text
405 "#+BEGIN: myblock :param1 val1 :param2 val2\nText\n#+END:"
406 (org-element-map (org-element-parse-buffer) 'dynamic-block 'identity)))
407 ;; Folded view
408 (org-test-with-temp-text
409 "#+BEGIN: myblock :param1 val1 :param2 val2\nText\n#+END:"
410 (org-cycle)
411 (should
412 (org-element-property
413 :hiddenp
414 (org-element-map
415 (org-element-parse-buffer) 'dynamic-block 'identity nil t))))
416 ;; Ignore case.
417 (should
418 (org-test-with-temp-text
419 "#+begin: myblock :param1 val1 :param2 val2\nText\n#+end:"
420 (org-element-map (org-element-parse-buffer) 'dynamic-block 'identity)))
421 ;; Ignore incomplete block.
422 (should-not
423 (org-test-with-temp-text "#+BEGIN: myblock :param1 val1 :param2 val2"
424 (org-element-map
425 (org-element-parse-buffer) 'dynamic-block 'identity nil t))))
428 ;;;; Entity
430 (ert-deftest test-org-element/entity-parser ()
431 "Test `entity' parser."
432 ;; Without brackets.
433 (should
434 (org-test-with-temp-text "\\sin"
435 (org-element-map (org-element-parse-buffer) 'entity 'identity)))
436 ;; With brackets.
437 (should
438 (org-element-property
439 :use-brackets-p
440 (org-test-with-temp-text "\\alpha{}text"
441 (org-element-map (org-element-parse-buffer) 'entity 'identity nil t))))
442 ;; User-defined entity.
443 (should
444 (equal
445 (org-element-property
446 :name
447 (let ((org-entities-user
448 '(("test" "test" nil "test" "test" "test" "test"))))
449 (org-test-with-temp-text "\\test"
450 (org-element-map (org-element-parse-buffer) 'entity 'identity nil t))))
451 "test")))
454 ;;;; Example Block
456 (ert-deftest test-org-element/example-block-parser ()
457 "Test `example-block' parser."
458 ;; Standard test.
459 (should
460 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText\n#+END_EXAMPLE"
461 (org-element-map (org-element-parse-buffer) 'example-block 'identity)))
462 ;; Test folded block.
463 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText\n#+END_EXAMPLE"
464 (org-cycle)
465 (should
466 (org-element-property
467 :hiddenp
468 (org-element-map
469 (org-element-parse-buffer) 'example-block 'identity nil t))))
470 ;; Ignore incomplete block.
471 (should-not
472 (org-test-with-temp-text "#+BEGIN_EXAMPLE"
473 (org-element-map
474 (org-element-parse-buffer) 'example-block 'identity nil t))))
476 (ert-deftest test-org-element/block-switches ()
477 "Test `example-block' and `src-block' switches parsing."
478 (let ((org-coderef-label-format "(ref:%s)"))
479 ;; 1. Test "-i" switch.
480 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
481 (should-not
482 (org-element-property :preserve-indent (org-element-at-point))))
483 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -i\n(+ 1 1)\n#+END_SRC"
484 (should (org-element-property :preserve-indent (org-element-at-point))))
485 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText.\n#+END_EXAMPLE"
486 (should-not
487 (org-element-property :preserve-indent (org-element-at-point))))
488 (org-test-with-temp-text "#+BEGIN_EXAMPLE -i\nText.\n#+END_EXAMPLE"
489 (should (org-element-property :preserve-indent (org-element-at-point))))
490 ;; 2. "-n -r -k" combination should number lines, retain labels but
491 ;; not use them in coderefs.
492 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n -r -k\nText.\n#+END_EXAMPLE"
493 (let ((element (org-element-at-point)))
494 (should (and (org-element-property :number-lines element)
495 (org-element-property :retain-labels element)
496 (not (org-element-property :use-labels element))))))
497 (org-test-with-temp-text
498 "#+BEGIN_SRC emacs-lisp -n -r -k\n(+ 1 1)\n#+END_SRC"
499 (let ((element (org-element-at-point)))
500 (should (and (org-element-property :number-lines element)
501 (org-element-property :retain-labels element)
502 (not (org-element-property :use-labels element))))))
503 ;; 3. "-n -r" combination should number-lines remove labels and not
504 ;; use them in coderefs.
505 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n -r\nText.\n#+END_EXAMPLE"
506 (let ((element (org-element-at-point)))
507 (should (and (org-element-property :number-lines element)
508 (not (org-element-property :retain-labels element))
509 (not (org-element-property :use-labels element))))))
510 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -n -r\n(+ 1 1)\n#+END_SRC"
511 (let ((element (org-element-at-point)))
512 (should (and (org-element-property :number-lines element)
513 (not (org-element-property :retain-labels element))
514 (not (org-element-property :use-labels element))))))
515 ;; 4. "-n" or "+n" should number lines, retain labels and use them
516 ;; in coderefs.
517 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n\nText.\n#+END_EXAMPLE"
518 (let ((element (org-element-at-point)))
519 (should (and (org-element-property :number-lines element)
520 (org-element-property :retain-labels element)
521 (org-element-property :use-labels element)))))
522 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -n\n(+ 1 1)\n#+END_SRC"
523 (let ((element (org-element-at-point)))
524 (should (and (org-element-property :number-lines element)
525 (org-element-property :retain-labels element)
526 (org-element-property :use-labels element)))))
527 (org-test-with-temp-text "#+BEGIN_EXAMPLE +n\nText.\n#+END_EXAMPLE"
528 (let ((element (org-element-at-point)))
529 (should (and (org-element-property :number-lines element)
530 (org-element-property :retain-labels element)
531 (org-element-property :use-labels element)))))
532 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp +n\n(+ 1 1)\n#+END_SRC"
533 (let ((element (org-element-at-point)))
534 (should (and (org-element-property :number-lines element)
535 (org-element-property :retain-labels element)
536 (org-element-property :use-labels element)))))
537 ;; 5. No switch should not number lines, but retain labels and use
538 ;; them in coderefs.
539 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText.\n#+END_EXAMPLE"
540 (let ((element (org-element-at-point)))
541 (should (and (not (org-element-property :number-lines element))
542 (org-element-property :retain-labels element)
543 (org-element-property :use-labels element)))))
544 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
545 (let ((element (org-element-at-point)))
546 (should (and (not (org-element-property :number-lines element))
547 (org-element-property :retain-labels element)
548 (org-element-property :use-labels element)))))
549 ;; 6. "-r" switch only: do not number lines, remove labels, and
550 ;; don't use labels in coderefs.
551 (org-test-with-temp-text "#+BEGIN_EXAMPLE -r\nText.\n#+END_EXAMPLE"
552 (let ((element (org-element-at-point)))
553 (should (and (not (org-element-property :number-lines element))
554 (not (org-element-property :retain-labels element))
555 (not (org-element-property :use-labels element))))))
556 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -r\n(+ 1 1)\n#+END_SRC"
557 (let ((element (org-element-at-point)))
558 (should (and (not (org-element-property :number-lines element))
559 (not (org-element-property :retain-labels element))
560 (not (org-element-property :use-labels element))))))
561 ;; 7. Recognize coderefs with user-defined syntax.
562 (org-test-with-temp-text
563 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText [ref:text]\n#+END_EXAMPLE"
564 (let ((element (org-element-at-point)))
565 (should
566 (equal (org-element-property :label-fmt element) "[ref:%s]"))))
567 (org-test-with-temp-text
568 "#+BEGIN_SRC emacs-lisp -l \"[ref:%s]\"\n(+ 1 1) [ref:text]\n#+END_SRC"
569 (let ((element (org-element-at-point)))
570 (should
571 (equal (org-element-property :label-fmt element) "[ref:%s]"))))))
574 ;;;; Export Block
576 (ert-deftest test-org-element/export-block-parser ()
577 "Test `export-block' parser."
578 ;; Standard test.
579 (should
580 (org-test-with-temp-text "#+BEGIN_LATEX\nText\n#+END_LATEX"
581 (org-element-map
582 (let ((org-element-block-name-alist
583 '(("LATEX" . org-element-export-block-parser))))
584 (org-element-parse-buffer))
585 'export-block 'identity)))
586 ;; Test folded block.
587 (org-test-with-temp-text "#+BEGIN_LATEX\nText\n#+END_LATEX"
588 (org-cycle)
589 (should
590 (org-element-property
591 :hiddenp
592 (org-element-map
593 (let ((org-element-block-name-alist
594 '(("LATEX" . org-element-export-block-parser))))
595 (org-element-parse-buffer))
596 'export-block 'identity nil t))))
597 ;; Ignore case.
598 (should
599 (org-test-with-temp-text "#+begin_latex\nText\n#+end_latex"
600 (org-element-map
601 (let ((org-element-block-name-alist
602 '(("LATEX" . org-element-export-block-parser))))
603 (org-element-parse-buffer))
604 'export-block 'identity)))
605 ;; Ignore incomplete block.
606 (should-not
607 (org-test-with-temp-text "#+BEGIN_LATEX"
608 (org-element-map
609 (let ((org-element-block-name-alist
610 '(("LATEX" . org-element-export-block-parser))))
611 (org-element-parse-buffer))
612 'export-block 'identity nil t))))
615 ;;;; Export Snippet
617 (ert-deftest test-org-element/export-snippet-parser ()
618 "Test `export-snippet' parser."
619 (should
620 (equal
621 '("back-end" . "contents")
622 (org-test-with-temp-text "@@back-end:contents@@"
623 (org-element-map
624 (org-element-parse-buffer) 'export-snippet
625 (lambda (snippet) (cons (org-element-property :back-end snippet)
626 (org-element-property :value snippet)))
627 nil t)))))
630 ;;;; Fixed Width
632 (ert-deftest test-org-element/fixed-width ()
633 "Test fixed-width area parsing."
634 ;; Preserve indentation.
635 (should
636 (org-test-with-temp-text ": no blank\n: one blank"
637 (org-element-map (org-element-parse-buffer) 'fixed-width 'identity)))
638 ;; Fixed-width with empty lines.
639 (should
640 (org-test-with-temp-text ": first part\n:\n: \n: second part"
641 (org-element-map (org-element-parse-buffer) 'fixed-width 'identity)))
642 ;; Parse indented fixed-width markers.
643 (should
644 (org-test-with-temp-text "Text\n : no blank\n : one blank"
645 (org-element-map (org-element-parse-buffer) 'fixed-width 'identity)))
646 ;; Distinguish fixed-width areas within a list and outside of it.
647 (should
648 (= 2
649 (length
650 (org-test-with-temp-text "
651 - Item
652 : fixed-width inside
653 : fixed-width outside"
654 (org-element-map
655 (org-element-parse-buffer) 'fixed-width 'identity))))))
658 ;;;; Footnote Definition
660 (ert-deftest test-org-element/footnote-definition-parser ()
661 "Test `footnote-definition' parser."
662 (should
663 (org-test-with-temp-text "[fn:1] Definition"
664 (org-element-map
665 (org-element-parse-buffer) 'footnote-definition 'identity nil t)))
666 ;; Footnote with more contents
667 (should
668 (= 28
669 (org-element-property
670 :end
671 (org-test-with-temp-text "[fn:1] Definition\n| a | b |"
672 (org-element-map
673 (org-element-parse-buffer)
674 'footnote-definition 'identity nil t)))))
675 ;; Footnote starting with special syntax.
676 (should-not
677 (org-test-with-temp-text "[fn:1] - no item"
678 (org-element-map (org-element-parse-buffer) 'item 'identity))))
681 ;;;; Footnotes Reference.
683 (ert-deftest test-org-element/footnote-reference-parser ()
684 "Test `footnote-reference' parser."
685 ;; 1. Parse a standard reference.
686 (org-test-with-temp-text "Text[fn:label]"
687 (should
688 (org-element-map
689 (org-element-parse-buffer) 'footnote-reference 'identity)))
690 ;; 2. Parse a normalized reference.
691 (org-test-with-temp-text "Text[1]"
692 (should
693 (org-element-map
694 (org-element-parse-buffer) 'footnote-reference 'identity)))
695 ;; 3. Parse an inline reference.
696 (org-test-with-temp-text "Text[fn:test:def]"
697 (should
698 (org-element-map
699 (org-element-parse-buffer) 'footnote-reference 'identity)))
700 ;; 4. Parse an anonymous reference.
701 (org-test-with-temp-text "Text[fn::def]"
702 (should
703 (org-element-map
704 (org-element-parse-buffer) 'footnote-reference 'identity)))
705 ;; 5. Parse nested footnotes.
706 (org-test-with-temp-text "Text[fn::def [fn:label]]"
707 (should
708 (= 2
709 (length
710 (org-element-map
711 (org-element-parse-buffer) 'footnote-reference 'identity)))))
712 ;; 6. Parse adjacent footnotes.
713 (org-test-with-temp-text "Text[fn:label1][fn:label2]"
714 (should
715 (= 2
716 (length
717 (org-element-map
718 (org-element-parse-buffer) 'footnote-reference 'identity)))))
719 ;; 7. Only properly closed footnotes are recognized as such.
720 (org-test-with-temp-text "Text[fn:label"
721 (should-not
722 (org-element-map
723 (org-element-parse-buffer) 'footnote-reference 'identity))))
726 ;;;; Headline
728 (ert-deftest test-org-element/headline-quote-keyword ()
729 "Test QUOTE keyword recognition."
730 ;; Reference test.
731 (org-test-with-temp-text "* Headline"
732 (let ((org-quote-string "QUOTE"))
733 (should-not (org-element-property :quotedp (org-element-at-point)))))
734 ;; Standard position.
735 (org-test-with-temp-text "* QUOTE Headline"
736 (let ((org-quote-string "QUOTE"))
737 (let ((headline (org-element-at-point)))
738 (should (org-element-property :quotedp headline))
739 ;; Test removal from raw value.
740 (should (equal (org-element-property :raw-value headline) "Headline"))))
741 ;; Case sensitivity.
742 (let ((org-quote-string "Quote"))
743 (should-not (org-element-property :quotedp (org-element-at-point)))))
744 ;; With another keyword.
745 (org-test-with-temp-text "* TODO QUOTE Headline"
746 (let ((org-quote-string "QUOTE")
747 (org-todo-keywords '((sequence "TODO" "DONE"))))
748 (should (org-element-property :quotedp (org-element-at-point))))))
750 (ert-deftest test-org-element/headline-comment-keyword ()
751 "Test COMMENT keyword recognition."
752 ;; Reference test.
753 (org-test-with-temp-text "* Headline"
754 (let ((org-comment-string "COMMENT"))
755 (should-not (org-element-property :commentedp (org-element-at-point)))))
756 ;; Standard position.
757 (org-test-with-temp-text "* COMMENT Headline"
758 (let ((org-comment-string "COMMENT"))
759 (let ((headline (org-element-at-point)))
760 (should (org-element-property :commentedp headline))
761 ;; Test removal from raw value.
762 (should (equal (org-element-property :raw-value headline) "Headline"))))
763 ;; Case sensitivity.
764 (let ((org-comment-string "Comment"))
765 (should-not (org-element-property :commentedp (org-element-at-point)))))
766 ;; With another keyword.
767 (org-test-with-temp-text "* TODO COMMENT Headline"
768 (let ((org-comment-string "COMMENT")
769 (org-todo-keywords '((sequence "TODO" "DONE"))))
770 (should (org-element-property :commentedp (org-element-at-point))))))
772 (ert-deftest test-org-element/headline-archive-tag ()
773 "Test ARCHIVE tag recognition."
774 ;; Reference test.
775 (org-test-with-temp-text "* Headline"
776 (let ((org-archive-tag "ARCHIVE"))
777 (should-not (org-element-property :archivedp (org-element-at-point)))))
778 ;; Single tag.
779 (org-test-with-temp-text "* Headline :ARCHIVE:"
780 (let ((org-archive-tag "ARCHIVE"))
781 (let ((headline (org-element-at-point)))
782 (should (org-element-property :archivedp headline))
783 ;; Test tag removal.
784 (should-not (org-element-property :tags headline))))
785 (let ((org-archive-tag "Archive"))
786 (should-not (org-element-property :archivedp (org-element-at-point)))))
787 ;; Multiple tags.
788 (org-test-with-temp-text "* Headline :test:ARCHIVE:"
789 (let ((org-archive-tag "ARCHIVE"))
790 (let ((headline (org-element-at-point)))
791 (should (org-element-property :archivedp headline))
792 ;; Test tag removal.
793 (should (equal (org-element-property :tags headline) '("test")))))))
796 ;;;; Horizontal Rule
798 (ert-deftest test-org-element/horizontal-rule-parser ()
799 "Test `horizontal-rule' parser."
800 ;; Standard.
801 (should
802 (org-test-with-temp-text "-----"
803 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity)))
804 ;; Indented.
805 (should
806 (org-test-with-temp-text " -----"
807 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity)))
808 ;; Hyphen must be alone on the line.
809 (should-not
810 (org-test-with-temp-text "-----wrong"
811 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity)))
812 ;; 4 hyphens is too small.
813 (should-not
814 (org-test-with-temp-text "----"
815 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity))))
818 ;;;; Inline Babel Call
820 (ert-deftest test-org-element/inline-babel-call-parser ()
821 "Test `inline-babel-call' parser."
822 (should
823 (org-test-with-temp-text "call_test()"
824 (org-element-map
825 (org-element-parse-buffer) 'inline-babel-call 'identity))))
828 ;;;; Inline Src Block
830 (ert-deftest test-org-element/inline-src-block-parser ()
831 "Test `inline-src-block' parser."
832 (should
833 (org-test-with-temp-text "src_emacs-lisp{(+ 1 1)}"
834 (org-element-map (org-element-parse-buffer) 'inline-src-block 'identity)))
835 ;; Test parsing at the beginning of an item.
836 (should
837 (org-test-with-temp-text "- src_emacs-lisp{(+ 1 1)}"
838 (org-element-map (org-element-parse-buffer) 'inline-src-block 'identity))))
841 ;;;; Inlinetask
843 (ert-deftest test-org-element/inlinetask-parser ()
844 "Test `inlinetask' parser."
845 (when (featurep 'org-inlinetask)
846 (let ((org-inlinetask-min-level 15))
847 ;; 1. Regular inlinetask.
848 (should
849 (org-test-with-temp-text
850 "*************** Task\nTest\n*************** END"
851 (org-element-map (org-element-parse-buffer) 'inlinetask 'identity)))
852 ;; 2. Degenerate inlinetask.
853 (should
854 (org-test-with-temp-text "*************** Task"
855 (org-element-map (org-element-parse-buffer) 'inlinetask 'identity)))
856 ;; TODO keyword.
857 (should
858 (equal
859 "TODO"
860 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
861 (org-test-with-temp-text "*************** TODO Task"
862 (org-element-property
863 :todo-keyword
864 (org-element-map
865 (org-element-parse-buffer) 'inlinetask 'identity nil t))))))
866 ;; Planning info.
867 (should
868 (equal
869 "2012-03-29 thu."
870 (org-test-with-temp-text "
871 *************** Task
872 DEADLINE: <2012-03-29 thu.>"
873 (org-element-property
874 :deadline
875 (org-element-map
876 (org-element-parse-buffer) 'inlinetask 'identity nil t)))))
877 ;; Priority.
878 (should
879 (equal
881 (org-test-with-temp-text "
882 *************** [#A] Task"
883 (org-element-property
884 :priority
885 (org-element-map
886 (org-element-parse-buffer) 'inlinetask 'identity nil t)))))
887 ;; Tags.
888 (should
889 (equal
890 '("test")
891 (org-test-with-temp-text "
892 *************** Task :test:"
893 (org-element-property
894 :tags
895 (org-element-map
896 (org-element-parse-buffer) 'inlinetask 'identity nil t))))))))
899 ;;;; Italic
901 (ert-deftest test-org-element/italic-parser ()
902 "Test `italic' parser."
903 ;; Regular test.
904 (should
905 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
906 (org-test-with-temp-text "/italic/"
907 (org-element-map (org-element-parse-buffer) 'italic 'identity nil t))))
908 ;; Multi-line markup.
909 (should
910 (equal
911 (org-element-contents
912 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
913 (org-test-with-temp-text "/first line\nsecond line/"
914 (org-element-map (org-element-parse-buffer) 'italic 'identity nil t))))
915 '("first line\nsecond line"))))
918 ;;;; Item
920 (ert-deftest test-org-element/item-parser ()
921 "Test `item' parser."
922 ;; Standard test.
923 (should
924 (org-test-with-temp-text "- item"
925 (org-element-map (org-element-parse-buffer) 'item 'identity)))
926 ;; Counter.
927 (should
928 (= 6
929 (org-element-property
930 :counter
931 (org-test-with-temp-text "6. [@6] item"
932 (org-element-map (org-element-parse-buffer) 'item 'identity nil t)))))
933 ;; Tag
934 (should
935 (equal
936 '("tag")
937 (org-element-property
938 :tag
939 (org-test-with-temp-text "- tag :: description"
940 (org-element-map (org-element-parse-buffer) 'item 'identity nil t)))))
941 ;; No tags in ordered lists.
942 (should-not
943 (org-element-property
944 :tag
945 (org-test-with-temp-text "1. tag :: description"
946 (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))
947 ;; Check-boxes
948 (should
949 (equal
950 '(trans on off)
951 (org-test-with-temp-text "
952 - [-] item 1
953 - [X] item 1.1
954 - [ ] item 1.2"
955 (org-element-map
956 (org-element-parse-buffer) 'item
957 (lambda (item) (org-element-property :checkbox item))))))
958 ;; Folded state.
959 (org-test-with-temp-text "* Headline
960 - item
962 paragraph below"
963 (forward-line)
964 (let ((org-cycle-include-plain-lists t)) (org-cycle))
965 (should
966 (org-element-property
967 :hiddenp
968 (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))
969 ;; Item starting with special syntax.
970 (should
971 (equal '(("- item"))
972 (org-test-with-temp-text "- - item"
973 (org-element-map
974 (org-element-parse-buffer) 'paragraph 'org-element-contents)))))
977 ;;;; Keyword
979 (ert-deftest test-org-element/keyword-parser ()
980 "Test `keyword' parser."
981 ;; Standard test.
982 (should
983 (org-test-with-temp-text "#+KEYWORD: value"
984 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
985 ;; Keywords are case-insensitive.
986 (should
987 (org-test-with-temp-text "#+keyword: value"
988 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
989 ;; Affiliated keywords are not keywords.
990 (should-not
991 (org-test-with-temp-text "#+NAME: value
992 Paragraph"
993 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
994 ;; Do not mix keywords with Babel calls and dynamic blocks.
995 (should-not
996 (org-test-with-temp-text "#+CALL: fun()"
997 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
998 (should-not
999 (org-test-with-temp-text "#+BEGIN: my-fun\nBody\n#+END:"
1000 (org-element-map (org-element-parse-buffer) 'keyword 'identity))))
1003 ;;;; Latex Environment
1005 (ert-deftest test-org-element/latex-environment-parser ()
1006 "Test `latex-environment' parser."
1007 (should
1008 (org-test-with-temp-text "\\begin{equation}\ne^{i\\pi}+1=0\n\\end{equation}"
1009 (org-element-map
1010 (org-element-parse-buffer) 'latex-environment 'identity)))
1011 ;; Allow nested environments.
1012 (should
1013 (equal
1014 "\\begin{outer}
1015 \\begin{inner}
1016 e^{i\\pi}+1=0
1017 \\end{inner}
1018 \\end{outer}"
1019 (org-test-with-temp-text "
1020 \\begin{outer}
1021 \\begin{inner}
1022 e^{i\\pi}+1=0
1023 \\end{inner}
1024 \\end{outer}"
1025 (org-element-property
1026 :value
1027 (org-element-map
1028 (org-element-parse-buffer) 'latex-environment 'identity nil t))))))
1031 ;;;; Latex Fragment
1033 (ert-deftest test-org-element/latex-fragment-parser ()
1034 "Test `latex-fragment' parser."
1035 (let ((org-latex-regexps
1036 '(("begin" "^[ ]*\\(\\\\begin{\\([a-zA-Z0-9\\*]+\\)[^