diff --git a/.travis.yml b/.travis.yml index c3e5b5bba..5ae3109a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,6 @@ before_install: - export PATH="/home/travis/.evm/bin:$PATH" - evm config path /tmp - evm install $EVM_EMACS --use --skip - - mkdir -p ~/.config/doom - - cp init.test.el ~/.config/doom/init.el - - bin/doom -y -i install env: - EVM_EMACS=emacs-25.3-travis - EVM_EMACS=emacs-26.1-travis diff --git a/core/cli/test.el b/core/cli/test.el index 003705222..00253a6db 100644 --- a/core/cli/test.el +++ b/core/cli/test.el @@ -1,5 +1,12 @@ ;;; core/cli/test.el -*- lexical-binding: t; -*- +(defun doom--emacs-binary () + (let ((emacs-binary-path (doom-path invocation-directory invocation-name)) + (runemacs-binary-path (if IS-WINDOWS (doom-path invocation-directory "runemacs.exe")))) + (if (and runemacs-binary-path (file-exists-p runemacs-binary-path)) + runemacs-binary-path + emacs-binary-path))) + (defcli! test (&rest targets) "Run Doom unit tests." (let (files error) @@ -14,6 +21,7 @@ (cdr (doom-module-load-path))))))) (while targets (let ((target (pop targets))) + ;; FIXME Module targets don't work (cond ((equal target ":core") (appendq! files (nreverse (doom-glob doom-core-dir "test/test-*.el")))) ((file-directory-p target) @@ -21,14 +29,13 @@ (appendq! files (nreverse (doom-glob target "test/test-*.el")))) ((file-exists-p target) (push target files))))) - (require 'restart-emacs) (with-temp-buffer (setenv "DOOMDIR" (concat doom-core-dir "test/")) (setenv "DOOMLOCALDIR" (concat doom-local-dir "test/")) (print! (start "Bootstrapping test environment, if necessary...")) (if (zerop (call-process - (restart-emacs--get-emacs-binary) + (doom--emacs-binary) nil t nil "--batch" "-l" (concat doom-core-dir "core.el") "--eval" (prin1-to-string @@ -49,18 +56,20 @@ (with-temp-buffer (unless (zerop - (call-process - (restart-emacs--get-emacs-binary) - nil t nil "--batch" - "-l" (concat doom-core-dir "core.el") - "-l" (concat doom-core-dir "test/helpers.el") - "--eval" (prin1-to-string `(doom-initialize 'force)) - "-l" "buttercup" - "-l" file - "-f" "buttercup-run")) + (apply #'call-process + (doom--emacs-binary) + nil t nil "--batch" + (append (list + "-l" (concat doom-core-dir "core.el") + "-l" (concat doom-core-dir "test/helpers.el")) + (when (file-in-directory-p file doom-modules-dir) + (list "-f" "doom-initialize-core")) + (list + "-l" file + "-f" "buttercup-run")))) (setq error t)) (message "%s" (buffer-string))) (print! (info "Ignoring %s" (relpath file))))) (if error - (error "A test failed") + (user-error "A test failed") t))) diff --git a/core/core-modules.el b/core/core-modules.el index 45f41a467..65f232a98 100644 --- a/core/core-modules.el +++ b/core/core-modules.el @@ -493,7 +493,7 @@ CATEGORY is a keyword, MODULE is a symbol and FLAGS are symbols. This is for testing and internal use. This is not the correct way to enable a module." - `(let ((doom-modules ,doom-modules) + `(let ((doom-modules (or ,doom-modules (doom-modules))) (module-path (doom-module-locate-path ,category ',module))) (doom-module-set ,category ',module diff --git a/core/test/helpers.el b/core/test/helpers.el index 89b1401db..a4d9986eb 100644 --- a/core/test/helpers.el +++ b/core/test/helpers.el @@ -1,6 +1,64 @@ -;; -*- no-byte-compile: t; -*- +;; -*- lexical-binding: t; no-byte-compile: t; -*- ;;; core/test/helpers.el +(eval-and-compile + (setq doom-interactive-mode 'test) + (doom-initialize 'force) + (require 'buttercup) + (setq split-width-threshold 0 + split-height-threshold 0 + window-min-width 0 + window-min-height 0)) + +;; +;;; Buttercup extensions + +(buttercup-define-matcher :to-expand-into (form expected) + (cl-destructuring-bind (form expected) + (mapcar #'funcall (list form expected)) + (let ((expanded (macroexpand-1 form))) + (if (equal expanded expected) + (cons t (format "Expected `%S' to not expand to `%S'" + form expected)) + (cons nil (format "Expected `%S' to not expand to `%S', but got `%S' instead" + form expected expanded)))))) + +(buttercup-define-matcher :to-output (form &optional expected-output) + (let ((expected-output (and (functionp expected-output) + (funcall expected-output))) + output) + (with-current-buffer (get-buffer "*Messages*") + (let ((standard-output (current-buffer)) + (start (point))) + (let ((inhibit-message t)) + (funcall form)) + (setq output (buffer-substring-no-properties start (point-max))) + (with-silent-modifications (erase-buffer)))) + (cond ((null expected-output) + (if (string-empty-p output) + (cons nil (format "Expected output %S, but got none" + expected-output)) + (cons t (format "Expected no output, but got %S" + output)))) + ((not (equal expected-output output)) + (cons nil (format "Expected output %S, but got %S instead" + expected-output output))) + ((cons t (format "Expected to not get %S as output" + expected-output)))))) + +(buttercup-define-matcher :to-contain-items (items expected) + (cl-destructuring-bind (items expected) + (mapcar #'funcall (list items expected)) + (if-let (missing (cl-set-difference expected items)) + (cons nil (format "Expected list to contain %S, but it was missing %S" + expected missing)) + (cons t (format "Expected list to not contain %S, but it did: %S" + expected items))))) + + +;; +;;; Helper macros + (defmacro insert!! (&rest text) "Insert TEXT in buffer, then move cursor to last {0} marker." `(progn diff --git a/core/test/test-autoload-buffers.el b/core/test/test-autoload-buffers.el index f80e2538c..5c44ce232 100644 --- a/core/test/test-autoload-buffers.el +++ b/core/test/test-autoload-buffers.el @@ -1,16 +1,12 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-autoload-buffers.el -(require 'core-projects) -(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))))) + + (require 'core-projects) + (load! "autoload/buffers" doom-core-dir) + (before-each (delete-other-windows) (setq a (switch-to-buffer (get-buffer-create "a")) @@ -25,7 +21,7 @@ (describe "buffer-list" (it "should only see four buffers" - (expect (doom-buffer-list) :to-have-same-items-as (list a b c d)))) + (expect (doom-buffer-list) :to-contain-items (list a b c d)))) (describe "project-buffer-list" :var (projectile-projects-cache-time projectile-projects-cache) @@ -34,7 +30,7 @@ (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 b (setq default-directory doom-core-dir)) (with-current-buffer c (setq default-directory "/tmp/")) (with-current-buffer d (setq default-directory "~")) (projectile-mode +1)) @@ -44,7 +40,7 @@ (it "returns buffers in the same project" (with-current-buffer a (expect (doom-project-buffer-list) - :to-have-same-items-as (list a b)))) + :to-contain-items (list a b)))) (it "returns all buffers if not in a project" (with-current-buffer c @@ -53,7 +49,10 @@ (describe "fallback-buffer" (it "returns a live buffer" - (expect (buffer-live-p (doom-fallback-buffer))))) + (expect (buffer-live-p (doom-fallback-buffer)))) + + (it "returns the scratch buffer" + (expect (doom-fallback-buffer) :to-equal (get-buffer "*scratch*")))) (describe "real buffers" (before-each @@ -72,7 +71,7 @@ (describe "real-buffer-list" (it "returns only real buffers" - (expect (doom-real-buffer-list) :to-have-same-items-as (list a b))))) + (expect (doom-real-buffer-list) :to-contain-items (list a b))))) (describe "buffer/window management" (describe "buffer search methods" @@ -85,14 +84,17 @@ (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))) + (expect (doom-buried-buffers) :to-contain-items (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 @@ -109,7 +111,7 @@ (expect (length (doom-visible-windows)) :to-be 1))) ;; TODO - (describe "kill-all-buffers") - (describe "kill-other-buffers") - (describe "kill-matching-buffers") - (describe "cleanup-session"))) + (xdescribe "kill-all-buffers") + (xdescribe "kill-other-buffers") + (xdescribe "kill-matching-buffers") + (xdescribe "cleanup-session"))) diff --git a/core/test/test-autoload-files.el b/core/test/test-autoload-files.el index 4251e6f0d..87a63edde 100644 --- a/core/test/test-autoload-files.el +++ b/core/test/test-autoload-files.el @@ -1,54 +1,152 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-autoload-files.el -;;; -(require 'core-projects) -(require 'projectile) (describe "core/autoload/files" - :var (src dest projectile-projects-cache-time projectile-projects-cache) - (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))) + (load! "autoload/files" doom-core-dir) - (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)))) + (xdescribe "doom-glob") + (xdescribe "doom-path") + (xdescribe "doom-dir") + (xdescribe "doom-files-in") - (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! (doom/copy-this-file existing)) - (expect 'y-or-n-p :to-have-been-called-times 1))) + (describe "library" + (describe "file-exists-p!" + (it "is a (quasi) drop-in replacement for `file-exists-p'" + (let ((default-directory doom-emacs-dir) + (init-file "init.el")) + (expect (file-exists-p "init.el")) + (expect (and (file-exists-p! "init.el") + (file-exists-p "init.el"))) + (expect (and (file-exists-p! init-file) + (file-exists-p init-file))) + (expect (and (file-exists-p! doom-emacs-dir) + (file-exists-p doom-emacs-dir))) + (expect (and (not (file-exists-p! "/cant/possibly/exist/please/dont/exist")) + (not (file-exists-p "/cant/possibly/exist/please/dont/exist")))))) - (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)))) + (it "returns the file path if it exists" + (expect (file-exists-p! "init.example.el" + doom-emacs-dir) + :to-equal (expand-file-name "init.example.el" doom-emacs-dir))) + + (it "understands compound statements" + (let ((default-directory doom-emacs-dir)) + (expect (file-exists-p! (and "init.el" "init.example.el"))) + (expect (file-exists-p! (or "doesnotexist" "init.example.el"))) + (expect (not (file-exists-p! (or "doesnotexist" "DOESNOTEXIST"))))) + (expect (file-exists-p! (and "init.el" "init.example.el") + doom-emacs-dir)) + (expect (file-exists-p! (and "init.el" "init.example.el") + doom-emacs-dir)) + (expect (file-exists-p! (or "doesnotexist" "init.example.el") + doom-emacs-dir)) + (expect (not (file-exists-p! (or "doesnotexist" "DOESNOTEXIST") + doom-emacs-dir)))) + + (it "understands nested compound statements" + (expect (file-exists-p! (and "init.el" "init.example.el" + (or "doesnotexist" "LICENSE")) + doom-emacs-dir)) + (expect (file-exists-p! (and "init.el" "init.example.el" + (and "LICENSE" "README.md" + (or "doesnotexist" + "early-init.el"))) + doom-emacs-dir)) + (expect (file-exists-p! (and "init.el" "init.example.el" + (or "edoesnotexist" "DOESNOTEXIST" + (and "idontexist" + "doanyofusexist?"))) + doom-emacs-dir) + :to-be nil)) + + (it "returns the last form if a compound file check succeeds" + (expect (file-exists-p! (and "init.el" "init.example.el" + (or "doesnotexist" "LICENSE")) + doom-emacs-dir) + :to-equal (expand-file-name "LICENSE" doom-emacs-dir)) + (expect (file-exists-p! (and "init.el" "init.example.el" + (or (or "doesnotexist" "DOESNOTEXIST") + "doanyofusreallyexist" + (or "cantexist" "LICENSE"))) + doom-emacs-dir) + :to-equal (expand-file-name "LICENSE" doom-emacs-dir))) + + (it "disregards the directory argument if given absolute path" + (expect (file-exists-p! "/tmp" "/directory/that/doesnt/exist")) + (expect (file-exists-p! doom-core-dir "/directory/that/doesnt/exist")) + (expect (file-exists-p! (and "/tmp" doom-core-dir) "/directory/that/doesnt/exist")) + (expect (file-exists-p! (or "/tmp" doom-core-dir) "/directory/that/doesnt/exist"))) + + (it "interpolates variables" + (let ((file-1 "init.el") + (file-2 "init.example.el") + (file-3 "LICENSE") + (file-404 "doesnotexistlikenoreally")) + (expect (file-exists-p! file-1 doom-emacs-dir)) + (expect (file-exists-p! (and file-1 file-2) doom-emacs-dir)) + (expect (file-exists-p! (and file-1 (or file-404 file-2)) doom-emacs-dir)) + (expect (file-exists-p! (or (and file-404 file-2) (and file-3 file-1)) + doom-emacs-dir)))) + + (it "interpolates forms" + (cl-letf (((symbol-function 'getfilename) + (lambda () "init.example.el"))) + (expect (file-exists-p! (and (or (if nil "init.el" "doesnotexist") + (getfilename)) + "LICENSE") + doom-emacs-dir) + :to-equal (expand-file-name "LICENSE" doom-emacs-dir)))))) + + (describe "interactive file operations" + :var (src dest projectile-projects-cache-time projectile-projects-cache) + + (require 'core-projects) + (require 'projectile) + + (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! (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-message.el b/core/test/test-autoload-format.el similarity index 80% rename from core/test/test-autoload-message.el rename to core/test/test-autoload-format.el index a7d90c122..237d26324 100644 --- a/core/test/test-autoload-message.el +++ b/core/test/test-autoload-format.el @@ -1,11 +1,11 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-autoload-message.el -(describe "core/autoload/message" +(describe "core/autoload/format" (describe "format!" - :var (doom-message-backend) + :var (doom-format-backend) (before-all - (setq doom-message-backend 'ansi)) + (setq doom-format-backend 'ansi)) (it "should be a drop-in replacement for `format'" (expect (format! "Hello %s" "World") @@ -16,7 +16,7 @@ :to-equal "Hello World")) (it "supports text properties in interactive sessions" - (let ((doom-message-backend 'text-properties)) + (let ((doom-format-backend 'text-properties)) (expect (get-text-property 0 'face (format! (red "Hello %s") "World")) :to-equal (list :foreground (face-foreground 'term-color-red))))) @@ -35,4 +35,10 @@ (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"))))) + :to-equal (format! (blue "Hello %s") "World")))) + + (xdescribe "insert!") + (xdescribe "print!") + (xdescribe "print-group!") + (xdescribe "error!") + (xdescribe "user-error!")) diff --git a/core/test/test-autoload-help.el b/core/test/test-autoload-help.el deleted file mode 100644 index 8df3a9a3a..000000000 --- a/core/test/test-autoload-help.el +++ /dev/null @@ -1,10 +0,0 @@ -;; -*- 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))) diff --git a/core/test/test-autoload-package.el b/core/test/test-autoload-package.el index ac5c81534..02923304c 100644 --- a/core/test/test-autoload-package.el +++ b/core/test/test-autoload-package.el @@ -1,138 +1,5 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-autoload-package.el +;;;###if nil -(describe "core/autoload/packages" - :var (package-alist - package-archive-contents - package-selected-packages - 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 - :dir (expand-file-name (format "%s/" name) package-user-dir)))) - (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 #'package--user-installed-p :and-call-fake (lambda (_p) t)) - (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 :modules ((:private))) - (doom-disabled-private-dummy :modules ((:private)) :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")) - package-selected-packages (mapcar #'car doom-packages))) - - (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" - (before-all - ;; In addition to `package-installed-p', `doom-package-installed-p' does - ;; file existence checks which won't work here, so we simplify it - (spy-on #'doom-package-installed-p :and-call-fake #'package-installed-p)) - - (it "returns all packages" - (expect (mapcar #'car (doom-find-packages)) - :to-have-same-items-as - (mapcar #'car doom-packages))) - (it "returns only disabled packages" - (expect (mapcar #'car (doom-find-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-find-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-find-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-find-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-find-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-find-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)))) +(xdescribe "core/autoload/packages") diff --git a/core/test/test-core-keybinds.el b/core/test/test-core-keybinds.el index 2db47792e..5482205b2 100644 --- a/core/test/test-core-keybinds.el +++ b/core/test/test-core-keybinds.el @@ -1,40 +1,34 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-core-keybinds.el -(require 'core-keybinds) - -(buttercup-define-matcher :to-expand-into (src result) - (let ((src (funcall src)) - (result (funcall result))) - (or (equal (macroexpand-1 src) result) - (error "'%s' expanded into '%s' instead of '%s'" - src (macroexpand-1 src) result)))) - (describe "core/keybinds" + (require 'core-keybinds) + (describe "map!" - :var (doom--map-evil-p doom-map-states) + :var (doom--map-evil-p states-alist) (before-each (setq doom--map-evil-p t - doom-map-states '((:n . normal) - (:v . visual) - (:i . insert) - (:e . emacs) - (:o . operator) - (:m . motion) - (:r . replace)))) + states-alist '((:n . normal) + (:v . visual) + (:i . insert) + (:e . emacs) + (:o . operator) + (:m . motion) + (:r . replace)))) (describe "Single keybinds" (it "binds a global key" - (expect '(map! "C-." #'a) :to-expand-into '(general-define-key "C-." #'a))) + (expect '(map! "C-." #'a) + :to-expand-into '(general-define-key "C-." #'a))) (it "binds a key in one evil state" - (dolist (state doom-map-states) + (dolist (state states-alist) (expect `(map! ,(car state) "C-." #'a) :to-expand-into `(general-define-key :states ',(cdr state) "C-." #'a)))) (it "binds a key in multiple evil states" - (expect `(map! :nvi "C-." #'a) + (expect '(map! :nvi "C-." #'a) :to-expand-into '(progn (general-define-key :states 'insert "C-." #'a) (general-define-key :states 'visual "C-." #'a) @@ -54,7 +48,7 @@ '(general-define-key "C-." #'a "C-," #'b "C-/" #'c))) (it "binds multiple keybinds in an evil state and preserve order" - (dolist (state doom-map-states) + (dolist (state states-alist) (expect `(map! ,(car state) "a" #'a ,(car state) "b" #'b ,(car state) "c" #'c) diff --git a/core/test/test-core-lib.el b/core/test/test-core-lib.el index 608fdb66e..06a35649e 100644 --- a/core/test/test-core-lib.el +++ b/core/test/test-core-lib.el @@ -1,28 +1,130 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-core-lib.el -(require 'core-lib) +(describe "core-lib" + (before-all + (require 'core-lib)) -(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" + (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))) + (expect (doom-unquote 'hello) :to-be 'hello) + (expect (doom-unquote 5) :to-be 5) + (expect (doom-unquote t) :to-be t))) (describe "doom-enlist" + (it "returns nil if given nil" + (expect (doom-enlist nil) :to-be nil)) (it "creates a list out of non-lists" (expect (doom-enlist 'a) :to-equal '(a))) - (it "does nothing to lists" + (it "returns lists as-is" (expect (doom-enlist '(a)) :to-equal '(a)))) + (describe "doom-keyword-intern" + (it "returns a keyword" + (expect (doom-keyword-intern "test") :to-equal :test)) + (it "errors if given anything but a string" + (expect (doom-keyword-intern t) :to-throw 'wrong-type-argument))) + + (describe "doom-keyword-name" + (it "returns the string name of a keyword" + (expect (doom-keyword-name :test) :to-equal "test")) + (it "errors if given anything but a keyword" + (expect (doom-keyword-name "test") :to-throw 'wrong-type-argument))) + + (describe "doom-partial" + (it "returns a closure" + (expect (functionp (doom-partial #'+ 1)))) + (it "returns a partial closure" + (expect (funcall (doom-partial #'+ 1) 2) :to-be 3))) + + (describe "doom-rpartial" + (it "returns a closure" + (expect (functionp (doom-rpartial #'+ 1)))) + (it "returns a partial closure with right-aligned arguments" + (expect (funcall (doom-rpartial #'/ 2) 10) :to-be 5))) + + + ;; --- Sugars ----------------------------- + (describe "lambda!" + (it "returns an interactive function" + (expect (commandp (lambda!))) + (expect (funcall (lambda! 5)) :to-equal 5))) + + (describe "lambda!!" + (it "returns an interactive function with a prefix argument" + (expect (commandp (lambda! #'ignore t))) + (expect (funcall (lambda!! (lambda (arg) + (interactive "P") + arg) + 5)) + :to-equal 5))) + + (describe "file!" + (it "returns the executing file" + (expect (eval-and-compile (file!)) + :to-equal (expand-file-name "test/test-core-lib.el" + doom-core-dir)))) + + (describe "dir!" + (it "returns the executing directory" + (expect (eval-and-compile (dir!)) + :to-equal (expand-file-name "test" doom-core-dir)))) + + (describe "pushnew!" + (it "pushes values onto a list symbol, in order" + (let ((a '(1 2 3))) + (expect (pushnew! a 9 8 7) + :to-equal '(7 8 9 1 2 3)))) + (it "only adds values that aren't already in the list" + (let ((a '(1 symbol 3.14 "test"))) + (expect (pushnew! a "test" 'symbol 3.14 1) + :to-equal '(1 symbol 3.14 "test"))))) + + (describe "prependq!" + (it "prepends a list to a list symbol" + (let ((list '(a b c))) + (expect (prependq! list '(d e f)) + :to-equal '(d e f a b c))))) + + (describe "append!" + (it "appends a list to a list symbol" + (let ((list '(a b c))) + (expect (appendq! list '(d e f)) + :to-equal '(a b c d e f))))) + + (describe "nconcq!" + (it "nconc's a list to a list symbol" + (let ((list '(a b c))) + (expect (nconcq! list '(d e f)) + :to-equal '(a b c d e f))))) + + (describe "delq!" + (it "delete's a symbol from a list" + (let ((list '(a b c))) + (delq! 'b list) + (expect list :to-equal '(a c)))) + (it "delete's an element from an alist by key" + (let ((alist '((a 1) (b 2) (c 3)))) + (delq! 'b alist 'assq) + (expect alist :to-equal '((a 1) (c 3)))))) + + (describe "delete!" + (it "delete's a string from a list" + (let ((list '("a" "b" "c"))) + (delete! "b" list) + (expect list :to-equal '("a" "c")))) + (it "delete's an element from an alist by key" + (let ((alist '(("a" 1) ("b" 2) ("c" 3)))) + (delete! (assoc "b" alist) alist) + (expect alist :to-equal '(("a" 1) ("c" 3)))))) - ;; --- Macros ----------------------------- (describe "hooks" (describe "add-hook!" :var (fake-mode-hook other-mode-hook some-mode-hook) @@ -31,15 +133,22 @@ other-mode-hook nil some-mode-hook '(first-hook second-hook))) + (it "resolves quoted hooks literally" + (expect '(add-hook! 'fake-mode-hook #'ignore) :to-expand-into + `(add-hook 'fake-mode-hook #'ignore nil nil))) + (it "resolves unquoted modes to their hook variables" + (expect '(add-hook! fake-mode #'ignore) :to-expand-into + `(add-hook 'fake-mode-hook #'ignore nil nil))) + (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" + (it "adds one-to-many 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) + (add-hook! (fake-mode other-mode some-mode) :append #'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))) @@ -47,7 +156,7 @@ (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)) + (add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) :append #'(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))) @@ -55,10 +164,18 @@ (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)) + (add-hook! 'some-mode-hook :append (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))) + (expect (caar (last other-mode-hook)) :to-be 'lambda)) + + (it "handles inline defuns as hook symbols" + (add-hook! fake-mode (defun hook-a ())) + (add-hook! 'other-mode-hook + (defun hook-b ()) + (defun hook-c ())) + (expect (car fake-mode-hook) :to-be 'hook-a) + (expect other-mode-hook :to-equal '(hook-b hook-c)))) (describe "remove-hook!" :var (fake-mode-hook) @@ -71,22 +188,92 @@ (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)))) + (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)))) + (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 + (describe "(un)setq-hook!" + :var (fake-hook x y z) + (before-each + (setq x 10 y 20 z 30)) + + (it "sets variables buffer-locally" + (setq-hook! 'fake-hook x 1) + (with-temp-buffer + (run-hooks 'fake-hook) + (expect (local-variable-p 'x)) + (expect (= x 1))) + (expect (= x 10))) + + (it "overwrites earlier hooks" + (setq-hook! 'fake-hook x 1 y 0) + (setq-hook! 'fake-hook x 5 y -1) + (with-temp-buffer + (run-hooks 'fake-hook) + (expect (= x 5)) + (expect (= y -1)))) + + (it "unset setq hooks" + (setq-hook! 'fake-hook x 1 y 0) + (unsetq-hook! 'fake-hook y) + (with-temp-buffer + (run-hooks 'fake-hook) + (expect (local-variable-p 'x)) + (expect (= x 1)) + (expect (not (local-variable-p 'y))) + (expect (= y 20)))))) + + (describe "load!" + (before-each + (spy-on 'load :and-return-value t)) + + (it "loads a file relative to the current directory" + (load! "path") + (expect 'load :to-have-been-called) + (expect 'load :to-have-been-called-with (expand-file-name "path" (eval-when-compile (dir!))) nil t)) + + (it "loads a file relative to a specified directory" + (load! "path" doom-etc-dir) + (expect 'load :to-have-been-called-with (expand-file-name "path" doom-etc-dir) nil t))) + + (describe "quiet!" + (it "suppresses output from message" + (expect (message "hello world") :to-output "hello world\n") + (expect (message "hello world") :to-output) + (let (doom-interactive-mode) + (expect (quiet! (message "hello world")) :not :to-output)) + (let ((doom-interactive-mode t)) + (expect (quiet! inhibit-message)) + (expect (quiet! save-silently)))) + + (it "suppresses load messages from `load' & `load-file'" + (let ((tmpfile (make-temp-file "test" nil ".el"))) + (with-temp-file tmpfile) + (let (doom-interactive-mode) + (expect (load-file tmpfile) :to-output (format "Loading %s (source)...\n" tmpfile)) + (expect (quiet! (load-file tmpfile)) :not :to-output)) + (delete-file tmpfile))) + + (it "won't suppress output in debug mode" + (let ((doom-debug-mode t) + (tmpfile (make-temp-file "test" nil ".el"))) + (dolist (doom-interactive-mode (list t nil)) + (expect (quiet! (message "hello world")) + :to-output "hello world\n") + (with-temp-file tmpfile) + (expect (quiet! (load-file tmpfile)) + :to-output (format "Loading %s (source)...\n" tmpfile))))))) diff --git a/core/test/test-core-modules.el b/core/test/test-core-modules.el index a786ad2ea..9263f305a 100644 --- a/core/test/test-core-modules.el +++ b/core/test/test-core-modules.el @@ -1,6 +1,7 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-core-modules.el +;;;###if nil ;; (require 'core-modules) -(describe "core-modules") +(xdescribe "core-modules") diff --git a/core/test/test-core-packages.el b/core/test/test-core-packages.el index ff3104b76..d4434ad9f 100644 --- a/core/test/test-core-packages.el +++ b/core/test/test-core-packages.el @@ -1,4 +1,5 @@ ;; -*- no-byte-compile: t; -*- ;;; core/test/test-core-packages.el +;;;###if nil -(describe "core-packages") +(xdescribe "core-packages") diff --git a/core/test/test-core-projects.el b/core/test/test-core-projects.el index 3dbd953d5..8febc5cdd 100644 --- a/core/test/test-core-projects.el +++ b/core/test/test-core-projects.el @@ -1,12 +1,17 @@ ;; -*- no-byte-compile: t; -*- -;;; ../core/test/test-core-projects.el - -(require 'core-projects) -(require 'projectile) +;;; core/test/test-core-projects.el (describe "core/projects" - (before-each (projectile-mode +1)) - (after-each (projectile-mode -1)) + :var (projectile-enable-caching) + + (require 'core-projects) + (require 'projectile) + + (before-each + (setq projectile-enable-caching nil) + (projectile-mode +1)) + (after-each + (projectile-mode -1)) (describe "project-p" (it "Should detect when in a valid project" diff --git a/core/test/test-core-ui.el b/core/test/test-core-ui.el index 0ace0bc73..5079aa996 100644 --- a/core/test/test-core-ui.el +++ b/core/test/test-core-ui.el @@ -1,17 +1,106 @@ ;; -*- no-byte-compile: t; -*- ;;; ../core/test/test-core-ui.el -(require 'core-ui) - (describe "core/ui" - (describe "doom|protect-fallback-buffer" - :var (kill-buffer-query-functions a b) + (before-all + (with-demoted-errors "Import error: %s" + (require 'core-ui))) + + (describe "doom-protect-fallback-buffer-h" + :var (kill-buffer-query-functions) (before-all - (setq kill-buffer-query-functions '(doom|protect-fallback-buffer))) + (setq kill-buffer-query-functions '(doom-protect-fallback-buffer-h))) (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))))))) + (expect (not (kill-buffer (doom-fallback-buffer)))))) + (describe "custom hooks" + (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 'hook) + (add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h) + (add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h) + (dolist (fn '(switch-to-buffer display-buffer)) + (advice-add fn :around #'doom-run-switch-buffer-hooks-a))) + (after-each + (remove-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h) + (remove-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h) + (dolist (fn '(switch-to-buffer display-buffer)) + (advice-remove fn #'doom-run-switch-buffer-hooks-a)) + (kill-buffer a) + (kill-buffer b)) + + (describe "switch-buffer" + :var (doom-switch-buffer-hook) + (before-each + (setq doom-switch-buffer-hook '(hook))) + (after-each + (setq doom-switch-buffer-hook nil)) + + (it "should trigger when switching buffers" + (switch-to-buffer b) + (switch-to-buffer a) + (switch-to-buffer b) + (expect '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 'hook :to-have-been-called-times 2))) + + + (describe "switch-window" + :var (doom-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 'hook) + (setq doom-switch-window-hook '(hook))) + + (it "should trigger when switching windows" + (select-window y) + (select-window x) + (select-window y) + (expect '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 'hook :to-have-been-called-times 2))) + + + (xdescribe "switch-frame" + :var (doom-switch-frame-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 'hook) + (setq doom-switch-window-hook '(hook))) + + (it "should trigger when switching windows" + (select-window y) + (select-window x) + (select-window y) + (expect '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 'hook :to-have-been-called-times 2)))))) diff --git a/core/test/test-core.el b/core/test/test-core.el index 07361463a..22892b4fd 100644 --- a/core/test/test-core.el +++ b/core/test/test-core.el @@ -2,118 +2,116 @@ ;;; core/test/test-core.el (describe "core" - (xdescribe "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) + :var (doom-interactive-mode) + (before-each + (setq doom-interactive-mode nil)) - (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" ))) - - (xdescribe "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" )) - - (xdescribe "initialize-modules" - (it "loads private init.el once, unless forced" )) - - (xdescribe "initialize-autoloads" - (it "loads autoloads file" ) - (it "ignores autoloads file if cleared" )) - - (describe "custom hooks" - (describe "switch hooks" - :var (before-hook after-hook a b) + (describe "initialization" + (describe "doom-initialize" + :var (doom-init-p) (before-each - (setq a (switch-to-buffer (get-buffer-create "a")) - b (get-buffer-create "b")) - (spy-on 'hook) - (add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h) - (add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h) - (dolist (fn '(switch-to-buffer display-buffer)) - (advice-add fn :around #'doom-run-switch-buffer-hooks-a))) - (after-each - (remove-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h) - (remove-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h) - (dolist (fn '(switch-to-buffer display-buffer)) - (advice-remove fn #'doom-run-switch-buffer-hooks-a)) - (kill-buffer a) - (kill-buffer b)) + (setq doom-init-p nil)) - (describe "switch-buffer" - :var (doom-switch-buffer-hook) + (it "initializes once" + (expect (doom-initialize)) + (expect (not (doom-initialize))) + (expect (not (doom-initialize))) + (expect doom-init-p)) + + (it "initializes multiple times, if forced" + (expect (doom-initialize)) + (expect (not (doom-initialize))) + (expect (doom-initialize 'force))) + + (describe "package initialization" (before-each - (setq doom-switch-buffer-hook '(hook))) - (after-each - (setq doom-switch-buffer-hook nil)) + (spy-on 'doom-initialize-packages :and-return-value t)) - (it "should trigger when switching buffers" - (switch-to-buffer b) - (switch-to-buffer a) - (switch-to-buffer b) - (expect 'hook :to-have-been-called-times 3)) + (it "initializes packages if core autoload file doesn't exist" + (let ((doom-autoload-file "doesnotexist")) + (doom-initialize)) + (expect 'doom-initialize-packages :to-have-been-called)) - (it "should trigger only once on the same buffer" - (switch-to-buffer b) - (switch-to-buffer b) - (switch-to-buffer a) - (expect 'hook :to-have-been-called-times 2))) + (it "doesn't initialize packages if core autoload file was loaded" + (let ((doom-interactive-mode t)) + (spy-on 'doom-load-autoloads-file :and-return-value t) + (doom-initialize) + (expect 'doom-load-autoloads-file :to-have-been-called-with doom-package-autoload-file) + (expect 'doom-initialize-packages :to-have-been-called))) + (it "initializes packages when forced" + (doom-initialize 'force) + (expect 'doom-initialize-packages :to-have-been-called))) - (describe "switch-window" - :var (doom-switch-window-hook x y) + (describe "autoloads files" (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 'hook) - (setq doom-switch-window-hook '(hook))) + (spy-on 'doom-load-autoloads-file) + (spy-on 'warn :and-return-value t)) - (it "should trigger when switching windows" - (select-window y) - (select-window x) - (select-window y) - (expect 'hook :to-have-been-called-times 3)) + (it "loads autoloads file" + (let ((doom-interactive-mode t)) + (ignore-errors (doom-initialize))) + (expect 'doom-load-autoloads-file + :to-have-been-called-with doom-autoload-file) + (expect 'doom-load-autoloads-file + :to-have-been-called-with doom-package-autoload-file)) - (it "should trigger only once on the same window" - (select-window y) - (select-window y) - (select-window x) - (expect 'hook :to-have-been-called-times 2)))))) + (it "does not load package autoloads file if noninteractive" + (doom-initialize) + (expect 'doom-load-autoloads-file + :to-have-been-called-with doom-autoload-file) + (expect 'doom-load-autoloads-file + :not :to-have-been-called-with doom-package-autoload-file)) + + (it "throws doom-autoload-error in interactive session where autoload files don't exist" + (let ((doom-interactive-mode t) + (doom-autoload-file "doesnotexist") + (doom-package-autoload-file "doesnotexist")) + (expect (doom-initialize) :to-throw 'doom-autoload-error))))) + + (describe "doom-initialize-core" + (before-each + (spy-on 'require)) + + (it "loads all doom core libraries" + (doom-initialize-core) + (expect 'require :to-have-been-called-with 'core-keybinds) + (expect 'require :to-have-been-called-with 'core-ui) + (expect 'require :to-have-been-called-with 'core-projects) + (expect 'require :to-have-been-called-with 'core-editor)))) + + (describe "doom-load-autoloads-file" + (before-each + (spy-on 'load :and-return-value t)) + + (it "loads the autoloads file" + (doom-load-autoloads-file doom-autoload-file) + (expect 'load :to-have-been-called-with (file-name-sans-extension doom-autoload-file) + 'noerror 'nomessage))) + + (describe "doom-load-envvars-file" + :var (envvarfile process-environment) + (before-each + (setq process-environment (copy-sequence process-environment)) + (with-temp-file doom-env-file + (insert "\n\n\nA=1\nB=2\nC=3\n"))) + (after-each + (delete-file doom-env-file)) + + (it "throws a file-error if file doesn't exist" + (expect (doom-load-envvars-file "/tmp/envvardoesnotexist") + :to-throw 'file-error)) + + (it "to fail silently if NOERROR is non-nil" + (expect (doom-load-envvars-file "/tmp/envvardoesnotexist" 'noerror) + :not :to-throw)) + + (it "loads a well-formed envvar file" + (expect (getenv "A") :not :to-be-truthy) + (expect (doom-load-envvars-file doom-env-file) + :to-equal '(("A" . "1") ("B" . "2") ("C" . "3"))) + (expect (getenv "A") :to-equal "1")) + + (it "fails on an invalid envvar file" + (with-temp-file doom-env-file (insert "A=1\nB=2\nC=3\n")) + (expect (doom-load-envvars-file doom-env-file) :to-throw)))) diff --git a/modules/editor/evil/test/test-evil.el b/modules/editor/evil/test/test-evil.el index 240a74b13..99694f11e 100644 --- a/modules/editor/evil/test/test-evil.el +++ b/modules/editor/evil/test/test-evil.el @@ -3,12 +3,11 @@ (describe "feature/evil" :var (resv project-root) - (before-all - (require! :editor evil) - (require 'evil) - (load! "../autoload/evil")) - (after-all - (unload-feature 'evil t)) + + (require! :editor evil) + (require 'evil) + (load! "../autoload/evil") + (before-each (fset 'resv #'+evil-resolve-vim-path-a) (spy-on 'doom-project-root :and-call-fake (lambda () project-root))) diff --git a/modules/lang/org/test/test-org.el b/modules/lang/org/test/test-org.el index 4ef30c231..cbe36f62d 100644 --- a/modules/lang/org/test/test-org.el +++ b/modules/lang/org/test/test-org.el @@ -19,33 +19,33 @@ (describe "headlines" (it "appends first-level headlines with an extra newline" - (insert! "* {0}Header") + (insert!! "* {0}Header") (+org/insert-item-below 1) (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") + (insert!! "* {0}Header") (+org/insert-item-above 1) (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") + (insert!! "** {0}Header") (+org/insert-item-below 1) (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") + (insert!! "** {0}Header") (+org/insert-item-above 1) (expect (eolp)) (expect (buffer-substring-no-properties (point-min) (point-max)) :to-equal "** \n** Header")) (it "appends headlines, skipping subtrees" - (insert! "** {0}First\n" + (insert!! "** {0}First\n" "*** sub 1\n" "*** sub 2\n" "**** subsub 1\n" @@ -63,7 +63,7 @@ "** Header") "\n"))) (it "prepends headlines, skipping subtrees" - (insert! "** First\n" + (insert!! "** First\n" "*** sub 1\n" "*** sub 2\n" "**** {0}subsub 1\n" @@ -83,18 +83,18 @@ (describe "plain lists" (it "appends items" - (insert! "+ {0}List item") + (insert!! "+ {0}List item") (+org/insert-item-below 1) (expect (buffer-substring-no-properties (point-min) (point-max)) :to-equal "+ List item\n+ ")) (it "prepends items" - (insert! "+ {0}List item") + (insert!! "+ {0}List item") (+org/insert-item-above 1) (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" + (insert!! "+ {0}List item\n" " + Sub item\n" "+ List item") (+org/insert-item-below 1) @@ -106,7 +106,7 @@ "+ List item") "\n"))) (it "prepends items, but skips over child items" - (insert! "+ List item\n" + (insert!! "+ List item\n" " + Sub item\n" "+ {0}List item") (+org/insert-item-above 1) @@ -120,7 +120,7 @@ (describe "numbered lists" (it "appends items and updates numbers" - (insert! "1. {0}List item\n" + (insert!! "1. {0}List item\n" "2. Sub item\n" "3. List item") (+org/insert-item-below 1) @@ -132,7 +132,7 @@ "4. List item") "\n"))) (it "prepends items and updates numbers" - (insert! "1. List item\n" + (insert!! "1. List item\n" "2. Sub item\n" "3. {0}List item") (+org/insert-item-above 1) diff --git a/modules/lang/web/test/test-web.el b/modules/lang/web/test/test-web.el index 72fbc04cf..ac97ad281 100644 --- a/modules/lang/web/test/test-web.el +++ b/modules/lang/web/test/test-web.el @@ -51,20 +51,20 @@ (describe "css-mode" (it "converts inline statements into multiline blocks" - (insert! "body { color: red{0}; font-size: 2em; }")) + (insert!! "body { color: red{0}; font-size: 2em; }")) (it "works when cursor is on closing brace" - (insert! "body { color: red; font-size: 2em; {0}}")) + (insert!! "body { color: red; font-size: 2em; {0}}")) (it "works when cursor is on opening brace" - (insert! "body {{0} color: red; font-size: 2em; }")) + (insert!! "body {{0} color: red; font-size: 2em; }")) (it "works when cursor is on same line" - (insert! "{0}body { color: red; font-size: 2em; }")))) + (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" + (insert!! "// test{0}\n" "body { color: red; font-size: 2em; }") (+css/comment-indent-new-line) (expect (string-trim (buffer-string)) :to-equal @@ -76,7 +76,7 @@ (expect (eolp)) (expect (line-number-at-pos) :to-be 2)) (it "preserves indentation within continued comments" - (insert! "// test{0}\n" + (insert!! "// test{0}\n" "body { color: red; font-size: 2em; }") (+css/comment-indent-new-line) (expect (string-trim (buffer-string)) :to-equal diff --git a/modules/ui/workspaces/test/test-workspaces.el b/modules/ui/workspaces/test/test-workspaces.el index f38173683..cc0e76c8c 100644 --- a/modules/ui/workspaces/test/test-workspaces.el +++ b/modules/ui/workspaces/test/test-workspaces.el @@ -11,10 +11,11 @@ persp1 persp1-name persp2 persp2-name wconf) + (require! :ui workspaces) + (require 'persp-mode) + (before-all - (delete-other-windows) - (require! :ui workspaces) - (require 'persp-mode)) + (delete-other-windows)) (before-each (switch-to-buffer "*scratch*")