about summary refs log tree commit diff
diff options
context:
space:
mode:
authorduncan <duncan@thorny.io>2024-06-21 16:02:33 +0100
committerduncan <duncan@thorny.io>2024-07-28 07:43:07 +0100
commit53fea63c0c198656bfdf44fc4655728117a9cf00 (patch)
tree9713637ca904803363eda5fc48f2d7883b2d2246
parentb2719c4914ad077869aad1d0f397f45cc21c71c6 (diff)
downloadrust-53fea63c0c198656bfdf44fc4655728117a9cf00.tar.gz
rust-53fea63c0c198656bfdf44fc4655728117a9cf00.zip
17470 - run test explorer tests at the package level and add missing extra_test_bin_args settings
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs39
3 files changed, 54 insertions, 10 deletions
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index ce148037fcf..3dd2a91d8fd 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -24,7 +24,7 @@ pub mod project_json;
 mod test_runner;
 
 use command::{CommandHandle, ParseFromLine};
-pub use test_runner::{CargoTestHandle, CargoTestMessage, TestState};
+pub use test_runner::{CargoTestHandle, CargoTestMessage, TestState, TestTarget};
 
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
 pub enum InvocationStrategy {
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs b/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs
index c136dd13664..74ebca34103 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/test_runner.rs
@@ -59,19 +59,38 @@ pub struct CargoTestHandle {
 }
 
 // Example of a cargo test command:
-// cargo test --workspace --no-fail-fast -- module::func -Z unstable-options --format=json
+// cargo test --workspace --no-fail-fast -- -Z unstable-options --format=json
+// or
+// cargo test --package my-package --no-fail-fast -- module::func -Z unstable-options --format=json
+
+#[derive(Debug)]
+pub enum TestTarget {
+    Workspace,
+    Package(String),
+}
 
 impl CargoTestHandle {
     pub fn new(
         path: Option<&str>,
         options: CargoOptions,
         root: &AbsPath,
+        test_target: TestTarget,
         sender: Sender<CargoTestMessage>,
     ) -> std::io::Result<Self> {
         let mut cmd = Command::new(Tool::Cargo.path());
         cmd.env("RUSTC_BOOTSTRAP", "1");
         cmd.arg("test");
-        cmd.arg("--workspace");
+
+        match &test_target {
+            TestTarget::Package(package) => {
+                cmd.arg("--package");
+                cmd.arg(package);
+            }
+            TestTarget::Workspace => {
+                cmd.arg("--workspace");
+            }
+        };
+
         // --no-fail-fast is needed to ensure that all requested tests will run
         cmd.arg("--no-fail-fast");
         cmd.arg("--manifest-path");
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 44ff273b5ae..9bb31463226 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -27,7 +27,7 @@ use lsp_types::{
     SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
 use paths::Utf8PathBuf;
-use project_model::{ManifestPath, ProjectWorkspaceKind, TargetKind};
+use project_model::{CargoWorkspace, ManifestPath, ProjectWorkspaceKind, TargetKind};
 use serde_json::json;
 use stdx::{format_to, never};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
@@ -199,6 +199,20 @@ pub(crate) fn handle_view_item_tree(
     Ok(res)
 }
 
+// cargo test requires the real package name which might contain hyphens but
+// the test identifier passed to this function is the namespace form where hyphens
+// are replaced with underscores so we have to reverse this and find the real package name
+fn find_package_name(namespace_root: &str, cargo: &CargoWorkspace) -> Option<String> {
+    cargo.packages().find_map(|p| {
+        let package_name = &cargo[p].name;
+        if package_name.replace('-', "_") == namespace_root {
+            Some(package_name.clone())
+        } else {
+            None
+        }
+    })
+}
+
 pub(crate) fn handle_run_test(
     state: &mut GlobalState,
     params: lsp_ext::RunTestParams,
@@ -206,7 +220,7 @@ pub(crate) fn handle_run_test(
     if let Some(_session) = state.test_run_session.take() {
         state.send_notification::<lsp_ext::EndRunTest>(());
     }
-    // We detect the lowest common ansector of all included tests, and
+    // We detect the lowest common ancestor of all included tests, and
     // run it. We ignore excluded tests for now, the client will handle
     // it for us.
     let lca = match params.include {
@@ -225,20 +239,31 @@ pub(crate) fn handle_run_test(
             .unwrap_or_default(),
         None => "".to_owned(),
     };
-    let test_path = if lca.is_empty() {
-        None
-    } else if let Some((_, path)) = lca.split_once("::") {
-        Some(path)
+    let (namespace_root, test_path) = if lca.is_empty() {
+        (None, None)
+    } else if let Some((namespace_root, path)) = lca.split_once("::") {
+        (Some(namespace_root), Some(path))
     } else {
-        None
+        (Some(lca.as_str()), None)
     };
     let mut handles = vec![];
     for ws in &*state.workspaces {
         if let ProjectWorkspaceKind::Cargo { cargo, .. } = &ws.kind {
+            let test_target = if let Some(namespace_root) = namespace_root {
+                if let Some(package_name) = find_package_name(namespace_root, cargo) {
+                    flycheck::TestTarget::Package(package_name)
+                } else {
+                    flycheck::TestTarget::Workspace
+                }
+            } else {
+                flycheck::TestTarget::Workspace
+            };
+
             let handle = flycheck::CargoTestHandle::new(
                 test_path,
                 state.config.cargo_test_options(),
                 cargo.workspace_root(),
+                test_target,
                 state.test_run_sender.clone(),
             )?;
             handles.push(handle);