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_generated_e2e_manifest_with_features(root: &Path, features: &[&str]) -> PathBuf {
let dir = root.join(E2E_RELATIVE_DIR);
std::fs::create_dir_all(&dir).expect("create e2e dir");
let manifest = dir.join("Cargo.toml");
let features_toml = if features.is_empty() {
String::new()
} else {
let quoted: Vec<String> = features.iter().map(|feature| format!("\"{feature}\"")).collect();
format!(", features = [{}]", quoted.join(", "))
};
std::fs::write(
&manifest,
format!(
"[workspace]\n\n[package]\nname = \"sample-core-e2e-rust\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n\
[dependencies]\nsample_core = {{ package = \"sample-core\", path = \"../..\"{features_toml} }}\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_ignores_an_unreached_optional_dependency() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!(
"[features]\ndefault = []\nnetworking = [\"dep:{REGISTRY_DEPENDENCY}\"]\n\n\
[dependencies]\n{REGISTRY_DEPENDENCY} = {{ version = \"{REQUIREMENT}\", optional = true }}\n"
),
);
write_generated_e2e_manifest_with_features(root, &[]);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert!(
findings.is_empty(),
"an optional dependency no requested or default feature activates must not be reported: {findings:?}"
);
}
#[test]
fn stale_lock_findings_reports_a_reached_optional_dependency() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!(
"[features]\ndefault = []\nnetworking = [\"dep:{REGISTRY_DEPENDENCY}\"]\n\n\
[dependencies]\n{REGISTRY_DEPENDENCY} = {{ version = \"{REQUIREMENT}\", optional = true }}\n"
),
);
write_generated_e2e_manifest_with_features(root, &["networking"]);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert_eq!(
findings.len(),
1,
"an optional dependency activated by a requested feature must still be checked: {findings:?}"
);
assert_eq!(findings[0].dependency, REGISTRY_DEPENDENCY);
}
#[test]
fn stale_lock_findings_reports_an_optional_dependency_reached_via_default_features() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_manifest(
root,
&format!(
"[features]\ndefault = [\"dep:{REGISTRY_DEPENDENCY}\"]\n\n\
[dependencies]\n{REGISTRY_DEPENDENCY} = {{ version = \"{REQUIREMENT}\", optional = true }}\n"
),
);
write_generated_e2e_manifest_with_features(root, &[]);
write_lock(root, STALE_PIN);
let findings = stale_lock_findings(&e2e_dir(root));
assert_eq!(
findings.len(),
1,
"an optional dependency activated by the target's own default features must still be checked: {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());
}
mod pending_publish {
use super::*;
const CANONICAL: &str = "3.12.0";
const PUBLISHED: &str = "3.11.6";
const LOCAL_CRATE: &str = "sample-core";
const GENERATED_RELATIVE_DIR: &str = "test_apps/rust";
fn write_root_crate(root: &Path, version: &str) {
std::fs::write(
root.join("Cargo.toml"),
format!("[package]\nname = \"{LOCAL_CRATE}\"\nversion = \"{version}\"\nedition = \"2024\"\n"),
)
.expect("write root Cargo.toml");
}
fn write_test_app_manifest(root: &Path, required_version: &str) -> PathBuf {
let dir = root.join(GENERATED_RELATIVE_DIR);
std::fs::create_dir_all(&dir).expect("create test_apps dir");
let manifest = dir.join("Cargo.toml");
std::fs::write(
&manifest,
format!(
"[workspace]\n\n[package]\nname = \"{LOCAL_CRATE}-e2e-rust\"\nversion = \"0.0.0\"\nedition = \
\"2024\"\n\n[dependencies]\n{LOCAL_CRATE} = {{ version = \"{required_version}\" }}\n"
),
)
.expect("write test-app Cargo.toml");
manifest
}
fn write_test_app_lock(root: &Path, locked_version: &str) {
std::fs::write(
root.join(GENERATED_RELATIVE_DIR).join("Cargo.lock"),
format!(
"version = 3\n\n[[package]]\nname = \"{LOCAL_CRATE}\"\nversion = \"{locked_version}\"\nsource = \
\"registry+https://github.com/rust-lang/crates.io-index\"\n"
),
)
.expect("write test-app Cargo.lock");
}
#[test]
fn plain_check_still_fails_on_a_pending_publish_disagreement() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_crate(root, CANONICAL);
let manifest = write_test_app_manifest(root, CANONICAL);
write_test_app_lock(root, PUBLISHED);
let generated: HashSet<PathBuf> = [manifest].into_iter().collect();
assert!(
check_generated_lock_freshness(&generated).is_some(),
"control: the plain check has no pending-publish exemption and must still fail here"
);
}
#[test]
fn tolerating_variant_warns_instead_of_failing_on_a_pending_publish_disagreement() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_crate(root, CANONICAL);
let manifest = write_test_app_manifest(root, CANONICAL);
write_test_app_lock(root, PUBLISHED);
let generated: HashSet<PathBuf> = [manifest].into_iter().collect();
let result = check_generated_lock_freshness_tolerating_pending_publish(&generated, root, Some(CANONICAL));
assert!(
result.is_none(),
"a disagreement fully explained by this crate's own not-yet-published version must not fail the \
run: {result:?}"
);
}
#[test]
fn tolerating_variant_without_canonical_behaves_like_the_plain_check() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path();
write_root_crate(root, CANONICAL);
let manifest = write_test_app_manifest(root, CANONICAL);
write_test_app_lock(root, PUBLISHED);
let generated: HashSet<PathBuf> = [manifest].into_iter().collect();
assert!(
check_generated_lock_freshness_tolerating_pending_publish(&generated, root, None).is_some(),
"no canonical version means no exemption is possible; this must still fail"
);
}
#[test]
fn tolerating_variant_still_fails_on_a_disagreement_not_explained_by_pending_publish() {
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].into_iter().collect();
assert!(
check_generated_lock_freshness_tolerating_pending_publish(&generated, root, Some(CANONICAL)).is_some(),
"a third-party lock drift unrelated to this crate's own version must still fail the run"
);
}
}