aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorStephen Gildea2018-07-31 22:34:35 -0700
committerStephen Gildea2018-07-31 22:34:35 -0700
commit1804fece02691798394c9e9bd519cd4a53776018 (patch)
tree9d5d441db29404f04417332be3507ba968eec42f /test
parent17205d361795eaaa8e09ae62875c7439bb57a078 (diff)
parent82d6416a28dc5b4ab65b8081f035679bec4e3604 (diff)
downloademacs-1804fece02691798394c9e9bd519cd4a53776018.tar.gz
emacs-1804fece02691798394c9e9bd519cd4a53776018.zip
Merge branch 'master' of git.savannah.gnu.org:/srv/git/emacs
Diffstat (limited to 'test')
-rw-r--r--test/Makefile.in1
-rw-r--r--test/lisp/auth-source-tests.el20
-rw-r--r--test/lisp/emacs-lisp/lisp-mode-tests.el23
-rw-r--r--test/lisp/emacs-lisp/package-tests.el12
-rw-r--r--test/lisp/epg-tests.el34
-rw-r--r--test/lisp/shadowfile-tests.el932
-rw-r--r--test/lisp/wdired-tests.el105
-rw-r--r--test/src/editfns-tests.el10
-rw-r--r--test/src/fns-tests.el11
-rw-r--r--test/src/thread-tests.el34
10 files changed, 1155 insertions, 27 deletions
diff --git a/test/Makefile.in b/test/Makefile.in
index 6070932508d..0bc893bc0c6 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -169,7 +169,6 @@ WRITE_LOG = > $@ 2>&1 || { STAT=$$?; cat $@; exit $$STAT; }
169ifdef EMACS_HYDRA_CI 169ifdef EMACS_HYDRA_CI
170## On Hydra, always show logs for certain problematic tests. 170## On Hydra, always show logs for certain problematic tests.
171lisp/net/tramp-tests.log \ 171lisp/net/tramp-tests.log \
172lisp/epg-tests.log \
173: WRITE_LOG = 2>&1 | tee $@ 172: WRITE_LOG = 2>&1 | tee $@
174endif 173endif
175 174
diff --git a/test/lisp/auth-source-tests.el b/test/lisp/auth-source-tests.el
index be516f2c40d..ca8a3eb78f0 100644
--- a/test/lisp/auth-source-tests.el
+++ b/test/lisp/auth-source-tests.el
@@ -344,5 +344,25 @@
344 "session" 344 "session"
345 (format "%s@%s" (plist-get auth-info :user) (plist-get auth-info :host))))) 345 (format "%s@%s" (plist-get auth-info :user) (plist-get auth-info :host)))))
346 346
347(ert-deftest auth-source-delete ()
348 (let* ((netrc-file (make-temp-file "auth-source-test" nil nil "\
349machine a1 port a2 user a3 password a4
350machine b1 port b2 user b3 password b4
351machine c1 port c2 user c3 password c4\n"))
352 (auth-sources (list netrc-file))
353 (auth-source-do-cache nil)
354 (expected '((:host "a1" :port "a2" :user "a3" :secret "a4")))
355 (parameters '(:max 1 :host t)))
356 (unwind-protect
357 (let ((found (apply #'auth-source-delete parameters)))
358 (dolist (f found)
359 (let ((s (plist-get f :secret)))
360 (setf f (plist-put f :secret
361 (if (functionp s) (funcall s) s)))))
362 ;; Note: The netrc backend doesn't delete anything, so
363 ;; this is actually the same as `auth-source-search'.
364 (should (equal found expected)))
365 (delete-file netrc-file))))
366
347(provide 'auth-source-tests) 367(provide 'auth-source-tests)
348;;; auth-source-tests.el ends here 368;;; auth-source-tests.el ends here
diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el b/test/lisp/emacs-lisp/lisp-mode-tests.el
index 8598d419788..30f606d3816 100644
--- a/test/lisp/emacs-lisp/lisp-mode-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mode-tests.el
@@ -113,6 +113,29 @@ noindent\" 3
113 ;; we're indenting ends on the previous line. 113 ;; we're indenting ends on the previous line.
114 (should (equal (buffer-string) original))))) 114 (should (equal (buffer-string) original)))))
115 115
116(ert-deftest indent-sexp-go ()
117 "Make sure `indent-sexp' doesn't stop after #s."
118 ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31984.
119 (with-temp-buffer
120 (emacs-lisp-mode)
121 (insert "#s(foo\nbar)\n")
122 (goto-char (point-min))
123 (indent-sexp)
124 (should (equal (buffer-string) "\
125#s(foo
126 bar)\n"))))
127
128(ert-deftest indent-sexp-cant-go ()
129 "`indent-sexp' shouldn't error before a sexp."
130 ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31984#32.
131 (with-temp-buffer
132 (emacs-lisp-mode)
133 (insert "(())")
134 (goto-char (1+ (point-min)))
135 ;; Paredit calls `indent-sexp' from this position.
136 (indent-sexp)
137 (should (equal (buffer-string) "(())"))))
138
116(ert-deftest lisp-indent-region () 139(ert-deftest lisp-indent-region ()
117 "Test basics of `lisp-indent-region'." 140 "Test basics of `lisp-indent-region'."
118 (with-temp-buffer 141 (with-temp-buffer
diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el
index b1adfabe525..f08bc92ff2a 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -473,7 +473,17 @@ Must called from within a `tar-mode' buffer."
473 (let ((process-environment 473 (let ((process-environment
474 (cons (concat "HOME=" homedir) 474 (cons (concat "HOME=" homedir)
475 process-environment))) 475 process-environment)))
476 (epg-find-configuration 'OpenPGP)) 476 (epg-find-configuration
477 'OpenPGP nil
478 ;; By default we require gpg2 2.1+ due to some
479 ;; practical problems with pinentry. But this
480 ;; test works fine with 2.0 as well.
481 (let ((prog-alist (copy-tree epg-config--program-alist)))
482 (setf (alist-get "gpg2"
483 (alist-get 'OpenPGP prog-alist)
484 nil nil #'equal)
485 "2.0")
486 prog-alist)))
477 (delete-directory homedir t)))) 487 (delete-directory homedir t))))
478 (let* ((keyring (expand-file-name "key.pub" package-test-data-dir)) 488 (let* ((keyring (expand-file-name "key.pub" package-test-data-dir))
479 (package-test-data-dir 489 (package-test-data-dir
diff --git a/test/lisp/epg-tests.el b/test/lisp/epg-tests.el
index c34e589a4ac..c1e98a6935e 100644
--- a/test/lisp/epg-tests.el
+++ b/test/lisp/epg-tests.el
@@ -23,7 +23,6 @@
23 23
24(require 'ert) 24(require 'ert)
25(require 'epg) 25(require 'epg)
26(require 'trace)
27 26
28(defvar epg-tests-context nil) 27(defvar epg-tests-context nil)
29 28
@@ -33,17 +32,26 @@
33 32
34(defconst epg-tests--config-program-alist 33(defconst epg-tests--config-program-alist
35 ;; The default `epg-config--program-alist' requires gpg2 2.1 or 34 ;; The default `epg-config--program-alist' requires gpg2 2.1 or
36 ;; greater due to some practical problems with pinentry. But the 35 ;; greater due to some practical problems with pinentry. But most
37 ;; tests here all work fine with 2.0 as well. 36 ;; tests here work fine with 2.0 as well.
38 (let ((prog-alist (copy-sequence epg-config--program-alist))) 37 (let ((prog-alist (copy-tree epg-config--program-alist)))
39 (setf (alist-get "gpg2" 38 (setf (alist-get "gpg2"
40 (alist-get 'OpenPGP prog-alist) 39 (alist-get 'OpenPGP prog-alist)
41 nil nil #'equal) 40 nil nil #'equal)
42 "2.0") 41 "2.0")
43 prog-alist)) 42 prog-alist))
44 43
45(defun epg-tests-find-usable-gpg-configuration (&optional _require-passphrase) 44(defun epg-tests-find-usable-gpg-configuration
46 (epg-find-configuration 'OpenPGP 'no-cache epg-tests--config-program-alist)) 45 (&optional require-passphrase require-public-key)
46 ;; Clear config cache because we may be using a different
47 ;; program-alist. We do want to update the cache, so that
48 ;; `epg-make-context' can use our result.
49 (setq epg--configurations nil)
50 (epg-find-configuration 'OpenPGP nil
51 ;; The symmetric operations fail on Hydra
52 ;; with gpg 2.0.
53 (if (or (not require-passphrase) require-public-key)
54 epg-tests--config-program-alist)))
47 55
48(defun epg-tests-passphrase-callback (_c _k _d) 56(defun epg-tests-passphrase-callback (_c _k _d)
49 ;; Need to create a copy here, since the string will be wiped out 57 ;; Need to create a copy here, since the string will be wiped out
@@ -63,14 +71,12 @@
63 (format "GNUPGHOME=%s" epg-tests-home-directory)) 71 (format "GNUPGHOME=%s" epg-tests-home-directory))
64 process-environment))) 72 process-environment)))
65 (unwind-protect 73 (unwind-protect
66 (let ((context (epg-make-context 'OpenPGP)) 74 ;; GNUPGHOME is needed to find a usable gpg, so we can't
67 (epg-config (epg-tests-find-usable-gpg-configuration 75 ;; check whether to skip any earlier (Bug#23561).
68 ,(if require-passphrase 76 (let ((epg-config (or (epg-tests-find-usable-gpg-configuration
69 `'require-passphrase)))) 77 ,require-passphrase ,require-public-key)
70 ;; GNUPGHOME is needed to find a usable gpg, so we can't 78 (ert-skip "No usable gpg config")))
71 ;; check whether to skip any earlier (Bug#23561). 79 (context (epg-make-context 'OpenPGP)))
72 (unless epg-config
73 (ert-skip "No usable gpg config"))
74 (setf (epg-context-program context) 80 (setf (epg-context-program context)
75 (alist-get 'program epg-config)) 81 (alist-get 'program epg-config))
76 (setf (epg-context-home-directory context) 82 (setf (epg-context-home-directory context)
diff --git a/test/lisp/shadowfile-tests.el b/test/lisp/shadowfile-tests.el
new file mode 100644
index 00000000000..085ab476ffe
--- /dev/null
+++ b/test/lisp/shadowfile-tests.el
@@ -0,0 +1,932 @@
1;;; shadowfile-tests.el --- Tests of shadowfile
2
3;; Copyright (C) 2018 Free Software Foundation, Inc.
4
5;; Author: Michael Albinus <michael.albinus@gmx.de>
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 `https://www.gnu.org/licenses/'.
19
20;;; Commentary:
21
22;; Some of the tests require access to a remote host files. Since
23;; this could be problematic, a mock-up connection method "mock" is
24;; used. Emulating a remote connection, it simply calls "sh -i".
25;; Tramp's file name handlers still run, so this test is sufficient
26;; except for connection establishing.
27
28;; If you want to test a real Tramp connection, set
29;; $REMOTE_TEMPORARY_FILE_DIRECTORY to a suitable value in order to
30;; overwrite the default value. If you want to skip tests accessing a
31;; remote host, set this environment variable to "/dev/null" or
32;; whatever is appropriate on your system.
33
34;; A whole test run can be performed calling the command `shadowfile-test-all'.
35
36;;; Code:
37
38(require 'ert)
39(require 'shadowfile)
40(require 'tramp)
41
42;; There is no default value on w32 systems, which could work out of the box.
43(defconst shadow-test-remote-temporary-file-directory
44 (cond
45 ((getenv "REMOTE_TEMPORARY_FILE_DIRECTORY"))
46 ((eq system-type 'windows-nt) null-device)
47 (t (add-to-list
48 'tramp-methods
49 '("mock"
50 (tramp-login-program "sh")
51 (tramp-login-args (("-i")))
52 (tramp-remote-shell "/bin/sh")
53 (tramp-remote-shell-args ("-c"))
54 (tramp-connection-timeout 10)))
55 (add-to-list
56 'tramp-default-host-alist
57 `("\\`mock\\'" nil ,(system-name)))
58 ;; Emacs' Makefile sets $HOME to a nonexistent value. Needed in
59 ;; batch mode only, therefore. It cannot be
60 ;; `temporary-directory', because the tests with "~" would fail.
61 (unless (and (null noninteractive) (file-directory-p "~/"))
62 (setenv "HOME" invocation-directory))
63 (format "/mock::%s" temporary-file-directory)))
64 "Temporary directory for Tramp tests.")
65
66(defconst shadow-test-info-file
67 (expand-file-name "shadows_test" temporary-file-directory)
68 "File to keep shadow information in during tests.")
69
70(defconst shadow-test-todo-file
71 (expand-file-name "shadow_todo_test" temporary-file-directory)
72 "File to store the list of uncopied shadows in during tests.")
73
74(ert-deftest shadow-test00-clusters ()
75 "Check cluster definitions.
76Per definition, all files are identical on the different hosts of
77a cluster (or site). This is not tested here; it must be
78guaranteed by the originator of a cluster definition."
79 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
80 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
81
82 (let ((text-quoting-style 'grave) ;; We inspect the *Messages* buffer!
83 (inhibit-message t)
84 (shadow-info-file shadow-test-info-file)
85 (shadow-todo-file shadow-test-todo-file)
86 shadow-clusters
87 cluster primary regexp mocked-input)
88 (unwind-protect
89 ;; We must mock `read-from-minibuffer' and `read-string', in
90 ;; order to avoid interactive arguments.
91 (cl-letf* (((symbol-function 'read-from-minibuffer)
92 (lambda (&rest args) (pop mocked-input)))
93 ((symbol-function 'read-string)
94 (lambda (&rest args) (pop mocked-input))))
95
96 ;; Cleanup.
97 (when (file-exists-p shadow-info-file)
98 (delete-file shadow-info-file))
99 (when (file-exists-p shadow-todo-file)
100 (delete-file shadow-todo-file))
101
102 ;; Define a cluster.
103 (setq cluster "cluster"
104 primary shadow-system-name
105 regexp (shadow-regexp-superquote primary)
106 mocked-input `(,cluster ,primary ,regexp))
107 (call-interactively 'shadow-define-cluster)
108 (should
109 (string-equal
110 (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
111 (should
112 (string-equal
113 (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
114 (should
115 (string-equal
116 (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
117 (should-not (shadow-get-cluster "non-existent-cluster-name"))
118
119 ;; Test `shadow-set-cluster' and `make-shadow-cluster'.
120 (shadow-set-cluster cluster primary regexp)
121 (should
122 (equal (shadow-get-cluster cluster)
123 (make-shadow-cluster
124 :name cluster :primary primary :regexp regexp)))
125
126 ;; The primary must be either `shadow-system-name', or a remote file.
127 (setq ;; The second "cluster" is wrong.
128 mocked-input `(,cluster ,cluster ,primary ,regexp))
129 (with-current-buffer (messages-buffer)
130 (narrow-to-region (point-max) (point-max)))
131 (call-interactively 'shadow-define-cluster)
132 (should
133 (string-match
134 (regexp-quote "Not a valid primary!")
135 (with-current-buffer (messages-buffer) (buffer-string))))
136 ;; The first cluster definition is still valid.
137 (should
138 (string-equal
139 (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
140 (should
141 (string-equal
142 (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
143 (should
144 (string-equal
145 (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
146
147 ;; The regexp must match the primary name.
148 (setq ;; The second "cluster" is wrong.
149 mocked-input `(,cluster ,primary ,cluster ,regexp))
150 (with-current-buffer (messages-buffer)
151 (narrow-to-region (point-max) (point-max)))
152 (call-interactively 'shadow-define-cluster)
153 (should
154 (string-match
155 (regexp-quote "Regexp doesn't include the primary host!")
156 (with-current-buffer (messages-buffer) (buffer-string))))
157 ;; The first cluster definition is still valid.
158 (should
159 (string-equal
160 (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
161 (should
162 (string-equal
163 (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
164 (should
165 (string-equal
166 (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
167
168 ;; Redefine the cluster.
169 (setq primary
170 (file-remote-p shadow-test-remote-temporary-file-directory)
171 regexp (shadow-regexp-superquote primary)
172 mocked-input `(,cluster ,primary ,regexp))
173 (call-interactively 'shadow-define-cluster)
174 (should
175 (string-equal
176 (shadow-cluster-name (shadow-get-cluster cluster)) cluster))
177 (should
178 (string-equal
179 (shadow-cluster-primary (shadow-get-cluster cluster)) primary))
180 (should
181 (string-equal
182 (shadow-cluster-regexp (shadow-get-cluster cluster)) regexp))
183
184 ;; Test `shadow-set-cluster' and `make-shadow-cluster'.
185 (shadow-set-cluster cluster primary regexp)
186 (should
187 (equal (shadow-get-cluster cluster)
188 (make-shadow-cluster
189 :name cluster :primary primary :regexp regexp))))
190
191 ;; Cleanup.
192 (with-current-buffer (messages-buffer) (widen))
193 (when (file-exists-p shadow-info-file)
194 (delete-file shadow-info-file))
195 (when (file-exists-p shadow-todo-file)
196 (delete-file shadow-todo-file)))))
197
198(ert-deftest shadow-test01-sites ()
199 "Check site definitions.
200Per definition, all files are identical on the different hosts of
201a cluster (or site). This is not tested here; it must be
202guaranteed by the originator of a cluster definition."
203 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
204 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
205
206 (let ((shadow-info-file shadow-test-info-file)
207 (shadow-todo-file shadow-test-todo-file)
208 shadow-clusters
209 cluster1 cluster2 primary1 primary2 regexp1 regexp2 mocked-input)
210 (unwind-protect
211 ;; We must mock `read-from-minibuffer' and `read-string', in
212 ;; order to avoid interactive arguments.
213 (cl-letf* (((symbol-function 'read-from-minibuffer)
214 (lambda (&rest args) (pop mocked-input)))
215 ((symbol-function 'read-string)
216 (lambda (&rest args) (pop mocked-input))))
217
218 ;; Cleanup.
219 (when (file-exists-p shadow-info-file)
220 (delete-file shadow-info-file))
221 (when (file-exists-p shadow-todo-file)
222 (delete-file shadow-todo-file))
223
224 ;; Define a cluster.
225 (setq cluster1 "cluster1"
226 primary1 shadow-system-name
227 regexp1 (shadow-regexp-superquote primary1))
228 (shadow-set-cluster cluster1 primary1 regexp1)
229
230 ;; A site is either a cluster identification, or a primary host.
231 (should (string-equal cluster1 (shadow-site-name cluster1)))
232 (should (string-equal primary1 (shadow-name-site primary1)))
233 (should
234 (string-equal (format "/%s:" cluster1) (shadow-name-site cluster1)))
235 (should (string-equal (system-name) (shadow-site-name primary1)))
236 (should
237 (string-equal
238 (file-remote-p shadow-test-remote-temporary-file-directory)
239 (shadow-name-site
240 (file-remote-p shadow-test-remote-temporary-file-directory))))
241 (should
242 (string-equal
243 (file-remote-p shadow-test-remote-temporary-file-directory)
244 (shadow-site-name
245 (file-remote-p shadow-test-remote-temporary-file-directory))))
246
247 (should (equal (shadow-site-cluster cluster1)
248 (shadow-get-cluster cluster1)))
249 (should (equal (shadow-site-cluster (shadow-name-site cluster1))
250 (shadow-get-cluster cluster1)))
251 (should (equal (shadow-site-cluster primary1)
252 (shadow-get-cluster cluster1)))
253 (should (equal (shadow-site-cluster (shadow-site-name primary1))
254 (shadow-get-cluster cluster1)))
255 (should (string-equal (shadow-site-primary cluster1) primary1))
256 (should (string-equal (shadow-site-primary primary1) primary1))
257
258 ;; `shadow-read-site' accepts "cluster", "/cluster:",
259 ;; "system", "/system:". It shall reject bad site names.
260 (setq mocked-input
261 `(,cluster1 ,(shadow-name-site cluster1)
262 ,primary1 ,(shadow-site-name primary1)
263 ,shadow-system-name "" "bad" "/bad:"))
264 (should (string-equal (shadow-read-site) cluster1))
265 (should (string-equal (shadow-read-site) (shadow-name-site cluster1)))
266 (should (string-equal (shadow-read-site) primary1))
267 (should (string-equal (shadow-read-site) (shadow-site-name primary1)))
268 (should (string-equal (shadow-read-site) shadow-system-name))
269 (should-not (shadow-read-site)) ; ""
270 (should-not (shadow-read-site)) ; "bad"
271 (should-not (shadow-read-site)) ; "/bad:"
272 (should-error (shadow-read-site)) ; no input at all
273
274 ;; Define a second cluster.
275 (setq cluster2 "cluster2"
276 primary2
277 (file-remote-p shadow-test-remote-temporary-file-directory)
278 regexp2 (format "^\\(%s\\|%s\\)$" shadow-system-name primary2))
279 (shadow-set-cluster cluster2 primary2 regexp2)
280
281 ;; `shadow-site-match' shall know all different kind of site names.
282 (should (shadow-site-match cluster1 cluster1))
283 (should (shadow-site-match primary1 primary1))
284 (should (shadow-site-match cluster1 primary1))
285 (should (shadow-site-match primary1 cluster1))
286 (should (shadow-site-match cluster2 cluster2))
287 (should (shadow-site-match primary2 primary2))
288 (should (shadow-site-match cluster2 primary2))
289 (should (shadow-site-match primary2 cluster2))
290
291 ;; The regexp of `cluster2' matches the primary of
292 ;; `cluster1'. Not vice versa.
293 (should (shadow-site-match cluster2 cluster1))
294 (should-not (shadow-site-match cluster1 cluster2))
295
296 ;; If we use the primaries of a cluster, it doesn't match.
297 (should-not
298 (shadow-site-match (shadow-site-primary cluster2) cluster1))
299 (should-not
300 (shadow-site-match (shadow-site-primary cluster1) cluster2)))
301
302 ;; Cleanup.
303 (when (file-exists-p shadow-info-file)
304 (delete-file shadow-info-file))
305 (when (file-exists-p shadow-todo-file)
306 (delete-file shadow-todo-file)))))
307
308(ert-deftest shadow-test02-files ()
309 "Check file manipulation functions."
310 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
311 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
312
313 (let ((shadow-info-file shadow-test-info-file)
314 (shadow-todo-file shadow-test-todo-file)
315 shadow-clusters
316 cluster primary regexp file hup)
317 (unwind-protect
318 (progn
319 ;; Cleanup.
320 (when (file-exists-p shadow-info-file)
321 (delete-file shadow-info-file))
322 (when (file-exists-p shadow-todo-file)
323 (delete-file shadow-todo-file))
324
325 ;; Define a cluster.
326 (setq cluster "cluster"
327 primary shadow-system-name
328 regexp (shadow-regexp-superquote primary)
329 file (make-temp-name
330 (expand-file-name
331 "shadowfile-tests" temporary-file-directory)))
332 (shadow-set-cluster cluster primary regexp)
333
334 ;; The constant structure to compare with.
335 (setq hup (make-tramp-file-name :host (system-name) :localname file))
336
337 ;; The structure a local file is transformed in.
338 (should (equal (shadow-parse-name file) hup))
339 (should (equal (shadow-parse-name (concat "/" cluster ":" file)) hup))
340 (should (equal (shadow-parse-name (concat primary file)) hup))
341
342 ;; A local file name is kept.
343 (should
344 (string-equal (shadow-local-file file) file))
345 ;; A file on this cluster is also local.
346 (should
347 (string-equal
348 (shadow-local-file (concat "/" cluster ":" file)) file))
349 ;; A file on the primary host is also local.
350 (should
351 (string-equal (shadow-local-file (concat primary file)) file))
352
353 ;; Redefine the cluster.
354 (setq primary
355 (file-remote-p shadow-test-remote-temporary-file-directory)
356 regexp (shadow-regexp-superquote primary))
357 (shadow-set-cluster cluster primary regexp)
358
359 ;; The structure of the local file is still the same.
360 (should (equal (shadow-parse-name file) hup))
361 ;; The cluster name must be used.
362 (setf (tramp-file-name-host hup) cluster)
363 (should (equal (shadow-parse-name (concat "/" cluster ":" file)) hup))
364 ;; The structure of a remote file is different.
365 (should
366 (equal (shadow-parse-name (concat primary file))
367 (tramp-dissect-file-name (concat primary file))))
368
369 ;; A local file is still local.
370 (should (shadow-local-file file))
371 ;; A file on this cluster is not local.
372 (should-not (shadow-local-file (concat "/" cluster ":" file)))
373 ;; A file on the primary host is not local.
374 (should-not (shadow-local-file (concat primary file)))
375 ;; There's no error on wrong FILE.
376 (should-not (shadow-local-file nil)))
377
378 ;; Cleanup.
379 (when (file-exists-p shadow-info-file)
380 (delete-file shadow-info-file))
381 (when (file-exists-p shadow-todo-file)
382 (delete-file shadow-todo-file)))))
383
384(ert-deftest shadow-test03-expand-cluster-in-file-name ()
385 "Check canonical file name of a cluster or site."
386 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
387 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
388
389 (let ((shadow-info-file shadow-test-info-file)
390 (shadow-todo-file shadow-test-todo-file)
391 shadow-clusters
392 cluster primary regexp file1 file2)
393 (unwind-protect
394 (progn
395 ;; Cleanup.
396 (when (file-exists-p shadow-info-file)
397 (delete-file shadow-info-file))
398 (when (file-exists-p shadow-todo-file)
399 (delete-file shadow-todo-file))
400
401 ;; Define a cluster.
402 (setq cluster "cluster"
403 primary shadow-system-name
404 regexp (shadow-regexp-superquote primary))
405 (shadow-set-cluster cluster primary regexp)
406
407 (setq file1
408 (make-temp-name
409 (expand-file-name "shadowfile-tests" temporary-file-directory))
410 file2
411 (make-temp-name
412 (expand-file-name
413 "shadowfile-tests"
414 shadow-test-remote-temporary-file-directory)))
415
416 ;; A local file name is kept.
417 (should
418 (string-equal (shadow-expand-cluster-in-file-name file1) file1))
419 ;; A remote file is kept.
420 (should
421 (string-equal (shadow-expand-cluster-in-file-name file2) file2))
422 ;; A cluster name is expanded to the primary name.
423 (should
424 (string-equal
425 (shadow-expand-cluster-in-file-name (format "/%s:%s" cluster file1))
426 (shadow-expand-cluster-in-file-name (concat primary file1))))
427 ;; A primary name is expanded if it is a local file name.
428 (should
429 (string-equal
430 (shadow-expand-cluster-in-file-name (concat primary file1)) file1))
431
432 ;; Redefine the cluster.
433 (setq primary
434 (file-remote-p shadow-test-remote-temporary-file-directory)
435 regexp (shadow-regexp-superquote primary))
436 (shadow-set-cluster cluster primary regexp)
437
438 ;; A cluster name is expanded to the primary name.
439 (should
440 (string-equal
441 (shadow-expand-cluster-in-file-name (format "/%s:%s" cluster file1))
442 (shadow-expand-cluster-in-file-name (concat primary file1))))
443 ;; A primary name is not expanded if it isn't is a local file name.
444 (should
445 (string-equal
446 (shadow-expand-cluster-in-file-name (concat primary file1))
447 (concat primary file1))))
448
449 ;; Cleanup.
450 (when (file-exists-p shadow-info-file)
451 (delete-file shadow-info-file))
452 (when (file-exists-p shadow-todo-file)
453 (delete-file shadow-todo-file)))))
454
455(ert-deftest shadow-test04-contract-file-name ()
456 "Check canonical file name of a cluster or site."
457 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
458 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
459
460 (let ((shadow-info-file shadow-test-info-file)
461 (shadow-todo-file shadow-test-todo-file)
462 shadow-clusters
463 cluster primary regexp file)
464 (unwind-protect
465 (progn
466 ;; Cleanup.
467 (when (file-exists-p shadow-info-file)
468 (delete-file shadow-info-file))
469 (when (file-exists-p shadow-todo-file)
470 (delete-file shadow-todo-file))
471
472 ;; Define a cluster.
473 (setq cluster "cluster"
474 primary shadow-system-name
475 regexp (shadow-regexp-superquote primary)
476 file (make-temp-name
477 (expand-file-name
478 "shadowfile-tests" temporary-file-directory)))
479 (shadow-set-cluster cluster primary regexp)
480
481 ;; The cluster name is prepended for local files.
482 (should
483 (string-equal
484 (shadow-contract-file-name file) (concat "/cluster:" file)))
485 ;; A cluster file name is preserved.
486 (should
487 (string-equal
488 (shadow-contract-file-name (concat "/cluster:" file))
489 (concat "/cluster:" file)))
490 ;; `shadow-system-name' is mapped to the cluster.
491 (should
492 (string-equal
493 (shadow-contract-file-name (concat shadow-system-name file))
494 (concat "/cluster:" file)))
495
496 ;; Redefine the cluster.
497 (setq primary
498 (file-remote-p shadow-test-remote-temporary-file-directory)
499 regexp (shadow-regexp-superquote primary))
500 (shadow-set-cluster cluster primary regexp)
501
502 ;; A remote file name is mapped to the cluster.
503 (should
504 (string-equal
505 (shadow-contract-file-name
506 (concat
507 (file-remote-p shadow-test-remote-temporary-file-directory) file))
508 (concat "/cluster:" file))))
509
510 ;; Cleanup.
511 (when (file-exists-p shadow-info-file)
512 (delete-file shadow-info-file))
513 (when (file-exists-p shadow-todo-file)
514 (delete-file shadow-todo-file)))))
515
516(ert-deftest shadow-test05-file-match ()
517 "Check `shadow-same-site' and `shadow-file-match'."
518 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
519 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
520
521 (let ((shadow-info-file shadow-test-info-file)
522 (shadow-todo-file shadow-test-todo-file)
523 shadow-clusters
524 cluster primary regexp file)
525 (unwind-protect
526 (progn
527 ;; Cleanup.
528 (when (file-exists-p shadow-info-file)
529 (delete-file shadow-info-file))
530 (when (file-exists-p shadow-todo-file)
531 (delete-file shadow-todo-file))
532
533 ;; Define a cluster.
534 (setq cluster "cluster"
535 primary shadow-system-name
536 regexp (shadow-regexp-superquote primary)
537 file (make-temp-name
538 (expand-file-name
539 "shadowfile-tests" temporary-file-directory)))
540 (shadow-set-cluster cluster primary regexp)
541
542 (should (shadow-same-site (shadow-parse-name "/cluster:") file))
543 (should
544 (shadow-same-site (shadow-parse-name shadow-system-name) file))
545 (should (shadow-same-site (shadow-parse-name file) file))
546
547 (should
548 (shadow-file-match
549 (shadow-parse-name (concat "/cluster:" file)) file))
550 (should
551 (shadow-file-match
552 (shadow-parse-name (concat shadow-system-name file)) file))
553 (should (shadow-file-match (shadow-parse-name file) file))
554
555 ;; Redefine the cluster.
556 (setq primary
557 (file-remote-p shadow-test-remote-temporary-file-directory)
558 regexp (shadow-regexp-superquote primary))
559 (shadow-set-cluster cluster primary regexp)
560
561 (should
562 (shadow-file-match
563 (shadow-parse-name
564 (concat
565 (file-remote-p shadow-test-remote-temporary-file-directory)
566 file))
567 file)))
568
569 ;; Cleanup.
570 (when (file-exists-p shadow-info-file)
571 (delete-file shadow-info-file))
572 (when (file-exists-p shadow-todo-file)
573 (delete-file shadow-todo-file)))))
574
575(ert-deftest shadow-test06-literal-groups ()
576 "Check literal group definitions."
577 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
578 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
579
580 (let ((shadow-info-file shadow-test-info-file)
581 (shadow-todo-file shadow-test-todo-file)
582 shadow-clusters shadow-literal-groups
583 cluster1 cluster2 primary regexp file1 file2 mocked-input)
584 (unwind-protect
585 ;; We must mock `read-from-minibuffer' and `read-string', in
586 ;; order to avoid interactive arguments.
587 (cl-letf* (((symbol-function 'read-from-minibuffer)
588 (lambda (&rest args) (pop mocked-input)))
589 ((symbol-function 'read-string)
590 (lambda (&rest args) (pop mocked-input))))
591
592 ;; Cleanup.
593 (when (file-exists-p shadow-info-file)
594 (delete-file shadow-info-file))
595 (when (file-exists-p shadow-todo-file)
596 (delete-file shadow-todo-file))
597
598 ;; Define clusters.
599 (setq cluster1 "cluster1"
600 primary shadow-system-name
601 regexp (shadow-regexp-superquote primary))
602 (shadow-set-cluster cluster1 primary regexp)
603
604 (setq cluster2 "cluster2"
605 primary
606 (file-remote-p shadow-test-remote-temporary-file-directory)
607 regexp (format "^\\(%s\\|%s\\)$" shadow-system-name primary))
608 (shadow-set-cluster cluster2 primary regexp)
609
610 ;; Define a literal group.
611 (setq file1
612 (make-temp-name
613 (expand-file-name "shadowfile-tests" temporary-file-directory))
614 file2
615 (make-temp-name
616 (expand-file-name
617 "shadowfile-tests"
618 shadow-test-remote-temporary-file-directory))
619 mocked-input `(,cluster1 ,file1 ,cluster2 ,file2 ,(kbd "RET")))
620 (with-temp-buffer
621 (setq-local buffer-file-name file1)
622 (call-interactively 'shadow-define-literal-group))
623
624 ;; `shadow-literal-groups' is a list of lists.
625 (should (consp shadow-literal-groups))
626 (should (consp (car shadow-literal-groups)))
627 (should-not (cdr shadow-literal-groups))
628
629 (should (member (format "/%s:%s" cluster1 (file-local-name file1))
630 (car shadow-literal-groups)))
631 (should (member (format "/%s:%s" cluster2 (file-local-name file2))
632 (car shadow-literal-groups))))
633
634 ;; Cleanup.
635 (when (file-exists-p shadow-info-file)
636 (delete-file shadow-info-file))
637 (when (file-exists-p shadow-todo-file)
638 (delete-file shadow-todo-file)))))
639
640(ert-deftest shadow-test07-regexp-groups ()
641 "Check regexp group definitions."
642 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
643 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
644
645 (let ((shadow-info-file shadow-test-info-file)
646 (shadow-todo-file shadow-test-todo-file)
647 shadow-clusters shadow-regexp-groups
648 cluster1 cluster2 primary regexp file mocked-input)
649 (unwind-protect
650 ;; We must mock `read-from-minibuffer' and `read-string', in
651 ;; order to avoid interactive arguments.
652 (cl-letf* (((symbol-function 'read-from-minibuffer)
653 (lambda (&rest args) (pop mocked-input)))
654 ((symbol-function 'read-string)
655 (lambda (&rest args) (pop mocked-input))))
656
657 ;; Cleanup.
658 (when (file-exists-p shadow-info-file)
659 (delete-file shadow-info-file))
660 (when (file-exists-p shadow-todo-file)
661 (delete-file shadow-todo-file))
662
663 ;; Define clusters.
664 (setq cluster1 "cluster1"
665 primary shadow-system-name
666 regexp (shadow-regexp-superquote primary))
667 (shadow-set-cluster cluster1 primary regexp)
668
669 (setq cluster2 "cluster2"
670 primary
671 (file-remote-p shadow-test-remote-temporary-file-directory)
672 regexp (format "^\\(%s\\|%s\\)$" shadow-system-name primary))
673 (shadow-set-cluster cluster2 primary regexp)
674
675 ;; Define a regexp group.
676 (setq file
677 (make-temp-name
678 (expand-file-name "shadowfile-tests" temporary-file-directory))
679 mocked-input `(,(shadow-regexp-superquote file)
680 ,cluster1 ,cluster2 ,(kbd "RET")))
681 (with-temp-buffer
682 (setq-local buffer-file-name nil)
683 (call-interactively 'shadow-define-regexp-group))
684
685 ;; `shadow-regexp-groups' is a list of lists.
686 (should (consp shadow-regexp-groups))
687 (should (consp (car shadow-regexp-groups)))
688 (should-not (cdr shadow-regexp-groups))
689
690 (should
691 (member
692 (concat
693 (shadow-site-primary cluster1) (shadow-regexp-superquote file))
694 (car shadow-regexp-groups)))
695 (should
696 (member
697 (concat
698 (shadow-site-primary cluster2) (shadow-regexp-superquote file))
699 (car shadow-regexp-groups))))
700
701 ;; Cleanup.
702 (when (file-exists-p shadow-info-file)
703 (delete-file shadow-info-file))
704 (when (file-exists-p shadow-todo-file)
705 (delete-file shadow-todo-file)))))
706
707(ert-deftest shadow-test08-shadow-todo ()
708 "Check that needed shadows are added to todo."
709 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
710 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
711 (skip-unless (file-writable-p shadow-test-remote-temporary-file-directory))
712
713 (let ((backup-inhibited t)
714 (shadow-info-file shadow-test-info-file)
715 (shadow-todo-file shadow-test-todo-file)
716 (shadow-inhibit-message t)
717 shadow-clusters shadow-literal-groups shadow-regexp-groups
718 shadow-files-to-copy
719 cluster1 cluster2 primary regexp file)
720 (unwind-protect
721 (condition-case err
722 (progn
723 ;; Cleanup.
724 (when (file-exists-p shadow-info-file)
725 (delete-file shadow-info-file))
726 (when (file-exists-p shadow-todo-file)
727 (delete-file shadow-todo-file))
728
729 (message "Point 1")
730 ;; Define clusters.
731 (setq cluster1 "cluster1"
732 primary shadow-system-name
733 regexp (shadow-regexp-superquote primary))
734 (shadow-set-cluster cluster1 primary regexp)
735
736 (setq cluster2 "cluster2"
737 primary
738 (file-remote-p shadow-test-remote-temporary-file-directory)
739 regexp (shadow-regexp-superquote primary))
740 (shadow-set-cluster cluster2 primary regexp)
741
742 (message "Point 2")
743 ;; Define a literal group.
744 (setq file
745 (make-temp-name
746 (expand-file-name "shadowfile-tests" temporary-file-directory))
747 shadow-literal-groups
748 `((,(concat "/cluster1:" file) ,(concat "/cluster2:" file))))
749
750 (message "Point 3")
751 ;; Save file from "cluster1" definition.
752 (with-temp-buffer
753 (setq buffer-file-name file)
754 (insert "foo")
755 (save-buffer))
756 (message "%s" file)
757 (message "%s" (shadow-contract-file-name (concat "/cluster2:" file)))
758 (message "%s" shadow-files-to-copy)
759 (should
760 (member
761 (cons file (shadow-contract-file-name (concat "/cluster2:" file)))
762 shadow-files-to-copy))
763
764 (message "Point 4")
765 ;; Save file from "cluster2" definition.
766 (with-temp-buffer
767 (message "Point 4.1")
768 (message "%s" file)
769 (message "%s" (shadow-site-primary cluster2))
770 (setq buffer-file-name (concat (shadow-site-primary cluster2) file))
771 (message "Point 4.2")
772 (insert "foo")
773 (message "%s" buffer-file-name)
774 (save-buffer))
775 (message "Point 4.3")
776 (message "%s" (shadow-site-primary cluster2))
777 (message "%s" (shadow-contract-file-name (concat "/cluster1:" file)))
778 (message "%s" shadow-files-to-copy)
779 (should
780 (member
781 (cons
782 (concat (shadow-site-primary cluster2) file)
783 (shadow-contract-file-name (concat "/cluster1:" file)))
784 shadow-files-to-copy))
785
786 (message "Point 5")
787 ;; Define a regexp group.
788 (setq shadow-files-to-copy nil
789 shadow-regexp-groups
790 `((,(concat (shadow-site-primary cluster1)
791 (shadow-regexp-superquote file))
792 ,(concat (shadow-site-primary cluster2)
793 (shadow-regexp-superquote file)))))
794
795 (message "Point 6")
796 ;; Save file from "cluster1" definition.
797 (with-temp-buffer
798 (setq buffer-file-name file)
799 (insert "foo")
800 (save-buffer))
801 (should
802 (member
803 (cons file (shadow-contract-file-name (concat "/cluster2:" file)))
804 shadow-files-to-copy))
805
806 (message "Point 7")
807 ;; Save file from "cluster2" definition.
808 (with-temp-buffer
809 (setq buffer-file-name (concat (shadow-site-primary cluster2) file))
810 (insert "foo")
811 (save-buffer))
812 (should
813 (member
814 (cons
815 (concat (shadow-site-primary cluster2) file)
816 (shadow-contract-file-name (concat "/cluster1:" file)))
817 shadow-files-to-copy)))
818 (error (message "Error: %s" err) (signal (car err) (cdr err))))
819
820 ;; Cleanup.
821 (when (file-exists-p shadow-info-file)
822 (delete-file shadow-info-file))
823 (when (file-exists-p shadow-todo-file)
824 (delete-file shadow-todo-file))
825 (ignore-errors
826 (when (file-exists-p file)
827 (delete-file file)))
828 (ignore-errors
829 (when (file-exists-p (concat (shadow-site-primary cluster2) file))
830 (delete-file (concat (shadow-site-primary cluster2) file)))))))
831
832(ert-deftest shadow-test09-shadow-copy-files ()
833 "Check that needed shadow files are copied."
834 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
835 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
836
837 (let ((backup-inhibited t)
838 (shadow-info-file shadow-test-info-file)
839 (shadow-todo-file shadow-test-todo-file)
840 (shadow-inhibit-message t)
841 (shadow-noquery t)
842 shadow-clusters shadow-files-to-copy
843 cluster1 cluster2 primary regexp file mocked-input)
844 (unwind-protect
845 (progn
846 ;; Cleanup.
847 (when (file-exists-p shadow-info-file)
848 (delete-file shadow-info-file))
849 (when (file-exists-p shadow-todo-file)
850 (delete-file shadow-todo-file))
851 (when (buffer-live-p shadow-todo-buffer)
852 (with-current-buffer shadow-todo-buffer (erase-buffer)))
853
854 ;; Define clusters.
855 (setq cluster1 "cluster1"
856 primary shadow-system-name
857 regexp (shadow-regexp-superquote primary))
858 (shadow-set-cluster cluster1 primary regexp)
859
860 (setq cluster2 "cluster2"
861 primary
862 (file-remote-p shadow-test-remote-temporary-file-directory)
863 regexp (shadow-regexp-superquote primary))
864 (shadow-set-cluster cluster2 primary regexp)
865
866 ;; Define files to copy.
867 (setq file
868 (make-temp-name
869 (expand-file-name "shadowfile-tests" temporary-file-directory))
870 shadow-literal-groups
871 `((,(concat "/cluster1:" file) ,(concat "/cluster2:" file)))
872 shadow-regexp-groups
873 `((,(concat (shadow-site-primary cluster1)
874 (shadow-regexp-superquote file))
875 ,(concat (shadow-site-primary cluster2)
876 (shadow-regexp-superquote file))))
877 mocked-input `(,(concat (shadow-site-primary cluster2) file)
878 ,file))
879
880 ;; Save files.
881 (with-temp-buffer
882 (setq buffer-file-name file)
883 (insert "foo")
884 (save-buffer))
885 (with-temp-buffer
886 (setq buffer-file-name (concat (shadow-site-primary cluster2) file))
887 (insert "foo")
888 (save-buffer))
889
890 ;; We must mock `write-region', in order to check proper
891 ;; action.
892 (add-function
893 :before (symbol-function 'write-region)
894 (lambda (&rest args)
895 (when (and (buffer-file-name) mocked-input)
896 (should (equal (buffer-file-name) (pop mocked-input)))))
897 '((name . "write-region-mock")))
898
899 ;; Copy the files.
900 (shadow-copy-files 'noquery)
901 (should-not shadow-files-to-copy)
902 (with-current-buffer shadow-todo-buffer
903 (goto-char (point-min))
904 (should
905 (looking-at (regexp-quote "(setq shadow-files-to-copy nil)")))))
906
907 ;; Cleanup.
908 (remove-function (symbol-function 'write-region) "write-region-mock")
909 (when (file-exists-p shadow-info-file)
910 (delete-file shadow-info-file))
911 (when (file-exists-p shadow-todo-file)
912 (delete-file shadow-todo-file))
913 (ignore-errors
914 (when (file-exists-p file)
915 (delete-file file)))
916 (ignore-errors
917 (when (file-exists-p (concat (shadow-site-primary cluster2) file))
918 (delete-file (concat (shadow-site-primary cluster2) file)))))))
919
920(defun shadowfile-test-all (&optional interactive)
921 "Run all tests for \\[shadowfile]."
922 (interactive "p")
923 (if interactive
924 (ert-run-tests-interactively "^shadowfile-")
925 (ert-run-tests-batch "^shadowfile-")))
926
927(let ((shadow-info-file shadow-test-info-file)
928 (shadow-todo-file shadow-test-todo-file))
929 (shadow-initialize))
930
931(provide 'shadowfile-tests)
932;;; shadowfile-tests.el ends here
diff --git a/test/lisp/wdired-tests.el b/test/lisp/wdired-tests.el
new file mode 100644
index 00000000000..7199470ea96
--- /dev/null
+++ b/test/lisp/wdired-tests.el
@@ -0,0 +1,105 @@
1;;; wdired-tests.el --- tests for wdired.el -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2018 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
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.
11
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.
16
17;; You should have received a copy of the GNU General Public License
18;; along with this program. If not, see <https://www.gnu.org/licenses/>.
19
20;;; Code:
21
22(require 'ert)
23(require 'dired)
24
25(ert-deftest wdired-test-bug32173-01 ()
26 "Test using non-nil wdired-use-interactive-rename.
27Partially modifying a file name should succeed."
28 (let* ((test-dir (make-temp-file "test-dir-" t))
29 (test-file (concat (file-name-as-directory test-dir) "foo.c"))
30 (replace "bar")
31 (new-file (replace-regexp-in-string "foo" replace test-file))
32 (wdired-use-interactive-rename t))
33 (write-region "" nil test-file nil 'silent)
34 (advice-add 'dired-query ; Don't ask confirmation to overwrite a file.
35 :override
36 (lambda (_sym _prompt &rest _args) (setq dired-query t))
37 '((name . "advice-dired-query")))
38 (let ((buf (find-file-noselect test-dir)))
39 (unwind-protect
40 (with-current-buffer buf
41 (should (equal (dired-file-name-at-point) test-file))
42 (dired-toggle-read-only)
43 (kill-region (point) (progn (search-forward ".")
44 (forward-char -1) (point)))
45 (insert replace)
46 (wdired-finish-edit)
47 (should (equal (dired-file-name-at-point) new-file)))
48 (if buf (kill-buffer buf))
49 (delete-directory test-dir t)))))
50
51(ert-deftest wdired-test-bug32173-02 ()
52 "Test using non-nil wdired-use-interactive-rename.
53Aborting an edit should leaving original file name unchanged."
54 (let* ((test-dir (make-temp-file "test-dir-" t))
55 (test-file (concat (file-name-as-directory test-dir) "foo.c"))
56 (wdired-use-interactive-rename t))
57 (write-region "" nil test-file nil 'silent)
58 ;; Make dired-do-create-files-regexp a noop to mimic typing C-g
59 ;; at its prompt before wdired-finish-edit returns.
60 (advice-add 'dired-do-create-files-regexp
61 :override
62 (lambda (&rest _) (ignore))
63 '((name . "advice-dired-do-create-files-regexp")))
64 (let ((buf (find-file-noselect test-dir)))
65 (unwind-protect
66 (with-current-buffer buf
67 (should (equal (dired-file-name-at-point) test-file))
68 (dired-toggle-read-only)
69 (kill-region (point) (progn (search-forward ".")
70 (forward-char -1) (point)))
71 (insert "bar")
72 (wdired-finish-edit)
73 (should (equal (dired-get-filename) test-file)))
74 (if buf (kill-buffer buf))
75 (delete-directory test-dir t)))))
76
77(ert-deftest wdired-test-unfinished-edit-01 ()
78 "Test editing a file name without saving the change.
79Finding the new name should be possible while still in
80wdired-mode."
81 :expected-result (if (< emacs-major-version 27) :failed :passed)
82 (let* ((test-dir (make-temp-file "test-dir-" t))
83 (test-file (concat (file-name-as-directory test-dir) "foo.c"))
84 (replace "bar")
85 (new-file (replace-regexp-in-string "foo" replace test-file)))
86 (write-region "" nil test-file nil 'silent)
87 (let ((buf (find-file-noselect test-dir)))
88 (unwind-protect
89 (with-current-buffer buf
90 (should (equal (dired-file-name-at-point) test-file))
91 (dired-toggle-read-only)
92 (kill-region (point) (progn (search-forward ".")
93 (forward-char -1) (point)))
94 (insert replace)
95 (should (equal (dired-get-filename) new-file))))
96 (when buf
97 (with-current-buffer buf
98 ;; Prevent kill-buffer-query-functions from chiming in.
99 (set-buffer-modified-p nil)
100 (kill-buffer buf)))
101 (delete-directory test-dir t))))
102
103
104(provide 'wdired-tests)
105;;; wdired-tests.el ends here
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index c828000bb4f..2951270dbf7 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -165,10 +165,12 @@
165 :type 'overflow-error) 165 :type 'overflow-error)
166 (should-error (read (substring (format "%d" most-negative-fixnum) 1)) 166 (should-error (read (substring (format "%d" most-negative-fixnum) 1))
167 :type 'overflow-error) 167 :type 'overflow-error)
168 (should-error (read (format "#x%x" most-negative-fixnum)) 168 (let ((binary-as-unsigned nil))
169 :type 'overflow-error) 169 (dolist (fmt '("%d" "%s" "#o%o" "#x%x"))
170 (should-error (read (format "#o%o" most-negative-fixnum)) 170 (dolist (val (list most-negative-fixnum (1+ most-negative-fixnum)
171 :type 'overflow-error) 171 -1 0 1
172 (1- most-positive-fixnum) most-positive-fixnum))
173 (should (eq val (read (format fmt val)))))))
172 (should-error (read (format "#32rG%x" most-positive-fixnum)) 174 (should-error (read (format "#32rG%x" most-positive-fixnum))
173 :type 'overflow-error)) 175 :type 'overflow-error))
174 176
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index d9cca557cf2..e4b9cbe25a4 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -23,6 +23,17 @@
23 23
24(require 'cl-lib) 24(require 'cl-lib)
25 25
26;; Test that equality predicates work correctly on NaNs when combined
27;; with hash tables based on those predicates. This was not the case
28;; for eql in Emacs 26.
29(ert-deftest fns-tests-equality-nan ()
30 (dolist (test (list #'eq #'eql #'equal))
31 (let* ((h (make-hash-table :test test))
32 (nan 0.0e+NaN)
33 (-nan (- nan)))
34 (puthash nan t h)
35 (should (eq (funcall test nan -nan) (gethash -nan h))))))
36
26(ert-deftest fns-tests-reverse () 37(ert-deftest fns-tests-reverse ()
27 (should-error (reverse)) 38 (should-error (reverse))
28 (should-error (reverse 1)) 39 (should-error (reverse 1))
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
index a00a9c84bd6..364f6d61f05 100644
--- a/test/src/thread-tests.el
+++ b/test/src/thread-tests.el
@@ -34,10 +34,11 @@
34(declare-function thread--blocker "thread.c" (thread)) 34(declare-function thread--blocker "thread.c" (thread))
35(declare-function thread-alive-p "thread.c" (thread)) 35(declare-function thread-alive-p "thread.c" (thread))
36(declare-function thread-join "thread.c" (thread)) 36(declare-function thread-join "thread.c" (thread))
37(declare-function thread-last-error "thread.c" ()) 37(declare-function thread-last-error "thread.c" (&optional cleanup))
38(declare-function thread-name "thread.c" (thread)) 38(declare-function thread-name "thread.c" (thread))
39(declare-function thread-signal "thread.c" (thread error-symbol data)) 39(declare-function thread-signal "thread.c" (thread error-symbol data))
40(declare-function thread-yield "thread.c" ()) 40(declare-function thread-yield "thread.c" ())
41(defvar main-thread)
41 42
42(ert-deftest threads-is-one () 43(ert-deftest threads-is-one ()
43 "Test for existence of a thread." 44 "Test for existence of a thread."
@@ -71,6 +72,11 @@
71 (skip-unless (featurep 'threads)) 72 (skip-unless (featurep 'threads))
72 (should (listp (all-threads)))) 73 (should (listp (all-threads))))
73 74
75(ert-deftest threads-main-thread ()
76 "Simple test for all-threads."
77 (skip-unless (featurep 'threads))
78 (should (eq main-thread (car (all-threads)))))
79
74(defvar threads-test-global nil) 80(defvar threads-test-global nil)
75 81
76(defun threads-test-thread1 () 82(defun threads-test-thread1 ()
@@ -94,15 +100,24 @@
94 (progn 100 (progn
95 (setq threads-test-global nil) 101 (setq threads-test-global nil)
96 (let ((thread (make-thread #'threads-test-thread1))) 102 (let ((thread (make-thread #'threads-test-thread1)))
97 (thread-join thread) 103 (and (= (thread-join thread) 23)
98 (and threads-test-global 104 (= threads-test-global 23)
99 (not (thread-alive-p thread))))))) 105 (not (thread-alive-p thread)))))))
100 106
101(ert-deftest threads-join-self () 107(ert-deftest threads-join-self ()
102 "Cannot `thread-join' the current thread." 108 "Cannot `thread-join' the current thread."
103 (skip-unless (featurep 'threads)) 109 (skip-unless (featurep 'threads))
104 (should-error (thread-join (current-thread)))) 110 (should-error (thread-join (current-thread))))
105 111
112(ert-deftest threads-join-error ()
113 "Test of error signalling from `thread-join'."
114 :tags '(:unstable)
115 (skip-unless (featurep 'threads))
116 (let ((thread (make-thread #'threads-call-error)))
117 (while (thread-alive-p thread)
118 (thread-yield))
119 (should-error (thread-join thread))))
120
106(defvar threads-test-binding nil) 121(defvar threads-test-binding nil)
107 122
108(defun threads-test-thread2 () 123(defun threads-test-thread2 ()
@@ -191,7 +206,7 @@
191(ert-deftest threads-mutex-signal () 206(ert-deftest threads-mutex-signal ()
192 "Test signaling a blocked thread." 207 "Test signaling a blocked thread."
193 (skip-unless (featurep 'threads)) 208 (skip-unless (featurep 'threads))
194 (should 209 (should-error
195 (progn 210 (progn
196 (setq threads-mutex (make-mutex)) 211 (setq threads-mutex (make-mutex))
197 (setq threads-mutex-key nil) 212 (setq threads-mutex-key nil)
@@ -200,8 +215,10 @@
200 (while (not threads-mutex-key) 215 (while (not threads-mutex-key)
201 (thread-yield)) 216 (thread-yield))
202 (thread-signal thr 'quit nil) 217 (thread-signal thr 'quit nil)
203 (thread-join thr)) 218 ;; `quit' is not catched by `should-error'. We must indicate it.
204 t))) 219 (condition-case nil
220 (thread-join thr)
221 (quit (signal 'error nil)))))))
205 222
206(defun threads-test-io-switch () 223(defun threads-test-io-switch ()
207 (setq threads-test-global 23)) 224 (setq threads-test-global 23))
@@ -275,6 +292,9 @@
275 (thread-yield)) 292 (thread-yield))
276 (should (equal (thread-last-error) 293 (should (equal (thread-last-error)
277 '(error "Error is called"))) 294 '(error "Error is called")))
295 (should (equal (thread-last-error 'cleanup)
296 '(error "Error is called")))
297 (should-not (thread-last-error))
278 (setq th2 (make-thread #'threads-custom "threads-custom")) 298 (setq th2 (make-thread #'threads-custom "threads-custom"))
279 (should (threadp th2)))) 299 (should (threadp th2))))
280 300