diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-05 04:34:03 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-05 04:34:03 -0500 |
| commit | 949a297da4ddd47840c4f0e427c17c753fd8219c (patch) | |
| tree | 56f0f3f868f96b5071391093e878499555e7072c | |
| parent | bc75218917e8e01bc67a2582d3fb2bac32bd28fe (diff) | |
| download | org-drill-949a297da4ddd47840c4f0e427c17c753fd8219c.tar.gz org-drill-949a297da4ddd47840c4f0e427c17c753fd8219c.zip | |
test: add navigation, key-binding, push-end, and leitner-rebox coverage
15 ERT tests covering:
- org-drill-goto-entry: marker → buffer + position
- org-drill-goto-drill-entry-heading: stays put on the drill heading,
walks up from a child sub-heading, errors outside any drill entry
- org-drill-command-keybinding-to-string: nil for unbound, string
for bound commands
- org-drill-push-end: appends to non-empty and empty lists
- org-drill-leitner-rebox (interactive — read-key-sequence mocked):
rating 0 resets to box 1, rating 1 decrements (with floor at 1),
rating 2 stays, ratings 3-5 promote, quit-key returns 'quit
| -rw-r--r-- | tests/test-org-drill-navigation-and-leitner-rebox.el | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/tests/test-org-drill-navigation-and-leitner-rebox.el b/tests/test-org-drill-navigation-and-leitner-rebox.el new file mode 100644 index 0000000..a0b17aa --- /dev/null +++ b/tests/test-org-drill-navigation-and-leitner-rebox.el @@ -0,0 +1,191 @@ +;;; test-org-drill-navigation-and-leitner-rebox.el --- Tests for navigation helpers and leitner-rebox -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for: +;; +;; - `org-drill-goto-entry': switches to a marker's buffer and position +;; - `org-drill-goto-drill-entry-heading': moves up the outline until +;; it finds the heading that owns the :drill: tag (handles being +;; called from a sub-heading) +;; - `org-drill-command-keybinding-to-string': human-readable key +;; description, used in messages like "Press C-c d to resume" +;; - `org-drill-push-end': in-place list-end push macro +;; - `org-drill-leitner-rebox': the rating loop for Leitner cards. +;; Tests drive ratings 0..5 by mocking `read-key-sequence' and +;; verify the DRILL_LEITNER_BOX property updates correctly. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'org) +(require 'org-drill) + +;;;; Helpers + +(defmacro with-fresh-drill-entry (&rest body) + (declare (indent 0)) + `(with-temp-buffer + (let ((org-startup-folded nil)) + (insert "* Question :drill:\nbody\n") + (org-mode) + (goto-char (point-min)) + ,@body))) + +(defmacro with-leitner-entry-in-box (box-num &rest body) + "Run BODY at point on a leitner-tagged entry currently in BOX-NUM." + (declare (indent 1)) + `(with-temp-buffer + (let ((org-startup-folded nil)) + (insert (format "* Question :leitner:\n:PROPERTIES:\n:DRILL_LEITNER_BOX: %d\n:END:\nbody\n" ,box-num)) + (org-mode) + (goto-char (point-min)) + ,@body))) + +(defun stub-read-key-sequence-with-string (return-string) + "Make `read-key-sequence' return the given string." + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) return-string))))) + +;;;; org-drill-goto-entry + +(ert-deftest test-org-drill-goto-entry-jumps-to-marker-position () + "After `goto-entry', point matches the marker's position." + (with-temp-buffer + (insert "abcdefghij\n") + (let ((m (make-marker))) + (set-marker m 5) + (org-drill-goto-entry m) + (should (= 5 (point)))))) + +;;;; org-drill-goto-drill-entry-heading + +(ert-deftest test-org-drill-goto-drill-entry-heading-on-drill-stays-put () + "Called on the drill heading itself, point doesn't move." + (with-fresh-drill-entry + (let ((before (point))) + (org-drill-goto-drill-entry-heading) + (should (= before (point)))))) + +(ert-deftest test-org-drill-goto-drill-entry-heading-from-child-walks-up () + "Called inside a sub-heading of a drill entry, walks up to the parent." + (with-temp-buffer + (let ((org-startup-folded nil)) + (insert "* Parent :drill:\n** Child\nchild body\n") + (org-mode) + (re-search-backward "^\\*\\* Child") + (org-drill-goto-drill-entry-heading) + (should (looking-at "^\\* Parent"))))) + +(ert-deftest test-org-drill-goto-drill-entry-heading-non-drill-errors () + "Called outside a drill entry → user-visible error." + (with-temp-buffer + (let ((org-startup-folded nil)) + (insert "* Plain heading\nbody\n") + (org-mode) + (goto-char (point-min)) + (should-error (org-drill-goto-drill-entry-heading))))) + +;;;; org-drill-command-keybinding-to-string + +(ert-deftest test-org-drill-command-keybinding-to-string-unbound-returns-nil () + "When CMD has no binding, returns nil." + (let ((cmd (make-symbol "fictional-org-drill-command-no-binding"))) + (should (null (org-drill-command-keybinding-to-string cmd))))) + +(ert-deftest test-org-drill-command-keybinding-to-string-bound-returns-string () + (let ((cmd (make-symbol "fictional-test-cmd"))) + (defalias cmd #'ignore) + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c x") cmd) + (let ((overriding-local-map map)) + (let ((result (org-drill-command-keybinding-to-string cmd))) + (should (stringp result)) + (should (string-match-p "C-c x" result))))))) + +;;;; org-drill-push-end + +(ert-deftest test-org-drill-push-end-appends-to-list-place () + (let ((lst (list 1 2 3))) + (org-drill-push-end 4 lst) + (should (equal '(1 2 3 4) lst)))) + +(ert-deftest test-org-drill-push-end-on-empty-list () + (let ((lst nil)) + (org-drill-push-end 'a lst) + (should (equal '(a) lst)))) + +;;;; org-drill-leitner-rebox + +(ert-deftest test-org-drill-leitner-rebox-rating-0-resets-to-box-1 () + "Quality 0 demotes the card all the way down to box 1." + (with-leitner-entry-in-box 4 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) "0")) + ((symbol-function 'sit-for) #'ignore)) + (let ((result (org-drill-leitner-rebox session))) + (should (eq t result)) + (should (equal "1" (org-entry-get (point) "DRILL_LEITNER_BOX")))))))) + +(ert-deftest test-org-drill-leitner-rebox-rating-1-decrements-by-one () + "Quality 1 demotes by one box." + (with-leitner-entry-in-box 3 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) "1")) + ((symbol-function 'sit-for) #'ignore)) + (org-drill-leitner-rebox session) + (should (equal "2" (org-entry-get (point) "DRILL_LEITNER_BOX"))))))) + +(ert-deftest test-org-drill-leitner-rebox-rating-1-from-box-1-stays-at-box-1 () + "Quality 1 from box 1 stays at box 1 — can't go lower." + (with-leitner-entry-in-box 1 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) "1")) + ((symbol-function 'sit-for) #'ignore)) + (org-drill-leitner-rebox session) + (should (equal "1" (org-entry-get (point) "DRILL_LEITNER_BOX"))))))) + +(ert-deftest test-org-drill-leitner-rebox-rating-2-stays-in-current-box () + "Quality 2 leaves the box unchanged." + (with-leitner-entry-in-box 3 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) "2")) + ((symbol-function 'sit-for) #'ignore)) + (org-drill-leitner-rebox session) + (should (equal "3" (org-entry-get (point) "DRILL_LEITNER_BOX"))))))) + +(ert-deftest test-org-drill-leitner-rebox-rating-3-promotes-by-one () + (with-leitner-entry-in-box 2 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) "3")) + ((symbol-function 'sit-for) #'ignore)) + (org-drill-leitner-rebox session) + (should (equal "3" (org-entry-get (point) "DRILL_LEITNER_BOX"))))))) + +(ert-deftest test-org-drill-leitner-rebox-rating-5-promotes-by-one () + (with-leitner-entry-in-box 3 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) "5")) + ((symbol-function 'sit-for) #'ignore)) + (org-drill-leitner-rebox session) + (should (equal "4" (org-entry-get (point) "DRILL_LEITNER_BOX"))))))) + +(ert-deftest test-org-drill-leitner-rebox-quit-key-returns-quit () + "Pressing the configured quit key returns the symbol `quit'." + (with-leitner-entry-in-box 2 + (let ((session (org-drill-session))) + (cl-letf (((symbol-function 'read-key-sequence) + (lambda (_prompt) (string org-drill--quit-key))) + ((symbol-function 'sit-for) #'ignore)) + (let ((result (org-drill-leitner-rebox session))) + (should (eq 'quit result))))))) + +(provide 'test-org-drill-navigation-and-leitner-rebox) + +;;; test-org-drill-navigation-and-leitner-rebox.el ends here |
