diff options
Diffstat (limited to 'test/lisp/emacs-lisp')
43 files changed, 2729 insertions, 233 deletions
diff --git a/test/lisp/emacs-lisp/benchmark-tests.el b/test/lisp/emacs-lisp/benchmark-tests.el index 14426aeec41..e1b67f1ed17 100644 --- a/test/lisp/emacs-lisp/benchmark-tests.el +++ b/test/lisp/emacs-lisp/benchmark-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Code: diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index d15bd8b6e65..f508c365427 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el @@ -21,7 +21,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -512,7 +512,9 @@ bytecompiled code, and their results compared.") `(let ((,file-name-var (make-temp-file "emacs"))) (unwind-protect (progn ,@body) - (delete-file ,file-name-var)))) + (delete-file ,file-name-var) + (let ((elc (concat ,file-name-var ".elc"))) + (if (file-exists-p elc) (delete-file elc)))))) (ert-deftest bytecomp-tests--unescaped-char-literals () "Check that byte compiling warns about unescaped character @@ -545,6 +547,34 @@ literals (Bug#20852)." This functionality has been obsolete for more than 10 years already and will be removed soon. See (elisp)Backquote in the manual."))))))) + +(ert-deftest bytecomp-tests-function-put () + "Check `function-put' operates during compilation." + (should (boundp 'lread--old-style-backquotes)) + (bytecomp-tests--with-temp-file source + (dolist (form '((function-put 'bytecomp-tests--foo 'foo 1) + (function-put 'bytecomp-tests--foo 'bar 2) + (defmacro bytecomp-tests--foobar () + `(cons ,(function-get 'bytecomp-tests--foo 'foo) + ,(function-get 'bytecomp-tests--foo 'bar))) + (defvar bytecomp-tests--foobar 1) + (setq bytecomp-tests--foobar (bytecomp-tests--foobar)))) + (print form (current-buffer))) + (write-region (point-min) (point-max) source nil 'silent) + (byte-compile-file source t) + (should (equal bytecomp-tests--foobar (cons 1 2))))) + +(ert-deftest bytecomp-tests--test-no-warnings-with-advice () + (defun f ()) + (define-advice f (:around (oldfun &rest args) test) + (apply oldfun args)) + (with-current-buffer (get-buffer-create "*Compile-Log*") + (let ((inhibit-read-only t)) (erase-buffer))) + (test-byte-comp-compile-and-load t '(defun f ())) + (with-current-buffer (get-buffer-create "*Compile-Log*") + (goto-char (point-min)) + (should-not (search-forward "Warning" nil t)))) + ;; Local Variables: ;; no-byte-compile: t ;; End: diff --git a/test/lisp/emacs-lisp/checkdoc-tests.el b/test/lisp/emacs-lisp/checkdoc-tests.el index 69985506f78..d832a862280 100644 --- a/test/lisp/emacs-lisp/checkdoc-tests.el +++ b/test/lisp/emacs-lisp/checkdoc-tests.el @@ -17,7 +17,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/cl-extra-tests.el b/test/lisp/emacs-lisp/cl-extra-tests.el index 5b2371e7b95..c37caa1aab7 100644 --- a/test/lisp/emacs-lisp/cl-extra-tests.el +++ b/test/lisp/emacs-lisp/cl-extra-tests.el @@ -15,7 +15,7 @@ ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see `http://www.gnu.org/licenses/'. +;; along with this program. If not, see `https://www.gnu.org/licenses/'. ;;; Code: diff --git a/test/lisp/emacs-lisp/cl-generic-tests.el b/test/lisp/emacs-lisp/cl-generic-tests.el index 0768e31f7e6..9b2b04bcca4 100644 --- a/test/lisp/emacs-lisp/cl-generic-tests.el +++ b/test/lisp/emacs-lisp/cl-generic-tests.el @@ -17,7 +17,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -219,5 +219,29 @@ (should (equal (cl--generic-1 '(5) nil) '("cinq" (5)))) (should (equal (cl--generic-1 '(6) nil) '("six" a)))) +(cl-defgeneric cl-generic-tests--generic (x)) +(cl-defmethod cl-generic-tests--generic ((x string)) + (message "%s is a string" x)) +(cl-defmethod cl-generic-tests--generic ((x integer)) + (message "%s is a number" x)) +(cl-defgeneric cl-generic-tests--generic-without-methods (x y)) +(defvar cl-generic-tests--this-file + (file-truename (or load-file-name buffer-file-name))) + +(ert-deftest cl-generic-tests--method-files--finds-methods () + "`method-files' returns a list of files and methods for a generic function." + (let ((retval (cl--generic-method-files 'cl-generic-tests--generic))) + (should (equal (length retval) 2)) + (mapc (lambda (x) + (should (equal (car x) cl-generic-tests--this-file)) + (should (equal (cadr x) 'cl-generic-tests--generic))) + retval) + (should-not (equal (nth 0 retval) (nth 1 retval))))) + +(ert-deftest cl-generic-tests--method-files--nonexistent-methods () + "`method-files' returns nil if asked to find a method which doesn't exist." + (should-not (cl--generic-method-files 'cl-generic-tests--undefined-generic)) + (should-not (cl--generic-method-files 'cl-generic-tests--generic-without-methods))) + (provide 'cl-generic-tests) ;;; cl-generic-tests.el ends here diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el b/test/lisp/emacs-lisp/cl-lib-tests.el index 65bd97f3b2d..692dd0f72cf 100644 --- a/test/lisp/emacs-lisp/cl-lib-tests.el +++ b/test/lisp/emacs-lisp/cl-lib-tests.el @@ -1,4 +1,4 @@ -;;; cl-lib.el --- tests for emacs-lisp/cl-lib.el -*- lexical-binding:t -*- +;;; cl-lib-tests.el --- tests for emacs-lisp/cl-lib.el -*- lexical-binding:t -*- ;; Copyright (C) 2013-2017 Free Software Foundation, Inc. @@ -15,7 +15,7 @@ ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see `http://www.gnu.org/licenses/'. +;; along with this program. If not, see `https://www.gnu.org/licenses/'. ;;; Commentary: @@ -195,15 +195,16 @@ (should (eql (cl-mismatch "Aa" "aA") 0)) (should (eql (cl-mismatch '(a b c) '(a b d)) 2))) -(ert-deftest cl-lib-test-loop () - (should (eql (cl-loop with (a b c) = '(1 2 3) return (+ a b c)) 6))) - (ert-deftest cl-lib-keyword-names-versus-values () (should (equal (funcall (cl-function (lambda (&key a b) (list a b))) :b :a :a 42) '(42 :a)))) +(ert-deftest cl-lib-empty-keyargs () + (should-error (funcall (cl-function (lambda (&key) 1)) + :b 1))) + (cl-defstruct (mystruct (:constructor cl-lib--con-1 (&aux (abc 1))) (:constructor cl-lib--con-2 (&optional def) "Constructor docstring.")) @@ -480,9 +481,6 @@ (should (= 239 (cl-parse-integer "zzef" :radix 16 :start 2))) (should (= -123 (cl-parse-integer " -123 ")))) -(ert-deftest cl-loop-destructuring-with () - (should (equal (cl-loop with (a b c) = '(1 2 3) return (+ a b c)) 6))) - (ert-deftest cl-flet-test () (should (equal (cl-flet ((f1 (x) x)) (let ((x #'f1)) (funcall x 5))) 5))) @@ -518,7 +516,25 @@ (ert-deftest cl-lib-symbol-macrolet-2 () (should (equal (cl-lib-symbol-macrolet-4+5) (+ 4 5)))) + +(ert-deftest cl-lib-symbol-macrolet-hide () + ;; bug#26325 + (should (equal (let ((y 5)) + (cl-symbol-macrolet ((x y)) + (list x + (let ((x 6)) (list x y)) + (cl-letf ((x 6)) (list x y))))) + '(5 (6 5) (6 6))))) + +(defun cl-lib-tests--dummy-function () + ;; Dummy function to see if the file is compiled. + t) + (ert-deftest cl-lib-defstruct-record () + ;; This test fails when compiled, see Bug#24402/27718. + :expected-result (if (byte-code-function-p + (symbol-function 'cl-lib-tests--dummy-function)) + :failed :passed) (cl-defstruct foo x) (let ((x (make-foo :x 42))) (should (recordp x)) @@ -548,4 +564,4 @@ (should cl-old-struct-compat-mode) (cl-old-struct-compat-mode (if saved 1 -1)))) -;;; cl-lib.el ends here +;;; cl-lib-tests.el ends here diff --git a/test/lisp/emacs-lisp/cl-macs-tests.el b/test/lisp/emacs-lisp/cl-macs-tests.el new file mode 100644 index 00000000000..575f170af6c --- /dev/null +++ b/test/lisp/emacs-lisp/cl-macs-tests.el @@ -0,0 +1,500 @@ +;;; cl-macs-tests.el --- tests for emacs-lisp/cl-macs.el -*- lexical-binding:t -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see `https://www.gnu.org/licenses/'. + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) +(require 'cl-macs) +(require 'ert) + + +;;;; cl-loop tests -- many adapted from Steele's CLtL2 + +;;; ANSI 6.1.1.7 Destructuring +(ert-deftest cl-macs-loop-and-assignment () + ;; Bug#6583 + :expected-result :failed + (should (equal (cl-loop for numlist in '((1 2 4.0) (5 6 8.3) (8 9 10.4)) + for a = (cl-first numlist) + and b = (cl-second numlist) + and c = (cl-third numlist) + collect (list c b a)) + '((4.0 2 1) (8.3 6 5) (10.4 9 8))))) + +(ert-deftest cl-macs-loop-destructure () + (should (equal (cl-loop for (a b c) in '((1 2 4.0) (5 6 8.3) (8 9 10.4)) + collect (list c b a)) + '((4.0 2 1) (8.3 6 5) (10.4 9 8))))) + +(ert-deftest cl-macs-loop-destructure-nil () + (should (equal (cl-loop for (a nil b) = '(1 2 3) + do (cl-return (list a b))) + '(1 3)))) + +(ert-deftest cl-macs-loop-destructure-cons () + (should (equal (cl-loop for ((a . b) (c . d)) in + '(((1.2 . 2.4) (3 . 4)) ((3.4 . 4.6) (5 . 6))) + collect (list a b c d)) + '((1.2 2.4 3 4) (3.4 4.6 5 6))))) + +(ert-deftest cl-loop-destructuring-with () + (should (equal (cl-loop with (a b c) = '(1 2 3) return (+ a b c)) 6))) + +;;; 6.1.2.1.1 The for-as-arithmetic subclause +(ert-deftest cl-macs-loop-for-as-arith () + "Test various for-as-arithmetic subclauses." + :expected-result :failed + (should (equal (cl-loop for i to 10 by 3 collect i) + '(0 3 6 9))) + (should (equal (cl-loop for i upto 3 collect i) + '(0 1 2 3))) + (should (equal (cl-loop for i below 3 collect i) + '(0 1 2))) + (should (equal (cl-loop for i below 10 by 2 collect i) + '(0 2 4 6 8))) + (should (equal (cl-loop for i downfrom 10 above 4 by 2 collect i) + '(10 8 6))) + (should (equal (cl-loop for i from 10 downto 1 by 3 collect i) + '(10 7 4 1))) + (should (equal (cl-loop for i above 0 by 2 downfrom 10 collect i) + '(10 8 6 4 2))) + (should (equal (cl-loop for i downto 10 from 15 collect i) + '(15 14 13 12 11 10)))) + +(ert-deftest cl-macs-loop-for-as-arith-order-side-effects () + "Test side effects generated by different arithmetic phrase order." + :expected-result :failed + (should + (equal (let ((x 1)) (cl-loop for i from x to 10 by (cl-incf x) collect i)) + '(1 3 5 7 9))) + (should + (equal (let ((x 1)) (cl-loop for i from x by (cl-incf x) to 10 collect i)) + '(1 3 5 7 9))) + (should + (equal (let ((x 1)) (cl-loop for i to 10 from x by (cl-incf x) collect i)) + '(1 3 5 7 9))) + (should + (equal (let ((x 1)) (cl-loop for i to 10 by (cl-incf x) from x collect i)) + '(2 4 6 8 10))) + (should + (equal (let ((x 1)) (cl-loop for i by (cl-incf x) from x to 10 collect i)) + '(2 4 6 8 10))) + (should + (equal (let ((x 1)) (cl-loop for i by (cl-incf x) to 10 from x collect i)) + '(2 4 6 8 10)))) + +(ert-deftest cl-macs-loop-for-as-arith-invalid () + "Test for invalid phrase combinations." + :expected-result :failed + ;; Mixing arithmetic-up and arithmetic-down* subclauses + (should-error (cl-loop for i downfrom 10 below 20 collect i)) + (should-error (cl-loop for i upfrom 20 above 10 collect i)) + (should-error (cl-loop for i upto 10 by 2 downfrom 5)) + ;; Repeated phrases + (should-error (cl-loop for i from 10 to 20 above 10)) + (should-error (cl-loop for i from 10 to 20 upfrom 0)) + (should-error (cl-loop for i by 2 to 10 by 5)) + ;; negative step + (should-error (cl-loop for i by -1)) + ;; no step given for a downward loop + (should-error (cl-loop for i downto -5 collect i))) + + +;;; 6.1.2.1.2 The for-as-in-list subclause +(ert-deftest cl-macs-loop-for-as-in-list () + (should (equal (cl-loop for x in '(1 2 3 4 5 6) collect (* x x)) + '(1 4 9 16 25 36))) + (should (equal (cl-loop for x in '(1 2 3 4 5 6) by #'cddr collect (* x x)) + '(1 9 25)))) + +;;; 6.1.2.1.3 The for-as-on-list subclause +(ert-deftest cl-macs-loop-for-as-on-list () + (should (equal (cl-loop for x on '(1 2 3 4) collect x) + '((1 2 3 4) (2 3 4) (3 4) (4)))) + (should (equal (cl-loop as (item) on '(1 2 3 4) by #'cddr collect item) + '(1 3)))) + +;;; 6.1.2.1.4 The for-as-equals-then subclause +(ert-deftest cl-macs-loop-for-as-equals-then () + (should (equal (cl-loop for item = 1 then (+ item 10) + repeat 5 + collect item) + '(1 11 21 31 41))) + (should (equal (cl-loop for x below 5 for y = nil then x collect (list x y)) + '((0 nil) (1 1) (2 2) (3 3) (4 4)))) + (should (equal (cl-loop for x below 5 and y = nil then x collect (list x y)) + '((0 nil) (1 0) (2 1) (3 2) (4 3)))) + (should (equal (cl-loop for x below 3 for y = (+ 10 x) nconc (list x y)) + '(0 10 1 11 2 12))) + (should (equal (cl-loop with start = 5 + for x = start then (cl-incf start) + repeat 5 + collect x) + '(5 6 7 8 9)))) + +;;; 6.1.2.1.5 The for-as-across subclause +(ert-deftest cl-macs-loop-for-as-across () + (should (string= (cl-loop for x across "aeiou" + concat (char-to-string x)) + "aeiou")) + (should (equal (cl-loop for v across (vector 1 2 3) vconcat (vector v (+ 10 v))) + [1 11 2 12 3 13]))) + +;;; 6.1.2.1.6 The for-as-hash subclause +(ert-deftest cl-macs-loop-for-as-hash () + ;; example in Emacs manual 4.7.3 + (should (equal (let ((hash (make-hash-table))) + (setf (gethash 1 hash) 10) + (setf (gethash "test" hash) "string") + (setf (gethash 'test hash) 'value) + (cl-loop for k being the hash-keys of hash + using (hash-values v) + collect (list k v))) + '((1 10) ("test" "string") (test value))))) + +;;; 6.1.2.2 Local Variable Initializations +(ert-deftest cl-macs-loop-with () + (should (equal (cl-loop with a = 1 + with b = (+ a 2) + with c = (+ b 3) + return (list a b c)) + '(1 3 6))) + (should (equal (let ((a 5) + (b 10)) + (cl-loop with a = 1 + and b = (+ a 2) + and c = (+ b 3) + return (list a b c))) + '(1 7 13))) + (should (and (equal (cl-loop for i below 3 with loop-with + do (push (* i i) loop-with) + finally (cl-return loop-with)) + '(4 1 0)) + (not (boundp 'loop-with))))) + +;;; 6.1.3 Value Accumulation Clauses +(ert-deftest cl-macs-loop-accum () + (should (equal (cl-loop for name in '(fred sue alice joe june) + for kids in '((bob ken) () () (kris sunshine) ()) + collect name + append kids) + '(fred bob ken sue alice joe kris sunshine june)))) + +(ert-deftest cl-macs-loop-collect () + (should (equal (cl-loop for i in '(bird 3 4 turtle (1 . 4) horse cat) + when (symbolp i) collect i) + '(bird turtle horse cat))) + (should (equal (cl-loop for i from 1 to 10 + if (cl-oddp i) collect i) + '(1 3 5 7 9))) + (should (equal (cl-loop for i in '(a b c d e f g) by #'cddr + collect i into my-list + finally return (nbutlast my-list)) + '(a c e)))) + +(ert-deftest cl-macs-loop-append/nconc () + (should (equal (cl-loop for x in '((a) (b) ((c))) + append x) + '(a b (c)))) + (should (equal (cl-loop for i upfrom 0 + as x in '(a b (c)) + nconc (if (cl-evenp i) (list x) nil)) + '(a (c))))) + +(ert-deftest cl-macs-loop-count () + (should (eql (cl-loop for i in '(a b nil c nil d e) + count i) + 5))) + +(ert-deftest cl-macs-loop-max/min () + (should (eql (cl-loop for i in '(2 1 5 3 4) + maximize i) + 5)) + (should (eql (cl-loop for i in '(2 1 5 3 4) + minimize i) + 1)) + (should (equal (cl-loop with series = '(4.3 1.2 5.7) + for v in series + minimize (round v) into min-result + maximize (round v) into max-result + collect (list min-result max-result)) + '((4 4) (1 4) (1 6))))) + +(ert-deftest cl-macs-loop-sum () + (should (eql (cl-loop for i in '(1 2 3 4 5) + sum i) + 15)) + (should (eql (cl-loop with series = '(1.2 4.3 5.7) + for v in series + sum (* 2.0 v)) + 22.4))) + +;;; 6.1.4 Termination Test Clauses +(ert-deftest cl-macs-loop-repeat () + (should (equal (cl-loop with n = 4 + repeat (1+ n) + collect n) + '(4 4 4 4 4))) + (should (equal (cl-loop for i upto 5 + repeat 3 + collect i) + '(0 1 2)))) + +(ert-deftest cl-macs-loop-always () + (should (cl-loop for i from 0 to 10 + always (< i 11))) + (should-not (cl-loop for i from 0 to 10 + always (< i 9) + finally (cl-return "you won't see this")))) + +(ert-deftest cl-macs-loop-never () + (should (cl-loop for i from 0 to 10 + never (> i 11))) + (should-not (cl-loop never t + finally (cl-return "you won't see this")))) + +(ert-deftest cl-macs-loop-thereis () + (should (eql (cl-loop for i from 0 + thereis (when (> i 10) i)) + 11)) + (should (string= (cl-loop thereis "Here is my value" + finally (cl-return "you won't see this")) + "Here is my value")) + (should (cl-loop for i to 10 + thereis (> i 11) + finally (cl-return i)))) + +(ert-deftest cl-macs-loop-anon-collection-conditional () + "Always/never/thereis should error when used with an anonymous +collection clause." + :expected-result :failed + (should-error (cl-loop always nil collect t)) + (should-error (cl-loop never t nconc t)) + (should-error (cl-loop thereis t append t))) + +(ert-deftest cl-macs-loop-while () + (should (equal (let ((stack '(a b c d e f))) + (cl-loop while stack + for item = (length stack) then (pop stack) + collect item)) + '(6 a b c d e f)))) + +(ert-deftest cl-macs-loop-until () + (should (equal (cl-loop for i to 100 + collect 10 + until (= i 3) + collect i) + '(10 0 10 1 10 2 10)))) + +;;; 6.1.5 Unconditional Execution Clauses +(ert-deftest cl-macs-loop-do () + (should (equal (cl-loop with list + for i from 1 to 3 + do + (push 10 list) + (push i list) + finally (cl-return list)) + '(3 10 2 10 1 10))) + (should (equal (cl-loop with res = 0 + for i from 1 to 10 + doing (cl-incf res i) + finally (cl-return res)) + 55)) + (should (equal (cl-loop for i from 10 + do (when (= i 15) + (cl-return i)) + finally (cl-return 0)) + 15))) + +;;; 6.1.6 Conditional Execution Clauses +(ert-deftest cl-macs-loop-when () + (should (equal (cl-loop for i in '(1 2 3 4 5 6) + when (and (> i 3) i) + collect it) + '(4 5 6))) + (should (eql (cl-loop for i in '(1 2 3 4 5 6) + when (and (> i 3) i) + return it) + 4)) + + (should (equal (cl-loop for elt in '(1 a 2 "a" (3 4) 5 6) + when (numberp elt) + when (cl-evenp elt) collect elt into even + else collect elt into odd + else + when (symbolp elt) collect elt into syms + else collect elt into other + finally return (list even odd syms other)) + '((2 6) (1 5) (a) ("a" (3 4)))))) + +(ert-deftest cl-macs-loop-if () + (should (equal (cl-loop for i to 5 + if (cl-evenp i) + collect i + and when (and (= i 2) 'two) + collect it + and if (< i 3) + collect "low") + '(0 2 two "low" 4))) + (should (equal (cl-loop for i to 5 + if (cl-evenp i) + collect i + and when (and (= i 2) 'two) + collect it + end + and if (< i 3) + collect "low") + '(0 "low" 2 two "low" 4))) + (should (equal (cl-loop with funny-numbers = '(6 13 -1) + for x below 10 + if (cl-evenp x) + collect x into evens + else + collect x into odds + and if (memq x funny-numbers) return (cdr it) + finally return (vector odds evens)) + [(1 3 5 7 9) (0 2 4 6 8)]))) + +(ert-deftest cl-macs-loop-unless () + (should (equal (cl-loop for i to 5 + unless (= i 3) + collect i + else + collect 'three) + '(0 1 2 three 4 5)))) + + +;;; 6.1.7.1 Control Transfer Clauses +(ert-deftest cl-macs-loop-named () + (should (eql (cl-loop named finished + for i to 10 + when (> (* i i) 30) + do (cl-return-from finished i)) + 6))) + +;;; 6.1.7.2 Initial and Final Execution +(ert-deftest cl-macs-loop-initially () + (should (equal (let ((var (list 1 2 3 4 5))) + (cl-loop for i in var + collect i + initially + (setf (car var) 10) + (setf (cadr var) 20))) + '(10 20 3 4 5)))) + +(ert-deftest cl-macs-loop-finally () + (should (eql (cl-loop for i from 10 + finally + (cl-incf i 10) + (cl-return i) + while (< i 20)) + 30))) + +;;; Emacs extensions to loop +(ert-deftest cl-macs-loop-in-ref () + (should (equal (cl-loop with my-list = (list 1 2 3 4 5) + for x in-ref my-list + do (cl-incf x) + finally return my-list) + '(2 3 4 5 6)))) + +(ert-deftest cl-macs-loop-across-ref () + (should (equal (cl-loop with my-vec = ["one" "two" "three"] + for x across-ref my-vec + do (setf (aref x 0) (upcase (aref x 0))) + finally return my-vec) + ["One" "Two" "Three"]))) + +(ert-deftest cl-macs-loop-being-elements () + (should (equal (let ((var "StRiNG")) + (cl-loop for x being the elements of var + collect (downcase x))) + (string-to-list "string")))) + +(ert-deftest cl-macs-loop-being-elements-of-ref () + (should (equal (let ((var (list 1 2 3 4 5))) + (cl-loop for x being the elements of-ref var + do (cl-incf x) + finally return var)) + '(2 3 4 5 6)))) + +(ert-deftest cl-macs-loop-being-symbols () + (should (eq (cl-loop for sym being the symbols + when (eq sym 'cl-loop) + return 'cl-loop) + 'cl-loop))) + +(ert-deftest cl-macs-loop-being-keymap () + (should (equal (let ((map (make-sparse-keymap)) + (parent (make-sparse-keymap)) + res) + (define-key map "f" #'forward-char) + (define-key map "b" #'backward-char) + (define-key parent "n" #'next-line) + (define-key parent "p" #'previous-line) + (set-keymap-parent map parent) + (cl-loop for b being the key-bindings of map + using (key-codes c) + do (push (list c b) res)) + (cl-loop for s being the key-seqs of map + using (key-bindings b) + do (push (list (cl-copy-seq s) b) res)) + res) + '(([?n] next-line) ([?p] previous-line) + ([?f] forward-char) ([?b] backward-char) + (?n next-line) (?p previous-line) + (?f forward-char) (?b backward-char))))) + +(ert-deftest cl-macs-loop-being-overlays () + (should (equal (let ((ov (make-overlay (point) (point)))) + (overlay-put ov 'prop "test") + (cl-loop for o being the overlays + when (eq o ov) + return (overlay-get o 'prop))) + "test"))) + +(ert-deftest cl-macs-loop-being-frames () + (should (eq (cl-loop with selected = (selected-frame) + for frame being the frames + when (eq frame selected) + return frame) + (selected-frame)))) + +(ert-deftest cl-macs-loop-being-windows () + (should (eq (cl-loop with selected = (selected-window) + for window being the windows + when (eq window selected) + return window) + (selected-window)))) + +(ert-deftest cl-macs-loop-being-buffers () + (should (eq (cl-loop with current = (current-buffer) + for buffer being the buffers + when (eq buffer current) + return buffer) + (current-buffer)))) + +(ert-deftest cl-macs-loop-vconcat () + (should (equal (cl-loop for x in (list 1 2 3 4 5) + vconcat (vector (1+ x))) + [2 3 4 5 6]))) + +;;; cl-macs-tests.el ends here diff --git a/test/lisp/emacs-lisp/cl-print-tests.el b/test/lisp/emacs-lisp/cl-print-tests.el index dfbe18d7844..a5dd5abf46b 100644 --- a/test/lisp/emacs-lisp/cl-print-tests.el +++ b/test/lisp/emacs-lisp/cl-print-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -34,7 +34,7 @@ (let ((print-circle t)) (should (equal (cl-prin1-to-string `((x . ,x) (y . ,x))) "((x . #1=#s(cl-print--test :a 1 :b 2)) (y . #1#))"))) - (should (string-match "\\`#f(compiled-function (x) .*\n\n.*)\\'" + (should (string-match "\\`#f(compiled-function (x) \"[^\"]+\" [^\)]*)\\'" (cl-prin1-to-string (symbol-function #'caar)))))) (ert-deftest cl-print-tests-2 () diff --git a/test/lisp/emacs-lisp/cl-seq-tests.el b/test/lisp/emacs-lisp/cl-seq-tests.el index 61e3d720331..8c0d55663ca 100644 --- a/test/lisp/emacs-lisp/cl-seq-tests.el +++ b/test/lisp/emacs-lisp/cl-seq-tests.el @@ -17,7 +17,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -27,7 +27,7 @@ (require 'cl-seq) (ert-deftest cl-union-test-00 () - "Test for http://debbugs.gnu.org/22729 ." + "Test for https://debbugs.gnu.org/22729 ." (let ((str1 "foo") (str2 (make-string 3 ?o))) ;; Emacs may make two string literals eql when reading. @@ -293,7 +293,7 @@ Body are forms defining the test." (should (= 3 (cl-search (nthcdr 2 list) list2))))) (ert-deftest cl-seq-test-bug24264 () - "Test for http://debbugs.gnu.org/24264 ." + "Test for https://debbugs.gnu.org/24264 ." (let ((list (append (make-list 8000005 1) '(8))) (list2 (make-list 8000005 2))) (should (cl-position 8 list)) diff --git a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el new file mode 100644 index 00000000000..ca49dcd213d --- /dev/null +++ b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el @@ -0,0 +1,134 @@ +;;; edebug-test-code.el --- Sample code for the Edebug test suite + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; Author: Gemini Lasswell + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This file contains sample code used by edebug-tests.el. +;; Before evaluation, it will be preprocessed by +;; `edebug-tests-setup-code-file' which will remove all tags +;; between !'s and save their positions for use by the tests. + +;;; Code: + +(defun edebug-test-code-fac (n) + !start!(if !step!(< 0 n) + (* n (edebug-test-code-fac (1- n)))!mult! + 1)) + +(defun edebug-test-code-concat (a b flag) + !start!(if flag!flag! + !then-start!(concat a!then-a! b!then-b!)!then-concat! + !else-start!(concat b!else-b! a!else-a!)!else-concat!)!if!) + +(defun edebug-test-code-range (num) + !start!(let ((index 0) + (result nil)) + (while (< index num)!test! + (push index result)!loop! + (cl-incf index))!end-loop! + (nreverse result))) + +(defun edebug-test-code-choices (input) + !start!(cond + ((eq input 0) "zero") + ((eq input 7) 42) + (t !edebug!(edebug)))) + +(defvar edebug-test-code-total nil) + +(defun edebug-test-code-multiply (times value) + !start!(setq edebug-test-code-total 0) + (cl-dotimes (index times) + (setq edebug-test-code-total (+ edebug-test-code-total value))!setq!) + edebug-test-code-total) + +(defun edebug-test-code-format-vector-node (node) + !start!(concat "[" + (apply 'concat (mapcar 'edebug-test-code-format-node node))!apply! + "]")) + +(defun edebug-test-code-format-list-node (node) + !start!(concat "{" + (apply 'concat (mapcar 'edebug-test-code-format-node node))!apply! + "}")) + +(defun edebug-test-code-format-node (node) + !start!(cond + (!vectorp!(vectorp node!vnode!)!vtest! !vbefore!(edebug-test-code-format-vector-node node)) + ((listp node) (edebug-test-code-format-list-node node)) + (t (format "%s" node)))) + +(defvar edebug-test-code-flavor "strawberry") + +(defmacro edebug-test-code-with-flavor (new-flavor &rest body) + (declare (debug (form body)) + (indent 1)) + `(let ((edebug-test-code-flavor ,new-flavor)) + ,@body)) + +(defun edebug-test-code-try-flavors () + (let* (tried) + (push edebug-test-code-flavor tried) + !macro!(edebug-test-code-with-flavor "chocolate" + (push edebug-test-code-flavor tried)) + tried)!end!) + +(unless (featurep 'edebug-tests-nutty)!nutty! + !setq!(setq edebug-test-code-flavor (car (edebug-test-code-try-flavors)))!end-setq!)!end-unless! + +(cl-defgeneric edebug-test-code-emphasize (x)) +(cl-defmethod edebug-test-code-emphasize ((x integer)) + !start!(format "The number is not %s or %s, but %s!" + (1+ x) (1- x) x)) +(cl-defmethod edebug-test-code-emphasize ((x string)) + !start!(format "***%s***" x)) + +(defun edebug-test-code-use-methods () + (list + !number!(edebug-test-code-emphasize 100) + !string!(edebug-test-code-emphasize "yes"))) + +(defun edebug-test-code-make-lambda (n) + (lambda (x) (+ x!x! n))) + +(defun edebug-test-code-use-lambda () + !start!(mapcar (edebug-test-code-make-lambda 10) '(1 2 3))) + +(defun edebug-test-code-circular-read-syntax () + '(#1=a . #1#)) + +(defun edebug-test-code-hash-read-syntax () + !start!(list #("abcd" 1 3 (face italic)) + #x01ff)) + +(defun edebug-test-code-empty-string-list () + !start!(list "")!step!) + +(defun edebug-test-code-current-buffer () + !start!(with-current-buffer (get-buffer-create "*edebug-test-code-buffer*") + !body!(format "current-buffer: %s" (current-buffer)))) + +(defun edebug-test-code-use-destructuring-bind () + (let ((two 2) (three 3)) + (cl-destructuring-bind (x . y) (cons two three) (+ x!x! y!y!)))) + +(provide 'edebug-test-code) +;;; edebug-test-code.el ends here diff --git a/test/lisp/emacs-lisp/edebug-tests.el b/test/lisp/emacs-lisp/edebug-tests.el new file mode 100644 index 00000000000..f6c016cdf80 --- /dev/null +++ b/test/lisp/emacs-lisp/edebug-tests.el @@ -0,0 +1,917 @@ +;;; edebug-tests.el --- Edebug test suite -*- lexical-binding:t -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; Author: Gemini Lasswell + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; These tests focus on Edebug's user interface for setting +;; breakpoints, stepping through and tracing code, and evaluating +;; values used by the code. In addition there are some tests of +;; Edebug's reader. There are large parts of Edebug's functionality +;; not covered by these tests, including coverage testing, macro +;; specifications, and the eval list buffer. + +;;; Code: + +(require 'cl-lib) +(require 'ert) +(require 'ert-x) +(require 'edebug) +(require 'kmacro) + +;; Use `eval-and-compile' because this is used by the macro +;; `edebug-tests-deftest'. +(eval-and-compile + (defvar edebug-tests-sample-code-file + (expand-file-name + "edebug-resources/edebug-test-code.el" + (file-name-directory (or (bound-and-true-p byte-compile-current-file) + load-file-name + buffer-file-name))) + "Name of file containing code samples for Edebug tests.")) + +(defvar edebug-tests-temp-file nil + "Name of temp file containing sample code stripped of stop point symbols.") +(defvar edebug-tests-stop-points nil + "An alist of alists mapping function symbol -> stop point name -> marker. +Used by the tests to refer to locations in `edebug-tests-temp-file'.") +(defvar edebug-tests-messages nil + "Messages collected during execution of the current test.") + +(defvar edebug-tests-@-result 'no-result + "Return value of `edebug-tests-func', or no-result if there isn't one yet.") + +(defvar edebug-tests-failure-in-post-command nil + "An error trapped in `edebug-tests-post-command'. +Since `should' failures which happen inside `post-command-hook' will +be trapped by the command loop, this preserves them until we get +back to the top level.") + +(defvar edebug-tests-keymap + (let ((map (make-sparse-keymap))) + (define-key map "@" 'edebug-tests-call-instrumented-func) + (define-key map "C-u" 'universal-argument) + (define-key map "C-p" 'previous-line) + (define-key map "C-n" 'next-line) + (define-key map "C-b" 'backward-char) + (define-key map "C-a" 'move-beginning-of-line) + (define-key map "C-e" 'move-end-of-line) + (define-key map "C-k" 'kill-line) + (define-key map "M-x" 'execute-extended-command) + (define-key map "C-M-x" 'eval-defun) + (define-key map "C-x X b" 'edebug-set-breakpoint) + (define-key map "C-x X w" 'edebug-where) + map) + "Keys used by the keyboard macros in Edebug's tests.") + +;;; Macros for defining tests: + +(defmacro edebug-tests-with-default-config (&rest body) + "Create a consistent environment for an Edebug test BODY to run in." + (declare (debug (body))) + `(cl-letf* ( + ;; These defcustoms are set to their original value. + (edebug-setup-hook nil) + (edebug-all-defs nil) + (edebug-all-forms nil) + (edebug-eval-macro-args nil) + (edebug-save-windows t) + (edebug-save-displayed-buffer-points nil) + (edebug-initial-mode 'step) + (edebug-trace nil) + (edebug-test-coverage nil) + (edebug-print-length 50) + (edebug-print-level 50) + (edebug-print-circle t) + (edebug-unwrap-results nil) + (edebug-on-error t) + (edebug-on-quit t) + (edebug-global-break-condition nil) + (edebug-sit-for-seconds 1) + + ;; sit-on interferes with keyboard macros. + (edebug-sit-on-break nil) + (edebug-continue-kbd-macro t)) + ,@body)) + +(defmacro edebug-tests-with-normal-env (&rest body) + "Set up the environment for an Edebug test BODY, run it, and clean up." + (declare (debug (body))) + `(edebug-tests-with-default-config + (let ((edebug-tests-failure-in-post-command nil) + (edebug-tests-temp-file (make-temp-file "edebug-tests-" nil ".el"))) + (edebug-tests-setup-code-file edebug-tests-temp-file) + (ert-with-message-capture + edebug-tests-messages + (unwind-protect + (with-current-buffer (find-file edebug-tests-temp-file) + (read-only-mode) + (setq lexical-binding t) + (eval-buffer) + ,@body + (when edebug-tests-failure-in-post-command + (signal (car edebug-tests-failure-in-post-command) + (cdr edebug-tests-failure-in-post-command)))) + (unload-feature 'edebug-test-code) + (with-current-buffer (find-file-noselect edebug-tests-temp-file) + (set-buffer-modified-p nil)) + (ignore-errors (kill-buffer (find-file-noselect + edebug-tests-temp-file))) + (ignore-errors (delete-file edebug-tests-temp-file))))))) + +;; The following macro and its support functions implement an extension +;; to keyboard macros to allow interleaving of keyboard macro +;; events with evaluation of Lisp expressions. The Lisp expressions +;; are called from within `post-command-hook', which is a strategy +;; inspired by `kmacro-step-edit-macro'. + +;; Some of the details necessary to get this to work with Edebug are: +;; -- ERT's `should' macros raise errors, and errors within +;; `post-command-hook' are trapped by the command loop. The +;; workaround is to trap and save an error inside the hook +;; function and reraise it after the macro exits. +;; -- `edebug-continue-kbd-macro' must be non-nil. +;; -- Edebug calls `exit-recursive-edit' which turns off keyboard +;; macro execution. Solved with an advice wrapper for +;; `exit-recursive-edit' which preserves the keyboard macro state. + +(defmacro edebug-tests-run-kbd-macro (&rest macro) + "Run a MACRO consisting of both keystrokes and test assertions. +MACRO should be a list, where each item is either a keyboard +macro segment (in string or vector form) or a Lisp expression. +Convert the macro segments into keyboard macros and execute them. +After the execution of the last event of each segment, evaluate +the Lisp expressions following the segment." + (let ((prepared (edebug-tests-prepare-macro macro))) + `(edebug-tests-run-macro ,@prepared))) + +;; Make support functions for edebug-tests-run-kbd-macro +;; available at compile time. +(eval-and-compile + (defun edebug-tests-prepare-macro (macro) + "Prepare a MACRO for execution. +MACRO should be a list containing strings, vectors, and Lisp +forms. Convert the strings and vectors to keyboard macros in +vector representation and concatenate them to make a single +keyboard macro. Also build a list of the same length as the +number of events in the keyboard macro. Each item in that list +will contain the code to evaluate after the corresponding event +in the keyboard macro, either nil or a thunk built from the forms +in the original list. Return a list containing the keyboard +macro as the first item, followed by the list of thunks and/or +nils." + (cl-loop + for item = (pop macro) + while item + for segment = (read-kbd-macro item) + for thunk = (edebug-tests-wrap-thunk + (cl-loop + for form in macro + until (or (stringp form) (vectorp form)) + collect form + do (pop macro))) + vconcat segment into segments + append (edebug-tests-pad-thunk-list (length segment) thunk) + into thunk-list + + finally return (cons segments thunk-list))) + + (defun edebug-tests-wrap-thunk (body) + "If BODY is non-nil, wrap it with a lambda form." + (when body + `(lambda () ,@body))) + + (defun edebug-tests-pad-thunk-list (length thunk) + "Return a list with LENGTH elements with THUNK in the last position. +All other elements will be nil." + (let ((thunk-seg (make-list length nil))) + (setf (car (last thunk-seg)) thunk) + thunk-seg))) + +;;; Support for test execution: + +(defvar edebug-tests-thunks nil + "List containing thunks to run after each command in a keyboard macro.") +(defvar edebug-tests-kbd-macro-index nil + "Index into `edebug-tests-run-unpacked-kbd-macro's current keyboard macro.") + +(defun edebug-tests-run-macro (kbdmac &rest thunks) + "Run a keyboard macro and execute a thunk after each command in it. +KBDMAC should be a vector of events and THUNKS a list of the +same length containing thunks and/or nils. Run the macro, and +after the execution of every command in the macro (which may not +be the same as every keystroke) execute the thunk at the same +index." + (let* ((edebug-tests-thunks thunks) + (edebug-tests-kbd-macro-index 0) + saved-local-map) + (with-current-buffer (find-file-noselect edebug-tests-temp-file) + (setq saved-local-map overriding-local-map) + (setq overriding-local-map edebug-tests-keymap) + (add-hook 'post-command-hook 'edebug-tests-post-command)) + (advice-add 'exit-recursive-edit + :around 'edebug-tests-preserve-keyboard-macro-state) + (unwind-protect + (kmacro-call-macro nil nil nil kbdmac) + (advice-remove 'exit-recursive-edit + 'edebug-tests-preserve-keyboard-macro-state) + (with-current-buffer (find-file-noselect edebug-tests-temp-file) + (setq overriding-local-map saved-local-map) + (remove-hook 'post-command-hook 'edebug-tests-post-command))))) + +(defun edebug-tests-preserve-keyboard-macro-state (orig &rest args) + "Call ORIG with ARGS preserving the value of `executing-kbd-macro'. +Useful to prevent `exit-recursive-edit' from stopping the current +keyboard macro." + (let ((executing-kbd-macro executing-kbd-macro)) + (apply orig args))) + +(defun edebug-tests-post-command () + "Run the thunk from `edebug-tests-thunks' matching the keyboard macro index." + (when (and edebug-tests-kbd-macro-index + (> executing-kbd-macro-index edebug-tests-kbd-macro-index)) + (let ((thunk (nth (1- executing-kbd-macro-index) edebug-tests-thunks))) + (when thunk + (condition-case err + (funcall thunk) + (error + (setq edebug-tests-failure-in-post-command err) + (signal (car err) (cdr err))))) + (setq edebug-tests-kbd-macro-index executing-kbd-macro-index)))) + +(defvar edebug-tests-func nil + "Instrumented function used to launch Edebug.") +(defvar edebug-tests-args nil + "Arguments for `edebug-tests-func'.") + +(defun edebug-tests-setup-@ (def-name args edebug-it) + "Set up the binding for @ in `edebug-tests-keymap'. +Find a definition for DEF-NAME in the current buffer and evaluate it. +Set globals so that `edebug-tests-call-instrumented-func' which +is bound to @ for edebug-tests' keyboard macros will call it with +ARGS. EDEBUG-IT is passed through to `eval-defun'." + (edebug-tests-locate-def def-name) + (eval-defun edebug-it) + (let* ((full-name (concat "edebug-test-code-" def-name)) + (sym (intern-soft full-name))) + (should (and sym (fboundp sym))) + (setq edebug-tests-func sym + edebug-tests-args args) + (setq edebug-tests-@-result 'no-result))) + +(defun edebug-tests-call-instrumented-func () + "Call `edebug-tests-func' with `edebug-tests-args' and save the results." + (interactive) + (let ((result (apply edebug-tests-func edebug-tests-args))) + (should (eq edebug-tests-@-result 'no-result)) + (setq edebug-tests-@-result result))) + +(defun edebug-tests-should-be-at (def-name point-name) + "Require that point be at the location in DEF-NAME named POINT-NAME. +DEF-NAME should be the suffix of a definition in the code samples +file (the part after \"edebug-tests\")." + (let ((stop-point (edebug-tests-get-stop-point def-name point-name))) + (should (eq (current-buffer) (find-file-noselect edebug-tests-temp-file))) + (should (eql (point) stop-point)))) + +(defun edebug-tests-get-stop-point (def-name point-name) + "Return the position in DEF-NAME of the stop point named POINT-NAME. +DEF-NAME should be the suffix of a definition in the code samples +file (the part after \"edebug-tests\")." + (let* ((full-name (concat "edebug-test-code-" def-name))(stop-point + (cdr (assoc point-name + (cdr (assoc full-name edebug-tests-stop-points)))))) + (unless stop-point + (ert-fail (format "%s not found in %s" point-name full-name))) + stop-point)) + +(defun edebug-tests-should-match-result-in-messages (value) + "Require that VALUE (a string) match an Edebug result in *Messages*. +Then clear edebug-tests' saved messages." + (should (string-match-p (concat "Result: " (regexp-quote value) "$") + edebug-tests-messages)) + (setq edebug-tests-messages "")) + +(defun edebug-tests-locate-def (def-name) + "Search for a definition of DEF-NAME from the start of the current buffer. +Place point at the end of DEF-NAME in the buffer." + (goto-char (point-min)) + (re-search-forward (concat "def\\S-+ edebug-test-code-" def-name))) + +(defconst edebug-tests-start-of-next-def-regexp "^(\\S-*def\\S-+ \\(\\S-+\\)" + "Regexp used to match the start of a definition.") +(defconst edebug-tests-stop-point-regexp "!\\(\\S-+?\\)!" + "Regexp used to match a stop point annotation in the sample code.") + +;;; Set up buffer containing code samples: + +(defmacro edebug-tests-deduplicate (name names-and-numbers) + "Return a unique variation on NAME. +NAME should be a string and NAMES-AND-NUMBERS an alist which can +be used by this macro to retain state. If NAME for example is +\"symbol\" then the first and subsequent uses of this macro will +evaluate to \"symbol\", \"symbol-1\", \"symbol-2\", etc." + (let ((g-name (gensym)) + (g-duplicate (gensym))) + `(let* ((,g-name ,name) + (,g-duplicate (assoc ,g-name ,names-and-numbers))) + (if (null ,g-duplicate) + (progn + (push (cons ,g-name 0) ,names-and-numbers) + ,g-name) + (cl-incf (cdr ,g-duplicate)) + (format "%s-%s" ,g-name (cdr ,g-duplicate)))))) + +(defun edebug-tests-setup-code-file (tmpfile) + "Extract stop points and loadable code from the sample code file. +Write the loadable code to a buffer for TMPFILE, and set +`edebug-tests-stop-points' to a map from defined symbols to stop +point names to positions in the file." + (with-current-buffer (find-file-noselect edebug-tests-sample-code-file) + (let ((marked-up-code (buffer-string))) + (with-temp-file tmpfile + (insert marked-up-code)))) + + (with-current-buffer (find-file-noselect tmpfile) + (let ((stop-points + ;; Delete all the !name! annotations from the code, but remember + ;; their names and where they were in an alist. + (cl-loop + initially (goto-char (point-min)) + while (re-search-forward edebug-tests-stop-point-regexp nil t) + for name = (match-string-no-properties 1) + do (replace-match "") + collect (cons name (point)))) + names-and-numbers) + + ;; Now build an alist mapping definition names to annotation + ;; names and positions. + ;; If duplicate symbols exist in the file, enter them in the + ;; alist as symbol, symbol-1, symbol-2 etc. + (setq edebug-tests-stop-points + (cl-loop + initially (goto-char (point-min)) + while (re-search-forward edebug-tests-start-of-next-def-regexp + nil t) + for name = + (edebug-tests-deduplicate (match-string-no-properties 1) + names-and-numbers) + for end-of-def = + (save-match-data + (save-excursion + (re-search-forward edebug-tests-start-of-next-def-regexp + nil 0) + (point))) + collect (cons name + (cl-loop + while (and stop-points + (< (cdar stop-points) end-of-def)) + collect (pop stop-points)))))))) + +;;; Tests + +(ert-deftest edebug-tests-check-keymap () + "Verify that `edebug-mode-map' is compatible with these tests. +If this test fails, one of two things is true. Either your +customizations modify `edebug-mode-map', in which case starting +Emacs with the -Q flag should fix the problem, or +`edebug-mode-map' has changed in edebug.el, in which case this +test and possibly others should be updated." + ;; The reason verify-keybinding is a macro instead of a function is + ;; that in the event of a failure, it makes the keybinding that + ;; failed show up in ERT's output. + (cl-macrolet ((verify-keybinding (key binding) + `(should (eq (lookup-key edebug-mode-map ,key) + ,binding)))) + (verify-keybinding " " 'edebug-step-mode) + (verify-keybinding "n" 'edebug-next-mode) + (verify-keybinding "g" 'edebug-go-mode) + (verify-keybinding "G" 'edebug-Go-nonstop-mode) + (verify-keybinding "t" 'edebug-trace-mode) + (verify-keybinding "T" 'edebug-Trace-fast-mode) + (verify-keybinding "c" 'edebug-continue-mode) + (verify-keybinding "C" 'edebug-Continue-fast-mode) + (verify-keybinding "f" 'edebug-forward-sexp) + (verify-keybinding "h" 'edebug-goto-here) + (verify-keybinding "I" 'edebug-instrument-callee) + (verify-keybinding "i" 'edebug-step-in) + (verify-keybinding "o" 'edebug-step-out) + (verify-keybinding "q" 'top-level) + (verify-keybinding "Q" 'edebug-top-level-nonstop) + (verify-keybinding "a" 'abort-recursive-edit) + (verify-keybinding "S" 'edebug-stop) + (verify-keybinding "b" 'edebug-set-breakpoint) + (verify-keybinding "u" 'edebug-unset-breakpoint) + (verify-keybinding "B" 'edebug-next-breakpoint) + (verify-keybinding "x" 'edebug-set-conditional-breakpoint) + (verify-keybinding "X" 'edebug-set-global-break-condition) + (verify-keybinding "r" 'edebug-previous-result) + (verify-keybinding "e" 'edebug-eval-expression) + (verify-keybinding "\C-x\C-e" 'edebug-eval-last-sexp) + (verify-keybinding "E" 'edebug-visit-eval-list) + (verify-keybinding "w" 'edebug-where) + (verify-keybinding "v" 'edebug-view-outside) ;; maybe obsolete?? + (verify-keybinding "p" 'edebug-bounce-point) + (verify-keybinding "P" 'edebug-view-outside) ;; same as v + (verify-keybinding "W" 'edebug-toggle-save-windows) + (verify-keybinding "?" 'edebug-help) + (verify-keybinding "d" 'edebug-backtrace) + (verify-keybinding "-" 'negative-argument) + (verify-keybinding "=" 'edebug-temp-display-freq-count))) + +(ert-deftest edebug-tests-stop-point-at-start-of-first-instrumented-function () + "Edebug stops at the beginning of an instrumented function." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "fac" '(0) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "fac" "start") + "SPC" (edebug-tests-should-be-at "fac" "step") + "g" (should (equal edebug-tests-@-result 1))))) + +(ert-deftest edebug-tests-step-showing-evaluation-results () + "Edebug prints expression evaluation results to the echo area." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "concat" '("x" "y" nil) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "concat" "start") + "SPC" (edebug-tests-should-be-at "concat" "flag") + (edebug-tests-should-match-result-in-messages "nil") + "SPC" (edebug-tests-should-be-at "concat" "else-start") + "SPC" (edebug-tests-should-be-at "concat" "else-b") + (edebug-tests-should-match-result-in-messages "\"y\"") + "SPC" (edebug-tests-should-be-at "concat" "else-a") + (edebug-tests-should-match-result-in-messages "\"x\"") + "SPC" (edebug-tests-should-be-at "concat" "else-concat") + (edebug-tests-should-match-result-in-messages "\"yx\"") + "SPC" (edebug-tests-should-be-at "concat" "if") + (edebug-tests-should-match-result-in-messages "\"yx\"") + "SPC" (should (equal edebug-tests-@-result "yx"))))) + +(ert-deftest edebug-tests-set-breakpoint-at-point () + "Edebug can set a breakpoint at point." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "concat" '("x" "y" t) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "concat" "start") + "C-n C-e b C-n" ; Move down, set a breakpoint and move away. + "g" (edebug-tests-should-be-at "concat" "then-concat") + (edebug-tests-should-match-result-in-messages "\"xy\"") + "g" (should (equal edebug-tests-@-result "xy"))))) + +(ert-deftest edebug-tests-set-temporary-breakpoint-at-point () + "Edebug can set a temporary breakpoint at point." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "range" '(3) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "range" "start") + "C-n C-n C-n C-e" ; Move down to the end of a sexp in the loop. + "C-u b" ; Set a temporary breakpoint. + "C-n" ; Move away. + "g" (edebug-tests-should-be-at "range" "loop") + (edebug-tests-should-match-result-in-messages "(0)") + "g" (should (equal edebug-tests-@-result '(0 1 2)))))) + +(ert-deftest edebug-tests-clear-breakpoint () + "Edebug can clear a breakpoint." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "range" '(3) t) + (edebug-tests-run-kbd-macro + "@" + (message "after @") + (edebug-tests-should-be-at "range" "start") + "C-n C-n C-n C-e b C-n" ; Move down, set a breakpoint and move away. + "g" (edebug-tests-should-be-at "range" "loop") + (edebug-tests-should-match-result-in-messages "(0)") + "g" (edebug-tests-should-be-at "range" "loop") + (edebug-tests-should-match-result-in-messages "(1 0)") + "u" ; Unset the breakpoint. + "g" (should (equal edebug-tests-@-result '(0 1 2)))))) + +(ert-deftest edebug-tests-move-point-to-next-breakpoint () + "Edebug can move point to the next breakpoint." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "concat" '("a" "b" nil) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "concat" "start") + "C-n C-e b" ; Move down, set a breakpoint. + "C-n b" ; Set another breakpoint on the next line. + "C-p C-p C-p" ; Move back up. + "B" (edebug-tests-should-be-at "concat" "then-concat") + "B" (edebug-tests-should-be-at "concat" "else-concat") + "G" (should (equal edebug-tests-@-result "ba"))))) + +(ert-deftest edebug-tests-move-point-back-to-stop-point () + "Edebug can move point back to a stop point." + (edebug-tests-with-normal-env + (let ((test-buffer (get-buffer-create "edebug-tests-temp"))) + (edebug-tests-setup-@ "fac" '(4) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "fac" "start") + "C-n w" (edebug-tests-should-be-at "fac" "start") + (pop-to-buffer test-buffer) + "C-x X w" (edebug-tests-should-be-at "fac" "start") + "g" (should (equal edebug-tests-@-result 24))) + (ignore-errors (kill-buffer test-buffer))))) + +(ert-deftest edebug-tests-jump-to-point () + "Edebug can stop at a temporary breakpoint at point." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "range" '(3) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "range" "start") + "C-n C-n C-n C-e" ; Move down to the end of a sexp in the loop. + "h" (edebug-tests-should-be-at "range" "loop") + (edebug-tests-should-match-result-in-messages "(0)") + "g" (should (equal edebug-tests-@-result '(0 1 2)))))) + +(ert-deftest edebug-tests-jump-forward-one-sexp () + "Edebug can run the program for one expression." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "range" '(3) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "range" "start") + "SPC SPC f" (edebug-tests-should-be-at "range" "test") + "g" (should (equal edebug-tests-@-result '(0 1 2)))))) + +(ert-deftest edebug-tests-run-out-of-containing-sexp () + "Edebug can run the program until the end of the containing sexp." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "range" '(3) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "range" "start") + "SPC SPC f" (edebug-tests-should-be-at "range" "test") + "o" (edebug-tests-should-be-at "range" "end-loop") + (edebug-tests-should-match-result-in-messages "nil") + "g" (should (equal edebug-tests-@-result '(0 1 2)))))) + +(ert-deftest edebug-tests-observe-breakpoint-in-source () + "Edebug will stop at a breakpoint embedded in source code." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "choices" '(8) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "choices" "start") + "g" (edebug-tests-should-be-at "choices" "edebug") + "g" (should (equal edebug-tests-@-result nil))))) + +(ert-deftest edebug-tests-set-conditional-breakpoint () + "Edebug can set and observe a conditional breakpoint." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "fac" '(5) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "fac" "start") + ;; Set conditional breakpoint at end of next line. + "C-n C-e x (eql SPC n SPC 3) RET" + "g" (edebug-tests-should-be-at "fac" "mult") + (edebug-tests-should-match-result-in-messages "6 (#o6, #x6, ?\\C-f)") + "g" (should (equal edebug-tests-@-result 120))))) + +(ert-deftest edebug-tests-error-trying-to-set-breakpoint-in-uninstrumented-code + () + "Edebug refuses to set a breakpoint in uninstrumented code." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "fac" '(5) t) + (let* ((debug-on-error nil) + (edebug-on-error nil) + error-message + (command-error-function (lambda (&rest args) + (setq error-message (cadar args))))) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "fac" "start") + "C-u 10 C-n" ; Move down and out of instrumented function. + "b" (should (string-match-p "Not inside instrumented form" + error-message)) + ;; The error stopped the keyboard macro. Start it again. + (should-not executing-kbd-macro) + (setq executing-kbd-macro t) + "g")))) + +(ert-deftest edebug-tests-set-and-break-on-global-condition () + "Edebug can break when a global condition becomes true." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "multiply" '(5 3) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "multiply" "start") + "X (> SPC edebug-test-code-total SPC 10) RET" + (should edebug-global-break-condition) + "g" (edebug-tests-should-be-at "multiply" "setq") + (should (eql (symbol-value 'edebug-test-code-total) 12)) + "X C-a C-k nil RET" ; Remove suggestion before entering nil. + "g" (should (equal edebug-tests-@-result 15))))) + +(ert-deftest edebug-tests-trace-showing-results-at-stop-points () + "Edebug can trace execution, showing results at stop points." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "concat" '("x" "y" nil) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "concat" "start") + "T" (should (string-match-p + (concat "Result: nil\n.*?" + "Result: \"y\"\n.*?" + "Result: \"x\"\n.*?" + "Result: \"yx\"\n.*?" + "Result: \"yx\"\n") + edebug-tests-messages)) + (should (equal edebug-tests-@-result "yx"))))) + +(ert-deftest edebug-tests-trace-showing-results-at-breakpoints () + "Edebug can trace execution, showing results at breakpoints." + (edebug-tests-with-normal-env + (edebug-tests-locate-def "format-vector-node") + (edebug-tests-run-kbd-macro "C-u C-M-x C-n C-n C-e C-x X b") + (edebug-tests-locate-def "format-list-node") + (edebug-tests-run-kbd-macro "C-u C-M-x C-n C-n C-e C-x X b") + (edebug-tests-setup-@ "format-node" '(([a b] [c d])) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "format-node" "start") + "C" (should (string-match-p + (concat "Result: \"ab\"\n.*?" + "Result: \"cd\"\n.*?" + "Result: \"\\[ab]\\[cd]\"\n") + edebug-tests-messages)) + (should (equal edebug-tests-@-result "{[ab][cd]}"))))) + +(ert-deftest edebug-tests-trace-function-call-and-return () + "Edebug can create a trace of function calls and returns." + (edebug-tests-with-normal-env + (edebug-tests-locate-def "format-vector-node") + (eval-defun t) + (edebug-tests-locate-def "format-list-node") + (eval-defun t) + (edebug-tests-setup-@ "format-node" '((a [b])) t) + (let ((edebug-trace t) + (trace-start (with-current-buffer + (get-buffer-create edebug-trace-buffer) (point-max)))) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "format-node" "start") + "g" (should (equal edebug-tests-@-result "{a[b]}"))) + (with-current-buffer edebug-trace-buffer + (should (string= + "{ edebug-test-code-format-node args: ((a [b])) +:{ edebug-test-code-format-list-node args: ((a [b])) +::{ edebug-test-code-format-node args: (a) +::} edebug-test-code-format-node result: a +::{ edebug-test-code-format-node args: ([b]) +:::{ edebug-test-code-format-vector-node args: ([b]) +::::{ edebug-test-code-format-node args: (b) +::::} edebug-test-code-format-node result: b +:::} edebug-test-code-format-vector-node result: [b] +::} edebug-test-code-format-node result: [b] +:} edebug-test-code-format-list-node result: {a[b]} +} edebug-test-code-format-node result: {a[b]} +" (buffer-substring trace-start (point-max)))))))) + +(ert-deftest edebug-tests-evaluate-expressions () + "Edebug can evaluate an expression in the context outside of itself." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "range" '(2) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "range" "start") + "SPC SPC f" (edebug-tests-should-be-at "range" "test") + (edebug-tests-should-match-result-in-messages "t") + "e (- SPC num SPC index) RET" + ;; Edebug just prints the result without "Result:" + (should (string-match-p + (regexp-quote "2 (#o2, #x2, ?\\C-b)") + edebug-tests-messages)) + "g" (should (equal edebug-tests-@-result '(0 1)))) + + ;; Do it again with lexical-binding turned off. + (setq lexical-binding nil) + (eval-buffer) + (should-not lexical-binding) + (edebug-tests-setup-@ "range" '(2) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "range" "start") + "SPC SPC f" (edebug-tests-should-be-at "range" "test") + (edebug-tests-should-match-result-in-messages "t") + "e (- SPC num SPC index) RET" + ;; Edebug just prints the result without "Result:" + (should (string-match-p + (regexp-quote "2 (#o2, #x2, ?\\C-b)") + edebug-tests-messages)) + "g" (should (equal edebug-tests-@-result '(0 1)))))) + +(ert-deftest edebug-tests-step-into-function () + "Edebug can step into a function." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "format-node" '([b]) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "format-node" "start") + "SPC SPC SPC SPC" + (edebug-tests-should-be-at "format-node" "vbefore") + "i" (edebug-tests-should-be-at "format-vector-node" "start") + "g" (should (equal edebug-tests-@-result "[b]"))))) + +(ert-deftest edebug-tests-error-stepping-into-subr () + "Edebug refuses to step into a C function." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "format-node" '([b]) t) + (let* ((debug-on-error nil) + (edebug-on-error nil) + error-message + (command-error-function (lambda (&rest args) + (setq error-message (cl-cadar args))))) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "format-node" "start") + "SPC" (edebug-tests-should-be-at "format-node" "vectorp") + "i" (should (string-match-p "vectorp is a built-in function" + error-message)) + ;; The error stopped the keyboard macro. Start it again. + (should-not executing-kbd-macro) + (setq executing-kbd-macro t) + "g" (should (equal edebug-tests-@-result "[b]")))))) + +(ert-deftest edebug-tests-step-into-macro-error () + "Edebug gives an error on trying to step into a macro (Bug#26847)." + :expected-result :failed + (ert-fail "Forcing failure because letting this test run aborts the others.") + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "try-flavors" nil t) + (let* ((debug-on-error nil) + (edebug-on-error nil) + (error-message "") + (command-error-function (lambda (&rest args) + (setq error-message (cl-cadar args))))) + (edebug-tests-run-kbd-macro + "@ SPC SPC SPC SPC SPC" + (edebug-tests-should-be-at "try-flavors" "macro") + "i" (should (string-match-p "edebug-test-code-try-flavors is a macro" + error-message)) + ;; The error stopped the keyboard macro. Start it again. + (should-not executing-kbd-macro) + (setq executing-kbd-macro t) + "g" (should (equal edebug-tests-@-result + '("chocolate" "strawberry"))))))) + +(ert-deftest edebug-tests-step-into-generic-method () + "Edebug can step into a generic method (Bug#22294)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "use-methods" nil t) + (edebug-tests-run-kbd-macro + "@ SPC" (edebug-tests-should-be-at "use-methods" "number") + "i" (edebug-tests-should-be-at "emphasize-1" "start") + "gg" (should (equal edebug-tests-@-result + '("The number is not 101 or 99, but 100!" + "***yes***")))))) + +(ert-deftest edebug-tests-break-in-lambda-out-of-defining-context () + "Edebug observes a breakpoint in a lambda executed out of defining context." + (edebug-tests-with-normal-env + (edebug-tests-locate-def "make-lambda") + (eval-defun t) + (goto-char (edebug-tests-get-stop-point "make-lambda" "x")) + (edebug-set-breakpoint t) + (edebug-tests-setup-@ "use-lambda" nil t) + (edebug-tests-run-kbd-macro + "@g" (edebug-tests-should-be-at "make-lambda" "x") + (edebug-tests-should-match-result-in-messages "1 (#o1, #x1, ?\\C-a)") + "g" (should (equal edebug-tests-@-result '(11 12 13)))))) + +(ert-deftest edebug-tests-respects-initial-mode () + "Edebug can stop first at breakpoint instead of first instrumented function." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "fac" '(4) t) + (goto-char (edebug-tests-get-stop-point "fac" "mult")) + (edebug-set-breakpoint t) + (setq edebug-initial-mode 'go) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "fac" "mult") + (edebug-tests-should-match-result-in-messages "1 (#o1, #x1, ?\\C-a)") + "G" (should (equal edebug-tests-@-result 24))))) + +(ert-deftest edebug-tests-step-through-non-definition () + "Edebug can step through a non-defining form." + (edebug-tests-with-normal-env + (goto-char (edebug-tests-get-stop-point "try-flavors" "end-unless")) + (edebug-tests-run-kbd-macro + "C-u C-M-x" + "SPC SPC" (edebug-tests-should-be-at "try-flavors" "nutty") + (edebug-tests-should-match-result-in-messages "nil") + "SPC" (edebug-tests-should-be-at "try-flavors" "setq") + "f" (edebug-tests-should-be-at "try-flavors" "end-setq") + (edebug-tests-should-match-result-in-messages "\"chocolate\"") + "g"))) + +(ert-deftest edebug-tests-conditional-breakpoints-can-use-lexical-variables () + "Edebug can set a conditional breakpoint using a lexical variable. Bug#12685" + (edebug-tests-with-normal-env + (should lexical-binding) + (edebug-tests-setup-@ "fac" '(5) t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at "fac" "start") + ;; Set conditional breakpoint at end of next line. + "C-n C-e x (eql SPC n SPC 3) RET" + "g" (edebug-tests-should-be-at "fac" "mult") + (edebug-tests-should-match-result-in-messages + "6 (#o6, #x6, ?\\C-f)")))) + +(ert-deftest edebug-tests-writable-buffer-state-is-preserved () + "On Edebug exit writable buffers are still writable (Bug#14144)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "choices" '(0) t) + (read-only-mode -1) + (edebug-tests-run-kbd-macro + "@g" (should (equal edebug-tests-@-result "zero"))) + (barf-if-buffer-read-only))) + +(ert-deftest edebug-tests-list-containing-empty-string-result-printing () + "Edebug correctly prints a list containing only an empty string (Bug#17934)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "empty-string-list" nil t) + (edebug-tests-run-kbd-macro + "@ SPC" (edebug-tests-should-be-at + "empty-string-list" "step") + (edebug-tests-should-match-result-in-messages "(\"\")") + "g"))) + +(ert-deftest edebug-tests-evaluation-of-current-buffer-bug-19611 () + "Edebug can evaluate `current-buffer' in correct context. (Bug#19611)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "current-buffer" nil t) + (edebug-tests-run-kbd-macro + "@" (edebug-tests-should-be-at + "current-buffer" "start") + "SPC SPC SPC" (edebug-tests-should-be-at + "current-buffer" "body") + "e (current-buffer) RET" + ;; Edebug just prints the result without "Result:" + (should (string-match-p + (regexp-quote "*edebug-test-code-buffer*") + edebug-tests-messages)) + "g" (should (equal edebug-tests-@-result + "current-buffer: *edebug-test-code-buffer*"))))) + +(ert-deftest edebug-tests-trivial-backquote () + "Edebug can instrument a trivial backquote expression (Bug#23651)." + (edebug-tests-with-normal-env + (read-only-mode -1) + (delete-region (point-min) (point-max)) + (insert "`1") + (read-only-mode) + (edebug-eval-defun nil) + (should (string-match-p (regexp-quote "1 (#o1, #x1, ?\\C-a)") + edebug-tests-messages)) + (setq edebug-tests-messages "") + + (setq edebug-initial-mode 'go) + ;; In Bug#23651 Edebug would hang reading `1. + (edebug-eval-defun t))) + +(ert-deftest edebug-tests-trivial-comma () + "Edebug can read a trivial comma expression (Bug#23651)." + (edebug-tests-with-normal-env + (read-only-mode -1) + (delete-region (point-min) (point-max)) + (insert ",1") + (read-only-mode) + (should-error (edebug-eval-defun t)))) + +(ert-deftest edebug-tests-circular-read-syntax () + "Edebug can instrument code using circular read object syntax (Bug#23660)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "circular-read-syntax" nil t) + (edebug-tests-run-kbd-macro + "@" (should (eql (car edebug-tests-@-result) + (cdr edebug-tests-@-result)))))) + +(ert-deftest edebug-tests-hash-read-syntax () + "Edebug can instrument code which uses # read syntax (Bug#25068)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "hash-read-syntax" nil t) + (edebug-tests-run-kbd-macro + "@g" (should (equal edebug-tests-@-result + '(#("abcd" 1 3 (face italic)) 511)))))) + +(ert-deftest edebug-tests-dotted-forms () + "Edebug can instrument code matching the tail of a dotted spec (Bug#6415)." + (edebug-tests-with-normal-env + (edebug-tests-setup-@ "use-destructuring-bind" nil t) + (edebug-tests-run-kbd-macro + "@ SPC SPC SPC SPC SPC SPC" + (edebug-tests-should-be-at "use-destructuring-bind" "x") + (edebug-tests-should-match-result-in-messages "2 (#o2, #x2, ?\\C-b)") + "SPC" + (edebug-tests-should-be-at "use-destructuring-bind" "y") + (edebug-tests-should-match-result-in-messages "3 (#o3, #x3, ?\\C-c)") + "g" + (should (equal edebug-tests-@-result 5))))) + +(provide 'edebug-tests) +;;; edebug-tests.el ends here diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el index 241ca65122d..818b3e76a1e 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: ;; @@ -192,7 +192,7 @@ (ert-deftest eieio-test-method-order-list-6 () ;; FIXME repeated intermittent failures on hydra (bug#24503) ;; ((:STATIC C) (:STATIC C-base1) (:STATIC C-base2)) != ((:STATIC C))") - (skip-unless (not (getenv "NIX_STORE"))) + (skip-unless (not (getenv "EMACS_HYDRA_CI"))) (let ((eieio-test-method-order-list nil) (ans '( (:STATIC C) diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el b/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el index da4cc5f51f3..738711c9c84 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el @@ -17,7 +17,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: ;; @@ -104,7 +104,7 @@ This is usually a symbol that starts with `:'." ;;; Slot Writers ;; -;; Replica of the test in eieio-tests.el - +;; Replica of the test in eieio-tests.el - (defclass persist-:printer (eieio-persistent) ((slot1 :initarg :slot1 @@ -164,7 +164,7 @@ persistent class.") "persist wos 1" :pnp (persist-not-persistent "pnp 1" :slot1 3) :file (concat default-directory "test-ps3.pt")))) - + (persist-test-save-and-compare persist-wos) (delete-file (oref persist-wos file)))) @@ -187,14 +187,36 @@ persistent class.") (ert-deftest eieio-test-non-persistent-as-slot-child () (let ((persist-woss - (persistent-with-objs-slot-subs + (persistent-with-objs-slot-subs "persist woss 1" :pnp (persist-not-persistent-subclass "pnps 1" :slot1 3) :file (concat default-directory "test-ps4.pt")))) - + (persist-test-save-and-compare persist-woss) (delete-file (oref persist-woss file)))) +;; A slot that can contain one of two different classes, to exercise +;; the `or' slot type. + +(defclass persistent-random-class () + ()) + +(defclass persistent-multiclass-slot (eieio-persistent) + ((slot1 :initarg :slot1 + :type (or persistent-random-class null persist-not-persistent)) + (slot2 :initarg :slot2 + :type (or persist-not-persistent persist-random-class null)))) + +(ert-deftest eieio-test-multiple-class-slot () + (let ((persist + (persistent-multiclass-slot "random string" + :slot1 (persistent-random-class) + :slot2 (persist-not-persistent) + :file (concat default-directory "test-ps5.pt")))) + (unwind-protect + (persist-test-save-and-compare persist) + (ignore-errors (delete-file (oref persist file)))))) + ;;; Slot with a list of Objects ;; ;; A slot that contains another object that isn't persistent @@ -206,13 +228,13 @@ persistent class.") (ert-deftest eieio-test-slot-with-list-of-objects () (let ((persist-wols - (persistent-with-objs-list-slot + (persistent-with-objs-list-slot "persist wols 1" :pnp (list (persist-not-persistent "pnp 1" :slot1 3) (persist-not-persistent "pnp 2" :slot1 4) (persist-not-persistent "pnp 3" :slot1 5)) :file (concat default-directory "test-ps5.pt")))) - + (persist-test-save-and-compare persist-wols) (delete-file (oref persist-wols file)))) diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el index c34560ab585..454f2aaca0e 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: ;; @@ -887,15 +887,33 @@ Subclasses to override slot attributes.") (should (= (length (eieio-build-class-alist 'opt-test1 nil)) 2)) (should (= (length (eieio-build-class-alist 'opt-test1 t)) 1))) +(mapatoms (lambda (a) + (when (and (fboundp a) + (string-match "\\`cl--?generic" + (symbol-name a))) + (trace-function-background a)))) + (defclass eieio--testing () ()) (defmethod constructor :static ((_x eieio--testing) newname &rest _args) (list newname 2)) +(defun eieio-test-dump-trace () + (message "%s" (with-current-buffer "*trace-output*" + (goto-char (point-min)) + (while (re-search-forward "[\0-\010\013-\037]" nil t) + (insert (prog1 (format "\\%03o" (char-before)) + (delete-char -1)))) + (buffer-string)))) +(eieio-test-dump-trace) + (ert-deftest eieio-test-37-obsolete-name-in-constructor () ;; FIXME repeated intermittent failures on hydra (bug#24503) - (skip-unless (not (getenv "NIX_STORE"))) - (should (equal (eieio--testing "toto") '("toto" 2)))) + (with-current-buffer "*trace-output*" + (erase-buffer)) + (unwind-protect + (should (equal (eieio--testing "toto") '("toto" 2))) + (eieio-test-dump-trace))) (ert-deftest eieio-autoload () "Tests to see whether reftex-auc has been autoloaded" diff --git a/test/lisp/emacs-lisp/ert-tests.el b/test/lisp/emacs-lisp/ert-tests.el index fc5790c3659..b620a662846 100644 --- a/test/lisp/emacs-lisp/ert-tests.el +++ b/test/lisp/emacs-lisp/ert-tests.el @@ -17,7 +17,7 @@ ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see `http://www.gnu.org/licenses/'. +;; along with this program. If not, see `https://www.gnu.org/licenses/'. ;;; Commentary: @@ -294,6 +294,15 @@ failed or if there was a problem." "the error signaled was a subtype of the expected type"))))) )) +(ert-deftest ert-test-should-error-argument () + "Errors due to evaluating arguments should not break tests." + (should-error (identity (/ 1 0)))) + +(ert-deftest ert-test-should-error-macroexpansion () + "Errors due to expanding macros should not break tests." + (cl-macrolet ((test () (error "Foo"))) + (should-error (test)))) + (ert-deftest ert-test-skip-unless () ;; Don't skip. (let ((test (make-ert-test :body (lambda () (skip-unless t))))) @@ -352,7 +361,7 @@ This macro is used to test if macroexpansion in `should' works." (let ((abc (ert-get-test 'ert-test-abc))) (should (equal (ert-test-tags abc) '(bar))) (should (equal (ert-test-documentation abc) "foo"))) - (should (equal (symbol-file 'ert-test-deftest 'ert-deftest) + (should (equal (symbol-file 'ert-test-deftest 'ert--test) (symbol-file 'ert-test--which-file 'defun))) (ert-deftest ert-test-def () :expected-result ':passed) @@ -367,12 +376,8 @@ This macro is used to test if macroexpansion in `should' works." (test (make-ert-test :body test-body)) (result (ert-run-test test))) (should (ert-test-failed-p result)) - (with-temp-buffer - (ert--print-backtrace (ert-test-failed-backtrace result)) - (goto-char (point-min)) - (end-of-line) - (let ((first-line (buffer-substring-no-properties (point-min) (point)))) - (should (equal first-line (format " %S()" test-body))))))) + (should (eq (nth 1 (car (ert-test-failed-backtrace result))) + 'signal)))) (ert-deftest ert-test-messages () :tags '(:causes-redisplay) diff --git a/test/lisp/emacs-lisp/ert-x-tests.el b/test/lisp/emacs-lisp/ert-x-tests.el index 4615d08e303..0cc89ac9977 100644 --- a/test/lisp/emacs-lisp/ert-x-tests.el +++ b/test/lisp/emacs-lisp/ert-x-tests.el @@ -18,7 +18,7 @@ ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see `http://www.gnu.org/licenses/'. +;; along with this program. If not, see `https://www.gnu.org/licenses/'. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el b/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el new file mode 100644 index 00000000000..ec2cf272368 --- /dev/null +++ b/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el @@ -0,0 +1,76 @@ +;;; faceup-test-mode.el --- Dummy major mode for testing `faceup'. + +;; Copyright (C) 2014-2017 Free Software Foundation, Inc. + +;; Author: Anders Lindgren +;; Keywords: languages, faces + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Dummy major-mode for testing `faceup', a regression test system for +;; font-lock keywords (syntax highlighting rules for Emacs). +;; +;; This mode use `syntax-propertize' to set the `syntax-table' +;; property on "<" and ">" in "<TEXT>" to make them act like +;; parentheses. +;; +;; This mode also sets the `help-echo' property on the text WARNING, +;; the effect is that Emacs displays a tooltip when you move your +;; mouse on to the text. + +;;; Code: + +(defvar faceup-test-mode-syntax-table + (make-syntax-table) + "Syntax table for `faceup-test-mode'.") + +(defvar faceup-test-font-lock-keywords + '(("\\_<WARNING\\_>" + (0 (progn + (add-text-properties (match-beginning 0) + (match-end 0) + '(help-echo "Baloon tip: Fly smoothly!")) + font-lock-warning-face)))) + "Highlight rules for `faceup-test-mode'.") + +(defun faceup-test-syntax-propertize (start end) + (goto-char start) + (funcall + (syntax-propertize-rules + ("\\(<\\)\\([^<>\n]*\\)\\(>\\)" + (1 "() ") + (3 ")( "))) + start end)) + +(defmacro faceup-test-define-prog-mode (mode name &rest args) + "Define a major mode for a programming language. +If `prog-mode' is defined, inherit from it." + (declare (indent defun)) + `(define-derived-mode + ,mode ,(and (fboundp 'prog-mode) 'prog-mode) + ,name ,@args)) + +(faceup-test-define-prog-mode faceup-test-mode "faceup-test" + "Dummy major mode for testing `faceup', a test system for font-lock." + (set (make-local-variable 'syntax-propertize-function) + #'faceup-test-syntax-propertize) + (setq font-lock-defaults '(faceup-test-font-lock-keywords nil))) + +(provide 'faceup-test-mode) + +;;; faceup-test-mode.el ends here diff --git a/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el b/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el new file mode 100644 index 00000000000..e9d8b7074c2 --- /dev/null +++ b/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el @@ -0,0 +1,32 @@ +;;; faceup-test-this-file-directory.el --- Support file for faceup tests + +;; Copyright (C) 2014-2017 Free Software Foundation, Inc. + +;; Author: Anders Lindgren +;; Keywords: languages, faces + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Support file for `faceup-test-basics.el'. This file is used to test +;; `faceup-this-file-directory' in various contexts. + +;;; Code: + +(defvar faceup-test-this-file-directory (faceup-this-file-directory)) + +;;; faceup-test-this-file-directory.el ends here diff --git a/test/lisp/emacs-lisp/faceup-resources/files/test1.txt b/test/lisp/emacs-lisp/faceup-resources/files/test1.txt new file mode 100644 index 00000000000..d971f364c2d --- /dev/null +++ b/test/lisp/emacs-lisp/faceup-resources/files/test1.txt @@ -0,0 +1,15 @@ +This is a test of `faceup', a regression test system for font-lock +keywords. It should use major mode `faceup-test-mode'. + +WARNING: The first word on this line should use +`font-lock-warning-face', and a tooltip should be displayed if the +mouse pointer is moved over it. + +In this mode "<" and ">" are parentheses, but only when on the same +line without any other "<" and ">" characters between them. +<OK> <NOT <OK> > +< +NOT OK +> + +test1.txt ends here. diff --git a/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup b/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup new file mode 100644 index 00000000000..7d4938adf17 --- /dev/null +++ b/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup @@ -0,0 +1,15 @@ +This is a test of `faceup', a regression test system for font-lock +keywords. It should use major mode `faceup-test-mode'. + +«(help-echo):"Baloon tip: Fly smoothly!":«w:WARNING»»: The first word on this line should use +`font-lock-warning-face', and a tooltip should be displayed if the +mouse pointer is moved over it. + +In this mode «s:"«(syntax-table):(4 . 41):<»"» and «s:"«(syntax-table):(5 . 40):>»"» are parentheses, but only when on the same +line without any other «s:"«(syntax-table):(4 . 41):<»"» and «s:"«(syntax-table):(5 . 40):>»"» characters between them. +«(syntax-table):(4 . 41):<»OK«(syntax-table):(5 . 40):>» <NOT «(syntax-table):(4 . 41):<»OK«(syntax-table):(5 . 40):>» > +< +NOT OK +> + +test1.txt ends here. diff --git a/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el b/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el new file mode 100644 index 00000000000..fd58c1bbca6 --- /dev/null +++ b/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el @@ -0,0 +1,269 @@ +;;; faceup-test-basics.el --- Tests for the `faceup' package. + +;; Copyright (C) 2014-2017 Free Software Foundation, Inc. + +;; Author: Anders Lindgren +;; Keywords: languages, faces + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Basic tests for the `faceup' package. + +;;; Code: + +(eval-when-compile (require 'cl-lib)) +(require 'faceup) + +(ert-deftest faceup-functions () + "Test primitive functions." + (should (equal (faceup-normalize-face-property '()) '())) + (should (equal (faceup-normalize-face-property 'a) '(a))) + (should (equal (faceup-normalize-face-property '(a)) '(a))) + (should (equal (faceup-normalize-face-property '(:x t)) '((:x t)))) + (should (equal (faceup-normalize-face-property '(:x t a)) '((:x t)))) + (should (equal (faceup-normalize-face-property '(:x t a b)) '((:x t)))) + (should (equal (faceup-normalize-face-property '(a :x t)) '(a (:x t)))) + (should (equal (faceup-normalize-face-property '(a b :x t)) + '(a b (:x t)))) + + (should (equal (faceup-normalize-face-property '(:x t :y nil)) + '((:y nil) (:x t)))) + (should (equal (faceup-normalize-face-property '(:x t :y nil a)) + '((:y nil) (:x t)))) + (should (equal (faceup-normalize-face-property '(:x t :y nil a b)) + '((:y nil) (:x t)))) + (should (equal (faceup-normalize-face-property '(a :x t :y nil)) + '(a (:y nil) (:x t)))) + (should (equal (faceup-normalize-face-property '(a b :x t :y nil)) + '(a b (:y nil) (:x t))))) + + +(ert-deftest faceup-markup-basics () + (should (equal (faceup-markup-string "") "")) + (should (equal (faceup-markup-string "test") "test"))) + +(ert-deftest faceup-markup-escaping () + (should (equal (faceup-markup-string "«") "««")) + (should (equal (faceup-markup-string "«A«B«C«") "««A««B««C««")) + (should (equal (faceup-markup-string "»") "«»")) + (should (equal (faceup-markup-string "»A»B»C»") "«»A«»B«»C«»"))) + +(ert-deftest faceup-markup-plain () + ;; UU + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face underline))) + "AB«U:CD»EF"))) + +(ert-deftest faceup-markup-plain-full-text () + ;; UUUUUU + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" 0 6 (face underline))) + "«U:ABCDEF»"))) + +(ert-deftest faceup-markup-anonymous-face () + ;; AA + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face (:underline t)))) + "AB«:(:underline t):CD»EF"))) + +(ert-deftest faceup-markup-anonymous-face-2keys () + ;; AA + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face (:foo t :bar nil)))) + "AB«:(:foo t):«:(:bar nil):CD»»EF")) + ;; Plist in list. + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face ((:foo t :bar nil))))) + "AB«:(:foo t):«:(:bar nil):CD»»EF")) + ;; Two plists. + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face ((:foo t) (:bar nil))))) + "AB«:(:bar nil):«:(:foo t):CD»»EF"))) + +(ert-deftest faceup-markup-anonymous-nested () + ;; AA + ;; IIII + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" + 1 2 (face ((:foo t))) + 2 4 (face ((:bar t) (:foo t))) + 4 5 (face ((:foo t))))) + "A«:(:foo t):B«:(:bar t):CD»E»F"))) + +(ert-deftest faceup-markup-nested () + ;; UU + ;; IIII + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" + 1 2 (face italic) + 2 4 (face (underline italic)) + 4 5 (face italic))) + "A«I:B«U:CD»E»F"))) + +(ert-deftest faceup-markup-overlapping () + ;; UUU + ;; III + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" + 1 2 (face italic) + 2 4 (face (underline italic)) + 4 5 (face underline))) + "A«I:B«U:CD»»«U:E»F")) + ;; III + ;; UUU + ;; ABCDEF + (should (equal (faceup-markup-string + #("ABCDEF" + 1 2 (face italic) + 2 4 (face (italic underline)) + 4 5 (face underline))) + "A«I:B»«U:«I:CD»E»F"))) + +(ert-deftest faceup-markup-multi-face () + ;; More than one face at the same location. + ;; + ;; The property to the front takes precedence, it is rendered as the + ;; innermost parenthesis pair. + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face (underline italic)))) + "AB«I:«U:CD»»EF")) + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (face (italic underline)))) + "AB«U:«I:CD»»EF")) + ;; Equal ranges, full text. + (should (equal (faceup-markup-string + #("ABCDEF" 0 6 (face (underline italic)))) + "«I:«U:ABCDEF»»")) + ;; Ditto, with stray markup characters. + (should (equal (faceup-markup-string + #("AB«CD»EF" 0 8 (face (underline italic)))) + "«I:«U:AB««CD«»EF»»"))) + +(ert-deftest faceup-markup-multi-property () + (let ((faceup-properties '(alpha beta gamma))) + ;; One property. + (should (equal (faceup-markup-string + #("ABCDEF" 2 4 (alpha (a l p h a)))) + "AB«(alpha):(a l p h a):CD»EF")) + + ;; Two properties, inner enclosed. + (should (equal (faceup-markup-string + (let ((s (copy-sequence "ABCDEFGHIJ"))) + (set-text-properties 2 8 '(alpha (a l p h a)) s) + (font-lock-append-text-property 4 6 'beta '(b e t a) s) + s)) + "AB«(alpha):(a l p h a):CD«(beta):(b e t a):EF»GH»IJ")) + + ;; Two properties, same end + (should (equal (faceup-markup-string + (let ((s (copy-sequence "ABCDEFGH"))) + (set-text-properties 2 6 '(alpha (a)) s) + (add-text-properties 4 6 '(beta (b)) s) + s)) + "AB«(alpha):(a):CD«(beta):(b):EF»»GH")) + + ;; Two properties, overlap. + (should (equal (faceup-markup-string + (let ((s (copy-sequence "ABCDEFGHIJ"))) + (set-text-properties 2 6 '(alpha (a)) s) + (add-text-properties 4 8 '(beta (b)) s) + s)) + "AB«(alpha):(a):CD«(beta):(b):EF»»«(beta):(b):GH»IJ")))) + + +(ert-deftest faceup-clean () + "Test the clean features of `faceup'." + (should (equal (faceup-clean-string "") "")) + (should (equal (faceup-clean-string "test") "test")) + (should (equal (faceup-clean-string "AB«U:CD»EF") "ABCDEF")) + (should (equal (faceup-clean-string "«U:ABCDEF»") "ABCDEF")) + (should (equal (faceup-clean-string "A«I:B«U:CD»E»F") "ABCDEF")) + (should (equal (faceup-clean-string "A«I:B«U:CD»»«U:E»F") "ABCDEF")) + (should (equal (faceup-clean-string "AB«I:«U:CD»»EF") "ABCDEF")) + (should (equal (faceup-clean-string "«I:«U:ABCDEF»»") "ABCDEF")) + (should (equal (faceup-clean-string "«(foo)I:ABC»DEF") "ABCDEF")) + (should (equal (faceup-clean-string "«:(:foo t):ABC»DEF") "ABCDEF")) + ;; Escaped markup characters. + (should (equal (faceup-clean-string "««") "«")) + (should (equal (faceup-clean-string "«»") "»")) + (should (equal (faceup-clean-string "A«I:B«U:CD»«»»«U:E»F") "ABCD»EF"))) + + +(ert-deftest faceup-render () + "Test the render features of `faceup'." + (should (equal (faceup-render-string "") "")) + (should (equal (faceup-render-string "««") "«")) + (should (equal (faceup-render-string "«»") "»")) + (should (equal (faceup-render-string "A«I:B«U:CD»«»»«U:E»F") "ABCD»EF"))) + + +(defvar faceup-test-resources-directory + (concat (file-name-directory + (substring (faceup-this-file-directory) 0 -1)) + "faceup-resources/") + "The `faceup-resources' directory.") + + +(defvar faceup-test-this-file-directory nil + "The result of `faceup-this-file-directory' in various contexts. + +This is set by the file test support file +`faceup-test-this-file-directory.el'.") + + +(ert-deftest faceup-directory () + "Test `faceup-this-file-directory'." + (let ((file (concat faceup-test-resources-directory + "faceup-test-this-file-directory.el")) + (load-file-name nil)) + ;; Test normal load. + (makunbound 'faceup-test-this-file-directory) + (load file nil :nomessage) + (should (equal faceup-test-this-file-directory + faceup-test-resources-directory)) + ;; Test `eval-buffer'. + (makunbound 'faceup-test-this-file-directory) + (save-excursion + (find-file file) + (eval-buffer)) + (should (equal faceup-test-this-file-directory + faceup-test-resources-directory)) + ;; Test `eval-defun'. + (makunbound 'faceup-test-this-file-directory) + (save-excursion + (find-file file) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + ;; Note: In batch mode, this prints the result of the + ;; evaluation. Unfortunately, this is hard to fix. + (eval-defun nil) + (forward-sexp)))) + (should (equal faceup-test-this-file-directory + faceup-test-resources-directory)))) + +(provide 'faceup-test-basics) + +;;; faceup-test-basics.el ends here diff --git a/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el b/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el new file mode 100644 index 00000000000..0f136862094 --- /dev/null +++ b/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el @@ -0,0 +1,63 @@ +;;; faceup-test-files.el --- Self test of `faceup' using dummy major mode. + +;; Copyright (C) 2014-2017 Free Software Foundation, Inc. + +;; Author: Anders Lindgren +;; Keywords: languages, faces + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Self test of `faceup' with a major mode that sets both the +;; `syntax-table' and the `echo-help' property. +;; +;; This file can also be seen as a blueprint of test cases for real +;; major modes. + +;;; Code: + +(require 'faceup) + +;; Note: The byte compiler needs the value to load `faceup-test-mode', +;; hence the `eval-and-compile'. +(eval-and-compile + (defvar faceup-test-files-dir (faceup-this-file-directory) + "The directory of this file.")) + +(require 'faceup-test-mode + (concat faceup-test-files-dir + "../faceup-resources/" + "faceup-test-mode.el")) + +(defun faceup-test-files-check-one (file) + "Test that FILE is fontified as the .faceup file describes. + +FILE is interpreted as relative to this source directory." + (let ((faceup-properties '(face syntax-table help-echo))) + (faceup-test-font-lock-file 'faceup-test-mode + (concat + faceup-test-files-dir + "../faceup-resources/" + file)))) +(faceup-defexplainer faceup-test-files-check-one) + +(ert-deftest faceup-files () + (should (faceup-test-files-check-one "files/test1.txt"))) + +(provide 'faceup-test-files) + +;;; faceup-test-files.el ends here diff --git a/test/lisp/emacs-lisp/generator-tests.el b/test/lisp/emacs-lisp/generator-tests.el index 1a567ac70fc..cbb136ae919 100644 --- a/test/lisp/emacs-lisp/generator-tests.el +++ b/test/lisp/emacs-lisp/generator-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -282,3 +282,13 @@ identical output. (ert-deftest cps-test-declarations-preserved () (should (equal (documentation 'generator-with-docstring) "Documentation!")) (should (equal (get 'generator-with-docstring 'lisp-indent-function) 5))) + +(ert-deftest cps-iter-lambda-with-dynamic-binding () + "`iter-lambda' with dynamic binding produces correct result (bug#25965)." + (should (= 1 + (iter-next + (funcall (iter-lambda () + (let* ((fill-column 10) ;;any special variable will do + (i 0) + (j (setq i (1+ i)))) + (iter-yield i)))))))) diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el new file mode 100644 index 00000000000..93f70827133 --- /dev/null +++ b/test/lisp/emacs-lisp/gv-tests.el @@ -0,0 +1,147 @@ +;;; gv-tests.el --- tests for gv.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Code: + +(require 'ert) +(eval-when-compile (require 'cl-lib)) + +(cl-defmacro gv-tests--in-temp-dir ((elvar elcvar) + (&rest filebody) + &rest body) + (declare (indent 2)) + `(let ((default-directory (make-temp-file "gv-test" t))) + (unwind-protect + (let ((,elvar "gv-test-deffoo.el") + (,elcvar "gv-test-deffoo.elc")) + (with-temp-file ,elvar + (insert ";; -*- lexical-binding: t; -*-\n") + (dolist (form ',filebody) + (pp form (current-buffer)))) + ,@body) + (delete-directory default-directory t)))) + +(ert-deftest gv-define-expander-in-file () + (gv-tests--in-temp-dir (el elc) + ((gv-define-setter gv-test-foo (newval cons) + `(setcar ,cons ,newval)) + (defvar gv-test-pair (cons 1 2)) + (setf (gv-test-foo gv-test-pair) 99) + (message "%d" (car gv-test-pair))) + (with-temp-buffer + (call-process (concat invocation-directory invocation-name) + nil '(t t) nil + "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el)) + "-l" elc) + (should (equal (buffer-string) "99\n"))))) + +(ert-deftest gv-define-expander-in-file-twice () + (gv-tests--in-temp-dir (el elc) + ((gv-define-setter gv-test-foo (newval cons) + `(setcar ,cons ,newval)) + (defvar gv-test-pair (cons 1 2)) + (setf (gv-test-foo gv-test-pair) 99) + (gv-define-setter gv-test-foo (newval cons) + `(setcdr ,cons ,newval)) + (setf (gv-test-foo gv-test-pair) 42) + (message "%S" gv-test-pair)) + (with-temp-buffer + (call-process (concat invocation-directory invocation-name) + nil '(t t) nil + "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el)) + "-l" elc) + (should (equal (buffer-string) "(99 . 42)\n"))))) + +(ert-deftest gv-dont-define-expander-in-file () + ;; The expander is defined while we are compiling the file, even + ;; though it's inside (when nil ...) because the compiler won't + ;; analyze the conditional. + :expected-result :failed + (gv-tests--in-temp-dir (el elc) + ((when nil (gv-define-setter gv-test-foo (newval cons) + `(setcar ,cons ,newval))) + (defvar gv-test-pair (cons 1 2)) + (setf (gv-test-foo gv-test-pair) 99) + (message "%d" (car gv-test-pair))) + (with-temp-buffer + (call-process (concat invocation-directory invocation-name) + nil '(t t) nil + "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el)) + "-l" elc) + (should (equal (buffer-string) + "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n"))))) + +(ert-deftest gv-define-expander-in-function () + ;; The expander is not defined while we are compiling the file, the + ;; compiler won't handle gv definitions not at top-level. + :expected-result :failed + (gv-tests--in-temp-dir (el elc) + ((defun foo () + (gv-define-setter gv-test-foo (newval cons) + `(setcar ,cons ,newval)) + t) + (defvar gv-test-pair (cons 1 2)) + (setf (gv-test-foo gv-test-pair) 99) + (message "%d" (car gv-test-pair))) + (with-temp-buffer + (call-process (concat invocation-directory invocation-name) + nil '(t t) nil + "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el)) + "-l" elc) + (should (equal (buffer-string) "99\n"))))) + +(ert-deftest gv-define-expander-out-of-file () + (gv-tests--in-temp-dir (el elc) + ((gv-define-setter gv-test-foo (newval cons) + `(setcar ,cons ,newval)) + (defvar gv-test-pair (cons 1 2))) + (with-temp-buffer + (call-process (concat invocation-directory invocation-name) + nil '(t t) nil + "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el)) + "-l" elc + "--eval" + (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99) + (message "%d" (car gv-test-pair))))) + (should (equal (buffer-string) "99\n"))))) + +(ert-deftest gv-dont-define-expander-other-file () + (gv-tests--in-temp-dir (el elc) + ((if nil (gv-define-setter gv-test-foo (newval cons) + `(setcar ,cons ,newval))) + (defvar gv-test-pair (cons 1 2))) + (with-temp-buffer + (call-process (concat invocation-directory invocation-name) + nil '(t t) nil + "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el)) + "-l" elc + "--eval" + (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99) + (message "%d" (car gv-test-pair))))) + (should (equal (buffer-string) + "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n"))))) + +;; `ert-deftest' messes up macroexpansion when the test file itself is +;; compiled (see Bug #24402). + +;; Local Variables: +;; no-byte-compile: t +;; End: + +;;; gv-tests.el ends here diff --git a/test/lisp/emacs-lisp/let-alist-tests.el b/test/lisp/emacs-lisp/let-alist-tests.el index d04645709e4..edcfe8a5291 100644 --- a/test/lisp/emacs-lisp/let-alist-tests.el +++ b/test/lisp/emacs-lisp/let-alist-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Code: diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el b/test/lisp/emacs-lisp/lisp-mode-tests.el index 582041cfc2d..6bc916f6c35 100644 --- a/test/lisp/emacs-lisp/lisp-mode-tests.el +++ b/test/lisp/emacs-lisp/lisp-mode-tests.el @@ -13,7 +13,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Code: @@ -198,6 +198,32 @@ Expected initialization file: `%s'\" (indent-region (point-min) (point-max)) (should (equal (buffer-string) correct))))) +(ert-deftest lisp-comment-indent-1 () + (with-temp-buffer + (insert "\ +\(let ( ;sf + (x 3)) + 4)") + (let ((indent-tabs-mode nil) + (correct (buffer-string))) + (emacs-lisp-mode) + (goto-char (point-min)) + (comment-indent) + (should (equal (buffer-string) correct))))) + +(ert-deftest lisp-comment-indent-2 () + (with-temp-buffer + (insert "\ +\(let (;;sf + (x 3)) + 4)") + (let ((indent-tabs-mode nil) + (correct (buffer-string))) + (emacs-lisp-mode) + (goto-char (point-min)) + (comment-indent) + (should (equal (buffer-string) correct))))) + (provide 'lisp-mode-tests) ;;; lisp-mode-tests.el ends here diff --git a/test/lisp/emacs-lisp/lisp-tests.el b/test/lisp/emacs-lisp/lisp-tests.el index ddbf378683b..654d949d388 100644 --- a/test/lisp/emacs-lisp/lisp-tests.el +++ b/test/lisp/emacs-lisp/lisp-tests.el @@ -19,7 +19,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -589,5 +589,36 @@ region." (should (= (point) before)) (should (= (mark) after)))) +(ert-deftest lisp-fill-paragraph-colon () + "Keywords below Emacs Lisp docstrings should not be filled (Bug#24622). +Keywords inside docstrings should be filled (Bug#7751)." + (elisp-tests-with-temp-buffer + " +\(defcustom custom value + \"First\n +Second\n +=!inside=Third line\" + =!keywords=:type 'sexp + :version \"26.1\" + :group 'lisp-tests)" + (goto-char inside) + (fill-paragraph) + (goto-char keywords) + (beginning-of-line) + (should (looking-at " :type 'sexp\n :version \"26.1\"\n :"))) + (elisp-tests-with-temp-buffer + " +\(defun foo () + \"Summary. +=!inside=Testing keywords: :one :two :three\" + (body))" ; FIXME: Remove parens around body to test Bug#28937 once it's fixed + (goto-char inside) + (let ((emacs-lisp-docstring-fill-column 30)) + (fill-paragraph)) + (forward-line) + (should (looking-at ":three")) + (end-of-line) + (should-not (eq (preceding-char) ?\))))) + (provide 'lisp-tests) ;;; lisp-tests.el ends here diff --git a/test/lisp/emacs-lisp/map-tests.el b/test/lisp/emacs-lisp/map-tests.el index 07e85cc5391..a434c9bd066 100644 --- a/test/lisp/emacs-lisp/map-tests.el +++ b/test/lisp/emacs-lisp/map-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -36,7 +36,7 @@ Each map is built from the following alist data: Evaluate BODY for each created map. \(fn (var map) body)" - (declare (indent 1) (debug t)) + (declare (indent 1) (debug (symbolp body))) (let ((alist (make-symbol "alist")) (vec (make-symbol "vec")) (ht (make-symbol "ht"))) @@ -63,6 +63,13 @@ Evaluate BODY for each created map. (with-maps-do map (should (= 5 (map-elt map 7 5))))) +(ert-deftest test-map-elt-testfn () + (let ((map (list (cons "a" 1) (cons "b" 2))) + ;; Make sure to use a non-eq "a", even when compiled. + (noneq-key (string ?a))) + (should-not (map-elt map noneq-key)) + (should (map-elt map noneq-key nil 'equal)))) + (ert-deftest test-map-elt-with-nil-value () (should (null (map-elt '((a . 1) (b)) @@ -94,6 +101,15 @@ Evaluate BODY for each created map. (should (eq (map-elt alist 2) 'b)))) +(ert-deftest test-map-put-testfn-alist () + (let ((alist (list (cons "a" 1) (cons "b" 2))) + ;; Make sure to use a non-eq "a", even when compiled. + (noneq-key (string ?a))) + (map-put alist noneq-key 3 'equal) + (should-not (cddr alist)) + (map-put alist noneq-key 9) + (should (cddr alist)))) + (ert-deftest test-map-put-return-value () (let ((ht (make-hash-table))) (should (eq (map-put ht 'a 'hello) 'hello)))) diff --git a/test/lisp/emacs-lisp/nadvice-tests.el b/test/lisp/emacs-lisp/nadvice-tests.el index b228da6cdb8..5cee61ee67d 100644 --- a/test/lisp/emacs-lisp/nadvice-tests.el +++ b/test/lisp/emacs-lisp/nadvice-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el index 62fdc751fb5..33209d3d990 100644 --- a/test/lisp/emacs-lisp/package-tests.el +++ b/test/lisp/emacs-lisp/package-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/pcase-tests.el b/test/lisp/emacs-lisp/pcase-tests.el index ef0b2f6b246..3bd14ed4b42 100644 --- a/test/lisp/emacs-lisp/pcase-tests.el +++ b/test/lisp/emacs-lisp/pcase-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/pp-tests.el b/test/lisp/emacs-lisp/pp-tests.el index b9ed79c7749..aed2d3770fb 100644 --- a/test/lisp/emacs-lisp/pp-tests.el +++ b/test/lisp/emacs-lisp/pp-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Code: diff --git a/test/lisp/emacs-lisp/regexp-opt-tests.el b/test/lisp/emacs-lisp/regexp-opt-tests.el index 92626317052..4beb7bfa1ca 100644 --- a/test/lisp/emacs-lisp/regexp-opt-tests.el +++ b/test/lisp/emacs-lisp/regexp-opt-tests.el @@ -19,7 +19,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Code: diff --git a/test/lisp/emacs-lisp/ring-tests.el b/test/lisp/emacs-lisp/ring-tests.el index c869f9dc875..00bcf8401c4 100644 --- a/test/lisp/emacs-lisp/ring-tests.el +++ b/test/lisp/emacs-lisp/ring-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/rmc-tests.el b/test/lisp/emacs-lisp/rmc-tests.el new file mode 100644 index 00000000000..7ab79fda774 --- /dev/null +++ b/test/lisp/emacs-lisp/rmc-tests.el @@ -0,0 +1,41 @@ +;;; rmc-tests.el --- Test suite for rmc.el -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; Author: Tino Calancha <tino.calancha@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'ert) +(require 'rmc) +(eval-when-compile (require 'cl-lib)) + + +(ert-deftest test-read-multiple-choice () + (dolist (char '(?y ?n)) + (cl-letf* (((symbol-function #'read-char) (lambda () char)) + (str (if (eq char ?y) "yes" "no"))) + (should (equal (list char str) + (read-multiple-choice "Do it? " '((?y "yes") (?n "no")))))))) + + +(provide 'rmc-tests) +;;; rmc-tests.el ends here diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el index 8b7945c9d27..d9ebb769613 100644 --- a/test/lisp/emacs-lisp/rx-tests.el +++ b/test/lisp/emacs-lisp/rx-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -33,5 +33,15 @@ (number-sequence ?< ?\]) (number-sequence ?- ?:)))))) +(ert-deftest rx-pcase () + (should (equal (pcase "a 1 2 3 1 1 b" + ((rx (let u (+ digit)) space + (let v (+ digit)) space + (let v (+ digit)) space + (backref u) space + (backref 1)) + (list u v))) + '("1" "3")))) + (provide 'rx-tests) ;; rx-tests.el ends here. diff --git a/test/lisp/emacs-lisp/seq-tests.el b/test/lisp/emacs-lisp/seq-tests.el index 495cf1e543c..5aa794a43b0 100644 --- a/test/lisp/emacs-lisp/seq-tests.el +++ b/test/lisp/emacs-lisp/seq-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el index 2b2a5cd0d71..0187f39d15d 100644 --- a/test/lisp/emacs-lisp/subr-x-tests.el +++ b/test/lisp/emacs-lisp/subr-x-tests.el @@ -16,7 +16,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <http://www.gnu.org/licenses/>. +;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -28,13 +28,13 @@ (require 'subr-x) -;; if-let tests +;; `if-let*' tests -(ert-deftest subr-x-test-if-let-single-binding-expansion () +(ert-deftest subr-x-test-if-let*-single-binding-expansion () "Test single bindings are expanded properly." (should (equal (macroexpand - '(if-let (a 1) + '(if-let* ((a 1)) (- a) "no")) '(let* ((a (and t 1))) @@ -43,53 +43,53 @@ "no")))) (should (equal (macroexpand - '(if-let (a) + '(if-let* (a) (- a) "no")) - '(let* ((a (and t nil))) + '(let* ((a (and t a))) (if a (- a) "no"))))) -(ert-deftest subr-x-test-if-let-single-symbol-expansion () +(ert-deftest subr-x-test-if-let*-single-symbol-expansion () "Test single symbol bindings are expanded properly." (should (equal (macroexpand - '(if-let (a) + '(if-let* (a) (- a) "no")) - '(let* ((a (and t nil))) + '(let* ((a (and t a))) (if a (- a) "no")))) (should (equal (macroexpand - '(if-let (a b c) + '(if-let* (a b c) (- a) "no")) - '(let* ((a (and t nil)) - (b (and a nil)) - (c (and b nil))) + '(let* ((a (and t a)) + (b (and a b)) + (c (and b c))) (if c (- a) "no")))) (should (equal (macroexpand - '(if-let (a (b 2) c) + '(if-let* (a (b 2) c) (- a) "no")) - '(let* ((a (and t nil)) + '(let* ((a (and t a)) (b (and a 2)) - (c (and b nil))) + (c (and b c))) (if c (- a) "no"))))) -(ert-deftest subr-x-test-if-let-nil-related-expansion () +(ert-deftest subr-x-test-if-let*-nil-related-expansion () "Test nil is processed properly." (should (equal (macroexpand - '(if-let (nil) + '(if-let* (nil) (- a) "no")) '(let* ((nil (and t nil))) @@ -98,27 +98,7 @@ "no")))) (should (equal (macroexpand - '(if-let ((nil)) - (- a) - "no")) - '(let* ((nil (and t nil))) - (if nil - (- a) - "no")))) - (should (equal - (macroexpand - '(if-let ((a 1) (nil) (b 2)) - (- a) - "no")) - '(let* ((a (and t 1)) - (nil (and a nil)) - (b (and nil 2))) - (if b - (- a) - "no")))) - (should (equal - (macroexpand - '(if-let ((a 1) nil (b 2)) + '(if-let* ((a 1) nil (b 2)) (- a) "no")) '(let* ((a (and t 1)) @@ -128,104 +108,106 @@ (- a) "no"))))) -(ert-deftest subr-x-test-if-let-malformed-binding () +(ert-deftest subr-x-test-if-let*-malformed-binding () "Test malformed bindings trigger errors." (should-error (macroexpand - '(if-let (_ (a 1 1) (b 2) (c 3) d) + '(if-let* (_ (a 1 1) (b 2) (c 3) d) (- a) "no")) :type 'error) (should-error (macroexpand - '(if-let (_ (a 1) (b 2 2) (c 3) d) + '(if-let* (_ (a 1) (b 2 2) (c 3) d) (- a) "no")) :type 'error) (should-error (macroexpand - '(if-let (_ (a 1) (b 2) (c 3 3) d) + '(if-let* (_ (a 1) (b 2) (c 3 3) d) (- a) "no")) :type 'error) (should-error (macroexpand - '(if-let ((a 1 1)) + '(if-let* ((a 1 1)) (- a) "no")) :type 'error)) -(ert-deftest subr-x-test-if-let-true () +(ert-deftest subr-x-test-if-let*-true () "Test `if-let' with truthy bindings." (should (equal - (if-let (a 1) + (if-let* ((a 1)) a "no") 1)) (should (equal - (if-let ((a 1) (b 2) (c 3)) + (if-let* ((a 1) (b 2) (c 3)) (list a b c) "no") (list 1 2 3)))) -(ert-deftest subr-x-test-if-let-false () +(ert-deftest subr-x-test-if-let*-false () "Test `if-let' with falsie bindings." (should (equal - (if-let (a nil) + (if-let* ((a nil)) (list a b c) "no") "no")) (should (equal - (if-let ((a nil) (b 2) (c 3)) + (if-let* ((a nil) (b 2) (c 3)) (list a b c) "no") "no")) (should (equal - (if-let ((a 1) (b nil) (c 3)) + (if-let* ((a 1) (b nil) (c 3)) (list a b c) "no") "no")) (should (equal - (if-let ((a 1) (b 2) (c nil)) + (if-let* ((a 1) (b 2) (c nil)) (list a b c) "no") "no")) (should (equal - (if-let (z (a 1) (b 2) (c 3)) - (list a b c) - "no") + (let (z) + (if-let* (z (a 1) (b 2) (c 3)) + (list a b c) + "no")) "no")) (should (equal - (if-let ((a 1) (b 2) (c 3) d) - (list a b c) - "no") + (let (d) + (if-let* ((a 1) (b 2) (c 3) d) + (list a b c) + "no")) "no"))) -(ert-deftest subr-x-test-if-let-bound-references () +(ert-deftest subr-x-test-if-let*-bound-references () "Test `if-let' bindings can refer to already bound symbols." (should (equal - (if-let ((a (1+ 0)) (b (1+ a)) (c (1+ b))) + (if-let* ((a (1+ 0)) (b (1+ a)) (c (1+ b))) (list a b c) "no") (list 1 2 3)))) -(ert-deftest subr-x-test-if-let-and-laziness-is-preserved () +(ert-deftest subr-x-test-if-let*-and-laziness-is-preserved () "Test `if-let' respects `and' laziness." (let (a-called b-called c-called) (should (equal - (if-let ((a nil) - (b (setq b-called t)) - (c (setq c-called t))) + (if-let* ((a nil) + (b (setq b-called t)) + (c (setq c-called t))) "yes" (list a-called b-called c-called)) (list nil nil nil)))) (let (a-called b-called c-called) (should (equal - (if-let ((a (setq a-called t)) - (b nil) - (c (setq c-called t))) + (if-let* ((a (setq a-called t)) + (b nil) + (c (setq c-called t))) "yes" (list a-called b-called c-called)) (list t nil nil)))) (let (a-called b-called c-called) (should (equal - (if-let ((a (setq a-called t)) + (if-let* ((a (setq a-called t)) (b (setq b-called t)) (c nil) (d (setq c-called t))) @@ -234,13 +216,13 @@ (list t t nil))))) -;; when-let tests +;; `when-let*' tests -(ert-deftest subr-x-test-when-let-body-expansion () +(ert-deftest subr-x-test-when-let*-body-expansion () "Test body allows for multiple sexps wrapping with progn." (should (equal (macroexpand - '(when-let (a 1) + '(when-let* ((a 1)) (message "opposite") (- a))) '(let* ((a (and t 1))) @@ -249,79 +231,46 @@ (message "opposite") (- a))))))) -(ert-deftest subr-x-test-when-let-single-binding-expansion () - "Test single bindings are expanded properly." - (should (equal - (macroexpand - '(when-let (a 1) - (- a))) - '(let* ((a (and t 1))) - (if a - (- a))))) - (should (equal - (macroexpand - '(when-let (a) - (- a))) - '(let* ((a (and t nil))) - (if a - (- a)))))) - -(ert-deftest subr-x-test-when-let-single-symbol-expansion () +(ert-deftest subr-x-test-when-let*-single-symbol-expansion () "Test single symbol bindings are expanded properly." (should (equal (macroexpand - '(when-let (a) + '(when-let* (a) (- a))) - '(let* ((a (and t nil))) + '(let* ((a (and t a))) (if a (- a))))) (should (equal (macroexpand - '(when-let (a b c) + '(when-let* (a b c) (- a))) - '(let* ((a (and t nil)) - (b (and a nil)) - (c (and b nil))) + '(let* ((a (and t a)) + (b (and a b)) + (c (and b c))) (if c (- a))))) (should (equal (macroexpand - '(when-let (a (b 2) c) + '(when-let* (a (b 2) c) (- a))) - '(let* ((a (and t nil)) + '(let* ((a (and t a)) (b (and a 2)) - (c (and b nil))) + (c (and b c))) (if c (- a)))))) -(ert-deftest subr-x-test-when-let-nil-related-expansion () +(ert-deftest subr-x-test-when-let*-nil-related-expansion () "Test nil is processed properly." (should (equal (macroexpand - '(when-let (nil) - (- a))) - '(let* ((nil (and t nil))) - (if nil - (- a))))) - (should (equal - (macroexpand - '(when-let ((nil)) + '(when-let* (nil) (- a))) '(let* ((nil (and t nil))) (if nil (- a))))) (should (equal (macroexpand - '(when-let ((a 1) (nil) (b 2)) - (- a))) - '(let* ((a (and t 1)) - (nil (and a nil)) - (b (and nil 2))) - (if b - (- a))))) - (should (equal - (macroexpand - '(when-let ((a 1) nil (b 2)) + '(when-let* ((a 1) nil (b 2)) (- a))) '(let* ((a (and t 1)) (nil (and a nil)) @@ -329,108 +278,176 @@ (if b (- a)))))) -(ert-deftest subr-x-test-when-let-malformed-binding () +(ert-deftest subr-x-test-when-let*-malformed-binding () "Test malformed bindings trigger errors." (should-error (macroexpand - '(when-let (_ (a 1 1) (b 2) (c 3) d) + '(when-let* (_ (a 1 1) (b 2) (c 3) d) (- a))) :type 'error) (should-error (macroexpand - '(when-let (_ (a 1) (b 2 2) (c 3) d) + '(when-let* (_ (a 1) (b 2 2) (c 3) d) (- a))) :type 'error) (should-error (macroexpand - '(when-let (_ (a 1) (b 2) (c 3 3) d) + '(when-let* (_ (a 1) (b 2) (c 3 3) d) (- a))) :type 'error) (should-error (macroexpand - '(when-let ((a 1 1)) + '(when-let* ((a 1 1)) (- a))) :type 'error)) -(ert-deftest subr-x-test-when-let-true () +(ert-deftest subr-x-test-when-let*-true () "Test `when-let' with truthy bindings." (should (equal - (when-let (a 1) + (when-let* ((a 1)) a) 1)) (should (equal - (when-let ((a 1) (b 2) (c 3)) + (when-let* ((a 1) (b 2) (c 3)) (list a b c)) (list 1 2 3)))) -(ert-deftest subr-x-test-when-let-false () +(ert-deftest subr-x-test-when-let*-false () "Test `when-let' with falsie bindings." (should (equal - (when-let (a nil) + (when-let* ((a nil)) (list a b c) "no") nil)) (should (equal - (when-let ((a nil) (b 2) (c 3)) + (when-let* ((a nil) (b 2) (c 3)) (list a b c) "no") nil)) (should (equal - (when-let ((a 1) (b nil) (c 3)) + (when-let* ((a 1) (b nil) (c 3)) (list a b c) "no") nil)) (should (equal - (when-let ((a 1) (b 2) (c nil)) + (when-let* ((a 1) (b 2) (c nil)) (list a b c) "no") nil)) (should (equal - (when-let (z (a 1) (b 2) (c 3)) - (list a b c) - "no") + (let (z) + (when-let* (z (a 1) (b 2) (c 3)) + (list a b c) + "no")) nil)) (should (equal - (when-let ((a 1) (b 2) (c 3) d) - (list a b c) - "no") + (let (d) + (when-let* ((a 1) (b 2) (c 3) d) + (list a b c) + "no")) nil))) -(ert-deftest subr-x-test-when-let-bound-references () +(ert-deftest subr-x-test-when-let*-bound-references () "Test `when-let' bindings can refer to already bound symbols." (should (equal - (when-let ((a (1+ 0)) (b (1+ a)) (c (1+ b))) + (when-let* ((a (1+ 0)) (b (1+ a)) (c (1+ b))) (list a b c)) (list 1 2 3)))) -(ert-deftest subr-x-test-when-let-and-laziness-is-preserved () +(ert-deftest subr-x-test-when-let*-and-laziness-is-preserved () "Test `when-let' respects `and' laziness." (let (a-called b-called c-called) (should (equal (progn - (when-let ((a nil) - (b (setq b-called t)) - (c (setq c-called t))) + (when-let* ((a nil) + (b (setq b-called t)) + (c (setq c-called t))) "yes") (list a-called b-called c-called)) (list nil nil nil)))) (let (a-called b-called c-called) (should (equal (progn - (when-let ((a (setq a-called t)) - (b nil) - (c (setq c-called t))) + (when-let* ((a (setq a-called t)) + (b nil) + (c (setq c-called t))) "yes") (list a-called b-called c-called)) (list t nil nil)))) (let (a-called b-called c-called) (should (equal (progn - (when-let ((a (setq a-called t)) - (b (setq b-called t)) - (c nil) - (d (setq c-called t))) + (when-let* ((a (setq a-called t)) + (b (setq b-called t)) + (c nil) + (d (setq c-called t))) "yes") (list a-called b-called c-called)) (list t t nil))))) +;; `and-let*' tests + +;; Adapted from the Guile tests +;; https://git.savannah.gnu.org/cgit/guile.git/tree/test-suite/tests/srfi-2.test + +(ert-deftest subr-x-and-let*-test-empty-varlist () + (should (equal 1 (and-let* () 1))) + (should (equal 2 (and-let* () 1 2))) + (should (equal t (and-let* ())))) + +(ert-deftest subr-x-and-let*-test-group-1 () + (should (equal nil (let ((x nil)) (and-let* (x))))) + (should (equal 1 (let ((x 1)) (and-let* (x))))) + (should (equal nil (and-let* ((x nil))))) + (should (equal 1 (and-let* ((x 1))))) + ;; The error doesn't trigger when compiled: the compiler will give + ;; a warning and then drop the erroneous code. Therefore, use + ;; `eval' to avoid compilation. + (should-error (eval '(and-let* (nil (x 1))) lexical-binding) + :type 'setting-constant) + (should (equal nil (and-let* ((nil) (x 1))))) + (should-error (eval '(and-let* (2 (x 1))) lexical-binding) + :type 'wrong-type-argument) + (should (equal 1 (and-let* ((2) (x 1))))) + (should (equal 2 (and-let* ((x 1) (2))))) + (should (equal nil (let ((x nil)) (and-let* (x) x)))) + (should (equal "" (let ((x "")) (and-let* (x) x)))) + (should (equal "" (let ((x "")) (and-let* (x))))) + (should (equal 2 (let ((x 1)) (and-let* (x) (+ x 1))))) + (should (equal nil (let ((x nil)) (and-let* (x) (+ x 1))))) + (should (equal 2 (let ((x 1)) (and-let* (((> x 0))) (+ x 1))))) + (should (equal t (let ((x 1)) (and-let* (((> x 0))))))) + (should (equal nil (let ((x 0)) (and-let* (((> x 0))) (+ x 1))))) + (should (equal 3 + (let ((x 1)) (and-let* (((> x 0)) (x (+ x 1))) (+ x 1)))))) + +(ert-deftest subr-x-and-let*-test-rebind () + (should + (equal 4 + (let ((x 1)) + (and-let* (((> x 0)) (x (+ x 1)) (x (+ x 1))) (+ x 1)))))) + +(ert-deftest subr-x-and-let*-test-group-2 () + (should + (equal 2 (let ((x 1)) (and-let* (x ((> x 0))) (+ x 1))))) + (should + (equal 2 (let ((x 1)) (and-let* (((progn x)) ((> x 0))) (+ x 1))))) + (should (equal nil (let ((x 0)) (and-let* (x ((> x 0))) (+ x 1))))) + (should (equal nil (let ((x nil)) (and-let* (x ((> x 0))) (+ x 1))))) + (should + (equal nil (let ((x nil)) (and-let* (((progn x)) ((> x 0))) (+ x 1)))))) + +(ert-deftest subr-x-and-let*-test-group-3 () + (should + (equal nil (let ((x 1)) (and-let* (x (y (- x 1)) ((> y 0))) (/ x y))))) + (should + (equal nil (let ((x 0)) (and-let* (x (y (- x 1)) ((> y 0))) (/ x y))))) + (should + (equal nil + (let ((x nil)) (and-let* (x (y (- x 1)) ((> y 0))) (/ x y))))) + (should + (equal (/ 3.0 2) + (let ((x 3.0)) (and-let* (x (y (- x 1)) ((> y 0))) (/ x y)))))) + + + ;; Thread first tests (ert-deftest subr-x-test-thread-first-no-forms () diff --git a/test/lisp/emacs-lisp/tabulated-list-test.el b/test/lisp/emacs-lisp/tabulated-list-test.el index b3a09ee375c..30a4f8f61b4 100644 --- a/test/lisp/emacs-lisp/tabulated-list-test.el +++ b/test/lisp/emacs-lisp/tabulated-list-test.el @@ -17,7 +17,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Code: diff --git a/test/lisp/emacs-lisp/testcover-resources/testcases.el b/test/lisp/emacs-lisp/testcover-resources/testcases.el index 1eb791a993c..6a9612db05a 100644 --- a/test/lisp/emacs-lisp/testcover-resources/testcases.el +++ b/test/lisp/emacs-lisp/testcover-resources/testcases.el @@ -17,7 +17,7 @@ ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see `http://www.gnu.org/licenses/'. +;; along with this program. If not, see `https://www.gnu.org/licenses/'. ;;; Commentary: @@ -53,7 +53,6 @@ ;; ==== constants-bug-25316 ==== "Testcover doesn't splotch constants." -:expected-result :failed ;; ==== (defconst testcover-testcase-const "apples") (defun testcover-testcase-zero () 0) @@ -76,7 +75,6 @@ ;; ==== customize-defcustom-bug-25326 ==== "Testcover doesn't prevent testing of defcustom values." -:expected-result :failed ;; ==== (defgroup testcover-testcase nil "Test case for testcover" @@ -135,7 +133,6 @@ ;; ==== 1-value-symbol-bug-25316 ==== "Wrapping a form with 1value prevents splotching." -:expected-result :failed ;; ==== (defun testcover-testcase-always-zero (num) (- num%%% num%%%)%%%) @@ -230,7 +227,6 @@ ;; ==== quotes-within-backquotes-bug-25316 ==== "Forms to instrument are found within quotes within backquotes." -:expected-result :failed ;; ==== (defun testcover-testcase-make-list () (list 'defun 'defvar)) @@ -296,7 +292,6 @@ ;; ==== backquote-1value-bug-24509 ==== "Commas within backquotes are recognized as non-1value." -:expected-result :failed ;; ==== (defmacro testcover-testcase-lambda (&rest body) `(lambda () ,@body)) @@ -320,7 +315,6 @@ ;; ==== pcase-bug-24688 ==== "Testcover copes with condition-case within backquoted list." -:expected-result :failed ;; ==== (defun testcover-testcase-pcase (form) (pcase form%%% @@ -335,7 +329,6 @@ ;; ==== defun-in-backquote-bug-11307-and-24743 ==== "Testcover handles defun forms within backquoted list." -:expected-result :failed ;; ==== (defmacro testcover-testcase-defun (name &rest body) (declare (debug (symbolp def-body))) @@ -348,7 +341,6 @@ ;; ==== closure-1value-bug ==== "Testcover does not mark closures as 1value." -:expected-result :failed ;; ==== ;; -*- lexical-binding:t -*- (setq testcover-testcase-foo nil) @@ -365,7 +357,6 @@ ;; ==== by-value-vs-by-reference-bug-25351 ==== "An object created by a 1value expression may be modified by other code." -:expected-result :failed ;; ==== (defun testcover-testcase-ab () (list 'a 'b)) @@ -396,9 +387,16 @@ (should (equal '(a b c) (testcover-testcase-dotted-bq nil '(d e)))) (should (equal '(a b c d e) (testcover-testcase-dotted-bq t '(d e)))) +;; ==== quoted-backquote ==== +"Testcover correctly instruments the quoted backquote symbol." +;; ==== +(defun testcover-testcase-special-symbols () + (list '\` '\, '\,@)) + +(should (equal '(\` \, \,@) (testcover-testcase-special-symbols))) + ;; ==== backquoted-vector-bug-25316 ==== "Testcover reinstruments within backquoted vectors." -:expected-result :failed ;; ==== (defun testcover-testcase-vec (a b c) `[,a%%% ,(list b%%% c%%%)%%%]%%%) @@ -415,7 +413,6 @@ ;; ==== vector-in-macro-spec-bug-25316 ==== "Testcover reinstruments within vectors." -:expected-result :failed ;; ==== (defmacro testcover-testcase-nth-case (arg vec) (declare (indent 1) @@ -435,7 +432,6 @@ ;; ==== mapcar-is-not-compose ==== "Mapcar with 1value arguments is not 1value." -:expected-result :failed ;; ==== (defvar testcover-testcase-num 0) (defun testcover-testcase-add-num (n) @@ -450,10 +446,10 @@ ;; ==== function-with-edebug-spec-bug-25316 ==== "Functions can have edebug specs too. -See c-make-font-lock-search-function for an example in the Emacs -sources. The other issue is that it's ok to use quote in an -edebug spec, so testcover needs to cope with that." -:expected-result :failed +See `c-make-font-lock-search-function' for an example in the +Emacs sources. `c-make-font-lock-search-function''s Edebug spec +also contains a quote. See comment in `testcover-analyze-coverage' +regarding the odd-looking coverage result for the quoted form." ;; ==== (defun testcover-testcase-make-function (forms) `(lambda (flag) (if flag 0 ,@forms%%%))%%%) @@ -462,7 +458,7 @@ edebug spec, so testcover needs to cope with that." (("quote" (&rest def-form)))) (defun testcover-testcase-thing () - (testcover-testcase-make-function '((+ 1 (+ 2 (+ 3 (+ 4 5))))))%%%) + (testcover-testcase-make-function '(!!!(+ 1 !!!(+ 2 !!!(+ 3 !!!(+ 4 5)%%%)%%%)%%%)%%%))%%%) (defun testcover-testcase-use-thing () (funcall (testcover-testcase-thing)%%% nil)%%%) @@ -490,4 +486,22 @@ edebug spec, so testcover needs to cope with that." (should (eq (testcover-testcase-how-do-i-know-you "Liz") 'unknown)) +;; ==== circular-lists-bug-24402 ==== +"Testcover captures and ignores circular list errors." +;; ==== +(defun testcover-testcase-cyc1 (a) + (let ((ls (make-list 10 a%%%)%%%)) + (nconc ls%%% ls%%%) + ls)) ; The lack of a mark here is due to an ignored circular list error. +(testcover-testcase-cyc1 1) +(testcover-testcase-cyc1 1) +(defun testcover-testcase-cyc2 (a b) + (let ((ls1 (make-list 10 a%%%)%%%) + (ls2 (make-list 10 b))) + (nconc ls2 ls2) + (nconc ls1%%% ls2) + ls1)) +(testcover-testcase-cyc2 1 2) +(testcover-testcase-cyc2 1 4) + ;; testcases.el ends here. diff --git a/test/lisp/emacs-lisp/testcover-tests.el b/test/lisp/emacs-lisp/testcover-tests.el index d31379c3aa2..2e03488b306 100644 --- a/test/lisp/emacs-lisp/testcover-tests.el +++ b/test/lisp/emacs-lisp/testcover-tests.el @@ -17,7 +17,7 @@ ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see `http://www.gnu.org/licenses/'. +;; along with this program. If not, see `https://www.gnu.org/licenses/'. ;;; Commentary: @@ -124,14 +124,12 @@ arguments for `testcover-start'." (save-current-buffer (set-buffer (find-file-noselect tempfile)) ;; Fail the test if the debugger tries to become active, - ;; which will happen if Testcover's reinstrumentation - ;; leaves an edebug-enter in the code. This will also - ;; prevent debugging these tests using Edebug. - (cl-letf (((symbol-function #'edebug-enter) + ;; which can happen if Testcover fails to attach itself + ;; correctly. Note that this will prevent debugging + ;; these tests using Edebug. + (cl-letf (((symbol-function #'edebug-default-enter) (lambda (&rest _args) - (ert-fail - (concat "Debugger invoked during test run " - "(possible edebug-enter not replaced)"))))) + (ert-fail "Debugger invoked during test run")))) (dolist (byte-compile '(t nil)) (testcover-tests-unmarkup-region (point-min) (point-max)) (unwind-protect diff --git a/test/lisp/emacs-lisp/thunk-tests.el b/test/lisp/emacs-lisp/thunk-tests.el index 89bf1f50113..a63ce289e8a 100644 --- a/test/lisp/emacs-lisp/thunk-tests.el +++ b/test/lisp/emacs-lisp/thunk-tests.el @@ -18,7 +18,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: @@ -51,5 +51,55 @@ (thunk-force thunk) (should (= x 1)))) + + +;; thunk-let tests + +(ert-deftest thunk-let-basic-test () + "Test whether bindings are established." + (should (equal (thunk-let ((x 1) (y 2)) (+ x y)) 3))) + +(ert-deftest thunk-let*-basic-test () + "Test whether bindings are established." + (should (equal (thunk-let* ((x 1) (y (+ 1 x))) (+ x y)) 3))) + +(ert-deftest thunk-let-bound-vars-cant-be-set-test () + "Test whether setting a `thunk-let' bound variable fails." + (should-error + (eval '(thunk-let ((x 1)) (let ((y 7)) (setq x (+ x y)) (* 10 x))) t))) + +(ert-deftest thunk-let-laziness-test () + "Test laziness of `thunk-let'." + (should + (equal (let ((x-evalled nil) + (y-evalled nil)) + (thunk-let ((x (progn (setq x-evalled t) (+ 1 2))) + (y (progn (setq y-evalled t) (+ 3 4)))) + (let ((evalled-y y)) + (list x-evalled y-evalled evalled-y)))) + (list nil t 7)))) + +(ert-deftest thunk-let*-laziness-test () + "Test laziness of `thunk-let*'." + (should + (equal (let ((x-evalled nil) + (y-evalled nil) + (z-evalled nil) + (a-evalled nil)) + (thunk-let* ((x (progn (setq x-evalled t) (+ 1 1))) + (y (progn (setq y-evalled t) (+ x 1))) + (z (progn (setq z-evalled t) (+ y 1))) + (a (progn (setq a-evalled t) (+ z 1)))) + (let ((evalled-z z)) + (list x-evalled y-evalled z-evalled a-evalled evalled-z)))) + (list t t t nil 4)))) + +(ert-deftest thunk-let-bad-binding-test () + "Test whether a bad binding causes an error when expanding." + (should-error (macroexpand '(thunk-let ((x 1 1)) x))) + (should-error (macroexpand '(thunk-let (27) x))) + (should-error (macroexpand '(thunk-let x x)))) + + (provide 'thunk-tests) ;;; thunk-tests.el ends here diff --git a/test/lisp/emacs-lisp/timer-tests.el b/test/lisp/emacs-lisp/timer-tests.el index b12a365ff3b..916625cac3a 100644 --- a/test/lisp/emacs-lisp/timer-tests.el +++ b/test/lisp/emacs-lisp/timer-tests.el @@ -15,7 +15,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: |