aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-05 14:10:30 -0500
committerCraig Jennings <c@cjennings.net>2026-05-05 14:10:30 -0500
commit9206de07d7bb1e549aacada300f637aee1b620e9 (patch)
tree540be33fc8d4e155bdc21ac8ca23d2eb8372b6e0 /tests
parent0d32f8f6df9406c12306d97592446408ba7984e3 (diff)
downloadorg-drill-9206de07d7bb1e549aacada300f637aee1b620e9.tar.gz
org-drill-9206de07d7bb1e549aacada300f637aee1b620e9.zip
test: cover --setup-display, --restore-display, --migrate-from-source, scope=directory
I added unit tests for the display-state helpers (capture text scale, variable-pitch, modeline; restore them on session exit), the directory branch of `org-drill-current-scope', and `--migrate-from-source''s three-branch cond (matching ID, no ID, ignore-new-items). Coverage moved from 81.8% to 82.4%.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-org-drill-display-state.el115
-rw-r--r--tests/test-org-drill-migrate-from-source.el99
2 files changed, 214 insertions, 0 deletions
diff --git a/tests/test-org-drill-display-state.el b/tests/test-org-drill-display-state.el
new file mode 100644
index 0000000..baad0a3
--- /dev/null
+++ b/tests/test-org-drill-display-state.el
@@ -0,0 +1,115 @@
+;;; test-org-drill-display-state.el --- Tests for display-state save/restore -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for `org-drill--setup-display' and `org-drill--restore-display',
+;; which save the user's text scale, variable-pitch mode, and modeline at
+;; session start and put them back at session end. Also covers the
+;; `directory' branch of `org-drill-current-scope'.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'org)
+(require 'org-drill)
+
+;;;; --save-display-state / --restore-display
+
+(ert-deftest test-save-display-state-records-current-buffer ()
+ "After save, `org-drill--saved-display-buffer' holds the buffer."
+ (with-temp-buffer
+ (let ((org-drill-text-size-during-session nil)
+ (org-drill-use-variable-pitch nil)
+ (org-drill-hide-modeline-during-session nil)
+ (org-drill--saved-display-buffer nil))
+ (org-drill--setup-display)
+ (should (eq (current-buffer) org-drill--saved-display-buffer)))))
+
+(ert-deftest test-save-display-state-skips-when-flags-nil ()
+ "With every flag nil, save records buffer but doesn't capture face/mode state."
+ (with-temp-buffer
+ (let ((org-drill-text-size-during-session nil)
+ (org-drill-use-variable-pitch nil)
+ (org-drill-hide-modeline-during-session nil)
+ (org-drill--saved-display-buffer nil)
+ (org-drill--saved-text-scale 'sentinel)
+ (org-drill--saved-variable-pitch-mode 'unbound)
+ (org-drill--saved-modeline-format 'sentinel))
+ (org-drill--setup-display)
+ ;; Saved-text-scale is left untouched because the flag was nil.
+ (should (eq 'sentinel org-drill--saved-text-scale))
+ (should (eq 'unbound org-drill--saved-variable-pitch-mode))
+ (should (eq 'sentinel org-drill--saved-modeline-format)))))
+
+(ert-deftest test-save-display-state-captures-modeline-when-hide-flag-set ()
+ "With `org-drill-hide-modeline-during-session' t, the modeline is saved and cleared."
+ (with-temp-buffer
+ (let ((org-drill-text-size-during-session nil)
+ (org-drill-use-variable-pitch nil)
+ (org-drill-hide-modeline-during-session t)
+ (org-drill--saved-display-buffer nil)
+ (org-drill--saved-modeline-format nil))
+ (setq-local mode-line-format "marker-mode-line")
+ (org-drill--setup-display)
+ (should (equal "marker-mode-line" org-drill--saved-modeline-format))
+ (should (null mode-line-format)))))
+
+(ert-deftest test-restore-display-puts-modeline-back ()
+ "Restore sets mode-line-format on the saved-display-buffer back to its prior value."
+ (with-temp-buffer
+ (let ((org-drill-text-size-during-session nil)
+ (org-drill-use-variable-pitch nil)
+ (org-drill-hide-modeline-during-session t)
+ (org-drill--saved-display-buffer (current-buffer))
+ (org-drill--saved-text-scale nil)
+ (org-drill--saved-variable-pitch-mode 'unbound)
+ (org-drill--saved-modeline-format "saved-modeline"))
+ (setq-local mode-line-format nil)
+ (org-drill--restore-display)
+ (should (equal "saved-modeline" mode-line-format))
+ (should (null org-drill--saved-modeline-format))
+ (should (null org-drill--saved-display-buffer)))))
+
+(ert-deftest test-restore-display-handles-killed-buffer-target ()
+ "If the saved-display-buffer was killed, restore must not crash."
+ (let ((tmp (generate-new-buffer " *drill-display-tmp*")))
+ (let ((org-drill-text-size-during-session nil)
+ (org-drill-use-variable-pitch nil)
+ (org-drill-hide-modeline-during-session t)
+ (org-drill--saved-display-buffer tmp)
+ (org-drill--saved-text-scale nil)
+ (org-drill--saved-variable-pitch-mode 'unbound)
+ (org-drill--saved-modeline-format "saved-modeline"))
+ (kill-buffer tmp)
+ (org-drill--restore-display)
+ (should (null org-drill--saved-display-buffer)))))
+
+;;;; org-drill-current-scope (directory branch)
+
+(ert-deftest test-org-drill-current-scope-directory-returns-org-files-list ()
+ "The `directory' scope expands to a list of .org files in the buffer's directory."
+ (let* ((tmpdir (make-temp-file "org-drill-scope-" t))
+ (a (expand-file-name "a.org" tmpdir))
+ (b (expand-file-name "b.org" tmpdir))
+ (skip (expand-file-name ".hidden.org" tmpdir))
+ (other (expand-file-name "c.txt" tmpdir)))
+ (unwind-protect
+ (progn
+ (write-region "" nil a)
+ (write-region "" nil b)
+ (write-region "" nil skip)
+ (write-region "" nil other)
+ (with-current-buffer (find-file-noselect a)
+ (let ((files (org-drill-current-scope 'directory)))
+ (should (member a files))
+ (should (member b files))
+ (should-not (member skip files))
+ (should-not (member other files)))))
+ (when (file-exists-p a) (delete-file a))
+ (when (file-exists-p b) (delete-file b))
+ (when (file-exists-p skip) (delete-file skip))
+ (when (file-exists-p other) (delete-file other))
+ (delete-directory tmpdir))))
+
+(provide 'test-org-drill-display-state)
+;;; test-org-drill-display-state.el ends here
diff --git a/tests/test-org-drill-migrate-from-source.el b/tests/test-org-drill-migrate-from-source.el
new file mode 100644
index 0000000..7b3d4ab
--- /dev/null
+++ b/tests/test-org-drill-migrate-from-source.el
@@ -0,0 +1,99 @@
+;;; test-org-drill-migrate-from-source.el --- Tests for --migrate-from-source -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for `org-drill--migrate-from-source', which walks SRC and copies
+;; scheduling data into matching DEST entries (matched by ID). The cond
+;; has three branches:
+;;
+;; - SRC entry has no ID, or isn't a drill entry → skip
+;; - SRC entry's ID matches a DEST ID → copy scheduling, drop from table
+;; - SRC entry has an ID with no DEST match → either copy as new item, or
+;; skip when ignore-new-items-p is t
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'org)
+(require 'org-drill)
+
+(defmacro with-two-org-tempfiles (src-content dest-content &rest body)
+ "Run BODY with SRC-BUF and DEST-BUF bound to org-mode buffers.
+SRC-CONTENT is loaded into SRC-BUF, DEST-CONTENT into DEST-BUF."
+ (declare (indent 2))
+ `(let ((src-file (make-temp-file "org-drill-mig-src-" nil ".org"))
+ (dest-file (make-temp-file "org-drill-mig-dst-" nil ".org"))
+ src-buf dest-buf)
+ (unwind-protect
+ (progn
+ (setq src-buf (find-file-noselect src-file))
+ (setq dest-buf (find-file-noselect dest-file))
+ (with-current-buffer src-buf
+ (let ((org-startup-folded nil))
+ (insert ,src-content)
+ (org-mode)))
+ (with-current-buffer dest-buf
+ (let ((org-startup-folded nil))
+ (insert ,dest-content)
+ (org-mode)))
+ ,@body)
+ (when (file-exists-p src-file) (delete-file src-file))
+ (when (file-exists-p dest-file) (delete-file dest-file)))))
+
+(ert-deftest test-migrate-matching-id-copies-scheduling ()
+ "When SRC has an ID matching DEST, scheduling lands on DEST."
+ (with-two-org-tempfiles
+ "* Card :drill:\n:PROPERTIES:\n:ID: shared\n:DRILL_LAST_INTERVAL: 12.0\n:DRILL_TOTAL_REPEATS: 4\n:DRILL_REPEATS_SINCE_FAIL: 3\n:DRILL_FAILURE_COUNT: 1\n:DRILL_AVERAGE_QUALITY: 3.5\n:DRILL_EASE: 2.5\n:END:\n"
+ "* Card :drill:\n:PROPERTIES:\n:ID: shared\n:END:\n"
+ (clrhash org-drill-dest-id-table)
+ (org-drill--build-dest-id-table dest-buf)
+ (should (gethash "shared" org-drill-dest-id-table))
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore))
+ (org-drill--migrate-from-source src-buf dest-buf nil))
+ ;; ID was consumed off the table.
+ (should-not (gethash "shared" org-drill-dest-id-table))
+ ;; DEST got the scheduling data.
+ (with-current-buffer dest-buf
+ (goto-char (point-min))
+ (should (equal "12.0" (org-entry-get (point) "DRILL_LAST_INTERVAL")))
+ (should (equal "4" (org-entry-get (point) "DRILL_TOTAL_REPEATS"))))))
+
+(ert-deftest test-migrate-no-id-on-src-is-skipped ()
+ "SRC entries without an ID don't touch DEST and don't drain the table."
+ (with-two-org-tempfiles
+ "* Card :drill:\n:PROPERTIES:\n:DRILL_LAST_INTERVAL: 5.0\n:END:\n"
+ "* Card :drill:\n:PROPERTIES:\n:ID: untouched\n:END:\n"
+ (clrhash org-drill-dest-id-table)
+ (org-drill--build-dest-id-table dest-buf)
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore))
+ (org-drill--migrate-from-source src-buf dest-buf nil))
+ (should (gethash "untouched" org-drill-dest-id-table))))
+
+(ert-deftest test-migrate-non-drill-entry-skipped ()
+ "Non-drill entries in SRC are skipped even when they have an ID."
+ (with-two-org-tempfiles
+ "* Note (no drill tag)\n:PROPERTIES:\n:ID: shared\n:END:\n"
+ "* Card :drill:\n:PROPERTIES:\n:ID: shared\n:END:\n"
+ (clrhash org-drill-dest-id-table)
+ (org-drill--build-dest-id-table dest-buf)
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore))
+ (org-drill--migrate-from-source src-buf dest-buf nil))
+ ;; Non-drill SRC didn't match, so the ID stays in the table.
+ (should (gethash "shared" org-drill-dest-id-table))))
+
+(ert-deftest test-migrate-ignore-new-items-skips-unmatched-src ()
+ "When ignore-new-items-p is t, unmatched SRC entries don't get copied."
+ (with-two-org-tempfiles
+ "* New card :drill:\n:PROPERTIES:\n:ID: src-only\n:END:\n"
+ "* Existing :drill:\n:PROPERTIES:\n:ID: dest-only\n:END:\n"
+ (clrhash org-drill-dest-id-table)
+ (org-drill--build-dest-id-table dest-buf)
+ (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)
+ ((symbol-function 'org-drill-copy-entry-to-other-buffer)
+ (lambda (&rest _) (error "should not be called"))))
+ (org-drill--migrate-from-source src-buf dest-buf t))
+ ;; dest-only is still in the table because nothing migrated to consume it.
+ (should (gethash "dest-only" org-drill-dest-id-table))))
+
+(provide 'test-org-drill-migrate-from-source)
+;;; test-org-drill-migrate-from-source.el ends here