org-element: Improve timestamps parsing
[org-mode.git] / testing / lisp / test-org-element.el
blob768f3d33e42a868a12a5c7f0f849c4cceff3c14e
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)))
65 ;; Use WITH-AFFILIATED argument.
66 (should
67 (equal
68 '("a" "1" "b" "2")
69 (org-test-with-temp-text "#+CAPTION[a]: 1\n#+CAPTION[b]: 2\nParagraph"
70 (org-element-map
71 (org-element-at-point) 'plain-text 'identity nil nil nil t)))))
75 ;;; Test Setters
77 (ert-deftest test-org-element/put-property ()
78 "Test `org-element-put-property' specifications."
79 ;; Standard test.
80 (org-test-with-temp-text "* Headline\n *a*"
81 (let ((tree (org-element-parse-buffer)))
82 (org-element-put-property
83 (org-element-map tree 'bold 'identity nil t) :test 1)
84 (should (org-element-property
85 :test (org-element-map tree 'bold 'identity nil t)))))
86 ;; Put property on a string.
87 (should
88 (org-element-property :test (org-element-put-property "Paragraph" :test t))))
90 (ert-deftest test-org-element/set-contents ()
91 "Test `org-element-set-contents' specifications."
92 ;; Accept multiple entries.
93 (should
94 (equal '("b" (italic nil "a"))
95 (org-test-with-temp-text "* Headline\n *a*"
96 (let ((tree (org-element-parse-buffer)))
97 (org-element-set-contents
98 (org-element-map tree 'bold 'identity nil t) "b" '(italic nil "a"))
99 (org-element-contents
100 (org-element-map tree 'bold 'identity nil t))))))
101 ;; Accept atoms and elements.
102 (should
103 (equal '("b")
104 (org-test-with-temp-text "* Headline\n *a*"
105 (let ((tree (org-element-parse-buffer)))
106 (org-element-set-contents
107 (org-element-map tree 'bold 'identity nil t) "b")
108 (org-element-contents
109 (org-element-map tree 'bold 'identity nil t))))))
110 (should
111 (equal '((italic nil "b"))
112 (org-test-with-temp-text "* Headline\n *a*"
113 (let ((tree (org-element-parse-buffer)))
114 (org-element-set-contents
115 (org-element-map tree 'bold 'identity nil t) '(italic nil "b"))
116 (org-element-contents
117 (org-element-map tree 'bold 'identity nil t))))))
118 ;; Allow nil contents.
119 (should-not
120 (org-test-with-temp-text "* Headline\n *a*"
121 (let ((tree (org-element-parse-buffer)))
122 (org-element-set-contents (org-element-map tree 'bold 'identity nil t))
123 (org-element-contents (org-element-map tree 'bold 'identity nil t))))))
125 (ert-deftest test-org-element/set-element ()
126 "Test `org-element-set-element' specifications."
127 (org-test-with-temp-text "* Headline\n*a*"
128 (let ((tree (org-element-parse-buffer)))
129 (org-element-set-element
130 (org-element-map tree 'bold 'identity nil t)
131 '(italic nil "b"))
132 ;; Check if object is correctly replaced.
133 (should (org-element-map tree 'italic 'identity))
134 (should-not (org-element-map tree 'bold 'identity))
135 ;; Check if new object's parent is correctly set.
136 (should
138 (org-element-property :parent
139 (org-element-map tree 'italic 'identity nil t))
140 (org-element-map tree 'paragraph 'identity nil t))))))
142 (ert-deftest test-org-element/adopt-elements ()
143 "Test `org-element-adopt-elements' specifications."
144 ;; Adopt an element.
145 (should
146 (equal '(plain-text italic)
147 (org-test-with-temp-text "* Headline\n *a*"
148 (let ((tree (org-element-parse-buffer)))
149 (org-element-adopt-elements
150 (org-element-map tree 'bold 'identity nil t) '(italic nil "a"))
151 (mapcar (lambda (blob) (org-element-type blob))
152 (org-element-contents
153 (org-element-map tree 'bold 'identity nil t)))))))
154 ;; Adopt a string.
155 (should
156 (equal '("a" "b")
157 (org-test-with-temp-text "* Headline\n *a*"
158 (let ((tree (org-element-parse-buffer)))
159 (org-element-adopt-elements
160 (org-element-map tree 'bold 'identity nil t) "b")
161 (org-element-contents
162 (org-element-map tree 'bold 'identity nil t)))))))
166 ;;; Test Parsers
168 ;;;; Affiliated Keywords
170 (ert-deftest test-org-element/affiliated-keywords-parser ()
171 "Test affiliated keywords parsing."
172 ;; Read simple keywords.
173 (should
174 (equal "para"
175 (org-element-property
176 :name
177 (org-test-with-temp-text "#+NAME: para\nParagraph"
178 (org-element-at-point)))))
179 (should
180 (= 1
181 (org-element-property
182 :begin
183 (org-test-with-temp-text "#+NAME: para\nParagraph"
184 (org-element-at-point)))))
185 ;; Parse multiple keywords.
186 (should
187 (equal
188 '("line2" "line1")
189 (org-element-property
190 :attr_ascii
191 (org-test-with-temp-text
192 "#+ATTR_ASCII: line1\n#+ATTR_ASCII: line2\nParagraph"
193 (org-element-at-point)))))
194 ;; Parse "parsed" keywords.
195 (should
196 (equal
197 '(("caption"))
198 (org-test-with-temp-text "#+CAPTION: caption\nParagraph"
199 (car (org-element-property :caption (org-element-at-point))))))
200 ;; Parse dual keywords.
201 (should
202 (equal
203 '((("long") "short"))
204 (org-test-with-temp-text "#+CAPTION[short]: long\nParagraph"
205 (org-element-property :caption (org-element-at-point)))))
206 ;; Allow multiple caption keywords.
207 (should
208 (equal
209 '((("l2") "s2") (("l1") "s1"))
210 (org-test-with-temp-text "#+CAPTION[s1]: l1\n#+CAPTION[s2]: l2\nParagraph"
211 (org-element-property :caption (org-element-at-point))))))
214 ;;;; Babel Call
216 (ert-deftest test-org-element/babel-call-parser ()
217 "Test `babel-call' parsing."
218 ;; Standard test.
219 (should
220 (org-test-with-temp-text "#+CALL: test()"
221 (org-element-map (org-element-parse-buffer) 'babel-call 'identity)))
222 ;; Ignore case.
223 (should
224 (org-test-with-temp-text "#+call: test()"
225 (org-element-map (org-element-parse-buffer) 'babel-call 'identity))))
228 ;;;; Bold
230 (ert-deftest test-org-element/bold-parser ()
231 "Test `bold' parser."
232 ;; Standard test.
233 (should
234 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
235 (org-test-with-temp-text "*bold*"
236 (org-element-map (org-element-parse-buffer) 'bold 'identity nil t))))
237 ;; Multi-line markup.
238 (should
239 (equal
240 (org-element-contents
241 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
242 (org-test-with-temp-text "*first line\nsecond line*"
243 (org-element-map (org-element-parse-buffer) 'bold 'identity nil t))))
244 '("first line\nsecond line"))))
247 ;;;; Center Block
249 (ert-deftest test-org-element/center-block-parser ()
250 "Test `center-block' parser."
251 ;; Standard test.
252 (should
253 (org-test-with-temp-text "#+BEGIN_CENTER\nText\n#+END_CENTER"
254 (org-element-map (org-element-parse-buffer) 'center-block 'identity)))
255 ;; Ignore case.
256 (should
257 (org-test-with-temp-text "#+begin_center\nText\n#+end_center"
258 (org-element-map (org-element-parse-buffer) 'center-block 'identity)))
259 ;; Test folded block.
260 (org-test-with-temp-text "#+BEGIN_CENTER\nText\n#+END_CENTER"
261 (org-cycle)
262 (should
263 (org-element-property
264 :hiddenp
265 (org-element-map
266 (org-element-parse-buffer) 'center-block 'identity nil t))))
267 ;; Ignore incomplete block.
268 (should-not
269 (org-test-with-temp-text "#+BEGIN_CENTER"
270 (org-element-map
271 (org-element-parse-buffer) 'center-block 'identity nil t))))
274 ;;;; Clock
276 (ert-deftest test-org-element/clock-parser ()
277 "Test `clock' parser."
278 ;; Running clock.
279 (let* ((org-clock-string "CLOCK:")
280 (clock (org-test-with-temp-text "CLOCK: [2012-01-01 sun. 00:01]"
281 (org-element-at-point))))
282 (should (eq (org-element-property :status clock) 'running))
283 (should
284 (equal (org-element-property :raw-value
285 (org-element-property :value clock))
286 "[2012-01-01 sun. 00:01]"))
287 (should-not (org-element-property :duration clock)))
288 ;; Closed clock.
289 (let* ((org-clock-string "CLOCK:")
290 (clock
291 (org-test-with-temp-text
292 "CLOCK: [2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02] => 0:01"
293 (org-element-at-point))))
294 (should (eq (org-element-property :status clock) 'closed))
295 (should (equal (org-element-property :raw-value
296 (org-element-property :value clock))
297 "[2012-01-01 sun. 00:01]--[2012-01-01 sun. 00:02]"))
298 (should (equal (org-element-property :duration clock) "0:01"))))
301 ;;;; Code
303 (ert-deftest test-org-element/code-parser ()
304 "Test `code' parser."
305 ;; Regular test.
306 (should
307 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
308 (org-test-with-temp-text "~code~"
309 (org-element-map (org-element-parse-buffer) 'code 'identity))))
310 ;; Multi-line markup.
311 (should
312 (equal
313 (org-element-property
314 :value
315 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
316 (org-test-with-temp-text "~first line\nsecond line~"
317 (org-element-map
318 (org-element-parse-buffer) 'code 'identity nil t))))
319 "first line\nsecond line")))
322 ;;;; Comment
324 (ert-deftest test-org-element/comment-parser ()
325 "Test `comment' parser."
326 ;; Regular comment.
327 (should
328 (org-test-with-temp-text "# Comment"
329 (org-element-map (org-element-parse-buffer) 'comment 'identity)))
330 ;; Inline comment.
331 (should
332 (org-test-with-temp-text " # Comment"
333 (org-element-map (org-element-parse-buffer) 'comment 'identity)))
334 ;; Preserve indentation.
335 (should
336 (equal
337 (org-element-property
338 :value
339 (org-test-with-temp-text "# No blank\n# One blank"
340 (org-element-map (org-element-parse-buffer) 'comment 'identity nil t)))
341 "No blank\n One blank"))
342 ;; Comment with blank lines.
343 (should
344 (equal
345 (org-element-property
346 :value
347 (org-test-with-temp-text "# First part\n# \n#\n# Second part"
348 (org-element-map (org-element-parse-buffer) 'comment 'identity nil t)))
349 "First part\n\n\nSecond part"))
350 ;; Do not mix comments and keywords.
351 (should
352 (eq 1
353 (org-test-with-temp-text "#+keyword: value\n# comment\n#+keyword: value"
354 (length (org-element-map
355 (org-element-parse-buffer) 'comment 'identity)))))
356 (should
357 (equal "comment"
358 (org-test-with-temp-text "#+keyword: value\n# comment\n#+keyword: value"
359 (org-element-property
360 :value
361 (org-element-map
362 (org-element-parse-buffer) 'comment 'identity nil t))))))
365 ;;;; Comment Block
367 (ert-deftest test-org-element/comment-block-parser ()
368 "Test `comment-block' parser."
369 ;; Standard test.
370 (should
371 (org-test-with-temp-text "#+BEGIN_COMMENT\nText\n#+END_COMMENT"
372 (org-element-map
373 (org-element-parse-buffer) 'comment-block 'identity)))
374 ;; Ignore case.
375 (should
376 (org-test-with-temp-text "#+begin_comment\nText\n#+end_comment"
377 (org-element-map
378 (org-element-parse-buffer) 'comment-block 'identity)))
379 ;; Test folded block.
380 (org-test-with-temp-text "#+BEGIN_COMMENT\nText\n#+END_COMMENT"
381 (org-cycle)
382 (should
383 (org-element-property
384 :hiddenp
385 (org-element-map
386 (org-element-parse-buffer) 'comment-block 'identity nil t))))
387 ;; Ignore incomplete block.
388 (should-not
389 (org-test-with-temp-text "#+BEGIN_COMMENT"
390 (org-element-map
391 (org-element-parse-buffer) 'comment-block 'identity nil t))))
394 ;;;; Diary Sexp
396 (ert-deftest test-org-element/diary-sexp-parser ()
397 "Test `diary-sexp' parser."
398 ;; Standard test.
399 (should
400 (eq 'diary-sexp
401 (org-test-with-temp-text
402 "%%(org-anniversary 1956 5 14)(2) Arthur Dent is %d years old"
403 (org-element-type (org-element-at-point)))))
404 ;; Diary sexp must live at beginning of line
405 (should-not
406 (eq 'diary-sexp
407 (org-test-with-temp-text " %%(org-bbdb-anniversaries)"
408 (org-element-type (org-element-at-point))))))
411 ;;;; Drawer
413 (ert-deftest test-org-element/drawer-parser ()
414 "Test `drawer' parser."
415 ;; Standard test.
416 (should
417 (let ((org-drawers '("TEST")))
418 (org-test-with-temp-text ":TEST:\nText\n:END:"
419 (org-element-map (org-element-parse-buffer) 'drawer 'identity))))
420 ;; Do not mix regular drawers and property drawers.
421 (should-not
422 (let ((org-drawers '("PROPERTIES")))
423 (org-test-with-temp-text ":PROPERTIES:\n:prop: value\n:END:"
424 (org-element-map
425 (org-element-parse-buffer) 'drawer 'identity nil t))))
426 ;; Ignore incomplete drawer.
427 (should-not
428 (let ((org-drawers '("TEST")))
429 (org-test-with-temp-text ":TEST:"
430 (org-element-map
431 (org-element-parse-buffer) 'drawer 'identity nil t)))))
434 ;;;; Dynamic Block
436 (ert-deftest test-org-element/dynamic-block-parser ()
437 "Test `dynamic-block' parser."
438 ;; Standard test.
439 (should
440 (org-test-with-temp-text
441 "#+BEGIN: myblock :param1 val1 :param2 val2\nText\n#+END:"
442 (org-element-map (org-element-parse-buffer) 'dynamic-block 'identity)))
443 ;; Folded view
444 (org-test-with-temp-text
445 "#+BEGIN: myblock :param1 val1 :param2 val2\nText\n#+END:"
446 (org-cycle)
447 (should
448 (org-element-property
449 :hiddenp
450 (org-element-map
451 (org-element-parse-buffer) 'dynamic-block 'identity nil t))))
452 ;; Ignore case.
453 (should
454 (org-test-with-temp-text
455 "#+begin: myblock :param1 val1 :param2 val2\nText\n#+end:"
456 (org-element-map (org-element-parse-buffer) 'dynamic-block 'identity)))
457 ;; Ignore incomplete block.
458 (should-not
459 (org-test-with-temp-text "#+BEGIN: myblock :param1 val1 :param2 val2"
460 (org-element-map
461 (org-element-parse-buffer) 'dynamic-block 'identity nil t))))
464 ;;;; Entity
466 (ert-deftest test-org-element/entity-parser ()
467 "Test `entity' parser."
468 ;; Without brackets.
469 (should
470 (org-test-with-temp-text "\\sin"
471 (org-element-map (org-element-parse-buffer) 'entity 'identity)))
472 ;; With brackets.
473 (should
474 (org-element-property
475 :use-brackets-p
476 (org-test-with-temp-text "\\alpha{}text"
477 (org-element-map (org-element-parse-buffer) 'entity 'identity nil t))))
478 ;; User-defined entity.
479 (should
480 (equal
481 (org-element-property
482 :name
483 (let ((org-entities-user
484 '(("test" "test" nil "test" "test" "test" "test"))))
485 (org-test-with-temp-text "\\test"
486 (org-element-map (org-element-parse-buffer) 'entity 'identity nil t))))
487 "test")))
490 ;;;; Example Block
492 (ert-deftest test-org-element/example-block-parser ()
493 "Test `example-block' parser."
494 ;; Standard test.
495 (should
496 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText\n#+END_EXAMPLE"
497 (org-element-map (org-element-parse-buffer) 'example-block 'identity)))
498 ;; Test folded block.
499 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText\n#+END_EXAMPLE"
500 (org-cycle)
501 (should
502 (org-element-property
503 :hiddenp
504 (org-element-map
505 (org-element-parse-buffer) 'example-block 'identity nil t))))
506 ;; Ignore incomplete block.
507 (should-not
508 (org-test-with-temp-text "#+BEGIN_EXAMPLE"
509 (org-element-map
510 (org-element-parse-buffer) 'example-block 'identity nil t)))
511 ;; Properly un-escape code.
512 (should
513 (equal "* Headline\n #+keyword\nText\n"
514 (org-test-with-temp-text
515 "#+BEGIN_EXAMPLE\n,* Headline\n ,#+keyword\nText\n#+END_EXAMPLE"
516 (org-element-property :value (org-element-at-point))))))
518 (ert-deftest test-org-element/block-switches ()
519 "Test `example-block' and `src-block' switches parsing."
520 (let ((org-coderef-label-format "(ref:%s)"))
521 ;; 1. Test "-i" switch.
522 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
523 (should-not
524 (org-element-property :preserve-indent (org-element-at-point))))
525 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -i\n(+ 1 1)\n#+END_SRC"
526 (should (org-element-property :preserve-indent (org-element-at-point))))
527 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText.\n#+END_EXAMPLE"
528 (should-not
529 (org-element-property :preserve-indent (org-element-at-point))))
530 (org-test-with-temp-text "#+BEGIN_EXAMPLE -i\nText.\n#+END_EXAMPLE"
531 (should (org-element-property :preserve-indent (org-element-at-point))))
532 ;; 2. "-n -r -k" combination should number lines, retain labels but
533 ;; not use them in coderefs.
534 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n -r -k\nText.\n#+END_EXAMPLE"
535 (let ((element (org-element-at-point)))
536 (should (and (org-element-property :number-lines element)
537 (org-element-property :retain-labels element)
538 (not (org-element-property :use-labels element))))))
539 (org-test-with-temp-text
540 "#+BEGIN_SRC emacs-lisp -n -r -k\n(+ 1 1)\n#+END_SRC"
541 (let ((element (org-element-at-point)))
542 (should (and (org-element-property :number-lines element)
543 (org-element-property :retain-labels element)
544 (not (org-element-property :use-labels element))))))
545 ;; 3. "-n -r" combination should number-lines remove labels and not
546 ;; use them in coderefs.
547 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n -r\nText.\n#+END_EXAMPLE"
548 (let ((element (org-element-at-point)))
549 (should (and (org-element-property :number-lines element)
550 (not (org-element-property :retain-labels element))
551 (not (org-element-property :use-labels element))))))
552 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -n -r\n(+ 1 1)\n#+END_SRC"
553 (let ((element (org-element-at-point)))
554 (should (and (org-element-property :number-lines element)
555 (not (org-element-property :retain-labels element))
556 (not (org-element-property :use-labels element))))))
557 ;; 4. "-n" or "+n" should number lines, retain labels and use them
558 ;; in coderefs.
559 (org-test-with-temp-text "#+BEGIN_EXAMPLE -n\nText.\n#+END_EXAMPLE"
560 (let ((element (org-element-at-point)))
561 (should (and (org-element-property :number-lines element)
562 (org-element-property :retain-labels element)
563 (org-element-property :use-labels element)))))
564 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -n\n(+ 1 1)\n#+END_SRC"
565 (let ((element (org-element-at-point)))
566 (should (and (org-element-property :number-lines element)
567 (org-element-property :retain-labels element)
568 (org-element-property :use-labels element)))))
569 (org-test-with-temp-text "#+BEGIN_EXAMPLE +n\nText.\n#+END_EXAMPLE"
570 (let ((element (org-element-at-point)))
571 (should (and (org-element-property :number-lines element)
572 (org-element-property :retain-labels element)
573 (org-element-property :use-labels element)))))
574 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp +n\n(+ 1 1)\n#+END_SRC"
575 (let ((element (org-element-at-point)))
576 (should (and (org-element-property :number-lines element)
577 (org-element-property :retain-labels element)
578 (org-element-property :use-labels element)))))
579 ;; 5. No switch should not number lines, but retain labels and use
580 ;; them in coderefs.
581 (org-test-with-temp-text "#+BEGIN_EXAMPLE\nText.\n#+END_EXAMPLE"
582 (let ((element (org-element-at-point)))
583 (should (and (not (org-element-property :number-lines element))
584 (org-element-property :retain-labels element)
585 (org-element-property :use-labels element)))))
586 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n(+ 1 1)\n#+END_SRC"
587 (let ((element (org-element-at-point)))
588 (should (and (not (org-element-property :number-lines element))
589 (org-element-property :retain-labels element)
590 (org-element-property :use-labels element)))))
591 ;; 6. "-r" switch only: do not number lines, remove labels, and
592 ;; don't use labels in coderefs.
593 (org-test-with-temp-text "#+BEGIN_EXAMPLE -r\nText.\n#+END_EXAMPLE"
594 (let ((element (org-element-at-point)))
595 (should (and (not (org-element-property :number-lines element))
596 (not (org-element-property :retain-labels element))
597 (not (org-element-property :use-labels element))))))
598 (org-test-with-temp-text "#+BEGIN_SRC emacs-lisp -r\n(+ 1 1)\n#+END_SRC"
599 (let ((element (org-element-at-point)))
600 (should (and (not (org-element-property :number-lines element))
601 (not (org-element-property :retain-labels element))
602 (not (org-element-property :use-labels element))))))
603 ;; 7. Recognize coderefs with user-defined syntax.
604 (org-test-with-temp-text
605 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText [ref:text]\n#+END_EXAMPLE"
606 (let ((element (org-element-at-point)))
607 (should
608 (equal (org-element-property :label-fmt element) "[ref:%s]"))))
609 (org-test-with-temp-text
610 "#+BEGIN_SRC emacs-lisp -l \"[ref:%s]\"\n(+ 1 1) [ref:text]\n#+END_SRC"
611 (let ((element (org-element-at-point)))
612 (should
613 (equal (org-element-property :label-fmt element) "[ref:%s]"))))))
616 ;;;; Export Block
618 (ert-deftest test-org-element/export-block-parser ()
619 "Test `export-block' parser."
620 ;; Standard test.
621 (should
622 (org-test-with-temp-text "#+BEGIN_LATEX\nText\n#+END_LATEX"
623 (org-element-map
624 (let ((org-element-block-name-alist
625 '(("LATEX" . org-element-export-block-parser))))
626 (org-element-parse-buffer))
627 'export-block 'identity)))
628 ;; Test folded block.
629 (org-test-with-temp-text "#+BEGIN_LATEX\nText\n#+END_LATEX"
630 (org-cycle)
631 (should
632 (org-element-property
633 :hiddenp
634 (org-element-map
635 (let ((org-element-block-name-alist
636 '(("LATEX" . org-element-export-block-parser))))
637 (org-element-parse-buffer))
638 'export-block 'identity nil t))))
639 ;; Ignore case.
640 (should
641 (org-test-with-temp-text "#+begin_latex\nText\n#+end_latex"
642 (org-element-map
643 (let ((org-element-block-name-alist
644 '(("LATEX" . org-element-export-block-parser))))
645 (org-element-parse-buffer))
646 'export-block 'identity)))
647 ;; Ignore incomplete block.
648 (should-not
649 (org-test-with-temp-text "#+BEGIN_LATEX"
650 (org-element-map
651 (let ((org-element-block-name-alist
652 '(("LATEX" . org-element-export-block-parser))))
653 (org-element-parse-buffer))
654 'export-block 'identity nil t))))
657 ;;;; Export Snippet
659 (ert-deftest test-org-element/export-snippet-parser ()
660 "Test `export-snippet' parser."
661 (should
662 (equal
663 '("back-end" . "contents")
664 (org-test-with-temp-text "@@back-end:contents@@"
665 (org-element-map
666 (org-element-parse-buffer) 'export-snippet
667 (lambda (snippet) (cons (org-element-property :back-end snippet)
668 (org-element-property :value snippet)))
669 nil t)))))
672 ;;;; Fixed Width
674 (ert-deftest test-org-element/fixed-width ()
675 "Test fixed-width area parsing."
676 ;; Preserve indentation.
677 (should
678 (org-test-with-temp-text ": no blank\n: one blank"
679 (org-element-map (org-element-parse-buffer) 'fixed-width 'identity)))
680 ;; Fixed-width with empty lines.
681 (should
682 (org-test-with-temp-text ": first part\n:\n: \n: second part"
683 (org-element-map (org-element-parse-buffer) 'fixed-width 'identity)))
684 ;; Parse indented fixed-width markers.
685 (should
686 (org-test-with-temp-text "Text\n : no blank\n : one blank"
687 (org-element-map (org-element-parse-buffer) 'fixed-width 'identity)))
688 ;; Distinguish fixed-width areas within a list and outside of it.
689 (should
690 (= 2
691 (length
692 (org-test-with-temp-text "
693 - Item
694 : fixed-width inside
695 : fixed-width outside"
696 (org-element-map
697 (org-element-parse-buffer) 'fixed-width 'identity))))))
700 ;;;; Footnote Definition
702 (ert-deftest test-org-element/footnote-definition-parser ()
703 "Test `footnote-definition' parser."
704 (should
705 (org-test-with-temp-text "[fn:1] Definition"
706 (org-element-map
707 (org-element-parse-buffer) 'footnote-definition 'identity nil t)))
708 ;; Footnote with more contents
709 (should
710 (= 28
711 (org-element-property
712 :end
713 (org-test-with-temp-text "[fn:1] Definition\n| a | b |"
714 (org-element-map
715 (org-element-parse-buffer)
716 'footnote-definition 'identity nil t)))))
717 ;; Footnote starting with special syntax.
718 (should-not
719 (org-test-with-temp-text "[fn:1] - no item"
720 (org-element-map (org-element-parse-buffer) 'item 'identity))))
723 ;;;; Footnotes Reference.
725 (ert-deftest test-org-element/footnote-reference-parser ()
726 "Test `footnote-reference' parser."
727 ;; 1. Parse a standard reference.
728 (org-test-with-temp-text "Text[fn:label]"
729 (should
730 (org-element-map
731 (org-element-parse-buffer) 'footnote-reference 'identity)))
732 ;; 2. Parse a normalized reference.
733 (org-test-with-temp-text "Text[1]"
734 (should
735 (org-element-map
736 (org-element-parse-buffer) 'footnote-reference 'identity)))
737 ;; 3. Parse an inline reference.
738 (org-test-with-temp-text "Text[fn:test:def]"
739 (should
740 (org-element-map
741 (org-element-parse-buffer) 'footnote-reference 'identity)))
742 ;; 4. Parse an anonymous reference.
743 (org-test-with-temp-text "Text[fn::def]"
744 (should
745 (org-element-map
746 (org-element-parse-buffer) 'footnote-reference 'identity)))
747 ;; 5. Parse nested footnotes.
748 (org-test-with-temp-text "Text[fn::def [fn:label]]"
749 (should
750 (= 2
751 (length
752 (org-element-map
753 (org-element-parse-buffer) 'footnote-reference 'identity)))))
754 ;; 6. Parse adjacent footnotes.
755 (org-test-with-temp-text "Text[fn:label1][fn:label2]"
756 (should
757 (= 2
758 (length
759 (org-element-map
760 (org-element-parse-buffer) 'footnote-reference 'identity)))))
761 ;; 7. Only properly closed footnotes are recognized as such.
762 (org-test-with-temp-text "Text[fn:label"
763 (should-not
764 (org-element-map
765 (org-element-parse-buffer) 'footnote-reference 'identity))))
768 ;;;; Headline
770 (ert-deftest test-org-element/headline-quote-keyword ()
771 "Test QUOTE keyword recognition."
772 ;; Reference test.
773 (org-test-with-temp-text "* Headline"
774 (let ((org-quote-string "QUOTE"))
775 (should-not (org-element-property :quotedp (org-element-at-point)))))
776 ;; Standard position.
777 (org-test-with-temp-text "* QUOTE Headline"
778 (let* ((org-quote-string "QUOTE")
779 (headline (org-element-at-point)))
780 (should (org-element-property :quotedp headline))
781 ;; Test removal from raw value.
782 (should (equal (org-element-property :raw-value headline) "Headline"))))
783 ;; Case sensitivity.
784 (org-test-with-temp-text "* QUOTE Headline"
785 (let* ((org-quote-string "Quote")
786 (headline (org-element-at-point)))
787 (should-not (org-element-property :quotedp headline))
788 (should (equal (org-element-property :raw-value headline)
789 "QUOTE Headline"))))
790 ;; With another keyword.
791 (org-test-with-temp-text "* TODO QUOTE Headline"
792 (let* ((org-quote-string "QUOTE")
793 (org-todo-keywords '((sequence "TODO" "DONE")))
794 (headline (org-element-at-point)))
795 (should (org-element-property :quotedp headline))
796 (should (equal (org-element-property :raw-value headline) "Headline"))))
797 ;; With the keyword only.
798 (org-test-with-temp-text "* QUOTE"
799 (let* ((org-quote-string "QUOTE")
800 (headline (org-element-at-point)))
801 (should (org-element-property :quotedp headline))
802 (should (equal (org-element-property :raw-value headline) "")))))
804 (ert-deftest test-org-element/headline-comment-keyword ()
805 "Test COMMENT keyword recognition."
806 ;; Reference test.
807 (org-test-with-temp-text "* Headline"
808 (let ((org-comment-string "COMMENT"))
809 (should-not (org-element-property :commentedp (org-element-at-point)))))
810 ;; Standard position.
811 (org-test-with-temp-text "* COMMENT Headline"
812 (let ((org-comment-string "COMMENT")
813 (headline (org-element-at-point)))
814 (should (org-element-property :commentedp headline))
815 (should (equal (org-element-property :raw-value headline) "Headline"))))
816 ;; Case sensitivity.
817 (org-test-with-temp-text "* COMMENT Headline"
818 (let* ((org-comment-string "Comment")
819 (headline (org-element-at-point)))
820 (should-not (org-element-property :commentedp headline))
821 (should (equal (org-element-property :raw-value headline)
822 "COMMENT Headline"))))
823 ;; With another keyword.
824 (org-test-with-temp-text "* TODO COMMENT Headline"
825 (let* ((org-comment-string "COMMENT")
826 (org-todo-keywords '((sequence "TODO" "DONE")))
827 (headline (org-element-at-point)))
828 (should (org-element-property :commentedp headline))
829 (should (equal (org-element-property :raw-value headline) "Headline"))))
830 ;; With the keyword only.
831 (org-test-with-temp-text "* COMMENT"
832 (let* ((org-comment-string "COMMENT")
833 (headline (org-element-at-point)))
834 (should (org-element-property :commentedp headline))
835 (should (equal (org-element-property :raw-value headline) "")))))
837 (ert-deftest test-org-element/headline-archive-tag ()
838 "Test ARCHIVE tag recognition."
839 ;; Reference test.
840 (org-test-with-temp-text "* Headline"
841 (let ((org-archive-tag "ARCHIVE"))
842 (should-not (org-element-property :archivedp (org-element-at-point)))))
843 ;; Single tag.
844 (org-test-with-temp-text "* Headline :ARCHIVE:"
845 (let ((org-archive-tag "ARCHIVE"))
846 (let ((headline (org-element-at-point)))
847 (should (org-element-property :archivedp headline))
848 ;; Test tag removal.
849 (should-not (org-element-property :tags headline))))
850 (let ((org-archive-tag "Archive"))
851 (should-not (org-element-property :archivedp (org-element-at-point)))))
852 ;; Multiple tags.
853 (org-test-with-temp-text "* Headline :test:ARCHIVE:"
854 (let ((org-archive-tag "ARCHIVE"))
855 (let ((headline (org-element-at-point)))
856 (should (org-element-property :archivedp headline))
857 ;; Test tag removal.
858 (should (equal (org-element-property :tags headline) '("test")))))))
861 ;;;; Horizontal Rule
863 (ert-deftest test-org-element/horizontal-rule-parser ()
864 "Test `horizontal-rule' parser."
865 ;; Standard.
866 (should
867 (org-test-with-temp-text "-----"
868 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity)))
869 ;; Indented.
870 (should
871 (org-test-with-temp-text " -----"
872 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity)))
873 ;; Hyphen must be alone on the line.
874 (should-not
875 (org-test-with-temp-text "-----wrong"
876 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity)))
877 ;; 4 hyphens is too small.
878 (should-not
879 (org-test-with-temp-text "----"
880 (org-element-map (org-element-parse-buffer) 'horizontal-rule 'identity))))
883 ;;;; Inline Babel Call
885 (ert-deftest test-org-element/inline-babel-call-parser ()
886 "Test `inline-babel-call' parser."
887 (should
888 (org-test-with-temp-text "call_test()"
889 (org-element-map
890 (org-element-parse-buffer) 'inline-babel-call 'identity))))
893 ;;;; Inline Src Block
895 (ert-deftest test-org-element/inline-src-block-parser ()
896 "Test `inline-src-block' parser."
897 (should
898 (org-test-with-temp-text "src_emacs-lisp{(+ 1 1)}"
899 (org-element-map (org-element-parse-buffer) 'inline-src-block 'identity)))
900 ;; Test parsing at the beginning of an item.
901 (should
902 (org-test-with-temp-text "- src_emacs-lisp{(+ 1 1)}"
903 (org-element-map (org-element-parse-buffer) 'inline-src-block 'identity))))
906 ;;;; Inlinetask
908 (ert-deftest test-org-element/inlinetask-parser ()
909 "Test `inlinetask' parser."
910 (when (featurep 'org-inlinetask)
911 (let ((org-inlinetask-min-level 15))
912 ;; 1. Regular inlinetask.
913 (should
914 (org-test-with-temp-text
915 "*************** Task\nTest\n*************** END"
916 (org-element-map (org-element-parse-buffer) 'inlinetask 'identity)))
917 ;; 2. Degenerate inlinetask.
918 (should
919 (org-test-with-temp-text "*************** Task"
920 (org-element-map (org-element-parse-buffer) 'inlinetask 'identity)))
921 ;; TODO keyword.
922 (should
923 (equal
924 "TODO"
925 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
926 (org-test-with-temp-text "*************** TODO Task"
927 (org-element-property
928 :todo-keyword
929 (org-element-map
930 (org-element-parse-buffer) 'inlinetask 'identity nil t))))))
931 ;; Planning info.
932 (should
933 (equal
934 "2012-03-29 thu."
935 (org-test-with-temp-text "
936 *************** Task
937 DEADLINE: <2012-03-29 thu.>"
938 (org-element-property
939 :deadline
940 (org-element-map
941 (org-element-parse-buffer) 'inlinetask 'identity nil t)))))
942 ;; Priority.
943 (should
944 (equal
946 (org-test-with-temp-text "
947 *************** [#A] Task"
948 (org-element-property
949 :priority
950 (org-element-map
951 (org-element-parse-buffer) 'inlinetask 'identity nil t)))))
952 ;; Tags.
953 (should
954 (equal
955 '("test")
956 (org-test-with-temp-text "
957 *************** Task :test:"
958 (org-element-property
959 :tags
960 (org-element-map
961 (org-element-parse-buffer) 'inlinetask 'identity nil t))))))))
964 ;;;; Italic
966 (ert-deftest test-org-element/italic-parser ()
967 "Test `italic' parser."
968 ;; Regular test.
969 (should
970 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
971 (org-test-with-temp-text "/italic/"
972 (org-element-map (org-element-parse-buffer) 'italic 'identity nil t))))
973 ;; Multi-line markup.
974 (should
975 (equal
976 (org-element-contents
977 (let ((org-emph-re "\\([ ('\"{]\\|^\\)\\(\\([+*/_=~]\\)\\([^ \n,\"']\\|[^ \n,\"'].*?\\(?:\n.*?\\)\\{0,1\\}[^ \n,\"']\\)\\3\\)\\([- .,:!?;'\")}\\]\\|$\\)"))
978 (org-test-with-temp-text "/first line\nsecond line/"
979 (org-element-map (org-element-parse-buffer) 'italic 'identity nil t))))
980 '("first line\nsecond line"))))
983 ;;;; Item
985 (ert-deftest test-org-element/item-parser ()
986 "Test `item' parser."
987 ;; Standard test.
988 (should
989 (org-test-with-temp-text "- item"
990 (org-element-map (org-element-parse-buffer) 'item 'identity)))
991 ;; Counter.
992 (should
993 (= 6
994 (org-element-property
995 :counter
996 (org-test-with-temp-text "6. [@6] item"
997 (org-element-map (org-element-parse-buffer) 'item 'identity nil t)))))
998 ;; Tag
999 (should
1000 (equal
1001 '("tag")
1002 (org-element-property
1003 :tag
1004 (org-test-with-temp-text "- tag :: description"
1005 (org-element-map (org-element-parse-buffer) 'item 'identity nil t)))))
1006 ;; No tags in ordered lists.
1007 (should-not
1008 (org-element-property
1009 :tag
1010 (org-test-with-temp-text "1. tag :: description"
1011 (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))
1012 ;; Check-boxes
1013 (should
1014 (equal
1015 '(trans on off)
1016 (org-test-with-temp-text "
1017 - [-] item 1
1018 - [X] item 1.1
1019 - [ ] item 1.2"
1020 (org-element-map
1021 (org-element-parse-buffer) 'item
1022 (lambda (item) (org-element-property :checkbox item))))))
1023 ;; Folded state.
1024 (org-test-with-temp-text "* Headline
1025 - item
1027 paragraph below"
1028 (forward-line)
1029 (let ((org-cycle-include-plain-lists t)) (org-cycle))
1030 (should
1031 (org-element-property
1032 :hiddenp
1033 (org-element-map (org-element-parse-buffer) 'item 'identity nil t))))
1034 ;; Item starting with special syntax.
1035 (should
1036 (equal '(("- item"))
1037 (org-test-with-temp-text "- - item"
1038 (org-element-map
1039 (org-element-parse-buffer) 'paragraph 'org-element-contents)))))
1042 ;;;; Keyword
1044 (ert-deftest test-org-element/keyword-parser ()
1045 "Test `keyword' parser."
1046 ;; Standard test.
1047 (should
1048 (org-test-with-temp-text "#+KEYWORD: value"
1049 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
1050 ;; Keywords are case-insensitive.
1051 (should
1052 (org-test-with-temp-text "#+keyword: value"
1053 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
1054 ;; Affiliated keywords are not keywords.
1055 (should-not
1056 (org-test-with-temp-text "#+NAME: value
1057 Paragraph"
1058 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
1059 ;; Do not mix keywords with Babel calls and dynamic blocks.
1060 (should-not
1061 (org-test-with-temp-text "#+CALL: fun()"
1062 (org-element-map (org-element-parse-buffer) 'keyword 'identity)))
1063 (should-not
1064 (org-test-with-temp-text "#+BEGIN: my-fun\nBody\n#+END:"
1065 (org-element-map (org-element-parse-buffer) 'keyword 'identity))))
1068 ;;;; Latex Environment
1070 (ert-deftest test-org-element/latex-environment-parser ()
1071 "Test `latex-environment' parser."
1072 (should
1073 (org-test-with-temp-text "\\begin{equation}\ne^{i\\pi}+1=0\n\\end{equation}"
1074 (org-element-map
1075 (org-element-parse-buffer) 'latex-environment 'identity)))
1076 ;; Allow nested environments.
1077 (should
1078 (equal
1079 "\\begin{outer}
1080 \\begin{inner}
1081 e^{i\\pi}+1=0
1082 \\end{inner}
1083 \\end{outer}"
1084 (org-test-with-temp-text "
1085 \\begin{outer}
1086 \\begin{inner}
1087 e^{i\\pi}+1=0
1088 \\end{inner}
1089 \\end{outer}"
1090 (org-element-property
1091 :value
1092 (org-element-map
1093 (org-element-parse-buffer) 'latex-environment 'identity nil t))))))
1096 ;;;; Latex Fragment
1098 (ert-deftest test-org-element/latex-fragment-parser ()
1099 "Test `latex-fragment' parser."
1100 (let ((org-latex-regexps
1101 '(("begin" "^[ ]*\\(\\\\begin{\\([a-zA-Z0-9\\*]+\\)[^