diff --git a/core/autoload/test.el b/core/autoload/test.el deleted file mode 100644 index 98243f517..000000000 --- a/core/autoload/test.el +++ /dev/null @@ -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)))) diff --git a/core/core-dispatcher.el b/core/core-dispatcher.el index 229fc361a..34255dd32 100644 --- a/core/core-dispatcher.el +++ b/core/core-dispatcher.el @@ -172,7 +172,7 @@ respectively." (def-dispatcher! test "Run Doom unit tests." - (load! "autoload/test") + (require 'core-tests) (doom//run-tests args)) (def-dispatcher! info diff --git a/core/core-tests.el b/core/core-tests.el new file mode 100644 index 000000000..efcb89a8b --- /dev/null +++ b/core/core-tests.el @@ -0,0 +1,68 @@ +;;; core/core-tests.el -*- lexical-binding: 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) + (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. + (quiet! (doom//reload-autoloads)) + (doom-initialize t)) + (let ((target-paths + ;; Convert targets 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 (mapcar (apply-partially #'expand-file-name arg) + doom-modules-dirs) + else + nconc (cl-loop for dir in doom-modules-dirs + for path = (expand-file-name arg dir) + if (file-directory-p path) + nconc + (doom-files-in + path :type 'dirs :depth 1 :full 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... + (require 'buttercup) + (mapc (lambda (file) (load file :noerror (not doom-debug-mode))) + (doom-files-in (mapcar (apply-partially #'expand-file-name "test/") + target-paths) + :match "\\.el$" :full t)) + ;; ... then run them + (when doom-debug-mode + (setq buttercup-stack-frame-style 'pretty)) + (let ((split-width-threshold 0) + (split-height-threshold 0) + (window-min-width 0) + (window-min-height 0)) + (buttercup-run)))) + + +;; +(defmacro def-test! (_name &rest _body)) + +(defmacro insert! (&rest text) + "Insert TEXT in buffer, then move cursor to last {0} marker." + `(progn + (insert ,@text) + (when (search-backward "{0}" nil t) + (replace-match "" t t)))) + +(provide 'core-tests) +;;; core-tests.el ends here diff --git a/core/packages.el b/core/packages.el index a6f962fde..d640bcb90 100644 --- a/core/packages.el +++ b/core/packages.el @@ -39,3 +39,6 @@ ;; autoload/debug.el (package! esup) + +;; autoload/test.el +(package! buttercup) diff --git a/core/test/autoload-buffers.el b/core/test/autoload-buffers.el deleted file mode 100644 index 98242988a..000000000 --- a/core/test/autoload-buffers.el +++ /dev/null @@ -1,130 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; core/test/autoload-buffers.el - -(defmacro with-temp-buffers!! (buffer-args &rest body) - (declare (indent defun)) - (let (buffers) - (dolist (bsym buffer-args) - (push `(,bsym (get-buffer-create ,(symbol-name bsym))) - buffers)) - `(save-window-excursion - (cl-flet ((buffer-list - (lambda () - (cl-remove-if-not #'buffer-live-p (list ,@(reverse (mapcar #'car buffers))))))) - (let* ((split-width-threshold 0) - (window-min-width 0) - persp-mode - ,@buffers) - (delete-other-windows) - ,@body - (let (kill-buffer-query-functions kill-buffer-hook) - (mapc #'kill-buffer (buffer-list)))))))) - -;; -(def-test! get-buffers - (with-temp-buffers!! (a b c) - (should (cl-every #'buffer-live-p (buffer-list))) - (should (equal (buffer-list) (list a b c))) - (dolist (buf (list (cons a doom-emacs-dir) - (cons b doom-emacs-dir) - (cons c "/tmp/"))) - (with-current-buffer (car buf) - (setq-local default-directory (cdr buf)))) - (projectile-mode +1) - (with-current-buffer a - ;; should produce all buffers - (let ((buffers (doom-buffer-list))) - (should (cl-every (lambda (x) (memq x buffers)) (list a b c)))) - ;; should produce only project buffers - (let ((buffers (doom-project-buffer-list))) - (should (cl-every (lambda (x) (memq x buffers)) (list a b))) - (should-not (memq c buffers)))) - ;; If no project is available, just get all buffers - (with-current-buffer c - (let ((buffers (doom-project-buffer-list))) - (should (cl-every (lambda (x) (memq x buffers)) (list a b c))))) - (projectile-mode -1))) - -(def-test! real-buffers - (let (doom-real-buffer-functions) - (with-temp-buffers!! (a b c d) - (with-current-buffer a - (setq-local buffer-file-name "x")) - (with-current-buffer b - (setq-local doom-real-buffer-p t)) - (with-current-buffer c - (rename-buffer "*C*")) - (should (doom-real-buffer-p a)) - (should (doom-real-buffer-p b)) - (should-not (doom-real-buffer-p c)) - (should-not (doom-real-buffer-p d)) - (let ((buffers (doom-real-buffer-list))) - (should (= (length buffers) 2)) - (should (cl-every (lambda (x) (memq x buffers)) (list a b))) - (should (cl-notany (lambda (x) (memq x buffers)) (list c d))))))) - -;; `doom-visible-windows' -;; `doom-visible-buffers' -;; `doom-buried-buffers' -(def-test! visible-buffers-and-windows - (with-temp-buffers!! (a b c d) - (switch-to-buffer a) - (should (eq (current-buffer) a)) - (should (eq (selected-window) (get-buffer-window a))) - (split-window nil 1) - (switch-to-buffer b) - (should (eq (current-buffer) b)) - (should (eq (selected-window) (get-buffer-window b))) - (should (cl-intersection (list a b) (doom-visible-buffers))) - (should (cl-intersection (list c d) (doom-buried-buffers))) - (should (cl-intersection (mapcar #'get-buffer-window (list a b)) - (doom-visible-windows))))) - -;; `doom-matching-buffers' -(def-test! matching-buffers - (with-temp-buffers!! (a b c) - (let ((buffers (doom-matching-buffers "^[ac]$"))) - (should (= 2 (length buffers))) - (should (cl-every #'bufferp buffers)) - (should (cl-every (lambda (x) (memq x buffers)) (list a c))) - (should (equal buffers (doom-matching-buffers "^[ac]$")))))) - -;; `doom-buffers-in-mode' -(def-test! buffers-in-mode - (with-temp-buffers!! (a b c d e) - (dolist (buf (list a b)) - (with-current-buffer buf - (delay-mode-hooks (emacs-lisp-mode)))) - (dolist (buf (list c d e)) - (with-current-buffer buf - (text-mode))) - (let ((el-buffers (doom-buffers-in-mode 'emacs-lisp-mode)) - (txt-buffers (doom-buffers-in-mode 'text-mode))) - (should (cl-every #'buffer-live-p (append el-buffers txt-buffers))) - (should (= 2 (length el-buffers))) - (should (= 3 (length txt-buffers)))))) - -;; `doom-fallback-buffer' -(def-test! fallback-buffer - (let ((fallback (doom-fallback-buffer))) - (should (buffer-live-p fallback)) - (should (equal (buffer-name fallback) doom-fallback-buffer-name)))) - -;; `doom-kill-buffer-and-windows' -(def-test! kill-buffer-and-windows - (with-temp-buffers!! (a b) - (switch-to-buffer a) (split-window-horizontally) - (switch-to-buffer b) (split-window-horizontally) - (switch-to-buffer a) - - (should (= (length (doom-visible-windows)) 3)) - (should (= (length (doom-buffer-list)) 2)) - - (doom-kill-buffer-and-windows a) - (should-not (buffer-live-p a)) - (should (= (length (doom-visible-windows)) 1)))) - -;; TODO doom/kill-all-buffers -;; TODO doom/kill-other-buffers -;; TODO doom/kill-matching-buffers -;; TODO doom/cleanup-session diff --git a/core/test/autoload-help.el b/core/test/autoload-help.el deleted file mode 100644 index 262f8fecb..000000000 --- a/core/test/autoload-help.el +++ /dev/null @@ -1,17 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; core/test/autoload-help.el - -(def-test! what-face - (insert (propertize "Hello " 'face 'font-lock-keyword-face)) - (insert "world") - - (should (equal (doom/what-face (point-min)) '((font-lock-keyword-face) ()))) - (should-not (doom/what-face (point-max)))) - -(def-test! what-face-overlays - (insert "Hello world") - (let ((ov (make-overlay 1 6))) - (overlay-put ov 'face 'font-lock-keyword-face)) - - (should (equal (doom/what-face (point-min)) '(() (font-lock-keyword-face)))) - (should-not (doom/what-face (point-max)))) diff --git a/core/test/autoload-message.el b/core/test/autoload-message.el deleted file mode 100644 index 0cdae9f09..000000000 --- a/core/test/autoload-message.el +++ /dev/null @@ -1,41 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; core/test/autoload-message.el - -;; ansi messages -(def-test! ansi-format - (let ((noninteractive t)) - (should (equal (format! "Hello %s" "World") - "Hello World")) - (should (equal (format! (red "Hello %s" "World")) - "Hello World")) - (should (equal (format! (green "Hello %s" "World")) - (format "\e[%dm%s\e[0m" - (cadr (assq 'green doom-message-fg)) - "Hello World"))) - (should (equal (format! (on-red "Hello %s" "World")) - (format "\e[%dm%s\e[0m" - (cadr (assq 'on-red doom-message-bg)) - "Hello World"))) - (should (equal (format! (bold "Hello %s" "World")) - (format "\e[%dm%s\e[0m" - (cadr (assq 'bold doom-message-fx)) - "Hello World"))))) - -(def-test! ansi-format-nested - (let ((noninteractive t)) - (should (equal (format! (bold (red "Hello %s" "World"))) - (format "\e[%dm%s\e[0m" 1 - (format "\e[%dm%s\e[0m" 31 "Hello World")))) - (should (equal (format! (on-red (bold "Hello %s" "World"))) - (format "\e[%dm%s\e[0m" 41 - (format "\e[%dm%s\e[0m" 1 "Hello World")))) - (should (equal (format! (dark (white "Hello %s" "World"))) - (format "\e[%dm%s\e[0m" 2 - (format "\e[%dm%s\e[0m" 37 "Hello World")))))) - -(def-test! ansi-format-apply - (let ((noninteractive t)) - (should (equal (format! (color 'red "Hello %s" "World")) - (format! (red "Hello %s" "World")))) - (should (equal (format! (color (if nil 'red 'blue) "Hello %s" "World")) - (format! (blue "Hello %s" "World")))))) diff --git a/core/test/autoload-package.el b/core/test/autoload-package.el deleted file mode 100644 index cb5f8595e..000000000 --- a/core/test/autoload-package.el +++ /dev/null @@ -1,72 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; core/test/autoload-package.el - -(require 'package) -(require 'quelpa) - -(defun -pkg (name version &optional reqs) - (package-desc-create :name name :version version :reqs reqs)) - -(defmacro with-packages!! (packages package-descs &rest body) -`(let* ((doom-packages-dir ,(expand-file-name "packages/" (file-name-directory load-file-name))) - (package-user-dir ,(expand-file-name "elpa" doom-packages-dir)) - (quelpa-dir ,(expand-file-name "quelpa" doom-packages-dir))) - ;; (make-directory doom-packages-dir t) - (let ((doom-packages ,packages) - (package-alist ,package-descs) - doom-core-packages) - (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _)))) - ,@body)) - ;; (delete-directory doom-packages-dir t) - )) - - -;; -;; Tests -;; - -(def-test! backend-detection - (let ((package-alist `((doom-dummy ,(-pkg '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)) - (should (eq (doom-package-backend 'org) 'emacs)))) - -(def-test! elpa-outdated-detection - (let* ((package-alist - `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234))))) - (package-archive-contents - `((doom-dummy ,(-pkg 'doom-dummy '(20170405 1234)))))) - (cl-letf (((symbol-function 'package-refresh-contents) (lambda (&rest _)))) - (should (equal (doom-package-outdated-p 'doom-dummy) - '(doom-dummy (20160405 1234) (20170405 1234))))))) - -;; TODO quelpa-outdated-detection - -(def-test! get-packages - (let ((quelpa-initialized-p t)) - (with-packages!! - '((doom-dummy)) - '((doom-dummy nil) - (doom-dummy-unwanted nil) - (doom-dummy-dep nil)) - (should (equal (doom-get-packages) '((doom-dummy))))))) - -(def-test! orphaned-packages - "Test `doom-get-orphaned-packages', which gets a list of packages that are -no longer enabled or depended on." - (with-packages!! - '((doom-dummy)) - `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234) '((doom-dummy-dep (1 0))))) - (doom-dummy-unwanted ,(-pkg 'doom-dummy-unwanted '(20160601 1234))) - (doom-dummy-dep ,(-pkg 'doom-dummy-dep '(20160301 1234)))) - (should (equal (doom-get-orphaned-packages) '(doom-dummy-unwanted))))) - -(def-test! missing-packages - "Test `doom-get-missing-packages, which gets a list of enabled packages that -aren't installed." - (with-packages!! - '((doom-dummy) (doom-dummy-installed)) - `((doom-dummy-installed ,(-pkg 'doom-dummy-installed '(20160405 1234)))) - (should (equal (doom-get-missing-packages) '((doom-dummy)))))) diff --git a/core/test/core-lib.el b/core/test/core-lib.el deleted file mode 100644 index bf1d1a934..000000000 --- a/core/test/core-lib.el +++ /dev/null @@ -1,116 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; core/test/core-lib.el - -;; --- Helpers ---------------------------- - -;; `doom--resolve-path-forms' -(def-test! resolve-path-forms - (should - (equal (doom--resolve-path-forms '(and "fileA" "fileB")) - '(and (file-exists-p (expand-file-name "fileA" nil)) - (file-exists-p (expand-file-name "fileB" nil)))))) - -;; `doom--resolve-hook-forms' -(def-test! resolve-hook-forms - (should (equal (doom--resolve-hook-forms '(js2-mode haskell-mode)) - '(js2-mode-hook haskell-mode-hook))) - (should (equal (doom--resolve-hook-forms '(quote (js2-mode-hook haskell-mode-hook))) - '(js2-mode-hook haskell-mode-hook)))) - -;; `doom-unquote' -(def-test! unquote - (should (equal (doom-unquote '(quote (a b c))) '(a b c))) - ;; nested - (should (equal (doom-unquote '(quote (quote (a b c)))) '(a b c))) - ;; sub-quote - (should (equal (doom-unquote '(quote (a (quote b) c))) '(a (quote b) c))) - ;; function - (should (equal (doom-unquote '(function a)) 'a))) - -;; `doom-enlist' -(def-test! enlist - (should (equal (doom-enlist 'a) '(a))) - (should (equal (doom-enlist '(a)) '(a)))) - - -;; --- Macros ----------------------------- - -;; `add-hook!' -(def-test! add-one-to-one-hook - (let ((hooks '(old-hook))) - (add-hook! 'hooks 'a-hook) - (should (equal hooks '(a-hook old-hook))))) - -(def-test! add-many-to-one-hook - (let ((hooks '(hook-x))) - (add-hook! 'hooks '(hook-a hook-b hook-c)) - (should (equal hooks '(hook-a hook-b hook-c hook-x))))) - -(def-test! 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))))) - -(def-test! 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-a hook-b hook-c))) - (should (equal hooks-b '(hook-a hook-b hook-c))) - (should (equal hooks-c '(hook-a hook-b hook-c))))) - -(def-test! add-non-literal-hooks - (let (some-mode-hook) - (add-hook! some-mode 'a-hook) - (should (equal some-mode-hook '(a-hook))))) - -;; `remove-hook!' -(def-test! 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)))) - -(def-test! remove-hook-forms - (let (hooks) - (add-hook! 'hooks (message "Hello world")) - (should hooks) - (remove-hook! 'hooks (message "Hello world")) - (should (null hooks)))) - -;; `add-transient-hook!' -(def-test! transient-hooks - (let (hooks value) - (add-transient-hook! 'hooks (setq value t)) - (run-hooks 'hooks) - (should (eq value t)) - (should (null hooks)))) - -(def-test! 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!' - - -;; --- Settings --------------------------- - -(def-test! set - (eval-and-compile - (def-setting! :-test-setting (x) `(setq result ,x)) - (should (fboundp 'doom--set:-test-setting)) - (let ((inhibit-message t) - result) - (set! :-test-setting t) - (should result) - (set! :non-existant-setting (error "This shouldn't trigger"))))) diff --git a/core/test/core-projects.el b/core/test/core-projects.el deleted file mode 100644 index 47435061b..000000000 --- a/core/test/core-projects.el +++ /dev/null @@ -1,47 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; ../core/test/core-projects.el - -(require 'projectile) - -;; -;; `doom-project-p' -(def-test! project-p - :minor-mode projectile-mode - (let ((buffer-file-name (expand-file-name "init.el" doom-emacs-dir)) - (default-directory doom-emacs-dir)) - (should (doom-project-p))) - (let ((buffer-file-name (expand-file-name "test" "~")) - (default-directory (expand-file-name "~"))) - (should-not (doom-project-p)))) - -;; `doom-project-root' -(def-test! project-root - :minor-mode projectile-mode - ;; Should resolve to project root - (let ((buffer-file-name (expand-file-name "core.el" doom-core-dir)) - (default-directory doom-core-dir)) - (should (equal (doom-project-root) doom-emacs-dir))) - ;; Should resolve to `default-directory' if not a project - (let ((buffer-file-name (expand-file-name "test" "~")) - (default-directory (expand-file-name "~"))) - (should (equal (doom-project-root) default-directory)))) - -;; `doom-project-expand' -(def-test! project-expand - :minor-mode projectile-mode - (let ((default-directory doom-core-dir)) - (should (equal (doom-project-expand "init.el") - (expand-file-name "init.el" (doom-project-root)))))) - -;; `project-file-exists-p!' -(def-test! project-has! - :minor-mode projectile-mode - (let ((default-directory doom-core-dir)) - ;; Resolve from project root - (should (project-file-exists-p! "init.el")) - ;; Chained file checks - (should (project-file-exists-p! (and "init.el" "LICENSE"))) - (should (project-file-exists-p! (or "init.el" "does-not-exist"))) - (should (project-file-exists-p! (and "init.el" (or "LICENSE" "does-not-exist")))) - ;; Should resolve relative paths from `default-directory' - (should (project-file-exists-p! (and "core/core.el" "./init.el"))))) diff --git a/core/test/core-ui.el b/core/test/core-ui.el deleted file mode 100644 index 9491628a7..000000000 --- a/core/test/core-ui.el +++ /dev/null @@ -1,34 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; ../core/test/core-ui.el - -(defmacro with-temp-windows!! (&rest body) - (declare (indent defun)) - `(cl-flet ((split-window (symbol-function #'split-window-horizontally))) - (delete-other-windows) - (let ((a (get-buffer-create "a")) - (b (get-buffer-create "b")) - (split-width-threshold 0) - (window-min-width 0)) - ,@body))) - -;; -(def-test! set-mode-name - (let ((after-change-major-mode-hook '(doom|set-mode-name)) - (doom-major-mode-names '((text-mode . "abc") - (lisp-mode . (lambda () "xyz")) - (js-mode . t)))) - (text-mode) - (should (equal mode-name "abc")) - (lisp-mode) - (should (equal mode-name "xyz")) - (should-error (js-mode)))) - -(def-test! protect-visible-buffers - (with-temp-windows!! - (let ((kill-buffer-query-functions '(doom|protect-visible-buffers))) - (switch-to-buffer a) (split-window) - (switch-to-buffer b) (split-window) - (switch-to-buffer a) - (should-not (kill-buffer)) - (select-window (get-buffer-window b)) - (should (kill-buffer))))) diff --git a/core/test/test-autoload-buffers.el b/core/test/test-autoload-buffers.el new file mode 100644 index 000000000..931c4ddfa --- /dev/null +++ b/core/test/test-autoload-buffers.el @@ -0,0 +1,114 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-autoload-buffers.el + +(load! "autoload/buffers" doom-core-dir) + +;; +(describe "core/autoload/buffers" + :var (a b c d) + (before-all + (spy-on 'buffer-list :and-call-fake + (lambda (&optional _) + (cl-remove-if-not #'buffer-live-p (list a b c d))))) + (before-each + (delete-other-windows) + (setq a (switch-to-buffer (get-buffer-create "a")) + b (get-buffer-create "b") + c (get-buffer-create "c") + d (get-buffer-create "d"))) + (after-each + (kill-buffer a) + (kill-buffer b) + (kill-buffer c) + (kill-buffer d)) + + (describe "buffer-list" + (it "should only see four buffers" + (expect (doom-buffer-list) :to-have-same-items-as (list a b c d)))) + + (describe "project-buffer-list" + :var (projectile-projects-cache-time projectile-projects-cache) + (before-all (require 'projectile)) + (after-all (unload-feature 'projectile t)) + + (before-each + (with-current-buffer a (setq default-directory doom-emacs-dir)) + (with-current-buffer b (setq default-directory doom-emacs-dir)) + (with-current-buffer c (setq default-directory "/tmp/")) + (with-current-buffer d (setq default-directory "~")) + (projectile-mode +1)) + (after-each + (projectile-mode -1)) + + (it "returns buffers in the same project" + (with-current-buffer a + (expect (doom-project-buffer-list) + :to-have-same-items-as (list a b)))) + + (it "returns all buffers if not in a project" + (with-current-buffer c + (expect (doom-project-buffer-list) + :to-have-same-items-as (buffer-list))))) + + (describe "fallback-buffer" + (it "returns a live buffer" + (expect (buffer-live-p (doom-fallback-buffer))))) + + (describe "real buffers" + (before-each + (doom-set-buffer-real a t) + (with-current-buffer b (setq buffer-file-name "x")) + (with-current-buffer c (rename-buffer "*C*"))) + + (describe "real-buffer-p" + (it "returns t for buffers manually marked real" + (expect (doom-real-buffer-p a))) + (it "returns t for file-visiting buffers" + (expect (doom-real-buffer-p b))) + (it "returns nil for temporary buffers" + (expect (doom-real-buffer-p c) :to-be nil) + (expect (doom-real-buffer-p d) :to-be nil))) + + (describe "real-buffer-list" + (it "returns only real buffers" + (expect (doom-real-buffer-list) :to-have-same-items-as (list a b))))) + + (describe "buffer/window management" + (describe "buffer search methods" + (before-each + (with-current-buffer a (lisp-mode)) + (with-current-buffer b (text-mode)) + (with-current-buffer c (text-mode)) + (split-window) + (switch-to-buffer b)) + + (it "can match buffers by regexp" + (expect (doom-matching-buffers "^[ac]$") :to-have-same-items-as (list a c))) + (it "can match buffers by major-mode" + (expect (doom-buffers-in-mode 'text-mode) :to-have-same-items-as (list b c))) + (it "can find all buried buffers" + (expect (doom-buried-buffers) + :to-have-same-items-as (list c d))) + (it "can find all visible buffers" + (expect (doom-visible-buffers) + :to-have-same-items-as (list a b))) + (it "can find all visible windows" + (expect (doom-visible-windows) + :to-have-same-items-as + (mapcar #'get-buffer-window (list a b))))) + + (describe "kill-buffer-and-windows" + (before-each + (split-window) (switch-to-buffer b) + (split-window) (switch-to-buffer a)) + + (it "kills the selected buffers and all its windows" + (doom-kill-buffer-and-windows a) + (expect (buffer-live-p a) :to-be nil) + (expect (length (doom-visible-windows)) :to-be 1))) + + ;; TODO + (describe "kill-all-buffers") + (describe "kill-other-buffers") + (describe "kill-matching-buffers") + (describe "cleanup-session"))) diff --git a/core/test/test-autoload-files.el b/core/test/test-autoload-files.el new file mode 100644 index 000000000..996cd7e17 --- /dev/null +++ b/core/test/test-autoload-files.el @@ -0,0 +1,54 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-autoload-files.el + +(describe "core/autoload/files" + :var (src dest projectile-projects-cache-time projectile-projects-cache) + (before-all (require 'projectile)) + (after-all (unload-feature 'projectile t)) + + (before-each + (setq src (make-temp-file "test-src") + existing (make-temp-file "test-existing") + dest (expand-file-name "test-dest" temporary-file-directory)) + (quiet! (find-file-literally src)) + (spy-on 'y-or-n-p :and-return-value nil) + (projectile-mode +1)) + + (after-each + (projectile-mode -1) + (switch-to-buffer (doom-fallback-buffer)) + (ignore-errors (delete-file src)) + (ignore-errors (delete-file existing)) + (ignore-errors (delete-file dest))) + + (describe "move-this-file" + (it "won't move to itself" + (expect (quiet! (doom/move-this-file src)) :to-throw)) + (it "will move to another file" + (expect (quiet! (doom/move-this-file dest t))) + (expect (file-exists-p dest)) + (expect (file-exists-p src) :to-be nil)) + (it "will prompt if overwriting a file" + (quiet! (doom/move-this-file existing)) + (expect 'y-or-n-p :to-have-been-called-times 1) + (expect (file-exists-p src)))) + + (describe "copy-this-file" + (it "refuses to copy to itself" + (expect (quiet! (doom/copy-this-file src)) :to-throw)) + (it "copies to another file" + (expect (quiet! (doom/copy-this-file dest t))) + (expect (file-exists-p! src dest))) + (it "prompts if overwriting a file" + (quiet! (quiet! (doom/copy-this-file existing))) + (expect 'y-or-n-p :to-have-been-called-times 1))) + + (describe "delete-this-file" + (it "fails gracefully on non-existent files" + (expect (quiet! (doom/delete-this-file dest)) :to-throw)) + (it "deletes existing files" + (quiet! (doom/delete-this-file existing t)) + (expect (file-exists-p existing) :to-be nil)) + (it "prompts to delete any existing file" + (quiet! (doom/delete-this-file existing)) + (expect 'y-or-n-p :to-have-been-called-times 1)))) diff --git a/core/test/test-autoload-help.el b/core/test/test-autoload-help.el new file mode 100644 index 000000000..765e51f95 --- /dev/null +++ b/core/test/test-autoload-help.el @@ -0,0 +1,31 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-autoload-help.el + +(load! "autoload/help" doom-core-dir) + +;; +(describe "core/autoload/help" + :var (a) + (before-each (setq a (switch-to-buffer (get-buffer-create "a")))) + (after-each (kill-buffer a)) + + (describe "what-face" + (before-each + (insert (propertize "Hello " 'face 'font-lock-keyword-face)) + (insert "world")) + (it "returns list of faces at point" + (expect (doom/what-face (point-min)) :to-equal '((font-lock-keyword-face) ()))) + (it "returns nil if no faces at point" + (expect (doom/what-face (point-max)) :to-be nil))) + + (describe "what-face overlays" + (before-each + (insert "Hello world") + (let ((ov (make-overlay 1 6))) + (overlay-put ov 'face 'font-lock-keyword-face))) + + (it "returns list of overlays at point" + (expect (doom/what-face (point-min)) :to-equal '(() (font-lock-keyword-face)))) + (it "returns nil if no overlays at point" + (expect (doom/what-face (point-max)) :to-be nil)))) + diff --git a/core/test/test-autoload-message.el b/core/test/test-autoload-message.el new file mode 100644 index 000000000..bc8644786 --- /dev/null +++ b/core/test/test-autoload-message.el @@ -0,0 +1,37 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-autoload-message.el + +(describe "core/autoload/message" + (describe "format!" + :var (noninteractive) + (before-all (setq noninteractive t)) + + (it "should be a drop-in replacement for `format'" + (expect (format! "Hello %s" "World") + :to-equal "Hello World")) + + (it "supports ansi coloring in noninteractive sessions" + (expect (format! (red "Hello %s" "World")) + :to-equal "Hello World")) + + (it "supports faces in interactive sessions" + (let (noninteractive) + (expect (get-text-property 0 'face (format! (red "Hello %s" "World"))) + :to-equal (list :foreground (face-foreground 'term-color-red))))) + + (it "supports nested color specs" + (expect (format! (bold (red "Hello %s" "World"))) + :to-equal (format "\e[%dm%s\e[0m" 1 + (format "\e[%dm%s\e[0m" 31 "Hello World"))) + (expect (format! (on-red (bold "Hello %s" "World"))) + :to-equal (format "\e[%dm%s\e[0m" 41 + (format "\e[%dm%s\e[0m" 1 "Hello World"))) + (expect (format! (dark (white "Hello %s" "World"))) + :to-equal (format "\e[%dm%s\e[0m" 2 + (format "\e[%dm%s\e[0m" 37 "Hello World")))) + + (it "supports dynamic color apply syntax" + (expect (format! (color 'red "Hello %s" "World")) + :to-equal (format! (red "Hello %s" "World"))) + (expect (format! (color (if nil 'red 'blue) "Hello %s" "World")) + :to-equal (format! (blue "Hello %s" "World")))))) diff --git a/core/test/test-autoload-package.el b/core/test/test-autoload-package.el new file mode 100644 index 000000000..73ba65722 --- /dev/null +++ b/core/test/test-autoload-package.el @@ -0,0 +1,128 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-autoload-package.el + +(describe "core/autoload/packages" + :var (package-alist + package-archive-contents + doom-packages + quelpa-cache + quelpa-initialized-p + doom-packages-dir + doom-core-packages + package-user-dir + quelpa-dir + pkg) + + (before-all + (fset 'pkg + (lambda (name version &optional reqs) + (package-desc-create :name name :version version :reqs reqs))) + (require 'package) + (require 'quelpa) + (setq doom-packages-dir (expand-file-name "packages/" (file-name-directory load-file-name)) + package-user-dir (expand-file-name "elpa" doom-packages-dir) + quelpa-dir (expand-file-name "quelpa" doom-packages-dir) + quelpa-initialized-p t + doom-core-packages nil) + (spy-on #'doom-initialize-packages :and-call-fake (lambda (&optional _))) + (spy-on #'package-refresh-contents :and-call-fake (lambda (&optional _))) + (spy-on #'quelpa-checkout :and-call-fake + (lambda (rcp _dir) + (when (eq (car rcp) 'doom-quelpa-dummy) + "20170405.1234")))) + + (after-all + (unload-feature 'package t) + (unload-feature 'quelpa t)) + + (before-each + (setq package-alist + `((doom-dummy ,(pkg 'doom-dummy '(20160405 1234))) + (doom-uptodate-dummy ,(pkg 'doom-uptodate-dummy '(20160605 1234))) + (doom-unwanted-dummy ,(pkg 'doom-unwanted-dummy '(20160605 1234))) + (doom-quelpa-dummy ,(pkg 'doom-quelpa-dummy '(20160405 1234))) + (doom-noquelpa-dummy ,(pkg 'doom-noquelpa-dummy '(20160405 1234)))) + package-archive-contents + `((doom-dummy ,(pkg 'doom-dummy '(20170405 1234))) + (doom-uptodate-dummy ,(pkg 'doom-uptodate-dummy '(20160605 1234)))) + doom-packages + '((doom-dummy) + (doom-uptodate-dummy) + (doom-missing-dummy) + (doom-noquelpa-dummy) + (doom-disabled-dummy :disable t) + (doom-private-dummy :private t) + (doom-disabled-private-dummy :private t :disable t) + (doom-quelpa-dummy :recipe (doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist"))) + quelpa-cache + '((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist") + (doom-noquelpa-dummy :fetcher github :repo "hlissner/does-not-exist-3") + (doom-new-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist-2")))) + + (describe "package-backend" + (it "determines the correct backend of a package" + (expect (doom-package-backend 'doom-dummy) :to-be 'elpa) + (expect (doom-package-backend 'doom-quelpa-dummy) :to-be 'quelpa) + (expect (doom-package-backend 'org) :to-be 'emacs)) + (it "errors out if package isn't installed" + (expect (doom-package-backend 'xyz) :to-throw))) + + (describe "package-outdated-p (elpa)" + (it "detects outdated ELPA packages and returns both versions" + (expect (doom-package-outdated-p 'doom-dummy) + :to-equal '(doom-dummy (20160405 1234) (20170405 1234)))) + (it "ignores up-to-date ELPA packages" + (expect (doom-package-outdated-p 'doom-uptodate-dummy) :to-be nil)) + + (it "detects outdated QUELPA packages and returns both versions" + (expect (doom-package-outdated-p 'doom-quelpa-dummy) + :to-equal '(doom-quelpa-dummy (20160405 1234) (20170405 1234)))) + (it "ignores up-to-date QUELPA packages" + (expect (doom-package-outdated-p 'doom-uptodate-dummy) :to-be nil)) + + (it "returns nil if package isn't installed" + (expect (doom-package-outdated-p 'xyz) :to-be nil))) + + (describe "get-packages" + (it "returns all packages" + (expect (mapcar #'car (doom-get-packages)) + :to-have-same-items-as + (mapcar #'car doom-packages))) + (it "returns only disabled packages" + (expect (mapcar #'car (doom-get-packages :disabled t)) + :to-have-same-items-as + '(doom-disabled-dummy doom-disabled-private-dummy))) + (it "returns only non-disabled packages" + (expect (mapcar #'car (doom-get-packages :disabled nil)) + :to-have-same-items-as + '(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-missing-dummy doom-noquelpa-dummy doom-private-dummy))) + (it "returns only installed packages" + (expect (mapcar #'car (doom-get-packages :disabled nil :installed t)) + :to-have-same-items-as + '(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-noquelpa-dummy))) + (it "returns only non-installed packages" + (expect (mapcar #'car (doom-get-packages :disabled nil :installed nil)) + :to-have-same-items-as + '(doom-missing-dummy doom-private-dummy))) + (it "returns only private packages" + (expect (mapcar #'car (doom-get-packages :private t)) + :to-have-same-items-as + '(doom-private-dummy doom-disabled-private-dummy))) + (it "returns only disabled and private packages" + (expect (mapcar #'car (doom-get-packages :disabled t :private t)) + :to-have-same-items-as + '(doom-disabled-private-dummy)))) + + (describe "get-orphaned-packages" + (it "returns orphaned packages" + (expect (doom-get-orphaned-packages) :to-contain 'doom-unwanted-dummy)) + (it "returns packages that have changed backends" + (expect (doom-get-orphaned-packages) :to-contain 'doom-noquelpa-dummy))) + + (describe "get-missing-packages" + (it "returns packages that haven't been installed" + (expect (mapcar #'car (doom-get-missing-packages)) + :to-contain 'doom-missing-dummy)) + (it "returns packages that have changed backends" + (expect (mapcar #'car (doom-get-missing-packages)) + :to-contain 'doom-noquelpa-dummy)))) diff --git a/core/test/test-core-lib.el b/core/test/test-core-lib.el new file mode 100644 index 000000000..761cd49a2 --- /dev/null +++ b/core/test/test-core-lib.el @@ -0,0 +1,90 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-core-lib.el + +(describe "core/lib" + ;; --- Helpers ---------------------------- + (describe "doom-unquote" + (it "unquotes a quoted form" + (expect (doom-unquote '(quote hello)) :to-be 'hello)) + (it "unquotes nested-quoted forms" + (expect (doom-unquote '(quote (quote (a b c)))) :to-equal '(a b c))) + (it "unquotes function-quoted forms" + (expect (doom-unquote '(function a)) :to-be 'a)) + (it "does nothing to unquoted forms" + (expect (doom-unquote 'hello) :to-be 'hello))) + + (describe "doom-enlist" + (it "creates a list out of non-lists" + (expect (doom-enlist 'a) :to-equal '(a))) + (it "does nothing to lists" + (expect (doom-enlist '(a)) :to-equal '(a)))) + + + ;; --- Macros ----------------------------- + (describe "hooks" + (describe "add-hook!" + :var (fake-mode-hook other-mode-hook some-mode-hook) + (before-each + (setq fake-mode-hook '(first-hook) + other-mode-hook nil + some-mode-hook '(first-hook second-hook))) + + (it "adds one-to-one hook" + (add-hook! fake-mode #'hook-2) + (add-hook! 'fake-mode-hook #'hook-1) + (expect fake-mode-hook :to-equal '(hook-1 hook-2 first-hook))) + + (it "adds many-to-one hook" + (add-hook! (fake-mode other-mode some-mode) #'hook-2) + (add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) #'hook-1) + (add-hook! :append (fake-mode other-mode some-mode) #'last-hook) + (expect fake-mode-hook :to-equal '(hook-1 hook-2 first-hook last-hook)) + (expect other-mode-hook :to-equal '(hook-1 hook-2 last-hook)) + (expect some-mode-hook :to-equal '(hook-1 hook-2 first-hook second-hook last-hook))) + + (it "adds many-to-many hooks and preserve provided order" + (add-hook! (fake-mode other-mode some-mode) #'(hook-3 hook-4)) + (add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) #'(hook-1 hook-2)) + (add-hook! :append '(fake-mode-hook other-mode-hook some-mode-hook) #'(last-hook-1 last-hook-2)) + (expect fake-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 first-hook last-hook-1 last-hook-2)) + (expect other-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 last-hook-1 last-hook-2)) + (expect some-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 first-hook second-hook last-hook-1 last-hook-2))) + + (it "adds implicit lambda to one hook" + (add-hook! fake-mode (progn)) + (add-hook! 'other-mode-hook (ignore)) + (add-hook! :append 'some-mode-hook (ignore)) + (expect (caar fake-mode-hook) :to-be 'lambda) + (expect (caar other-mode-hook) :to-be 'lambda) + (expect (caar (last other-mode-hook)) :to-be 'lambda))) + + (describe "remove-hook!" + :var (fake-mode-hook) + (before-each + (setq fake-mode-hook '(first-hook second-hook third-hook fourth-hook))) + (it "removes one hook" + (remove-hook! fake-mode #'third-hook) + (remove-hook! 'fake-mode-hook #'second-hook) + (expect fake-mode-hook :to-equal '(first-hook fourth-hook))) + (it "removes multiple hooks" + (remove-hook! fake-mode #'(first-hook third-hook)) + (remove-hook! 'fake-mode-hook #'(second-hook fourth-hook)) + (expect fake-mode-hook :to-be nil)))) + + (describe "add-transient-hook!" + (it "adds a transient function to hooks" + (let (hooks value) + (add-transient-hook! 'hooks (setq value t)) + (run-hooks 'hooks) + (expect value) + (expect hooks :to-be nil))) + (it "advises a function with a transient advisor" + (let (value) + (add-transient-hook! #'ignore (setq value (not value))) + (ignore t) + (expect value) + ;; repeat to ensure it was only run once + (ignore t) + (expect value)))) + + (xdescribe "associate!")) ; TODO diff --git a/core/test/test-core-modules.el b/core/test/test-core-modules.el new file mode 100644 index 000000000..bd9aea708 --- /dev/null +++ b/core/test/test-core-modules.el @@ -0,0 +1,4 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-core-modules.el + +(describe "core-modules") diff --git a/core/test/test-core-packages.el b/core/test/test-core-packages.el new file mode 100644 index 000000000..ff3104b76 --- /dev/null +++ b/core/test/test-core-packages.el @@ -0,0 +1,4 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-core-packages.el + +(describe "core-packages") diff --git a/core/test/test-core-projects.el b/core/test/test-core-projects.el new file mode 100644 index 000000000..e2c715283 --- /dev/null +++ b/core/test/test-core-projects.el @@ -0,0 +1,46 @@ +;; -*- no-byte-compile: t; -*- +;;; ../core/test/test-core-projects.el + +(require 'core-projects) + +(describe "core/projects" + (before-all (require 'projectile)) + (after-all (unload-feature 'projectile t)) + + (before-each (projectile-mode +1)) + (after-each (projectile-mode -1)) + + (describe "project-p" + (it "Should detect when in a valid project" + (let ((buffer-file-name (expand-file-name "init.el" doom-emacs-dir)) + (default-directory doom-emacs-dir)) + (expect (doom-project-p)))) + (it "Should detect when not in a valid project" + (let ((buffer-file-name (expand-file-name "test" "~")) + (default-directory (expand-file-name "~"))) + (expect (doom-project-p) :to-be nil)))) + + (describe "project-root" + (it "should resolve to the project's root" + (let ((buffer-file-name (expand-file-name "core.el" doom-core-dir)) + (default-directory doom-core-dir)) + (expect (doom-project-root) :to-equal doom-emacs-dir))) + (it "should resolve to the `default-directory'" + (let ((buffer-file-name (expand-file-name "test" "/")) + (default-directory (expand-file-name "/"))) + (expect (doom-project-root) :to-equal default-directory)))) + + (describe "project-expand" + (it "expands to a path relative to the project root" + (let ((default-directory doom-core-dir)) + (expect (doom-project-expand "init.el") + :to-equal (expand-file-name "init.el" (doom-project-root)))))) + + (describe "project-file-exists-p!" + (let ((default-directory doom-core-dir)) + ;; Resolve from project root + (expect (project-file-exists-p! "init.el")) + ;; Chained file checks + (expect (project-file-exists-p! (and "init.el" "LICENSE"))) + (expect (project-file-exists-p! (or "init.el" "does-not-exist"))) + (expect (project-file-exists-p! (and "init.el" (or "LICENSE" "does-not-exist"))))))) diff --git a/core/test/test-core-ui.el b/core/test/test-core-ui.el new file mode 100644 index 000000000..d347392f9 --- /dev/null +++ b/core/test/test-core-ui.el @@ -0,0 +1,132 @@ +;; -*- no-byte-compile: t; -*- +;;; ../core/test/test-core-ui.el + +(describe "core/ui" + (describe "doom|set-mode-name" + :var (doom-major-mode-names after-change-major-mode-hook) + (before-all + (setq doom-major-mode-names + '((text-mode . "abc") + (lisp-mode . (lambda () "xyz")) + (js-mode . t)) + after-change-major-mode-hook '(doom|set-mode-name))) + + (it "changes `mode-name' to match a given string" + (text-mode) + (expect mode-name :to-equal "abc")) + + (it "changes `mode-name' to the result of a function" + (lisp-mode) + (expect mode-name :to-equal "xyz")) + + (it "should fail if given an invalid name" + (expect (js-mode) :to-throw 'error))) + + + (describe "doom|protect-visible-buffers" + :var (kill-buffer-query-functions wconf a b) + (before-each + (setq a (switch-to-buffer (get-buffer-create "a")) + b (get-buffer-create "b") + kill-buffer-query-functions '(doom|protect-visible-buffers) + wconf (current-window-configuration)) + (delete-other-windows)) + + (after-each + (let (kill-buffer-query-functions kill-buffer-hook) + (kill-buffer a) + (kill-buffer b)) + (set-window-configuration wconf)) + + (it "shouldn't kill buffers that are visible in more than one window" + (with-temp-buffer-window + (switch-to-buffer a) (split-window) + (switch-to-buffer b) (split-window) + (switch-to-buffer a) + (expect (kill-buffer) :to-be nil) + + (select-window (get-buffer-window b)) + (expect (kill-buffer))))) + + + (describe "doom|protect-fallback-buffer" + :var (kill-buffer-query-functions a b) + (before-all + (setq kill-buffer-query-functions '(doom|protect-fallback-buffer))) + + (it "should kill other buffers" + (expect (kill-buffer (get-buffer-create "a")))) + + (it "shouldn't kill the fallback buffer" + (expect (not (kill-buffer (doom-fallback-buffer)))))) + + + (describe "switch hooks" + :var (before-hook after-hook a b) + (before-each + (setq a (switch-to-buffer (get-buffer-create "a")) + b (get-buffer-create "b")) + (spy-on 'before-hook) + (spy-on 'after-hook) + (doom|init-custom-hooks)) + (after-each + (doom|init-custom-hooks 'disable) + (kill-buffer a) + (kill-buffer b)) + + + (describe "switch-buffer" + :var (doom-before-switch-buffer-hook + doom-after-switch-buffer-hook) + (before-each + (setq doom-before-switch-buffer-hook '(before-hook) + doom-after-switch-buffer-hook '(after-hook))) + (after-each + (setq doom-before-switch-buffer-hook nil + doom-after-switch-buffer-hook nil)) + + (it "should trigger when switching buffers" + (switch-to-buffer b) + (switch-to-buffer a) + (switch-to-buffer b) + (expect 'before-hook :to-have-been-called-times 3) + (expect 'after-hook :to-have-been-called-times 3)) + + (it "should trigger only once on the same buffer" + (switch-to-buffer b) + (switch-to-buffer b) + (switch-to-buffer a) + (expect 'before-hook :to-have-been-called-times 2) + (expect 'after-hook :to-have-been-called-times 2))) + + + (describe "switch-window" + :var (doom-before-switch-window-hook + doom-after-switch-window-hook + x y) + (before-each + (delete-other-windows) + (setq x (get-buffer-window a) + y (save-selected-window (split-window))) + (with-selected-window y + (switch-to-buffer b)) + (select-window x) + (spy-calls-reset 'before-hook) + (spy-calls-reset 'after-hook) + (setq doom-before-switch-window-hook '(before-hook) + doom-after-switch-window-hook '(after-hook))) + + (it "should trigger when switching windows" + (select-window y) + (select-window x) + (select-window y) + (expect 'before-hook :to-have-been-called-times 3) + (expect 'after-hook :to-have-been-called-times 3)) + + (it "should trigger only once on the same window" + (select-window y) + (select-window y) + (select-window x) + (expect 'before-hook :to-have-been-called-times 2) + (expect 'after-hook :to-have-been-called-times 2))))) + diff --git a/core/test/test-core.el b/core/test/test-core.el new file mode 100644 index 000000000..437df8173 --- /dev/null +++ b/core/test/test-core.el @@ -0,0 +1,56 @@ +;; -*- no-byte-compile: t; -*- +;;; core/test/test-core.el + +(xdescribe "core" + (describe "initialize" + :var (doom-init-p doom-init-modules-p doom-private-dir) + (before-each + (setq doom-init-p nil + doom-init-modules-p nil + doom-private-dir doom-emacs-dir) + + (spy-on 'require) + (spy-on 'load) + (spy-on 'doom//reload-doom-autoloads) + (spy-on 'doom//reload-package-autoloads) + (spy-on 'doom-initialize-autoloads) + (spy-on 'doom-ensure-core-directories) + (spy-on 'doom-ensure-core-packages) + (spy-on 'doom-ensure-packages-initialized) + (spy-on 'doom-ensure-same-emacs-version-p)) + + (describe "in interactive session" + :var (noninteractive) + (before-each (setq noninteractive t)) + + (it "initializes once, unless forced") + (it "does not initialize on consecutive invokations") + (it "loads all core libraries" ) + (it "loads autoloads file" ) + (it "does not load autoloads file if forced" ) + (it "regenerates missing autoloads" )) + + (describe "in non-interactive session" + :var (noninteractive) + (before-each (setq noninteractive nil)) + + (it "initializes once, unless forced") + (it "does not initialize on consecutive invokations") + (it "does not load all core libraries" ) + (it "loads autoloads file" ) + (it "does not load autoloads file if forced" ) + (it "does not regenerate missing autoloads" ))) + + (describe "initialize-packages" + (before-each (spy-on 'quelpa-setup-p)) + + (it "initializes package.el once, unless forced" ) + (it "initializes quelpa once, unless forced" ) + (it "initializes doom-packages once, unless forced" )) + + (describe "initialize-modules" + (it "loads private init.el once, unless forced" )) + + (describe "initialize-autoloads" + (it "loads autoloads file" ) + (it "ignores autoloads file if cleared" ))) diff --git a/modules/completion/company/test/company.el b/modules/completion/company/test/company.el deleted file mode 100644 index 5e4eadf3d..000000000 --- a/modules/completion/company/test/company.el +++ /dev/null @@ -1,21 +0,0 @@ -;; -*- lexical-binding: t; no-byte-compile: t; -*- -;;; completion/company/test/company.el - -;; -(def-test! set-company-backend - :minor-mode company-mode - (let ((company-backends '(default))) - (set! :company-backend 'emacs-lisp-mode '(backend-1)) - (set! :company-backend 'lisp-interaction-mode 'backend-1 'backend-2) - (set! :company-backend 'text-mode 'backend-1) - (with-temp-buffer - (emacs-lisp-mode) - (should (equal company-backends '((backend-1) default)))) - (with-temp-buffer - (lisp-interaction-mode) - (should (equal company-backends '(backend-1 backend-2 default)))) - (with-temp-buffer - (text-mode) - (should (equal company-backends '(backend-1 default)))) - ;; global backends shouldn't be affected - (should (equal company-backends '(default))))) diff --git a/modules/completion/company/test/test-company.el b/modules/completion/company/test/test-company.el new file mode 100644 index 000000000..8d7c3d61a --- /dev/null +++ b/modules/completion/company/test/test-company.el @@ -0,0 +1,44 @@ +;; -*- lexical-binding: t; no-byte-compile: t; -*- +;;; completion/company/test/test-company.el + +(load! "../autoload") + +;; +(xdescribe "completion/company" + :var (company-backends) + + (before-all + (provide 'company)) + (after-all + (unload-feature 'company t)) + + (describe ":company-backend" + :var (text-mode-hook company-backends) + (before-each + (setq company-backends '(default) + text-mode-hook nil)) + + (it "adds grouped backends" + (set-company-backend! 'text-mode '(backend-1)) + (with-temp-buffer + (text-mode) + (expect company-backends :to-equal '((backend-1) default)))) + + (it "adds multiple backends" + (set-company-backend! 'text-mode 'backend-1 'backend-2) + (with-temp-buffer + (text-mode) + (expect company-backends :to-equal '(backend-1 backend-2 default)))) + + (it "adds single backend" + (set-company-backend! 'text-mode 'backend-1) + (with-temp-buffer + (text-mode) + (expect company-backends :to-equal '(backend-1 default)))) + + (it "overwrites past values" + (set-company-backend! 'text-mode 'backend-1) + (set-company-backend! 'text-mode 'backend-2) + (with-temp-buffer + (text-mode) + (expect company-backends :to-equal '(backend-2 default)))))) diff --git a/modules/feature/evil/autoload/evil.el b/modules/feature/evil/autoload/evil.el index 42fda391a..51ba28006 100644 --- a/modules/feature/evil/autoload/evil.el +++ b/modules/feature/evil/autoload/evil.el @@ -18,6 +18,36 @@ `(set-evil-initial-state! ,modes ,state)) +;; +;; Custom arguments / interactive codes +;; + +;;;###autoload +(after! evil + ;; These arg types will highlight matches in the current buffer + (evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match) + (evil-ex-define-argument-type global-match :runner +evil-ex-global-match) + ;; Other commands can make use of this + (evil-define-interactive-code "" + :ex-arg buffer-match (list (if (evil-ex-p) evil-ex-argument))) + (macroexpand ' + (evil-define-interactive-code "" + :ex-arg global-match (list (if (evil-ex-p) evil-ex-argument)))) + + ;; By default :g[lobal] doesn't highlight matches in the current buffer. I've + ;; got to write my own argument type and interactive code to get it to do so. + (evil-ex-define-argument-type global-delim-match :runner +evil-ex-global-delim-match) + (dolist (sym '(evil-ex-global evil-ex-global-inverted)) + (evil-set-command-property sym :ex-arg 'global-delim-match)) + + ;; Forward declare these so that ex completion works, even if the autoloaded + ;; functions aren't loaded yet. + (evil-set-command-properties + '+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :evil-mc t :keep-visual t :suppress-operator t) + (evil-set-command-properties + '+evil:mc :move-point nil :ex-arg 'global-match :ex-bang t :evil-mc t)) + + ;; ;; Commands ;; diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index 5b932d71f..52a854dcd 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -141,28 +141,6 @@ variable for an explanation of the defaults (in comments). See (advice-add #'evil-window-split :override #'+evil*window-split) (advice-add #'evil-window-vsplit :override #'+evil*window-vsplit) - ;; By default :g[lobal] doesn't highlight matches in the current buffer. I've - ;; got to write my own argument type and interactive code to get it to do so. - (evil-ex-define-argument-type global-delim-match :runner +evil-ex-global-delim-match) - (dolist (sym '(evil-ex-global evil-ex-global-inverted)) - (evil-set-command-property sym :ex-arg 'global-delim-match)) - - ;; These arg types will highlight matches in the current buffer - (evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match) - (evil-ex-define-argument-type global-match :runner +evil-ex-global-match) - ;; Other commands can make use of this - (evil-define-interactive-code "" - :ex-arg buffer-match (list (if (evil-ex-p) evil-ex-argument))) - (evil-define-interactive-code "" - :ex-arg global-match (list (if (evil-ex-p) evil-ex-argument))) - - ;; Forward declare these so that ex completion works, even if the autoloaded - ;; functions aren't loaded yet. - (evil-set-command-properties - '+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :evil-mc t :keep-visual t :suppress-operator t) - (evil-set-command-properties - '+evil:mc :move-point nil :ex-arg 'global-match :ex-bang t :evil-mc t) - ;; Ensure jump points are created (defun +evil*set-jump (&rest _) (evil-set-jump)) diff --git a/modules/feature/evil/test/autoload-files.el b/modules/feature/evil/test/autoload-files.el deleted file mode 100644 index 1dd09486c..000000000 --- a/modules/feature/evil/test/autoload-files.el +++ /dev/null @@ -1,47 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; feature/evil/test/autoload-files.el - -(defmacro with-temp-files!! (src dest &rest body) - "Run FORMS in the context of a temporary package setup (as in, it won't -affects your Emacs packages)." - (declare (indent 2) (doc-string 3)) - `(let ((it ,src) - (other ,dest)) - (with-temp-file it - (insert "Hello world")) - (with-minor-mode! projectile-mode - (unwind-protect - (progn - (should (file-exists-p it)) - (find-file-literally it) - (should (equal (buffer-string) "Hello world")) - (should (equal (buffer-file-name) it)) - (let ((inhibit-message (not doom-debug-mode))) - ,@body)) - (ignore-errors (delete-file it)) - ,(if dest `(ignore-errors (delete-file other))))))) - -;; -(def-test! move-this-file - ":mv" - (with-temp-files!! "/tmp/doom-buffer" "/tmp/doom-buffer-new" - (should-error (+evil:move-this-file it)) - (should (+evil:move-this-file other t)) - (should (file-exists-p other)) - (should (not (file-exists-p it))))) - -(def-test! copy-this-file - ":cp" - (with-temp-files!! "/tmp/doom-buffer-2" "/tmp/doom-buffer-2-new" - (should-error (+evil:copy-this-file it)) - (should (+evil:copy-this-file other t)) - (should (file-exists-p other)) - (should (file-exists-p it)))) - -(def-test! delete-this-file - ":rm" - (with-temp-files!! "/tmp/doom-buffer-3" nil - (should-error (+evil:delete-this-file "this-file-does-not-exist")) - (should (+evil:delete-this-file nil t)) - (should (not (file-exists-p it))))) - diff --git a/modules/feature/evil/test/evil.el b/modules/feature/evil/test/evil.el deleted file mode 100644 index 525f4f153..000000000 --- a/modules/feature/evil/test/evil.el +++ /dev/null @@ -1,59 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; feature/evil/test/evil.el - -;; -;; `evil-ex-replace-special-filenames' -(def-test! resolve-vim-path - (cl-flet ((do-it #'evil-ex-replace-special-filenames)) - ;; file modifiers - (let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el") - (default-directory "~/.emacs.d/test/modules/")) - (should (equal (do-it "%") "feature/test-evil.el")) - (should (equal (do-it "%:r") "feature/test-evil")) - (should (equal (do-it "%:r.elc") "feature/test-evil.elc")) - (should (equal (do-it "%:e") "el")) - (should (equal (do-it "%:p") (expand-file-name buffer-file-name))) - (should (equal (do-it "%:h") "feature")) - (should (equal (do-it "%:t") "test-evil.el")) - (should (equal (do-it "%:.") "feature/test-evil.el")) - (should (equal (do-it "%:~") "~/.emacs.d/test/modules/feature/test-evil.el")) - (should (equal (file-truename (do-it "%:p")) - (file-truename buffer-file-name)))) - ;; nested file modifiers - (let ((buffer-file-name "~/vim/src/version.c") - (default-directory "~/vim/")) - (should (equal (do-it "%:p") (expand-file-name "~/vim/src/version.c"))) - (should (equal (do-it "%:p:.") "src/version.c")) - (should (equal (do-it "%:p:~") "~/vim/src/version.c")) - (should (equal (do-it "%:h") "src")) - (should (equal (do-it "%:p:h") (expand-file-name "~/vim/src"))) - (should (equal (do-it "%:p:h:h") (expand-file-name "~/vim"))) - (should (equal (do-it "%:t") "version.c")) - (should (equal (do-it "%:p:t") "version.c")) - (should (equal (do-it "%:r") "src/version")) - (should (equal (do-it "%:p:r") (expand-file-name "~/vim/src/version"))) - (should (equal (do-it "%:t:r") "version"))) - ;; empty file modifiers - (let (buffer-file-name default-directory) - (should (equal (do-it "%") "")) - (should (equal (do-it "%:r") "")) - (should (equal (do-it "%:e") "")) - (should (equal (do-it "%:h") "")) - (should (equal (do-it "%:t") "")) - (should (equal (do-it "%:.") "")) - (should (equal (do-it "%:~") "")) - (should (equal (do-it "%:P") ""))))) - -(def-test! file-modifiers - (cl-flet ((do-it #'evil-ex-replace-special-filenames)) - (let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el") - (default-directory "~/.emacs.d/test/modules/")) - (should (equal (do-it "%:s?e?x?") "fxature/test-evil.el")) - (should (equal (do-it "%:gs?e?x?") "fxaturx/txst-xvil.xl"))))) - -(def-test! empty-file-modifiers - (cl-flet ((do-it #'evil-ex-replace-special-filenames)) - (let (buffer-file-name default-directory) - (should (equal (do-it "%:s?e?x?") "")) - (should (equal (do-it "%:gs?e?x?") ""))))) - diff --git a/modules/feature/evil/test/test-evil.el b/modules/feature/evil/test/test-evil.el new file mode 100644 index 000000000..844e37d86 --- /dev/null +++ b/modules/feature/evil/test/test-evil.el @@ -0,0 +1,66 @@ +;; -*- no-byte-compile: t; -*- +;;; feature/evil/test/test-evil.el + +(describe "feature/evil" + :var (resv project-root) + (before-all (require 'evil)) + (after-all (unload-feature 'evil t)) + (before-each + (fset 'resv #'+evil*resolve-vim-path) + (spy-on 'doom-project-root :and-call-fake (lambda () project-root))) + + ;; `evil-ex-replace-special-filenames' / `+evil*resolve-vim-path' + (describe "file modifiers" + (it "supports basic vim file modifiers" + (let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el") + (default-directory "~/.emacs.d/test/modules/") + (project-root "~/.emacs.d/")) + (expect (resv "%") :to-equal "feature/test-evil.el") + (expect (resv "%:r") :to-equal "feature/test-evil") + (expect (resv "%:r.elc") :to-equal "feature/test-evil.elc") + (expect (resv "%:e") :to-equal "el") + (expect (resv "%:p") :to-equal (expand-file-name buffer-file-name)) + (expect (resv "%:h") :to-equal "feature") + (expect (resv "%:t") :to-equal "test-evil.el") + (expect (resv "%:.") :to-equal "feature/test-evil.el") + (expect (resv "%:~") :to-equal "~/.emacs.d/test/modules/feature/test-evil.el") + (expect (file-truename (resv "%:p")) + :to-equal (file-truename buffer-file-name)))) + + (it "supports nested vim file modifiers" + (let ((buffer-file-name "~/vim/src/version.c") + (default-directory "~/vim/") + (project-root "~/vim/")) + (expect (resv "%:p") :to-equal (expand-file-name "~/vim/src/version.c")) + (expect (resv "%:p:.") :to-equal "src/version.c") + (expect (resv "%:p:~") :to-equal "~/vim/src/version.c") + (expect (resv "%:h") :to-equal "src") + (expect (resv "%:p:h") :to-equal (expand-file-name "~/vim/src")) + (expect (resv "%:p:h:h") :to-equal (expand-file-name "~/vim")) + (expect (resv "%:t") :to-equal "version.c") + (expect (resv "%:p:t") :to-equal "version.c") + (expect (resv "%:r") :to-equal "src/version") + (expect (resv "%:p:r") :to-equal (expand-file-name "~/vim/src/version")) + (expect (resv "%:t:r") :to-equal "version"))) + + (it "cleans up empty file modifiers" + (let (buffer-file-name default-directory) + (expect (resv "%") :to-equal "") + (expect (resv "%:r") :to-equal "") + (expect (resv "%:e") :to-equal "") + (expect (resv "%:h") :to-equal "") + (expect (resv "%:t") :to-equal "") + (expect (resv "%:.") :to-equal "") + (expect (resv "%:~") :to-equal "") + (expect (resv "%:P") :to-equal ""))) + + (it "supports substitution modifiers" + (let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el") + (default-directory "~/.emacs.d/test/modules/")) + (expect (resv "%:s?e?x?") :to-equal "fxature/test-evil.el") + (expect (resv "%:gs?e?x?") :to-equal "fxaturx/txst-xvil.xl"))) + + (it "cleans up empty substitution modifiers" + (let (buffer-file-name default-directory) + (expect (resv "%:s?e?x?") :to-equal "") + (expect (resv "%:gs?e?x?") :to-equal ""))))) diff --git a/modules/feature/workspaces/test/autoload-workspaces.el b/modules/feature/workspaces/test/autoload-workspaces.el deleted file mode 100644 index acd647ba9..000000000 --- a/modules/feature/workspaces/test/autoload-workspaces.el +++ /dev/null @@ -1,124 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; feature/workspaces/test/autoload-workspaces.el - -(require! :feature workspaces) -(doom|init-custom-hooks) - -(defmacro with-workspace!! (buffer-args &rest body) - (declare (indent defun)) - (let ((buffers - (cl-loop for bsym in buffer-args - collect `(,bsym (get-buffer-create ,(symbol-name bsym)))))) - `(let ((persp-auto-resume-time -1) - (persp-auto-save-opt 0)) - (require 'persp-mode) - (let (noninteractive) - (persp-mode +1)) - (let (persp-before-switch-functions persp-activated-functions) - (+workspace-switch +workspaces-main t)) - (let* (,@buffers) - (cl-loop with persp = (get-current-persp) - for buf in (list ,@(mapcar #'car buffers)) - do (persp-add-buffer buf persp) - do (with-current-buffer buf - (setq buffer-file-name (make-temp-file "workspaces-test-")))) - ,@body - (let (kill-buffer-query-functions kill-buffer-hook) - (mapc #'kill-buffer (list ,@(mapcar #'car buffers))))) - (let (noninteractive) - (persp-mode -1))))) - -;; `+workspaces|init' -(def-test! init - (with-workspace!! () - (should (equal (+workspace-current-name) +workspaces-main)))) - -;; `+workspaces*auto-add-buffer' -(def-test! auto-add-buffer-to-persp - (let ((a (generate-new-buffer "a"))) - (doom-set-buffer-real a t) - (with-workspace!! () - (should-not (+workspace-contains-buffer-p a)) - (switch-to-buffer a) - (should (+workspace-contains-buffer-p a))))) - -;; `+workspace-current' -;; `+workspace-current-name' -(def-test! current - (with-workspace!! () - (should (equal (+workspace-current-name) +workspaces-main)) - (should (+workspace-exists-p +workspaces-main)) - (let ((workspace (+workspace-get +workspaces-main)) - (current-workspace (+workspace-current))) - (should workspace) - (should (+workspace-p workspace)) - (should (+workspace-p current-workspace)) - (should (equal workspace current-workspace))))) - -;; `+workspace-list' -;; `+workspace-list-names' -(def-test! workspace-list - (with-workspace!! () - (should (equal (+workspace-list-names) - (list (+workspace-current-name)))) - (should (equal (+workspace-list) - (list (+workspace-current)))))) - -;; `+workspace-new' -;; `+workspace-rename' -;; `+workspace-delete' -(def-test! workspace-crud - "Creating, reading, updating and deleting workspaces." - (with-workspace!! () - (let ((new-workspace-name "*new-test*") - (renamed-workspace-name "*old-test*")) - (should (+workspace-new new-workspace-name)) - (should (seq-contains (+workspace-list-names) new-workspace-name)) - (should (equal new-workspace-name - (+workspace-rename new-workspace-name renamed-workspace-name))) - (should-not (seq-contains (+workspace-list-names) new-workspace-name)) - (should (seq-contains (+workspace-list-names) renamed-workspace-name)) - (should (= (length (+workspace-list-names)) 2)) - (+workspace-delete renamed-workspace-name) - (should (= (length (+workspace-list-names)) 1))))) - -;; `+workspace-switch' -(def-test! workspace-switch - (with-workspace!! () - (let ((new-workspace-name "*new-test*")) - (should-error (+workspace-switch new-workspace-name)) - (should (+workspace-switch new-workspace-name t)) - (should (equal (+workspace-current-name) new-workspace-name))))) - -;; `+workspace-buffer-list' -;; `+workspace-contains-buffer-p' -(def-test! buffer-list - (with-workspace!! (a b) - (let ((c (get-buffer-create "c")) - (d (get-buffer-create "d"))) - (should (+workspace-contains-buffer-p a)) - (should (+workspace-contains-buffer-p b)) - (should-not (+workspace-contains-buffer-p c)) - ;; New (and real) buffers should be added to workspace buffer list. - (doom-set-buffer-real c t) - (switch-to-buffer "c") - (should (+workspace-contains-buffer-p c)) - ;; unreal buffers shouldn't - (switch-to-buffer "d") - (should-not (+workspace-contains-buffer-p d))))) - -;; `+workspace/close-window-or-workspace' -(def-test! close-window-or-workspace - (with-workspace!! (a b) - (let ((ws (+workspace-current-name)) - (inhibit-message t)) - (+workspace-switch "test" t) - (split-window) - (should (equal (+workspace-current-name) "test")) - (should (= (length (doom-visible-windows)) 2)) - ;; kill window if more than one - (+workspace/close-window-or-workspace) - (should (= (length (doom-visible-windows)) 1)) - ;; kill workspace on last window - (+workspace/close-window-or-workspace) - (should (equal (+workspace-current-name) "main"))))) diff --git a/modules/feature/workspaces/test/test-workspaces.el b/modules/feature/workspaces/test/test-workspaces.el new file mode 100644 index 000000000..7d7d1f6a9 --- /dev/null +++ b/modules/feature/workspaces/test/test-workspaces.el @@ -0,0 +1,135 @@ +;; -*- no-byte-compile: t; -*- +;;; feature/workspaces/test/test-workspaces.el + +(describe "feature/workspaces" + :var (persp-auto-resume-time + persp-auto-save-opt + persp-switch-to-added-buffer + in1 in2 out1 out2 + persp1 persp1-name persp2 persp2-name + doom-before-switch-buffer-hook + doom-after-switch-buffer-hook) + + (before-all + (require! :feature workspaces) + (require 'persp-mode)) + (after-all + (unload-feature 'persp-mode t)) + + (before-each + (setq persp-auto-resume-time -1 + persp-auto-save-opt 0 + persp-switch-to-added-buffer nil + in1 (get-buffer-create "a") + in2 (get-buffer-create "b") + out1 (get-buffer-create "c") + out2 (get-buffer-create "d")) + (doom-set-buffer-real in1 t) + (doom-set-buffer-real out1 t) + (let (noninteractive) + (persp-mode +1)) + (let (persp-before-switch-functions persp-activated-functions) + (setq persp1-name +workspaces-main + persp1 (persp-add-new persp1-name) + persp2-name "test" + persp2 (persp-add-new persp2-name)) + (persp-frame-switch +workspaces-main)) + (delete-other-windows) + (switch-to-buffer in1) + (persp-add-buffer (list in1 in2)) + (spy-on 'persp-add-buffer :and-call-through) + (doom|init-custom-hooks)) + + (after-each + (doom|init-custom-hooks 'disable) + (let (kill-buffer-query-functions kill-buffer-hook) + (mapc #'kill-buffer (list in1 in2 out1 out2))) + (let (noninteractive) + (mapc #'persp-kill (cdr (persp-names))) + (persp-mode -1))) + + ;; + (describe "switch" + (it "throws an error when switching to a non-existent workspace" + (expect (+workspace-switch "non-existent") :to-throw)) + (it "switches to a valid workspace" + (+workspace-switch persp2-name) + (expect (+workspace-current-name) :to-equal persp2-name))) + + (describe "current" + (it "returns the current workspace persp" + (expect (+workspace-p (+workspace-current))) + (expect (+workspace-current) :to-equal (get-current-persp))) + (it "returns the current workspace's name" + (expect (+workspace-current-name) :to-equal persp1-name) + (persp-switch (persp-name persp2)) + (expect (+workspace-current-name) :to-equal persp2-name))) + + (describe "exists-p" + (it "returns t for valid workspaces" + (expect (+workspace-exists-p persp1-name))) + (it "returns t for non-current (but valid) workspaces" + (expect (+workspace-exists-p persp2-name))) + (it "returns nil for non-existent workspaces" + (expect (+workspace-exists-p "non-existent") :to-be nil))) + + (describe "buffer membership" + (it "returns t for buffers in current workspace" + (expect (+workspace-contains-buffer-p in1))) + (it "returns nil for buffers outside of current workspace" + (expect (+workspace-contains-buffer-p out1) :to-be nil)) + (it "automatically adds interactively opened buffers" + (expect (+workspace-contains-buffer-p out1) :to-be nil) + (switch-to-buffer out1) + (expect (+workspace-contains-buffer-p out1))) + (xit "returns a list of orphaned buffers" + (expect (+workspace-orphaned-buffer-list) :to-contain out2))) + + (describe "list" + (it "returns a list of names" + (expect (+workspace-list-names) + :to-have-same-items-as (list persp1-name persp2-name))) + (it "returns a list of perspective structs" + (expect (+workspace-list) + :to-have-same-items-as (list persp1 persp2)))) + + (describe "CRUD" + (it "creates new workspaces" + (+workspace-new "X") + (expect (+workspace-list-names) :to-contain "X")) + (it "renames an existing workspace" + (+workspace-rename persp2-name "X") + (expect (persp-name persp2) :to-equal "X") + (expect (+workspace-list-names) + :to-have-same-items-as (list persp1-name "X"))) + (it "deletes a live workspace" + (+workspace-delete persp2-name) + (expect (+workspace-list-names) :not :to-contain persp2-name))) + + (describe "command" + (describe "new" + (it "creates a new, blank workspace" + (quiet! (+workspace/new "X")) + (expect (one-window-p)) + (expect (current-buffer) :to-be (doom-fallback-buffer))) + (it "clones a workspace" + (quiet! (+workspace/new "X" t)) + (expect (current-buffer) :to-be in1))) + + (describe "rename" + (it "renames the current workspace" + (quiet! (+workspace/rename "X")) + (expect (+workspace-current-name) :to-equal "X"))) + + (describe "close-window-or-workspace" + (before-each + (+workspace-switch persp2-name) + (split-window) + (expect (length (doom-visible-windows)) :to-be 2)) + (it "kills window if more than one window" + (quiet! (+workspace/close-window-or-workspace)) + (expect (length (doom-visible-windows)) :to-be 1)) + (it "kills workspace on last window" + (quiet! (+workspace/close-window-or-workspace) + (+workspace/close-window-or-workspace)) + (expect (+workspace-current-name) :to-equal persp1-name))))) diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index 838123621..d3f41f539 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -40,7 +40,7 @@ "Improve imenu support with better expression regexps and Doom-specific forms." (setq imenu-generic-expression '(("Evil Commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1) - ("Unit tests" "^\\s-*(\\(?:ert-deftest\\|def-test!\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1) + ("Unit tests" "^\\s-*(\\(?:ert-deftest\\|describe\\) +\"\\([^\")]+\\)\"" 1) ("Package" "^\\s-*(\\(?:def-\\)?package! +\\(\\_<[^ ()\n]+\\_>\\)" 1) ("Settings" "^\\s-*(def-setting! +\\([^ ()\n]+\\)" 1) ("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\n]+\\)" 1) @@ -113,3 +113,11 @@ (def-project-mode! +emacs-lisp-ert-mode :modes (emacs-lisp-mode) :match "/test[/-].+\\.el$") + +(associate! buttercup-minor-mode + :modes (emacs-lisp-mode) + :match "/test[/-].+\\.el$") + +(after! buttercup + (set! :yas-minor-mode 'buttercup-minor-mode)) + diff --git a/modules/lang/org/test/autoload-org.el b/modules/lang/org/test/autoload-org.el deleted file mode 100644 index 3c7b9a6bc..000000000 --- a/modules/lang/org/test/autoload-org.el +++ /dev/null @@ -1,62 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; lang/org/test/autoload-org.el - -(require! :lang org) - -(defmacro should-org-buffer!! (source expected &rest body) - `(should-buffer! ,source ,expected - (org-mode) - ,@body)) - -;; -;; `+org/insert-item' -(def-test! insert-item-h1 - "Should append/prepend new first-level headers with an extra newline." - (should-org-buffer!! ("* {0}Header") ("* Header\n\n* {|}") - (+org/insert-item 'below)) - (should-org-buffer!! ("* {0}Header") ("* {|}\n\n* Header") - (+org/insert-item 'above))) - -(def-test! insert-item-h2 - "Should append/prepend new second-level (and higher) headers without an extra -newline." - (should-org-buffer!! ("** {0}Header") ("** Header\n** {|}") - (+org/insert-item 'below)) - (should-org-buffer!! ("** {0}Header") ("** {|}\n** Header") - (+org/insert-item 'above))) - -(def-test! insert-item-plain-list - "Should append/prepend new second-level (and higher) headers without an extra -newline." - (should-org-buffer!! ("+ {0}List item") ("+ List item\n+ {|}") - (+org/insert-item 'below)) - (should-org-buffer!! ("+ {0}List item" - " + Sub item") - ("+ List item" - " + Sub item" - "+ {|}") - (+org/insert-item 'below)) - (should-org-buffer!! ("+ {0}List item" - "+ Next item") - ("+ List item" - "+ {|}" - "+ Next item") - (+org/insert-item 'below))) - -(def-test! insert-item-numbered-list - "Should append/prepend new second-level (and higher) headers without an extra -newline." - (should-org-buffer!! ("1. {0}List item") ("1. List item\n2. {|}") - (+org/insert-item 'below)) - (should-org-buffer!! ("1. {0}List item" - "2. Sub item") - ("1. List item" - "2. {|}" - "3. Sub item") - (+org/insert-item 'below)) - (should-org-buffer!! ("1. {0}List item" - "2. Next item") - ("1. {|}" - "2. List item" - "3. Next item") - (+org/insert-item 'above))) diff --git a/modules/lang/org/test/test-org.el b/modules/lang/org/test/test-org.el new file mode 100644 index 000000000..40f78bd1e --- /dev/null +++ b/modules/lang/org/test/test-org.el @@ -0,0 +1,145 @@ +;; -*- no-byte-compile: t; -*- +;;; lang/org/test/test-autoload-org.el + +(describe "lang/org" + ;; `+org/insert-item' + (describe "insert-item" + (before-all + (require 'org) + (load! "../autoload/org.el")) + (after-all + (unload-feature 'org t)) + + (before-each + (set-buffer (get-buffer-create "org")) + (erase-buffer) + (delay-mode-hooks (org-mode))) + (after-each + (kill-buffer (get-buffer "org"))) + + (describe "headlines" + (it "appends first-level headlines with an extra newline" + (insert! "* {0}Header") + (+org/insert-item 'below) + (expect (eobp)) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "* Header\n\n* ")) + (it "prepends first-level headlines with an extra newline" + (insert! "* {0}Header") + (+org/insert-item 'above) + (expect (eolp)) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "* \n\n* Header")) + + (it "appends second-level headlines with an no extra newline" + (insert! "** {0}Header") + (+org/insert-item 'below) + (expect (eobp)) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "** Header\n** ")) + (it "prepends second-level headlines with an no extra newline" + (insert! "** {0}Header") + (+org/insert-item 'above) + (expect (eolp)) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "** \n** Header")) + + (it "appends headlines, skipping subtrees" + (insert! "** {0}First\n" + "*** sub 1\n" + "*** sub 2\n" + "**** subsub 1\n" + "** Header") + (+org/insert-item 'below) + (expect (eolp)) + (expect (line-number-at-pos) :to-be 5) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal + (string-join '("** First" + "*** sub 1" + "*** sub 2" + "**** subsub 1" + "** " + "** Header") + "\n"))) + (it "prepends headlines, skipping subtrees" + (insert! "** First\n" + "*** sub 1\n" + "*** sub 2\n" + "**** {0}subsub 1\n" + "** Header") + (+org/insert-item 'above) + (expect (eolp)) + (expect (line-number-at-pos) :to-be 4) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal + (string-join '("** First" + "*** sub 1" + "*** sub 2" + "**** " + "**** subsub 1" + "** Header") + "\n")))) + + (describe "plain lists" + (it "appends items" + (insert! "+ {0}List item") + (+org/insert-item 'below) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "+ List item\n+ ")) + (it "prepends items" + (insert! "+ {0}List item") + (+org/insert-item 'above) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal "+ \n+ List item")) + + (it "appends items, but skips over child items" + (insert! "+ {0}List item\n" + " + Sub item\n" + "+ List item") + (+org/insert-item 'below) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal + (string-join '("+ List item" + " + Sub item" + "+ " + "+ List item") + "\n"))) + (it "prepends items, but skips over child items" + (insert! "+ List item\n" + " + Sub item\n" + "+ {0}List item") + (+org/insert-item 'above) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal + (string-join '("+ List item" + " + Sub item" + "+ " + "+ List item") + "\n")))) + + (describe "numbered lists" + (it "appends items and updates numbers" + (insert! "1. {0}List item\n" + "2. Sub item\n" + "3. List item") + (+org/insert-item 'below) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal + (string-join '("1. List item" + "2. " + "3. Sub item" + "4. List item") + "\n"))) + (it "prepends items and updates numbers" + (insert! "1. List item\n" + "2. Sub item\n" + "3. {0}List item") + (+org/insert-item 'above) + (expect (buffer-substring-no-properties (point-min) (point-max)) + :to-equal + (string-join '("1. List item" + "2. Sub item" + "3. " + "4. List item") + "\n")))))) diff --git a/modules/lang/web/test/autoload-css.el b/modules/lang/web/test/autoload-css.el deleted file mode 100644 index 5dc3104a6..000000000 --- a/modules/lang/web/test/autoload-css.el +++ /dev/null @@ -1,32 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; lang/web/test/autoload-css.el - -(def-test! toggle-inline-or-block - (let ((css-indent-offset 2)) - (should-buffer! - ("body { color: red{0}; font-size: 2em; }") - ("body {" - " color: red{|};" - " font-size: 2em;" - "}") - (delay-mode-hooks (css-mode)) - (+css/toggle-inline-or-block)))) - -(def-test! comment-indent-new-line - (should-buffer! - ("// test{0}" - "body { color: red; font-size: 2em; }") - ("// test" - "// {|}" - "body { color: red; font-size: 2em; }") - (delay-mode-hooks (scss-mode)) - (+css/comment-indent-new-line)) - (should-buffer! - ("// test{0}" - "body { color: red; font-size: 2em; }") - ("// test" - "// {|}" - "body { color: red; font-size: 2em; }") - (delay-mode-hooks (scss-mode)) - (+css/comment-indent-new-line))) - diff --git a/modules/lang/web/test/autoload-html.el b/modules/lang/web/test/autoload-html.el deleted file mode 100644 index 95b6cc88f..000000000 --- a/modules/lang/web/test/autoload-html.el +++ /dev/null @@ -1,14 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; lang/web/test/autoload-html.el - -(def-test! encode-entities - (should (equal (+web-encode-entities "Hello world") - "Hello world")) - (should (equal (+web-encode-entities "H€llø wørld") - "H€llø wørld"))) - -(def-test! decode-entities - (should (equal (+web-decode-entities "Hello world") - "Hello world")) - (should (equal (+web-decode-entities "H€llø wørld") - "H€llø wørld"))) diff --git a/modules/lang/web/test/test-web.el b/modules/lang/web/test/test-web.el new file mode 100644 index 000000000..27edb7c73 --- /dev/null +++ b/modules/lang/web/test/test-web.el @@ -0,0 +1,93 @@ +;; -*- no-byte-compile: t; -*- +;;; lang/web/test/test-autoload-web.el + +(describe "lang/web" + (describe "+html" + (before-all (load! "../autoload/html.el")) + + (describe "encode entities" + (it "encodes strings with html entities" + (expect (+web-encode-entities "H€llø wørld") + :to-equal "H€llø wørld")) + (it "does nothing when html entities are absent" + (expect (+web-encode-entities "Hello world") + :to-equal "Hello world"))) + + (describe "decode entities" + (it "decodes strings with html entities" + (expect (+web-decode-entities "H€llø wørld") + :to-equal "H€llø wørld")) + (it "does nothing when html entities are absent" + (expect (+web-decode-entities "Hello world") + :to-equal "Hello world")))) + + (describe "+css" + :var (css-indent-offset) + (before-all + (load! "../autoload/css.el") + (require 'smartparens) + (smartparens-mode +1)) + (after-all + (smartparens-mode -1) + (unload-feature 'smartparens t)) + + (before-each + (setq css-indent-offset 2) + (set-buffer (get-buffer-create "css")) + (delay-mode-hooks (css-mode))) + (after-each + (kill-buffer (get-buffer "css"))) + + (describe "toggle-inline-or-block" + (after-each + (+css/toggle-inline-or-block) + (expect (string-trim (buffer-string)) :to-equal + (string-join + '("body {" + " color: red;" + " font-size: 2em;" + "}") + "\n"))) + + (describe "css-mode" + (before-each ) + (it "converts inline statements into multiline blocks" + (insert! "body { color: red{0}; font-size: 2em; }")) + (it "works when cursor is on closing brace" + (insert! "body { color: red; font-size: 2em; {0}}")) + (it "works when cursor is on opening brace" + (insert! "body {{0} color: red; font-size: 2em; }")) + (it "works when cursor is on same line" + (insert! "{0}body { color: red; font-size: 2em; }")))) + + (describe "comment-indent-new-line" + (before-each + (delay-mode-hooks (scss-mode))) + + (it "continues commented lines on newline" + (insert! "// test{0}\n" + "body { color: red; font-size: 2em; }") + (+css/comment-indent-new-line) + (expect (string-trim (buffer-string)) :to-equal + (string-join + '("// test" + "// " + "body { color: red; font-size: 2em; }") + "\n")) + (expect (eolp)) + (expect (line-number-at-pos) :to-be 2)) + (it "preserves indentation within continued comments" + (insert! "// test{0}\n" + "body { color: red; font-size: 2em; }") + (+css/comment-indent-new-line) + (expect (string-trim (buffer-string)) :to-equal + (string-join + '("// test" + "// " + "body { color: red; font-size: 2em; }") + "\n")) + (expect (eolp)) + (expect (line-number-at-pos) :to-be 2))))) + + +;; diff --git a/modules/tools/password-store/test/autoload-pass.el b/modules/tools/password-store/test/autoload-pass.el deleted file mode 100644 index ec3a9d0e4..000000000 --- a/modules/tools/password-store/test/autoload-pass.el +++ /dev/null @@ -1,42 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; tools/password-store/test/autoload-pass.el - -(load! "../autoload") - -(defmacro with-passwords!! (buffer-args &rest body) - (declare (indent defun)) - `(cl-letf - (((symbol-function '+pass-get-entry) - (lambda (entry) - (when (equal entry "fake/source") - '((secret . "defuse-account-gad") - ("login" . "HL2532-GANDI") - ("alt-login" . "hlissner") - ("email" . "henrik@lissner.net") - ("url" . "https://www.gandi.net/login")))))) - ,@body)) - -;; -(def-test! get-field - (with-passwords!! - (should (equal (+pass-get-field "fake/source" "login") - "HL2532-GANDI")) - (should (equal (+pass-get-field "fake/source" "email") - "henrik@lissner.net")) - (should (equal (+pass-get-field "fake/source" '("alt-login" "email")) - "hlissner")) - (should (equal (+pass-get-field "fake/source" '("username" "email")) - "henrik@lissner.net")))) - -(def-test! missing-fields-return-nil - (with-passwords!! - (should-not (+pass-get-field "fake/source" '("x" "y" "z"))))) - -(def-test! missing-entries-throw-error - (with-passwords!! - (should-error (+pass-get-field "nonexistent/source" "login")))) - -(def-test! get-login - (with-passwords!! - (should (equal (+pass-get-user "fake/source") "HL2532-GANDI")) - (should (equal (+pass-get-secret "fake/source") "defuse-account-gad")))) diff --git a/modules/tools/password-store/test/test-pass.el b/modules/tools/password-store/test/test-pass.el new file mode 100644 index 000000000..b1138fa75 --- /dev/null +++ b/modules/tools/password-store/test/test-pass.el @@ -0,0 +1,41 @@ +;; -*- no-byte-compile: t; -*- +;;; tools/password-store/test/test-pass.el + +(describe "tools/password-store" + (before-all + (load! "../autoload")) + + (before-each + (spy-on 'auth-source-pass-parse-entry :and-call-fake + (lambda (entry) + (when (equal entry "fake/source") + '((secret . "defuse-account-gad") + ("login" . "HL2532") + ("alt-login" . "hlissner") + ("email" . "henrik@lissner.net") + ("url" . "https://some-place.net/login")))))) + + (describe "get field" + (it "returns specific fields" + (expect (+pass-get-field "fake/source" "email") + :to-equal "henrik@lissner.net")) + (it "returns first existing of a list of fields" + (expect (+pass-get-field "fake/source" '("alt-login" "email")) + :to-equal "hlissner") + (expect (+pass-get-field "fake/source" '("username" "email")) + :to-equal "henrik@lissner.net")) + (it "returns nil for missing fields" + (expect (+pass-get-field "fake/source" '("x" "y" "z")) + :to-be nil)) + (it "throws error on missing entries" + (expect (+pass-get-field "nonexistent/source" "login") + :to-throw))) + + (describe "get user/secret" + (it "returns the user" + (let ((+pass-user-fields '("login" "user" "username" "email"))) + (expect (+pass-get-user "fake/source") + :to-equal "HL2532"))) + (it "returns the secret" + (expect (+pass-get-secret "fake/source") + :to-equal "defuse-account-gad")))) diff --git a/modules/ui/doom-dashboard/test/doom-dashboard.el b/modules/ui/doom-dashboard/test/doom-dashboard.el deleted file mode 100644 index cfa828ca9..000000000 --- a/modules/ui/doom-dashboard/test/doom-dashboard.el +++ /dev/null @@ -1,50 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; ui/doom-dashboard/test/doom-dashboard.el - -(require! :ui doom-dashboard) - -(defun -dashboard-test-pwd (spec file) - (let ((kill-buffer-query-functions '(+doom-dashboard|reload-on-kill)) - (+doom-dashboard-pwd-policy (car spec)) - (fallback-buffer (doom-fallback-buffer)) - +doom-dashboard--last-cwd - projectile-enable-caching) - (with-temp-buffer - (setq buffer-file-name file - default-directory (file-name-directory file) - doom-real-buffer-p t)) - (should +doom-dashboard--last-cwd) - (+doom-dashboard-update-pwd) - (should (equal (buffer-local-value 'default-directory fallback-buffer) - (cdr spec))))) - -;; -(def-test! dashboard-p - (let ((fallback-buffer (doom-fallback-buffer))) - (should (equal (buffer-name fallback-buffer) +doom-dashboard-name)) - (should (+doom-dashboard-p fallback-buffer)))) - -(def-test! get-pwd - :minor-mode projectile-mode - (let ((default-directory doom-core-dir) - (+doom-dashboard--last-cwd doom-core-dir) - projectile-enable-caching) - (dolist (spec (list (cons 'last-project doom-emacs-dir) - (cons 'last doom-core-dir) - (cons (lambda (x) "x") "x") - (cons "~" (expand-file-name "~")) - (cons nil default-directory))) - (let ((+doom-dashboard-pwd-policy (car spec))) - (should (equal (+doom-dashboard--get-pwd) (cdr spec))))))) - -(def-test! pwd-policy - :minor-mode projectile-mode - (dolist (spec (list (cons 'last-project doom-emacs-dir) - (cons 'last doom-core-dir) - (cons "~" (expand-file-name "~/")) - (cons (lambda (x) "/tmp") "/tmp/"))) - (-dashboard-test-pwd spec (expand-file-name "core.el" doom-core-dir)))) - -;; -(def-test! inhibit-refresh :skip t) -(def-test! inhibit-functions :skip t) diff --git a/modules/ui/doom-dashboard/test/test-doom-dashboard.el b/modules/ui/doom-dashboard/test/test-doom-dashboard.el new file mode 100644 index 000000000..558b96328 --- /dev/null +++ b/modules/ui/doom-dashboard/test/test-doom-dashboard.el @@ -0,0 +1,40 @@ +;; -*- no-byte-compile: t; -*- +;;; ui/doom-dashboard/test/test-doom-dashboard.el + +(require! :ui doom-dashboard) + +(describe "ui/doom-dashboard" + :var (default-directory projectile-enable-caching) + (before-all + (require 'projectile) + (setq projectile-enable-caching nil)) + (after-all + (unload-feature 'projectile t)) + + (before-each (projectile-mode +1)) + (after-each (projectile-mode +1)) + + (describe "get-pwd" + :var (+doom-dashboard--last-cwd) + (before-each + (setq +doom-dashboard--last-cwd doom-core-dir + default-directory doom-core-dir)) + (it "returns the current directory when policy is nil" + (let (+doom-dashboard-pwd-policy) + (expect (+doom-dashboard--get-pwd) :to-equal default-directory))) + (it "returns a path if policy is a path" + (let ((+doom-dashboard-pwd-policy "~")) + (expect (+doom-dashboard--get-pwd) :to-equal (expand-file-name "~")))) + (it "returns return value of policy as a function" + (let ((+doom-dashboard-pwd-policy (lambda (x) "x"))) + (expect (+doom-dashboard--get-pwd) :to-equal "x"))) + (it "returns last cwd if policy is 'last" + (let ((+doom-dashboard-pwd-policy 'last)) + (expect (+doom-dashboard--get-pwd) :to-equal doom-core-dir))) + (it "returns last project if policy is 'last-project" + (let ((+doom-dashboard-pwd-policy 'last-project)) + (expect (+doom-dashboard--get-pwd) :to-equal doom-emacs-dir)))) + + (describe "dashboard-p" + (it "changes the fallback buffer to the dashboard buffer" + (expect (+doom-dashboard-p (doom-fallback-buffer))))))