aboutsummaryrefslogtreecommitdiff
path: root/tests/test-hugo-config-commands.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-14 01:30:33 -0500
committerCraig Jennings <c@cjennings.net>2026-05-14 01:30:33 -0500
commit54f54840686b29d510b360caeb43d254aec09ffe (patch)
treeca03723a186d8e1f272de6096bf33ae7eb5db52c /tests/test-hugo-config-commands.el
parenta9a9e56148e9ab83f9abc4e4c531be86974364d1 (diff)
downloaddotemacs-54f54840686b29d510b360caeb43d254aec09ffe.tar.gz
dotemacs-54f54840686b29d510b360caeb43d254aec09ffe.zip
test(hugo-config): cover new-post, export, navigation, preview, publish
Sibling tests covered the pure helpers (`cj/hugo--post-file-path`, `cj/hugo--post-template`, `cj/hugo--post-metadata`, `cj/hugo--collect-drafts`, `cj/hugo-open-blog-dir-external`, `cj/hugo-toggle-draft`). This batch covers the remaining commands and preview helpers: - `cj/hugo-new-post`: writes the template to a slugged file, errors when one already exists. - `cj/hugo-export-post`: errors outside org-mode, delegates to `org-hugo-export-to-md` otherwise. - `cj/hugo-open-blog-dir`: ensures the dir exists and opens dired on it. - `cj/hugo-open-draft`: messages when no drafts, otherwise picks via `completing-read` and opens. - `cj/hugo--preview-filter`: opens the browser when Hugo prints "Web Server is available", ignores arbitrary output. - `cj/hugo--preview-sentinel`: clears the process var on clean exit, messages on a non-zero exit. - `cj/hugo-preview`: stops a running server, starts one when stopped (verifying `start-process` got the "server" arg). - `cj/hugo-publish`: hands off to `magit-status-setup-buffer` on `website-dir`. ox-hugo's `org-hugo-slug` is stubbed via `defun` (the package isn't installed in batch); `require`, `org-hugo-export-to-md`, `dired`, `find-file`, `browse-url`, `start-process`, `kill-process`, and `magit-status-setup-buffer` are stubbed per-test.
Diffstat (limited to 'tests/test-hugo-config-commands.el')
-rw-r--r--tests/test-hugo-config-commands.el235
1 files changed, 235 insertions, 0 deletions
diff --git a/tests/test-hugo-config-commands.el b/tests/test-hugo-config-commands.el
new file mode 100644
index 00000000..a387d57d
--- /dev/null
+++ b/tests/test-hugo-config-commands.el
@@ -0,0 +1,235 @@
+;;; test-hugo-config-commands.el --- Tests for hugo-config command wrappers + preview helpers -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Sibling tests cover the pure helpers (`cj/hugo--post-file-path`,
+;; `cj/hugo--post-template`, `cj/hugo--post-metadata`,
+;; `cj/hugo--collect-drafts`, `cj/hugo-open-blog-dir-external`,
+;; `cj/hugo-toggle-draft`). This file covers the remaining
+;; commands + preview helpers:
+;;
+;; cj/hugo-new-post
+;; cj/hugo-export-post
+;; cj/hugo-open-blog-dir
+;; cj/hugo-open-draft
+;; cj/hugo--preview-filter
+;; cj/hugo--preview-sentinel
+;; cj/hugo-preview
+;; cj/hugo-publish
+;;
+;; ox-hugo / magit / hugo / browse-url / dired are all stubbed.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'hugo-config)
+
+;; ox-hugo isn't installed in the batch environment. Provide a tiny
+;; slug stub so the post-creation tests can build a filename.
+(unless (fboundp 'org-hugo-slug)
+ (defun org-hugo-slug (title)
+ "Stub slugifier for batch tests."
+ (downcase (replace-regexp-in-string "[^a-zA-Z0-9]+" "-" title))))
+
+;;; cj/hugo-new-post
+
+(ert-deftest test-hugo-new-post-creates-file-with-template ()
+ "Normal: a new post writes the template to a slugged file."
+ (let* ((tmp-dir (make-temp-file "test-hugo-" t))
+ (cj/hugo-content-org-dir tmp-dir))
+ (unwind-protect
+ (cl-letf (((symbol-function 'read-from-minibuffer)
+ (lambda (&rest _) "My New Post"))
+ ((symbol-function 'message) #'ignore))
+ (cj/hugo-new-post)
+ (let ((expected (cj/hugo--post-file-path "My New Post")))
+ (should (file-exists-p expected))
+ (with-temp-buffer
+ (insert-file-contents expected)
+ (should (string-match-p "#\\+title: My New Post" (buffer-string)))
+ (should (string-match-p "#\\+hugo_draft: true" (buffer-string))))
+ ;; The find-file opened a buffer; kill it so the temp dir can go.
+ (when-let ((buf (get-file-buffer expected)))
+ (kill-buffer buf))))
+ (delete-directory tmp-dir t))))
+
+(ert-deftest test-hugo-new-post-errors-when-file-exists ()
+ "Error: re-creating an existing post signals user-error."
+ (let* ((tmp-dir (make-temp-file "test-hugo-" t))
+ (cj/hugo-content-org-dir tmp-dir))
+ (unwind-protect
+ (let* ((path (cj/hugo--post-file-path "Duplicate Post")))
+ (with-temp-file path (insert "already here"))
+ (cl-letf (((symbol-function 'read-from-minibuffer)
+ (lambda (&rest _) "Duplicate Post"))
+ ((symbol-function 'message) #'ignore))
+ (should-error (cj/hugo-new-post) :type 'user-error)))
+ (delete-directory tmp-dir t))))
+
+;;; cj/hugo-export-post
+
+(ert-deftest test-hugo-export-post-error-not-in-org-mode ()
+ "Error: outside org-mode the export errors with user-error.
+
+ox-hugo isn't installed in the batch environment, so `require' is
+stubbed before the org-mode-derived guard runs."
+ (with-temp-buffer
+ (cl-letf (((symbol-function 'require)
+ (lambda (feat &rest _) (if (eq feat 'ox-hugo) t (error "unstubbed require: %s" feat))))
+ ((symbol-function 'org-hugo-export-to-md)
+ (lambda () (error "shouldn't run"))))
+ (should-error (cj/hugo-export-post) :type 'user-error))))
+
+(ert-deftest test-hugo-export-post-normal-delegates-to-ox-hugo ()
+ "Normal: in an org-mode buffer the export delegates to `org-hugo-export-to-md'."
+ (let ((called nil)
+ (msg nil))
+ (with-temp-buffer
+ (delay-mode-hooks (org-mode))
+ (cl-letf (((symbol-function 'require)
+ (lambda (feat &rest _) (if (eq feat 'ox-hugo) t (error "unstubbed require: %s" feat))))
+ ((symbol-function 'org-hugo-export-to-md)
+ (lambda () (setq called t)))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args) (setq msg (apply #'format fmt args)))))
+ (cj/hugo-export-post)))
+ (should called)
+ (should (string-match-p "Exported" msg))))
+
+;;; cj/hugo-open-blog-dir
+
+(ert-deftest test-hugo-open-blog-dir-creates-and-opens-dired ()
+ "Normal: missing dir gets created, then dired opens it."
+ (let* ((tmp (concat (make-temp-file "test-hugo-blog-" t) "/sub"))
+ (cj/hugo-content-org-dir tmp)
+ (dired-arg nil))
+ (unwind-protect
+ (cl-letf (((symbol-function 'dired)
+ (lambda (d) (setq dired-arg d))))
+ (cj/hugo-open-blog-dir))
+ (when (file-directory-p tmp) (delete-directory tmp t)))
+ (should (equal dired-arg tmp))))
+
+;;; cj/hugo-open-draft
+
+(ert-deftest test-hugo-open-draft-empty-list-messages ()
+ "Boundary: no drafts -> messages \"No drafts\"."
+ (let ((msg nil))
+ (cl-letf (((symbol-function 'cj/hugo--collect-drafts)
+ (lambda (_) nil))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (setq msg (apply #'format fmt args)))))
+ (cj/hugo-open-draft))
+ (should (string-match-p "No drafts" msg))))
+
+(ert-deftest test-hugo-open-draft-picks-via-completing-read ()
+ "Normal: with drafts, completing-read picks one and find-file opens it."
+ (let ((opened nil))
+ (cl-letf (((symbol-function 'cj/hugo--collect-drafts)
+ (lambda (_) '(("Foo Post" . "/tmp/foo.org")
+ ("Bar Post" . "/tmp/bar.org"))))
+ ((symbol-function 'completing-read)
+ (lambda (&rest _) "Foo Post"))
+ ((symbol-function 'find-file)
+ (lambda (f) (setq opened f))))
+ (cj/hugo-open-draft))
+ (should (equal opened "/tmp/foo.org"))))
+
+;;; cj/hugo--preview-filter
+
+(ert-deftest test-hugo-preview-filter-opens-browser-on-ready-line ()
+ "Normal: a 'Web Server is available' line in OUTPUT triggers `browse-url'."
+ (let ((url nil))
+ (cl-letf (((symbol-function 'process-buffer)
+ (lambda (_) nil))
+ ((symbol-function 'process-live-p)
+ (lambda (_) t))
+ ((symbol-function 'browse-url)
+ (lambda (u) (setq url u)))
+ ((symbol-function 'set-process-filter) #'ignore))
+ (cj/hugo--preview-filter 'fake-proc
+ "Web Server is available at http://localhost:1313/\n"))
+ (should (equal url "http://localhost:1313/"))))
+
+(ert-deftest test-hugo-preview-filter-does-not-open-on-other-output ()
+ "Boundary: arbitrary output doesn't trigger the browser."
+ (let ((url nil))
+ (cl-letf (((symbol-function 'process-buffer) (lambda (_) nil))
+ ((symbol-function 'process-live-p) (lambda (_) t))
+ ((symbol-function 'browse-url)
+ (lambda (u) (setq url u)))
+ ((symbol-function 'set-process-filter) #'ignore))
+ (cj/hugo--preview-filter 'fake-proc "Hugo built site in 5ms\n"))
+ (should-not url)))
+
+;;; cj/hugo--preview-sentinel
+
+(ert-deftest test-hugo-preview-sentinel-clears-process-var-on-clean-exit ()
+ "Normal: a clean exit clears `cj/hugo--preview-process'."
+ (let ((cj/hugo--preview-process 'fake-proc))
+ (cl-letf (((symbol-function 'process-status) (lambda (_) 'exit))
+ ((symbol-function 'process-exit-status) (lambda (_) 0)))
+ (cj/hugo--preview-sentinel 'fake-proc "finished\n"))
+ (should-not cj/hugo--preview-process)))
+
+(ert-deftest test-hugo-preview-sentinel-messages-on-crash ()
+ "Boundary: a non-zero exit logs the crash message."
+ (let ((cj/hugo--preview-process 'fake-proc)
+ (msg nil))
+ (cl-letf (((symbol-function 'process-status) (lambda (_) 'exit))
+ ((symbol-function 'process-exit-status) (lambda (_) 1))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (setq msg (apply #'format fmt args)))))
+ (cj/hugo--preview-sentinel 'fake-proc "exited abnormally\n"))
+ (should (string-match-p "hugo server crashed" msg))))
+
+;;; cj/hugo-preview
+
+(ert-deftest test-hugo-preview-stops-running-server ()
+ "Normal: with a live process, preview kills it and clears the var."
+ (let ((cj/hugo--preview-process 'fake-proc)
+ (killed nil)
+ (msg nil))
+ (cl-letf (((symbol-function 'process-live-p) (lambda (_) t))
+ ((symbol-function 'kill-process)
+ (lambda (p) (setq killed p)))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (setq msg (apply #'format fmt args)))))
+ (cj/hugo-preview))
+ (should (eq killed 'fake-proc))
+ (should-not cj/hugo--preview-process)
+ (should (string-match-p "stopped" msg))))
+
+(ert-deftest test-hugo-preview-starts-server-when-stopped ()
+ "Normal: with no live process, preview starts the hugo server."
+ (let ((cj/hugo--preview-process nil)
+ (start-args nil))
+ (cl-letf (((symbol-function 'process-live-p) (lambda (_) nil))
+ ((symbol-function 'start-process)
+ (lambda (&rest args)
+ (setq start-args args)
+ 'fake-proc))
+ ((symbol-function 'set-process-filter) #'ignore)
+ ((symbol-function 'set-process-sentinel) #'ignore)
+ ((symbol-function 'message) #'ignore))
+ (cj/hugo-preview))
+ (should (eq cj/hugo--preview-process 'fake-proc))
+ (should (member "server" start-args))))
+
+;;; cj/hugo-publish
+
+(ert-deftest test-hugo-publish-opens-magit-on-website-dir ()
+ "Normal: publish hands off to `magit-status-setup-buffer' on the website dir."
+ (let ((called-with nil))
+ (cl-letf (((symbol-function 'magit-status-setup-buffer)
+ (lambda (d) (setq called-with d))))
+ (cj/hugo-publish))
+ (should (equal called-with website-dir))))
+
+(provide 'test-hugo-config-commands)
+;;; test-hugo-config-commands.el ends here