diff tests/automated/test-harness.el @ 5125:b5df3737028a ben-lisp-object

merge
author Ben Wing <ben@xemacs.org>
date Wed, 24 Feb 2010 01:58:04 -0600
parents e813cf16c015
children 3daf9fc57cd4
line wrap: on
line diff
--- a/tests/automated/test-harness.el	Wed Jan 20 07:05:57 2010 -0600
+++ b/tests/automated/test-harness.el	Wed Feb 24 01:58:04 2010 -0600
@@ -1,7 +1,7 @@
 ;; test-harness.el --- Run Emacs Lisp test suites.
 
 ;;; Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
-;;; Copyright (C) 2002 Ben Wing.
+;;; Copyright (C) 2002, 2010 Ben Wing.
 
 ;; Author: Martin Buchholz
 ;; Maintainer: Stephen J. Turnbull <stephen@xemacs.org>
@@ -115,6 +115,12 @@
 	  (length "byte-compiler-tests.el:")) ; use the longest file name
   "Format for \"No tests\" lines printed after a file is run.")
 
+(defconst test-harness-aborted-summary-template
+  (format "%%-%ds          %%%dd tests completed (aborted)."
+	  (length "byte-compiler-tests.el:") ; use the longest file name
+	  5)
+  "Format for summary lines printed after a test run on a file was aborted.")
+
 ;;;###autoload
 (defun test-emacs-test-file (filename)
   "Test a file of Lisp code named FILENAME.
@@ -209,12 +215,20 @@
       (defconst test-harness-failure-tag "FAIL")
       (defconst test-harness-success-tag "PASS")
 
+;;;;; BEGIN DEFINITION OF MACROS USEFUL IN TEST CODE
+
       (defmacro Known-Bug-Expect-Failure (&rest body)
+	"Wrap a BODY that consists of tests that are known to fail.
+This causes messages to be printed on failure indicating that this is expected,
+and on success indicating that this is unexpected."
 	`(let ((test-harness-failure-tag "KNOWN BUG")
 	       (test-harness-success-tag "PASS (FAILURE EXPECTED)"))
 	  ,@body))
 
       (defmacro Known-Bug-Expect-Error (expected-error &rest body)
+	"Wrap a BODY that consists of tests that are known to trigger an error.
+This causes messages to be printed on failure indicating that this is expected,
+and on success indicating that this is unexpected."
 	(let ((quoted-body (if (= 1 (length body))
 			       `(quote ,(car body)) `(quote (progn ,@body)))))
           `(let ((test-harness-failure-tag "KNOWN BUG")
@@ -237,6 +251,10 @@
                (incf wrong-error-failures))))))
 
       (defmacro Implementation-Incomplete-Expect-Failure (&rest body)
+	"Wrap a BODY containing tests that are known to fail due to incomplete code.
+This causes messages to be printed on failure indicating that the
+implementation is incomplete (and hence the failure is expected); and on
+success indicating that this is unexpected."
 	`(let ((test-harness-failure-tag "IMPLEMENTATION INCOMPLETE")
 	       (test-harness-success-tag "PASS (FAILURE EXPECTED)"))
 	  ,@body))
@@ -269,28 +287,118 @@
 
       (defmacro Assert (assertion &optional failing-case description)
 	"Test passes if ASSERTION is true.
-Optional FAILING-CASE describes the particular failure.
-Optional DESCRIPTION describes the assertion.
-FAILING-CASE and DESCRIPTION are useful when Assert is used in a loop."
-	`(condition-case error-info
-	  (progn
-	    (assert ,assertion)
-	    (Print-Pass "%S" (quote ,(or description assertion)))
-	    (incf passes))
-	  (cl-assertion-failed
-	   (Print-Failure (if ,failing-case
-			      "Assertion failed: %S; failing case = %S"
-			    "Assertion failed: %S")
-			  (quote ,(or description assertion)) ,failing-case)
-	   (incf assertion-failures))
-	  (t (Print-Failure (if ,failing-case
-				"%S ==> error: %S; failing case =  %S"
-			      "%S ==> error: %S")
-			    (quote ,(or description assertion))
-			    error-info ,failing-case)
-	     (incf other-failures)
-	     )))
+Optional FAILING-CASE describes the particular failure.  Optional
+DESCRIPTION describes the assertion; by default, the unevalated assertion
+expression is given.  FAILING-CASE and DESCRIPTION are useful when Assert
+is used in a loop."
+	(let ((description
+	       (or description `(quote ,assertion))))
+	  `(condition-case error-info
+	    (progn
+	      (assert ,assertion)
+	      (Print-Pass "%S" ,description)
+	      (incf passes))
+	    (cl-assertion-failed
+	     (Print-Failure (if ,failing-case
+				"Assertion failed: %S; failing case = %S"
+			      "Assertion failed: %S")
+			    ,description ,failing-case)
+	     (incf assertion-failures))
+	    (t (Print-Failure (if ,failing-case
+				  "%S ==> error: %S; failing case =  %S"
+				"%S ==> error: %S")
+			      ,description error-info ,failing-case)
+	       (incf other-failures)
+	       ))))
+
+;;;;; BEGIN DEFINITION OF SPECIFIC KINDS OF ASSERT MACROS
+
+      (defmacro Assert-test (test testval expected &optional failing-case
+			     description)
+	"Test passes if TESTVAL compares correctly to EXPECTED using TEST.
+TEST should be a two-argument predicate (i.e. a function of two arguments
+that returns t or nil), such as `eq', `eql', `equal', `equalp', `=', `<=',
+'>', 'file-newer-than-file-p' etc.  Optional FAILING-CASE describes the
+particular failure; any value given here will be concatenated with a phrase
+describing the expected and actual values of the comparison.  Optional
+DESCRIPTION describes the assertion; by default, the unevalated comparison
+expressions are given.  FAILING-CASE and DESCRIPTION are useful when Assert
+is used in a loop."
+	(let* ((assertion `(,test ,testval ,expected))
+	       (failmsg `(format "%S should be `%s' to %S but isn't"
+			  ,testval ',test ,expected))
+	       (failmsg2 (if failing-case `(concat 
+					   (format "%S, " ,failing-case)
+					   ,failmsg)
+			  failmsg)))
+	  `(Assert ,assertion ,failmsg2 ,description)))
 
+      (defmacro Assert-test-not (test testval expected &optional failing-case
+				 description)
+	"Test passes if TESTVAL does not compare correctly to EXPECTED using TEST.
+TEST should be a two-argument predicate (i.e. a function of two arguments
+that returns t or nil), such as `eq', `eql', `equal', `equalp', `=', `<=',
+'>', 'file-newer-than-file-p' etc.  Optional FAILING-CASE describes the
+particular failure; any value given here will be concatenated with a phrase
+describing the expected and actual values of the comparison.  Optional
+DESCRIPTION describes the assertion; by default, the unevalated comparison
+expressions are given.  FAILING-CASE and DESCRIPTION are useful when Assert
+is used in a loop."
+	(let* ((assertion `(not (,test ,testval ,expected)))
+	       (failmsg `(format "%S shouldn't be `%s' to %S but is"
+			  ,testval ',test ,expected))
+	       (failmsg2 (if failing-case `(concat 
+					   (format "%S, " ,failing-case)
+					   ,failmsg)
+			  failmsg)))
+	  `(Assert ,assertion ,failmsg2 ,description)))
+
+      ;; Specific versions of `Assert-test'.  These are just convenience
+      ;; functions, functioning identically to `Assert-test', and duplicating
+      ;; the doc string for each would be too annoying.
+      (defmacro Assert-eq (testval expected &optional failing-case
+			   description)
+	`(Assert-test eq ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-eql (testval expected &optional failing-case
+			    description)
+	`(Assert-test eql ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-equal (testval expected &optional failing-case
+			      description)
+	`(Assert-test equal ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-equalp (testval expected &optional failing-case
+			      description)
+	`(Assert-test equalp ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-string= (testval expected &optional failing-case
+			      description)
+	`(Assert-test string= ,testval ,expected ,failing-case ,description))
+      (defmacro Assert= (testval expected &optional failing-case
+			 description)
+	`(Assert-test = ,testval ,expected ,failing-case ,description))
+      (defmacro Assert<= (testval expected &optional failing-case
+			  description)
+	`(Assert-test <= ,testval ,expected ,failing-case ,description))
+
+      ;; Specific versions of `Assert-test-not'.  These are just convenience
+      ;; functions, functioning identically to `Assert-test-not', and
+      ;; duplicating the doc string for each would be too annoying.
+      (defmacro Assert-not-eq (testval expected &optional failing-case
+			       description)
+	`(Assert-test-not eq ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-not-eql (testval expected &optional failing-case
+				description)
+	`(Assert-test-not eql ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-not-equal (testval expected &optional failing-case
+				  description)
+	`(Assert-test-not equal ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-not-equalp (testval expected &optional failing-case
+				   description)
+	`(Assert-test-not equalp ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-not-string= (testval expected &optional failing-case
+				    description)
+	`(Assert-test-not string= ,testval ,expected ,failing-case ,description))
+      (defmacro Assert-not= (testval expected &optional failing-case
+			     description)
+	`(Assert-test-not = ,testval ,expected ,failing-case ,description))
 
       (defmacro Check-Error (expected-error &rest body)
 	(let ((quoted-body (if (= 1 (length body))
@@ -396,7 +504,7 @@
 	 (princ (format "Unexpected error %S while executing interpreted code\n"
 		error-info))
 	 (message "Unexpected error %S while executing interpreted code." error-info)
-	 (message "Test suite execution aborted." error-info)
+	 (message "Test suite execution aborted.")
 	 ))
       (princ "\nTesting Compiled Lisp\n\n")
       (let (code
@@ -417,7 +525,7 @@
 	   (princ (format "Unexpected error %S while executing byte-compiled code\n"
 			  error-info))
 	   (message "Unexpected error %S while executing byte-compiled code." error-info)
-	   (message "Test suite execution aborted." error-info)
+	   (message "Test suite execution aborted.")
 	   )))
       (princ (format "\nSUMMARY for %s:\n" filename))
       (princ (format "\t%5d passes\n" passes))
@@ -434,12 +542,16 @@
 		       other-failures))
 	     (basename (file-name-nondirectory filename))
 	     (summary-msg
-	      (if (> total 0)
-		  (format test-harness-file-summary-template
-			  (concat basename ":")
-			  passes total (/ (* 100 passes) total))
-		(format test-harness-null-summary-template
-			(concat basename ":"))))
+	      (cond ((> unexpected-test-file-failures 0)
+		     (format test-harness-aborted-summary-template
+			     (concat basename ":") total))
+		    ((> total 0)
+		     (format test-harness-file-summary-template
+			     (concat basename ":")
+			     passes total (/ (* 100 passes) total)))
+		    (t
+		     (format test-harness-null-summary-template
+			     (concat basename ":")))))
 	     (reasons ""))
 	(maphash (lambda (key value)
 		   (setq reasons
@@ -530,7 +642,10 @@
 Use this from the command line, with `-batch';
 it won't work in an interactive Emacs.
 Each file is processed even if an error occurred previously.
-For example, invoke \"xemacs -batch -f batch-test-emacs tests/*.el\""
+A directory can be given as well, and all files will be processed --
+however, the file test-harness.el, which implements the test harness,
+will be skipped.
+For example, invoke \"xemacs -batch -f batch-test-emacs tests\""
   ;; command-line-args-left is what is left of the command line (from
   ;; startup.el)
   (defvar command-line-args-left)	;Avoid 'free variable' warning
@@ -579,14 +694,19 @@
 		 (basename (file-name-nondirectory (first head)))
 		 (nsucc (second head))
 		 (ntest (third head)))
-	    (if (> ntest 0)
-		(message test-harness-file-summary-template
-			 (concat basename ":")
-			 nsucc
-			 ntest
-			 (/ (* 100 nsucc) ntest))
-	      (message test-harness-null-summary-template
-		       (concat basename ":")))
+	    (cond ((member (first head) unexpected-test-suite-failure-files)
+		   (message test-harness-aborted-summary-template
+			    (concat basename ":")
+			    ntest))
+		  ((> ntest 0)
+		   (message test-harness-file-summary-template
+			    (concat basename ":")
+			    nsucc
+			    ntest
+			    (/ (* 100 nsucc) ntest)))
+		  (t
+		   (message test-harness-null-summary-template
+			    (concat basename ":"))))
 	    (setq results (cdr results)))))
       (when (> unexpected-test-suite-failures 0)
 	(message "\n***** There %s %d unexpected test suite %s in %s:"