mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-24 22:40:51 -08:00
dc4e6b1329; Update copyright years in more files64b3777631; Run set-copyright from admin.el8e1c56ae46; Add 2024 to copyright years # Conflicts: # doc/misc/modus-themes.org # doc/misc/texinfo.tex # etc/NEWS # etc/refcards/ru-refcard.tex # etc/themes/modus-operandi-theme.el # etc/themes/modus-themes.el # etc/themes/modus-vivendi-theme.el # lib/alloca.in.h # lib/binary-io.h # lib/c-ctype.h # lib/c-strcasecmp.c # lib/c-strncasecmp.c # lib/careadlinkat.c # lib/cloexec.c # lib/close-stream.c # lib/diffseq.h # lib/dup2.c # lib/filemode.h # lib/fpending.c # lib/fpending.h # lib/fsusage.c # lib/getgroups.c # lib/getloadavg.c # lib/gettext.h # lib/gettime.c # lib/gettimeofday.c # lib/group-member.c # lib/malloc.c # lib/md5-stream.c # lib/md5.c # lib/md5.h # lib/memmem.c # lib/memrchr.c # lib/nanosleep.c # lib/save-cwd.h # lib/sha1.c # lib/sig2str.c # lib/stdlib.in.h # lib/strtoimax.c # lib/strtol.c # lib/strtoll.c # lib/time_r.c # lib/xalloc-oversized.h # lisp/auth-source-pass.el # lisp/emacs-lisp/lisp-mnt.el # lisp/emacs-lisp/timer.el # lisp/info-look.el # lisp/jit-lock.el # lisp/loadhist.el # lisp/mail/rmail.el # lisp/net/ntlm.el # lisp/net/webjump.el # lisp/progmodes/asm-mode.el # lisp/progmodes/project.el # lisp/progmodes/sh-script.el # lisp/textmodes/flyspell.el # lisp/textmodes/reftex-toc.el # lisp/textmodes/reftex.el # lisp/textmodes/tex-mode.el # lisp/url/url-gw.el # m4/alloca.m4 # m4/clock_time.m4 # m4/d-type.m4 # m4/dirent_h.m4 # m4/dup2.m4 # m4/euidaccess.m4 # m4/fchmodat.m4 # m4/filemode.m4 # m4/fsusage.m4 # m4/getgroups.m4 # m4/getloadavg.m4 # m4/getrandom.m4 # m4/gettime.m4 # m4/gettimeofday.m4 # m4/gnulib-common.m4 # m4/group-member.m4 # m4/inttypes.m4 # m4/malloc.m4 # m4/manywarnings.m4 # m4/mempcpy.m4 # m4/memrchr.m4 # m4/mkostemp.m4 # m4/mktime.m4 # m4/nproc.m4 # m4/nstrftime.m4 # m4/pathmax.m4 # m4/pipe2.m4 # m4/pselect.m4 # m4/pthread_sigmask.m4 # m4/readlink.m4 # m4/realloc.m4 # m4/sig2str.m4 # m4/ssize_t.m4 # m4/stat-time.m4 # m4/stddef_h.m4 # m4/stdint.m4 # m4/stdio_h.m4 # m4/stdlib_h.m4 # m4/stpcpy.m4 # m4/strnlen.m4 # m4/strtoimax.m4 # m4/strtoll.m4 # m4/time_h.m4 # m4/timegm.m4 # m4/timer_time.m4 # m4/timespec.m4 # m4/unistd_h.m4 # m4/warnings.m4 # nt/configure.bat # nt/preprep.c # test/lisp/register-tests.el
543 lines
16 KiB
EmacsLisp
543 lines
16 KiB
EmacsLisp
;;; undo-tests.el --- Tests of primitive-undo -*- lexical-binding: t -*-
|
|
|
|
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
|
|
|
;; Author: Aaron S. Hawley <aaron.s.hawley@gmail.com>
|
|
|
|
;; This file is part of GNU Emacs.
|
|
;;
|
|
;; GNU Emacs is free software: you can redistribute it and/or
|
|
;; modify it under the terms of the GNU General Public License as
|
|
;; published by the Free Software Foundation, either version 3 of the
|
|
;; License, or (at your option) any later version.
|
|
;;
|
|
;; GNU Emacs is distributed in the hope that it will be useful, but
|
|
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
;; General Public License for more details.
|
|
;;
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
|
|
;; Profiling when the code was translate from C to Lisp on 2012-12-24.
|
|
|
|
;;; C
|
|
|
|
;; (elp-instrument-function 'primitive-undo)
|
|
;; (load-file "undo-test.elc")
|
|
;; (benchmark 100 '(let ((undo-test5-error nil)) (undo-test-all)))
|
|
;; Elapsed time: 305.218000s (104.841000s in 14804 GCs)
|
|
;; M-x elp-results
|
|
;; Function Name Call Count Elapsed Time Average Time
|
|
;; primitive-undo 2600 3.4889999999 0.0013419230
|
|
|
|
;;; Lisp
|
|
|
|
;; (load-file "primundo.elc")
|
|
;; (elp-instrument-function 'primitive-undo)
|
|
;; (benchmark 100 '(undo-test-all))
|
|
;; Elapsed time: 295.974000s (104.582000s in 14704 GCs)
|
|
;; M-x elp-results
|
|
;; Function Name Call Count Elapsed Time Average Time
|
|
;; primitive-undo 2700 3.6869999999 0.0013655555
|
|
|
|
;;; Code:
|
|
|
|
(require 'ert)
|
|
(require 'ert-x)
|
|
(require 'facemenu)
|
|
|
|
(ert-deftest undo-test0 ()
|
|
"Test basics of \\[undo]."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(condition-case err
|
|
(undo)
|
|
(error
|
|
(unless (string= "No further undo information"
|
|
(cadr err))
|
|
(error err))))
|
|
(undo-boundary)
|
|
(insert "This")
|
|
(undo-boundary)
|
|
(erase-buffer)
|
|
(undo-boundary)
|
|
(insert "That")
|
|
(undo-boundary)
|
|
(forward-word -1)
|
|
(undo-boundary)
|
|
(insert "With ")
|
|
(undo-boundary)
|
|
(forward-word -1)
|
|
(undo-boundary)
|
|
(kill-word 1)
|
|
(undo-boundary)
|
|
(put-text-property (point-min) (point-max) 'face 'bold)
|
|
(undo-boundary)
|
|
(remove-list-of-text-properties (point-min) (point-max) '(face))
|
|
(undo-boundary)
|
|
(set-buffer-multibyte (not enable-multibyte-characters))
|
|
(undo-boundary)
|
|
(undo)
|
|
(should
|
|
(equal (should-error (undo-more nil))
|
|
'(wrong-type-argument number-or-marker-p nil)))
|
|
(undo-more 7)
|
|
(should (string-equal "" (buffer-string)))))
|
|
|
|
(ert-deftest undo-test1 ()
|
|
"Test undo of \\[undo] command (redo)."
|
|
(require 'facemenu)
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(undo-boundary)
|
|
(insert "This")
|
|
(undo-boundary)
|
|
(erase-buffer)
|
|
(undo-boundary)
|
|
(insert "That")
|
|
(undo-boundary)
|
|
(forward-word -1)
|
|
(undo-boundary)
|
|
(insert "With ")
|
|
(undo-boundary)
|
|
(forward-word -1)
|
|
(undo-boundary)
|
|
(kill-word 1)
|
|
(undo-boundary)
|
|
(facemenu-add-face 'bold (point-min) (point-max))
|
|
(undo-boundary)
|
|
(set-buffer-multibyte (not enable-multibyte-characters))
|
|
(undo-boundary)
|
|
(should
|
|
(string-equal (buffer-string)
|
|
(progn
|
|
(undo)
|
|
(undo-more 4)
|
|
(undo)
|
|
;(undo-more -4)
|
|
(buffer-string))))))
|
|
|
|
(ert-deftest undo-test2 ()
|
|
"Test basic redoing with \\[undo] command."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(undo-boundary)
|
|
(insert "One")
|
|
(undo-boundary)
|
|
(insert " Zero")
|
|
(undo-boundary)
|
|
(push-mark nil t)
|
|
(delete-region (save-excursion
|
|
(forward-word -1)
|
|
(point)) (point))
|
|
(undo-boundary)
|
|
(beginning-of-line)
|
|
(insert "Zero")
|
|
(undo-boundary)
|
|
(undo)
|
|
(should
|
|
(string-equal (buffer-string)
|
|
(progn
|
|
(undo-more 2)
|
|
(undo)
|
|
(buffer-string))))))
|
|
|
|
(ert-deftest undo-test4 ()
|
|
"Test \\[undo] of \\[flush-lines]."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(dotimes (i 1048576)
|
|
(if (zerop (% i 2))
|
|
(insert "Evenses")
|
|
(insert "Oddses")))
|
|
(undo-boundary)
|
|
(should
|
|
;; Avoid string-equal because ERT will save the `buffer-string'
|
|
;; to the explanation. Using `not' will record nil or non-nil.
|
|
(not
|
|
(null
|
|
(string-equal (buffer-string)
|
|
(progn
|
|
(flush-lines "oddses" (point-min) (point-max))
|
|
(undo-boundary)
|
|
(undo)
|
|
(undo)
|
|
(buffer-string))))))))
|
|
|
|
(ert-deftest undo-test5 ()
|
|
"Test basic redoing with \\[undo] command."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(undo-boundary)
|
|
(insert "AYE")
|
|
(undo-boundary)
|
|
(insert " BEE")
|
|
(undo-boundary)
|
|
(setq buffer-undo-list (cons '(0.0 bogus) buffer-undo-list))
|
|
(push-mark nil t)
|
|
(delete-region (save-excursion
|
|
(forward-word -1)
|
|
(point)) (point))
|
|
(undo-boundary)
|
|
(beginning-of-line)
|
|
(insert "CEE")
|
|
(undo-boundary)
|
|
(undo)
|
|
(setq buffer-undo-list (cons "bogus" buffer-undo-list))
|
|
(should
|
|
(string-equal
|
|
(buffer-string)
|
|
(progn
|
|
(if (and (boundp 'undo-test5-error) (not undo-test5-error))
|
|
(progn
|
|
(should (null (undo-more 2)))
|
|
(should (undo)))
|
|
;; Errors are generated by new Lisp version of
|
|
;; `primitive-undo' not by built-in C version.
|
|
(should
|
|
(equal (should-error (undo-more 2))
|
|
'(error "Unrecognized entry in undo list (0.0 bogus)")))
|
|
(should
|
|
(equal (should-error (undo))
|
|
'(error "Unrecognized entry in undo list \"bogus\""))))
|
|
(buffer-string))))))
|
|
|
|
;; https://debbugs.gnu.org/14824
|
|
(ert-deftest undo-test-buffer-modified ()
|
|
"Test undoing marks buffer unmodified."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(insert "1")
|
|
(undo-boundary)
|
|
(set-buffer-modified-p nil)
|
|
(insert "2")
|
|
(undo)
|
|
(should-not (buffer-modified-p))))
|
|
|
|
(ert-deftest undo-test-file-modified ()
|
|
"Test undoing marks buffer visiting file unmodified."
|
|
(ert-with-temp-file tempfile
|
|
(with-current-buffer (find-file-noselect tempfile)
|
|
(insert "1")
|
|
(undo-boundary)
|
|
(set-buffer-modified-p nil)
|
|
(insert "2")
|
|
(undo)
|
|
(should-not (buffer-modified-p)))))
|
|
|
|
(ert-deftest undo-test-region-not-most-recent ()
|
|
"Test undo in region of an edit not the most recent."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(transient-mark-mode 1)
|
|
(insert "1111")
|
|
(undo-boundary)
|
|
(goto-char 2)
|
|
(insert "2")
|
|
(forward-char 2)
|
|
(undo-boundary)
|
|
(insert "3")
|
|
(undo-boundary)
|
|
;; Highlight around "2", not "3"
|
|
(push-mark (+ 3 (point-min)) t t)
|
|
(setq mark-active t)
|
|
(goto-char (point-min))
|
|
(undo)
|
|
(should (string= (buffer-string)
|
|
"11131"))))
|
|
|
|
(ert-deftest undo-test-region-deletion ()
|
|
"Test undoing a deletion to demonstrate bug 17235."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(transient-mark-mode 1)
|
|
(insert "12345")
|
|
(search-backward "4")
|
|
(undo-boundary)
|
|
(funcall-interactively 'delete-forward-char 1)
|
|
(search-backward "1")
|
|
(undo-boundary)
|
|
(insert "xxxx")
|
|
(undo-boundary)
|
|
(insert "yy")
|
|
(search-forward "35")
|
|
(undo-boundary)
|
|
;; Select "35"
|
|
(push-mark (point) t t)
|
|
(setq mark-active t)
|
|
(forward-char -2)
|
|
(undo) ; Expect "4" to come back
|
|
(should (string= (buffer-string)
|
|
"xxxxyy12345"))))
|
|
|
|
(ert-deftest undo-test-region-example ()
|
|
"The same example test case described in comments for
|
|
undo-make-selective-list."
|
|
;; buf pos:
|
|
;; 123456789 buffer-undo-list undo-deltas
|
|
;; --------- ---------------- -----------
|
|
;; aaa (1 . 4) (1 . -3)
|
|
;; aaba (3 . 4) N/A (in region)
|
|
;; ccaaba (1 . 3) (1 . -2)
|
|
;; ccaabaddd (7 . 10) (7 . -3)
|
|
;; ccaabdd ("ad" . 6) (6 . 2)
|
|
;; ccaabaddd (6 . 8) (6 . -2)
|
|
;; | |<-- region: "caab", from 2 to 6
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(transient-mark-mode 1)
|
|
(insert "aaa")
|
|
(goto-char 3)
|
|
(undo-boundary)
|
|
(insert "b")
|
|
(goto-char 1)
|
|
(undo-boundary)
|
|
(insert "cc")
|
|
(goto-char 7)
|
|
(undo-boundary)
|
|
(insert "ddd")
|
|
(search-backward "ad")
|
|
(undo-boundary)
|
|
(funcall-interactively 'delete-forward-char 2)
|
|
(undo-boundary)
|
|
;; Select "dd"
|
|
(push-mark (point) t t)
|
|
(setq mark-active t)
|
|
(goto-char (point-max))
|
|
(undo)
|
|
(undo-boundary)
|
|
(should (string= (buffer-string)
|
|
"ccaabaddd"))
|
|
;; Select "caab"
|
|
(push-mark 2 t t)
|
|
(setq mark-active t)
|
|
(goto-char 6)
|
|
(undo)
|
|
(undo-boundary)
|
|
(should (string= (buffer-string)
|
|
"ccaaaddd"))))
|
|
|
|
(ert-deftest undo-test-region-eob ()
|
|
"Test undo in region of a deletion at EOB, demonstrating bug 16411."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(transient-mark-mode 1)
|
|
(insert "This sentence corrupted?")
|
|
(undo-boundary)
|
|
;; Same as recipe at
|
|
;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=16411
|
|
(insert "aaa")
|
|
(undo-boundary)
|
|
(undo)
|
|
;; Select entire buffer
|
|
(push-mark (point) t t)
|
|
(setq mark-active t)
|
|
(goto-char (point-min))
|
|
;; Should undo the undo of "aaa", ie restore it.
|
|
(undo)
|
|
(should (string= (buffer-string)
|
|
"This sentence corrupted?aaa"))))
|
|
|
|
(ert-deftest undo-test-marker-adjustment-nominal ()
|
|
"Test nominal behavior of marker adjustments."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(insert "abcdefg")
|
|
(undo-boundary)
|
|
(let ((m (make-marker)))
|
|
(set-marker m 2 (current-buffer))
|
|
(goto-char (point-min))
|
|
(funcall-interactively 'delete-forward-char 3)
|
|
(undo-boundary)
|
|
(should (= (point-min) (marker-position m)))
|
|
(undo)
|
|
(undo-boundary)
|
|
(should (= 2 (marker-position m))))))
|
|
|
|
(ert-deftest undo-test-region-t-marker ()
|
|
"Test undo in region containing marker with t insertion-type."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(transient-mark-mode 1)
|
|
(insert "abcdefg")
|
|
(undo-boundary)
|
|
(let ((m (make-marker)))
|
|
(set-marker-insertion-type m t)
|
|
(set-marker m (point-min) (current-buffer)) ; m at a
|
|
(goto-char (+ 2 (point-min)))
|
|
(push-mark (point) t t)
|
|
(setq mark-active t)
|
|
(goto-char (point-min))
|
|
(funcall-interactively 'delete-forward-char 1) ; delete region covering "ab"
|
|
(undo-boundary)
|
|
(should (= (point-min) (marker-position m)))
|
|
;; Resurrect "ab". m's insertion type means the reinsertion
|
|
;; moves it forward 2, and then the marker adjustment returns it
|
|
;; to its rightful place.
|
|
(undo)
|
|
(undo-boundary)
|
|
(should (= (point-min) (marker-position m))))))
|
|
|
|
(ert-deftest undo-test-marker-adjustment-moved ()
|
|
"Test marker adjustment behavior when the marker moves.
|
|
Demonstrates bug 16818."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(insert "abcdefghijk")
|
|
(undo-boundary)
|
|
(let ((m (make-marker)))
|
|
(set-marker m 2 (current-buffer)) ; m at b
|
|
(goto-char (point-min))
|
|
(funcall-interactively 'delete-forward-char 3) ; m at d
|
|
(undo-boundary)
|
|
(set-marker m 4) ; m at g
|
|
(undo)
|
|
(undo-boundary)
|
|
;; m still at g, but shifted 3 because deletion undone
|
|
(should (= 7 (marker-position m))))))
|
|
|
|
(ert-deftest undo-test-region-mark-adjustment ()
|
|
"Test that the mark's marker adjustment in undo history doesn't
|
|
obstruct undo in region from finding the correct change group.
|
|
Demonstrates bug 16818."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(transient-mark-mode 1)
|
|
(insert "First line\n")
|
|
(insert "Second line\n")
|
|
(undo-boundary)
|
|
|
|
(goto-char (point-min))
|
|
(insert "aaa")
|
|
(undo-boundary)
|
|
|
|
(undo)
|
|
(undo-boundary)
|
|
|
|
(goto-char (point-max))
|
|
(insert "bbb")
|
|
(undo-boundary)
|
|
|
|
(push-mark (point) t t)
|
|
(setq mark-active t)
|
|
(goto-char (- (point) 3))
|
|
(funcall-interactively 'delete-forward-char 1)
|
|
(undo-boundary)
|
|
|
|
(insert "bbb")
|
|
(undo-boundary)
|
|
|
|
(goto-char (point-min))
|
|
(push-mark (point) t t)
|
|
(setq mark-active t)
|
|
(goto-char (+ (point) 3))
|
|
(undo)
|
|
(undo-boundary)
|
|
|
|
(should (string= (buffer-string) "aaaFirst line\nSecond line\nbbb"))))
|
|
|
|
(ert-deftest undo-test-combine-change-calls-1 ()
|
|
"Test how `combine-change-calls' updates `buffer-undo-list'.
|
|
Case 1: a file-visiting buffer with `buffer-undo-list' non-nil
|
|
and `buffer-modified-p' non-nil when `combine-change-calls' is
|
|
called."
|
|
(ert-with-temp-file tempfile
|
|
(with-current-buffer (find-file tempfile)
|
|
(insert "A")
|
|
(undo-boundary)
|
|
(insert "B")
|
|
(undo-boundary)
|
|
(insert "C")
|
|
(undo-boundary)
|
|
(insert " ")
|
|
(undo-boundary)
|
|
(insert "D")
|
|
(undo-boundary)
|
|
(insert "E")
|
|
(undo-boundary)
|
|
(insert "F")
|
|
(should (= (length buffer-undo-list) 14))
|
|
(goto-char (point-min))
|
|
(combine-change-calls (point-min) (point-max)
|
|
(re-search-forward "ABC ")
|
|
(replace-match "Z "))
|
|
(should (= (length buffer-undo-list) 15)))))
|
|
|
|
(ert-deftest undo-test-combine-change-calls-2 ()
|
|
"Test how `combine-change-calls' updates `buffer-undo-list'.
|
|
Case 2: a file-visiting buffer with `buffer-undo-list' non-nil
|
|
and `buffer-modified-p' nil when `combine-change-calls' is
|
|
called."
|
|
(ert-with-temp-file tempfile
|
|
(with-current-buffer (find-file tempfile)
|
|
(insert "A")
|
|
(undo-boundary)
|
|
(insert "B")
|
|
(undo-boundary)
|
|
(insert "C")
|
|
(undo-boundary)
|
|
(insert " ")
|
|
(undo-boundary)
|
|
(insert "D")
|
|
(undo-boundary)
|
|
(insert "E")
|
|
(undo-boundary)
|
|
(insert "F")
|
|
(should (= (length buffer-undo-list) 14))
|
|
(save-buffer)
|
|
(goto-char (point-min))
|
|
(combine-change-calls (point-min) (point-max)
|
|
(re-search-forward "ABC ")
|
|
(replace-match "Z "))
|
|
(should (= (length buffer-undo-list) 15)))))
|
|
|
|
(ert-deftest undo-test-combine-change-calls-3 ()
|
|
"Test how `combine-change-calls' updates `buffer-undo-list'.
|
|
Case 3: a file-visiting buffer with `buffer-undo-list' nil and
|
|
`buffer-modified-p' nil when `combine-change-calls' is called."
|
|
(ert-with-temp-file tempfile
|
|
(with-current-buffer (find-file tempfile)
|
|
(insert "ABC DEF")
|
|
(save-buffer)
|
|
(kill-buffer))
|
|
(with-current-buffer (find-file tempfile)
|
|
(should (= (length buffer-undo-list) 0))
|
|
(goto-char (point-min))
|
|
(combine-change-calls (point-min) (point-max)
|
|
(re-search-forward "ABC ")
|
|
(replace-match "Z "))
|
|
(should (= (length buffer-undo-list) 1)))))
|
|
|
|
(defun undo-test-all (&optional interactive)
|
|
"Run all tests for \\[undo]."
|
|
(interactive "p")
|
|
(if interactive
|
|
(ert-run-tests-interactively "^undo-")
|
|
(ert-run-tests-batch "^undo-")))
|
|
|
|
(ert-deftest undo-test-skip-invalidated-markers ()
|
|
"Test marker adjustment when the marker points nowhere.
|
|
Demonstrates bug 25599."
|
|
(with-temp-buffer
|
|
(buffer-enable-undo)
|
|
(insert ";; aaaaaaaaa
|
|
;; bbbbbbbb")
|
|
(let ((overlay-modified
|
|
(lambda (ov after-p _beg _end &optional _length)
|
|
(unless after-p
|
|
(when (overlay-buffer ov)
|
|
(delete-overlay ov))))))
|
|
(save-excursion
|
|
(goto-char (point-min))
|
|
(let ((ov (make-overlay (pos-bol 2) (pos-eol 2))))
|
|
(overlay-put ov 'insert-in-front-hooks
|
|
(list overlay-modified)))))
|
|
(kill-region (point-min) (pos-bol 2))
|
|
(undo-boundary)
|
|
(undo)))
|
|
|
|
(provide 'undo-tests)
|
|
;;; undo-tests.el ends here
|