diff --git a/Makefile b/Makefile index fcfba1e1e..6e4cd645a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Ensure emacs always runs from this makefile's PWD EMACS_FLAGS=--eval "(setq user-emacs-directory default-directory)" EMACS=emacs --batch $(EMACS_FLAGS) -l core/core.el - +TESTS=$(patsubst %,-l %, $(wildcard test/test-*.el)) # Tasks all: install update autoloads @@ -33,6 +33,12 @@ clean: clean-cache: @$(EMACS) -f 'doom/clean-cache' +test: init.el + @$(EMACS) -f 'doom-initialize-autoloads' -l ert $(TESTS) -f ert-run-tests-batch-and-exit + +test/%: init.el + @$(EMACS) -f 'doom-initialize-autoloads' -l ert -l $@.el -f ert-run-tests-batch-and-exit + # Syntactic sugar for bootstrapping modules. Allows: make bootstrap javascript # See doom/bootstrap for more information. diff --git a/core/autoload/test.el b/core/autoload/test.el new file mode 100644 index 000000000..37b4ad9e5 --- /dev/null +++ b/core/autoload/test.el @@ -0,0 +1,9 @@ +;;; ../core/autoload/test.el + +;;;###autoload +(defmacro def-test-group! (name &rest body) + (declare (indent defun)) + (dolist (form body) + (when (eq (car form) 'ert-deftest) + (setf (cadr form) (intern (format "test-%s-%s" name (symbol-name (cadr form))))))) + `(progn ,@body)) diff --git a/test/test-basic.el b/test/test-basic.el new file mode 100644 index 000000000..5be1826ad --- /dev/null +++ b/test/test-basic.el @@ -0,0 +1,4 @@ +;;; ../test/test-basic.el + +(ert-deftest doom-basic () + (should t)) diff --git a/test/test-core-lib-buffers.el b/test/test-core-lib-buffers.el new file mode 100644 index 000000000..02bc011ee --- /dev/null +++ b/test/test-core-lib-buffers.el @@ -0,0 +1,36 @@ +;;; ../test/test-core-lib-buffers.el + +(def-test-group! core-lib-buffers + (ert-deftest get-buffers () + (let ((a (get-buffer-create "*a*")) + (b (get-buffer-create "*b*")) + (c (get-buffer-create "*c*")) + (buffers (doom-buffer-list))) + (should buffers) + (should (cl-every (lambda (b) (memq b buffers)) (list a b c))) + (should (cl-every 'bufferp buffers)))) + + (ert-deftest matching-buffers () + (let ((a (get-buffer-create "*a*")) + (b (get-buffer-create "*b*")) + (c (get-buffer-create "*c*")) + (buffers (doom-matching-buffers "^\\*[ac]\\*$"))) + (should (= 2 (length buffers))) + (should (cl-every (lambda (b) (memq b buffers)) (list a c))) + (should (cl-every 'bufferp buffers)))) + + (ert-deftest buffers-in-mode () + (dolist (name (list "*a*" "*b*")) + (with-current-buffer (get-buffer-create name) + (emacs-lisp-mode))) + (dolist (name (list "*c*" "*d*" "*e*")) + (with-current-buffer (get-buffer-create name) + (text-mode))) + (let ((el-buffers (doom-buffers-in-mode 'emacs-lisp-mode)) + (txt-buffers (doom-buffers-in-mode 'text-mode))) + (should (cl-every 'bufferp (append el-buffers txt-buffers))) + (should (= 2 (length el-buffers))) + (should (= 3 (length txt-buffers))))) + + ;; TODO + ) diff --git a/test/test-core-lib-package.el b/test/test-core-lib-package.el new file mode 100644 index 000000000..f96b24cc5 --- /dev/null +++ b/test/test-core-lib-package.el @@ -0,0 +1,78 @@ +;;; ../test/test-core-lib-package.el + +(defun test-package-new (name version &optional reqs) + (package-desc-create :name name :version version :reqs reqs)) + +;; TODO +(defmacro with-temp-packages! (&rest forms) + "Run FORMS in the context of a temporary package setup (as in, it won't +affects your Emacs packages)." + `(let* ((doom-local-dir ,(expand-file-name "test/.local/" doom-emacs-dir)) + (doom-packages-dir (concat doom-local-dir "packages/")) + (doom-etc-dir (concat doom-local-dir "etc/")) + (doom-cache-dir (concat doom-local-dir "cache/")) + (package-user-dir (expand-file-name "elpa" doom-packages-dir)) + package-alist + package-archive-contents + package-initialize) + (package-initialize) + ,@forms)) + + +;; +;; Tests +;; + +(def-test-group! core-lib-package + (ert-deftest backend-detection () + "TODO" + (let ((package-alist `((doom-dummy ,(test-package-new 'doom-dummy '(20160405 1234))))) + (quelpa-cache '((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist"))) + (quelpa-initialized-p t)) + (should (eq (doom-package-backend 'doom-dummy) 'elpa)) + (should (eq (doom-package-backend 'doom-quelpa-dummy) 'quelpa)))) + + (ert-deftest elpa-outdated-detection () + "TODO" + (let* ((doom--last-refresh (current-time)) + (package-alist + `((doom-dummy ,(test-package-new 'doom-dummy '(20160405 1234))))) + (package-archive-contents + `((doom-dummy ,(test-package-new 'doom-dummy '(20170405 1234))))) + (outdated (doom-package-outdated-p 'doom-dummy))) + (should outdated) + (should (equal outdated '(doom-dummy (20160405 1234) (20170405 1234)))))) + + ;; TODO quelpa-outdated-detection + + (ert-deftest get-packages () + "TODO" + (let ((quelpa-initialized-p t) + (doom-packages '((doom-dummy))) + (package-alist + `((doom-dummy nil) + (doom-dummy-dep nil))) + doom-protected-packages) + (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _)))) + (should (equal (doom-get-packages) '((doom-dummy))))))) + + (ert-deftest orphaned-packages () + "Test `doom-get-orphaned-packages', which gets a list of packages that are +no longer enabled or depended on." + (let ((doom-packages '((doom-dummy))) + (package-alist + `((doom-dummy ,(test-package-new 'doom-dummy '(20160405 1234) '((doom-dummy-dep (1 0))))) + (doom-dummy-unwanted ,(test-package-new 'doom-dummy-unwanted '(20160601 1234))) + (doom-dummy-dep ,(test-package-new 'doom-dummy-dep '(20160301 1234))))) + doom-protected-packages) + (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _)))) + (should (equal (doom-get-orphaned-packages) '(doom-dummy-unwanted)))))) + + (ert-deftest missing-packages () + "Test `doom-get-missing-packages, which gets a list of enabled packages that +aren't installed." + (let ((doom-packages '((doom-dummy) (doom-dummy-installed))) + (package-alist `((doom-dummy-installed ,(test-package-new 'doom-dummy-installed '(20160405 1234))))) + doom-protected-packages) + (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _)))) + (should (equal (doom-get-missing-packages) '((doom-dummy)))))))) diff --git a/test/test-core-lib.el b/test/test-core-lib.el new file mode 100644 index 000000000..357e317d2 --- /dev/null +++ b/test/test-core-lib.el @@ -0,0 +1,65 @@ +;;; ../test/test-core-lib.el + +(def-test-group! core-lib + ;; `add-hook!' + (ert-deftest add-one-to-one-hook () + (let (hooks) + (add-hook! 'hooks 'a-hook) + (should (equal hooks '(a-hook))))) + + (ert-deftest add-many-to-one-hook () + (let (hooks) + (add-hook! 'hooks '(hook-a hook-b hook-c)) + (should (equal hooks '(hook-c hook-b hook-a))))) + + (ert-deftest add-one-to-many-hooks () + (let (hooks-a hooks-b hooks-c) + (add-hook! '(hooks-a hooks-b hooks-c) 'a-hook) + (should (equal hooks-a '(a-hook))) + (should (equal hooks-b '(a-hook))) + (should (equal hooks-c '(a-hook))))) + + (ert-deftest add-many-to-many-hooks () + (let (hooks-a hooks-b hooks-c) + (add-hook! '(hooks-a hooks-b hooks-c) '(hook-a hook-b hook-c)) + (should (equal hooks-a '(hook-c hook-b hook-a))) + (should (equal hooks-b '(hook-c hook-b hook-a))) + (should (equal hooks-c '(hook-c hook-b hook-a))))) + + (ert-deftest add-non-literal-hooks () + (let (some-mode-hook) + (add-hook! some-mode 'a-hook) + (should (equal some-mode-hook '(a-hook))))) + + ;; `remove-hook!' + (ert-deftest remove-hooks () + (let ((hooks-a '(hook-c hook-b hook-a)) + (hooks-b '(hook-c hook-b hook-a)) + (hooks-c '(hook-c hook-b hook-a))) + (remove-hook! '(hooks-a hooks-b hooks-c) '(hook-a hook-b hook-c)) + (should (null hooks-a)) + (should (null hooks-b)) + (should (null hooks-c)))) + + ;; `add-transient-hook!' + (ert-deftest transient-hooks () + (let (hooks value) + (add-transient-hook! hooks (setq value t)) + (run-hooks 'hooks) + (should (eq value t)) + (should (null hooks)))) + + (ert-deftest transient-function () + (let (value) + (add-transient-hook! ignore (setq value (not value))) + (ignore t) + (should (eq value t)) + ;; repeat to ensure it was only run once + (ignore t) + (should (eq value t)))) + + ;; TODO `associate!' + + ;; TODO `def-setting!' & `set!' + + )