org-export: Fix bug with default DATE value
[org-mode.git] / testing / lisp / test-org-export.el
blobe0bfa777a0e0e069573e8c6d2e3b4fab204d62ba
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 (cons type (intern (format "org-%s-%s" backend type)))
32 transcode-table)))))
33 (flet ,(let (transcoders)
34 (dolist (type (append org-element-all-elements
35 org-element-all-objects)
36 transcoders)
37 (push `(,(intern (format "org-%s-%s" backend type))
38 (obj contents info)
39 (,(intern (format "org-element-%s-interpreter" type))
40 obj contents))
41 transcoders)))
42 ,@body)))
44 (defmacro org-test-with-parsed-data (data &rest body)
45 "Execute body with parsed data available.
47 DATA is a string containing the data to be parsed. BODY is the
48 body to execute. Parse tree is available under the `tree'
49 variable, and communication channel under `info'.
51 This function calls `org-export-collect-tree-properties'. As
52 such, `:ignore-list' (for `org-element-map') and
53 `:parse-tree' (for `org-export-get-genealogy') properties are
54 already filled in `info'."
55 (declare (debug (form body)) (indent 1))
56 `(org-test-with-temp-text ,data
57 (let* ((tree (org-element-parse-buffer))
58 (info (org-export-collect-tree-properties
59 tree (org-export-get-environment))))
60 ,@body)))
64 ;;; Tests
66 (ert-deftest test-org-export/parse-option-keyword ()
67 "Test reading all standard #+OPTIONS: items."
68 (should
69 (equal
70 (org-export-parse-option-keyword
71 "H:1 num:t \\n:t timestamp:t arch:t author:t creator:t d:t email:t
72 *:t e:t ::t f:t pri:t -:t ^:t toc:t |:t tags:t tasks:t <:t todo:t")
73 '(:headline-levels
74 1 :preserve-breaks t :section-numbers t :time-stamp-file t
75 :with-archived-trees t :with-author t :with-creator t :with-drawers t
76 :with-email t :with-emphasize t :with-entities t :with-fixed-width t
77 :with-footnotes t :with-priority t :with-special-strings t
78 :with-sub-superscript t :with-toc t :with-tables t :with-tags t
79 :with-tasks t :with-timestamps t :with-todo-keywords t)))
80 ;; Test some special values.
81 (should
82 (equal
83 (org-export-parse-option-keyword
84 "arch:headline creator:comment d:(\"TEST\")
85 ^:{} toc:1 tags:not-in-toc tasks:todo num:2 <:active")
86 '( :section-numbers
88 :with-archived-trees headline :with-creator comment
89 :with-drawers ("TEST") :with-sub-superscript {} :with-toc 1
90 :with-tags not-in-toc :with-tasks todo :with-timestamps active))))
92 (ert-deftest test-org-export/get-inbuffer-options ()
93 "Test reading all standard export keywords."
94 (should
95 (equal
96 (org-test-with-temp-text "#+AUTHOR: Me, Myself and I
97 #+CREATOR: Idem
98 #+DATE: Today
99 #+DESCRIPTION: Testing
100 #+DESCRIPTION: with two lines
101 #+EMAIL: some@email.org
102 #+EXPORT_EXCLUDE_TAGS: noexport invisible
103 #+KEYWORDS: test
104 #+LANGUAGE: en
105 #+EXPORT_SELECT_TAGS: export
106 #+TITLE: Some title
107 #+TITLE: with spaces"
108 (org-export-get-inbuffer-options))
109 '(:author
110 ("Me, Myself and I") :creator "Idem" :date ("Today")
111 :description "Testing\nwith two lines" :email "some@email.org"
112 :exclude-tags ("noexport" "invisible") :keywords "test" :language "en"
113 :select-tags ("export") :title ("Some title with spaces")))))
115 (ert-deftest test-org-export/handle-options ()
116 "Test if export options have an impact on output."
117 ;; Test exclude tags.
118 (org-test-with-temp-text "* Head1 :noexport:"
119 (org-test-with-backend test
120 (should
121 (equal (org-export-as 'test nil nil nil '(:exclude-tags ("noexport")))
122 ""))))
123 ;; Test include tags.
124 (org-test-with-temp-text "
125 * Head1
126 * Head2
127 ** Sub-Head2.1 :export:
128 *** Sub-Head2.1.1
129 * Head2"
130 (org-test-with-backend test
131 (should
132 (equal
133 "* Head2\n** Sub-Head2.1 :export:\n*** Sub-Head2.1.1\n"
134 (let ((org-tags-column 0))
135 (org-export-as 'test nil nil nil '(:select-tags ("export"))))))))
136 ;; Test mixing include tags and exclude tags.
137 (org-test-with-temp-text "
138 * Head1 :export:
139 ** Sub-Head1 :noexport:
140 ** Sub-Head2
141 * Head2 :noexport:
142 ** Sub-Head1 :export:"
143 (org-test-with-backend test
144 (should
145 (string-match
146 "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
147 (org-export-as
148 'test nil nil nil
149 '(:select-tags ("export") :exclude-tags ("noexport")))))))
150 ;; Ignore tasks.
151 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
152 (org-test-with-temp-text "* TODO Head1"
153 (org-test-with-backend test
154 (should (equal (org-export-as 'test nil nil nil '(:with-tasks nil))
155 "")))))
156 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
157 (org-test-with-temp-text "* TODO Head1"
158 (org-test-with-backend test
159 (should (equal (org-export-as 'test nil nil nil '(:with-tasks t))
160 "* TODO Head1\n")))))
161 ;; Archived tree.
162 (org-test-with-temp-text "* Head1 :archive:"
163 (let ((org-archive-tag "archive"))
164 (org-test-with-backend test
165 (should
166 (equal (org-export-as 'test nil nil nil '(:with-archived-trees nil))
167 "")))))
168 (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
169 (let ((org-archive-tag "archive"))
170 (org-test-with-backend test
171 (should
172 (string-match
173 "\\* Head1[ \t]+:archive:"
174 (org-export-as 'test nil nil nil
175 '(:with-archived-trees headline)))))))
176 (org-test-with-temp-text "* Head1 :archive:"
177 (let ((org-archive-tag "archive"))
178 (org-test-with-backend test
179 (should
180 (string-match
181 "\\`\\* Head1[ \t]+:archive:\n\\'"
182 (org-export-as 'test nil nil nil '(:with-archived-trees t)))))))
183 ;; Drawers.
184 (let ((org-drawers '("TEST")))
185 (org-test-with-temp-text ":TEST:\ncontents\n:END:"
186 (org-test-with-backend test
187 (should (equal (org-export-as 'test nil nil nil '(:with-drawers nil))
188 ""))
189 (should (equal (org-export-as 'test nil nil nil '(:with-drawers t))
190 ":TEST:\ncontents\n:END:\n")))))
191 (let ((org-drawers '("FOO" "BAR")))
192 (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
193 (org-test-with-backend test
194 (should
195 (equal (org-export-as 'test nil nil nil '(:with-drawers ("FOO")))
196 ":FOO:\nkeep\n:END:\n")))))
197 ;; Timestamps.
198 (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
199 (org-test-with-backend test
200 (should
201 (equal (org-export-as 'test nil nil nil '(:with-timestamps t))
202 "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>\n"))
203 (should
204 (equal (org-export-as 'test nil nil nil '(:with-timestamps nil)) ""))
205 (should
206 (equal (org-export-as 'test nil nil nil '(:with-timestamps active))
207 "<2012-04-29 sun. 10:45>\n"))
208 (should
209 (equal (org-export-as 'test nil nil nil '(:with-timestamps inactive))
210 "[2012-04-29 sun. 10:45]\n"))))
211 ;; Clocks.
212 (let ((org-clock-string "CLOCK:"))
213 (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
214 (org-test-with-backend test
215 (should
216 (equal (org-export-as 'test nil nil nil '(:with-clocks t))
217 "CLOCK: [2012-04-29 sun. 10:45]\n"))
218 (should
219 (equal (org-export-as 'test nil nil nil '(:with-clocks nil)) "")))))
220 ;; Plannings.
221 (let ((org-closed-string "CLOSED:"))
222 (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
223 (org-test-with-backend test
224 (should
225 (equal (org-export-as 'test nil nil nil '(:with-plannings t))
226 "CLOSED: [2012-04-29 sun. 10:45]\n"))
227 (should
228 (equal (org-export-as 'test nil nil nil '(:with-plannings nil))
229 ""))))))
231 (ert-deftest test-org-export/comment-tree ()
232 "Test if export process ignores commented trees."
233 (let ((org-comment-string "COMMENT"))
234 (org-test-with-temp-text "* COMMENT Head1"
235 (org-test-with-backend test
236 (should (equal (org-export-as 'test) ""))))))
238 (ert-deftest test-org-export/export-scope ()
239 "Test all export scopes."
240 (org-test-with-temp-text "
241 * Head1
242 ** Head2
243 text
244 *** Head3"
245 (org-test-with-backend test
246 ;; Subtree.
247 (forward-line 3)
248 (should (equal (org-export-as 'test 'subtree) "text\n*** Head3\n"))
249 ;; Visible.
250 (goto-char (point-min))
251 (forward-line)
252 (org-cycle)
253 (should (equal (org-export-as 'test nil 'visible) "* Head1\n"))
254 ;; Body only.
255 (flet ((org-test-template (body info) (format "BEGIN\n%sEND" body)))
256 (push '(template . org-test-template) org-test-translate-alist)
257 (should (equal (org-export-as 'test nil nil 'body-only)
258 "* Head1\n** Head2\ntext\n*** Head3\n"))
259 (should (equal (org-export-as 'test)
260 "BEGIN\n* Head1\n** Head2\ntext\n*** Head3\nEND")))
261 ;; Region.
262 (goto-char (point-min))
263 (forward-line 3)
264 (transient-mark-mode 1)
265 (push-mark (point) t t)
266 (goto-char (point-at-eol))
267 (should (equal (org-export-as 'test) "text\n"))))
268 ;; Subtree with a code block calling another block outside.
269 (org-test-with-temp-text "
270 * Head1
271 #+BEGIN_SRC emacs-lisp :noweb yes :exports results
272 <<test>>
273 #+END_SRC
274 * Head2
275 #+NAME: test
276 #+BEGIN_SRC emacs-lisp
277 \(+ 1 2)
278 #+END_SRC"
279 (org-test-with-backend test
280 (forward-line 1)
281 (should (equal (org-export-as 'test 'subtree) ": 3\n"))))
282 ;; Subtree's EXPORT_TITLE property.
283 (org-test-with-backend test
284 (flet ((org-test-template (body info)
285 (org-export-data (plist-get info :title) info)))
286 (push '(template . org-test-template) org-test-translate-alist)
287 (org-test-with-temp-text "
288 * Headline
289 :PROPERTIES:
290 :EXPORT_TITLE: subtree-title
291 :END:
292 Paragraph"
293 (forward-line)
294 (should (equal "subtree-title" (org-export-as 'test 'subtree)))))))
296 (ert-deftest test-org-export/export-snippet ()
297 "Test export snippets transcoding."
298 (org-test-with-temp-text "<test@A><t@B>"
299 (org-test-with-backend test
300 (flet ((org-test-export-snippet
301 (snippet contents info)
302 (when (eq (org-export-snippet-backend snippet) 'test)
303 (org-element-property :value snippet))))
304 (let ((org-export-snippet-translation-alist nil))
305 (should (equal (org-export-as 'test) "A\n")))
306 (let ((org-export-snippet-translation-alist '(("t" . "test"))))
307 (should (equal (org-export-as 'test) "AB\n")))))))
309 (ert-deftest test-org-export/expand-include ()
310 "Test file inclusion in an Org buffer."
311 ;; Full insertion with recursive inclusion.
312 (org-test-with-temp-text
313 (format "#+INCLUDE: \"%s/examples/include.org\"" org-test-dir)
314 (org-export-expand-include-keyword)
315 (should (equal (buffer-string)
316 "Small Org file with an include keyword.
318 #+BEGIN_SRC emacs-lisp :exports results\n(+ 2 1)\n#+END_SRC
320 Success!
322 * Heading
323 body\n")))
324 ;; Localized insertion.
325 (org-test-with-temp-text
326 (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\""
327 org-test-dir)
328 (org-export-expand-include-keyword)
329 (should (equal (buffer-string)
330 "Small Org file with an include keyword.\n")))
331 ;; Insertion with constraints on headlines level.
332 (org-test-with-temp-text
333 (format
334 "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-\""
335 org-test-dir)
336 (org-export-expand-include-keyword)
337 (should (equal (buffer-string) "* Top heading\n** Heading\nbody\n")))
338 ;; Inclusion within an example block.
339 (org-test-with-temp-text
340 (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\" example"
341 org-test-dir)
342 (org-export-expand-include-keyword)
343 (should
344 (equal
345 (buffer-string)
346 "#+BEGIN_EXAMPLE\nSmall Org file with an include keyword.\n#+END_EXAMPLE\n")))
347 ;; Inclusion within a src-block.
348 (org-test-with-temp-text
349 (format
350 "#+INCLUDE: \"%s/examples/include.org\" :lines \"4-5\" src emacs-lisp"
351 org-test-dir)
352 (org-export-expand-include-keyword)
353 (should (equal (buffer-string)
354 "#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n"))))
356 (ert-deftest test-org-export/user-ignore-list ()
357 "Test if `:ignore-list' accepts user input."
358 (org-test-with-backend test
359 (flet ((skip-note-head
360 (data backend info)
361 ;; Ignore headlines with the word "note" in their title.
362 (org-element-map
363 data 'headline
364 (lambda (headline)
365 (when (string-match "\\<note\\>"
366 (org-element-property :raw-value headline))
367 (org-export-ignore-element headline info)))
368 info)
369 data))
370 ;; Install function in parse tree filters.
371 (let ((org-export-filter-parse-tree-functions '(skip-note-head)))
372 (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
373 (should (equal (org-export-as 'test) "* Head1\n")))))))
375 (ert-deftest test-org-export/before-parsing-hook ()
376 "Test `org-export-before-parsing-hook'."
377 (org-test-with-backend test
378 (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 2"
379 (let ((org-export-before-parsing-hook
380 '((lambda ()
381 (org-map-entries
382 (lambda ()
383 (delete-region (point) (progn (forward-line) (point)))))))))
384 (should (equal (org-export-as 'test) "Body 1\nBody 2\n"))))))
386 (ert-deftest test-org-export/set-element ()
387 "Test `org-export-set-element' specifications."
388 (org-test-with-parsed-data "* Headline\n*a*"
389 (org-export-set-element
390 (org-element-map tree 'bold 'identity nil t)
391 '(italic nil "b"))
392 ;; Check if object is correctly replaced.
393 (should (org-element-map tree 'italic 'identity))
394 (should-not (org-element-map tree 'bold 'identity))
395 ;; Check if new object's parent is correctly set.
396 (should
397 (equal
398 (org-element-property :parent
399 (org-element-map tree 'italic 'identity nil t))
400 (org-element-map tree 'paragraph 'identity nil t)))))
404 ;;; Affiliated Keywords
406 (ert-deftest test-org-export/read-attribute ()
407 "Test `org-export-read-attribute' specifications."
408 ;; Standard test.
409 (should
410 (equal
411 (org-export-read-attribute
412 :attr_html
413 (org-test-with-temp-text "#+ATTR_HTML: :a 1 :b 2\nParagraph"
414 (org-element-current-element)))
415 '(:a 1 :b 2)))
416 ;; Return nil on empty attribute.
417 (should-not
418 (org-export-read-attribute
419 :attr_html
420 (org-test-with-temp-text "Paragraph" (org-element-current-element)))))
423 ;;; Footnotes
425 (ert-deftest test-org-export/footnotes ()
426 "Test footnotes specifications."
427 (let ((org-footnote-section nil)
428 (org-export-with-footnotes t))
429 ;; 1. Read every type of footnote.
430 (org-test-with-parsed-data
431 "Text[fn:1] [1] [fn:label:C] [fn::D]\n\n[fn:1] A\n\n[1] B"
432 (should
433 (equal
434 '((1 . "A") (2 . "B") (3 . "C") (4 . "D"))
435 (org-element-map
436 tree 'footnote-reference
437 (lambda (ref)
438 (let ((def (org-export-get-footnote-definition ref info)))
439 (cons (org-export-get-footnote-number ref info)
440 (if (eq (org-element-property :type ref) 'inline) (car def)
441 (car (org-element-contents
442 (car (org-element-contents def))))))))
443 info))))
444 ;; 2. Test nested footnotes order.
445 (org-test-with-parsed-data
446 "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
447 (should
448 (equal
449 '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
450 (org-element-map
451 tree 'footnote-reference
452 (lambda (ref)
453 (when (org-export-footnote-first-reference-p ref info)
454 (cons (org-export-get-footnote-number ref info)
455 (org-element-property :label ref))))
456 info))))
457 ;; 3. Test nested footnote in invisible definitions.
458 (org-test-with-temp-text "Text[1]\n\n[1] B [2]\n\n[2] C."
459 ;; Hide definitions.
460 (narrow-to-region (point) (point-at-eol))
461 (let* ((tree (org-element-parse-buffer))
462 (info (org-combine-plists
463 `(:parse-tree ,tree)
464 (org-export-collect-tree-properties
465 tree (org-export-get-environment)))))
466 ;; Both footnotes should be seen.
467 (should
468 (= (length (org-export-collect-footnote-definitions tree info)) 2))))
469 ;; 4. Test footnotes definitions collection.
470 (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
472 \[fn:2] B [fn:3] [fn::D].
474 \[fn:3] C."
475 (should (= (length (org-export-collect-footnote-definitions tree info))
476 4)))
477 ;; 5. Test export of footnotes defined outside parsing scope.
478 (org-test-with-temp-text "[fn:1] Out of scope
479 * Title
480 Paragraph[fn:1]"
481 (org-test-with-backend test
482 (flet ((org-test-footnote-reference
483 (fn-ref contents info)
484 (org-element-interpret-data
485 (org-export-get-footnote-definition fn-ref info))))
486 (forward-line)
487 (should (equal "ParagraphOut of scope\n"
488 (org-export-as 'test 'subtree))))))))
492 ;;; Headlines and Inlinetasks
494 (ert-deftest test-org-export/get-tags ()
495 "Test `org-export-get-tags' specifications."
496 (let ((org-export-exclude-tags '("noexport"))
497 (org-export-select-tags '("export")))
498 ;; Standard test: tags which are not a select tag, an exclude tag,
499 ;; or specified as optional argument shouldn't be ignored.
500 (should
501 (org-test-with-parsed-data "* Headline :tag:"
502 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
503 info)))
504 ;; Exclude tags are removed.
505 (should-not
506 (org-test-with-parsed-data "* Headline :noexport:"
507 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
508 info)))
509 ;; Select tags are removed.
510 (should-not
511 (org-test-with-parsed-data "* Headline :export:"
512 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
513 info)))
514 (should
515 (equal
516 '("tag")
517 (org-test-with-parsed-data "* Headline :tag:export:"
518 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
519 info))))
520 ;; Tags provided in the optional argument are also ignored.
521 (should-not
522 (org-test-with-parsed-data "* Headline :ignore:"
523 (org-export-get-tags (org-element-map tree 'headline 'identity info t)
524 info '("ignore"))))))
528 ;;; Links
530 (ert-deftest test-org-export/fuzzy-link ()
531 "Test fuzzy links specifications."
532 ;; 1. Links to invisible (keyword) targets should be ignored.
533 (org-test-with-parsed-data
534 "Paragraph.\n#+TARGET: Test\n[[Test]]"
535 (should-not
536 (org-element-map
537 tree 'link
538 (lambda (link)
539 (org-export-get-ordinal
540 (org-export-resolve-fuzzy-link link info) info)) info)))
541 ;; 2. Link to an headline should return headline's number.
542 (org-test-with-parsed-data
543 "Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
544 (should
545 ;; Note: Headline's number is in fact a list of numbers.
546 (equal '(2)
547 (org-element-map
548 tree 'link
549 (lambda (link)
550 (org-export-get-ordinal
551 (org-export-resolve-fuzzy-link link info) info)) info t))))
552 ;; 3. Link to a target in an item should return item's number.
553 (org-test-with-parsed-data
554 "- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
555 (should
556 ;; Note: Item's number is in fact a list of numbers.
557 (equal '(1 2)
558 (org-element-map
559 tree 'link
560 (lambda (link)
561 (org-export-get-ordinal
562 (org-export-resolve-fuzzy-link link info) info)) info t))))
563 ;; 4. Link to a target in a footnote should return footnote's
564 ;; number.
565 (org-test-with-parsed-data "
566 Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
567 (should
568 (equal '(2 3)
569 (org-element-map
570 tree 'link
571 (lambda (link)
572 (org-export-get-ordinal
573 (org-export-resolve-fuzzy-link link info) info)) info))))
574 ;; 5. Link to a named element should return sequence number of that
575 ;; element.
576 (org-test-with-parsed-data
577 "#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
578 (should
579 (= 2
580 (org-element-map
581 tree 'link
582 (lambda (link)
583 (org-export-get-ordinal
584 (org-export-resolve-fuzzy-link link info) info)) info t))))
585 ;; 6. Link to a target not within an item, a table, a footnote
586 ;; reference or definition should return section number.
587 (org-test-with-parsed-data
588 "* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
589 (should
590 (equal '(2)
591 (org-element-map
592 tree 'link
593 (lambda (link)
594 (org-export-get-ordinal
595 (org-export-resolve-fuzzy-link link info) info)) info t)))))
597 (ert-deftest test-org-export/resolve-coderef ()
598 "Test `org-export-resolve-coderef' specifications."
599 (let ((org-coderef-label-format "(ref:%s)"))
600 ;; 1. A link to a "-n -k -r" block returns line number.
601 (org-test-with-parsed-data
602 "#+BEGIN_EXAMPLE -n -k -r\nText (ref:coderef)\n#+END_EXAMPLE"
603 (should (= (org-export-resolve-coderef "coderef" info) 1)))
604 (org-test-with-parsed-data
605 "#+BEGIN_SRC emacs-lisp -n -k -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
606 (should (= (org-export-resolve-coderef "coderef" info) 1)))
607 ;; 2. A link to a "-n -r" block returns line number.
608 (org-test-with-parsed-data
609 "#+BEGIN_EXAMPLE -n -r\nText (ref:coderef)\n#+END_EXAMPLE"
610 (should (= (org-export-resolve-coderef "coderef" info) 1)))
611 (org-test-with-parsed-data
612 "#+BEGIN_SRC emacs-lisp -n -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
613 (should (= (org-export-resolve-coderef "coderef" info) 1)))
614 ;; 3. A link to a "-n" block returns coderef.
615 (org-test-with-parsed-data
616 "#+BEGIN_SRC emacs-lisp -n\n(+ 1 1) (ref:coderef)\n#+END_SRC"
617 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
618 (org-test-with-parsed-data
619 "#+BEGIN_EXAMPLE -n\nText (ref:coderef)\n#+END_EXAMPLE"
620 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
621 ;; 4. A link to a "-r" block returns line number.
622 (org-test-with-parsed-data
623 "#+BEGIN_SRC emacs-lisp -r\n(+ 1 1) (ref:coderef)\n#+END_SRC"
624 (should (= (org-export-resolve-coderef "coderef" info) 1)))
625 (org-test-with-parsed-data
626 "#+BEGIN_EXAMPLE -r\nText (ref:coderef)\n#+END_EXAMPLE"
627 (should (= (org-export-resolve-coderef "coderef" info) 1)))
628 ;; 5. A link to a block without a switch returns coderef.
629 (org-test-with-parsed-data
630 "#+BEGIN_SRC emacs-lisp\n(+ 1 1) (ref:coderef)\n#+END_SRC"
631 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
632 (org-test-with-parsed-data
633 "#+BEGIN_EXAMPLE\nText (ref:coderef)\n#+END_EXAMPLE"
634 (should (equal (org-export-resolve-coderef "coderef" info) "coderef")))
635 ;; 6. Correctly handle continued line numbers. A "+n" switch
636 ;; should resume numbering from previous block with numbered
637 ;; lines, ignoring blocks not numbering lines in the process.
638 ;; A "-n" switch resets count.
639 (org-test-with-parsed-data "
640 #+BEGIN_EXAMPLE -n
641 Text.
642 #+END_EXAMPLE
644 #+BEGIN_SRC emacs-lisp
645 \(- 1 1)
646 #+END_SRC
648 #+BEGIN_SRC emacs-lisp +n -r
649 \(+ 1 1) (ref:addition)
650 #+END_SRC
652 #+BEGIN_EXAMPLE -n -r
653 Another text. (ref:text)
654 #+END_EXAMPLE"
655 (should (= (org-export-resolve-coderef "addition" info) 2))
656 (should (= (org-export-resolve-coderef "text" info) 1)))
657 ;; 7. Recognize coderef with user-specified syntax.
658 (org-test-with-parsed-data
659 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText. [ref:text]\n#+END_EXAMPLE"
660 (should (equal (org-export-resolve-coderef "text" info) "text")))))
662 (ert-deftest test-org-exprot/resolve-fuzzy-link ()
663 "Test `org-export-resolve-fuzzy-link' specifications."
664 ;; 1. Match target objects.
665 (org-test-with-parsed-data "<<target>> [[target]]"
666 (should
667 (org-export-resolve-fuzzy-link
668 (org-element-map tree 'link 'identity info t) info)))
669 ;; 2. Match target elements.
670 (org-test-with-parsed-data "#+TARGET: target\n[[target]]"
671 (should
672 (org-export-resolve-fuzzy-link
673 (org-element-map tree 'link 'identity info t) info)))
674 ;; 3. Match named elements.
675 (org-test-with-parsed-data "#+NAME: target\nParagraph\n\n[[target]]"
676 (should
677 (org-export-resolve-fuzzy-link
678 (org-element-map tree 'link 'identity info t) info)))
679 ;; 4. Match exact headline's name.
680 (org-test-with-parsed-data "* My headline\n[[My headline]]"
681 (should
682 (org-export-resolve-fuzzy-link
683 (org-element-map tree 'link 'identity info t) info)))
684 ;; 5. Targets objects have priority over named elements and headline
685 ;; titles.
686 (org-test-with-parsed-data
687 "* target\n#+NAME: target\n<<target>>\n\n[[target]]"
688 (should
689 (eq 'target
690 (org-element-type
691 (org-export-resolve-fuzzy-link
692 (org-element-map tree 'link 'identity info t) info)))))
693 ;; 6. Named elements have priority over headline titles.
694 (org-test-with-parsed-data
695 "* target\n#+NAME: target\nParagraph\n\n[[target]]"
696 (should
697 (eq 'paragraph
698 (org-element-type
699 (org-export-resolve-fuzzy-link
700 (org-element-map tree 'link 'identity info t) info)))))
701 ;; 7. If link's path starts with a "*", only match headline titles,
702 ;; though.
703 (org-test-with-parsed-data
704 "* target\n#+NAME: target\n<<target>>\n\n[[*target]]"
705 (should
706 (eq 'headline
707 (org-element-type
708 (org-export-resolve-fuzzy-link
709 (org-element-map tree 'link 'identity info t) info)))))
710 ;; 8. Return nil if no match.
711 (org-test-with-parsed-data "[[target]]"
712 (should-not
713 (org-export-resolve-fuzzy-link
714 (org-element-map tree 'link 'identity info t) info))))
716 (ert-deftest test-org-export/resolve-id-link ()
717 "Test `org-export-resolve-id-link' specifications."
718 ;; 1. Regular test for custom-id link.
719 (org-test-with-parsed-data "* Headline1
720 :PROPERTIES:
721 :CUSTOM-ID: test
722 :END:
723 * Headline 2
724 \[[#test]]"
725 (should
726 (org-export-resolve-id-link
727 (org-element-map tree 'link 'identity info t) info)))
728 ;; 2. Failing test for custom-id link.
729 (org-test-with-parsed-data "* Headline1
730 :PROPERTIES:
731 :CUSTOM-ID: test
732 :END:
733 * Headline 2
734 \[[#no-match]]"
735 (should-not
736 (org-export-resolve-id-link
737 (org-element-map tree 'link 'identity info t) info)))
738 ;; 3. Test for internal id target.
739 (org-test-with-parsed-data "* Headline1
740 :PROPERTIES:
741 :ID: aaaa
742 :END:
743 * Headline 2
744 \[[id:aaaa]]"
745 (should
746 (org-export-resolve-id-link
747 (org-element-map tree 'link 'identity info t) info)))
748 ;; 4. Test for external id target.
749 (org-test-with-parsed-data "[[id:aaaa]]"
750 (should
751 (org-export-resolve-id-link
752 (org-element-map tree 'link 'identity info t)
753 (org-combine-plists info '(:id-alist (("aaaa" . "external-file"))))))))
755 (ert-deftest test-org-export/resolve-radio-link ()
756 "Test `org-export-resolve-radio-link' specifications."
757 ;; Standard test.
758 (org-test-with-temp-text "<<<radio>>> radio"
759 (org-update-radio-target-regexp)
760 (should
761 (let* ((tree (org-element-parse-buffer))
762 (info `(:parse-tree ,tree)))
763 (org-export-resolve-radio-link
764 (org-element-map tree 'link 'identity info t)
765 info))))
766 ;; Radio target with objects.
767 (org-test-with-temp-text "<<<radio \\alpha>>> radio \\alpha"
768 (org-update-radio-target-regexp)
769 (should
770 (let* ((tree (org-element-parse-buffer))
771 (info `(:parse-tree ,tree)))
772 (org-export-resolve-radio-link
773 (org-element-map tree 'link 'identity info t)
774 info)))))
778 ;;; Macro
780 (ert-deftest test-org-export/define-macro ()
781 "Try defining various Org macro using in-buffer #+MACRO: keyword."
782 ;; Parsed macro.
783 (should (equal (org-test-with-temp-text "#+MACRO: one 1"
784 (org-export-get-inbuffer-options))
785 '(:macro-one ("1"))))
786 ;; Evaled macro.
787 (should (equal (org-test-with-temp-text "#+MACRO: two (eval (+ 1 1))"
788 (org-export-get-inbuffer-options))
789 '(:macro-two ("(eval (+ 1 1))"))))
790 ;; Incomplete macro.
791 (should-not (org-test-with-temp-text "#+MACRO: three"
792 (org-export-get-inbuffer-options)))
793 ;; Macro with newline character.
794 (should (equal (org-test-with-temp-text "#+MACRO: four a\\nb"
795 (org-export-get-inbuffer-options))
796 '(:macro-four ("a\nb"))))
797 ;; Macro with protected newline character.
798 (should (equal (org-test-with-temp-text "#+MACRO: five a\\\\nb"
799 (org-export-get-inbuffer-options))
800 '(:macro-five ("a\\nb"))))
801 ;; Recursive macro.
802 (org-test-with-temp-text "#+MACRO: six 6\n#+MACRO: seven 1 + {{{six}}}"
803 (should
804 (equal
805 (org-export-get-inbuffer-options)
806 '(:macro-six
807 ("6")
808 :macro-seven
809 ("1 + " (macro (:key "six" :value "{{{six}}}" :args nil :begin 5 :end 14
810 :post-blank 0 :parent nil))))))))
812 (ert-deftest test-org-export/expand-macro ()
813 "Test `org-export-expand-macro' specifications."
814 ;; Standard test.
815 (should
816 (equal
817 "some text"
818 (org-test-with-parsed-data "#+MACRO: macro some text\n{{{macro}}}"
819 (org-export-expand-macro
820 (org-element-map tree 'macro 'identity info t) info))))
821 ;; Macro with arguments.
822 (should
823 (equal
824 "some text"
825 (org-test-with-parsed-data "#+MACRO: macro $1 $2\n{{{macro(some,text)}}}"
826 (org-export-expand-macro
827 (org-element-map tree 'macro 'identity info t) info))))
828 ;; Macro with "eval"
829 (should
830 (equal
832 (org-test-with-parsed-data "#+MACRO: add (eval (+ $1 $2))\n{{{add(1,2)}}}"
833 (org-export-expand-macro
834 (org-element-map tree 'macro 'identity info t) info))))
835 ;; Nested macros.
836 (should
837 (equal
838 "inner outer"
839 (org-test-with-parsed-data
840 "#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\n{{{out}}}"
841 (flet ((translate-macro (macro contents info)
842 (org-export-expand-macro macro info)))
843 (org-export-expand-macro
844 (org-element-map tree 'macro 'identity info t)
845 (org-combine-plists
846 info `(:translate-alist ((macro . translate-macro))))))))))
850 ;;; Src-block and example-block
852 (ert-deftest test-org-export/unravel-code ()
853 "Test `org-export-unravel-code' function."
854 (let ((org-coderef-label-format "(ref:%s)"))
855 ;; 1. Code without reference.
856 (org-test-with-temp-text "#+BEGIN_EXAMPLE\n(+ 1 1)\n#+END_EXAMPLE"
857 (should (equal (org-export-unravel-code (org-element-current-element))
858 '("(+ 1 1)\n"))))
859 ;; 2. Code with reference.
860 (org-test-with-temp-text
861 "#+BEGIN_EXAMPLE\n(+ 1 1) (ref:test)\n#+END_EXAMPLE"
862 (should (equal (org-export-unravel-code (org-element-current-element))
863 '("(+ 1 1)\n" (1 . "test")))))
864 ;; 3. Code with user-defined reference.
865 (org-test-with-temp-text
866 "#+BEGIN_EXAMPLE -l \"[ref:%s]\"\n(+ 1 1) [ref:test]\n#+END_EXAMPLE"
867 (should (equal (org-export-unravel-code (org-element-current-element))
868 '("(+ 1 1)\n" (1 . "test")))))
869 ;; 4. Code references keys are relative to the current block.
870 (org-test-with-temp-text "
871 #+BEGIN_EXAMPLE -n
872 \(+ 1 1)
873 #+END_EXAMPLE
874 #+BEGIN_EXAMPLE +n
875 \(+ 2 2)
876 \(+ 3 3) (ref:one)
877 #+END_EXAMPLE"
878 (goto-line 5)
879 (should (equal (org-export-unravel-code (org-element-current-element))
880 '("(+ 2 2)\n(+ 3 3)\n" (2 . "one")))))
881 ;; 5. Free up comma-protected lines.
883 ;; 5.1. In an Org source block, every line is protected.
884 (org-test-with-temp-text
885 "#+BEGIN_SRC org\n,* Test\n,# comment\n,Text\n#+END_SRC"
886 (should (equal (org-export-unravel-code (org-element-current-element))
887 '("* Test\n# comment\nText\n"))))
888 ;; 5.2. In other blocks, only headlines, comments and keywords are
889 ;; protected.
890 (org-test-with-temp-text
891 "#+BEGIN_EXAMPLE\n,* Headline\n, * Not headline\n,Keep\n#+END_EXAMPLE"
892 (should (equal (org-export-unravel-code (org-element-current-element))
893 '("* Headline\n, * Not headline\n,Keep\n"))))))
897 ;;; Tables
899 (ert-deftest test-org-export/special-column ()
900 "Test if the table's special column is properly recognized."
901 ;; 1. First column is special if it contains only a special marking
902 ;; characters or empty cells.
903 (org-test-with-temp-text "
904 | ! | 1 |
905 | | 2 |"
906 (should
907 (org-export-table-has-special-column-p
908 (org-element-map
909 (org-element-parse-buffer) 'table 'identity nil 'first-match))))
910 ;; 2. If the column contains anything else, it isn't special.
911 (org-test-with-temp-text "
912 | ! | 1 |
913 | b | 2 |"
914 (should-not
915 (org-export-table-has-special-column-p
916 (org-element-map
917 (org-element-parse-buffer) 'table 'identity nil 'first-match))))
918 ;; 3. Special marking characters are "#", "^", "*", "_", "/", "$"
919 ;; and "!".
920 (org-test-with-temp-text "
921 | # | 1 |
922 | ^ | 2 |
923 | * | 3 |
924 | _ | 4 |
925 | / | 5 |
926 | $ | 6 |
927 | ! | 7 |"
928 (should
929 (org-export-table-has-special-column-p
930 (org-element-map
931 (org-element-parse-buffer) 'table 'identity nil 'first-match))))
932 ;; 4. A first column with only empty cells isn't considered as
933 ;; special.
934 (org-test-with-temp-text "
935 | | 1 |
936 | | 2 |"
937 (should-not
938 (org-export-table-has-special-column-p
939 (org-element-map
940 (org-element-parse-buffer) 'table 'identity nil 'first-match)))))
942 (ert-deftest test-org-export/table-row-is-special-p ()
943 "Test `org-export-table-row-is-special-p' specifications."
944 ;; 1. A row is special if it has a special marking character in the
945 ;; special column.
946 (org-test-with-parsed-data "| ! | 1 |"
947 (should
948 (org-export-table-row-is-special-p
949 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
950 ;; 2. A row is special when its first field is "/"
951 (org-test-with-parsed-data "
952 | / | 1 |
953 | a | b |"
954 (should
955 (org-export-table-row-is-special-p
956 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
957 ;; 3. A row only containing alignment cookies is also considered as
958 ;; special.
959 (org-test-with-parsed-data "| <5> | | <l> | <l22> |"
960 (should
961 (org-export-table-row-is-special-p
962 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
963 ;; 4. Everything else isn't considered as special.
964 (org-test-with-parsed-data "| \alpha | | c |"
965 (should-not
966 (org-export-table-row-is-special-p
967 (org-element-map tree 'table-row 'identity nil 'first-match) info)))
968 ;; 5. Table's rules are never considered as special rows.
969 (org-test-with-parsed-data "|---+---|"
970 (should-not
971 (org-export-table-row-is-special-p
972 (org-element-map tree 'table-row 'identity nil 'first-match) info))))
974 (ert-deftest test-org-export/has-header-p ()
975 "Test `org-export-table-has-header-p' specifications."
976 ;; 1. With an header.
977 (org-test-with-parsed-data "
978 | a | b |
979 |---+---|
980 | c | d |"
981 (should
982 (org-export-table-has-header-p
983 (org-element-map tree 'table 'identity info 'first-match)
984 info)))
985 ;; 2. Without an header.
986 (org-test-with-parsed-data "
987 | a | b |
988 | c | d |"
989 (should-not
990 (org-export-table-has-header-p
991 (org-element-map tree 'table 'identity info 'first-match)
992 info)))
993 ;; 3. Don't get fooled with starting and ending rules.
994 (org-test-with-parsed-data "
995 |---+---|
996 | a | b |
997 | c | d |
998 |---+---|"
999 (should-not
1000 (org-export-table-has-header-p
1001 (org-element-map tree 'table 'identity info 'first-match)
1002 info))))
1004 (ert-deftest test-org-export/table-row-group ()
1005 "Test `org-export-table-row-group' specifications."
1006 ;; 1. A rule creates a new group.
1007 (org-test-with-parsed-data "
1008 | a | b |
1009 |---+---|
1010 | 1 | 2 |"
1011 (should
1012 (equal
1013 '(1 nil 2)
1014 (mapcar (lambda (row) (org-export-table-row-group row info))
1015 (org-element-map tree 'table-row 'identity)))))
1016 ;; 2. Special rows are ignored in count.
1017 (org-test-with-parsed-data "
1018 | / | < | > |
1019 |---|---+---|
1020 | | 1 | 2 |"
1021 (should
1022 (equal
1023 '(nil nil 1)
1024 (mapcar (lambda (row) (org-export-table-row-group row info))
1025 (org-element-map tree 'table-row 'identity)))))
1026 ;; 3. Double rules also are ignored in count.
1027 (org-test-with-parsed-data "
1028 | a | b |
1029 |---+---|
1030 |---+---|
1031 | 1 | 2 |"
1032 (should
1033 (equal
1034 '(1 nil nil 2)
1035 (mapcar (lambda (row) (org-export-table-row-group row info))
1036 (org-element-map tree 'table-row 'identity))))))
1038 (ert-deftest test-org-export/table-cell-width ()
1039 "Test `org-export-table-cell-width' specifications."
1040 ;; 1. Width is primarily determined by width cookies. If no cookie
1041 ;; is found, cell's width is nil.
1042 (org-test-with-parsed-data "
1043 | / | <l> | <6> | <l7> |
1044 | | a | b | c |"
1045 (should
1046 (equal
1047 '(nil 6 7)
1048 (mapcar (lambda (cell) (org-export-table-cell-width cell info))
1049 (org-element-map tree 'table-cell 'identity info)))))
1050 ;; 2. The last width cookie has precedence.
1051 (org-test-with-parsed-data "
1052 | <6> |
1053 | <7> |
1054 | a |"
1055 (should
1056 (equal
1057 '(7)
1058 (mapcar (lambda (cell) (org-export-table-cell-width cell info))
1059 (org-element-map tree 'table-cell 'identity info)))))
1060 ;; 3. Valid width cookies must have a specific row.
1061 (org-test-with-parsed-data "| <6> | cell |"
1062 (should
1063 (equal
1064 '(nil nil)
1065 (mapcar (lambda (cell) (org-export-table-cell-width cell info))
1066 (org-element-map tree 'table-cell 'identity))))))
1068 (ert-deftest test-org-export/table-cell-alignment ()
1069 "Test `org-export-table-cell-alignment' specifications."
1070 (let ((org-table-number-fraction 0.5)
1071 (org-table-number-regexp "^[0-9]+$"))
1072 ;; 1. Alignment is primarily determined by alignment cookies.
1073 (org-test-with-temp-text "| <l> | <c> | <r> |"
1074 (let* ((tree (org-element-parse-buffer))
1075 (info `(:parse-tree ,tree)))
1076 (should
1077 (equal
1078 '(left center right)
1079 (mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
1080 (org-element-map tree 'table-cell 'identity))))))
1081 ;; 2. The last alignment cookie has precedence.
1082 (org-test-with-parsed-data "
1083 | <l8> |
1084 | cell |
1085 | <r9> |"
1086 (should
1087 (equal
1088 '(right right right)
1089 (mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
1090 (org-element-map tree 'table-cell 'identity)))))
1091 ;; 3. If there's no cookie, cell's contents determine alignment.
1092 ;; A column mostly made of cells containing numbers will align
1093 ;; its cells to the right.
1094 (org-test-with-parsed-data "
1095 | 123 |
1096 | some text |
1097 | 12345 |"
1098 (should
1099 (equal
1100 '(right right right)
1101 (mapcar (lambda (cell)
1102 (org-export-table-cell-alignment cell info))
1103 (org-element-map tree 'table-cell 'identity)))))
1104 ;; 4. Otherwise, they will be aligned to the left.
1105 (org-test-with-parsed-data "
1106 | text |
1107 | some text |
1108 | \alpha |"
1109 (should
1110 (equal
1111 '(left left left)
1112 (mapcar (lambda (cell)
1113 (org-export-table-cell-alignment cell info))
1114 (org-element-map tree 'table-cell 'identity)))))))
1116 (ert-deftest test-org-export/table-cell-borders ()
1117 "Test `org-export-table-cell-borders' specifications."
1118 ;; 1. Recognize various column groups indicators.
1119 (org-test-with-parsed-data "| / | < | > | <> |"
1120 (should
1121 (equal
1122 '((right bottom top) (left bottom top) (right bottom top)
1123 (right left bottom top))
1124 (mapcar (lambda (cell)
1125 (org-export-table-cell-borders cell info))
1126 (org-element-map tree 'table-cell 'identity)))))
1127 ;; 2. Accept shortcuts to define column groups.
1128 (org-test-with-parsed-data "| / | < | < |"
1129 (should
1130 (equal
1131 '((right bottom top) (right left bottom top) (left bottom top))
1132 (mapcar (lambda (cell)
1133 (org-export-table-cell-borders cell info))
1134 (org-element-map tree 'table-cell 'identity)))))
1135 ;; 3. A valid column groups row must start with a "/".
1136 (org-test-with-parsed-data "
1137 | | < |
1138 | a | b |"
1139 (should
1140 (equal '((top) (top) (bottom) (bottom))
1141 (mapcar (lambda (cell)
1142 (org-export-table-cell-borders cell info))
1143 (org-element-map tree 'table-cell 'identity)))))
1144 ;; 4. Take table rules into consideration.
1145 (org-test-with-parsed-data "
1146 | 1 |
1147 |---|
1148 | 2 |"
1149 (should
1150 (equal '((below top) (bottom above))
1151 (mapcar (lambda (cell)
1152 (org-export-table-cell-borders cell info))
1153 (org-element-map tree 'table-cell 'identity)))))
1154 ;; 5. Top and (resp. bottom) rules induce both `top' and `above'
1155 ;; (resp. `bottom' and `below') borders. Any special row is
1156 ;; ignored.
1157 (org-test-with-parsed-data "
1158 |---+----|
1159 | / | |
1160 | | 1 |
1161 |---+----|"
1162 (should
1163 (equal '((bottom below top above))
1164 (last
1165 (mapcar (lambda (cell)
1166 (org-export-table-cell-borders cell info))
1167 (org-element-map tree 'table-cell 'identity)))))))
1169 (ert-deftest test-org-export/table-dimensions ()
1170 "Test `org-export-table-dimensions' specifications."
1171 ;; 1. Standard test.
1172 (org-test-with-parsed-data "
1173 | 1 | 2 | 3 |
1174 | 4 | 5 | 6 |"
1175 (should
1176 (equal '(2 . 3)
1177 (org-export-table-dimensions
1178 (org-element-map tree 'table 'identity info 'first-match) info))))
1179 ;; 2. Ignore horizontal rules and special columns.
1180 (org-test-with-parsed-data "
1181 | / | < | > |
1182 | 1 | 2 | 3 |
1183 |---+---+---|
1184 | 4 | 5 | 6 |"
1185 (should
1186 (equal '(2 . 3)
1187 (org-export-table-dimensions
1188 (org-element-map tree 'table 'identity info 'first-match) info)))))
1190 (ert-deftest test-org-export/table-cell-address ()
1191 "Test `org-export-table-cell-address' specifications."
1192 ;; 1. Standard test: index is 0-based.
1193 (org-test-with-parsed-data "| a | b |"
1194 (should
1195 (equal '((0 . 0) (0 . 1))
1196 (org-element-map
1197 tree 'table-cell
1198 (lambda (cell) (org-export-table-cell-address cell info))
1199 info))))
1200 ;; 2. Special column isn't counted, nor are special rows.
1201 (org-test-with-parsed-data "
1202 | / | <> |
1203 | | c |"
1204 (should
1205 (equal '(0 . 0)
1206 (org-export-table-cell-address
1207 (car (last (org-element-map tree 'table-cell 'identity info)))
1208 info))))
1209 ;; 3. Tables rules do not count either.
1210 (org-test-with-parsed-data "
1211 | a |
1212 |---|
1213 | b |
1214 |---|
1215 | c |"
1216 (should
1217 (equal '(2 . 0)
1218 (org-export-table-cell-address
1219 (car (last (org-element-map tree 'table-cell 'identity info)))
1220 info))))
1221 ;; 4. Return nil for special cells.
1222 (org-test-with-parsed-data "| / | a |"
1223 (should-not
1224 (org-export-table-cell-address
1225 (org-element-map tree 'table-cell 'identity nil 'first-match)
1226 info))))
1228 (ert-deftest test-org-export/get-table-cell-at ()
1229 "Test `org-export-get-table-cell-at' specifications."
1230 ;; 1. Address ignores special columns, special rows and rules.
1231 (org-test-with-parsed-data "
1232 | / | <> |
1233 | | a |
1234 |---+----|
1235 | | b |"
1236 (should
1237 (equal '("b")
1238 (org-element-contents
1239 (org-export-get-table-cell-at
1240 '(1 . 0)
1241 (org-element-map tree 'table 'identity info 'first-match)
1242 info)))))
1243 ;; 2. Return value for a non-existent address is nil.
1244 (org-test-with-parsed-data "| a |"
1245 (should-not
1246 (org-export-get-table-cell-at
1247 '(2 . 2)
1248 (org-element-map tree 'table 'identity info 'first-match)
1249 info)))
1250 (org-test-with-parsed-data "| / |"
1251 (should-not
1252 (org-export-get-table-cell-at
1253 '(0 . 0)
1254 (org-element-map tree 'table 'identity info 'first-match)
1255 info))))
1257 (ert-deftest test-org-export/table-cell-starts-colgroup-p ()
1258 "Test `org-export-table-cell-starts-colgroup-p' specifications."
1259 ;; 1. A cell at a beginning of a row always starts a column group.
1260 (org-test-with-parsed-data "| a |"
1261 (should
1262 (org-export-table-cell-starts-colgroup-p
1263 (org-element-map tree 'table-cell 'identity info 'first-match)
1264 info)))
1265 ;; 2. Special column should be ignored when determining the
1266 ;; beginning of the row.
1267 (org-test-with-parsed-data "
1268 | / | |
1269 | | a |"
1270 (should
1271 (org-export-table-cell-starts-colgroup-p
1272 (org-element-map tree 'table-cell 'identity info 'first-match)
1273 info)))
1274 ;; 2. Explicit column groups.
1275 (org-test-with-parsed-data "
1276 | / | | < |
1277 | a | b | c |"
1278 (should
1279 (equal
1280 '(yes no yes)
1281 (org-element-map
1282 tree 'table-cell
1283 (lambda (cell)
1284 (if (org-export-table-cell-starts-colgroup-p cell info) 'yes 'no))
1285 info)))))
1287 (ert-deftest test-org-export/table-cell-ends-colgroup-p ()
1288 "Test `org-export-table-cell-ends-colgroup-p' specifications."
1289 ;; 1. A cell at the end of a row always ends a column group.
1290 (org-test-with-parsed-data "| a |"
1291 (should
1292 (org-export-table-cell-ends-colgroup-p
1293 (org-element-map tree 'table-cell 'identity info 'first-match)
1294 info)))
1295 ;; 2. Special column should be ignored when determining the
1296 ;; beginning of the row.
1297 (org-test-with-parsed-data "
1298 | / | |
1299 | | a |"
1300 (should
1301 (org-export-table-cell-ends-colgroup-p
1302 (org-element-map tree 'table-cell 'identity info 'first-match)
1303 info)))
1304 ;; 3. Explicit column groups.
1305 (org-test-with-parsed-data "
1306 | / | < | |
1307 | a | b | c |"
1308 (should
1309 (equal
1310 '(yes no yes)
1311 (org-element-map
1312 tree 'table-cell
1313 (lambda (cell)
1314 (if (org-export-table-cell-ends-colgroup-p cell info) 'yes 'no))
1315 info)))))
1317 (ert-deftest test-org-export/table-row-starts-rowgroup-p ()
1318 "Test `org-export-table-row-starts-rowgroup-p' specifications."
1319 ;; 1. A row at the beginning of a table always starts a row group.
1320 ;; So does a row following a table rule.
1321 (org-test-with-parsed-data "
1322 | a |
1323 |---|
1324 | b |"
1325 (should
1326 (equal
1327 '(yes no yes)
1328 (org-element-map
1329 tree 'table-row
1330 (lambda (row)
1331 (if (org-export-table-row-starts-rowgroup-p row info) 'yes 'no))
1332 info))))
1333 ;; 2. Special rows should be ignored when determining the beginning
1334 ;; of the row.
1335 (org-test-with-parsed-data "
1336 | / | < |
1337 | | a |
1338 |---+---|
1339 | / | < |
1340 | | b |"
1341 (should
1342 (equal
1343 '(yes no yes)
1344 (org-element-map
1345 tree 'table-row
1346 (lambda (row)
1347 (if (org-export-table-row-starts-rowgroup-p row info) 'yes 'no))
1348 info)))))
1350 (ert-deftest test-org-export/table-row-ends-rowgroup-p ()
1351 "Test `org-export-table-row-ends-rowgroup-p' specifications."
1352 ;; 1. A row at the end of a table always ends a row group. So does
1353 ;; a row preceding a table rule.
1354 (org-test-with-parsed-data "
1355 | a |
1356 |---|
1357 | b |"
1358 (should
1359 (equal
1360 '(yes no yes)
1361 (org-element-map
1362 tree 'table-row
1363 (lambda (row)
1364 (if (org-export-table-row-ends-rowgroup-p row info) 'yes 'no))
1365 info))))
1366 ;; 2. Special rows should be ignored when determining the beginning
1367 ;; of the row.
1368 (org-test-with-parsed-data "
1369 | | a |
1370 | / | < |
1371 |---+---|
1372 | | b |
1373 | / | < |"
1374 (should
1375 (equal
1376 '(yes no yes)
1377 (org-element-map
1378 tree 'table-row
1379 (lambda (row)
1380 (if (org-export-table-row-ends-rowgroup-p row info) 'yes 'no))
1381 info)))))
1383 (ert-deftest test-org-export/table-row-starts-header-p ()
1384 "Test `org-export-table-row-starts-header-p' specifications."
1385 ;; 1. Only the row starting the first row group starts the table
1386 ;; header.
1387 (org-test-with-parsed-data "
1388 | a |
1389 | b |
1390 |---|
1391 | c |"
1392 (should
1393 (equal
1394 '(yes no no no)
1395 (org-element-map
1396 tree 'table-row
1397 (lambda (row)
1398 (if (org-export-table-row-starts-header-p row info) 'yes 'no))
1399 info))))
1400 ;; 2. A row cannot start an header if there's no header in the
1401 ;; table.
1402 (org-test-with-parsed-data "
1403 | a |
1404 |---|"
1405 (should-not
1406 (org-export-table-row-starts-header-p
1407 (org-element-map tree 'table-row 'identity info 'first-match)
1408 info))))
1410 (ert-deftest test-org-export/table-row-ends-header-p ()
1411 "Test `org-export-table-row-ends-header-p' specifications."
1412 ;; 1. Only the row starting the first row group starts the table
1413 ;; header.
1414 (org-test-with-parsed-data "
1415 | a |
1416 | b |
1417 |---|
1418 | c |"
1419 (should
1420 (equal
1421 '(no yes no no)
1422 (org-element-map
1423 tree 'table-row
1424 (lambda (row)
1425 (if (org-export-table-row-ends-header-p row info) 'yes 'no))
1426 info))))
1427 ;; 2. A row cannot start an header if there's no header in the
1428 ;; table.
1429 (org-test-with-parsed-data "
1430 | a |
1431 |---|"
1432 (should-not
1433 (org-export-table-row-ends-header-p
1434 (org-element-map tree 'table-row 'identity info 'first-match)
1435 info))))
1438 (provide 'test-org-export)
1439 ;;; test-org-export.el end here