ADD test for project deadline
This commit is contained in:
parent
ca17ee15d5
commit
efe3eac7c3
|
@ -36,16 +36,20 @@ left/right slot."
|
||||||
|
|
||||||
;; monad-y things
|
;; monad-y things
|
||||||
|
|
||||||
(defmacro either>>= (either form)
|
(defmacro either-as>>= (sym either form)
|
||||||
"Bind EITHER to FORM where the right slot is bound to 'it'."
|
"Bind EITHER to FORM where the right slot is bound to SYM."
|
||||||
(declare (indent 1))
|
(declare (indent 2))
|
||||||
(let ((e (make-symbol "--either")))
|
(let ((e (make-symbol "--either")))
|
||||||
`(let ((,e ,either))
|
`(let ((,e ,either))
|
||||||
(pcase ,e
|
(pcase ,e
|
||||||
(`(:left ,_) ,e)
|
(`(:left ,_) ,e)
|
||||||
(`(:right ,it) ,form)
|
(`(:right ,,sym) ,form)
|
||||||
(e (error "Learn to use monads, dummy; this isn't one: %s" e))))))
|
(e (error "Learn to use monads, dummy; this isn't one: %s" e))))))
|
||||||
|
|
||||||
|
(defmacro either>>= (either form)
|
||||||
|
"Bind EITHER to FORM where the right slot is bound to 'it'."
|
||||||
|
`(either-as>>= it ,either ,form))
|
||||||
|
|
||||||
(defun either-foldM (fun init xs)
|
(defun either-foldM (fun init xs)
|
||||||
"Mondically apply FUN to XS (a list).
|
"Mondically apply FUN to XS (a list).
|
||||||
|
|
||||||
|
|
|
@ -851,7 +851,7 @@ deadline (eg via epoch time) or if it has a repeater."
|
||||||
(< parent-epoch this-epoch))))))
|
(< parent-epoch this-epoch))))))
|
||||||
|
|
||||||
(defun org-x-dag-bs-action-project-inner (node-data ancestry child-bss)
|
(defun org-x-dag-bs-action-project-inner (node-data ancestry child-bss)
|
||||||
(cl-flet
|
(cl-flet*
|
||||||
((new-proj
|
((new-proj
|
||||||
(status)
|
(status)
|
||||||
(either :right `(:sp-proj ,status)))
|
(either :right `(:sp-proj ,status)))
|
||||||
|
@ -861,45 +861,39 @@ deadline (eg via epoch time) or if it has a repeater."
|
||||||
(is-next
|
(is-next
|
||||||
(task-data)
|
(task-data)
|
||||||
(-let (((&plist :todo :sched) task-data))
|
(-let (((&plist :todo :sched) task-data))
|
||||||
(or sched (equal todo org-x-kw-next)))))
|
(or sched (equal todo org-x-kw-next))))
|
||||||
;; rankings
|
(check-sched
|
||||||
;; *-active > proj-wait > proj-held > (proj-stuck == iter-empty) > *-complete
|
(planning)
|
||||||
(org-x-dag-bs-action-with-closed node-data ancestry "projects"
|
(if-let (sched (-some->> planning (org-ml-get-property :scheduled)))
|
||||||
(if child-bss
|
(if child-bss (either :left "Projects cannot be scheduled")
|
||||||
`(:sp-proj :proj-complete ,it-comptime)
|
(let ((sp (org-x-dag-partition-timestamp sched)))
|
||||||
`(:sp-task :task-complete ,it-comptime))
|
(if (< 0 (plist-get sp :length))
|
||||||
|
(->> "Tasks cannot have ranged scheduled timestamps"
|
||||||
(org-x-dag-bs-action-check-children child-bss
|
(either :left))
|
||||||
(either :left "Completed projects cannot have active children")
|
(either :right sp))))
|
||||||
(either :right `(:sp-proj :proj-complete ,it-comptime))
|
(either :right nil)))
|
||||||
`(:sp-task :task-complete ,it-comptime)
|
(check-dead
|
||||||
(lambda (local)
|
(planning)
|
||||||
(pcase local
|
(if-let (dead (-some->> planning (org-ml-get-property :deadline)))
|
||||||
(`(:sp-proj :proj-complete ,_) t)
|
(let ((dp (org-x-dag-partition-timestamp dead)))
|
||||||
(`(:sp-iter :iter-complete ,_) t)
|
|
||||||
(`(:sp-task :task-complete ,_) t)
|
|
||||||
(_ nil))))
|
|
||||||
|
|
||||||
(-let* (((sched dead) (-some->> it-planning
|
|
||||||
(org-ml-get-properties '(:scheduled :deadline))))
|
|
||||||
(sp (-some-> sched (org-x-dag-partition-timestamp)))
|
|
||||||
(dp (-some-> dead (org-x-dag-partition-timestamp)))
|
|
||||||
(task-default (->> (list :todo it-todo :sched sp :dead dp)
|
|
||||||
(list :sp-task :task-active))))
|
|
||||||
(cond
|
(cond
|
||||||
((and child-bss (equal it-todo org-x-kw-hold))
|
((< 0 (plist-get dp :length))
|
||||||
(new-proj :proj-held))
|
(either :left "Actions cannot have ranged deadlines"))
|
||||||
((and child-bss sp)
|
((and child-bss (plist-get dp :repeater))
|
||||||
(either :left "Projects cannot be scheduled"))
|
(either :left "Projects cannot have repeated deadlines"))
|
||||||
((and sp (< 0 (plist-get sp :length)))
|
|
||||||
(either :left "Projects cannot have ranged scheduled timestamps"))
|
|
||||||
((and dp (< 0 (plist-get dp :length)))
|
|
||||||
(either :left "Projects cannot have ranged deadline timestamps"))
|
|
||||||
((and child-bss (plist-get node-data :effort))
|
|
||||||
(either :left "Projects cannot have effort"))
|
|
||||||
((org-x-dag-action-dead-after-parent-p ancestry dead)
|
((org-x-dag-action-dead-after-parent-p ancestry dead)
|
||||||
(either :left "Action deadline cannot end after parent deadline"))
|
(either :left "Action deadline cannot end after parent deadline"))
|
||||||
((equal it-todo org-x-kw-todo)
|
(t
|
||||||
|
(either :right dp))))
|
||||||
|
(either :right nil)))
|
||||||
|
(check-todo
|
||||||
|
(todo task-default)
|
||||||
|
(cond
|
||||||
|
((and child-bss (plist-get node-data :effort))
|
||||||
|
(either :left "Projects cannot have effort"))
|
||||||
|
((and child-bss (equal todo org-x-kw-hold))
|
||||||
|
(new-proj :proj-held))
|
||||||
|
((equal todo org-x-kw-todo)
|
||||||
(org-x-dag-bs-action-rankfold-children child-bss task-default
|
(org-x-dag-bs-action-rankfold-children child-bss task-default
|
||||||
(lambda (acc next)
|
(lambda (acc next)
|
||||||
(->> (pcase `(,acc ,next)
|
(->> (pcase `(,acc ,next)
|
||||||
|
@ -943,8 +937,8 @@ deadline (eg via epoch time) or if it has a repeater."
|
||||||
(`(,_ (:sp-task :task-active ,_)) t)
|
(`(,_ (:sp-task :task-active ,_)) t)
|
||||||
|
|
||||||
;; any pair that makes it this far is completed in both,
|
;; any pair that makes it this far is completed in both,
|
||||||
;; which means neither takes precedence, which means choose
|
;; which means neither takes precedence, which means
|
||||||
;; the left one
|
;; choose the left one
|
||||||
(`(,_ ,_) nil))
|
(`(,_ ,_) nil))
|
||||||
(either :right)))
|
(either :right)))
|
||||||
|
|
||||||
|
@ -984,9 +978,36 @@ deadline (eg via epoch time) or if it has a repeater."
|
||||||
(t (org-x-dag-bs-error-kw "Task action" o)))))
|
(t (org-x-dag-bs-error-kw "Task action" o)))))
|
||||||
(e (error "Pattern fail: %s" e))))))
|
(e (error "Pattern fail: %s" e))))))
|
||||||
(child-bss
|
(child-bss
|
||||||
(org-x-dag-bs-error-kw "Project action" it-todo))
|
(org-x-dag-bs-error-kw "Project action" todo))
|
||||||
(t
|
(t
|
||||||
(either :right task-default)))))))
|
(either :right task-default)))))
|
||||||
|
|
||||||
|
;; rankings
|
||||||
|
;; *-active > proj-wait > proj-held > (proj-stuck == iter-empty) > *-complete
|
||||||
|
(org-x-dag-bs-action-with-closed node-data ancestry "projects"
|
||||||
|
(if child-bss
|
||||||
|
`(:sp-proj :proj-complete ,it-comptime)
|
||||||
|
`(:sp-task :task-complete ,it-comptime))
|
||||||
|
|
||||||
|
(org-x-dag-bs-action-check-children child-bss
|
||||||
|
(either :left "Completed projects cannot have active children")
|
||||||
|
(either :right `(:sp-proj :proj-complete ,it-comptime))
|
||||||
|
`(:sp-task :task-complete ,it-comptime)
|
||||||
|
(lambda (local)
|
||||||
|
(pcase local
|
||||||
|
(`(:sp-proj :proj-complete ,_) t)
|
||||||
|
(`(:sp-iter :iter-complete ,_) t)
|
||||||
|
(`(:sp-task :task-complete ,_) t)
|
||||||
|
(_ nil))))
|
||||||
|
|
||||||
|
(either-as>>= sp (check-sched it-planning)
|
||||||
|
(either-as>>= dp (check-dead it-planning)
|
||||||
|
;; TODO it seems a bit odd that the only reason I need sp and dp here
|
||||||
|
;; is to seed the sub-project task form; idk why this is weird but it
|
||||||
|
;; smells like something could be optimized somewhere
|
||||||
|
(->> (list :todo it-todo :sched sp :dead dp)
|
||||||
|
(list :sp-task :task-active)
|
||||||
|
(check-todo it-todo)))))))
|
||||||
|
|
||||||
(defun org-x-dag-node-data-is-iterator-p (node-data)
|
(defun org-x-dag-node-data-is-iterator-p (node-data)
|
||||||
(-let (((&plist :props) node-data))
|
(-let (((&plist :props) node-data))
|
||||||
|
@ -1053,6 +1074,7 @@ deadline (eg via epoch time) or if it has a repeater."
|
||||||
(ts-data child-scheds)
|
(ts-data child-scheds)
|
||||||
(->> (list :dead (plist-get ts-data :dead)
|
(->> (list :dead (plist-get ts-data :dead)
|
||||||
:child-scheds child-scheds
|
:child-scheds child-scheds
|
||||||
|
;; TODO this can be an epoch and not a datetime
|
||||||
:leading-sched-dt (-> (org-x-dag-pts-max child-scheds)
|
:leading-sched-dt (-> (org-x-dag-pts-max child-scheds)
|
||||||
(plist-get :datetime)))
|
(plist-get :datetime)))
|
||||||
(funcall new-active-fun))))
|
(funcall new-active-fun))))
|
||||||
|
|
|
@ -89,6 +89,20 @@ CLOSED: [2022-06-10 Fri 19:13]
|
||||||
:ID: a834a585-acd1-44e9-8e62-17793146d6ab
|
:ID: a834a585-acd1-44e9-8e62-17793146d6ab
|
||||||
:CREATED: [2022-06-10 Fri 19:13]
|
:CREATED: [2022-06-10 Fri 19:13]
|
||||||
:END:
|
:END:
|
||||||
|
** TODO this is a deadlined project
|
||||||
|
DEADLINE: <2022-06-12 Sun>
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: 51798071-f860-48fb-b3d8-e526ce270290
|
||||||
|
:CREATED: [2022-06-12 Sun 18:09]
|
||||||
|
:END:
|
||||||
|
*** NEXT subtask
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: fc1f3dda-a4b7-4b0d-b37c-fa67e112023a
|
||||||
|
:CREATED: [2022-06-12 Sun 18:10]
|
||||||
|
:END:
|
||||||
|
:LOGGING:
|
||||||
|
- State "NEXT" from "TODO" [2022-06-12 Sun 18:10]
|
||||||
|
:END:
|
||||||
* iterators
|
* iterators
|
||||||
** TODO this is an iterator
|
** TODO this is an iterator
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|
|
@ -46,6 +46,11 @@
|
||||||
(->> (org-ml-from-string 'timestamp s)
|
(->> (org-ml-from-string 'timestamp s)
|
||||||
(org-ml-timestamp-get-start-time)))
|
(org-ml-timestamp-get-start-time)))
|
||||||
|
|
||||||
|
(defun timestamp-to-epoch (s)
|
||||||
|
(->> (org-ml-from-string 'timestamp s)
|
||||||
|
(org-ml-timestamp-get-start-time)
|
||||||
|
(org-ml-time-to-unixtime)))
|
||||||
|
|
||||||
(buttercup-define-matcher :to-be-left-with (a x)
|
(buttercup-define-matcher :to-be-left-with (a x)
|
||||||
(cl-destructuring-bind
|
(cl-destructuring-bind
|
||||||
((a-expr . a) (x-expr . x))
|
((a-expr . a) (x-expr . x))
|
||||||
|
@ -112,6 +117,14 @@
|
||||||
(and (eq (org-ml-get-type a) (org-ml-get-type b))
|
(and (eq (org-ml-get-type a) (org-ml-get-type b))
|
||||||
(plists-equal-p (get-useful-props a) (get-useful-props b)))))
|
(plists-equal-p (get-useful-props a) (get-useful-props b)))))
|
||||||
|
|
||||||
|
(defun pts-equal-p (a b)
|
||||||
|
(-let (((&plist :datetime da :repeater ra :warning wa :length la) a)
|
||||||
|
((&plist :datetime db :repeater rb :warning wb :length lb) b))
|
||||||
|
(and (equal da db)
|
||||||
|
(equal ra rb)
|
||||||
|
(equal wa wb)
|
||||||
|
(equal la lb))))
|
||||||
|
|
||||||
(defun plist-diff-msg (eq-funs expr a b)
|
(defun plist-diff-msg (eq-funs expr a b)
|
||||||
(-let (((a-diff b-diff common-diffs) (split-plists eq-funs a b)))
|
(-let (((a-diff b-diff common-diffs) (split-plists eq-funs a b)))
|
||||||
(cond
|
(cond
|
||||||
|
@ -173,12 +186,9 @@
|
||||||
(let* ((ancestry (list :canceled-parent-p c
|
(let* ((ancestry (list :canceled-parent-p c
|
||||||
:held-parent-p h
|
:held-parent-p h
|
||||||
:parent-deadline e))
|
:parent-deadline e))
|
||||||
(ancestry-eq-funs (list :parent-deadline #'element-equal-p))
|
(ancestry-eq-funs nil)
|
||||||
(local-eq-funs (list :sched #'element-equal-p
|
(local-eq-funs (list :sched #'element-equal-p
|
||||||
;; TODO this is wrong
|
:child-scheds #'pts-equal-p))
|
||||||
:child-scheds (lambda (a b)
|
|
||||||
(seq-set-equal-p
|
|
||||||
a b #'element-equal-p))))
|
|
||||||
(f (->> (-partial #'status-diff-msg local-eq-funs test-expr y s d)
|
(f (->> (-partial #'status-diff-msg local-eq-funs test-expr y s d)
|
||||||
(-partial #'ancestry-diff-msg ancestry-eq-funs test-expr ancestry)
|
(-partial #'ancestry-diff-msg ancestry-eq-funs test-expr ancestry)
|
||||||
(-partial #'buffer-status-diff-msg test-expr :action)
|
(-partial #'buffer-status-diff-msg test-expr :action)
|
||||||
|
@ -280,7 +290,13 @@
|
||||||
(it "Canceled"
|
(it "Canceled"
|
||||||
(expect "322af50a-f431-4940-8caf-cc5acdf5a555" :id-to-be-action
|
(expect "322af50a-f431-4940-8caf-cc5acdf5a555" :id-to-be-action
|
||||||
nil nil nil :sp-task '(:task-complete)
|
nil nil nil :sp-task '(:task-complete)
|
||||||
'(:canceledp t :epoch 1654903560))))
|
'(:canceledp t :epoch 1654903560)))
|
||||||
|
|
||||||
|
(it "Deadlined"
|
||||||
|
(let ((d (timestamp-to-epoch "<2022-06-12 Sun>")))
|
||||||
|
(expect "fc1f3dda-a4b7-4b0d-b37c-fa67e112023a" :id-to-be-action
|
||||||
|
nil nil d :sp-task '(:task-active)
|
||||||
|
'(:todo "NEXT" :sched nil :dead nil)))))
|
||||||
|
|
||||||
(describe "Standalone Tasks"
|
(describe "Standalone Tasks"
|
||||||
(it "Active"
|
(it "Active"
|
||||||
|
|
Loading…
Reference in New Issue