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