diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-13 15:25:52 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-13 15:25:52 -0500 |
| commit | c3514440eb3de3101576baa5c3c592c0d908f70b (patch) | |
| tree | 6534504d1a90a9c014a09c446f2f384677e80e10 /tests/test-org-agenda-config-category.el | |
| parent | e076815895ed452e021ae4c1986eca1f0e67aa41 (diff) | |
| download | dotemacs-c3514440eb3de3101576baa5c3c592c0d908f70b.tar.gz dotemacs-c3514440eb3de3101576baa5c3c592c0d908f70b.zip | |
feat(org-agenda): use project name as todo.org category
The %c column on agenda blocks rendered every project's todo.org as "todo:" -- org defaults the buffer category to the filename without extension, so every entry looked alike. An org-mode-hook now overrides org-category with the parent directory's basename (stripping a single leading dot, so ~/.emacs.d/todo.org reads as "emacs.d") whenever a todo.org file opens and its category is still the filename default. Explicit #+CATEGORY: keywords still win.
14 tests in test-org-agenda-config-category.el cover the helper's normal/boundary/error paths and the hook's override + explicit-category-preserved cases.
Diffstat (limited to 'tests/test-org-agenda-config-category.el')
| -rw-r--r-- | tests/test-org-agenda-config-category.el | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/tests/test-org-agenda-config-category.el b/tests/test-org-agenda-config-category.el new file mode 100644 index 00000000..6a54d9e6 --- /dev/null +++ b/tests/test-org-agenda-config-category.el @@ -0,0 +1,137 @@ +;;; test-org-agenda-config-category.el --- Tests for project-name category derivation -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for the agenda-display category helpers in org-agenda-config.el: +;; - cj/--org-todo-category-from-file (pure) +;; - cj/--org-set-todo-category (org-mode-hook side effect) +;; +;; Goal: when a buffer visits a project-local todo.org, its `org-category` +;; should be the parent directory name (the project slug) rather than the +;; default "todo" -- so the agenda's %c column shows "emacs.d:" instead of +;; "todo:" for every project's tasks. + +;;; Code: + +(require 'ert) +(require 'org) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'org-agenda-config) + +;;; ---------- cj/--org-todo-category-from-file (pure helper) ---------- + +;;; Normal Cases + +(ert-deftest test-org-agenda-config-category-normal-emacs-d-todo () + "Normal: todo.org under .emacs.d returns \"emacs.d\"." + (should (equal "emacs.d" + (cj/--org-todo-category-from-file + "/home/cjennings/.emacs.d/todo.org")))) + +(ert-deftest test-org-agenda-config-category-normal-project-todo () + "Normal: todo.org under a project dir returns the project basename." + (should (equal "dotemacs" + (cj/--org-todo-category-from-file + "/home/cjennings/code/dotemacs/todo.org")))) + +(ert-deftest test-org-agenda-config-category-normal-deep-project () + "Normal: deeply nested todo.org returns only the immediate parent." + (should (equal "frontend" + (cj/--org-todo-category-from-file + "/home/cjennings/projects/work/myapp/frontend/todo.org")))) + +;;; Boundary Cases + +(ert-deftest test-org-agenda-config-category-boundary-non-todo-file () + "Boundary: non-todo.org file returns nil so default category stays." + (should (null (cj/--org-todo-category-from-file + "/home/cjennings/sync/org/roam/inbox.org")))) + +(ert-deftest test-org-agenda-config-category-boundary-schedule-org () + "Boundary: schedule.org returns nil; not a project todo file." + (should (null (cj/--org-todo-category-from-file + "/home/cjennings/sync/org/schedule.org")))) + +(ert-deftest test-org-agenda-config-category-boundary-todo-at-fs-root () + "Boundary: /todo.org with no real parent directory returns nil." + (should (null (cj/--org-todo-category-from-file "/todo.org")))) + +(ert-deftest test-org-agenda-config-category-boundary-relative-path () + "Boundary: bare relative \"todo.org\" with no directory returns nil." + (should (null (cj/--org-todo-category-from-file "todo.org")))) + +(ert-deftest test-org-agenda-config-category-boundary-todo-with-trailing-dir () + "Boundary: tolerate a path that is already directory-form." + (should (equal "emacs.d" + (cj/--org-todo-category-from-file + "/home/cjennings/.emacs.d/todo.org")))) + +;;; Error Cases + +(ert-deftest test-org-agenda-config-category-error-nil-path () + "Error: nil PATH returns nil, no signal." + (should (null (cj/--org-todo-category-from-file nil)))) + +(ert-deftest test-org-agenda-config-category-error-empty-path () + "Error: empty-string PATH returns nil." + (should (null (cj/--org-todo-category-from-file "")))) + +;;; ---------- cj/--org-set-todo-category (hook function) ---------- + +(defmacro test-org-agenda-config-category--with-file (path body-form) + "Visit PATH in a temp buffer with org-mode active, evaluate BODY-FORM. +Sets `buffer-file-name' so the hook's lookup sees the desired path. +Suppresses other org-mode hooks to keep the test isolated." + (declare (indent 1)) + `(with-temp-buffer + (let ((org-mode-hook nil) + (text-mode-hook nil)) + (org-mode)) + (setq buffer-file-name ,path) + ;; mimic org's default category (filename-sans-extension) so the + ;; hook's "only override the default" guard is exercised. + (setq-local org-category + (and ,path + (file-name-sans-extension + (file-name-nondirectory ,path)))) + ,body-form)) + +;;; Normal Cases + +(ert-deftest test-org-agenda-config-category-hook-normal-overrides-todo () + "Normal: hook overrides default \"todo\" with the parent dir name." + (test-org-agenda-config-category--with-file "/home/cjennings/.emacs.d/todo.org" + (progn + (cj/--org-set-todo-category) + (should (equal "emacs.d" org-category))))) + +(ert-deftest test-org-agenda-config-category-hook-normal-leaves-inbox-alone () + "Normal: hook leaves inbox.org's category at its filename default." + (test-org-agenda-config-category--with-file "/home/cjennings/sync/org/roam/inbox.org" + (progn + (cj/--org-set-todo-category) + (should (equal "inbox" org-category))))) + +;;; Boundary Cases + +(ert-deftest test-org-agenda-config-category-hook-boundary-respects-explicit () + "Boundary: explicit category (not the filename default) is preserved." + (test-org-agenda-config-category--with-file "/home/cjennings/.emacs.d/todo.org" + (progn + (setq-local org-category "Personal") + (cj/--org-set-todo-category) + (should (equal "Personal" org-category))))) + +(ert-deftest test-org-agenda-config-category-hook-boundary-nil-buffer-file-name () + "Boundary: hook is safe in buffers with no `buffer-file-name'." + (with-temp-buffer + (let ((org-mode-hook nil) + (text-mode-hook nil)) + (org-mode)) + (setq buffer-file-name nil) + (cj/--org-set-todo-category) + ;; no error and no spurious mutation + (should t))) + +(provide 'test-org-agenda-config-category) +;;; test-org-agenda-config-category.el ends here |
