aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-statistics-source-buffer.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-org-drill-statistics-source-buffer.el')
-rw-r--r--tests/test-org-drill-statistics-source-buffer.el174
1 files changed, 174 insertions, 0 deletions
diff --git a/tests/test-org-drill-statistics-source-buffer.el b/tests/test-org-drill-statistics-source-buffer.el
new file mode 100644
index 0000000..5732b63
--- /dev/null
+++ b/tests/test-org-drill-statistics-source-buffer.el
@@ -0,0 +1,174 @@
+;;; test-org-drill-statistics-source-buffer.el --- Dashboard source-buffer tests -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; ERT tests for the statistics dashboard's source-buffer plumbing and
+;; the org-drill-card link type. The dashboard must scan the deck the
+;; command was invoked from, not its own buffer, and its card links must
+;; be followable.
+
+;;; Code:
+
+(require 'ert)
+(require 'org-drill)
+(require 'org)
+
+(defmacro org-drill-statistics-source-test--with-deck (var &rest body)
+ "Run BODY with VAR bound to a live org deck buffer holding two drill cards."
+ (declare (indent 1))
+ `(let ((,var (generate-new-buffer "*source-deck*")))
+ (unwind-protect
+ (with-current-buffer ,var
+ (org-mode)
+ (insert "* Card one :drill:\nBody one.\n"
+ "* Card two :drill:\nBody two.\n")
+ (goto-char (point-min))
+ ,@body)
+ (when (buffer-live-p ,var) (kill-buffer ,var)))))
+
+;;; Normal cases
+
+(ert-deftest test-org-drill-statistics-render-counts-source-deck-cards ()
+ "Rendering into the dashboard counts the cards of the source deck.
+With the default file scope, the card scans must run in the source
+buffer, not the dashboard buffer being rendered into."
+ (org-drill-statistics-source-test--with-deck deck
+ (let ((dash (generate-new-buffer "*dash-test*"))
+ (org-drill-scope 'file)
+ (org-drill-session-log nil))
+ (unwind-protect
+ (progn
+ (with-current-buffer dash (org-mode))
+ (org-drill-statistics--render dash 'file "last 90d" nil deck)
+ (with-current-buffer dash
+ (goto-char (point-min))
+ ;; Overview table data row: | total | new | mature | lapsed |
+ (should (search-forward "| 2 | " nil t))))
+ (kill-buffer dash)))))
+
+(ert-deftest test-org-drill-statistics-refresh-uses-stored-source ()
+ "Refresh from inside the dashboard re-scans the stored source deck."
+ (org-drill-statistics-source-test--with-deck deck
+ (let ((dash (generate-new-buffer "*dash-test*"))
+ (org-drill-scope 'file)
+ (org-drill-session-log nil))
+ (unwind-protect
+ (progn
+ (with-current-buffer dash (org-mode))
+ (org-drill-statistics--render dash 'file "last 90d" nil deck)
+ (with-current-buffer dash
+ (org-drill-statistics-refresh)
+ (goto-char (point-min))
+ (should (search-forward "| 2 | " nil t))))
+ (kill-buffer dash)))))
+
+(ert-deftest test-org-drill-statistics-card-link-type-is-registered ()
+ "The org-drill-card link type has a follow handler registered."
+ (should (functionp (org-link-get-parameter "org-drill-card" :follow))))
+
+(ert-deftest test-org-drill-statistics-card-link-encodes-file ()
+ "Card links carry the file identity after the position."
+ (let ((link (org-drill-statistics--card-link "Heading" 42 "/tmp/deck.org")))
+ (should (string-prefix-p "[[org-drill-card:42@/tmp/deck.org][" link))))
+
+(ert-deftest test-org-drill-statistics-follow-jumps-to-file-position ()
+ "Following a card link visits the file and moves point to the position."
+ (let* ((file (make-temp-file "org-drill-follow-test" nil ".org"
+ "* Card one :drill:\nBody.\n"))
+ (buf nil))
+ (unwind-protect
+ (progn
+ (org-drill-statistics--follow-card-link (format "1@%s" file))
+ (setq buf (current-buffer))
+ (should (equal (buffer-file-name) file))
+ (should (= (point) 1)))
+ (when (and buf (buffer-live-p buf)) (kill-buffer buf))
+ (delete-file file))))
+
+;;; Boundary cases
+
+(ert-deftest test-org-drill-statistics-render-empty-deck-counts-zero ()
+ "An empty source deck renders a zero-card overview, not an error."
+ (let ((deck (generate-new-buffer "*empty-deck*"))
+ (dash (generate-new-buffer "*dash-test*"))
+ (org-drill-scope 'file)
+ (org-drill-session-log nil))
+ (unwind-protect
+ (progn
+ (with-current-buffer deck (org-mode))
+ (with-current-buffer dash (org-mode))
+ (org-drill-statistics--render dash 'file "last 90d" nil deck)
+ (with-current-buffer dash
+ (goto-char (point-min))
+ (should (search-forward "| 0 | " nil t))))
+ (kill-buffer deck)
+ (kill-buffer dash))))
+
+(ert-deftest test-org-drill-statistics-card-link-empty-file-omits-identity ()
+ "A card link built with no file still carries the position."
+ (let ((link (org-drill-statistics--card-link "Heading" 7 nil)))
+ (should (string-prefix-p "[[org-drill-card:7@][" link))))
+
+(ert-deftest test-org-drill-statistics-export-cards-from-source-deck ()
+ "CSV export scans the stored source deck, not the dashboard buffer."
+ (org-drill-statistics-source-test--with-deck deck
+ (let ((dash (generate-new-buffer "*dash-test*"))
+ (dir (make-temp-file "org-drill-export-test" t))
+ (org-drill-scope 'file)
+ (org-drill-session-log nil))
+ (unwind-protect
+ (progn
+ (with-current-buffer dash (org-mode))
+ (org-drill-statistics--render dash 'file "last 90d" nil deck)
+ (with-current-buffer dash
+ (org-drill-statistics-export-csv dir))
+ (with-temp-buffer
+ (insert-file-contents (expand-file-name "cards.csv" dir))
+ ;; Header plus one row per deck card.
+ (should (= 3 (count-lines (point-min) (point-max))))))
+ (kill-buffer dash)
+ (delete-directory dir t)))))
+
+(ert-deftest test-org-drill-statistics-follow-clamps-position-floor ()
+ "A zero or garbage position clamps to buffer start instead of erroring."
+ (let* ((file (make-temp-file "org-drill-follow-clamp" nil ".org"
+ "* Card :drill:\n"))
+ (buf nil))
+ (unwind-protect
+ (progn
+ (org-drill-statistics--follow-card-link (format "0@%s" file))
+ (setq buf (current-buffer))
+ (should (= (point) 1)))
+ (when (and buf (buffer-live-p buf)) (kill-buffer buf))
+ (delete-file file))))
+
+;;; Error cases
+
+(ert-deftest test-org-drill-statistics-refresh-dead-source-signals-user-error ()
+ "Refresh after the source deck is killed signals a clear user-error."
+ (let ((dash (generate-new-buffer "*dash-test*"))
+ (deck (generate-new-buffer "*doomed-deck*"))
+ (org-drill-scope 'file)
+ (org-drill-session-log nil))
+ (unwind-protect
+ (progn
+ (with-current-buffer deck
+ (org-mode)
+ (insert "* Card :drill:\n"))
+ (with-current-buffer dash (org-mode))
+ (org-drill-statistics--render dash 'file "last 90d" nil deck)
+ (kill-buffer deck)
+ (with-current-buffer dash
+ (should-error (org-drill-statistics-refresh)
+ :type 'user-error)))
+ (when (buffer-live-p deck) (kill-buffer deck))
+ (kill-buffer dash))))
+
+(ert-deftest test-org-drill-statistics-follow-dead-source-signals-user-error ()
+ "Following a bufferless link with no live source signals a user-error."
+ (with-temp-buffer
+ ;; No dashboard source var set in this buffer; empty file identity.
+ (should-error (org-drill-statistics--follow-card-link "5@")
+ :type 'user-error)))
+
+(provide 'test-org-drill-statistics-source-buffer)
+;;; test-org-drill-statistics-source-buffer.el ends here