Undo in region after markers in undo history relocated
[bpt/emacs.git] / test / automated / undo-tests.el
1 ;;; undo-tests.el --- Tests of primitive-undo
2
3 ;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
4
5 ;; Author: Aaron S. Hawley <aaron.s.hawley@gmail.com>
6
7 ;; This program is free software: you can redistribute it and/or
8 ;; modify it under the terms of the GNU General Public License as
9 ;; published by the Free Software Foundation, either version 3 of the
10 ;; License, or (at your option) any later version.
11 ;;
12 ;; This program is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details.
16 ;;
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/'.
19
20 ;;; Commentary:
21
22 ;; Profiling when the code was translate from C to Lisp on 2012-12-24.
23
24 ;;; C
25
26 ;; (elp-instrument-function 'primitive-undo)
27 ;; (load-file "undo-test.elc")
28 ;; (benchmark 100 '(let ((undo-test5-error nil)) (undo-test-all)))
29 ;; Elapsed time: 305.218000s (104.841000s in 14804 GCs)
30 ;; M-x elp-results
31 ;; Function Name Call Count Elapsed Time Average Time
32 ;; primitive-undo 2600 3.4889999999 0.0013419230
33
34 ;;; Lisp
35
36 ;; (load-file "primundo.elc")
37 ;; (elp-instrument-function 'primitive-undo)
38 ;; (benchmark 100 '(undo-test-all))
39 ;; Elapsed time: 295.974000s (104.582000s in 14704 GCs)
40 ;; M-x elp-results
41 ;; Function Name Call Count Elapsed Time Average Time
42 ;; primitive-undo 2700 3.6869999999 0.0013655555
43
44 ;;; Code:
45
46 (require 'ert)
47
48 (ert-deftest undo-test0 ()
49 "Test basics of \\[undo]."
50 (with-temp-buffer
51 (buffer-enable-undo)
52 (condition-case err
53 (undo)
54 (error
55 (unless (string= "No further undo information"
56 (cadr err))
57 (error err))))
58 (undo-boundary)
59 (insert "This")
60 (undo-boundary)
61 (erase-buffer)
62 (undo-boundary)
63 (insert "That")
64 (undo-boundary)
65 (forward-word -1)
66 (undo-boundary)
67 (insert "With ")
68 (undo-boundary)
69 (forward-word -1)
70 (undo-boundary)
71 (kill-word 1)
72 (undo-boundary)
73 (put-text-property (point-min) (point-max) 'face 'bold)
74 (undo-boundary)
75 (remove-text-properties (point-min) (point-max) '(face default))
76 (undo-boundary)
77 (set-buffer-multibyte (not enable-multibyte-characters))
78 (undo-boundary)
79 (undo)
80 (should
81 (equal (should-error (undo-more nil))
82 '(wrong-type-argument number-or-marker-p nil)))
83 (undo-more 7)
84 (should (string-equal "" (buffer-string)))))
85
86 (ert-deftest undo-test1 ()
87 "Test undo of \\[undo] command (redo)."
88 (with-temp-buffer
89 (buffer-enable-undo)
90 (undo-boundary)
91 (insert "This")
92 (undo-boundary)
93 (erase-buffer)
94 (undo-boundary)
95 (insert "That")
96 (undo-boundary)
97 (forward-word -1)
98 (undo-boundary)
99 (insert "With ")
100 (undo-boundary)
101 (forward-word -1)
102 (undo-boundary)
103 (kill-word 1)
104 (undo-boundary)
105 (facemenu-add-face 'bold (point-min) (point-max))
106 (undo-boundary)
107 (set-buffer-multibyte (not enable-multibyte-characters))
108 (undo-boundary)
109 (should
110 (string-equal (buffer-string)
111 (progn
112 (undo)
113 (undo-more 4)
114 (undo)
115 ;(undo-more -4)
116 (buffer-string))))))
117
118 (ert-deftest undo-test2 ()
119 "Test basic redoing with \\[undo] command."
120 (with-temp-buffer
121 (buffer-enable-undo)
122 (undo-boundary)
123 (insert "One")
124 (undo-boundary)
125 (insert " Zero")
126 (undo-boundary)
127 (push-mark nil t)
128 (delete-region (save-excursion
129 (forward-word -1)
130 (point)) (point))
131 (undo-boundary)
132 (beginning-of-line)
133 (insert "Zero")
134 (undo-boundary)
135 (undo)
136 (should
137 (string-equal (buffer-string)
138 (progn
139 (undo-more 2)
140 (undo)
141 (buffer-string))))))
142
143 (ert-deftest undo-test4 ()
144 "Test \\[undo] of \\[flush-lines]."
145 (with-temp-buffer
146 (buffer-enable-undo)
147 (dotimes (i 1048576)
148 (if (zerop (% i 2))
149 (insert "Evenses")
150 (insert "Oddses")))
151 (undo-boundary)
152 (should
153 ;; Avoid string-equal because ERT will save the `buffer-string'
154 ;; to the explanation. Using `not' will record nil or non-nil.
155 (not
156 (null
157 (string-equal (buffer-string)
158 (progn
159 (flush-lines "oddses" (point-min) (point-max))
160 (undo-boundary)
161 (undo)
162 (undo)
163 (buffer-string))))))))
164
165 (ert-deftest undo-test5 ()
166 "Test basic redoing with \\[undo] command."
167 (with-temp-buffer
168 (buffer-enable-undo)
169 (undo-boundary)
170 (insert "AYE")
171 (undo-boundary)
172 (insert " BEE")
173 (undo-boundary)
174 (setq buffer-undo-list (cons '(0.0 bogus) buffer-undo-list))
175 (push-mark nil t)
176 (delete-region (save-excursion
177 (forward-word -1)
178 (point)) (point))
179 (undo-boundary)
180 (beginning-of-line)
181 (insert "CEE")
182 (undo-boundary)
183 (undo)
184 (setq buffer-undo-list (cons "bogus" buffer-undo-list))
185 (should
186 (string-equal
187 (buffer-string)
188 (progn
189 (if (and (boundp 'undo-test5-error) (not undo-test5-error))
190 (progn
191 (should (null (undo-more 2)))
192 (should (undo)))
193 ;; Errors are generated by new Lisp version of
194 ;; `primitive-undo' not by built-in C version.
195 (should
196 (equal (should-error (undo-more 2))
197 '(error "Unrecognized entry in undo list (0.0 bogus)")))
198 (should
199 (equal (should-error (undo))
200 '(error "Unrecognized entry in undo list \"bogus\""))))
201 (buffer-string))))))
202
203 ;; http://debbugs.gnu.org/14824
204 (ert-deftest undo-test-buffer-modified ()
205 "Test undoing marks buffer unmodified."
206 (with-temp-buffer
207 (buffer-enable-undo)
208 (insert "1")
209 (undo-boundary)
210 (set-buffer-modified-p nil)
211 (insert "2")
212 (undo)
213 (should-not (buffer-modified-p))))
214
215 (ert-deftest undo-test-file-modified ()
216 "Test undoing marks buffer visiting file unmodified."
217 (let ((tempfile (make-temp-file "undo-test")))
218 (unwind-protect
219 (progn
220 (with-current-buffer (find-file-noselect tempfile)
221 (insert "1")
222 (undo-boundary)
223 (set-buffer-modified-p nil)
224 (insert "2")
225 (undo)
226 (should-not (buffer-modified-p))))
227 (delete-file tempfile))))
228
229 (ert-deftest undo-test-in-region-not-most-recent ()
230 "Test undo in region of an edit not the most recent."
231 (with-temp-buffer
232 (buffer-enable-undo)
233 (transient-mark-mode 1)
234 (insert "1111")
235 (undo-boundary)
236 (goto-char 2)
237 (insert "2")
238 (forward-char 2)
239 (undo-boundary)
240 (insert "3")
241 (undo-boundary)
242 ;; Highlight around "2", not "3"
243 (push-mark (+ 3 (point-min)) t t)
244 (setq mark-active t)
245 (goto-char (point-min))
246 (undo)
247 (should (string= (buffer-string)
248 "11131"))))
249
250 (ert-deftest undo-test-in-region-eob ()
251 "Test undo in region of a deletion at EOB, demonstrating bug 16411."
252 (with-temp-buffer
253 (buffer-enable-undo)
254 (transient-mark-mode 1)
255 (insert "This sentence corrupted?")
256 (undo-boundary)
257 ;; Same as recipe at
258 ;; http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16411
259 (insert "aaa")
260 (undo-boundary)
261 (undo)
262 ;; Select entire buffer
263 (push-mark (point) t t)
264 (setq mark-active t)
265 (goto-char (point-min))
266 ;; Should undo the undo of "aaa", ie restore it.
267 (undo)
268 (should (string= (buffer-string)
269 "This sentence corrupted?aaa"))))
270
271 (ert-deftest undo-test-marker-adjustment-nominal ()
272 "Test nominal behavior of marker adjustments."
273 (with-temp-buffer
274 (buffer-enable-undo)
275 (insert "abcdefg")
276 (undo-boundary)
277 (let ((m (make-marker)))
278 (set-marker m 2 (current-buffer))
279 (goto-char (point-min))
280 (delete-forward-char 3)
281 (undo-boundary)
282 (should (= (point-min) (marker-position m)))
283 (undo)
284 (undo-boundary)
285 (should (= 2 (marker-position m))))))
286
287 (ert-deftest undo-test-region-t-marker ()
288 "Test undo in region containing marker with t insertion-type."
289 (with-temp-buffer
290 (buffer-enable-undo)
291 (transient-mark-mode 1)
292 (insert "abcdefg")
293 (undo-boundary)
294 (let ((m (make-marker)))
295 (set-marker-insertion-type m t)
296 (set-marker m (point-min) (current-buffer)) ; m at a
297 (goto-char (+ 2 (point-min)))
298 (push-mark (point) t t)
299 (setq mark-active t)
300 (goto-char (point-min))
301 (delete-forward-char 1) ;; delete region covering "ab"
302 (undo-boundary)
303 (should (= (point-min) (marker-position m)))
304 ;; Resurrect "ab". m's insertion type means the reinsertion
305 ;; moves it forward 2, and then the marker adjustment returns it
306 ;; to its rightful place.
307 (undo)
308 (undo-boundary)
309 (should (= (point-min) (marker-position m))))))
310
311 (ert-deftest undo-test-marker-adjustment-moved ()
312 "Test marker adjustment behavior when the marker moves.
313 Demonstrates bug 16818."
314 (with-temp-buffer
315 (buffer-enable-undo)
316 (insert "abcdefghijk")
317 (undo-boundary)
318 (let ((m (make-marker)))
319 (set-marker m 2 (current-buffer)) ; m at b
320 (goto-char (point-min))
321 (delete-forward-char 3) ; m at d
322 (undo-boundary)
323 (set-marker m 4) ; m at g
324 (undo)
325 (undo-boundary)
326 ;; m still at g, but shifted 3 because deletion undone
327 (should (= 7 (marker-position m))))))
328
329 (ert-deftest undo-test-region-mark-adjustment ()
330 "Test that the mark's marker adjustment in undo history doesn't
331 obstruct undo in region from finding the correct change group.
332 Demonstrates bug 16818."
333 (with-temp-buffer
334 (buffer-enable-undo)
335 (transient-mark-mode 1)
336 (insert "First line\n")
337 (insert "Second line\n")
338 (undo-boundary)
339
340 (goto-char (point-min))
341 (insert "aaa")
342 (undo-boundary)
343
344 (undo)
345 (undo-boundary)
346
347 (goto-char (point-max))
348 (insert "bbb")
349 (undo-boundary)
350
351 (push-mark (point) t t)
352 (setq mark-active t)
353 (goto-char (- (point) 3))
354 (delete-forward-char 1)
355 (undo-boundary)
356
357 (insert "bbb")
358 (undo-boundary)
359
360 (goto-char (point-min))
361 (push-mark (point) t t)
362 (setq mark-active t)
363 (goto-char (+ (point) 3))
364 (undo)
365 (undo-boundary)
366
367 (should (string= (buffer-string) "aaaFirst line\nSecond line\nbbb"))))
368
369 (defun undo-test-all (&optional interactive)
370 "Run all tests for \\[undo]."
371 (interactive "p")
372 (if interactive
373 (ert-run-tests-interactively "^undo-")
374 (ert-run-tests-batch "^undo-")))
375
376 (provide 'undo-tests)
377 ;;; undo-tests.el ends here