Ihor Radchenko <[email protected]> writes: >>> Even :NOBLOCKING: no will be treated as t. The code checks whether it is >>> present and not "nil". That's all.
Sounds good. Removed my hesitant comment. >>> The second case looks like a bug. See new patch that fixes said behavior. The worg page on org syntax says that COMMENT always has to come after TODO. > Morgan Smith <[email protected]> writes: > >> Ihor Radchenko <[email protected]> writes: >> >>> I think the way the code works is searching the keyword name via >>> 'member', so the first instance "wins". But this is basically undefined >>> behavior. Do you really want to test for undefined behaviors? >> >> Well this is where we differ in our expectations of the test-suite. >> >> I like to have a reproducible, hands-off method for determining what the >> current state of the software is. This allows me to make large, sweeping >> changes and then use the test-suite to see the fallout. I see the test-suite >> as something to aid in development. >> >> I believe you see the test-suite as a promise of how the software should >> function. You want users to be able to look through the test-suite to see >> the >> recommended ways of using the software. > > Not exactly. I just observe that test suite was the only source of truth > available when checking for expected behavior in the past. I do not want > to break that useful function of the test suite. > > I also understand your arguments. > > What about explicitly marking the test cases that are testing underfined > behavior and may be broken if necessary in the future? You know that makes a lot of sense. Currently, if one breaks the test-suite then they know they probably messed up. If I fill the test-suite full of undefined behavior then people might get too comfortable changing the test suite. I hadn't considered that and I do think that concept has merit. I realized only a few of those where actually undefined behavior so I removed those. I think we can grantee the remaining cases. I'll ponder on how to test undefined behavior but I suppose I should work through all the defined behavior first :P Oh and my standard blurb: Tests pass after each patch on emacs 30.2. Tests pass after final patch on emacs 28 and 29. Tests pass after final patch with TZ set to UTC, Europe/Istanbul, and America/New_York.
>From 318bda0a3dd04824d69122a79363345f50f9516b Mon Sep 17 00:00:00 2001 From: Morgan Smith <[email protected]> Date: Wed, 25 Feb 2026 14:25:44 -0500 Subject: [PATCH 1/3] Testing: Refactor some tests * testing/lisp/test-org.el (test-org/org-encode-time, test-org/toggle-comment, test-org/closest-date, test-org/org-todo-prefix, test-org/entry-blocked-p): Refactor --- testing/lisp/test-org.el | 369 ++++++++++++++------------------------- 1 file changed, 133 insertions(+), 236 deletions(-) diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index e38d20d9c..ccbcf188b 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -80,61 +80,26 @@ org-test-without-dow (ert-deftest test-org/toggle-comment () "Test `org-toggle-comment' specifications." - ;; Simple headline. - (should - (equal "* Test" - (org-test-with-temp-text "* COMMENT Test" - (org-toggle-comment) - (buffer-string)))) - (should - (equal "* COMMENT Test" - (org-test-with-temp-text "* Test" - (org-toggle-comment) - (buffer-string)))) - ;; Headline with a regular keyword. - (should - (equal "* TODO Test" - (org-test-with-temp-text "* TODO COMMENT Test" - (org-toggle-comment) - (buffer-string)))) - (should - (equal "* TODO COMMENT Test" - (org-test-with-temp-text "* TODO Test" - (org-toggle-comment) - (buffer-string)))) - ;; Empty headline. - (should - (equal "* " - (org-test-with-temp-text "* COMMENT" - (org-toggle-comment) - (buffer-string)))) - (should - (equal "* COMMENT" - (org-test-with-temp-text "* " - (org-toggle-comment) - (buffer-string)))) - ;; Headline with a single keyword. - (should - (equal "* TODO " - (org-test-with-temp-text "* TODO COMMENT" - (org-toggle-comment) - (buffer-string)))) - (should - (equal "* TODO COMMENT" - (org-test-with-temp-text "* TODO" - (org-toggle-comment) - (buffer-string)))) - ;; Headline with a keyword, a priority cookie and contents. - (should - (equal "* TODO [#A] Headline" - (org-test-with-temp-text "* TODO [#A] COMMENT Headline" - (org-toggle-comment) - (buffer-string)))) - (should - (equal "* TODO [#A] COMMENT Headline" - (org-test-with-temp-text "* TODO [#A] Headline" - (org-toggle-comment) - (buffer-string))))) + (cl-flet ((test-toggle-comment (input expected) + (should (equal expected + (org-test-with-temp-text input + (org-toggle-comment) + (buffer-string)))))) + ;; Simple headline. + (test-toggle-comment "* COMMENT Test" "* Test") + (test-toggle-comment "* Test" "* COMMENT Test") + ;; Headline with a regular keyword. + (test-toggle-comment "* TODO COMMENT Test" "* TODO Test") + (test-toggle-comment "* TODO Test" "* TODO COMMENT Test") + ;; Empty headline. + (test-toggle-comment "* COMMENT" "* ") + (test-toggle-comment "* " "* COMMENT") + ;; Headline with a single keyword. + (test-toggle-comment "* TODO COMMENT" "* TODO ") + (test-toggle-comment "* TODO" "* TODO COMMENT") + ;; Headline with a keyword, a priority cookie and contents. + (test-toggle-comment "* TODO [#A] COMMENT Headline" "* TODO [#A] Headline") + (test-toggle-comment "* TODO [#A] Headline" "* TODO [#A] COMMENT Headline"))) (ert-deftest test-org/comment-dwim () "Test `comment-dwim' behaviour in an Org buffer." @@ -252,60 +217,44 @@ test-org/comment-dwim (ert-deftest test-org/org-encode-time () "Test various ways to call `org-encode-time'" - (org-test-with-timezone "UTC" - ;; list as the sole argument - (should (string-equal - "2022-03-24 23:30:01" - (format-time-string - "%F %T" - (org-encode-time '(1 30 23 24 3 2022 nil -1 nil))))) - ;; SECOND...YEAR - (should (string-equal - "2022-03-24 23:30:02" - (format-time-string - "%F %T" - (org-encode-time 2 30 23 24 3 2022)))) - ;; SECOND...YEAR IGNORED DST ZONE - (should (string-equal - "2022-03-24 23:30:03" - (format-time-string - "%F %T" - (org-encode-time 3 30 23 24 3 2022 nil -1 nil)))) - ;; function call - (should (string-equal - "2022-03-24 23:30:04" - (format-time-string - "%F %T" - (org-encode-time (apply #'list 4 30 23 '(24 3 2022 nil -1 nil)))))) - ;; wrong number of arguments - (if (not (version< emacs-version "27.1")) - (should-error (string-equal - "2022-03-24 23:30:05" + (cl-flet ((test-org-encode-time (input expected &optional (time-format-string "%F %T") + zone) + (should (string-equal + expected (format-time-string - "%F %T" - (org-encode-time 5 30 23 24 3 2022 nil)))))) - ;; daylight saving time - (if (not (version< emacs-version "27.1")) - ;; DST value is not ignored for multiple arguments unlike for `encode-time' - (should (string-equal - "2022-04-01 00:30:06 +0200 CEST" - (format-time-string - "%F %T %z %Z" - (org-encode-time 6 30 23 31 3 2022 nil nil "Europe/Madrid") - "Europe/Madrid"))) - (should (string-equal - "2022-03-31 23:30:07 +0200 CEST" - (format-time-string - "%F %T %z %Z" - (org-encode-time 7 30 23 31 3 2022 nil t "Europe/Madrid") - "Europe/Madrid")))) - (org-test-with-timezone "Europe/Madrid" - ;; Standard time is not forced when DST is not specified - (should (string-equal - "2022-03-31 23:30:08" - (format-time-string - "%F %T" - (org-encode-time 8 30 23 31 3 2022)))))) + time-format-string + input + zone))))) + (org-test-with-timezone "UTC" + ;; list as the sole argument + (test-org-encode-time (org-encode-time '(1 30 23 24 3 2022 nil -1 nil)) + "2022-03-24 23:30:01") + ;; SECOND...YEAR + (test-org-encode-time (org-encode-time 2 30 23 24 3 2022) + "2022-03-24 23:30:02") + ;; SECOND...YEAR IGNORED DST ZONE + (test-org-encode-time (org-encode-time 3 30 23 24 3 2022 nil -1 nil) + "2022-03-24 23:30:03") + ;; function call + (test-org-encode-time (org-encode-time (apply #'list 4 30 23 '(24 3 2022 nil -1 nil))) + "2022-03-24 23:30:04") + ;; wrong number of arguments + (if (not (version< emacs-version "27.1")) + (should-error (org-encode-time 5 30 23 24 3 2022 nil)))) + ;; daylight saving time + (if (not (version< emacs-version "27.1")) + ;; DST value is not ignored for multiple arguments unlike for `encode-time' + (test-org-encode-time (org-encode-time 6 30 23 31 3 2022 nil nil "Europe/Madrid") + "2022-04-01 00:30:06 +0200 CEST" + "%F %T %z %Z" + "Europe/Madrid") + (test-org-encode-time (org-encode-time 7 30 23 31 3 2022 nil t "Europe/Madrid") + "2022-03-31 23:30:07 +0200 CEST" + "%F %T %z %Z" + "Europe/Madrid")) + (org-test-with-timezone "Europe/Madrid" + ;; Standard time is not forced when DST is not specified + (test-org-encode-time (org-encode-time 8 30 23 31 3 2022) "2022-03-31 23:30:08")))) (ert-deftest test-org/org-time-string-to-time () "Test `org-time-string-to-time' around DST transition." @@ -431,79 +380,47 @@ test-org/closest-date "Test `org-closest-date' specifications." (require 'calendar) ;; Time stamps without a repeater are returned unchanged. - (should - (equal - '(3 29 2012) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29>" "<2014-03-04>" nil)))) - ;; Time stamps with a null repeater are returned unchanged. - (should - (equal - '(3 29 2012) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29 +0d>" "<2014-03-04>" nil)))) - ;; if PREFER is set to `past' always return a date before, or equal - ;; to CURRENT. - (should - (equal - '(3 1 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29 +1m>" "<2014-03-04>" 'past)))) - (should - (equal - '(3 4 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-04 +1m>" "<2014-03-04>" 'past)))) - ;; if PREFER is set to `future' always return a date before, or equal - ;; to CURRENT. - (should - (equal - '(3 29 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29 +1m>" "<2014-03-04>" 'future)))) - (should - (equal - '(3 4 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-04 +1m>" "<2014-03-04>" 'future)))) - ;; If PREFER is neither `past' nor `future', select closest date. - (should - (equal - '(3 1 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29 +1m>" "<2014-03-04>" nil)))) - (should - (equal - '(5 4 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-04 +1m>" "<2014-04-28>" nil)))) - ;; Test "day" repeater. - (should - (equal '(3 8 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2014-03-04 +2d>" "<2014-03-09>" 'past)))) - (should - (equal '(3 10 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2014-03-04 +2d>" "<2014-03-09>" 'future)))) - ;; Test "month" repeater. - (should - (equal '(1 5 2015) - (calendar-gregorian-from-absolute - (org-closest-date "<2014-03-05 +2m>" "<2015-02-04>" 'past)))) - (should - (equal '(3 29 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29 +2m>" "<2014-03-04>" 'future)))) - ;; Test "year" repeater. - (should - (equal '(3 5 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2014-03-05 +2y>" "<2015-02-04>" 'past)))) - (should - (equal '(3 29 2014) - (calendar-gregorian-from-absolute - (org-closest-date "<2012-03-29 +2y>" "<2014-03-04>" 'future))))) + (cl-flet ((test-closest-date (input expected) + (should (equal expected + (calendar-gregorian-from-absolute + (apply #'org-closest-date input)))))) + (test-closest-date '("<2012-03-29>" "<2014-03-04>" nil) + '(3 29 2012)) + ;; Time stamps with a null repeater are returned unchanged. + (test-closest-date '("<2012-03-29 +0d>" "<2014-03-04>" nil) + '(3 29 2012)) + ;; if PREFER is set to `past' always return a date before, or equal + ;; to CURRENT. + (test-closest-date '("<2012-03-29 +1m>" "<2014-03-04>" past) + '(3 1 2014)) + (test-closest-date '("<2012-03-04 +1m>" "<2014-03-04>" past) + '(3 4 2014)) + ;; if PREFER is set to `future' always return a date before, or equal + ;; to CURRENT. + (test-closest-date '("<2012-03-29 +1m>" "<2014-03-04>" future) + '(3 29 2014)) + (test-closest-date '("<2012-03-04 +1m>" "<2014-03-04>" future) + '(3 4 2014)) + ;; If PREFER is neither `past' nor `future', select closest date. + (test-closest-date '("<2012-03-29 +1m>" "<2014-03-04>" nil) + '(3 1 2014)) + (test-closest-date '("<2012-03-04 +1m>" "<2014-04-28>" nil) + '(5 4 2014)) + ;; Test "day" repeater. + (test-closest-date '("<2014-03-04 +2d>" "<2014-03-09>" past) + '(3 8 2014)) + (test-closest-date '("<2014-03-04 +2d>" "<2014-03-09>" future) + '(3 10 2014)) + ;; Test "month" repeater. + (test-closest-date '("<2014-03-05 +2m>" "<2015-02-04>" past) + '(1 5 2015)) + (test-closest-date '("<2012-03-29 +2m>" "<2014-03-04>" future) + '(3 29 2014)) + ;; Test "year" repeater. + (test-closest-date '("<2014-03-05 +2y>" "<2015-02-04>" past) + '(3 5 2014)) + (test-closest-date '("<2012-03-29 +2y>" "<2014-03-04>" future) + '(3 29 2014)))) (ert-deftest test-org/deadline-close-p () "Test `org-deadline-close-p' specifications." @@ -2752,46 +2669,29 @@ test-org/in-archived-heading-p (ert-deftest test-org/entry-blocked-p () ;; Check other dependencies. - (should - (org-test-with-temp-text "* TODO Blocked\n** DONE one\n** TODO two" - (let ((org-enforce-todo-dependencies t) - (org-blocker-hook - '(org-block-todo-from-children-or-siblings-or-parent))) - (org-entry-blocked-p)))) - (should-not - (org-test-with-temp-text "* TODO Blocked\n** DONE one\n** DONE two" - (let ((org-enforce-todo-dependencies t) - (org-blocker-hook - '(org-block-todo-from-children-or-siblings-or-parent))) - (org-entry-blocked-p)))) - ;; Entry without a TODO keyword or with a DONE keyword cannot be - ;; blocked. - (should-not - (org-test-with-temp-text "* Blocked\n** TODO one" - (let ((org-enforce-todo-dependencies t) - (org-blocker-hook - '(org-block-todo-from-children-or-siblings-or-parent))) - (org-entry-blocked-p)))) - (should-not - (org-test-with-temp-text "* DONE Blocked\n** TODO one" - (let ((org-enforce-todo-dependencies t) - (org-blocker-hook - '(org-block-todo-from-children-or-siblings-or-parent))) - (org-entry-blocked-p)))) - ;; Follow :ORDERED: specifications. - (should - (org-test-with-temp-text - "* H\n:PROPERTIES:\n:ORDERED: t\n:END:\n** TODO one\n** <point>TODO two" - (let ((org-enforce-todo-dependencies t) - (org-blocker-hook - '(org-block-todo-from-children-or-siblings-or-parent))) - (org-entry-blocked-p)))) - (should-not - (org-test-with-temp-text - "* H\n:PROPERTIES:\n:ORDERED: t\n:END:\n** <point>TODO one\n** DONE two" - (let ((org-enforce-todo-dependencies t) - (org-blocker-hook - '(org-block-todo-from-children-or-siblings-or-parent))) + (let ((org-enforce-todo-dependencies t)) + (should + (org-test-with-temp-text "* TODO Blocked\n** DONE one\n** TODO two" + (org-entry-blocked-p))) + (should-not + (org-test-with-temp-text "* TODO Blocked\n** DONE one\n** DONE two" + (org-entry-blocked-p))) + ;; Entry without a TODO keyword or with a DONE keyword cannot be + ;; blocked. + (should-not + (org-test-with-temp-text "* Blocked\n** TODO one" + (org-entry-blocked-p))) + (should-not + (org-test-with-temp-text "* DONE Blocked\n** TODO one" + (org-entry-blocked-p))) + ;; Follow :ORDERED: specifications. + (should + (org-test-with-temp-text + "* H\n:PROPERTIES:\n:ORDERED: t\n:END:\n** TODO one\n** <point>TODO two" + (org-entry-blocked-p))) + (should-not + (org-test-with-temp-text + "* H\n:PROPERTIES:\n:ORDERED: t\n:END:\n** <point>TODO one\n** DONE two" (org-entry-blocked-p))))) (ert-deftest test-org/get-outline-path () @@ -9171,21 +9071,18 @@ test-org/org-todo-prefix "Test `org-todo' prefix arg behavior." ;; FIXME: Add tests for all other allowed prefix arguments. ;; -1 prefix arg should cancel repeater and mark DONE. - (should - (string-match-p - "DONE H\\(.*\n\\)*<2012-03-29 Thu \\+0y>" - (let ((org-todo-keywords '((sequence "TODO" "DONE")))) - (org-test-with-temp-text "* TODO H\n<2012-03-29 Thu +2y>" - (org-todo -1) - (buffer-string))))) - ;; - prefix arg should cancel repeater and mark DONE. - (should - (string-match-p - "DONE H\\(.*\n\\)*<2012-03-29 Thu \\+0y>" - (let ((org-todo-keywords '((sequence "TODO" "DONE")))) - (org-test-with-temp-text "* TODO H\n<2012-03-29 Thu +2y>" - (org-todo '-) - (buffer-string))))) + (cl-flet ((test-org-todo (input-text arg expected) + (should + (string-equal + expected + (let ((org-todo-keywords '((sequence "TODO" "DONE")))) + (org-test-with-temp-text input-text + (org-todo -1) + (buffer-string))))))) + (test-org-todo "* TODO H\n<2012-03-29 Thu +2y>" -1 + "* DONE H\n<2012-03-29 Thu +0y>") + (test-org-todo "* TODO H\n<2012-03-29 Thu +2y>" '- + "* DONE H\n<2012-03-29 Thu +0y>")) ;; C-u forces logging note. ;; However, logging falls back to "time" when `org-inhibit-logging' ;; is 'note. base-commit: 1025e3b49a98f175b124dbccd774918360fe7e11 -- 2.52.0
>From beab82b9073d28d7e654a4246d11b2fa0289c8d1 Mon Sep 17 00:00:00 2001 From: Morgan Smith <[email protected]> Date: Wed, 25 Feb 2026 14:46:44 -0500 Subject: [PATCH 2/3] Testing: Add more tests * testing/lisp/test-org.el (test-org/org-log-into-drawer): New test. (test-org/move-subtree): Test setting `org-edit-keep-region'. (test-org/org-log-done): Use `ert-simulate-command' to make the test more realistic. (test-org/toggle-comment, test-org/closest-date, test-org/entry-blocked-p, test-org/map-entries, test-org/org-todo-prefix): Add new test cases. squash me --- testing/lisp/test-org.el | 261 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 245 insertions(+), 16 deletions(-) diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index ccbcf188b..51265d255 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -29,6 +29,8 @@ (require 'org-refile) (require 'org-agenda) +(require 'ert-x) + ;;; Helpers @@ -88,6 +90,11 @@ test-org/toggle-comment ;; Simple headline. (test-toggle-comment "* COMMENT Test" "* Test") (test-toggle-comment "* Test" "* COMMENT Test") + ;; Delete extra spaces/tabs + (test-toggle-comment "* COMMENT Test" "* Test") + ;; Sub-heading + (test-toggle-comment "* test\n<point>** subheading" "* test\n** COMMENT subheading") + (test-toggle-comment "* test\n<point>** COMMENT subheading" "* test\n** subheading") ;; Headline with a regular keyword. (test-toggle-comment "* TODO COMMENT Test" "* TODO Test") (test-toggle-comment "* TODO Test" "* TODO COMMENT Test") @@ -99,7 +106,12 @@ test-org/toggle-comment (test-toggle-comment "* TODO" "* TODO COMMENT") ;; Headline with a keyword, a priority cookie and contents. (test-toggle-comment "* TODO [#A] COMMENT Headline" "* TODO [#A] Headline") - (test-toggle-comment "* TODO [#A] Headline" "* TODO [#A] COMMENT Headline"))) + (test-toggle-comment "* TODO [#A] Headline" "* TODO [#A] COMMENT Headline") + ;; Before first headline + (should-error + (org-test-with-temp-text "<point>\n* Heading" (org-toggle-comment))) + (should-error + (org-test-with-temp-text "" (org-toggle-comment))))) (ert-deftest test-org/comment-dwim () "Test `comment-dwim' behaviour in an Org buffer." @@ -406,11 +418,21 @@ test-org/closest-date '(3 1 2014)) (test-closest-date '("<2012-03-04 +1m>" "<2014-04-28>" nil) '(5 4 2014)) + ;; Test "hour" repeater. + (test-closest-date '("<2014-03-04 +50h>" "<2014-03-09>" past) + '(3 8 2014)) + (test-closest-date '("<2014-03-04 +50h>" "<2014-03-09>" future) + '(3 10 2014)) ;; Test "day" repeater. (test-closest-date '("<2014-03-04 +2d>" "<2014-03-09>" past) '(3 8 2014)) (test-closest-date '("<2014-03-04 +2d>" "<2014-03-09>" future) '(3 10 2014)) + ;; Test "week" repeater. + (test-closest-date '("<2014-03-04 +1w>" "<2014-03-09>" past) + '(3 4 2014)) + (test-closest-date '("<2014-03-04 +1w>" "<2014-03-09>" future) + '(3 11 2014)) ;; Test "month" repeater. (test-closest-date '("<2014-03-05 +2m>" "<2015-02-04>" past) '(1 5 2015)) @@ -2692,6 +2714,19 @@ test-org/entry-blocked-p (should-not (org-test-with-temp-text "* H\n:PROPERTIES:\n:ORDERED: t\n:END:\n** <point>TODO one\n** DONE two" + (org-entry-blocked-p))) + ;; Follow :NOBLOCKING: + (should-not + (org-test-with-temp-text "* TODO Blocked\n:PROPERTIES:\n:NOBLOCKING: t\n:END:\n** DONE one\n** TODO two" + (org-entry-blocked-p))) + (should-not + (org-test-with-temp-text "* TODO Blocked\n:PROPERTIES:\n:NOBLOCKING: \n:END:\n** DONE one\n** TODO two" + (org-entry-blocked-p))) + (should + (org-test-with-temp-text "* TODO Blocked\n:PROPERTIES:\n:NOBLOCKING: nil\n:END:\n** DONE one\n** TODO two" + (org-entry-blocked-p))) + (should + (org-test-with-temp-text "* TODO Blocked\n** DONE one\n** TODO two\n:PROPERTIES:\n:NOBLOCKING: \n:END:" (org-entry-blocked-p))))) (ert-deftest test-org/get-outline-path () @@ -2838,6 +2873,51 @@ test-org/map-entries (equal '(1 11) (org-test-with-temp-text "* Level 1\n** Level 2" (org-map-entries #'point)))) + ;; Region scope. + (should + (equal nil + (org-test-with-temp-text "* Level 1\n** Level 2" + (org-map-entries #'point nil 'region)))) + (should + (equal '(1 11) + (org-test-with-temp-text "* Level 1\n** Level 2" + (push-mark) + (push-mark (point-max) nil t) + (org-map-entries #'point t 'region)))) + (should + (equal '(2) + (org-test-with-temp-text "\n* Level 1\n** Level 2" + (push-mark) + (push-mark (point-max) nil t) + (org-map-entries #'point t 'region-start-level)))) + ;; Tree scope. + (should + (equal '(13 23) + (org-test-with-temp-text "* ignore me\n<point>* Level 1\n** Level 2\n* ignore me" + (org-map-entries #'point t 'tree)))) + ;; File scope. + (should + (equal nil ;; FIXME: docstring implies this should work but it clearly doesn't + (org-test-with-temp-text "* Level 1\n** Level 2" + (org-map-entries #'point t 'file)))) + (should + (equal '(1 11) + (org-test-with-temp-text-in-file "* Level 1\n** Level 2" + (org-map-entries #'point t 'file)))) + (should + (equal '(1 11) + (org-test-with-temp-text-in-file "* Level 1\n** Level 2" + (org-map-entries #'point t (list buffer-file-name))))) + (should + (equal '(1 11) + (org-test-with-temp-text-in-file "* Level 1\n** Level 2" + (let ((org-agenda-files (list buffer-file-name))) + (org-map-entries #'point t 'agenda))))) + ;; Sexp scope. FIXME: not documented! + (should + (equal '(1 11) + (org-test-with-temp-text-in-file "* Level 1\n** Level 2" + (org-map-entries #'point t '(list (buffer-file-name (current-buffer))))))) ;; Level match. (should (equal '(1) @@ -5877,9 +5957,14 @@ test-org/move-subtree (should-error (funcall func) :type 'user-error) - (funcall func) + ;; Use `ert-simulate-command' so that `this-command' + ;; gets set which is used in `org--deactivate-mark' + (ert-simulate-command (list func)) (should (equal expected (buffer-string))) + ;; Mark will remain active depending on `org-edit-keep-region' + (should (eq (and selection (alist-get func org-edit-keep-region)) + mark-active)) (deactivate-mark) (undo-boundary) (undo) @@ -5929,7 +6014,12 @@ test-org/move-subtree (test-move-subtree 'up "* T\n** <point>H1\n** H2\n* T2\n" 'error - "H2"))) + "H2") + (dolist (org-edit-keep-region '(nil ((org-metadown . nil)) ((org-metadown . t)))) + (test-move-subtree 'down + "* T\n** <point>H1\n** H2\n** H3\n" + "* T\n** H3\n** H1\n** H2\n" + "H2")))) (ert-deftest test-org/demote () "Test `org-demote' specifications." @@ -8973,10 +9063,11 @@ test-org/org-log-done expected-string (org-test-with-temp-text test-string - (org-set-regexps-and-options) - (org-todo "DONE") - (when (memq 'org-add-log-note (default-value 'post-command-hook)) - (org-add-log-note)) + (org-set-regexps-and-options) ;; apply #+STARTUP: options + ;; Use `ert-simulate-command' to run + ;; `post-command-hook' where the logging actually + ;; takes place + (ert-simulate-command '(org-todo "DONE")) (buffer-string))))))) (let ((org-todo-keywords '((sequence "TODO" "DONE")))) (test-org-log-done nil t "* TODO task" "* DONE task") @@ -9067,22 +9158,160 @@ test-org/org-log-done - State \"DONE\" from \"TODO\" " time-string " \\\\ note")))))) +(ert-deftest test-org/org-log-into-drawer () + "Test `org-log-into-drawer' specifications. +Behavior can be modified by setting `org-log-into-drawer', by keywords in +\"#+STARTUP:\", or by the property \"LOG_INTO_DRAWER\"." + (let* ((time-string + (org-test-with-temp-text "" + (org-insert-timestamp (current-time) t t) + (buffer-string))) + (state-change-string + (concat "- State \"WAIT\" from \"TODO\" " time-string)) + (logbook-string (concat ":LOGBOOK:\n" state-change-string "\n:END:")) + (custom-logbook-string (concat ":custom:\n" state-change-string "\n:END:"))) + (cl-flet* + ((test-org-log-into-drawer + (org-log-into-drawer-val test-string expected-string) + (let ((org-log-into-drawer org-log-into-drawer-val)) + (should + (string= + expected-string + (org-test-with-temp-text + test-string + (org-set-regexps-and-options) ;; apply #+STARTUP: options + ;; Use `ert-simulate-command' to run + ;; `post-command-hook' where the logging actually + ;; takes place + (ert-simulate-command '(org-todo "WAIT")) + (buffer-string)))))) + (log-into-drawer-property (value) + (concat ":PROPERTIES: +:LOG_INTO_DRAWER: " value " +:END:\n"))) + (let ((org-todo-keywords '((sequence "TODO" "WAIT(!)" "DONE")))) + (test-org-log-into-drawer nil "* TODO task" + (concat "* WAIT task\n" state-change-string)) + (test-org-log-into-drawer t "* TODO task" + (concat "* WAIT task\n" logbook-string)) + (test-org-log-into-drawer "custom" "* TODO task" + (concat "* WAIT task\n" custom-logbook-string)) + ;; LOG_INTO_DRAWER property overrides `org-log-into-drawer' + (test-org-log-into-drawer t (concat "* TODO task\n" (log-into-drawer-property "nil")) + (concat "* WAIT task\n" (log-into-drawer-property "nil") + state-change-string)) + (test-org-log-into-drawer t (concat "* TODO task\n" (log-into-drawer-property "t")) + (concat "* WAIT task\n" (log-into-drawer-property "t") + logbook-string "\n")) + ;; FIXME: Having an empty property results in a funny logbook + ;; (test-org-log-into-drawer t (concat "* TODO task\n" (log-into-drawer-property "")) + ;; (concat "* WAIT task\n" (log-into-drawer-property "") + ;; logbook-string "\n")) + (test-org-log-into-drawer t (concat "* TODO task\n" (log-into-drawer-property "custom")) + (concat "* WAIT task\n" (log-into-drawer-property "custom") + custom-logbook-string "\n")) + (test-org-log-into-drawer nil "#+STARTUP: logdrawer\n<point>* TODO task" + (concat "#+STARTUP: logdrawer\n* WAIT task\n" logbook-string)) + ;; LOG_INTO_DRAWER property overrides #+STARTUP: logdrawer + (test-org-log-into-drawer nil (concat "#+STARTUP: logdrawer\n<point>* TODO task\n" + (log-into-drawer-property "nil")) + (concat "#+STARTUP: logdrawer\n* WAIT task\n" + (log-into-drawer-property "nil") + state-change-string)) + ;; LOG_INTO_DRAWER property overrides #+STARTUP: nologdrawer + (test-org-log-into-drawer nil (concat "#+STARTUP: nologdrawer\n<point>* TODO task\n" + (log-into-drawer-property "t")) + (concat "#+STARTUP: nologdrawer\n* WAIT task\n" + (log-into-drawer-property "t") + logbook-string "\n")) + ;; #+STARTUP: logdrawer overrides `org-log-into-drawer' + (test-org-log-into-drawer t (concat "#+STARTUP: nologdrawer\n<point>* TODO task") + (concat "#+STARTUP: nologdrawer\n* WAIT task\n" + state-change-string)))))) + (ert-deftest test-org/org-todo-prefix () "Test `org-todo' prefix arg behavior." - ;; FIXME: Add tests for all other allowed prefix arguments. - ;; -1 prefix arg should cancel repeater and mark DONE. + ;; FIXME: Add tests `org-todo-keywords' set to a `type' list + ;; FIXME: Add tests for numeric prefix arg of 0 (cl-flet ((test-org-todo (input-text arg expected) (should (string-equal - expected - (let ((org-todo-keywords '((sequence "TODO" "DONE")))) + (or (and (eq expected 'unchanged) input-text) + expected) + (let ((org-todo-keywords '((sequence "TODO" "DONE") + (sequence "KWD1" "KWD2" "DONE")))) (org-test-with-temp-text input-text - (org-todo -1) + (org-todo arg) (buffer-string))))))) - (test-org-todo "* TODO H\n<2012-03-29 Thu +2y>" -1 - "* DONE H\n<2012-03-29 Thu +0y>") - (test-org-todo "* TODO H\n<2012-03-29 Thu +2y>" '- - "* DONE H\n<2012-03-29 Thu +0y>")) + (test-org-todo "* TODO H" nil "* DONE H") + ;; unsupported prefix argument + (dolist (arg '(-3 -2 "bad todo state")) + (should-error + (org-test-with-temp-text "* TODO test" (org-todo arg)))) + (dolist (arg '(-1 -)) + ;; -1 prefix arg should cancel repeater and mark DONE. + (test-org-todo "* TODO H\n<2012-03-29 Thu +2y>" arg + "* DONE H\n<2012-03-29 Thu +0y>")) + + ;; switch to next or previous sequence + (dolist (arg '(nextset (16) previousset)) + (test-org-todo "* TODO H" arg "* KWD1 H") + (test-org-todo "* KWD1 H" arg "* TODO H")) + + ;; FIXME: COMMENT keyword always comes after TODO keyword + ;; (test-org-todo "* COMMENT TODO H" nil "* TODO COMMENT TODO H") + + (test-org-todo "* TODO COMMENT H" nil "* DONE COMMENT H") + (test-org-todo "* COMMENT H\n<point>** TODO H" nil "* COMMENT H\n** DONE H") + + (test-org-todo "* H" 'right "* TODO H") + (test-org-todo "* TODO H" 'right "* DONE H") + (test-org-todo "* KWD1 H" 'right "* KWD2 H") + (test-org-todo "* KWD2 H" 'right "* DONE H") + (test-org-todo "* H" 'left "* DONE H") + (test-org-todo "* TODO H" 'left "* H") + (test-org-todo "* KWD2 H" 'left "* KWD1 H") + + ;; Jump straight to specified state + (test-org-todo "* TODO H" 'done "* DONE H") + (test-org-todo "* TODO H" 3 "* KWD1 H") + (test-org-todo "* TODO H" "TODO" 'unchanged) + (test-org-todo "* DONE H" "DONE" 'unchanged) + (test-org-todo "* DONE H" 'done 'unchanged) + + ;; Blocking + (let ((org-enforce-todo-dependencies t)) + (test-org-todo "* TODO H\n** TODO block" nil 'unchanged) + (test-org-todo "* TODO H\n** TODO block" '(64) "* DONE H\n** TODO block") + (let ((org-inhibit-blocking t)) + (test-org-todo "* TODO H\n** TODO block" nil "* DONE H\n** TODO block")) + (let ((noblocking-property ":PROPERTIES: +:NOBLOCKING: t +:END:")) + (test-org-todo (concat "* TODO H\n" noblocking-property "** TODO block") + nil + (concat "* DONE H\n" noblocking-property "** TODO block")))) + + (let ((org-enforce-todo-checkbox-dependencies t)) + (test-org-todo "* TODO H\n- [ ] block" nil 'unchanged) + (test-org-todo "* TODO H\n- [ ] block" '(64) "* DONE H\n- [ ] block") + (let ((org-inhibit-blocking t)) + (test-org-todo "* TODO H\n- [ ] block" nil "* DONE H\n- [ ] block")) + (let ((noblocking-property ":PROPERTIES: +:NOBLOCKING: t +:END:")) + (test-org-todo (concat "* TODO H\n" noblocking-property "- [ ] block") + nil + (concat "* DONE H\n" noblocking-property "- [ ] block"))))) + ;; Region + (should + (string-equal + "* DONE H1\n* H2" + (org-test-with-temp-text "* TODO H1\n* DONE H2" + (push-mark) + (push-mark (point-max) nil t) + (org-todo) + (buffer-string)))) ;; C-u forces logging note. ;; However, logging falls back to "time" when `org-inhibit-logging' ;; is 'note. -- 2.52.0
>From ff1a6807db9113a47b161e225aeb9fec053c6caa Mon Sep 17 00:00:00 2001 From: Morgan Smith <[email protected]> Date: Fri, 6 Mar 2026 21:44:09 -0500 Subject: [PATCH 3/3] org-todo: Remove support for using the COMMENT keyword wrong * lisp/org.el (org-todo): Remove logic that allows for COMMENT to come before the TODO keyword. * testing/lisp/test-org.el (test-org/org-todo-prefix): Enable test. --- lisp/org.el | 7 +------ testing/lisp/test-org.el | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index fc51d4ba3..73c834816 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -9698,7 +9698,6 @@ org-todo (when (equal (prefix-numeric-value arg) -1) (org-cancel-repeaters) (setq arg nil)) (when (< (prefix-numeric-value arg) -1) (user-error "Prefix argument %d not supported" arg)) (let ((org-blocker-hook org-blocker-hook) - commentp case-fold-search) (when (equal arg '(64)) (setq arg nil org-blocker-hook nil)) @@ -9709,9 +9708,6 @@ org-todo (save-excursion (catch 'exit (org-back-to-heading t) - (when (org-in-commented-heading-p t) - (org-toggle-comment) - (setq commentp t)) (when (looking-at org-outline-regexp) (goto-char (1- (match-end 0)))) (or (looking-at (concat " +" org-todo-regexp "\\( +\\|[ \t]*$\\)")) (looking-at "\\(?: *\\|[ \t]*$\\)")) @@ -9903,8 +9899,7 @@ org-todo (just-one-space))) (when org-trigger-hook (save-excursion - (run-hook-with-args 'org-trigger-hook change-plist))) - (when commentp (org-toggle-comment)))))))) + (run-hook-with-args 'org-trigger-hook change-plist))))))))) (defun org-block-todo-from-children-or-siblings-or-parent (change-plist) "Block turning an entry into a TODO, using the hierarchy. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 51265d255..e4e29ccb7 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -9258,8 +9258,8 @@ test-org/org-todo-prefix (test-org-todo "* TODO H" arg "* KWD1 H") (test-org-todo "* KWD1 H" arg "* TODO H")) - ;; FIXME: COMMENT keyword always comes after TODO keyword - ;; (test-org-todo "* COMMENT TODO H" nil "* TODO COMMENT TODO H") + ;; COMMENT keyword always comes after TODO keyword + (test-org-todo "* COMMENT TODO H" nil "* TODO COMMENT TODO H") (test-org-todo "* TODO COMMENT H" nil "* DONE COMMENT H") (test-org-todo "* COMMENT H\n<point>** TODO H" nil "* COMMENT H\n** DONE H") -- 2.52.0
