use super::*;
const E2E_RELATIVE_DIR: &str = "e2e/rust";
const REGISTRY_DEPENDENCY: &str = "sample-json";
const STALE_PIN: &str = "1.25.0";
const FRESH_PIN: &str = "1.26.0";
const REQUIREMENT: &str = "1.26";
fn write_root_manifest(root: &Path, dependencies: &str) {
std::fs::write(
root.join("Cargo.toml"),
format!("[package]\nname = \"sample-core\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n{dependencies}"),
)
.expect("write root Cargo.toml");
}
fn write_generated_e2e_manifest(root: &Path) -> PathBuf {
let dir = root.join(E2E_RELATIVE_DIR);
std::fs::create_dir_all(&dir).expect("create e2e dir");
let manifest = dir.join("Cargo.toml");
std::fs::write(
&manifest,
"[workspace]\n\n[package]\nname = \"sample-core-e2e-rust\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n\
[dependencies]\nsample_core = { package = \"sample-core\", path = \"../..\" }\n",
)
.expect("write generated e2e Cargo.toml");
manifest
}
fn write_lock(root: &Path, pin: &str) {
std::fs::write(
root.join(E2E_RELATIVE_DIR).join("Cargo.lock"),
format!(
"version = 4\n\n\
[[package]]\nname = \"sample-core-e2e-rust\"\nversion = \"0.1.0\"\n\n\
[[package]]\nname = \"sample-core\"\nversion = \"0.1.0\"\n\n\
[[package]]\nname = \"{REGISTRY_DEPENDENCY}\"\nversion = \"{pin}\"\n"
),
)
.expect("write Cargo.lock");
}
fn e2e_dir(root: &Path) -> PathBuf {
root.join(E2E_RELATIVE_DIR)
}
#[test]
fn stale_lock_findings_reports_a_requirement_no_locked_version_satisfies() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!("[dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n"),
);
write_generated_e2e_manifest(root);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert_eq!(findings.len(), 1, "expected exactly one finding, got: {findings:?}");
let finding = &findings[0];
assert_eq!(finding.dependency, REGISTRY_DEPENDENCY);
assert_eq!(finding.requirement, REQUIREMENT);
assert_eq!(finding.locked_versions, vec![STALE_PIN.to_string()]);
assert_eq!(finding.lock, e2e_dir(root).join("Cargo.lock"));
assert_eq!(
finding.declared_in,
root.join("Cargo.toml"),
"the requirement is declared in the path dependency, not in the manifest alef generated"
);
}
#[test]
fn stale_lock_findings_accepts_a_lock_that_satisfies_every_requirement() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!("[dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n"),
);
write_generated_e2e_manifest(root);
write_lock(root, FRESH_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert!(
findings.is_empty(),
"a lock that resolves must be reported clean: {findings:?}"
);
}
#[test]
fn stale_lock_findings_ignores_a_dependency_absent_from_the_lock() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(root, "[dependencies]\nsample-absent = \"2\"\n");
write_generated_e2e_manifest(root);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert!(
findings.is_empty(),
"a package missing from the lock is not evidence of staleness: {findings:?}"
);
}
#[test]
fn stale_lock_findings_resolves_a_workspace_inherited_requirement() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!(
"[workspace]\nmembers = []\n\n[workspace.dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n\n\
[dependencies]\n{REGISTRY_DEPENDENCY} = {{ workspace = true }}\n"
),
);
write_generated_e2e_manifest(root);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert_eq!(
findings.len(),
1,
"expected the inherited requirement, got: {findings:?}"
);
assert_eq!(findings[0].dependency, REGISTRY_DEPENDENCY);
assert_eq!(findings[0].requirement, REQUIREMENT);
}
#[test]
fn stale_lock_findings_ignores_a_git_dependency() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!(
"[dependencies]\n{REGISTRY_DEPENDENCY} = {{ git = \"https://example.invalid/sample.git\", version = \
\"{REQUIREMENT}\" }}\n"
),
);
write_generated_e2e_manifest(root);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert!(
findings.is_empty(),
"a git dependency carries no registry pin: {findings:?}"
);
}
#[test]
fn stale_lock_findings_skips_a_directory_with_no_committed_lock() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!("[dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n"),
);
write_generated_e2e_manifest(root);
let findings = stale_lock_findings(&e2e_dir(root));
assert!(
findings.is_empty(),
"a directory with no lock has nothing to check: {findings:?}"
);
}
#[test]
fn check_generated_lock_freshness_names_the_dependency_and_the_remedy() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!("[dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n"),
);
let manifest = write_generated_e2e_manifest(root);
write_lock(root, STALE_PIN);
let generated: HashSet<PathBuf> = [manifest, root.join(E2E_RELATIVE_DIR).join("tests/basic_test.rs")]
.into_iter()
.collect();
let error = check_generated_lock_freshness(&generated).expect("a stale lock must fail the run");
let message = format!("{error:#}");
assert!(
message.contains(REGISTRY_DEPENDENCY),
"message must name the dependency: {message}"
);
assert!(
message.contains(STALE_PIN),
"message must name the stale pin: {message}"
);
assert!(
message.contains(REQUIREMENT),
"message must name the requirement: {message}"
);
assert!(
message.contains("cargo update"),
"message must name the remedy: {message}"
);
assert!(
message.contains(&e2e_dir(root).join("Cargo.lock").display().to_string()),
"message must name the lock: {message}"
);
}
#[test]
fn check_generated_lock_freshness_passes_a_resolvable_lock() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!("[dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n"),
);
let manifest = write_generated_e2e_manifest(root);
write_lock(root, FRESH_PIN);
let generated: HashSet<PathBuf> = [manifest].into_iter().collect();
assert!(
check_generated_lock_freshness(&generated).is_none(),
"a resolvable lock must not fail the run"
);
}
#[test]
fn check_generated_lock_freshness_ignores_non_manifest_paths() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!("[dependencies]\n{REGISTRY_DEPENDENCY} = \"{REQUIREMENT}\"\n"),
);
write_generated_e2e_manifest(root);
write_lock(root, STALE_PIN);
let generated: HashSet<PathBuf> = [root.join(E2E_RELATIVE_DIR).join("tests/basic_test.rs")]
.into_iter()
.collect();
assert!(check_generated_lock_freshness(&generated).is_none());
}