branch: master commit ef04c24b93b4f200a6af37aabc8ba24084640d68 Author: Ian Dunn <du...@gnu.org> Commit: Ian Dunn <du...@gnu.org>
Added has-tags? and matches? conditions * org-edna.el (org-edna-condition/has-tags?): New defun. (org-edna--heading-matches): New helper defun. (org-edna-condition/matches?): New defun. * org-edna-tests.el: Refactored to consolidate common forms. (org-edna-protect-test-file): (org-edna-test-setup): (org-edna-with-point-at-test-heading): (org-edna-with-test-heading): New helper macros. (org-edna-test-children-marks): New helper function. (org-edna-doc-test/has-tags): (org-edna-doc-test/matches): (org-edna-doc-test/chain): New tests. * org-edna.org (Checking Tags): (Matching Headings): Sections for new conditions. --- org-edna-tests.el | 1920 +++++++++++++++++++++++----------------------------- org-edna-tests.org | 36 + org-edna.el | 33 +- org-edna.info | 215 +++--- org-edna.org | 55 +- 5 files changed, 1092 insertions(+), 1167 deletions(-) diff --git a/org-edna-tests.el b/org-edna-tests.el index 52c901a..b6adf15 100644 --- a/org-edna-tests.el +++ b/org-edna-tests.el @@ -69,6 +69,48 @@ (with-current-buffer (get-file-buffer org-edna-test-file) (revert-buffer nil t))) +(defmacro org-edna-protect-test-file (&rest body) + (declare (indent 0)) + `(unwind-protect + (progn ,@body) + ;; Change the test file back to its original state. + (org-edna-test-restore-test-file))) + +(defmacro org-edna-test-setup (&rest body) + "Common settings for tests." + (declare (indent 0)) + ;; Override `current-time' so we can get a deterministic value + `(cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) + ;; Only use the test file in the agenda + (org-agenda-files `(,org-edna-test-file)) + ;; Ensure interactive modification of TODO states works. + (org-todo-keywords '((sequence "TODO" "|" "DONE"))) + ;; Only block based on Edna + (org-blocker-hook 'org-edna-blocker-function) + ;; Only trigger based on Edna + (org-trigger-hook 'org-edna-trigger-function) + ;; Inhibit messages if indicated + (inhibit-message org-edna-test-inhibit-messages)) + ,@body)) + +(defmacro org-edna-with-point-at-test-heading (heading-id &rest body) + (declare (indent 1)) + `(org-with-point-at (org-edna-find-test-heading ,heading-id) + ,@body)) + +(defmacro org-edna-with-test-heading (heading-id &rest body) + "Establish a test case with test heading HEADING-ID. + +HEADING-ID is a UUID string of a heading to use. + +Moves point to the heading, protects the test file, sets default +test settings, then runs BODY." + (declare (indent 1)) + `(org-edna-test-setup + (org-edna-protect-test-file + (org-edna-with-point-at-test-heading ,heading-id + ,@body)))) + (defun org-edna-find-test-heading (id) "Find the test heading with id ID. @@ -97,8 +139,11 @@ This avoids org-id digging into its internal database." (dolist (pom poms) (org-edna-test-change-todo-state pom "TODO"))) +(defun org-edna-test-children-marks () + (org-edna-collect-descendants nil)) + -;;;; Parser Tests +;;; Parser Tests (ert-deftest org-edna-parse-form-no-arguments () (let* ((input-string "test-string") @@ -469,48 +514,48 @@ This avoids org-id digging into its internal database." (should (equal output-form expected-form)))) -;; Finders +;;; Finders (defsubst org-edna-heading (pom) (org-with-point-at pom (org-get-heading t t t t))) (ert-deftest org-edna-finder/match-single-arg () - (let* ((org-agenda-files `(,org-edna-test-file)) - (targets (org-edna-finder/match "test&1"))) - (should (= (length targets) 2)) - (should (string-equal (org-edna-heading (nth 0 targets)) "Tagged Heading 1")) - (should (string-equal (org-edna-heading (nth 1 targets)) "Tagged Heading 2")))) + (org-edna-test-setup + (let* ((targets (org-edna-finder/match "test&1"))) + (should (= (length targets) 2)) + (should (string-equal (org-edna-heading (nth 0 targets)) "Tagged Heading 1")) + (should (string-equal (org-edna-heading (nth 1 targets)) "Tagged Heading 2"))))) (ert-deftest org-edna-finder/ids-single () - (let* ((org-agenda-files `(,org-edna-test-file)) - (test-id "caccd0a6-d400-410a-9018-b0635b07a37e") - (targets (org-edna-finder/ids test-id))) - (should (= (length targets) 1)) - (should (string-equal (org-edna-heading (nth 0 targets)) "Blocking Test")) - (should (string-equal (org-entry-get (nth 0 targets) "ID") test-id)))) + (org-edna-test-setup + (let* ((test-id "caccd0a6-d400-410a-9018-b0635b07a37e") + (targets (org-edna-finder/ids test-id))) + (should (= (length targets) 1)) + (should (string-equal (org-edna-heading (nth 0 targets)) "Blocking Test")) + (should (string-equal (org-entry-get (nth 0 targets) "ID") test-id))))) (ert-deftest org-edna-finder/ids-multiple () - (let* ((org-agenda-files `(,org-edna-test-file)) - (test-ids '("0d491588-7da3-43c5-b51a-87fbd34f79f7" - "b010cbad-60dc-46ef-a164-eb155e62cbb2")) - (targets (apply 'org-edna-finder/ids test-ids))) - (should (= (length targets) 2)) - (should (string-equal (org-edna-heading (nth 0 targets)) "ID Heading 1")) - (should (string-equal (org-entry-get (nth 0 targets) "ID") (nth 0 test-ids))) - (should (string-equal (org-edna-heading (nth 1 targets)) "ID Heading 2")) - (should (string-equal (org-entry-get (nth 1 targets) "ID") (nth 1 test-ids))))) + (org-edna-test-setup + (let* ((test-ids '("0d491588-7da3-43c5-b51a-87fbd34f79f7" + "b010cbad-60dc-46ef-a164-eb155e62cbb2")) + (targets (apply 'org-edna-finder/ids test-ids))) + (should (= (length targets) 2)) + (should (string-equal (org-edna-heading (nth 0 targets)) "ID Heading 1")) + (should (string-equal (org-entry-get (nth 0 targets) "ID") (nth 0 test-ids))) + (should (string-equal (org-edna-heading (nth 1 targets)) "ID Heading 2")) + (should (string-equal (org-entry-get (nth 1 targets) "ID") (nth 1 test-ids)))))) (ert-deftest org-edna-finder/match-blocker () - (let* ((org-agenda-files `(,org-edna-test-file)) - (heading (org-edna-find-test-heading "caccd0a6-d400-410a-9018-b0635b07a37e")) - (blocker (org-entry-get heading "BLOCKER")) - blocking-entry) - (should (string-equal "match(\"test&1\")" blocker)) - (org-with-point-at heading - (setq blocking-entry (org-edna-process-form blocker 'condition))) - (should (string-equal (substring-no-properties blocking-entry) - "TODO Tagged Heading 1 :1:test:")))) + (org-edna-test-setup + (let* ((heading (org-edna-find-test-heading "caccd0a6-d400-410a-9018-b0635b07a37e")) + (blocker (org-entry-get heading "BLOCKER")) + blocking-entry) + (should (string-equal "match(\"test&1\")" blocker)) + (org-with-point-at heading + (setq blocking-entry (org-edna-process-form blocker 'condition))) + (should (string-equal (substring-no-properties blocking-entry) + "TODO Tagged Heading 1 :1:test:"))))) (ert-deftest org-edna-finder/file () (let* ((targets (org-edna-finder/file org-edna-test-file))) @@ -1183,564 +1228,450 @@ This avoids org-id digging into its internal database." (should (not (org-edna--get-cache-entry 'org-edna-finder/match '("test&1")))))))) -;; Actions +;;; Actions (ert-deftest org-edna-action/todo-test () - (let* ((org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7"))) - (unwind-protect - (org-with-point-at target - (org-edna-action/todo! nil "DONE") - (should (string-equal (org-entry-get nil "TODO") "DONE")) - (org-edna-action/todo! nil "TODO") - (should (string-equal (org-entry-get nil "TODO") "TODO")) - (org-edna-action/todo! nil 'DONE) - (should (string-equal (org-entry-get nil "TODO") "DONE")) - (org-edna-action/todo! nil 'TODO) - (should (string-equal (org-entry-get nil "TODO") "TODO"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7" + (org-edna-action/todo! nil "DONE") + (should (string-equal (org-entry-get nil "TODO") "DONE")) + (org-edna-action/todo! nil "TODO") + (should (string-equal (org-entry-get nil "TODO") "TODO")) + (org-edna-action/todo! nil 'DONE) + (should (string-equal (org-entry-get nil "TODO") "DONE")) + (org-edna-action/todo! nil 'TODO) + (should (string-equal (org-entry-get nil "TODO") "TODO")))) ;; Scheduled (ert-deftest org-edna-action-scheduled/wkdy () - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7"))) - (unwind-protect - (org-with-point-at target - (org-edna-action/scheduled! nil "Mon") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-17 Mon>")) - (org-edna-action/scheduled! nil 'rm) - (should (not (org-entry-get nil "SCHEDULED"))) - (org-edna-action/scheduled! nil "Mon 9:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-17 Mon 09:00>")) - (org-edna-action/scheduled! nil 'rm) - (should (not (org-entry-get nil "SCHEDULED")))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7" + (org-edna-action/scheduled! nil "Mon") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-17 Mon>")) + (org-edna-action/scheduled! nil 'rm) + (should (not (org-entry-get nil "SCHEDULED"))) + (org-edna-action/scheduled! nil "Mon 9:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-17 Mon 09:00>")) + (org-edna-action/scheduled! nil 'rm) + (should (not (org-entry-get nil "SCHEDULED"))))) (ert-deftest org-edna-action-scheduled/cp () - (let* ((org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7")) - (source (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5")) - (pairs '((cp . rm) (copy . remove) ("cp" . "rm") ("copy" . "remove")))) - (unwind-protect - (org-with-point-at target - (dolist (pair pairs) - (org-edna-action/scheduled! source (car pair)) - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>")) - (org-edna-action/scheduled! source (cdr pair)) - (should (not (org-entry-get nil "SCHEDULED"))))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7" + (let* ((source (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5")) + (pairs '((cp . rm) (copy . remove) ("cp" . "rm") ("copy" . "remove")))) + (dolist (pair pairs) + (org-edna-action/scheduled! source (car pair)) + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")) + (org-edna-action/scheduled! source (cdr pair)) + (should (not (org-entry-get nil "SCHEDULED"))))))) (ert-deftest org-edna-action-scheduled/inc () - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 15, 2000 - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>")) - ;; Increment 1 minute - (org-edna-action/scheduled! nil "+1M") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:01>")) - ;; Decrement 1 minute - (org-edna-action/scheduled! nil "-1M") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>")) - ;; +1 day - (org-edna-action/scheduled! nil "+1d") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-16 Sun 00:00>")) - ;; +1 hour from current time - (org-edna-action/scheduled! nil "++1h") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 01:00>")) - ;; Back to Saturday - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>")) - ;; -1 day to Friday - (org-edna-action/scheduled! nil "-1d") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-14 Fri 00:00>")) - ;; Increment two days to the next weekday - (org-edna-action/scheduled! nil "+2wkdy") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-17 Mon 00:00>")) - ;; Increment one day, expected to land on a weekday - (org-edna-action/scheduled! nil "+1wkdy") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-18 Tue 00:00>")) - ;; Move forward 8 days, then backward until we find a weekend - (org-edna-action/scheduled! nil "+8d -wknd") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-23 Sun 00:00>")) - ;; Move forward one week, then forward until we find a weekday - ;; (org-edna-action/scheduled! nil "+1w +wkdy") - ;; (should (string-equal (org-entry-get nil "SCHEDULED") - ;; "<2000-01-31 Mon 00:00>")) - ;; Back to Saturday for other tests - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" + ;; Time starts at Jan 15, 2000 + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")) + ;; Increment 1 minute + (org-edna-action/scheduled! nil "+1M") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:01>")) + ;; Decrement 1 minute + (org-edna-action/scheduled! nil "-1M") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")) + ;; +1 day + (org-edna-action/scheduled! nil "+1d") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-16 Sun 00:00>")) + ;; +1 hour from current time + (org-edna-action/scheduled! nil "++1h") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 01:00>")) + ;; Back to Saturday + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")) + ;; -1 day to Friday + (org-edna-action/scheduled! nil "-1d") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-14 Fri 00:00>")) + ;; Increment two days to the next weekday + (org-edna-action/scheduled! nil "+2wkdy") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-17 Mon 00:00>")) + ;; Increment one day, expected to land on a weekday + (org-edna-action/scheduled! nil "+1wkdy") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-18 Tue 00:00>")) + ;; Move forward 8 days, then backward until we find a weekend + (org-edna-action/scheduled! nil "+8d -wknd") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-23 Sun 00:00>")) + ;; Move forward one week, then forward until we find a weekday + ;; (org-edna-action/scheduled! nil "+1w +wkdy") + ;; (should (string-equal (org-entry-get nil "SCHEDULED") + ;; "<2000-01-31 Mon 00:00>")) + ;; Back to Saturday for other tests + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")))) (ert-deftest org-edna-action-scheduled/landing () "Test landing arguments to scheduled increment." - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 15, 2000 - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>")) - ;; Move forward 10 days, then backward until we find a weekend - (org-edna-action/scheduled! nil "+10d -wknd") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-23 Sun 00:00>")) - ;; Move forward one week, then forward until we find a weekday - (org-edna-action/scheduled! nil "+1w +wkdy") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-31 Mon 00:00>")) - ;; Back to Saturday for other tests - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" + ;; Time starts at Jan 15, 2000 + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")) + ;; Move forward 10 days, then backward until we find a weekend + (org-edna-action/scheduled! nil "+10d -wknd") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-23 Sun 00:00>")) + ;; Move forward one week, then forward until we find a weekday + (org-edna-action/scheduled! nil "+1w +wkdy") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-31 Mon 00:00>")) + ;; Back to Saturday for other tests + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")))) (ert-deftest org-edna-action-scheduled/landing-no-hour () "Test landing arguments to scheduled increment, without hour." - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "caf27724-0887-4565-9765-ed2f1edcfb16"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 1, 2017 - (org-edna-action/scheduled! nil "2017-01-01 Sun") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2017-01-01 Sun>")) - ;; Move forward 10 days, then backward until we find a weekend - (org-edna-action/scheduled! nil "+10d -wknd") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2017-01-08 Sun>")) - ;; Move forward one week, then forward until we find a weekday - (org-edna-action/scheduled! nil "+1w +wkdy") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2017-01-16 Mon>")) - ;; Back to Saturday for other tests - (org-edna-action/scheduled! nil "2017-01-01 Sun") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2017-01-01 Sun>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "caf27724-0887-4565-9765-ed2f1edcfb16" + ;; Time starts at Jan 1, 2017 + (org-edna-action/scheduled! nil "2017-01-01 Sun") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2017-01-01 Sun>")) + ;; Move forward 10 days, then backward until we find a weekend + (org-edna-action/scheduled! nil "+10d -wknd") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2017-01-08 Sun>")) + ;; Move forward one week, then forward until we find a weekday + (org-edna-action/scheduled! nil "+1w +wkdy") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2017-01-16 Mon>")) + ;; Back to Saturday for other tests + (org-edna-action/scheduled! nil "2017-01-01 Sun") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2017-01-01 Sun>")))) (ert-deftest org-edna-action-scheduled/float () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 15, 2000 - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>")) - ;; The third Tuesday of next month (Feb 15th) - (org-edna-action/scheduled! nil "float 3 Tue") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-02-15 Tue 00:00>")) - ;; The second Friday of the following May (May 12th) - (org-edna-action/scheduled! nil "float 2 5 May") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-05-12 Fri 00:00>")) - ;; Move forward to the second Wednesday of the next month (June 14th) - (org-edna-action/scheduled! nil "float 2 Wednesday") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-06-14 Wed 00:00>")) - ;; Move forward to the first Thursday in the following Jan (Jan 4th, 2001) - (org-edna-action/scheduled! nil "float 1 4 Jan") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2001-01-04 Thu 00:00>")) - ;; The fourth Monday in Feb, 2000 (Feb 28th) - (org-edna-action/scheduled! nil "float ++4 monday") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-02-28 Mon 00:00>")) - ;; The second Monday after Mar 12th, 2000 (Mar 20th) - (org-edna-action/scheduled! nil "float 2 monday Mar 12") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-03-20 Mon 00:00>")) - ;; Back to Saturday for other tests - (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "SCHEDULED") - "<2000-01-15 Sat 00:00>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" + ;; Time starts at Jan 15, 2000 + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")) + ;; The third Tuesday of next month (Feb 15th) + (org-edna-action/scheduled! nil "float 3 Tue") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-02-15 Tue 00:00>")) + ;; The second Friday of the following May (May 12th) + (org-edna-action/scheduled! nil "float 2 5 May") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-05-12 Fri 00:00>")) + ;; Move forward to the second Wednesday of the next month (June 14th) + (org-edna-action/scheduled! nil "float 2 Wednesday") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-06-14 Wed 00:00>")) + ;; Move forward to the first Thursday in the following Jan (Jan 4th, 2001) + (org-edna-action/scheduled! nil "float 1 4 Jan") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2001-01-04 Thu 00:00>")) + ;; The fourth Monday in Feb, 2000 (Feb 28th) + (org-edna-action/scheduled! nil "float ++4 monday") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-02-28 Mon 00:00>")) + ;; The second Monday after Mar 12th, 2000 (Mar 20th) + (org-edna-action/scheduled! nil "float 2 monday Mar 12") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-03-20 Mon 00:00>")) + ;; Back to Saturday for other tests + (org-edna-action/scheduled! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "SCHEDULED") + "<2000-01-15 Sat 00:00>")))) (ert-deftest org-edna-action-deadline/wkdy () - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7"))) - (unwind-protect - (org-with-point-at target - (org-edna-action/deadline! nil "Mon") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-17 Mon>")) - (org-edna-action/deadline! nil 'rm) - (should (not (org-entry-get nil "DEADLINE"))) - (org-edna-action/deadline! nil "Mon 9:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-17 Mon 09:00>")) - (org-edna-action/deadline! nil 'rm) - (should (not (org-entry-get nil "DEADLINE")))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7" + (org-edna-action/deadline! nil "Mon") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-17 Mon>")) + (org-edna-action/deadline! nil 'rm) + (should (not (org-entry-get nil "DEADLINE"))) + (org-edna-action/deadline! nil "Mon 9:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-17 Mon 09:00>")) + (org-edna-action/deadline! nil 'rm) + (should (not (org-entry-get nil "DEADLINE"))))) (ert-deftest org-edna-action-deadline/cp () - (let* ((org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7")) - (source (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5")) - (pairs '((cp . rm) (copy . remove) ("cp" . "rm") ("copy" . "remove")))) - (unwind-protect - (org-with-point-at target - (dolist (pair pairs) - (org-edna-action/deadline! source (car pair)) - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>")) - (org-edna-action/deadline! source (cdr pair)) - (should (not (org-entry-get nil "DEADLINE"))))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "0d491588-7da3-43c5-b51a-87fbd34f79f7" + (let* ((source (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5")) + (pairs '((cp . rm) (copy . remove) ("cp" . "rm") ("copy" . "remove")))) + (dolist (pair pairs) + (org-edna-action/deadline! source (car pair)) + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")) + (org-edna-action/deadline! source (cdr pair)) + (should (not (org-entry-get nil "DEADLINE"))))))) (ert-deftest org-edna-action-deadline/inc () - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 15, 2000 - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>")) - ;; Increment 1 minute - (org-edna-action/deadline! nil "+1M") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:01>")) - ;; Decrement 1 minute - (org-edna-action/deadline! nil "-1M") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>")) - ;; +1 day - (org-edna-action/deadline! nil "+1d") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-16 Sun 00:00>")) - ;; +1 hour from current time - (org-edna-action/deadline! nil "++1h") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 01:00>")) - ;; Back to Saturday - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>")) - ;; -1 day to Friday - (org-edna-action/deadline! nil "-1d") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-14 Fri 00:00>")) - ;; Increment two days to the next weekday - (org-edna-action/deadline! nil "+2wkdy") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-17 Mon 00:00>")) - ;; Increment one day, expected to land on a weekday - (org-edna-action/deadline! nil "+1wkdy") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-18 Tue 00:00>")) - ;; Move forward 8 days, then backward until we find a weekend - (org-edna-action/deadline! nil "+8d -wknd") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-23 Sun 00:00>")) - ;; Move forward one week, then forward until we find a weekday - ;; (org-edna-action/deadline! nil "+1w +wkdy") - ;; (should (string-equal (org-entry-get nil "DEADLINE") - ;; "<2000-01-31 Mon 00:00>")) - ;; Back to Saturday for other tests - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" + ;; Time starts at Jan 15, 2000 + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")) + ;; Increment 1 minute + (org-edna-action/deadline! nil "+1M") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:01>")) + ;; Decrement 1 minute + (org-edna-action/deadline! nil "-1M") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")) + ;; +1 day + (org-edna-action/deadline! nil "+1d") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-16 Sun 00:00>")) + ;; +1 hour from current time + (org-edna-action/deadline! nil "++1h") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 01:00>")) + ;; Back to Saturday + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")) + ;; -1 day to Friday + (org-edna-action/deadline! nil "-1d") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-14 Fri 00:00>")) + ;; Increment two days to the next weekday + (org-edna-action/deadline! nil "+2wkdy") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-17 Mon 00:00>")) + ;; Increment one day, expected to land on a weekday + (org-edna-action/deadline! nil "+1wkdy") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-18 Tue 00:00>")) + ;; Move forward 8 days, then backward until we find a weekend + (org-edna-action/deadline! nil "+8d -wknd") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-23 Sun 00:00>")) + ;; Move forward one week, then forward until we find a weekday + ;; (org-edna-action/deadline! nil "+1w +wkdy") + ;; (should (string-equal (org-entry-get nil "DEADLINE") + ;; "<2000-01-31 Mon 00:00>")) + ;; Back to Saturday for other tests + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")))) (ert-deftest org-edna-action-deadline/landing () "Test landing arguments to deadline increment." - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 15, 2000 - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>")) - ;; Move forward 10 days, then backward until we find a weekend - (org-edna-action/deadline! nil "+10d -wknd") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-23 Sun 00:00>")) - ;; Move forward one week, then forward until we find a weekday - (org-edna-action/deadline! nil "+1w +wkdy") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-31 Mon 00:00>")) - ;; Back to Saturday for other tests - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" + ;; Time starts at Jan 15, 2000 + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")) + ;; Move forward 10 days, then backward until we find a weekend + (org-edna-action/deadline! nil "+10d -wknd") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-23 Sun 00:00>")) + ;; Move forward one week, then forward until we find a weekday + (org-edna-action/deadline! nil "+1w +wkdy") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-31 Mon 00:00>")) + ;; Back to Saturday for other tests + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")))) (ert-deftest org-edna-action-deadline/landing-no-hour () "Test landing arguments to deadline increment, without hour." - ;; Override `current-time' so we can get a deterministic value - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (org-agenda-files `(,org-edna-test-file)) - (inhibit-message org-edna-test-inhibit-messages) - (target (org-edna-find-test-heading "caf27724-0887-4565-9765-ed2f1edcfb16"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 1, 2017 - (org-edna-action/deadline! nil "2017-01-01 Sun") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2017-01-01 Sun>")) - ;; Move forward 10 days, then backward until we find a weekend - (org-edna-action/deadline! nil "+10d -wknd") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2017-01-08 Sun>")) - ;; Move forward one week, then forward until we find a weekday - (org-edna-action/deadline! nil "+1w +wkdy") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2017-01-16 Mon>")) - ;; Back to Saturday for other tests - (org-edna-action/deadline! nil "2017-01-01 Sun") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2017-01-01 Sun>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "caf27724-0887-4565-9765-ed2f1edcfb16" + ;; Time starts at Jan 1, 2017 + (org-edna-action/deadline! nil "2017-01-01 Sun") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2017-01-01 Sun>")) + ;; Move forward 10 days, then backward until we find a weekend + (org-edna-action/deadline! nil "+10d -wknd") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2017-01-08 Sun>")) + ;; Move forward one week, then forward until we find a weekday + (org-edna-action/deadline! nil "+1w +wkdy") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2017-01-16 Mon>")) + ;; Back to Saturday for other tests + (org-edna-action/deadline! nil "2017-01-01 Sun") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2017-01-01 Sun>")))) (ert-deftest org-edna-action-deadline/float () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (inhibit-message org-edna-test-inhibit-messages) - (org-agenda-files `(,org-edna-test-file)) - (target (org-edna-find-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5"))) - (unwind-protect - (org-with-point-at target - ;; Time starts at Jan 15, 2000 - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>")) - ;; The third Tuesday of next month (Feb 15th) - (org-edna-action/deadline! nil "float 3 Tue") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-02-15 Tue 00:00>")) - ;; The second Friday of the following May (May 12th) - (org-edna-action/deadline! nil "float 2 5 May") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-05-12 Fri 00:00>")) - ;; Move forward to the second Wednesday of the next month (June 14th) - (org-edna-action/deadline! nil "float 2 Wednesday") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-06-14 Wed 00:00>")) - ;; Move forward to the first Thursday in the following Jan (Jan 4th, 2001) - (org-edna-action/deadline! nil "float 1 4 Jan") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2001-01-04 Thu 00:00>")) - ;; The fourth Monday in Feb, 2000 (Feb 28th) - (org-edna-action/deadline! nil "float ++4 monday") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-02-28 Mon 00:00>")) - ;; The second Monday after Mar 12th, 2000 (Mar 20th) - (org-edna-action/deadline! nil "float 2 monday Mar 12") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-03-20 Mon 00:00>")) - ;; Back to Saturday for other tests - (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") - (should (string-equal (org-entry-get nil "DEADLINE") - "<2000-01-15 Sat 00:00>"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading "97e6b0f0-40c4-464f-b760-6e5ca9744eb5" + ;; Time starts at Jan 15, 2000 + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")) + ;; The third Tuesday of next month (Feb 15th) + (org-edna-action/deadline! nil "float 3 Tue") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-02-15 Tue 00:00>")) + ;; The second Friday of the following May (May 12th) + (org-edna-action/deadline! nil "float 2 5 May") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-05-12 Fri 00:00>")) + ;; Move forward to the second Wednesday of the next month (June 14th) + (org-edna-action/deadline! nil "float 2 Wednesday") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-06-14 Wed 00:00>")) + ;; Move forward to the first Thursday in the following Jan (Jan 4th, 2001) + (org-edna-action/deadline! nil "float 1 4 Jan") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2001-01-04 Thu 00:00>")) + ;; The fourth Monday in Feb, 2000 (Feb 28th) + (org-edna-action/deadline! nil "float ++4 monday") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-02-28 Mon 00:00>")) + ;; The second Monday after Mar 12th, 2000 (Mar 20th) + (org-edna-action/deadline! nil "float 2 monday Mar 12") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-03-20 Mon 00:00>")) + ;; Back to Saturday for other tests + (org-edna-action/deadline! nil "2000-01-15 Sat 00:00") + (should (string-equal (org-entry-get nil "DEADLINE") + "<2000-01-15 Sat 00:00>")))) (ert-deftest org-edna-action-tag () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/tag! nil "tag") - (should (equal (org-get-tags) '("tag"))) - (org-edna-action/tag! nil "") - (should (equal (org-get-tags) '("")))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (org-edna-action/tag! nil "tag") + (should (equal (org-get-tags) '("tag"))) + (org-edna-action/tag! nil "") + (should (equal (org-get-tags) '(""))))) (ert-deftest org-edna-action-property () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/set-property! nil "TEST" "1") - (should (equal (org-entry-get nil "TEST") "1")) - (org-edna-action/delete-property! nil "TEST") - (should-not (org-entry-get nil "TEST"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (org-edna-action/set-property! nil "TEST" "1") + (should (equal (org-entry-get nil "TEST") "1")) + (org-edna-action/delete-property! nil "TEST") + (should-not (org-entry-get nil "TEST")))) (ert-deftest org-edna-action-property/inc-dec () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/set-property! nil "TEST" "1") - (should (equal (org-entry-get nil "TEST") "1")) - (org-edna-action/set-property! nil "TEST" 'inc) - (should (equal (org-entry-get nil "TEST") "2")) - (org-edna-action/set-property! nil "TEST" 'dec) - (should (equal (org-entry-get nil "TEST") "1")) - (org-edna-action/delete-property! nil "TEST") - (should-not (org-entry-get nil "TEST")) - (should-error (org-edna-action/set-property! nil "TEST" 'inc)) - (should-error (org-edna-action/set-property! nil "TEST" 'dec)) - (org-edna-action/set-property! nil "TEST" "a") - (should (equal (org-entry-get nil "TEST") "a")) - (should-error (org-edna-action/set-property! nil "TEST" 'inc)) - (should-error (org-edna-action/set-property! nil "TEST" 'dec)) - (org-edna-action/delete-property! nil "TEST") - (should-not (org-entry-get nil "TEST"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (org-edna-action/set-property! nil "TEST" "1") + (should (equal (org-entry-get nil "TEST") "1")) + (org-edna-action/set-property! nil "TEST" 'inc) + (should (equal (org-entry-get nil "TEST") "2")) + (org-edna-action/set-property! nil "TEST" 'dec) + (should (equal (org-entry-get nil "TEST") "1")) + (org-edna-action/delete-property! nil "TEST") + (should-not (org-entry-get nil "TEST")) + (should-error (org-edna-action/set-property! nil "TEST" 'inc)) + (should-error (org-edna-action/set-property! nil "TEST" 'dec)) + (org-edna-action/set-property! nil "TEST" "a") + (should (equal (org-entry-get nil "TEST") "a")) + (should-error (org-edna-action/set-property! nil "TEST" 'inc)) + (should-error (org-edna-action/set-property! nil "TEST" 'dec)) + (org-edna-action/delete-property! nil "TEST") + (should-not (org-entry-get nil "TEST")))) (ert-deftest org-edna-action-property/next-prev () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/set-property! nil "TEST" "a") - (should (equal (org-entry-get nil "TEST") "a")) - (should-error (org-edna-action/set-property! nil "TEST" 'next)) - (should-error (org-edna-action/set-property! nil "TEST" 'prev)) - (should-error (org-edna-action/set-property! nil "TEST" 'previous)) - (org-edna-action/delete-property! nil "TEST") - (should-not (org-entry-get nil "TEST")) - ;; Test moving forwards - (org-edna-action/set-property! nil "COUNTER" "a") - (should (equal (org-entry-get nil "COUNTER") "a")) - (org-edna-action/set-property! nil "COUNTER" 'next) - (should (equal (org-entry-get nil "COUNTER") "b")) - ;; Test moving forwards past the last one - (org-edna-action/set-property! nil "COUNTER" "d") - (should (equal (org-entry-get nil "COUNTER") "d")) - (org-edna-action/set-property! nil "COUNTER" 'next) - (should (equal (org-entry-get nil "COUNTER") "a")) - ;; Test moving backwards past the first one - (org-edna-action/set-property! nil "COUNTER" 'prev) - (should (equal (org-entry-get nil "COUNTER") "d")) - ;; Test moving backwards normally - (org-edna-action/set-property! nil "COUNTER" 'previous) - (should (equal (org-entry-get nil "COUNTER") "c")) - (org-edna-action/delete-property! nil "COUNTER") - (should-not (org-entry-get nil "COUNTER"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (org-edna-action/set-property! nil "TEST" "a") + (should (equal (org-entry-get nil "TEST") "a")) + (should-error (org-edna-action/set-property! nil "TEST" 'next)) + (should-error (org-edna-action/set-property! nil "TEST" 'prev)) + (should-error (org-edna-action/set-property! nil "TEST" 'previous)) + (org-edna-action/delete-property! nil "TEST") + (should-not (org-entry-get nil "TEST")) + ;; Test moving forwards + (org-edna-action/set-property! nil "COUNTER" "a") + (should (equal (org-entry-get nil "COUNTER") "a")) + (org-edna-action/set-property! nil "COUNTER" 'next) + (should (equal (org-entry-get nil "COUNTER") "b")) + ;; Test moving forwards past the last one + (org-edna-action/set-property! nil "COUNTER" "d") + (should (equal (org-entry-get nil "COUNTER") "d")) + (org-edna-action/set-property! nil "COUNTER" 'next) + (should (equal (org-entry-get nil "COUNTER") "a")) + ;; Test moving backwards past the first one + (org-edna-action/set-property! nil "COUNTER" 'prev) + (should (equal (org-entry-get nil "COUNTER") "d")) + ;; Test moving backwards normally + (org-edna-action/set-property! nil "COUNTER" 'previous) + (should (equal (org-entry-get nil "COUNTER") "c")) + (org-edna-action/delete-property! nil "COUNTER") + (should-not (org-entry-get nil "COUNTER")))) (ert-deftest org-edna-action-clock () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/clock-in! nil) - (should (org-clocking-p)) - (should (equal org-clock-hd-marker pom)) - (org-edna-action/clock-out! nil) - (should-not (org-clocking-p))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (org-edna-action/clock-in! nil) + (should (org-clocking-p)) + (should (equal org-clock-hd-marker (point-marker))) + (org-edna-action/clock-out! nil) + (should-not (org-clocking-p)))) (ert-deftest org-edna-action-priority () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages) - (org-lowest-priority ?C) - (org-highest-priority ?A) - (org-default-priority ?B)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/set-priority! nil "A") - (should (equal (org-entry-get nil "PRIORITY") "A")) - (org-edna-action/set-priority! nil 'down) - (should (equal (org-entry-get nil "PRIORITY") "B")) - (org-edna-action/set-priority! nil 'up) - (should (equal (org-entry-get nil "PRIORITY") "A")) - (org-edna-action/set-priority! nil ?C) - (should (equal (org-entry-get nil "PRIORITY") "C")) - (org-edna-action/set-priority! nil 'remove) - (should (equal (org-entry-get nil "PRIORITY") "B"))) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (let ((org-lowest-priority ?C) + (org-highest-priority ?A) + (org-default-priority ?B)) + (org-edna-action/set-priority! nil "A") + (should (equal (org-entry-get nil "PRIORITY") "A")) + (org-edna-action/set-priority! nil 'down) + (should (equal (org-entry-get nil "PRIORITY") "B")) + (org-edna-action/set-priority! nil 'up) + (should (equal (org-entry-get nil "PRIORITY") "A")) + (org-edna-action/set-priority! nil ?C) + (should (equal (org-entry-get nil "PRIORITY") "C")) + (org-edna-action/set-priority! nil 'remove) + (should (equal (org-entry-get nil "PRIORITY") "B"))))) (ert-deftest org-edna-action-effort () - (let ((pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/set-effort! nil "0:01") - (should (equal (org-entry-get nil "EFFORT") "0:01")) - (org-edna-action/set-effort! nil 'increment) - (should (equal (org-entry-get nil "EFFORT") "0:02")) - (org-entry-delete nil "EFFORT")) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-id-heading-one + (org-edna-action/set-effort! nil "0:01") + (should (equal (org-entry-get nil "EFFORT") "0:01")) + (org-edna-action/set-effort! nil 'increment) + (should (equal (org-entry-get nil "EFFORT") "0:02")) + (org-entry-delete nil "EFFORT"))) (ert-deftest org-edna-action-archive () - (let* ((inhibit-message org-edna-test-inhibit-messages) - (org-archive-save-context-info '(todo)) - (pom (org-edna-find-test-heading org-edna-test-archive-heading)) - ;; Archive it to the same location - (org-archive-location "::** Archive") - (org-edna-prompt-for-archive nil)) - (unwind-protect - (org-with-point-at pom - (org-edna-action/archive! nil) - (should (equal (org-entry-get nil "ARCHIVE_TODO") "TODO")) - (org-entry-delete nil "ARCHIVE_TODO")) - (org-edna-test-restore-test-file)))) + (org-edna-with-test-heading org-edna-test-archive-heading + (let* ((org-archive-save-context-info '(todo)) + ;; Archive it to the same location + (org-archive-location "::** Archive") + ;; We're non-interactive, so no prompt. + (org-edna-prompt-for-archive nil)) + (org-edna-action/archive! nil) + (should (equal (org-entry-get nil "ARCHIVE_TODO") "TODO")) + (org-entry-delete nil "ARCHIVE_TODO")))) (ert-deftest org-edna-action-chain () - (let ((inhibit-message org-edna-test-inhibit-messages) - (old-pom (org-edna-find-test-heading org-edna-test-id-heading-one)) - (new-pom (org-edna-find-test-heading org-edna-test-id-heading-two))) - (unwind-protect - (progn - (org-entry-put old-pom "TEST" "1") - (org-with-point-at new-pom - (org-edna-action/chain! old-pom "TEST") - (should (equal (org-entry-get nil "TEST") "1"))) - (org-entry-delete old-pom "TEST") - (org-entry-delete new-pom "TEST")) - (org-edna-test-restore-test-file)))) + (org-edna-test-setup + (let ((old-pom (org-edna-find-test-heading org-edna-test-id-heading-one)) + (new-pom (org-edna-find-test-heading org-edna-test-id-heading-two))) + (org-edna-protect-test-file + (org-entry-put old-pom "TEST" "1") + (org-with-point-at new-pom + (org-edna-action/chain! old-pom "TEST") + (should (equal (org-entry-get nil "TEST") "1"))) + (org-entry-delete old-pom "TEST") + (org-entry-delete new-pom "TEST"))))) -;; Conditions +;;; Conditions (defun org-edna-test-condition-form (func-sym pom-true pom-false block-true block-false &rest args) - (let* ((inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at pom-true - (should-not (apply func-sym t args)) - (should (equal (apply func-sym nil args) block-true))) - (org-with-point-at pom-false - (should (equal (apply func-sym t args) block-false)) - (should-not (apply func-sym nil args))))) + (org-edna-test-setup + (let* ((block-true (or block-true (org-with-point-at pom-true (org-get-heading)))) + (block-false (or block-false (org-with-point-at pom-false (org-get-heading))))) + (org-with-point-at pom-true + (should-not (apply func-sym t args)) + (should (equal (apply func-sym nil args) block-true))) + (org-with-point-at pom-false + (should (equal (apply func-sym t args) block-false)) + (should-not (apply func-sym nil args)))))) (ert-deftest org-edna-condition-done () (let* ((pom-done (org-edna-find-test-heading org-edna-test-id-heading-four)) @@ -1817,8 +1748,32 @@ This avoids org-id digging into its internal database." block-true block-false string))) +(ert-deftest org-edna-condition/has-tags () + (let* ((pom-true (org-edna-find-test-heading "0fa0d4dd-40f2-4251-a558-4c6e2898c2df")) + (pom-false (org-edna-find-test-heading org-edna-test-id-heading-one)) + (block-true (org-with-point-at pom-true (org-get-heading))) + (block-false (org-with-point-at pom-false (org-get-heading)))) + (org-edna-test-condition-form 'org-edna-condition/has-tags? + pom-true pom-false + block-true block-false + "test"))) + +(ert-deftest org-edna-condition/matches-tags () + (org-edna-test-condition-form + 'org-edna-condition/matches? + (org-edna-find-test-heading "0fa0d4dd-40f2-4251-a558-4c6e2898c2df") + (org-edna-find-test-heading org-edna-test-id-heading-one) + nil nil + "1&test") + (org-edna-test-condition-form + 'org-edna-condition/matches? + (org-edna-find-test-heading org-edna-test-id-heading-four) + (org-edna-find-test-heading "0fa0d4dd-40f2-4251-a558-4c6e2898c2df") + nil nil + "TODO==\"DONE\"")) + -;; Consideration +;;; Consideration (ert-deftest org-edna-consideration/any () (let ((blocks-all-blocking `("a" "c" "b")) @@ -1855,587 +1810,382 @@ This avoids org-id digging into its internal database." ;;; Full Run-through Tests from the Documentation +(defmacro org-edna-doc-test-setup (heading-id &rest body) + (declare (indent 1)) + `(org-edna-with-test-heading ,heading-id + (save-restriction + ;; Only allow operating on the current tree + (org-narrow-to-subtree) + ;; Show the entire subtree + (outline-show-all) + ,@body))) + (ert-deftest org-edna-doc-test/ancestors () - (let* ((start-heading (org-edna-find-test-heading "24a0c3bb-7e69-4e9e-bb98-5aba2ff17bb1")) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (let* ((heading1-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading2-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading3-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading4-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading5-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify that we can't change the TODO state to DONE - (should (org-edna-test-check-block heading5-pom "Initial state of heading 5")) - ;; Change the state at 4 to DONE - (org-edna-test-change-todo-state heading4-pom "DONE") - ;; Verify that ALL ancestors need to be changed - (should (org-edna-test-check-block heading5-pom "Heading 5 after parent changed")) - (org-edna-test-mark-done heading1-pom heading3-pom) - ;; Only need 1, 3, and 4 to change 5 - (should (not (org-edna-test-check-block heading5-pom - "Heading 5 after all parents changed"))) - ;; Change the state back to TODO on all of them - (org-edna-test-mark-todo heading1-pom heading3-pom heading4-pom heading5-pom)))) - (org-edna-test-restore-test-file)))) + (org-edna-doc-test-setup "24a0c3bb-7e69-4e9e-bb98-5aba2ff17bb1" + (pcase-let* ((`(,heading1-pom ,heading2-pom ,heading3-pom ,heading4-pom ,heading5-pom) + (org-edna-test-children-marks))) + ;; Verify that we can't change the TODO state to DONE + (should (org-edna-test-check-block heading5-pom "Initial state of heading 5")) + ;; Change the state at 4 to DONE + (org-edna-test-mark-done heading4-pom) + ;; Verify that ALL ancestors need to be changed + (should (org-edna-test-check-block heading5-pom "Heading 5 after parent changed")) + (org-edna-test-mark-done heading1-pom heading3-pom) + ;; Only need 1, 3, and 4 to change 5 + (should (not (org-edna-test-check-block heading5-pom + "Heading 5 after all parents changed"))) + ;; Change the state back to TODO on all of them + (org-edna-test-mark-todo heading1-pom heading3-pom heading4-pom heading5-pom)))) (ert-deftest org-edna-doc-test/ancestors-cache () - (let* ((start-heading (org-edna-find-test-heading "24a0c3bb-7e69-4e9e-bb98-5aba2ff17bb1")) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Enable cache - (org-edna-finder-use-cache t) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (let* ((heading1-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading2-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading3-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading4-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading5-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify that we can't change the TODO state to DONE - (should (org-edna-test-check-block heading5-pom "Initial state of heading 5")) - ;; Change the state at 4 to DONE - (org-edna-test-change-todo-state heading4-pom "DONE") - ;; Verify that ALL ancestors need to be changed - (should (org-edna-test-check-block heading5-pom "Heading 5 after parent changed")) - (org-edna-test-mark-done heading1-pom heading3-pom) - ;; Only need 1, 3, and 4 to change 5 - (should (not (org-edna-test-check-block heading5-pom - "Heading 5 after all parents changed"))) - ;; Change the state back to TODO on all of them - (org-edna-test-mark-todo heading1-pom heading3-pom heading4-pom heading5-pom)))) - (org-edna-test-restore-test-file)))) + (let ((org-edna-finder-use-cache t)) + (org-edna-doc-test-setup "24a0c3bb-7e69-4e9e-bb98-5aba2ff17bb1" + (pcase-let* ((`(,heading1-pom ,heading2-pom ,heading3-pom ,heading4-pom ,heading5-pom) + (org-edna-test-children-marks))) + ;; Verify that we can't change the TODO state to DONE + (should (org-edna-test-check-block heading5-pom "Initial state of heading 5")) + ;; Change the state at 4 to DONE + (org-edna-test-mark-done heading4-pom) + ;; Verify that ALL ancestors need to be changed + (should (org-edna-test-check-block heading5-pom "Heading 5 after parent changed")) + (org-edna-test-mark-done heading1-pom heading3-pom) + ;; Only need 1, 3, and 4 to change 5 + (should (not (org-edna-test-check-block heading5-pom + "Heading 5 after all parents changed"))) + ;; Change the state back to TODO on all of them + (org-edna-test-mark-todo heading1-pom heading3-pom heading4-pom heading5-pom))))) (ert-deftest org-edna-doc-test/descendants () - (let* ((start-heading (org-edna-find-test-heading "cc18dc74-00e8-4081-b46f-e36800041fe7")) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (let* ((heading1-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading2-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading3-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading4-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading5-pom (progn (org-next-visible-heading 1) (point-marker)))) - (should (org-edna-test-check-block heading1-pom "Heading 1 initial state")) - ;; Change the state at 2 to DONE - (org-edna-test-mark-done heading2-pom) - ;; Verify that ALL descendants need to be changed - (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 2")) - ;; Try 3 - (org-edna-test-mark-done heading3-pom) - ;; Verify that ALL descendants need to be changed - (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 3")) - ;; Try 4 - (org-edna-test-mark-done heading4-pom) - ;; Verify that ALL descendants need to be changed - (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 4")) - ;; Try 5 - (org-edna-test-mark-done heading5-pom) - ;; Verify that ALL descendants need to be changed - (should (not (org-edna-test-check-block heading1-pom "Heading 1 after changing 5")))))) - (org-edna-test-restore-test-file)))) + (org-edna-doc-test-setup "cc18dc74-00e8-4081-b46f-e36800041fe7" + (pcase-let* ((`(,heading1-pom ,heading2-pom ,heading3-pom ,heading4-pom ,heading5-pom) + (org-edna-test-children-marks))) + (should (org-edna-test-check-block heading1-pom "Heading 1 initial state")) + ;; Change the state at 2 to DONE + (org-edna-test-mark-done heading2-pom) + ;; Verify that ALL descendants need to be changed + (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 2")) + ;; Try 3 + (org-edna-test-mark-done heading3-pom) + ;; Verify that ALL descendants need to be changed + (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 3")) + ;; Try 4 + (org-edna-test-mark-done heading4-pom) + ;; Verify that ALL descendants need to be changed + (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 4")) + ;; Try 5 + (org-edna-test-mark-done heading5-pom) + ;; Verify that ALL descendants need to be changed + (should (not (org-edna-test-check-block heading1-pom "Heading 1 after changing 5")))))) (ert-deftest org-edna-doc-test/descendants-cache () - (let* ((start-heading (org-edna-find-test-heading "cc18dc74-00e8-4081-b46f-e36800041fe7")) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Enable cache - (org-edna-finder-use-cache t) - (inhibit-message org-edna-test-inhibit-messages)) - (unwind-protect - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (let* ((heading1-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading2-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading3-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading4-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading5-pom (progn (org-next-visible-heading 1) (point-marker)))) - (should (org-edna-test-check-block heading1-pom "Heading 1 initial state")) - ;; Change the state at 2 to DONE - (org-edna-test-mark-done heading2-pom) - ;; Verify that ALL descendants need to be changed - (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 2")) - ;; Try 3 - (org-edna-test-mark-done heading3-pom) - ;; Verify that ALL descendants need to be changed - (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 3")) - ;; Try 4 - (org-edna-test-mark-done heading4-pom) - ;; Verify that ALL descendants need to be changed - (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 4")) - ;; Try 5 - (org-edna-test-mark-done heading5-pom) - ;; Verify that ALL descendants need to be changed - (should (not (org-edna-test-check-block heading1-pom "Heading 1 after changing 5")))))) - (org-edna-test-restore-test-file)))) + (let ((org-edna-finder-use-cache t)) + (org-edna-doc-test-setup "cc18dc74-00e8-4081-b46f-e36800041fe7" + (pcase-let* ((`(,heading1-pom ,heading2-pom ,heading3-pom ,heading4-pom ,heading5-pom) + (org-edna-test-children-marks))) + (should (org-edna-test-check-block heading1-pom "Heading 1 initial state")) + ;; Change the state at 2 to DONE + (org-edna-test-mark-done heading2-pom) + ;; Verify that ALL descendants need to be changed + (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 2")) + ;; Try 3 + (org-edna-test-mark-done heading3-pom) + ;; Verify that ALL descendants need to be changed + (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 3")) + ;; Try 4 + (org-edna-test-mark-done heading4-pom) + ;; Verify that ALL descendants need to be changed + (should (org-edna-test-check-block heading1-pom "Heading 1 after changing 4")) + ;; Try 5 + (org-edna-test-mark-done heading5-pom) + ;; Verify that ALL descendants need to be changed + (should (not (org-edna-test-check-block heading1-pom "Heading 1 after changing 5"))))))) (ert-deftest org-edna-doc-test/laundry () "Test for the \"laundry\" example in the documentation." - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "e57ce099-9f37-47f4-a6bb-61a84eb1fbbe")) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((heading1-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading2-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading3-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading4-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify that headings 2, 3, and 4 are all blocked - (should (org-edna-test-check-block heading2-pom - "Initial attempt to change heading 2")) - (should (org-edna-test-check-block heading3-pom - "Initial attempt to change heading 3")) - (should (org-edna-test-check-block heading4-pom - "Initial attempt to change heading 4")) - ;; Mark heading 1 as DONE - (should (not (org-edna-test-check-block heading1-pom - "Set heading 1 to DONE"))) - ;; Only heading 2 should have a scheduled time - (should (string-equal (org-entry-get heading2-pom "SCHEDULED") - "<2000-01-15 Sat 01:00>")) - (should (not (org-entry-get heading3-pom "SCHEDULED"))) - (should (not (org-entry-get heading4-pom "SCHEDULED"))) - ;; The others should still be blocked. - (should (org-edna-test-check-block heading3-pom - "Second attempt to change heading 3")) - (should (org-edna-test-check-block heading4-pom - "Second attempt to change heading 4")) - ;; Try changing heading 2 - (should (not (org-edna-test-check-block heading2-pom - "Set heading 2 to DONE"))) - (should (string-equal (org-entry-get heading3-pom "SCHEDULED") - "<2000-01-16 Sun 09:00>")) - ;; 4 should still be blocked - (should (org-edna-test-check-block heading4-pom - "Second attempt to change heading 4"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "e57ce099-9f37-47f4-a6bb-61a84eb1fbbe" + (pcase-let* ((`(,heading1-pom ,heading2-pom ,heading3-pom ,heading4-pom) + (org-edna-test-children-marks))) + ;; Verify that headings 2, 3, and 4 are all blocked + (should (org-edna-test-check-block heading2-pom + "Initial attempt to change heading 2")) + (should (org-edna-test-check-block heading3-pom + "Initial attempt to change heading 3")) + (should (org-edna-test-check-block heading4-pom + "Initial attempt to change heading 4")) + ;; Mark heading 1 as DONE + (should (not (org-edna-test-check-block heading1-pom + "Set heading 1 to DONE"))) + ;; Only heading 2 should have a scheduled time + (should (string-equal (org-entry-get heading2-pom "SCHEDULED") + "<2000-01-15 Sat 01:00>")) + (should (not (org-entry-get heading3-pom "SCHEDULED"))) + (should (not (org-entry-get heading4-pom "SCHEDULED"))) + ;; The others should still be blocked. + (should (org-edna-test-check-block heading3-pom + "Second attempt to change heading 3")) + (should (org-edna-test-check-block heading4-pom + "Second attempt to change heading 4")) + ;; Try changing heading 2 + (should (not (org-edna-test-check-block heading2-pom + "Set heading 2 to DONE"))) + (should (string-equal (org-entry-get heading3-pom "SCHEDULED") + "<2000-01-16 Sun 09:00>")) + ;; 4 should still be blocked + (should (org-edna-test-check-block heading4-pom + "Second attempt to change heading 4"))))) (ert-deftest org-edna-doc-test/laundry-cache () "Test for the \"laundry\" example in the documentation. This version enables cache, ensuring that the repeated calls to the relative finders all still work while cache is enabled." - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "e57ce099-9f37-47f4-a6bb-61a84eb1fbbe")) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - ;; Enable cache - (org-edna-finder-use-cache t) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((heading1-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading2-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading3-pom (progn (org-next-visible-heading 1) (point-marker))) - (heading4-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify that headings 2, 3, and 4 are all blocked - (should (org-edna-test-check-block heading2-pom - "Initial attempt to change heading 2")) - (should (org-edna-test-check-block heading3-pom - "Initial attempt to change heading 3")) - (should (org-edna-test-check-block heading4-pom - "Initial attempt to change heading 4")) - ;; Mark heading 1 as DONE - (should (not (org-edna-test-check-block heading1-pom - "Set heading 1 to DONE"))) - ;; Only heading 2 should have a scheduled time - (should (string-equal (org-entry-get heading2-pom "SCHEDULED") - "<2000-01-15 Sat 01:00>")) - (should (not (org-entry-get heading3-pom "SCHEDULED"))) - (should (not (org-entry-get heading4-pom "SCHEDULED"))) - ;; The others should still be blocked. - (should (org-edna-test-check-block heading3-pom - "Second attempt to change heading 3")) - (should (org-edna-test-check-block heading4-pom - "Second attempt to change heading 4")) - ;; Try changing heading 2 - (should (not (org-edna-test-check-block heading2-pom - "Set heading 2 to DONE"))) - (should (string-equal (org-entry-get heading3-pom "SCHEDULED") - "<2000-01-16 Sun 09:00>")) - ;; 4 should still be blocked - (should (org-edna-test-check-block heading4-pom - "Second attempt to change heading 4"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (let ((org-edna-finder-use-cache t)) + (org-edna-doc-test-setup "e57ce099-9f37-47f4-a6bb-61a84eb1fbbe" + (pcase-let* ((`(,heading1-pom ,heading2-pom ,heading3-pom ,heading4-pom) + (org-edna-test-children-marks))) + ;; Verify that headings 2, 3, and 4 are all blocked + (should (org-edna-test-check-block heading2-pom + "Initial attempt to change heading 2")) + (should (org-edna-test-check-block heading3-pom + "Initial attempt to change heading 3")) + (should (org-edna-test-check-block heading4-pom + "Initial attempt to change heading 4")) + ;; Mark heading 1 as DONE + (should (not (org-edna-test-check-block heading1-pom + "Set heading 1 to DONE"))) + ;; Only heading 2 should have a scheduled time + (should (string-equal (org-entry-get heading2-pom "SCHEDULED") + "<2000-01-15 Sat 01:00>")) + (should (not (org-entry-get heading3-pom "SCHEDULED"))) + (should (not (org-entry-get heading4-pom "SCHEDULED"))) + ;; The others should still be blocked. + (should (org-edna-test-check-block heading3-pom + "Second attempt to change heading 3")) + (should (org-edna-test-check-block heading4-pom + "Second attempt to change heading 4")) + ;; Try changing heading 2 + (should (not (org-edna-test-check-block heading2-pom + "Set heading 2 to DONE"))) + (should (string-equal (org-entry-get heading3-pom "SCHEDULED") + "<2000-01-16 Sun 09:00>")) + ;; 4 should still be blocked + (should (org-edna-test-check-block heading4-pom + "Second attempt to change heading 4")))))) (ert-deftest org-edna-doc-test/nightly () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "8b6d9820-d943-4622-85c9-4a346e033453")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((nightly-pom (progn (org-next-visible-heading 1) (point-marker))) - (lunch-pom (progn (org-next-visible-heading 1) (point-marker))) - (door-pom (progn (org-next-visible-heading 1) (point-marker))) - (dog-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify that Nightly is blocked - (should (org-edna-test-check-block nightly-pom "Initial Nightly Check")) - ;; Check off Lunch, and verify that nightly is still blocked - (org-edna-test-mark-done lunch-pom) - (should (org-edna-test-check-block nightly-pom "Nightly after Lunch")) - ;; Check off Door, and verify that nightly is still blocked - (org-edna-test-mark-done door-pom) - (should (org-edna-test-check-block nightly-pom "Nightly after Door")) - ;; Check off Dog. This should trigger the others. - (org-edna-test-mark-done dog-pom) - (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Nightly Trigger")) - (should (org-edna-test-compare-todos door-pom "TODO" "Door after Nightly Trigger")) - (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Nightly Trigger")) - (should (string-equal (org-entry-get nightly-pom "DEADLINE") - "<2000-01-16 Sun +1d>"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "8b6d9820-d943-4622-85c9-4a346e033453" + (pcase-let* ((`(,nightly-pom ,lunch-pom ,door-pom ,dog-pom) + (org-edna-test-children-marks))) + ;; Verify that Nightly is blocked + (should (org-edna-test-check-block nightly-pom "Initial Nightly Check")) + ;; Check off Lunch, and verify that nightly is still blocked + (org-edna-test-mark-done lunch-pom) + (should (org-edna-test-check-block nightly-pom "Nightly after Lunch")) + ;; Check off Door, and verify that nightly is still blocked + (org-edna-test-mark-done door-pom) + (should (org-edna-test-check-block nightly-pom "Nightly after Door")) + ;; Check off Dog. This should trigger the others. + (org-edna-test-mark-done dog-pom) + (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Nightly Trigger")) + (should (org-edna-test-compare-todos door-pom "TODO" "Door after Nightly Trigger")) + (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Nightly Trigger")) + (should (string-equal (org-entry-get nightly-pom "DEADLINE") + "<2000-01-16 Sun +1d>"))))) (ert-deftest org-edna-doc-test/nightly-cache () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "8b6d9820-d943-4622-85c9-4a346e033453")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - ;; Enable cache - (org-edna-finder-use-cache t) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((nightly-pom (progn (org-next-visible-heading 1) (point-marker))) - (lunch-pom (progn (org-next-visible-heading 1) (point-marker))) - (door-pom (progn (org-next-visible-heading 1) (point-marker))) - (dog-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify that Nightly is blocked - (should (org-edna-test-check-block nightly-pom "Initial Nightly Check")) - ;; Check off Lunch, and verify that nightly is still blocked - (org-edna-test-mark-done lunch-pom) - (should (org-edna-test-check-block nightly-pom "Nightly after Lunch")) - ;; Check off Door, and verify that nightly is still blocked - (org-edna-test-mark-done door-pom) - (should (org-edna-test-check-block nightly-pom "Nightly after Door")) - ;; Check off Dog. This should trigger the others. - (org-edna-test-mark-done dog-pom) - (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Nightly Trigger")) - (should (org-edna-test-compare-todos door-pom "TODO" "Door after Nightly Trigger")) - (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Nightly Trigger")) - (should (string-equal (org-entry-get nightly-pom "DEADLINE") - "<2000-01-16 Sun +1d>"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (let ((org-edna-finder-use-cache t)) + (org-edna-doc-test-setup "8b6d9820-d943-4622-85c9-4a346e033453" + (pcase-let* ((`(,nightly-pom ,lunch-pom ,door-pom ,dog-pom) + (org-edna-test-children-marks))) + ;; Verify that Nightly is blocked + (should (org-edna-test-check-block nightly-pom "Initial Nightly Check")) + ;; Check off Lunch, and verify that nightly is still blocked + (org-edna-test-mark-done lunch-pom) + (should (org-edna-test-check-block nightly-pom "Nightly after Lunch")) + ;; Check off Door, and verify that nightly is still blocked + (org-edna-test-mark-done door-pom) + (should (org-edna-test-check-block nightly-pom "Nightly after Door")) + ;; Check off Dog. This should trigger the others. + (org-edna-test-mark-done dog-pom) + (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Nightly Trigger")) + (should (org-edna-test-compare-todos door-pom "TODO" "Door after Nightly Trigger")) + (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Nightly Trigger")) + (should (string-equal (org-entry-get nightly-pom "DEADLINE") + "<2000-01-16 Sun +1d>")))))) (ert-deftest org-edna-doc-test/daily () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "630805bb-a864-4cdc-9a6f-0f126e887c66")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((daily-pom (progn (org-next-visible-heading 1) (point-marker))) - (lunch-pom (progn (org-next-visible-heading 1) (point-marker))) - (door-pom (progn (org-next-visible-heading 1) (point-marker))) - (dog-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Check off Lunch. This should trigger the others. - (org-edna-test-mark-done lunch-pom) - (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Daily Trigger")) - (should (org-edna-test-compare-todos door-pom "TODO" "Door after Daily Trigger")) - (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Daily Trigger")) - (should (string-equal (org-entry-get daily-pom "DEADLINE") - "<2000-01-16 Sun +1d>")) - ;; Check off Door. This should trigger the others. - (org-edna-test-mark-done door-pom) - (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Door Trigger")) - (should (org-edna-test-compare-todos door-pom "TODO" "Door after Door Trigger")) - (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Door Trigger")) - (should (string-equal (org-entry-get daily-pom "DEADLINE") - "<2000-01-17 Mon +1d>")) - ;; Check off Dog. This should trigger the others. - (org-edna-test-mark-done dog-pom) - (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Dog Trigger")) - (should (org-edna-test-compare-todos door-pom "TODO" "Door after Dog Trigger")) - (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Dog Trigger")) - (should (string-equal (org-entry-get daily-pom "DEADLINE") - "<2000-01-18 Tue +1d>"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "630805bb-a864-4cdc-9a6f-0f126e887c66" + (pcase-let* ((`(,daily-pom ,lunch-pom ,door-pom ,dog-pom) + (org-edna-test-children-marks))) + ;; Check off Lunch. This should trigger the others. + (org-edna-test-mark-done lunch-pom) + (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Daily Trigger")) + (should (org-edna-test-compare-todos door-pom "TODO" "Door after Daily Trigger")) + (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Daily Trigger")) + (should (string-equal (org-entry-get daily-pom "DEADLINE") + "<2000-01-16 Sun +1d>")) + ;; Check off Door. This should trigger the others. + (org-edna-test-mark-done door-pom) + (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Door Trigger")) + (should (org-edna-test-compare-todos door-pom "TODO" "Door after Door Trigger")) + (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Door Trigger")) + (should (string-equal (org-entry-get daily-pom "DEADLINE") + "<2000-01-17 Mon +1d>")) + ;; Check off Dog. This should trigger the others. + (org-edna-test-mark-done dog-pom) + (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Dog Trigger")) + (should (org-edna-test-compare-todos door-pom "TODO" "Door after Dog Trigger")) + (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Dog Trigger")) + (should (string-equal (org-entry-get daily-pom "DEADLINE") + "<2000-01-18 Tue +1d>"))))) (ert-deftest org-edna-doc-test/weekly () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "cf529a5e-1b0c-40c3-8f85-fe2fc4df0ffd")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((weekly-pom (progn (org-next-visible-heading 1) (point-marker))) - (lunch-pom (progn (org-next-visible-heading 1) (point-marker))) - (door-pom (progn (org-next-visible-heading 1) (point-marker))) - (dog-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Check off Lunch. This should trigger the others. - (org-edna-test-mark-done lunch-pom) - (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Weekly Trigger")) - (should (org-edna-test-compare-todos door-pom "TODO" "Door after Weekly Trigger")) - (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Weekly Trigger")) - (should (string-equal (org-entry-get weekly-pom "DEADLINE") - "<2000-01-16 Sun +1d>"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "cf529a5e-1b0c-40c3-8f85-fe2fc4df0ffd" + (pcase-let* ((`(,weekly-pom ,lunch-pom ,door-pom ,dog-pom) + (org-edna-test-children-marks))) + ;; Check off Lunch. This should trigger the others. + (org-edna-test-mark-done lunch-pom) + (should (org-edna-test-compare-todos lunch-pom "TODO" "Lunch after Weekly Trigger")) + (should (org-edna-test-compare-todos door-pom "TODO" "Door after Weekly Trigger")) + (should (org-edna-test-compare-todos dog-pom "TODO" "Dog after Weekly Trigger")) + (should (string-equal (org-entry-get weekly-pom "DEADLINE") + "<2000-01-16 Sun +1d>"))))) (ert-deftest org-edna-doc-test/basic-shower () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "34d67756-927b-4a21-a62d-7989bd138946")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((shower-pom (progn (org-next-visible-heading 1) (point-marker))) - (towels-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify towels is blocked - (should (org-edna-test-check-block towels-pom "Initial Towels Check")) - ;; Check off "Take Shower" and verify that it incremented the property - (org-edna-test-mark-done shower-pom) - (should (string-equal (org-entry-get shower-pom "COUNT") "1")) - ;; Verify towels is blocked - (should (org-edna-test-check-block towels-pom "Towels Check, Count=1")) - ;; Check off "Take Shower" and verify that it incremented the property - (org-edna-test-mark-done shower-pom) - (should (string-equal (org-entry-get shower-pom "COUNT") "2")) - ;; Verify towels is blocked - (should (org-edna-test-check-block towels-pom "Towels Check, Count=2")) - ;; Check off "Take Shower" and verify that it incremented the property - (org-edna-test-mark-done shower-pom) - (should (string-equal (org-entry-get shower-pom "COUNT") "3")) - ;; Verify that towels is no longer blocked. - (should (not (org-edna-test-check-block towels-pom "Towels Check, Count=3"))) - ;; Verify that the property was reset. - (should (string-equal (org-entry-get shower-pom "COUNT") "0"))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "34d67756-927b-4a21-a62d-7989bd138946" + (pcase-let* ((`(,shower-pom ,towels-pom) (org-edna-test-children-marks))) + ;; Verify towels is blocked + (should (org-edna-test-check-block towels-pom "Initial Towels Check")) + ;; Check off "Take Shower" and verify that it incremented the property + (org-edna-test-mark-done shower-pom) + (should (string-equal (org-entry-get shower-pom "COUNT") "1")) + ;; Verify towels is blocked + (should (org-edna-test-check-block towels-pom "Towels Check, Count=1")) + ;; Check off "Take Shower" and verify that it incremented the property + (org-edna-test-mark-done shower-pom) + (should (string-equal (org-entry-get shower-pom "COUNT") "2")) + ;; Verify towels is blocked + (should (org-edna-test-check-block towels-pom "Towels Check, Count=2")) + ;; Check off "Take Shower" and verify that it incremented the property + (org-edna-test-mark-done shower-pom) + (should (string-equal (org-entry-get shower-pom "COUNT") "3")) + ;; Verify that towels is no longer blocked. + (should (not (org-edna-test-check-block towels-pom "Towels Check, Count=3"))) + ;; Verify that the property was reset. + (should (string-equal (org-entry-get shower-pom "COUNT") "0"))))) (ert-deftest org-edna-doc-test/snow-shoveling () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "b1d89bd8-db96-486e-874c-98e2b3a8cbf2")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((monday-pom (progn (org-next-visible-heading 1) (point-marker))) - (tuesday-pom (progn (org-next-visible-heading 1) (point-marker))) - (wednesday-pom (progn (org-next-visible-heading 1) (point-marker))) - (shovel-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify shovels is blocked - (should (org-edna-test-check-block shovel-pom "Initial Shovel Check")) - - ;; Mark Monday as done - (org-edna-test-mark-done monday-pom) - (should (not (org-edna-test-check-block shovel-pom "Shovel after changing Monday"))) - ;; Reset - (org-edna-test-mark-todo monday-pom tuesday-pom wednesday-pom shovel-pom) - - ;; Mark Tuesday as done - (org-edna-test-mark-done tuesday-pom) - (should (not (org-edna-test-check-block shovel-pom "Shovel after changing Tuesday"))) - - ;; Reset - (org-edna-test-mark-todo monday-pom tuesday-pom wednesday-pom shovel-pom) - ;; Mark Wednesday as done - (org-edna-test-mark-done wednesday-pom) - (should (not (org-edna-test-check-block shovel-pom "Shovel after changing Wednesday")))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "b1d89bd8-db96-486e-874c-98e2b3a8cbf2" + (pcase-let* ((`(,monday-pom ,tuesday-pom ,wednesday-pom ,shovel-pom) + (org-edna-test-children-marks))) + ;; Verify shovels is blocked + (should (org-edna-test-check-block shovel-pom "Initial Shovel Check")) + + ;; Mark Monday as done + (org-edna-test-mark-done monday-pom) + (should (not (org-edna-test-check-block shovel-pom "Shovel after changing Monday"))) + ;; Reset + (org-edna-test-mark-todo monday-pom tuesday-pom wednesday-pom shovel-pom) + + ;; Mark Tuesday as done + (org-edna-test-mark-done tuesday-pom) + (should (not (org-edna-test-check-block shovel-pom "Shovel after changing Tuesday"))) + + ;; Reset + (org-edna-test-mark-todo monday-pom tuesday-pom wednesday-pom shovel-pom) + ;; Mark Wednesday as done + (org-edna-test-mark-done wednesday-pom) + (should (not (org-edna-test-check-block shovel-pom "Shovel after changing Wednesday")))))) (ert-deftest org-edna-doc-test/consider-fraction () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "7de5af8b-a226-463f-8360-edd88b99462a")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((shovel-pom (progn (org-next-visible-heading 1) (point-marker))) - (room-pom (progn (org-next-visible-heading 1) (point-marker))) - (vacuum-pom (progn (org-next-visible-heading 1) (point-marker))) - (lunch-pom (progn (org-next-visible-heading 1) (point-marker))) - (edna-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify Edna is blocked - (should (org-edna-test-check-block edna-pom "Initial Edna Check")) - - ;; Mark Shovel snow as done - (org-edna-test-mark-done shovel-pom) - ;; Verify Edna is still blocked - (should (org-edna-test-check-block edna-pom "Edna Check after Shovel")) - - ;; Mark Vacuum as done - (org-edna-test-mark-done vacuum-pom) - ;; Verify Edna is still blocked - (should (org-edna-test-check-block edna-pom "Edna Check after Vacuum")) - - ;; Mark Room as done - (org-edna-test-mark-done room-pom) - ;; Verify Edna is no longer blocked - (should (not (org-edna-test-check-block edna-pom "Edna Check after Room")))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "7de5af8b-a226-463f-8360-edd88b99462a" + (pcase-let* ((`(,shovel-pom ,room-pom ,vacuum-pom ,lunch-pom ,edna-pom) + (org-edna-test-children-marks))) + ;; Verify Edna is blocked + (should (org-edna-test-check-block edna-pom "Initial Edna Check")) + + ;; Mark Shovel snow as done + (org-edna-test-mark-done shovel-pom) + ;; Verify Edna is still blocked + (should (org-edna-test-check-block edna-pom "Edna Check after Shovel")) + + ;; Mark Vacuum as done + (org-edna-test-mark-done vacuum-pom) + ;; Verify Edna is still blocked + (should (org-edna-test-check-block edna-pom "Edna Check after Vacuum")) + + ;; Mark Room as done + (org-edna-test-mark-done room-pom) + ;; Verify Edna is no longer blocked + (should (not (org-edna-test-check-block edna-pom "Edna Check after Room")))))) (ert-deftest org-edna-doc-test/consider-number () - (cl-letf* (((symbol-function 'current-time) (lambda () org-edna-test-time)) - (start-heading (org-edna-find-test-heading "b79279f7-be3c-45ac-96dc-6e962a5873d4")) - ;; Only use the test file in the agenda - (org-agenda-files `(,org-edna-test-file)) - (org-todo-keywords '((sequence "TODO" "|" "DONE"))) - ;; Only block based on Edna - (org-blocker-hook 'org-edna-blocker-function) - ;; Only trigger based on Edna - (org-trigger-hook 'org-edna-trigger-function) - (inhibit-message org-edna-test-inhibit-messages)) - (org-with-point-at start-heading - (save-restriction - ;; Only allow operating on the current tree - (org-narrow-to-subtree) - ;; Show the entire subtree - (outline-show-all) - (unwind-protect - (let* ((shovel-pom (progn (org-next-visible-heading 1) (point-marker))) - (room-pom (progn (org-next-visible-heading 1) (point-marker))) - (vacuum-pom (progn (org-next-visible-heading 1) (point-marker))) - (lunch-pom (progn (org-next-visible-heading 1) (point-marker))) - (edna-pom (progn (org-next-visible-heading 1) (point-marker)))) - ;; Verify Edna is blocked - (should (org-edna-test-check-block edna-pom "Initial Edna Check")) - - ;; Mark Shovel snow as done - (org-edna-test-mark-done shovel-pom) - ;; Verify Edna is still blocked - (should (org-edna-test-check-block edna-pom "Edna Check after Shovel")) - - ;; Mark Vacuum as done - (org-edna-test-mark-done vacuum-pom) - ;; Verify Edna is still blocked - (should (org-edna-test-check-block edna-pom "Edna Check after Vacuum")) - - ;; Mark Room as done - (org-edna-test-mark-done room-pom) - ;; Verify Edna is no longer blocked - (should (not (org-edna-test-check-block edna-pom "Edna Check after Room")))) - ;; Change the test file back to its original state. - (org-edna-test-restore-test-file)))))) + (org-edna-doc-test-setup "b79279f7-be3c-45ac-96dc-6e962a5873d4" + (pcase-let* ((`(,shovel-pom ,room-pom ,vacuum-pom ,lunch-pom ,edna-pom) + (org-edna-test-children-marks))) + ;; Verify Edna is blocked + (should (org-edna-test-check-block edna-pom "Initial Edna Check")) + + ;; Mark Shovel snow as done + (org-edna-test-mark-done shovel-pom) + ;; Verify Edna is still blocked + (should (org-edna-test-check-block edna-pom "Edna Check after Shovel")) + + ;; Mark Vacuum as done + (org-edna-test-mark-done vacuum-pom) + ;; Verify Edna is still blocked + (should (org-edna-test-check-block edna-pom "Edna Check after Vacuum")) + + ;; Mark Room as done + (org-edna-test-mark-done room-pom) + ;; Verify Edna is no longer blocked + (should (not (org-edna-test-check-block edna-pom "Edna Check after Room")))))) + +(ert-deftest org-edna-doc-test/has-tags () + (org-edna-doc-test-setup "6885e932-2c3e-4f20-ac22-5f5a0e791d67" + (pcase-let* ((`(,first-pom ,second-pom ,third-pom) + (org-edna-test-children-marks))) + ;; Verify that 3 is blocked + (should (org-edna-test-check-block third-pom "Initial Check")) + + ;; Remove the tag from Task 1 + (org-with-point-at first-pom + (org-set-tags-to "")) + + ;; Verify that 3 is still blocked + (should (org-edna-test-check-block third-pom "Check after removing tag1")) + + ;; Remove the tag from Task 2 + (org-with-point-at second-pom + (org-set-tags-to "")) + + ;; Verify that 3 is no longer blocked + (should (not (org-edna-test-check-block third-pom "Check after removing tag2")))))) + +(ert-deftest org-edna-doc-test/matches () + (org-edna-doc-test-setup "8170bf82-c2ea-49e8-bd79-97a95176783f" + (pcase-let* ((`(,first-pom ,second-pom ,third-pom) (org-edna-test-children-marks))) + ;; Verify that 3 is blocked + (should (org-edna-test-check-block third-pom "Initial Check")) + + ;; Set 1 to DONE + (org-edna-test-mark-done first-pom) + + ;; Verify that 3 is still blocked + (should (org-edna-test-check-block third-pom "Check after First")) + + ;; Set 2 to DONE + (org-edna-test-mark-done second-pom) + + ;; Verify that 3 is no longer blocked + (should (not (org-edna-test-check-block third-pom "Check after Second")))))) + +(ert-deftest org-edna-doc-test/chain () + (org-edna-doc-test-setup "1bd282ea-9238-47ea-9b4d-dafba19d278b" + (pcase-let* ((`(,first-pom ,second-pom) (org-edna-test-children-marks))) + ;; Set 1 to DONE + (org-edna-test-mark-done first-pom) + (should (string-equal (org-entry-get second-pom "COUNT") "2"))))) (provide 'org-edna-tests) diff --git a/org-edna-tests.org b/org-edna-tests.org index 35d5455..2819700 100644 --- a/org-edna-tests.org +++ b/org-edna-tests.org @@ -22,7 +22,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #+END_QUOTE * Test Pool ** TODO Tagged Heading 1 :1:test: +:PROPERTIES: +:ID: 0fa0d4dd-40f2-4251-a558-4c6e2898c2df +:END: ** TODO Tagged Heading 2 :1:test: +:PROPERTIES: +:ID: 30957f69-8c31-4a13-86ff-f0c5026fb65d +:END: ** TODO ID Heading 1 :PROPERTIES: :ID: 0d491588-7da3-43c5-b51a-87fbd34f79f7 @@ -312,3 +318,33 @@ DEADLINE: <2000-01-15 Sat +1d> :PROPERTIES: :BLOCKER: consider(2) rest-of-siblings-wrap :END: +** Has Tags +:PROPERTIES: +:ID: 6885e932-2c3e-4f20-ac22-5f5a0e791d67 +:END: +*** Task 1 :tag1: +*** Task 2 :tag3:tag2: +*** TODO Task 3 +:PROPERTIES: +:BLOCKER: rest-of-siblings-wrap has-tags?("tag1" "tag2") +:END: +** Matches +:PROPERTIES: +:ID: 8170bf82-c2ea-49e8-bd79-97a95176783f +:END: +*** TODO Task 1 +*** TODO Task 2 +*** TODO Task 3 +:PROPERTIES: +:BLOCKER: rest-of-siblings-wrap !matches?("TODO==\"DONE\"") +:END: +** Chain +:PROPERTIES: +:ID: 1bd282ea-9238-47ea-9b4d-dafba19d278b +:END: +*** TODO Heading 1 +:PROPERTIES: +:COUNT: 2 +:TRIGGER: next-sibling chain!("COUNT") +:END: +*** TODO Heading 2 diff --git a/org-edna.el b/org-edna.el index 929d8ff..f804dba 100644 --- a/org-edna.el +++ b/org-edna.el @@ -498,7 +498,7 @@ specific form were generated, the results will be regenerated and stored in cache. Minor changes to an Org file, such as setting properties or -adding unrelated headlines, will be taken into account." +adding unrelated headings, will be taken into account." :group 'org-edna :type 'boolean) @@ -2017,6 +2017,37 @@ starting from target's position." (when (org-xor condition neg) (format "%s %s in %s" (if neg "Did Not Find" "Found") match (buffer-name))))) +(defun org-edna-condition/has-tags? (neg &rest tags) + "Check if the target heading has tags. + +Edna Syntax: has-tags?(\"tag1\" \"tag2\"...) + +Block if the target heading has any of the tags tag1, tag2, etc." + (let* ((condition (apply 'org-edna-entry-has-tags-p tags))) + (when (org-xor condition neg) + (org-get-heading)))) + +(defun org-edna--heading-matches (match-string) + "Return non-nil if the current heading matches MATCH-STRING." + (let* ((matcher (cdr (org-make-tags-matcher match-string))) + (todo (org-entry-get nil "TODO")) + (tags (org-get-tags-at)) + (level (org-reduced-level (org-outline-level)))) + (funcall matcher todo tags level))) + +(defun org-edna-condition/matches? (neg match-string) + "Matches a heading against a match string. + +Edna Syntax: matches?(\"MATCH-STRING\") + +Blocks if the target heading matches MATCH-STRING. + +MATCH-STRING is a valid match string as passed to +`org-map-entries'." + (let* ((condition (org-edna--heading-matches match-string))) + (when (org-xor condition neg) + (org-get-heading)))) + ;;; Consideration diff --git a/org-edna.info b/org-edna.info index 691f110..abd1b88 100644 --- a/org-edna.info +++ b/org-edna.info @@ -91,6 +91,8 @@ Conditions * Lisp Variable Set:: * Heading Has Property:: * Regexp Search:: Search for a regular expression +* Checking Tags:: Matching against a set of tags +* Matching Headings:: Matching against a match string * Negating Conditions:: @@ -880,7 +882,7 @@ scheduled!(“+1wkdy”) scheduled!(“+1d +wkdy”) Same as above deadline!(“+1m -wkdy”) - Set SCHEDULED up one month, but move backward to find a weekend + Set DEADLINE up one month, but move backward to find a weekend scheduled!(“float 2 Tue Feb”) Set SCHEDULED to the second Tuesday in the following February scheduled!(“float 3 Thu”) @@ -1182,6 +1184,8 @@ means block if any target heading isn’t done. * Lisp Variable Set:: * Heading Has Property:: * Regexp Search:: Search for a regular expression +* Checking Tags:: Matching against a set of tags +* Matching Headings:: Matching against a match string * Negating Conditions:: @@ -1269,7 +1273,7 @@ to VALUE. showered at least three times. -File: org-edna.info, Node: Regexp Search, Next: Negating Conditions, Prev: Heading Has Property, Up: Conditions +File: org-edna.info, Node: Regexp Search, Next: Checking Tags, Prev: Heading Has Property, Up: Conditions Regexp Search ------------- @@ -1280,10 +1284,59 @@ Regexp Search in any of the targets. The targets are expected to be files, although this will work with -other targets as well. +other targets as well. When given a target heading, the heading’s file +will be searched. -File: org-edna.info, Node: Negating Conditions, Prev: Regexp Search, Up: Conditions +File: org-edna.info, Node: Checking Tags, Next: Matching Headings, Prev: Regexp Search, Up: Conditions + +Checking Tags +------------- + + • Syntax: has-tags?(“TAG1” “TAG2” ...) + + Blocks the source heading if any of the target headings have one or +more of the given tags. + + * TODO Task 1 :tag1: + * TODO Task 2 :tag3:tag2: + * TODO Task 3 + :PROPERTIES: + :BLOCKER: rest-of-siblings-wrap has-tags?("tag1" "tag2") + :END: + + In the above example, Tasks 1 and 2 will block Task 3. Task 1 will +block it because it contains “tag1” as one of its tags, and likewise for +Task 2 and “tag2”. + + Note that marking “Task 1” or “Task 2” as DONE will not unblock “Task +3”. If you want to set up such a system, use the *note match:: finder. + + +File: org-edna.info, Node: Matching Headings, Next: Negating Conditions, Prev: Checking Tags, Up: Conditions + +Matching Headings +----------------- + + • Syntax: matches?(“MATCH-STRING”) + + Blocks the source heading if any of the target headings match against +MATCH-STRING. + + MATCH-STRING is a string passed to ‘org-map-entries’. + + * TODO Task 1 + * TODO Task 2 + * TODO Task 3 + :PROPERTIES: + :BLOCKER: rest-of-siblings-wrap !matches?("TODO==\"DONE\"") + :END: + + In the above example, Tasks 1 and 2 will block Task 3 until they’re +marked as DONE. + + +File: org-edna.info, Node: Negating Conditions, Prev: Matching Headings, Up: Conditions Negating Conditions ------------------- @@ -1782,6 +1835,8 @@ File: org-edna.info, Node: 10, Next: 10beta8, Up: Changelog • Added “buffer” option for match finder • Added timestamp sorting to relatives finder • Inverted meaning of consideration to avoid confusion + • Added *note has-tags?: Checking Tags. and *note matches?: Matching + Headings. conditions File: org-edna.info, Node: 10beta8, Next: 10beta7, Prev: 10, Up: Changelog @@ -1898,81 +1953,83 @@ Big release here, with three new features. Tag Table: Node: Top225 -Node: Copying4217 -Node: Introduction5039 -Node: Installation and Setup5987 -Node: Basic Operation6711 -Node: Blockers8562 -Node: Triggers8848 -Node: Syntax9110 -Node: Basic Features9800 -Node: Finders10154 -Node: ancestors11919 -Node: children12513 -Node: descendants12923 -Node: file13445 -Node: first-child14194 -Node: ids14454 -Node: match15115 -Node: next-sibling15753 -Node: next-sibling-wrap16010 -Node: olp16324 -Node: org-file16736 -Node: parent17381 -Node: previous-sibling17579 -Node: previous-sibling-wrap17840 -Node: relatives18119 -Node: rest-of-siblings21845 -Node: rest-of-siblings-wrap22130 -Node: self22479 -Node: siblings22640 -Node: siblings-wrap22877 -Node: Actions23181 -Node: Scheduled/Deadline23944 -Node: TODO State27459 -Node: Archive28184 -Node: Chain Property28504 -Node: Clocking29257 -Node: Property29669 -Node: Priority31842 -Node: Tag32411 -Node: Effort32628 -Node: Getting Help33012 -Node: Advanced Features33457 -Node: Finder Cache33905 -Node: Conditions34944 -Node: Heading is DONE35621 -Node: File Has Headings35827 -Node: Heading TODO State36249 -Node: Lisp Variable Set36543 -Node: Heading Has Property37211 -Node: Regexp Search37957 -Node: Negating Conditions38337 -Node: Consideration38728 -Node: Conditional Forms40912 -Node: Setting the Properties43600 -Node: Extending Edna44684 -Node: Naming Conventions45174 -Node: Finders 145966 -Node: Actions 146328 -Node: Conditions 146787 -Node: Contributing47673 -Node: Bugs48539 -Node: Working with EDE48896 -Node: Compiling Edna49980 -Node: Testing Edna50849 -Node: Before Sending Changes51830 -Node: Developing with Bazaar52517 -Node: Documentation53258 -Node: Changelog53714 -Node: 1053975 -Node: 10beta854377 -Node: 10beta754500 -Node: 10beta654794 -Node: 10beta555070 -Node: 10beta455457 -Node: 10beta355710 -Node: 10beta256149 +Node: Copying4346 +Node: Introduction5168 +Node: Installation and Setup6116 +Node: Basic Operation6840 +Node: Blockers8691 +Node: Triggers8977 +Node: Syntax9239 +Node: Basic Features9929 +Node: Finders10283 +Node: ancestors12048 +Node: children12642 +Node: descendants13052 +Node: file13574 +Node: first-child14323 +Node: ids14583 +Node: match15244 +Node: next-sibling15882 +Node: next-sibling-wrap16139 +Node: olp16453 +Node: org-file16865 +Node: parent17510 +Node: previous-sibling17708 +Node: previous-sibling-wrap17969 +Node: relatives18248 +Node: rest-of-siblings21974 +Node: rest-of-siblings-wrap22259 +Node: self22608 +Node: siblings22769 +Node: siblings-wrap23006 +Node: Actions23310 +Node: Scheduled/Deadline24073 +Node: TODO State27587 +Node: Archive28312 +Node: Chain Property28632 +Node: Clocking29385 +Node: Property29797 +Node: Priority31970 +Node: Tag32539 +Node: Effort32756 +Node: Getting Help33140 +Node: Advanced Features33585 +Node: Finder Cache34033 +Node: Conditions35072 +Node: Heading is DONE35878 +Node: File Has Headings36084 +Node: Heading TODO State36506 +Node: Lisp Variable Set36800 +Node: Heading Has Property37468 +Node: Regexp Search38214 +Node: Checking Tags38657 +Node: Matching Headings39559 +Node: Negating Conditions40156 +Node: Consideration40551 +Node: Conditional Forms42735 +Node: Setting the Properties45423 +Node: Extending Edna46507 +Node: Naming Conventions46997 +Node: Finders 147789 +Node: Actions 148151 +Node: Conditions 148610 +Node: Contributing49496 +Node: Bugs50362 +Node: Working with EDE50719 +Node: Compiling Edna51803 +Node: Testing Edna52672 +Node: Before Sending Changes53653 +Node: Developing with Bazaar54340 +Node: Documentation55081 +Node: Changelog55537 +Node: 1055798 +Node: 10beta856300 +Node: 10beta756423 +Node: 10beta656717 +Node: 10beta556993 +Node: 10beta457380 +Node: 10beta357633 +Node: 10beta258072 End Tag Table diff --git a/org-edna.org b/org-edna.org index 2188f53..89c32aa 100644 --- a/org-edna.org +++ b/org-edna.org @@ -699,7 +699,7 @@ Examples: - deadline!(copy) deadline!("+1h") :: Copy the source deadline to the target, then increment it by an hour. - scheduled!("+1wkdy") :: Set SCHEDULED to the next weekday - scheduled!("+1d +wkdy") :: Same as above -- deadline!("+1m -wkdy") :: Set SCHEDULED up one month, but move backward to find a weekend +- deadline!("+1m -wkdy") :: Set DEADLINE up one month, but move backward to find a weekend - scheduled!("float 2 Tue Feb") :: Set SCHEDULED to the second Tuesday in the following February - scheduled!("float 3 Thu") :: Set SCHEDULED to the third Thursday in the following month @@ -1071,7 +1071,57 @@ Blocks the source heading if the regular expression REGEXP is present in any of the targets. The targets are expected to be files, although this will work with other targets -as well. +as well. When given a target heading, the heading's file will be searched. +*** Checking Tags +:PROPERTIES: +:CUSTOM_ID: has-tags +:DESCRIPTION: Matching against a set of tags +:END: + +- Syntax: has-tags?("TAG1" "TAG2" ...) + +Blocks the source heading if any of the target headings have one or more of the +given tags. + +#+begin_src org +,* TODO Task 1 :tag1: +,* TODO Task 2 :tag3:tag2: +,* TODO Task 3 + :PROPERTIES: + :BLOCKER: rest-of-siblings-wrap has-tags?("tag1" "tag2") + :END: +#+end_src + +In the above example, Tasks 1 and 2 will block Task 3. Task 1 will block it +because it contains "tag1" as one of its tags, and likewise for Task 2 and +"tag2". + +Note that marking "Task 1" or "Task 2" as DONE will not unblock "Task 3". If +you want to set up such a system, use the [[#match][match]] finder. +*** Matching Headings +:PROPERTIES: +:CUSTOM_ID: matches +:DESCRIPTION: Matching against a match string +:END: + +- Syntax: matches?("MATCH-STRING") + +Blocks the source heading if any of the target headings match against +MATCH-STRING. + +MATCH-STRING is a string passed to ~org-map-entries~. + +#+begin_src org +,* TODO Task 1 +,* TODO Task 2 +,* TODO Task 3 + :PROPERTIES: + :BLOCKER: rest-of-siblings-wrap !matches?("TODO==\"DONE\"") + :END: +#+end_src + +In the above example, Tasks 1 and 2 will block Task 3 until they're marked as +DONE. *** Negating Conditions :PROPERTIES: @@ -1544,6 +1594,7 @@ making any changes: - Added "buffer" option for match finder - Added timestamp sorting to relatives finder - Inverted meaning of consideration to avoid confusion +- Added [[#has-tags][has-tags?]] and [[#matches][matches?]] conditions ** 1.0beta8 Quick fix for beta7.