diff options
Diffstat (limited to 'test/src/eval-tests.el')
| -rw-r--r-- | test/src/eval-tests.el | 206 |
1 files changed, 187 insertions, 19 deletions
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el index 7ff60dd01c4..bb2f04e8ee1 100644 --- a/test/src/eval-tests.el +++ b/test/src/eval-tests.el | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | ;;; eval-tests.el --- unit tests for src/eval.c -*- lexical-binding: t; -*- | 1 | ;;; eval-tests.el --- unit tests for src/eval.c -*- lexical-binding: t; -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2016-2017 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2016-2022 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Author: Philipp Stephani <phst@google.com> | 5 | ;; Author: Philipp Stephani <phst@google.com> |
| 6 | 6 | ||
| @@ -26,28 +26,53 @@ | |||
| 26 | ;;; Code: | 26 | ;;; Code: |
| 27 | 27 | ||
| 28 | (require 'ert) | 28 | (require 'ert) |
| 29 | (eval-when-compile (require 'cl-lib)) | ||
| 30 | (require 'subr-x) | ||
| 29 | 31 | ||
| 30 | (ert-deftest eval-tests--bug24673 () | 32 | (ert-deftest eval-tests--bug24673 () |
| 31 | "Checks that Bug#24673 has been fixed." | 33 | "Check that Bug#24673 has been fixed." |
| 32 | ;; This should not crash. | 34 | ;; This should not crash. |
| 33 | (should-error (funcall '(closure)) :type 'invalid-function)) | 35 | (should-error (funcall '(closure)) :type 'invalid-function)) |
| 34 | 36 | ||
| 35 | (defvar byte-compile-debug) | 37 | (defvar byte-compile-debug) |
| 36 | 38 | ||
| 37 | (ert-deftest eval-tests--bugs-24912-and-24913 () | 39 | (ert-deftest eval-tests--bugs-24912-and-24913 () |
| 38 | "Checks that Emacs doesn’t accept weird argument lists. | 40 | "Check that Emacs doesn't accept weird argument lists. |
| 39 | Bug#24912 and Bug#24913." | 41 | Bug#24912 and Bug#24913." |
| 40 | (dolist (args '((&optional) (&rest) (&optional &rest) (&rest &optional) | 42 | (dolist (lb '(t false)) |
| 41 | (&optional &rest a) (&optional a &rest) | 43 | (ert-info ((prin1-to-string lb) :prefix "lexical-binding: ") |
| 42 | (&rest a &optional) (&rest &optional a) | 44 | (let ((lexical-binding lb)) |
| 43 | (&optional &optional) (&optional &optional a) | 45 | (dolist (args '((&rest &optional) |
| 44 | (&optional a &optional b) | 46 | (&rest a &optional) (&rest &optional a) |
| 45 | (&rest &rest) (&rest &rest a) | 47 | (&optional &optional) (&optional &optional a) |
| 46 | (&rest a &rest b))) | 48 | (&optional a &optional b) |
| 47 | (should-error (eval `(funcall (lambda ,args)) t) :type 'invalid-function) | 49 | (&rest &rest) (&rest &rest a) |
| 48 | (should-error (byte-compile-check-lambda-list args)) | 50 | (&rest a &rest b) |
| 49 | (let ((byte-compile-debug t)) | 51 | (&rest) (&optional &rest) |
| 50 | (should-error (eval `(byte-compile (lambda ,args)) t))))) | 52 | )) |
| 53 | (ert-info ((prin1-to-string args) :prefix "args: ") | ||
| 54 | (should-error | ||
| 55 | (eval `(funcall (lambda ,args)) lb) :type 'invalid-function) | ||
| 56 | (should-error (byte-compile-check-lambda-list args)) | ||
| 57 | (let ((byte-compile-debug t)) | ||
| 58 | (should-error (eval `(byte-compile (lambda ,args)) lb))))))))) | ||
| 59 | |||
| 60 | (ert-deftest eval-tests-accept-empty-optional () | ||
| 61 | "Check that Emacs accepts empty &optional arglists. | ||
| 62 | Bug#24912." | ||
| 63 | (dolist (lb '(t false)) | ||
| 64 | (ert-info ((prin1-to-string lb) :prefix "lexical-binding: ") | ||
| 65 | (let ((lexical-binding lb)) | ||
| 66 | (dolist (args '((&optional) (&optional &rest a))) | ||
| 67 | (ert-info ((prin1-to-string args) :prefix "args: ") | ||
| 68 | (let ((fun `(lambda ,args 'ok))) | ||
| 69 | (ert-info ("eval") | ||
| 70 | (should (eq (funcall (eval fun lb)) 'ok))) | ||
| 71 | (ert-info ("byte comp check") | ||
| 72 | (byte-compile-check-lambda-list args)) | ||
| 73 | (ert-info ("bytecomp") | ||
| 74 | (let ((byte-compile-debug t)) | ||
| 75 | (should (eq (funcall (byte-compile fun)) 'ok))))))))))) | ||
| 51 | 76 | ||
| 52 | 77 | ||
| 53 | (dolist (form '(let let*)) | 78 | (dolist (form '(let let*)) |
| @@ -61,22 +86,165 @@ Bug#24912 and Bug#24913." | |||
| 61 | 86 | ||
| 62 | (ert-deftest eval-tests--if-dot-string () | 87 | (ert-deftest eval-tests--if-dot-string () |
| 63 | "Check that Emacs rejects (if . \"string\")." | 88 | "Check that Emacs rejects (if . \"string\")." |
| 64 | (should-error (eval '(if . "abc")) :type 'wrong-type-argument) | 89 | (should-error (eval '(if . "abc") nil) :type 'wrong-type-argument) |
| 90 | (should-error (eval '(if . "abc") t) :type 'wrong-type-argument) | ||
| 65 | (let ((if-tail (list '(setcdr if-tail "abc") t))) | 91 | (let ((if-tail (list '(setcdr if-tail "abc") t))) |
| 66 | (should-error (eval (cons 'if if-tail)))) | 92 | (should-error (eval (cons 'if if-tail) nil) :type 'void-variable) |
| 93 | (should-error (eval (cons 'if if-tail) t) :type 'void-variable)) | ||
| 67 | (let ((if-tail (list '(progn (setcdr if-tail "abc") nil) t))) | 94 | (let ((if-tail (list '(progn (setcdr if-tail "abc") nil) t))) |
| 68 | (should-error (eval (cons 'if if-tail))))) | 95 | (should-error (eval (cons 'if if-tail) nil) :type 'void-variable) |
| 96 | (should-error (eval (cons 'if if-tail) t) :type 'void-variable))) | ||
| 69 | 97 | ||
| 70 | (ert-deftest eval-tests--let-with-circular-defs () | 98 | (ert-deftest eval-tests--let-with-circular-defs () |
| 71 | "Check that Emacs reports an error for (let VARS ...) when VARS is circular." | 99 | "Check that Emacs reports an error for (let VARS ...) when VARS is circular." |
| 72 | (let ((vars (list 'v))) | 100 | (let ((vars (list 'v))) |
| 73 | (setcdr vars vars) | 101 | (setcdr vars vars) |
| 74 | (dolist (let-sym '(let let*)) | 102 | (dolist (let-sym '(let let*)) |
| 75 | (should-error (eval (list let-sym vars)))))) | 103 | (should-error (eval (list let-sym vars) nil))))) |
| 76 | 104 | ||
| 77 | (ert-deftest eval-tests--mutating-cond () | 105 | (ert-deftest eval-tests--mutating-cond () |
| 78 | "Check that Emacs doesn't crash on a cond clause that mutates during eval." | 106 | "Check that Emacs doesn't crash on a cond clause that mutates during eval." |
| 79 | (let ((clauses (list '((progn (setcdr clauses "ouch") nil))))) | 107 | (let ((clauses (list '((progn (setcdr clauses "ouch") nil))))) |
| 80 | (should-error (eval (cons 'cond clauses))))) | 108 | (should-error (eval (cons 'cond clauses) nil)) |
| 109 | (should-error (eval (cons 'cond clauses) t)))) | ||
| 110 | |||
| 111 | (ert-deftest defvar/bug31072 () | ||
| 112 | "Check that Bug#31072 is fixed." | ||
| 113 | (should-error (eval '(defvar 1) t) :type 'wrong-type-argument)) | ||
| 114 | |||
| 115 | (ert-deftest defvaralias-overwrite-warning () | ||
| 116 | "Test for Bug#5950." | ||
| 117 | (defvar eval-tests--foo) | ||
| 118 | (setq eval-tests--foo 2) | ||
| 119 | (defvar eval-tests--foo-alias) | ||
| 120 | (setq eval-tests--foo-alias 1) | ||
| 121 | (cl-letf (((symbol-function 'display-warning) | ||
| 122 | (lambda (type &rest _) | ||
| 123 | (throw 'got-warning type)))) | ||
| 124 | ;; Warn if we lose a value through aliasing. | ||
| 125 | (should (equal | ||
| 126 | '(defvaralias losing-value eval-tests--foo-alias) | ||
| 127 | (catch 'got-warning | ||
| 128 | (defvaralias 'eval-tests--foo-alias 'eval-tests--foo)))) | ||
| 129 | ;; Don't warn if we don't. | ||
| 130 | (makunbound 'eval-tests--foo-alias) | ||
| 131 | (should (eq 'no-warning | ||
| 132 | (catch 'got-warning | ||
| 133 | (defvaralias 'eval-tests--foo-alias 'eval-tests--foo) | ||
| 134 | 'no-warning))))) | ||
| 135 | |||
| 136 | (ert-deftest eval-tests-byte-code-being-evaluated-is-protected-from-gc () | ||
| 137 | "Regression test for Bug#33014. | ||
| 138 | Check that byte-compiled objects being executed by exec-byte-code | ||
| 139 | are found on the stack and therefore not garbage collected." | ||
| 140 | (should (string= (eval-tests-33014-func) | ||
| 141 | "before after: ok foo: (e) bar: (a b c d e) baz: a bop: c"))) | ||
| 142 | |||
| 143 | (defvar eval-tests-33014-var "ok") | ||
| 144 | (defun eval-tests-33014-func () | ||
| 145 | "A function which has a non-trivial constants vector when byte-compiled." | ||
| 146 | (let ((result "before ")) | ||
| 147 | (eval-tests-33014-redefine) | ||
| 148 | (garbage-collect) | ||
| 149 | (setq result (concat result (format "after: %s" eval-tests-33014-var))) | ||
| 150 | (let ((vals '(0 1 2 3)) | ||
| 151 | (things '(a b c d e))) | ||
| 152 | (dolist (val vals) | ||
| 153 | (setq result | ||
| 154 | (concat result " " | ||
| 155 | (cond | ||
| 156 | ((= val 0) (format "foo: %s" (last things))) | ||
| 157 | ((= val 1) (format "bar: %s" things)) | ||
| 158 | ((= val 2) (format "baz: %s" (car things))) | ||
| 159 | (t (format "bop: %s" (nth 2 things)))))))) | ||
| 160 | result)) | ||
| 161 | |||
| 162 | (defun eval-tests-33014-redefine () | ||
| 163 | "Remove the Lisp reference to the byte-compiled object." | ||
| 164 | (setf (symbol-function #'eval-tests-33014-func) nil)) | ||
| 165 | |||
| 166 | (ert-deftest eval-tests-19790-backquote-comma-dot-substitution () | ||
| 167 | "Regression test for Bug#19790. | ||
| 168 | Don't handle destructive splicing in backquote expressions (like | ||
| 169 | in Common Lisp). Instead, make sure substitution in backquote | ||
| 170 | expressions works for identifiers starting with period." | ||
| 171 | (should (equal (let ((.x 'identity)) (eval `(,.x 'ok) nil)) 'ok)) | ||
| 172 | (should (equal (let ((.x 'identity)) (eval `(,.x 'ok) t)) 'ok))) | ||
| 173 | |||
| 174 | (ert-deftest eval-tests/backtrace-in-batch-mode () | ||
| 175 | (let ((emacs (expand-file-name invocation-name invocation-directory))) | ||
| 176 | (skip-unless (file-executable-p emacs)) | ||
| 177 | (with-temp-buffer | ||
| 178 | (let ((status (call-process emacs nil t nil | ||
| 179 | "--quick" "--batch" | ||
| 180 | (concat "--eval=" | ||
| 181 | (prin1-to-string | ||
| 182 | '(progn | ||
| 183 | (defun foo () (error "Boo")) | ||
| 184 | (foo))))))) | ||
| 185 | (should (natnump status)) | ||
| 186 | (should-not (eql status 0))) | ||
| 187 | (goto-char (point-min)) | ||
| 188 | (ert-info ((concat "Process output:\n" (buffer-string))) | ||
| 189 | (search-forward " foo()") | ||
| 190 | (search-forward " normal-top-level()"))))) | ||
| 191 | |||
| 192 | (ert-deftest eval-tests/backtrace-in-batch-mode/inhibit () | ||
| 193 | (let ((emacs (expand-file-name invocation-name invocation-directory))) | ||
| 194 | (skip-unless (file-executable-p emacs)) | ||
| 195 | (with-temp-buffer | ||
| 196 | (let ((status (call-process | ||
| 197 | emacs nil t nil | ||
| 198 | "--quick" "--batch" | ||
| 199 | (concat "--eval=" | ||
| 200 | (prin1-to-string | ||
| 201 | '(progn | ||
| 202 | (defun foo () (error "Boo")) | ||
| 203 | (let ((backtrace-on-error-noninteractive nil)) | ||
| 204 | (foo)))))))) | ||
| 205 | (should (natnump status)) | ||
| 206 | (should-not (eql status 0))) | ||
| 207 | (should (equal (string-trim (buffer-string)) "Boo"))))) | ||
| 208 | |||
| 209 | (ert-deftest eval-tests/backtrace-in-batch-mode/demoted-errors () | ||
| 210 | (let ((emacs (expand-file-name invocation-name invocation-directory))) | ||
| 211 | (skip-unless (file-executable-p emacs)) | ||
| 212 | (with-temp-buffer | ||
| 213 | (should (eql 0 (call-process emacs nil t nil | ||
| 214 | "--quick" "--batch" | ||
| 215 | (concat "--eval=" | ||
| 216 | (prin1-to-string | ||
| 217 | '(with-demoted-errors "Error: %S" | ||
| 218 | (error "Boo"))))))) | ||
| 219 | (goto-char (point-min)) | ||
| 220 | (should (equal (string-trim (buffer-string)) | ||
| 221 | "Error: (error \"Boo\")"))))) | ||
| 222 | |||
| 223 | (ert-deftest eval-tests/funcall-with-delayed-message () | ||
| 224 | ;; Check that `funcall-with-delayed-message' displays its message before | ||
| 225 | ;; its function terminates iff the timeout is short enough. | ||
| 226 | |||
| 227 | ;; This also serves as regression test for bug#55628 where a short | ||
| 228 | ;; timeout was rounded up to the next whole second. | ||
| 229 | (dolist (params '((0.8 0.4) | ||
| 230 | (0.1 0.8))) | ||
| 231 | (let ((timeout (nth 0 params)) | ||
| 232 | (work-time (nth 1 params))) | ||
| 233 | (ert-info ((prin1-to-string params) :prefix "params: ") | ||
| 234 | (with-current-buffer "*Messages*" | ||
| 235 | (let ((inhibit-read-only t)) | ||
| 236 | (erase-buffer)) | ||
| 237 | (let ((stop (+ (float-time) work-time))) | ||
| 238 | (funcall-with-delayed-message | ||
| 239 | timeout "timed out" | ||
| 240 | (lambda () | ||
| 241 | (while (< (float-time) stop)) | ||
| 242 | (message "finished")))) | ||
| 243 | (let ((expected-messages | ||
| 244 | (if (< timeout work-time) | ||
| 245 | "timed out\nfinished" | ||
| 246 | "finished"))) | ||
| 247 | (should (equal (string-trim (buffer-string)) | ||
| 248 | expected-messages)))))))) | ||
| 81 | 249 | ||
| 82 | ;;; eval-tests.el ends here | 250 | ;;; eval-tests.el ends here |