Files
Marcos Paulo 16a0786a2d
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: recurring task toggle, Templater render, icons in Explorer rows and tabs (MiniMax M3.1 Flash)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 11:16:23 -03:00

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);
}