PageRenderTime 68ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/lisp/test-harness.el

https://bitbucket.org/jsparkes/xemacs-gtk
Emacs Lisp | 772 lines | 623 code | 73 blank | 76 comment | 20 complexity | bb92db5699063dced4a8ee0ff05ab6f5 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. ;; test-harness.el --- Run Emacs Lisp test suites.
  2. ;;; Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
  3. ;;; Copyright (C) 2002, 2010 Ben Wing.
  4. ;; Author: Martin Buchholz
  5. ;; Maintainer: Stephen J. Turnbull <stephen@xemacs.org>
  6. ;; Keywords: testing
  7. ;; This file is part of XEmacs.
  8. ;; XEmacs is free software: you can redistribute it and/or modify it
  9. ;; under the terms of the GNU General Public License as published by the
  10. ;; Free Software Foundation, either version 3 of the License, or (at your
  11. ;; option) any later version.
  12. ;; XEmacs is distributed in the hope that it will be useful, but WITHOUT
  13. ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15. ;; for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with XEmacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Synched up with: Not in FSF.
  19. ;;; Commentary:
  20. ;;; A test suite harness for testing XEmacs.
  21. ;;; The actual tests are in other files in this directory.
  22. ;;; Basically you just create files of emacs-lisp, and use the
  23. ;;; Assert, Check-Error, Check-Message, and Check-Error-Message functions
  24. ;;; to create tests. See `test-harness-from-buffer' below.
  25. ;;; Don't suppress tests just because they're due to known bugs not yet
  26. ;;; fixed -- use the Known-Bug-Expect-Failure and
  27. ;;; Implementation-Incomplete-Expect-Failure wrapper macros to mark them.
  28. ;;; A lot of the tests we run push limits; suppress Ebola message with the
  29. ;;; Ignore-Ebola wrapper macro.
  30. ;;; Some noisy code will call `message'. Output from `message' can be
  31. ;;; suppressed with the Silence-Message macro. Functions that are known to
  32. ;;; issue messages include `write-region', `find-tag', `tag-loop-continue',
  33. ;;; `insert', and `mark-whole-buffer'. N.B. The Silence-Message macro
  34. ;;; currently does not suppress the newlines printed by `message'.
  35. ;;; Definitely do not use Silence-Message with Check-Message.
  36. ;;; In general it should probably only be used on code that prepares for a
  37. ;;; test, not on tests.
  38. ;;;
  39. ;;; You run the tests using M-x test-emacs-test-file,
  40. ;;; or $(EMACS) -batch -l test-harness -f batch-test-emacs file ...
  41. ;;; which is run for you by the `make check' target in the top-level Makefile.
  42. (require 'bytecomp)
  43. (defvar unexpected-test-suite-failures 0
  44. "Cumulative number of unexpected failures since test-harness was loaded.
  45. \"Unexpected failures\" are those caught by a generic handler established
  46. outside of the test context. As such they involve an abort of the test
  47. suite for the file being tested.
  48. They often occur during preparation of a test or recording of the results.
  49. For example, an executable used to generate test data might not be present
  50. on the system, or a system error might occur while reading a data file.")
  51. (defvar unexpected-test-suite-failure-files nil
  52. "List of test files causing unexpected failures.")
  53. ;; Declared for dynamic scope; _do not_ initialize here.
  54. (defvar unexpected-test-file-failures)
  55. (defvar test-harness-bug-expected nil
  56. "Non-nil means a bug is expected; backtracing/debugging should not happen.
  57. However, the individual test summary should be printed.")
  58. (defvar test-harness-test-compiled nil
  59. "Non-nil means the test code was compiled before execution.
  60. You probably should not make tests depend on compilation.
  61. However, it can be useful to conditionally change messages based on whether
  62. the code was compiled or not. For example, the case that motivated the
  63. implementation of this variable:
  64. \(when test-harness-test-compiled
  65. ;; this ha-a-ack depends on the failing compiled test coming last
  66. \(setq test-harness-failure-tag
  67. \"KNOWN BUG - fix reverted; after 2003-10-31 notify stephen\n\"))")
  68. (defvar test-harness-verbose
  69. (and (not noninteractive) (> (device-baud-rate) search-slow-speed))
  70. "*Non-nil means print messages describing progress of emacs-tester.")
  71. (defvar test-harness-unexpected-error-enter-debugger debug-on-error
  72. "*Non-nil means enter debugger when an unexpected error occurs.
  73. Only applies interactively. Normally true if `debug-on-error' has been set.
  74. See also `test-harness-assertion-failure-enter-debugger' and
  75. `test-harness-unexpected-error-show-backtrace'.")
  76. (defvar test-harness-assertion-failure-enter-debugger debug-on-error
  77. "*Non-nil means enter debugger when an assertion failure occurs.
  78. Only applies interactively. Normally true if `debug-on-error' has been set.
  79. See also `test-harness-unexpected-error-enter-debugger' and
  80. `test-harness-assertion-failure-show-backtrace'.")
  81. (defvar test-harness-unexpected-error-show-backtrace t
  82. "*Non-nil means show backtrace upon unexpected error.
  83. Only applies when debugger is not entered. Normally true by default. See also
  84. `test-harness-unexpected-error-enter-debugger' and
  85. `test-harness-assertion-failure-show-backtrace'.")
  86. (defvar test-harness-assertion-failure-show-backtrace stack-trace-on-error
  87. "*Non-nil means show backtrace upon assertion failure.
  88. Only applies when debugger is not entered. Normally true if
  89. `stack-trace-on-error' has been set. See also
  90. `test-harness-assertion-failure-enter-debugger' and
  91. `test-harness-unexpected-error-show-backtrace'.")
  92. (defvar test-harness-file-results-alist nil
  93. "Each element is a list (FILE SUCCESSES TESTS).
  94. The order is the reverse of the order in which tests are run.
  95. FILE is a string naming the test file.
  96. SUCCESSES is a non-negative integer, the number of successes.
  97. TESTS is a non-negative integer, the number of tests run.")
  98. (defvar test-harness-risk-infloops nil
  99. "*Non-nil to run tests that may loop infinitely in buggy implementations.")
  100. (defvar test-harness-current-file nil)
  101. (defvar emacs-lisp-file-regexp "\\.el\\'"
  102. "*Regexp which matches Emacs Lisp source files.")
  103. (defconst test-harness-file-summary-template
  104. (format "%%-%ds %%%dd of %%%dd tests successful (%%3d%%%%)."
  105. (length "byte-compiler-tests.el:") ; use the longest file name
  106. 5
  107. 5)
  108. "Format for summary lines printed after each file is run.")
  109. (defconst test-harness-null-summary-template
  110. (format "%%-%ds No tests run."
  111. (length "byte-compiler-tests.el:")) ; use the longest file name
  112. "Format for \"No tests\" lines printed after a file is run.")
  113. (defconst test-harness-aborted-summary-template
  114. (format "%%-%ds %%%dd tests completed (aborted)."
  115. (length "byte-compiler-tests.el:") ; use the longest file name
  116. 5)
  117. "Format for summary lines printed after a test run on a file was aborted.")
  118. ;;;###autoload
  119. (defun test-emacs-test-file (filename)
  120. "Test a file of Lisp code named FILENAME.
  121. The output file's name is made by appending `c' to the end of FILENAME."
  122. (interactive
  123. (let ((file buffer-file-name)
  124. (file-name nil)
  125. (file-dir nil))
  126. (and file
  127. (eq (cdr (assq 'major-mode (buffer-local-variables)))
  128. 'emacs-lisp-mode)
  129. (setq file-name (file-name-nondirectory file)
  130. file-dir (file-name-directory file)))
  131. (list (read-file-name "Test file: " file-dir nil nil file-name))))
  132. ;; Expand now so we get the current buffer's defaults
  133. (setq filename (expand-file-name filename))
  134. ;; If we're testing a file that's in a buffer and is modified, offer
  135. ;; to save it first.
  136. (or noninteractive
  137. (let ((b (get-file-buffer (expand-file-name filename))))
  138. (if (and b (buffer-modified-p b)
  139. (y-or-n-p (format "save buffer %s first? " (buffer-name b))))
  140. (save-excursion (set-buffer b) (save-buffer)))))
  141. (if (or noninteractive test-harness-verbose)
  142. (message "Testing %s..." filename))
  143. (let ((test-harness-current-file filename)
  144. input-buffer)
  145. (save-excursion
  146. (setq input-buffer (get-buffer-create " *Test Input*"))
  147. (set-buffer input-buffer)
  148. (erase-buffer)
  149. (insert-file-contents filename)
  150. ;; Run hooks including the uncompression hook.
  151. ;; If they change the file name, then change it for the output also.
  152. (let ((buffer-file-name filename)
  153. (default-major-mode 'emacs-lisp-mode)
  154. (enable-local-eval nil))
  155. (normal-mode)
  156. (setq filename buffer-file-name)))
  157. (test-harness-from-buffer input-buffer filename)
  158. (kill-buffer input-buffer)
  159. ))
  160. (defsubst test-harness-backtrace ()
  161. "Display a reasonable-size backtrace."
  162. (let ((print-escape-newlines t)
  163. (print-length 50))
  164. (backtrace nil t)))
  165. (defsubst test-harness-assertion-failure-do-debug (error-info)
  166. "Maybe enter debugger or display a backtrace on assertion failure.
  167. ERROR-INFO is a cons of the args (SIG . DATA) that were passed to `signal'.
  168. The debugger will be entered if noninteractive and
  169. `test-harness-unexpected-error-enter-debugger' is non-nil; else, a
  170. backtrace will be displayed if `test-harness-unexpected-error-show-backtrace'
  171. is non-nil."
  172. (when (not test-harness-bug-expected)
  173. (cond ((and (not noninteractive)
  174. test-harness-assertion-failure-enter-debugger)
  175. (funcall debugger 'error error-info))
  176. (test-harness-assertion-failure-show-backtrace
  177. (test-harness-backtrace)))))
  178. (defsubst test-harness-unexpected-error-do-debug (error-info)
  179. "Maybe enter debugger or display a backtrace on unexpected error.
  180. ERROR-INFO is a cons of the args (SIG . DATA) that were passed to `signal'.
  181. The debugger will be entered if noninteractive and
  182. `test-harness-unexpected-error-enter-debugger' is non-nil; else, a
  183. backtrace will be displayed if `test-harness-unexpected-error-show-backtrace'
  184. is non-nil."
  185. (when (not test-harness-bug-expected)
  186. (cond ((and (not noninteractive)
  187. test-harness-unexpected-error-enter-debugger)
  188. (funcall debugger 'error error-info))
  189. (test-harness-unexpected-error-show-backtrace
  190. (test-harness-backtrace)))))
  191. (defsubst test-harness-unexpected-error-condition-handler (error-info context-msg)
  192. "Condition handler for when unexpected errors occur.
  193. Useful in conjunction with `call-with-condition-handler'. ERROR-INFO is the
  194. value passed to the condition handler. CONTEXT-MSG is a string indicating
  195. the context in which the unexpected error occurred. A message is outputted
  196. including CONTEXT-MSG in it, `unexpected-test-file-failures' is incremented,
  197. and `test-harness-unexpected-error-do-debug' is called, which may enter the
  198. debugger or output a backtrace, depending on the settings of
  199. `test-harness-unexpected-error-enter-debugger' and
  200. `test-harness-unexpected-error-show-backtrace'.
  201. The function returns normally, which causes error-handling processing to
  202. continue; if you want to catch the error, you also need to wrap everything
  203. in `condition-case'. See also `test-harness-error-wrap', which does this
  204. wrapping."
  205. (incf unexpected-test-file-failures)
  206. (princ (format "Unexpected error %S while %s\n"
  207. error-info context-msg))
  208. (message "Unexpected error %S while %s." error-info context-msg)
  209. (test-harness-unexpected-error-do-debug error-info))
  210. (defmacro test-harness-error-wrap (context-msg abort-msg &rest body)
  211. "Wrap BODY so that unexpected errors are caught.
  212. The debugger will be entered if noninteractive and
  213. `test-harness-unexpected-error-enter-debugger' is non-nil; else, a backtrace
  214. will be displayed if `test-harness-unexpected-error-show-backtrace' is
  215. non-nil. CONTEXT-MSG is displayed as part of a message shown before entering
  216. the debugger or showing a backtrace, and ABORT-MSG, if non-nil, is displayed
  217. afterwards. See "
  218. `(condition-case nil
  219. (call-with-condition-handler
  220. #'(lambda (error-info)
  221. (test-harness-unexpected-error-condition-handler
  222. error-info ,context-msg))
  223. #'(lambda ()
  224. ,@body))
  225. (error ,(if abort-msg `(message ,abort-msg) nil))))
  226. (defun test-harness-read-from-buffer (buffer)
  227. "Read forms from BUFFER, and turn it into a lambda test form."
  228. (let ((body nil))
  229. (goto-char (point-min) buffer)
  230. (condition-case nil
  231. (call-with-condition-handler
  232. #'(lambda (error-info)
  233. ;; end-of-file is expected, so don't output error or backtrace
  234. ;; or enter debugger in this case.
  235. (unless (eq 'end-of-file (car error-info))
  236. (test-harness-unexpected-error-condition-handler
  237. error-info "reading forms from buffer")))
  238. #'(lambda ()
  239. (while t
  240. (setq body (cons (read buffer) body)))))
  241. (error nil))
  242. `(lambda ()
  243. (defvar passes)
  244. (defvar assertion-failures)
  245. (defvar no-error-failures)
  246. (defvar wrong-error-failures)
  247. (defvar missing-message-failures)
  248. (defvar other-failures)
  249. (defvar trick-optimizer)
  250. ,@(nreverse body))))
  251. (defun test-harness-from-buffer (inbuffer filename)
  252. "Run tests in buffer INBUFFER, visiting FILENAME."
  253. (defvar trick-optimizer)
  254. (let ((passes 0)
  255. (assertion-failures 0)
  256. (no-error-failures 0)
  257. (wrong-error-failures 0)
  258. (missing-message-failures 0)
  259. (other-failures 0)
  260. (unexpected-test-file-failures 0)
  261. ;; #### perhaps this should be a defvar, and output at the very end
  262. ;; OTOH, this way AC types can use a null EMACSPACKAGEPATH to find
  263. ;; what stuff is needed, and ways to avoid using them
  264. (skipped-test-reasons (make-hash-table :test 'equal))
  265. (trick-optimizer nil)
  266. (debug-on-error t)
  267. )
  268. (with-output-to-temp-buffer "*Test-Log*"
  269. (princ (format "Testing %s...\n\n" filename))
  270. (defconst test-harness-failure-tag "FAIL")
  271. (defconst test-harness-success-tag "PASS")
  272. ;;;;; BEGIN DEFINITION OF MACROS USEFUL IN TEST CODE
  273. (defmacro Known-Bug-Expect-Failure (&rest body)
  274. "Wrap a BODY that consists of tests that are known to fail.
  275. This causes messages to be printed on failure indicating that this is expected,
  276. and on success indicating that this is unexpected."
  277. `(let ((test-harness-bug-expected t)
  278. (test-harness-failure-tag "KNOWN BUG")
  279. (test-harness-success-tag "PASS (FAIL EXPECTED: was bug fixed?)"))
  280. ,@body))
  281. (defmacro Known-Bug-Expect-Error (expected-error &rest body)
  282. "Wrap a BODY containing a test known to trigger an error it shouldn't.
  283. This causes messages to be printed on failure indicating that this is expected
  284. of the bug, and on success indicating that this is unexpected."
  285. `(let ((test-harness-bug-expected t)
  286. (test-harness-failure-tag "KNOWN BUG")
  287. (test-harness-success-tag
  288. (format "PASS (EXPECTED ERROR %S due to bug: fixed?)"
  289. (quote ,expected-error))))
  290. (condition-case err
  291. (progn ,@body)
  292. (,expected-error)
  293. (error
  294. (let ((m (format " Expected %S due to bug, got %S: mutated?\n"
  295. (quote ,expected-error) err)))
  296. (if (noninteractive) (message m))
  297. (princ m))))))
  298. (defmacro Implementation-Incomplete-Expect-Failure (&rest body)
  299. "Wrap a BODY containing tests that are known to fail due to incomplete code.
  300. This causes messages to be printed on failure indicating that the
  301. implementation is incomplete (and hence the failure is expected); and on
  302. success indicating that this is unexpected."
  303. `(let ((test-harness-bug-expected t)
  304. (test-harness-failure-tag "IMPLEMENTATION INCOMPLETE")
  305. (test-harness-success-tag
  306. "PASS (FAILURE EXPECTED: feature implemented?)"))
  307. ,@body))
  308. (defun Print-Failure (fmt &rest args)
  309. (setq fmt (format "%s: %s" test-harness-failure-tag fmt))
  310. (if (noninteractive) (apply #'message fmt args))
  311. (princ (concat (apply #'format fmt args) "\n")))
  312. (defun Print-Pass (fmt &rest args)
  313. (setq fmt (format "%s: %s" test-harness-success-tag fmt))
  314. (and (or test-harness-verbose test-harness-bug-expected)
  315. (if (and noninteractive test-harness-bug-expected)
  316. (apply #'message fmt args))
  317. (princ (concat (apply #'format fmt args) "\n"))))
  318. (defun Print-Skip (test reason &optional fmt &rest args)
  319. (setq fmt (concat "SKIP: %S BECAUSE %S" fmt))
  320. (princ (concat (apply #'format fmt test reason args) "\n")))
  321. (defmacro Skip-Test-Unless (condition reason description &rest body)
  322. "Unless CONDITION is satisfied, skip test BODY.
  323. REASON is a description of the condition failure, and must be unique (it
  324. is used as a hash key). DESCRIPTION describes the tests that were skipped.
  325. BODY is a sequence of expressions and may contain several tests."
  326. `(if (not ,condition)
  327. (let ((count (gethash ,reason skipped-test-reasons)))
  328. (puthash ,reason (if (null count) 1 (1+ count))
  329. skipped-test-reasons)
  330. (Print-Skip ,description ,reason))
  331. ,@body))
  332. (defmacro Assert (assertion &optional failing-case description)
  333. "Test passes if ASSERTION is true.
  334. Optional FAILING-CASE describes the particular failure. Optional
  335. DESCRIPTION describes the assertion; by default, the unevalated assertion
  336. expression is given. FAILING-CASE and DESCRIPTION are useful when Assert
  337. is used in a loop."
  338. (let ((test-assertion assertion)
  339. (negated nil))
  340. (when (and (listp test-assertion)
  341. (eql 2 (length test-assertion))
  342. (memq (car test-assertion) '(not null)))
  343. (setq test-assertion (cadr test-assertion))
  344. (setq negated t))
  345. (when (and (listp test-assertion)
  346. (eql 3 (length test-assertion))
  347. (member (car test-assertion)
  348. '(eq eql equal equalp = string= < <= > >=)))
  349. (let* ((test (car test-assertion))
  350. (testval (second test-assertion))
  351. (expected (third test-assertion))
  352. (failmsg `(format ,(if negated
  353. "%S shouldn't be `%s' to %S but is"
  354. "%S should be `%s' to %S but isn't")
  355. ,testval ',test ,expected)))
  356. (setq failing-case (if failing-case
  357. `(concat
  358. (format "%S, " ,failing-case)
  359. ,failmsg)
  360. failmsg)))))
  361. (let ((description
  362. (or description `(quote ,assertion))))
  363. `(condition-case nil
  364. (call-with-condition-handler
  365. #'(lambda (error-info)
  366. (if (eq 'cl-assertion-failed (car error-info))
  367. (progn
  368. (Print-Failure
  369. (if ,failing-case
  370. "Assertion failed: %S; failing case = %S"
  371. "Assertion failed: %S")
  372. ,description ,failing-case)
  373. (incf assertion-failures)
  374. (test-harness-assertion-failure-do-debug error-info)
  375. nil)
  376. (Print-Failure
  377. (if ,failing-case
  378. "%S ==> error: %S; failing case = %S"
  379. "%S ==> error: %S")
  380. ,description error-info ,failing-case)
  381. (incf other-failures)
  382. (test-harness-unexpected-error-do-debug error-info)
  383. nil))
  384. #'(lambda ()
  385. (assert ,assertion)
  386. (Print-Pass "%S" ,description)
  387. (incf passes)
  388. t))
  389. (cl-assertion-failed nil))))
  390. (defmacro Check-Error (expected-error &rest body)
  391. (let ((quoted-body (if (eql 1 (length body))
  392. `(quote ,(car body)) `(quote (progn ,@body)))))
  393. `(condition-case error-info
  394. (progn
  395. (setq trick-optimizer (progn ,@body))
  396. (Print-Failure "%S executed successfully, but expected error %S"
  397. ,quoted-body
  398. ',expected-error)
  399. (incf no-error-failures))
  400. (,expected-error
  401. (Print-Pass "%S ==> error %S, as expected"
  402. ,quoted-body ',expected-error)
  403. (incf passes))
  404. (error
  405. (Print-Failure "%S ==> expected error %S, got error %S instead"
  406. ,quoted-body ',expected-error error-info)
  407. (incf wrong-error-failures)))))
  408. (defmacro Check-Error-Message (expected-error expected-error-regexp
  409. &rest body)
  410. (let ((quoted-body (if (eql 1 (length body))
  411. `(quote ,(car body)) `(quote (progn ,@body)))))
  412. `(condition-case error-info
  413. (progn
  414. (setq trick-optimizer (progn ,@body))
  415. (Print-Failure "%S executed successfully, but expected error %S"
  416. ,quoted-body ',expected-error)
  417. (incf no-error-failures))
  418. (,expected-error
  419. ;; #### Damn, this binding doesn't capture frobs, eg, for
  420. ;; invalid_argument() ... you only get the REASON. And for
  421. ;; wrong_type_argument(), there's no reason only FROBs.
  422. ;; If this gets fixed, fix tests in regexp-tests.el.
  423. (let ((error-message (second error-info)))
  424. (if (string-match ,expected-error-regexp error-message)
  425. (progn
  426. (Print-Pass "%S ==> error %S %S, as expected"
  427. ,quoted-body error-message ',expected-error)
  428. (incf passes))
  429. (Print-Failure "%S ==> got error %S as expected, but error message %S did not match regexp %S"
  430. ,quoted-body ',expected-error error-message ,expected-error-regexp)
  431. (incf wrong-error-failures))))
  432. (error
  433. (Print-Failure "%S ==> expected error %S, got error %S instead"
  434. ,quoted-body ',expected-error error-info)
  435. (incf wrong-error-failures)))))
  436. ;; Do not use this with Silence-Message.
  437. (defmacro Check-Message (expected-message-regexp &rest body)
  438. (let ((quoted-body (if (eql 1 (length body))
  439. `(quote ,(car body))
  440. `(quote (progn ,@body)))))
  441. `(Skip-Test-Unless (fboundp 'defadvice) "can't defadvice"
  442. ,expected-message-regexp
  443. (let ((messages ""))
  444. (defadvice message (around collect activate)
  445. (defvar messages)
  446. (let ((msg-string (apply 'format (ad-get-args 0))))
  447. (setq messages (concat messages msg-string))
  448. msg-string))
  449. (ignore-errors
  450. (call-with-condition-handler
  451. #'(lambda (error-info)
  452. (Print-Failure "%S ==> unexpected error %S"
  453. ,quoted-body error-info)
  454. (incf other-failures)
  455. (test-harness-unexpected-error-do-debug error-info))
  456. #'(lambda ()
  457. (setq trick-optimizer (progn ,@body))
  458. (if (string-match ,expected-message-regexp messages)
  459. (progn
  460. (Print-Pass
  461. "%S ==> value %S, message %S, matching %S, as expected"
  462. ,quoted-body trick-optimizer messages
  463. ',expected-message-regexp)
  464. (incf passes))
  465. (Print-Failure
  466. "%S ==> value %S, message %S, NOT matching expected %S"
  467. ,quoted-body trick-optimizer messages
  468. ',expected-message-regexp)
  469. (incf missing-message-failures)))))
  470. (ad-unadvise 'message)))))
  471. ;; #### Perhaps this should override `message' itself, too?
  472. (defmacro Silence-Message (&rest body)
  473. `(flet ((append-message (&rest args) ())
  474. (clear-message (&rest args) ()))
  475. ,@body))
  476. (defmacro Ignore-Ebola (&rest body)
  477. `(let ((debug-issue-ebola-notices -42)) ,@body))
  478. (defun Int-to-Marker (pos)
  479. (save-excursion
  480. (set-buffer standard-output)
  481. (save-excursion
  482. (goto-char pos)
  483. (point-marker))))
  484. (princ "Testing Interpreted Lisp\n\n")
  485. (test-harness-error-wrap
  486. "executing interpreted code"
  487. "Test suite execution aborted."
  488. (funcall (test-harness-read-from-buffer inbuffer)))
  489. (princ "\nTesting Compiled Lisp\n\n")
  490. (let (code
  491. (test-harness-test-compiled t))
  492. (test-harness-error-wrap
  493. "byte-compiling code" nil
  494. (setq code
  495. ;; our lisp code is often intentionally dubious,
  496. ;; so throw away _all_ the byte compiler warnings.
  497. (letf (((symbol-function 'byte-compile-warn)
  498. 'ignore))
  499. (byte-compile (test-harness-read-from-buffer
  500. inbuffer))))
  501. )
  502. (test-harness-error-wrap "executing byte-compiled code"
  503. "Test suite execution aborted."
  504. (if code (funcall code)))
  505. )
  506. (princ (format "\nSUMMARY for %s:\n" filename))
  507. (princ (format "\t%5d passes\n" passes))
  508. (princ (format "\t%5d assertion failures\n" assertion-failures))
  509. (princ (format "\t%5d errors that should have been generated, but weren't\n" no-error-failures))
  510. (princ (format "\t%5d wrong-error failures\n" wrong-error-failures))
  511. (princ (format "\t%5d missing-message failures\n" missing-message-failures))
  512. (princ (format "\t%5d other failures\n" other-failures))
  513. (let* ((total (+ passes
  514. assertion-failures
  515. no-error-failures
  516. wrong-error-failures
  517. missing-message-failures
  518. other-failures))
  519. (basename (file-name-nondirectory filename))
  520. (summary-msg
  521. (cond ((> unexpected-test-file-failures 0)
  522. (format test-harness-aborted-summary-template
  523. (concat basename ":") total))
  524. ((> total 0)
  525. (format test-harness-file-summary-template
  526. (concat basename ":")
  527. passes total (/ (* 100 passes) total)))
  528. (t
  529. (format test-harness-null-summary-template
  530. (concat basename ":")))))
  531. (reasons ""))
  532. (maphash (lambda (key value)
  533. (setq reasons
  534. (concat reasons
  535. (format "\n %d tests skipped because %s."
  536. value key))))
  537. skipped-test-reasons)
  538. (when (> (length reasons) 1)
  539. (setq summary-msg (concat summary-msg reasons "
  540. It may be that XEmacs cannot find your installed packages. Set
  541. EMACSPACKAGEPATH to the package hierarchy root or configure with
  542. --package-path to enable the skipped tests.")))
  543. (setq test-harness-file-results-alist
  544. (cons (list filename passes total)
  545. test-harness-file-results-alist))
  546. (message "%s" summary-msg))
  547. (when (> unexpected-test-file-failures 0)
  548. (setq unexpected-test-suite-failure-files
  549. (cons filename unexpected-test-suite-failure-files))
  550. (setq unexpected-test-suite-failures
  551. (+ unexpected-test-suite-failures unexpected-test-file-failures))
  552. (message "Test suite execution failed unexpectedly."))
  553. (fmakunbound 'Assert)
  554. (fmakunbound 'Check-Error)
  555. (fmakunbound 'Check-Message)
  556. (fmakunbound 'Check-Error-Message)
  557. (fmakunbound 'Ignore-Ebola)
  558. (fmakunbound 'Int-to-Marker)
  559. (and noninteractive
  560. (message "%s" (buffer-substring-no-properties
  561. nil nil "*Test-Log*")))
  562. )))
  563. (defvar test-harness-results-point-max nil)
  564. (defmacro displaying-emacs-test-results (&rest body)
  565. `(let ((test-harness-results-point-max test-harness-results-point-max))
  566. ;; Log the file name.
  567. (test-harness-log-file)
  568. ;; Record how much is logged now.
  569. ;; We will display the log buffer if anything more is logged
  570. ;; before the end of BODY.
  571. (or test-harness-results-point-max
  572. (save-excursion
  573. (set-buffer (get-buffer-create "*Test-Log*"))
  574. (setq test-harness-results-point-max (point-max))))
  575. (unwind-protect
  576. (condition-case error-info
  577. (progn ,@body)
  578. (error
  579. (test-harness-report-error error-info)))
  580. (save-excursion
  581. ;; If there were compilation warnings, display them.
  582. (set-buffer "*Test-Log*")
  583. (if (= test-harness-results-point-max (point-max))
  584. nil
  585. (if temp-buffer-show-function
  586. (let ((show-buffer (get-buffer-create "*Test-Log-Show*")))
  587. (save-excursion
  588. (set-buffer show-buffer)
  589. (setq buffer-read-only nil)
  590. (erase-buffer))
  591. (copy-to-buffer show-buffer
  592. (save-excursion
  593. (goto-char test-harness-results-point-max)
  594. (forward-line -1)
  595. (point))
  596. (point-max))
  597. (funcall temp-buffer-show-function show-buffer))
  598. (select-window
  599. (prog1 (selected-window)
  600. (select-window (display-buffer (current-buffer)))
  601. (goto-char test-harness-results-point-max)
  602. (recenter 1)))))))))
  603. (defun batch-test-emacs-1 (file)
  604. (condition-case error-info
  605. (progn (test-emacs-test-file file) t)
  606. (error
  607. (princ ">>Error occurred processing ")
  608. (princ file)
  609. (princ ": ")
  610. (display-error error-info nil)
  611. (terpri)
  612. nil)))
  613. (defun batch-test-emacs ()
  614. "Run `test-harness' on the files remaining on the command line.
  615. Use this from the command line, with `-batch';
  616. it won't work in an interactive Emacs.
  617. Each file is processed even if an error occurred previously.
  618. A directory can be given as well, and all files will be processed.
  619. For example, invoke \"xemacs -batch -f batch-test-emacs tests\""
  620. ;; command-line-args-left is what is left of the command line (from
  621. ;; startup.el)
  622. (defvar command-line-args-left) ;Avoid 'free variable' warning
  623. (defvar debug-issue-ebola-notices)
  624. (if (not noninteractive)
  625. (error "`batch-test-emacs' is to be used only with -batch"))
  626. (let ((error nil))
  627. (dolist (file command-line-args-left)
  628. (if (file-directory-p file)
  629. (dolist (file-in-dir (directory-files file t))
  630. (when (and (string-match emacs-lisp-file-regexp file-in-dir)
  631. (not (or (auto-save-file-name-p file-in-dir)
  632. (backup-file-name-p file-in-dir))))
  633. (or (batch-test-emacs-1 file-in-dir)
  634. (setq error t))))
  635. (or (batch-test-emacs-1 file)
  636. (setq error t))))
  637. (let ((namelen 0)
  638. (succlen 0)
  639. (testlen 0)
  640. (results test-harness-file-results-alist))
  641. ;; compute maximum lengths of variable components of report
  642. ;; probably should just use (length "byte-compiler-tests.el")
  643. ;; and 5-place sizes -- this will also work for the file-by-file
  644. ;; printing when Adrian's kludge gets reverted
  645. (labels ((print-width (i)
  646. (let ((x 10) (y 1))
  647. (while (>= i x)
  648. (setq x (* 10 x) y (1+ y)))
  649. y)))
  650. (while results
  651. (let* ((head (car results))
  652. (nn (length (file-name-nondirectory (first head))))
  653. (ss (print-width (second head)))
  654. (tt (print-width (third head))))
  655. (when (> nn namelen) (setq namelen nn))
  656. (when (> ss succlen) (setq succlen ss))
  657. (when (> tt testlen) (setq testlen tt)))
  658. (setq results (cdr results))))
  659. ;; create format and print
  660. (let ((results (reverse test-harness-file-results-alist)))
  661. (while results
  662. (let* ((head (car results))
  663. (basename (file-name-nondirectory (first head)))
  664. (nsucc (second head))
  665. (ntest (third head)))
  666. (cond ((member (first head) unexpected-test-suite-failure-files)
  667. (message test-harness-aborted-summary-template
  668. (concat basename ":")
  669. ntest))
  670. ((> ntest 0)
  671. (message test-harness-file-summary-template
  672. (concat basename ":")
  673. nsucc
  674. ntest
  675. (/ (* 100 nsucc) ntest)))
  676. (t
  677. (message test-harness-null-summary-template
  678. (concat basename ":"))))
  679. (setq results (cdr results)))))
  680. (when (> unexpected-test-suite-failures 0)
  681. (message "\n***** There %s %d unexpected test suite %s in %s:"
  682. (if (= unexpected-test-suite-failures 1) "was" "were")
  683. unexpected-test-suite-failures
  684. (if (= unexpected-test-suite-failures 1) "failure" "failures")
  685. (if (eql (length unexpected-test-suite-failure-files) 1)
  686. "file"
  687. "files"))
  688. (while unexpected-test-suite-failure-files
  689. (let ((line (pop unexpected-test-suite-failure-files)))
  690. (while (and (< (length line) 61)
  691. unexpected-test-suite-failure-files)
  692. (setq line
  693. (concat line " "
  694. (pop unexpected-test-suite-failure-files))))
  695. (message line)))))
  696. (message "\nDone")
  697. (kill-emacs (if error 1 0))))
  698. (provide 'test-harness)
  699. ;;; test-harness.el ends here