test-org-export.el 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. ;;; test-org-export.el --- Tests for org-export.el
  2. ;; Copyright (C) 2012 Nicolas Goaziou
  3. ;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
  4. ;; Released under the GNU General Public License version 3
  5. ;; see: http://www.gnu.org/licenses/gpl-3.0.html
  6. ;;;; Comments
  7. ;;; Code:
  8. (unless (featurep 'org-export)
  9. (signal 'missing-test-dependency "org-export"))
  10. ;;; Tests
  11. (defmacro org-test-with-backend (backend &rest body)
  12. "Execute body with an export back-end defined.
  13. BACKEND is the name, as a string, of the back-end. BODY is the
  14. body to execute. The defined back-end simply returns parsed data
  15. as Org syntax."
  16. (declare (debug (form body)) (indent 1))
  17. `(flet ,(let (transcoders)
  18. (dolist (type (append org-element-all-elements
  19. org-element-all-objects)
  20. transcoders)
  21. (push `(,(intern (format "org-%s-%s" backend type))
  22. (obj contents info)
  23. (,(intern (format "org-element-%s-interpreter" type))
  24. obj contents))
  25. transcoders)))
  26. ,@body))
  27. (ert-deftest test-org-export/parse-option-keyword ()
  28. "Test reading all standard #+OPTIONS: items."
  29. (should
  30. (equal
  31. (org-export-parse-option-keyword
  32. "H:1 num:t \\n:t timestamp:t arch:t author:t creator:t d:t email:t
  33. *:t e:t ::t f:t pri:t -:t ^:t toc:t |:t tags:t tasks:t <:t todo:t")
  34. '(:headline-levels
  35. 1 :preserve-breaks t :section-numbers t :time-stamp-file t
  36. :with-archived-trees t :with-author t :with-creator t :with-drawers t
  37. :with-email t :with-emphasize t :with-entities t :with-fixed-width t
  38. :with-footnotes t :with-priority t :with-special-strings t
  39. :with-sub-superscript t :with-toc t :with-tables t :with-tags t
  40. :with-tasks t :with-timestamps t :with-todo-keywords t)))
  41. ;; Test some special values.
  42. (should
  43. (equal
  44. (org-export-parse-option-keyword
  45. "arch:headline creator:comment d:(\"TEST\")
  46. ^:{} toc:1 tags:not-in-toc tasks:todo num:2")
  47. '( :section-numbers
  48. 2
  49. :with-archived-trees headline :with-creator comment
  50. :with-drawers ("TEST") :with-sub-superscript {} :with-toc 1
  51. :with-tags not-in-toc :with-tasks todo))))
  52. (ert-deftest test-org-export/get-inbuffer-options ()
  53. "Test reading all standard export keywords."
  54. (should
  55. (equal
  56. (org-test-with-temp-text "#+AUTHOR: Me, Myself and I
  57. #+CREATOR: Idem
  58. #+DATE: Today
  59. #+DESCRIPTION: Testing
  60. #+DESCRIPTION: with two lines
  61. #+EMAIL: some@email.org
  62. #+EXPORT_EXCLUDE_TAGS: noexport invisible
  63. #+KEYWORDS: test
  64. #+LANGUAGE: en
  65. #+EXPORT_SELECT_TAGS: export
  66. #+TITLE: Some title
  67. #+TITLE: with spaces"
  68. (org-export-get-inbuffer-options))
  69. '(:author
  70. "Me, Myself and I" :creator "Idem" :date "Today"
  71. :description "Testing\nwith two lines" :email "some@email.org"
  72. :exclude-tags ("noexport" "invisible") :keywords "test" :language "en"
  73. :select-tags ("export") :title "Some title with spaces"))))
  74. (ert-deftest test-org-export/define-macro ()
  75. "Try defining various Org macro using in-buffer #+MACRO: keyword."
  76. ;; Parsed macro.
  77. (should (equal (org-test-with-temp-text "#+MACRO: one 1"
  78. (org-export-get-inbuffer-options))
  79. '(:macro-one ("1"))))
  80. ;; Evaled macro.
  81. (should (equal (org-test-with-temp-text "#+MACRO: two (eval (+ 1 1))"
  82. (org-export-get-inbuffer-options))
  83. '(:macro-two "(eval (+ 1 1))")))
  84. ;; Incomplete macro.
  85. (should-not (org-test-with-temp-text "#+MACRO: three"
  86. (org-export-get-inbuffer-options)))
  87. ;; Macro with newline character.
  88. (should (equal (org-test-with-temp-text "#+MACRO: four a\\nb"
  89. (org-export-get-inbuffer-options))
  90. '(:macro-four ("a\nb"))))
  91. ;; Macro with protected newline character.
  92. (should (equal (org-test-with-temp-text "#+MACRO: five a\\\\nb"
  93. (org-export-get-inbuffer-options))
  94. '(:macro-five ("a\\nb"))))
  95. ;; Recursive macro.
  96. (org-test-with-temp-text "#+MACRO: six 6\n#+MACRO: seven 1 + {{{six}}}"
  97. (should
  98. (equal
  99. (org-export-get-inbuffer-options)
  100. '(:macro-six
  101. ("6")
  102. :macro-seven
  103. ("1 + " (macro (:key "six" :value "{{{six}}}" :args nil :begin 5 :end 14
  104. :post-blank 0))))))))
  105. (ert-deftest test-org-export/handle-options ()
  106. "Test if export options have an impact on output."
  107. ;; Test exclude tags.
  108. (org-test-with-temp-text "* Head1 :noexport:"
  109. (org-test-with-backend "test"
  110. (should
  111. (equal (org-export-as 'test nil nil nil '(:exclude-tags ("noexport")))
  112. ""))))
  113. ;; Test include tags.
  114. (org-test-with-temp-text "
  115. * Head1
  116. ** Sub-Head1.1 :export:
  117. *** Sub-Head1.1.1
  118. * Head2"
  119. (org-test-with-backend "test"
  120. (should
  121. (string-match
  122. "\\* Head1\n\\*\\* Sub-Head1.1[ \t]+:export:\n\\*\\*\\* Sub-Head1.1.1\n"
  123. (org-export-as 'test nil nil nil '(:select-tags ("export")))))))
  124. ;; Test mixing include tags and exclude tags.
  125. (org-test-with-temp-text "
  126. * Head1 :export:
  127. ** Sub-Head1 :noexport:
  128. ** Sub-Head2
  129. * Head2 :noexport:
  130. ** Sub-Head1 :export:"
  131. (org-test-with-backend "test"
  132. (should
  133. (string-match
  134. "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
  135. (org-export-as
  136. 'test nil nil nil
  137. '(:select-tags ("export") :exclude-tags ("noexport")))))))
  138. ;; Ignore tasks.
  139. (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
  140. (org-test-with-temp-text "* TODO Head1"
  141. (org-test-with-backend "test"
  142. (should (equal (org-export-as 'test nil nil nil '(:with-tasks nil))
  143. "")))))
  144. (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
  145. (org-test-with-temp-text "* TODO Head1"
  146. (org-test-with-backend "test"
  147. (should (equal (org-export-as 'test nil nil nil '(:with-tasks t))
  148. "* TODO Head1\n")))))
  149. ;; Archived tree.
  150. (org-test-with-temp-text "* Head1 :archive:"
  151. (let ((org-archive-tag "archive"))
  152. (org-test-with-backend "test"
  153. (should
  154. (equal (org-export-as 'test nil nil nil '(:with-archived-trees nil))
  155. "")))))
  156. (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
  157. (let ((org-archive-tag "archive"))
  158. (org-test-with-backend "test"
  159. (should
  160. (string-match
  161. "\\* Head1[ \t]+:archive:"
  162. (org-export-as 'test nil nil nil
  163. '(:with-archived-trees headline)))))))
  164. (org-test-with-temp-text "* Head1 :archive:"
  165. (let ((org-archive-tag "archive"))
  166. (org-test-with-backend "test"
  167. (should
  168. (string-match
  169. "\\`\\* Head1[ \t]+:archive:\n\\'"
  170. (org-export-as 'test nil nil nil '(:with-archived-trees t)))))))
  171. ;; Drawers.
  172. (let ((org-drawers '("TEST")))
  173. (org-test-with-temp-text ":TEST:\ncontents\n:END:"
  174. (org-test-with-backend "test"
  175. (should (equal (org-export-as 'test nil nil nil '(:with-drawers nil))
  176. "")))))
  177. (let ((org-drawers '("TEST")))
  178. (org-test-with-temp-text ":TEST:\ncontents\n:END:"
  179. (org-test-with-backend "test"
  180. (should (equal (org-export-as 'test nil nil nil '(:with-drawers t))
  181. ":TEST:\ncontents\n:END:\n"))))))
  182. (ert-deftest test-org-export/comment-tree ()
  183. "Test if export process ignores commented trees."
  184. (let ((org-comment-string "COMMENT"))
  185. (org-test-with-temp-text "* COMMENT Head1"
  186. (org-test-with-backend "test"
  187. (should (equal (org-export-as 'test) ""))))))
  188. (ert-deftest test-org-export/export-scope ()
  189. "Test all export scopes."
  190. (org-test-with-temp-text "
  191. * Head1
  192. ** Head2
  193. text
  194. *** Head3"
  195. (org-test-with-backend "test"
  196. ;; Subtree.
  197. (forward-line 3)
  198. (should (equal (org-export-as 'test 'subtree) "text\n*** Head3\n"))
  199. ;; Visible.
  200. (goto-char (point-min))
  201. (forward-line)
  202. (org-cycle)
  203. (should (equal (org-export-as 'test nil 'visible) "* Head1\n"))
  204. ;; Body only.
  205. (flet ((org-test-template (body info) (format "BEGIN\n%sEND" body)))
  206. (should (equal (org-export-as 'test nil nil 'body-only)
  207. "* Head1\n** Head2\ntext\n*** Head3\n"))
  208. (should (equal (org-export-as 'test)
  209. "BEGIN\n* Head1\n** Head2\ntext\n*** Head3\nEND")))
  210. ;; Region.
  211. (goto-char (point-min))
  212. (forward-line 3)
  213. (mark-paragraph)
  214. (should (equal (org-export-as 'test) "text\n")))))
  215. (ert-deftest test-org-export/export-snippet ()
  216. "Test export snippets transcoding."
  217. (org-test-with-temp-text "@test{A}@t{B}"
  218. (org-test-with-backend "test"
  219. (flet ((org-test-export-snippet
  220. (snippet contents info)
  221. (when (eq (org-export-snippet-backend snippet) 'test)
  222. (org-element-property :value snippet))))
  223. (let ((org-export-snippet-translation-alist nil))
  224. (should (equal (org-export-as 'test) "A\n")))
  225. (let ((org-export-snippet-translation-alist '(("t" . "test"))))
  226. (should (equal (org-export-as 'test) "AB\n")))))))
  227. (ert-deftest test-org-export/expand-include ()
  228. "Test file inclusion in an Org buffer."
  229. ;; Full insertion with recursive inclusion.
  230. (org-test-with-temp-text
  231. (format "#+INCLUDE: \"%s/examples/include.org\"" org-test-dir)
  232. (org-export-expand-include-keyword)
  233. (should (equal (buffer-string)
  234. "Small Org file with an include keyword.
  235. #+BEGIN_SRC emacs-lisp :exports results\n(+ 2 1)\n#+END_SRC
  236. Success!
  237. * Heading
  238. body\n")))
  239. ;; Localized insertion.
  240. (org-test-with-temp-text
  241. (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\""
  242. org-test-dir)
  243. (org-export-expand-include-keyword)
  244. (should (equal (buffer-string)
  245. "Small Org file with an include keyword.\n")))
  246. ;; Insertion with constraints on headlines level.
  247. (org-test-with-temp-text
  248. (format
  249. "* Top heading\n#+INCLUDE: \"%s/examples/include.org\" :lines \"9-\""
  250. org-test-dir)
  251. (org-export-expand-include-keyword)
  252. (should (equal (buffer-string) "* Top heading\n** Heading\nbody\n")))
  253. ;; Inclusion within an example block.
  254. (org-test-with-temp-text
  255. (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\" example"
  256. org-test-dir)
  257. (org-export-expand-include-keyword)
  258. (should
  259. (equal
  260. (buffer-string)
  261. "#+BEGIN_EXAMPLE\nSmall Org file with an include keyword.\n#+END_EXAMPLE\n")))
  262. ;; Inclusion within a src-block.
  263. (org-test-with-temp-text
  264. (format
  265. "#+INCLUDE: \"%s/examples/include.org\" :lines \"4-5\" src emacs-lisp"
  266. org-test-dir)
  267. (org-export-expand-include-keyword)
  268. (should (equal (buffer-string)
  269. "#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n"))))
  270. (ert-deftest test-org-export/user-ignore-list ()
  271. "Test if `:ignore-list' accepts user input."
  272. (org-test-with-backend "test"
  273. (flet ((skip-note-head
  274. (data backend info)
  275. ;; Ignore headlines with the word "note" in their title.
  276. (org-element-map
  277. data 'headline
  278. (lambda (headline)
  279. (when (string-match "\\<note\\>"
  280. (org-element-property :raw-value headline))
  281. (org-export-ignore-element headline info)))
  282. info)
  283. data))
  284. ;; Install function in parse tree filters.
  285. (let ((org-export-filter-parse-tree-functions '(skip-note-head)))
  286. (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
  287. (should (equal (org-export-as 'test) "* Head1\n")))))))
  288. (ert-deftest test-org-export/footnotes ()
  289. "Test footnotes specifications."
  290. (let ((org-footnote-section nil))
  291. ;; 1. Read every type of footnote.
  292. (org-test-with-temp-text
  293. "Text[fn:1] [1] [fn:label:C] [fn::D]\n\n[fn:1] A\n\n[1] B"
  294. (let* ((tree (org-element-parse-buffer))
  295. (info (org-combine-plists
  296. (org-export-initial-options) '(:with-footnotes t))))
  297. (setq info (org-combine-plists
  298. info (org-export-collect-tree-properties tree info 'test)))
  299. (should
  300. (equal
  301. '((1 . "A") (2 . "B") (3 . "C") (4 . "D"))
  302. (org-element-map
  303. tree 'footnote-reference
  304. (lambda (ref)
  305. (let ((def (org-export-get-footnote-definition ref info)))
  306. (cons (org-export-get-footnote-number ref info)
  307. (if (eq (org-element-property :type ref) 'inline) (car def)
  308. (car (org-element-contents
  309. (car (org-element-contents def))))))))
  310. info)))))
  311. ;; 2. Test nested footnotes order.
  312. (org-test-with-temp-text
  313. "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
  314. (let* ((tree (org-element-parse-buffer))
  315. (info (org-combine-plists
  316. (org-export-initial-options) '(:with-footnotes t))))
  317. (setq info (org-combine-plists
  318. info (org-export-collect-tree-properties tree info 'test)))
  319. (should
  320. (equal
  321. '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
  322. (org-element-map
  323. tree 'footnote-reference
  324. (lambda (ref)
  325. (when (org-export-footnote-first-reference-p ref info)
  326. (cons (org-export-get-footnote-number ref info)
  327. (org-element-property :label ref))))
  328. info)))))
  329. ;; 3. Test nested footnote in invisible definitions.
  330. (org-test-with-temp-text "Text[1]\n\n[1] B [2]\n\n[2] C."
  331. ;; Hide definitions.
  332. (narrow-to-region (point) (point-at-eol))
  333. (let* ((tree (org-element-parse-buffer))
  334. (info (org-combine-plists
  335. (org-export-initial-options) '(:with-footnotes t))))
  336. (setq info (org-combine-plists
  337. info (org-export-collect-tree-properties tree info 'test)))
  338. ;; Both footnotes should be seen.
  339. (should
  340. (= (length (org-export-collect-footnote-definitions tree info)) 2))))))
  341. (ert-deftest test-org-export/fuzzy-links ()
  342. "Test fuzz link export specifications."
  343. ;; 1. Links to invisible (keyword) targets should be ignored.
  344. (org-test-with-temp-text
  345. "Paragraph.\n#+TARGET: Test\n[[Test]]"
  346. (let* ((tree (org-element-parse-buffer))
  347. (info (org-combine-plists (org-export-initial-options))))
  348. (setq info (org-combine-plists
  349. info (org-export-collect-tree-properties tree info 'test)))
  350. (should-not
  351. (org-element-map
  352. tree 'link
  353. (lambda (link)
  354. (org-export-get-ordinal
  355. (org-export-resolve-fuzzy-link link info) info)) info))))
  356. ;; 2. Link to an headline should return headline's number.
  357. (org-test-with-temp-text
  358. "Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
  359. (let* ((tree (org-element-parse-buffer))
  360. (info (org-combine-plists (org-export-initial-options))))
  361. (setq info (org-combine-plists
  362. info (org-export-collect-tree-properties tree info 'test)))
  363. (should
  364. ;; Note: Headline's number is in fact a list of numbers.
  365. (equal '(2)
  366. (org-element-map
  367. tree 'link
  368. (lambda (link)
  369. (org-export-get-ordinal
  370. (org-export-resolve-fuzzy-link link info) info)) info t)))))
  371. ;; 3. Link to a target in an item should return item's number.
  372. (org-test-with-temp-text
  373. "- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
  374. (let* ((tree (org-element-parse-buffer))
  375. (info (org-combine-plists (org-export-initial-options))))
  376. (setq info (org-combine-plists
  377. info (org-export-collect-tree-properties tree info 'test)))
  378. (should
  379. ;; Note: Item's number is in fact a list of numbers.
  380. (equal '(1 2)
  381. (org-element-map
  382. tree 'link
  383. (lambda (link)
  384. (org-export-get-ordinal
  385. (org-export-resolve-fuzzy-link link info) info)) info t)))))
  386. ;; 4. Link to a target in a footnote should return footnote's
  387. ;; number.
  388. (org-test-with-temp-text
  389. "Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
  390. (let* ((tree (org-element-parse-buffer))
  391. (info (org-combine-plists (org-export-initial-options))))
  392. (setq info (org-combine-plists
  393. info (org-export-collect-tree-properties tree info 'test)))
  394. (should
  395. (equal '(2 3)
  396. (org-element-map
  397. tree 'link
  398. (lambda (link)
  399. (org-export-get-ordinal
  400. (org-export-resolve-fuzzy-link link info) info)) info)))))
  401. ;; 5. Link to a named element should return sequence number of that
  402. ;; element.
  403. (org-test-with-temp-text
  404. "#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
  405. (let* ((tree (org-element-parse-buffer))
  406. (info (org-combine-plists (org-export-initial-options))))
  407. (setq info (org-combine-plists
  408. info (org-export-collect-tree-properties tree info 'test)))
  409. (should
  410. (= 2
  411. (org-element-map
  412. tree 'link
  413. (lambda (link)
  414. (org-export-get-ordinal
  415. (org-export-resolve-fuzzy-link link info) info)) info t)))))
  416. ;; 6. Link to a target not within an item, a table, a footnote
  417. ;; reference or definition should return section number.
  418. (org-test-with-temp-text
  419. "* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
  420. (let* ((tree (org-element-parse-buffer))
  421. (info (org-combine-plists (org-export-initial-options))))
  422. (setq info (org-combine-plists
  423. info (org-export-collect-tree-properties tree info 'test)))
  424. (should
  425. (equal '(2)
  426. (org-element-map
  427. tree 'link
  428. (lambda (link)
  429. (org-export-get-ordinal
  430. (org-export-resolve-fuzzy-link link info) info)) info t))))))