diff options
| author | Kenichi Handa | 2012-11-23 23:36:24 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2012-11-23 23:36:24 +0900 |
| commit | 2aaec2d9be5cec44ea3b59cba476fd3e091f2fc9 (patch) | |
| tree | 3711b97807201b7eeaa066003b1c3a4ce929e5bb /lisp/emacs-lisp | |
| parent | e1d276cbf9e18f13101328f56bed1a1c0a66e63a (diff) | |
| parent | e7d0e5ee247a155a268ffbf80bedbe25e15b5032 (diff) | |
| download | emacs-2aaec2d9be5cec44ea3b59cba476fd3e091f2fc9.tar.gz emacs-2aaec2d9be5cec44ea3b59cba476fd3e091f2fc9.zip | |
Diffstat (limited to 'lisp/emacs-lisp')
| -rw-r--r-- | lisp/emacs-lisp/byte-run.el | 10 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 4 | ||||
| -rw-r--r-- | lisp/emacs-lisp/edebug.el | 15 | ||||
| -rw-r--r-- | lisp/emacs-lisp/ert-x.el | 47 | ||||
| -rw-r--r-- | lisp/emacs-lisp/ert.el | 804 | ||||
| -rw-r--r-- | lisp/emacs-lisp/nadvice.el | 50 | ||||
| -rw-r--r-- | lisp/emacs-lisp/trace.el | 206 |
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 | ||
| 97 | To be used in ERT tests. If BODY finishes successfully, the test | 96 | To 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 | ||
| 150 | NOTE: Since the command is not called by `call-interactively' | 149 | NOTE: Since the command is not called by `call-interactively' |
| 151 | test for `called-interactively' in the command will fail." | 150 | test 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 | |||
| 224 | None of the ARGS are modified, but the return value may share | 223 | None of the ARGS are modified, but the return value may share |
| 225 | structure with the plists in ARGS." | 224 | structure 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 | ||
| 246 | This is useful if THUNK has undesirable side-effects on an Emacs | 245 | This is useful if THUNK has undesirable side-effects on an Emacs |
| 247 | buffer with a fixed name such as *Messages*." | 246 | buffer 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 | ||
| 264 | See `ert-call-with-buffer-renamed' for details." | 263 | See `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 | ||
| 107 | ERT-PRED is a predicate, ERT-LIST is the input list." | 106 | ERT-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 | ||
| 115 | Elements are compared using `eql'." | 114 | Elements 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 | ||
| 123 | Elements are compared using `eql'." | 122 | Elements 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 | ||
| 131 | Elements are compared using `eq'." | 130 | Elements 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 | |||
| 273 | and the body." | 273 | and 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 | ||
| 295 | BODY is evaluated as a `progn' when the test is run. It should | 295 | BODY 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 | |||
| 451 | and error signaling specific to the particular variant of | 447 | and 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 |
| 453 | FORM-DESCRIPTION-FORM before it has called INNER-FORM." | 449 | FORM-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 | ||
| 471 | Returns the value of FORM." | 466 | Returns 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 | ||
| 480 | Returns nil." | 475 | Returns 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." | |||
| 490 | Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES, | 485 | Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES, |
| 491 | and aborts the current test as failed if it doesn't." | 486 | and 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 | ||
| 518 | The error signaled needs to match TYPE. TYPE should be a list | 513 | The 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." | |||
| 581 | Returns nil if they are." | 576 | Returns 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." | |||
| 648 | Returns nil if they are equivalent, i.e., have the same value for | 643 | Returns nil if they are equivalent, i.e., have the same value for |
| 649 | each key, where absent values are treated as nil. The order of | 644 | each key, where absent values are treated as nil. The order of |
| 650 | key/value pairs in each list does not matter." | 645 | key/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 | ||
| 735 | Bound dynamically. This is a list of (PREFIX . MESSAGE) pairs.") | 731 | Bound 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 | ||
| 741 | To be used within ERT tests. MESSAGE-FORM should evaluate to a | 737 | To 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 | ||
| 837 | This function records failures and errors and either terminates | 834 | This function records failures and errors and either terminates |
| @@ -839,21 +836,21 @@ the test silently or calls the interactive debugger, as | |||
| 839 | appropriate. | 836 | appropriate. |
| 840 | 837 | ||
| 841 | INFO is the ert--test-execution-info corresponding to this test | 838 | INFO is the ert--test-execution-info corresponding to this test |
| 842 | run. DEBUGGER-ARGS are the arguments to `debugger'." | 839 | run. 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 | ||
| 879 | This mainly sets up debugger-related bindings." | 876 | This 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 | ||
| 935 | Returns the result and stores it in ERT-TEST's `most-recent-result' slot." | 935 | Returns 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 | |||
| 1053 | contained in UNIVERSE." | 1053 | contained 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." | |||
| 1278 | SELECTOR is the selector that was used to select TESTS." | 1283 | SELECTOR 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 | ||
| 1351 | EXPECTEDP specifies whether the result was expected." | 1356 | EXPECTEDP 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 | ||
| 1363 | EXPECTEDP specifies whether the result was expected." | 1368 | EXPECTEDP 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 | ||
| 1385 | RESULT must be an `ert-test-result-with-condition'." | 1390 | RESULT 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 | ||
| 1538 | This can be used as an inverse of `add-to-list'." | 1543 | This 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 | |||
| 1557 | include the default, if any. | 1562 | include the default, if any. |
| 1558 | 1563 | ||
| 1559 | Signals an error if no test name was read." | 1564 | Signals 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." | |||
| 2121 | EWOC-FN specifies the direction and should be either `ewoc-prev' | 2127 | EWOC-FN specifies the direction and should be either `ewoc-prev' |
| 2122 | or `ewoc-next'. If there are no more nodes in that direction, an | 2128 | or `ewoc-next'. If there are no more nodes in that direction, an |
| 2123 | error is signaled with the message ERROR-MESSAGE." | 2129 | error 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 | ||
| 2212 | To be used in the ERT results buffer." | 2218 | To 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 | ||
| 2295 | To be used in the ERT results buffer." | 2301 | To 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 | ||
| 2304 | To be used in the ERT results buffer." | 2310 | To 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." | |||
| 2443 | To be used in the ERT results buffer." | 2450 | To 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. | 178 | LEVEL is the trace level, ARGS is the list of arguments passed to FUNCTION, |
| 182 | (format "%s%s%d -> %s: %s\n" | 179 | and CONTEXT is a string describing the dynamic context (e.g. values of |
| 183 | (mapconcat 'char-to-string (make-string (1- level) ?|) " ") | 180 | some 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)))) | 191 | LEVEL is the trace level, VALUE value returned by FUNCTION, |
| 195 | argument-bindings | 192 | and CONTEXT is a string describing the dynamic context (e.g. values of |
| 196 | " ")))) | 193 | some 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 | 208 | FUNCTION is the name of the traced function. |
| 212 | ;; (quietly if BACKGROUND is t). | 209 | BUFFER is the buffer where the trace should be printed. |
| 213 | (ad-make-advice | 210 | BACKGROUND if nil means to display BUFFER. |
| 214 | trace-advice-name nil t | 211 | CONTEXT if non-nil should be a function that returns extra info that should |
| 215 | `(advice | 212 | be 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. |
| 252 | For every call of FUNCTION Lisp-style trace messages that display argument | 280 | For every call of FUNCTION Lisp-style trace messages that display argument |
| 253 | and return values will be inserted into BUFFER. This function generates the | 281 | and 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 | |||
| 255 | there might be!! The trace BUFFER will popup whenever FUNCTION is called. | 283 | there might be!! The trace BUFFER will popup whenever FUNCTION is called. |
| 256 | Do not use this to trace functions that switch buffers or do any other | 284 | Do not use this to trace functions that switch buffers or do any other |
| 257 | display oriented stuff, use `trace-function-background' instead." | 285 | display 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. |
| 267 | When this tracing is enabled, every call to FUNCTION writes | 292 | When this tracing is enabled, every call to FUNCTION writes |
| 268 | a Lisp-style trace message (showing the arguments and return value) | 293 | a Lisp-style trace message (showing the arguments and return value) |
| @@ -272,12 +297,11 @@ The trace output goes to BUFFER quietly, without changing | |||
| 272 | the window or buffer configuration. | 297 | the window or buffer configuration. |
| 273 | 298 | ||
| 274 | BUFFER defaults to `trace-buffer'." | 299 | BUFFER 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 | |||
| 285 | activated only if the advice of FUNCTION is currently active. If FUNCTION | 309 | activated only if the advice of FUNCTION is currently active. If FUNCTION |
| 286 | was not traced this is a noop." | 310 | was 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 | ||