131 lines
4.5 KiB
Rust
131 lines
4.5 KiB
Rust
//! Toggling a task line: the status, the completion date and the deletion.
|
|
|
|
use notescraft_tasks::{StatusType, ToggleCfg, next_status, status_type, toggle};
|
|
use notescraft_templates::Date;
|
|
|
|
/// The day the tests toggle on.
|
|
fn today() -> Date {
|
|
Date::new(2026, 10, 22).expect("a valid date")
|
|
}
|
|
|
|
/// The default configuration of a toggle.
|
|
fn cfg() -> ToggleCfg {
|
|
ToggleCfg::default()
|
|
}
|
|
|
|
#[test]
|
|
fn a_todo_task_becomes_done_with_the_completion_date() {
|
|
let out = toggle("- [ ] Buy milk 📅 2026-10-20", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [x] Buy milk 📅 2026-10-20 ✅ 2026-10-22"]);
|
|
assert_eq!(out.next_index, None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_done_task_becomes_todo_and_loses_the_completion_date() {
|
|
let out = toggle("- [x] Buy milk 📅 2026-10-20 ✅ 2026-10-20", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [ ] Buy milk 📅 2026-10-20"]);
|
|
}
|
|
|
|
#[test]
|
|
fn the_completion_date_goes_when_it_is_not_at_the_end() {
|
|
let out = toggle("- [x] Buy milk ✅ 2026-10-20 📅 2026-10-01", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [ ] Buy milk 📅 2026-10-01"]);
|
|
}
|
|
|
|
#[test]
|
|
fn a_task_in_progress_becomes_done() {
|
|
let out = toggle("- [/] Buy milk", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [x] Buy milk ✅ 2026-10-22"]);
|
|
}
|
|
|
|
#[test]
|
|
fn a_cancelled_task_becomes_todo_and_keeps_its_cancellation_date() {
|
|
let out = toggle("- [-] Buy milk ❌ 2026-10-20", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [ ] Buy milk ❌ 2026-10-20"]);
|
|
}
|
|
|
|
#[test]
|
|
fn the_completion_date_is_not_written_when_it_is_turned_off() {
|
|
let cfg = ToggleCfg { set_done_date: false, ..ToggleCfg::default() };
|
|
let out = toggle("- [ ] Buy milk", today(), &cfg).expect("a task");
|
|
assert_eq!(out.lines, ["- [x] Buy milk"]);
|
|
}
|
|
|
|
#[test]
|
|
fn an_old_completion_date_is_replaced_by_today() {
|
|
let out = toggle("- [ ] Buy milk ✅ 2026-01-01", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [x] Buy milk ✅ 2026-10-22"]);
|
|
}
|
|
|
|
#[test]
|
|
fn a_task_that_is_dropped_on_completion_is_deleted() {
|
|
let out = toggle("- [ ] Buy milk 🏁 delete", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, Vec::<String>::new());
|
|
assert_eq!(out.next_index, None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_dropped_task_that_goes_back_to_todo_stays() {
|
|
let out = toggle("- [x] Buy milk 🏁 delete", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [ ] Buy milk 🏁 delete"]);
|
|
}
|
|
|
|
#[test]
|
|
fn the_text_outside_the_signifiers_is_byte_preserved() {
|
|
let original = " * [ ] Buy milk #home 📅 2026-10-20";
|
|
let out = toggle(original, today(), &cfg()).expect("a task");
|
|
let result = out.lines.first().expect("one line");
|
|
let open = original.find('[').expect("a box");
|
|
let close = original.find(']').expect("a box");
|
|
assert_eq!(&result[..open], &original[..open]);
|
|
assert_eq!(&result[open..open + 2], "[x");
|
|
assert!(result[open + 2..].starts_with(&original[close..]));
|
|
assert_eq!(result, " * [x] Buy milk #home 📅 2026-10-20 ✅ 2026-10-22");
|
|
}
|
|
|
|
#[test]
|
|
fn the_indent_and_the_marker_are_kept() {
|
|
let out = toggle(" 1. [ ] Buy milk", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, [" 1. [x] Buy milk ✅ 2026-10-22"]);
|
|
}
|
|
|
|
#[test]
|
|
fn a_recurring_task_gets_its_next_occurrence() {
|
|
let out = toggle("- [ ] Water 🔁 every week 📅 2026-10-20", today(), &cfg()).expect("a task");
|
|
assert_eq!(out.lines, ["- [ ] Water 🔁 every week 📅 2026-10-27", "- [x] Water 🔁 every week 📅 2026-10-20 ✅ 2026-10-22"]);
|
|
assert_eq!(out.next_index, Some(0));
|
|
}
|
|
|
|
#[test]
|
|
fn a_line_that_is_not_a_task_has_no_toggle() {
|
|
assert!(toggle("Buy milk", today(), &cfg()).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn the_status_kinds_are_known() {
|
|
assert_eq!(status_type(' '), StatusType::Todo);
|
|
assert_eq!(status_type('/'), StatusType::InProgress);
|
|
assert_eq!(status_type('x'), StatusType::Done);
|
|
assert_eq!(status_type('X'), StatusType::Done);
|
|
assert_eq!(status_type('-'), StatusType::Cancelled);
|
|
assert_eq!(status_type('?'), StatusType::Todo);
|
|
}
|
|
|
|
#[test]
|
|
fn the_next_status_follows_the_plugin() {
|
|
assert_eq!(next_status(' '), 'x');
|
|
assert_eq!(next_status('/'), 'x');
|
|
assert_eq!(next_status('x'), ' ');
|
|
assert_eq!(next_status('X'), ' ');
|
|
assert_eq!(next_status('-'), ' ');
|
|
assert_eq!(next_status('?'), 'x');
|
|
}
|
|
|
|
#[test]
|
|
fn the_default_configuration_writes_the_completion_date() {
|
|
let cfg = ToggleCfg::default();
|
|
assert!(cfg.set_done_date);
|
|
assert!(!cfg.remove_scheduled_on_recurrence);
|
|
assert!(!cfg.next_below);
|
|
}
|