fix(tasks): test time-tracking including automatic back-tracking
This commit is contained in:
parent
d950c13098
commit
db4f9ee8cb
294
src/tasks.rs
294
src/tasks.rs
|
@ -113,7 +113,9 @@ impl Tasks {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn time_tracked_for<'a, E>(events: E, ids: &Vec<EventId>) -> u64
|
fn time_tracked_for<'a, E>(events: E, ids: &Vec<EventId>) -> u64
|
||||||
where E: IntoIterator<Item=&'a Event> {
|
where
|
||||||
|
E: IntoIterator<Item=&'a Event>,
|
||||||
|
{
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut start: Option<Timestamp> = None;
|
let mut start: Option<Timestamp> = None;
|
||||||
for event in events {
|
for event in events {
|
||||||
|
@ -126,6 +128,7 @@ impl Tasks {
|
||||||
}
|
}
|
||||||
_ => if let Some(stamp) = start {
|
_ => if let Some(stamp) = start {
|
||||||
total += (event.created_at - stamp).as_u64();
|
total += (event.created_at - stamp).as_u64();
|
||||||
|
start = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,16 +487,26 @@ impl Tasks {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_task_title(&self, id: &EventId) -> String {
|
fn get_task_title(&self, id: &EventId) -> String {
|
||||||
self.tasks.get(id).map_or(id.to_string(), |t| t.get_title())
|
self.tasks.get(id).map_or(id.to_string(), |t| t.get_title())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn track_at(&mut self, time: Timestamp) -> EventId {
|
pub(crate) fn track_at(&mut self, time: Timestamp) -> EventId {
|
||||||
info!("Tracking \"{:?}\" from {}", self.position.map(|id| self.get_task_title(&id)), time.to_human_datetime());
|
info!("Tracking \"{:?}\" from {}", self.position.map(|id| self.get_task_title(&id)), time.to_human_datetime());
|
||||||
self.submit(
|
let pos = self.get_position();
|
||||||
build_tracking(self.get_position())
|
let tracking = build_tracking(pos);
|
||||||
.custom_created_at(time)
|
self.get_own_history().map(|events| {
|
||||||
)
|
if let Some(event) = events.pop_last() {
|
||||||
|
if event.kind.as_u16() == TRACKING_KIND &&
|
||||||
|
(pos == None && event.tags.is_empty()) ||
|
||||||
|
event.tags.iter().all(|t| t.content().map(|str| str.to_string()) == pos.map(|id| id.to_string())) {
|
||||||
|
// Replace last for easier calculation
|
||||||
|
} else {
|
||||||
|
events.insert(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.submit(tracking.custom_created_at(time))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn submit(&mut self, builder: EventBuilder) -> EventId {
|
fn submit(&mut self, builder: EventBuilder) -> EventId {
|
||||||
|
@ -520,7 +533,7 @@ impl Tasks {
|
||||||
t.children.insert(event.id);
|
t.children.insert(event.id);
|
||||||
});
|
});
|
||||||
if self.tasks.contains_key(&event.id) {
|
if self.tasks.contains_key(&event.id) {
|
||||||
debug!("Did not insert duplicate event {}", event.id);
|
warn!("Did not insert duplicate event {}", event.id);
|
||||||
} else {
|
} else {
|
||||||
self.tasks.insert(event.id, Task::new(event));
|
self.tasks.insert(event.id, Task::new(event));
|
||||||
}
|
}
|
||||||
|
@ -532,6 +545,10 @@ impl Tasks {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_own_history(&mut self) -> Option<&mut BTreeSet<Event>> {
|
||||||
|
self.history.get_mut(&self.sender.pubkey())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn undo(&mut self) {
|
pub(crate) fn undo(&mut self) {
|
||||||
self.sender.clear().into_iter().rev().for_each(|event| {
|
self.sender.clear().into_iter().rev().for_each(|event| {
|
||||||
self.remove(&event)
|
self.remove(&event)
|
||||||
|
@ -545,7 +562,7 @@ impl Tasks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tasks.remove(&event.id);
|
self.tasks.remove(&event.id);
|
||||||
self.history.get_mut(&self.sender.pubkey()).map(|t| t.remove(event));
|
self.get_own_history().map(|t| t.remove(event));
|
||||||
self.referenced_tasks(event, |t| { t.props.remove(event); });
|
self.referenced_tasks(event, |t| { t.props.remove(event); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,131 +647,136 @@ impl<'a> Iterator for ParentIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stub_tasks() -> Tasks {
|
#[cfg(test)]
|
||||||
use std::sync::mpsc;
|
mod tasks_test {
|
||||||
use nostr_sdk::Keys;
|
use super::*;
|
||||||
|
|
||||||
let (tx, _rx) = mpsc::channel();
|
fn stub_tasks() -> Tasks {
|
||||||
Tasks::from(EventSender {
|
use std::sync::mpsc;
|
||||||
tx,
|
use nostr_sdk::Keys;
|
||||||
keys: Keys::generate(),
|
|
||||||
queue: Default::default(),
|
let (tx, _rx) = mpsc::channel();
|
||||||
})
|
Tasks::from(EventSender {
|
||||||
}
|
tx,
|
||||||
|
keys: Keys::generate(),
|
||||||
#[test]
|
queue: Default::default(),
|
||||||
fn test_tracking() {
|
})
|
||||||
let mut tasks = stub_tasks();
|
}
|
||||||
|
|
||||||
//let task = tasks.make_task("task");
|
#[test]
|
||||||
tasks.track_at(Timestamp::from(0));
|
fn test_tracking() {
|
||||||
assert_eq!(tasks.history.len(), 1);
|
let mut tasks = stub_tasks();
|
||||||
let zero = EventId::all_zeros();
|
|
||||||
|
//let task = tasks.make_task("task");
|
||||||
tasks.move_to(Some(zero));
|
tasks.track_at(Timestamp::from(0));
|
||||||
let now: Timestamp = Timestamp::now() - 2u64;
|
assert_eq!(tasks.history.len(), 1);
|
||||||
tasks.track_at(Timestamp::from(1));
|
let zero = EventId::all_zeros();
|
||||||
assert!(tasks.time_tracked(zero) > now.as_u64());
|
|
||||||
|
tasks.move_to(Some(zero));
|
||||||
tasks.move_to(None);
|
let now: Timestamp = Timestamp::now() - 2u64;
|
||||||
tasks.track_at(Timestamp::from(2));
|
tasks.track_at(Timestamp::from(1));
|
||||||
assert_eq!(tasks.history.values().nth(0).unwrap().len(), 5);
|
assert!(tasks.time_tracked(zero) > now.as_u64());
|
||||||
assert_eq!(tasks.time_tracked(zero), 2);
|
|
||||||
}
|
tasks.move_to(None);
|
||||||
|
tasks.track_at(Timestamp::from(2));
|
||||||
#[test]
|
assert_eq!(tasks.get_own_history().unwrap().len(), 3);
|
||||||
fn test_depth() {
|
assert_eq!(tasks.time_tracked(zero), 1);
|
||||||
let mut tasks = stub_tasks();
|
}
|
||||||
|
|
||||||
let t1 = tasks.make_task("t1");
|
#[test]
|
||||||
let task1 = tasks.get_by_id(&t1).unwrap();
|
fn test_depth() {
|
||||||
assert_eq!(tasks.depth, 1);
|
let mut tasks = stub_tasks();
|
||||||
assert_eq!(task1.pure_state(), State::Open);
|
|
||||||
debug!("{:?}", tasks);
|
let t1 = tasks.make_task("t1");
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
let task1 = tasks.get_by_id(&t1).unwrap();
|
||||||
tasks.depth = 0;
|
assert_eq!(tasks.depth, 1);
|
||||||
assert_eq!(tasks.current_tasks().len(), 0);
|
assert_eq!(task1.pure_state(), State::Open);
|
||||||
|
debug!("{:?}", tasks);
|
||||||
tasks.move_to(Some(t1));
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
tasks.depth = 2;
|
tasks.depth = 0;
|
||||||
assert_eq!(tasks.current_tasks().len(), 0);
|
assert_eq!(tasks.current_tasks().len(), 0);
|
||||||
let t2 = tasks.make_task("t2");
|
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
tasks.move_to(Some(t1));
|
||||||
assert_eq!(tasks.get_task_path(Some(t2)), "t1>t2");
|
tasks.depth = 2;
|
||||||
assert_eq!(tasks.relative_path(t2), "t2");
|
assert_eq!(tasks.current_tasks().len(), 0);
|
||||||
let t3 = tasks.make_task("t3");
|
let t2 = tasks.make_task("t2");
|
||||||
assert_eq!(tasks.current_tasks().len(), 2);
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
|
assert_eq!(tasks.get_task_path(Some(t2)), "t1>t2");
|
||||||
tasks.move_to(Some(t2));
|
assert_eq!(tasks.relative_path(t2), "t2");
|
||||||
assert_eq!(tasks.current_tasks().len(), 0);
|
let t3 = tasks.make_task("t3");
|
||||||
let t4 = tasks.make_task("t4");
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
|
||||||
assert_eq!(tasks.get_task_path(Some(t4)), "t1>t2>t4");
|
tasks.move_to(Some(t2));
|
||||||
assert_eq!(tasks.relative_path(t4), "t4");
|
assert_eq!(tasks.current_tasks().len(), 0);
|
||||||
tasks.depth = 2;
|
let t4 = tasks.make_task("t4");
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
tasks.depth = -1;
|
assert_eq!(tasks.get_task_path(Some(t4)), "t1>t2>t4");
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
assert_eq!(tasks.relative_path(t4), "t4");
|
||||||
|
tasks.depth = 2;
|
||||||
tasks.move_to(Some(t1));
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
assert_eq!(tasks.relative_path(t4), "t2>t4");
|
tasks.depth = -1;
|
||||||
assert_eq!(tasks.current_tasks().len(), 2);
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
tasks.depth = 2;
|
|
||||||
assert_eq!(tasks.current_tasks().len(), 3);
|
tasks.move_to(Some(t1));
|
||||||
tasks.set_filter(vec![t2]);
|
assert_eq!(tasks.relative_path(t4), "t2>t4");
|
||||||
assert_eq!(tasks.current_tasks().len(), 2);
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
tasks.depth = 1;
|
tasks.depth = 2;
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
assert_eq!(tasks.current_tasks().len(), 3);
|
||||||
tasks.depth = -1;
|
tasks.set_filter(vec![t2]);
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
tasks.set_filter(vec![t2, t3]);
|
tasks.depth = 1;
|
||||||
assert_eq!(tasks.current_tasks().len(), 2);
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
tasks.depth = 2;
|
tasks.depth = -1;
|
||||||
assert_eq!(tasks.current_tasks().len(), 3);
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
tasks.depth = 1;
|
tasks.set_filter(vec![t2, t3]);
|
||||||
assert_eq!(tasks.current_tasks().len(), 2);
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
|
tasks.depth = 2;
|
||||||
tasks.move_to(None);
|
assert_eq!(tasks.current_tasks().len(), 3);
|
||||||
assert_eq!(tasks.current_tasks().len(), 1);
|
tasks.depth = 1;
|
||||||
tasks.depth = 2;
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
assert_eq!(tasks.current_tasks().len(), 3);
|
|
||||||
tasks.depth = 3;
|
tasks.move_to(None);
|
||||||
assert_eq!(tasks.current_tasks().len(), 4);
|
assert_eq!(tasks.current_tasks().len(), 1);
|
||||||
tasks.depth = 9;
|
tasks.depth = 2;
|
||||||
assert_eq!(tasks.current_tasks().len(), 4);
|
assert_eq!(tasks.current_tasks().len(), 3);
|
||||||
tasks.depth = -1;
|
tasks.depth = 3;
|
||||||
assert_eq!(tasks.current_tasks().len(), 2);
|
assert_eq!(tasks.current_tasks().len(), 4);
|
||||||
}
|
tasks.depth = 9;
|
||||||
|
assert_eq!(tasks.current_tasks().len(), 4);
|
||||||
#[test]
|
tasks.depth = -1;
|
||||||
fn test_empty_task_title_fallback_to_id() {
|
assert_eq!(tasks.current_tasks().len(), 2);
|
||||||
let mut tasks = stub_tasks();
|
}
|
||||||
|
|
||||||
let empty = tasks.make_task("");
|
#[test]
|
||||||
let empty_task = tasks.get_by_id(&empty).unwrap();
|
fn test_empty_task_title_fallback_to_id() {
|
||||||
let empty_id = empty_task.event.id.to_string();
|
let mut tasks = stub_tasks();
|
||||||
assert_eq!(empty_task.get_title(), empty_id);
|
|
||||||
assert_eq!(tasks.get_task_path(Some(empty)), empty_id);
|
let empty = tasks.make_task("");
|
||||||
}
|
let empty_task = tasks.get_by_id(&empty).unwrap();
|
||||||
|
let empty_id = empty_task.event.id.to_string();
|
||||||
#[test]
|
assert_eq!(empty_task.get_title(), empty_id);
|
||||||
fn test_unknown_task() {
|
assert_eq!(tasks.get_task_path(Some(empty)), empty_id);
|
||||||
let mut tasks = stub_tasks();
|
}
|
||||||
|
|
||||||
let zero = EventId::all_zeros();
|
#[test]
|
||||||
assert_eq!(tasks.get_task_path(Some(zero)), zero.to_string());
|
fn test_unknown_task() {
|
||||||
tasks.move_to(Some(zero));
|
let mut tasks = stub_tasks();
|
||||||
let dangling = tasks.make_task("test");
|
|
||||||
assert_eq!(
|
let zero = EventId::all_zeros();
|
||||||
tasks.get_task_path(Some(dangling)),
|
assert_eq!(tasks.get_task_path(Some(zero)), zero.to_string());
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000>test"
|
tasks.move_to(Some(zero));
|
||||||
);
|
let dangling = tasks.make_task("test");
|
||||||
assert_eq!(tasks.relative_path(dangling), "test");
|
assert_eq!(
|
||||||
|
tasks.get_task_path(Some(dangling)),
|
||||||
use itertools::Itertools;
|
"0000000000000000000000000000000000000000000000000000000000000000>test"
|
||||||
assert_eq!("test toast".split(' ').collect_vec().len(), 3);
|
);
|
||||||
assert_eq!(
|
assert_eq!(tasks.relative_path(dangling), "test");
|
||||||
"test toast".split_ascii_whitespace().collect_vec().len(),
|
|
||||||
2
|
use itertools::Itertools;
|
||||||
);
|
assert_eq!("test toast".split(' ').collect_vec().len(), 3);
|
||||||
|
assert_eq!(
|
||||||
|
"test toast".split_ascii_whitespace().collect_vec().len(),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue