From: Morgan Smith <[email protected]>
To: Ihor Radchenko <[email protected]>
Cc: [email protected], [email protected]
Subject: Re: [PATCH] Add test suite for org habit
Date: Sat, 18 Oct 2025 21:44:27 -0400 [thread overview]
Message-ID: <CH3PR84MB34245377412B6E3917F9646FC5F4A@CH3PR84MB3424.NAMPRD84.PROD.OUTLOOK.COM> (raw)
In-Reply-To: <87jz0sjc60.fsf@localhost>
[-- Attachment #1: Type: text/plain, Size: 1483 bytes --]
See attached two files.
0001-address-comments.patch is simply the changes I've made since the
last review and is not meant to be applied (sorry about the whitespace
noise).
The other file is meant to be applied.
Tested on emacs 28, 29, and 30 inside of containers. Tested on an emacs
31.0.5 development build outside of any containers.
Ihor Radchenko <[email protected]> writes:
> Morgan Smith <[email protected]> writes:
>
>> TLDR: I wrote a test suite for org habit. See attached.
>
> Thanks!
> Two comments:
>
> 1. One of the tests is failing on my side:
> FAILED test-org-habit/following-days
Org habit has bugs. Both with respect to daylight savings and
`org-extend-today-until'. I have codified these bugs in the test suite
and added TODO's. I am learning that getting time right is very tricky
and while the solution will likely be only a few lines, figuring it out
will be quite difficult.
> 2. I feel that
> "\nShave * * * * * * ! \n"
> and similar string are rather hard to read and may create headaches
> if we ever change the default value of `org-habit-graph-column' for
> any reason. IMHO, A helper function to format those expected strings
> will improve the code.
I have shaved off a good deal of the strings (and decoupled those from
`org-habit-graph-column'). I've left a couple as they are. I feel
testing the complete default configuration at least once is important.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-address-comments.patch --]
[-- Type: text/x-patch, Size: 13333 bytes --]
From e68af3f741c059f4884e756ad840a940b3a8fb83 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Sat, 18 Oct 2025 21:19:50 -0400
Subject: [PATCH] address comments
---
testing/lisp/test-org-habit.el | 231 +++++++++++++++++++++------------
1 file changed, 146 insertions(+), 85 deletions(-)
diff --git a/testing/lisp/test-org-habit.el b/testing/lisp/test-org-habit.el
index 652a2ca70..37bf1d3c2 100644
--- a/testing/lisp/test-org-habit.el
+++ b/testing/lisp/test-org-habit.el
@@ -100,7 +100,8 @@ test-org-habit/simple-habit
"Test the agenda view for a simple habit."
(org-test-at-time "2009-10-22"
(let ((org-agenda-custom-commands
- org-test-habit-no-fluff-agenda))
+ org-test-habit-no-fluff-agenda)
+ (org-habit-graph-column 5))
(org-test-agenda-with-agenda
"* TODO habit
SCHEDULED: <2009-10-21 Sat ++2d>
@@ -111,122 +112,179 @@ test-org-habit/simple-habit
- State \"DONE\" from \"TODO\" [2009-10-17 Sun]"
(should
(string-equal
- "\nhabit * * ! \n"
+ "\nhabit * * ! \n"
(progn
(org-agenda nil "f")
(buffer-string))))))))
+(ert-deftest test-org-habit/org-extend-today-until ()
+ "Test habit graph with `org-extend-today-until' set."
+ (org-test-at-time "2009-10-20"
+ (let ((org-agenda-custom-commands
+ org-test-habit-no-fluff-agenda)
+ (org-habit-preceding-days 5)
+ (org-habit-following-days 5)
+ (org-habit-graph-column 5)
+ (org-habit-show-all-today t))
+ (dolist (org-extend-today-until '(0 1 2))
+ (org-test-agenda-with-agenda
+ "* TODO habit
+SCHEDULED: <2009-10-20 Sat ++1d>
+:PROPERTIES:
+:STYLE: habit
+:END:
+- State \"DONE\" from \"TODO\" [2009-10-19 Sun 00:20]
+- State \"DONE\" from \"TODO\" [2009-10-17 Sun 01:20]"
+ (should
+ (string-equal
+ (cl-case org-extend-today-until
+ (0 "\nhabit * *! \n")
+ ;; TODO: This is not correct at all. Should be the following
+ ;; (1 "\nhabit ** ! \n")
+ ;; (2 "\nhabit * * ! \n")
+ (t "\nhabit * * \n"))
+ (progn
+ (org-agenda nil "f")
+ (buffer-string)))))))))
+
+(ert-deftest test-org-habit/dst ()
+ "Test the habit graph traversing a daylight savings time transition."
+ ;; DST transition [2009-11-01 01:59] -> [2009-11-01 01:00]
+ (org-test-with-timezone "America/New_York"
+ (org-test-at-time "2009-10-28"
+ (let ((org-agenda-custom-commands
+ org-test-habit-no-fluff-agenda)
+ (org-habit-preceding-days 5)
+ (org-habit-following-days 5)
+ (org-habit-graph-column 5))
+ (org-test-agenda-with-agenda
+ "* TODO habit
+SCHEDULED: <2009-10-28 Sat ++1d>
+:PROPERTIES:
+:STYLE: habit
+:END:
+- State \"DONE\" from \"TODO\" [2009-10-27 Sun]
+- State \"DONE\" from \"TODO\" [2009-10-25 Sun]"
+ (should
+ (string-equal
+ ;; TODO: we lost a day in the transition! should be:
+ ;; "\nhabit * *! \n"
+ "\nhabit * *! \n"
+ (progn
+ (org-agenda nil "f")
+ (buffer-string)))))))))
+
(ert-deftest test-org-habit/habit ()
"Test the agenda view for a habit."
(org-test-at-time "2009-10-17"
(org-test-habit
- (should
- (string-equal
- "\nShave * * * * * * ! \n"
- (progn
- (org-agenda nil "f")
- (buffer-string)))))))
+ (should
+ (string-equal
+ "\nShave * * * * * * ! \n"
+ (progn
+ (org-agenda nil "f")
+ (buffer-string)))))))
(ert-deftest test-org-habit/graph-column ()
"Test how modifiying `org-habit-graph-column' affects habits in the agenda."
(org-test-at-time "2009-10-17"
(org-test-habit
- (dolist (org-habit-graph-column '(0 1 2 3 10 20 40 100))
- (should
- (string-equal
- (cl-case org-habit-graph-column
- (0 "\n * * * * * * ! \n")
- (1 "\nS * * * * * * ! \n")
- (2 "\nSh * * * * * * ! \n")
- (3 "\nSha * * * * * * ! \n")
- ((10 20 40 100) (concat "\nShave"
- (make-string (- org-habit-graph-column 2) 32)
- "* * * * * * ! \n"))
- (t (cl-assert nil nil "Missing case!")))
- (progn
- (org-agenda nil "f")
- (buffer-string))))))))
+ (dolist (org-habit-graph-column '(0 1 2 3 10 20 40 100))
+ (should
+ (string-equal
+ (cl-case org-habit-graph-column
+ (0 "\n * * * * * * ! \n")
+ (1 "\nS * * * * * * ! \n")
+ (2 "\nSh * * * * * * ! \n")
+ (3 "\nSha * * * * * * ! \n")
+ ((10 20 40 100) (concat "\nShave"
+ (make-string (- org-habit-graph-column 2) 32)
+ "* * * * * * ! \n"))
+ (t (cl-assert nil nil "Missing case!")))
+ (progn
+ (org-agenda nil "f")
+ (buffer-string))))))))
(ert-deftest test-org-habit/preceding-days ()
"Test how modifiying `org-habit-preceding-days' affects habits in the agenda."
(org-test-at-time "2009-10-17"
(org-test-habit
- (dolist (org-habit-preceding-days '(0 1 2 3 10 20 40 100))
- (should
- (string-equal
- (cl-case org-habit-preceding-days
- (0 "\nShave ! \n")
- (1 "\nShave ! \n")
- (2 "\nShave * ! \n")
- (3 "\nShave * ! \n")
- (10 "\nShave * * * ! \n")
- (20 "\nShave * * * * * * ! \n")
- ((40 100) (concat "\nShave"
- (make-string org-habit-preceding-days 32)
- "* * * * * * * * * * ! \n"))
- (t (cl-assert nil nil "Missing case!")))
- (progn
- (org-agenda nil "f")
- (buffer-string))))))))
+ (dolist (org-habit-preceding-days '(0 1 2 3 10 20 40 100))
+ (should
+ (string-equal
+ (cl-case org-habit-preceding-days
+ (0 " ! \n")
+ (1 " ! \n")
+ (2 " * ! \n")
+ (3 " * ! \n")
+ (10 " * * * ! \n")
+ (20 " * * * * * * ! \n")
+ ((40 100) (concat (make-string (- org-habit-preceding-days 34) 32)
+ "* * * * * * * * * * ! \n"))
+ (t (cl-assert nil nil "Missing case!")))
+ (progn
+ (org-agenda nil "f")
+ (buffer-substring (+ 1 org-habit-graph-column) (point-max)))))))))
(ert-deftest test-org-habit/following-days ()
"Test how modifiying `org-habit-following-days' affects habits in the agenda."
- (org-test-at-time "2009-10-17"
- (org-test-habit
- (dolist (org-habit-following-days '(0 1 2 3 10 20 40 100))
- (should
- (string-equal
- (cl-case org-habit-following-days
- (0 "\nShave * * * * * * \n")
- ((1 2 3 10 20 40 100)
- (concat "\nShave * * * * * * !"
- (make-string org-habit-following-days 32)
- "\n"))
- (t (cl-assert nil nil "Missing case!")))
- (progn
- (org-agenda nil "f")
- (buffer-string))))))))
+ (org-test-with-timezone "UTC0" ;; Avoid DST. See `test-org-habit/dst'.
+ (org-test-at-time "2009-10-17"
+ (org-test-habit
+ (dolist (org-habit-following-days '(0 1 2 3 10 20 40 100))
+ (should
+ (string-equal
+ (cl-case org-habit-following-days
+ (0 " * * * * * * \n")
+ ((1 2 3 10 20 40 100)
+ (concat " * * * * * * !"
+ (make-string org-habit-following-days 32)
+ "\n"))
+ (t (cl-assert nil nil "Missing case!")))
+ (progn
+ (org-agenda nil "f")
+ (buffer-substring (+ 1 org-habit-graph-column) (point-max))))))))))
(ert-deftest test-org-habit/show-habits ()
"Test displaying habits in the agenda at various points in time.
Also test modifying the variables `org-habit-show-habits',
`org-habit-show-habits-only-for-today', and `org-habit-show-all-today'."
(org-test-habit
- (dolist (org-habit-show-habits '(nil t))
- (dolist (org-habit-show-habits-only-for-today '(nil t))
- (dolist (org-habit-show-all-today '(nil t))
- (dolist (test-time '(2009-10-15
- 2009-10-16
- 2009-10-17
- 2009-10-18
- 2009-10-19
- 2009-10-20
- 2009-10-21
- 2009-10-22))
- (let ((expected-output-string
- (cl-case test-time
+ (dolist (org-habit-show-habits '(nil t))
+ (dolist (org-habit-show-habits-only-for-today '(nil t))
+ (dolist (org-habit-show-all-today '(nil t))
+ (dolist (test-time '(2009-10-15
+ 2009-10-16
+ 2009-10-17
+ 2009-10-18
+ 2009-10-19
+ 2009-10-20
+ 2009-10-21
+ 2009-10-22))
+ (let ((expected-output-string
+ (cl-case test-time
(2009-10-15
- "\nShave * * * * * * * \n")
+ " * * * * * * * \n")
(2009-10-16
- "\nShave * * * * * * *! \n")
+ "* * * * * * *! \n")
(2009-10-17
- "\nShave * * * * * * ! \n")
+ " * * * * * * ! \n")
(2009-10-18
- "\nShave * * * * * * ! \n")
+ " * * * * * * ! \n")
(2009-10-19
- "\nShave * * * * * * ! \n")
+ " * * * * * * ! \n")
(2009-10-20
- "\nShave * * * * * * ! \n")
+ "* * * * * * ! \n")
(2009-10-21
- "\nShave * * * * * ! \n")
+ " * * * * * ! \n")
(2009-10-22
- "\nShave * * * * * ! \n")
+ " * * * * * ! \n")
(t (cl-assert nil t "Missing case for: %S!" (symbol-name test-time))))))
- (org-test-at-time (symbol-name test-time)
- (should
- (string-equal
- (if org-habit-show-habits
- (cl-case test-time
+ (org-test-at-time (symbol-name test-time)
+ (should
+ (string-equal
+ (if org-habit-show-habits
+ (cl-case test-time
((2009-10-15 2009-10-16)
(if org-habit-show-all-today
expected-output-string
@@ -234,10 +292,13 @@ test-org-habit/show-habits
((2009-10-17 2009-10-18 2009-10-19 2009-10-20 2009-10-21 2009-10-22)
expected-output-string)
(t (cl-assert nil t "Missing case for: %S!" (symbol-name test-time))))
- "")
- (progn
- (org-agenda nil "f")
- (buffer-string))))))))))))
+ "")
+ (progn
+ (org-agenda nil "f")
+ (let ((result (buffer-string)))
+ (if (string-empty-p result)
+ result
+ (substring result (+ 1 org-habit-graph-column)))))))))))))))
(ert-deftest test-org-habit/toggle-display-in-agenda ()
"Test the agenda view for a habit."
--
2.51.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-testing-lisp-test-org-habit.el-Add-org-habit-tests.patch --]
[-- Type: text/x-patch, Size: 16101 bytes --]
From da3cf8e92264c0ac1c0d04c1c0562c4a059e47ce Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Thu, 23 Jan 2025 15:35:50 -0500
Subject: [PATCH] testing/lisp/test-org-habit.el: Add org habit tests
* testing/lisp/test-org-habit.el: New file full of tests.
---
testing/lisp/test-org-habit.el | 401 +++++++++++++++++++++++++++++++++
1 file changed, 401 insertions(+)
create mode 100644 testing/lisp/test-org-habit.el
diff --git a/testing/lisp/test-org-habit.el b/testing/lisp/test-org-habit.el
new file mode 100644
index 000000000..37bf1d3c2
--- /dev/null
+++ b/testing/lisp/test-org-habit.el
@@ -0,0 +1,401 @@
+;;; test-org-habit.el --- Tests for org-habit.el -*- lexical-binding: t ; -*-
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+\f
+;;; Commentary:
+
+;; Unit tests for Org Habits.
+\f
+;;; Code:
+
+(require 'org-test "../testing/org-test")
+(require 'org-agenda)
+(require 'org-habit)
+(require 'test-org-agenda)
+
+\f
+;; Tests
+
+(defvar org-test-habit-no-fluff-agenda
+ '(("f" "no fluff" agenda ""
+ ((org-agenda-overriding-header "")
+ (org-agenda-format-date "")
+ (org-agenda-span 'day)
+ (org-agenda-show-all-dates nil)
+ (org-agenda-todo-keyword-format "")
+ (org-agenda-prefix-format "")))))
+
+(defun org-test-habit-agenda-string (repeater-type-string repeater-deadline?)
+ "Return an org habit test string.
+REPEATER-TYPE-STRING is used as the repeater type (ex. \".+\").
+When REPEATER-DEADLINE? is non-nil, add a repeater deadline.
+Order is determined by `org-log-states-order-reversed'."
+ (concat
+ "* TODO Shave
+SCHEDULED: <2009-10-17 Sat " repeater-type-string "2d"
+ (if repeater-deadline?
+ "/4d"
+ "")
+ ">
+:PROPERTIES:
+:STYLE: habit
+:LAST_REPEAT: [2009-10-19 Mon 00:36]
+:END:
+"
+
+ (if org-log-states-order-reversed
+ "- State \"DONE\" from \"TODO\" [2009-10-15 Thu]
+- State \"DONE\" from \"TODO\" [2009-10-12 Mon]
+- CLOSING NOTE [2009-10-10 Sat] \\
+ this style occurs when `org-log-done' is `note'.
+- State \"DONE\" from \"TODO\" [2009-10-04 Sun]
+- State \"DONE\" from \"TODO\" [2009-10-02 Fri]
+- State \"DONE\" from \"TODO\" [2009-09-29 Tue]
+- State \"DONE\" from \"TODO\" [2009-09-25 Fri]
+- State \"DONE\" from \"TODO\" [2009-09-19 Sat]
+- State \"DONE\" from \"TODO\" [2009-09-16 Wed]
+- State \"DONE\" from \"TODO\" [2009-09-12 Sat]"
+
+ "- State \"DONE\" from \"TODO\" [2009-09-12 Sat]
+- State \"DONE\" from \"TODO\" [2009-09-16 Wed]
+- State \"DONE\" from \"TODO\" [2009-09-19 Sat]
+- State \"DONE\" from \"TODO\" [2009-09-25 Fri]
+- State \"DONE\" from \"TODO\" [2009-09-29 Tue]
+- State \"DONE\" from \"TODO\" [2009-10-02 Fri]
+- State \"DONE\" from \"TODO\" [2009-10-04 Sun]
+- CLOSING NOTE [2009-10-10 Sat] \\
+ this style occurs when `org-log-done' is `note'.
+- State \"DONE\" from \"TODO\" [2009-10-12 Mon]
+- State \"DONE\" from \"TODO\" [2009-10-15 Thu]")))
+
+(defmacro org-test-habit (&rest body)
+ "Run BODY multiple times for testing habits.
+Add agenda from `org-test-habit-no-fluff-agenda' to
+`org-agenda-custom-commands'.
+
+Use habit data from `org-test-habit-agenda-string' both with and without
+a repeater deadline and the the log data reversed and not-reversed."
+ (declare (indent 0))
+ `(let ((org-agenda-custom-commands
+ org-test-habit-no-fluff-agenda))
+ (dolist (org-log-states-order-reversed '(t nil))
+ (dolist (repeater-deadline? '(nil t))
+ (dolist (repeater-type-string '(".+" "+" "++"))
+ (org-test-agenda-with-agenda
+ (org-test-habit-agenda-string repeater-type-string repeater-deadline?)
+ ,@body))))))
+
+(ert-deftest test-org-habit/simple-habit ()
+ "Test the agenda view for a simple habit."
+ (org-test-at-time "2009-10-22"
+ (let ((org-agenda-custom-commands
+ org-test-habit-no-fluff-agenda)
+ (org-habit-graph-column 5))
+ (org-test-agenda-with-agenda
+ "* TODO habit
+SCHEDULED: <2009-10-21 Sat ++2d>
+:PROPERTIES:
+:STYLE: habit
+:END:
+- State \"DONE\" from \"TODO\" [2009-10-19 Sun]
+- State \"DONE\" from \"TODO\" [2009-10-17 Sun]"
+ (should
+ (string-equal
+ "\nhabit * * ! \n"
+ (progn
+ (org-agenda nil "f")
+ (buffer-string))))))))
+
+(ert-deftest test-org-habit/org-extend-today-until ()
+ "Test habit graph with `org-extend-today-until' set."
+ (org-test-at-time "2009-10-20"
+ (let ((org-agenda-custom-commands
+ org-test-habit-no-fluff-agenda)
+ (org-habit-preceding-days 5)
+ (org-habit-following-days 5)
+ (org-habit-graph-column 5)
+ (org-habit-show-all-today t))
+ (dolist (org-extend-today-until '(0 1 2))
+ (org-test-agenda-with-agenda
+ "* TODO habit
+SCHEDULED: <2009-10-20 Sat ++1d>
+:PROPERTIES:
+:STYLE: habit
+:END:
+- State \"DONE\" from \"TODO\" [2009-10-19 Sun 00:20]
+- State \"DONE\" from \"TODO\" [2009-10-17 Sun 01:20]"
+ (should
+ (string-equal
+ (cl-case org-extend-today-until
+ (0 "\nhabit * *! \n")
+ ;; TODO: This is not correct at all. Should be the following
+ ;; (1 "\nhabit ** ! \n")
+ ;; (2 "\nhabit * * ! \n")
+ (t "\nhabit * * \n"))
+ (progn
+ (org-agenda nil "f")
+ (buffer-string)))))))))
+
+(ert-deftest test-org-habit/dst ()
+ "Test the habit graph traversing a daylight savings time transition."
+ ;; DST transition [2009-11-01 01:59] -> [2009-11-01 01:00]
+ (org-test-with-timezone "America/New_York"
+ (org-test-at-time "2009-10-28"
+ (let ((org-agenda-custom-commands
+ org-test-habit-no-fluff-agenda)
+ (org-habit-preceding-days 5)
+ (org-habit-following-days 5)
+ (org-habit-graph-column 5))
+ (org-test-agenda-with-agenda
+ "* TODO habit
+SCHEDULED: <2009-10-28 Sat ++1d>
+:PROPERTIES:
+:STYLE: habit
+:END:
+- State \"DONE\" from \"TODO\" [2009-10-27 Sun]
+- State \"DONE\" from \"TODO\" [2009-10-25 Sun]"
+ (should
+ (string-equal
+ ;; TODO: we lost a day in the transition! should be:
+ ;; "\nhabit * *! \n"
+ "\nhabit * *! \n"
+ (progn
+ (org-agenda nil "f")
+ (buffer-string)))))))))
+
+(ert-deftest test-org-habit/habit ()
+ "Test the agenda view for a habit."
+ (org-test-at-time "2009-10-17"
+ (org-test-habit
+ (should
+ (string-equal
+ "\nShave * * * * * * ! \n"
+ (progn
+ (org-agenda nil "f")
+ (buffer-string)))))))
+
+(ert-deftest test-org-habit/graph-column ()
+ "Test how modifiying `org-habit-graph-column' affects habits in the agenda."
+ (org-test-at-time "2009-10-17"
+ (org-test-habit
+ (dolist (org-habit-graph-column '(0 1 2 3 10 20 40 100))
+ (should
+ (string-equal
+ (cl-case org-habit-graph-column
+ (0 "\n * * * * * * ! \n")
+ (1 "\nS * * * * * * ! \n")
+ (2 "\nSh * * * * * * ! \n")
+ (3 "\nSha * * * * * * ! \n")
+ ((10 20 40 100) (concat "\nShave"
+ (make-string (- org-habit-graph-column 2) 32)
+ "* * * * * * ! \n"))
+ (t (cl-assert nil nil "Missing case!")))
+ (progn
+ (org-agenda nil "f")
+ (buffer-string))))))))
+
+(ert-deftest test-org-habit/preceding-days ()
+ "Test how modifiying `org-habit-preceding-days' affects habits in the agenda."
+ (org-test-at-time "2009-10-17"
+ (org-test-habit
+ (dolist (org-habit-preceding-days '(0 1 2 3 10 20 40 100))
+ (should
+ (string-equal
+ (cl-case org-habit-preceding-days
+ (0 " ! \n")
+ (1 " ! \n")
+ (2 " * ! \n")
+ (3 " * ! \n")
+ (10 " * * * ! \n")
+ (20 " * * * * * * ! \n")
+ ((40 100) (concat (make-string (- org-habit-preceding-days 34) 32)
+ "* * * * * * * * * * ! \n"))
+ (t (cl-assert nil nil "Missing case!")))
+ (progn
+ (org-agenda nil "f")
+ (buffer-substring (+ 1 org-habit-graph-column) (point-max)))))))))
+
+(ert-deftest test-org-habit/following-days ()
+ "Test how modifiying `org-habit-following-days' affects habits in the agenda."
+ (org-test-with-timezone "UTC0" ;; Avoid DST. See `test-org-habit/dst'.
+ (org-test-at-time "2009-10-17"
+ (org-test-habit
+ (dolist (org-habit-following-days '(0 1 2 3 10 20 40 100))
+ (should
+ (string-equal
+ (cl-case org-habit-following-days
+ (0 " * * * * * * \n")
+ ((1 2 3 10 20 40 100)
+ (concat " * * * * * * !"
+ (make-string org-habit-following-days 32)
+ "\n"))
+ (t (cl-assert nil nil "Missing case!")))
+ (progn
+ (org-agenda nil "f")
+ (buffer-substring (+ 1 org-habit-graph-column) (point-max))))))))))
+
+(ert-deftest test-org-habit/show-habits ()
+ "Test displaying habits in the agenda at various points in time.
+Also test modifying the variables `org-habit-show-habits',
+`org-habit-show-habits-only-for-today', and `org-habit-show-all-today'."
+ (org-test-habit
+ (dolist (org-habit-show-habits '(nil t))
+ (dolist (org-habit-show-habits-only-for-today '(nil t))
+ (dolist (org-habit-show-all-today '(nil t))
+ (dolist (test-time '(2009-10-15
+ 2009-10-16
+ 2009-10-17
+ 2009-10-18
+ 2009-10-19
+ 2009-10-20
+ 2009-10-21
+ 2009-10-22))
+ (let ((expected-output-string
+ (cl-case test-time
+ (2009-10-15
+ " * * * * * * * \n")
+ (2009-10-16
+ "* * * * * * *! \n")
+ (2009-10-17
+ " * * * * * * ! \n")
+ (2009-10-18
+ " * * * * * * ! \n")
+ (2009-10-19
+ " * * * * * * ! \n")
+ (2009-10-20
+ "* * * * * * ! \n")
+ (2009-10-21
+ " * * * * * ! \n")
+ (2009-10-22
+ " * * * * * ! \n")
+ (t (cl-assert nil t "Missing case for: %S!" (symbol-name test-time))))))
+ (org-test-at-time (symbol-name test-time)
+ (should
+ (string-equal
+ (if org-habit-show-habits
+ (cl-case test-time
+ ((2009-10-15 2009-10-16)
+ (if org-habit-show-all-today
+ expected-output-string
+ ""))
+ ((2009-10-17 2009-10-18 2009-10-19 2009-10-20 2009-10-21 2009-10-22)
+ expected-output-string)
+ (t (cl-assert nil t "Missing case for: %S!" (symbol-name test-time))))
+ "")
+ (progn
+ (org-agenda nil "f")
+ (let ((result (buffer-string)))
+ (if (string-empty-p result)
+ result
+ (substring result (+ 1 org-habit-graph-column)))))))))))))))
+
+(ert-deftest test-org-habit/toggle-display-in-agenda ()
+ "Test the agenda view for a habit."
+ (let ((org-agenda-custom-commands
+ '(("f" "no fluff" agenda ""
+ ;; This differs from `org-test-habit-no-fluff-agenda' by
+ ;; adding this header. Without this we have cases where
+ ;; the agenda buffer is completly empty and that causes
+ ;; funny things to happen
+ ((org-agenda-overriding-header "h")
+ (org-agenda-format-date "")
+ (org-agenda-span 'day)
+ (org-agenda-show-all-dates nil)
+ (org-agenda-todo-keyword-format "")
+ (org-agenda-prefix-format "")))))
+ (org-habit-graph-column 7)
+ (org-habit-following-days 1)
+ (org-habit-preceding-days 5))
+ ;; (test-time . expected-string)
+ (dolist (test-data '(("2009-10-15" . "h\n\nShave * * * \n")
+ ("2009-10-17" . "h\n\nShave * * ! \n")))
+ (org-test-at-time (car test-data)
+ (org-test-agenda-with-agenda
+ (org-test-habit-agenda-string "++" nil)
+ (org-agenda nil "f")
+ (should
+ (string-equal
+ (if (string-equal (car test-data) "2009-10-17")
+ (cdr test-data)
+ "h\n")
+ (buffer-string)))
+ (org-habit-toggle-display-in-agenda nil)
+ (should
+ (string-equal
+ "h\n"
+ (buffer-string)))
+ (org-habit-toggle-display-in-agenda nil)
+ (should
+ (string-equal
+ (if (string-equal (car test-data) "2009-10-17")
+ (cdr test-data)
+ "h\n")
+ (buffer-string)))
+ (org-habit-toggle-display-in-agenda t)
+ (should
+ (string-equal
+ (cdr test-data)
+ (buffer-string))))))))
+
+;;; Bad habits
+
+(ert-deftest test-org-habit/bad-habit-no-repeater ()
+ "Test a habit without a repeater."
+ (org-test-agenda-with-agenda
+ "* TODO no repeater
+SCHEDULED: <2009-10-17 Sat>
+:PROPERTIES:
+:STYLE: habit
+:END:"
+ (should-error
+ (org-agenda nil "a"))))
+
+(ert-deftest test-org-habit/bad-habit-short-repeater ()
+ "Test a habit with a period of less then 1 day."
+ (org-test-agenda-with-agenda
+ "* TODO repeat period less then 1 day
+SCHEDULED: <2009-10-17 Sat +0d>
+:PROPERTIES:
+:STYLE: habit
+:END:"
+ (should-error
+ (org-agenda nil "a"))))
+
+(ert-deftest test-org-habit/bad-habit-no-scheduled ()
+ "Test a habit that is not scheduled."
+ (org-test-agenda-with-agenda
+ "* TODO no scheduled <2009-10-17 Sat +1d>
+:PROPERTIES:
+:STYLE: habit
+:END:"
+ (should-error
+ (org-agenda nil "a"))))
+
+(ert-deftest test-org-habit/bad-habit-deadline-less-scheduled ()
+ "Test a habit where the deadline is less then or equal to the scheduled."
+ (dolist (deadline '("1d" "2d"))
+ (org-test-agenda-with-agenda
+ (concat
+ "* TODO deadline < or = to scheduled
+SCHEDULED: <2009-10-17 Sat +2d/" deadline ">
+:PROPERTIES:
+:STYLE: habit
+:END:")
+ (should-error
+ (org-agenda nil "a")))))
+
+\f
+(provide 'test-org-habit)
+\f
+;;; test-org-habit.el ends here
--
2.51.0
next prev parent reply other threads:[~2025-10-19 1:44 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-03 18:23 [PATCH] Add test suite for org habit Morgan Smith
2025-10-04 0:06 ` John Wiegley
2025-10-18 13:14 ` Ihor Radchenko
2025-10-18 18:05 ` Morgan Smith
2025-10-18 18:31 ` Ihor Radchenko
2025-10-19 1:44 ` Morgan Smith [this message]
2025-10-19 12:07 ` Ihor Radchenko
2025-10-19 19:30 ` Morgan Smith
2025-10-25 13:17 ` Ihor Radchenko
2025-10-25 16:10 ` Morgan Smith
2025-10-25 17:22 ` Ihor Radchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CH3PR84MB34245377412B6E3917F9646FC5F4A@CH3PR84MB3424.NAMPRD84.PROD.OUTLOOK.COM \
[email protected] \
[email protected] \
[email protected] \
[email protected] \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).