aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
authorKenichi Handa2012-11-23 23:36:24 +0900
committerKenichi Handa2012-11-23 23:36:24 +0900
commit2aaec2d9be5cec44ea3b59cba476fd3e091f2fc9 (patch)
tree3711b97807201b7eeaa066003b1c3a4ce929e5bb /lisp/emacs-lisp
parente1d276cbf9e18f13101328f56bed1a1c0a66e63a (diff)
parente7d0e5ee247a155a268ffbf80bedbe25e15b5032 (diff)
downloademacs-2aaec2d9be5cec44ea3b59cba476fd3e091f2fc9.tar.gz
emacs-2aaec2d9be5cec44ea3b59cba476fd3e091f2fc9.zip
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/byte-run.el10
-rw-r--r--lisp/emacs-lisp/bytecomp.el4
-rw-r--r--lisp/emacs-lisp/edebug.el15
-rw-r--r--lisp/emacs-lisp/ert-x.el47
-rw-r--r--lisp/emacs-lisp/ert.el804
-rw-r--r--lisp/emacs-lisp/nadvice.el50
-rw-r--r--lisp/emacs-lisp/trace.el206
7 files changed, 617 insertions, 519 deletions
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 462b4a25154..b4582a41d6c 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -81,8 +81,14 @@ The return value of this function is not used."
81 #'(lambda (f _args new-name when) 81 #'(lambda (f _args new-name when)
82 `(make-obsolete ',f ',new-name ,when))) 82 `(make-obsolete ',f ',new-name ,when)))
83 (list 'compiler-macro 83 (list 'compiler-macro
84 #'(lambda (f _args compiler-function) 84 #'(lambda (f args compiler-function)
85 `(put ',f 'compiler-macro #',compiler-function))) 85 ;; FIXME: Make it possible to just reuse `args'.
86 `(eval-and-compile
87 (put ',f 'compiler-macro
88 ,(if (eq (car-safe compiler-function) 'lambda)
89 `(lambda ,(append (cadr compiler-function) args)
90 ,@(cddr compiler-function))
91 `#',compiler-function)))))
86 (list 'doc-string 92 (list 'doc-string
87 #'(lambda (f _args pos) 93 #'(lambda (f _args pos)
88 (list 'put (list 'quote f) ''doc-string-elt (list 'quote pos)))) 94 (list 'put (list 'quote f) ''doc-string-elt (list 'quote pos))))
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index a325e0f3e44..60036c86dc0 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -2509,8 +2509,8 @@ If FORM is a lambda or a macro, byte-compile it as a function."
2509 (when (symbolp form) 2509 (when (symbolp form)
2510 (unless (memq (car-safe fun) '(closure lambda)) 2510 (unless (memq (car-safe fun) '(closure lambda))
2511 (error "Don't know how to compile %S" fun)) 2511 (error "Don't know how to compile %S" fun))
2512 (setq fun (byte-compile--reify-function fun)) 2512 (setq lexical-binding (eq (car fun) 'closure))
2513 (setq lexical-binding (eq (car fun) 'closure))) 2513 (setq fun (byte-compile--reify-function fun)))
2514 (unless (eq (car-safe fun) 'lambda) 2514 (unless (eq (car-safe fun) 'lambda)
2515 (error "Don't know how to compile %S" fun)) 2515 (error "Don't know how to compile %S" fun))
2516 ;; Expand macros. 2516 ;; Expand macros.
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 483ed64de20..12311711fe0 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -4268,6 +4268,21 @@ With prefix argument, make it a temporary breakpoint."
4268 4268
4269;;; Finalize Loading 4269;;; Finalize Loading
4270 4270
4271;; When edebugging a function, some of the sub-expressions are
4272;; wrapped in (edebug-enter (lambda () ..)), so we need to teach
4273;; called-interactively-p that calls within the inner lambda should refer to
4274;; the outside function.
4275(add-hook 'called-interactively-p-functions
4276 #'edebug--called-interactively-skip)
4277(defun edebug--called-interactively-skip (i frame1 frame2)
4278 (when (and (eq (car-safe (nth 1 frame1)) 'lambda)
4279 (eq (nth 1 (nth 1 frame1)) '())
4280 (eq (nth 1 frame2) 'edebug-enter))
4281 ;; `edebug-enter' calls itself on its first invocation.
4282 (if (eq (nth 1 (internal--called-interactively-p--get-frame i))
4283 'edebug-enter)
4284 2 1)))
4285
4271;; Finally, hook edebug into the rest of Emacs. 4286;; Finally, hook edebug into the rest of Emacs.
4272;; There are probably some other things that could go here. 4287;; There are probably some other things that could go here.
4273 4288
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index c3b8e5e10d4..60d74774e87 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -1,4 +1,4 @@
1;;; ert-x.el --- Staging area for experimental extensions to ERT 1;;; ert-x.el --- Staging area for experimental extensions to ERT -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 2008, 2010-2012 Free Software Foundation, Inc. 3;; Copyright (C) 2008, 2010-2012 Free Software Foundation, Inc.
4 4
@@ -28,8 +28,7 @@
28 28
29;;; Code: 29;;; Code:
30 30
31(eval-when-compile 31(eval-when-compile (require 'cl-lib))
32 (require 'cl))
33(require 'ert) 32(require 'ert)
34 33
35 34
@@ -90,8 +89,8 @@ ERT--THUNK with that buffer as current."
90 (kill-buffer ert--buffer) 89 (kill-buffer ert--buffer)
91 (remhash ert--buffer ert--test-buffers)))) 90 (remhash ert--buffer ert--test-buffers))))
92 91
93(defmacro* ert-with-test-buffer ((&key ((:name name-form))) 92(cl-defmacro ert-with-test-buffer ((&key ((:name name-form)))
94 &body body) 93 &body body)
95 "Create a test buffer and run BODY in that buffer. 94 "Create a test buffer and run BODY in that buffer.
96 95
97To be used in ERT tests. If BODY finishes successfully, the test 96To be used in ERT tests. If BODY finishes successfully, the test
@@ -116,10 +115,10 @@ the name of the test and the result of NAME-FORM."
116 "Kill all test buffers that are still live." 115 "Kill all test buffers that are still live."
117 (interactive) 116 (interactive)
118 (let ((count 0)) 117 (let ((count 0))
119 (maphash (lambda (buffer dummy) 118 (maphash (lambda (buffer _dummy)
120 (when (or (not (buffer-live-p buffer)) 119 (when (or (not (buffer-live-p buffer))
121 (kill-buffer buffer)) 120 (kill-buffer buffer))
122 (incf count))) 121 (cl-incf count)))
123 ert--test-buffers) 122 ert--test-buffers)
124 (message "%s out of %s test buffers killed" 123 (message "%s out of %s test buffers killed"
125 count (hash-table-count ert--test-buffers))) 124 count (hash-table-count ert--test-buffers)))
@@ -149,9 +148,9 @@ the rest are arguments to the command.
149 148
150NOTE: Since the command is not called by `call-interactively' 149NOTE: Since the command is not called by `call-interactively'
151test for `called-interactively' in the command will fail." 150test for `called-interactively' in the command will fail."
152 (assert (listp command) t) 151 (cl-assert (listp command) t)
153 (assert (commandp (car command)) t) 152 (cl-assert (commandp (car command)) t)
154 (assert (not unread-command-events) t) 153 (cl-assert (not unread-command-events) t)
155 (let (return-value) 154 (let (return-value)
156 ;; For the order of things here see command_loop_1 in keyboard.c. 155 ;; For the order of things here see command_loop_1 in keyboard.c.
157 ;; 156 ;;
@@ -175,7 +174,7 @@ test for `called-interactively' in the command will fail."
175 (when (boundp 'last-repeatable-command) 174 (when (boundp 'last-repeatable-command)
176 (setq last-repeatable-command real-last-command)) 175 (setq last-repeatable-command real-last-command))
177 (when (and deactivate-mark transient-mark-mode) (deactivate-mark)) 176 (when (and deactivate-mark transient-mark-mode) (deactivate-mark))
178 (assert (not unread-command-events) t) 177 (cl-assert (not unread-command-events) t)
179 return-value)) 178 return-value))
180 179
181(defun ert-run-idle-timers () 180(defun ert-run-idle-timers ()
@@ -198,7 +197,7 @@ rather than the entire match."
198 (with-temp-buffer 197 (with-temp-buffer
199 (insert s) 198 (insert s)
200 (dolist (x regexps) 199 (dolist (x regexps)
201 (destructuring-bind (regexp subexp) (if (listp x) x `(,x nil)) 200 (cl-destructuring-bind (regexp subexp) (if (listp x) x `(,x nil))
202 (goto-char (point-min)) 201 (goto-char (point-min))
203 (while (re-search-forward regexp nil t) 202 (while (re-search-forward regexp nil t)
204 (replace-match "" t t nil subexp)))) 203 (replace-match "" t t nil subexp))))
@@ -224,15 +223,15 @@ would return the string \"foo bar baz quux\" where the substring
224None of the ARGS are modified, but the return value may share 223None of the ARGS are modified, but the return value may share
225structure with the plists in ARGS." 224structure with the plists in ARGS."
226 (with-temp-buffer 225 (with-temp-buffer
227 (loop with current-plist = nil 226 (cl-loop with current-plist = nil
228 for x in args do 227 for x in args do
229 (etypecase x 228 (cl-etypecase x
230 (string (let ((begin (point))) 229 (string (let ((begin (point)))
231 (insert x) 230 (insert x)
232 (set-text-properties begin (point) current-plist))) 231 (set-text-properties begin (point) current-plist)))
233 (list (unless (zerop (mod (length x) 2)) 232 (list (unless (zerop (mod (length x) 2))
234 (error "Odd number of args in plist: %S" x)) 233 (error "Odd number of args in plist: %S" x))
235 (setq current-plist x)))) 234 (setq current-plist x))))
236 (buffer-string))) 235 (buffer-string)))
237 236
238 237
@@ -245,8 +244,8 @@ buffer, and renames the original buffer back to BUFFER-NAME.
245 244
246This is useful if THUNK has undesirable side-effects on an Emacs 245This is useful if THUNK has undesirable side-effects on an Emacs
247buffer with a fixed name such as *Messages*." 246buffer with a fixed name such as *Messages*."
248 (lexical-let ((new-buffer-name (generate-new-buffer-name 247 (let ((new-buffer-name (generate-new-buffer-name
249 (format "%s orig buffer" buffer-name)))) 248 (format "%s orig buffer" buffer-name))))
250 (with-current-buffer (get-buffer-create buffer-name) 249 (with-current-buffer (get-buffer-create buffer-name)
251 (rename-buffer new-buffer-name)) 250 (rename-buffer new-buffer-name))
252 (unwind-protect 251 (unwind-protect
@@ -258,7 +257,7 @@ buffer with a fixed name such as *Messages*."
258 (with-current-buffer new-buffer-name 257 (with-current-buffer new-buffer-name
259 (rename-buffer buffer-name))))) 258 (rename-buffer buffer-name)))))
260 259
261(defmacro* ert-with-buffer-renamed ((buffer-name-form) &body body) 260(cl-defmacro ert-with-buffer-renamed ((buffer-name-form) &body body)
262 "Protect the buffer named BUFFER-NAME from side-effects and run BODY. 261 "Protect the buffer named BUFFER-NAME from side-effects and run BODY.
263 262
264See `ert-call-with-buffer-renamed' for details." 263See `ert-call-with-buffer-renamed' for details."
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index ff00be7a237..ab6dcb58143 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -1,4 +1,4 @@
1;;; ert.el --- Emacs Lisp Regression Testing 1;;; ert.el --- Emacs Lisp Regression Testing -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 2007-2008, 2010-2012 Free Software Foundation, Inc. 3;; Copyright (C) 2007-2008, 2010-2012 Free Software Foundation, Inc.
4 4
@@ -54,8 +54,7 @@
54 54
55;;; Code: 55;;; Code:
56 56
57(eval-when-compile 57(eval-when-compile (require 'cl-lib))
58 (require 'cl))
59(require 'button) 58(require 'button)
60(require 'debug) 59(require 'debug)
61(require 'easymenu) 60(require 'easymenu)
@@ -105,33 +104,33 @@
105 "A reimplementation of `remove-if-not'. 104 "A reimplementation of `remove-if-not'.
106 105
107ERT-PRED is a predicate, ERT-LIST is the input list." 106ERT-PRED is a predicate, ERT-LIST is the input list."
108 (loop for ert-x in ert-list 107 (cl-loop for ert-x in ert-list
109 if (funcall ert-pred ert-x) 108 if (funcall ert-pred ert-x)
110 collect ert-x)) 109 collect ert-x))
111 110
112(defun ert--intersection (a b) 111(defun ert--intersection (a b)
113 "A reimplementation of `intersection'. Intersect the sets A and B. 112 "A reimplementation of `intersection'. Intersect the sets A and B.
114 113
115Elements are compared using `eql'." 114Elements are compared using `eql'."
116 (loop for x in a 115 (cl-loop for x in a
117 if (memql x b) 116 if (memql x b)
118 collect x)) 117 collect x))
119 118
120(defun ert--set-difference (a b) 119(defun ert--set-difference (a b)
121 "A reimplementation of `set-difference'. Subtract the set B from the set A. 120 "A reimplementation of `set-difference'. Subtract the set B from the set A.
122 121
123Elements are compared using `eql'." 122Elements are compared using `eql'."
124 (loop for x in a 123 (cl-loop for x in a
125 unless (memql x b) 124 unless (memql x b)
126 collect x)) 125 collect x))
127 126
128(defun ert--set-difference-eq (a b) 127(defun ert--set-difference-eq (a b)
129 "A reimplementation of `set-difference'. Subtract the set B from the set A. 128 "A reimplementation of `set-difference'. Subtract the set B from the set A.
130 129
131Elements are compared using `eq'." 130Elements are compared using `eq'."
132 (loop for x in a 131 (cl-loop for x in a
133 unless (memq x b) 132 unless (memq x b)
134 collect x)) 133 collect x))
135 134
136(defun ert--union (a b) 135(defun ert--union (a b)
137 "A reimplementation of `union'. Compute the union of the sets A and B. 136 "A reimplementation of `union'. Compute the union of the sets A and B.
@@ -149,7 +148,7 @@ Elements are compared using `eql'."
149 (make-symbol (format "%s%s" 148 (make-symbol (format "%s%s"
150 prefix 149 prefix
151 (prog1 ert--gensym-counter 150 (prog1 ert--gensym-counter
152 (incf ert--gensym-counter)))))) 151 (cl-incf ert--gensym-counter))))))
153 152
154(defun ert--coerce-to-vector (x) 153(defun ert--coerce-to-vector (x)
155 "Coerce X to a vector." 154 "Coerce X to a vector."
@@ -158,19 +157,19 @@ Elements are compared using `eql'."
158 x 157 x
159 (vconcat x))) 158 (vconcat x)))
160 159
161(defun* ert--remove* (x list &key key test) 160(cl-defun ert--remove* (x list &key key test)
162 "Does not support all the keywords of remove*." 161 "Does not support all the keywords of remove*."
163 (unless key (setq key #'identity)) 162 (unless key (setq key #'identity))
164 (unless test (setq test #'eql)) 163 (unless test (setq test #'eql))
165 (loop for y in list 164 (cl-loop for y in list
166 unless (funcall test x (funcall key y)) 165 unless (funcall test x (funcall key y))
167 collect y)) 166 collect y))
168 167
169(defun ert--string-position (c s) 168(defun ert--string-position (c s)
170 "Return the position of the first occurrence of C in S, or nil if none." 169 "Return the position of the first occurrence of C in S, or nil if none."
171 (loop for i from 0 170 (cl-loop for i from 0
172 for x across s 171 for x across s
173 when (eql x c) return i)) 172 when (eql x c) return i))
174 173
175(defun ert--mismatch (a b) 174(defun ert--mismatch (a b)
176 "Return index of first element that differs between A and B. 175 "Return index of first element that differs between A and B.
@@ -184,29 +183,30 @@ Like `mismatch'. Uses `equal' for comparison."
184 (t 183 (t
185 (let ((la (length a)) 184 (let ((la (length a))
186 (lb (length b))) 185 (lb (length b)))
187 (assert (arrayp a) t) 186 (cl-assert (arrayp a) t)
188 (assert (arrayp b) t) 187 (cl-assert (arrayp b) t)
189 (assert (<= la lb) t) 188 (cl-assert (<= la lb) t)
190 (loop for i below la 189 (cl-loop for i below la
191 when (not (equal (aref a i) (aref b i))) return i 190 when (not (equal (aref a i) (aref b i))) return i
192 finally (return (if (/= la lb) 191 finally (cl-return (if (/= la lb)
193 la 192 la
194 (assert (equal a b) t) 193 (cl-assert (equal a b) t)
195 nil))))))) 194 nil)))))))
196 195
197(defun ert--subseq (seq start &optional end) 196(defun ert--subseq (seq start &optional end)
198 "Return a subsequence of SEQ from START to END." 197 "Return a subsequence of SEQ from START to END."
199 (when (char-table-p seq) (error "Not supported")) 198 (when (char-table-p seq) (error "Not supported"))
200 (let ((vector (substring (ert--coerce-to-vector seq) start end))) 199 (let ((vector (substring (ert--coerce-to-vector seq) start end)))
201 (etypecase seq 200 (cl-etypecase seq
202 (vector vector) 201 (vector vector)
203 (string (concat vector)) 202 (string (concat vector))
204 (list (append vector nil)) 203 (list (append vector nil))
205 (bool-vector (loop with result = (make-bool-vector (length vector) nil) 204 (bool-vector (cl-loop with result
206 for i below (length vector) do 205 = (make-bool-vector (length vector) nil)
207 (setf (aref result i) (aref vector i)) 206 for i below (length vector) do
208 finally (return result))) 207 (setf (aref result i) (aref vector i))
209 (char-table (assert nil))))) 208 finally (cl-return result)))
209 (char-table (cl-assert nil)))))
210 210
211(defun ert-equal-including-properties (a b) 211(defun ert-equal-including-properties (a b)
212 "Return t if A and B have similar structure and contents. 212 "Return t if A and B have similar structure and contents.
@@ -225,10 +225,10 @@ Emacs bug 6581 at URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6581'."
225;;; Defining and locating tests. 225;;; Defining and locating tests.
226 226
227;; The data structure that represents a test case. 227;; The data structure that represents a test case.
228(defstruct ert-test 228(cl-defstruct ert-test
229 (name nil) 229 (name nil)
230 (documentation nil) 230 (documentation nil)
231 (body (assert nil)) 231 (body (cl-assert nil))
232 (most-recent-result nil) 232 (most-recent-result nil)
233 (expected-result-type ':passed) 233 (expected-result-type ':passed)
234 (tags '())) 234 (tags '()))
@@ -273,7 +273,7 @@ Returns a two-element list containing the keys-and-values plist
273and the body." 273and the body."
274 (let ((extracted-key-accu '()) 274 (let ((extracted-key-accu '())
275 (remaining keys-and-body)) 275 (remaining keys-and-body))
276 (while (and (consp remaining) (keywordp (first remaining))) 276 (while (keywordp (car-safe remaining))
277 (let ((keyword (pop remaining))) 277 (let ((keyword (pop remaining)))
278 (unless (consp remaining) 278 (unless (consp remaining)
279 (error "Value expected after keyword %S in %S" 279 (error "Value expected after keyword %S in %S"
@@ -283,13 +283,13 @@ and the body."
283 keys-and-body)) 283 keys-and-body))
284 (push (cons keyword (pop remaining)) extracted-key-accu))) 284 (push (cons keyword (pop remaining)) extracted-key-accu)))
285 (setq extracted-key-accu (nreverse extracted-key-accu)) 285 (setq extracted-key-accu (nreverse extracted-key-accu))
286 (list (loop for (key . value) in extracted-key-accu 286 (list (cl-loop for (key . value) in extracted-key-accu
287 collect key 287 collect key
288 collect value) 288 collect value)
289 remaining))) 289 remaining)))
290 290
291;;;###autoload 291;;;###autoload
292(defmacro* ert-deftest (name () &body docstring-keys-and-body) 292(cl-defmacro ert-deftest (name () &body docstring-keys-and-body)
293 "Define NAME (a symbol) as a test. 293 "Define NAME (a symbol) as a test.
294 294
295BODY is evaluated as a `progn' when the test is run. It should 295BODY is evaluated as a `progn' when the test is run. It should
@@ -313,12 +313,13 @@ description of valid values for RESULT-TYPE.
313 (indent 2)) 313 (indent 2))
314 (let ((documentation nil) 314 (let ((documentation nil)
315 (documentation-supplied-p nil)) 315 (documentation-supplied-p nil))
316 (when (stringp (first docstring-keys-and-body)) 316 (when (stringp (car docstring-keys-and-body))
317 (setq documentation (pop docstring-keys-and-body) 317 (setq documentation (pop docstring-keys-and-body)
318 documentation-supplied-p t)) 318 documentation-supplied-p t))
319 (destructuring-bind ((&key (expected-result nil expected-result-supplied-p) 319 (cl-destructuring-bind
320 (tags nil tags-supplied-p)) 320 ((&key (expected-result nil expected-result-supplied-p)
321 body) 321 (tags nil tags-supplied-p))
322 body)
322 (ert--parse-keys-and-body docstring-keys-and-body) 323 (ert--parse-keys-and-body docstring-keys-and-body)
323 `(progn 324 `(progn
324 (ert-set-test ',name 325 (ert-set-test ',name
@@ -388,16 +389,11 @@ DATA is displayed to the user and should state the reason of the failure."
388(defun ert--expand-should-1 (whole form inner-expander) 389(defun ert--expand-should-1 (whole form inner-expander)
389 "Helper function for the `should' macro and its variants." 390 "Helper function for the `should' macro and its variants."
390 (let ((form 391 (let ((form
391 ;; If `cl-macroexpand' isn't bound, the code that we're 392 (macroexpand form (cond
392 ;; compiling doesn't depend on cl and thus doesn't need an 393 ((boundp 'macroexpand-all-environment)
393 ;; environment arg for `macroexpand'. 394 macroexpand-all-environment)
394 (if (fboundp 'cl-macroexpand) 395 ((boundp 'cl-macro-environment)
395 ;; Suppress warning about run-time call to cl function: we 396 cl-macro-environment)))))
396 ;; only call it if it's fboundp.
397 (with-no-warnings
398 (cl-macroexpand form (and (boundp 'cl-macro-environment)
399 cl-macro-environment)))
400 (macroexpand form))))
401 (cond 397 (cond
402 ((or (atom form) (ert--special-operator-p (car form))) 398 ((or (atom form) (ert--special-operator-p (car form)))
403 (let ((value (ert--gensym "value-"))) 399 (let ((value (ert--gensym "value-")))
@@ -410,10 +406,10 @@ DATA is displayed to the user and should state the reason of the failure."
410 (t 406 (t
411 (let ((fn-name (car form)) 407 (let ((fn-name (car form))
412 (arg-forms (cdr form))) 408 (arg-forms (cdr form)))
413 (assert (or (symbolp fn-name) 409 (cl-assert (or (symbolp fn-name)
414 (and (consp fn-name) 410 (and (consp fn-name)
415 (eql (car fn-name) 'lambda) 411 (eql (car fn-name) 'lambda)
416 (listp (cdr fn-name))))) 412 (listp (cdr fn-name)))))
417 (let ((fn (ert--gensym "fn-")) 413 (let ((fn (ert--gensym "fn-"))
418 (args (ert--gensym "args-")) 414 (args (ert--gensym "args-"))
419 (value (ert--gensym "value-")) 415 (value (ert--gensym "value-"))
@@ -451,35 +447,34 @@ should return code that calls INNER-FORM and performs the checks
451and error signaling specific to the particular variant of 447and error signaling specific to the particular variant of
452`should'. The code that INNER-EXPANDER returns must not call 448`should'. The code that INNER-EXPANDER returns must not call
453FORM-DESCRIPTION-FORM before it has called INNER-FORM." 449FORM-DESCRIPTION-FORM before it has called INNER-FORM."
454 (lexical-let ((inner-expander inner-expander)) 450 (ert--expand-should-1
455 (ert--expand-should-1 451 whole form
456 whole form 452 (lambda (inner-form form-description-form value-var)
457 (lambda (inner-form form-description-form value-var) 453 (let ((form-description (ert--gensym "form-description-")))
458 (let ((form-description (ert--gensym "form-description-"))) 454 `(let (,form-description)
459 `(let (,form-description) 455 ,(funcall inner-expander
460 ,(funcall inner-expander 456 `(unwind-protect
461 `(unwind-protect 457 ,inner-form
462 ,inner-form 458 (setq ,form-description ,form-description-form)
463 (setq ,form-description ,form-description-form) 459 (ert--signal-should-execution ,form-description))
464 (ert--signal-should-execution ,form-description)) 460 `,form-description
465 `,form-description 461 value-var))))))
466 value-var))))))) 462
467 463(cl-defmacro should (form)
468(defmacro* should (form)
469 "Evaluate FORM. If it returns nil, abort the current test as failed. 464 "Evaluate FORM. If it returns nil, abort the current test as failed.
470 465
471Returns the value of FORM." 466Returns the value of FORM."
472 (ert--expand-should `(should ,form) form 467 (ert--expand-should `(should ,form) form
473 (lambda (inner-form form-description-form value-var) 468 (lambda (inner-form form-description-form _value-var)
474 `(unless ,inner-form 469 `(unless ,inner-form
475 (ert-fail ,form-description-form))))) 470 (ert-fail ,form-description-form)))))
476 471
477(defmacro* should-not (form) 472(cl-defmacro should-not (form)
478 "Evaluate FORM. If it returns non-nil, abort the current test as failed. 473 "Evaluate FORM. If it returns non-nil, abort the current test as failed.
479 474
480Returns nil." 475Returns nil."
481 (ert--expand-should `(should-not ,form) form 476 (ert--expand-should `(should-not ,form) form
482 (lambda (inner-form form-description-form value-var) 477 (lambda (inner-form form-description-form _value-var)
483 `(unless (not ,inner-form) 478 `(unless (not ,inner-form)
484 (ert-fail ,form-description-form))))) 479 (ert-fail ,form-description-form)))))
485 480
@@ -490,10 +485,10 @@ Returns nil."
490Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES, 485Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES,
491and aborts the current test as failed if it doesn't." 486and aborts the current test as failed if it doesn't."
492 (let ((signaled-conditions (get (car condition) 'error-conditions)) 487 (let ((signaled-conditions (get (car condition) 'error-conditions))
493 (handled-conditions (etypecase type 488 (handled-conditions (cl-etypecase type
494 (list type) 489 (list type)
495 (symbol (list type))))) 490 (symbol (list type)))))
496 (assert signaled-conditions) 491 (cl-assert signaled-conditions)
497 (unless (ert--intersection signaled-conditions handled-conditions) 492 (unless (ert--intersection signaled-conditions handled-conditions)
498 (ert-fail (append 493 (ert-fail (append
499 (funcall form-description-fn) 494 (funcall form-description-fn)
@@ -512,7 +507,7 @@ and aborts the current test as failed if it doesn't."
512 507
513;; FIXME: The expansion will evaluate the keyword args (if any) in 508;; FIXME: The expansion will evaluate the keyword args (if any) in
514;; nonstandard order. 509;; nonstandard order.
515(defmacro* should-error (form &rest keys &key type exclude-subtypes) 510(cl-defmacro should-error (form &rest keys &key type exclude-subtypes)
516 "Evaluate FORM and check that it signals an error. 511 "Evaluate FORM and check that it signals an error.
517 512
518The error signaled needs to match TYPE. TYPE should be a list 513The error signaled needs to match TYPE. TYPE should be a list
@@ -560,19 +555,19 @@ failed."
560 555
561(defun ert--proper-list-p (x) 556(defun ert--proper-list-p (x)
562 "Return non-nil if X is a proper list, nil otherwise." 557 "Return non-nil if X is a proper list, nil otherwise."
563 (loop 558 (cl-loop
564 for firstp = t then nil 559 for firstp = t then nil
565 for fast = x then (cddr fast) 560 for fast = x then (cddr fast)
566 for slow = x then (cdr slow) do 561 for slow = x then (cdr slow) do
567 (when (null fast) (return t)) 562 (when (null fast) (cl-return t))
568 (when (not (consp fast)) (return nil)) 563 (when (not (consp fast)) (cl-return nil))
569 (when (null (cdr fast)) (return t)) 564 (when (null (cdr fast)) (cl-return t))
570 (when (not (consp (cdr fast))) (return nil)) 565 (when (not (consp (cdr fast))) (cl-return nil))
571 (when (and (not firstp) (eq fast slow)) (return nil)))) 566 (when (and (not firstp) (eq fast slow)) (cl-return nil))))
572 567
573(defun ert--explain-format-atom (x) 568(defun ert--explain-format-atom (x)
574 "Format the atom X for `ert--explain-equal'." 569 "Format the atom X for `ert--explain-equal'."
575 (typecase x 570 (cl-typecase x
576 (fixnum (list x (format "#x%x" x) (format "?%c" x))) 571 (fixnum (list x (format "#x%x" x) (format "?%c" x)))
577 (t x))) 572 (t x)))
578 573
@@ -581,7 +576,7 @@ failed."
581Returns nil if they are." 576Returns nil if they are."
582 (if (not (equal (type-of a) (type-of b))) 577 (if (not (equal (type-of a) (type-of b)))
583 `(different-types ,a ,b) 578 `(different-types ,a ,b)
584 (etypecase a 579 (cl-etypecase a
585 (cons 580 (cons
586 (let ((a-proper-p (ert--proper-list-p a)) 581 (let ((a-proper-p (ert--proper-list-p a))
587 (b-proper-p (ert--proper-list-p b))) 582 (b-proper-p (ert--proper-list-p b)))
@@ -593,19 +588,19 @@ Returns nil if they are."
593 ,a ,b 588 ,a ,b
594 first-mismatch-at 589 first-mismatch-at
595 ,(ert--mismatch a b)) 590 ,(ert--mismatch a b))
596 (loop for i from 0 591 (cl-loop for i from 0
597 for ai in a 592 for ai in a
598 for bi in b 593 for bi in b
599 for xi = (ert--explain-equal-rec ai bi) 594 for xi = (ert--explain-equal-rec ai bi)
600 do (when xi (return `(list-elt ,i ,xi))) 595 do (when xi (cl-return `(list-elt ,i ,xi)))
601 finally (assert (equal a b) t))) 596 finally (cl-assert (equal a b) t)))
602 (let ((car-x (ert--explain-equal-rec (car a) (car b)))) 597 (let ((car-x (ert--explain-equal-rec (car a) (car b))))
603 (if car-x 598 (if car-x
604 `(car ,car-x) 599 `(car ,car-x)
605 (let ((cdr-x (ert--explain-equal-rec (cdr a) (cdr b)))) 600 (let ((cdr-x (ert--explain-equal-rec (cdr a) (cdr b))))
606 (if cdr-x 601 (if cdr-x
607 `(cdr ,cdr-x) 602 `(cdr ,cdr-x)
608 (assert (equal a b) t) 603 (cl-assert (equal a b) t)
609 nil)))))))) 604 nil))))))))
610 (array (if (not (equal (length a) (length b))) 605 (array (if (not (equal (length a) (length b)))
611 `(arrays-of-different-length ,(length a) ,(length b) 606 `(arrays-of-different-length ,(length a) ,(length b)
@@ -613,12 +608,12 @@ Returns nil if they are."
613 ,@(unless (char-table-p a) 608 ,@(unless (char-table-p a)
614 `(first-mismatch-at 609 `(first-mismatch-at
615 ,(ert--mismatch a b)))) 610 ,(ert--mismatch a b))))
616 (loop for i from 0 611 (cl-loop for i from 0
617 for ai across a 612 for ai across a
618 for bi across b 613 for bi across b
619 for xi = (ert--explain-equal-rec ai bi) 614 for xi = (ert--explain-equal-rec ai bi)
620 do (when xi (return `(array-elt ,i ,xi))) 615 do (when xi (cl-return `(array-elt ,i ,xi)))
621 finally (assert (equal a b) t)))) 616 finally (cl-assert (equal a b) t))))
622 (atom (if (not (equal a b)) 617 (atom (if (not (equal a b))
623 (if (and (symbolp a) (symbolp b) (string= a b)) 618 (if (and (symbolp a) (symbolp b) (string= a b))
624 `(different-symbols-with-the-same-name ,a ,b) 619 `(different-symbols-with-the-same-name ,a ,b)
@@ -637,10 +632,10 @@ Returns nil if they are."
637 632
638(defun ert--significant-plist-keys (plist) 633(defun ert--significant-plist-keys (plist)
639 "Return the keys of PLIST that have non-null values, in order." 634 "Return the keys of PLIST that have non-null values, in order."
640 (assert (zerop (mod (length plist) 2)) t) 635 (cl-assert (zerop (mod (length plist) 2)) t)
641 (loop for (key value . rest) on plist by #'cddr 636 (cl-loop for (key value . rest) on plist by #'cddr
642 unless (or (null value) (memq key accu)) collect key into accu 637 unless (or (null value) (memq key accu)) collect key into accu
643 finally (return accu))) 638 finally (cl-return accu)))
644 639
645(defun ert--plist-difference-explanation (a b) 640(defun ert--plist-difference-explanation (a b)
646 "Return a programmer-readable explanation of why A and B are different plists. 641 "Return a programmer-readable explanation of why A and B are different plists.
@@ -648,8 +643,8 @@ Returns nil if they are."
648Returns nil if they are equivalent, i.e., have the same value for 643Returns nil if they are equivalent, i.e., have the same value for
649each key, where absent values are treated as nil. The order of 644each key, where absent values are treated as nil. The order of
650key/value pairs in each list does not matter." 645key/value pairs in each list does not matter."
651 (assert (zerop (mod (length a) 2)) t) 646 (cl-assert (zerop (mod (length a) 2)) t)
652 (assert (zerop (mod (length b) 2)) t) 647 (cl-assert (zerop (mod (length b) 2)) t)
653 ;; Normalizing the plists would be another way to do this but it 648 ;; Normalizing the plists would be another way to do this but it
654 ;; requires a total ordering on all lisp objects (since any object 649 ;; requires a total ordering on all lisp objects (since any object
655 ;; is valid as a text property key). Perhaps defining such an 650 ;; is valid as a text property key). Perhaps defining such an
@@ -659,21 +654,21 @@ key/value pairs in each list does not matter."
659 (keys-b (ert--significant-plist-keys b)) 654 (keys-b (ert--significant-plist-keys b))
660 (keys-in-a-not-in-b (ert--set-difference-eq keys-a keys-b)) 655 (keys-in-a-not-in-b (ert--set-difference-eq keys-a keys-b))
661 (keys-in-b-not-in-a (ert--set-difference-eq keys-b keys-a))) 656 (keys-in-b-not-in-a (ert--set-difference-eq keys-b keys-a)))
662 (flet ((explain-with-key (key) 657 (cl-flet ((explain-with-key (key)
663 (let ((value-a (plist-get a key)) 658 (let ((value-a (plist-get a key))
664 (value-b (plist-get b key))) 659 (value-b (plist-get b key)))
665 (assert (not (equal value-a value-b)) t) 660 (cl-assert (not (equal value-a value-b)) t)
666 `(different-properties-for-key 661 `(different-properties-for-key
667 ,key ,(ert--explain-equal-including-properties value-a 662 ,key ,(ert--explain-equal-including-properties value-a
668 value-b))))) 663 value-b)))))
669 (cond (keys-in-a-not-in-b 664 (cond (keys-in-a-not-in-b
670 (explain-with-key (first keys-in-a-not-in-b))) 665 (explain-with-key (car keys-in-a-not-in-b)))
671 (keys-in-b-not-in-a 666 (keys-in-b-not-in-a
672 (explain-with-key (first keys-in-b-not-in-a))) 667 (explain-with-key (car keys-in-b-not-in-a)))
673 (t 668 (t
674 (loop for key in keys-a 669 (cl-loop for key in keys-a
675 when (not (equal (plist-get a key) (plist-get b key))) 670 when (not (equal (plist-get a key) (plist-get b key)))
676 return (explain-with-key key))))))) 671 return (explain-with-key key)))))))
677 672
678(defun ert--abbreviate-string (s len suffixp) 673(defun ert--abbreviate-string (s len suffixp)
679 "Shorten string S to at most LEN chars. 674 "Shorten string S to at most LEN chars.
@@ -697,29 +692,30 @@ Returns a programmer-readable explanation of why A and B are not
697`ert-equal-including-properties', or nil if they are." 692`ert-equal-including-properties', or nil if they are."
698 (if (not (equal a b)) 693 (if (not (equal a b))
699 (ert--explain-equal a b) 694 (ert--explain-equal a b)
700 (assert (stringp a) t) 695 (cl-assert (stringp a) t)
701 (assert (stringp b) t) 696 (cl-assert (stringp b) t)
702 (assert (eql (length a) (length b)) t) 697 (cl-assert (eql (length a) (length b)) t)
703 (loop for i from 0 to (length a) 698 (cl-loop for i from 0 to (length a)
704 for props-a = (text-properties-at i a) 699 for props-a = (text-properties-at i a)
705 for props-b = (text-properties-at i b) 700 for props-b = (text-properties-at i b)
706 for difference = (ert--plist-difference-explanation props-a props-b) 701 for difference = (ert--plist-difference-explanation
707 do (when difference 702 props-a props-b)
708 (return `(char ,i ,(substring-no-properties a i (1+ i)) 703 do (when difference
709 ,difference 704 (cl-return `(char ,i ,(substring-no-properties a i (1+ i))
710 context-before 705 ,difference
711 ,(ert--abbreviate-string 706 context-before
712 (substring-no-properties a 0 i) 707 ,(ert--abbreviate-string
713 10 t) 708 (substring-no-properties a 0 i)
714 context-after 709 10 t)
715 ,(ert--abbreviate-string 710 context-after
716 (substring-no-properties a (1+ i)) 711 ,(ert--abbreviate-string
717 10 nil)))) 712 (substring-no-properties a (1+ i))
718 ;; TODO(ohler): Get `equal-including-properties' fixed in 713 10 nil))))
719 ;; Emacs, delete `ert-equal-including-properties', and 714 ;; TODO(ohler): Get `equal-including-properties' fixed in
720 ;; re-enable this assertion. 715 ;; Emacs, delete `ert-equal-including-properties', and
721 ;;finally (assert (equal-including-properties a b) t) 716 ;; re-enable this assertion.
722 ))) 717 ;;finally (cl-assert (equal-including-properties a b) t)
718 )))
723(put 'ert-equal-including-properties 719(put 'ert-equal-including-properties
724 'ert-explainer 720 'ert-explainer
725 'ert--explain-equal-including-properties) 721 'ert--explain-equal-including-properties)
@@ -734,8 +730,8 @@ Returns a programmer-readable explanation of why A and B are not
734 730
735Bound dynamically. This is a list of (PREFIX . MESSAGE) pairs.") 731Bound dynamically. This is a list of (PREFIX . MESSAGE) pairs.")
736 732
737(defmacro* ert-info ((message-form &key ((:prefix prefix-form) "Info: ")) 733(cl-defmacro ert-info ((message-form &key ((:prefix prefix-form) "Info: "))
738 &body body) 734 &body body)
739 "Evaluate MESSAGE-FORM and BODY, and report the message if BODY fails. 735 "Evaluate MESSAGE-FORM and BODY, and report the message if BODY fails.
740 736
741To be used within ERT tests. MESSAGE-FORM should evaluate to a 737To be used within ERT tests. MESSAGE-FORM should evaluate to a
@@ -755,18 +751,19 @@ and is displayed in front of the value of MESSAGE-FORM."
755 "Non-nil means enter debugger when a test fails or terminates with an error.") 751 "Non-nil means enter debugger when a test fails or terminates with an error.")
756 752
757;; The data structures that represent the result of running a test. 753;; The data structures that represent the result of running a test.
758(defstruct ert-test-result 754(cl-defstruct ert-test-result
759 (messages nil) 755 (messages nil)
760 (should-forms nil) 756 (should-forms nil)
761 ) 757 )
762(defstruct (ert-test-passed (:include ert-test-result))) 758(cl-defstruct (ert-test-passed (:include ert-test-result)))
763(defstruct (ert-test-result-with-condition (:include ert-test-result)) 759(cl-defstruct (ert-test-result-with-condition (:include ert-test-result))
764 (condition (assert nil)) 760 (condition (cl-assert nil))
765 (backtrace (assert nil)) 761 (backtrace (cl-assert nil))
766 (infos (assert nil))) 762 (infos (cl-assert nil)))
767(defstruct (ert-test-quit (:include ert-test-result-with-condition))) 763(cl-defstruct (ert-test-quit (:include ert-test-result-with-condition)))
768(defstruct (ert-test-failed (:include ert-test-result-with-condition))) 764(cl-defstruct (ert-test-failed (:include ert-test-result-with-condition)))
769(defstruct (ert-test-aborted-with-non-local-exit (:include ert-test-result))) 765(cl-defstruct (ert-test-aborted-with-non-local-exit
766 (:include ert-test-result)))
770 767
771 768
772(defun ert--record-backtrace () 769(defun ert--record-backtrace ()
@@ -779,7 +776,7 @@ and is displayed in front of the value of MESSAGE-FORM."
779 ;; `ert-results-pop-to-backtrace-for-test-at-point' given that we 776 ;; `ert-results-pop-to-backtrace-for-test-at-point' given that we
780 ;; already have `ert-results-rerun-test-debugging-errors-at-point'. 777 ;; already have `ert-results-rerun-test-debugging-errors-at-point'.
781 ;; For batch use, however, printing the backtrace may be useful. 778 ;; For batch use, however, printing the backtrace may be useful.
782 (loop 779 (cl-loop
783 ;; 6 is the number of frames our own debugger adds (when 780 ;; 6 is the number of frames our own debugger adds (when
784 ;; compiled; more when interpreted). FIXME: Need to describe a 781 ;; compiled; more when interpreted). FIXME: Need to describe a
785 ;; procedure for determining this constant. 782 ;; procedure for determining this constant.
@@ -796,33 +793,33 @@ and is displayed in front of the value of MESSAGE-FORM."
796 (print-level 8) 793 (print-level 8)
797 (print-length 50)) 794 (print-length 50))
798 (dolist (frame backtrace) 795 (dolist (frame backtrace)
799 (ecase (first frame) 796 (cl-ecase (car frame)
800 ((nil) 797 ((nil)
801 ;; Special operator. 798 ;; Special operator.
802 (destructuring-bind (special-operator &rest arg-forms) 799 (cl-destructuring-bind (special-operator &rest arg-forms)
803 (cdr frame) 800 (cdr frame)
804 (insert 801 (insert
805 (format " %S\n" (list* special-operator arg-forms))))) 802 (format " %S\n" (cons special-operator arg-forms)))))
806 ((t) 803 ((t)
807 ;; Function call. 804 ;; Function call.
808 (destructuring-bind (fn &rest args) (cdr frame) 805 (cl-destructuring-bind (fn &rest args) (cdr frame)
809 (insert (format " %S(" fn)) 806 (insert (format " %S(" fn))
810 (loop for firstp = t then nil 807 (cl-loop for firstp = t then nil
811 for arg in args do 808 for arg in args do
812 (unless firstp 809 (unless firstp
813 (insert " ")) 810 (insert " "))
814 (insert (format "%S" arg))) 811 (insert (format "%S" arg)))
815 (insert ")\n"))))))) 812 (insert ")\n")))))))
816 813
817;; A container for the state of the execution of a single test and 814;; A container for the state of the execution of a single test and
818;; environment data needed during its execution. 815;; environment data needed during its execution.
819(defstruct ert--test-execution-info 816(cl-defstruct ert--test-execution-info
820 (test (assert nil)) 817 (test (cl-assert nil))
821 (result (assert nil)) 818 (result (cl-assert nil))
822 ;; A thunk that may be called when RESULT has been set to its final 819 ;; A thunk that may be called when RESULT has been set to its final
823 ;; value and test execution should be terminated. Should not 820 ;; value and test execution should be terminated. Should not
824 ;; return. 821 ;; return.
825 (exit-continuation (assert nil)) 822 (exit-continuation (cl-assert nil))
826 ;; The binding of `debugger' outside of the execution of the test. 823 ;; The binding of `debugger' outside of the execution of the test.
827 next-debugger 824 next-debugger
828 ;; The binding of `ert-debug-on-error' that is in effect for the 825 ;; The binding of `ert-debug-on-error' that is in effect for the
@@ -831,7 +828,7 @@ and is displayed in front of the value of MESSAGE-FORM."
831 ;; don't remember whether this feature is important.) 828 ;; don't remember whether this feature is important.)
832 ert-debug-on-error) 829 ert-debug-on-error)
833 830
834(defun ert--run-test-debugger (info debugger-args) 831(defun ert--run-test-debugger (info args)
835 "During a test run, `debugger' is bound to a closure that calls this function. 832 "During a test run, `debugger' is bound to a closure that calls this function.
836 833
837This function records failures and errors and either terminates 834This function records failures and errors and either terminates
@@ -839,21 +836,21 @@ the test silently or calls the interactive debugger, as
839appropriate. 836appropriate.
840 837
841INFO is the ert--test-execution-info corresponding to this test 838INFO is the ert--test-execution-info corresponding to this test
842run. DEBUGGER-ARGS are the arguments to `debugger'." 839run. ARGS are the arguments to `debugger'."
843 (destructuring-bind (first-debugger-arg &rest more-debugger-args) 840 (cl-destructuring-bind (first-debugger-arg &rest more-debugger-args)
844 debugger-args 841 args
845 (ecase first-debugger-arg 842 (cl-ecase first-debugger-arg
846 ((lambda debug t exit nil) 843 ((lambda debug t exit nil)
847 (apply (ert--test-execution-info-next-debugger info) debugger-args)) 844 (apply (ert--test-execution-info-next-debugger info) args))
848 (error 845 (error
849 (let* ((condition (first more-debugger-args)) 846 (let* ((condition (car more-debugger-args))
850 (type (case (car condition) 847 (type (cl-case (car condition)
851 ((quit) 'quit) 848 ((quit) 'quit)
852 (otherwise 'failed))) 849 (otherwise 'failed)))
853 (backtrace (ert--record-backtrace)) 850 (backtrace (ert--record-backtrace))
854 (infos (reverse ert--infos))) 851 (infos (reverse ert--infos)))
855 (setf (ert--test-execution-info-result info) 852 (setf (ert--test-execution-info-result info)
856 (ecase type 853 (cl-ecase type
857 (quit 854 (quit
858 (make-ert-test-quit :condition condition 855 (make-ert-test-quit :condition condition
859 :backtrace backtrace 856 :backtrace backtrace
@@ -864,39 +861,42 @@ run. DEBUGGER-ARGS are the arguments to `debugger'."
864 :infos infos)))) 861 :infos infos))))
865 ;; Work around Emacs's heuristic (in eval.c) for detecting 862 ;; Work around Emacs's heuristic (in eval.c) for detecting
866 ;; errors in the debugger. 863 ;; errors in the debugger.
867 (incf num-nonmacro-input-events) 864 (cl-incf num-nonmacro-input-events)
868 ;; FIXME: We should probably implement more fine-grained 865 ;; FIXME: We should probably implement more fine-grained
869 ;; control a la non-t `debug-on-error' here. 866 ;; control a la non-t `debug-on-error' here.
870 (cond 867 (cond
871 ((ert--test-execution-info-ert-debug-on-error info) 868 ((ert--test-execution-info-ert-debug-on-error info)
872 (apply (ert--test-execution-info-next-debugger info) debugger-args)) 869 (apply (ert--test-execution-info-next-debugger info) args))
873 (t)) 870 (t))
874 (funcall (ert--test-execution-info-exit-continuation info))))))) 871 (funcall (ert--test-execution-info-exit-continuation info)))))))
875 872
876(defun ert--run-test-internal (ert-test-execution-info) 873(defun ert--run-test-internal (test-execution-info)
877 "Low-level function to run a test according to ERT-TEST-EXECUTION-INFO. 874 "Low-level function to run a test according to TEST-EXECUTION-INFO.
878 875
879This mainly sets up debugger-related bindings." 876This mainly sets up debugger-related bindings."
880 (lexical-let ((info ert-test-execution-info)) 877 (setf (ert--test-execution-info-next-debugger test-execution-info) debugger
881 (setf (ert--test-execution-info-next-debugger info) debugger 878 (ert--test-execution-info-ert-debug-on-error test-execution-info)
882 (ert--test-execution-info-ert-debug-on-error info) ert-debug-on-error) 879 ert-debug-on-error)
883 (catch 'ert--pass 880 (catch 'ert--pass
884 ;; For now, each test gets its own temp buffer and its own 881 ;; For now, each test gets its own temp buffer and its own
885 ;; window excursion, just to be safe. If this turns out to be 882 ;; window excursion, just to be safe. If this turns out to be
886 ;; too expensive, we can remove it. 883 ;; too expensive, we can remove it.
887 (with-temp-buffer 884 (with-temp-buffer
888 (save-window-excursion 885 (save-window-excursion
889 (let ((debugger (lambda (&rest debugger-args) 886 (let ((debugger (lambda (&rest args)
890 (ert--run-test-debugger info debugger-args))) 887 (ert--run-test-debugger test-execution-info
891 (debug-on-error t) 888 args)))
892 (debug-on-quit t) 889 (debug-on-error t)
893 ;; FIXME: Do we need to store the old binding of this 890 (debug-on-quit t)
894 ;; and consider it in `ert--run-test-debugger'? 891 ;; FIXME: Do we need to store the old binding of this
895 (debug-ignored-errors nil) 892 ;; and consider it in `ert--run-test-debugger'?
896 (ert--infos '())) 893 (debug-ignored-errors nil)
897 (funcall (ert-test-body (ert--test-execution-info-test info)))))) 894 (ert--infos '()))
898 (ert-pass)) 895 (funcall (ert-test-body (ert--test-execution-info-test
899 (setf (ert--test-execution-info-result info) (make-ert-test-passed))) 896 test-execution-info))))))
897 (ert-pass))
898 (setf (ert--test-execution-info-result test-execution-info)
899 (make-ert-test-passed))
900 nil) 900 nil)
901 901
902(defun ert--force-message-log-buffer-truncation () 902(defun ert--force-message-log-buffer-truncation ()
@@ -934,18 +934,18 @@ The elements are of type `ert-test'.")
934 934
935Returns the result and stores it in ERT-TEST's `most-recent-result' slot." 935Returns the result and stores it in ERT-TEST's `most-recent-result' slot."
936 (setf (ert-test-most-recent-result ert-test) nil) 936 (setf (ert-test-most-recent-result ert-test) nil)
937 (block error 937 (cl-block error
938 (lexical-let ((begin-marker 938 (let ((begin-marker
939 (with-current-buffer (get-buffer-create "*Messages*") 939 (with-current-buffer (get-buffer-create "*Messages*")
940 (set-marker (make-marker) (point-max))))) 940 (set-marker (make-marker) (point-max)))))
941 (unwind-protect 941 (unwind-protect
942 (lexical-let ((info (make-ert--test-execution-info 942 (let ((info (make-ert--test-execution-info
943 :test ert-test 943 :test ert-test
944 :result 944 :result
945 (make-ert-test-aborted-with-non-local-exit) 945 (make-ert-test-aborted-with-non-local-exit)
946 :exit-continuation (lambda () 946 :exit-continuation (lambda ()
947 (return-from error nil)))) 947 (cl-return-from error nil))))
948 (should-form-accu (list))) 948 (should-form-accu (list)))
949 (unwind-protect 949 (unwind-protect
950 (let ((ert--should-execution-observer 950 (let ((ert--should-execution-observer
951 (lambda (form-description) 951 (lambda (form-description)
@@ -987,32 +987,32 @@ t -- Always matches.
987 RESULT." 987 RESULT."
988 ;; It would be easy to add `member' and `eql' types etc., but I 988 ;; It would be easy to add `member' and `eql' types etc., but I
989 ;; haven't bothered yet. 989 ;; haven't bothered yet.
990 (etypecase result-type 990 (cl-etypecase result-type
991 ((member nil) nil) 991 ((member nil) nil)
992 ((member t) t) 992 ((member t) t)
993 ((member :failed) (ert-test-failed-p result)) 993 ((member :failed) (ert-test-failed-p result))
994 ((member :passed) (ert-test-passed-p result)) 994 ((member :passed) (ert-test-passed-p result))
995 (cons 995 (cons
996 (destructuring-bind (operator &rest operands) result-type 996 (cl-destructuring-bind (operator &rest operands) result-type
997 (ecase operator 997 (cl-ecase operator
998 (and 998 (and
999 (case (length operands) 999 (cl-case (length operands)
1000 (0 t) 1000 (0 t)
1001 (t 1001 (t
1002 (and (ert-test-result-type-p result (first operands)) 1002 (and (ert-test-result-type-p result (car operands))
1003 (ert-test-result-type-p result `(and ,@(rest operands))))))) 1003 (ert-test-result-type-p result `(and ,@(cdr operands)))))))
1004 (or 1004 (or
1005 (case (length operands) 1005 (cl-case (length operands)
1006 (0 nil) 1006 (0 nil)
1007 (t 1007 (t
1008 (or (ert-test-result-type-p result (first operands)) 1008 (or (ert-test-result-type-p result (car operands))
1009 (ert-test-result-type-p result `(or ,@(rest operands))))))) 1009 (ert-test-result-type-p result `(or ,@(cdr operands)))))))
1010 (not 1010 (not
1011 (assert (eql (length operands) 1)) 1011 (cl-assert (eql (length operands) 1))
1012 (not (ert-test-result-type-p result (first operands)))) 1012 (not (ert-test-result-type-p result (car operands))))
1013 (satisfies 1013 (satisfies
1014 (assert (eql (length operands) 1)) 1014 (cl-assert (eql (length operands) 1))
1015 (funcall (first operands) result))))))) 1015 (funcall (car operands) result)))))))
1016 1016
1017(defun ert-test-result-expected-p (test result) 1017(defun ert-test-result-expected-p (test result)
1018 "Return non-nil if TEST's expected result type matches RESULT." 1018 "Return non-nil if TEST's expected result type matches RESULT."
@@ -1053,9 +1053,9 @@ set implied by them without checking whether it is really
1053contained in UNIVERSE." 1053contained in UNIVERSE."
1054 ;; This code needs to match the etypecase in 1054 ;; This code needs to match the etypecase in
1055 ;; `ert-insert-human-readable-selector'. 1055 ;; `ert-insert-human-readable-selector'.
1056 (etypecase selector 1056 (cl-etypecase selector
1057 ((member nil) nil) 1057 ((member nil) nil)
1058 ((member t) (etypecase universe 1058 ((member t) (cl-etypecase universe
1059 (list universe) 1059 (list universe)
1060 ((member t) (ert-select-tests "" universe)))) 1060 ((member t) (ert-select-tests "" universe))))
1061 ((member :new) (ert-select-tests 1061 ((member :new) (ert-select-tests
@@ -1083,7 +1083,7 @@ contained in UNIVERSE."
1083 universe)) 1083 universe))
1084 ((member :unexpected) (ert-select-tests `(not :expected) universe)) 1084 ((member :unexpected) (ert-select-tests `(not :expected) universe))
1085 (string 1085 (string
1086 (etypecase universe 1086 (cl-etypecase universe
1087 ((member t) (mapcar #'ert-get-test 1087 ((member t) (mapcar #'ert-get-test
1088 (apropos-internal selector #'ert-test-boundp))) 1088 (apropos-internal selector #'ert-test-boundp)))
1089 (list (ert--remove-if-not (lambda (test) 1089 (list (ert--remove-if-not (lambda (test)
@@ -1093,51 +1093,51 @@ contained in UNIVERSE."
1093 universe)))) 1093 universe))))
1094 (ert-test (list selector)) 1094 (ert-test (list selector))
1095 (symbol 1095 (symbol
1096 (assert (ert-test-boundp selector)) 1096 (cl-assert (ert-test-boundp selector))
1097 (list (ert-get-test selector))) 1097 (list (ert-get-test selector)))
1098 (cons 1098 (cons
1099 (destructuring-bind (operator &rest operands) selector 1099 (cl-destructuring-bind (operator &rest operands) selector
1100 (ecase operator 1100 (cl-ecase operator
1101 (member 1101 (member
1102 (mapcar (lambda (purported-test) 1102 (mapcar (lambda (purported-test)
1103 (etypecase purported-test 1103 (cl-etypecase purported-test
1104 (symbol (assert (ert-test-boundp purported-test)) 1104 (symbol (cl-assert (ert-test-boundp purported-test))
1105 (ert-get-test purported-test)) 1105 (ert-get-test purported-test))
1106 (ert-test purported-test))) 1106 (ert-test purported-test)))
1107 operands)) 1107 operands))
1108 (eql 1108 (eql
1109 (assert (eql (length operands) 1)) 1109 (cl-assert (eql (length operands) 1))
1110 (ert-select-tests `(member ,@operands) universe)) 1110 (ert-select-tests `(member ,@operands) universe))
1111 (and 1111 (and
1112 ;; Do these definitions of AND, NOT and OR satisfy de 1112 ;; Do these definitions of AND, NOT and OR satisfy de
1113 ;; Morgan's laws? Should they? 1113 ;; Morgan's laws? Should they?
1114 (case (length operands) 1114 (cl-case (length operands)
1115 (0 (ert-select-tests 't universe)) 1115 (0 (ert-select-tests 't universe))
1116 (t (ert-select-tests `(and ,@(rest operands)) 1116 (t (ert-select-tests `(and ,@(cdr operands))
1117 (ert-select-tests (first operands) 1117 (ert-select-tests (car operands)
1118 universe))))) 1118 universe)))))
1119 (not 1119 (not
1120 (assert (eql (length operands) 1)) 1120 (cl-assert (eql (length operands) 1))
1121 (let ((all-tests (ert-select-tests 't universe))) 1121 (let ((all-tests (ert-select-tests 't universe)))
1122 (ert--set-difference all-tests 1122 (ert--set-difference all-tests
1123 (ert-select-tests (first operands) 1123 (ert-select-tests (car operands)
1124 all-tests)))) 1124 all-tests))))
1125 (or 1125 (or
1126 (case (length operands) 1126 (cl-case (length operands)
1127 (0 (ert-select-tests 'nil universe)) 1127 (0 (ert-select-tests 'nil universe))
1128 (t (ert--union (ert-select-tests (first operands) universe) 1128 (t (ert--union (ert-select-tests (car operands) universe)
1129 (ert-select-tests `(or ,@(rest operands)) 1129 (ert-select-tests `(or ,@(cdr operands))
1130 universe))))) 1130 universe)))))
1131 (tag 1131 (tag
1132 (assert (eql (length operands) 1)) 1132 (cl-assert (eql (length operands) 1))
1133 (let ((tag (first operands))) 1133 (let ((tag (car operands)))
1134 (ert-select-tests `(satisfies 1134 (ert-select-tests `(satisfies
1135 ,(lambda (test) 1135 ,(lambda (test)
1136 (member tag (ert-test-tags test)))) 1136 (member tag (ert-test-tags test))))
1137 universe))) 1137 universe)))
1138 (satisfies 1138 (satisfies
1139 (assert (eql (length operands) 1)) 1139 (cl-assert (eql (length operands) 1))
1140 (ert--remove-if-not (first operands) 1140 (ert--remove-if-not (car operands)
1141 (ert-select-tests 't universe)))))))) 1141 (ert-select-tests 't universe))))))))
1142 1142
1143(defun ert--insert-human-readable-selector (selector) 1143(defun ert--insert-human-readable-selector (selector)
@@ -1146,26 +1146,27 @@ contained in UNIVERSE."
1146 ;; `backtrace' slot of the result objects in the 1146 ;; `backtrace' slot of the result objects in the
1147 ;; `most-recent-result' slots of test case objects in (eql ...) or 1147 ;; `most-recent-result' slots of test case objects in (eql ...) or
1148 ;; (member ...) selectors. 1148 ;; (member ...) selectors.
1149 (labels ((rec (selector) 1149 (cl-labels ((rec (selector)
1150 ;; This code needs to match the etypecase in `ert-select-tests'. 1150 ;; This code needs to match the etypecase in
1151 (etypecase selector 1151 ;; `ert-select-tests'.
1152 ((or (member nil t 1152 (cl-etypecase selector
1153 :new :failed :passed 1153 ((or (member nil t
1154 :expected :unexpected) 1154 :new :failed :passed
1155 string 1155 :expected :unexpected)
1156 symbol) 1156 string
1157 selector) 1157 symbol)
1158 (ert-test 1158 selector)
1159 (if (ert-test-name selector) 1159 (ert-test
1160 (make-symbol (format "<%S>" (ert-test-name selector))) 1160 (if (ert-test-name selector)
1161 (make-symbol "<unnamed test>"))) 1161 (make-symbol (format "<%S>" (ert-test-name selector)))
1162 (cons 1162 (make-symbol "<unnamed test>")))
1163 (destructuring-bind (operator &rest operands) selector 1163 (cons
1164 (ecase operator 1164 (cl-destructuring-bind (operator &rest operands) selector
1165 ((member eql and not or) 1165 (cl-ecase operator
1166 `(,operator ,@(mapcar #'rec operands))) 1166 ((member eql and not or)
1167 ((member tag satisfies) 1167 `(,operator ,@(mapcar #'rec operands)))
1168 selector))))))) 1168 ((member tag satisfies)
1169 selector)))))))
1169 (insert (format "%S" (rec selector))))) 1170 (insert (format "%S" (rec selector)))))
1170 1171
1171 1172
@@ -1182,21 +1183,21 @@ contained in UNIVERSE."
1182;; that corresponds to this run in order to be able to update the 1183;; that corresponds to this run in order to be able to update the
1183;; statistics correctly when a test is re-run interactively and has a 1184;; statistics correctly when a test is re-run interactively and has a
1184;; different result than before. 1185;; different result than before.
1185(defstruct ert--stats 1186(cl-defstruct ert--stats
1186 (selector (assert nil)) 1187 (selector (cl-assert nil))
1187 ;; The tests, in order. 1188 ;; The tests, in order.
1188 (tests (assert nil) :type vector) 1189 (tests (cl-assert nil) :type vector)
1189 ;; A map of test names (or the test objects themselves for unnamed 1190 ;; A map of test names (or the test objects themselves for unnamed
1190 ;; tests) to indices into the `tests' vector. 1191 ;; tests) to indices into the `tests' vector.
1191 (test-map (assert nil) :type hash-table) 1192 (test-map (cl-assert nil) :type hash-table)
1192 ;; The results of the tests during this run, in order. 1193 ;; The results of the tests during this run, in order.
1193 (test-results (assert nil) :type vector) 1194 (test-results (cl-assert nil) :type vector)
1194 ;; The start times of the tests, in order, as reported by 1195 ;; The start times of the tests, in order, as reported by
1195 ;; `current-time'. 1196 ;; `current-time'.
1196 (test-start-times (assert nil) :type vector) 1197 (test-start-times (cl-assert nil) :type vector)
1197 ;; The end times of the tests, in order, as reported by 1198 ;; The end times of the tests, in order, as reported by
1198 ;; `current-time'. 1199 ;; `current-time'.
1199 (test-end-times (assert nil) :type vector) 1200 (test-end-times (cl-assert nil) :type vector)
1200 (passed-expected 0) 1201 (passed-expected 0)
1201 (passed-unexpected 0) 1202 (passed-unexpected 0)
1202 (failed-expected 0) 1203 (failed-expected 0)
@@ -1246,21 +1247,25 @@ Also changes the counters in STATS to match."
1246 (results (ert--stats-test-results stats)) 1247 (results (ert--stats-test-results stats))
1247 (old-test (aref tests pos)) 1248 (old-test (aref tests pos))
1248 (map (ert--stats-test-map stats))) 1249 (map (ert--stats-test-map stats)))
1249 (flet ((update (d) 1250 (cl-flet ((update (d)
1250 (if (ert-test-result-expected-p (aref tests pos) 1251 (if (ert-test-result-expected-p (aref tests pos)
1251 (aref results pos)) 1252 (aref results pos))
1252 (etypecase (aref results pos) 1253 (cl-etypecase (aref results pos)
1253 (ert-test-passed (incf (ert--stats-passed-expected stats) d)) 1254 (ert-test-passed
1254 (ert-test-failed (incf (ert--stats-failed-expected stats) d)) 1255 (cl-incf (ert--stats-passed-expected stats) d))
1255 (null) 1256 (ert-test-failed
1256 (ert-test-aborted-with-non-local-exit) 1257 (cl-incf (ert--stats-failed-expected stats) d))
1257 (ert-test-quit)) 1258 (null)
1258 (etypecase (aref results pos) 1259 (ert-test-aborted-with-non-local-exit)
1259 (ert-test-passed (incf (ert--stats-passed-unexpected stats) d)) 1260 (ert-test-quit))
1260 (ert-test-failed (incf (ert--stats-failed-unexpected stats) d)) 1261 (cl-etypecase (aref results pos)
1261 (null) 1262 (ert-test-passed
1262 (ert-test-aborted-with-non-local-exit) 1263 (cl-incf (ert--stats-passed-unexpected stats) d))
1263 (ert-test-quit))))) 1264 (ert-test-failed
1265 (cl-incf (ert--stats-failed-unexpected stats) d))
1266 (null)
1267 (ert-test-aborted-with-non-local-exit)
1268 (ert-test-quit)))))
1264 ;; Adjust counters to remove the result that is currently in stats. 1269 ;; Adjust counters to remove the result that is currently in stats.
1265 (update -1) 1270 (update -1)
1266 ;; Put new test and result into stats. 1271 ;; Put new test and result into stats.
@@ -1278,11 +1283,11 @@ Also changes the counters in STATS to match."
1278SELECTOR is the selector that was used to select TESTS." 1283SELECTOR is the selector that was used to select TESTS."
1279 (setq tests (ert--coerce-to-vector tests)) 1284 (setq tests (ert--coerce-to-vector tests))
1280 (let ((map (make-hash-table :size (length tests)))) 1285 (let ((map (make-hash-table :size (length tests))))
1281 (loop for i from 0 1286 (cl-loop for i from 0
1282 for test across tests 1287 for test across tests
1283 for key = (ert--stats-test-key test) do 1288 for key = (ert--stats-test-key test) do
1284 (assert (not (gethash key map))) 1289 (cl-assert (not (gethash key map)))
1285 (setf (gethash key map) i)) 1290 (setf (gethash key map) i))
1286 (make-ert--stats :selector selector 1291 (make-ert--stats :selector selector
1287 :tests tests 1292 :tests tests
1288 :test-map map 1293 :test-map map
@@ -1324,8 +1329,8 @@ SELECTOR is the selector that was used to select TESTS."
1324 (force-mode-line-update) 1329 (force-mode-line-update)
1325 (unwind-protect 1330 (unwind-protect
1326 (progn 1331 (progn
1327 (loop for test in tests do 1332 (cl-loop for test in tests do
1328 (ert-run-or-rerun-test stats test listener)) 1333 (ert-run-or-rerun-test stats test listener))
1329 (setq abortedp nil)) 1334 (setq abortedp nil))
1330 (setf (ert--stats-aborted-p stats) abortedp) 1335 (setf (ert--stats-aborted-p stats) abortedp)
1331 (setf (ert--stats-end-time stats) (current-time)) 1336 (setf (ert--stats-end-time stats) (current-time))
@@ -1349,7 +1354,7 @@ SELECTOR is the selector that was used to select TESTS."
1349 "Return a character that represents the test result RESULT. 1354 "Return a character that represents the test result RESULT.
1350 1355
1351EXPECTEDP specifies whether the result was expected." 1356EXPECTEDP specifies whether the result was expected."
1352 (let ((s (etypecase result 1357 (let ((s (cl-etypecase result
1353 (ert-test-passed ".P") 1358 (ert-test-passed ".P")
1354 (ert-test-failed "fF") 1359 (ert-test-failed "fF")
1355 (null "--") 1360 (null "--")
@@ -1361,7 +1366,7 @@ EXPECTEDP specifies whether the result was expected."
1361 "Return a string that represents the test result RESULT. 1366 "Return a string that represents the test result RESULT.
1362 1367
1363EXPECTEDP specifies whether the result was expected." 1368EXPECTEDP specifies whether the result was expected."
1364 (let ((s (etypecase result 1369 (let ((s (cl-etypecase result
1365 (ert-test-passed '("passed" "PASSED")) 1370 (ert-test-passed '("passed" "PASSED"))
1366 (ert-test-failed '("failed" "FAILED")) 1371 (ert-test-failed '("failed" "FAILED"))
1367 (null '("unknown" "UNKNOWN")) 1372 (null '("unknown" "UNKNOWN"))
@@ -1383,9 +1388,9 @@ Ensures a final newline is inserted."
1383 "Insert `ert-info' infos from RESULT into current buffer. 1388 "Insert `ert-info' infos from RESULT into current buffer.
1384 1389
1385RESULT must be an `ert-test-result-with-condition'." 1390RESULT must be an `ert-test-result-with-condition'."
1386 (check-type result ert-test-result-with-condition) 1391 (cl-check-type result ert-test-result-with-condition)
1387 (dolist (info (ert-test-result-with-condition-infos result)) 1392 (dolist (info (ert-test-result-with-condition-infos result))
1388 (destructuring-bind (prefix . message) info 1393 (cl-destructuring-bind (prefix . message) info
1389 (let ((begin (point)) 1394 (let ((begin (point))
1390 (indentation (make-string (+ (length prefix) 4) ?\s)) 1395 (indentation (make-string (+ (length prefix) 4) ?\s))
1391 (end nil)) 1396 (end nil))
@@ -1421,14 +1426,14 @@ Returns the stats object."
1421 (ert-run-tests 1426 (ert-run-tests
1422 selector 1427 selector
1423 (lambda (event-type &rest event-args) 1428 (lambda (event-type &rest event-args)
1424 (ecase event-type 1429 (cl-ecase event-type
1425 (run-started 1430 (run-started
1426 (destructuring-bind (stats) event-args 1431 (cl-destructuring-bind (stats) event-args
1427 (message "Running %s tests (%s)" 1432 (message "Running %s tests (%s)"
1428 (length (ert--stats-tests stats)) 1433 (length (ert--stats-tests stats))
1429 (ert--format-time-iso8601 (ert--stats-start-time stats))))) 1434 (ert--format-time-iso8601 (ert--stats-start-time stats)))))
1430 (run-ended 1435 (run-ended
1431 (destructuring-bind (stats abortedp) event-args 1436 (cl-destructuring-bind (stats abortedp) event-args
1432 (let ((unexpected (ert-stats-completed-unexpected stats)) 1437 (let ((unexpected (ert-stats-completed-unexpected stats))
1433 (expected-failures (ert--stats-failed-expected stats))) 1438 (expected-failures (ert--stats-failed-expected stats)))
1434 (message "\n%sRan %s tests, %s results as expected%s (%s)%s\n" 1439 (message "\n%sRan %s tests, %s results as expected%s (%s)%s\n"
@@ -1446,19 +1451,19 @@ Returns the stats object."
1446 (format "\n%s expected failures" expected-failures))) 1451 (format "\n%s expected failures" expected-failures)))
1447 (unless (zerop unexpected) 1452 (unless (zerop unexpected)
1448 (message "%s unexpected results:" unexpected) 1453 (message "%s unexpected results:" unexpected)
1449 (loop for test across (ert--stats-tests stats) 1454 (cl-loop for test across (ert--stats-tests stats)
1450 for result = (ert-test-most-recent-result test) do 1455 for result = (ert-test-most-recent-result test) do
1451 (when (not (ert-test-result-expected-p test result)) 1456 (when (not (ert-test-result-expected-p test result))
1452 (message "%9s %S" 1457 (message "%9s %S"
1453 (ert-string-for-test-result result nil) 1458 (ert-string-for-test-result result nil)
1454 (ert-test-name test)))) 1459 (ert-test-name test))))
1455 (message "%s" ""))))) 1460 (message "%s" "")))))
1456 (test-started 1461 (test-started
1457 ) 1462 )
1458 (test-ended 1463 (test-ended
1459 (destructuring-bind (stats test result) event-args 1464 (cl-destructuring-bind (stats test result) event-args
1460 (unless (ert-test-result-expected-p test result) 1465 (unless (ert-test-result-expected-p test result)
1461 (etypecase result 1466 (cl-etypecase result
1462 (ert-test-passed 1467 (ert-test-passed
1463 (message "Test %S passed unexpectedly" (ert-test-name test))) 1468 (message "Test %S passed unexpectedly" (ert-test-name test)))
1464 (ert-test-result-with-condition 1469 (ert-test-result-with-condition
@@ -1484,7 +1489,7 @@ Returns the stats object."
1484 (ert--pp-with-indentation-and-newline 1489 (ert--pp-with-indentation-and-newline
1485 (ert-test-result-with-condition-condition result))) 1490 (ert-test-result-with-condition-condition result)))
1486 (goto-char (1- (point-max))) 1491 (goto-char (1- (point-max)))
1487 (assert (looking-at "\n")) 1492 (cl-assert (looking-at "\n"))
1488 (delete-char 1) 1493 (delete-char 1)
1489 (message "Test %S condition:" (ert-test-name test)) 1494 (message "Test %S condition:" (ert-test-name test))
1490 (message "%s" (buffer-string)))) 1495 (message "%s" (buffer-string))))
@@ -1532,7 +1537,7 @@ the tests)."
1532 (1 font-lock-keyword-face nil t) 1537 (1 font-lock-keyword-face nil t)
1533 (2 font-lock-function-name-face nil t))))) 1538 (2 font-lock-function-name-face nil t)))))
1534 1539
1535(defun* ert--remove-from-list (list-var element &key key test) 1540(cl-defun ert--remove-from-list (list-var element &key key test)
1536 "Remove ELEMENT from the value of LIST-VAR if present. 1541 "Remove ELEMENT from the value of LIST-VAR if present.
1537 1542
1538This can be used as an inverse of `add-to-list'." 1543This can be used as an inverse of `add-to-list'."
@@ -1557,7 +1562,7 @@ If ADD-DEFAULT-TO-PROMPT is non-nil, PROMPT will be modified to
1557include the default, if any. 1562include the default, if any.
1558 1563
1559Signals an error if no test name was read." 1564Signals an error if no test name was read."
1560 (etypecase default 1565 (cl-etypecase default
1561 (string (let ((symbol (intern-soft default))) 1566 (string (let ((symbol (intern-soft default)))
1562 (unless (and symbol (ert-test-boundp symbol)) 1567 (unless (and symbol (ert-test-boundp symbol))
1563 (setq default nil)))) 1568 (setq default nil))))
@@ -1614,11 +1619,11 @@ Nothing more than an interactive interface to `ert-make-test-unbound'."
1614;;; Display of test progress and results. 1619;;; Display of test progress and results.
1615 1620
1616;; An entry in the results buffer ewoc. There is one entry per test. 1621;; An entry in the results buffer ewoc. There is one entry per test.
1617(defstruct ert--ewoc-entry 1622(cl-defstruct ert--ewoc-entry
1618 (test (assert nil)) 1623 (test (cl-assert nil))
1619 ;; If the result of this test was expected, its ewoc entry is hidden 1624 ;; If the result of this test was expected, its ewoc entry is hidden
1620 ;; initially. 1625 ;; initially.
1621 (hidden-p (assert nil)) 1626 (hidden-p (cl-assert nil))
1622 ;; An ewoc entry may be collapsed to hide details such as the error 1627 ;; An ewoc entry may be collapsed to hide details such as the error
1623 ;; condition. 1628 ;; condition.
1624 ;; 1629 ;;
@@ -1694,7 +1699,7 @@ Also sets `ert--results-progress-bar-button-begin'."
1694 ((ert--stats-current-test stats) 'running) 1699 ((ert--stats-current-test stats) 'running)
1695 ((ert--stats-end-time stats) 'finished) 1700 ((ert--stats-end-time stats) 'finished)
1696 (t 'preparing)))) 1701 (t 'preparing))))
1697 (ecase state 1702 (cl-ecase state
1698 (preparing 1703 (preparing
1699 (insert "")) 1704 (insert ""))
1700 (aborted 1705 (aborted
@@ -1705,12 +1710,12 @@ Also sets `ert--results-progress-bar-button-begin'."
1705 (t 1710 (t
1706 (insert "Aborted.")))) 1711 (insert "Aborted."))))
1707 (running 1712 (running
1708 (assert (ert--stats-current-test stats)) 1713 (cl-assert (ert--stats-current-test stats))
1709 (insert "Running test: ") 1714 (insert "Running test: ")
1710 (ert-insert-test-name-button (ert-test-name 1715 (ert-insert-test-name-button (ert-test-name
1711 (ert--stats-current-test stats)))) 1716 (ert--stats-current-test stats))))
1712 (finished 1717 (finished
1713 (assert (not (ert--stats-current-test stats))) 1718 (cl-assert (not (ert--stats-current-test stats)))
1714 (insert "Finished."))) 1719 (insert "Finished.")))
1715 (insert "\n") 1720 (insert "\n")
1716 (if (ert--stats-end-time stats) 1721 (if (ert--stats-end-time stats)
@@ -1813,7 +1818,7 @@ non-nil, returns the face for expected results.."
1813(defun ert-face-for-stats (stats) 1818(defun ert-face-for-stats (stats)
1814 "Return a face that represents STATS." 1819 "Return a face that represents STATS."
1815 (cond ((ert--stats-aborted-p stats) 'nil) 1820 (cond ((ert--stats-aborted-p stats) 'nil)
1816 ((plusp (ert-stats-completed-unexpected stats)) 1821 ((cl-plusp (ert-stats-completed-unexpected stats))
1817 (ert-face-for-test-result nil)) 1822 (ert-face-for-test-result nil))
1818 ((eql (ert-stats-completed-expected stats) (ert-stats-total stats)) 1823 ((eql (ert-stats-completed-expected stats) (ert-stats-total stats))
1819 (ert-face-for-test-result t)) 1824 (ert-face-for-test-result t))
@@ -1824,7 +1829,7 @@ non-nil, returns the face for expected results.."
1824 (let* ((test (ert--ewoc-entry-test entry)) 1829 (let* ((test (ert--ewoc-entry-test entry))
1825 (stats ert--results-stats) 1830 (stats ert--results-stats)
1826 (result (let ((pos (ert--stats-test-pos stats test))) 1831 (result (let ((pos (ert--stats-test-pos stats test)))
1827 (assert pos) 1832 (cl-assert pos)
1828 (aref (ert--stats-test-results stats) pos))) 1833 (aref (ert--stats-test-results stats) pos)))
1829 (hiddenp (ert--ewoc-entry-hidden-p entry)) 1834 (hiddenp (ert--ewoc-entry-hidden-p entry))
1830 (expandedp (ert--ewoc-entry-expanded-p entry)) 1835 (expandedp (ert--ewoc-entry-expanded-p entry))
@@ -1850,7 +1855,7 @@ non-nil, returns the face for expected results.."
1850 (ert--string-first-line (ert-test-documentation test)) 1855 (ert--string-first-line (ert-test-documentation test))
1851 'font-lock-face 'font-lock-doc-face) 1856 'font-lock-face 'font-lock-doc-face)
1852 "\n")) 1857 "\n"))
1853 (etypecase result 1858 (cl-etypecase result
1854 (ert-test-passed 1859 (ert-test-passed
1855 (if (ert-test-result-expected-p test result) 1860 (if (ert-test-result-expected-p test result)
1856 (insert " passed\n") 1861 (insert " passed\n")
@@ -1908,9 +1913,10 @@ BUFFER-NAME, if non-nil, is the buffer name to use."
1908 (make-string (ert-stats-total stats) 1913 (make-string (ert-stats-total stats)
1909 (ert-char-for-test-result nil t))) 1914 (ert-char-for-test-result nil t)))
1910 (set (make-local-variable 'ert--results-listener) listener) 1915 (set (make-local-variable 'ert--results-listener) listener)
1911 (loop for test across (ert--stats-tests stats) do 1916 (cl-loop for test across (ert--stats-tests stats) do
1912 (ewoc-enter-last ewoc 1917 (ewoc-enter-last ewoc
1913 (make-ert--ewoc-entry :test test :hidden-p t))) 1918 (make-ert--ewoc-entry :test test
1919 :hidden-p t)))
1914 (ert--results-update-ewoc-hf ert--results-ewoc ert--results-stats) 1920 (ert--results-update-ewoc-hf ert--results-ewoc ert--results-stats)
1915 (goto-char (1- (point-max))) 1921 (goto-char (1- (point-max)))
1916 buffer))))) 1922 buffer)))))
@@ -1945,21 +1951,21 @@ and how to display message."
1945 default nil)) 1951 default nil))
1946 nil)) 1952 nil))
1947 (unless message-fn (setq message-fn 'message)) 1953 (unless message-fn (setq message-fn 'message))
1948 (lexical-let ((output-buffer-name output-buffer-name) 1954 (let ((output-buffer-name output-buffer-name)
1949 buffer 1955 buffer
1950 listener 1956 listener
1951 (message-fn message-fn)) 1957 (message-fn message-fn))
1952 (setq listener 1958 (setq listener
1953 (lambda (event-type &rest event-args) 1959 (lambda (event-type &rest event-args)
1954 (ecase event-type 1960 (cl-ecase event-type
1955 (run-started 1961 (run-started
1956 (destructuring-bind (stats) event-args 1962 (cl-destructuring-bind (stats) event-args
1957 (setq buffer (ert--setup-results-buffer stats 1963 (setq buffer (ert--setup-results-buffer stats
1958 listener 1964 listener
1959 output-buffer-name)) 1965 output-buffer-name))
1960 (pop-to-buffer buffer))) 1966 (pop-to-buffer buffer)))
1961 (run-ended 1967 (run-ended
1962 (destructuring-bind (stats abortedp) event-args 1968 (cl-destructuring-bind (stats abortedp) event-args
1963 (funcall message-fn 1969 (funcall message-fn
1964 "%sRan %s tests, %s results were as expected%s" 1970 "%sRan %s tests, %s results were as expected%s"
1965 (if (not abortedp) 1971 (if (not abortedp)
@@ -1976,19 +1982,19 @@ and how to display message."
1976 ert--results-ewoc) 1982 ert--results-ewoc)
1977 stats))) 1983 stats)))
1978 (test-started 1984 (test-started
1979 (destructuring-bind (stats test) event-args 1985 (cl-destructuring-bind (stats test) event-args
1980 (with-current-buffer buffer 1986 (with-current-buffer buffer
1981 (let* ((ewoc ert--results-ewoc) 1987 (let* ((ewoc ert--results-ewoc)
1982 (pos (ert--stats-test-pos stats test)) 1988 (pos (ert--stats-test-pos stats test))
1983 (node (ewoc-nth ewoc pos))) 1989 (node (ewoc-nth ewoc pos)))
1984 (assert node) 1990 (cl-assert node)
1985 (setf (ert--ewoc-entry-test (ewoc-data node)) test) 1991 (setf (ert--ewoc-entry-test (ewoc-data node)) test)
1986 (aset ert--results-progress-bar-string pos 1992 (aset ert--results-progress-bar-string pos
1987 (ert-char-for-test-result nil t)) 1993 (ert-char-for-test-result nil t))
1988 (ert--results-update-stats-display-maybe ewoc stats) 1994 (ert--results-update-stats-display-maybe ewoc stats)
1989 (ewoc-invalidate ewoc node))))) 1995 (ewoc-invalidate ewoc node)))))
1990 (test-ended 1996 (test-ended
1991 (destructuring-bind (stats test result) event-args 1997 (cl-destructuring-bind (stats test result) event-args
1992 (with-current-buffer buffer 1998 (with-current-buffer buffer
1993 (let* ((ewoc ert--results-ewoc) 1999 (let* ((ewoc ert--results-ewoc)
1994 (pos (ert--stats-test-pos stats test)) 2000 (pos (ert--stats-test-pos stats test))
@@ -2020,28 +2026,28 @@ and how to display message."
2020(define-derived-mode ert-results-mode special-mode "ERT-Results" 2026(define-derived-mode ert-results-mode special-mode "ERT-Results"
2021 "Major mode for viewing results of ERT test runs.") 2027 "Major mode for viewing results of ERT test runs.")
2022 2028
2023(loop for (key binding) in 2029(cl-loop for (key binding) in
2024 '(;; Stuff that's not in the menu. 2030 '( ;; Stuff that's not in the menu.
2025 ("\t" forward-button) 2031 ("\t" forward-button)
2026 ([backtab] backward-button) 2032 ([backtab] backward-button)
2027 ("j" ert-results-jump-between-summary-and-result) 2033 ("j" ert-results-jump-between-summary-and-result)
2028 ("L" ert-results-toggle-printer-limits-for-test-at-point) 2034 ("L" ert-results-toggle-printer-limits-for-test-at-point)
2029 ("n" ert-results-next-test) 2035 ("n" ert-results-next-test)
2030 ("p" ert-results-previous-test) 2036 ("p" ert-results-previous-test)
2031 ;; Stuff that is in the menu. 2037 ;; Stuff that is in the menu.
2032 ("R" ert-results-rerun-all-tests) 2038 ("R" ert-results-rerun-all-tests)
2033 ("r" ert-results-rerun-test-at-point) 2039 ("r" ert-results-rerun-test-at-point)
2034 ("d" ert-results-rerun-test-at-point-debugging-errors) 2040 ("d" ert-results-rerun-test-at-point-debugging-errors)
2035 ("." ert-results-find-test-at-point-other-window) 2041 ("." ert-results-find-test-at-point-other-window)
2036 ("b" ert-results-pop-to-backtrace-for-test-at-point) 2042 ("b" ert-results-pop-to-backtrace-for-test-at-point)
2037 ("m" ert-results-pop-to-messages-for-test-at-point) 2043 ("m" ert-results-pop-to-messages-for-test-at-point)
2038 ("l" ert-results-pop-to-should-forms-for-test-at-point) 2044 ("l" ert-results-pop-to-should-forms-for-test-at-point)
2039 ("h" ert-results-describe-test-at-point) 2045 ("h" ert-results-describe-test-at-point)
2040 ("D" ert-delete-test) 2046 ("D" ert-delete-test)
2041 ("T" ert-results-pop-to-timings) 2047 ("T" ert-results-pop-to-timings)
2042 ) 2048 )
2043 do 2049 do
2044 (define-key ert-results-mode-map key binding)) 2050 (define-key ert-results-mode-map key binding))
2045 2051
2046(easy-menu-define ert-results-mode-menu ert-results-mode-map 2052(easy-menu-define ert-results-mode-menu ert-results-mode-map
2047 "Menu for `ert-results-mode'." 2053 "Menu for `ert-results-mode'."
@@ -2121,15 +2127,15 @@ To be used in the ERT results buffer."
2121EWOC-FN specifies the direction and should be either `ewoc-prev' 2127EWOC-FN specifies the direction and should be either `ewoc-prev'
2122or `ewoc-next'. If there are no more nodes in that direction, an 2128or `ewoc-next'. If there are no more nodes in that direction, an
2123error is signaled with the message ERROR-MESSAGE." 2129error is signaled with the message ERROR-MESSAGE."
2124 (loop 2130 (cl-loop
2125 (setq node (funcall ewoc-fn ert--results-ewoc node)) 2131 (setq node (funcall ewoc-fn ert--results-ewoc node))
2126 (when (null node) 2132 (when (null node)
2127 (error "%s" error-message)) 2133 (error "%s" error-message))
2128 (unless (ert--ewoc-entry-hidden-p (ewoc-data node)) 2134 (unless (ert--ewoc-entry-hidden-p (ewoc-data node))
2129 (goto-char (ewoc-location node)) 2135 (goto-char (ewoc-location node))
2130 (return)))) 2136 (cl-return))))
2131 2137
2132(defun ert--results-expand-collapse-button-action (button) 2138(defun ert--results-expand-collapse-button-action (_button)
2133 "Expand or collapse the test node BUTTON belongs to." 2139 "Expand or collapse the test node BUTTON belongs to."
2134 (let* ((ewoc ert--results-ewoc) 2140 (let* ((ewoc ert--results-ewoc)
2135 (node (save-excursion 2141 (node (save-excursion
@@ -2158,11 +2164,11 @@ To be used in the ERT results buffer."
2158(defun ert--ewoc-position (ewoc node) 2164(defun ert--ewoc-position (ewoc node)
2159 ;; checkdoc-order: nil 2165 ;; checkdoc-order: nil
2160 "Return the position of NODE in EWOC, or nil if NODE is not in EWOC." 2166 "Return the position of NODE in EWOC, or nil if NODE is not in EWOC."
2161 (loop for i from 0 2167 (cl-loop for i from 0
2162 for node-here = (ewoc-nth ewoc 0) then (ewoc-next ewoc node-here) 2168 for node-here = (ewoc-nth ewoc 0) then (ewoc-next ewoc node-here)
2163 do (when (eql node node-here) 2169 do (when (eql node node-here)
2164 (return i)) 2170 (cl-return i))
2165 finally (return nil))) 2171 finally (cl-return nil)))
2166 2172
2167(defun ert-results-jump-between-summary-and-result () 2173(defun ert-results-jump-between-summary-and-result ()
2168 "Jump back and forth between the test run summary and individual test results. 2174 "Jump back and forth between the test run summary and individual test results.
@@ -2210,7 +2216,7 @@ To be used in the ERT results buffer."
2210 "Return the test at point, or nil. 2216 "Return the test at point, or nil.
2211 2217
2212To be used in the ERT results buffer." 2218To be used in the ERT results buffer."
2213 (assert (eql major-mode 'ert-results-mode)) 2219 (cl-assert (eql major-mode 'ert-results-mode))
2214 (if (ert--results-test-node-or-null-at-point) 2220 (if (ert--results-test-node-or-null-at-point)
2215 (let* ((node (ert--results-test-node-at-point)) 2221 (let* ((node (ert--results-test-node-at-point))
2216 (test (ert--ewoc-entry-test (ewoc-data node)))) 2222 (test (ert--ewoc-entry-test (ewoc-data node))))
@@ -2282,9 +2288,9 @@ definition."
2282 (point)) 2288 (point))
2283 ((eventp last-command-event) 2289 ((eventp last-command-event)
2284 (posn-point (event-start last-command-event))) 2290 (posn-point (event-start last-command-event)))
2285 (t (assert nil)))) 2291 (t (cl-assert nil))))
2286 2292
2287(defun ert--results-progress-bar-button-action (button) 2293(defun ert--results-progress-bar-button-action (_button)
2288 "Jump to details for the test represented by the character clicked in BUTTON." 2294 "Jump to details for the test represented by the character clicked in BUTTON."
2289 (goto-char (ert--button-action-position)) 2295 (goto-char (ert--button-action-position))
2290 (ert-results-jump-between-summary-and-result)) 2296 (ert-results-jump-between-summary-and-result))
@@ -2294,7 +2300,7 @@ definition."
2294 2300
2295To be used in the ERT results buffer." 2301To be used in the ERT results buffer."
2296 (interactive) 2302 (interactive)
2297 (assert (eql major-mode 'ert-results-mode)) 2303 (cl-assert (eql major-mode 'ert-results-mode))
2298 (let ((selector (ert--stats-selector ert--results-stats))) 2304 (let ((selector (ert--stats-selector ert--results-stats)))
2299 (ert-run-tests-interactively selector (buffer-name)))) 2305 (ert-run-tests-interactively selector (buffer-name))))
2300 2306
@@ -2303,13 +2309,13 @@ To be used in the ERT results buffer."
2303 2309
2304To be used in the ERT results buffer." 2310To be used in the ERT results buffer."
2305 (interactive) 2311 (interactive)
2306 (destructuring-bind (test redefinition-state) 2312 (cl-destructuring-bind (test redefinition-state)
2307 (ert--results-test-at-point-allow-redefinition) 2313 (ert--results-test-at-point-allow-redefinition)
2308 (when (null test) 2314 (when (null test)
2309 (error "No test at point")) 2315 (error "No test at point"))
2310 (let* ((stats ert--results-stats) 2316 (let* ((stats ert--results-stats)
2311 (progress-message (format "Running %stest %S" 2317 (progress-message (format "Running %stest %S"
2312 (ecase redefinition-state 2318 (cl-ecase redefinition-state
2313 ((nil) "") 2319 ((nil) "")
2314 (redefined "new definition of ") 2320 (redefined "new definition of ")
2315 (deleted "deleted ")) 2321 (deleted "deleted "))
@@ -2350,7 +2356,7 @@ To be used in the ERT results buffer."
2350 (stats ert--results-stats) 2356 (stats ert--results-stats)
2351 (pos (ert--stats-test-pos stats test)) 2357 (pos (ert--stats-test-pos stats test))
2352 (result (aref (ert--stats-test-results stats) pos))) 2358 (result (aref (ert--stats-test-results stats) pos)))
2353 (etypecase result 2359 (cl-etypecase result
2354 (ert-test-passed (error "Test passed, no backtrace available")) 2360 (ert-test-passed (error "Test passed, no backtrace available"))
2355 (ert-test-result-with-condition 2361 (ert-test-result-with-condition
2356 (let ((backtrace (ert-test-result-with-condition-backtrace result)) 2362 (let ((backtrace (ert-test-result-with-condition-backtrace result))
@@ -2408,13 +2414,14 @@ To be used in the ERT results buffer."
2408 (ert-simple-view-mode) 2414 (ert-simple-view-mode)
2409 (if (null (ert-test-result-should-forms result)) 2415 (if (null (ert-test-result-should-forms result))
2410 (insert "\n(No should forms during this test.)\n") 2416 (insert "\n(No should forms during this test.)\n")
2411 (loop for form-description in (ert-test-result-should-forms result) 2417 (cl-loop for form-description
2412 for i from 1 do 2418 in (ert-test-result-should-forms result)
2413 (insert "\n") 2419 for i from 1 do
2414 (insert (format "%s: " i)) 2420 (insert "\n")
2415 (let ((begin (point))) 2421 (insert (format "%s: " i))
2416 (ert--pp-with-indentation-and-newline form-description) 2422 (let ((begin (point)))
2417 (ert--make-xrefs-region begin (point))))) 2423 (ert--pp-with-indentation-and-newline form-description)
2424 (ert--make-xrefs-region begin (point)))))
2418 (goto-char (point-min)) 2425 (goto-char (point-min))
2419 (insert "`should' forms executed during test `") 2426 (insert "`should' forms executed during test `")
2420 (ert-insert-test-name-button (ert-test-name test)) 2427 (ert-insert-test-name-button (ert-test-name test))
@@ -2443,17 +2450,16 @@ To be used in the ERT results buffer."
2443To be used in the ERT results buffer." 2450To be used in the ERT results buffer."
2444 (interactive) 2451 (interactive)
2445 (let* ((stats ert--results-stats) 2452 (let* ((stats ert--results-stats)
2446 (start-times (ert--stats-test-start-times stats))
2447 (end-times (ert--stats-test-end-times stats))
2448 (buffer (get-buffer-create "*ERT timings*")) 2453 (buffer (get-buffer-create "*ERT timings*"))
2449 (data (loop for test across (ert--stats-tests stats) 2454 (data (cl-loop for test across (ert--stats-tests stats)
2450 for start-time across (ert--stats-test-start-times stats) 2455 for start-time across (ert--stats-test-start-times
2451 for end-time across (ert--stats-test-end-times stats) 2456 stats)
2452 collect (list test 2457 for end-time across (ert--stats-test-end-times stats)
2453 (float-time (subtract-time end-time 2458 collect (list test
2454 start-time)))))) 2459 (float-time (subtract-time
2460 end-time start-time))))))
2455 (setq data (sort data (lambda (a b) 2461 (setq data (sort data (lambda (a b)
2456 (> (second a) (second b))))) 2462 (> (cl-second a) (cl-second b)))))
2457 (pop-to-buffer buffer) 2463 (pop-to-buffer buffer)
2458 (let ((inhibit-read-only t)) 2464 (let ((inhibit-read-only t))
2459 (buffer-disable-undo) 2465 (buffer-disable-undo)
@@ -2462,13 +2468,13 @@ To be used in the ERT results buffer."
2462 (if (null data) 2468 (if (null data)
2463 (insert "(No data)\n") 2469 (insert "(No data)\n")
2464 (insert (format "%-3s %8s %8s\n" "" "time" "cumul")) 2470 (insert (format "%-3s %8s %8s\n" "" "time" "cumul"))
2465 (loop for (test time) in data 2471 (cl-loop for (test time) in data
2466 for cumul-time = time then (+ cumul-time time) 2472 for cumul-time = time then (+ cumul-time time)
2467 for i from 1 do 2473 for i from 1 do
2468 (let ((begin (point))) 2474 (progn
2469 (insert (format "%3s: %8.3f %8.3f " i time cumul-time)) 2475 (insert (format "%3s: %8.3f %8.3f " i time cumul-time))
2470 (ert-insert-test-name-button (ert-test-name test)) 2476 (ert-insert-test-name-button (ert-test-name test))
2471 (insert "\n")))) 2477 (insert "\n"))))
2472 (goto-char (point-min)) 2478 (goto-char (point-min))
2473 (insert "Tests by run time (seconds):\n\n") 2479 (insert "Tests by run time (seconds):\n\n")
2474 (forward-line 1)))) 2480 (forward-line 1))))
@@ -2481,7 +2487,7 @@ To be used in the ERT results buffer."
2481 (error "Requires Emacs 24")) 2487 (error "Requires Emacs 24"))
2482 (let (test-name 2488 (let (test-name
2483 test-definition) 2489 test-definition)
2484 (etypecase test-or-test-name 2490 (cl-etypecase test-or-test-name
2485 (symbol (setq test-name test-or-test-name 2491 (symbol (setq test-name test-or-test-name
2486 test-definition (ert-get-test test-or-test-name))) 2492 test-definition (ert-get-test test-or-test-name)))
2487 (ert-test (setq test-name (ert-test-name test-or-test-name) 2493 (ert-test (setq test-name (ert-test-name test-or-test-name)
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el
index 540e0166ec2..d9c5316b1b8 100644
--- a/lisp/emacs-lisp/nadvice.el
+++ b/lisp/emacs-lisp/nadvice.el
@@ -402,6 +402,56 @@ of the piece of advice."
402 (if (fboundp function-name) 402 (if (fboundp function-name)
403 (symbol-function function-name)))))) 403 (symbol-function function-name))))))
404 404
405;; When code is advised, called-interactively-p needs to be taught to skip
406;; the advising frames.
407;; FIXME: This Major Ugly Hack won't handle calls to called-interactively-p
408;; done from the advised function if the deepest advice is an around advice!
409;; In other cases (calls from an advice or calls from the advised function when
410;; the deepest advice is not an around advice), it should hopefully get
411;; it right.
412(add-hook 'called-interactively-p-functions
413 #'advice--called-interactively-skip)
414(defun advice--called-interactively-skip (origi frame1 frame2)
415 (let* ((i origi)
416 (get-next-frame
417 (lambda ()
418 (setq frame1 frame2)
419 (setq frame2 (internal--called-interactively-p--get-frame i))
420 ;; (message "Advice Frame %d = %S" i frame2)
421 (setq i (1+ i)))))
422 (when (and (eq (nth 1 frame2) 'apply)
423 (progn
424 (funcall get-next-frame)
425 (advice--p (indirect-function (nth 1 frame2)))))
426 (funcall get-next-frame)
427 ;; If we now have the symbol, this was the head advice and
428 ;; we're done.
429 (while (advice--p (nth 1 frame1))
430 ;; This was an inner advice called from some earlier advice.
431 ;; The stack frames look different depending on the particular
432 ;; kind of the earlier advice.
433 (let ((inneradvice (nth 1 frame1)))
434 (if (and (eq (nth 1 frame2) 'apply)
435 (progn
436 (funcall get-next-frame)
437 (advice--p (indirect-function
438 (nth 1 frame2)))))
439 ;; The earlier advice was something like a before/after
440 ;; advice where the "next" code is called directly by the
441 ;; advice--p object.
442 (funcall get-next-frame)
443 ;; It's apparently an around advice, where the "next" is
444 ;; called by the body of the advice in any way it sees fit,
445 ;; so we need to skip the frames of that body.
446 (while
447 (progn
448 (funcall get-next-frame)
449 (not (and (eq (nth 1 frame2) 'apply)
450 (eq (nth 3 frame2) inneradvice)))))
451 (funcall get-next-frame)
452 (funcall get-next-frame))))
453 (- i origi 1))))
454
405 455
406(provide 'nadvice) 456(provide 'nadvice)
407;;; nadvice.el ends here 457;;; nadvice.el ends here
diff --git a/lisp/emacs-lisp/trace.el b/lisp/emacs-lisp/trace.el
index c6fff7aa443..722e6270e95 100644
--- a/lisp/emacs-lisp/trace.el
+++ b/lisp/emacs-lisp/trace.el
@@ -1,4 +1,4 @@
1;;; trace.el --- tracing facility for Emacs Lisp functions 1;;; trace.el --- tracing facility for Emacs Lisp functions -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 1993, 1998, 2000-2012 Free Software Foundation, Inc. 3;; Copyright (C) 1993, 1998, 2000-2012 Free Software Foundation, Inc.
4 4
@@ -151,18 +151,15 @@
151 151
152;;; Code: 152;;; Code:
153 153
154(require 'advice)
155
156(defgroup trace nil 154(defgroup trace nil
157 "Tracing facility for Emacs Lisp functions." 155 "Tracing facility for Emacs Lisp functions."
158 :prefix "trace-" 156 :prefix "trace-"
159 :group 'lisp) 157 :group 'lisp)
160 158
161;;;###autoload 159;;;###autoload
162(defcustom trace-buffer (purecopy "*trace-output*") 160(defcustom trace-buffer "*trace-output*"
163 "Trace output will by default go to that buffer." 161 "Trace output will by default go to that buffer."
164 :type 'string 162 :type 'string)
165 :group 'trace)
166 163
167;; Current level of traced function invocation: 164;; Current level of traced function invocation:
168(defvar trace-level 0) 165(defvar trace-level 0)
@@ -176,78 +173,109 @@
176(defvar inhibit-trace nil 173(defvar inhibit-trace nil
177 "If non-nil, all tracing is temporarily inhibited.") 174 "If non-nil, all tracing is temporarily inhibited.")
178 175
179(defun trace-entry-message (function level argument-bindings) 176(defun trace-entry-message (function level args context)
180 ;; Generates a string that describes that FUNCTION has been entered at 177 "Generate a string that describes that FUNCTION has been entered.
181 ;; trace LEVEL with ARGUMENT-BINDINGS. 178LEVEL is the trace level, ARGS is the list of arguments passed to FUNCTION,
182 (format "%s%s%d -> %s: %s\n" 179and CONTEXT is a string describing the dynamic context (e.g. values of
183 (mapconcat 'char-to-string (make-string (1- level) ?|) " ") 180some global variables)."
184 (if (> level 1) " " "") 181 (let ((print-circle t))
185 level 182 (format "%s%s%d -> %S%s\n"
186 function 183 (mapconcat 'char-to-string (make-string (1- level) ?|) " ")
187 (let ((print-circle t)) 184 (if (> level 1) " " "")
188 (mapconcat (lambda (binding) 185 level
189 (concat 186 (cons function args)
190 (symbol-name (ad-arg-binding-field binding 'name)) 187 context)))
191 "=" 188
192 ;; do this so we'll see strings: 189(defun trace-exit-message (function level value context)
193 (prin1-to-string 190 "Generate a string that describes that FUNCTION has exited.
194 (ad-arg-binding-field binding 'value)))) 191LEVEL is the trace level, VALUE value returned by FUNCTION,
195 argument-bindings 192and CONTEXT is a string describing the dynamic context (e.g. values of
196 " ")))) 193some global variables)."
197 194 (let ((print-circle t))
198(defun trace-exit-message (function level value) 195 (format "%s%s%d <- %s: %S%s\n"
199 ;; Generates a string that describes that FUNCTION has been exited at 196 (mapconcat 'char-to-string (make-string (1- level) ?|) " ")
200 ;; trace LEVEL and that it returned VALUE. 197 (if (> level 1) " " "")
201 (format "%s%s%d <- %s: %s\n" 198 level
202 (mapconcat 'char-to-string (make-string (1- level) ?|) " ") 199 function
203 (if (> level 1) " " "") 200 ;; Do this so we'll see strings:
204 level 201 value
205 function 202 context)))
206 ;; do this so we'll see strings: 203
207 (let ((print-circle t)) (prin1-to-string value)))) 204(defvar trace--timer nil)
208 205
209(defun trace-make-advice (function buffer background) 206(defun trace-make-advice (function buffer background context)
210 ;; Builds the piece of advice to be added to FUNCTION's advice info 207 "Build the piece of advice to be added to trace FUNCTION.
211 ;; so that it will generate the proper trace output in BUFFER 208FUNCTION is the name of the traced function.
212 ;; (quietly if BACKGROUND is t). 209BUFFER is the buffer where the trace should be printed.
213 (ad-make-advice 210BACKGROUND if nil means to display BUFFER.
214 trace-advice-name nil t 211CONTEXT if non-nil should be a function that returns extra info that should
215 `(advice 212be printed along with the arguments in the trace."
216 lambda () 213 (lambda (body &rest args)
217 (let ((trace-level (1+ trace-level)) 214 (let ((trace-level (1+ trace-level))
218 (trace-buffer (get-buffer-create ,buffer))) 215 (trace-buffer (get-buffer-create buffer))
219 (unless inhibit-trace 216 (ctx (funcall context)))
220 (with-current-buffer trace-buffer 217 (unless inhibit-trace
221 (set (make-local-variable 'window-point-insertion-type) t) 218 (with-current-buffer trace-buffer
222 ,(unless background '(display-buffer trace-buffer)) 219 (set (make-local-variable 'window-point-insertion-type) t)
223 (goto-char (point-max)) 220 (unless (or background trace--timer
224 ;; Insert a separator from previous trace output: 221 (get-buffer-window trace-buffer 'visible))
225 (if (= trace-level 1) (insert trace-separator)) 222 (setq trace--timer
226 (insert 223 ;; Postpone the display to some later time, in case we
227 (trace-entry-message 224 ;; can't actually do it now.
228 ',function trace-level ad-arg-bindings)))) 225 (run-with-timer 0 nil
229 ad-do-it 226 (lambda ()
230 (unless inhibit-trace 227 (setq trace--timer nil)
231 (with-current-buffer trace-buffer 228 (display-buffer trace-buffer)))))
232 ,(unless background '(display-buffer trace-buffer)) 229 (goto-char (point-max))
233 (goto-char (point-max)) 230 ;; Insert a separator from previous trace output:
234 (insert 231 (if (= trace-level 1) (insert trace-separator))
235 (trace-exit-message 232 (insert
236 ',function trace-level ad-return-value)))))))) 233 (trace-entry-message
237 234 function trace-level args ctx))))
238(defun trace-function-internal (function buffer background) 235 (let ((result))
239 ;; Adds trace advice for FUNCTION and activates it. 236 (unwind-protect
240 (ad-add-advice 237 (setq result (list (apply body args)))
241 function 238 (unless inhibit-trace
242 (trace-make-advice function (or buffer trace-buffer) background) 239 (let ((ctx (funcall context)))
243 'around 'last) 240 (with-current-buffer trace-buffer
244 (ad-activate function nil)) 241 (unless background (display-buffer trace-buffer))
242 (goto-char (point-max))
243 (insert
244 (trace-exit-message
245 function
246 trace-level
247 (if result (car result) '\!non-local\ exit\!)
248 ctx))))))
249 (car result)))))
250
251(defun trace-function-internal (function buffer background context)
252 "Add trace advice for FUNCTION."
253 (advice-add
254 function :around
255 (trace-make-advice function (or buffer trace-buffer) background
256 (or context (lambda () "")))
257 `((name . ,trace-advice-name))))
245 258
246(defun trace-is-traced (function) 259(defun trace-is-traced (function)
247 (ad-find-advice function 'around trace-advice-name)) 260 (advice-member-p trace-advice-name function))
261
262(defun trace--read-args (prompt)
263 (cons
264 (intern (completing-read prompt obarray 'fboundp t))
265 (when current-prefix-arg
266 (list
267 (read-buffer "Output to buffer: " trace-buffer)
268 (let ((exp
269 (let ((minibuffer-completing-symbol t))
270 (read-from-minibuffer "Context expression: "
271 nil read-expression-map t
272 'read-expression-history))))
273 `(lambda ()
274 (let ((print-circle t))
275 (concat " [" (prin1-to-string ,exp) "]"))))))))
248 276
249;;;###autoload 277;;;###autoload
250(defun trace-function (function &optional buffer) 278(defun trace-function-foreground (function &optional buffer context)
251 "Traces FUNCTION with trace output going to BUFFER. 279 "Traces FUNCTION with trace output going to BUFFER.
252For every call of FUNCTION Lisp-style trace messages that display argument 280For every call of FUNCTION Lisp-style trace messages that display argument
253and return values will be inserted into BUFFER. This function generates the 281and return values will be inserted into BUFFER. This function generates the
@@ -255,14 +283,11 @@ trace advice for FUNCTION and activates it together with any other advice
255there might be!! The trace BUFFER will popup whenever FUNCTION is called. 283there might be!! The trace BUFFER will popup whenever FUNCTION is called.
256Do not use this to trace functions that switch buffers or do any other 284Do not use this to trace functions that switch buffers or do any other
257display oriented stuff, use `trace-function-background' instead." 285display oriented stuff, use `trace-function-background' instead."
258 (interactive 286 (interactive (trace--read-args "Trace function: "))
259 (list 287 (trace-function-internal function buffer nil context))
260 (intern (completing-read "Trace function: " obarray 'fboundp t))
261 (read-buffer "Output to buffer: " trace-buffer)))
262 (trace-function-internal function buffer nil))
263 288
264;;;###autoload 289;;;###autoload
265(defun trace-function-background (function &optional buffer) 290(defun trace-function-background (function &optional buffer context)
266 "Traces FUNCTION with trace output going quietly to BUFFER. 291 "Traces FUNCTION with trace output going quietly to BUFFER.
267When this tracing is enabled, every call to FUNCTION writes 292When this tracing is enabled, every call to FUNCTION writes
268a Lisp-style trace message (showing the arguments and return value) 293a Lisp-style trace message (showing the arguments and return value)
@@ -272,12 +297,11 @@ The trace output goes to BUFFER quietly, without changing
272the window or buffer configuration. 297the window or buffer configuration.
273 298
274BUFFER defaults to `trace-buffer'." 299BUFFER defaults to `trace-buffer'."
275 (interactive 300 (interactive (trace--read-args "Trace function in background: "))
276 (list 301 (trace-function-internal function buffer t context))
277 (intern 302
278 (completing-read "Trace function in background: " obarray 'fboundp t)) 303;;;###autoload
279 (read-buffer "Output to buffer: " trace-buffer))) 304(defalias 'trace-function 'trace-function-foreground)
280 (trace-function-internal function buffer t))
281 305
282(defun untrace-function (function) 306(defun untrace-function (function)
283 "Untraces FUNCTION and possibly activates all remaining advice. 307 "Untraces FUNCTION and possibly activates all remaining advice.
@@ -285,16 +309,14 @@ Activation is performed with `ad-update', hence remaining advice will get
285activated only if the advice of FUNCTION is currently active. If FUNCTION 309activated only if the advice of FUNCTION is currently active. If FUNCTION
286was not traced this is a noop." 310was not traced this is a noop."
287 (interactive 311 (interactive
288 (list (ad-read-advised-function "Untrace function" 'trace-is-traced))) 312 (list (intern (completing-read "Untrace function: "
289 (when (trace-is-traced function) 313 obarray #'trace-is-traced t))))
290 (ad-remove-advice function 'around trace-advice-name) 314 (advice-remove function trace-advice-name))
291 (ad-update function)))
292 315
293(defun untrace-all () 316(defun untrace-all ()
294 "Untraces all currently traced functions." 317 "Untraces all currently traced functions."
295 (interactive) 318 (interactive)
296 (ad-do-advised-functions (function) 319 (mapatoms #'untrace-function))
297 (untrace-function function)))
298 320
299(provide 'trace) 321(provide 'trace)
300 322