aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-statistics-distribution.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-31 08:35:16 -0500
committerCraig Jennings <c@cjennings.net>2026-05-31 08:35:16 -0500
commit26cc4472dea261a1ad13fbee8fb6a91b019f77bb (patch)
treea7063337b05c3ea278a5b910d0f1420de033dfe8 /tests/test-org-drill-statistics-distribution.el
parent532ce532465834ce06238648ba1490c48bed29ca (diff)
downloadorg-drill-26cc4472dea261a1ad13fbee8fb6a91b019f77bb.tar.gz
org-drill-26cc4472dea261a1ad13fbee8fb6a91b019f77bb.zip
feat: add the org-drill statistics dashboard renderer
Step 1 shipped the session-log data layer. This is the renderer on top of it. org-drill-statistics opens a read-only dashboard with five sections: an overview (card counts plus a last-session recap), trends (reviews-per-day and pass-rate-per-day quadrant-block sparklines over the trend window, plus a 12-week table), a quality histogram, a needs-attention view (leech candidates, long-overdue, and forgotten-new cards), and a 7-day forecast counted from SCHEDULED dates. A buffer-wide filter (scope, range, algorithm) sits in the header and cycles with s/r/a. The other keys are q to bury, g to refresh, e for the CSV-export hook that lands next, and RET to follow the card link at point. The aggregation math lives in pure helpers (day-bucketing, sparkline scaling, weekly aggregates, the histogram, the attention selectors, forecast bucketing). The render helpers are thin string formatters over them, so the logic is unit-tested independently of the UI. New defcustoms tune the views: org-drill-statistics-trend-days, -forecast-days, -attention-row-limit, and -leech-quality-threshold. I added require 'calendar for the Monday week-start arithmetic in the weekly aggregates. CSV export and the manual and README entries are the step-3 follow-on.
Diffstat (limited to 'tests/test-org-drill-statistics-distribution.el')
-rw-r--r--tests/test-org-drill-statistics-distribution.el84
1 files changed, 84 insertions, 0 deletions
diff --git a/tests/test-org-drill-statistics-distribution.el b/tests/test-org-drill-statistics-distribution.el
new file mode 100644
index 0000000..f98d9aa
--- /dev/null
+++ b/tests/test-org-drill-statistics-distribution.el
@@ -0,0 +1,84 @@
+;;; test-org-drill-statistics-distribution.el --- Tests for distribution statistics -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; ERT tests for the org-drill statistics dashboard distribution block.
+
+;;; Code:
+
+(require 'ert)
+(require 'org-drill)
+(require 'cl-lib)
+(require 'org)
+
+(ert-deftest test-org-drill-statistics-distribution-subheading ()
+ "The rendered section opens with the Quality Distribution subheading."
+ (let ((out (org-drill-statistics--render-distribution [1 0 2 3 5 4])))
+ (should (string-prefix-p "** Quality Distribution" out))))
+
+(ert-deftest test-org-drill-statistics-distribution-all-six-rows ()
+ "Every quality 0..5 gets a row even when its count is zero."
+ (let* ((out (org-drill-statistics--render-distribution [0 0 0 0 0 0]))
+ (lines (split-string out "\n" t)))
+ ;; subheading + note line + six quality rows.
+ (dotimes (q 6)
+ (should (string-match-p (format "^%d " q) out)))))
+
+(ert-deftest test-org-drill-statistics-distribution-counts-and-percent ()
+ "Each row shows the absolute count and the percent of total."
+ ;; Total 10: quality 5 has 5 (50%), quality 0 has 1 (10%).
+ (let ((out (org-drill-statistics--render-distribution [1 1 1 1 1 5])))
+ (should (string-match-p "^5 .* 5 50%$" out))
+ (should (string-match-p "^0 .* 1 10%$" out))))
+
+(ert-deftest test-org-drill-statistics-distribution-total-line ()
+ "A non-empty histogram reports the total rating count."
+ (let ((out (org-drill-statistics--render-distribution [2 0 0 0 0 3])))
+ (should (string-match-p "Total ratings: 5" out))))
+
+(ert-deftest test-org-drill-statistics-distribution-empty-note ()
+ "An all-zero histogram emits the empty note and 0%% percentages."
+ (let ((out (org-drill-statistics--render-distribution [0 0 0 0 0 0])))
+ (should (string-match-p "No quality ratings recorded yet\\." out))
+ (should (string-match-p "^3 .* 0 0%$" out))))
+
+(ert-deftest test-org-drill-statistics-distribution-bar-scales-to-max ()
+ "The largest count fills the full bar width; smaller counts scale down."
+ (let* ((org-drill-statistics-distribution-bar-width 10)
+ (out (org-drill-statistics--render-distribution [10 0 0 0 0 5]))
+ (block (char-to-string ?\x2588)))
+ ;; Quality 0 (count 10, the max) fills all 10 blocks.
+ (should (string-match-p
+ (concat "^0 " (regexp-quote (make-string 10 ?\x2588)))
+ out))
+ ;; Quality 5 (count 5, half the max) fills 5 blocks.
+ (should (string-match-p
+ (concat "^5 " (regexp-quote (make-string 5 ?\x2588)) " ")
+ out))))
+
+(ert-deftest test-org-drill-statistics-distribution-pure-no-buffer ()
+ "Rendering returns a string and does not switch or create buffers."
+ (let ((before (buffer-list)))
+ (should (stringp (org-drill-statistics--render-distribution [1 2 3 4 5 6])))
+ (should (equal before (buffer-list)))))
+
+(ert-deftest test-org-drill-statistics-distribution-from-histogram-helper ()
+ "Renderer composes with the quality-histogram aggregator over a fixture log.
+Components integrated:
+- org-drill-statistics--quality-histogram (real)
+- org-drill-statistics--render-distribution (real, entry point)
+Validates the count for a known fixture flows through to the rendered row."
+ (let* ((rec (make-org-drill-session-record
+ :start-time (float-time)
+ :end-time (float-time)
+ :qualities [5 5 5 0]))
+ (hist (org-drill-statistics--quality-histogram (list rec)))
+ (out (org-drill-statistics--render-distribution hist)))
+ (should (string-match-p "Total ratings: 4" out))
+ ;; Quality 5 appears three times (75%).
+ (should (string-match-p "^5 .* 3 75%$" out))
+ ;; Quality 0 appears once (25%).
+ (should (string-match-p "^0 .* 1 25%$" out))))
+
+(provide 'test-org-drill-statistics-distribution)
+
+;;; test-org-drill-statistics-distribution.el ends here