这是indexloc提供的服务,不要输入任何密码
Skip to content

test: increase coverage for lockfiles #10633

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 264 additions & 0 deletions crates/turborepo-lockfiles/src/bun/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,4 +577,268 @@ mod test {
let lockfile = BunLockfile::from_str(&contents);
assert!(lockfile.is_err(), "matching packages have differing shas");
}

#[test]
fn test_subgraph_with_empty_workspace_packages() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test subgraph with no workspace packages
let subgraph = lockfile.subgraph(&[], &["turbo@2.3.3".into()]).unwrap();
let subgraph_data = subgraph.lockfile().unwrap();

// Should only contain root workspace
assert_eq!(subgraph_data.workspaces.len(), 1);
assert!(subgraph_data.workspaces.contains_key(""));

// Should contain the requested package
assert!(subgraph_data
.packages
.values()
.any(|p| p.ident == "turbo@2.3.3"));
}

#[test]
fn test_subgraph_with_missing_package() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test subgraph with non-existent package
let subgraph = lockfile
.subgraph(&["apps/docs".into()], &["nonexistent-package".into()])
.unwrap();
let subgraph_data = subgraph.lockfile().unwrap();

// Should not contain the non-existent package
assert!(!subgraph_data
.packages
.values()
.any(|p| p.ident == "nonexistent-package"));

// But should still include the workspace
assert!(subgraph_data.workspaces.contains_key("apps/docs"));
}

#[test]
fn test_resolve_package_with_invalid_workspace() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test with invalid workspace
let result = lockfile.resolve_package("invalid/workspace", "is-odd", "3.0.1");
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
crate::Error::MissingWorkspace(_)
));
}

#[test]
fn test_resolve_package_with_nonexistent_package() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test with nonexistent package
let result = lockfile
.resolve_package("apps/docs", "nonexistent-package", "1.0.0")
.unwrap();
assert!(result.is_none());
}

#[test]
fn test_all_dependencies_with_invalid_key() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test with invalid package key
let result = lockfile.all_dependencies("invalid-package-key");
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
crate::Error::MissingPackage(_)
));
}

#[test]
fn test_global_change_detection() {
let lockfile1 = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();
let lockfile2 = BunLockfile::from_str(PATCH_LOCKFILE).unwrap();

// Current implementation only returns true if package manager types differ
// Both lockfiles are BunLockfile, so this returns false
assert!(!lockfile1.global_change(&lockfile2));

// Same lockfile should not show global change
assert!(!lockfile1.global_change(&lockfile1));
}

#[test]
fn test_turbo_version_detection() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

let turbo_version = lockfile.turbo_version();
assert_eq!(turbo_version, Some("2.3.3".to_string()));
}

#[test]
fn test_turbo_version_missing() {
// Create a lockfile without turbo
let contents = serde_json::to_string(&json!({
"lockfileVersion": 0,
"workspaces": {
"": {
"name": "test"
}
},
"packages": {}
}))
.unwrap();
let lockfile = BunLockfile::from_str(&contents).unwrap();

let turbo_version = lockfile.turbo_version();
assert!(turbo_version.is_none());
}

#[test]
fn test_human_name_generation() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

let package = crate::Package::new("is-odd", "3.0.1");
let human_name = lockfile.human_name(&package);
assert_eq!(human_name, Some("is-odd@3.0.1".to_string()));

// Test with nonexistent package
let nonexistent = crate::Package::new("nonexistent", "1.0.0");
let human_name = lockfile.human_name(&nonexistent);
assert!(human_name.is_none());
}

#[test]
fn test_encode_decode_roundtrip() {
let original = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test encode/decode roundtrip
let encoded = original.encode().unwrap();
let decoded = BunLockfile::from_bytes(&encoded).unwrap();

// Should preserve basic structure
assert_eq!(
original.data.lockfile_version,
decoded.data.lockfile_version
);
assert_eq!(
original.data.workspaces.len(),
decoded.data.workspaces.len()
);
assert_eq!(original.data.packages.len(), decoded.data.packages.len());
}

#[test]
fn test_optional_peer_dependencies() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test that optional peer dependencies are handled correctly
let all_deps = lockfile
.all_dependencies("@turbo/gen@1.13.4")
.unwrap()
.unwrap();

// Should include regular dependencies but may skip optional peers
assert!(all_deps.len() > 0);

// Verify no missing package errors for optional peers
for (dep_key, _) in &all_deps {
// All returned dependencies should exist in the lockfile
assert!(
lockfile.data.packages.contains_key(dep_key)
|| lockfile.package_entry(dep_key).is_some()
);
}
}

