From 340164c64e90d44b1bdf620b514166db1f76cc98 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 24 Jun 2026 00:47:20 +0900 Subject: test: port more unimplemented tests Co-Authored-By: Claude Opus 4.8 (1M context) --- .../dependency_resolver/default_policy_test.rs | 208 +++++++++++++- .../security_advisory_pool_filter_test.rs | 317 ++++++++++++++++++++- .../tests/dependency_resolver/solver_test.rs | 8 +- 3 files changed, 513 insertions(+), 20 deletions(-) (limited to 'crates/shirabe/tests/dependency_resolver') diff --git a/crates/shirabe/tests/dependency_resolver/default_policy_test.rs b/crates/shirabe/tests/dependency_resolver/default_policy_test.rs index 776de6c..fafe0e2 100644 --- a/crates/shirabe/tests/dependency_resolver/default_policy_test.rs +++ b/crates/shirabe/tests/dependency_resolver/default_policy_test.rs @@ -3,6 +3,7 @@ use indexmap::IndexMap; use shirabe::dependency_resolver::PolicyInterface; use shirabe::dependency_resolver::default_policy::DefaultPolicy; +use shirabe::package::Link; use shirabe::package::handle::{CompleteAliasPackageHandle, CompletePackageHandle}; use shirabe::repository::array_repository::ArrayRepository; use shirabe::repository::handle::{LockArrayRepositoryHandle, RepositoryInterfaceHandle}; @@ -556,28 +557,217 @@ fn test_select_local_repos_first() { assert_eq!(expected, selected); } -#[ignore = "set_provides/set_replaces only exist on RootPackage handles; CompletePackage from get_package has no set_provides"] +/// PHP `new Link($source, $target, $constraint, $type)`: prettyConstraint defaults to +/// `(string) $constraint`. +fn link(source: &str, target: &str, constraint: AnyConstraint, r#type: &str) -> Link { + let pretty = constraint.get_pretty_string(); + Link::new( + source.to_string(), + target.to_string(), + constraint, + Some(r#type.to_string()), + pretty, + ) +} + +fn as_complete( + package: &shirabe::package::handle::PackageInterfaceHandle, +) -> CompletePackageHandle { + CompletePackageHandle::from_rc_unchecked(package.as_rc().clone()) +} + +fn constraint(operator: &str, version: &str) -> AnyConstraint { + SimpleConstraint::new(operator.to_string(), version.to_string(), None).into() +} + +#[ignore] #[test] fn test_select_all_providers() { let _tear_down = TearDown; - let _fixtures = set_up(); - todo!() + let mut fixtures = set_up(); + + let package_a = get_package("A", "1.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + let package_b = get_package("B", "2.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + + let mut provides_a: IndexMap = IndexMap::new(); + provides_a.insert( + "x".to_string(), + link("A", "X", constraint("==", "1.0"), Link::TYPE_PROVIDE), + ); + as_complete(&package_a).__set_provides(provides_a); + let mut provides_b: IndexMap = IndexMap::new(); + provides_b.insert( + "x".to_string(), + link("B", "X", constraint("==", "1.0"), Link::TYPE_PROVIDE), + ); + as_complete(&package_b).__set_provides(provides_b); + + fixtures + .repository_set + .add_repository(RepositoryInterfaceHandle::new(fixtures.repo)) + .unwrap(); + + let pool = fixtures + .repository_set + .create_pool_for_packages( + vec!["A".to_string(), "B".to_string()], + Some(fixtures.repo_locked.clone()), + ) + .unwrap(); + + let literals = vec![package_a.get_id(), package_b.get_id()]; + let expected = literals.clone(); + + let selected = fixtures + .policy + .select_preferred_packages(&pool, literals, None); + + assert_eq!(expected, selected); } -#[ignore = "set_provides/set_replaces only exist on RootPackage handles; CompletePackage from get_package has no set_replaces"] +#[ignore] #[test] fn test_prefer_non_replacing_from_same_repo() { let _tear_down = TearDown; - let _fixtures = set_up(); - todo!() + let mut fixtures = set_up(); + + let package_a = get_package("A", "1.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + let package_b = get_package("B", "2.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + + let mut replaces_b: IndexMap = IndexMap::new(); + replaces_b.insert( + "a".to_string(), + link("B", "A", constraint("==", "1.0"), Link::TYPE_REPLACE), + ); + as_complete(&package_b).__set_replaces(replaces_b); + + fixtures + .repository_set + .add_repository(RepositoryInterfaceHandle::new(fixtures.repo)) + .unwrap(); + + let pool = fixtures + .repository_set + .create_pool_for_packages( + vec!["A".to_string(), "B".to_string()], + Some(fixtures.repo_locked.clone()), + ) + .unwrap(); + + let literals = vec![package_a.get_id(), package_b.get_id()]; + let expected = literals.clone(); + + let selected = fixtures + .policy + .select_preferred_packages(&pool, literals, None); + + assert_eq!(expected, selected); } -#[ignore = "set_replaces only exists on RootPackage handles; CompletePackage from get_package has no set_replaces"] +#[ignore] #[test] fn test_prefer_replacing_package_from_same_vendor() { let _tear_down = TearDown; - let _fixtures = set_up(); - todo!() + let mut fixtures = set_up(); + + // test with default order + let package_b = get_package("vendor-b/replacer", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let package_a = get_package("vendor-a/replacer", "1.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + + let mut replaces_a: IndexMap = IndexMap::new(); + replaces_a.insert( + "vendor-a/package".to_string(), + link( + "vendor-a/replacer", + "vendor-a/package", + constraint("==", "1.0"), + Link::TYPE_REPLACE, + ), + ); + as_complete(&package_a).__set_replaces(replaces_a); + let mut replaces_b: IndexMap = IndexMap::new(); + replaces_b.insert( + "vendor-a/package".to_string(), + link( + "vendor-b/replacer", + "vendor-a/package", + constraint("==", "1.0"), + Link::TYPE_REPLACE, + ), + ); + as_complete(&package_b).__set_replaces(replaces_b); + + fixtures + .repository_set + .add_repository(RepositoryInterfaceHandle::new(fixtures.repo)) + .unwrap(); + + let pool = fixtures + .repository_set + .create_pool_for_packages( + vec![ + "vendor-a/replacer".to_string(), + "vendor-b/replacer".to_string(), + ], + Some(fixtures.repo_locked.clone()), + ) + .unwrap(); + + let literals = vec![package_a.get_id(), package_b.get_id()]; + let expected = literals.clone(); + + let selected = fixtures.policy.select_preferred_packages( + &pool, + literals, + Some("vendor-a/package".to_string()), + ); + assert_eq!(expected, selected); + + // test with reversed order in repo + let repo = ArrayRepository::new(vec![]).unwrap(); + let package_a = CompletePackageHandle::dup(&as_complete(&package_a)); + repo.add_package(package_a.clone().into()).unwrap(); + let package_b = CompletePackageHandle::dup(&as_complete(&package_b)); + repo.add_package(package_b.clone().into()).unwrap(); + + let mut repository_set = RepositorySet::new( + "dev", + IndexMap::new(), + vec![], + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + repository_set + .add_repository(RepositoryInterfaceHandle::new(repo)) + .unwrap(); + + let pool = fixtures + .repository_set + .create_pool_for_packages( + vec![ + "vendor-a/replacer".to_string(), + "vendor-b/replacer".to_string(), + ], + Some(fixtures.repo_locked.clone()), + ) + .unwrap(); + + let literals = vec![package_a.get_id(), package_b.get_id()]; + let expected = literals.clone(); + + let selected = fixtures.policy.select_preferred_packages( + &pool, + literals, + Some("vendor-a/package".to_string()), + ); + assert_eq!(expected, selected); } #[ignore] diff --git a/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs b/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs index 98ac131..7938657 100644 --- a/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs +++ b/crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs @@ -12,24 +12,272 @@ use shirabe::dependency_resolver::SecurityAdvisoryPoolFilter; use shirabe::dependency_resolver::pool::Pool; use shirabe::dependency_resolver::request::Request; use shirabe::package::handle::{CompletePackageHandle, PackageHandle, PackageInterfaceHandle}; -use shirabe_php_shim::PhpMixed; +use shirabe::repository::{PackageRepository, RepositoryInterfaceHandle}; +use shirabe_php_shim::{PhpMixed, uniqid}; +use shirabe_semver::constraint::{AnyConstraint, SimpleConstraint}; +#[ignore] #[test] -#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"] fn test_filter_packages_by_advisories() { - todo!() + let audit_config = AuditConfig::new( + true, + Auditor::FORMAT_SUMMARY.to_string(), + Auditor::ABANDONED_FAIL.to_string(), + true, + true, + false, + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + let filter = SecurityAdvisoryPoolFilter::new(Auditor, audit_config); + + let advisory1 = + generate_security_advisory("acme/package", Some("CVE-1999-1000"), ">=1.0.0,<1.1.0"); + let advisory2 = + generate_security_advisory("acme/package", Some("CVE-1999-1001"), ">=1.0.0,<1.1.0"); + let mut security_advisories: IndexMap = IndexMap::new(); + security_advisories.insert( + "acme/package".to_string(), + PhpMixed::List(vec![ + PhpMixed::Array(advisory1.clone()), + PhpMixed::Array(advisory2.clone()), + ]), + ); + let mut config: IndexMap = IndexMap::new(); + config.insert("package".to_string(), PhpMixed::List(vec![])); + config.insert( + "security-advisories".to_string(), + PhpMixed::Array(security_advisories), + ); + let repository = RepositoryInterfaceHandle::new(PackageRepository::new(config)); + + let package: PackageInterfaceHandle = PackageHandle::new( + "acme/package".to_string(), + "1.0.0.0".to_string(), + "1.0".to_string(), + ) + .into(); + let expected_package1: PackageInterfaceHandle = PackageHandle::new( + "acme/package".to_string(), + "2.0.0.0".to_string(), + "2.0".to_string(), + ) + .into(); + let expected_package2: PackageInterfaceHandle = PackageHandle::new( + "acme/other".to_string(), + "1.0.0.0".to_string(), + "1.0".to_string(), + ) + .into(); + + let pool = Pool::new( + vec![ + package.clone(), + expected_package1.clone(), + expected_package2.clone(), + ], + vec![], + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + let filtered_pool = filter + .filter(pool, vec![repository], &Request::new(None)) + .unwrap(); + + let packages = filtered_pool.get_packages(); + assert_eq!(packages.len(), 2); + assert!(packages[0].ptr_eq(&expected_package1)); + assert!(packages[1].ptr_eq(&expected_package2)); + + let constraint: AnyConstraint = + SimpleConstraint::new("==".to_string(), "1.0.0.0".to_string(), None).into(); + assert!(filtered_pool.is_security_removed_package_version("acme/package", Some(&constraint))); + assert_eq!( + filtered_pool + .get_all_abandoned_removed_package_versions() + .len(), + 0 + ); + + let advisory_map = filtered_pool.get_all_security_removed_package_versions(); + assert!(advisory_map.contains_key("acme/package")); + assert!(advisory_map["acme/package"].contains_key("1.0.0.0")); + assert_eq!( + vec![ + advisory1["advisoryId"].as_string().unwrap().to_string(), + advisory2["advisoryId"].as_string().unwrap().to_string(), + ], + filtered_pool.get_security_advisory_identifiers_for_package_version( + "acme/package", + Some(&constraint) + ), + ); } +#[ignore] #[test] -#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"] fn test_dont_filter_packages_by_ignored_advisories() { - todo!() + let mut ignore_list: IndexMap> = IndexMap::new(); + ignore_list.insert("CVE-2024-1234".to_string(), None); + let audit_config = AuditConfig::new( + true, + Auditor::FORMAT_SUMMARY.to_string(), + Auditor::ABANDONED_FAIL.to_string(), + true, + true, + false, + ignore_list.clone(), + ignore_list, + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + let filter = SecurityAdvisoryPoolFilter::new(Auditor, audit_config); + + let mut security_advisories: IndexMap = IndexMap::new(); + security_advisories.insert( + "acme/package".to_string(), + PhpMixed::List(vec![PhpMixed::Array(generate_security_advisory( + "acme/package", + Some("CVE-2024-1234"), + ">=1.0.0,<1.1.0", + ))]), + ); + let mut config: IndexMap = IndexMap::new(); + config.insert("package".to_string(), PhpMixed::List(vec![])); + config.insert( + "security-advisories".to_string(), + PhpMixed::Array(security_advisories), + ); + let repository = RepositoryInterfaceHandle::new(PackageRepository::new(config)); + + let expected_package1: PackageInterfaceHandle = PackageHandle::new( + "acme/package".to_string(), + "1.0.0.0".to_string(), + "1.0".to_string(), + ) + .into(); + let expected_package2: PackageInterfaceHandle = PackageHandle::new( + "acme/package".to_string(), + "1.1.0.0".to_string(), + "1.1".to_string(), + ) + .into(); + + let pool = Pool::new( + vec![expected_package1.clone(), expected_package2.clone()], + vec![], + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + let filtered_pool = filter + .filter(pool, vec![repository], &Request::new(None)) + .unwrap(); + + let packages = filtered_pool.get_packages(); + assert_eq!(packages.len(), 2); + assert!(packages[0].ptr_eq(&expected_package1)); + assert!(packages[1].ptr_eq(&expected_package2)); + assert_eq!( + filtered_pool + .get_all_abandoned_removed_package_versions() + .len(), + 0 + ); + assert_eq!( + filtered_pool + .get_all_security_removed_package_versions() + .len(), + 0 + ); } +#[ignore] #[test] -#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"] fn test_dont_filter_packages_with_block_insecure_disabled() { - todo!() + let audit_config = AuditConfig::new( + true, + Auditor::FORMAT_SUMMARY.to_string(), + Auditor::ABANDONED_FAIL.to_string(), + false, + true, + false, + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + let filter = SecurityAdvisoryPoolFilter::new(Auditor, audit_config); + + let mut security_advisories: IndexMap = IndexMap::new(); + security_advisories.insert( + "acme/package".to_string(), + PhpMixed::List(vec![PhpMixed::Array(generate_security_advisory( + "acme/package", + Some("CVE-2024-1234"), + ">=1.0.0,<1.1.0", + ))]), + ); + let mut config: IndexMap = IndexMap::new(); + config.insert("package".to_string(), PhpMixed::List(vec![])); + config.insert( + "security-advisories".to_string(), + PhpMixed::Array(security_advisories), + ); + let repository = RepositoryInterfaceHandle::new(PackageRepository::new(config)); + + let expected_package1: PackageInterfaceHandle = PackageHandle::new( + "acme/package".to_string(), + "1.0.0.0".to_string(), + "1.0".to_string(), + ) + .into(); + let expected_package2: PackageInterfaceHandle = PackageHandle::new( + "acme/package".to_string(), + "1.1.0.0".to_string(), + "1.1".to_string(), + ) + .into(); + + let pool = Pool::new( + vec![expected_package1.clone(), expected_package2.clone()], + vec![], + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), + ); + let filtered_pool = filter + .filter(pool, vec![repository], &Request::new(None)) + .unwrap(); + + let packages = filtered_pool.get_packages(); + assert_eq!(packages.len(), 2); + assert!(packages[0].ptr_eq(&expected_package1)); + assert!(packages[1].ptr_eq(&expected_package2)); + assert_eq!( + filtered_pool + .get_all_abandoned_removed_package_versions() + .len(), + 0 + ); + assert_eq!( + filtered_pool + .get_all_security_removed_package_versions() + .len(), + 0 + ); } #[test] @@ -106,3 +354,58 @@ fn test_dont_filter_packages_with_abandoned_package() { 0 ); } + +fn generate_security_advisory( + package_name: &str, + cve: Option<&str>, + affected_versions: &str, +) -> IndexMap { + let mut source: IndexMap = IndexMap::new(); + source.insert( + "name".to_string(), + PhpMixed::String("Security Advisory".to_string()), + ); + source.insert("remoteId".to_string(), PhpMixed::String("test".to_string())); + + let mut advisory: IndexMap = IndexMap::new(); + advisory.insert( + "advisoryId".to_string(), + PhpMixed::String(uniqid("PKSA-", false)), + ); + advisory.insert( + "packageName".to_string(), + PhpMixed::String(package_name.to_string()), + ); + advisory.insert("remoteId".to_string(), PhpMixed::String("test".to_string())); + advisory.insert( + "title".to_string(), + PhpMixed::String("Security Advisory".to_string()), + ); + advisory.insert("link".to_string(), PhpMixed::Null); + advisory.insert( + "cve".to_string(), + match cve { + Some(cve) => PhpMixed::String(cve.to_string()), + None => PhpMixed::Null, + }, + ); + advisory.insert( + "affectedVersions".to_string(), + PhpMixed::String(affected_versions.to_string()), + ); + advisory.insert("source".to_string(), PhpMixed::String("Tests".to_string())); + advisory.insert( + "reportedAt".to_string(), + PhpMixed::String("2024-04-31 12:37:47".to_string()), + ); + advisory.insert( + "composerRepository".to_string(), + PhpMixed::String("Package Repository".to_string()), + ); + advisory.insert("severity".to_string(), PhpMixed::String("high".to_string())); + advisory.insert( + "sources".to_string(), + PhpMixed::List(vec![PhpMixed::Array(source)]), + ); + advisory +} diff --git a/crates/shirabe/tests/dependency_resolver/solver_test.rs b/crates/shirabe/tests/dependency_resolver/solver_test.rs index c9c4d26..a688190 100644 --- a/crates/shirabe/tests/dependency_resolver/solver_test.rs +++ b/crates/shirabe/tests/dependency_resolver/solver_test.rs @@ -277,7 +277,7 @@ fn test_solver_remove_if_not_requested() { ); } -#[ignore = "get_pretty_string path reaches an unimplemented todo!() (in_array non-strict in php-shim)"] +#[ignore = "get_pretty_string path reaches an unimplemented stub (in_array non-strict in php-shim)"] #[test] fn test_install_non_existing_package_fails() { let fixtures = set_up(); @@ -1921,7 +1921,7 @@ fn test_issue265() { ); } -#[ignore = "get_pretty_string path reaches an unimplemented todo!() (in_array non-strict in php-shim)"] +#[ignore = "get_pretty_string path reaches an unimplemented stub (in_array non-strict in php-shim)"] #[test] fn test_conflict_result_empty() { let fixtures = set_up(); @@ -1979,7 +1979,7 @@ fn test_conflict_result_empty() { ); } -#[ignore = "get_pretty_string path reaches an unimplemented todo!() (in_array non-strict in php-shim)"] +#[ignore = "get_pretty_string path reaches an unimplemented stub (in_array non-strict in php-shim)"] #[test] fn test_unsatisfiable_requires() { let fixtures = set_up(); @@ -2027,7 +2027,7 @@ fn test_unsatisfiable_requires() { ); } -#[ignore = "get_pretty_string path reaches an unimplemented todo!() (Intervals::is_subset_of)"] +#[ignore = "get_pretty_string path reaches an unimplemented stub (Intervals::is_subset_of)"] #[test] fn test_require_mismatch_exception() { let fixtures = set_up(); -- cgit v1.3.1