#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![forbid(unsafe_code)]
pub extern crate lsp;
mod client;
mod codec;
pub mod jsonrpc;
mod server;
mod service;
mod transport;
pub use self::{
client::{CancellationToken, Client, TokenCanceller},
service::{ExitedError, LspService, MessageStream},
transport::Server,
};
pub use async_trait::async_trait;
use auto_impl::auto_impl;
use lspower_macros::rpc;
#[rpc]
#[async_trait]
#[auto_impl(Arc, Box)]
pub trait LanguageServer: Send + Sync + 'static {
#[rpc(name = "initialize")]
async fn initialize(&self, params: lsp::InitializeParams) -> crate::jsonrpc::Result<lsp::InitializeResult>;
#[rpc(name = "initialized")]
async fn initialized(&self, _params: lsp::InitializedParams) {
}
#[rpc(name = "shutdown")]
async fn shutdown(&self) -> crate::jsonrpc::Result<()>;
#[rpc(name = "workspace/didChangeWorkspaceFolders")]
async fn did_change_workspace_folders(&self, _params: lsp::DidChangeWorkspaceFoldersParams) {
log::warn!("Got a workspace/didChangeWorkspaceFolders notification, but it is not implemented");
}
#[rpc(name = "workspace/didChangeConfiguration")]
async fn did_change_configuration(&self, _params: lsp::DidChangeConfigurationParams) {
log::warn!("Got a workspace/didChangeConfiguration notification, but it is not implemented");
}
#[rpc(name = "workspace/didChangeWatchedFiles")]
async fn did_change_watched_files(&self, _params: lsp::DidChangeWatchedFilesParams) {
log::warn!("Got a workspace/didChangeWatchedFiles notification, but it is not implemented");
}
#[rpc(name = "workspace/symbol")]
async fn symbol(
&self,
_params: lsp::WorkspaceSymbolParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::SymbolInformation>>> {
log::error!("Got a workspace/symbol request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "workspace/executeCommand")]
async fn execute_command(
&self,
_params: lsp::ExecuteCommandParams,
) -> crate::jsonrpc::Result<Option<serde_json::Value>> {
log::error!("Got a workspace/executeCommand request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/didOpen")]
async fn did_open(&self, _params: lsp::DidOpenTextDocumentParams) {
log::warn!("Got a textDocument/didOpen notification, but it is not implemented");
}
#[rpc(name = "textDocument/didChange")]
async fn did_change(&self, _params: lsp::DidChangeTextDocumentParams) {
log::warn!("Got a textDocument/didChange notification, but it is not implemented");
}
#[rpc(name = "textDocument/willSave")]
async fn will_save(&self, _params: lsp::WillSaveTextDocumentParams) {
log::warn!("Got a textDocument/willSave notification, but it is not implemented");
}
#[rpc(name = "textDocument/willSaveWaitUntil")]
async fn will_save_wait_until(
&self,
_params: lsp::WillSaveTextDocumentParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::TextEdit>>> {
log::error!("Got a textDocument/willSaveWaitUntil request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/didSave")]
async fn did_save(&self, _params: lsp::DidSaveTextDocumentParams) {
log::warn!("Got a textDocument/didSave notification, but it is not implemented");
}
#[rpc(name = "textDocument/didClose")]
async fn did_close(&self, _params: lsp::DidCloseTextDocumentParams) {
log::warn!("Got a textDocument/didClose notification, but it is not implemented");
}
#[rpc(name = "textDocument/completion")]
async fn completion(
&self,
_params: lsp::CompletionParams,
) -> crate::jsonrpc::Result<Option<lsp::CompletionResponse>> {
log::error!("Got a textDocument/completion request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "completionItem/resolve")]
async fn completion_resolve(&self, _params: lsp::CompletionItem) -> crate::jsonrpc::Result<lsp::CompletionItem> {
log::error!("Got a completionItem/resolve request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/hover")]
async fn hover(&self, _params: lsp::HoverParams) -> crate::jsonrpc::Result<Option<lsp::Hover>> {
log::error!("Got a textDocument/hover request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/signatureHelp")]
async fn signature_help(
&self,
_params: lsp::SignatureHelpParams,
) -> crate::jsonrpc::Result<Option<lsp::SignatureHelp>> {
log::error!("Got a textDocument/signatureHelp request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/declaration")]
async fn goto_declaration(
&self,
_params: lsp::request::GotoDeclarationParams,
) -> crate::jsonrpc::Result<Option<lsp::request::GotoDeclarationResponse>> {
log::error!("Got a textDocument/declaration request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/definition")]
async fn goto_definition(
&self,
_params: lsp::GotoDefinitionParams,
) -> crate::jsonrpc::Result<Option<lsp::GotoDefinitionResponse>> {
log::error!("Got a textDocument/definition request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/typeDefinition")]
async fn goto_type_definition(
&self,
_params: lsp::request::GotoTypeDefinitionParams,
) -> crate::jsonrpc::Result<Option<lsp::request::GotoTypeDefinitionResponse>> {
log::error!("Got a textDocument/typeDefinition request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/implementation")]
async fn goto_implementation(
&self,
_params: lsp::request::GotoImplementationParams,
) -> crate::jsonrpc::Result<Option<lsp::request::GotoImplementationResponse>> {
log::error!("Got a textDocument/implementation request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/references")]
async fn references(&self, _params: lsp::ReferenceParams) -> crate::jsonrpc::Result<Option<Vec<lsp::Location>>> {
log::error!("Got a textDocument/references request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/documentHighlight")]
async fn document_highlight(
&self,
_params: lsp::DocumentHighlightParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::DocumentHighlight>>> {
log::error!("Got a textDocument/documentHighlight request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/documentSymbol")]
async fn document_symbol(
&self,
_params: lsp::DocumentSymbolParams,
) -> crate::jsonrpc::Result<Option<lsp::DocumentSymbolResponse>> {
log::error!("Got a textDocument/documentSymbol request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/codeAction")]
async fn code_action(
&self,
_params: lsp::CodeActionParams,
) -> crate::jsonrpc::Result<Option<lsp::CodeActionResponse>> {
log::error!("Got a textDocument/codeAction request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/codeLens")]
async fn code_lens(&self, _params: lsp::CodeLensParams) -> crate::jsonrpc::Result<Option<Vec<lsp::CodeLens>>> {
log::error!("Got a textDocument/codeLens request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "codeLens/resolve")]
async fn code_lens_resolve(&self, _params: lsp::CodeLens) -> crate::jsonrpc::Result<lsp::CodeLens> {
log::error!("Got a codeLens/resolve request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/documentLink")]
async fn document_link(
&self,
_params: lsp::DocumentLinkParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::DocumentLink>>> {
log::error!("Got a textDocument/documentLink request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "documentLink/resolve")]
async fn document_link_resolve(&self, _params: lsp::DocumentLink) -> crate::jsonrpc::Result<lsp::DocumentLink> {
log::error!("Got a documentLink/resolve request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/documentColor")]
async fn document_color(
&self,
_params: lsp::DocumentColorParams,
) -> crate::jsonrpc::Result<Vec<lsp::ColorInformation>> {
log::error!("Got a textDocument/documentColor request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/colorPresentation")]
async fn color_presentation(
&self,
_params: lsp::ColorPresentationParams,
) -> crate::jsonrpc::Result<Vec<lsp::ColorPresentation>> {
log::error!("Got a textDocument/colorPresentation request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/formatting")]
async fn formatting(
&self,
_params: lsp::DocumentFormattingParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::TextEdit>>> {
log::error!("Got a textDocument/formatting request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/rangeFormatting")]
async fn range_formatting(
&self,
_params: lsp::DocumentRangeFormattingParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::TextEdit>>> {
log::error!("Got a textDocument/rangeFormatting request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/onTypeFormatting")]
async fn on_type_formatting(
&self,
_params: lsp::DocumentOnTypeFormattingParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::TextEdit>>> {
log::error!("Got a textDocument/onTypeFormatting request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/rename")]
async fn rename(&self, _params: lsp::RenameParams) -> crate::jsonrpc::Result<Option<lsp::WorkspaceEdit>> {
log::error!("Got a textDocument/rename request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/prepareRename")]
async fn prepare_rename(
&self,
_params: lsp::TextDocumentPositionParams,
) -> crate::jsonrpc::Result<Option<lsp::PrepareRenameResponse>> {
log::error!("Got a textDocument/prepareRename request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/foldingRange")]
async fn folding_range(
&self,
_params: lsp::FoldingRangeParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::FoldingRange>>> {
log::error!("Got a textDocument/foldingRange request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/selectionRange")]
async fn selection_range(
&self,
_params: lsp::SelectionRangeParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::SelectionRange>>> {
log::error!("Got a textDocument/selectionRange request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "callHierarchy/incomingCalls")]
async fn incoming_calls(
&self,
_params: lsp::CallHierarchyIncomingCallsParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::CallHierarchyIncomingCall>>> {
log::error!("Got a callHierarchy/incomingCalls request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "callHierarchy/outgoingCalls")]
async fn outgoing_calls(
&self,
_params: lsp::CallHierarchyOutgoingCallsParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::CallHierarchyOutgoingCall>>> {
log::error!("Got a callHierarchy/outgoingCalls request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/prepareCallHierarchy")]
async fn prepare_call_hierarchy(
&self,
_params: lsp::CallHierarchyPrepareParams,
) -> crate::jsonrpc::Result<Option<Vec<lsp::CallHierarchyItem>>> {
log::error!("Got a textDocument/prepareCallHierarchy request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/semanticTokens/full")]
async fn semantic_tokens_full(
&self,
_params: lsp::SemanticTokensParams,
) -> crate::jsonrpc::Result<Option<lsp::SemanticTokensResult>> {
log::error!("Got a textDocument/semanticTokens/full request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/semanticTokens/full/delta")]
async fn semantic_tokens_full_delta(
&self,
_params: lsp::SemanticTokensDeltaParams,
) -> crate::jsonrpc::Result<Option<lsp::SemanticTokensFullDeltaResult>> {
log::error!("Got a textDocument/semanticTokens/full/delta request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "textDocument/semanticTokens/range")]
async fn semantic_tokens_range(
&self,
_params: lsp::SemanticTokensRangeParams,
) -> crate::jsonrpc::Result<Option<lsp::SemanticTokensRangeResult>> {
log::error!("Got a textDocument/semanticTokens/range request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "workspace/semanticTokens/refresh")]
async fn semantic_tokens_refresh(&self) -> crate::jsonrpc::Result<()> {
log::error!("Got a workspace/semanticTokens/refresh request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
#[rpc(name = "codeAction/resolve")]
async fn code_action_resolve(&self, _params: lsp::CodeAction) -> crate::jsonrpc::Result<lsp::CodeAction> {
log::error!("Got a codeAction/resolve request, but it is not implemented");
Err(crate::jsonrpc::Error::method_not_found())
}
async fn request_else(
&self,
method: &str,
_params: Option<serde_json::Value>,
) -> crate::jsonrpc::Result<Option<serde_json::Value>> {
log::error!(
"Got a {} request, but LanguageServer::request_else is not implemented",
method
);
Err(crate::jsonrpc::Error::method_not_found())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jsonrpc::{Id, Incoming, Outgoing, Response};
use serde_json::json;
use std::task::Poll;
use tower_test::mock::Spawn;
#[derive(Debug, Default)]
struct Mock;
#[async_trait]
impl crate::LanguageServer for Mock {
async fn initialize(&self, _: lsp::InitializeParams) -> crate::jsonrpc::Result<lsp::InitializeResult> {
Ok(lsp::InitializeResult::default())
}
async fn shutdown(&self) -> crate::jsonrpc::Result<()> {
Ok(())
}
}
mod helper {
use super::*;
use crate::jsonrpc::Incoming;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::json;
use std::task::Poll;
use tower_test::mock::Spawn;
pub(super) async fn initialize(service: &mut Spawn<LspService>) {
let params = serde_json::from_value::<lsp::InitializeParams>(json!({ "capabilities": {} })).unwrap();
let request: Incoming = request("initialize", params).unwrap();
let response =
serde_json::from_value(json!({ "jsonrpc": "2.0", "result": { "capabilities": {} }, "id": 1 })).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(Some(response)));
}
pub(super) fn request<I: Serialize, O: DeserializeOwned>(
method: &str,
params: I,
) -> Result<O, serde_json::Error> {
serde_json::from_value(json!({
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": 1,
}))
}
}
#[tokio::test]
async fn initialize() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
helper::initialize(&mut service).await;
}
#[tokio::test]
async fn initialized() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
helper::initialize(&mut service).await;
let params = lsp::InitializedParams {};
let request: Incoming = helper::request("initialized", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn shutdown() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
helper::initialize(&mut service).await;
let request: Incoming = helper::request("shutdown", ()).unwrap();
let response = Response::ok(Id::Number(1), json!(null));
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
mod call_hierarchy {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use std::task::Poll;
use tower_test::mock::Spawn;
#[tokio::test]
async fn incoming_calls() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CallHierarchyIncomingCallsParams {
item: lsp::CallHierarchyItem {
name: Default::default(),
kind: lsp::SymbolKind::NULL,
tags: Default::default(),
detail: Default::default(),
uri: lsp::Url::parse("inmemory::///test").unwrap(),
range: Default::default(),
selection_range: Default::default(),
data: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("callHierarchy/incomingCalls", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn outgoing_calls() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CallHierarchyOutgoingCallsParams {
item: lsp::CallHierarchyItem {
name: Default::default(),
kind: lsp::SymbolKind::NULL,
tags: Default::default(),
detail: Default::default(),
uri: lsp::Url::parse("inmemory::///test").unwrap(),
range: Default::default(),
selection_range: Default::default(),
data: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("callHierarchy/outgoingCalls", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
mod code_action {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use std::task::Poll;
use tower_test::mock::Spawn;
#[tokio::test]
async fn resolve() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CodeAction::default();
let request: Incoming = helper::request("codeAction/resolve", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
mod completion_item {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use std::task::Poll;
use tower_test::mock::Spawn;
#[tokio::test]
async fn resolve() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CompletionItem::default();
let request: Incoming = helper::request("completionItem/resolve", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
mod text_document {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use std::task::Poll;
use tower_test::mock::Spawn;
mod semantic_tokens {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use std::task::Poll;
use tower_test::mock::Spawn;
mod full {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use std::task::Poll;
use tower_test::mock::Spawn;
#[tokio::test]
async fn delta() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::SemanticTokensDeltaParams {
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
previous_result_id: Default::default(),
};
let request: Incoming = helper::request("textDocument/semanticTokens/full", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
#[tokio::test]
async fn full() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::SemanticTokensParams {
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
};
let request: Incoming = helper::request("textDocument/semanticTokens/full", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn range() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::SemanticTokensRangeParams {
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
range: Default::default(),
};
let request: Incoming = helper::request("textDocument/semanticTokens/range", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn refresh() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let request: Incoming = helper::request("textDocument/semanticTokens/refresh", ()).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
#[tokio::test]
async fn code_action() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CodeActionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
range: Default::default(),
context: Default::default(),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/codeAction", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn code_lens() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CodeLensParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/codeLens", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn code_lens_resolve() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CodeLens {
range: Default::default(),
command: Default::default(),
data: Default::default(),
};
let request: Incoming = helper::request("textDocument/codeLensResolve", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn color_presentation() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::ColorPresentationParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
color: lsp::Color {
red: Default::default(),
green: Default::default(),
blue: Default::default(),
alpha: Default::default(),
},
range: Default::default(),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/colorPresentation", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn completion() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CompletionParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
context: Default::default(),
};
let request: Incoming = helper::request("textDocument/completion", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn declaration() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::request::GotoDeclarationParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/declaration", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn definition() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::GotoDefinitionParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/definition", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn did_change() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidChangeTextDocumentParams {
text_document: lsp::VersionedTextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
version: Default::default(),
},
content_changes: Default::default(),
};
let request: Incoming = helper::request("textDocument/didChange", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn did_close() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidCloseTextDocumentParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
};
let request: Incoming = helper::request("textDocument/didClose", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn did_open() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidOpenTextDocumentParams {
text_document: lsp::TextDocumentItem {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
language_id: Default::default(),
version: Default::default(),
text: Default::default(),
},
};
let request: Incoming = helper::request("textDocument/didOpen", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn did_save() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidSaveTextDocumentParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
text: Default::default(),
};
let request: Incoming = helper::request("textDocument/didSave", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn document_color() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentColorParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/documentColor", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn document_highlight() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentHighlightParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/documentHighlight", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn document_link() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentLinkParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/documentLink", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn document_link_resolve() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentLink {
range: Default::default(),
target: Default::default(),
tooltip: Default::default(),
data: Default::default(),
};
let request: Incoming = helper::request("textDocument/documentLinkResolve", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn document_symbol() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentSymbolParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/documentSymbol", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn folding_range() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::FoldingRangeParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/foldingRange", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn formatting() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentFormattingParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
options: Default::default(),
work_done_progress_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/formatting", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn hover() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::HoverParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/hover", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn implementation() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::request::GotoImplementationParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/implementation", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn on_type_formatting() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentOnTypeFormattingParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
ch: Default::default(),
options: Default::default(),
};
let request: Incoming = helper::request("textDocument/onTypeFormatting", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn prepare_call_hierarchy() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::CallHierarchyPrepareParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/prepareCallHierarchy", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn prepare_rename() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
};
let request: Incoming = helper::request("textDocument/prepareRename", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn range_formatting() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DocumentRangeFormattingParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
range: Default::default(),
options: Default::default(),
work_done_progress_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/rangeFormatting", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn references() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::ReferenceParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
context: lsp::ReferenceContext {
include_declaration: Default::default(),
},
};
let request: Incoming = helper::request("textDocument/references", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn rename() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::RenameParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
new_name: Default::default(),
work_done_progress_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/rename", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn request_else() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = None::<serde_json::Value>;
let request: Incoming = helper::request("foo/bar", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn selection_range() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::SelectionRangeParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
positions: Default::default(),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/selectionRange", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn signature_help() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::SignatureHelpParams {
context: Default::default(),
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/signatureHelp", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn type_definition() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::request::GotoTypeDefinitionParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
position: Default::default(),
},
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
};
let request: Incoming = helper::request("textDocument/typeDefinition", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn will_save() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::WillSaveTextDocumentParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
reason: lsp::TextDocumentSaveReason::MANUAL,
};
let request: Incoming = helper::request("textDocument/willSave", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn will_save_wait_until() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::WillSaveTextDocumentParams {
text_document: lsp::TextDocumentIdentifier {
uri: lsp::Url::parse("inmemory::///test").unwrap(),
},
reason: lsp::TextDocumentSaveReason::MANUAL,
};
let request: Incoming = helper::request("textDocument/willSaveWaitUntil", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
mod workspace {
use super::*;
use crate::jsonrpc::{Error, Id, Incoming, Outgoing, Response};
use serde_json::Value;
use std::task::Poll;
use tower_test::mock::Spawn;
#[tokio::test]
async fn did_change_configuration() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidChangeConfigurationParams { settings: Value::Null };
let request: Incoming = helper::request("workspace/didChangeConfiguration", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn did_change_watched_files() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidChangeWatchedFilesParams {
changes: Default::default(),
};
let request: Incoming = helper::request("workspace/didChangeWatchedFiles", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn did_change_workspace_folders() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::DidChangeWorkspaceFoldersParams::default();
let request: Incoming = helper::request("workspace/didChangeWorkspaceFolders", params).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(request.clone()).await, Ok(None));
}
#[tokio::test]
async fn execute_command() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::ExecuteCommandParams::default();
let request: Incoming = helper::request("workspace/executeCommand", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
#[tokio::test]
async fn symbol() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
super::helper::initialize(&mut service).await;
let params = lsp::WorkspaceSymbolParams::default();
let request: Incoming = helper::request("workspace/symbol", params).unwrap();
let response = Response::error(Some(Id::Number(1)), Error::method_not_found());
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(
service.call(request.clone()).await,
Ok(Some(Outgoing::Response(response)))
);
}
}
}