use chrono;
use todo_lib::tfilter::TodoStatus;
use todo_lib::{tfilter, todo, todotxt, tsort};
fn init_tasks() -> todo::TaskVec {
let mut t = Vec::new();
let now = chrono::Local::now().date_naive();
t.push(todotxt::Task::parse("call mother #tagone +family @parents", now));
t.push(todotxt::Task::parse(
"x (C) 2018-10-05 2018-10-01 call to car service and schedule repair +car @repair",
now,
));
t.push(todotxt::Task::parse(
"(B) 2018-10-15 repair #tagtwo family car +Car @repair due:2018-12-01 t:2019-01-02",
now,
));
t.push(todotxt::Task::parse("(A) Kid's art #tagthree school lesson +Family @Kids due:2018-11-10 rec:1w", now));
t.push(todotxt::Task::parse("take kid to hockey #tagone #tagtwo game +Family @kids due:2018-11-18", now));
t.push(todotxt::Task::parse("xmas vacations +FamilyHoliday due:2018-12-24", now));
t
}
fn init_tasks_with_empty() -> todo::TaskVec {
let mut t = Vec::new();
let now = chrono::Local::now().date_naive();
t.push(todotxt::Task::parse("call mother #tagone +family @parents", now));
t.push(todotxt::Task::parse("", now));
t.push(todotxt::Task::parse("xmas vacations +FamilyHoliday due:2018-12-24", now));
t.push(todotxt::Task::parse("", now));
t
}
#[test]
fn one_item() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.range = tfilter::ItemRange::One(t.len());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids.len(), 0);
cflt.range = tfilter::ItemRange::One(t.len() + 1);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids.len(), 0);
}
#[test]
fn item_range() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.range = tfilter::ItemRange::Range(t.len(), t.len() + 5);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids.len(), 0);
cflt.range = tfilter::ItemRange::One(1);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids.len(), 0);
cflt.range = tfilter::ItemRange::Range(1, 3);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2, 3]);
cflt.range = tfilter::ItemRange::None;
}
#[test]
fn item_status() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.range = tfilter::ItemRange::One(0);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0]);
cflt.all = tfilter::TodoStatus::All;
cflt.range = tfilter::ItemRange::Range(0, 10);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 1, 2, 3, 4, 5]);
cflt.all = tfilter::TodoStatus::Done;
cflt.range = tfilter::ItemRange::Range(0, 10);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![1]);
cflt.all = tfilter::TodoStatus::Active;
cflt.range = tfilter::ItemRange::Range(0, 10);
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 2, 3, 4, 5]);
}
#[test]
fn item_regex() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.all = tfilter::TodoStatus::All;
cflt.regex = Some("car".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![1, 2]);
cflt.all = tfilter::TodoStatus::Active;
cflt.use_regex = true;
cflt.regex = Some("CA[rl]".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 2]);
}
#[test]
fn item_projects() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.include.projects.push("car".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2]);
cflt.include.projects.clear();
cflt.include.projects.push("FAMILY".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 3, 4]);
cflt.include.projects.clear();
cflt.include.projects.push("FAMILY*".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 3, 4, 5]);
cflt.include.projects.clear();
cflt.include.projects.push("*holiday".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![5]);
cflt.include.projects.clear();
cflt.include.projects.push("*family*".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 3, 4, 5]);
cflt.include.projects.clear();
cflt.exclude.projects.push("*family*".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2]);
cflt.exclude.projects.clear();
cflt.exclude.projects.push("FAMILY".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2, 5]);
cflt.exclude.projects.clear();
cflt.include.projects.push("*family*".to_owned());
cflt.exclude.projects.push("FAMILY".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![5]);
}
#[test]
fn item_contexts() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.include.contexts.push("kids".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![3, 4]);
cflt.include.contexts.clear();
cflt.exclude.contexts.push("kids".to_owned());
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 2, 5]);
}
#[test]
fn item_priority() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.all = tfilter::TodoStatus::All;
cflt.pri = Some(tfilter::Priority { value: 'b' as u8 - 'a' as u8, span: tfilter::ValueSpan::Equal });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2]);
cflt.pri = Some(tfilter::Priority { value: 'b' as u8 - 'a' as u8, span: tfilter::ValueSpan::Higher });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2, 3]);
cflt.pri = Some(tfilter::Priority { value: 'b' as u8 - 'a' as u8, span: tfilter::ValueSpan::Lower });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 1, 2, 4, 5]);
cflt.pri = Some(tfilter::Priority { value: todotxt::NO_PRIORITY, span: tfilter::ValueSpan::Any });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![1, 2, 3]);
cflt.pri = Some(tfilter::Priority { value: todotxt::NO_PRIORITY, span: tfilter::ValueSpan::None });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 4, 5]);
}
#[test]
fn item_recurrence() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.all = tfilter::TodoStatus::All;
cflt.rec = Some(tfilter::Recurrence { span: tfilter::ValueSpan::Any });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![3]);
cflt.rec = Some(tfilter::Recurrence { span: tfilter::ValueSpan::None });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 1, 2, 4, 5]);
}
#[test]
fn item_due() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.all = tfilter::TodoStatus::All;
cflt.due = Some(tfilter::DateRange { span: tfilter::ValueSpan::Any, days: Default::default() });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2, 3, 4, 5]);
cflt.due = Some(tfilter::DateRange { span: tfilter::ValueSpan::None, days: Default::default() });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 1]);
let sconf = tsort::Conf { fields: Some("due".to_string()), rev: true };
let mut ids: todo::IDVec = vec![0, 1, 2, 3, 4, 5];
tsort::sort(&mut ids, &t, &sconf);
assert_eq!(ids, vec![1, 0, 5, 2, 4, 3]);
}
#[test]
fn item_threshold() {
let t = init_tasks();
let mut cflt = tfilter::Conf::default();
cflt.thr = Some(tfilter::DateRange { span: tfilter::ValueSpan::Any, days: Default::default() });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![2]);
cflt.thr = Some(tfilter::DateRange { span: tfilter::ValueSpan::None, days: Default::default() });
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, vec![0, 3, 4, 5]);
let sconf = tsort::Conf { fields: Some("thr".to_string()), rev: false };
let mut ids: todo::IDVec = vec![0, 1, 2, 3, 4, 5];
tsort::sort(&mut ids, &t, &sconf);
assert_eq!(ids, vec![2, 0, 1, 3, 4, 5]);
}
#[test]
fn item_tags() {
let t = init_tasks();
struct Test {
inc: Vec<&'static str>,
exc: Vec<&'static str>,
res: todo::IDVec,
}
let tests: Vec<Test> = vec![
Test { inc: vec!["tagone"], exc: Vec::new(), res: vec![0, 4] },
Test { inc: vec!["tagone", "tagtwo"], exc: Vec::new(), res: vec![0, 2, 4] },
Test { inc: vec!["tagone"], exc: vec!["tagtwo"], res: vec![0] },
Test { inc: vec!["any"], exc: Vec::new(), res: vec![0, 2, 3, 4] },
Test { inc: vec!["none"], exc: Vec::new(), res: vec![5] },
];
for (idx, test) in tests.iter().enumerate() {
let mut cflt = tfilter::Conf::default();
for tg in test.inc.iter() {
cflt.include.hashtags.push(tg.to_string());
}
for tg in test.exc.iter() {
cflt.exclude.hashtags.push(tg.to_string());
}
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, test.res, "{}. {:?} != {:?}", idx, ids, test.res);
}
}
#[test]
fn empty_tasks() {
let t = init_tasks_with_empty();
struct Test {
inc: TodoStatus,
res: todo::IDVec,
}
let tests: Vec<Test> = vec![
Test { inc: TodoStatus::Active, res: vec![0, 2] },
Test { inc: TodoStatus::Empty, res: vec![1, 3] },
Test { inc: TodoStatus::All, res: vec![0, 1, 2, 3] },
];
for (idx, test) in tests.iter().enumerate() {
let mut cflt = tfilter::Conf::default();
cflt.all = test.inc;
let ids = tfilter::filter(&t, &cflt);
assert_eq!(ids, test.res, "{idx}. {ids:?} != {:?}", test.res);
}
}