242 lines
7.0 KiB
Rust
242 lines
7.0 KiB
Rust
|
|
//! Cluster 4 — diary frequency wiring at the WikiConfig + index layer.
|
||
|
|
//!
|
||
|
|
//! These tests exercise the path/URI shape for each frequency and the
|
||
|
|
//! index's ability to recognise non-daily diary entries. The
|
||
|
|
//! integration through `executeCommand` is exercised in the LSP-level
|
||
|
|
//! tests via the Neovim keymap harness; here we stay at the pure-Rust
|
||
|
|
//! layer so failures land with a clean stack.
|
||
|
|
|
||
|
|
use std::path::PathBuf;
|
||
|
|
|
||
|
|
use nuwiki_core::date::{DiaryDate, DiaryFrequency, DiaryPeriod};
|
||
|
|
use nuwiki_core::syntax::vimwiki::VimwikiSyntax;
|
||
|
|
use nuwiki_core::syntax::SyntaxPlugin;
|
||
|
|
use nuwiki_lsp::config::WikiConfig;
|
||
|
|
use nuwiki_lsp::diary;
|
||
|
|
use nuwiki_lsp::index::{diary_period_for_uri, WorkspaceIndex};
|
||
|
|
use tower_lsp::lsp_types::Url;
|
||
|
|
|
||
|
|
fn cfg(root: &str, frequency: &str) -> WikiConfig {
|
||
|
|
let mut c = WikiConfig::from_root(PathBuf::from(root));
|
||
|
|
c.diary_rel_path = "diary".into();
|
||
|
|
c.diary_frequency = frequency.into();
|
||
|
|
c
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn frequency_helper_picks_up_config_value() {
|
||
|
|
assert_eq!(cfg("/tmp", "daily").frequency(), DiaryFrequency::Daily);
|
||
|
|
assert_eq!(cfg("/tmp", "weekly").frequency(), DiaryFrequency::Weekly);
|
||
|
|
assert_eq!(cfg("/tmp", "monthly").frequency(), DiaryFrequency::Monthly);
|
||
|
|
assert_eq!(cfg("/tmp", "yearly").frequency(), DiaryFrequency::Yearly);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn diary_path_for_period_picks_right_stem_per_frequency() {
|
||
|
|
let c = cfg("/wiki", "daily");
|
||
|
|
let day = DiaryPeriod::Day(DiaryDate::from_ymd(2026, 5, 12).unwrap());
|
||
|
|
let wk = DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 19,
|
||
|
|
};
|
||
|
|
let mo = DiaryPeriod::Month {
|
||
|
|
year: 2026,
|
||
|
|
month: 5,
|
||
|
|
};
|
||
|
|
let yr = DiaryPeriod::Year { year: 2026 };
|
||
|
|
assert_eq!(
|
||
|
|
c.diary_path_for_period(&day),
|
||
|
|
PathBuf::from("/wiki/diary/2026-05-12.wiki")
|
||
|
|
);
|
||
|
|
assert_eq!(
|
||
|
|
c.diary_path_for_period(&wk),
|
||
|
|
PathBuf::from("/wiki/diary/2026-W19.wiki")
|
||
|
|
);
|
||
|
|
assert_eq!(
|
||
|
|
c.diary_path_for_period(&mo),
|
||
|
|
PathBuf::from("/wiki/diary/2026-05.wiki")
|
||
|
|
);
|
||
|
|
assert_eq!(
|
||
|
|
c.diary_path_for_period(&yr),
|
||
|
|
PathBuf::from("/wiki/diary/2026.wiki")
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn uri_for_period_produces_file_url_per_frequency() {
|
||
|
|
let c = cfg("/wiki", "weekly");
|
||
|
|
let wk = DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 19,
|
||
|
|
};
|
||
|
|
let u = diary::uri_for_period(&c, &wk).unwrap();
|
||
|
|
assert!(
|
||
|
|
u.as_str().ends_with("/wiki/diary/2026-W19.wiki"),
|
||
|
|
"got: {u}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ===== Index recognition =====
|
||
|
|
|
||
|
|
fn make_index_with(entries: &[&str]) -> WorkspaceIndex {
|
||
|
|
let root = PathBuf::from("/wiki");
|
||
|
|
let mut idx = WorkspaceIndex::new(Some(root.clone())).with_diary_rel_path(Some("diary".into()));
|
||
|
|
for stem in entries {
|
||
|
|
let path = format!("/wiki/diary/{stem}.wiki");
|
||
|
|
let uri = Url::from_file_path(&path).unwrap();
|
||
|
|
let ast = VimwikiSyntax::new().parse("= entry =\n");
|
||
|
|
idx.upsert(uri, &ast);
|
||
|
|
}
|
||
|
|
idx
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn index_recognises_all_four_frequency_stems() {
|
||
|
|
let idx = make_index_with(&["2026-05-12", "2026-W19", "2026-05", "2026"]);
|
||
|
|
for (stem, expected) in [
|
||
|
|
(
|
||
|
|
"2026-05-12",
|
||
|
|
DiaryPeriod::Day(DiaryDate::from_ymd(2026, 5, 12).unwrap()),
|
||
|
|
),
|
||
|
|
(
|
||
|
|
"2026-W19",
|
||
|
|
DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 19,
|
||
|
|
},
|
||
|
|
),
|
||
|
|
(
|
||
|
|
"2026-05",
|
||
|
|
DiaryPeriod::Month {
|
||
|
|
year: 2026,
|
||
|
|
month: 5,
|
||
|
|
},
|
||
|
|
),
|
||
|
|
("2026", DiaryPeriod::Year { year: 2026 }),
|
||
|
|
] {
|
||
|
|
let uri = Url::from_file_path(format!("/wiki/diary/{stem}.wiki")).unwrap();
|
||
|
|
let page = idx.page(&uri).expect(stem);
|
||
|
|
assert_eq!(
|
||
|
|
page.diary_period,
|
||
|
|
Some(expected),
|
||
|
|
"stem {stem} should index as {expected:?}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn index_only_sets_diary_date_for_daily_entries() {
|
||
|
|
let idx = make_index_with(&["2026-05-12", "2026-W19"]);
|
||
|
|
let daily = Url::from_file_path("/wiki/diary/2026-05-12.wiki").unwrap();
|
||
|
|
let weekly = Url::from_file_path("/wiki/diary/2026-W19.wiki").unwrap();
|
||
|
|
assert!(idx.page(&daily).unwrap().diary_date.is_some());
|
||
|
|
assert!(idx.page(&weekly).unwrap().diary_date.is_none());
|
||
|
|
assert!(idx.page(&weekly).unwrap().diary_period.is_some());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn diary_period_for_uri_rejects_paths_outside_diary_dir() {
|
||
|
|
// Non-diary path with a date-looking stem — should NOT count.
|
||
|
|
let uri = Url::from_file_path("/wiki/notes/2026-05-12.wiki").unwrap();
|
||
|
|
let root = PathBuf::from("/wiki");
|
||
|
|
assert!(diary_period_for_uri(&uri, Some(&root), Some("diary")).is_none());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn next_prev_period_navigate_at_the_same_frequency() {
|
||
|
|
// Mix entries at different frequencies. Navigation should stay
|
||
|
|
// within the same flavour as the pivot.
|
||
|
|
let idx = make_index_with(&[
|
||
|
|
"2026-W18",
|
||
|
|
"2026-W19",
|
||
|
|
"2026-W20", // weekly
|
||
|
|
"2026-04",
|
||
|
|
"2026-05",
|
||
|
|
"2026-06", // monthly
|
||
|
|
"2026-05-10",
|
||
|
|
"2026-05-12", // daily
|
||
|
|
]);
|
||
|
|
let pivot_w = DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 19,
|
||
|
|
};
|
||
|
|
let next_w = diary::next_period(&idx, &pivot_w).unwrap();
|
||
|
|
assert_eq!(
|
||
|
|
next_w.period,
|
||
|
|
DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 20
|
||
|
|
}
|
||
|
|
);
|
||
|
|
let prev_w = diary::prev_period(&idx, &pivot_w).unwrap();
|
||
|
|
assert_eq!(
|
||
|
|
prev_w.period,
|
||
|
|
DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 18
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
let pivot_m = DiaryPeriod::Month {
|
||
|
|
year: 2026,
|
||
|
|
month: 5,
|
||
|
|
};
|
||
|
|
let next_m = diary::next_period(&idx, &pivot_m).unwrap();
|
||
|
|
assert_eq!(
|
||
|
|
next_m.period,
|
||
|
|
DiaryPeriod::Month {
|
||
|
|
year: 2026,
|
||
|
|
month: 6
|
||
|
|
}
|
||
|
|
);
|
||
|
|
let prev_m = diary::prev_period(&idx, &pivot_m).unwrap();
|
||
|
|
assert_eq!(
|
||
|
|
prev_m.period,
|
||
|
|
DiaryPeriod::Month {
|
||
|
|
year: 2026,
|
||
|
|
month: 4
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn next_prev_period_returns_none_past_the_edge() {
|
||
|
|
let idx = make_index_with(&["2026-W19"]);
|
||
|
|
let only = DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 19,
|
||
|
|
};
|
||
|
|
assert!(diary::next_period(&idx, &only).is_none());
|
||
|
|
assert!(diary::prev_period(&idx, &only).is_none());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn diary_period_for_uri_handles_each_frequency_under_diary_dir() {
|
||
|
|
let root = PathBuf::from("/wiki");
|
||
|
|
for (stem, expected) in [
|
||
|
|
(
|
||
|
|
"2026-05-12",
|
||
|
|
DiaryPeriod::Day(DiaryDate::from_ymd(2026, 5, 12).unwrap()),
|
||
|
|
),
|
||
|
|
(
|
||
|
|
"2026-W19",
|
||
|
|
DiaryPeriod::Week {
|
||
|
|
iso_year: 2026,
|
||
|
|
iso_week: 19,
|
||
|
|
},
|
||
|
|
),
|
||
|
|
(
|
||
|
|
"2026-05",
|
||
|
|
DiaryPeriod::Month {
|
||
|
|
year: 2026,
|
||
|
|
month: 5,
|
||
|
|
},
|
||
|
|
),
|
||
|
|
("2026", DiaryPeriod::Year { year: 2026 }),
|
||
|
|
] {
|
||
|
|
let uri = Url::from_file_path(format!("/wiki/diary/{stem}.wiki")).unwrap();
|
||
|
|
let got = diary_period_for_uri(&uri, Some(&root), Some("diary"));
|
||
|
|
assert_eq!(got, Some(expected), "stem {stem}");
|
||
|
|
}
|
||
|
|
}
|