diff --git a/crates/turborepo-lockfiles/src/npm.rs b/crates/turborepo-lockfiles/src/npm.rs index 847b1bbed363d..dc297e6fcc70d 100644 --- a/crates/turborepo-lockfiles/src/npm.rs +++ b/crates/turborepo-lockfiles/src/npm.rs @@ -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::().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(()) + } } diff --git a/crates/turborepo-lockfiles/src/pnpm/data.rs b/crates/turborepo-lockfiles/src/pnpm/data.rs index 86f7d3791a9f3..4ad6c34636c09 100644 --- a/crates/turborepo-lockfiles/src/pnpm/data.rs +++ b/crates/turborepo-lockfiles/src/pnpm/data.rs @@ -1479,4 +1479,87 @@ c: crate::Error::MissingWorkspace("apps/docs".to_string()).to_string() ); } + + #[test] + fn test_subgraph_with_empty_workspace_packages() { + let lockfile = PnpmLockfile::from_bytes(PNPM8).unwrap(); + + // Test subgraph with no workspace packages + let subgraph = lockfile.subgraph(&[], &["/is-odd@3.0.1".into()]).unwrap(); + let pnpm_subgraph = (subgraph.as_ref() as &dyn Any) + .downcast_ref::() + .unwrap(); + + // Should only contain root importer + assert_eq!(pnpm_subgraph.importers.len(), 1); + assert!(pnpm_subgraph.importers.contains_key(".")); + + // Should contain the requested package + assert!( + pnpm_subgraph + .packages + .as_ref() + .unwrap() + .contains_key("/is-odd@3.0.1") + ); + } + + #[test] + fn test_subgraph_with_missing_package() { + let lockfile = PnpmLockfile::from_bytes(PNPM8).unwrap(); + + // Test subgraph with non-existent package + let result = lockfile.subgraph(&["packages/a".into()], &["nonexistent-package".into()]); + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + crate::Error::MissingPackage(_) + )); + } + + #[test] + fn test_resolve_package_with_invalid_workspace() { + let lockfile = PnpmLockfile::from_bytes(PNPM8).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_global_change_detection() { + let lockfile1 = PnpmLockfile::from_bytes(PNPM8).unwrap(); + let lockfile2 = PnpmLockfile::from_bytes(PNPM8_6).unwrap(); + + // Different lockfiles should show global change + assert!(lockfile1.global_change(&lockfile2)); + + // Same lockfile should not show global change + assert!(!lockfile1.global_change(&lockfile1)); + } + + #[test] + fn test_all_dependencies_with_invalid_key() { + let lockfile = PnpmLockfile::from_bytes(PNPM8).unwrap(); + + // Test with invalid package key + let result = lockfile.all_dependencies("invalid-package-key").unwrap(); + assert!(result.is_none()); + } + + #[test] + fn test_workspace_link_resolution() { + let lockfile = PnpmLockfile::from_bytes(PNPM8).unwrap(); + + // Test workspace link resolution - current implementation returns None + // for workspace links since they're not actual packages in the lockfile + let workspace_dep = lockfile + .resolve_package("packages/a", "c", "workspace:*") + .unwrap(); + assert!(workspace_dep.is_none()); + } }