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