X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/a9faac5c6333bcbfb30a00debf3de7a44e430e49..418cd7265a941032b467215839b3726b3ba37b0b:/lisp/emacs-lisp/ert.el diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el index 6e543458df..ad5e20cb8a 100644 --- a/lisp/emacs-lisp/ert.el +++ b/lisp/emacs-lisp/ert.el @@ -1,6 +1,6 @@ ;;; ert.el --- Emacs Lisp Regression Testing -;; Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. +;; Copyright (C) 2007-2008, 2010-2012 Free Software Foundation, Inc. ;; Author: Christian Ohler ;; Keywords: lisp, tools @@ -219,7 +219,7 @@ Emacs bug 6581 at URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6581'." ;; This implementation is inefficient. Rather than making it ;; efficient, let's hope bug 6581 gets fixed so that we can delete ;; it altogether. - (not (ert--explain-not-equal-including-properties a b))) + (not (ert--explain-equal-including-properties a b))) ;;; Defining and locating tests. @@ -248,7 +248,7 @@ Emacs bug 6581 at URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6581'." ;; We disallow nil since `ert-test-at-point' and related functions ;; want to return a test name, but also need an out-of-band value ;; on failure. Nil is the most natural out-of-band value; using 0 - ;; or "" or signalling an error would be too awkward. + ;; or "" or signaling an error would be too awkward. ;; ;; Note that nil is still a valid value for the `name' slot in ;; ert-test objects. It designates an anonymous test. @@ -392,7 +392,7 @@ DATA is displayed to the user and should state the reason of the failure." ;; compiling doesn't depend on cl and thus doesn't need an ;; environment arg for `macroexpand'. (if (fboundp 'cl-macroexpand) - ;; Suppress warning about run-time call to cl funtion: we + ;; Suppress warning about run-time call to cl function: we ;; only call it if it's fboundp. (with-no-warnings (cl-macroexpand form (and (boundp 'cl-macro-environment) @@ -448,7 +448,7 @@ arguments: INNER-FORM and FORM-DESCRIPTION-FORM, where INNER-FORM is an expression equivalent to FORM, and FORM-DESCRIPTION-FORM is an expression that returns a description of FORM. INNER-EXPANDER should return code that calls INNER-FORM and performs the checks -and error signalling specific to the particular variant of +and error signaling specific to the particular variant of `should'. The code that INNER-EXPANDER returns must not call FORM-DESCRIPTION-FORM before it has called INNER-FORM." (lexical-let ((inner-expander inner-expander)) @@ -489,17 +489,17 @@ Returns nil." Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES, and aborts the current test as failed if it doesn't." - (let ((signalled-conditions (get (car condition) 'error-conditions)) + (let ((signaled-conditions (get (car condition) 'error-conditions)) (handled-conditions (etypecase type (list type) (symbol (list type))))) - (assert signalled-conditions) - (unless (ert--intersection signalled-conditions handled-conditions) + (assert signaled-conditions) + (unless (ert--intersection signaled-conditions handled-conditions) (ert-fail (append (funcall form-description-fn) (list :condition condition - :fail-reason (concat "the error signalled did not" + :fail-reason (concat "the error signaled did not" " have the expected type"))))) (when exclude-subtypes (unless (member (car condition) handled-conditions) @@ -507,7 +507,7 @@ and aborts the current test as failed if it doesn't." (funcall form-description-fn) (list :condition condition - :fail-reason (concat "the error signalled was a subtype" + :fail-reason (concat "the error signaled was a subtype" " of the expected type")))))))) ;; FIXME: The expansion will evaluate the keyword args (if any) in @@ -515,7 +515,7 @@ and aborts the current test as failed if it doesn't." (defmacro* should-error (form &rest keys &key type exclude-subtypes) "Evaluate FORM and check that it signals an error. -The error signalled needs to match TYPE. TYPE should be a list +The error signaled needs to match TYPE. TYPE should be a list of condition names. (It can also be a non-nil symbol, which is equivalent to a singleton list containing that symbol.) If EXCLUDE-SUBTYPES is nil, the error matches TYPE if one of its @@ -523,7 +523,7 @@ condition names is an element of TYPE. If EXCLUDE-SUBTYPES is non-nil, the error matches TYPE if it is an element of TYPE. If the error matches, returns (ERROR-SYMBOL . DATA) from the -error. If not, or if no error was signalled, abort the test as +error. If not, or if no error was signaled, abort the test as failed." (unless type (setq type ''error)) (ert--expand-should @@ -571,16 +571,14 @@ failed." (when (and (not firstp) (eq fast slow)) (return nil)))) (defun ert--explain-format-atom (x) - "Format the atom X for `ert--explain-not-equal'." + "Format the atom X for `ert--explain-equal'." (typecase x (fixnum (list x (format "#x%x" x) (format "?%c" x))) (t x))) -(defun ert--explain-not-equal (a b) - "Explainer function for `equal'. - -Returns a programmer-readable explanation of why A and B are not -`equal', or nil if they are." +(defun ert--explain-equal-rec (a b) + "Return a programmer-readable explanation of why A and B are not `equal'. +Returns nil if they are." (if (not (equal (type-of a) (type-of b))) `(different-types ,a ,b) (etypecase a @@ -598,13 +596,13 @@ Returns a programmer-readable explanation of why A and B are not (loop for i from 0 for ai in a for bi in b - for xi = (ert--explain-not-equal ai bi) + for xi = (ert--explain-equal-rec ai bi) do (when xi (return `(list-elt ,i ,xi))) finally (assert (equal a b) t))) - (let ((car-x (ert--explain-not-equal (car a) (car b)))) + (let ((car-x (ert--explain-equal-rec (car a) (car b)))) (if car-x `(car ,car-x) - (let ((cdr-x (ert--explain-not-equal (cdr a) (cdr b)))) + (let ((cdr-x (ert--explain-equal-rec (cdr a) (cdr b)))) (if cdr-x `(cdr ,cdr-x) (assert (equal a b) t) @@ -618,7 +616,7 @@ Returns a programmer-readable explanation of why A and B are not (loop for i from 0 for ai across a for bi across b - for xi = (ert--explain-not-equal ai bi) + for xi = (ert--explain-equal-rec ai bi) do (when xi (return `(array-elt ,i ,xi))) finally (assert (equal a b) t)))) (atom (if (not (equal a b)) @@ -627,7 +625,15 @@ Returns a programmer-readable explanation of why A and B are not `(different-atoms ,(ert--explain-format-atom a) ,(ert--explain-format-atom b))) nil))))) -(put 'equal 'ert-explainer 'ert--explain-not-equal) + +(defun ert--explain-equal (a b) + "Explainer function for `equal'." + ;; Do a quick comparison in C to avoid running our expensive + ;; comparison when possible. + (if (equal a b) + nil + (ert--explain-equal-rec a b))) +(put 'equal 'ert-explainer 'ert--explain-equal) (defun ert--significant-plist-keys (plist) "Return the keys of PLIST that have non-null values, in order." @@ -658,8 +664,8 @@ key/value pairs in each list does not matter." (value-b (plist-get b key))) (assert (not (equal value-a value-b)) t) `(different-properties-for-key - ,key ,(ert--explain-not-equal-including-properties value-a - value-b))))) + ,key ,(ert--explain-equal-including-properties value-a + value-b))))) (cond (keys-in-a-not-in-b (explain-with-key (first keys-in-a-not-in-b))) (keys-in-b-not-in-a @@ -681,13 +687,16 @@ If SUFFIXP is non-nil, returns a suffix of S, otherwise a prefix." (t (substring s 0 len))))) -(defun ert--explain-not-equal-including-properties (a b) +;; TODO(ohler): Once bug 6581 is fixed, rename this to +;; `ert--explain-equal-including-properties-rec' and add a fast-path +;; wrapper like `ert--explain-equal'. +(defun ert--explain-equal-including-properties (a b) "Explainer function for `ert-equal-including-properties'. Returns a programmer-readable explanation of why A and B are not `ert-equal-including-properties', or nil if they are." (if (not (equal a b)) - (ert--explain-not-equal a b) + (ert--explain-equal a b) (assert (stringp a) t) (assert (stringp b) t) (assert (eql (length a) (length b)) t) @@ -713,7 +722,7 @@ Returns a programmer-readable explanation of why A and B are not ))) (put 'ert-equal-including-properties 'ert-explainer - 'ert--explain-not-equal-including-properties) + 'ert--explain-equal-including-properties) ;;; Implementation of `ert-info'. @@ -853,7 +862,7 @@ run. DEBUGGER-ARGS are the arguments to `debugger'." (make-ert-test-failed :condition condition :backtrace backtrace :infos infos)))) - ;; Work around Emacs' heuristic (in eval.c) for detecting + ;; Work around Emacs's heuristic (in eval.c) for detecting ;; errors in the debugger. (incf num-nonmacro-input-events) ;; FIXME: We should probably implement more fine-grained @@ -1010,36 +1019,36 @@ t -- Always matches. (ert-test-result-type-p result (ert-test-expected-result-type test))) (defun ert-select-tests (selector universe) - "Return the tests that match SELECTOR. + "Return a list of tests that match SELECTOR. -UNIVERSE specifies the set of tests to select from; it should be -a list of tests, or t, which refers to all tests named by symbols -in `obarray'. +UNIVERSE specifies the set of tests to select from; it should be a list +of tests, or t, which refers to all tests named by symbols in `obarray'. -Returns the set of tests as a list. +Valid SELECTORs: -Valid selectors: - -nil -- Selects the empty set. -t -- Selects UNIVERSE. +nil -- Selects the empty set. +t -- Selects UNIVERSE. :new -- Selects all tests that have not been run yet. -:failed, :passed -- Select tests according to their most recent result. +:failed, :passed -- Select tests according to their most recent result. :expected, :unexpected -- Select tests according to their most recent result. -a string -- Selects all tests that have a name that matches the string, - a regexp. -a test -- Selects that test. +a string -- A regular expression selecting all tests with matching names. +a test -- (i.e., an object of the ert-test data-type) Selects that test. a symbol -- Selects the test that the symbol names, errors if none. -\(member TESTS...\) -- Selects TESTS, a list of tests or symbols naming tests. +\(member TESTS...) -- Selects the elements of TESTS, a list of tests + or symbols naming tests. \(eql TEST\) -- Selects TEST, a test or a symbol naming a test. -\(and SELECTORS...\) -- Selects the tests that match all SELECTORS. -\(or SELECTORS...\) -- Selects the tests that match any SELECTOR. -\(not SELECTOR\) -- Selects all tests that do not match SELECTOR. +\(and SELECTORS...) -- Selects the tests that match all SELECTORS. +\(or SELECTORS...) -- Selects the tests that match any of the SELECTORS. +\(not SELECTOR) -- Selects all tests that do not match SELECTOR. \(tag TAG) -- Selects all tests that have TAG on their tags list. -\(satisfies PREDICATE\) -- Selects all tests that satisfy PREDICATE. + A tag is an arbitrary label you can apply when you define a test. +\(satisfies PREDICATE) -- Selects all tests that satisfy PREDICATE. + PREDICATE is a function that takes an ert-test object as argument, + and returns non-nil if it is selected. Only selectors that require a superset of tests, such as (satisfies ...), strings, :new, etc. make use of UNIVERSE. -Selectors that do not, such as \(member ...\), just return the +Selectors that do not, such as (member ...), just return the set implied by them without checking whether it is really contained in UNIVERSE." ;; This code needs to match the etypecase in @@ -1244,12 +1253,14 @@ Also changes the counters in STATS to match." (ert-test-passed (incf (ert--stats-passed-expected stats) d)) (ert-test-failed (incf (ert--stats-failed-expected stats) d)) (null) - (ert-test-aborted-with-non-local-exit)) + (ert-test-aborted-with-non-local-exit) + (ert-test-quit)) (etypecase (aref results pos) (ert-test-passed (incf (ert--stats-passed-unexpected stats) d)) (ert-test-failed (incf (ert--stats-failed-unexpected stats) d)) (null) - (ert-test-aborted-with-non-local-exit))))) + (ert-test-aborted-with-non-local-exit) + (ert-test-quit))))) ;; Adjust counters to remove the result that is currently in stats. (update -1) ;; Put new test and result into stats. @@ -1342,7 +1353,8 @@ EXPECTEDP specifies whether the result was expected." (ert-test-passed ".P") (ert-test-failed "fF") (null "--") - (ert-test-aborted-with-non-local-exit "aA")))) + (ert-test-aborted-with-non-local-exit "aA") + (ert-test-quit "qQ")))) (elt s (if expectedp 0 1)))) (defun ert-string-for-test-result (result expectedp) @@ -1353,7 +1365,8 @@ EXPECTEDP specifies whether the result was expected." (ert-test-passed '("passed" "PASSED")) (ert-test-failed '("failed" "FAILED")) (null '("unknown" "UNKNOWN")) - (ert-test-aborted-with-non-local-exit '("aborted" "ABORTED"))))) + (ert-test-aborted-with-non-local-exit '("aborted" "ABORTED")) + (ert-test-quit '("quit" "QUIT"))))) (elt s (if expectedp 0 1)))) (defun ert--pp-with-indentation-and-newline (object) @@ -1392,7 +1405,7 @@ RESULT must be an `ert-test-result-with-condition'." ;;; Running tests in batch mode. (defvar ert-batch-backtrace-right-margin 70 - "*The maximum line length for printing backtraces in `ert-run-tests-batch'.") + "The maximum line length for printing backtraces in `ert-run-tests-batch'.") ;;;###autoload (defun ert-run-tests-batch (&optional selector) @@ -1468,9 +1481,8 @@ Returns the stats object." (let ((print-escape-newlines t) (print-level 5) (print-length 10)) - (let ((begin (point))) - (ert--pp-with-indentation-and-newline - (ert-test-result-with-condition-condition result)))) + (ert--pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result))) (goto-char (1- (point-max))) (assert (looking-at "\n")) (delete-char 1) @@ -1478,7 +1490,9 @@ Returns the stats object." (message "%s" (buffer-string)))) (ert-test-aborted-with-non-local-exit (message "Test %S aborted with non-local exit" - (ert-test-name test))))) + (ert-test-name test))) + (ert-test-quit + (message "Quit during %S" (ert-test-name test))))) (let* ((max (prin1-to-string (length (ert--stats-tests stats)))) (format-string (concat "%9s %" (prin1-to-string (length max)) @@ -1587,7 +1601,7 @@ Nothing more than an interactive interface to `ert-make-test-unbound'." (defun ert-delete-all-tests () "Make all symbols in `obarray' name no test." (interactive) - (when (interactive-p) + (when (called-interactively-p 'any) (unless (y-or-n-p "Delete all tests? ") (error "Aborted"))) ;; We can't use `ert-select-tests' here since that gives us only @@ -1777,7 +1791,7 @@ EWOC and STATS are arguments for `ert--results-update-stats-display'." BEGIN and END specify a region in the current buffer." (save-excursion (save-restriction - (narrow-to-region begin (point)) + (narrow-to-region begin end) ;; Inhibit optimization in `debugger-make-xrefs' that would ;; sometimes insert unrelated backtrace info into our buffer. (let ((debugger-previous-backtrace nil)) @@ -1853,7 +1867,9 @@ non-nil, returns the face for expected results.." (ert-test-result-with-condition-condition result)) (ert--make-xrefs-region begin (point))))) (ert-test-aborted-with-non-local-exit - (insert " aborted\n"))) + (insert " aborted\n")) + (ert-test-quit + (insert " quit\n"))) (insert "\n"))))) nil) @@ -1874,7 +1890,6 @@ BUFFER-NAME, if non-nil, is the buffer name to use." (unless buffer-name (setq buffer-name "*ert*")) (let ((buffer (get-buffer-create buffer-name))) (with-current-buffer buffer - (setq buffer-read-only t) (let ((inhibit-read-only t)) (buffer-disable-undo) (erase-buffer) @@ -1997,19 +2012,12 @@ and how to display message." ;;; Simple view mode for auxiliary information like stack traces or ;;; messages. Mainly binds "q" for quit. -(define-derived-mode ert-simple-view-mode fundamental-mode "ERT-View" +(define-derived-mode ert-simple-view-mode special-mode "ERT-View" "Major mode for viewing auxiliary information in ERT.") -(loop for (key binding) in - '(("q" quit-window) - ) - do - (define-key ert-simple-view-mode-map key binding)) - - ;;; Commands and button actions for the results buffer. -(define-derived-mode ert-results-mode fundamental-mode "ERT-Results" +(define-derived-mode ert-results-mode special-mode "ERT-Results" "Major mode for viewing results of ERT test runs.") (loop for (key binding) in @@ -2017,7 +2025,6 @@ and how to display message." ("\t" forward-button) ([backtab] backward-button) ("j" ert-results-jump-between-summary-and-result) - ("q" quit-window) ("L" ert-results-toggle-printer-limits-for-test-at-point) ("n" ert-results-next-test) ("p" ert-results-previous-test) @@ -2113,7 +2120,7 @@ To be used in the ERT results buffer." EWOC-FN specifies the direction and should be either `ewoc-prev' or `ewoc-next'. If there are no more nodes in that direction, an -error is signalled with the message ERROR-MESSAGE." +error is signaled with the message ERROR-MESSAGE." (loop (setq node (funcall ewoc-fn ert--results-ewoc node)) (when (null node) @@ -2349,7 +2356,6 @@ To be used in the ERT results buffer." (let ((backtrace (ert-test-result-with-condition-backtrace result)) (buffer (get-buffer-create "*ERT Backtrace*"))) (pop-to-buffer buffer) - (setq buffer-read-only t) (let ((inhibit-read-only t)) (buffer-disable-undo) (erase-buffer) @@ -2375,7 +2381,6 @@ To be used in the ERT results buffer." (result (aref (ert--stats-test-results stats) pos))) (let ((buffer (get-buffer-create "*ERT Messages*"))) (pop-to-buffer buffer) - (setq buffer-read-only t) (let ((inhibit-read-only t)) (buffer-disable-undo) (erase-buffer) @@ -2397,7 +2402,6 @@ To be used in the ERT results buffer." (result (aref (ert--stats-test-results stats) pos))) (let ((buffer (get-buffer-create "*ERT list of should forms*"))) (pop-to-buffer buffer) - (setq buffer-read-only t) (let ((inhibit-read-only t)) (buffer-disable-undo) (erase-buffer) @@ -2451,7 +2455,6 @@ To be used in the ERT results buffer." (setq data (sort data (lambda (a b) (> (second a) (second b))))) (pop-to-buffer buffer) - (setq buffer-read-only t) (let ((inhibit-read-only t)) (buffer-disable-undo) (erase-buffer)