1 ;;; test-org-export.el --- Tests for org-export.el
3 ;; Copyright (C) 2012 Nicolas Goaziou
5 ;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
7 ;; Released under the GNU General Public License version 3
8 ;; see: http://www.gnu.org/licenses/gpl-3.0.html
16 (unless (featurep 'org-export
)
17 (signal 'missing-test-dependency
"org-export"))
23 (defmacro org-test-with-backend
(backend &rest body
)
24 "Execute body with an export back-end defined.
26 BACKEND is the name, as a string, of the back-end. BODY is the
27 body to execute. The defined back-end simply returns parsed data
29 (declare (debug (form body
)) (indent 1))
30 `(flet ,(let (transcoders)
31 (dolist (type (append org-element-all-elements
32 org-element-all-objects
)
34 (push `(,(intern (format "org-%s-%s" backend type
))
36 (,(intern (format "org-element-%s-interpreter" type
))
41 (defmacro org-test-with-parsed-data
(data &rest body
)
42 "Execute body with parsed data available.
44 DATA is a string containing the data to be parsed. BODY is the
45 body to execute. Parse tree is available under the `tree'
46 variable, and communication channel under `info'.
48 This function calls `org-export-collect-tree-properties'. As
49 such, `:ignore-list' (for `org-element-map') and
50 `:parse-tree' (for `org-export-get-genealogy') properties are
51 already filled in `info'."
52 (declare (debug (form body
)) (indent 1))
53 `(org-test-with-temp-text ,data
54 (let* ((tree (org-element-parse-buffer))
55 (info (org-export-collect-tree-properties tree nil nil
)))
58 (ert-deftest test-org-export
/parse-option-keyword
()
59 "Test reading all standard #+OPTIONS: items."
62 (org-export-parse-option-keyword
63 "H:1 num:t \\n:t timestamp:t arch:t author:t creator:t d:t email:t
64 *:t e:t ::t f:t pri:t -:t ^:t toc:t |:t tags:t tasks:t <:t todo:t")
66 1 :preserve-breaks t
:section-numbers t
:time-stamp-file t
67 :with-archived-trees t
:with-author t
:with-creator t
:with-drawers t
68 :with-email t
:with-emphasize t
:with-entities t
:with-fixed-width t
69 :with-footnotes t
:with-priority t
:with-special-strings t
70 :with-sub-superscript t
:with-toc t
:with-tables t
:with-tags t
71 :with-tasks t
:with-timestamps t
:with-todo-keywords t
)))
72 ;; Test some special values.
75 (org-export-parse-option-keyword
76 "arch:headline creator:comment d:(\"TEST\")
77 ^:{} toc:1 tags:not-in-toc tasks:todo num:2")
80 :with-archived-trees headline
:with-creator comment
81 :with-drawers
("TEST") :with-sub-superscript
{} :with-toc
1
82 :with-tags not-in-toc
:with-tasks todo
))))
84 (ert-deftest test-org-export
/get-inbuffer-options
()
85 "Test reading all standard export keywords."
88 (org-test-with-temp-text "#+AUTHOR: Me, Myself and I
91 #+DESCRIPTION: Testing
92 #+DESCRIPTION: with two lines
93 #+EMAIL: some@email.org
94 #+EXPORT_EXCLUDE_TAGS: noexport invisible
97 #+EXPORT_SELECT_TAGS: export
100 (org-export-get-inbuffer-options))
102 ("Me, Myself and I") :creator
"Idem" :date
"Today"
103 :description
"Testing\nwith two lines" :email
"some@email.org"
104 :exclude-tags
("noexport" "invisible") :keywords
"test" :language
"en"
105 :select-tags
("export") :title
("Some title with spaces")))))
107 (ert-deftest test-org-export
/define-macro
()
108 "Try defining various Org macro using in-buffer #+MACRO: keyword."
110 (should (equal (org-test-with-temp-text "#+MACRO: one 1"
111 (org-export-get-inbuffer-options))
112 '(:macro-one
("1"))))
114 (should (equal (org-test-with-temp-text "#+MACRO: two (eval (+ 1 1))"
115 (org-export-get-inbuffer-options))
116 '(:macro-two
"(eval (+ 1 1))")))
118 (should-not (org-test-with-temp-text "#+MACRO: three"
119 (org-export-get-inbuffer-options)))
120 ;; Macro with newline character.
121 (should (equal (org-test-with-temp-text "#+MACRO: four a\\nb"
122 (org-export-get-inbuffer-options))
123 '(:macro-four
("a\nb"))))
124 ;; Macro with protected newline character.
125 (should (equal (org-test-with-temp-text "#+MACRO: five a\\\\nb"
126 (org-export-get-inbuffer-options))
127 '(:macro-five
("a\\nb"))))
129 (org-test-with-temp-text "#+MACRO: six 6\n#+MACRO: seven 1 + {{{six}}}"
132 (org-export-get-inbuffer-options)
136 ("1 + " (macro (:key
"six" :value
"{{{six}}}" :args nil
:begin
5 :end
14
137 :post-blank
0))))))))
139 (ert-deftest test-org-export
/handle-options
()
140 "Test if export options have an impact on output."
141 ;; Test exclude tags.
142 (org-test-with-temp-text "* Head1 :noexport:"
143 (org-test-with-backend "test"
145 (equal (org-export-as 'test nil nil nil
'(:exclude-tags
("noexport")))
147 ;; Test include tags.
148 (org-test-with-temp-text "
150 ** Sub-Head1.1 :export:
153 (org-test-with-backend "test"
156 "\\* Head1\n\\*\\* Sub-Head1.1[ \t]+:export:\n\\*\\*\\* Sub-Head1.1.1\n"
157 (org-export-as 'test nil nil nil
'(:select-tags
("export")))))))
158 ;; Test mixing include tags and exclude tags.
159 (org-test-with-temp-text "
161 ** Sub-Head1 :noexport:
164 ** Sub-Head1 :export:"
165 (org-test-with-backend "test"
168 "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
171 '(:select-tags
("export") :exclude-tags
("noexport")))))))
173 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
174 (org-test-with-temp-text "* TODO Head1"
175 (org-test-with-backend "test"
176 (should (equal (org-export-as 'test nil nil nil
'(:with-tasks nil
))
178 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
179 (org-test-with-temp-text "* TODO Head1"
180 (org-test-with-backend "test"
181 (should (equal (org-export-as 'test nil nil nil
'(:with-tasks t
))
182 "* TODO Head1\n")))))
184 (org-test-with-temp-text "* Head1 :archive:"
185 (let ((org-archive-tag "archive"))
186 (org-test-with-backend "test"
188 (equal (org-export-as 'test nil nil nil
'(:with-archived-trees nil
))
190 (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
191 (let ((org-archive-tag "archive"))
192 (org-test-with-backend "test"
195 "\\* Head1[ \t]+:archive:"
196 (org-export-as 'test nil nil nil
197 '(:with-archived-trees headline
)))))))
198 (org-test-with-temp-text "* Head1 :archive:"
199 (let ((org-archive-tag "archive"))
200 (org-test-with-backend "test"
203 "\\`\\* Head1[ \t]+:archive:\n\\'"
204 (org-export-as 'test nil nil nil
'(:with-archived-trees t
)))))))
206 (let ((org-drawers '("TEST")))
207 (org-test-with-temp-text ":TEST:\ncontents\n:END:"
208 (org-test-with-backend "test"
209 (should (equal (org-export-as 'test nil nil nil
'(:with-drawers nil
))
211 (let ((org-drawers '("TEST")))
212 (org-test-with-temp-text ":TEST:\ncontents\n:END:"
213 (org-test-with-backend "test"
214 (should (equal (org-export-as 'test nil nil nil
'(:with-drawers t
))
215 ":TEST:\ncontents\n:END:\n"))))))
217 (ert-deftest test-org-export
/comment-tree
()
218 "Test if export process ignores commented trees."
219 (let ((org-comment-string "COMMENT"))
220 (org-test-with-temp-text "* COMMENT Head1"
221 (org-test-with-backend "test"
222 (should (equal (org-export-as 'test
) ""))))))
224 (ert-deftest test-org-export
/export-scope
()
225 "Test all export scopes."
226 (org-test-with-temp-text "
231 (org-test-with-backend "test"
234 (should (equal (org-export-as 'test
'subtree
) "text\n*** Head3\n"))
236 (goto-char (point-min))
239 (should (equal (org-export-as 'test nil
'visible
) "* Head1\n"))
241 (flet ((org-test-template (body info
) (format "BEGIN\n%sEND" body
)))
242 (should (equal (org-export-as 'test nil nil
'body-only
)
243 "* Head1\n** Head2\ntext\n*** Head3\n"))
244 (should (equal (org-export-as 'test
)
245 "BEGIN\n* Head1\n** Head2\ntext\n*** Head3\nEND")))
247 (goto-char (point-min))
249 (transient-mark-mode 1)
250 (push-mark (point) t t
)
251 (goto-char (point-at-eol))
252 (should (equal (org-export-as 'test
) "text\n"))))
253 ;; Subtree with a code block calling another block outside.
254 (org-test-with-temp-text "
256 #+BEGIN_SRC emacs-lisp :noweb yes :exports results
261 #+BEGIN_SRC emacs-lisp
264 (org-test-with-backend "test"
266 (should (equal (org-export-as 'test
'subtree
) ": 3\n")))))
268 (ert-deftest test-org-export
/export-snippet
()
269 "Test export snippets transcoding."
270 (org-test-with-temp-text "@test{A}@t{B}"
271 (org-test-with-backend "test"
272 (flet ((org-test-export-snippet
273 (snippet contents info
)
274 (when (eq (org-export-snippet-backend snippet
) 'test
)
275 (org-element-property :value snippet
))))
276 (let ((org-export-snippet-translation-alist nil
))
277 (should (equal (org-export-as 'test
) "A\n")))
278 (let ((org-export-snippet-translation-alist '(("t" .
"test"))))
279 (should (equal (org-export-as 'test
) "AB\n")))))))
281 (ert-deftest test-org-export
/expand-include
()
282 "Test file inclusion in an Org buffer."
283 ;; Full insertion with recursive inclusion.
284 (org-test-with-temp-text
285 (format "#+INCLUDE: \"%s/examples/include.org\"" org-test-dir
)
286 (org-export-expand-include-keyword)
287 (should (equal (buffer-string)
288 "Small Org file with an include keyword.
290 #+BEGIN_SRC emacs-lisp :exports results\n(+ 2 1)\n#+END_SRC
296 ;; Localized insertion.
297 (org-test-with-temp-text
298 (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\""
300 (org-export-expand-include-keyword)
301 (should (equal (buffer-string)
302 "Small Org file with an include keyword.\n")))
303 ;; Insertion with constraints on headlines level.
304 (org-test-with-temp-text
306 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-\""
308 (org-export-expand-include-keyword)
309 (should (equal (buffer-string) "* Top heading\n** Heading\nbody\n")))
310 ;; Inclusion within an example block.
311 (org-test-with-temp-text
312 (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\" example"
314 (org-export-expand-include-keyword)
318 "#+BEGIN_EXAMPLE\nSmall Org file with an include keyword.\n#+END_EXAMPLE\n")))
319 ;; Inclusion within a src-block.
320 (org-test-with-temp-text
322 "#+INCLUDE: \"%s/examples/include.org\" :lines \"4-5\" src emacs-lisp"
324 (org-export-expand-include-keyword)
325 (should (equal (buffer-string)
326 "#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n"))))
328 (ert-deftest test-org-export
/user-ignore-list
()
329 "Test if `:ignore-list' accepts user input."
330 (org-test-with-backend "test"
331 (flet ((skip-note-head
333 ;; Ignore headlines with the word "note" in their title.
337 (when (string-match "\\<note\\>"
338 (org-element-property :raw-value headline
))
339 (org-export-ignore-element headline info
)))
342 ;; Install function in parse tree filters.
343 (let ((org-export-filter-parse-tree-functions '(skip-note-head)))
344 (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
345 (should (equal (org-export-as 'test
) "* Head1\n")))))))
347 (ert-deftest test-org-export
/before-parsing-hook
()
348 "Test `org-export-before-parsing-hook'."
349 (org-test-with-backend "test"
350 (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 2"
351 (let ((org-export-before-parsing-hook
355 (delete-region (point) (progn (forward-line) (point)))))))))
356 (should (equal (org-export-as 'test
) "Body 1\nBody 2\n"))))))
362 (ert-deftest test-org-export
/footnotes
()
363 "Test footnotes specifications."
364 (let ((org-footnote-section nil
))
365 ;; 1. Read every type of footnote.
366 (org-test-with-temp-text
367 "Text[fn:1] [1] [fn:label:C] [fn::D]\n\n[fn:1] A\n\n[1] B"
368 (let* ((tree (org-element-parse-buffer))
369 (info (org-export-store-footnote-definitions
370 `(:parse-tree
,tree
:with-footnotes t
))))
373 '((1 .
"A") (2 .
"B") (3 .
"C") (4 .
"D"))
375 tree
'footnote-reference
377 (let ((def (org-export-get-footnote-definition ref info
)))
378 (cons (org-export-get-footnote-number ref info
)
379 (if (eq (org-element-property :type ref
) 'inline
) (car def
)
380 (car (org-element-contents
381 (car (org-element-contents def
))))))))
383 ;; 2. Test nested footnotes order.
384 (org-test-with-temp-text
385 "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
386 (let* ((tree (org-element-parse-buffer))
387 (info (org-export-store-footnote-definitions
388 `(:parse-tree
,tree
:with-footnotes t
))))
391 '((1 .
"fn:1") (2 .
"fn:2") (3 .
"fn:3") (4))
393 tree
'footnote-reference
395 (when (org-export-footnote-first-reference-p ref info
)
396 (cons (org-export-get-footnote-number ref info
)
397 (org-element-property :label ref
))))
399 ;; 3. Test nested footnote in invisible definitions.
400 (org-test-with-temp-text "Text[1]\n\n[1] B [2]\n\n[2] C."
402 (narrow-to-region (point) (point-at-eol))
403 (let* ((tree (org-element-parse-buffer))
404 (info (org-export-store-footnote-definitions
405 `(:parse-tree
,tree
:with-footnotes t
))))
406 ;; Both footnotes should be seen.
408 (= (length (org-export-collect-footnote-definitions tree info
)) 2))))
409 ;; 4. Test footnotes definitions collection.
410 (org-test-with-temp-text "Text[fn:1:A[fn:2]] [fn:3].
412 \[fn:2] B [fn:3] [fn::D].
415 (let* ((tree (org-element-parse-buffer))
416 (info (org-export-store-footnote-definitions
417 `(:parse-tree
,tree
:with-footnotes t
))))
418 (should (= (length (org-export-collect-footnote-definitions tree info
))
420 ;; 5. Test export of footnotes defined outside parsing scope.
421 (org-test-with-temp-text "[fn:1] Out of scope
424 (org-test-with-backend "test"
425 (flet ((org-test-footnote-reference
426 (fn-ref contents info
)
427 (org-element-interpret-data
428 (org-export-get-footnote-definition fn-ref info
))))
430 (should (equal "ParagraphOut of scope\n"
431 (org-export-as 'test
'subtree
))))))))
437 (ert-deftest test-org-export
/fuzzy-links
()
438 "Test fuzzy link export specifications."
439 ;; 1. Links to invisible (keyword) targets should be ignored.
440 (org-test-with-temp-text
441 "Paragraph.\n#+TARGET: Test\n[[Test]]"
442 (let* ((tree (org-element-parse-buffer))
443 (info (org-export-collect-tree-properties tree nil
'test
)))
448 (org-export-get-ordinal
449 (org-export-resolve-fuzzy-link link info
) info
)) info
))))
450 ;; 2. Link to an headline should return headline's number.
451 (org-test-with-temp-text
452 "Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
453 (let* ((tree (org-element-parse-buffer))
454 (info (org-export-collect-tree-properties tree nil
'test
)))
456 ;; Note: Headline's number is in fact a list of numbers.
461 (org-export-get-ordinal
462 (org-export-resolve-fuzzy-link link info
) info
)) info t
)))))
463 ;; 3. Link to a target in an item should return item's number.
464 (org-test-with-temp-text
465 "- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
466 (let* ((tree (org-element-parse-buffer))
467 (info (org-export-collect-tree-properties tree nil
'test
)))
469 ;; Note: Item's number is in fact a list of numbers.
474 (org-export-get-ordinal
475 (org-export-resolve-fuzzy-link link info
) info
)) info t
)))))
476 ;; 4. Link to a target in a footnote should return footnote's
478 (org-test-with-temp-text
479 "Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
480 (let* ((tree (org-element-parse-buffer))
481 (info (org-export-collect-tree-properties tree nil
'test
)))
487 (org-export-get-ordinal
488 (org-export-resolve-fuzzy-link link info
) info
)) info
)))))
489 ;; 5. Link to a named element should return sequence number of that
491 (org-test-with-temp-text
492 "#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
493 (let* ((tree (org-element-parse-buffer))
494 (info (org-export-collect-tree-properties tree nil
'test
)))
500 (org-export-get-ordinal
501 (org-export-resolve-fuzzy-link link info
) info
)) info t
)))))
502 ;; 6. Link to a target not within an item, a table, a footnote
503 ;; reference or definition should return section number.
504 (org-test-with-temp-text
505 "* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
506 (let* ((tree (org-element-parse-buffer))
507 (info (org-export-collect-tree-properties tree nil
'test
)))
513 (org-export-get-ordinal
514 (org-export-resolve-fuzzy-link link info
) info
)) info t
))))))
516 (defun test-org-export/resolve-coderef
()
517 "Test `org-export-resolve-coderef' specifications."
518 (let ((org-coderef-label-format "(ref:%s)"))
519 ;; 1. A link to a "-n -k -r" block returns line number.
520 (org-test-with-temp-text
521 "#+BEGIN_EXAMPLE -n -k -r\nText (ref:coderef)\n#+END_EXAMPLE"
522 (let ((tree (org-element-parse-buffer)))
524 (= (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
)) 1))))
525 (org-test-with-temp-text
526 "#+BEGIN_SRC emacs-lisp -n -k -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
527 (let ((tree (org-element-parse-buffer)))
529 (= (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
)) 1))))
530 ;; 2. A link to a "-n -r" block returns line number.
531 (org-test-with-temp-text
532 "#+BEGIN_EXAMPLE -n -r\nText (ref:coderef)\n#+END_EXAMPLE"
533 (let ((tree (org-element-parse-buffer)))
535 (= (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
)) 1))))
536 (org-test-with-temp-text
537 "#+BEGIN_SRC emacs-lisp -n -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
538 (let ((tree (org-element-parse-buffer)))
540 (= (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
)) 1))))
541 ;; 3. A link to a "-n" block returns coderef.
542 (org-test-with-temp-text
543 "#+BEGIN_SRC emacs-lisp -n\n(+ 1 1) (ref:coderef)\n#+END_SRC"
544 (let ((tree (org-element-parse-buffer)))
546 (equal (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
))
548 (org-test-with-temp-text
549 "#+BEGIN_EXAMPLE -n\nText (ref:coderef)\n#+END_EXAMPLE"
550 (let ((tree (org-element-parse-buffer)))
552 (equal (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
))
554 ;; 4. A link to a "-r" block returns line number.
555 (org-test-with-temp-text
556 "#+BEGIN_SRC emacs-lisp -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
557 (let ((tree (org-element-parse-buffer)))
559 (= (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
)) 1))))
560 (org-test-with-temp-text
561 "#+BEGIN_EXAMPLE -r\nText (ref:coderef)\n#+END_EXAMPLE"
562 (let ((tree (org-element-parse-buffer)))
564 (= (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
)) 1))))
565 ;; 5. A link to a block without a switch returns coderef.
566 (org-test-with-temp-text
567 "#+BEGIN_SRC emacs-lisp\n(+ 1 1) (ref:coderef)\n#+END_SRC"
568 (let ((tree (org-element-parse-buffer)))
570 (equal (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
))
572 (org-test-with-temp-text
573 "#+BEGIN_EXAMPLE\nText (ref:coderef)\n#+END_EXAMPLE"
574 (let ((tree (org-element-parse-buffer)))
576 (equal (org-export-resolve-coderef "coderef" `(:parse-tree
,tree
))
578 ;; 6. Correctly handle continued line numbers. A "+n" switch
579 ;; should resume numbering from previous block with numbered
580 ;; lines, ignoring blocks not numbering lines in the process.
581 ;; A "-n" switch resets count.
582 (org-test-with-temp-text "
587 #+BEGIN_SRC emacs-lisp
591 #+BEGIN_SRC emacs-lisp +n -r
592 \(+ 1 1) (ref:addition)
595 #+BEGIN_EXAMPLE -n -r
596 Another text. (ref:text)
598 (let* ((tree (org-element-parse-buffer))
599 (info `(:parse-tree
,tree
)))
600 (should (= (org-export-resolve-coderef "addition" info
) 2))
601 (should (= (org-export-resolve-coderef "text" info
) 1))))
602 ;; 7. Recognize coderef with user-specified syntax.
603 (org-test-with-temp-text
604 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText. [ref:text]\n#+END_EXAMPLE"
605 (let ((tree (org-element-parse-buffer)))
606 (should (equal (org-export-resolve-coderef "text" `(:parse-tree
,tree
))
611 ;;; Src-block and example-block
613 (ert-deftest test-org-export
/unravel-code
()
614 "Test `org-export-unravel-code' function."
615 (let ((org-coderef-label-format "(ref:%s)"))
616 ;; 1. Code without reference.
617 (org-test-with-temp-text "#+BEGIN_EXAMPLE\n(+ 1 1)\n#+END_EXAMPLE"
618 (should (equal (org-export-unravel-code (org-element-current-element))
620 ;; 2. Code with reference.
621 (org-test-with-temp-text
622 "#+BEGIN_EXAMPLE\n(+ 1 1) (ref:test)\n#+END_EXAMPLE"
623 (should (equal (org-export-unravel-code (org-element-current-element))
624 '("(+ 1 1)\n" (1 .
"test")))))
625 ;; 3. Code with user-defined reference.
626 (org-test-with-temp-text
627 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\n(+ 1 1) [ref:test]\n#+END_EXAMPLE"
628 (should (equal (org-export-unravel-code (org-element-current-element))
629 '("(+ 1 1)\n" (1 .
"test")))))
630 ;; 4. Code references keys are relative to the current block.
631 (org-test-with-temp-text "
640 (should (equal (org-export-unravel-code (org-element-current-element))
641 '("(+ 2 2)\n(+ 3 3)\n" (2 .
"one")))))
642 ;; 5. Free up comma-protected lines.
644 ;; 5.1. In an Org source block, every line is protected.
645 (org-test-with-temp-text
646 "#+BEGIN_SRC org\n,* Test\n,# comment\n,Text\n#+END_SRC"
647 (should (equal (org-export-unravel-code (org-element-current-element))
648 '("* Test\n# comment\nText\n"))))
649 ;; 5.2. In other blocks, only headlines, comments and keywords are
651 (org-test-with-temp-text
652 "#+BEGIN_EXAMPLE\n,* Headline\n, * Not headline\n,Keep\n#+END_EXAMPLE"
653 (should (equal (org-export-unravel-code (org-element-current-element))
654 '("* Headline\n, * Not headline\n,Keep\n"))))))
660 (ert-deftest test-org-export
/special-column
()
661 "Test if the table's special column is properly recognized."
662 ;; 1. First column is special if it contains only a special marking
663 ;; characters or empty cells.
664 (org-test-with-temp-text "
668 (org-export-table-has-special-column-p
670 (org-element-parse-buffer) 'table
'identity nil
'first-match
))))
671 ;; 2. If the column contains anything else, it isn't special.
672 (org-test-with-temp-text "
676 (org-export-table-has-special-column-p
678 (org-element-parse-buffer) 'table
'identity nil
'first-match
))))
679 ;; 3. Special marking characters are "#", "^", "*", "_", "/", "$"
681 (org-test-with-temp-text "
690 (org-export-table-has-special-column-p
692 (org-element-parse-buffer) 'table
'identity nil
'first-match
))))
693 ;; 4. A first column with only empty cells isn't considered as
695 (org-test-with-temp-text "
699 (org-export-table-has-special-column-p
701 (org-element-parse-buffer) 'table
'identity nil
'first-match
)))))
703 (ert-deftest test-org-export
/special-row
()
704 "Test if special rows in a table are properly recognized."
705 ;; 1. A row is special if it has a special marking character in the
707 (org-test-with-parsed-data "| ! | 1 |"
709 (org-export-table-row-is-special-p
710 (org-element-map tree
'table-row
'identity nil
'first-match
) info
)))
711 ;; 2. A row is special when its first field is "/"
712 (org-test-with-parsed-data "
716 (org-export-table-row-is-special-p
717 (org-element-map tree
'table-row
'identity nil
'first-match
) info
)))
718 ;; 3. A row only containing alignment cookies is also considered as
720 (org-test-with-parsed-data "| <5> | | <l> | <l22> |"
722 (org-export-table-row-is-special-p
723 (org-element-map tree
'table-row
'identity nil
'first-match
) info
)))
724 ;; 4. Everything else isn't considered as special.
725 (org-test-with-parsed-data "| a | | c |"
727 (org-export-table-row-is-special-p
728 (org-element-map tree
'table-row
'identity nil
'first-match
) info
)))
729 ;; 5. Table's rules are never considered as special rows.
730 (org-test-with-parsed-data "|---+---|"
732 (org-export-table-row-is-special-p
733 (org-element-map tree
'table-row
'identity nil
'first-match
) info
))))
735 (ert-deftest test-org-export
/has-header-p
()
736 "Test `org-export-table-has-header-p' specifications."
737 ;; 1. With an header.
738 (org-test-with-parsed-data "
743 (org-export-table-has-header-p
744 (org-element-map tree
'table
'identity info
'first-match
)
746 ;; 2. Without an header.
747 (org-test-with-parsed-data "
751 (org-export-table-has-header-p
752 (org-element-map tree
'table
'identity info
'first-match
)
754 ;; 3. Don't get fooled with starting and ending rules.
755 (org-test-with-parsed-data "
761 (org-export-table-has-header-p
762 (org-element-map tree
'table
'identity info
'first-match
)
765 (ert-deftest test-org-export
/table-row-group
()
766 "Test `org-export-table-row-group' specifications."
767 ;; 1. A rule creates a new group.
768 (org-test-with-parsed-data "
775 (mapcar (lambda (row) (org-export-table-row-group row info
))
776 (org-element-map tree
'table-row
'identity
)))))
777 ;; 2. Special rows are ignored in count.
778 (org-test-with-parsed-data "
785 (mapcar (lambda (row) (org-export-table-row-group row info
))
786 (org-element-map tree
'table-row
'identity
)))))
787 ;; 3. Double rules also are ignored in count.
788 (org-test-with-parsed-data "
796 (mapcar (lambda (row) (org-export-table-row-group row info
))
797 (org-element-map tree
'table-row
'identity
))))))
799 (ert-deftest test-org-export
/table-cell-width
()
800 "Test `org-export-table-cell-width' specifications."
801 ;; 1. Width is primarily determined by width cookies. If no cookie
802 ;; is found, cell's width is nil.
803 (org-test-with-parsed-data "
804 | / | <l> | <6> | <l7> |
809 (mapcar (lambda (cell) (org-export-table-cell-width cell info
))
810 (org-element-map tree
'table-cell
'identity info
)))))
811 ;; 2. The last width cookie has precedence.
812 (org-test-with-parsed-data "
819 (mapcar (lambda (cell) (org-export-table-cell-width cell info
))
820 (org-element-map tree
'table-cell
'identity info
)))))
821 ;; 3. Valid width cookies must have a specific row.
822 (org-test-with-parsed-data "| <6> | cell |"
826 (mapcar (lambda (cell) (org-export-table-cell-width cell info
))
827 (org-element-map tree
'table-cell
'identity
))))))
829 (ert-deftest test-org-export
/table-cell-alignment
()
830 "Test `org-export-table-cell-alignment' specifications."
831 (let ((org-table-number-fraction 0.5)
832 (org-table-number-regexp "^[0-9]+$"))
833 ;; 1. Alignment is primarily determined by alignment cookies.
834 (org-test-with-temp-text "| <l> | <c> | <r> |"
835 (let* ((tree (org-element-parse-buffer))
836 (info `(:parse-tree
,tree
)))
840 (mapcar (lambda (cell) (org-export-table-cell-alignment cell info
))
841 (org-element-map tree
'table-cell
'identity
))))))
842 ;; 2. The last alignment cookie has precedence.
843 (org-test-with-temp-text "
847 (let* ((tree (org-element-parse-buffer))
848 (info `(:parse-tree
,tree
)))
852 (mapcar (lambda (cell) (org-export-table-cell-alignment cell info
))
853 (org-element-map tree
'table-cell
'identity
))))))
854 ;; 3. If there's no cookie, cell's contents determine alignment.
855 ;; A column mostly made of cells containing numbers will align
856 ;; its cells to the right.
857 (org-test-with-temp-text "
861 (let* ((tree (org-element-parse-buffer))
862 (info `(:parse-tree
,tree
)))
866 (mapcar (lambda (cell)
867 (org-export-table-cell-alignment cell info
))
868 (org-element-map tree
'table-cell
'identity
))))))
869 ;; 5. Otherwise, they will be aligned to the left.
870 (org-test-with-temp-text "
874 (let* ((tree (org-element-parse-buffer))
875 (info `(:parse-tree
,tree
)))
879 (mapcar (lambda (cell)
880 (org-export-table-cell-alignment cell info
))
881 (org-element-map tree
'table-cell
'identity
))))))))
883 (ert-deftest test-org-export
/table-cell-borders
()
884 "Test `org-export-table-cell-borders' specifications."
885 ;; 1. Recognize various column groups indicators.
886 (org-test-with-parsed-data "| / | < | > | <> |"
889 '((right bottom top
) (left bottom top
) (right bottom top
)
890 (right left bottom top
))
891 (mapcar (lambda (cell)
892 (org-export-table-cell-borders cell info
))
893 (org-element-map tree
'table-cell
'identity
)))))
894 ;; 2. Accept shortcuts to define column groups.
895 (org-test-with-parsed-data "| / | < | < |"
898 '((right bottom top
) (right left bottom top
) (left bottom top
))
899 (mapcar (lambda (cell)
900 (org-export-table-cell-borders cell info
))
901 (org-element-map tree
'table-cell
'identity
)))))
902 ;; 3. A valid column groups row must start with a "/".
903 (org-test-with-parsed-data "
907 (equal '((top) (top) (bottom) (bottom))
908 (mapcar (lambda (cell)
909 (org-export-table-cell-borders cell info
))
910 (org-element-map tree
'table-cell
'identity
)))))
911 ;; 4. Take table rules into consideration.
912 (org-test-with-parsed-data "
917 (equal '((below top
) (bottom above
))
918 (mapcar (lambda (cell)
919 (org-export-table-cell-borders cell info
))
920 (org-element-map tree
'table-cell
'identity
)))))
921 ;; 5. Top and (resp. bottom) rules induce both `top' and `above'
922 ;; (resp. `bottom' and `below') borders. Any special row is
924 (org-test-with-parsed-data "
930 (equal '((bottom below top above
))
932 (mapcar (lambda (cell)
933 (org-export-table-cell-borders cell info
))
934 (org-element-map tree
'table-cell
'identity
)))))))
936 (ert-deftest test-org-export
/table-dimensions
()
937 "Test `org-export-table-dimensions' specifications."
939 (org-test-with-parsed-data "
944 (org-export-table-dimensions
945 (org-element-map tree
'table
'identity info
'first-match
) info
))))
946 ;; 2. Ignore horizontal rules and special columns.
947 (org-test-with-parsed-data "
954 (org-export-table-dimensions
955 (org-element-map tree
'table
'identity info
'first-match
) info
)))))
957 (ert-deftest test-org-export
/table-cell-address
()
958 "Test `org-export-table-cell-address' specifications."
959 ;; 1. Standard test: index is 0-based.
960 (org-test-with-parsed-data "| a | b |"
962 (equal '((0 .
0) (0 .
1))
965 (lambda (cell) (org-export-table-cell-address cell info
))
967 ;; 2. Special column isn't counted, nor are special rows.
968 (org-test-with-parsed-data "
973 (org-export-table-cell-address
974 (car (last (org-element-map tree
'table-cell
'identity info
)))
976 ;; 3. Tables rules do not count either.
977 (org-test-with-parsed-data "
985 (org-export-table-cell-address
986 (car (last (org-element-map tree
'table-cell
'identity info
)))
988 ;; 4. Return nil for special cells.
989 (org-test-with-parsed-data "| / | a |"
991 (org-export-table-cell-address
992 (org-element-map tree
'table-cell
'identity nil
'first-match
)
995 (ert-deftest test-org-export
/get-table-cell-at
()
996 "Test `org-export-get-table-cell-at' specifications."
997 ;; 1. Address ignores special columns, special rows and rules.
998 (org-test-with-parsed-data "
1005 (org-element-contents
1006 (org-export-get-table-cell-at
1008 (org-element-map tree
'table
'identity info
'first-match
)
1010 ;; 2. Return value for a non-existent address is nil.
1011 (org-test-with-parsed-data "| a |"
1013 (org-export-get-table-cell-at
1015 (org-element-map tree
'table
'identity info
'first-match
)
1017 (org-test-with-parsed-data "| / |"
1019 (org-export-get-table-cell-at
1021 (org-element-map tree
'table
'identity info
'first-match
)
1024 (ert-deftest test-org-export
/table-cell-starts-colgroup-p
()
1025 "Test `org-export-table-cell-starts-colgroup-p' specifications."
1026 ;; 1. A cell at a beginning of a row always starts a column group.
1027 (org-test-with-parsed-data "| a |"
1029 (org-export-table-cell-starts-colgroup-p
1030 (org-element-map tree
'table-cell
'identity info
'first-match
)
1032 ;; 2. Special column should be ignored when determining the
1033 ;; beginning of the row.
1034 (org-test-with-parsed-data "
1038 (org-export-table-cell-starts-colgroup-p
1039 (org-element-map tree
'table-cell
'identity info
'first-match
)
1041 ;; 2. Explicit column groups.
1042 (org-test-with-parsed-data "
1051 (if (org-export-table-cell-starts-colgroup-p cell info
) 'yes
'no
))
1054 (ert-deftest test-org-export
/table-cell-ends-colgroup-p
()
1055 "Test `org-export-table-cell-ends-colgroup-p' specifications."
1056 ;; 1. A cell at the end of a row always ends a column group.
1057 (org-test-with-parsed-data "| a |"
1059 (org-export-table-cell-ends-colgroup-p
1060 (org-element-map tree
'table-cell
'identity info
'first-match
)
1062 ;; 2. Special column should be ignored when determining the
1063 ;; beginning of the row.
1064 (org-test-with-parsed-data "
1068 (org-export-table-cell-ends-colgroup-p
1069 (org-element-map tree
'table-cell
'identity info
'first-match
)
1071 ;; 3. Explicit column groups.
1072 (org-test-with-parsed-data "
1081 (if (org-export-table-cell-ends-colgroup-p cell info
) 'yes
'no
))
1084 (ert-deftest test-org-export
/table-row-starts-rowgroup-p
()
1085 "Test `org-export-table-row-starts-rowgroup-p' specifications."
1086 ;; 1. A row at the beginning of a table always starts a row group.
1087 ;; So does a row following a table rule.
1088 (org-test-with-parsed-data "
1098 (if (org-export-table-row-starts-rowgroup-p row info
) 'yes
'no
))
1100 ;; 2. Special rows should be ignored when determining the beginning
1102 (org-test-with-parsed-data "
1114 (if (org-export-table-row-starts-rowgroup-p row info
) 'yes
'no
))
1117 (ert-deftest test-org-export
/table-row-ends-rowgroup-p
()
1118 "Test `org-export-table-row-ends-rowgroup-p' specifications."
1119 ;; 1. A row at the end of a table always ends a row group. So does
1120 ;; a row preceding a table rule.
1121 (org-test-with-parsed-data "
1131 (if (org-export-table-row-ends-rowgroup-p row info
) 'yes
'no
))
1133 ;; 2. Special rows should be ignored when determining the beginning
1135 (org-test-with-parsed-data "
1147 (if (org-export-table-row-ends-rowgroup-p row info
) 'yes
'no
))
1150 (ert-deftest test-org-export
/table-row-starts-header-p
()
1151 "Test `org-export-table-row-starts-header-p' specifications."
1152 ;; 1. Only the row starting the first row group starts the table
1154 (org-test-with-parsed-data "
1165 (if (org-export-table-row-starts-header-p row info
) 'yes
'no
))
1167 ;; 2. A row cannot start an header if there's no header in the
1169 (org-test-with-parsed-data "
1173 (org-export-table-row-starts-header-p
1174 (org-element-map tree
'table-row
'identity info
'first-match
)
1177 (ert-deftest test-org-export
/table-row-ends-header-p
()
1178 "Test `org-export-table-row-ends-header-p' specifications."
1179 ;; 1. Only the row starting the first row group starts the table
1181 (org-test-with-parsed-data "
1192 (if (org-export-table-row-ends-header-p row info
) 'yes
'no
))
1194 ;; 2. A row cannot start an header if there's no header in the
1196 (org-test-with-parsed-data "
1200 (org-export-table-row-ends-header-p
1201 (org-element-map tree
'table-row
'identity info
'first-match
)
1205 (provide 'test-org-export
)
1206 ;;; test-org-export.el end here