#[test]
fn test_package_version_extraction() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test version extraction from different package formats
for (_, entry) in &lockfile.data.packages {
let version = entry.version();
// Version should be non-empty and valid
assert!(!version.is_empty());

// Should extract version after @ symbol
if entry.ident.contains('@') {
assert!(entry.ident.ends_with(version));
}
}
}

#[test]
fn test_subgraph_preserves_patches() {
let lockfile = BunLockfile::from_str(PATCH_LOCKFILE).unwrap();

let subgraph = lockfile
.subgraph(&["apps/b".into()], &["is-odd@3.0.0".into()])
.unwrap();
let subgraph_data = subgraph.lockfile().unwrap();

// Should preserve patches for included packages
assert!(subgraph_data
.patched_dependencies
.contains_key("is-odd@3.0.0"));
assert_eq!(
subgraph_data.patched_dependencies.get("is-odd@3.0.0"),
Some(&"patches/is-odd@3.0.0.patch".to_string())
);
}

#[test]
fn test_workspace_dependency_types() {
let lockfile = BunLockfile::from_str(BASIC_LOCKFILE).unwrap();

// Test that different dependency types are handled correctly
for (_, workspace) in &lockfile.data.workspaces {
// Verify that dependencies maps exist and are accessible
if let Some(_deps) = &workspace.dependencies {
// Dependencies can be empty
}
if let Some(_dev_deps) = &workspace.dev_dependencies {
// Dev dependencies can be empty
}
if let Some(_opt_deps) = &workspace.optional_dependencies {
// Optional dependencies can be empty
}
}
}

#[test]
fn test_malformed_json_handling() {
let malformed_json = r#"
{
"lockfileVersion": 0,
"workspaces": {
"": {
"name": "test"
}
},
"packages": {
"invalid": ["incomplete
"#;

let result = BunLockfile::from_str(malformed_json);
assert!(result.is_err());
}

#[test]
fn test_trailing_commas_handling() {
let json_with_trailing_commas = r#"
{
"lockfileVersion": 0,
"workspaces": {
"": {
"name": "test",
}
},
"packages": {},
}
"#;

let result = BunLockfile::from_str(json_with_trailing_commas);
assert!(result.is_ok(), "Should handle trailing commas gracefully");
}
}
76 changes: 76 additions & 0 deletions crates/turborepo-lockfiles/src/npm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,4 +469,80 @@ mod test {
assert_eq!(lockfile.turbo_version().as_deref(), Some("1.5.5"));
Ok(())
}

#[test]
fn test_subgraph_with_empty_inputs() -> Result<(), Error> {
let lockfile = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;

// Test with empty workspace packages and packages
let subgraph = lockfile.subgraph(&[], &[])?;
let subgraph_npm = subgraph.as_ref() as &dyn Any;
let subgraph_npm = subgraph_npm.downcast_ref::<NpmLockfile>().unwrap();

// Should contain root package if it exists
assert!(subgraph_npm.packages.contains_key(""));
assert_eq!(subgraph_npm.packages.len(), 1);

Ok(())
}

#[test]
fn test_resolve_package_with_invalid_workspace() -> Result<(), Error> {
let lockfile = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;

// Test with invalid workspace
let result = lockfile.resolve_package("invalid/workspace", "lodash", "^4.17.21");
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::MissingWorkspace(_)));

Ok(())
}

#[test]
fn test_global_change_detection() -> Result<(), Error> {
let lockfile1 = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;
let lockfile2 = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;

// Same lockfile should not show global change
assert!(!lockfile1.global_change(&lockfile2));

Ok(())
}

#[test]
fn test_all_dependencies_with_invalid_key() -> Result<(), Error> {
let lockfile = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;

// Test with invalid package key
let result = lockfile.all_dependencies("invalid-package-key")?;
assert!(result.is_none());

Ok(())
}

#[test]
fn test_human_name_with_nonexistent_package() -> Result<(), Error> {
let lockfile = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;

let package = Package {
key: "nonexistent-package".to_string(),
version: "1.0.0".to_string(),
};

let result = lockfile.human_name(&package);
assert!(result.is_none());

Ok(())
}

#[test]
fn test_patches_with_empty_lockfile() -> Result<(), Error> {
let lockfile = NpmLockfile::load(include_bytes!("../fixtures/npm-lock.json"))?;

// NPM lockfile should have no patches by default
let patches = lockfile.patches()?;
assert!(patches.is_empty());

Ok(())
}
}
Loading
Loading