test-org-capture.el 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. ;;; test-org-capture.el --- Tests for org-capture.el -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2015, 2017 Nicolas Goaziou
  3. ;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
  4. ;; This program is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. ;;; Commentary:
  15. ;; Unit tests for Org Capture library.
  16. ;;; Code:
  17. (require 'org-capture)
  18. (ert-deftest test-org-capture/fill-template ()
  19. "Test `org-capture-fill-template' specifications."
  20. ;; When working on these tests consider to also change
  21. ;; `test-org-feed/fill-template'.
  22. ;; %(sexp) placeholder.
  23. (should
  24. (equal "success!\n"
  25. (org-capture-fill-template "%(concat \"success\" \"!\")")))
  26. ;; It is possible to include other place holders in %(sexp). In
  27. ;; that case properly escape \ and " characters.
  28. (should
  29. (equal "Nested string \"\\\"\\\"\"\n"
  30. (let ((org-store-link-plist nil))
  31. (org-capture-fill-template "%(concat \"%i\")"
  32. "Nested string \"\\\"\\\"\""))))
  33. ;; %<...> placeholder.
  34. (should
  35. (equal (concat (format-time-string "%Y") "\n")
  36. (org-capture-fill-template "%<%Y>")))
  37. ;; %t and %T placeholders.
  38. (should
  39. (equal (concat (format-time-string (org-time-stamp-format nil nil)) "\n")
  40. (org-capture-fill-template "%t")))
  41. (should
  42. (equal (concat (format-time-string (org-time-stamp-format t nil)) "\n")
  43. (org-capture-fill-template "%T")))
  44. ;; %u and %U placeholders.
  45. (should
  46. (equal
  47. (concat (format-time-string (org-time-stamp-format nil t)) "\n")
  48. (org-capture-fill-template "%u")))
  49. (should
  50. (equal
  51. (concat (format-time-string (org-time-stamp-format t t)) "\n")
  52. (org-capture-fill-template "%U")))
  53. ;; %i placeholder. Make sure sexp placeholders are not expanded
  54. ;; when they are inserted through this one.
  55. (should
  56. (equal "success!\n"
  57. (let ((org-store-link-plist nil))
  58. (org-capture-fill-template "%i" "success!"))))
  59. (should
  60. (equal "%(concat \"no \" \"evaluation\")\n"
  61. (let ((org-store-link-plist nil))
  62. (org-capture-fill-template
  63. "%i" "%(concat \"no \" \"evaluation\")"))))
  64. ;; When %i contents span over multiple line, repeat initial leading
  65. ;; characters over each line.
  66. (should
  67. (equal "> line 1\n> line 2\n"
  68. (let ((org-store-link-plist nil))
  69. (org-capture-fill-template "> %i" "line 1\nline 2"))))
  70. ;; Test %-escaping with \ character.
  71. (should
  72. (equal "%i\n"
  73. (let ((org-store-link-plist nil))
  74. (org-capture-fill-template "\\%i" "success!"))))
  75. (should
  76. (equal "\\success!\n"
  77. (let ((org-store-link-plist nil))
  78. (org-capture-fill-template "\\\\%i" "success!"))))
  79. (should
  80. (equal "\\%i\n"
  81. (let ((org-store-link-plist nil))
  82. (org-capture-fill-template "\\\\\\%i" "success!"))))
  83. ;; More than one placeholder in the same template.
  84. (should
  85. (equal "success! success! success! success!\n"
  86. (let ((org-store-link-plist nil))
  87. (org-capture-fill-template "%i %i %i %i" "success!"))))
  88. ;; %(sexp) placeholder with an input containing the traps %, " and )
  89. ;; all at once which is complicated to parse.
  90. (should
  91. (equal "5 % Less (See Item \"3)\" Somewhere)\n"
  92. (let ((org-store-link-plist nil))
  93. (org-capture-fill-template
  94. "%(capitalize \"%i\")"
  95. "5 % less (see item \"3)\" somewhere)")))))
  96. (ert-deftest test-org-capture/refile ()
  97. "Test `org-capture-refile' specifications."
  98. ;; When refiling, make sure the headline being refiled is the one
  99. ;; being captured. In particular, empty lines after the entry may
  100. ;; be removed, and we don't want to shift onto the next heading.
  101. (should
  102. (string-prefix-p
  103. "** H1"
  104. (org-test-with-temp-text-in-file "* A\n* B\n"
  105. (let* ((file (buffer-file-name))
  106. (org-capture-templates
  107. `(("t" "Todo" entry (file+headline ,file "A") "** H1 %?"))))
  108. (org-capture nil "t")
  109. (insert "\n")
  110. (cl-letf (((symbol-function 'org-refile)
  111. (lambda ()
  112. (interactive)
  113. (throw :return
  114. (buffer-substring-no-properties
  115. (line-beginning-position)
  116. (line-end-position))))))
  117. (catch :return (org-capture-refile)))))))
  118. ;; When the entry is refiled, `:jump-to-captured' moves point to the
  119. ;; refile location, not the initial capture target.
  120. (should
  121. (org-test-with-temp-text-in-file "* Refile target"
  122. (let ((file1 (buffer-file-name)))
  123. (org-test-with-temp-text-in-file "* A"
  124. (let* ((file2 (buffer-file-name))
  125. (org-capture-templates
  126. `(("t" "Todo" entry (file+headline ,file2 "A")
  127. "** H1 %?" :jump-to-captured t))))
  128. (org-capture nil "t")
  129. (cl-letf (((symbol-function 'org-refile-get-location)
  130. (lambda (&rest args)
  131. (list (file-name-nondirectory file1) file1 nil nil))))
  132. (org-capture-refile)
  133. (list file1 file2 (buffer-file-name)))))))))
  134. (ert-deftest test-org-capture/abort ()
  135. "Test aborting a capture process."
  136. ;; Test that capture can be aborted after inserting at end of
  137. ;; capture buffer.
  138. (should
  139. (equal
  140. "* A\n* B\n"
  141. (org-test-with-temp-text-in-file "* A\n* B\n"
  142. (let* ((file (buffer-file-name))
  143. (org-capture-templates
  144. `(("t" "Todo" entry (file+headline ,file "A") "** H1 %?"))))
  145. (org-capture nil "t")
  146. (goto-char (point-max))
  147. (insert "Capture text")
  148. (org-capture-kill))
  149. (buffer-string))))
  150. (should
  151. (equal "| a |\n| b |"
  152. (org-test-with-temp-text-in-file "| a |\n| b |"
  153. (let* ((file (buffer-file-name))
  154. (org-capture-templates
  155. `(("t" "Table" table-line (file ,file) "| x |"))))
  156. (org-capture nil "t")
  157. (org-capture-kill))
  158. (buffer-string))))
  159. ;; Test aborting a capture that split the line.
  160. (should
  161. (equal
  162. "* AB\n"
  163. (org-test-with-temp-text-in-file "* AB\n"
  164. (let* ((file (buffer-file-name))
  165. (org-capture-templates
  166. `(("t" "Todo" entry
  167. (file+function ,file (lambda () (goto-char 4))) "** H1 %?"))))
  168. (org-capture nil "t")
  169. (org-capture-kill))
  170. (buffer-string)))))
  171. (ert-deftest test-org-caputre/entry ()
  172. "Test `entry' type in capture template."
  173. ;; Do not break next headline.
  174. (should
  175. (equal
  176. "* A\n** H1 Capture text\n* B\n"
  177. (org-test-with-temp-text-in-file "* A\n* B\n"
  178. (let* ((file (buffer-file-name))
  179. (org-capture-templates
  180. `(("t" "Todo" entry (file+headline ,file "A") "** H1 %?"))))
  181. (org-capture nil "t")
  182. (goto-char (point-max))
  183. (insert "Capture text")
  184. (org-capture-finalize))
  185. (buffer-string)))))
  186. (ert-deftest test-org-capture/table-line ()
  187. "Test `table-line' type in capture template."
  188. ;; When a only file is specified, use the first table available.
  189. (should
  190. (equal "Text
  191. | a |
  192. | x |
  193. | b |"
  194. (org-test-with-temp-text-in-file "Text\n\n| a |\n\n| b |"
  195. (let* ((file (buffer-file-name))
  196. (org-capture-templates
  197. `(("t" "Table" table-line (file ,file) "| x |"
  198. :immediate-finish t))))
  199. (org-capture nil "t"))
  200. (buffer-string))))
  201. ;; When an entry is specified, find the first table in the
  202. ;; corresponding section.
  203. (should
  204. (equal "* Foo
  205. | a |
  206. * Inbox
  207. | b |
  208. | x |
  209. "
  210. (org-test-with-temp-text-in-file "* Foo\n| a |\n* Inbox\n| b |\n"
  211. (let* ((file (buffer-file-name))
  212. (org-capture-templates
  213. `(("t" "Table" table-line (file+headline ,file "Inbox")
  214. "| x |" :immediate-finish t))))
  215. (org-capture nil "t"))
  216. (buffer-string))))
  217. (should
  218. (equal "* Inbox
  219. | a |
  220. | x |
  221. | b |
  222. "
  223. (org-test-with-temp-text-in-file "* Inbox\n| a |\n\n| b |\n"
  224. (let* ((file (buffer-file-name))
  225. (org-capture-templates
  226. `(("t" "Table" table-line (file+headline ,file "Inbox")
  227. "| x |" :immediate-finish t))))
  228. (org-capture nil "t"))
  229. (buffer-string))))
  230. ;; When a precise location is specified, find the first table after
  231. ;; point, down to the end of the section.
  232. (should
  233. (equal "| a |
  234. | b |
  235. | x |
  236. "
  237. (org-test-with-temp-text-in-file "| a |\n\n\n| b |\n"
  238. (let* ((file (buffer-file-name))
  239. (org-capture-templates
  240. `(("t" "Table" table-line (file+function ,file forward-line)
  241. "| x |" :immediate-finish t))))
  242. (org-capture nil "t"))
  243. (buffer-string))))
  244. ;; Create a new table with an empty header when none can be found.
  245. (should
  246. (equal "| | |\n|---+---|\n| a | b |\n"
  247. (org-test-with-temp-text-in-file ""
  248. (let* ((file (buffer-file-name))
  249. (org-capture-templates
  250. `(("t" "Table" table-line (file ,file) "| a | b |"
  251. :immediate-finish t))))
  252. (org-capture nil "t"))
  253. (buffer-string))))
  254. ;; Properly insert row with formulas.
  255. (should
  256. (equal "| 1 |\n| 2 |\n#+TBLFM: "
  257. (org-test-with-temp-text-in-file "| 1 |\n#+TBLFM: "
  258. (let* ((file (buffer-file-name))
  259. (org-capture-templates
  260. `(("t" "Table" table-line (file ,file)
  261. "| 2 |" :immediate-finish t))))
  262. (org-capture nil "t"))
  263. (buffer-string))))
  264. ;; When `:prepend' is nil, add the row at the end of the table.
  265. (should
  266. (equal "| a |\n| x |\n"
  267. (org-test-with-temp-text-in-file "| a |"
  268. (let* ((file (buffer-file-name))
  269. (org-capture-templates
  270. `(("t" "Table" table-line (file ,file)
  271. "| x |" :immediate-finish t))))
  272. (org-capture nil "t"))
  273. (buffer-string))))
  274. ;; When `:prepend' is non-nil, add it as the first row after the
  275. ;; header, if there is one, or the first row otherwise.
  276. (should
  277. (equal "| a |\n|---|\n| x |\n| b |"
  278. (org-test-with-temp-text-in-file "| a |\n|---|\n| b |"
  279. (let* ((file (buffer-file-name))
  280. (org-capture-templates
  281. `(("t" "Table" table-line (file ,file)
  282. "| x |" :immediate-finish t :prepend t))))
  283. (org-capture nil "t"))
  284. (buffer-string))))
  285. (should
  286. (equal "| x |\n| a |"
  287. (org-test-with-temp-text-in-file "| a |"
  288. (let* ((file (buffer-file-name))
  289. (org-capture-templates
  290. `(("t" "Table" table-line (file ,file)
  291. "| x |" :immediate-finish t :prepend t))))
  292. (org-capture nil "t"))
  293. (buffer-string))))
  294. ;; When `:table-line-pos' is set and is meaningful, obey it.
  295. (should
  296. (equal "| a |\n|---|\n| b |\n| x |\n|---|\n| c |"
  297. (org-test-with-temp-text-in-file "| a |\n|---|\n| b |\n|---|\n| c |"
  298. (let* ((file (buffer-file-name))
  299. (org-capture-templates
  300. `(("t" "Table" table-line (file ,file)
  301. "| x |" :immediate-finish t :table-line-pos "II-1"))))
  302. (org-capture nil "t"))
  303. (buffer-string))))
  304. (should
  305. (equal "| a |\n|---|\n| x |\n| b |\n|---|\n| c |"
  306. (org-test-with-temp-text-in-file "| a |\n|---|\n| b |\n|---|\n| c |"
  307. (let* ((file (buffer-file-name))
  308. (org-capture-templates
  309. `(("t" "Table" table-line (file ,file)
  310. "| x |" :immediate-finish t :table-line-pos "I+1"))))
  311. (org-capture nil "t"))
  312. (buffer-string))))
  313. ;; Throw an error on invalid `:table-line-pos' specifications.
  314. (should-error
  315. (org-test-with-temp-text-in-file "| a |"
  316. (let* ((file (buffer-file-name))
  317. (org-capture-templates
  318. `(("t" "Table" table-line (file ,file)
  319. "| x |" :immediate-finish t :table-line-pos "II+99"))))
  320. (org-capture nil "t")
  321. t)))
  322. ;; Update formula when capturing one or more rows.
  323. (should
  324. (equal
  325. '(("@3$1" . "9"))
  326. (org-test-with-temp-text-in-file "| 1 |\n|---|\n| 9 |\n#+tblfm: @2$1=9"
  327. (let* ((file (buffer-file-name))
  328. (org-capture-templates
  329. `(("t" "Table" table-line (file ,file)
  330. "| 2 |" :immediate-finish t :table-line-pos "I-1"))))
  331. (org-capture nil "t")
  332. (org-table-get-stored-formulas)))))
  333. (should
  334. (equal
  335. '(("@4$1" . "9"))
  336. (org-test-with-temp-text-in-file "| 1 |\n|---|\n| 9 |\n#+tblfm: @2$1=9"
  337. (let* ((file (buffer-file-name))
  338. (org-capture-templates
  339. `(("t" "Table" table-line (file ,file)
  340. "| 2 |\n| 3 |" :immediate-finish t :table-line-pos "I-1"))))
  341. (org-capture nil "t")
  342. (org-table-get-stored-formulas)))))
  343. ;; Do not update formula when cell in inserted below affected row.
  344. (should-not
  345. (equal
  346. '(("@3$1" . "9"))
  347. (org-test-with-temp-text-in-file "| 1 |\n|---|\n| 9 |\n#+tblfm: @2$1=9"
  348. (let* ((file (buffer-file-name))
  349. (org-capture-templates
  350. `(("t" "Table" table-line (file ,file)
  351. "| 2 |" :immediate-finish t))))
  352. (org-capture nil "t")
  353. (org-table-get-stored-formulas))))))
  354. (ert-deftest test-org-capture/plain ()
  355. "Test `plain' type in capture template."
  356. ;; Insert at end of the file, unless `:prepend' is non-nil.
  357. (should
  358. (equal "Some text.\nFoo\n"
  359. (org-test-with-temp-text-in-file "Some text."
  360. (let* ((file (buffer-file-name))
  361. (org-capture-templates
  362. `(("t" "Text" plain (file ,file) "Foo"
  363. :immediate-finish t))))
  364. (org-capture nil "t")
  365. (buffer-string)))))
  366. (should
  367. (equal "Foo\nSome text."
  368. (org-test-with-temp-text-in-file "Some text."
  369. (let* ((file (buffer-file-name))
  370. (org-capture-templates
  371. `(("t" "Text" plain (file ,file) "Foo"
  372. :immediate-finish t :prepend t))))
  373. (org-capture nil "t")
  374. (buffer-string)))))
  375. ;; When a headline is specified, add it at the beginning of the
  376. ;; entry, past any meta-data, or at its end, depending on
  377. ;; `:prepend'.
  378. (should
  379. (equal "* A\nSCHEDULED: <2012-03-29 Thu>\nSome text.\nFoo\n* B"
  380. (org-test-with-temp-text-in-file
  381. "* A\nSCHEDULED: <2012-03-29 Thu>\nSome text.\n* B"
  382. (let* ((file (buffer-file-name))
  383. (org-capture-templates
  384. `(("t" "Text" plain (file+headline ,file "A") "Foo"
  385. :immediate-finish t))))
  386. (org-capture nil "t")
  387. (buffer-string)))))
  388. (should
  389. (equal "* A\nSCHEDULED: <2012-03-29 Thu>\nFoo\nSome text.\n* B"
  390. (org-test-with-temp-text-in-file
  391. "* A\nSCHEDULED: <2012-03-29 Thu>\nSome text.\n* B"
  392. (let* ((file (buffer-file-name))
  393. (org-capture-templates
  394. `(("t" "Text" plain (file+headline ,file "A") "Foo"
  395. :immediate-finish t :prepend t))))
  396. (org-capture nil "t")
  397. (buffer-string)))))
  398. ;; At an exact position, in the middle of a line, make sure to
  399. ;; insert text on a line on its own.
  400. (should
  401. (equal "A\nX\nB"
  402. (org-test-with-temp-text-in-file "AB"
  403. (let* ((file (buffer-file-name))
  404. (org-capture-templates
  405. `(("t" "Text" plain (file+function ,file forward-char) "X"
  406. :immediate-finish t))))
  407. (org-capture nil "t")
  408. (buffer-string)))))
  409. ;; Pathological case: insert an empty template in an empty file.
  410. (should
  411. (equal ""
  412. (org-test-with-temp-text-in-file ""
  413. (let* ((file (buffer-file-name))
  414. (org-capture-templates
  415. `(("t" "Text" plain (file ,file) ""
  416. :immediate-finish t))))
  417. (org-capture nil "t")
  418. (buffer-string))))))
  419. (provide 'test-org-capture)
  420. ;;; test-org-capture.el ends here