summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorChristian Ohler <ohler@gnu.org>2011-01-13 03:08:24 +1100
committerChristian Ohler <ohler@gnu.org>2011-01-13 03:08:24 +1100
commitd221e7808c01fdc9234734f95ecf49e902085ddd (patch)
tree09d270adbfdeada366ecd2328b2660a75358dd0c /test
parent03d32f1b2263270b75a0b3324c52c39965345665 (diff)
downloademacs-d221e7808c01fdc9234734f95ecf49e902085ddd.tar.gz
Add ERT, a tool for automated testing in Emacs Lisp.
* Makefile.in, configure.in, doc/misc/Makefile.in, doc/misc/makefile.w32-in: Add ERT. Make "make check" run tests in test/automated. * doc/misc/ert.texi, lisp/emacs-lisp/ert.el, lisp/emacs-lisp/ert-x.el: New files. * test/automated: New directory.
Diffstat (limited to 'test')
-rw-r--r--test/ChangeLog8
-rw-r--r--test/automated/Makefile.in158
-rw-r--r--test/automated/ert-tests.el949
-rw-r--r--test/automated/ert-x-tests.el273
4 files changed, 1388 insertions, 0 deletions
diff --git a/test/ChangeLog b/test/ChangeLog
index 3b1921c5987..695a51b7f4f 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-13 Christian Ohler <ohler@gnu.org>
+
+ * automated: New directory for automated tests.
+
+ * automated/ert-tests.el, automated/ert-x-tests.el: New files.
+
+ * automated/Makefile.in: New file.
+
2010-11-11 Stefan Monnier <monnier@iro.umontreal.ca>
* indent/modula2.mod: New file.
diff --git a/test/automated/Makefile.in b/test/automated/Makefile.in
new file mode 100644
index 00000000000..80a853056b1
--- /dev/null
+++ b/test/automated/Makefile.in
@@ -0,0 +1,158 @@
+# Maintenance productions for the automated test directory
+# Copyright (C) 2010, 2011 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 <http://www.gnu.org/licenses/>.
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+abs_top_builddir = @abs_top_builddir@
+test = $(srcdir)
+VPATH = $(srcdir)
+lispsrc = $(top_srcdir)/lisp
+lisp = ${abs_top_builddir}/lisp
+
+# You can specify a different executable on the make command line,
+# e.g. "make EMACS=../src/emacs ...".
+
+# We sometimes change directory before running Emacs (typically when
+# building out-of-tree, we chdir to the source directory), so we need
+# to use an absolute file name.
+EMACS = ${abs_top_builddir}/src/emacs
+
+# Command line flags for Emacs.
+
+EMACSOPT = -batch --no-site-file --no-site-lisp
+
+# Extra flags to pass to the byte compiler
+BYTE_COMPILE_EXTRA_FLAGS =
+# For example to not display the undefined function warnings you can use this:
+# BYTE_COMPILE_EXTRA_FLAGS = --eval '(setq byte-compile-warnings (quote (not unresolved)))'
+# The example above is just for developers, it should not be used by default.
+
+# The actual Emacs command run in the targets below.
+emacs = EMACSLOADPATH=$(lispsrc):$(test) LC_ALL=C $(EMACS) $(EMACSOPT)
+
+# Common command to find subdirectories
+setwins=subdirs=`(find . -type d -print)`; \
+ for file in $$subdirs; do \
+ case $$file in */.* | */.*/* | */=* ) ;; \
+ *) wins="$$wins $$file" ;; \
+ esac; \
+ done
+
+all: test
+
+doit:
+
+
+# Files MUST be compiled one by one. If we compile several files in a
+# row (i.e., in the same instance of Emacs) we can't make sure that
+# the compilation environment is clean. We also set the load-path of
+# the Emacs used for compilation to the current directory and its
+# subdirectories, to make sure require's and load's in the files being
+# compiled find the right files.
+
+.SUFFIXES: .elc .el
+
+# An old-fashioned suffix rule, which, according to the GNU Make manual,
+# cannot have prerequisites.
+.el.elc:
+ @echo Compiling $<
+ @$(emacs) $(BYTE_COMPILE_EXTRA_FLAGS) -f batch-byte-compile $<
+
+.PHONY: lisp-compile compile-main compile compile-always
+
+lisp-compile:
+ cd $(lisp); $(MAKE) $(MFLAGS) compile EMACS=$(EMACS)
+
+# In `compile-main' we could directly do
+# ... | xargs $(MAKE) $(MFLAGS) EMACS="$(EMACS)"
+# and it works, but it generates a lot of messages like
+# make[2]: « gnus/gnus-mlspl.elc » is up to date.
+# so instead, we use "xargs echo" to split the list of file into manageable
+# chunks and then use an intermediate `compile-targets' target so the
+# actual targets (the .elc files) are not mentioned as targets on the
+# make command line.
+
+
+.PHONY: compile-targets
+# TARGETS is set dynamically in the recursive call from `compile-main'.
+compile-targets: $(TARGETS)
+
+# Compile all the Elisp files that need it. Beware: it approximates
+# `no-byte-compile', so watch out for false-positives!
+compile-main: compile-clean lisp-compile
+ @(cd $(test); $(setwins); \
+ els=`echo "$$wins " | sed -e 's|/\./|/|g' -e 's|/\. | |g' -e 's| |/*.el |g'`; \
+ for el in $$els; do \
+ test -f $$el || continue; \
+ test ! -f $${el}c && GREP_OPTIONS= grep '^;.*no-byte-compile: t' $$el > /dev/null && continue; \
+ echo "$${el}c"; \
+ done | xargs echo) | \
+ while read chunk; do \
+ $(MAKE) $(MFLAGS) compile-targets EMACS="$(EMACS)" TARGETS="$$chunk"; \
+ done
+
+.PHONY: compile-clean
+# Erase left-over .elc files that do not have a corresponding .el file.
+compile-clean:
+ @cd $(test); $(setwins); \
+ elcs=`echo "$$wins " | sed -e 's|/\./|/|g' -e 's|/\. | |g' -e 's| |/*.elc |g'`; \
+ for el in $$(echo $$elcs | sed -e 's/\.elc/\.el/g'); do \
+ if test -f "$$el" -o \! -f "$${el}c"; then :; else \
+ echo rm "$${el}c"; \
+ rm "$${el}c"; \
+ fi \
+ done
+
+# Compile all Lisp files, but don't recompile those that are up to
+# date. Some .el files don't get compiled because they set the
+# local variable no-byte-compile.
+# Calling make recursively because suffix rule cannot have prerequisites.
+# Explicitly pass EMACS (sometimes ../src/bootstrap-emacs) to those
+# sub-makes that run rules that use it, for the sake of some non-GNU makes.
+compile: $(LOADDEFS) autoloads compile-first
+ $(MAKE) $(MFLAGS) compile-main EMACS=$(EMACS)
+
+# Compile all Lisp files. This is like `compile' but compiles files
+# unconditionally. Some files don't actually get compiled because they
+# set the local variable no-byte-compile.
+compile-always: doit
+ cd $(test); rm -f *.elc */*.elc */*/*.elc */*/*/*.elc
+ $(MAKE) $(MFLAGS) compile EMACS=$(EMACS)
+
+bootstrap-clean:
+ cd $(test); rm -f *.elc */*.elc */*/*.elc */*/*/*.elc
+
+distclean:
+ -rm -f ./Makefile
+
+maintainer-clean: distclean bootstrap-clean
+
+check: compile-main
+ @(cd $(test); $(setwins); \
+ pattern=`echo "$$wins " | sed -e 's|/\./|/|g' -e 's|/\. | |g' -e 's| |/*.el |g'`; \
+ for el in $$pattern; do \
+ test -f $$el || continue; \
+ args="$$args -l $$el"; \
+ els="$$els $$el"; \
+ done; \
+ echo Testing $$els; \
+ $(emacs) $$args -f ert-run-tests-batch-and-exit)
+
+# Makefile ends here.
diff --git a/test/automated/ert-tests.el b/test/automated/ert-tests.el
new file mode 100644
index 00000000000..3c9e2fef0c7
--- /dev/null
+++ b/test/automated/ert-tests.el
@@ -0,0 +1,949 @@
+;;; ert-tests.el --- ERT's self-tests
+
+;; Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+
+;; Author: Christian Ohler <ohler@gnu.org>
+
+;; 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 `http://www.gnu.org/licenses/'.
+
+;;; Commentary:
+
+;; This file is part of ERT, the Emacs Lisp Regression Testing tool.
+;; See ert.el or the texinfo manual for more details.
+
+;;; Code:
+
+(eval-when-compile
+ (require 'cl))
+(require 'ert)
+
+
+;;; Self-test that doesn't rely on ERT, for bootstrapping.
+
+;; This is used to test that bodies actually run.
+(defvar ert--test-body-was-run)
+(ert-deftest ert-test-body-runs ()
+ (setq ert--test-body-was-run t))
+
+(defun ert-self-test ()
+ "Run ERT's self-tests and make sure they actually ran."
+ (let ((window-configuration (current-window-configuration)))
+ (let ((ert--test-body-was-run nil))
+ ;; The buffer name chosen here should not compete with the default
+ ;; results buffer name for completion in `switch-to-buffer'.
+ (let ((stats (ert-run-tests-interactively "^ert-" " *ert self-tests*")))
+ (assert ert--test-body-was-run)
+ (if (zerop (ert-stats-completed-unexpected stats))
+ ;; Hide results window only when everything went well.
+ (set-window-configuration window-configuration)
+ (error "ERT self-test failed"))))))
+
+(defun ert-self-test-and-exit ()
+ "Run ERT's self-tests and exit Emacs.
+
+The exit code will be zero if the tests passed, nonzero if they
+failed or if there was a problem."
+ (unwind-protect
+ (progn
+ (ert-self-test)
+ (kill-emacs 0))
+ (unwind-protect
+ (progn
+ (message "Error running tests")
+ (backtrace))
+ (kill-emacs 1))))
+
+
+;;; Further tests are defined using ERT.
+
+(ert-deftest ert-test-nested-test-body-runs ()
+ "Test that nested test bodies run."
+ (lexical-let ((was-run nil))
+ (let ((test (make-ert-test :body (lambda ()
+ (setq was-run t)))))
+ (assert (not was-run))
+ (ert-run-test test)
+ (assert was-run))))
+
+
+;;; Test that pass/fail works.
+(ert-deftest ert-test-pass ()
+ (let ((test (make-ert-test :body (lambda ()))))
+ (let ((result (ert-run-test test)))
+ (assert (ert-test-passed-p result)))))
+
+(ert-deftest ert-test-fail ()
+ (let ((test (make-ert-test :body (lambda () (ert-fail "failure message")))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (assert (ert-test-failed-p result) t)
+ (assert (equal (ert-test-result-with-condition-condition result)
+ '(ert-test-failed "failure message"))
+ t))))
+
+(ert-deftest ert-test-fail-debug-with-condition-case ()
+ (let ((test (make-ert-test :body (lambda () (ert-fail "failure message")))))
+ (condition-case condition
+ (progn
+ (let ((ert-debug-on-error t))
+ (ert-run-test test))
+ (assert nil))
+ ((error)
+ (assert (equal condition '(ert-test-failed "failure message")) t)))))
+
+(ert-deftest ert-test-fail-debug-with-debugger-1 ()
+ (let ((test (make-ert-test :body (lambda () (ert-fail "failure message")))))
+ (let ((debugger (lambda (&rest debugger-args)
+ (assert nil))))
+ (let ((ert-debug-on-error nil))
+ (ert-run-test test)))))
+
+(ert-deftest ert-test-fail-debug-with-debugger-2 ()
+ (let ((test (make-ert-test :body (lambda () (ert-fail "failure message")))))
+ (block nil
+ (let ((debugger (lambda (&rest debugger-args)
+ (return-from nil nil))))
+ (let ((ert-debug-on-error t))
+ (ert-run-test test))
+ (assert nil)))))
+
+(ert-deftest ert-test-fail-debug-nested-with-debugger ()
+ (let ((test (make-ert-test :body (lambda ()
+ (let ((ert-debug-on-error t))
+ (ert-fail "failure message"))))))
+ (let ((debugger (lambda (&rest debugger-args)
+ (assert nil nil "Assertion a"))))
+ (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (let ((test (make-ert-test :body (lambda ()
+ (let ((ert-debug-on-error nil))
+ (ert-fail "failure message"))))))
+ (block nil
+ (let ((debugger (lambda (&rest debugger-args)
+ (return-from nil nil))))
+ (let ((ert-debug-on-error t))
+ (ert-run-test test))
+ (assert nil nil "Assertion b")))))
+
+(ert-deftest ert-test-error ()
+ (let ((test (make-ert-test :body (lambda () (error "Error message")))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (assert (ert-test-failed-p result) t)
+ (assert (equal (ert-test-result-with-condition-condition result)
+ '(error "Error message"))
+ t))))
+
+(ert-deftest ert-test-error-debug ()
+ (let ((test (make-ert-test :body (lambda () (error "Error message")))))
+ (condition-case condition
+ (progn
+ (let ((ert-debug-on-error t))
+ (ert-run-test test))
+ (assert nil))
+ ((error)
+ (assert (equal condition '(error "Error message")) t)))))
+
+
+;;; Test that `should' works.
+(ert-deftest ert-test-should ()
+ (let ((test (make-ert-test :body (lambda () (should nil)))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (assert (ert-test-failed-p result) t)
+ (assert (equal (ert-test-result-with-condition-condition result)
+ '(ert-test-failed ((should nil) :form nil :value nil)))
+ t)))
+ (let ((test (make-ert-test :body (lambda () (should t)))))
+ (let ((result (ert-run-test test)))
+ (assert (ert-test-passed-p result) t))))
+
+(ert-deftest ert-test-should-value ()
+ (should (eql (should 'foo) 'foo))
+ (should (eql (should 'bar) 'bar)))
+
+(ert-deftest ert-test-should-not ()
+ (let ((test (make-ert-test :body (lambda () (should-not t)))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (assert (ert-test-failed-p result) t)
+ (assert (equal (ert-test-result-with-condition-condition result)
+ '(ert-test-failed ((should-not t) :form t :value t)))
+ t)))
+ (let ((test (make-ert-test :body (lambda () (should-not nil)))))
+ (let ((result (ert-run-test test)))
+ (assert (ert-test-passed-p result)))))
+
+(ert-deftest ert-test-should-with-macrolet ()
+ (let ((test (make-ert-test :body (lambda ()
+ (macrolet ((foo () `(progn t nil)))
+ (should (foo)))))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (should (ert-test-failed-p result))
+ (should (equal
+ (ert-test-result-with-condition-condition result)
+ '(ert-test-failed ((should (foo))
+ :form (progn t nil)
+ :value nil)))))))
+
+(ert-deftest ert-test-should-error ()
+ ;; No error.
+ (let ((test (make-ert-test :body (lambda () (should-error (progn))))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (should (ert-test-failed-p result))
+ (should (equal (ert-test-result-with-condition-condition result)
+ '(ert-test-failed
+ ((should-error (progn))
+ :form (progn)
+ :value nil
+ :fail-reason "did not signal an error"))))))
+ ;; A simple error.
+ (should (equal (should-error (error "Foo"))
+ '(error "Foo")))
+ ;; Error of unexpected type.
+ (let ((test (make-ert-test :body (lambda ()
+ (should-error (error "Foo")
+ :type 'singularity-error)))))
+ (let ((result (ert-run-test test)))
+ (should (ert-test-failed-p result))
+ (should (equal
+ (ert-test-result-with-condition-condition result)
+ '(ert-test-failed
+ ((should-error (error "Foo") :type 'singularity-error)
+ :form (error "Foo")
+ :condition (error "Foo")
+ :fail-reason
+ "the error signalled did not have the expected type"))))))
+ ;; Error of the expected type.
+ (let* ((error nil)
+ (test (make-ert-test
+ :body (lambda ()
+ (setq error
+ (should-error (signal 'singularity-error nil)
+ :type 'singularity-error))))))
+ (let ((result (ert-run-test test)))
+ (should (ert-test-passed-p result))
+ (should (equal error '(singularity-error))))))
+
+(ert-deftest ert-test-should-error-subtypes ()
+ (should-error (signal 'singularity-error nil)
+ :type 'singularity-error
+ :exclude-subtypes t)
+ (let ((test (make-ert-test
+ :body (lambda ()
+ (should-error (signal 'arith-error nil)
+ :type 'singularity-error)))))
+ (let ((result (ert-run-test test)))
+ (should (ert-test-failed-p result))
+ (should (equal
+ (ert-test-result-with-condition-condition result)
+ '(ert-test-failed
+ ((should-error (signal 'arith-error nil)
+ :type 'singularity-error)
+ :form (signal arith-error nil)
+ :condition (arith-error)
+ :fail-reason
+ "the error signalled did not have the expected type"))))))
+ (let ((test (make-ert-test
+ :body (lambda ()
+ (should-error (signal 'arith-error nil)
+ :type 'singularity-error
+ :exclude-subtypes t)))))
+ (let ((result (ert-run-test test)))
+ (should (ert-test-failed-p result))
+ (should (equal
+ (ert-test-result-with-condition-condition result)
+ '(ert-test-failed
+ ((should-error (signal 'arith-error nil)
+ :type 'singularity-error
+ :exclude-subtypes t)
+ :form (signal arith-error nil)
+ :condition (arith-error)
+ :fail-reason
+ "the error signalled did not have the expected type"))))))
+ (let ((test (make-ert-test
+ :body (lambda ()
+ (should-error (signal 'singularity-error nil)
+ :type 'arith-error
+ :exclude-subtypes t)))))
+ (let ((result (ert-run-test test)))
+ (should (ert-test-failed-p result))
+ (should (equal
+ (ert-test-result-with-condition-condition result)
+ '(ert-test-failed
+ ((should-error (signal 'singularity-error nil)
+ :type 'arith-error
+ :exclude-subtypes t)
+ :form (signal singularity-error nil)
+ :condition (singularity-error)
+ :fail-reason
+ "the error signalled was a subtype of the expected type")))))
+ ))
+
+(defmacro ert--test-my-list (&rest args)
+ "Don't use this. Instead, call `list' with ARGS, it does the same thing.
+
+This macro is used to test if macroexpansion in `should' works."
+ `(list ,@args))
+
+(ert-deftest ert-test-should-failure-debugging ()
+ "Test that `should' errors contain the information we expect them to."
+ (loop for (body expected-condition) in
+ `((,(lambda () (let ((x nil)) (should x)))
+ (ert-test-failed ((should x) :form x :value nil)))
+ (,(lambda () (let ((x t)) (should-not x)))
+ (ert-test-failed ((should-not x) :form x :value t)))
+ (,(lambda () (let ((x t)) (should (not x))))
+ (ert-test-failed ((should (not x)) :form (not t) :value nil)))
+ (,(lambda () (let ((x nil)) (should-not (not x))))
+ (ert-test-failed ((should-not (not x)) :form (not nil) :value t)))
+ (,(lambda () (let ((x t) (y nil)) (should-not
+ (ert--test-my-list x y))))
+ (ert-test-failed
+ ((should-not (ert--test-my-list x y))
+ :form (list t nil)
+ :value (t nil))))
+ (,(lambda () (let ((x t)) (should (error "Foo"))))
+ (error "Foo")))
+ do
+ (let ((test (make-ert-test :body body)))
+ (condition-case actual-condition
+ (progn
+ (let ((ert-debug-on-error t))
+ (ert-run-test test))
+ (assert nil))
+ ((error)
+ (should (equal actual-condition expected-condition)))))))
+
+(ert-deftest ert-test-deftest ()
+ (should (equal (macroexpand '(ert-deftest abc () "foo" :tags '(bar)))
+ '(progn
+ (ert-set-test 'abc
+ (make-ert-test :name 'abc
+ :documentation "foo"
+ :tags '(bar)
+ :body (lambda ())))
+ (push '(ert-deftest . abc) current-load-list)
+ 'abc)))
+ (should (equal (macroexpand '(ert-deftest def ()
+ :expected-result ':passed))
+ '(progn
+ (ert-set-test 'def
+ (make-ert-test :name 'def
+ :expected-result-type ':passed
+ :body (lambda ())))
+ (push '(ert-deftest . def) current-load-list)
+ 'def)))
+ ;; :documentation keyword is forbidden
+ (should-error (macroexpand '(ert-deftest ghi ()
+ :documentation "foo"))))
+
+(ert-deftest ert-test-record-backtrace ()
+ (let ((test (make-ert-test :body (lambda () (ert-fail "foo")))))
+ (let ((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 " signal(ert-test-failed (\"foo\"))")))))))
+
+(ert-deftest ert-test-messages ()
+ :tags '(:causes-redisplay)
+ (let* ((message-string "Test message")
+ (messages-buffer (get-buffer-create "*Messages*"))
+ (test (make-ert-test :body (lambda () (message "%s" message-string)))))
+ (with-current-buffer messages-buffer
+ (let ((result (ert-run-test test)))
+ (should (equal (concat message-string "\n")
+ (ert-test-result-messages result)))))))
+
+(ert-deftest ert-test-running-tests ()
+ (let ((outer-test (ert-get-test 'ert-test-running-tests)))
+ (should (equal (ert-running-test) outer-test))
+ (let (test1 test2 test3)
+ (setq test1 (make-ert-test
+ :name "1"
+ :body (lambda ()
+ (should (equal (ert-running-test) outer-test))
+ (should (equal ert--running-tests
+ (list test1 test2 test3
+ outer-test)))))
+ test2 (make-ert-test
+ :name "2"
+ :body (lambda ()
+ (should (equal (ert-running-test) outer-test))
+ (should (equal ert--running-tests
+ (list test3 test2 outer-test)))
+ (ert-run-test test1)))
+ test3 (make-ert-test
+ :name "3"
+ :body (lambda ()
+ (should (equal (ert-running-test) outer-test))
+ (should (equal ert--running-tests
+ (list test3 outer-test)))
+ (ert-run-test test2))))
+ (should (ert-test-passed-p (ert-run-test test3))))))
+
+(ert-deftest ert-test-test-result-expected-p ()
+ "Test `ert-test-result-expected-p' and (implicitly) `ert-test-result-type-p'."
+ ;; passing test
+ (let ((test (make-ert-test :body (lambda ()))))
+ (should (ert-test-result-expected-p test (ert-run-test test))))
+ ;; unexpected failure
+ (let ((test (make-ert-test :body (lambda () (ert-fail "failed")))))
+ (should-not (ert-test-result-expected-p test (ert-run-test test))))
+ ;; expected failure
+ (let ((test (make-ert-test :body (lambda () (ert-fail "failed"))
+ :expected-result-type ':failed)))
+ (should (ert-test-result-expected-p test (ert-run-test test))))
+ ;; `not' expected type
+ (let ((test (make-ert-test :body (lambda ())
+ :expected-result-type '(not :failed))))
+ (should (ert-test-result-expected-p test (ert-run-test test))))
+ (let ((test (make-ert-test :body (lambda ())
+ :expected-result-type '(not :passed))))
+ (should-not (ert-test-result-expected-p test (ert-run-test test))))
+ ;; `and' expected type
+ (let ((test (make-ert-test :body (lambda ())
+ :expected-result-type '(and :passed :failed))))
+ (should-not (ert-test-result-expected-p test (ert-run-test test))))
+ (let ((test (make-ert-test :body (lambda ())
+ :expected-result-type '(and :passed
+ (not :failed)))))
+ (should (ert-test-result-expected-p test (ert-run-test test))))
+ ;; `or' expected type
+ (let ((test (make-ert-test :body (lambda ())
+ :expected-result-type '(or (and :passed :failed)
+ :passed))))
+ (should (ert-test-result-expected-p test (ert-run-test test))))
+ (let ((test (make-ert-test :body (lambda ())
+ :expected-result-type '(or (and :passed :failed)
+ nil (not t)))))
+ (should-not (ert-test-result-expected-p test (ert-run-test test)))))
+
+;;; Test `ert-select-tests'.
+(ert-deftest ert-test-select-regexp ()
+ (should (equal (ert-select-tests "^ert-test-select-regexp$" t)
+ (list (ert-get-test 'ert-test-select-regexp)))))
+
+(ert-deftest ert-test-test-boundp ()
+ (should (ert-test-boundp 'ert-test-test-boundp))
+ (should-not (ert-test-boundp (make-symbol "ert-not-a-test"))))
+
+(ert-deftest ert-test-select-member ()
+ (should (equal (ert-select-tests '(member ert-test-select-member) t)
+ (list (ert-get-test 'ert-test-select-member)))))
+
+(ert-deftest ert-test-select-test ()
+ (should (equal (ert-select-tests (ert-get-test 'ert-test-select-test) t)
+ (list (ert-get-test 'ert-test-select-test)))))
+
+(ert-deftest ert-test-select-symbol ()
+ (should (equal (ert-select-tests 'ert-test-select-symbol t)
+ (list (ert-get-test 'ert-test-select-symbol)))))
+
+(ert-deftest ert-test-select-and ()
+ (let ((test (make-ert-test
+ :name nil
+ :body nil
+ :most-recent-result (make-ert-test-failed
+ :condition nil
+ :backtrace nil
+ :infos nil))))
+ (should (equal (ert-select-tests `(and (member ,test) :failed) t)
+ (list test)))))
+
+(ert-deftest ert-test-select-tag ()
+ (let ((test (make-ert-test
+ :name nil
+ :body nil
+ :tags '(a b))))
+ (should (equal (ert-select-tests `(tag a) (list test)) (list test)))
+ (should (equal (ert-select-tests `(tag b) (list test)) (list test)))
+ (should (equal (ert-select-tests `(tag c) (list test)) '()))))
+
+
+;;; Tests for utility functions.
+(ert-deftest ert-test-proper-list-p ()
+ (should (ert--proper-list-p '()))
+ (should (ert--proper-list-p '(1)))
+ (should (ert--proper-list-p '(1 2)))
+ (should (ert--proper-list-p '(1 2 3)))
+ (should (ert--proper-list-p '(1 2 3 4)))
+ (should (not (ert--proper-list-p 'a)))
+ (should (not (ert--proper-list-p '(1 . a))))
+ (should (not (ert--proper-list-p '(1 2 . a))))
+ (should (not (ert--proper-list-p '(1 2 3 . a))))
+ (should (not (ert--proper-list-p '(1 2 3 4 . a))))
+ (let ((a (list 1)))
+ (setf (cdr (last a)) a)
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2)))
+ (setf (cdr (last a)) a)
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3)))
+ (setf (cdr (last a)) a)
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3 4)))
+ (setf (cdr (last a)) a)
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2)))
+ (setf (cdr (last a)) (cdr a))
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3)))
+ (setf (cdr (last a)) (cdr a))
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3 4)))
+ (setf (cdr (last a)) (cdr a))
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3)))
+ (setf (cdr (last a)) (cddr a))
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3 4)))
+ (setf (cdr (last a)) (cddr a))
+ (should (not (ert--proper-list-p a))))
+ (let ((a (list 1 2 3 4)))
+ (setf (cdr (last a)) (cdddr a))
+ (should (not (ert--proper-list-p a)))))
+
+(ert-deftest ert-test-parse-keys-and-body ()
+ (should (equal (ert--parse-keys-and-body '(foo)) '(nil (foo))))
+ (should (equal (ert--parse-keys-and-body '(:bar foo)) '((:bar foo) nil)))
+ (should (equal (ert--parse-keys-and-body '(:bar foo a (b)))
+ '((:bar foo) (a (b)))))
+ (should (equal (ert--parse-keys-and-body '(:bar foo :a (b)))
+ '((:bar foo :a (b)) nil)))
+ (should (equal (ert--parse-keys-and-body '(bar foo :a (b)))
+ '(nil (bar foo :a (b)))))
+ (should-error (ert--parse-keys-and-body '(:bar foo :a))))
+
+
+(ert-deftest ert-test-run-tests-interactively ()
+ :tags '(:causes-redisplay)
+ (let ((passing-test (make-ert-test :name 'passing-test
+ :body (lambda () (ert-pass))))
+ (failing-test (make-ert-test :name 'failing-test
+ :body (lambda () (ert-fail
+ "failure message")))))
+ (let ((ert-debug-on-error nil))
+ (let* ((buffer-name (generate-new-buffer-name " *ert-test-run-tests*"))
+ (messages nil)
+ (mock-message-fn
+ (lambda (format-string &rest args)
+ (push (apply #'format format-string args) messages))))
+ (save-window-excursion
+ (unwind-protect
+ (let ((case-fold-search nil))
+ (ert-run-tests-interactively
+ `(member ,passing-test ,failing-test) buffer-name
+ mock-message-fn)
+ (should (equal messages `(,(concat
+ "Ran 2 tests, 1 results were "
+ "as expected, 1 unexpected"))))
+ (with-current-buffer buffer-name
+ (goto-char (point-min))
+ (should (equal
+ (buffer-substring (point-min)
+ (save-excursion
+ (forward-line 4)
+ (point)))
+ (concat
+ "Selector: (member <passing-test> <failing-test>)\n"
+ "Passed: 1\n"
+ "Failed: 1 (1 unexpected)\n"
+ "Total: 2/2\n")))))
+ (when (get-buffer buffer-name)
+ (kill-buffer buffer-name))))))))
+
+(ert-deftest ert-test-special-operator-p ()
+ (should (ert--special-operator-p 'if))
+ (should-not (ert--special-operator-p 'car))
+ (should-not (ert--special-operator-p 'ert--special-operator-p))
+ (let ((b (ert--gensym)))
+ (should-not (ert--special-operator-p b))
+ (fset b 'if)
+ (should (ert--special-operator-p b))))
+
+(ert-deftest ert-test-list-of-should-forms ()
+ (let ((test (make-ert-test :body (lambda ()
+ (should t)
+ (should (null '()))
+ (should nil)
+ (should t)))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (should (equal (ert-test-result-should-forms result)
+ '(((should t) :form t :value t)
+ ((should (null '())) :form (null nil) :value t)
+ ((should nil) :form nil :value nil)))))))
+
+(ert-deftest ert-test-list-of-should-forms-observers-should-not-stack ()
+ (let ((test (make-ert-test
+ :body (lambda ()
+ (let ((test2 (make-ert-test
+ :body (lambda ()
+ (should t)))))
+ (let ((result (ert-run-test test2)))
+ (should (ert-test-passed-p result))))))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (should (ert-test-passed-p result))
+ (should (eql (length (ert-test-result-should-forms result))
+ 1)))))
+
+(ert-deftest ert-test-list-of-should-forms-no-deep-copy ()
+ (let ((test (make-ert-test :body (lambda ()
+ (let ((obj (list 'a)))
+ (should (equal obj '(a)))
+ (setf (car obj) 'b)
+ (should (equal obj '(b))))))))
+ (let ((result (let ((ert-debug-on-error nil))
+ (ert-run-test test))))
+ (should (ert-test-passed-p result))
+ (should (equal (ert-test-result-should-forms result)
+ '(((should (equal obj '(a))) :form (equal (b) (a)) :value t
+ :explanation nil)
+ ((should (equal obj '(b))) :form (equal (b) (b)) :value t
+ :explanation nil)
+ ))))))
+
+(ert-deftest ert-test-remprop ()
+ (let ((x (ert--gensym)))
+ (should (equal (symbol-plist x) '()))
+ ;; Remove nonexistent property on empty plist.
+ (ert--remprop x 'b)
+ (should (equal (symbol-plist x) '()))
+ (put x 'a 1)
+ (should (equal (symbol-plist x) '(a 1)))
+ ;; Remove nonexistent property on nonempty plist.
+ (ert--remprop x 'b)
+ (should (equal (symbol-plist x) '(a 1)))
+ (put x 'b 2)
+ (put x 'c 3)
+ (put x 'd 4)
+ (should (equal (symbol-plist x) '(a 1 b 2 c 3 d 4)))
+ ;; Remove property that is neither first nor last.
+ (ert--remprop x 'c)
+ (should (equal (symbol-plist x) '(a 1 b 2 d 4)))
+ ;; Remove last property from a plist of length >1.
+ (ert--remprop x 'd)
+ (should (equal (symbol-plist x) '(a 1 b 2)))
+ ;; Remove first property from a plist of length >1.
+ (ert--remprop x 'a)
+ (should (equal (symbol-plist x) '(b 2)))
+ ;; Remove property when there is only one.
+ (ert--remprop x 'b)
+ (should (equal (symbol-plist x) '()))))
+
+(ert-deftest ert-test-remove-if-not ()
+ (let ((list (list 'a 'b 'c 'd))
+ (i 0))
+ (let ((result (ert--remove-if-not (lambda (x)
+ (should (eql x (nth i list)))
+ (incf i)
+ (member i '(2 3)))
+ list)))
+ (should (equal i 4))
+ (should (equal result '(b c)))
+ (should (equal list '(a b c d)))))
+ (should (equal '()
+ (ert--remove-if-not (lambda (x) (should nil)) '()))))
+
+(ert-deftest ert-test-remove* ()
+ (let ((list (list 'a 'b 'c 'd))
+ (key-index 0)
+ (test-index 0))
+ (let ((result
+ (ert--remove* 'foo list
+ :key (lambda (x)
+ (should (eql x (nth key-index list)))
+ (prog1
+ (list key-index x)
+ (incf key-index)))
+ :test
+ (lambda (a b)
+ (should (eql a 'foo))
+ (should (equal b (list test-index
+ (nth test-index list))))
+ (incf test-index)
+ (member test-index '(2 3))))))
+ (should (equal key-index 4))
+ (should (equal test-index 4))
+ (should (equal result '(a d)))
+ (should (equal list '(a b c d)))))
+ (let ((x (cons nil nil))
+ (y (cons nil nil)))
+ (should (equal (ert--remove* x (list x y))
+ ;; or (list x), since we use `equal' -- the
+ ;; important thing is that only one element got
+ ;; removed, this proves that the default test is
+ ;; `eql', not `equal'
+ (list y)))))
+
+
+(ert-deftest ert-test-set-functions ()
+ (let ((c1 (cons nil nil))
+ (c2 (cons nil nil))
+ (sym (make-symbol "a")))
+ (let ((e '())
+ (a (list 'a 'b sym nil "" "x" c1 c2))
+ (b (list c1 'y 'b sym 'x)))
+ (should (equal (ert--set-difference e e) e))
+ (should (equal (ert--set-difference a e) a))
+ (should (equal (ert--set-difference e a) e))
+ (should (equal (ert--set-difference a a) e))
+ (should (equal (ert--set-difference b e) b))
+ (should (equal (ert--set-difference e b) e))
+ (should (equal (ert--set-difference b b) e))
+ (should (equal (ert--set-difference a b) (list 'a nil "" "x" c2)))
+ (should (equal (ert--set-difference b a) (list 'y 'x)))
+
+ ;; We aren't testing whether this is really using `eq' rather than `eql'.
+ (should (equal (ert--set-difference-eq e e) e))
+ (should (equal (ert--set-difference-eq a e) a))
+ (should (equal (ert--set-difference-eq e a) e))
+ (should (equal (ert--set-difference-eq a a) e))
+ (should (equal (ert--set-difference-eq b e) b))
+ (should (equal (ert--set-difference-eq e b) e))
+ (should (equal (ert--set-difference-eq b b) e))
+ (should (equal (ert--set-difference-eq a b) (list 'a nil "" "x" c2)))
+ (should (equal (ert--set-difference-eq b a) (list 'y 'x)))
+
+ (should (equal (ert--union e e) e))
+ (should (equal (ert--union a e) a))
+ (should (equal (ert--union e a) a))
+ (should (equal (ert--union a a) a))
+ (should (equal (ert--union b e) b))
+ (should (equal (ert--union e b) b))
+ (should (equal (ert--union b b) b))
+ (should (equal (ert--union a b) (list 'a 'b sym nil "" "x" c1 c2 'y 'x)))
+ (should (equal (ert--union b a) (list c1 'y 'b sym 'x 'a nil "" "x" c2)))
+
+ (should (equal (ert--intersection e e) e))
+ (should (equal (ert--intersection a e) e))
+ (should (equal (ert--intersection e a) e))
+ (should (equal (ert--intersection a a) a))
+ (should (equal (ert--intersection b e) e))
+ (should (equal (ert--intersection e b) e))
+ (should (equal (ert--intersection b b) b))
+ (should (equal (ert--intersection a b) (list 'b sym c1)))
+ (should (equal (ert--intersection b a) (list c1 'b sym))))))
+
+(ert-deftest ert-test-gensym ()
+ ;; Since the expansion of `should' calls `ert--gensym' and thus has a
+ ;; side-effect on `ert--gensym-counter', we have to make sure all
+ ;; macros in our test body are expanded before we rebind
+ ;; `ert--gensym-counter' and run the body. Otherwise, the test would
+ ;; fail if run interpreted.
+ (let ((body (byte-compile
+ '(lambda ()
+ (should (equal (symbol-name (ert--gensym)) "G0"))
+ (should (equal (symbol-name (ert--gensym)) "G1"))
+ (should (equal (symbol-name (ert--gensym)) "G2"))
+ (should (equal (symbol-name (ert--gensym "foo")) "foo3"))
+ (should (equal (symbol-name (ert--gensym "bar")) "bar4"))
+ (should (equal ert--gensym-counter 5))))))
+ (let ((ert--gensym-counter 0))
+ (funcall body))))
+
+(ert-deftest ert-test-coerce-to-vector ()
+ (let* ((a (vector))
+ (b (vector 1 a 3))
+ (c (list))
+ (d (list b a)))
+ (should (eql (ert--coerce-to-vector a) a))
+ (should (eql (ert--coerce-to-vector b) b))
+ (should (equal (ert--coerce-to-vector c) (vector)))
+ (should (equal (ert--coerce-to-vector d) (vector b a)))))
+
+(ert-deftest ert-test-string-position ()
+ (should (eql (ert--string-position ?x "") nil))
+ (should (eql (ert--string-position ?a "abc") 0))
+ (should (eql (ert--string-position ?b "abc") 1))
+ (should (eql (ert--string-position ?c "abc") 2))
+ (should (eql (ert--string-position ?d "abc") nil))
+ (should (eql (ert--string-position ?A "abc") nil)))
+
+(ert-deftest ert-test-mismatch ()
+ (should (eql (ert--mismatch "" "") nil))
+ (should (eql (ert--mismatch "" "a") 0))
+ (should (eql (ert--mismatch "a" "a") nil))
+ (should (eql (ert--mismatch "ab" "a") 1))
+ (should (eql (ert--mismatch "Aa" "aA") 0))
+ (should (eql (ert--mismatch '(a b c) '(a b d)) 2)))
+
+(ert-deftest ert-test-string-first-line ()
+ (should (equal (ert--string-first-line "") ""))
+ (should (equal (ert--string-first-line "abc") "abc"))
+ (should (equal (ert--string-first-line "abc\n") "abc"))
+ (should (equal (ert--string-first-line "foo\nbar") "foo"))
+ (should (equal (ert--string-first-line " foo\nbar\nbaz\n") " foo")))
+
+(ert-deftest ert-test-explain-not-equal ()
+ (should (equal (ert--explain-not-equal nil 'foo)
+ '(different-atoms nil foo)))
+ (should (equal (ert--explain-not-equal '(a a) '(a b))
+ '(list-elt 1 (different-atoms a b))))
+ (should (equal (ert--explain-not-equal '(1 48) '(1 49))
+ '(list-elt 1 (different-atoms (48 "#x30" "?0")
+ (49 "#x31" "?1")))))
+ (should (equal (ert--explain-not-equal 'nil '(a))
+ '(different-types nil (a))))
+ (should (equal (ert--explain-not-equal '(a b c) '(a b c d))
+ '(proper-lists-of-different-length 3 4 (a b c) (a b c d)
+ first-mismatch-at 3)))
+ (let ((sym (make-symbol "a")))
+ (should (equal (ert--explain-not-equal 'a sym)
+ `(different-symbols-with-the-same-name a ,sym)))))
+
+(ert-deftest ert-test-explain-not-equal-improper-list ()
+ (should (equal (ert--explain-not-equal '(a . b) '(a . c))
+ '(cdr (different-atoms b c)))))
+
+(ert-deftest ert-test-significant-plist-keys ()
+ (should (equal (ert--significant-plist-keys '()) '()))
+ (should (equal (ert--significant-plist-keys '(a b c d e f c g p q r nil s t))
+ '(a c e p s))))
+
+(ert-deftest ert-test-plist-difference-explanation ()
+ (should (equal (ert--plist-difference-explanation
+ '(a b c nil) '(a b))
+ nil))
+ (should (equal (ert--plist-difference-explanation
+ '(a b c t) '(a b))
+ '(different-properties-for-key c (different-atoms t nil))))
+ (should (equal (ert--plist-difference-explanation
+ '(a b c t) '(c nil a b))
+ '(different-properties-for-key c (different-atoms t nil))))
+ (should (equal (ert--plist-difference-explanation
+ '(a b c (foo . bar)) '(c (foo . baz) a b))
+ '(different-properties-for-key c
+ (cdr
+ (different-atoms bar baz))))))
+
+(ert-deftest ert-test-abbreviate-string ()
+ (should (equal (ert--abbreviate-string "foo" 4 nil) "foo"))
+ (should (equal (ert--abbreviate-string "foo" 3 nil) "foo"))
+ (should (equal (ert--abbreviate-string "foo" 3 nil) "foo"))
+ (should (equal (ert--abbreviate-string "foo" 2 nil) "fo"))
+ (should (equal (ert--abbreviate-string "foo" 1 nil) "f"))
+ (should (equal (ert--abbreviate-string "foo" 0 nil) ""))
+ (should (equal (ert--abbreviate-string "bar" 4 t) "bar"))
+ (should (equal (ert--abbreviate-string "bar" 3 t) "bar"))
+ (should (equal (ert--abbreviate-string "bar" 3 t) "bar"))
+ (should (equal (ert--abbreviate-string "bar" 2 t) "ar"))
+ (should (equal (ert--abbreviate-string "bar" 1 t) "r"))
+ (should (equal (ert--abbreviate-string "bar" 0 t) "")))
+
+(ert-deftest ert-test-explain-not-equal-string-properties ()
+ (should
+ (equal (ert--explain-not-equal-including-properties #("foo" 0 1 (a b))
+ "foo")
+ '(char 0 "f"
+ (different-properties-for-key a (different-atoms b nil))
+ context-before ""
+ context-after "oo")))
+ (should (equal (ert--explain-not-equal-including-properties
+ #("foo" 1 3 (a b))
+ #("goo" 0 1 (c d)))
+ '(array-elt 0 (different-atoms (?f "#x66" "?f")
+ (?g "#x67" "?g")))))
+ (should
+ (equal (ert--explain-not-equal-including-properties
+ #("foo" 0 1 (a b c d) 1 3 (a b))
+ #("foo" 0 1 (c d a b) 1 2 (a foo)))
+ '(char 1 "o" (different-properties-for-key a (different-atoms b foo))
+ context-before "f" context-after "o"))))
+
+(ert-deftest ert-test-equal-including-properties ()
+ (should (equal-including-properties "foo" "foo"))
+ (should (ert-equal-including-properties "foo" "foo"))
+
+ (should (equal-including-properties #("foo" 0 3 (a b))
+ (propertize "foo" 'a 'b)))
+ (should (ert-equal-including-properties #("foo" 0 3 (a b))
+ (propertize "foo" 'a 'b)))
+
+ (should (equal-including-properties #("foo" 0 3 (a b c d))
+ (propertize "foo" 'a 'b 'c 'd)))
+ (should (ert-equal-including-properties #("foo" 0 3 (a b c d))
+ (propertize "foo" 'a 'b 'c 'd)))
+
+ (should-not (equal-including-properties #("foo" 0 3 (a b c e))
+ (propertize "foo" 'a 'b 'c 'd)))
+ (should-not (ert-equal-including-properties #("foo" 0 3 (a b c e))
+ (propertize "foo" 'a 'b 'c 'd)))
+
+ ;; This is bug 6581.
+ (should-not (equal-including-properties #("foo" 0 3 (a (t)))
+ (propertize "foo" 'a (list t))))
+ (should (ert-equal-including-properties #("foo" 0 3 (a (t)))
+ (propertize "foo" 'a (list t)))))
+
+(ert-deftest ert-test-stats-set-test-and-result ()
+ (let* ((test-1 (make-ert-test :name 'test-1
+ :body (lambda () nil)))
+ (test-2 (make-ert-test :name 'test-2
+ :body (lambda () nil)))
+ (test-3 (make-ert-test :name 'test-2
+ :body (lambda () nil)))
+ (stats (ert--make-stats (list test-1 test-2) 't))
+ (failed (make-ert-test-failed :condition nil
+ :backtrace nil
+ :infos nil)))
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 0 (ert-stats-completed stats)))
+ (should (eql 0 (ert-stats-completed-expected stats)))
+ (should (eql 0 (ert-stats-completed-unexpected stats)))
+ (ert--stats-set-test-and-result stats 0 test-1 (make-ert-test-passed))
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 1 (ert-stats-completed stats)))
+ (should (eql 1 (ert-stats-completed-expected stats)))
+ (should (eql 0 (ert-stats-completed-unexpected stats)))
+ (ert--stats-set-test-and-result stats 0 test-1 failed)
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 1 (ert-stats-completed stats)))
+ (should (eql 0 (ert-stats-completed-expected stats)))
+ (should (eql 1 (ert-stats-completed-unexpected stats)))
+ (ert--stats-set-test-and-result stats 0 test-1 nil)
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 0 (ert-stats-completed stats)))
+ (should (eql 0 (ert-stats-completed-expected stats)))
+ (should (eql 0 (ert-stats-completed-unexpected stats)))
+ (ert--stats-set-test-and-result stats 0 test-3 failed)
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 1 (ert-stats-completed stats)))
+ (should (eql 0 (ert-stats-completed-expected stats)))
+ (should (eql 1 (ert-stats-completed-unexpected stats)))
+ (ert--stats-set-test-and-result stats 1 test-2 (make-ert-test-passed))
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 2 (ert-stats-completed stats)))
+ (should (eql 1 (ert-stats-completed-expected stats)))
+ (should (eql 1 (ert-stats-completed-unexpected stats)))
+ (ert--stats-set-test-and-result stats 0 test-1 (make-ert-test-passed))
+ (should (eql 2 (ert-stats-total stats)))
+ (should (eql 2 (ert-stats-completed stats)))
+ (should (eql 2 (ert-stats-completed-expected stats)))
+ (should (eql 0 (ert-stats-completed-unexpected stats)))))
+
+
+(provide 'ert-tests)
+
+;;; ert-tests.el ends here
diff --git a/test/automated/ert-x-tests.el b/test/automated/ert-x-tests.el
new file mode 100644
index 00000000000..80fff40d86a
--- /dev/null
+++ b/test/automated/ert-x-tests.el
@@ -0,0 +1,273 @@
+;;; ert-x-tests.el --- Tests for ert-x.el
+
+;; Copyright (C) 2008, 2010, 2011 Free Software Foundation, Inc.
+
+;; Author: Phil Hagelberg
+;; Author: Christian Ohler <ohler@gnu.org>
+
+;; 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 `http://www.gnu.org/licenses/'.
+
+;;; Commentary:
+
+;; This file is part of ERT, the Emacs Lisp Regression Testing tool.
+;; See ert.el or the texinfo manual for more details.
+
+;;; Code:
+
+(eval-when-compile
+ (require 'cl))
+(require 'ert)
+(require 'ert-x)
+
+;;; Utilities
+
+(ert-deftest ert-test-buffer-string-reindented ()
+ (ert-with-test-buffer (:name "well-indented")
+ (insert (concat "(hello (world\n"
+ " 'elisp)\n"))
+ (emacs-lisp-mode)
+ (should (equal (ert-buffer-string-reindented) (buffer-string))))
+ (ert-with-test-buffer (:name "badly-indented")
+ (insert (concat "(hello\n"
+ " world)"))
+ (emacs-lisp-mode)
+ (should-not (equal (ert-buffer-string-reindented) (buffer-string)))))
+
+(defun ert--hash-table-to-alist (table)
+ (let ((accu nil))
+ (maphash (lambda (key value)
+ (push (cons key value) accu))
+ table)
+ (nreverse accu)))
+
+(ert-deftest ert-test-test-buffers ()
+ (let (buffer-1
+ buffer-2)
+ (let ((test-1
+ (make-ert-test
+ :name 'test-1
+ :body (lambda ()
+ (ert-with-test-buffer (:name "foo")
+ (should (string-match
+ "[*]Test buffer (ert-test-test-buffers): foo[*]"
+ (buffer-name)))
+ (setq buffer-1 (current-buffer))))))
+ (test-2
+ (make-ert-test
+ :name 'test-2
+ :body (lambda ()
+ (ert-with-test-buffer (:name "bar")
+ (should (string-match
+ "[*]Test buffer (ert-test-test-buffers): bar[*]"
+ (buffer-name)))
+ (setq buffer-2 (current-buffer))
+ (ert-fail "fail for test"))))))
+ (let ((ert--test-buffers (make-hash-table :weakness t)))
+ (ert-run-tests `(member ,test-1 ,test-2) #'ignore)
+ (should (equal (ert--hash-table-to-alist ert--test-buffers)
+ `((,buffer-2 . t))))
+ (should-not (buffer-live-p buffer-1))
+ (should (buffer-live-p buffer-2))))))
+
+
+(ert-deftest ert-filter-string ()
+ (should (equal (ert-filter-string "foo bar baz" "quux")
+ "foo bar baz"))
+ (should (equal (ert-filter-string "foo bar baz" "bar")
+ "foo baz")))
+
+(ert-deftest ert-propertized-string ()
+ (should (ert-equal-including-properties
+ (ert-propertized-string "a" '(a b) "b" '(c t) "cd")
+ #("abcd" 1 2 (a b) 2 4 (c t))))
+ (should (ert-equal-including-properties
+ (ert-propertized-string "foo " '(face italic) "bar" " baz" nil
+ " quux")
+ #("foo bar baz quux" 4 11 (face italic)))))
+
+
+;;; Tests for ERT itself that require test features from ert-x.el.
+
+(ert-deftest ert-test-run-tests-interactively-2 ()
+ :tags '(:causes-redisplay)
+ (let ((passing-test (make-ert-test :name 'passing-test
+ :body (lambda () (ert-pass))))
+ (failing-test (make-ert-test :name 'failing-test
+ :body (lambda ()
+ (ert-info ((propertize "foo\nbar"
+ 'a 'b))
+ (ert-fail
+ "failure message"))))))
+ (let ((ert-debug-on-error nil))
+ (let* ((buffer-name (generate-new-buffer-name "*ert-test-run-tests*"))
+ (messages nil)
+ (mock-message-fn
+ (lambda (format-string &rest args)
+ (push (apply #'format format-string args) messages))))
+ (flet ((expected-string (with-font-lock-p)
+ (ert-propertized-string
+ "Selector: (member <passing-test> <failing-test>)\n"
+ "Passed: 1\n"
+ "Failed: 1 (1 unexpected)\n"
+ "Total: 2/2\n\n"
+ "Started at:\n"
+ "Finished.\n"
+ "Finished at:\n\n"
+ `(category ,(button-category-symbol
+ 'ert--results-progress-bar-button)
+ button (t)
+ face ,(if with-font-lock-p
+ 'ert-test-result-unexpected
+ 'button))
+ ".F" nil "\n\n"
+ `(category ,(button-category-symbol
+ 'ert--results-expand-collapse-button)
+ button (t)
+ face ,(if with-font-lock-p
+ 'ert-test-result-unexpected
+ 'button))
+ "F" nil " "
+ `(category ,(button-category-symbol
+ 'ert--test-name-button)
+ button (t)
+ ert-test-name failing-test)
+ "failing-test"
+ nil "\n Info: " '(a b) "foo\n"
+ nil " " '(a b) "bar"
+ nil "\n (ert-test-failed \"failure message\")\n\n\n"
+ )))
+ (save-window-excursion
+ (unwind-protect
+ (let ((case-fold-search nil))
+ (ert-run-tests-interactively
+ `(member ,passing-test ,failing-test) buffer-name
+ mock-message-fn)
+ (should (equal messages `(,(concat
+ "Ran 2 tests, 1 results were "
+ "as expected, 1 unexpected"))))
+ (with-current-buffer buffer-name
+ (font-lock-mode 0)
+ (should (ert-equal-including-properties
+ (ert-filter-string (buffer-string)
+ '("Started at:\\(.*\\)$" 1)
+ '("Finished at:\\(.*\\)$" 1))
+ (expected-string nil)))
+ ;; `font-lock-mode' only works if interactive, so
+ ;; pretend we are.
+ (let ((noninteractive nil))
+ (font-lock-mode 1))
+ (should (ert-equal-including-properties
+ (ert-filter-string (buffer-string)
+ '("Started at:\\(.*\\)$" 1)
+ '("Finished at:\\(.*\\)$" 1))
+ (expected-string t)))))
+ (when (get-buffer buffer-name)
+ (kill-buffer buffer-name)))))))))
+
+(ert-deftest ert-test-describe-test ()
+ "Tests `ert-describe-test'."
+ (save-window-excursion
+ (ert-with-buffer-renamed ("*Help*")
+ (if (< emacs-major-version 24)
+ (should (equal (should-error (ert-describe-test 'ert-describe-test))
+ '(error "Requires Emacs 24")))
+ (ert-describe-test 'ert-test-describe-test)
+ (with-current-buffer "*Help*"
+ (let ((case-fold-search nil))
+ (should (string-match (concat
+ "\\`ert-test-describe-test is a test"
+ " defined in `ert-x-tests.elc?'\\.\n\n"
+ "Tests `ert-describe-test'\\.\n\\'")
+ (buffer-string)))))))))
+
+(ert-deftest ert-test-message-log-truncation ()
+ :tags '(:causes-redisplay)
+ (let ((test (make-ert-test
+ :body (lambda ()
+ ;; Emacs would combine messages if we
+ ;; generate the same message multiple
+ ;; times.
+ (message "a")
+ (message "b")
+ (message "c")
+ (message "d")))))
+ (let (result)
+ (ert-with-buffer-renamed ("*Messages*")
+ (let ((message-log-max 2))
+ (setq result (ert-run-test test)))
+ (should (equal (with-current-buffer "*Messages*"
+ (buffer-string))
+ "c\nd\n")))
+ (should (equal (ert-test-result-messages result) "a\nb\nc\nd\n")))))
+
+(ert-deftest ert-test-builtin-message-log-flushing ()
+ "This test attempts to demonstrate that there is no way to
+force immediate truncation of the *Messages* buffer from Lisp
+\(and hence justifies the existence of
+`ert--force-message-log-buffer-truncation'\): The only way that
+came to my mind was \(message \"\"\), which doesn't have the
+desired effect."
+ :tags '(:causes-redisplay)
+ (ert-with-buffer-renamed ("*Messages*")
+ (with-current-buffer "*Messages*"
+ (should (equal (buffer-string) ""))
+ ;; We used to get sporadic failures in this test that involved
+ ;; a spurious newline at the beginning of the buffer, before
+ ;; the first message. Below, we print a message and erase the
+ ;; buffer since this seems to eliminate the sporadic failures.
+ (message "foo")
+ (erase-buffer)
+ (should (equal (buffer-string) ""))
+ (let ((message-log-max 2))
+ (let ((message-log-max t))
+ (loop for i below 4 do
+ (message "%s" i))
+ (should (equal (buffer-string) "0\n1\n2\n3\n")))
+ (should (equal (buffer-string) "0\n1\n2\n3\n"))
+ (message "")
+ (should (equal (buffer-string) "0\n1\n2\n3\n"))
+ (message "Test message")
+ (should (equal (buffer-string) "3\nTest message\n"))))))
+
+(ert-deftest ert-test-force-message-log-buffer-truncation ()
+ :tags '(:causes-redisplay)
+ (labels ((body ()
+ (loop for i below 3 do
+ (message "%s" i)))
+ ;; Uses the implicit messages buffer truncation implemented
+ ;; in Emacs' C core.
+ (c (x)
+ (ert-with-buffer-renamed ("*Messages*")
+ (let ((message-log-max x))
+ (body))
+ (with-current-buffer "*Messages*"
+ (buffer-string))))
+ ;; Uses our lisp reimplementation.
+ (lisp (x)
+ (ert-with-buffer-renamed ("*Messages*")
+ (let ((message-log-max t))
+ (body))
+ (let ((message-log-max x))
+ (ert--force-message-log-buffer-truncation))
+ (with-current-buffer "*Messages*"
+ (buffer-string)))))
+ (loop for x in '(0 1 2 3 4 t) do
+ (should (equal (c x) (lisp x))))))
+
+
+(provide 'ert-x-tests)
+
+;;; ert-x-tests.el ends here