From e6f28bb7e615b1c40feeb25240ca98faaff8a89f Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Thu, 15 Dec 2022 02:52:39 +0000 Subject: [PATCH] include recurring tasks in working-set, but not +PENDING --- taskchampion/taskchampion/src/replica.rs | 56 ++++++++++++++++++++-- taskchampion/taskchampion/src/task/task.rs | 21 ++++++-- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/taskchampion/taskchampion/src/replica.rs b/taskchampion/taskchampion/src/replica.rs index 1c0f171be..b583f01f1 100644 --- a/taskchampion/taskchampion/src/replica.rs +++ b/taskchampion/taskchampion/src/replica.rs @@ -211,12 +211,21 @@ impl Replica { /// Rebuild this replica's working set, based on whether tasks are pending or not. If /// `renumber` is true, then existing tasks may be moved to new working-set indices; in any - /// case, on completion all pending tasks are in the working set and all non- pending tasks are - /// not. + /// case, on completion all pending and recurring tasks are in the working set and all tasks + /// with other statuses are not. pub fn rebuild_working_set(&mut self, renumber: bool) -> anyhow::Result<()> { let pending = String::from(Status::Pending.to_taskmap()); - self.taskdb - .rebuild_working_set(|t| t.get("status") == Some(&pending), renumber)?; + let recurring = String::from(Status::Recurring.to_taskmap()); + self.taskdb.rebuild_working_set( + |t| { + if let Some(st) = t.get("status") { + st == &pending || st == &recurring + } else { + false + } + }, + renumber, + )?; Ok(()) } @@ -454,6 +463,27 @@ mod tests { assert!(ws.by_uuid(t.get_uuid()).is_none()); } + #[test] + fn rebuild_working_set_includes_recurring() { + let mut rep = Replica::new_inmemory(); + + let t = rep + .new_task(Status::Completed, "another task".into()) + .unwrap(); + let uuid = t.get_uuid(); + + let t = rep.get_task(uuid).unwrap().unwrap(); + { + let mut t = t.into_mut(&mut rep); + t.set_status(Status::Recurring).unwrap(); + } + + rep.rebuild_working_set(true).unwrap(); + + let ws = rep.working_set().unwrap(); + assert!(ws.by_uuid(uuid).is_some()); + } + #[test] fn new_pending_adds_to_working_set() { let mut rep = Replica::new_inmemory(); @@ -472,6 +502,24 @@ mod tests { assert_eq!(ws.by_uuid(t.get_uuid()), Some(1)); } + #[test] + fn new_recurring_adds_to_working_set() { + let mut rep = Replica::new_inmemory(); + + let t = rep + .new_task(Status::Recurring, "to-be-recurring".into()) + .unwrap(); + let uuid = t.get_uuid(); + + let ws = rep.working_set().unwrap(); + assert_eq!(ws.len(), 1); // only one non-none value + assert!(ws.by_index(0).is_none()); + assert_eq!(ws.by_index(1), Some(uuid)); + + let ws = rep.working_set().unwrap(); + assert_eq!(ws.by_uuid(t.get_uuid()), Some(1)); + } + #[test] fn get_does_not_exist() { let mut rep = Replica::new_inmemory(); diff --git a/taskchampion/taskchampion/src/task/task.rs b/taskchampion/taskchampion/src/task/task.rs index f742afdcb..34e9f2382 100644 --- a/taskchampion/taskchampion/src/task/task.rs +++ b/taskchampion/taskchampion/src/task/task.rs @@ -328,13 +328,13 @@ impl<'r> TaskMut<'r> { /// new status puts it in that set. pub fn set_status(&mut self, status: Status) -> anyhow::Result<()> { match status { - Status::Pending => { - // clear "end" when a task becomes "pending" + Status::Pending | Status::Recurring => { + // clear "end" when a task becomes "pending" or "recurring" if self.taskmap.contains_key(Prop::End.as_ref()) { self.set_timestamp(Prop::End.as_ref(), None)?; } - let uuid = self.uuid; - self.replica.add_to_working_set(uuid)?; + // ..and add to working set + self.replica.add_to_working_set(self.uuid)?; } Status::Completed | Status::Deleted => { // set "end" when a task is deleted or completed @@ -860,6 +860,19 @@ mod test { }); } + #[test] + fn test_set_status_recurring() { + with_mut_task(|mut task| { + task.done().unwrap(); + + task.set_status(Status::Recurring).unwrap(); + assert_eq!(task.get_status(), Status::Recurring); + assert!(!task.taskmap.contains_key("end")); + assert!(!task.has_tag(&stag(SyntheticTag::Pending))); // recurring is not +PENDING + assert!(!task.has_tag(&stag(SyntheticTag::Completed))); + }); + } + #[test] fn test_set_status_completed() { with_mut_task(|mut task| {