325 lines
9.9 KiB
Rust
325 lines
9.9 KiB
Rust
//! Lockfile integration test
|
|
|
|
use std::fs;
|
|
use std::str::FromStr;
|
|
|
|
// TODO(tarcieri): add more example `Cargo.lock` files which cover more scenarios
|
|
|
|
use cargo_lock::{
|
|
Lockfile, MetadataKey, ResolveVersion, Version,
|
|
package::{GitReference, SourceKind},
|
|
};
|
|
|
|
/// Path to a V1 `Cargo.lock` file.
|
|
const V1_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v1";
|
|
|
|
/// Path to a V2 `Cargo.lock` file.
|
|
const V2_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v2";
|
|
|
|
/// Path to a V3 `Cargo.lock` file.
|
|
const V3_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v3";
|
|
|
|
/// Path to a V4 `Cargo.lock` file.
|
|
const V4_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v4";
|
|
|
|
/// Load example V1 `Cargo.lock` file (from the Cargo project itself)
|
|
#[test]
|
|
fn load_example_v1_lockfile() {
|
|
let lockfile = Lockfile::load(V1_LOCKFILE_PATH).unwrap();
|
|
|
|
assert_eq!(lockfile.version, ResolveVersion::V1);
|
|
assert_eq!(lockfile.packages.len(), 141);
|
|
assert_eq!(lockfile.metadata.len(), 136);
|
|
|
|
let package = &lockfile.packages[0];
|
|
assert_eq!(package.name.as_ref(), "adler32");
|
|
assert_eq!(package.version, Version::parse("1.0.4").unwrap());
|
|
|
|
let metadata_key: MetadataKey =
|
|
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)"
|
|
.parse()
|
|
.unwrap();
|
|
|
|
let metadata_value = &lockfile.metadata[&metadata_key];
|
|
assert_eq!(
|
|
metadata_value.as_ref(),
|
|
"5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
|
);
|
|
}
|
|
|
|
/// Load example V2 `Cargo.lock` file
|
|
#[test]
|
|
fn load_example_v2_lockfile() {
|
|
let lockfile = Lockfile::load(V2_LOCKFILE_PATH).unwrap();
|
|
assert_eq!(lockfile.version, ResolveVersion::V2);
|
|
assert_eq!(lockfile.packages.len(), 25);
|
|
assert_eq!(lockfile.metadata.len(), 0);
|
|
}
|
|
|
|
/// Load example V3 `Cargo.lock` file
|
|
#[test]
|
|
fn load_example_v3_lockfile() {
|
|
let lockfile = Lockfile::load(V3_LOCKFILE_PATH).unwrap();
|
|
assert_eq!(lockfile.version, ResolveVersion::V3);
|
|
assert_eq!(lockfile.packages.len(), 25);
|
|
assert_eq!(lockfile.metadata.len(), 0);
|
|
}
|
|
|
|
/// Ensure V3 lockfiles encode their version correctly.
|
|
#[test]
|
|
fn serialize_v3() {
|
|
let lockfile = Lockfile::load(V3_LOCKFILE_PATH).unwrap();
|
|
let reserialized = lockfile.to_string();
|
|
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
|
|
assert_eq!(lockfile2.version, ResolveVersion::V3);
|
|
assert_eq!(lockfile2.packages, lockfile.packages);
|
|
}
|
|
|
|
/// Load example V4 `Cargo.lock` file
|
|
#[test]
|
|
fn load_example_v4_lockfile() {
|
|
let lockfile = Lockfile::load(V4_LOCKFILE_PATH).unwrap();
|
|
assert_eq!(lockfile.version, ResolveVersion::V4);
|
|
assert_eq!(lockfile.packages.len(), 25);
|
|
assert_eq!(lockfile.metadata.len(), 0);
|
|
|
|
let source_kind = lockfile
|
|
.packages
|
|
.iter()
|
|
.find(|pkg| pkg.name.as_str() == "url")
|
|
.and_then(|pkg| pkg.source.as_ref())
|
|
.map(|id| id.kind())
|
|
.unwrap();
|
|
assert_eq!(
|
|
source_kind,
|
|
&SourceKind::Git(GitReference::Tag("a-_+#$)z".into()))
|
|
);
|
|
|
|
let source_kind = lockfile
|
|
.packages
|
|
.iter()
|
|
.find(|pkg| pkg.name.as_str() == "toml")
|
|
.and_then(|pkg| pkg.source.as_ref())
|
|
.map(|id| id.kind())
|
|
.unwrap();
|
|
assert_eq!(
|
|
source_kind,
|
|
&SourceKind::Git(GitReference::Branch("a-_+#$)z".into()))
|
|
);
|
|
}
|
|
|
|
/// Ensure V4 lockfiles encode their version correctly.
|
|
#[test]
|
|
fn serialize_v4() {
|
|
let lockfile = Lockfile::load(V4_LOCKFILE_PATH).unwrap();
|
|
let reserialized = lockfile.to_string();
|
|
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
|
|
assert_eq!(lockfile2.version, ResolveVersion::V4);
|
|
assert_eq!(lockfile2.packages, lockfile.packages);
|
|
}
|
|
|
|
/// Ensure we can serialize a V2 lockfile as a V1 lockfile
|
|
#[test]
|
|
fn serialize_v2_to_v1() {
|
|
let mut lockfile = Lockfile::load(V2_LOCKFILE_PATH).unwrap();
|
|
lockfile.version = ResolveVersion::V1;
|
|
|
|
let reserialized = lockfile.to_string();
|
|
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
|
|
assert_eq!(lockfile2.version, ResolveVersion::V1);
|
|
assert_eq!(lockfile2.packages, lockfile.packages);
|
|
}
|
|
|
|
/// Ensure we can serialize a V1 lockfile as a V2 lockfile
|
|
#[test]
|
|
fn serialize_v1_to_v2() {
|
|
let mut lockfile = Lockfile::load(V1_LOCKFILE_PATH).unwrap();
|
|
lockfile.version = ResolveVersion::V2;
|
|
|
|
let reserialized = lockfile.to_string();
|
|
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
|
|
assert_eq!(lockfile.packages, lockfile2.packages);
|
|
}
|
|
|
|
/// Test that encoded V1 lockfiles match what Cargo would normally write.
|
|
#[test]
|
|
fn serde_matches_v1() {
|
|
let lockfile = Lockfile::load(V1_LOCKFILE_PATH).unwrap();
|
|
let reserialized = lockfile.to_string();
|
|
let file_content = fs::read_to_string(V1_LOCKFILE_PATH).unwrap();
|
|
|
|
assert_eq!(reserialized, file_content);
|
|
}
|
|
|
|
/// Test that encoded V2 lockfiles match what Cargo would normally write.
|
|
#[test]
|
|
fn serde_matches_v2() {
|
|
let lockfile = Lockfile::load(V2_LOCKFILE_PATH).unwrap();
|
|
let reserialized = lockfile.to_string();
|
|
let file_content = fs::read_to_string(V2_LOCKFILE_PATH).unwrap();
|
|
|
|
assert_eq!(reserialized, file_content);
|
|
}
|
|
|
|
/// Test that encoded V3 lockfiles match what Cargo would normally write.
|
|
#[test]
|
|
fn serde_matches_v3() {
|
|
let lockfile = Lockfile::load(V3_LOCKFILE_PATH).unwrap();
|
|
let reserialized = lockfile.to_string();
|
|
let file_content = fs::read_to_string(V3_LOCKFILE_PATH).unwrap();
|
|
|
|
assert_eq!(reserialized, file_content);
|
|
}
|
|
|
|
/// Test that encoded lockfiles with unused patch match what Cargo would normally write.
|
|
#[test]
|
|
fn serde_matches_unused_patch() {
|
|
let file_path = "tests/examples/Cargo.lock.unused-patch";
|
|
let lockfile = Lockfile::load(file_path).unwrap();
|
|
let reserialized = lockfile.to_string();
|
|
let file_content = fs::read_to_string(file_path).unwrap();
|
|
|
|
assert_eq!(reserialized, file_content);
|
|
}
|
|
|
|
/// Dependency tree tests
|
|
#[cfg(feature = "dependency-tree")]
|
|
mod tree {
|
|
use super::{Lockfile, V1_LOCKFILE_PATH, V2_LOCKFILE_PATH};
|
|
|
|
/// Compute a dependency graph from a non-trivial example V1 `Cargo.lock`
|
|
#[test]
|
|
fn compute_from_v1_example_lockfile() {
|
|
let tree = Lockfile::load(V1_LOCKFILE_PATH)
|
|
.unwrap()
|
|
.dependency_tree()
|
|
.unwrap();
|
|
|
|
assert_eq!(tree.nodes().len(), 141);
|
|
}
|
|
|
|
/// Compute a dependency graph from a non-trivial example V2 `Cargo.lock`
|
|
#[test]
|
|
fn compute_from_v2_example_lockfile() {
|
|
let tree = Lockfile::load(V2_LOCKFILE_PATH)
|
|
.unwrap()
|
|
.dependency_tree()
|
|
.unwrap();
|
|
|
|
assert_eq!(tree.nodes().len(), 25);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn source_disambiguation_single_version_different_registries() {
|
|
source_disambiguation("single_version_different_registries");
|
|
}
|
|
|
|
#[test]
|
|
fn source_disambiguation_single_version_different_source_types() {
|
|
source_disambiguation("single_version_different_source_types");
|
|
}
|
|
|
|
#[test]
|
|
fn source_disambiguation_two_versions_different_registries() {
|
|
source_disambiguation("two_versions_different_registries");
|
|
}
|
|
|
|
#[test]
|
|
fn source_disambiguation_two_versions_different_source_types() {
|
|
source_disambiguation("two_versions_different_source_types");
|
|
}
|
|
|
|
#[test]
|
|
fn source_disambiguation_two_versions_same_registry() {
|
|
source_disambiguation("two_versions_same_registry");
|
|
}
|
|
|
|
/// Test logic related to the disambiguation of dependency specifications when
|
|
/// the lock file contains multiple versions of the same crate and/or multiple
|
|
/// sources for the same crate.
|
|
fn source_disambiguation(test_file_suffix: &str) {
|
|
let original = fs::read_to_string(format!(
|
|
"tests/examples/source_disambiguation/Cargo.lock.{}",
|
|
test_file_suffix
|
|
))
|
|
.unwrap();
|
|
let re_encoded = Lockfile::from_str(&original).unwrap().to_string();
|
|
|
|
assert_eq!(original, re_encoded);
|
|
}
|
|
|
|
/// Test that a lockfile with git sources are correctly encoded
|
|
#[test]
|
|
fn encoding_registry_and_git() {
|
|
let lockfile = r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "tower-buffer"
|
|
version = "0.3.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a"
|
|
dependencies = [
|
|
"tracing 0.1.35",
|
|
]
|
|
|
|
[[package]]
|
|
name = "tracing"
|
|
version = "0.1.35"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
|
|
|
|
[[package]]
|
|
name = "tracing"
|
|
version = "0.2.0"
|
|
source = "git+https://github.com/tokio-rs/tracing.git?rev=1e09e50e8d15580b5929adbade9c782a6833e4a0#1e09e50e8d15580b5929adbade9c782a6833e4a0"
|
|
|
|
[[package]]
|
|
name = "example"
|
|
version = "0.1.0"
|
|
dependencies = [
|
|
"tower-buffer",
|
|
"tracing 0.2.0",
|
|
]
|
|
"#;
|
|
|
|
assert_eq!(lockfile, Lockfile::from_str(lockfile).unwrap().to_string(),);
|
|
}
|
|
|
|
#[cfg(feature = "dependency-tree")]
|
|
#[test]
|
|
fn hash_fragment_dep() {
|
|
use cargo_lock::Lockfile;
|
|
|
|
let lockfile_str = r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "parent"
|
|
version = "0.1.0"
|
|
source = "git+https://github.com/nope/parent?rev=xxxx#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
dependencies = [
|
|
"child 0.1.0 (git+https://github.com/nope/child?rev=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)",
|
|
"child 0.1.0 (git+https://github.com/nope/child?rev=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)",
|
|
]
|
|
|
|
[[package]]
|
|
name = "child"
|
|
version = "0.1.0"
|
|
source = "git+https://github.com/nope/child?rev=aaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
|
|
[[package]]
|
|
name = "child"
|
|
version = "0.1.0"
|
|
source = "git+https://github.com/nope/child?rev=bbbb#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
"#;
|
|
let lockfile = Lockfile::from_str(lockfile_str).unwrap();
|
|
assert_eq!(lockfile_str, lockfile.to_string(),);
|
|
// This will fail to resolve if child source URLs aren't normalized when deriving
|
|
// dependencies from packges.
|
|
let _tree = cargo_lock::dependency::tree::Tree::new(&lockfile).unwrap();
|
|
}
|