;; -*- 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 (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)))))) (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 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)))))))