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