org-export: Include title, author, date and email macros
[org-mode.git] / testing / lisp / test-org-export.el
blobb8463fb4a1fff8e788827e3320331de93ac04965
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
10 ;;;; Comments
14 ;;; Code:
16 (unless (featurep 'org-export)
17 (signal 'missing-test-dependency "org-export"))
19 (defmacro org-test-with-backend (backend &rest body)
20 "Execute body with an export back-end defined.
22 BACKEND is the name of the back-end. BODY is the body to
23 execute. The defined back-end simply returns parsed data as Org
24 syntax."
25 (declare (debug (form body)) (indent 1))
26 `(let ((,(intern (format "org-%s-translate-alist" backend))
27 ',(let (transcode-table)
28 (dolist (type (append org-element-all-elements
29 org-element-all-objects)
30 transcode-table)
31 (push
32 (cons type
33 (lambda (obj contents info)
34 (funcall
35 (intern (format "org-element-%s-interpreter" type))
36 obj contents)))
37 transcode-table)))))
38 (progn ,@body)))
40 (defmacro org-test-with-parsed-data (data &rest body)
41 "Execute body with parsed data available.
43 DATA is a string containing the data to be parsed. BODY is the
44 body to execute. Parse tree is available under the `tree'
45 variable, and communication channel under `info'.
47 This function calls `org-export-collect-tree-properties'. As
48 such, `:ignore-list' (for `org-element-map') and
49 `:parse-tree' (for `org-export-get-genealogy') properties are
50 already filled in `info'."
51 (declare (debug (form body)) (indent 1))
52 `(org-test-with-temp-text ,data
53 (let* ((tree (org-element-parse-buffer))
54 (info (org-export-collect-tree-properties
55 tree (org-export-get-environment))))
56 ,@body)))
60 ;;; Internal Tests
62 (ert-deftest test-org-export/bind-keyword ()
63 "Test reading #+BIND: keywords."
64 ;; Test with `org-export-all-BIND' set to t.
65 (should
66 (org-test-with-temp-text "#+BIND: variable value"
67 (let ((org-export-allow-BIND t))
68 (org-export--install-letbind-maybe)
69 (eq variable 'value))))
70 ;; Test with `org-export-all-BIND' set to nil.
71 (should-not
72 (org-test-with-temp-text "#+BIND: variable value"
73 (let ((org-export-allow-BIND nil))
74 (org-export--install-letbind-maybe)
75 (boundp 'variable))))
76 ;; Test with `org-export-all-BIND' set to 'confirm and
77 ;; `org-export--allow-BIND-local' to t .
78 (should
79 (org-test-with-temp-text "#+BIND: variable value"
80 (let ((org-export-allow-BIND 'confirm))
81 (org-set-local 'org-export--allow-BIND-local t)
82 (org-export--install-letbind-maybe)
83 (eq variable 'value))))
84 ;; Test with `org-export-all-BIND' set to 'confirm and
85 ;; `org-export--allow-BIND-local' to nil.
86 (should-not
87 (org-test-with-temp-text "#+BIND: variable value"
88 (let ((org-export-allow-BIND 'confirm))
89 (org-set-local 'org-export--allow-BIND-local nil)
90 (org-export--install-letbind-maybe)
91 (boundp 'variable))))
92 ;; BIND keywords are case-insensitive.
93 (should
94 (org-test-with-temp-text "#+bind: variable value"
95 (let ((org-export-allow-BIND t))
96 (org-export--install-letbind-maybe)
97 (eq variable 'value)))))
99 (ert-deftest test-org-export/parse-option-keyword ()
100 "Test reading all standard #+OPTIONS: items."
101 (should
102 (equal
103 (org-export--parse-option-keyword
104 "H:1 num:t \\n:t timestamp:t arch:t author:t creator:t d:t email:t
105 *:t e:t ::t f:t pri:t -:t ^:t toc:t |:t tags:t tasks:t <:t todo:t inline:nil
106 stat:t")
107 '(:headline-levels
108 1 :preserve-breaks t :section-numbers t :time-stamp-file t
109 :with-archived-trees t :with-author t :with-creator t :with-drawers t
110 :with-email t :with-emphasize t :with-entities t :with-fixed-width t
111 :with-footnotes t :with-inlinetasks nil :with-priority t
112 :with-special-strings t :with-statistics-cookies t :with-sub-superscript t
113 :with-toc t :with-tables t :with-tags t :with-tasks t :with-timestamps t
114 :with-todo-keywords t)))
115 ;; Test some special values.
116 (should
117 (equal
118 (org-export--parse-option-keyword
119 "arch:headline creator:comment d:(\"TEST\")
120 ^:{} toc:1 tags:not-in-toc tasks:todo num:2 <:active")
121 '( :section-numbers
123 :with-archived-trees headline :with-creator comment
124 :with-drawers ("TEST") :with-sub-superscript {} :with-toc 1
125 :with-tags not-in-toc :with-tasks todo :with-timestamps active))))
127 (ert-deftest test-org-export/get-inbuffer-options ()
128 "Test reading all standard export keywords."
129 (should
130 (equal
131 (org-test-with-temp-text "#+AUTHOR: Me, Myself and I
132 #+CREATOR: Idem
133 #+DATE: Today
134 #+DESCRIPTION: Testing
135 #+DESCRIPTION: with two lines
136 #+EMAIL: some@email.org
137 #+EXCLUDE_TAGS: noexport invisible
138 #+KEYWORDS: test
139 #+LANGUAGE: en
140 #+SELECT_TAGS: export
141 #+TITLE: Some title
142 #+TITLE: with spaces"
143 (org-export--get-inbuffer-options))
144 '(:author
145 ("Me, Myself and I") :creator "Idem" :date ("Today")
146 :description "Testing\nwith two lines" :email "some@email.org"
147 :exclude-tags ("noexport" "invisible") :keywords "test" :language "en"
148 :select-tags ("export") :title ("Some title with spaces")))))
150 (ert-deftest test-org-export/get-subtree-options ()
151 "Test setting options from headline's properties."
152 ;; EXPORT_TITLE.
153 (org-test-with-temp-text "#+TITLE: Title
154 * Headline
155 :PROPERTIES:
156 :EXPORT_TITLE: Subtree Title
157 :END:
158 Paragraph"
159 (forward-line)
160 (should (equal (plist-get (org-export-get-environment nil t) :title)
161 '("Subtree Title"))))
162 :title
163 '("subtree-title")
164 ;; EXPORT_OPTIONS.
165 (org-test-with-temp-text "#+OPTIONS: H:1
166 * Headline
167 :PROPERTIES:
168 :EXPORT_OPTIONS: H:2
169 :END:
170 Paragraph"
171 (forward-line)
172 (should
173 (= 2 (plist-get (org-export-get-environment nil t) :headline-levels))))
174 ;; EXPORT_DATE.
175 (org-test-with-temp-text "#+DATE: today
176 * Headline
177 :PROPERTIES:
178 :EXPORT_DATE: 29-03-2012
179 :END:
180 Paragraph"
181 (forward-line)
182 (should (equal (plist-get (org-export-get-environment nil t) :date)
183 '("29-03-2012"))))
184 ;; Export properties are case-insensitive.
185 (org-test-with-temp-text "* Headline
186 :PROPERTIES:
187 :EXPORT_Date: 29-03-2012
188 :END:
189 Paragraph"
190 (should (equal (plist-get (org-export-get-environment nil t) :date)
191 '("29-03-2012")))))
193 (ert-deftest test-org-export/handle-options ()
194 "Test if export options have an impact on output."
195 ;; Test exclude tags.
196 (org-test-with-temp-text "* Head1 :noexport:"
197 (org-test-with-backend test
198 (should
199 (equal (org-export-as 'test nil nil nil '(:exclude-tags ("noexport")))
200 ""))))
201 ;; Test include tags.
202 (org-test-with-temp-text "
203 * Head1
204 * Head2
205 ** Sub-Head2.1 :export:
206 *** Sub-Head2.1.1
207 * Head2"
208 (org-test-with-backend test
209 (should
210 (equal
211 "* Head2\n** Sub-Head2.1 :export:\n*** Sub-Head2.1.1\n"
212 (let ((org-tags-column 0))
213 (org-export-as 'test nil nil nil '(:select-tags ("export"))))))))
214 ;; Test mixing include tags and exclude tags.
215 (org-test-with-temp-text "
216 * Head1 :export:
217 ** Sub-Head1 :noexport:
218 ** Sub-Head2
219 * Head2 :noexport:
220 ** Sub-Head1 :export:"
221 (org-test-with-backend test
222 (should
223 (string-match
224 "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
225 (org-export-as
226 'test nil nil nil
227 '(:select-tags ("export") :exclude-tags ("noexport")))))))
228 ;; Ignore tasks.
229 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
230 (org-test-with-temp-text "* TODO Head1"
231 (org-test-with-backend test
232 (should (equal (org-export-as 'test nil nil nil '(:with-tasks nil))
233 "")))))
234 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
235 (org-test-with-temp-text "* TODO Head1"
236 (org-test-with-backend test
237 (should (equal (org-export-as 'test nil nil nil '(:with-tasks t))
238 "* TODO Head1\n")))))
239 ;; Archived tree.
240 (org-test-with-temp-text "* Head1 :archive:"
241 (let ((org-archive-tag "archive"))
242 (org-test-with-backend test
243 (should
244 (equal (org-export-as 'test nil nil nil '(:with-archived-trees nil))
245 "")))))
246 (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
247 (let ((org-archive-tag "archive"))
248 (org-test-with-backend test
249 (should
250 (string-match
251 "\\* Head1[ \t]+:archive:"
252 (org-export-as 'test nil nil nil
253 '(:with-archived-trees headline)))))))
254 (org-test-with-temp-text "* Head1 :archive:"
255 (let ((org-archive-tag "archive"))
256 (org-test-with-backend test
257 (should
258 (string-match
259 "\\`\\* Head1[ \t]+:archive:\n\\'"
260 (org-export-as 'test nil nil nil '(:with-archived-trees t)))))))
261 ;; Drawers.
262 (let ((org-drawers '("TEST")))
263 (org-test-with-temp-text ":TEST:\ncontents\n:END:"
264 (org-test-with-backend test
265 (should (equal (org-export-as 'test nil nil nil '(:with-drawers nil))
266 ""))
267 (should (equal (org-export-as 'test nil nil nil '(:with-drawers t))
268 ":TEST:\ncontents\n:END:\n")))))
269 (let ((org-drawers '("FOO" "BAR")))
270 (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
271 (org-test-with-backend test
272 (should
273 (equal (org-export-as 'test nil nil nil '(:with-drawers ("FOO")))
274 ":FOO:\nkeep\n:END:\n")))))
275 ;; Timestamps.
276 (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
277 (org-test-with-backend test
278 (should
279 (equal (org-export-as 'test nil nil nil '(:with-timestamps t))
280 "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>\n"))
281 (should
282 (equal (org-export-as 'test nil nil nil '(:with-timestamps nil)) ""))
283 (should
284 (equal (org-export-as 'test nil nil nil '(:with-timestamps active))
285 "<2012-04-29 sun. 10:45>\n"))
286 (should
287 (equal (org-export-as 'test nil nil nil '(:with-timestamps inactive))
288 "[2012-04-29 sun. 10:45]\n"))))
289 ;; Clocks.
290 (let ((org-clock-string "CLOCK:"))
291 (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
292 (org-test-with-backend test
293 (should
294 (equal (org-export-as 'test nil nil nil '(:with-clocks t))
295 "CLOCK: [2012-04-29 sun. 10:45]\n"))
296 (should
297 (equal (org-export-as 'test nil nil nil '(:with-clocks nil)) "")))))
298 ;; Plannings.
299 (let ((org-closed-string "CLOSED:"))
300 (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
301 (org-test-with-backend test
302 (should
303 (equal (org-export-as 'test nil nil nil '(:with-plannings t))
304 "CLOSED: [2012-04-29 sun. 10:45]\n"))
305 (should
306 (equal (org-export-as 'test nil nil nil '(:with-plannings nil))
307 "")))))
308 ;; Inlinetasks.
309 (when (featurep 'org-inlinetask)
310 (should
311 (equal
312 (let ((org-inlinetask-min-level 15))
313 (org-test-with-temp-text "*************** Task"
314 (org-test-with-backend test
315 (org-export-as 'test nil nil nil '(:with-inlinetasks nil)))))
316 ""))
317 (should
318 (equal
319 (let ((org-inlinetask-min-level 15))
320 (org-test-with-temp-text
321 "*************** Task\nContents\n*************** END"
322 (org-test-with-backend test
323 (org-export-as 'test nil nil nil '(:with-inlinetasks nil)))))
324 "")))
325 ;; Statistics cookies.
326 (should
327 (equal ""
328 (org-test-with-temp-text "[0/0]"
329 (org-test-with-backend test
330 (org-export-as
331 'test nil nil nil '(:with-statistics-cookies nil)))))))
333 (ert-deftest test-org-export/comment-tree ()
334 "Test if export process ignores commented trees."
335 (let ((org-comment-string "COMMENT"))
336 (org-test-with-temp-text "* COMMENT Head1"
337 (org-test-with-backend test
338 (should (equal (org-export-as 'test) ""))))))
340 (ert-deftest test-org-export/export-scope ()
341 "Test all export scopes."
342 (org-test-with-temp-text "
343 * Head1
344 ** Head2
345 text
346 *** Head3"
347 (org-test-with-backend test
348 ;; Subtree.
349 (forward-line 3)
350 (should (equal (org-export-as 'test 'subtree) "text\n*** Head3\n"))
351 ;; Visible.
352 (goto-char (point-min))
353 (forward-line)
354 (org-cycle)
355 (should (equal (org-export-as 'test nil 'visible) "* Head1\n"))
356 ;; Body only.
357 (flet ((org-test-template (body info) (format "BEGIN\n%sEND" body)))
358 (push '(template . org-test-template) org-test-translate-alist)
359 (should (equal (org-export-as 'test nil nil 'body-only)
360 "* Head1\n** Head2\ntext\n*** Head3\n"))
361 (should (equal (org-export-as 'test)
362 "BEGIN\n* Head1\n** Head2\ntext\n*** Head3\nEND")))
363 ;; Region.
364 (goto-char (point-min))
365 (forward-line 3)
366 (transient-mark-mode 1)
367 (push-mark (point) t t)
368 (goto-char (point-at-eol))
369 (should (equal (org-export-as 'test) "text\n"))))
370 ;; Subtree with a code block calling another block outside.
371 (org-test-with-temp-text "
372 * Head1
373 #+BEGIN_SRC emacs-lisp :noweb yes :exports results
374 <<test>>
375 #+END_SRC
376 * Head2
377 #+NAME: test
378 #+BEGIN_SRC emacs-lisp
379 \(+ 1 2)
380 #+END_SRC"
381 (org-test-with-backend test
382 (forward-line 1)
383 (should (equal (org-export-as 'test 'subtree) ": 3\n")))))
385 (ert-deftest test-org-export/expand-include ()
386 "Test file inclusion in an Org buffer."
387 ;; Full insertion with recursive inclusion.
388 (org-test-with-temp-text
389 (format "#+INCLUDE: \"%s/examples/include.org\"" org-test-dir)
390 (org-export-expand-include-keyword)
391 (should (equal (buffer-string)
392 "Small Org file with an include keyword.
394 #+BEGIN_SRC emacs-lisp :exports results\n(+ 2 1)\n#+END_SRC
396 Success!
398 * Heading
399 body\n")))
400 ;; Localized insertion.
401 (org-test-with-temp-text
402 (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\""
403 org-test-dir)
404 (org-export-expand-include-keyword)
405 (should (equal (buffer-string)
406 "Small Org file with an include keyword.\n")))
407 ;; Insertion with constraints on headlines level.
408 (org-test-with-temp-text
409 (format
410 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-\""
411 org-test-dir)
412 (org-export-expand-include-keyword)
413 (should (equal (buffer-string) "* Top heading\n** Heading\nbody\n")))
414 ;; Inclusion within an example block.
415 (org-test-with-temp-text
416 (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\" example"
417 org-test-dir)
418 (org-export-expand-include-keyword)
419 (should
420 (equal
421 (buffer-string)
422 "#+BEGIN_EXAMPLE\nSmall Org file with an include keyword.\n#+END_EXAMPLE\n")))
423 ;; Inclusion within a src-block.
424 (org-test-with-temp-text
425 (format
426 "#+INCLUDE: \"%s/examples/include.org\" :lines \"4-5\" src emacs-lisp"
427 org-test-dir)
428 (org-export-expand-include-keyword)
429 (should (equal (buffer-string)
430 "#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n"))))
432 (ert-deftest test-org-export/expand-macro ()
433 "Test macro expansion in an Org buffer."
434 ;; Standard macro expansion.
435 (should
436 (equal "#+MACRO: macro1 value\nvalue"
437 (org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
438 (let (info)
439 (org-macro-initialize-templates)
440 (org-export-expand-macro info) (buffer-string)))))
441 ;; Export specific macros.
442 (should
443 (equal "me 2012-03-29 me@here Title"
444 (org-test-with-temp-text
446 #+TITLE: Title
447 #+DATE: 2012-03-29
448 #+AUTHOR: me
449 #+EMAIL: me@here
450 {{{author}}} {{{date}}} {{{email}}} {{{title}}}"
451 (let ((info (org-export-get-environment)))
452 (org-macro-initialize-templates)
453 (org-export-expand-macro info)
454 (goto-char (point-max))
455 (buffer-substring (line-beginning-position)
456 (line-end-position)))))))
458 (ert-deftest test-org-export/user-ignore-list ()
459 "Test if `:ignore-list' accepts user input."
460 (org-test-with-backend test
461 (flet ((skip-note-head
462 (data backend info)
463 ;; Ignore headlines with the word "note" in their title.
464 (org-element-map
465 data 'headline
466 (lambda (headline)
467 (when (string-match "\\<note\\>"
468 (org-element-property :raw-value headline))
469 (org-export-ignore-element headline info)))
470 info)
471 data))
472 ;; Install function in parse tree filters.
473 (let ((org-export-filter-parse-tree-functions '(skip-note-head)))
474 (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
475 (should (equal (org-export-as 'test) "* Head1\n")))))))
477 (ert-deftest test-org-export/before-parsing-hook ()
478 "Test `org-export-before-parsing-hook'."
479 (org-test-with-backend test
480 (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 2"
481 (let ((org-export-before-parsing-hook
482 '((lambda (backend)
483 (org-map-entries
484 (lambda ()
485 (delete-region (point) (progn (forward-line) (point)))))))))
486 (should (equal (org-export-as 'test) "Body 1\nBody 2\n"))))))
490 ;;; Affiliated Keywords
492 (ert-deftest test-org-export/read-attribute ()
493 "Test `org-export-read-attribute' specifications."
494 ;; Standard test.
495 (should
496 (equal
497 (org-export-read-attribute
498 :attr_html
499 (org-test-with-temp-text "#+ATTR_HTML: :a 1 :b 2\nParagraph"
500 (org-element-at-point)))
501 '(:a 1 :b 2)))
502 ;; Return nil on empty attribute.
503 (should-not
504 (org-export-read-attribute
505 :attr_html
506 (org-test-with-temp-text "Paragraph" (org-element-at-point)))))
508 (ert-deftest test-org-export/get-caption ()
509 "Test `org-export-get-caption' specifications."
510 ;; Without optional argument, return long caption
511 (should
512 (equal
513 '("l")
514 (org-test-with-temp-text "#+CAPTION[s]: l\nPara"
515 (org-export-get-caption (org-element-at-point)))))
516 ;; With optional argument, return short caption.
517 (should
518 (equal
519 '("s")
520 (org-test-with-temp-text "#+CAPTION[s]: l\nPara"
521 (org-export-get-caption (org-element-at-point) t))))
522 ;; Multiple lines are separated by white spaces.
523 (should
524 (equal
525 '("a" " " "b")
526 (org-test-with-temp-text "#+CAPTION: a\n#+CAPTION: b\nPara"
527 (org-export-get-caption (org-element-at-point))))))
531 ;;; Export Snippets
533 (ert-deftest test-org-export/export-snippet ()
534 "Test export snippets transcoding."
535 (org-test-with-temp-text "@@test:A@@@@t:B@@"
536 (org-test-with-backend test
537 (let ((org-test-translate-alist
538 (cons (cons 'export-snippet
539 (lambda (snippet contents info)
540 (when (eq (org-export-snippet-backend snippet) 'test)
541 (org-element-property :value snippet))))
542 org-test-translate-alist)))
543 (let ((org-export-snippet-translation-alist nil))
544 (should (equal (org-export-as 'test) "A\n")))
545 (let ((org-export-snippet-translation-alist '(("t" . "test"))))
546 (should (equal (org-export-as 'test) "AB\n")))))))
550 ;;; Footnotes
552 (ert-deftest test-org-export/footnotes ()
553 "Test footnotes specifications."
554 (let ((org-footnote-section nil)
555 (org-export-with-footnotes t))
556 ;; 1. Read every type of footnote.
557 (should
558 (equal
559 '((1 . "A\n") (2 . "B") (3 . "C") (4 . "D"))
560 (org-test-with-parsed-data
561 "Text[fn:1] [1] [fn:label:C] [fn::D]\n\n[fn:1] A\n\n[1] B"
562 (org-element-map
563 tree 'footnote-reference
564 (lambda (ref)
565 (let ((def (org-export-get-footnote-definition ref info)))
566 (cons (org-export-get-footnote-number ref info)
567 (if (eq (org-element-property :type ref) 'inline) (car def)
568 (car (org-element-contents
569 (car (org-element-contents def))))))))
570 info))))
571 ;; 2. Test nested footnotes order.
572 (org-test-with-parsed-data
573 "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
574 (should
575 (equal
576 '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
577 (org-element-map
578 tree 'footnote-reference
579 (lambda (ref)
580 (when (org-export-footnote-first-reference-p ref info)
581 (cons (org-export-get-footnote-number ref info)
582 (org-element-property :label ref))))
583 info))))
584 ;; 3. Test nested footnote in invisible definitions.
585 (org-test-with-temp-text "Text[1]\n\n[1] B [2]\n\n[2] C."
586 ;; Hide definitions.
587 (narrow-to-region (point) (point-at-eol))
588 (let* ((tree (org-element-parse-buffer))
589 (info (org-combine-plists
590 `(:parse-tree ,tree)
591 (org-export-collect-tree-properties
592 tree (org-export-get-environment)))))
593 ;; Both footnotes should be seen.
594 (should
595 (= (length (org-export-collect-footnote-definitions tree info)) 2))))
596 ;; 4. Test footnotes definitions collection.
597 (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
599 \[fn:2] B [fn:3] [fn::D].
601 \[fn:3] C."
602 (should (= (length (org-export-collect-footnote-definitions tree info))
603 4)))
604 ;; 5. Test export of footnotes defined outside parsing scope.
605 (org-test-with-temp-text "[fn:1] Out of scope
606 * Title
607 Paragraph[fn:1]"
608 (org-test-with-backend test
609 (let ((org-test-translate-alist
610 (cons (cons 'footnote-reference
611 (lambda (fn contents info)
612 (org-element-interpret-data
613 (org-export-get-footnote-definition fn info))))
614 org-test-translate-alist)))
615 (forward-line)
616 (should (equal "ParagraphOut of scope\n"
617 (org-export-as 'test 'subtree))))))))
621 ;;; Headlines and Inlinetasks
623 (ert-deftest test-org-export/get-relative-level ()
624 "Test `org-export-get-relative-level' specifications."
625 ;; Standard test.
626 (should
627 (equal '(1 2)
628 (let ((org-odd-levels-only nil))
629 (org-test-with-parsed-data "* Headline 1\n** Headline 2"
630 (org-element-map
631 tree 'headline
632 (lambda (h) (org-export-get-relative-level h info))
633 info)))))
634 ;; Missing levels
635 (should
636 (equal '(1 3)
637 (let ((org-odd-levels-only nil))
638 (org-test-with-parsed-data "** Headline 1\n**** Headline 2"
639 (org-element-map
640 tree 'headline
641 (lambda (h) (org-export-get-relative-level h info))
642 info))))))
644 (ert-deftest test-org-export/low-level-p ()
645 "Test `org-export-low-level-p' specifications."
646 (should
647 (equal
648 '(no yes)
649 (let ((org-odd-levels-only nil))
650 (org-test-with-parsed-data "* Headline 1\n** Headline 2"
651 (org-element-map
652 tree 'headline
653 (lambda (h) (if (org-export-low-level-p h info) 'yes 'no))
654 (plist-put info :headline-levels 1)))))))
656 (ert-deftest test-org-export/get-headline-number ()
657 "Test `org-export-get-headline-number' specifications."
658 ;; Standard test.
659 (should
660 (equal
661 '((1) (1 1))
662 (let ((org-odd-levels-only nil))
663 (org-test-with-parsed-data "* Headline 1\n** Headline 2"
664 (org-element-map
665 tree 'headline
666 (lambda (h) (org-export-get-headline-number h info))
667 info)))))
668 ;; Missing levels are replaced with 0.
669 (should
670 (equal
671 '((1) (1 0 1))
672 (let ((org-odd-levels-only nil))
673 (org-test-with-parsed-data "* Headline 1\n*** Headline 2"
674 (org-element-map
675 tree 'headline
676 (lambda (h) (org-export-get-headline-number h info))
677 info))))))
679 (ert-deftest test-org-export/numbered-headline-p ()
680 "Test `org-export-numbered-headline-p' specifications."
681 ;; If `:section-numbers' is nil, never number headlines.
682 (should-not
683 (org-test-with-parsed-data "* Headline"
684 (org-element-map
685 tree 'headline
686 (lambda (h) (org-export-numbered-headline-p h info))
687 (plist-put info :section-numbers nil))))
688 ;; If `:section-numbers' is a number, only number headlines with
689 ;; a level greater that it.
690 (should
691 (equal
692 '(yes no)
693 (org-test-with-parsed-data "* Headline 1\n** Headline 2"
694 (org-element-map
695 tree 'headline
696 (lambda (h) (if (org-export-numbered-headline-p h info) 'yes 'no))
697 (plist-put info :section-numbers 1)))))
698 ;; Otherwise, headlines are always numbered.
699 (should
700 (org-test-with-parsed-data "* Headline"
701 (org-element-map
702 tree 'headline
703 (lambda (h) (org-export-numbered-headline-p h info))
704 (plist-put info :section-numbers t)))))
706 (ert-deftest test-org-export/number-to-roman ()
707 "Test `org-export-number-to-roman' specifications."
708 ;; If number is negative, return it as a string.
709 (should (equal (org-export-number-to-roman -1) "-1"))
710 ;; Otherwise, return it as a roman number.
711 (should (equal (org-export-number-to-roman 1449) "MCDXLIX")))
713 (ert-deftest test-org-export/get-tags ()
714 "Test `org-export-get-tags' specifications."
715 (let ((org-export-exclude-tags '("noexport"))
716 (org-export-select-tags '("export")))
717 ;; Standard test: tags which are not a select tag, an exclude tag,
718 ;; or specified as optional argument shouldn't be ignored.
719 (should
720 (org-test-with-parsed-data "* Headline :tag:"
721 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
722 info)))
723 ;; Exclude tags are removed.
724 (should-not
725 (org-test-with-parsed-data "* Headline :noexport:"
726 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
727 info)))
728 ;; Select tags are removed.
729 (should-not
730 (org-test-with-parsed-data "* Headline :export:"
731 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
732 info)))
733 (should
734 (equal
735 '("tag")
736 (org-test-with-parsed-data "* Headline :tag:export:"
737 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
738 info))))
739 ;; Tags provided in the optional argument are also ignored.
740 (should-not
741 (org-test-with-parsed-data "* Headline :ignore:"
742 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
743 info '("ignore"))))))
745 (ert-deftest test-org-export/get-node-property ()
746 "Test`org-export-get-node-property' specifications."
747 ;; Standard test.
748 (should
749 (equal "value"
750 (org-test-with-parsed-data "* Headline
751 :PROPERTIES:
752 :prop: value
753 :END:"
754 (org-export-get-node-property
755 :prop (org-element-map tree 'headline 'identity nil t)))))
756 ;; Test inheritance.
757 (should
758 (equal "value"
759 (org-test-with-parsed-data "* Parent
760 :PROPERTIES:
761 :prop: value
762 :END:
763 ** Headline
764 Paragraph"
765 (org-export-get-node-property
766 :prop (org-element-map tree 'paragraph 'identity nil t) t))))
767 ;; Cannot return a value before the first headline.
768 (should-not
769 (org-test-with-parsed-data "Paragraph
770 * Headline
771 :PROPERTIES:
772 :prop: value
773 :END:"
774 (org-export-get-node-property
775 :prop (org-element-map tree 'paragraph 'identity nil t)))))
777 (ert-deftest test-org-export/first-sibling-p ()
778 "Test `org-export-first-sibling-p' specifications."
779 ;; Standard test.
780 (should
781 (equal
782 '(yes yes no)
783 (org-test-with-parsed-data "* Headline\n** Headline 2\n** Headline 3"
784 (org-element-map
785 tree 'headline
786 (lambda (h) (if (org-export-first-sibling-p h info) 'yes 'no))
787 info))))
788 ;; Ignore headlines not exported.
789 (should
790 (equal
791 '(yes)
792 (let ((org-export-exclude-tags '("ignore")))
793 (org-test-with-parsed-data "* Headline :ignore:\n* Headline 2"
794 (org-element-map
795 tree 'headline
796 (lambda (h) (if (org-export-first-sibling-p h info) 'yes 'no))
797 info))))))
799 (ert-deftest test-org-export/last-sibling-p ()
800 "Test `org-export-last-sibling-p' specifications."
801 ;; Standard test.
802 (should
803 (equal
804 '(yes no yes)
805 (org-test-with-parsed-data "* Headline\n** Headline 2\n** Headline 3"
806 (org-element-map
807 tree 'headline
808 (lambda (h) (if (org-export-last-sibling-p h info) 'yes 'no))
809 info))))
810 ;; Ignore headlines not exported.
811 (should
812 (equal
813 '(yes)
814 (let ((org-export-exclude-tags '("ignore")))
815 (org-test-with-parsed-data "* Headline\n* Headline 2 :ignore:"
816 (org-element-map
817 tree 'headline
818 (lambda (h) (if (org-export-last-sibling-p h info) 'yes 'no))
819 info))))))
823 ;;; Links
825 (ert-deftest test-org-export/get-coderef-format ()
826 "Test `org-export-get-coderef-format' specifications."
827 ;; A link without description returns "%s"
828 (should (equal (org-export-get-coderef-format "(ref:line)" nil)
829 "%s"))
830 ;; Return "%s" when path is matched within description.
831 (should (equal (org-export-get-coderef-format "path" "desc (path)")
832 "desc %s"))
833 ;; Otherwise return description.
834 (should (equal (org-export-get-coderef-format "path" "desc")
835 "desc")))
837 (ert-deftest test-org-export/inline-image-p ()
838 "Test `org-export-inline-image-p' specifications."
839 (should
840 (org-export-inline-image-p
841 (org-test-with-temp-text "[[#id]]"
842 (org-element-map
843 (org-element-parse-buffer) 'link 'identity nil t))
844 '(("custom-id" . "id")))))
846 (ert-deftest test-org-export/fuzzy-link ()
847 "Test fuzzy links specifications."
848 ;; 1. Links to invisible (keyword) targets should be ignored.
849 (org-test-with-parsed-data
850 "Paragraph.\n#+TARGET: Test\n[[Test]]"
851 (should-not
852 (org-element-map
853 tree 'link
854 (lambda (link)
855 (org-export-get-ordinal
856 (org-export-resolve-fuzzy-link link info) info)) info)))
857 ;; 2. Link to an headline should return headline's number.
858 (org-test-with-parsed-data
859 "Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
860 (should
861 ;; Note: Headline's number is in fact a list of numbers.
862 (equal '(2)
863 (org-element-map
864 tree 'link
865 (lambda (link)
866 (org-export-get-ordinal
867 (org-export-resolve-fuzzy-link link info) info)) info t))))
868 ;; 3. Link to a target in an item should return item's number.
869 (org-test-with-parsed-data
870 "- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
871 (should
872 ;; Note: Item's number is in fact a list of numbers.
873 (equal '(1 2)
874 (org-element-map
875 tree 'link
876 (lambda (link)
877 (org-export-get-ordinal
878 (org-export-resolve-fuzzy-link link info) info)) info t))))
879 ;; 4. Link to a target in a footnote should return footnote's
880 ;; number.
881 (org-test-with-parsed-data "
882 Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
883 (should
884 (equal '(2 3)
885 (org-element-map
886 tree 'link
887 (lambda (link)
888 (org-export-get-ordinal
889 (org-export-resolve-fuzzy-link link info) info)) info))))
890 ;; 5. Link to a named element should return sequence number of that
891 ;; element.
892 (org-test-with-parsed-data
893 "#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
894 (should
895 (= 2
896 (org-element-map
897 tree 'link
898 (lambda (link)
899 (org-export-get-ordinal
900 (org-export-resolve-fuzzy-link link info) info)) info t))))
901 ;; 6. Link to a target not within an item, a table, a footnote
902 ;; reference or definition should return section number.
903 (org-test-with-parsed-data
904 "* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
905 (should
906 (equal '(2)
907 (org-element-map
908 tree 'link
909 (lambda (link)
910 (org-export-get-ordinal
911 (org-export-resolve-fuzzy-link link info) info)) info t)))))
913 (ert-deftest test-org-export/resolve-coderef ()
914 "Test `org-export-resolve-coderef' specifications."
915 (let ((org-coderef-label-format "(ref:%s)"))
916 ;; 1. A link to a "-n -k -r" block returns line number.
917 (org-test-with-parsed-data
918 "#+BEGIN_EXAMPLE -n -k -r\nText (ref:coderef)\n#+END_EXAMPLE"
919 (should (= (org-export-resolve-coderef "coderef" info) 1)))
920 (org-test-with-parsed-data
921 "#+BEGIN_SRC emacs-lisp -n -k -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
922 (should (= (org-export-resolve-coderef "coderef" info) 1)))
923 ;; 2. A link to a "-n -r" block returns line number.
924 (org-test-with-parsed-data
925 "#+BEGIN_EXAMPLE -n -r\nText (ref:coderef)\n#+END_EXAMPLE"
926 (should (= (org-export-resolve-coderef "coderef" info) 1)))
927 (org-test-with-parsed-data
928 "#+BEGIN_SRC emacs-lisp -n -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
929 (should (= (org-export-resolve-coderef "coderef" info) 1)))
930 ;; 3. A link to a "-n" block returns coderef.
931 (org-test-with-parsed-data
932 "#+BEGIN_SRC emacs-lisp -n\n(+ 1 1) (ref:coderef)\n#+END_SRC"
933 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
934 (org-test-with-parsed-data
935 "#+BEGIN_EXAMPLE -n\nText (ref:coderef)\n#+END_EXAMPLE"
936 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
937 ;; 4. A link to a "-r" block returns line number.
938 (org-test-with-parsed-data
939 "#+BEGIN_SRC emacs-lisp -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
940 (should (= (org-export-resolve-coderef "coderef" info) 1)))
941 (org-test-with-parsed-data
942 "#+BEGIN_EXAMPLE -r\nText (ref:coderef)\n#+END_EXAMPLE"
943 (should (= (org-export-resolve-coderef "coderef" info) 1)))
944 ;; 5. A link to a block without a switch returns coderef.
945 (org-test-with-parsed-data
946 "#+BEGIN_SRC emacs-lisp\n(+ 1 1) (ref:coderef)\n#+END_SRC"
947 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
948 (org-test-with-parsed-data
949 "#+BEGIN_EXAMPLE\nText (ref:coderef)\n#+END_EXAMPLE"
950 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
951 ;; 6. Correctly handle continued line numbers. A "+n" switch
952 ;; should resume numbering from previous block with numbered
953 ;; lines, ignoring blocks not numbering lines in the process.
954 ;; A "-n" switch resets count.
955 (org-test-with-parsed-data "
956 #+BEGIN_EXAMPLE -n
957 Text.
958 #+END_EXAMPLE
960 #+BEGIN_SRC emacs-lisp
961 \(- 1 1)
962 #+END_SRC
964 #+BEGIN_SRC emacs-lisp +n -r
965 \(+ 1 1) (ref:addition)
966 #+END_SRC
968 #+BEGIN_EXAMPLE -n -r
969 Another text. (ref:text)
970 #+END_EXAMPLE"
971 (should (= (org-export-resolve-coderef "addition" info) 2))
972 (should (= (org-export-resolve-coderef "text" info) 1)))
973 ;; 7. Recognize coderef with user-specified syntax.
974 (org-test-with-parsed-data
975 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText. [ref:text]\n#+END_EXAMPLE"
976 (should (equal (org-export-resolve-coderef "text" info) "text")))))
978 (ert-deftest test-org-export/resolve-fuzzy-link ()
979 "Test `org-export-resolve-fuzzy-link' specifications."
980 ;; 1. Match target objects.
981 (org-test-with-parsed-data "<<target>> [[target]]"
982 (should
983 (org-export-resolve-fuzzy-link
984 (org-element-map tree 'link 'identity info t) info)))
985 ;; 2. Match target elements.
986 (org-test-with-parsed-data "#+TARGET: target\n[[target]]"
987 (should
988 (org-export-resolve-fuzzy-link
989 (org-element-map tree 'link 'identity info t) info)))
990 ;; 3. Match named elements.
991 (org-test-with-parsed-data "#+NAME: target\nParagraph\n\n[[target]]"
992 (should
993 (org-export-resolve-fuzzy-link
994 (org-element-map tree 'link 'identity info t) info)))
995 ;; 4. Match exact headline's name.
996 (org-test-with-parsed-data "* My headline\n[[My headline]]"
997 (should
998 (org-export-resolve-fuzzy-link
999 (org-element-map tree 'link 'identity info t) info)))
1000 ;; 5. Targets objects have priority over named elements and headline
1001 ;; titles.
1002 (org-test-with-parsed-data
1003 "* target\n#+NAME: target\n<<target>>\n\n[[target]]"
1004 (should
1005 (eq 'target
1006 (org-element-type
1007 (org-export-resolve-fuzzy-link
1008 (org-element-map tree 'link 'identity info t) info)))))
1009 ;; 6. Named elements have priority over headline titles.
1010 (org-test-with-parsed-data
1011 "* target\n#+NAME: target\nParagraph\n\n[[target]]"
1012 (should
1013 (eq 'paragraph
1014 (org-element-type
1015 (org-export-resolve-fuzzy-link
1016 (org-element-map tree 'link 'identity info t) info)))))
1017 ;; 7. If link's path starts with a "*", only match headline titles,
1018 ;; though.
1019 (org-test-with-parsed-data
1020 "* target\n#+NAME: target\n<<target>>\n\n[[*target]]"
1021 (should
1022 (eq 'headline
1023 (org-element-type
1024 (org-export-resolve-fuzzy-link
1025 (org-element-map tree 'link 'identity info t) info)))))
1026 ;; 8. Return nil if no match.
1027 (org-test-with-parsed-data "[[target]]"
1028 (should-not
1029 (org-export-resolve-fuzzy-link
1030 (org-element-map tree 'link 'identity info t) info))))
1032 (ert-deftest test-org-export/resolve-id-link ()
1033 "Test `org-export-resolve-id-link' specifications."
1034 ;; 1. Regular test for custom-id link.
1035 (org-test-with-parsed-data "* Headline1
1036 :PROPERTIES:
1037 :CUSTOM-ID: test
1038 :END:
1039 * Headline 2
1040 \[[#test]]"
1041 (should
1042 (org-export-resolve-id-link
1043 (org-element-map tree 'link 'identity info t) info)))
1044 ;; 2. Failing test for custom-id link.
1045 (org-test-with-parsed-data "* Headline1
1046 :PROPERTIES:
1047 :CUSTOM-ID: test
1048 :END:
1049 * Headline 2
1050 \[[#no-match]]"
1051 (should-not
1052 (org-export-resolve-id-link
1053 (org-element-map tree 'link 'identity info t) info)))
1054 ;; 3. Test for internal id target.
1055 (org-test-with-parsed-data "* Headline1
1056 :PROPERTIES:
1057 :ID: aaaa
1058 :END:
1059 * Headline 2
1060 \[[id:aaaa]]"
1061 (should
1062 (org-export-resolve-id-link
1063 (org-element-map tree 'link 'identity info t) info)))
1064 ;; 4. Test for external id target.
1065 (org-test-with-parsed-data "[[id:aaaa]]"
1066 (should
1067 (org-export-resolve-id-link
1068 (org-element-map tree 'link 'identity info t)
1069 (org-combine-plists info '(:id-alist (("aaaa" . "external-file"))))))))
1071 (ert-deftest test-org-export/resolve-radio-link ()
1072 "Test `org-export-resolve-radio-link' specifications."
1073 ;; Standard test.
1074 (org-test-with-temp-text "<<<radio>>> radio"
1075 (org-update-radio-target-regexp)
1076 (should
1077 (let* ((tree (org-element-parse-buffer))
1078 (info `(:parse-tree ,tree)))
1079 (org-export-resolve-radio-link
1080 (org-element-map tree 'link 'identity info t)
1081 info))))
1082 ;; Radio target with objects.
1083 (org-test-with-temp-text "<<<radio \\alpha>>> radio \\alpha"
1084 (org-update-radio-target-regexp)
1085 (should
1086 (let* ((tree (org-element-parse-buffer))
1087 (info `(:parse-tree ,tree)))
1088 (org-export-resolve-radio-link
1089 (org-element-map tree 'link 'identity info t)
1090 info)))))
1094 ;;; Src-block and example-block
1096 (ert-deftest test-org-export/unravel-code ()
1097 "Test `org-export-unravel-code' function."
1098 (let ((org-coderef-label-format "(ref:%s)"))
1099 ;; 1. Code without reference.
1100 (org-test-with-temp-text "#+BEGIN_EXAMPLE\n(+ 1 1)\n#+END_EXAMPLE"
1101 (should (equal (org-export-unravel-code (org-element-at-point))
1102 '("(+ 1 1)\n"))))
1103 ;; 2. Code with reference.
1104 (org-test-with-temp-text
1105 "#+BEGIN_EXAMPLE\n(+ 1 1) (ref:test)\n#+END_EXAMPLE"
1106 (should (equal (org-export-unravel-code (org-element-at-point))
1107 '("(+ 1 1)\n" (1 . "test")))))
1108 ;; 3. Code with user-defined reference.
1109 (org-test-with-temp-text
1110 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\n(+ 1 1) [ref:test]\n#+END_EXAMPLE"
1111 (should (equal (org-export-unravel-code (org-element-at-point))
1112 '("(+ 1 1)\n" (1 . "test")))))
1113 ;; 4. Code references keys are relative to the current block.
1114 (org-test-with-temp-text "
1115 #+BEGIN_EXAMPLE -n
1116 \(+ 1 1)
1117 #+END_EXAMPLE
1118 #+BEGIN_EXAMPLE +n
1119 \(+ 2 2)
1120 \(+ 3 3) (ref:one)
1121 #+END_EXAMPLE"
1122 (goto-line 5)
1123 (should (equal (org-export-unravel-code (org-element-at-point))
1124 '("(+ 2 2)\n(+ 3 3)\n" (2 . "one")))))))
1128 ;;; Tables
1130 (ert-deftest test-org-export/special-column ()
1131 "Test if the table's special column is properly recognized."
1132 ;; 1. First column is special if it contains only a special marking
1133 ;; characters or empty cells.
1134 (org-test-with-temp-text "
1135 | ! | 1 |
1136 | | 2 |"
1137 (should
1138 (org-export-table-has-special-column-p
1139 (org-element-map
1140 (org-element-parse-buffer) 'table 'identity nil 'first-match))))
1141 ;; 2. If the column contains anything else, it isn't special.
1142 (org-test-with-temp-text "
1143 | ! | 1 |
1144 | b | 2 |"
1145 (should-not
1146 (org-export-table-has-special-column-p
1147 (org-element-map
1148 (org-element-parse-buffer) 'table 'identity nil 'first-match))))
1149 ;; 3. Special marking characters are "#", "^", "*", "_", "/", "$"
1150 ;; and "!".
1151 (org-test-with-temp-text "
1152 | # | 1 |
1153 | ^ | 2 |
1154 | * | 3 |
1155 | _ | 4 |
1156 | / | 5 |
1157 | $ | 6 |
1158 | ! | 7 |"
1159 (should
1160 (org-export-table-has-special-column-p
1161 (org-element-map
1162 (org-element-parse-buffer) 'table 'identity nil 'first-match))))
1163 ;; 4. A first column with only empty cells isn't considered as
1164 ;; special.
1165 (org-test-with-temp-text "
1166 | | 1 |
1167 | | 2 |"
1168 (should-not
1169 (org-export-table-has-special-column-p
1170 (org-element-map
1171 (org-element-parse-buffer) 'table 'identity nil 'first-match)))))
1173 (ert-deftest test-org-export/table-row-is-special-p ()
1174 "Test `org-export-table-row-is-special-p' specifications."
1175 ;; 1. A row is special if it has a special marking character in the
1176 ;; special column.
1177 (org-test-with-parsed-data "| ! | 1 |"
1178 (should
1179 (org-export-table-row-is-special-p
1180 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
1181 ;; 2. A row is special when its first field is "/"
1182 (org-test-with-parsed-data "
1183 | / | 1 |
1184 | a | b |"
1185 (should
1186 (org-export-table-row-is-special-p
1187 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
1188 ;; 3. A row only containing alignment cookies is also considered as
1189 ;; special.
1190 (org-test-with-parsed-data "| <5> | | <l> | <l22> |"
1191 (should
1192 (org-export-table-row-is-special-p
1193 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
1194 ;; 4. Everything else isn't considered as special.
1195 (org-test-with-parsed-data "| \alpha | | c |"
1196 (should-not
1197 (org-export-table-row-is-special-p
1198 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
1199 ;; 5. Table's rules are never considered as special rows.
1200 (org-test-with-parsed-data "|---+---|"
1201 (should-not
1202 (org-export-table-row-is-special-p
1203 (org-element-map tree 'table-row 'identity nil 'first-match) info))))
1205 (ert-deftest test-org-export/has-header-p ()
1206 "Test `org-export-table-has-header-p' specifications."
1207 ;; 1. With an header.
1208 (org-test-with-parsed-data "
1209 | a | b |
1210 |---+---|
1211 | c | d |"
1212 (should
1213 (org-export-table-has-header-p
1214 (org-element-map tree 'table 'identity info 'first-match)
1215 info)))
1216 ;; 2. Without an header.
1217 (org-test-with-parsed-data "
1218 | a | b |
1219 | c | d |"
1220 (should-not
1221 (org-export-table-has-header-p
1222 (org-element-map tree 'table 'identity info 'first-match)
1223 info)))
1224 ;; 3. Don't get fooled with starting and ending rules.
1225 (org-test-with-parsed-data "
1226 |---+---|
1227 | a | b |
1228 | c | d |
1229 |---+---|"
1230 (should-not
1231 (org-export-table-has-header-p
1232 (org-element-map tree 'table 'identity info 'first-match)
1233 info))))
1235 (ert-deftest test-org-export/table-row-group ()
1236 "Test `org-export-table-row-group' specifications."
1237 ;; 1. A rule creates a new group.
1238 (org-test-with-parsed-data "
1239 | a | b |
1240 |---+---|
1241 | 1 | 2 |"
1242 (should
1243 (equal
1244 '(1 nil 2)
1245 (mapcar (lambda (row) (org-export-table-row-group row info))
1246 (org-element-map tree 'table-row 'identity)))))
1247 ;; 2. Special rows are ignored in count.
1248 (org-test-with-parsed-data "
1249 | / | < | > |
1250 |---|---+---|
1251 | | 1 | 2 |"
1252 (should
1253 (equal
1254 '(nil nil 1)
1255 (mapcar (lambda (row) (org-export-table-row-group row info))
1256 (org-element-map tree 'table-row 'identity)))))
1257 ;; 3. Double rules also are ignored in count.
1258 (org-test-with-parsed-data "
1259 | a | b |
1260 |---+---|
1261 |---+---|
1262 | 1 | 2 |"
1263 (should
1264 (equal
1265 '(1 nil nil 2)
1266 (mapcar (lambda (row) (org-export-table-row-group row info))
1267 (org-element-map tree 'table-row 'identity))))))
1269 (ert-deftest test-org-export/table-cell-width ()
1270 "Test `org-export-table-cell-width' specifications."
1271 ;; 1. Width is primarily determined by width cookies. If no cookie
1272 ;; is found, cell's width is nil.
1273 (org-test-with-parsed-data "
1274 | / | <l> | <6> | <l7> |
1275 | | a | b | c |"
1276 (should
1277 (equal
1278 '(nil 6 7)
1279 (mapcar (lambda (cell) (org-export-table-cell-width cell info))
1280 (org-element-map tree 'table-cell 'identity info)))))
1281 ;; 2. The last width cookie has precedence.
1282 (org-test-with-parsed-data "
1283 | <6> |
1284 | <7> |
1285 | a |"
1286 (should
1287 (equal
1288 '(7)
1289 (mapcar (lambda (cell) (org-export-table-cell-width cell info))
1290 (org-element-map tree 'table-cell 'identity info)))))
1291 ;; 3. Valid width cookies must have a specific row.
1292 (org-test-with-parsed-data "| <6> | cell |"
1293 (should
1294 (equal
1295 '(nil nil)
1296 (mapcar (lambda (cell) (org-export-table-cell-width cell info))
1297 (org-element-map tree 'table-cell 'identity))))))
1299 (ert-deftest test-org-export/table-cell-alignment ()
1300 "Test `org-export-table-cell-alignment' specifications."
1301 (let ((org-table-number-fraction 0.5)
1302 (org-table-number-regexp "^[0-9]+$"))
1303 ;; 1. Alignment is primarily determined by alignment cookies.
1304 (org-test-with-temp-text "| <l> | <c> | <r> |"
1305 (let* ((tree (org-element-parse-buffer))
1306 (info `(:parse-tree ,tree)))
1307 (should
1308 (equal
1309 '(left center right)
1310 (mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
1311 (org-element-map tree 'table-cell 'identity))))))
1312 ;; 2. The last alignment cookie has precedence.
1313 (org-test-with-parsed-data "
1314 | <l8> |
1315 | cell |
1316 | <r9> |"
1317 (should
1318 (equal
1319 '(right right right)
1320 (mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
1321 (org-element-map tree 'table-cell 'identity)))))
1322 ;; 3. If there's no cookie, cell's contents determine alignment.
1323 ;; A column mostly made of cells containing numbers will align
1324 ;; its cells to the right.
1325 (org-test-with-parsed-data "
1326 | 123 |
1327 | some text |
1328 | 12345 |"
1329 (should
1330 (equal
1331 '(right right right)
1332 (mapcar (lambda (cell)
1333 (org-export-table-cell-alignment cell info))
1334 (org-element-map tree 'table-cell 'identity)))))
1335 ;; 4. Otherwise, they will be aligned to the left.
1336 (org-test-with-parsed-data "
1337 | text |
1338 | some text |
1339 | \alpha |"
1340 (should
1341 (equal
1342 '(left left left)
1343 (mapcar (lambda (cell)
1344 (org-export-table-cell-alignment cell info))
1345 (org-element-map tree 'table-cell 'identity)))))))
1347 (ert-deftest test-org-export/table-cell-borders ()
1348 "Test `org-export-table-cell-borders' specifications."
1349 ;; 1. Recognize various column groups indicators.
1350 (org-test-with-parsed-data "| / | < | > | <> |"
1351 (should
1352 (equal
1353 '((right bottom top) (left bottom top) (right bottom top)
1354 (right left bottom top))
1355 (mapcar (lambda (cell)
1356 (org-export-table-cell-borders cell info))
1357 (org-element-map tree 'table-cell 'identity)))))
1358 ;; 2. Accept shortcuts to define column groups.
1359 (org-test-with-parsed-data "| / | < | < |"
1360 (should
1361 (equal
1362 '((right bottom top) (right left bottom top) (left bottom top))
1363 (mapcar (lambda (cell)
1364 (org-export-table-cell-borders cell info))
1365 (org-element-map tree 'table-cell 'identity)))))
1366 ;; 3. A valid column groups row must start with a "/".
1367 (org-test-with-parsed-data "
1368 | | < |
1369 | a | b |"
1370 (should
1371 (equal '((top) (top) (bottom) (bottom))
1372 (mapcar (lambda (cell)
1373 (org-export-table-cell-borders cell info))
1374 (org-element-map tree 'table-cell 'identity)))))
1375 ;; 4. Take table rules into consideration.
1376 (org-test-with-parsed-data "
1377 | 1 |
1378 |---|
1379 | 2 |"
1380 (should
1381 (equal '((below top) (bottom above))
1382 (mapcar (lambda (cell)
1383 (org-export-table-cell-borders cell info))
1384 (org-element-map tree 'table-cell 'identity)))))
1385 ;; 5. Top and (resp. bottom) rules induce both `top' and `above'
1386 ;; (resp. `bottom' and `below') borders. Any special row is
1387 ;; ignored.
1388 (org-test-with-parsed-data "
1389 |---+----|
1390 | / | |
1391 | | 1 |
1392 |---+----|"
1393 (should
1394 (equal '((bottom below top above))
1395 (last
1396 (mapcar (lambda (cell)
1397 (org-export-table-cell-borders cell info))
1398 (org-element-map tree 'table-cell 'identity)))))))
1400 (ert-deftest test-org-export/table-dimensions ()
1401 "Test `org-export-table-dimensions' specifications."
1402 ;; 1. Standard test.
1403 (org-test-with-parsed-data "
1404 | 1 | 2 | 3 |
1405 | 4 | 5 | 6 |"
1406 (should
1407 (equal '(2 . 3)
1408 (org-export-table-dimensions
1409 (org-element-map tree 'table 'identity info 'first-match) info))))
1410 ;; 2. Ignore horizontal rules and special columns.
1411 (org-test-with-parsed-data "
1412 | / | < | > |
1413 | 1 | 2 | 3 |
1414 |---+---+---|
1415 | 4 | 5 | 6 |"
1416 (should
1417 (equal '(2 . 3)
1418 (org-export-table-dimensions
1419 (org-element-map tree 'table 'identity info 'first-match) info)))))
1421 (ert-deftest test-org-export/table-cell-address ()
1422 "Test `org-export-table-cell-address' specifications."
1423 ;; 1. Standard test: index is 0-based.
1424 (org-test-with-parsed-data "| a | b |"
1425 (should
1426 (equal '((0 . 0) (0 . 1))
1427 (org-element-map
1428 tree 'table-cell
1429 (lambda (cell) (org-export-table-cell-address cell info))
1430 info))))
1431 ;; 2. Special column isn't counted, nor are special rows.
1432 (org-test-with-parsed-data "
1433 | / | <> |
1434 | | c |"
1435 (should
1436 (equal '(0 . 0)
1437 (org-export-table-cell-address
1438 (car (last (org-element-map tree 'table-cell 'identity info)))
1439 info))))
1440 ;; 3. Tables rules do not count either.
1441 (org-test-with-parsed-data "
1442 | a |
1443 |---|
1444 | b |
1445 |---|
1446 | c |"
1447 (should
1448 (equal '(2 . 0)
1449 (org-export-table-cell-address
1450 (car (last (org-element-map tree 'table-cell 'identity info)))
1451 info))))
1452 ;; 4. Return nil for special cells.
1453 (org-test-with-parsed-data "| / | a |"
1454 (should-not
1455 (org-export-table-cell-address
1456 (org-element-map tree 'table-cell 'identity nil 'first-match)
1457 info))))
1459 (ert-deftest test-org-export/get-table-cell-at ()
1460 "Test `org-export-get-table-cell-at' specifications."
1461 ;; 1. Address ignores special columns, special rows and rules.
1462 (org-test-with-parsed-data "
1463 | / | <> |
1464 | | a |
1465 |---+----|
1466 | | b |"
1467 (should
1468 (equal '("b")
1469 (org-element-contents
1470 (org-export-get-table-cell-at
1471 '(1 . 0)
1472 (org-element-map tree 'table 'identity info 'first-match)
1473 info)))))
1474 ;; 2. Return value for a non-existent address is nil.
1475 (org-test-with-parsed-data "| a |"
1476 (should-not
1477 (org-export-get-table-cell-at
1478 '(2 . 2)
1479 (org-element-map tree 'table 'identity info 'first-match)
1480 info)))
1481 (org-test-with-parsed-data "| / |"
1482 (should-not
1483 (org-export-get-table-cell-at
1484 '(0 . 0)
1485 (org-element-map tree 'table 'identity info 'first-match)
1486 info))))
1488 (ert-deftest test-org-export/table-cell-starts-colgroup-p ()
1489 "Test `org-export-table-cell-starts-colgroup-p' specifications."
1490 ;; 1. A cell at a beginning of a row always starts a column group.
1491 (org-test-with-parsed-data "| a |"
1492 (should
1493 (org-export-table-cell-starts-colgroup-p
1494 (org-element-map tree 'table-cell 'identity info 'first-match)
1495 info)))
1496 ;; 2. Special column should be ignored when determining the
1497 ;; beginning of the row.
1498 (org-test-with-parsed-data "
1499 | / | |
1500 | | a |"
1501 (should
1502 (org-export-table-cell-starts-colgroup-p
1503 (org-element-map tree 'table-cell 'identity info 'first-match)
1504 info)))
1505 ;; 2. Explicit column groups.
1506 (org-test-with-parsed-data "
1507 | / | | < |
1508 | a | b | c |"
1509 (should
1510 (equal
1511 '(yes no yes)
1512 (org-element-map
1513 tree 'table-cell
1514 (lambda (cell)
1515 (if (org-export-table-cell-starts-colgroup-p cell info) 'yes 'no))
1516 info)))))
1518 (ert-deftest test-org-export/table-cell-ends-colgroup-p ()
1519 "Test `org-export-table-cell-ends-colgroup-p' specifications."
1520 ;; 1. A cell at the end of a row always ends a column group.
1521 (org-test-with-parsed-data "| a |"
1522 (should
1523 (org-export-table-cell-ends-colgroup-p
1524 (org-element-map tree 'table-cell 'identity info 'first-match)
1525 info)))
1526 ;; 2. Special column should be ignored when determining the
1527 ;; beginning of the row.
1528 (org-test-with-parsed-data "
1529 | / | |
1530 | | a |"
1531 (should
1532 (org-export-table-cell-ends-colgroup-p
1533 (org-element-map tree 'table-cell 'identity info 'first-match)
1534 info)))
1535 ;; 3. Explicit column groups.
1536 (org-test-with-parsed-data "
1537 | / | < | |
1538 | a | b | c |"
1539 (should
1540 (equal
1541 '(yes no yes)
1542 (org-element-map
1543 tree 'table-cell
1544 (lambda (cell)
1545 (if (org-export-table-cell-ends-colgroup-p cell info) 'yes 'no))
1546 info)))))
1548 (ert-deftest test-org-export/table-row-starts-rowgroup-p ()
1549 "Test `org-export-table-row-starts-rowgroup-p' specifications."
1550 ;; 1. A row at the beginning of a table always starts a row group.
1551 ;; So does a row following a table rule.
1552 (org-test-with-parsed-data "
1553 | a |
1554 |---|
1555 | b |"
1556 (should
1557 (equal
1558 '(yes no yes)
1559 (org-element-map
1560 tree 'table-row
1561 (lambda (row)
1562 (if (org-export-table-row-starts-rowgroup-p row info) 'yes 'no))
1563 info))))
1564 ;; 2. Special rows should be ignored when determining the beginning
1565 ;; of the row.
1566 (org-test-with-parsed-data "
1567 | / | < |
1568 | | a |
1569 |---+---|
1570 | / | < |
1571 | | b |"
1572 (should
1573 (equal
1574 '(yes no yes)
1575 (org-element-map
1576 tree 'table-row
1577 (lambda (row)
1578 (if (org-export-table-row-starts-rowgroup-p row info) 'yes 'no))
1579 info)))))
1581 (ert-deftest test-org-export/table-row-ends-rowgroup-p ()
1582 "Test `org-export-table-row-ends-rowgroup-p' specifications."
1583 ;; 1. A row at the end of a table always ends a row group. So does
1584 ;; a row preceding a table rule.
1585 (org-test-with-parsed-data "
1586 | a |
1587 |---|
1588 | b |"
1589 (should
1590 (equal
1591 '(yes no yes)
1592 (org-element-map
1593 tree 'table-row
1594 (lambda (row)
1595 (if (org-export-table-row-ends-rowgroup-p row info) 'yes 'no))
1596 info))))
1597 ;; 2. Special rows should be ignored when determining the beginning
1598 ;; of the row.
1599 (org-test-with-parsed-data "
1600 | | a |
1601 | / | < |
1602 |---+---|
1603 | | b |
1604 | / | < |"
1605 (should
1606 (equal
1607 '(yes no yes)
1608 (org-element-map
1609 tree 'table-row
1610 (lambda (row)
1611 (if (org-export-table-row-ends-rowgroup-p row info) 'yes 'no))
1612 info)))))
1614 (ert-deftest test-org-export/table-row-starts-header-p ()
1615 "Test `org-export-table-row-starts-header-p' specifications."
1616 ;; 1. Only the row starting the first row group starts the table
1617 ;; header.
1618 (org-test-with-parsed-data "
1619 | a |
1620 | b |
1621 |---|
1622 | c |"
1623 (should
1624 (equal
1625 '(yes no no no)
1626 (org-element-map
1627 tree 'table-row
1628 (lambda (row)
1629 (if (org-export-table-row-starts-header-p row info) 'yes 'no))
1630 info))))
1631 ;; 2. A row cannot start an header if there's no header in the
1632 ;; table.
1633 (org-test-with-parsed-data "
1634 | a |
1635 |---|"
1636 (should-not
1637 (org-export-table-row-starts-header-p
1638 (org-element-map tree 'table-row 'identity info 'first-match)
1639 info))))
1641 (ert-deftest test-org-export/table-row-ends-header-p ()
1642 "Test `org-export-table-row-ends-header-p' specifications."
1643 ;; 1. Only the row starting the first row group starts the table
1644 ;; header.
1645 (org-test-with-parsed-data "
1646 | a |
1647 | b |
1648 |---|
1649 | c |"
1650 (should
1651 (equal
1652 '(no yes no no)
1653 (org-element-map
1654 tree 'table-row
1655 (lambda (row)
1656 (if (org-export-table-row-ends-header-p row info) 'yes 'no))
1657 info))))
1658 ;; 2. A row cannot start an header if there's no header in the
1659 ;; table.
1660 (org-test-with-parsed-data "
1661 | a |
1662 |---|"
1663 (should-not
1664 (org-export-table-row-ends-header-p
1665 (org-element-map tree 'table-row 'identity info 'first-match)
1666 info))))
1670 ;;; Topology
1672 (ert-deftest test-org-export/get-next-element ()
1673 "Test `org-export-get-next-element' specifications."
1674 ;; Standard test.
1675 (should
1676 (equal "b"
1677 (org-test-with-parsed-data "* Headline\n*a* b"
1678 (org-export-get-next-element
1679 (org-element-map tree 'bold 'identity info t) info))))
1680 ;; Return nil when no previous element.
1681 (should-not
1682 (org-test-with-parsed-data "* Headline\na *b*"
1683 (org-export-get-next-element
1684 (org-element-map tree 'bold 'identity info t) info)))
1685 ;; Non-exportable elements are ignored.
1686 (should-not
1687 (let ((org-export-with-timestamps nil))
1688 (org-test-with-parsed-data "\alpha <2012-03-29 Thu>"
1689 (org-export-get-next-element
1690 (org-element-map tree 'entity 'identity info t) info)))))
1692 (ert-deftest test-org-export/get-previous-element ()
1693 "Test `org-export-get-previous-element' specifications."
1694 ;; Standard test.
1695 (should
1696 (equal "a "
1697 (org-test-with-parsed-data "* Headline\na *b*"
1698 (org-export-get-previous-element
1699 (org-element-map tree 'bold 'identity info t) info))))
1700 ;; Return nil when no previous element.
1701 (should-not
1702 (org-test-with-parsed-data "* Headline\n*a* b"
1703 (org-export-get-previous-element
1704 (org-element-map tree 'bold 'identity info t) info)))
1705 ;; Non-exportable elements are ignored.
1706 (should-not
1707 (let ((org-export-with-timestamps nil))
1708 (org-test-with-parsed-data "<2012-03-29 Thu> \alpha"
1709 (org-export-get-previous-element
1710 (org-element-map tree 'entity 'identity info t) info)))))
1713 (provide 'test-org-export)
1714 ;;; test-org-export.el end here