use std::path::Path;
use crate::{
cargo_affected, combined_output, git, init_git_with_initial_commit, replace_in_file,
write_two_module_project,
};
#[test]
fn new_integration_test_is_selected_and_tagged() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
write_two_module_project(dir, "sample_new_test");
init_git_with_initial_commit(dir);
let collect = cargo_affected(dir, &["affected", "collect"]);
assert!(
collect.status.success(),
"collect failed: {}",
String::from_utf8_lossy(&collect.stderr)
);
std::fs::create_dir_all(dir.join("tests")).unwrap();
std::fs::write(
dir.join("tests/integration_new.rs"),
"#[test]\nfn test_brand_new() {\n assert_eq!(1 + 1, 2);\n}\n",
)
.unwrap();
let status = cargo_affected(dir, &["affected", "status", "-v"]);
assert!(
status.status.success(),
"status (with new test) failed: {}",
String::from_utf8_lossy(&status.stderr)
);
let stdout = String::from_utf8_lossy(&status.stdout);
assert!(
stdout.contains("test_brand_new"),
"status should list the new test, got:\n{stdout}"
);
assert!(
stdout.contains("(new)"),
"status should tag new tests with (new), got:\n{stdout}"
);
assert!(
stdout.contains("1 new"),
"status should report 1 new test in the summary, got:\n{stdout}"
);
}
#[test]
fn ignored_test_not_perpetually_new() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
write_ignored_test_project(dir, "sample_ignored_new");
init_git_with_initial_commit(dir);
let collect = cargo_affected(dir, &["affected", "collect"]);
assert!(
collect.status.success(),
"collect failed: {}",
String::from_utf8_lossy(&collect.stderr)
);
let status = cargo_affected(dir, &["affected", "status", "-v"]);
assert!(
status.status.success(),
"status failed: {}",
String::from_utf8_lossy(&status.stderr)
);
let combined = combined_output(&status);
assert!(
!combined.contains("(new)"),
"an ignored test must not be flagged (new), got:\n{combined}"
);
assert!(
!combined.contains("test_ignored"),
"the ignored test must not be selected, got:\n{combined}"
);
replace_in_file(&dir.join("src/lib.rs"), " #[ignore]\n", "");
let status = cargo_affected(dir, &["affected", "status", "-v"]);
assert!(
status.status.success(),
"status after un-ignore failed: {}",
String::from_utf8_lossy(&status.stderr)
);
let combined = combined_output(&status);
assert!(
combined.contains("test_ignored (new)"),
"a test that stops being ignored must be picked up as new, got:\n{combined}"
);
}
#[test]
fn newly_ignored_test_excluded_from_affected() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
write_single_test_project(dir, "sample_newly_ignored_affected");
init_git_with_initial_commit(dir);
let collect = cargo_affected(dir, &["affected", "collect"]);
assert!(
collect.status.success(),
"initial collect failed: {}",
String::from_utf8_lossy(&collect.stderr),
);
replace_in_file(
&dir.join("src/lib.rs"),
" #[test]\n fn test_add()",
" #[test]\n #[ignore]\n fn test_add()",
);
replace_in_file(&dir.join("src/lib.rs"), "a + b", "a + b + 0");
git(dir, &["add", "."]);
git(dir, &["commit", "-q", "-m", "ignore + edit add"]);
let status = cargo_affected(dir, &["affected", "status", "-v"]);
assert!(
status.status.success(),
"status failed: {}",
String::from_utf8_lossy(&status.stderr),
);
let combined = combined_output(&status);
assert!(
!combined.contains("test_add"),
"newly-ignored test_add must not be selected, got:\n{combined}",
);
let run = cargo_affected(dir, &["affected", "run"]);
assert!(
run.status.success(),
"run with only a newly-ignored affected test must exit 0 (no \
nextest invocation), got status={:?} stderr=\n{}\nstdout=\n{}",
run.status.code(),
String::from_utf8_lossy(&run.stderr),
String::from_utf8_lossy(&run.stdout),
);
}
fn write_single_test_project(dir: &Path, crate_name: &str) {
std::fs::write(
dir.join("Cargo.toml"),
format!(
"[package]\nname = \"{crate_name}\"\nversion = \"0.1.0\"\nedition = \"2021\"\n"
),
)
.unwrap();
std::fs::write(dir.join(".gitignore"), "/target\n/Cargo.lock\n").unwrap();
let src = dir.join("src");
std::fs::create_dir_all(&src).unwrap();
std::fs::write(
src.join("lib.rs"),
r#"pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(1, 2), 3);
}
}
"#,
)
.unwrap();
}
#[test]
fn new_test_detection_uses_run_features() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
write_feature_gated_test_project(dir, "sample_feature_listing");
init_git_with_initial_commit(dir);
let collect = cargo_affected(dir, &["affected", "collect"]);
assert!(
collect.status.success(),
"collect failed: {}",
String::from_utf8_lossy(&collect.stderr)
);
let run = cargo_affected(dir, &["affected", "run", "-v", "--", "--features", "extra"]);
assert!(
run.status.success(),
"run failed: stderr=\n{}\nstdout=\n{}",
String::from_utf8_lossy(&run.stderr),
String::from_utf8_lossy(&run.stdout)
);
let combined = combined_output(&run);
assert!(
combined.contains("test_extra (new)"),
"the feature-gated test must be detected as new, got:\n{combined}"
);
assert!(
combined.contains("PASS") && combined.contains("test_extra"),
"nextest must actually run the feature-gated test, got:\n{combined}"
);
assert!(
!combined.contains("test_base"),
"test_base is in the DB and unaffected — it must not run, got:\n{combined}"
);
}
fn write_ignored_test_project(dir: &Path, crate_name: &str) {
std::fs::write(
dir.join("Cargo.toml"),
format!(
"[package]\nname = \"{crate_name}\"\nversion = \"0.1.0\"\nedition = \"2021\"\n"
),
)
.unwrap();
std::fs::write(dir.join(".gitignore"), "/target\n/Cargo.lock\n").unwrap();
let src = dir.join("src");
std::fs::create_dir_all(&src).unwrap();
std::fs::write(
src.join("lib.rs"),
r#"pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(1, 2), 3);
}
#[test]
#[ignore]
fn test_ignored() {
assert_eq!(add(0, 0), 0);
}
}
"#,
)
.unwrap();
}
fn write_feature_gated_test_project(dir: &Path, crate_name: &str) {
std::fs::write(
dir.join("Cargo.toml"),
format!(
"[package]\nname = \"{crate_name}\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n\
[features]\nextra = []\n"
),
)
.unwrap();
std::fs::write(dir.join(".gitignore"), "/target\n/Cargo.lock\n").unwrap();
let src = dir.join("src");
std::fs::create_dir_all(&src).unwrap();
std::fs::write(
src.join("lib.rs"),
r#"pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_base() {
assert_eq!(add(1, 1), 2);
}
#[cfg(feature = "extra")]
#[test]
fn test_extra() {
assert_eq!(add(2, 2), 4);
}
}
"#,
)
.unwrap();
}