add more tests for various scenarios (#2812)
* add more tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanups Signed-off-by: Jess Frazelle <github@jessfraz.com> * clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> * even more tests Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -67,6 +67,12 @@ impl Discovered {
|
||||
}
|
||||
|
||||
impl IntoDiagnostic for Discovered {
|
||||
fn to_lsp_diagnostic(&self, code: &str) -> Diagnostic {
|
||||
(&self).to_lsp_diagnostic(code)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnostic for &Discovered {
|
||||
fn to_lsp_diagnostic(&self, code: &str) -> Diagnostic {
|
||||
let message = self.finding.title.to_owned();
|
||||
let source_range = self.pos;
|
||||
|
||||
@ -14,21 +14,21 @@ use tower_lsp::{
|
||||
jsonrpc::Result as RpcResult,
|
||||
lsp_types::{
|
||||
CompletionItem, CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, CreateFilesParams,
|
||||
DeleteFilesParams, DiagnosticOptions, DiagnosticServerCapabilities, DidChangeConfigurationParams,
|
||||
DidChangeTextDocumentParams, DidChangeWatchedFilesParams, DidChangeWorkspaceFoldersParams,
|
||||
DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentDiagnosticParams,
|
||||
DocumentDiagnosticReport, DocumentDiagnosticReportResult, DocumentFilter, DocumentFormattingParams,
|
||||
DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse, Documentation, FoldingRange, FoldingRangeParams,
|
||||
FoldingRangeProviderCapability, FullDocumentDiagnosticReport, Hover, HoverContents, HoverParams,
|
||||
HoverProviderCapability, InitializeParams, InitializeResult, InitializedParams, InlayHint, InlayHintParams,
|
||||
InsertTextFormat, MarkupContent, MarkupKind, MessageType, OneOf, Position, RelatedFullDocumentDiagnosticReport,
|
||||
RenameFilesParams, RenameParams, SemanticToken, SemanticTokenType, SemanticTokens, SemanticTokensFullOptions,
|
||||
SemanticTokensLegend, SemanticTokensOptions, SemanticTokensParams, SemanticTokensRegistrationOptions,
|
||||
SemanticTokensResult, SemanticTokensServerCapabilities, ServerCapabilities, SignatureHelp,
|
||||
SignatureHelpOptions, SignatureHelpParams, StaticRegistrationOptions, TextDocumentItem,
|
||||
TextDocumentRegistrationOptions, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
|
||||
TextEdit, WorkDoneProgressOptions, WorkspaceEdit, WorkspaceFolder, WorkspaceFoldersServerCapabilities,
|
||||
WorkspaceServerCapabilities,
|
||||
DeleteFilesParams, DiagnosticOptions, DiagnosticServerCapabilities, DiagnosticSeverity,
|
||||
DidChangeConfigurationParams, DidChangeTextDocumentParams, DidChangeWatchedFilesParams,
|
||||
DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
|
||||
DidSaveTextDocumentParams, DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportResult,
|
||||
DocumentFilter, DocumentFormattingParams, DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse,
|
||||
Documentation, FoldingRange, FoldingRangeParams, FoldingRangeProviderCapability, FullDocumentDiagnosticReport,
|
||||
Hover, HoverContents, HoverParams, HoverProviderCapability, InitializeParams, InitializeResult,
|
||||
InitializedParams, InlayHint, InlayHintParams, InsertTextFormat, MarkupContent, MarkupKind, MessageType, OneOf,
|
||||
Position, RelatedFullDocumentDiagnosticReport, RenameFilesParams, RenameParams, SemanticToken,
|
||||
SemanticTokenType, SemanticTokens, SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions,
|
||||
SemanticTokensParams, SemanticTokensRegistrationOptions, SemanticTokensResult,
|
||||
SemanticTokensServerCapabilities, ServerCapabilities, SignatureHelp, SignatureHelpOptions, SignatureHelpParams,
|
||||
StaticRegistrationOptions, TextDocumentItem, TextDocumentRegistrationOptions, TextDocumentSyncCapability,
|
||||
TextDocumentSyncKind, TextDocumentSyncOptions, TextEdit, WorkDoneProgressOptions, WorkspaceEdit,
|
||||
WorkspaceFolder, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
||||
},
|
||||
Client, LanguageServer,
|
||||
};
|
||||
@ -168,14 +168,18 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
}
|
||||
|
||||
async fn inner_on_change(&self, params: TextDocumentItem, force: bool) {
|
||||
self.clear_diagnostics_map(¶ms.uri).await;
|
||||
// We already updated the code map in the shared backend.
|
||||
|
||||
// Lets update the tokens.
|
||||
let tokens = match crate::token::lexer(¶ms.text) {
|
||||
Ok(tokens) => tokens,
|
||||
Err(err) => {
|
||||
self.add_to_diagnostics(¶ms, err).await;
|
||||
self.add_to_diagnostics(¶ms, err, true).await;
|
||||
self.token_map.remove(¶ms.uri.to_string()).await;
|
||||
self.ast_map.remove(¶ms.uri.to_string()).await;
|
||||
self.symbols_map.remove(¶ms.uri.to_string()).await;
|
||||
self.semantic_tokens_map.remove(¶ms.uri.to_string()).await;
|
||||
self.memory_map.remove(¶ms.uri.to_string()).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -215,7 +219,10 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
let ast = match result {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
self.add_to_diagnostics(¶ms, err).await;
|
||||
self.add_to_diagnostics(¶ms, err, true).await;
|
||||
self.ast_map.remove(¶ms.uri.to_string()).await;
|
||||
self.symbols_map.remove(¶ms.uri.to_string()).await;
|
||||
self.memory_map.remove(¶ms.uri.to_string()).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -243,6 +250,21 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
ast.get_lsp_symbols(¶ms.text).unwrap_or_default(),
|
||||
)
|
||||
.await;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let discovered_findings = ast
|
||||
.lint(checks::lint_variables)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
// Clear the lints before we lint.
|
||||
self.clear_diagnostics_map(¶ms.uri, Some(DiagnosticSeverity::INFORMATION))
|
||||
.await;
|
||||
for discovered_finding in &discovered_findings {
|
||||
self.add_to_diagnostics(¶ms, discovered_finding, false).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send the notification to the client that the ast was updated.
|
||||
@ -261,12 +283,9 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
for discovered_finding in ast.lint(checks::lint_variables).into_iter().flatten() {
|
||||
self.add_to_diagnostics(¶ms, discovered_finding).await;
|
||||
}
|
||||
}
|
||||
// If we made it here we can clear the diagnostics.
|
||||
self.clear_diagnostics_map(¶ms.uri, Some(DiagnosticSeverity::ERROR))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +383,19 @@ impl Backend {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn clear_diagnostics_map(&self, uri: &url::Url) {
|
||||
async fn clear_diagnostics_map(&self, uri: &url::Url, severity: Option<DiagnosticSeverity>) {
|
||||
let mut items = match self.diagnostics_map.get(uri.as_str()).await {
|
||||
Some(DocumentDiagnosticReport::Full(report)) => report.full_document_diagnostic_report.items.clone(),
|
||||
_ => vec![],
|
||||
};
|
||||
|
||||
// If we only want to clear a specific severity, do that.
|
||||
if let Some(severity) = severity {
|
||||
items.retain(|x| x.severity != Some(severity));
|
||||
} else {
|
||||
items.clear();
|
||||
}
|
||||
|
||||
self.diagnostics_map
|
||||
.insert(
|
||||
uri.to_string(),
|
||||
@ -372,7 +403,7 @@ impl Backend {
|
||||
related_documents: None,
|
||||
full_document_diagnostic_report: FullDocumentDiagnosticReport {
|
||||
result_id: None,
|
||||
items: vec![],
|
||||
items: items.clone(),
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -380,7 +411,7 @@ impl Backend {
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
self.client.publish_diagnostics(uri.clone(), vec![], None).await;
|
||||
self.client.publish_diagnostics(uri.clone(), items, None).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,6 +419,7 @@ impl Backend {
|
||||
&self,
|
||||
params: &TextDocumentItem,
|
||||
diagnostic: DiagT,
|
||||
clear_all_before_add: bool,
|
||||
) {
|
||||
self.client
|
||||
.log_message(MessageType::INFO, format!("adding {:?} to diag", diagnostic))
|
||||
@ -395,6 +427,16 @@ impl Backend {
|
||||
|
||||
let diagnostic = diagnostic.to_lsp_diagnostic(¶ms.text);
|
||||
|
||||
if clear_all_before_add {
|
||||
self.clear_diagnostics_map(¶ms.uri, None).await;
|
||||
} else if diagnostic.severity == Some(DiagnosticSeverity::ERROR) {
|
||||
// If the diagnostic is an error, it will be the only error we get since that halts
|
||||
// execution.
|
||||
// Clear the diagnostics before we add a new one.
|
||||
self.clear_diagnostics_map(¶ms.uri, Some(DiagnosticSeverity::ERROR))
|
||||
.await;
|
||||
}
|
||||
|
||||
let DocumentDiagnosticReport::Full(mut report) = self
|
||||
.diagnostics_map
|
||||
.get(params.uri.clone().as_str())
|
||||
@ -410,6 +452,19 @@ impl Backend {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
// Ensure we don't already have this diagnostic.
|
||||
if report
|
||||
.full_document_diagnostic_report
|
||||
.items
|
||||
.iter()
|
||||
.any(|x| x == &diagnostic)
|
||||
{
|
||||
self.client
|
||||
.publish_diagnostics(params.uri.clone(), report.full_document_diagnostic_report.items, None)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
report.full_document_diagnostic_report.items.push(diagnostic);
|
||||
|
||||
self.diagnostics_map
|
||||
@ -443,7 +498,8 @@ impl Backend {
|
||||
let memory = match executor_ctx.run(ast, None).await {
|
||||
Ok(memory) => memory,
|
||||
Err(err) => {
|
||||
self.add_to_diagnostics(params, err).await;
|
||||
self.memory_map.remove(¶ms.uri.to_string()).await;
|
||||
self.add_to_diagnostics(params, err, false).await;
|
||||
|
||||
// Since we already published the diagnostics we don't really care about the error
|
||||
// string.
|
||||
|
||||
@ -2998,3 +2998,674 @@ async fn test_kcl_lsp_folding() {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_with_parse_error_and_ast_unchanged_but_has_diagnostics_reparse() {
|
||||
let server = kcl_lsp_server(false).await.unwrap();
|
||||
|
||||
let code = r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
|> ^^^things(3.14, %)"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: code.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_with_lint_and_ast_unchanged_but_has_diagnostics_reparse() {
|
||||
let server = kcl_lsp_server(false).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(3.14, %)"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: code.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_with_lint_and_parse_error_and_ast_unchanged_but_has_diagnostics_reparse() {
|
||||
let server = kcl_lsp_server(false).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
|> ^^^^thing(3.14, %)"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: code.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_lint_and_ast_unchanged_but_has_diagnostics_reexecute() {
|
||||
let server = kcl_lsp_server(true).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %, $seg01)
|
||||
|> line([-20, 0], %, $seg01)
|
||||
|> close(%)
|
||||
|> extrude(3.14, %)"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(ref diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 2);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: code.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 2);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_lint_reexecute_new_lint() {
|
||||
let server = kcl_lsp_server(true).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %, $seg01)
|
||||
|> line([-20, 0], %, $seg01)
|
||||
|> close(%)
|
||||
|> extrude(3.14, %)"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(ref diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 2);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: r#"const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %, $seg01)
|
||||
|> line([-20, 0], %, $seg01)
|
||||
|> close(%)
|
||||
|> extrude(3.14, %)
|
||||
const NEW_LINT = 1"#
|
||||
.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 2);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_lint_reexecute_new_ast_error() {
|
||||
let server = kcl_lsp_server(true).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %, $seg01)
|
||||
|> line([-20, 0], %, $seg01)
|
||||
|> close(%)
|
||||
|> ^^^extrude(3.14, %)"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(ref diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: r#"const part001 = startSketchOn('XY')
|
||||
|> ^^^^startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %, $seg01)
|
||||
|> line([-20, 0], %, $seg01)
|
||||
|> close(%)
|
||||
|> extrude(3.14, %)
|
||||
const NEW_LINT = 1"#
|
||||
.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_lint_reexecute_had_lint_new_parse_error() {
|
||||
let server = kcl_lsp_server(true).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(ref diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(symbols_map != vec![]);
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server
|
||||
.semantic_tokens_map
|
||||
.get("file:///test.kcl")
|
||||
.await
|
||||
.unwrap()
|
||||
.clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(memory != ProgramMemory::default());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: r#"const part001 = startSketchOn('XY')
|
||||
|> ^^^^startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(3.14, %)
|
||||
const NEW_LINT = 1"#
|
||||
.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await;
|
||||
assert!(ast.is_none());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").await;
|
||||
assert!(symbols_map.is_none());
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server
|
||||
.semantic_tokens_map
|
||||
.get("file:///test.kcl")
|
||||
.await
|
||||
.unwrap()
|
||||
.clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_kcl_lsp_code_lint_reexecute_had_lint_new_execution_error() {
|
||||
let server = kcl_lsp_server(true).await.unwrap();
|
||||
|
||||
let code = r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %)
|
||||
|> line([0, 20], %)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
"#;
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: code.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(ref diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
|
||||
// Get the token map.
|
||||
let token_map = server.token_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(token_map != vec![]);
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(symbols_map != vec![]);
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server
|
||||
.semantic_tokens_map
|
||||
.get("file:///test.kcl")
|
||||
.await
|
||||
.unwrap()
|
||||
.clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(memory != ProgramMemory::default());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
.did_change(tower_lsp::lsp_types::DidChangeTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::VersionedTextDocumentIdentifier {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
version: 2,
|
||||
},
|
||||
content_changes: vec![tower_lsp::lsp_types::TextDocumentContentChangeEvent {
|
||||
range: None,
|
||||
range_length: None,
|
||||
text: r#"const LINT = 1
|
||||
const part001 = startSketchOn('XY')
|
||||
|> startProfileAt([-10, -10], %)
|
||||
|> line([20, 0], %, $seg01)
|
||||
|> line([0, 20], %, $seg01)
|
||||
|> line([-20, 0], %)
|
||||
|> close(%)
|
||||
"#
|
||||
.to_string(),
|
||||
}],
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Get the token map.
|
||||
let token_map = server.token_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(token_map != vec![]);
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(ast != crate::ast::types::Program::default());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
assert!(symbols_map != vec![]);
|
||||
|
||||
// Get the semantic tokens map.
|
||||
let semantic_tokens_map = server
|
||||
.semantic_tokens_map
|
||||
.get("file:///test.kcl")
|
||||
.await
|
||||
.unwrap()
|
||||
.clone();
|
||||
assert!(semantic_tokens_map != vec![]);
|
||||
|
||||
// Get the memory.
|
||||
let memory = server.memory_map.get("file:///test.kcl").await;
|
||||
assert!(memory.is_none());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
let diagnostics = server.diagnostics_map.get("file:///test.kcl").await.unwrap().clone();
|
||||
// Check the diagnostics.
|
||||
if let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics {
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 2);
|
||||
} else {
|
||||
panic!("Expected full diagnostics");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user