use rumdl_lib::lsp::server::RumdlLanguageServer;
use tower_lsp::lsp_types::*;
use tower_lsp::{LanguageServer, LspService};
#[tokio::test]
async fn test_formatting_without_did_open() {
let (service, _socket) = LspService::new(|client| RumdlLanguageServer::new(client, None));
let init_params = InitializeParams {
capabilities: ClientCapabilities::default(),
initialization_options: None,
process_id: Some(1),
root_path: None,
root_uri: None,
trace: None,
workspace_folders: None,
client_info: None,
locale: None,
};
let _init_result = service.inner().initialize(init_params).await.unwrap();
let temp_dir = std::env::temp_dir();
let test_file = temp_dir.join("test_unopened.md");
let test_content = "#Missing space\n\nTrailing spaces \n";
std::fs::write(&test_file, test_content).unwrap();
let uri = Url::from_file_path(&test_file).unwrap();
let formatting_params = DocumentFormattingParams {
text_document: TextDocumentIdentifier { uri: uri.clone() },
options: FormattingOptions {
tab_size: 4,
insert_spaces: true,
properties: std::collections::HashMap::new(),
trim_trailing_whitespace: Some(true),
insert_final_newline: Some(true),
trim_final_newlines: Some(true),
},
work_done_progress_params: WorkDoneProgressParams::default(),
};
let result = service.inner().formatting(formatting_params).await;
std::fs::remove_file(&test_file).ok();
assert!(result.is_ok(), "Formatting should not error");
let edits = result.unwrap();
assert!(edits.is_some(), "Should return Some(edits), not None");
let edits = edits.unwrap();
assert!(
!edits.is_empty(),
"Should return formatting edits for the file on disk, but got empty array"
);
if !edits.is_empty() {
assert_eq!(edits.len(), 1, "Should have one edit replacing the document");
let edit = &edits[0];
assert!(edit.new_text.contains("# Missing space"), "Should fix the heading");
assert!(!edit.new_text.contains(" \n"), "Should remove trailing spaces");
assert!(edit.new_text.ends_with('\n'), "Should add final newline");
}
}
#[tokio::test]
async fn test_formatting_with_did_open_still_works() {
let (service, _socket) = LspService::new(|client| RumdlLanguageServer::new(client, None));
let init_params = InitializeParams {
capabilities: ClientCapabilities::default(),
initialization_options: None,
process_id: Some(1),
root_path: None,
root_uri: None,
trace: None,
workspace_folders: None,
client_info: None,
locale: None,
};
let _init_result = service.inner().initialize(init_params).await.unwrap();
let uri = Url::parse("file:///test/opened.md").unwrap();
let text = "#Missing space\n\nTrailing spaces \n";
service
.inner()
.did_open(DidOpenTextDocumentParams {
text_document: TextDocumentItem {
uri: uri.clone(),
language_id: "markdown".to_string(),
version: 1,
text: text.to_string(),
},
})
.await;
let formatting_params = DocumentFormattingParams {
text_document: TextDocumentIdentifier { uri: uri.clone() },
options: FormattingOptions {
tab_size: 4,
insert_spaces: true,
properties: std::collections::HashMap::new(),
trim_trailing_whitespace: Some(true),
insert_final_newline: Some(true),
trim_final_newlines: Some(true),
},
work_done_progress_params: WorkDoneProgressParams::default(),
};
let result = service.inner().formatting(formatting_params).await;
assert!(result.is_ok(), "Formatting should succeed");
let edits = result.unwrap();
assert!(edits.is_some(), "Should return Some(edits)");
let edits = edits.unwrap();
assert!(!edits.is_empty(), "Should return formatting edits");
assert_eq!(edits.len(), 1, "Should have one edit");
let edit = &edits[0];
assert!(edit.new_text.contains("# Missing space"), "Should fix the heading");
assert!(!edit.new_text.contains(" \n"), "Should remove trailing spaces");
assert!(edit.new_text.ends_with('\n'), "Should add final newline");
}
#[tokio::test]
async fn test_formatting_nonexistent_file() {
let (service, _socket) = LspService::new(|client| RumdlLanguageServer::new(client, None));
let init_params = InitializeParams {
capabilities: ClientCapabilities::default(),
initialization_options: None,
process_id: Some(1),
root_path: None,
root_uri: None,
trace: None,
workspace_folders: None,
client_info: None,
locale: None,
};
let _init_result = service.inner().initialize(init_params).await.unwrap();
let uri = Url::parse("file:///nonexistent/file.md").unwrap();
let formatting_params = DocumentFormattingParams {
text_document: TextDocumentIdentifier { uri: uri.clone() },
options: FormattingOptions {
tab_size: 4,
insert_spaces: true,
properties: std::collections::HashMap::new(),
trim_trailing_whitespace: Some(true),
insert_final_newline: Some(true),
trim_final_newlines: Some(true),
},
work_done_progress_params: WorkDoneProgressParams::default(),
};
let result = service.inner().formatting(formatting_params).await;
assert!(result.is_ok(), "Should not error on non-existent file");
let edits = result.unwrap();
assert!(edits.is_none(), "Should return None for non-existent file per LSP spec");
}