refactor!: restructure Doom core

BREAKING CHANGE: This restructures the project in preparation for Doom
to be split into two repos. Users that have reconfigured Doom's CLI
stand a good chance of seeing breakage, especially if they've referred
to any core-* feature, e.g.

  (after! core-cli-ci ...)

To fix it, simply s/core-/doom-/, i.e.

  (after! doom-cli-ci ...)

What this commit specifically changes is:
- Renames all core features from core-* to doom-*
- Moves core/core-* -> lisp/doom-*
- Moves core/autoloads/* -> lisp/lib/*
- Moves core/templates -> templates/

Ref: #4273
This commit is contained in:
Henrik Lissner 2022-07-30 21:49:00 +02:00
parent a9866e37e4
commit b9933e6637
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
69 changed files with 147 additions and 145 deletions

View file

@ -0,0 +1,160 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-buffers.el
(describe "core/autoload/buffers"
:var (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"))
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 lists"
(describe "doom-buffer-list"
(it "should only see four buffers"
(expect (doom-buffer-list) :to-contain-items (list a b c d)))))
;; TODO predicate tests
(xdescribe "predicate functions"
(describe "doom-dired-buffer-p")
(describe "doom-special-buffer-p")
(describe "doom-temp-buffer-p")
(describe "doom-visible-buffer-p")
(describe "doom-buried-buffer-p")
(describe "doom-non-file-visiting-buffer-p")
(describe "doom-dired-buffer-p")
(describe "doom-buffer-frame-predicate"))
(describe "doom-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-core-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-contain-items (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 "doom-fallback-buffer"
(it "returns a live 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
(with-current-buffer b (setq buffer-file-name "x"))
(with-current-buffer c (rename-buffer "*C*")))
(describe "doom-mark-buffer-as-real-h"
(with-current-buffer a
(doom-mark-buffer-as-real-h)
(expect (buffer-local-value 'doom-real-buffer-p a))))
(describe "doom-set-buffer-real"
(it "sets `doom-real-buffer-p' buffer-locally"
(doom-set-buffer-real a t)
(expect (buffer-local-value 'doom-real-buffer-p a))))
(describe "doom-real-buffer-p"
(it "returns t for buffers manually marked real"
(doom-set-buffer-real a t)
(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 "doom-unreal-buffer-p"
(it "returns t for unreal buffers"
(expect (doom-unreal-buffer-p c))
(expect (doom-unreal-buffer-p d)))
(it "returns nil for real buffers"
(doom-set-buffer-real a t)
(expect (not (doom-unreal-buffer-p a)))
(expect (not (doom-unreal-buffer-p b)))))
(describe "doom-real-buffer-list"
(it "returns only real buffers"
(expect (doom-real-buffer-list) :to-contain-items (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))
(describe "doom-matching-buffers"
(it "can match buffers by regexp"
(expect (doom-matching-buffers "^[ac]$") :to-have-same-items-as (list a c))))
(describe "doom-buffers-in-mode"
(it "can match buffers by major-mode"
(expect (doom-buffers-in-mode 'text-mode) :to-have-same-items-as (list b c))))
(describe "doom-buried-buffers"
(it "can find all buried buffers"
(expect (doom-buried-buffers) :to-contain-items (list c d))))
(describe "doom-visible-buffers"
(it "can find all visible buffers"
(expect (doom-visible-buffers)
:to-have-same-items-as (list a b))))
(describe "doom-visible-windows"
(it "can find all visible windows"
(expect (doom-visible-windows)
:to-have-same-items-as
(mapcar #'get-buffer-window (list a b))))))
(describe "killing buffers/windows"
(describe "doom-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
(xdescribe "doom-fixup-windows")
(xdescribe "doom-kill-buffer-fixup-windows")
(xdescribe "doom-kill-buffers-fixup-windows"))
(xdescribe "commands"
(describe "doom/kill-all-buffers")
(describe "doom/kill-other-buffers")
(describe "doom/kill-matching-buffers")
(describe "doom/kill-buried-buffers")
(describe "doom/kill-project-buffers"))))

164
test/test-autoload-files.el Normal file
View file

@ -0,0 +1,164 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-files.el
(describe "core/autoload/files"
(load! "autoload/files" doom-core-dir)
(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"))))))
(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)))))
;; TODO
(xdescribe "doom-glob")
(xdescribe "doom-path")
(xdescribe "doom-dir")
(xdescribe "doom-files-in")
(xdescribe "doom-file-size")
(xdescribe "doom-directory-size")
(xdescribe "doom-file-cookie-p"))
(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))))
(xdescribe "sudo {this,find} file"
(before-each
(spy-on 'find-file :and-return-value nil)
(spy-on 'find-alternate-file :and-return-value nil))
(describe "doom/sudo-find-file")
(describe "doom/sudo-this-file")))

View file

@ -0,0 +1,44 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-message.el
(describe "core/autoload/format"
(describe "format!"
:var (doom-output-backend)
(before-all
(setq doom-output-backend 'ansi))
(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 text properties in interactive sessions"
(let ((doom-output-backend 'text-properties))
(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"))))
(xdescribe "insert!")
(xdescribe "print!")
(xdescribe "print-group!")
(xdescribe "error!")
(xdescribe "user-error!"))

View file

@ -0,0 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-package.el
;;;###if nil
(xdescribe "core/autoload/packages")

256
test/test-core-keybinds.el Normal file
View file

@ -0,0 +1,256 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-keybinds.el
(describe "core/keybinds"
(require 'core-keybinds)
;; FIXME test against their side effects rather than their implementation
(describe "map!"
:var (doom--map-evil-p states-alist)
(before-each
(setq doom--map-evil-p t
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)))
(it "binds a key in one evil state"
(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)
:to-expand-into
'(progn (general-define-key :states 'insert "C-." #'a)
(general-define-key :states 'visual "C-." #'a)
(general-define-key :states 'normal "C-." #'a))))
(it "binds evil keybinds together with global keybinds"
(expect '(map! :ng "C-." #'a)
:to-expand-into
'(progn
(general-define-key :states 'normal "C-." #'a)
(general-define-key "C-." #'a)))))
(describe "Multiple keybinds"
(it "binds global keys and preserves order"
(expect '(map! "C-." #'a "C-," #'b "C-/" #'c)
:to-expand-into
'(general-define-key "C-." #'a "C-," #'b "C-/" #'c)))
(it "binds multiple keybinds in an evil state and preserve order"
(dolist (state states-alist)
(expect `(map! ,(car state) "a" #'a
,(car state) "b" #'b
,(car state) "c" #'c)
:to-expand-into
`(general-define-key :states ',(cdr state)
"a" #'a
"b" #'b
"c" #'c))))
(it "binds multiple keybinds in different evil states"
(expect `(map! :n "a" #'a
:n "b" #'b
:n "e" #'e
:v "c" #'c
:i "d" #'d)
:to-expand-into
`(progn (general-define-key :states 'insert "d" #'d)
(general-define-key :states 'visual "c" #'c)
(general-define-key :states 'normal "a" #'a "b" #'b "e" #'e))))
(it "groups multi-state keybinds while preserving same-group key order"
(expect `(map! :n "a" #'a
:v "c" #'c
:n "b" #'b
:i "d" #'d
:n "e" #'e)
:to-expand-into
`(progn (general-define-key :states 'insert "d" #'d)
(general-define-key :states 'visual "c" #'c)
(general-define-key :states 'normal "a" #'a "b" #'b "e" #'e))))
(it "binds multiple keybinds in multiple evil states"
(expect `(map! :nvi "a" #'a
:nvi "b" #'b
:nvi "c" #'c)
:to-expand-into
'(progn (general-define-key :states 'insert "a" #'a "b" #'b "c" #'c)
(general-define-key :states 'visual "a" #'a "b" #'b "c" #'c)
(general-define-key :states 'normal "a" #'a "b" #'b "c" #'c)))))
(describe "Nested keybinds"
(it "binds global keys"
(expect '(map! "C-." #'a
("C-a" #'b)
("C-x" #'c))
:to-expand-into
'(progn (general-define-key "C-." #'a)
(general-define-key "C-a" #'b)
(general-define-key "C-x" #'c))))
(it "binds nested evil keybinds"
(expect '(map! :n "C-." #'a
(:n "C-a" #'b)
(:n "C-x" #'c))
:to-expand-into
'(progn (general-define-key :states 'normal "C-." #'a)
(general-define-key :states 'normal "C-a" #'b)
(general-define-key :states 'normal "C-x" #'c))))
(it "binds global keybinds in between evil keybinds"
(expect '(map! :n "a" #'a
"b" #'b
:n "c" #'c)
:to-expand-into
'(progn (general-define-key "b" #'b)
(general-define-key :states 'normal "a" #'a "c" #'c)))))
;;
(describe "Properties"
(describe ":after"
(it "wraps `general-define-key' in a `after!' block"
(dolist (form '((map! :after helm "a" #'a "b" #'b)
(map! (:after helm "a" #'a "b" #'b))))
(expect form :to-expand-into '(after! helm (general-define-key "a" #'a "b" #'b))))
(expect '(map! "a" #'a (:after helm "b" #'b "c" #'c))
:to-expand-into
'(progn
(general-define-key "a" #'a)
(after! helm
(general-define-key "b" #'b "c" #'c))))
(expect '(map! (:after helm "b" #'b "c" #'c) "a" #'a)
:to-expand-into
'(progn
(after! helm
(general-define-key "b" #'b "c" #'c))
(general-define-key "a" #'a))))
(it "nests `after!' blocks"
(expect '(map! :after x "a" #'a
(:after y "b" #'b
(:after z "c" #'c)))
:to-expand-into
'(after! x
(progn
(general-define-key "a" #'a)
(after! y
(progn
(general-define-key "b" #'b)
(after! z
(general-define-key "c" #'c))))))))
(it "nests `after!' blocks in other nested blocks"
(expect '(map! :after x "a" #'a
(:when t "b" #'b
(:after z "c" #'c)))
:to-expand-into
'(after! x
(progn
(general-define-key "a" #'a)
(when t
(progn
(general-define-key "b" #'b)
(after! z (general-define-key "c" #'c)))))))))
(describe ":desc"
(it "add a :which-key property to a keybind's DEF"
(expect '(map! :desc "A" "a" #'a)
:to-expand-into
`(general-define-key "a" (list :def #'a :which-key "A")))))
(describe ":when/:unless"
(it "wraps keys in a conditional block"
(dolist (prop '(:when :unless))
(let ((prop-fn (intern (doom-keyword-name prop))))
(expect `(map! ,prop t "a" #'a "b" #'b)
:to-expand-into
`(,prop-fn t (general-define-key "a" #'a "b" #'b)))
(expect `(map! (,prop t "a" #'a "b" #'b))
:to-expand-into
`(,prop-fn t (general-define-key "a" #'a "b" #'b))))))
(it "nests conditional blocks"
(expect '(map! (:when t "a" #'a (:when t "b" #'b)))
:to-expand-into
'(when t
(progn (general-define-key "a" #'a)
(when t (general-define-key "b" #'b)))))))
(describe ":leader"
(it "uses leader definer"
(expect '(map! :leader "a" #'a "b" #'b)
:to-expand-into
'(doom--define-leader-key "a" #'a "b" #'b)))
(it "it persists for nested keys"
(expect '(map! :leader "a" #'a ("b" #'b))
:to-expand-into
'(progn (doom--define-leader-key "a" #'a)
(doom--define-leader-key "b" #'b)))))
(describe ":localleader"
(it "uses localleader definer"
(expect '(map! :localleader "a" #'a "b" #'b)
:to-expand-into
'(define-localleader-key! "a" #'a "b" #'b)))
(it "it persists for nested keys"
(expect '(map! :localleader "a" #'a ("b" #'b))
:to-expand-into
'(progn (define-localleader-key! "a" #'a)
(define-localleader-key! "b" #'b)))))
(describe ":map/:keymap"
(it "specifies a single keymap for keys"
(expect '(map! :map emacs-lisp-mode-map "a" #'a)
:to-expand-into
'(general-define-key :keymaps '(emacs-lisp-mode-map) "a" #'a)))
(it "specifies multiple keymap for keys"
(expect '(map! :map (lisp-mode-map emacs-lisp-mode-map) "a" #'a)
:to-expand-into
'(general-define-key :keymaps '(lisp-mode-map emacs-lisp-mode-map) "a" #'a))))
(describe ":mode"
(it "appends -map to MODE"
(expect '(map! :mode emacs-lisp-mode "a" #'a)
:to-expand-into
'(general-define-key :keymaps '(emacs-lisp-mode-map) "a" #'a))))
(describe ":prefix"
(it "specifies a prefix for all keys"
(expect '(map! :prefix "a" "x" #'x "y" #'y "z" #'z)
:to-expand-into
'(general-define-key :prefix "a" "x" #'x "y" #'y "z" #'z)))
(it "overwrites previous inline :prefix properties"
(expect '(map! :prefix "a" "x" #'x "y" #'y :prefix "b" "z" #'z)
:to-expand-into
'(progn (general-define-key :prefix "a" "x" #'x "y" #'y)
(general-define-key :prefix "b" "z" #'z))))
(it "accumulates keys when nested"
(expect '(map! (:prefix "a" "x" #'x (:prefix "b" "x" #'x)))
:to-expand-into
`(progn (general-define-key :prefix "a" "x" #'x)
(general-define-key :prefix (general--concat nil "a" "b")
"x" #'x)))))
(describe ":textobj"
(it "defines keys in evil-{inner,outer}-text-objects-map"
(expect '(map! :textobj "a" #'inner #'outer)
:to-expand-into
'(map! (:map evil-inner-text-objects-map "a" #'inner)
(:map evil-outer-text-objects-map "a" #'outer))))))))

271
test/test-core-lib.el Normal file
View file

@ -0,0 +1,271 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-lib.el
(describe "core-lib"
(before-all
(require '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)
(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 "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
(eval-and-compile load-file-name))))
(describe "dir!"
(it "returns the executing directory"
(expect (eval-and-compile (dir!))
:to-equal
(eval-and-compile
(directory-file-name (file-name-directory load-file-name))))))
(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 "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 "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 "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 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! (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)))
(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! '(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)))
(it "adds implicit lambda to one hook"
(add-hook! fake-mode (progn))
(add-hook! 'other-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))
(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)
(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))))
(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 'nomessage))
(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 'nomessage)))
(describe "quiet!"
:var (doom-debug-mode)
(before-each
(setq doom-debug-mode nil))
(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)))))))

23
test/test-core-modules.el Normal file
View file

@ -0,0 +1,23 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-modules.el
(xdescribe "core-modules"
(require 'core-modules)
(describe "doom!")
(describe "doom-modules")
(describe "doom-module-p")
(describe "doom-module-get")
(describe "doom-module-put")
(describe "doom-module-set")
(describe "doom-module-path")
(describe "doom-module-locate-path")
(describe "doom-module-from-path")
(describe "doom-module-load-path")
(describe "require!")
(describe "featurep!")
(describe "after!")
(describe "use-package!")
(describe "use-package-hook!"))

View file

@ -0,0 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-packages.el
;;;###if nil
(xdescribe "core-packages")

View file

@ -0,0 +1,40 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-projects.el
(describe "core/projects"
: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"
(expect (doom-project-p doom-emacs-dir)))
(it "Should detect when not in a valid project"
(expect (doom-project-p (expand-file-name "~")) :to-be nil)))
(describe "project-root"
(it "should resolve to the project's root"
(expect (doom-project-root doom-core-dir) :to-equal-file doom-emacs-dir))
(it "should return nil if not in a project"
(expect (doom-project-root (expand-file-name "~")) :to-be nil)))
(describe "project-expand"
(it "expands to a path relative to the project root"
(expect (doom-project-expand "init.el" doom-core-dir) :to-equal-file
(expand-file-name "init.el" (doom-project-root doom-core-dir)))))
(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")))))))

106
test/test-core-ui.el Normal file
View file

@ -0,0 +1,106 @@
;; -*- no-byte-compile: t; -*-
;;; ../core/test/test-core-ui.el
(describe "core/ui"
(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-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))))))
(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))))))

127
test/test-core.el Normal file
View file

@ -0,0 +1,127 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core.el
(describe "core"
:var (doom-interactive-p)
(before-each
(setq doom-interactive-p nil))
(describe "initialization"
(describe "doom-initialize"
:var (doom-init-p)
(before-each
(setq doom-init-p nil))
(it "initializes once"
(expect (doom-initialize nil 'noerror))
(expect (not (doom-initialize nil 'noerror)))
(expect (not (doom-initialize nil 'noerror)))
(expect doom-init-p))
(it "initializes multiple times, if forced"
(expect (doom-initialize nil 'noerror))
(expect (not (doom-initialize nil 'noerror)))
(expect (doom-initialize 'force 'noerror)))
(describe "package initialization"
(before-each
(spy-on 'doom-initialize-packages :and-return-value t))
(it "initializes packages if core autoload file doesn't exist"
(let ((doom-autoloads-file "doesnotexist"))
(expect (doom-initialize nil 'noerror))
(expect 'doom-initialize-packages :to-have-been-called))
(it "doesn't initialize packages if core autoload file was loaded"
(let ((doom-interactive-p t))
(spy-on 'doom-load-autoloads-file :and-return-value t)
(doom-initialize nil 'noerror)
(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 'noerror)
(expect 'doom-initialize-packages :to-have-been-called)))
(describe "autoloads files"
(before-each
(spy-on 'doom-load-autoloads-file)
(spy-on 'warn :and-return-value t))
(it "loads autoloads files"
(ignore-errors (doom-initialize nil 'noerror))
(expect 'doom-load-autoloads-file
:to-have-been-called-with doom-autoloads-file)
(expect 'doom-load-autoloads-file
:to-have-been-called-with doom-package-autoload-file))
(it "throws doom-autoload-error when autoload files don't exist"
(let ((doom-autoloads-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"
:var (doom-autoloads-file doom-alt-autoload-file result)
(before-each
(setq doom-autoloads-file (make-temp-file "doom-autoload" nil ".el"))
(with-temp-file doom-autoloads-file)
(byte-compile-file doom-autoloads-file))
(after-each
(delete-file doom-autoloads-file)
(delete-file (byte-compile-dest-file doom-autoloads-file)))
(it "loads the byte-compiled autoloads file if available"
(doom-load-autoloads-file doom-autoloads-file)
(expect (caar load-history) :to-equal-file
(byte-compile-dest-file doom-autoloads-file))
(delete-file (byte-compile-dest-file doom-autoloads-file))
(doom-load-autoloads-file doom-autoloads-file)
(expect (caar load-history) :to-equal-file doom-autoloads-file))
(it "returns non-nil if successful"
(expect (doom-load-autoloads-file doom-autoloads-file)))
(it "returns nil on failure or error, non-fatally"
(expect (doom-load-autoloads-file "/does/not/exist") :to-be nil)))
(describe "doom-load-envvars-file"
:var (doom-env-file process-environment)
(before-each
(setq process-environment nil
doom-env-file (make-temp-file "doom-env"))
(with-temp-file doom-env-file
(insert "A=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 "returns the new value for `process-environment'"
(expect (doom-load-envvars-file doom-env-file)
:to-have-same-items-as '("A" "B" "C")))
(it "alters environment variables"
(dolist (key '("A" "B" "C"))
(expect (getenv key) :not :to-be-truthy))
(expect (doom-load-envvars-file doom-env-file))
(expect (getenv "A") :to-equal "1")
(expect (getenv "B") :to-equal "2")
(expect (getenv "C") :to-equal "3"))))