Fix cargo test task for tests module in lib.rs, main.rs, mod.rs (#25092)

Closes #19161

Release Notes:
- Fixed not being able to spawn the `cargo test` task for a `tests`
module in `lib.rs`, `main.rs`, or `mod.rs`
This commit is contained in:
Cole Miller 2025-02-20 15:28:34 -05:00 committed by GitHub
parent 0eea8c3e60
commit 274e70e81d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -469,8 +469,8 @@ const RUST_BIN_NAME_TASK_VARIABLE: VariableName =
const RUST_BIN_KIND_TASK_VARIABLE: VariableName = const RUST_BIN_KIND_TASK_VARIABLE: VariableName =
VariableName::Custom(Cow::Borrowed("RUST_BIN_KIND")); VariableName::Custom(Cow::Borrowed("RUST_BIN_KIND"));
const RUST_MAIN_FUNCTION_TASK_VARIABLE: VariableName = const RUST_TEST_FRAGMENT_TASK_VARIABLE: VariableName =
VariableName::Custom(Cow::Borrowed("_rust_main_function_end")); VariableName::Custom(Cow::Borrowed("RUST_TEST_FRAGMENT"));
impl ContextProvider for RustContextProvider { impl ContextProvider for RustContextProvider {
fn build_context( fn build_context(
@ -489,36 +489,35 @@ impl ContextProvider for RustContextProvider {
let local_abs_path = local_abs_path.as_deref(); let local_abs_path = local_abs_path.as_deref();
let is_main_function = task_variables let mut variables = TaskVariables::default();
.get(&RUST_MAIN_FUNCTION_TASK_VARIABLE)
.is_some();
if is_main_function { if let Some(target) = local_abs_path
if let Some(target) = local_abs_path.and_then(|path| { .and_then(|path| package_name_and_bin_name_from_abs_path(path, project_env.as_ref()))
package_name_and_bin_name_from_abs_path(path, project_env.as_ref()) {
}) { variables.extend(TaskVariables::from_iter([
return Task::ready(Ok(TaskVariables::from_iter([ (RUST_PACKAGE_TASK_VARIABLE.clone(), target.package_name),
(RUST_PACKAGE_TASK_VARIABLE.clone(), target.package_name), (RUST_BIN_NAME_TASK_VARIABLE.clone(), target.target_name),
(RUST_BIN_NAME_TASK_VARIABLE.clone(), target.target_name), (
( RUST_BIN_KIND_TASK_VARIABLE.clone(),
RUST_BIN_KIND_TASK_VARIABLE.clone(), target.target_kind.to_string(),
target.target_kind.to_string(), ),
), ]));
])));
}
} }
if let Some(package_name) = local_abs_path if let Some(package_name) = local_abs_path
.and_then(|local_abs_path| local_abs_path.parent()) .and_then(|local_abs_path| local_abs_path.parent())
.and_then(|path| human_readable_package_name(path, project_env.as_ref())) .and_then(|path| human_readable_package_name(path, project_env.as_ref()))
{ {
return Task::ready(Ok(TaskVariables::from_iter([( variables.insert(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name);
RUST_PACKAGE_TASK_VARIABLE.clone(),
package_name,
)])));
} }
Task::ready(Ok(TaskVariables::default())) if let (Some(path), Some(stem)) = (local_abs_path, task_variables.get(&VariableName::Stem))
{
let fragment = test_fragment(&variables, path, stem);
variables.insert(RUST_TEST_FRAGMENT_TASK_VARIABLE, fragment);
};
Task::ready(Ok(variables))
} }
fn associated_tasks( fn associated_tasks(
@ -589,7 +588,7 @@ impl ContextProvider for RustContextProvider {
"test".into(), "test".into(),
"-p".into(), "-p".into(),
RUST_PACKAGE_TASK_VARIABLE.template_value(), RUST_PACKAGE_TASK_VARIABLE.template_value(),
VariableName::Stem.template_value(), RUST_TEST_FRAGMENT_TASK_VARIABLE.template_value(),
], ],
tags: vec!["rust-mod-test".to_owned()], tags: vec!["rust-mod-test".to_owned()],
cwd: Some("$ZED_DIRNAME".to_owned()), cwd: Some("$ZED_DIRNAME".to_owned()),
@ -824,6 +823,29 @@ async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServ
.log_err() .log_err()
} }
fn test_fragment(variables: &TaskVariables, path: &Path, stem: &str) -> String {
let fragment = if stem == "lib" {
// This isn't quite right---it runs the tests for the entire library, rather than
// just for the top-level `mod tests`. But we don't really have the means here to
// filter out just that module.
Some("--lib".to_owned())
} else if stem == "mod" {
maybe!({ Some(path.parent()?.file_name()?.to_string_lossy().to_string()) })
} else if stem == "main" {
if let (Some(bin_name), Some(bin_kind)) = (
variables.get(&RUST_BIN_NAME_TASK_VARIABLE),
variables.get(&RUST_BIN_KIND_TASK_VARIABLE),
) {
Some(format!("--{bin_kind}={bin_name}"))
} else {
None
}
} else {
Some(stem.to_owned())
};
fragment.unwrap_or_else(|| "--".to_owned())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::num::NonZeroU32; use std::num::NonZeroU32;
@ -1179,4 +1201,34 @@ mod tests {
); );
} }
} }
#[test]
fn test_rust_test_fragment() {
#[track_caller]
fn check(
variables: impl IntoIterator<Item = (VariableName, &'static str)>,
path: &str,
expected: &str,
) {
let path = Path::new(path);
let found = test_fragment(
&TaskVariables::from_iter(variables.into_iter().map(|(k, v)| (k, v.to_owned()))),
path,
&path.file_stem().unwrap().to_str().unwrap(),
);
assert_eq!(expected, found);
}
check([], "/project/src/lib.rs", "--lib");
check([], "/project/src/foo/mod.rs", "foo");
check(
[
(RUST_BIN_KIND_TASK_VARIABLE.clone(), "bin"),
(RUST_BIN_NAME_TASK_VARIABLE, "x"),
],
"/project/src/main.rs",
"--bin=x",
);
check([], "/project/src/main.rs", "--");
}
} }