aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorTom Tromey2018-08-09 17:56:53 -0600
committerTom Tromey2018-08-09 17:56:53 -0600
commitaccb7b7ecc19f85c2750ded1046a464bc73c6a52 (patch)
tree1aa94af022d6700a93a8ff2b73f5b210046ac010 /test
parentf822a2516d88eeb2118fbbc8554f155e86dfd74e (diff)
parent53483df0de0085dbc9ef0b15a0f629ab808b0147 (diff)
downloademacs-accb7b7ecc19f85c2750ded1046a464bc73c6a52.tar.gz
emacs-accb7b7ecc19f85c2750ded1046a464bc73c6a52.zip
Merge remote-tracking branch 'origin/master' into feature/bignum
Diffstat (limited to 'test')
-rw-r--r--test/lisp/auth-source-tests.el20
-rw-r--r--test/lisp/calendar/todo-mode-tests.el190
-rw-r--r--test/lisp/custom-tests.el87
-rw-r--r--test/lisp/emacs-lisp/backtrace-tests.el436
-rw-r--r--test/lisp/emacs-lisp/cl-print-tests.el178
-rw-r--r--test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el9
-rw-r--r--test/lisp/emacs-lisp/edebug-tests.el29
-rw-r--r--test/lisp/emacs-lisp/ert-tests.el2
-rw-r--r--test/lisp/emacs-lisp/lisp-mode-tests.el23
-rw-r--r--test/lisp/emacs-lisp/package-tests.el31
-rw-r--r--test/lisp/emacs-lisp/subr-x-tests.el47
-rw-r--r--test/lisp/epg-tests.el38
-rw-r--r--test/lisp/filenotify-tests.el4
-rw-r--r--test/lisp/net/secrets-tests.el6
-rw-r--r--test/lisp/net/tramp-archive-tests.el18
-rw-r--r--test/lisp/net/tramp-tests.el102
-rw-r--r--test/lisp/progmodes/compile-tests.el46
-rw-r--r--test/lisp/shadowfile-tests.el945
-rw-r--r--test/lisp/wdired-tests.el129
-rw-r--r--test/src/editfns-tests.el8
-rw-r--r--test/src/fns-tests.el11
-rw-r--r--test/src/regex-emacs-tests.el (renamed from test/src/regex-tests.el)6
-rw-r--r--test/src/thread-tests.el125
23 files changed, 2352 insertions, 138 deletions
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/calendar/todo-mode-tests.el b/test/lisp/calendar/todo-mode-tests.el
index 159294f8162..325faeff514 100644
--- a/test/lisp/calendar/todo-mode-tests.el
+++ b/test/lisp/calendar/todo-mode-tests.el
@@ -25,6 +25,7 @@
25;;; Code: 25;;; Code:
26 26
27(require 'ert) 27(require 'ert)
28(require 'ert-x)
28(require 'todo-mode) 29(require 'todo-mode)
29 30
30(defvar todo-test-data-dir 31(defvar todo-test-data-dir
@@ -561,11 +562,12 @@ source file is different."
561 ;; Headers in the todo file are still hidden. 562 ;; Headers in the todo file are still hidden.
562 (should (equal (overlay-get (todo-get-overlay 'header) 'display) ""))))) 563 (should (equal (overlay-get (todo-get-overlay 'header) 'display) "")))))
563 564
564(defun todo-test--insert-item (item &optional priority) 565(defun todo-test--insert-item (item &optional priority
566 _arg diary-type date-type time where)
565 "Insert string ITEM into current category with priority PRIORITY. 567 "Insert string ITEM into current category with priority PRIORITY.
566Use defaults for all other item insertion parameters. This 568The remaining arguments (except _ARG, which is ignored) specify
567provides a noninteractive API for todo-insert-item for use in 569item insertion parameters. This provides a noninteractive API
568automatic testing." 570for todo-insert-item for use in automatic testing."
569 (cl-letf (((symbol-function 'read-from-minibuffer) 571 (cl-letf (((symbol-function 'read-from-minibuffer)
570 (lambda (_prompt) item)) 572 (lambda (_prompt) item))
571 ((symbol-function 'read-number) ; For todo-set-item-priority 573 ((symbol-function 'read-number) ; For todo-set-item-priority
@@ -581,6 +583,186 @@ automatic testing."
581 (todo-test--insert-item item 1) 583 (todo-test--insert-item item 1)
582 (should (equal (overlay-get (todo-get-overlay 'header) 'display) ""))))) 584 (should (equal (overlay-get (todo-get-overlay 'header) 'display) "")))))
583 585
586(defun todo-test--done-items-separator (&optional eol)
587 "Set up test of command interaction with done items separator.
588With non-nil argument EOL, return the position at the end of the
589separator, otherwise, return the position at the beginning."
590 (todo-test--show 1)
591 (goto-char (point-max))
592 ;; See comment about recentering in todo-test-raise-lower-priority.
593 (set-window-buffer nil (current-buffer))
594 (todo-toggle-view-done-items)
595 ;; FIXME: Point should now be on the first done item, and in batch
596 ;; testing it is, so we have to move back one line to the done items
597 ;; separator; but for some reason, in the graphical test
598 ;; environment, it stays on the last empty line of the todo items
599 ;; section, so there we have to advance one character to the done
600 ;; items separator.
601 (if (display-graphic-p)
602 (forward-char)
603 (forward-line -1))
604 (if eol (forward-char)))
605
606(ert-deftest todo-test-done-items-separator01-bol ()
607 "Test item copying and here insertion at BOL of separator.
608Both should be user errors."
609 (with-todo-test
610 (todo-test--done-items-separator)
611 (let* ((copy-err "Item copying is not valid here")
612 (here-err "Item insertion is not valid here")
613 (insert-item-test (lambda (where)
614 (should-error (todo-insert-item--basic
615 nil nil nil nil where)))))
616 (should (string= copy-err (cadr (funcall insert-item-test 'copy))))
617 (should (string= here-err (cadr (funcall insert-item-test 'here)))))))
618
619(ert-deftest todo-test-done-items-separator01-eol ()
620 "Test item copying and here insertion at EOL of separator.
621Both should be user errors."
622 (with-todo-test
623 (todo-test--done-items-separator 'eol)
624 (let* ((copy-err "Item copying is not valid here")
625 (here-err "Item insertion is not valid here")
626 (insert-item-test (lambda (where)
627 (should-error (todo-insert-item--basic
628 nil nil nil nil where)))))
629 (should (string= copy-err (cadr (funcall insert-item-test 'copy))))
630 (should (string= here-err (cadr (funcall insert-item-test 'here)))))))
631
632(ert-deftest todo-test-done-items-separator02-bol ()
633 "Test item editing commands at BOL of done items separator.
634They should all be noops."
635 (with-todo-test
636 (todo-test--done-items-separator)
637 (should-not (todo-item-done))
638 (should-not (todo-raise-item-priority))
639 (should-not (todo-lower-item-priority))
640 (should-not (called-interactively-p #'todo-set-item-priority))
641 (should-not (called-interactively-p #'todo-move-item))
642 (should-not (called-interactively-p #'todo-delete-item))
643 (should-not (called-interactively-p #'todo-edit-item))))
644
645(ert-deftest todo-test-done-items-separator02-eol ()
646 "Test item editing command at EOL of done items separator.
647They should all be noops."
648 (with-todo-test
649 (todo-test--done-items-separator 'eol)
650 (should-not (todo-item-done))
651 (should-not (todo-raise-item-priority))
652 (should-not (todo-lower-item-priority))
653 (should-not (called-interactively-p #'todo-set-item-priority))
654 (should-not (called-interactively-p #'todo-move-item))
655 (should-not (called-interactively-p #'todo-delete-item))
656 (should-not (called-interactively-p #'todo-edit-item))))
657
658(ert-deftest todo-test-done-items-separator03-bol ()
659 "Test item marking at BOL of done items separator.
660This should be a noop, adding no marks to the category."
661 (with-todo-test
662 (todo-test--done-items-separator)
663 (call-interactively #'todo-toggle-mark-item)
664 (should-not (assoc (todo-current-category) todo-categories-with-marks))))
665
666(ert-deftest todo-test-done-items-separator03-eol ()
667 "Test item marking at EOL of done items separator.
668This should be a noop, adding no marks to the category."
669 (with-todo-test
670 (todo-test--done-items-separator 'eol)
671 (call-interactively #'todo-toggle-mark-item)
672 (should-not (assoc (todo-current-category) todo-categories-with-marks))))
673
674(ert-deftest todo-test-done-items-separator04-bol ()
675 "Test moving to previous item from BOL of done items separator.
676This should move point to the last not done todo item."
677 (with-todo-test
678 (todo-test--done-items-separator)
679 (let ((last-item (save-excursion
680 ;; Move to empty line after last todo item.
681 (forward-line -1)
682 (todo-previous-item)
683 (todo-item-string))))
684 (should (string= last-item (save-excursion
685 (todo-previous-item)
686 (todo-item-string)))))))
687
688(ert-deftest todo-test-done-items-separator04-eol ()
689 "Test moving to previous item from EOL of done items separator.
690This should move point to the last not done todo item."
691 (with-todo-test
692 (todo-test--done-items-separator 'eol)
693 (let ((last-item (save-excursion
694 ;; Move to empty line after last todo item.
695 (forward-line -1)
696 (todo-previous-item)
697 (todo-item-string))))
698 (should (string= last-item (save-excursion
699 (todo-previous-item)
700 (todo-item-string)))))))
701
702(ert-deftest todo-test-done-items-separator05-bol ()
703 "Test moving to next item from BOL of done items separator.
704This should move point to the first done todo item."
705 (with-todo-test
706 (todo-test--done-items-separator)
707 (let ((first-done (save-excursion
708 ;; Move to empty line after last todo item.
709 (forward-line -1)
710 (todo-next-item)
711 (todo-item-string))))
712 (should (string= first-done (save-excursion
713 (todo-next-item)
714 (todo-item-string)))))))
715
716(ert-deftest todo-test-done-items-separator05-eol ()
717 "Test moving to next item from EOL of done items separator.
718This should move point to the first done todo item."
719 (with-todo-test
720 (todo-test--done-items-separator 'eol)
721 (let ((first-done (save-excursion
722 ;; Move to empty line after last todo item.
723 (forward-line -1)
724 (todo-next-item)
725 (todo-item-string))))
726 (should (string= first-done (save-excursion
727 (todo-next-item)
728 (todo-item-string)))))))
729
730;; Item highlighting uses hl-line-mode, which enables highlighting in
731;; post-command-hook. For some reason, in the test environment, the
732;; hook function is not automatically run, so after enabling item
733;; highlighting, use ert-simulate-command around the next command,
734;; which explicitly runs the hook function.
735(ert-deftest todo-test-done-items-separator06-bol ()
736 "Test enabling item highlighting at BOL of done items separator.
737Subsequently moving to an item should show it highlighted."
738 (with-todo-test
739 (todo-test--done-items-separator)
740 (call-interactively #'todo-toggle-item-highlighting)
741 (ert-simulate-command '(todo-previous-item))
742 (should (eq 'hl-line (get-char-property (point) 'face)))))
743
744(ert-deftest todo-test-done-items-separator06-eol ()
745 "Test enabling item highlighting at EOL of done items separator.
746Subsequently moving to an item should show it highlighted."
747 (with-todo-test
748 (todo-test--done-items-separator 'eol)
749 (todo-toggle-item-highlighting)
750 (forward-line -1)
751 (ert-simulate-command '(todo-previous-item))
752 (should (eq 'hl-line (get-char-property (point) 'face)))))
753
754(ert-deftest todo-test-done-items-separator07 ()
755 "Test item highlighting when crossing done items separator.
756The highlighting should remain enabled."
757 (with-todo-test
758 (todo-test--done-items-separator)
759 (todo-previous-item)
760 (todo-toggle-item-highlighting)
761 (todo-next-item) ; Now on empty line above separator.
762 (forward-line) ; Now on separator.
763 (ert-simulate-command '(forward-line)) ; Now on first done item.
764 (should (eq 'hl-line (get-char-property (point) 'face)))))
765
584 766
585(provide 'todo-mode-tests) 767(provide 'todo-mode-tests)
586;;; todo-mode-tests.el ends here 768;;; todo-mode-tests.el ends here
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 00000000000..96887f8f5fe
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
1;;; custom-tests.el --- tests for custom.el -*- lexical-binding: t -*-
2
3;; Copyright (C) 2018 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs 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;; GNU Emacs 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
24(ert-deftest custom-theme--load-path ()
25 "Test `custom-theme--load-path' behavior."
26 (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
27 (unwind-protect
28 ;; Create all temporary files under the same deletable parent.
29 (let ((temporary-file-directory tmpdir))
30 ;; Path is empty.
31 (let ((custom-theme-load-path ()))
32 (should (null (custom-theme--load-path))))
33
34 ;; Path comprises non-existent file.
35 (let* ((name (make-temp-name tmpdir))
36 (custom-theme-load-path (list name)))
37 (should (not (file-exists-p name)))
38 (should (null (custom-theme--load-path))))
39
40 ;; Path comprises existing file.
41 (let* ((file (make-temp-file "file"))
42 (custom-theme-load-path (list file)))
43 (should (file-exists-p file))
44 (should (not (file-directory-p file)))
45 (should (null (custom-theme--load-path))))
46
47 ;; Path comprises existing directory.
48 (let* ((dir (make-temp-file "dir" t))
49 (custom-theme-load-path (list dir)))
50 (should (file-directory-p dir))
51 (should (equal (custom-theme--load-path) custom-theme-load-path)))
52
53 ;; Expand `custom-theme-directory' path element.
54 (let ((custom-theme-load-path '(custom-theme-directory)))
55 (let ((custom-theme-directory (make-temp-name tmpdir)))
56 (should (not (file-exists-p custom-theme-directory)))
57 (should (null (custom-theme--load-path))))
58 (let ((custom-theme-directory (make-temp-file "file")))
59 (should (file-exists-p custom-theme-directory))
60 (should (not (file-directory-p custom-theme-directory)))
61 (should (null (custom-theme--load-path))))
62 (let ((custom-theme-directory (make-temp-file "dir" t)))
63 (should (file-directory-p custom-theme-directory))
64 (should (equal (custom-theme--load-path)
65 (list custom-theme-directory)))))
66
67 ;; Expand t path element.
68 (let ((custom-theme-load-path '(t)))
69 (let ((data-directory (make-temp-name tmpdir)))
70 (should (not (file-exists-p data-directory)))
71 (should (null (custom-theme--load-path))))
72 (let ((data-directory tmpdir)
73 (themedir (expand-file-name "themes" tmpdir)))
74 (should (not (file-exists-p themedir)))
75 (should (null (custom-theme--load-path)))
76 (with-temp-file themedir)
77 (should (file-exists-p themedir))
78 (should (not (file-directory-p themedir)))
79 (should (null (custom-theme--load-path)))
80 (delete-file themedir)
81 (make-directory themedir)
82 (should (file-directory-p themedir))
83 (should (equal (custom-theme--load-path) (list themedir))))))
84 (when (file-directory-p tmpdir)
85 (delete-directory tmpdir t)))))
86
87;;; custom-tests.el ends here
diff --git a/test/lisp/emacs-lisp/backtrace-tests.el b/test/lisp/emacs-lisp/backtrace-tests.el
new file mode 100644
index 00000000000..edd45c770c5
--- /dev/null
+++ b/test/lisp/emacs-lisp/backtrace-tests.el
@@ -0,0 +1,436 @@
1;;; backtrace-tests.el --- Tests for backtraces -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2018 Free Software Foundation, Inc.
4
5;; Author: Gemini Lasswell
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
21
22;;; Code:
23
24(require 'backtrace)
25(require 'ert)
26(require 'ert-x)
27(require 'seq)
28
29;; Delay evaluation of the backtrace-creating functions until
30;; load so that the backtraces are the same whether this file
31;; is compiled or not.
32
33(eval-and-compile
34 (defconst backtrace-tests--uncompiled-functions
35 '(progn
36 (defun backtrace-tests--make-backtrace (arg)
37 (backtrace-tests--setup-buffer))
38
39 (defun backtrace-tests--setup-buffer ()
40 "Set up the current buffer in backtrace mode."
41 (backtrace-mode)
42 (setq backtrace-frames (backtrace-get-frames))
43 (let ((this-index))
44 ;; Discard all past `backtrace-tests-make-backtrace'.
45 (dotimes (index (length backtrace-frames))
46 (when (eq (backtrace-frame-fun (nth index backtrace-frames))
47 'backtrace-tests--make-backtrace)
48 (setq this-index index)))
49 (setq backtrace-frames (seq-subseq backtrace-frames 0 (1+ this-index))))
50 (backtrace-print))))
51
52 (eval backtrace-tests--uncompiled-functions))
53
54(defun backtrace-tests--backtrace-lines ()
55 (if debugger-stack-frame-as-list
56 '(" (backtrace-get-frames)\n"
57 " (setq backtrace-frames (backtrace-get-frames))\n"
58 " (backtrace-tests--setup-buffer)\n"
59 " (backtrace-tests--make-backtrace %s)\n")
60 '(" backtrace-get-frames()\n"
61 " (setq backtrace-frames (backtrace-get-frames))\n"
62 " backtrace-tests--setup-buffer()\n"
63 " backtrace-tests--make-backtrace(%s)\n")))
64
65(defconst backtrace-tests--line-count (length (backtrace-tests--backtrace-lines)))
66
67(defun backtrace-tests--backtrace-lines-with-locals ()
68 (let ((lines (backtrace-tests--backtrace-lines))
69 (locals '(" [no locals]\n"
70 " [no locals]\n"
71 " [no locals]\n"
72 " arg = %s\n")))
73 (apply #'append (cl-mapcar #'list lines locals))))
74
75(defun backtrace-tests--result (value)
76 (format (apply #'concat (backtrace-tests--backtrace-lines))
77 (cl-prin1-to-string value)))
78
79(defun backtrace-tests--result-with-locals (value)
80 (let ((str (cl-prin1-to-string value)))
81 (format (apply #'concat (backtrace-tests--backtrace-lines-with-locals))
82 str str)))
83
84;; TODO check that debugger-batch-max-lines still works
85
86(defconst backtrace-tests--header "Test header\n")
87(defun backtrace-tests--insert-header ()
88 (insert backtrace-tests--header))
89
90;;; Tests
91
92(ert-deftest backtrace-tests--variables ()
93 "Backtrace buffers can show and hide local variables."
94 (ert-with-test-buffer (:name "variables")
95 (let ((results (concat backtrace-tests--header
96 (backtrace-tests--result 'value)))
97 (last-frame (format (nth (1- backtrace-tests--line-count)
98 (backtrace-tests--backtrace-lines)) 'value))
99 (last-frame-with-locals
100 (format (apply #'concat (nthcdr (* 2 (1- backtrace-tests--line-count))
101 (backtrace-tests--backtrace-lines-with-locals)))
102 'value 'value)))
103 (backtrace-tests--make-backtrace 'value)
104 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
105 (backtrace-print)
106 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
107 results))
108 ;; Go to the last frame.
109 (goto-char (point-max))
110 (forward-line -1)
111 ;; Turn on locals for that frame.
112 (backtrace-toggle-locals)
113 (should (string= (backtrace-tests--get-substring (point) (point-max))
114 last-frame-with-locals))
115 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
116 (concat results
117 (format (car (last (backtrace-tests--backtrace-lines-with-locals)))
118 'value))))
119 ;; Turn off locals for that frame.
120 (backtrace-toggle-locals)
121 (should (string= (backtrace-tests--get-substring (point) (point-max))
122 last-frame))
123 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
124 results))
125 ;; Turn all locals on.
126 (backtrace-toggle-locals '(4))
127 (should (string= (backtrace-tests--get-substring (point) (point-max))
128 last-frame-with-locals))
129 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
130 (concat backtrace-tests--header
131 (backtrace-tests--result-with-locals 'value))))
132 ;; Turn all locals off.
133 (backtrace-toggle-locals '(4))
134 (should (string= (backtrace-tests--get-substring
135 (point) (+ (point) (length last-frame)))
136 last-frame))
137 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
138 results)))))
139
140(ert-deftest backtrace-tests--backward-frame ()
141 "`backtrace-backward-frame' moves backward to the start of a frame."
142 (ert-with-test-buffer (:name "backward")
143 (let ((results (concat backtrace-tests--header
144 (backtrace-tests--result nil))))
145 (backtrace-tests--make-backtrace nil)
146 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
147 (backtrace-print)
148 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
149 results))
150
151 ;; Try to move backward from header.
152 (goto-char (+ (point-min) (/ (length backtrace-tests--header) 2)))
153 (let ((pos (point)))
154 (should-error (backtrace-backward-frame))
155 (should (= pos (point))))
156
157 ;; Try to move backward from start of first line.
158 (forward-line)
159 (let ((pos (point)))
160 (should-error (backtrace-backward-frame))
161 (should (= pos (point))))
162
163 ;; Move backward from middle of line.
164 (let ((start (point)))
165 (forward-char (/ (length (nth 0 (backtrace-tests--backtrace-lines))) 2))
166 (backtrace-backward-frame)
167 (should (= start (point))))
168
169 ;; Move backward from end of buffer.
170 (goto-char (point-max))
171 (backtrace-backward-frame)
172 (let* ((last (format (car (last (backtrace-tests--backtrace-lines))) nil))
173 (len (length last)))
174 (should (string= (buffer-substring-no-properties (point) (+ (point) len))
175 last)))
176
177 ;; Move backward from start of line.
178 (backtrace-backward-frame)
179 (let* ((line (car (last (backtrace-tests--backtrace-lines) 2)))
180 (len (length line)))
181 (should (string= (buffer-substring-no-properties (point) (+ (point) len))
182 line))))))
183
184(ert-deftest backtrace-tests--forward-frame ()
185 "`backtrace-forward-frame' moves forward to the start of a frame."
186 (ert-with-test-buffer (:name "forward")
187 (let* ((arg '(1 2 3))
188 (results (concat backtrace-tests--header
189 (backtrace-tests--result arg)))
190 (first-line (nth 0 (backtrace-tests--backtrace-lines))))
191 (backtrace-tests--make-backtrace arg)
192 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
193 (backtrace-print)
194 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
195 results))
196 ;; Move forward from header.
197 (goto-char (+ (point-min) (/ (length backtrace-tests--header) 2)))
198 (backtrace-forward-frame)
199 (should (string= (backtrace-tests--get-substring
200 (point) (+ (point) (length first-line)))
201 first-line))
202
203 (let ((start (point))
204 (offset (/ (length first-line) 2))
205 (second-line (nth 1 (backtrace-tests--backtrace-lines))))
206 ;; Move forward from start of first frame.
207 (backtrace-forward-frame)
208 (should (string= (backtrace-tests--get-substring
209 (point) (+ (point) (length second-line)))
210 second-line))
211 ;; Move forward from middle of first frame.
212 (goto-char (+ start offset))
213 (backtrace-forward-frame)
214 (should (string= (backtrace-tests--get-substring
215 (point) (+ (point) (length second-line)))
216 second-line)))
217 ;; Try to move forward from middle of last frame.
218 (goto-char (- (point-max)
219 (/ 2 (length (car (last (backtrace-tests--backtrace-lines)))))))
220 (should-error (backtrace-forward-frame))
221 ;; Try to move forward from end of buffer.
222 (goto-char (point-max))
223 (should-error (backtrace-forward-frame)))))
224
225(ert-deftest backtrace-tests--single-and-multi-line ()
226 "Forms in backtrace frames can be on a single line or on multiple lines."
227 (ert-with-test-buffer (:name "single-multi-line")
228 (let* ((arg '(lambda (x) ; Quote this so it isn't made into a closure.
229 (let ((number (1+ x)))
230 (+ x number))))
231 (header-string "Test header: ")
232 (header (format "%s%s\n" header-string arg))
233 (insert-header-function (lambda ()
234 (insert header-string)
235 (insert (backtrace-print-to-string arg))
236 (insert "\n")))
237 (results (concat header (backtrace-tests--result arg)))
238 (last-line (format (nth (1- backtrace-tests--line-count)
239 (backtrace-tests--backtrace-lines))
240 arg))
241 (last-line-locals (format (nth (1- (* 2 backtrace-tests--line-count))
242 (backtrace-tests--backtrace-lines-with-locals))
243 arg)))
244
245 (backtrace-tests--make-backtrace arg)
246 (setq backtrace-insert-header-function insert-header-function)
247 (backtrace-print)
248 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
249 results))
250 ;; Check pp and collapse for the form in the header.
251 (goto-char (point-min))
252 (backtrace-tests--verify-single-and-multi-line header)
253 ;; Check pp and collapse for the last frame.
254 (goto-char (point-max))
255 (backtrace-backward-frame)
256 (backtrace-tests--verify-single-and-multi-line last-line)
257 ;; Check pp and collapse for local variables in the last line.
258 (goto-char (point-max))
259 (backtrace-backward-frame)
260 (backtrace-toggle-locals)
261 (forward-line)
262 (backtrace-tests--verify-single-and-multi-line last-line-locals))))
263
264(defun backtrace-tests--verify-single-and-multi-line (line)
265 "Verify that `backtrace-single-line' and `backtrace-multi-line' work at point.
266Point should be at the beginning of a line, and LINE should be a
267string containing the text of the line at point. Assume that the
268line contains the strings \"lambda\" and \"number\"."
269 (let ((pos (point)))
270 (backtrace-multi-line)
271 ;; Verify point is still at the start of the line.
272 (should (= pos (point))))
273
274 ;; Verify the form now spans multiple lines.
275 (let ((pos (point)))
276 (search-forward "number")
277 (should-not (= pos (point-at-bol))))
278 ;; Collapse the form.
279 (backtrace-single-line)
280 ;; Verify that the form is now back on one line,
281 ;; and that point is at the same place.
282 (should (string= (backtrace-tests--get-substring
283 (- (point) 6) (point)) "number"))
284 (should-not (= (point) (point-at-bol)))
285 (should (string= (backtrace-tests--get-substring
286 (point-at-bol) (1+ (point-at-eol)))
287 line)))
288
289(ert-deftest backtrace-tests--print-circle ()
290 "Backtrace buffers can toggle `print-circle' syntax."
291 (ert-with-test-buffer (:name "print-circle")
292 (let* ((print-circle nil)
293 (arg (let ((val (make-list 5 'a))) (nconc val val) val))
294 (results (backtrace-tests--make-regexp
295 (backtrace-tests--result arg)))
296 (results-circle (regexp-quote (let ((print-circle t))
297 (backtrace-tests--result arg))))
298 (last-frame (backtrace-tests--make-regexp
299 (format (nth (1- backtrace-tests--line-count)
300 (backtrace-tests--backtrace-lines))
301 arg)))
302 (last-frame-circle (regexp-quote
303 (let ((print-circle t))
304 (format (nth (1- backtrace-tests--line-count)
305 (backtrace-tests--backtrace-lines))
306 arg)))))
307 (backtrace-tests--make-backtrace arg)
308 (backtrace-print)
309 (should (string-match-p results
310 (backtrace-tests--get-substring (point-min) (point-max))))
311 ;; Go to the last frame.
312 (goto-char (point-max))
313 (forward-line -1)
314 ;; Turn on print-circle for that frame.
315 (backtrace-toggle-print-circle)
316 (should (string-match-p last-frame-circle
317 (backtrace-tests--get-substring (point) (point-max))))
318 ;; Turn off print-circle for the frame.
319 (backtrace-toggle-print-circle)
320 (should (string-match-p last-frame
321 (backtrace-tests--get-substring (point) (point-max))))
322 (should (string-match-p results
323 (backtrace-tests--get-substring (point-min) (point-max))))
324 ;; Turn print-circle on for the buffer.
325 (backtrace-toggle-print-circle '(4))
326 (should (string-match-p last-frame-circle
327 (backtrace-tests--get-substring (point) (point-max))))
328 (should (string-match-p results-circle
329 (backtrace-tests--get-substring (point-min) (point-max))))
330 ;; Turn print-circle off.
331 (backtrace-toggle-print-circle '(4))
332 (should (string-match-p last-frame
333 (backtrace-tests--get-substring
334 (point) (+ (point) (length last-frame)))))
335 (should (string-match-p results
336 (backtrace-tests--get-substring (point-min) (point-max)))))))
337
338(defun backtrace-tests--make-regexp (str)
339 "Make regexp from STR for `backtrace-tests--print-circle'.
340Used for results of printing circular objects without
341`print-circle' on. Look for #n in string STR where n is any
342digit and replace with #[0-9]."
343 (let ((regexp (regexp-quote str)))
344 (with-temp-buffer
345 (insert regexp)
346 (goto-char (point-min))
347 (while (re-search-forward "#[0-9]" nil t)
348 (replace-match "#[0-9]")))
349 (buffer-string)))
350
351(ert-deftest backtrace-tests--expand-ellipsis ()
352 "Backtrace buffers ellipsify large forms as buttons which expand the ellipses."
353 ;; make a backtrace with an ellipsis
354 ;; expand the ellipsis
355 (ert-with-test-buffer (:name "variables")
356 (let* ((print-level nil)
357 (print-length nil)
358 (backtrace-line-length 300)
359 (arg (make-list 40 (make-string 10 ?a)))
360 (results (backtrace-tests--result arg)))
361 (backtrace-tests--make-backtrace arg)
362 (backtrace-print)
363
364 ;; There should be an ellipsis. Find and expand it.
365 (goto-char (point-min))
366 (search-forward "...")
367 (backward-char)
368 (push-button)
369
370 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
371 results)))))
372
373(ert-deftest backtrace-tests--expand-ellipses ()
374 "Backtrace buffers ellipsify large forms and can expand the ellipses."
375 (ert-with-test-buffer (:name "variables")
376 (let* ((print-level nil)
377 (print-length nil)
378 (backtrace-line-length 300)
379 (arg (let ((outer (make-list 40 (make-string 10 ?a)))
380 (nested (make-list 40 (make-string 10 ?b))))
381 (setf (nth 39 nested) (make-list 40 (make-string 10 ?c)))
382 (setf (nth 39 outer) nested)
383 outer))
384 (results (backtrace-tests--result-with-locals arg)))
385
386 ;; Make a backtrace with local variables visible.
387 (backtrace-tests--make-backtrace arg)
388 (backtrace-print)
389 (backtrace-toggle-locals '(4))
390
391 ;; There should be two ellipses.
392 (goto-char (point-min))
393 (should (search-forward "..."))
394 (should (search-forward "..."))
395 (should-error (search-forward "..."))
396
397 ;; Expanding the last frame without argument should expand both
398 ;; ellipses, but the expansions will contain one ellipsis each.
399 (let ((buffer-len (- (point-max) (point-min))))
400 (goto-char (point-max))
401 (backtrace-backward-frame)
402 (backtrace-expand-ellipses)
403 (should (> (- (point-max) (point-min)) buffer-len))
404 (goto-char (point-min))
405 (should (search-forward "..."))
406 (should (search-forward "..."))
407 (should-error (search-forward "...")))
408
409 ;; Expanding with argument should remove all ellipses.
410 (goto-char (point-max))
411 (backtrace-backward-frame)
412 (backtrace-expand-ellipses '(4))
413 (goto-char (point-min))
414
415 (should-error (search-forward "..."))
416 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
417 results)))))
418
419
420(ert-deftest backtrace-tests--to-string ()
421 "Backtraces can be produced as strings."
422 (let ((frames (ert-with-test-buffer (:name nil)
423 (backtrace-tests--make-backtrace "string")
424 backtrace-frames)))
425 (should (string= (backtrace-to-string frames)
426 (backtrace-tests--result "string")))))
427
428(defun backtrace-tests--get-substring (beg end)
429 "Return the visible text between BEG and END.
430Strip the string properties because it makes failed test results
431easier to read."
432 (substring-no-properties (filter-buffer-substring beg end)))
433
434(provide 'backtrace-tests)
435
436;;; backtrace-tests.el ends here
diff --git a/test/lisp/emacs-lisp/cl-print-tests.el b/test/lisp/emacs-lisp/cl-print-tests.el
index 404d323d0c1..a469b5526c0 100644
--- a/test/lisp/emacs-lisp/cl-print-tests.el
+++ b/test/lisp/emacs-lisp/cl-print-tests.el
@@ -56,19 +56,30 @@
56 (let ((long-list (make-list 5 'a)) 56 (let ((long-list (make-list 5 'a))
57 (long-vec (make-vector 5 'b)) 57 (long-vec (make-vector 5 'b))
58 (long-struct (cl-print-tests-con)) 58 (long-struct (cl-print-tests-con))
59 (long-string (make-string 5 ?a))
59 (print-length 4)) 60 (print-length 4))
60 (should (equal "(a a a a ...)" (cl-prin1-to-string long-list))) 61 (should (equal "(a a a a ...)" (cl-prin1-to-string long-list)))
61 (should (equal "[b b b b ...]" (cl-prin1-to-string long-vec))) 62 (should (equal "[b b b b ...]" (cl-prin1-to-string long-vec)))
62 (should (equal "#s(cl-print-tests-struct :a nil :b nil :c nil :d nil ...)" 63 (should (equal "#s(cl-print-tests-struct :a nil :b nil :c nil :d nil ...)"
63 (cl-prin1-to-string long-struct))))) 64 (cl-prin1-to-string long-struct)))
65 (should (equal "\"aaaa...\"" (cl-prin1-to-string long-string)))))
64 66
65(ert-deftest cl-print-tests-4 () 67(ert-deftest cl-print-tests-4 ()
66 "CL printing observes `print-level'." 68 "CL printing observes `print-level'."
67 (let ((deep-list '(a (b (c (d (e)))))) 69 (let* ((deep-list '(a (b (c (d (e))))))
68 (deep-struct (cl-print-tests-con)) 70 (buried-vector '(a (b (c (d [e])))))
69 (print-level 4)) 71 (deep-struct (cl-print-tests-con))
72 (buried-struct `(a (b (c (d ,deep-struct)))))
73 (buried-string '(a (b (c (d #("hello" 0 5 (cl-print-test t)))))))
74 (buried-simple-string '(a (b (c (d "hello")))))
75 (print-level 4))
70 (setf (cl-print-tests-struct-a deep-struct) deep-list) 76 (setf (cl-print-tests-struct-a deep-struct) deep-list)
71 (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string deep-list))) 77 (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string deep-list)))
78 (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-vector)))
79 (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-struct)))
80 (should (equal "(a (b (c (d ...))))" (cl-prin1-to-string buried-string)))
81 (should (equal "(a (b (c (d \"hello\"))))"
82 (cl-prin1-to-string buried-simple-string)))
72 (should (equal "#s(cl-print-tests-struct :a (a (b (c ...))) :b nil :c nil :d nil :e nil)" 83 (should (equal "#s(cl-print-tests-struct :a (a (b (c ...))) :b nil :c nil :d nil :e nil)"
73 (cl-prin1-to-string deep-struct))))) 84 (cl-prin1-to-string deep-struct)))))
74 85
@@ -82,6 +93,129 @@
82 (should (equal "((quote a) (function b) (\\` ((\\, c) (\\,@ d))))" 93 (should (equal "((quote a) (function b) (\\` ((\\, c) (\\,@ d))))"
83 (cl-prin1-to-string quoted-stuff)))))) 94 (cl-prin1-to-string quoted-stuff))))))
84 95
96(ert-deftest cl-print-tests-strings ()
97 "CL printing prints strings and propertized strings."
98 (let* ((str1 "abcdefghij")
99 (str2 #("abcdefghij" 3 6 (bold t) 7 9 (italic t)))
100 (str3 #("abcdefghij" 0 10 (test t)))
101 (obj '(a b))
102 ;; Since the byte compiler reuses string literals,
103 ;; and the put-text-property call is destructive, use
104 ;; copy-sequence to make a new string.
105 (str4 (copy-sequence "abcdefghij")))
106 (put-text-property 0 5 'test obj str4)
107 (put-text-property 7 10 'test obj str4)
108
109 (should (equal "\"abcdefghij\"" (cl-prin1-to-string str1)))
110 (should (equal "#(\"abcdefghij\" 3 6 (bold t) 7 9 (italic t))"
111 (cl-prin1-to-string str2)))
112 (should (equal "#(\"abcdefghij\" 0 10 (test t))"
113 (cl-prin1-to-string str3)))
114 (let ((print-circle nil))
115 (should
116 (equal
117 "#(\"abcdefghij\" 0 5 (test (a b)) 7 10 (test (a b)))"
118 (cl-prin1-to-string str4))))
119 (let ((print-circle t))
120 (should
121 (equal
122 "#(\"abcdefghij\" 0 5 (test #1=(a b)) 7 10 (test #1#))"
123 (cl-prin1-to-string str4))))))
124
125(ert-deftest cl-print-tests-ellipsis-cons ()
126 "Ellipsis expansion works in conses."
127 (let ((print-length 4)
128 (print-level 3))
129 (cl-print-tests-check-ellipsis-expansion
130 '(0 1 2 3 4 5) "(0 1 2 3 ...)" "4 5")
131 (cl-print-tests-check-ellipsis-expansion
132 '(0 1 2 3 4 5 6 7 8 9) "(0 1 2 3 ...)" "4 5 6 7 ...")
133 (cl-print-tests-check-ellipsis-expansion
134 '(a (b (c (d (e))))) "(a (b (c ...)))" "(d (e))")
135 (cl-print-tests-check-ellipsis-expansion
136 (let ((x (make-list 6 'b)))
137 (setf (nthcdr 6 x) 'c)
138 x)
139 "(b b b b ...)" "b b . c")))
140
141(ert-deftest cl-print-tests-ellipsis-vector ()
142 "Ellipsis expansion works in vectors."
143 (let ((print-length 4)
144 (print-level 3))
145 (cl-print-tests-check-ellipsis-expansion
146 [0 1 2 3 4 5] "[0 1 2 3 ...]" "4 5")
147 (cl-print-tests-check-ellipsis-expansion
148 [0 1 2 3 4 5 6 7 8 9] "[0 1 2 3 ...]" "4 5 6 7 ...")
149 (cl-print-tests-check-ellipsis-expansion
150 [a [b [c [d [e]]]]] "[a [b [c ...]]]" "[d [e]]")))
151
152(ert-deftest cl-print-tests-ellipsis-string ()
153 "Ellipsis expansion works in strings."
154 (let ((print-length 4)
155 (print-level 3))
156 (cl-print-tests-check-ellipsis-expansion
157 "abcdefg" "\"abcd...\"" "efg")
158 (cl-print-tests-check-ellipsis-expansion
159 "abcdefghijk" "\"abcd...\"" "efgh...")
160 (cl-print-tests-check-ellipsis-expansion
161 '(1 (2 (3 #("abcde" 0 5 (test t)))))
162 "(1 (2 (3 ...)))" "#(\"abcd...\" 0 5 (test t))")
163 (cl-print-tests-check-ellipsis-expansion
164 #("abcd" 0 1 (bold t) 1 2 (invisible t) 3 4 (italic t))
165 "#(\"abcd\" 0 1 (bold t) ...)" "1 2 (invisible t) ...")))
166
167(ert-deftest cl-print-tests-ellipsis-struct ()
168 "Ellipsis expansion works in structures."
169 (let ((print-length 4)
170 (print-level 3)
171 (struct (cl-print-tests-con)))
172 (cl-print-tests-check-ellipsis-expansion
173 struct "#s(cl-print-tests-struct :a nil :b nil :c nil :d nil ...)" ":e nil")
174 (let ((print-length 2))
175 (cl-print-tests-check-ellipsis-expansion
176 struct "#s(cl-print-tests-struct :a nil :b nil ...)" ":c nil :d nil ..."))
177 (cl-print-tests-check-ellipsis-expansion
178 `(a (b (c ,struct)))
179 "(a (b (c ...)))"
180 "#s(cl-print-tests-struct :a nil :b nil :c nil :d nil ...)")))
181
182(ert-deftest cl-print-tests-ellipsis-circular ()
183 "Ellipsis expansion works with circular objects."
184 (let ((wide-obj (list 0 1 2 3 4))
185 (deep-obj `(0 (1 (2 (3 (4))))))
186 (print-length 4)
187 (print-level 3))
188 (setf (nth 4 wide-obj) wide-obj)
189 (setf (car (cadadr (cadadr deep-obj))) deep-obj)
190 (let ((print-circle nil))
191 (cl-print-tests-check-ellipsis-expansion-rx
192 wide-obj (regexp-quote "(0 1 2 3 ...)") "\\`#[0-9]\\'")
193 (cl-print-tests-check-ellipsis-expansion-rx
194 deep-obj (regexp-quote "(0 (1 (2 ...)))") "\\`(3 (#[0-9]))\\'"))
195 (let ((print-circle t))
196 (cl-print-tests-check-ellipsis-expansion
197 wide-obj "#1=(0 1 2 3 ...)" "#1#")
198 (cl-print-tests-check-ellipsis-expansion
199 deep-obj "#1=(0 (1 (2 ...)))" "(3 (#1#))"))))
200
201(defun cl-print-tests-check-ellipsis-expansion (obj expected expanded)
202 (let* ((result (cl-prin1-to-string obj))
203 (pos (next-single-property-change 0 'cl-print-ellipsis result))
204 value)
205 (should pos)
206 (setq value (get-text-property pos 'cl-print-ellipsis result))
207 (should (equal expected result))
208 (should (equal expanded (with-output-to-string (cl-print-expand-ellipsis
209 value nil))))))
210
211(defun cl-print-tests-check-ellipsis-expansion-rx (obj expected expanded)
212 (let* ((result (cl-prin1-to-string obj))
213 (pos (next-single-property-change 0 'cl-print-ellipsis result))
214 (value (get-text-property pos 'cl-print-ellipsis result)))
215 (should (string-match expected result))
216 (should (string-match expanded (with-output-to-string
217 (cl-print-expand-ellipsis value nil))))))
218
85(ert-deftest cl-print-circle () 219(ert-deftest cl-print-circle ()
86 (let ((x '(#1=(a . #1#) #1#))) 220 (let ((x '(#1=(a . #1#) #1#)))
87 (let ((print-circle nil)) 221 (let ((print-circle nil))
@@ -99,5 +233,41 @@
99 (let ((print-circle t)) 233 (let ((print-circle t))
100 (should (equal "(0 . #1=(0 . #1#))" (cl-prin1-to-string x)))))) 234 (should (equal "(0 . #1=(0 . #1#))" (cl-prin1-to-string x))))))
101 235
236(ert-deftest cl-print-tests-print-to-string-with-limit ()
237 (let* ((thing10 (make-list 10 'a))
238 (thing100 (make-list 100 'a))
239 (thing10x10 (make-list 10 thing10))
240 (nested-thing (let ((val 'a))
241 (dotimes (_i 20)
242 (setq val (list val)))
243 val))
244 ;; Make a consistent environment for this test.
245 (print-circle nil)
246 (print-level nil)
247 (print-length nil))
248
249 ;; Print something that fits in the space given.
250 (should (string= (cl-prin1-to-string thing10)
251 (cl-print-to-string-with-limit #'cl-prin1 thing10 100)))
252
253 ;; Print something which needs to be abbreviated and which can be.
254 (should (< (length (cl-print-to-string-with-limit #'cl-prin1 thing100 100))
255 100
256 (length (cl-prin1-to-string thing100))))
257
258 ;; Print something resistant to easy abbreviation.
259 (should (string= (cl-prin1-to-string thing10x10)
260 (cl-print-to-string-with-limit #'cl-prin1 thing10x10 100)))
261
262 ;; Print something which should be abbreviated even if the limit is large.
263 (should (< (length (cl-print-to-string-with-limit #'cl-prin1 nested-thing 1000))
264 (length (cl-prin1-to-string nested-thing))))
265
266 ;; Print with no limits.
267 (dolist (thing (list thing10 thing100 thing10x10 nested-thing))
268 (let ((rep (cl-prin1-to-string thing)))
269 (should (string= rep (cl-print-to-string-with-limit #'cl-prin1 thing 0)))
270 (should (string= rep (cl-print-to-string-with-limit #'cl-prin1 thing nil)))))))
271
102 272
103;;; cl-print-tests.el ends here. 273;;; cl-print-tests.el ends here.
diff --git a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
index e86c2f1c1e7..97dead057a9 100644
--- a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
+++ b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
@@ -41,7 +41,7 @@
41(defun edebug-test-code-range (num) 41(defun edebug-test-code-range (num)
42 !start!(let ((index 0) 42 !start!(let ((index 0)
43 (result nil)) 43 (result nil))
44 (while (< index num)!test! 44 (while !lt!(< index num)!test!
45 (push index result)!loop! 45 (push index result)!loop!
46 (cl-incf index))!end-loop! 46 (cl-incf index))!end-loop!
47 (nreverse result))) 47 (nreverse result)))
@@ -130,5 +130,12 @@
130 (let ((two 2) (three 3)) 130 (let ((two 2) (three 3))
131 (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!)))) 131 (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!))))
132 132
133(defun edebug-test-code-use-cl-macrolet (x)
134 (cl-macrolet ((wrap (func &rest args)
135 `(format "The result of applying %s to %s is %S"
136 ',func!func! ',args
137 ,(cons func args))))
138 (wrap + 1 x)))
139
133(provide 'edebug-test-code) 140(provide 'edebug-test-code)
134;;; edebug-test-code.el ends here 141;;; edebug-test-code.el ends here
diff --git a/test/lisp/emacs-lisp/edebug-tests.el b/test/lisp/emacs-lisp/edebug-tests.el
index 85f6bd47db2..7880aaf95bc 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -432,9 +432,11 @@ test and possibly others should be updated."
432 (verify-keybinding "P" 'edebug-view-outside) ;; same as v 432 (verify-keybinding "P" 'edebug-view-outside) ;; same as v
433 (verify-keybinding "W" 'edebug-toggle-save-windows) 433 (verify-keybinding "W" 'edebug-toggle-save-windows)
434 (verify-keybinding "?" 'edebug-help) 434 (verify-keybinding "?" 'edebug-help)
435 (verify-keybinding "d" 'edebug-backtrace) 435 (verify-keybinding "d" 'edebug-pop-to-backtrace)
436 (verify-keybinding "-" 'negative-argument) 436 (verify-keybinding "-" 'negative-argument)
437 (verify-keybinding "=" 'edebug-temp-display-freq-count))) 437 (verify-keybinding "=" 'edebug-temp-display-freq-count)
438 (should (eq (lookup-key backtrace-mode-map "n") 'backtrace-forward-frame))
439 (should (eq (lookup-key backtrace-mode-map "s") 'backtrace-goto-source))))
438 440
439(ert-deftest edebug-tests-stop-point-at-start-of-first-instrumented-function () 441(ert-deftest edebug-tests-stop-point-at-start-of-first-instrumented-function ()
440 "Edebug stops at the beginning of an instrumented function." 442 "Edebug stops at the beginning of an instrumented function."
@@ -913,5 +915,28 @@ test and possibly others should be updated."
913 "g" 915 "g"
914 (should (equal edebug-tests-@-result 5))))) 916 (should (equal edebug-tests-@-result 5)))))
915 917
918(ert-deftest edebug-tests-cl-macrolet ()
919 "Edebug can instrument `cl-macrolet' expressions. (Bug#29919)"
920 (edebug-tests-with-normal-env
921 (edebug-tests-setup-@ "use-cl-macrolet" '(10) t)
922 (edebug-tests-run-kbd-macro
923 "@ SPC SPC"
924 (edebug-tests-should-be-at "use-cl-macrolet" "func")
925 (edebug-tests-should-match-result-in-messages "+")
926 "g"
927 (should (equal edebug-tests-@-result "The result of applying + to (1 x) is 11")))))
928
929(ert-deftest edebug-tests-backtrace-goto-source ()
930 "Edebug can jump to instrumented source from its *Edebug-Backtrace* buffer."
931 (edebug-tests-with-normal-env
932 (edebug-tests-setup-@ "range" '(2) t)
933 (edebug-tests-run-kbd-macro
934 "@ SPC SPC"
935 (edebug-tests-should-be-at "range" "lt")
936 "dns" ; Pop to backtrace, next frame, goto source.
937 (edebug-tests-should-be-at "range" "start")
938 "g"
939 (should (equal edebug-tests-@-result '(0 1))))))
940
916(provide 'edebug-tests) 941(provide 'edebug-tests)
917;;; edebug-tests.el ends here 942;;; edebug-tests.el ends here
diff --git a/test/lisp/emacs-lisp/ert-tests.el b/test/lisp/emacs-lisp/ert-tests.el
index cb957bd9fd6..1fe5b79ef36 100644
--- a/test/lisp/emacs-lisp/ert-tests.el
+++ b/test/lisp/emacs-lisp/ert-tests.el
@@ -376,7 +376,7 @@ This macro is used to test if macroexpansion in `should' works."
376 (test (make-ert-test :body test-body)) 376 (test (make-ert-test :body test-body))
377 (result (ert-run-test test))) 377 (result (ert-run-test test)))
378 (should (ert-test-failed-p result)) 378 (should (ert-test-failed-p result))
379 (should (eq (nth 1 (car (ert-test-failed-backtrace result))) 379 (should (eq (backtrace-frame-fun (car (ert-test-failed-backtrace result)))
380 'signal)))) 380 'signal))))
381 381
382(ert-deftest ert-test-messages () 382(ert-deftest ert-test-messages ()
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 db6d103a2ef..f08bc92ff2a 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -112,7 +112,7 @@
112 upload-base) 112 upload-base)
113 &rest body) 113 &rest body)
114 "Set up temporary locations and variables for testing." 114 "Set up temporary locations and variables for testing."
115 (declare (indent 1)) 115 (declare (indent 1) (debug (([&rest form]) body)))
116 `(let* ((package-test-user-dir (make-temp-file "pkg-test-user-dir-" t)) 116 `(let* ((package-test-user-dir (make-temp-file "pkg-test-user-dir-" t))
117 (process-environment (cons (format "HOME=%s" package-test-user-dir) 117 (process-environment (cons (format "HOME=%s" package-test-user-dir)
118 process-environment)) 118 process-environment))
@@ -158,6 +158,7 @@
158 158
159(defmacro with-fake-help-buffer (&rest body) 159(defmacro with-fake-help-buffer (&rest body)
160 "Execute BODY in a temp buffer which is treated as the \"*Help*\" buffer." 160 "Execute BODY in a temp buffer which is treated as the \"*Help*\" buffer."
161 (declare (debug body))
161 `(with-temp-buffer 162 `(with-temp-buffer
162 (help-mode) 163 (help-mode)
163 ;; Trick `help-buffer' into using the temp buffer. 164 ;; Trick `help-buffer' into using the temp buffer.
@@ -467,15 +468,23 @@ Must called from within a `tar-mode' buffer."
467 468
468(ert-deftest package-test-signed () 469(ert-deftest package-test-signed ()
469 "Test verifying package signature." 470 "Test verifying package signature."
470 (skip-unless (ignore-errors 471 (skip-unless (let ((homedir (make-temp-file "package-test" t)))
471 (let ((homedir (make-temp-file "package-test" t))) 472 (unwind-protect
472 (unwind-protect 473 (let ((process-environment
473 (let ((process-environment 474 (cons (concat "HOME=" homedir)
474 (cons (format "HOME=%s" homedir) 475 process-environment)))
475 process-environment))) 476 (epg-find-configuration
476 (epg-check-configuration 477 'OpenPGP nil
477 (epg-find-configuration 'OpenPGP))) 478 ;; By default we require gpg2 2.1+ due to some
478 (delete-directory homedir t))))) 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)))
487 (delete-directory homedir t))))
479 (let* ((keyring (expand-file-name "key.pub" package-test-data-dir)) 488 (let* ((keyring (expand-file-name "key.pub" package-test-data-dir))
480 (package-test-data-dir 489 (package-test-data-dir
481 (expand-file-name "package-resources/signed" package-test-file-dir))) 490 (expand-file-name "package-resources/signed" package-test-file-dir)))
@@ -506,7 +515,7 @@ Must called from within a `tar-mode' buffer."
506 (with-fake-help-buffer 515 (with-fake-help-buffer
507 (describe-package 'signed-good) 516 (describe-package 'signed-good)
508 (goto-char (point-min)) 517 (goto-char (point-min))
509 (should (re-search-forward "signed-good is an? \\(\\S-+\\) package." nil t)) 518 (should (re-search-forward "Package signed-good is \\(\\S-+\\)\\." nil t))
510 (should (string-equal (match-string-no-properties 1) "installed")) 519 (should (string-equal (match-string-no-properties 1) "installed"))
511 (should (re-search-forward 520 (should (re-search-forward
512 "Status: Installed in ['`‘]signed-good-1.0/['’]." 521 "Status: Installed in ['`‘]signed-good-1.0/['’]."
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f6..81467bab2d4 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
532 (format "abs sum is: %s")) 532 (format "abs sum is: %s"))
533 "abs sum is: 15"))) 533 "abs sum is: 15")))
534 534
535
536;; Substring tests
537
538(ert-deftest subr-x-test-string-trim-left ()
539 "Test `string-trim-left' behavior."
540 (should (equal (string-trim-left "") ""))
541 (should (equal (string-trim-left " \t\n\r") ""))
542 (should (equal (string-trim-left " \t\n\ra") "a"))
543 (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
544 (should (equal (string-trim-left "" "") ""))
545 (should (equal (string-trim-left "a" "") "a"))
546 (should (equal (string-trim-left "aa" "a*") ""))
547 (should (equal (string-trim-left "ba" "a*") "ba"))
548 (should (equal (string-trim-left "aa" "a*?") "aa"))
549 (should (equal (string-trim-left "aa" "a+?") "a")))
550
551(ert-deftest subr-x-test-string-trim-right ()
552 "Test `string-trim-right' behavior."
553 (should (equal (string-trim-right "") ""))
554 (should (equal (string-trim-right " \t\n\r") ""))
555 (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
556 (should (equal (string-trim-right "a \t\n\r") "a"))
557 (should (equal (string-trim-right "" "") ""))
558 (should (equal (string-trim-right "a" "") "a"))
559 (should (equal (string-trim-right "aa" "a*") ""))
560 (should (equal (string-trim-right "ab" "a*") "ab"))
561 (should (equal (string-trim-right "aa" "a*?") "")))
562
563(ert-deftest subr-x-test-string-remove-prefix ()
564 "Test `string-remove-prefix' behavior."
565 (should (equal (string-remove-prefix "" "") ""))
566 (should (equal (string-remove-prefix "" "a") "a"))
567 (should (equal (string-remove-prefix "a" "") ""))
568 (should (equal (string-remove-prefix "a" "b") "b"))
569 (should (equal (string-remove-prefix "a" "a") ""))
570 (should (equal (string-remove-prefix "a" "aa") "a"))
571 (should (equal (string-remove-prefix "a" "ab") "b")))
572
573(ert-deftest subr-x-test-string-remove-suffix ()
574 "Test `string-remove-suffix' behavior."
575 (should (equal (string-remove-suffix "" "") ""))
576 (should (equal (string-remove-suffix "" "a") "a"))
577 (should (equal (string-remove-suffix "a" "") ""))
578 (should (equal (string-remove-suffix "a" "b") "b"))
579 (should (equal (string-remove-suffix "a" "a") ""))
580 (should (equal (string-remove-suffix "a" "aa") "a"))
581 (should (equal (string-remove-suffix "a" "ba") "b")))
535 582
536(provide 'subr-x-tests) 583(provide 'subr-x-tests)
537;;; subr-x-tests.el ends here 584;;; subr-x-tests.el ends here
diff --git a/test/lisp/epg-tests.el b/test/lisp/epg-tests.el
index 7efe04bfc00..c1e98a6935e 100644
--- a/test/lisp/epg-tests.el
+++ b/test/lisp/epg-tests.el
@@ -32,17 +32,26 @@
32 32
33(defconst epg-tests--config-program-alist 33(defconst epg-tests--config-program-alist
34 ;; The default `epg-config--program-alist' requires gpg2 2.1 or 34 ;; The default `epg-config--program-alist' requires gpg2 2.1 or
35 ;; greater due to some practical problems with pinentry. But the 35 ;; greater due to some practical problems with pinentry. But most
36 ;; tests here all work fine with 2.0 as well. 36 ;; tests here work fine with 2.0 as well.
37 (let ((prog-alist (copy-sequence epg-config--program-alist))) 37 (let ((prog-alist (copy-tree epg-config--program-alist)))
38 (setf (alist-get "gpg2" 38 (setf (alist-get "gpg2"
39 (alist-get 'OpenPGP prog-alist) 39 (alist-get 'OpenPGP prog-alist)
40 nil nil #'equal) 40 nil nil #'equal)
41 "2.0") 41 "2.0")
42 prog-alist)) 42 prog-alist))
43 43
44(defun epg-tests-find-usable-gpg-configuration (&optional _require-passphrase) 44(defun epg-tests-find-usable-gpg-configuration
45 (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)))
46 55
47(defun epg-tests-passphrase-callback (_c _k _d) 56(defun epg-tests-passphrase-callback (_c _k _d)
48 ;; 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
@@ -62,12 +71,14 @@
62 (format "GNUPGHOME=%s" epg-tests-home-directory)) 71 (format "GNUPGHOME=%s" epg-tests-home-directory))
63 process-environment))) 72 process-environment)))
64 (unwind-protect 73 (unwind-protect
65 (let ((context (epg-make-context 'OpenPGP))) 74 ;; GNUPGHOME is needed to find a usable gpg, so we can't
75 ;; check whether to skip any earlier (Bug#23561).
76 (let ((epg-config (or (epg-tests-find-usable-gpg-configuration
77 ,require-passphrase ,require-public-key)
78 (ert-skip "No usable gpg config")))
79 (context (epg-make-context 'OpenPGP)))
66 (setf (epg-context-program context) 80 (setf (epg-context-program context)
67 (alist-get 'program 81 (alist-get 'program epg-config))
68 (epg-tests-find-usable-gpg-configuration
69 ,(if require-passphrase
70 `'require-passphrase))))
71 (setf (epg-context-home-directory context) 82 (setf (epg-context-home-directory context)
72 epg-tests-home-directory) 83 epg-tests-home-directory)
73 ,(if require-passphrase 84 ,(if require-passphrase
@@ -96,7 +107,6 @@
96 (delete-directory epg-tests-home-directory t))))) 107 (delete-directory epg-tests-home-directory t)))))
97 108
98(ert-deftest epg-decrypt-1 () 109(ert-deftest epg-decrypt-1 ()
99 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
100 (with-epg-tests (:require-passphrase t) 110 (with-epg-tests (:require-passphrase t)
101 (should (equal "test" 111 (should (equal "test"
102 (epg-decrypt-string epg-tests-context "\ 112 (epg-decrypt-string epg-tests-context "\
@@ -108,14 +118,12 @@ jA0EAwMCE19JBLTvvmhgyRrGGglRbnKkK9PJG8fDwO5ccjysrR7IcdNcnA==
108-----END PGP MESSAGE-----"))))) 118-----END PGP MESSAGE-----")))))
109 119
110(ert-deftest epg-roundtrip-1 () 120(ert-deftest epg-roundtrip-1 ()
111 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
112 (with-epg-tests (:require-passphrase t) 121 (with-epg-tests (:require-passphrase t)
113 (let ((cipher (epg-encrypt-string epg-tests-context "symmetric" nil))) 122 (let ((cipher (epg-encrypt-string epg-tests-context "symmetric" nil)))
114 (should (equal "symmetric" 123 (should (equal "symmetric"
115 (epg-decrypt-string epg-tests-context cipher)))))) 124 (epg-decrypt-string epg-tests-context cipher))))))
116 125
117(ert-deftest epg-roundtrip-2 () 126(ert-deftest epg-roundtrip-2 ()
118 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
119 (with-epg-tests (:require-passphrase t 127 (with-epg-tests (:require-passphrase t
120 :require-public-key t 128 :require-public-key t
121 :require-secret-key t) 129 :require-secret-key t)
@@ -126,7 +134,6 @@ jA0EAwMCE19JBLTvvmhgyRrGGglRbnKkK9PJG8fDwO5ccjysrR7IcdNcnA==
126 (epg-decrypt-string epg-tests-context cipher)))))) 134 (epg-decrypt-string epg-tests-context cipher))))))
127 135
128(ert-deftest epg-sign-verify-1 () 136(ert-deftest epg-sign-verify-1 ()
129 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
130 (with-epg-tests (:require-passphrase t 137 (with-epg-tests (:require-passphrase t
131 :require-public-key t 138 :require-public-key t
132 :require-secret-key t) 139 :require-secret-key t)
@@ -140,7 +147,6 @@ jA0EAwMCE19JBLTvvmhgyRrGGglRbnKkK9PJG8fDwO5ccjysrR7IcdNcnA==
140 (should (eq 'good (epg-signature-status (car verify-result))))))) 147 (should (eq 'good (epg-signature-status (car verify-result)))))))
141 148
142(ert-deftest epg-sign-verify-2 () 149(ert-deftest epg-sign-verify-2 ()
143 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
144 (with-epg-tests (:require-passphrase t 150 (with-epg-tests (:require-passphrase t
145 :require-public-key t 151 :require-public-key t
146 :require-secret-key t) 152 :require-secret-key t)
@@ -156,7 +162,6 @@ jA0EAwMCE19JBLTvvmhgyRrGGglRbnKkK9PJG8fDwO5ccjysrR7IcdNcnA==
156 (should (eq 'good (epg-signature-status (car verify-result))))))) 162 (should (eq 'good (epg-signature-status (car verify-result)))))))
157 163
158(ert-deftest epg-sign-verify-3 () 164(ert-deftest epg-sign-verify-3 ()
159 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
160 (with-epg-tests (:require-passphrase t 165 (with-epg-tests (:require-passphrase t
161 :require-public-key t 166 :require-public-key t
162 :require-secret-key t) 167 :require-secret-key t)
@@ -171,7 +176,6 @@ jA0EAwMCE19JBLTvvmhgyRrGGglRbnKkK9PJG8fDwO5ccjysrR7IcdNcnA==
171 (should (eq 'good (epg-signature-status (car verify-result))))))) 176 (should (eq 'good (epg-signature-status (car verify-result)))))))
172 177
173(ert-deftest epg-import-1 () 178(ert-deftest epg-import-1 ()
174 (skip-unless (epg-tests-find-usable-gpg-configuration 'require-passphrase))
175 (with-epg-tests (:require-passphrase nil) 179 (with-epg-tests (:require-passphrase nil)
176 (should (= 0 (length (epg-list-keys epg-tests-context)))) 180 (should (= 0 (length (epg-list-keys epg-tests-context))))
177 (should (= 0 (length (epg-list-keys epg-tests-context nil t))))) 181 (should (= 0 (length (epg-list-keys epg-tests-context nil t)))))
diff --git a/test/lisp/filenotify-tests.el b/test/lisp/filenotify-tests.el
index 56403f43092..612ea8cd7f4 100644
--- a/test/lisp/filenotify-tests.el
+++ b/test/lisp/filenotify-tests.el
@@ -891,9 +891,9 @@ delivered."
891 891
892 ;; Modify file. We wait for two seconds, in order to 892 ;; Modify file. We wait for two seconds, in order to
893 ;; have another timestamp. One second seems to be too 893 ;; have another timestamp. One second seems to be too
894 ;; short. 894 ;; short. And Cygwin sporadically requires more than two.
895 (ert-with-message-capture captured-messages 895 (ert-with-message-capture captured-messages
896 (sleep-for 2) 896 (sleep-for (if (eq system-type 'cygwin) 3 2))
897 (write-region 897 (write-region
898 "foo bla" nil file-notify--test-tmpfile nil 'no-message) 898 "foo bla" nil file-notify--test-tmpfile nil 'no-message)
899 899
diff --git a/test/lisp/net/secrets-tests.el b/test/lisp/net/secrets-tests.el
index 9aa79dab0eb..de3ce731bec 100644
--- a/test/lisp/net/secrets-tests.el
+++ b/test/lisp/net/secrets-tests.el
@@ -92,7 +92,8 @@
92 (should (secrets-open-session)) 92 (should (secrets-open-session))
93 93
94 ;; There must be at least the collections "Login" and "session". 94 ;; There must be at least the collections "Login" and "session".
95 (should (member "Login" (secrets-list-collections))) 95 (should (or (member "Login" (secrets-list-collections))
96 (member "login" (secrets-list-collections))))
96 (should (member "session" (secrets-list-collections))) 97 (should (member "session" (secrets-list-collections)))
97 98
98 ;; Create a random collection. This asks for a password 99 ;; Create a random collection. This asks for a password
@@ -160,7 +161,8 @@
160 ;; There shall be no items in the "session" collection. 161 ;; There shall be no items in the "session" collection.
161 (should-not (secrets-list-items "session")) 162 (should-not (secrets-list-items "session"))
162 ;; There shall be items in the "Login" collection. 163 ;; There shall be items in the "Login" collection.
163 (should (secrets-list-items "Login")) 164 (should (or (secrets-list-items "Login")
165 (secrets-list-items "login")))
164 166
165 ;; Create a new item. 167 ;; Create a new item.
166 (should (setq item-path (secrets-create-item "session" "foo" "secret"))) 168 (should (setq item-path (secrets-create-item "session" "foo" "secret")))
diff --git a/test/lisp/net/tramp-archive-tests.el b/test/lisp/net/tramp-archive-tests.el
index 0a8716be0d7..e7597864c6e 100644
--- a/test/lisp/net/tramp-archive-tests.el
+++ b/test/lisp/net/tramp-archive-tests.el
@@ -311,6 +311,7 @@ This checks also `file-name-as-directory', `file-name-directory',
311 311
312(ert-deftest tramp-archive-test07-file-exists-p () 312(ert-deftest tramp-archive-test07-file-exists-p ()
313 "Check `file-exist-p', `write-region' and `delete-file'." 313 "Check `file-exist-p', `write-region' and `delete-file'."
314 :tags '(:expensive-test)
314 (skip-unless tramp-archive-enabled) 315 (skip-unless tramp-archive-enabled)
315 316
316 (unwind-protect 317 (unwind-protect
@@ -333,6 +334,7 @@ This checks also `file-name-as-directory', `file-name-directory',
333 334
334(ert-deftest tramp-archive-test08-file-local-copy () 335(ert-deftest tramp-archive-test08-file-local-copy ()
335 "Check `file-local-copy'." 336 "Check `file-local-copy'."
337 :tags '(:expensive-test)
336 (skip-unless tramp-archive-enabled) 338 (skip-unless tramp-archive-enabled)
337 339
338 (let (tmp-name) 340 (let (tmp-name)
@@ -359,6 +361,7 @@ This checks also `file-name-as-directory', `file-name-directory',
359 361
360(ert-deftest tramp-archive-test09-insert-file-contents () 362(ert-deftest tramp-archive-test09-insert-file-contents ()
361 "Check `insert-file-contents'." 363 "Check `insert-file-contents'."
364 :tags '(:expensive-test)
362 (skip-unless tramp-archive-enabled) 365 (skip-unless tramp-archive-enabled)
363 366
364 (let ((tmp-name (expand-file-name "bar/bar" tramp-archive-test-archive))) 367 (let ((tmp-name (expand-file-name "bar/bar" tramp-archive-test-archive)))
@@ -385,6 +388,7 @@ This checks also `file-name-as-directory', `file-name-directory',
385 388
386(ert-deftest tramp-archive-test11-copy-file () 389(ert-deftest tramp-archive-test11-copy-file ()
387 "Check `copy-file'." 390 "Check `copy-file'."
391 :tags '(:expensive-test)
388 (skip-unless tramp-archive-enabled) 392 (skip-unless tramp-archive-enabled)
389 393
390 ;; Copy simple file. 394 ;; Copy simple file.
@@ -450,6 +454,7 @@ This checks also `file-name-as-directory', `file-name-directory',
450 454
451(ert-deftest tramp-archive-test15-copy-directory () 455(ert-deftest tramp-archive-test15-copy-directory ()
452 "Check `copy-directory'." 456 "Check `copy-directory'."
457 :tags '(:expensive-test)
453 (skip-unless tramp-archive-enabled) 458 (skip-unless tramp-archive-enabled)
454 459
455 (let* ((tmp-name1 (expand-file-name "bar" tramp-archive-test-archive)) 460 (let* ((tmp-name1 (expand-file-name "bar" tramp-archive-test-archive))
@@ -504,6 +509,7 @@ This checks also `file-name-as-directory', `file-name-directory',
504 509
505(ert-deftest tramp-archive-test16-directory-files () 510(ert-deftest tramp-archive-test16-directory-files ()
506 "Check `directory-files'." 511 "Check `directory-files'."
512 :tags '(:expensive-test)
507 (skip-unless tramp-archive-enabled) 513 (skip-unless tramp-archive-enabled)
508 514
509 (let ((tmp-name tramp-archive-test-archive) 515 (let ((tmp-name tramp-archive-test-archive)
@@ -527,6 +533,7 @@ This checks also `file-name-as-directory', `file-name-directory',
527 533
528(ert-deftest tramp-archive-test17-insert-directory () 534(ert-deftest tramp-archive-test17-insert-directory ()
529 "Check `insert-directory'." 535 "Check `insert-directory'."
536 :tags '(:expensive-test)
530 (skip-unless tramp-archive-enabled) 537 (skip-unless tramp-archive-enabled)
531 538
532 (let (;; We test for the summary line. Keyword "total" could be localized. 539 (let (;; We test for the summary line. Keyword "total" could be localized.
@@ -569,6 +576,7 @@ This checks also `file-name-as-directory', `file-name-directory',
569(ert-deftest tramp-archive-test18-file-attributes () 576(ert-deftest tramp-archive-test18-file-attributes ()
570 "Check `file-attributes'. 577 "Check `file-attributes'.
571This tests also `file-readable-p' and `file-regular-p'." 578This tests also `file-readable-p' and `file-regular-p'."
579 :tags '(:expensive-test)
572 (skip-unless tramp-archive-enabled) 580 (skip-unless tramp-archive-enabled)
573 581
574 (let ((tmp-name1 (expand-file-name "foo.txt" tramp-archive-test-archive)) 582 (let ((tmp-name1 (expand-file-name "foo.txt" tramp-archive-test-archive))
@@ -619,6 +627,7 @@ This tests also `file-readable-p' and `file-regular-p'."
619 627
620(ert-deftest tramp-archive-test19-directory-files-and-attributes () 628(ert-deftest tramp-archive-test19-directory-files-and-attributes ()
621 "Check `directory-files-and-attributes'." 629 "Check `directory-files-and-attributes'."
630 :tags '(:expensive-test)
622 (skip-unless tramp-archive-enabled) 631 (skip-unless tramp-archive-enabled)
623 632
624 (let ((tmp-name (expand-file-name "bar" tramp-archive-test-archive)) 633 (let ((tmp-name (expand-file-name "bar" tramp-archive-test-archive))
@@ -644,6 +653,7 @@ This tests also `file-readable-p' and `file-regular-p'."
644(ert-deftest tramp-archive-test20-file-modes () 653(ert-deftest tramp-archive-test20-file-modes ()
645 "Check `file-modes'. 654 "Check `file-modes'.
646This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." 655This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
656 :tags '(:expensive-test)
647 (skip-unless tramp-archive-enabled) 657 (skip-unless tramp-archive-enabled)
648 658
649 (let ((tmp-name1 (expand-file-name "foo.txt" tramp-archive-test-archive)) 659 (let ((tmp-name1 (expand-file-name "foo.txt" tramp-archive-test-archive))
@@ -673,6 +683,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
673 683
674(ert-deftest tramp-archive-test21-file-links () 684(ert-deftest tramp-archive-test21-file-links ()
675 "Check `file-symlink-p' and `file-truename'" 685 "Check `file-symlink-p' and `file-truename'"
686 :tags '(:expensive-test)
676 (skip-unless tramp-archive-enabled) 687 (skip-unless tramp-archive-enabled)
677 688
678 ;; We must use `file-truename' for the file archive, because it 689 ;; We must use `file-truename' for the file archive, because it
@@ -711,6 +722,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
711 722
712(ert-deftest tramp-archive-test26-file-name-completion () 723(ert-deftest tramp-archive-test26-file-name-completion ()
713 "Check `file-name-completion' and `file-name-all-completions'." 724 "Check `file-name-completion' and `file-name-all-completions'."
725 :tags '(:expensive-test)
714 (skip-unless tramp-archive-enabled) 726 (skip-unless tramp-archive-enabled)
715 727
716 (let ((tmp-name tramp-archive-test-archive)) 728 (let ((tmp-name tramp-archive-test-archive))
@@ -802,8 +814,9 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
802 (zerop (nth 1 fsi)) 814 (zerop (nth 1 fsi))
803 (zerop (nth 2 fsi)))))) 815 (zerop (nth 2 fsi))))))
804 816
805(ert-deftest tramp-archive-test43-auto-load () 817(ert-deftest tramp-archive-test44-auto-load ()
806 "Check that `tramp-archive' autoloads properly." 818 "Check that `tramp-archive' autoloads properly."
819 :tags '(:expensive-test)
807 (skip-unless tramp-archive-enabled) 820 (skip-unless tramp-archive-enabled)
808 ;; Autoloading tramp-archive works since Emacs 27.1. 821 ;; Autoloading tramp-archive works since Emacs 27.1.
809 (skip-unless (tramp-archive--test-emacs27-p)) 822 (skip-unless (tramp-archive--test-emacs27-p))
@@ -832,8 +845,9 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
832 (mapconcat 'shell-quote-argument load-path " -L ") 845 (mapconcat 'shell-quote-argument load-path " -L ")
833 (shell-quote-argument (format code file))))))))) 846 (shell-quote-argument (format code file)))))))))
834 847
835(ert-deftest tramp-archive-test43-delay-load () 848(ert-deftest tramp-archive-test44-delay-load ()
836 "Check that `tramp-archive' is loaded lazily, only when needed." 849 "Check that `tramp-archive' is loaded lazily, only when needed."
850 :tags '(:expensive-test)
837 (skip-unless tramp-archive-enabled) 851 (skip-unless tramp-archive-enabled)
838 ;; Autoloading tramp-archive works since Emacs 27.1. 852 ;; Autoloading tramp-archive works since Emacs 27.1.
839 (skip-unless (tramp-archive--test-emacs27-p)) 853 (skip-unless (tramp-archive--test-emacs27-p))
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 5c5eff8798d..293a0054560 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -2182,7 +2182,7 @@ This checks also `file-name-as-directory', `file-name-directory',
2182 (unwind-protect 2182 (unwind-protect
2183 ;; FIXME: This fails on my QNAP server, see 2183 ;; FIXME: This fails on my QNAP server, see
2184 ;; /share/Web/owncloud/data/owncloud.log 2184 ;; /share/Web/owncloud/data/owncloud.log
2185 (unless (tramp--test-owncloud-p) 2185 (unless (tramp--test-nextcloud-p)
2186 (write-region "foo" nil source) 2186 (write-region "foo" nil source)
2187 (should (file-exists-p source)) 2187 (should (file-exists-p source))
2188 (make-directory target) 2188 (make-directory target)
@@ -2205,7 +2205,7 @@ This checks also `file-name-as-directory', `file-name-directory',
2205 (unwind-protect 2205 (unwind-protect
2206 ;; FIXME: This fails on my QNAP server, see 2206 ;; FIXME: This fails on my QNAP server, see
2207 ;; /share/Web/owncloud/data/owncloud.log 2207 ;; /share/Web/owncloud/data/owncloud.log
2208 (unless (and (tramp--test-owncloud-p) 2208 (unless (and (tramp--test-nextcloud-p)
2209 (or (not (file-remote-p source)) 2209 (or (not (file-remote-p source))
2210 (not (file-remote-p target)))) 2210 (not (file-remote-p target))))
2211 (make-directory source) 2211 (make-directory source)
@@ -2231,7 +2231,7 @@ This checks also `file-name-as-directory', `file-name-directory',
2231 ;; FIXME: This fails on my QNAP server, see 2231 ;; FIXME: This fails on my QNAP server, see
2232 ;; /share/Web/owncloud/data/owncloud.log 2232 ;; /share/Web/owncloud/data/owncloud.log
2233 (unless 2233 (unless
2234 (and (tramp--test-owncloud-p) (not (file-remote-p source))) 2234 (and (tramp--test-nextcloud-p) (not (file-remote-p source)))
2235 (make-directory source) 2235 (make-directory source)
2236 (should (file-directory-p source)) 2236 (should (file-directory-p source))
2237 (write-region "foo" nil (expand-file-name "foo" source)) 2237 (write-region "foo" nil (expand-file-name "foo" source))
@@ -2320,7 +2320,7 @@ This checks also `file-name-as-directory', `file-name-directory',
2320 (unwind-protect 2320 (unwind-protect
2321 ;; FIXME: This fails on my QNAP server, see 2321 ;; FIXME: This fails on my QNAP server, see
2322 ;; /share/Web/owncloud/data/owncloud.log 2322 ;; /share/Web/owncloud/data/owncloud.log
2323 (unless (tramp--test-owncloud-p) 2323 (unless (tramp--test-nextcloud-p)
2324 (make-directory source) 2324 (make-directory source)
2325 (should (file-directory-p source)) 2325 (should (file-directory-p source))
2326 (write-region "foo" nil (expand-file-name "foo" source)) 2326 (write-region "foo" nil (expand-file-name "foo" source))
@@ -2344,7 +2344,7 @@ This checks also `file-name-as-directory', `file-name-directory',
2344 (unwind-protect 2344 (unwind-protect
2345 ;; FIXME: This fails on my QNAP server, see 2345 ;; FIXME: This fails on my QNAP server, see
2346 ;; /share/Web/owncloud/data/owncloud.log 2346 ;; /share/Web/owncloud/data/owncloud.log
2347 (unless (tramp--test-owncloud-p) 2347 (unless (tramp--test-nextcloud-p)
2348 (make-directory source) 2348 (make-directory source)
2349 (should (file-directory-p source)) 2349 (should (file-directory-p source))
2350 (write-region "foo" nil (expand-file-name "foo" source)) 2350 (write-region "foo" nil (expand-file-name "foo" source))
@@ -4427,10 +4427,10 @@ This does not support external Emacs calls."
4427 (string-equal 4427 (string-equal
4428 "mock" (file-remote-p tramp-test-temporary-file-directory 'method))) 4428 "mock" (file-remote-p tramp-test-temporary-file-directory 'method)))
4429 4429
4430(defun tramp--test-owncloud-p () 4430(defun tramp--test-nextcloud-p ()
4431 "Check, whether the owncloud method is used." 4431 "Check, whether the nextcloud method is used."
4432 (string-equal 4432 (string-equal
4433 "owncloud" (file-remote-p tramp-test-temporary-file-directory 'method))) 4433 "nextcloud" (file-remote-p tramp-test-temporary-file-directory 'method)))
4434 4434
4435(defun tramp--test-rsync-p () 4435(defun tramp--test-rsync-p ()
4436 "Check, whether the rsync method is used. 4436 "Check, whether the rsync method is used.
@@ -5056,6 +5056,8 @@ process sentinels. They shall not disturb each other."
5056;; This test is inspired by Bug#29163. 5056;; This test is inspired by Bug#29163.
5057(ert-deftest tramp-test43-auto-load () 5057(ert-deftest tramp-test43-auto-load ()
5058 "Check that Tramp autoloads properly." 5058 "Check that Tramp autoloads properly."
5059 (skip-unless (tramp--test-enabled))
5060
5059 (let ((default-directory (expand-file-name temporary-file-directory)) 5061 (let ((default-directory (expand-file-name temporary-file-directory))
5060 (code 5062 (code
5061 (format 5063 (format
@@ -5166,42 +5168,52 @@ Since it unloads Tramp, it shall be the last test to run."
5166 ;; cannot test older Emacsen, therefore. 5168 ;; cannot test older Emacsen, therefore.
5167 (skip-unless (tramp--test-emacs26-p)) 5169 (skip-unless (tramp--test-emacs26-p))
5168 5170
5169 (when (featurep 'tramp) 5171 ;; We have autoloaded objects from tramp.el and tramp-archive.el.
5170 (unload-feature 'tramp 'force) 5172 ;; In order to remove them, we first need to load both packages.
5171 ;; No Tramp feature must be left. 5173 (require 'tramp)
5172 (should-not (featurep 'tramp)) 5174 (require 'tramp-archive)
5173 (should-not (all-completions "tramp" (delq 'tramp-tests features))) 5175 (should (featurep 'tramp))
5174 ;; `file-name-handler-alist' must be clean. 5176 (should (featurep 'tramp-archive))
5175 (should-not (all-completions "tramp" (mapcar 'cdr file-name-handler-alist))) 5177 ;; This unloads also tramp-archive.el and tramp-theme.el if needed.
5176 ;; There shouldn't be left a bound symbol, except buffer-local 5178 (unload-feature 'tramp 'force)
5177 ;; variables, and autoload functions. We do not regard our test 5179 ;; No Tramp feature must be left.
5178 ;; symbols, and the Tramp unload hooks. 5180 (should-not (featurep 'tramp))
5179 (mapatoms 5181 (should-not (featurep 'tramp-archive))
5180 (lambda (x) 5182 (should-not (featurep 'tramp-theme))
5181 (and (or (and (boundp x) (null (local-variable-if-set-p x))) 5183 (should-not
5182 (and (functionp x) (null (autoloadp (symbol-function x))))) 5184 (all-completions
5183 (string-match "^tramp" (symbol-name x)) 5185 "tramp" (delq 'tramp-tests (delq 'tramp-archive-tests features))))
5184 (not (string-match "^tramp--?test" (symbol-name x))) 5186 ;; `file-name-handler-alist' must be clean.
5185 (not (string-match "unload-hook$" (symbol-name x))) 5187 (should-not (all-completions "tramp" (mapcar 'cdr file-name-handler-alist)))
5186 (ert-fail (format "`%s' still bound" x))))) 5188 ;; There shouldn't be left a bound symbol, except buffer-local
5187 ;; The defstruct `tramp-file-name' and all its internal functions 5189 ;; variables, and autoload functions. We do not regard our test
5188 ;; shall be purged. 5190 ;; symbols, and the Tramp unload hooks.
5189 (should-not (cl--find-class 'tramp-file-name)) 5191 (mapatoms
5190 (mapatoms 5192 (lambda (x)
5191 (lambda (x) 5193 (and (or (and (boundp x) (null (local-variable-if-set-p x)))
5192 (and (functionp x) 5194 (and (functionp x) (null (autoloadp (symbol-function x)))))
5193 (string-match "tramp-file-name" (symbol-name x)) 5195 (string-match "^tramp" (symbol-name x))
5194 (ert-fail (format "Structure function `%s' still exists" x))))) 5196 (not (string-match "^tramp\\(-archive\\)?--?test" (symbol-name x)))
5195 ;; There shouldn't be left a hook function containing a Tramp 5197 (not (string-match "unload-hook$" (symbol-name x)))
5196 ;; function. We do not regard the Tramp unload hooks. 5198 (ert-fail (format "`%s' still bound" x)))))
5197 (mapatoms 5199 ;; The defstruct `tramp-file-name' and all its internal functions
5198 (lambda (x) 5200 ;; shall be purged.
5199 (and (boundp x) 5201 (should-not (cl--find-class 'tramp-file-name))
5200 (string-match "-\\(hook\\|function\\)s?$" (symbol-name x)) 5202 (mapatoms
5201 (not (string-match "unload-hook$" (symbol-name x))) 5203 (lambda (x)
5202 (consp (symbol-value x)) 5204 (and (functionp x)
5203 (ignore-errors (all-completions "tramp" (symbol-value x))) 5205 (string-match "tramp-file-name" (symbol-name x))
5204 (ert-fail (format "Hook `%s' still contains Tramp function" x))))))) 5206 (ert-fail (format "Structure function `%s' still exists" x)))))
5207 ;; There shouldn't be left a hook function containing a Tramp
5208 ;; function. We do not regard the Tramp unload hooks.
5209 (mapatoms
5210 (lambda (x)
5211 (and (boundp x)
5212 (string-match "-\\(hook\\|function\\)s?$" (symbol-name x))
5213 (not (string-match "unload-hook$" (symbol-name x)))
5214 (consp (symbol-value x))
5215 (ignore-errors (all-completions "tramp" (symbol-value x)))
5216 (ert-fail (format "Hook `%s' still contains Tramp function" x))))))
5205 5217
5206(defun tramp-test-all (&optional interactive) 5218(defun tramp-test-all (&optional interactive)
5207 "Run all tests for \\[tramp]." 5219 "Run all tests for \\[tramp]."
@@ -5222,7 +5234,7 @@ Since it unloads Tramp, it shall be the last test to run."
5222;; * Fix `tramp-test05-expand-file-name-relative' in `expand-file-name'. 5234;; * Fix `tramp-test05-expand-file-name-relative' in `expand-file-name'.
5223;; * Fix `tramp-test06-directory-file-name' for `ftp'. 5235;; * Fix `tramp-test06-directory-file-name' for `ftp'.
5224;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file' 5236;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file'
5225;; do not work properly for `owncloud'. 5237;; do not work properly for `nextcloud'.
5226;; * Fix `tramp-test29-start-file-process' on MS Windows (`process-send-eof'?). 5238;; * Fix `tramp-test29-start-file-process' on MS Windows (`process-send-eof'?).
5227;; * Fix `tramp-test30-interrupt-process', timeout doesn't work reliably. 5239;; * Fix `tramp-test30-interrupt-process', timeout doesn't work reliably.
5228;; * Fix Bug#16928 in `tramp-test42-asynchronous-requests'. 5240;; * Fix Bug#16928 in `tramp-test42-asynchronous-requests'.
diff --git a/test/lisp/progmodes/compile-tests.el b/test/lisp/progmodes/compile-tests.el
index a106030aea1..4e2dc86eae0 100644
--- a/test/lisp/progmodes/compile-tests.el
+++ b/test/lisp/progmodes/compile-tests.el
@@ -343,6 +343,29 @@ meaning a range of columns starting on LINE and ending on
343END-LINE, if that matched. TYPE can be left out, in which case 343END-LINE, if that matched. TYPE can be left out, in which case
344any message type is accepted.") 344any message type is accepted.")
345 345
346(defconst compile-tests--grep-regexp-testcases
347 ;; Bug#32051.
348 '(("c:/Users/my.name/src/project\\src\\kbhit.hpp\0\ 29:#include <termios.h>"
349 1 nil 29 "c:/Users/my.name/src/project\\src\\kbhit.hpp")
350 ("d:/gnu/emacs/branch/src/callproc.c\0\ 214:#ifdef DOS_NT"
351 1 nil 214 "d:/gnu/emacs/branch/src/callproc.c")
352 ("/gnu/emacs/branch/src/callproc.c\0\ 214:#ifdef DOS_NT"
353 1 nil 214 "/gnu/emacs/branch/src/callproc.c"))
354 "List of tests for `grep-regexp-list'.
355The format is the same as `compile-tests--test-regexps-data', but
356the match is expected to be the same when NUL bytes are replaced
357with colon.")
358
359(defconst compile-tests--grep-regexp-tricky-testcases
360 ;; Bug#7378.
361 '(("./x11-libs---nx/3.4.0:0:C.30253.1289557929.792611.C/nx-3.4.0.exheres-0\0\ 42:some text"
362 1 nil 42 "./x11-libs---nx/3.4.0:0:C.30253.1289557929.792611.C/nx-3.4.0.exheres-0")
363 ("2011-08-31_11:57:03_1\0\ 7:Date: Wed, 31 Aug 2011 11:57:03 +0000"
364 1 nil 7 "2011-08-31_11:57:03_1"))
365 "List of tricky tests for `grep-regexp-list'.
366Same as `compile-tests--grep-regexp-testcases', but these cases
367can only work with the NUL byte to disambiguate colons.")
368
346(defun compile--test-error-line (test) 369(defun compile--test-error-line (test)
347 (erase-buffer) 370 (erase-buffer)
348 (setq compilation-locs (make-hash-table)) 371 (setq compilation-locs (make-hash-table))
@@ -370,7 +393,8 @@ any message type is accepted.")
370 (should (equal (car (nth 2 (compilation--loc->file-struct loc))) 393 (should (equal (car (nth 2 (compilation--loc->file-struct loc)))
371 (or end-line line))) 394 (or end-line line)))
372 (when type 395 (when type
373 (should (equal type (compilation--message->type msg))))))) 396 (should (equal type (compilation--message->type msg)))))
397 msg))
374 398
375(ert-deftest compile-test-error-regexps () 399(ert-deftest compile-test-error-regexps ()
376 "Test the `compilation-error-regexp-alist' regexps. 400 "Test the `compilation-error-regexp-alist' regexps.
@@ -379,4 +403,24 @@ The test data is in `compile-tests--test-regexps-data'."
379 (font-lock-mode -1) 403 (font-lock-mode -1)
380 (mapc #'compile--test-error-line compile-tests--test-regexps-data))) 404 (mapc #'compile--test-error-line compile-tests--test-regexps-data)))
381 405
406(ert-deftest compile-test-grep-regexps ()
407 "Test the `grep-regexp-alist' regexps.
408The test data is in `compile-tests--grep-regexp-testcases'."
409 (with-temp-buffer
410 (grep-mode)
411 (setq buffer-read-only nil)
412 (font-lock-mode -1)
413 (dolist (testcase compile-tests--grep-regexp-testcases)
414 (let (msg1 msg2)
415 (setq msg1 (ert-info ((format "%S" testcase) :prefix "testcase: ")
416 (compile--test-error-line testcase)))
417 ;; Make sure replacing the NUL character with a colon still matches.
418 (setf (car testcase) (replace-regexp-in-string "\0" ":" (car testcase)))
419 (setq msg2 (ert-info ((format "%S" testcase) :prefix "testcase: ")
420 (compile--test-error-line testcase)))
421 (should (equal msg1 msg2))))
422 (dolist (testcase compile-tests--grep-regexp-tricky-testcases)
423 (ert-info ((format "%S" testcase) :prefix "testcase: ")
424 (compile--test-error-line testcase)))))
425
382;;; compile-tests.el ends here 426;;; compile-tests.el ends here
diff --git a/test/lisp/shadowfile-tests.el b/test/lisp/shadowfile-tests.el
new file mode 100644
index 00000000000..22f7b2de6ed
--- /dev/null
+++ b/test/lisp/shadowfile-tests.el
@@ -0,0 +1,945 @@
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 (require 'trace)
724 (dolist (elt (all-completions "shadow-" obarray 'functionp))
725 (trace-function-background (intern elt)))
726 (trace-function-background 'save-buffer)
727 (dolist (elt write-file-functions)
728 (trace-function-background elt))
729 ;; Cleanup.
730 (when (file-exists-p shadow-info-file)
731 (delete-file shadow-info-file))
732 (when (file-exists-p shadow-todo-file)
733 (delete-file shadow-todo-file))
734
735 (message "Point 1")
736 ;; Define clusters.
737 (setq cluster1 "cluster1"
738 primary shadow-system-name
739 regexp (shadow-regexp-superquote primary))
740 (shadow-set-cluster cluster1 primary regexp)
741
742 (setq cluster2 "cluster2"
743 primary
744 (file-remote-p shadow-test-remote-temporary-file-directory)
745 regexp (shadow-regexp-superquote primary))
746 (shadow-set-cluster cluster2 primary regexp)
747
748 (message "Point 2")
749 ;; Define a literal group.
750 (setq file
751 (make-temp-name
752 (expand-file-name "shadowfile-tests" temporary-file-directory))
753 shadow-literal-groups
754 `((,(concat "/cluster1:" file) ,(concat "/cluster2:" file))))
755
756 (message "Point 3")
757 ;; Save file from "cluster1" definition.
758 (with-temp-buffer
759 (setq buffer-file-name file)
760 (insert "foo")
761 (save-buffer))
762 (message "%s" file)
763 (message "%s" (shadow-contract-file-name (concat "/cluster2:" file)))
764 (message "%s" shadow-files-to-copy)
765 (should
766 (member
767 (cons file (shadow-contract-file-name (concat "/cluster2:" file)))
768 shadow-files-to-copy))
769
770 (message "Point 4")
771 ;; Save file from "cluster2" definition.
772 (with-temp-buffer
773 (message "Point 4.1")
774 (message "%s" file)
775 (message "%s" (shadow-site-primary cluster2))
776 (setq buffer-file-name (concat (shadow-site-primary cluster2) file))
777 (message "Point 4.2")
778 (insert "foo")
779 (message "%s" buffer-file-name)
780 (message "%s" write-file-functions)
781 (setenv "BUG_32226" "1")
782 (save-buffer))
783 (setenv "BUG_32226")
784 (message "Point 4.3")
785 (message "%s" (shadow-site-primary cluster2))
786 (message "%s" (shadow-contract-file-name (concat "/cluster1:" file)))
787 (message "%s" shadow-files-to-copy)
788 (should
789 (member
790 (cons
791 (concat (shadow-site-primary cluster2) file)
792 (shadow-contract-file-name (concat "/cluster1:" file)))
793 shadow-files-to-copy))
794
795 (message "Point 5")
796 ;; Define a regexp group.
797 (setq shadow-files-to-copy nil
798 shadow-regexp-groups
799 `((,(concat (shadow-site-primary cluster1)
800 (shadow-regexp-superquote file))
801 ,(concat (shadow-site-primary cluster2)
802 (shadow-regexp-superquote file)))))
803
804 (message "Point 6")
805 ;; Save file from "cluster1" definition.
806 (with-temp-buffer
807 (setq buffer-file-name file)
808 (insert "foo")
809 (save-buffer))
810 (should
811 (member
812 (cons file (shadow-contract-file-name (concat "/cluster2:" file)))
813 shadow-files-to-copy))
814
815 (message "Point 7")
816 ;; Save file from "cluster2" definition.
817 (with-temp-buffer
818 (setq buffer-file-name (concat (shadow-site-primary cluster2) file))
819 (insert "foo")
820 (save-buffer))
821 (should
822 (member
823 (cons
824 (concat (shadow-site-primary cluster2) file)
825 (shadow-contract-file-name (concat "/cluster1:" file)))
826 shadow-files-to-copy)))
827 (error (message "Error: %s" err) (signal (car err) (cdr err))))
828
829 (setenv "BUG_32226")
830 (untrace-all)
831 (message "%s" (with-current-buffer trace-buffer (buffer-string)))
832
833 ;; Cleanup.
834 (when (file-exists-p shadow-info-file)
835 (delete-file shadow-info-file))
836 (when (file-exists-p shadow-todo-file)
837 (delete-file shadow-todo-file))
838 (ignore-errors
839 (when (file-exists-p file)
840 (delete-file file)))
841 (ignore-errors
842 (when (file-exists-p (concat (shadow-site-primary cluster2) file))
843 (delete-file (concat (shadow-site-primary cluster2) file)))))))
844
845(ert-deftest shadow-test09-shadow-copy-files ()
846 "Check that needed shadow files are copied."
847 (skip-unless (not (memq system-type '(windows-nt ms-dos))))
848 (skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
849
850 (let ((backup-inhibited t)
851 (shadow-info-file shadow-test-info-file)
852 (shadow-todo-file shadow-test-todo-file)
853 (shadow-inhibit-message t)
854 (shadow-noquery t)
855 shadow-clusters shadow-files-to-copy
856 cluster1 cluster2 primary regexp file mocked-input)
857 (unwind-protect
858 (progn
859 ;; Cleanup.
860 (when (file-exists-p shadow-info-file)
861 (delete-file shadow-info-file))
862 (when (file-exists-p shadow-todo-file)
863 (delete-file shadow-todo-file))
864 (when (buffer-live-p shadow-todo-buffer)
865 (with-current-buffer shadow-todo-buffer (erase-buffer)))
866
867 ;; Define clusters.
868 (setq cluster1 "cluster1"
869 primary shadow-system-name
870 regexp (shadow-regexp-superquote primary))
871 (shadow-set-cluster cluster1 primary regexp)
872
873 (setq cluster2 "cluster2"
874 primary
875 (file-remote-p shadow-test-remote-temporary-file-directory)
876 regexp (shadow-regexp-superquote primary))
877 (shadow-set-cluster cluster2 primary regexp)
878
879 ;; Define files to copy.
880 (setq file
881 (make-temp-name
882 (expand-file-name "shadowfile-tests" temporary-file-directory))
883 shadow-literal-groups
884 `((,(concat "/cluster1:" file) ,(concat "/cluster2:" file)))
885 shadow-regexp-groups
886 `((,(concat (shadow-site-primary cluster1)
887 (shadow-regexp-superquote file))
888 ,(concat (shadow-site-primary cluster2)
889 (shadow-regexp-superquote file))))
890 mocked-input `(,(concat (shadow-site-primary cluster2) file)
891 ,file))
892
893 ;; Save files.
894 (with-temp-buffer
895 (setq buffer-file-name file)
896 (insert "foo")
897 (save-buffer))
898 (with-temp-buffer
899 (setq buffer-file-name (concat (shadow-site-primary cluster2) file))
900 (insert "foo")
901 (save-buffer))
902
903 ;; We must mock `write-region', in order to check proper
904 ;; action.
905 (add-function
906 :before (symbol-function 'write-region)
907 (lambda (&rest args)
908 (when (and (buffer-file-name) mocked-input)
909 (should (equal (buffer-file-name) (pop mocked-input)))))
910 '((name . "write-region-mock")))
911
912 ;; Copy the files.
913 (shadow-copy-files 'noquery)
914 (should-not shadow-files-to-copy)
915 (with-current-buffer shadow-todo-buffer
916 (goto-char (point-min))
917 (should
918 (looking-at (regexp-quote "(setq shadow-files-to-copy nil)")))))
919
920 ;; Cleanup.
921 (remove-function (symbol-function 'write-region) "write-region-mock")
922 (when (file-exists-p shadow-info-file)
923 (delete-file shadow-info-file))
924 (when (file-exists-p shadow-todo-file)
925 (delete-file shadow-todo-file))
926 (ignore-errors
927 (when (file-exists-p file)
928 (delete-file file)))
929 (ignore-errors
930 (when (file-exists-p (concat (shadow-site-primary cluster2) file))
931 (delete-file (concat (shadow-site-primary cluster2) file)))))))
932
933(defun shadowfile-test-all (&optional interactive)
934 "Run all tests for \\[shadowfile]."
935 (interactive "p")
936 (if interactive
937 (ert-run-tests-interactively "^shadowfile-")
938 (ert-run-tests-batch "^shadowfile-")))
939
940(let ((shadow-info-file shadow-test-info-file)
941 (shadow-todo-file shadow-test-todo-file))
942 (shadow-initialize))
943
944(provide 'shadowfile-tests)
945;;; 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..b4ef4ab2486
--- /dev/null
+++ b/test/lisp/wdired-tests.el
@@ -0,0 +1,129 @@
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(require 'wdired)
25
26(defvar dired-query) ; Pacify byte compiler.
27
28(ert-deftest wdired-test-bug32173-01 ()
29 "Test using non-nil wdired-use-interactive-rename.
30Partially modifying a file name should succeed."
31 (let* ((test-dir (make-temp-file "test-dir-" t))
32 (test-file (concat (file-name-as-directory test-dir) "foo.c"))
33 (replace "bar")
34 (new-file (replace-regexp-in-string "foo" replace test-file))
35 (wdired-use-interactive-rename t))
36 (write-region "" nil test-file nil 'silent)
37 (advice-add 'dired-query ; Don't ask confirmation to overwrite a file.
38 :override
39 (lambda (_sym _prompt &rest _args) (setq dired-query t))
40 '((name . "advice-dired-query")))
41 (let ((buf (find-file-noselect test-dir)))
42 (unwind-protect
43 (with-current-buffer buf
44 (should (equal (dired-file-name-at-point) test-file))
45 (dired-toggle-read-only)
46 (kill-region (point) (progn (search-forward ".")
47 (forward-char -1) (point)))
48 (insert replace)
49 (wdired-finish-edit)
50 (should (equal (dired-file-name-at-point) new-file)))
51 (if buf (kill-buffer buf))
52 (delete-directory test-dir t)))))
53
54(ert-deftest wdired-test-bug32173-02 ()
55 "Test using non-nil wdired-use-interactive-rename.
56Aborting an edit should leaving original file name unchanged."
57 (let* ((test-dir (make-temp-file "test-dir-" t))
58 (test-file (concat (file-name-as-directory test-dir) "foo.c"))
59 (wdired-use-interactive-rename t))
60 (write-region "" nil test-file nil 'silent)
61 ;; Make dired-do-create-files-regexp a noop to mimic typing C-g
62 ;; at its prompt before wdired-finish-edit returns.
63 (advice-add 'dired-do-create-files-regexp
64 :override
65 (lambda (&rest _) (ignore))
66 '((name . "advice-dired-do-create-files-regexp")))
67 (let ((buf (find-file-noselect test-dir)))
68 (unwind-protect
69 (with-current-buffer buf
70 (should (equal (dired-file-name-at-point) test-file))
71 (dired-toggle-read-only)
72 (kill-region (point) (progn (search-forward ".")
73 (forward-char -1) (point)))
74 (insert "bar")
75 (wdired-finish-edit)
76 (should (equal (dired-get-filename) test-file)))
77 (if buf (kill-buffer buf))
78 (delete-directory test-dir t)))))
79
80(ert-deftest wdired-test-symlink-name ()
81 "Test the file name of a symbolic link.
82The Dired and WDired functions returning the name should include
83only the name before the link arrow."
84 (let* ((test-dir (make-temp-file "test-dir-" t))
85 (link-name "foo"))
86 (let ((buf (find-file-noselect test-dir)))
87 (unwind-protect
88 (with-current-buffer buf
89 (make-symbolic-link "./bar/baz" link-name)
90 (revert-buffer)
91 (let* ((file-name (dired-get-filename))
92 (dir-part (file-name-directory file-name))
93 (lf-name (concat dir-part link-name)))
94 (should (equal file-name lf-name))
95 (dired-toggle-read-only)
96 (should (equal (wdired-get-filename) lf-name))
97 (dired-toggle-read-only)))
98 (if buf (kill-buffer buf))
99 (delete-directory test-dir t)))))
100
101(ert-deftest wdired-test-unfinished-edit-01 ()
102 "Test editing a file name without saving the change.
103Finding the new name should be possible while still in
104wdired-mode."
105 :expected-result (if (< emacs-major-version 27) :failed :passed)
106 (let* ((test-dir (make-temp-file "test-dir-" t))
107 (test-file (concat (file-name-as-directory test-dir) "foo.c"))
108 (replace "bar")
109 (new-file (replace-regexp-in-string "foo" replace test-file)))
110 (write-region "" nil test-file nil 'silent)
111 (let ((buf (find-file-noselect test-dir)))
112 (unwind-protect
113 (with-current-buffer buf
114 (should (equal (dired-file-name-at-point) test-file))
115 (dired-toggle-read-only)
116 (kill-region (point) (progn (search-forward ".")
117 (forward-char -1) (point)))
118 (insert replace)
119 (should (equal (dired-get-filename) new-file))))
120 (when buf
121 (with-current-buffer buf
122 ;; Prevent kill-buffer-query-functions from chiming in.
123 (set-buffer-modified-p nil)
124 (kill-buffer buf)))
125 (delete-directory test-dir t))))
126
127
128(provide 'wdired-tests)
129;;; wdired-tests.el ends here
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index 501e0d87818..8dee4bdc0fd 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -169,7 +169,13 @@
169 (should (eq (type-of (read (format "#o%o" most-negative-fixnum))) 169 (should (eq (type-of (read (format "#o%o" most-negative-fixnum)))
170 'integer)) 170 'integer))
171 (should (eq (type-of (read (format "#32rG%x" most-positive-fixnum))) 171 (should (eq (type-of (read (format "#32rG%x" most-positive-fixnum)))
172 'integer))) 172 'integer))
173 (let ((binary-as-unsigned nil))
174 (dolist (fmt '("%d" "%s" "#o%o" "#x%x"))
175 (dolist (val (list most-negative-fixnum (1+ most-negative-fixnum)
176 -1 0 1
177 (1- most-positive-fixnum) most-positive-fixnum))
178 (should (eq val (read (format fmt val))))))))
173 179
174(ert-deftest format-%o-invalid-float () 180(ert-deftest format-%o-invalid-float ()
175 (should-error (format "%o" -1e-37) 181 (should-error (format "%o" -1e-37)
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index d560f0bb0d9..f722ed6333e 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/regex-tests.el b/test/src/regex-emacs-tests.el
index 083ed5c4c8c..7a075908a6b 100644
--- a/test/src/regex-tests.el
+++ b/test/src/regex-emacs-tests.el
@@ -1,4 +1,4 @@
1;;; regex-tests.el --- tests for regex.c functions -*- lexical-binding: t -*- 1;;; regex-emacs-tests.el --- tests for regex-emacs.c -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 2015-2018 Free Software Foundation, Inc. 3;; Copyright (C) 2015-2018 Free Software Foundation, Inc.
4 4
@@ -24,7 +24,7 @@
24(defvar regex-tests--resources-dir 24(defvar regex-tests--resources-dir
25 (concat (concat (file-name-directory (or load-file-name buffer-file-name)) 25 (concat (concat (file-name-directory (or load-file-name buffer-file-name))
26 "/regex-resources/")) 26 "/regex-resources/"))
27 "Path to regex-resources directory next to the \"regex-tests.el\" file.") 27 "Path to regex-resources directory next to the \"regex-emacs-tests.el\" file.")
28 28
29(ert-deftest regex-word-cc-fallback-test () 29(ert-deftest regex-word-cc-fallback-test ()
30 "Test that \"[[:cc:]]*x\" matches \"x\" (bug#24020). 30 "Test that \"[[:cc:]]*x\" matches \"x\" (bug#24020).
@@ -683,4 +683,4 @@ This evaluates the TESTS test cases from glibc."
683 (should-not (string-match "\\`x\\{65535\\}" (make-string 65534 ?x))) 683 (should-not (string-match "\\`x\\{65535\\}" (make-string 65534 ?x)))
684 (should-error (string-match "\\`x\\{65536\\}" "X") :type 'invalid-regexp)) 684 (should-error (string-match "\\`x\\{65536\\}" "X") :type 'invalid-regexp))
685 685
686;;; regex-tests.el ends here 686;;; regex-emacs-tests.el ends here
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
index 0e909d3e511..364f6d61f05 100644
--- a/test/src/thread-tests.el
+++ b/test/src/thread-tests.el
@@ -19,38 +19,64 @@
19 19
20;;; Code: 20;;; Code:
21 21
22;; Declare the functions in case Emacs has been configured --without-threads.
23(declare-function all-threads "thread.c" ())
24(declare-function condition-mutex "thread.c" (cond))
25(declare-function condition-name "thread.c" (cond))
26(declare-function condition-notify "thread.c" (cond &optional all))
27(declare-function condition-wait "thread.c" (cond))
28(declare-function current-thread "thread.c" ())
29(declare-function make-condition-variable "thread.c" (mutex &optional name))
30(declare-function make-mutex "thread.c" (&optional name))
31(declare-function make-thread "thread.c" (function &optional name))
32(declare-function mutex-lock "thread.c" (mutex))
33(declare-function mutex-unlock "thread.c" (mutex))
34(declare-function thread--blocker "thread.c" (thread))
35(declare-function thread-alive-p "thread.c" (thread))
36(declare-function thread-join "thread.c" (thread))
37(declare-function thread-last-error "thread.c" (&optional cleanup))
38(declare-function thread-name "thread.c" (thread))
39(declare-function thread-signal "thread.c" (thread error-symbol data))
40(declare-function thread-yield "thread.c" ())
41(defvar main-thread)
42
22(ert-deftest threads-is-one () 43(ert-deftest threads-is-one ()
23 "Test for existence of a thread." 44 "Test for existence of a thread."
24 (skip-unless (fboundp 'make-thread)) 45 (skip-unless (featurep 'threads))
25 (should (current-thread))) 46 (should (current-thread)))
26 47
27(ert-deftest threads-threadp () 48(ert-deftest threads-threadp ()
28 "Test of threadp." 49 "Test of threadp."
29 (skip-unless (fboundp 'make-thread)) 50 (skip-unless (featurep 'threads))
30 (should (threadp (current-thread)))) 51 (should (threadp (current-thread))))
31 52
32(ert-deftest threads-type () 53(ert-deftest threads-type ()
33 "Test of thread type." 54 "Test of thread type."
34 (skip-unless (fboundp 'make-thread)) 55 (skip-unless (featurep 'threads))
35 (should (eq (type-of (current-thread)) 'thread))) 56 (should (eq (type-of (current-thread)) 'thread)))
36 57
37(ert-deftest threads-name () 58(ert-deftest threads-name ()
38 "Test for name of a thread." 59 "Test for name of a thread."
39 (skip-unless (fboundp 'make-thread)) 60 (skip-unless (featurep 'threads))
40 (should 61 (should
41 (string= "hi bob" (thread-name (make-thread #'ignore "hi bob"))))) 62 (string= "hi bob" (thread-name (make-thread #'ignore "hi bob")))))
42 63
43(ert-deftest threads-alive () 64(ert-deftest threads-alive ()
44 "Test for thread liveness." 65 "Test for thread liveness."
45 (skip-unless (fboundp 'make-thread)) 66 (skip-unless (featurep 'threads))
46 (should 67 (should
47 (thread-alive-p (make-thread #'ignore)))) 68 (thread-alive-p (make-thread #'ignore))))
48 69
49(ert-deftest threads-all-threads () 70(ert-deftest threads-all-threads ()
50 "Simple test for all-threads." 71 "Simple test for all-threads."
51 (skip-unless (fboundp 'make-thread)) 72 (skip-unless (featurep 'threads))
52 (should (listp (all-threads)))) 73 (should (listp (all-threads))))
53 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
54(defvar threads-test-global nil) 80(defvar threads-test-global nil)
55 81
56(defun threads-test-thread1 () 82(defun threads-test-thread1 ()
@@ -58,7 +84,7 @@
58 84
59(ert-deftest threads-basic () 85(ert-deftest threads-basic ()
60 "Basic thread test." 86 "Basic thread test."
61 (skip-unless (fboundp 'make-thread)) 87 (skip-unless (featurep 'threads))
62 (should 88 (should
63 (progn 89 (progn
64 (setq threads-test-global nil) 90 (setq threads-test-global nil)
@@ -69,20 +95,29 @@
69 95
70(ert-deftest threads-join () 96(ert-deftest threads-join ()
71 "Test of `thread-join'." 97 "Test of `thread-join'."
72 (skip-unless (fboundp 'make-thread)) 98 (skip-unless (featurep 'threads))
73 (should 99 (should
74 (progn 100 (progn
75 (setq threads-test-global nil) 101 (setq threads-test-global nil)
76 (let ((thread (make-thread #'threads-test-thread1))) 102 (let ((thread (make-thread #'threads-test-thread1)))
77 (thread-join thread) 103 (and (= (thread-join thread) 23)
78 (and threads-test-global 104 (= threads-test-global 23)
79 (not (thread-alive-p thread))))))) 105 (not (thread-alive-p thread)))))))
80 106
81(ert-deftest threads-join-self () 107(ert-deftest threads-join-self ()
82 "Cannot `thread-join' the current thread." 108 "Cannot `thread-join' the current thread."
83 (skip-unless (fboundp 'make-thread)) 109 (skip-unless (featurep 'threads))
84 (should-error (thread-join (current-thread)))) 110 (should-error (thread-join (current-thread))))
85 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
86(defvar threads-test-binding nil) 121(defvar threads-test-binding nil)
87 122
88(defun threads-test-thread2 () 123(defun threads-test-thread2 ()
@@ -92,7 +127,7 @@
92 127
93(ert-deftest threads-let-binding () 128(ert-deftest threads-let-binding ()
94 "Simple test of threads and let bindings." 129 "Simple test of threads and let bindings."
95 (skip-unless (fboundp 'make-thread)) 130 (skip-unless (featurep 'threads))
96 (should 131 (should
97 (progn 132 (progn
98 (setq threads-test-global nil) 133 (setq threads-test-global nil)
@@ -104,22 +139,22 @@
104 139
105(ert-deftest threads-mutexp () 140(ert-deftest threads-mutexp ()
106 "Simple test of `mutexp'." 141 "Simple test of `mutexp'."
107 (skip-unless (fboundp 'make-thread)) 142 (skip-unless (featurep 'threads))
108 (should-not (mutexp 'hi))) 143 (should-not (mutexp 'hi)))
109 144
110(ert-deftest threads-mutexp-2 () 145(ert-deftest threads-mutexp-2 ()
111 "Another simple test of `mutexp'." 146 "Another simple test of `mutexp'."
112 (skip-unless (fboundp 'make-thread)) 147 (skip-unless (featurep 'threads))
113 (should (mutexp (make-mutex)))) 148 (should (mutexp (make-mutex))))
114 149
115(ert-deftest threads-mutex-type () 150(ert-deftest threads-mutex-type ()
116 "type-of mutex." 151 "type-of mutex."
117 (skip-unless (fboundp 'make-thread)) 152 (skip-unless (featurep 'threads))
118 (should (eq (type-of (make-mutex)) 'mutex))) 153 (should (eq (type-of (make-mutex)) 'mutex)))
119 154
120(ert-deftest threads-mutex-lock-unlock () 155(ert-deftest threads-mutex-lock-unlock ()
121 "Test mutex-lock and unlock." 156 "Test mutex-lock and unlock."
122 (skip-unless (fboundp 'make-thread)) 157 (skip-unless (featurep 'threads))
123 (should 158 (should
124 (let ((mx (make-mutex))) 159 (let ((mx (make-mutex)))
125 (mutex-lock mx) 160 (mutex-lock mx)
@@ -128,7 +163,7 @@
128 163
129(ert-deftest threads-mutex-recursive () 164(ert-deftest threads-mutex-recursive ()
130 "Test mutex recursion." 165 "Test mutex recursion."
131 (skip-unless (fboundp 'make-thread)) 166 (skip-unless (featurep 'threads))
132 (should 167 (should
133 (let ((mx (make-mutex))) 168 (let ((mx (make-mutex)))
134 (mutex-lock mx) 169 (mutex-lock mx)
@@ -149,7 +184,7 @@
149 184
150(ert-deftest threads-mutex-contention () 185(ert-deftest threads-mutex-contention ()
151 "Test of mutex contention." 186 "Test of mutex contention."
152 (skip-unless (fboundp 'make-thread)) 187 (skip-unless (featurep 'threads))
153 (should 188 (should
154 (progn 189 (progn
155 (setq threads-mutex (make-mutex)) 190 (setq threads-mutex (make-mutex))
@@ -170,8 +205,8 @@
170 205
171(ert-deftest threads-mutex-signal () 206(ert-deftest threads-mutex-signal ()
172 "Test signaling a blocked thread." 207 "Test signaling a blocked thread."
173 (skip-unless (fboundp 'make-thread)) 208 (skip-unless (featurep 'threads))
174 (should 209 (should-error
175 (progn 210 (progn
176 (setq threads-mutex (make-mutex)) 211 (setq threads-mutex (make-mutex))
177 (setq threads-mutex-key nil) 212 (setq threads-mutex-key nil)
@@ -180,15 +215,17 @@
180 (while (not threads-mutex-key) 215 (while (not threads-mutex-key)
181 (thread-yield)) 216 (thread-yield))
182 (thread-signal thr 'quit nil) 217 (thread-signal thr 'quit nil)
183 (thread-join thr)) 218 ;; `quit' is not catched by `should-error'. We must indicate it.
184 t))) 219 (condition-case nil
220 (thread-join thr)
221 (quit (signal 'error nil)))))))
185 222
186(defun threads-test-io-switch () 223(defun threads-test-io-switch ()
187 (setq threads-test-global 23)) 224 (setq threads-test-global 23))
188 225
189(ert-deftest threads-io-switch () 226(ert-deftest threads-io-switch ()
190 "Test that `accept-process-output' causes thread switch." 227 "Test that `accept-process-output' causes thread switch."
191 (skip-unless (fboundp 'make-thread)) 228 (skip-unless (featurep 'threads))
192 (should 229 (should
193 (progn 230 (progn
194 (setq threads-test-global nil) 231 (setq threads-test-global nil)
@@ -199,67 +236,71 @@
199 236
200(ert-deftest threads-condvarp () 237(ert-deftest threads-condvarp ()
201 "Simple test of `condition-variable-p'." 238 "Simple test of `condition-variable-p'."
202 (skip-unless (fboundp 'make-thread)) 239 (skip-unless (featurep 'threads))
203 (should-not (condition-variable-p 'hi))) 240 (should-not (condition-variable-p 'hi)))
204 241
205(ert-deftest threads-condvarp-2 () 242(ert-deftest threads-condvarp-2 ()
206 "Another simple test of `condition-variable-p'." 243 "Another simple test of `condition-variable-p'."
207 (skip-unless (fboundp 'make-thread)) 244 (skip-unless (featurep 'threads))
208 (should (condition-variable-p (make-condition-variable (make-mutex))))) 245 (should (condition-variable-p (make-condition-variable (make-mutex)))))
209 246
210(ert-deftest threads-condvar-type () 247(ert-deftest threads-condvar-type ()
211 "type-of condvar" 248 "type-of condvar"
212 (skip-unless (fboundp 'make-thread)) 249 (skip-unless (featurep 'threads))
213 (should (eq (type-of (make-condition-variable (make-mutex))) 250 (should (eq (type-of (make-condition-variable (make-mutex)))
214 'condition-variable))) 251 'condition-variable)))
215 252
216(ert-deftest threads-condvar-mutex () 253(ert-deftest threads-condvar-mutex ()
217 "Simple test of `condition-mutex'." 254 "Simple test of `condition-mutex'."
218 (skip-unless (fboundp 'make-thread)) 255 (skip-unless (featurep 'threads))
219 (should 256 (should
220 (let ((m (make-mutex))) 257 (let ((m (make-mutex)))
221 (eq m (condition-mutex (make-condition-variable m)))))) 258 (eq m (condition-mutex (make-condition-variable m))))))
222 259
223(ert-deftest threads-condvar-name () 260(ert-deftest threads-condvar-name ()
224 "Simple test of `condition-name'." 261 "Simple test of `condition-name'."
225 (skip-unless (fboundp 'make-thread)) 262 (skip-unless (featurep 'threads))
226 (should 263 (should
227 (eq nil (condition-name (make-condition-variable (make-mutex)))))) 264 (eq nil (condition-name (make-condition-variable (make-mutex))))))
228 265
229(ert-deftest threads-condvar-name-2 () 266(ert-deftest threads-condvar-name-2 ()
230 "Another simple test of `condition-name'." 267 "Another simple test of `condition-name'."
231 (skip-unless (fboundp 'make-thread)) 268 (skip-unless (featurep 'threads))
232 (should 269 (should
233 (string= "hi bob" 270 (string= "hi bob"
234 (condition-name (make-condition-variable (make-mutex) 271 (condition-name (make-condition-variable (make-mutex)
235 "hi bob"))))) 272 "hi bob")))))
236(defun call-error () 273
274(defun threads-call-error ()
237 "Call `error'." 275 "Call `error'."
238 (error "Error is called")) 276 (error "Error is called"))
239 277
240;; This signals an error internally; the error should be caught. 278;; This signals an error internally; the error should be caught.
241(defun thread-custom () 279(defun threads-custom ()
242 (defcustom thread-custom-face 'highlight 280 (defcustom threads-custom-face 'highlight
243 "Face used for thread customizations." 281 "Face used for thread customizations."
244 :type 'face 282 :type 'face
245 :group 'widget-faces)) 283 :group 'widget-faces))
246 284
247(ert-deftest thread-errors () 285(ert-deftest threads-errors ()
248 "Test what happens when a thread signals an error." 286 "Test what happens when a thread signals an error."
249 (skip-unless (fboundp 'make-thread)) 287 (skip-unless (featurep 'threads))
250 (let (th1 th2) 288 (let (th1 th2)
251 (setq th1 (make-thread #'call-error "call-error")) 289 (setq th1 (make-thread #'threads-call-error "call-error"))
252 (should (threadp th1)) 290 (should (threadp th1))
253 (while (thread-alive-p th1) 291 (while (thread-alive-p th1)
254 (thread-yield)) 292 (thread-yield))
255 (should (equal (thread-last-error) 293 (should (equal (thread-last-error)
256 '(error "Error is called"))) 294 '(error "Error is called")))
257 (setq th2 (make-thread #'thread-custom "thread-custom")) 295 (should (equal (thread-last-error 'cleanup)
296 '(error "Error is called")))
297 (should-not (thread-last-error))
298 (setq th2 (make-thread #'threads-custom "threads-custom"))
258 (should (threadp th2)))) 299 (should (threadp th2))))
259 300
260(ert-deftest thread-sticky-point () 301(ert-deftest threads-sticky-point ()
261 "Test bug #25165 with point movement in cloned buffer." 302 "Test bug #25165 with point movement in cloned buffer."
262 (skip-unless (fboundp 'make-thread)) 303 (skip-unless (featurep 'threads))
263 (with-temp-buffer 304 (with-temp-buffer
264 (insert "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") 305 (insert "Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
265 (goto-char (point-min)) 306 (goto-char (point-min))
@@ -268,9 +309,9 @@
268 (sit-for 1) 309 (sit-for 1)
269 (should (= (point) 21)))) 310 (should (= (point) 21))))
270 311
271(ert-deftest thread-signal-early () 312(ert-deftest threads-signal-early ()
272 "Test signaling a thread as soon as it is started by the OS." 313 "Test signaling a thread as soon as it is started by the OS."
273 (skip-unless (fboundp 'make-thread)) 314 (skip-unless (featurep 'threads))
274 (let ((thread 315 (let ((thread
275 (make-thread #'(lambda () 316 (make-thread #'(lambda ()
276 (while t (thread-yield)))))) 317 (while t (thread-yield))))))
@@ -291,7 +332,7 @@
291 332
292(ert-deftest threads-condvar-wait () 333(ert-deftest threads-condvar-wait ()
293 "Test waiting on conditional variable." 334 "Test waiting on conditional variable."
294 (skip-unless (fboundp 'make-thread)) 335 (skip-unless (featurep 'threads))
295 (let ((cv-mutex (make-mutex)) 336 (let ((cv-mutex (make-mutex))
296 new-thread) 337 new-thread)
297 ;; We could have spurious threads from the previous tests still 338 ;; We could have spurious threads from the previous tests still