refactor(tests): group test files by feature, drop phase/cluster naming
Restructures the integration test layout so each file is named after
what it covers, not the implementation phase it landed in.
nuwiki-core (renames only):
vimwiki_lexer → lexer
vimwiki_parser → parser
vimwiki_tags → tags
vimwiki_table_alignment → table_alignment
diary_period → diary
list_continuation → lists
transclusion_attrs → transclusion
+ table colspan/rowspan tests moved here from parity_cluster_1
nuwiki-lsp (renames + merges + one split):
cluster_a_list_rewriters → commands_lists
cluster_b_table_rewriters → commands_tables
cluster_c_link_helpers +
phase19_followlink_creates → commands_links
phase13_rename_commands → commands_files
phase17_colorize → commands_colorize
phase17_html_export → html_export
phase15_link_health → link_health
phase18_multi_wiki → multi_wiki
phase19_folding → folding
nav → navigation
lsp_helpers → helpers
phase16_diary +
diary_frequency → diary
phase11_plumbing +
parity_cluster_1 (config) → index_and_config
tags_index_and_lsp +
phase17_backfill → commands_tags
phase14_edit_commands → split into
commands_checkboxes,
commands_headings,
commands_tasks
Net: 30 → 28 integration-test files. 456 → 455 tests (the one
removed test was a dummy `paragraph_render_is_unchanged` whose only
purpose was to keep a `ParagraphNode` import alive in
parity_cluster_1; the import is exercised elsewhere now).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
//! Phase 19: LSP folding-range provider.
|
||||
//!
|
||||
//! Drives `folding::folding_ranges` directly. The handler wiring is
|
||||
//! shallow — it just calls into this function — so we verify the
|
||||
//! shapes here and trust the integration via the LSP test harness in
|
||||
//! `lsp_helpers.rs`.
|
||||
|
||||
use nuwiki_core::syntax::vimwiki::VimwikiSyntax;
|
||||
use nuwiki_core::syntax::SyntaxPlugin;
|
||||
use nuwiki_lsp::folding;
|
||||
|
||||
fn parse(src: &str) -> nuwiki_core::ast::DocumentNode {
|
||||
VimwikiSyntax::new().parse(src)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_headings_no_lists_emits_no_folds() {
|
||||
let src = "just text\non two lines\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
assert!(folds.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_heading_folds_to_end_of_document() {
|
||||
let src = "= Title =\nbody line 1\nbody line 2\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
assert_eq!(folds.len(), 1);
|
||||
assert_eq!(folds[0].start_line, 0);
|
||||
// body line 2 is line 2; trailing newline pushes line_count to 4 so
|
||||
// last_line == 3 (the empty line after the final newline).
|
||||
assert!(folds[0].end_line >= 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sibling_headings_each_get_their_own_fold() {
|
||||
let src = "= One =\nbody\n= Two =\nbody2\n= Three =\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
let heading_folds: Vec<_> = folds
|
||||
.iter()
|
||||
.filter(|f| f.start_line == 0 || f.start_line == 2 || f.start_line == 4)
|
||||
.collect();
|
||||
assert_eq!(heading_folds.len(), 3, "got: {folds:?}");
|
||||
// One closes before Two
|
||||
assert_eq!(heading_folds[0].end_line, 1);
|
||||
// Two closes before Three
|
||||
assert_eq!(heading_folds[1].end_line, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_heading_folds_inside_parent() {
|
||||
let src = "= Outer =\nintro\n== Inner ==\nbody\n= Other =\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
// Outer fold spans up to the line before `= Other =` (line 4).
|
||||
let outer = folds
|
||||
.iter()
|
||||
.find(|f| f.start_line == 0)
|
||||
.expect("outer fold");
|
||||
assert_eq!(outer.end_line, 3);
|
||||
// Inner fold is bounded by the next h1 too (since the only following
|
||||
// heading is h1, which has level <= 2).
|
||||
let inner = folds
|
||||
.iter()
|
||||
.find(|f| f.start_line == 2)
|
||||
.expect("inner fold");
|
||||
assert_eq!(inner.end_line, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn top_level_list_gets_its_own_fold() {
|
||||
let src = "before\n- item one\n- item two\n- item three\nafter\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
let list_fold = folds.iter().find(|f| f.start_line == 1);
|
||||
assert!(list_fold.is_some(), "expected a list fold: {folds:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_line_blocks_are_not_folded() {
|
||||
let src = "= Solo =\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
// A heading on the only line of the document covers nothing
|
||||
// foldable, so it's omitted.
|
||||
let none_for_solo = folds
|
||||
.iter()
|
||||
.all(|f| !(f.start_line == 0 && f.end_line == 0));
|
||||
assert!(none_for_solo, "got: {folds:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fold_kind_is_region() {
|
||||
use tower_lsp::lsp_types::FoldingRangeKind;
|
||||
let src = "= H =\nbody\n";
|
||||
let ast = parse(src);
|
||||
let folds = folding::folding_ranges(&ast, folding::line_count(src));
|
||||
assert!(!folds.is_empty());
|
||||
assert_eq!(folds[0].kind, Some(FoldingRangeKind::Region));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_count_matches_intuitive_definition() {
|
||||
assert_eq!(folding::line_count(""), 0);
|
||||
assert_eq!(folding::line_count("one"), 1);
|
||||
assert_eq!(folding::line_count("one\n"), 2); // trailing newline → virtual empty line
|
||||
assert_eq!(folding::line_count("one\ntwo"), 2);
|
||||
assert_eq!(folding::line_count("one\ntwo\n"), 3);
|
||||
}
|
||||
Reference in New Issue
Block a user