142 lines
4.3 KiB
Rust
142 lines
4.3 KiB
Rust
//! Tests of the scan of a note.
|
|
|
|
use notescraft_tasks::{ScanCfg, Task, scan_note};
|
|
|
|
/// Scans a note with the default configuration.
|
|
fn scan(text: &str) -> Vec<Task> {
|
|
scan_note("notes/n.md", text, &ScanCfg::default())
|
|
}
|
|
|
|
/// The descriptions of the tasks of a note.
|
|
fn descriptions(tasks: &[Task]) -> Vec<&str> {
|
|
tasks.iter().map(|task| task.description.as_str()).collect()
|
|
}
|
|
|
|
#[test]
|
|
fn tasks_in_a_fence_are_ignored() {
|
|
let text = "- [ ] first\n```\n- [ ] hidden\n```\n- [ ] last\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(descriptions(&tasks), vec!["first", "last"]);
|
|
assert_eq!(tasks[0].line, 0);
|
|
assert_eq!(tasks[1].line, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn an_unclosed_fence_hides_the_rest_of_the_note() {
|
|
let text = "- [ ] first\n```\n- [ ] hidden\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(descriptions(&tasks), vec!["first"]);
|
|
}
|
|
|
|
#[test]
|
|
fn frontmatter_lines_are_ignored() {
|
|
let text = "---\ntags: [work]\nstatus: open\n---\n- [ ] real\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(descriptions(&tasks), vec!["real"]);
|
|
assert_eq!(tasks[0].line, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn a_note_without_frontmatter_starts_at_the_first_line() {
|
|
let tasks = scan("- [ ] real\n");
|
|
assert_eq!(tasks[0].line, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn the_heading_is_tracked_across_levels() {
|
|
let text = "# One\n## Two\n### Three\n- [ ] a\n## Four\n- [ ] b\n# Five\n- [ ] c\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(tasks.len(), 3);
|
|
assert_eq!(tasks[0].heading.as_deref(), Some("Three"));
|
|
assert_eq!(tasks[1].heading.as_deref(), Some("Four"));
|
|
assert_eq!(tasks[2].heading.as_deref(), Some("Five"));
|
|
}
|
|
|
|
#[test]
|
|
fn a_task_without_a_heading_above_has_none() {
|
|
let tasks = scan("- [ ] a\n");
|
|
assert_eq!(tasks[0].heading, None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_nested_task_knows_its_parent() {
|
|
let text = "- [ ] parent\n - [ ] child\n - [ ] grandchild\n- [ ] sibling\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(tasks.len(), 4);
|
|
assert_eq!(tasks[0].parent_line, None);
|
|
assert_eq!(tasks[1].parent_line, Some(0));
|
|
assert_eq!(tasks[2].parent_line, Some(1));
|
|
assert_eq!(tasks[3].parent_line, None);
|
|
}
|
|
|
|
#[test]
|
|
fn a_child_of_a_filtered_out_task_has_no_parent() {
|
|
let cfg = ScanCfg { global_filter: Some("#task".to_owned()) };
|
|
let text = "- [ ] parent\n - [ ] child #task\n";
|
|
let tasks = scan_note("n.md", text, &cfg);
|
|
assert_eq!(tasks.len(), 1);
|
|
assert_eq!(tasks[0].parent_line, None);
|
|
}
|
|
|
|
#[test]
|
|
fn the_global_filter_selects_the_lines() {
|
|
let cfg = ScanCfg { global_filter: Some("#task".to_owned()) };
|
|
let text = "- [ ] a #task\n- [ ] b\n- [ ] c #task\n";
|
|
let tasks = scan_note("n.md", text, &cfg);
|
|
assert_eq!(descriptions(&tasks), vec!["a", "c"]);
|
|
}
|
|
|
|
#[test]
|
|
fn without_a_filter_every_checkbox_is_a_task() {
|
|
let text = "- [ ] a #task\n- [ ] b\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(descriptions(&tasks), vec!["a #task", "b"]);
|
|
}
|
|
|
|
#[test]
|
|
fn the_filter_stays_in_the_source_line() {
|
|
let cfg = ScanCfg { global_filter: Some("#task".to_owned()) };
|
|
let tasks = scan_note("n.md", "- [ ] a #task\n", &cfg);
|
|
assert_eq!(tasks[0].original, "- [ ] a #task");
|
|
assert_eq!(tasks[0].description, "a");
|
|
}
|
|
|
|
#[test]
|
|
fn a_note_with_many_tasks_is_capped() {
|
|
let mut text = String::new();
|
|
for number in 0..1500 {
|
|
text.push_str("- [ ] task ");
|
|
text.push_str(&number.to_string());
|
|
text.push('\n');
|
|
}
|
|
let tasks = scan(&text);
|
|
assert_eq!(tasks.len(), 1000);
|
|
assert_eq!(tasks[999].description, "task 999");
|
|
}
|
|
|
|
#[test]
|
|
fn carriage_returns_are_not_part_of_the_original() {
|
|
let text = "- [ ] a\r\n- [ ] b\r\n";
|
|
let tasks = scan(text);
|
|
assert_eq!(tasks.len(), 2);
|
|
assert_eq!(tasks[0].original, "- [ ] a");
|
|
assert_eq!(tasks[1].original, "- [ ] b");
|
|
assert!(tasks.iter().all(|task| !task.original.contains('\r')));
|
|
}
|
|
|
|
#[test]
|
|
fn the_path_and_the_line_are_filled() {
|
|
let tasks = scan_note("notes/deep/n.md", "text\n- [ ] a\n", &ScanCfg::default());
|
|
assert_eq!(tasks[0].path, "notes/deep/n.md");
|
|
assert_eq!(tasks[0].line, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn the_signifiers_of_a_task_are_read() {
|
|
let tasks = scan("- [ ] a 📅 2026-10-20 🔺\n");
|
|
assert_eq!(tasks[0].description, "a");
|
|
assert_eq!(tasks[0].priority, notescraft_tasks::Priority::Highest);
|
|
let due = tasks[0].due.map(|date| format!("{:04}-{:02}-{:02}", date.year(), date.month(), date.day()));
|
|
assert_eq!(due, Some("2026-10-20".to_owned()));
|
|
}
|