Move unit tests from ert to buttercup
Easier to organize and write. Now I can hopefully strive for better coverage!
This commit is contained in:
parent
98d2f1de3f
commit
eaca8c58fa
41 changed files with 1371 additions and 1101 deletions
|
@ -1,169 +0,0 @@
|
|||
;;; core/autoload/test.el -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
|
||||
(defun doom//run-tests (&optional modules)
|
||||
"Run all loaded tests, specified by MODULES (a list of module cons cells) or
|
||||
command line args following a double dash (each arg should be in the
|
||||
'module/submodule' format).
|
||||
|
||||
If neither is available, run all tests in all enabled modules."
|
||||
(interactive)
|
||||
(require 'core-packages)
|
||||
(doom//reload-autoloads)
|
||||
(let (noninteractive)
|
||||
;; Core libraries aren't fully loaded in a noninteractive session, so we
|
||||
;; reload it with `noninteractive' set to nil to force them to.
|
||||
(doom-initialize t)
|
||||
(doom-initialize-modules t))
|
||||
(condition-case-unless-debug ex
|
||||
(let ((target-paths
|
||||
;; Convert targets (either from MODULES or `argv') into a list of
|
||||
;; string paths, pointing to the root directory of modules
|
||||
(cond ((stringp (car modules)) ; command line
|
||||
(save-match-data
|
||||
(cl-loop for arg in modules
|
||||
if (string= arg ":core") collect doom-core-dir
|
||||
else if (string-match-p "/" arg)
|
||||
nconc (cl-loop for dir in doom-modules-dirs
|
||||
collect (expand-file-name arg dir))
|
||||
else
|
||||
nconc (cl-loop for dir in doom-modules-dirs
|
||||
for path = (expand-file-name arg dir)
|
||||
if (file-directory-p path)
|
||||
nconc
|
||||
(cl-remove-if-not
|
||||
#'file-directory-p
|
||||
(directory-files path t "^[^.]" t)))
|
||||
finally do (setq argv nil))))
|
||||
|
||||
(modules ; cons-cells given to MODULES
|
||||
(cl-loop for (module . submodule) in modules
|
||||
if (doom-module-locate-path module submodule)
|
||||
collect it))
|
||||
|
||||
((append (list doom-core-dir)
|
||||
(doom-module-load-path))))))
|
||||
;; Load all the unit test files...
|
||||
(dolist (path target-paths)
|
||||
(let ((test-path (expand-file-name "test/" path)))
|
||||
(when (file-directory-p test-path)
|
||||
(dolist (test-file (reverse (doom-files-in test-path :match "\\.el$" :full t)))
|
||||
(load test-file nil :noerror)))))
|
||||
;; ... then run them
|
||||
(switch-to-buffer (get-buffer-create "*blank*"))
|
||||
(if noninteractive
|
||||
(ert-run-tests-batch-and-exit)
|
||||
(call-interactively #'ert-run-tests-interactively)))
|
||||
('error
|
||||
(lwarn 'doom-test :error
|
||||
"%s -> %s"
|
||||
(car ex) (error-message-string ex)))))
|
||||
|
||||
|
||||
;; --- Test helpers -----------------------
|
||||
|
||||
(defmacro def-test! (name &rest body)
|
||||
"Define a namespaced ERT test."
|
||||
(declare (indent defun) (doc-string 2))
|
||||
(let (plist)
|
||||
(while (keywordp (car body))
|
||||
(push (pop body) plist)
|
||||
(push (pop body) plist))
|
||||
(setq plist (reverse plist))
|
||||
(when-let* ((modes (doom-enlist (plist-get plist :minor-mode))))
|
||||
(dolist (mode modes)
|
||||
(setq body `((with-minor-mode! ,mode ,@body)))))
|
||||
(when-let* ((before (plist-get plist :before)))
|
||||
(setq body `(,@before ,@body)))
|
||||
(when-let* ((after (plist-get plist :after)))
|
||||
(setq body `(,@body @after)))
|
||||
`(ert-deftest
|
||||
,(intern (format "%s::%s"
|
||||
(if (file-in-directory-p load-file-name doom-core-dir)
|
||||
(format "core/%s" (file-name-base load-file-name))
|
||||
(replace-regexp-in-string "^.*/modules/\\([^/]+\\)/\\([^/]+\\)/test/" "\\1/\\2:"
|
||||
(file-name-sans-extension load-file-name)))
|
||||
name))
|
||||
()
|
||||
,(if (plist-get plist :skip)
|
||||
`(ert-skip ,(plist-get plist :skip))
|
||||
`(with-temp-buffer
|
||||
(save-mark-and-excursion
|
||||
(save-window-excursion
|
||||
,@body)))))))
|
||||
|
||||
(defmacro should-buffer! (initial expected &rest body)
|
||||
"Test that a buffer with INITIAL text, run BODY, then test it against EXPECTED.
|
||||
|
||||
INITIAL will recognize cursor markers in the form {[0-9]}. A {0} marker marks
|
||||
where the cursor should be after setup. Otherwise, the cursor will be placed at
|
||||
`point-min'.
|
||||
|
||||
EXPECTED will recognize one (optional) cursor marker: {|}, this is the
|
||||
'expected' location of the cursor after BODY is finished, and will be tested
|
||||
against."
|
||||
(declare (indent 2))
|
||||
`(with-temp-buffer
|
||||
(cl-loop for line in ',initial
|
||||
do (insert line "\n"))
|
||||
(goto-char (point-min))
|
||||
(let (marker-list)
|
||||
(save-excursion
|
||||
(while (re-search-forward "{\\([0-9]\\)}" nil t)
|
||||
(push (cons (match-string 1)
|
||||
(set-marker (make-marker) (match-beginning 0)))
|
||||
marker-list)
|
||||
(replace-match "" t t))
|
||||
(if (not marker-list)
|
||||
(goto-char (point-min))
|
||||
(sort marker-list
|
||||
(lambda (m1 m2) (< (marker-position m1)
|
||||
(marker-position m2))))
|
||||
(when (equal (caar marker-list) "0")
|
||||
(goto-char! 0)))
|
||||
,@body
|
||||
(let ((result-text (buffer-string))
|
||||
(point (point))
|
||||
expected-text)
|
||||
(with-temp-buffer
|
||||
(cl-loop for line in ',expected
|
||||
do (insert line "\n"))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "{|}" nil t)
|
||||
(replace-match "" t t)
|
||||
(should (equal (point) point))))
|
||||
(setq expected-text (buffer-string))
|
||||
(should (equal expected-text result-text))))))))
|
||||
|
||||
(defmacro goto-char! (index)
|
||||
"Meant to be used with `should-buffer!'. Will move the cursor to one of the
|
||||
cursor markers. e.g. Go to marker {2} with (goto-char! 2)."
|
||||
`(goto-char (point! ,index)))
|
||||
|
||||
(defmacro point! (index)
|
||||
"Meant to be used with `should-buffer!'. Returns the position of a cursor
|
||||
marker. e.g. {2} can be retrieved with (point! 2)."
|
||||
`(cdr (assoc ,(cond ((numberp index) (number-to-string index))
|
||||
((symbolp index) (symbol-name index))
|
||||
((stringp index) index))
|
||||
marker-list)))
|
||||
|
||||
(defmacro with-minor-mode! (mode &rest body)
|
||||
"Activate a minor mode while in BODY, deactivating it after."
|
||||
(declare (indent defun))
|
||||
`(progn (,mode +1)
|
||||
,@body
|
||||
(,mode -1)))
|
||||
|
||||
(defmacro let-advice! (binds &rest body)
|
||||
"Temporarily bind advice in BINDS while in BODY.
|
||||
|
||||
e.g. (old-fn :before advice-fn)
|
||||
(old-fn :around advice-fn)"
|
||||
(declare (indent defun))
|
||||
`(progn
|
||||
,@(cl-loop for (target type advice) in binds
|
||||
collect `(advice-add #',target ,type #',advice))
|
||||
,@body
|
||||
,@(cl-loop for (target type advice) in binds
|
||||
collect `(advice-remove #',target #',advice))))
|
Loading…
Add table
Add a link
Reference in a new issue