Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21661 from Wilfred/initial_flycheck_tests
Add integration tests for flycheck
Lukas Wirth 2 months ago
parent e538437 · parent 3f65590 · commit 7278462
-rw-r--r--crates/rust-analyzer/src/flycheck.rs4
-rw-r--r--crates/rust-analyzer/tests/slow-tests/flycheck.rs76
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs1
-rw-r--r--crates/rust-analyzer/tests/slow-tests/support.rs51
4 files changed, 131 insertions, 1 deletions
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index 47f7a57f72..f7f861a99e 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -382,6 +382,7 @@ enum FlycheckCommandOrigin {
ProjectJsonRunnable,
}
+#[derive(Debug)]
enum StateChange {
Restart {
generation: DiagnosticsGeneration,
@@ -435,6 +436,7 @@ enum DiagnosticsReceived {
}
#[allow(clippy::large_enum_variant)]
+#[derive(Debug)]
enum Event {
RequestStateChange(StateChange),
CheckEvent(Option<CheckMessage>),
@@ -445,6 +447,7 @@ const SAVED_FILE_PLACEHOLDER_DOLLAR: &str = "$saved_file";
const LABEL_INLINE: &str = "{label}";
const SAVED_FILE_INLINE: &str = "{saved_file}";
+#[derive(Debug)]
struct Substitutions<'a> {
label: Option<&'a str>,
saved_file: Option<&'a str>,
@@ -950,6 +953,7 @@ impl FlycheckActor {
}
#[allow(clippy::large_enum_variant)]
+#[derive(Debug)]
enum CheckMessage {
/// A message from `cargo check`, including details like the path
/// to the relevant `Cargo.toml`.
diff --git a/crates/rust-analyzer/tests/slow-tests/flycheck.rs b/crates/rust-analyzer/tests/slow-tests/flycheck.rs
new file mode 100644
index 0000000000..0aa107e823
--- /dev/null
+++ b/crates/rust-analyzer/tests/slow-tests/flycheck.rs
@@ -0,0 +1,76 @@
+use test_utils::skip_slow_tests;
+
+use crate::support::Project;
+
+#[test]
+fn test_flycheck_diagnostics_for_unused_variable() {
+ if skip_slow_tests() {
+ return;
+ }
+
+ let server = Project::with_fixture(
+ r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/main.rs
+fn main() {
+ let x = 1;
+}
+"#,
+ )
+ .with_config(serde_json::json!({
+ "checkOnSave": true,
+ }))
+ .server()
+ .wait_until_workspace_is_loaded();
+
+ let diagnostics = server.wait_for_diagnostics();
+ assert!(
+ diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")),
+ "expected unused variable diagnostic, got: {:?}",
+ diagnostics.diagnostics,
+ );
+}
+
+#[test]
+fn test_flycheck_diagnostic_cleared_after_fix() {
+ if skip_slow_tests() {
+ return;
+ }
+
+ let server = Project::with_fixture(
+ r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/main.rs
+fn main() {
+ let x = 1;
+}
+"#,
+ )
+ .with_config(serde_json::json!({
+ "checkOnSave": true,
+ }))
+ .server()
+ .wait_until_workspace_is_loaded();
+
+ // Wait for the unused variable diagnostic to appear.
+ let diagnostics = server.wait_for_diagnostics();
+ assert!(
+ diagnostics.diagnostics.iter().any(|d| d.message.contains("unused variable")),
+ "expected unused variable diagnostic, got: {:?}",
+ diagnostics.diagnostics,
+ );
+
+ // Fix the code by removing the unused variable.
+ server.write_file_and_save("src/main.rs", "fn main() {}\n".to_owned());
+
+ // Wait for diagnostics to be cleared.
+ server.wait_for_diagnostics_cleared();
+}
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index b4a7b44d16..26ba549a29 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -15,6 +15,7 @@
extern crate rustc_driver as _;
mod cli;
+mod flycheck;
mod ratoml;
mod support;
mod testdir;
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index 195ad226ae..7ee31f3d53 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -8,7 +8,9 @@ use std::{
use crossbeam_channel::{Receiver, after, select};
use itertools::Itertools;
use lsp_server::{Connection, Message, Notification, Request};
-use lsp_types::{TextDocumentIdentifier, Url, notification::Exit, request::Shutdown};
+use lsp_types::{
+ PublishDiagnosticsParams, TextDocumentIdentifier, Url, notification::Exit, request::Shutdown,
+};
use parking_lot::{Mutex, MutexGuard};
use paths::{Utf8Path, Utf8PathBuf};
use rust_analyzer::{
@@ -407,6 +409,53 @@ impl Server {
.unwrap_or_else(|Timeout| panic!("timeout while waiting for ws to load"));
self
}
+ pub(crate) fn wait_for_diagnostics(&self) -> PublishDiagnosticsParams {
+ for msg in self.messages.borrow().iter() {
+ if let Message::Notification(n) = msg
+ && n.method == "textDocument/publishDiagnostics"
+ {
+ let params: PublishDiagnosticsParams =
+ serde_json::from_value(n.params.clone()).unwrap();
+ if !params.diagnostics.is_empty() {
+ return params;
+ }
+ }
+ }
+ loop {
+ let msg = self
+ .recv()
+ .unwrap_or_else(|Timeout| panic!("timeout while waiting for diagnostics"))
+ .expect("connection closed while waiting for diagnostics");
+ if let Message::Notification(n) = &msg
+ && n.method == "textDocument/publishDiagnostics"
+ {
+ let params: PublishDiagnosticsParams =
+ serde_json::from_value(n.params.clone()).unwrap();
+ if !params.diagnostics.is_empty() {
+ return params;
+ }
+ }
+ }
+ }
+
+ pub(crate) fn wait_for_diagnostics_cleared(&self) {
+ loop {
+ let msg = self
+ .recv()
+ .unwrap_or_else(|Timeout| panic!("timeout while waiting for diagnostics to clear"))
+ .expect("connection closed while waiting for diagnostics to clear");
+ if let Message::Notification(n) = &msg
+ && n.method == "textDocument/publishDiagnostics"
+ {
+ let params: PublishDiagnosticsParams =
+ serde_json::from_value(n.params.clone()).unwrap();
+ if params.diagnostics.is_empty() {
+ return;
+ }
+ }
+ }
+ }
+
fn wait_for_message_cond(
&self,
n: usize,