diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-05 14:15:45 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-05 14:15:45 -0500 |
| commit | 657f494c2ae157fe11bcab1fab0d787dc1fa9752 (patch) | |
| tree | a9af6851214fea24acb609ade4d78acc65d731c5 | |
| parent | b395eaaa0d75bb66497006eb0607aac183d0c40e (diff) | |
| download | org-drill-657f494c2ae157fe11bcab1fab0d787dc1fa9752.tar.gz org-drill-657f494c2ae157fe11bcab1fab0d787dc1fa9752.zip | |
test: cover leitner-start-box and --read-rating-key input shapes
I added tests for `org-drill-leitner-start-box' (move N entries from
unboxed into box 1, respect the count arg, zero is a noop) and for
`org-drill--read-rating-key' (string input, arrow vector, wheel-event
vector, help key showing help block, tags key triggering set-tags,
typed-answer rendering in the prompt).
Coverage moved from 85.7% to 87.0%.
| -rw-r--r-- | tests/test-org-drill-leitner-start-box.el | 79 | ||||
| -rw-r--r-- | tests/test-org-drill-read-rating-key.el | 119 |
2 files changed, 198 insertions, 0 deletions
diff --git a/tests/test-org-drill-leitner-start-box.el b/tests/test-org-drill-leitner-start-box.el new file mode 100644 index 0000000..a221e7d --- /dev/null +++ b/tests/test-org-drill-leitner-start-box.el @@ -0,0 +1,79 @@ +;;; test-org-drill-leitner-start-box.el --- Tests for leitner-start-box -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `org-drill-leitner-start-box', which moves N entries from the +;; unboxed queue into box 1 by setting their DRILL_LEITNER_BOX property. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'org) +(require 'org-drill) + +(defmacro with-leitner-unboxed-tempfile (content &rest body) + "Run BODY in a tempfile-backed org buffer with CONTENT. +Initializes leitner queues empty, mocks `sit-for' and `message' to ignore." + (declare (indent 1)) + `(let ((tmpfile (make-temp-file "org-drill-start-box-" nil ".org")) + (org-drill-leitner-boxed-entries nil) + (org-drill-leitner-unboxed-entries nil)) + (unwind-protect + (with-current-buffer (find-file-noselect tmpfile) + (let ((org-startup-folded nil)) + (insert ,content) + (org-mode) + (goto-char (point-min)) + (cl-letf (((symbol-function 'sit-for) #'ignore) + ((symbol-function 'message) #'ignore)) + ,@body))) + (when (file-exists-p tmpfile) (delete-file tmpfile))))) + +(ert-deftest test-leitner-start-box-sets-box-property-on-each-entry () + "Each unboxed entry processed gets DRILL_LEITNER_BOX = \"1\"." + (with-leitner-unboxed-tempfile + "* A :leitner:\nbody\n* B :leitner:\nbody\n" + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (let ((org-drill-question-tag org-drill-leitner-tag)) + (org-drill-all-leitner-capture 'file)) + (should (= 2 (length org-drill-leitner-unboxed-entries))) + (org-drill-leitner-start-box 2) + (let ((boxed-count 0)) + (org-map-entries + (lambda () + (when (equal "1" (org-entry-get (point) "DRILL_LEITNER_BOX")) + (cl-incf boxed-count)))) + (should (= 2 boxed-count)))))) + +(ert-deftest test-leitner-start-box-respects-number-arg () + "Asking for fewer entries than available only boxes that many." + (with-leitner-unboxed-tempfile + "* A :leitner:\nbody\n* B :leitner:\nbody\n* C :leitner:\nbody\n" + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (let ((org-drill-question-tag org-drill-leitner-tag)) + (org-drill-all-leitner-capture 'file)) + (org-drill-leitner-start-box 1) + (let ((boxed-count 0)) + (org-map-entries + (lambda () + (when (equal "1" (org-entry-get (point) "DRILL_LEITNER_BOX")) + (cl-incf boxed-count)))) + (should (= 1 boxed-count)))))) + +(ert-deftest test-leitner-start-box-zero-is-noop () + "Asking for zero entries doesn't touch any." + (with-leitner-unboxed-tempfile + "* A :leitner:\nbody\n" + (cl-letf (((symbol-function 'org-drill-progress-message) #'ignore)) + (let ((org-drill-question-tag org-drill-leitner-tag)) + (org-drill-all-leitner-capture 'file)) + (org-drill-leitner-start-box 0) + (let ((boxed-count 0)) + (org-map-entries + (lambda () + (when (equal "1" (org-entry-get (point) "DRILL_LEITNER_BOX")) + (cl-incf boxed-count)))) + (should (= 0 boxed-count)))))) + +(provide 'test-org-drill-leitner-start-box) +;;; test-org-drill-leitner-start-box.el ends here diff --git a/tests/test-org-drill-read-rating-key.el b/tests/test-org-drill-read-rating-key.el new file mode 100644 index 0000000..7f05755 --- /dev/null +++ b/tests/test-org-drill-read-rating-key.el @@ -0,0 +1,119 @@ +;;; test-org-drill-read-rating-key.el --- Tests for --read-rating-key -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `org-drill--read-rating-key', the post-presentation key loop +;; shared by `org-drill-reschedule' and `org-drill-leitner-rebox'. +;; +;; The loop reads keys via `org-drill--read-key-sequence' until it gets a +;; 0-5 char, edit, quit, or C-g. Three input shapes are recognized: +;; +;; - String (a typed character) +;; - Vector starting with a symbol (arrow / page keys) +;; - Vector starting with an event list (mouse wheel) + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'org) +(require 'org-drill) + +(defmacro with-keys-and-buffer (keys &rest body) + "Run BODY with `org-drill--read-key-sequence' returning successive KEYS. +KEYS is a list — each call returns the next element." + (declare (indent 1)) + `(let ((__remaining__ ,keys)) + (with-temp-buffer + (insert "* Drill :drill:\nsome body line\nanother line\n") + (goto-char (point-min)) + (cl-letf (((symbol-function 'org-drill--read-key-sequence) + (lambda (&rest _) + (or (pop __remaining__) + (error "Test ran out of mock keys")))) + ((symbol-function 'org-set-tags-command) #'ignore)) + ,@body)))) + +(ert-deftest test-read-rating-key-direct-numeric-returns-char () + "A string input \"3\" makes the loop return the ?3 character." + (with-keys-and-buffer '("3") + (should (eql ?3 (org-drill--read-rating-key nil "help"))))) + +(ert-deftest test-read-rating-key-quit-key-returns-quit () + "Quit key terminates the loop and returns the quit char." + (with-keys-and-buffer (list (string org-drill--quit-key)) + (should (eql org-drill--quit-key + (org-drill--read-rating-key nil "help"))))) + +(ert-deftest test-read-rating-key-edit-key-returns-edit () + "Edit key terminates the loop and returns the edit char." + (with-keys-and-buffer (list (string org-drill--edit-key)) + (should (eql org-drill--edit-key + (org-drill--read-rating-key nil "help"))))) + +(ert-deftest test-read-rating-key-arrow-key-then-numeric-returns-numeric () + "An arrow-key vector is processed (no terminal effect) and the next +numeric input ends the loop." + (with-keys-and-buffer (list (vector 'down) "5") + (should (eql ?5 (org-drill--read-rating-key nil "help"))))) + +(ert-deftest test-read-rating-key-wheel-event-then-numeric () + "A wheel-event vector is dispatched without terminating; loop ends on +the next numeric character." + (let ((scroll-called nil)) + (cl-letf (((symbol-function 'mwheel-scroll) + (lambda (&rest _) (setq scroll-called t)))) + (with-keys-and-buffer (list (vector '(wheel-up nil)) "0") + (should (eql ?0 (org-drill--read-rating-key nil "help"))))))) + +(ert-deftest test-read-rating-key-help-key-shows-help-then-numeric () + "Pressing the help key on the first iteration causes the next prompt to +include the rating-help-block, then numeric ends the loop." + (let ((seen-prompts nil)) + (cl-letf (((symbol-function 'org-drill--read-key-sequence) + (let ((counter 0) + (keys (list (string org-drill--help-key) "4"))) + (lambda (prompt) + (push prompt seen-prompts) + (cl-incf counter) + (pop keys)))) + ((symbol-function 'org-set-tags-command) #'ignore)) + (with-temp-buffer + (insert "* Drill :drill:\nbody\n") + (goto-char (point-min)) + (should (eql ?4 (org-drill--read-rating-key nil "RATING-HELP"))) + ;; Second prompt (after help key) carries the help block. + (should (cl-some (lambda (p) (string-match-p "RATING-HELP" p)) + seen-prompts)))))) + +(ert-deftest test-read-rating-key-tags-key-invokes-tags-command () + "If the tags key is used to terminate the loop, org-set-tags-command runs." + (let ((tags-called nil)) + (cl-letf (((symbol-function 'org-drill--read-key-sequence) + (let ((keys (list (string org-drill--tags-key)))) + (lambda (&rest _) (pop keys)))) + ((symbol-function 'org-set-tags-command) + (lambda (&rest _) (setq tags-called t)))) + ;; tags-key is not in the loop's terminal-set, so the loop would spin — + ;; but `--read-rating-key' terminates only on quit/edit/C-g/0-5, so + ;; tags-key alone won't end the loop. We feed quit-key as a follow-up. + (cl-letf (((symbol-function 'org-drill--read-key-sequence) + (let ((keys (list (string org-drill--tags-key) + (string org-drill--quit-key)))) + (lambda (&rest _) (pop keys))))) + (with-temp-buffer + (insert "* Drill :drill:\nbody\n") + (org-drill--read-rating-key nil "help") + (should tags-called)))))) + +(ert-deftest test-read-rating-key-typed-answer-shown-in-prompt () + "A non-nil typed-answer arg appears in the prompt as 'Your answer: ...'." + (let ((seen-prompt nil)) + (cl-letf (((symbol-function 'org-drill--read-key-sequence) + (lambda (prompt) (setq seen-prompt prompt) "0")) + ((symbol-function 'org-set-tags-command) #'ignore)) + (with-temp-buffer + (org-drill--read-rating-key "my-typed-answer" "help")) + (should (string-match-p "Your answer: my-typed-answer" seen-prompt))))) + +(provide 'test-org-drill-read-rating-key) +;;; test-org-drill-read-rating-key.el ends here |
