//! Task navigation (`nuwiki.list.nextTask`) plus a smoke test that the //! `COMMANDS` registry advertises every list/heading/file handler the //! editor surface relies on. use nuwiki_core::syntax::vimwiki::VimwikiSyntax; use nuwiki_core::syntax::SyntaxPlugin; use nuwiki_lsp::commands::ops; use tower_lsp::lsp_types::Url; fn parse(src: &str) -> nuwiki_core::ast::DocumentNode { VimwikiSyntax::new().parse(src) } fn dummy_uri() -> Url { Url::parse("file:///tmp/note.wiki").unwrap() } // ===== next_task ===== #[test] fn next_task_returns_first_unfinished() { let src = "- [X] done\n- [ ] todo\n- [ ] later\n"; let doc = parse(src); let loc = ops::next_task(&doc, &dummy_uri(), src, 0, 0, true).expect("found a task"); // Should be line 1 (the first [ ]). assert_eq!(loc.range.start.line, 1); } #[test] fn next_task_wraps_around_when_no_task_after_cursor() { // Only task is on line 0; cursor on line 2 → wraps back. let src = "- [ ] todo\n- [X] done\n- [X] also done\n"; let doc = parse(src); let loc = ops::next_task(&doc, &dummy_uri(), src, 2, 0, true).expect("found"); assert_eq!(loc.range.start.line, 0); } #[test] fn next_task_returns_none_when_no_open_tasks() { let src = "- [X] a\n- [X] b\n"; let doc = parse(src); let loc = ops::next_task(&doc, &dummy_uri(), src, 0, 0, true); assert!(loc.is_none()); } #[test] fn next_task_only_counts_items_with_checkboxes() { // Plain items without a `[…]` are ignored — they're not tasks. let src = "- plain\n- [ ] real task\n"; let doc = parse(src); let loc = ops::next_task(&doc, &dummy_uri(), src, 0, 0, true).expect("found"); assert_eq!(loc.range.start.line, 1); } // ===== smoke: COMMANDS list matches registered handlers ===== #[test] fn commands_list_is_complete() { let names: Vec<&str> = nuwiki_lsp::commands::COMMANDS.to_vec(); for name in [ "nuwiki.file.delete", "nuwiki.list.toggleCheckbox", "nuwiki.list.cycleCheckbox", "nuwiki.list.rejectCheckbox", "nuwiki.list.nextTask", "nuwiki.heading.addLevel", "nuwiki.heading.removeLevel", ] { assert!(names.contains(&name), "missing: {name}"); } }