aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/dependency_resolver
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/tests/dependency_resolver')
-rw-r--r--crates/shirabe/tests/dependency_resolver/default_policy_test.rs523
-rw-r--r--crates/shirabe/tests/dependency_resolver/pool_builder_test.rs2
-rw-r--r--crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs263
-rw-r--r--crates/shirabe/tests/dependency_resolver/rule_set_test.rs60
-rw-r--r--crates/shirabe/tests/dependency_resolver/rule_test.rs81
-rw-r--r--crates/shirabe/tests/dependency_resolver/security_advisory_pool_filter_test.rs89
-rw-r--r--crates/shirabe/tests/dependency_resolver/solver_test.rs521
-rw-r--r--crates/shirabe/tests/dependency_resolver/transaction_test.rs5
8 files changed, 1397 insertions, 147 deletions
diff --git a/crates/shirabe/tests/dependency_resolver/default_policy_test.rs b/crates/shirabe/tests/dependency_resolver/default_policy_test.rs
index 077dd71..776de6c 100644
--- a/crates/shirabe/tests/dependency_resolver/default_policy_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/default_policy_test.rs
@@ -1,17 +1,23 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php
use indexmap::IndexMap;
+use shirabe::dependency_resolver::PolicyInterface;
use shirabe::dependency_resolver::default_policy::DefaultPolicy;
+use shirabe::package::handle::{CompleteAliasPackageHandle, CompletePackageHandle};
use shirabe::repository::array_repository::ArrayRepository;
+use shirabe::repository::handle::{LockArrayRepositoryHandle, RepositoryInterfaceHandle};
use shirabe::repository::lock_array_repository::LockArrayRepository;
use shirabe::repository::repository_set::RepositorySet;
use shirabe::util::platform::Platform;
+use shirabe_semver::constraint::{AnyConstraint, SimpleConstraint};
+
+use crate::test_case::get_package;
#[allow(dead_code)]
struct Fixtures {
repository_set: RepositorySet,
repo: ArrayRepository,
- repo_locked: LockArrayRepository,
+ repo_locked: LockArrayRepositoryHandle,
policy: DefaultPolicy,
}
@@ -25,7 +31,7 @@ fn set_up() -> Fixtures {
IndexMap::new(),
);
let repo = ArrayRepository::new(vec![]).unwrap();
- let repo_locked = LockArrayRepository::new(vec![]).unwrap();
+ let repo_locked = LockArrayRepositoryHandle::new(LockArrayRepository::new(vec![]).unwrap());
let policy = DefaultPolicy::new(false, false, None);
@@ -48,141 +54,558 @@ impl Drop for TearDown {
}
}
-// These build a Pool from packages and exercise DefaultPolicy::selectPreferredPackages.
-// Constructing the packages/constraints parses versions through a look-around regex the
-// regex crate cannot compile, and the setup mirrors the solver fixtures.
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_single() {
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();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a.get_id()];
+ let expected = vec![package_a.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0");
+ let package_a2 = get_package("A", "2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_picks_latest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.0.1-alpha");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_picks_latest_stable_with_prefer_stable() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.0.1-alpha");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a1.get_id()];
+
+ let policy = DefaultPolicy::new(true, false, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest_with_prefer_dev_over_prerelease() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+
+ for stability in ["alpha1", "beta1", "RC1"] {
+ let mut fixtures = set_up();
+
+ Platform::put_env("COMPOSER_PREFER_DEV_OVER_PRERELEASE", "1");
+ let dev_package = get_package("A", "dev-master");
+ let prerelease_package = get_package("A", &format!("1.0.0-{}", stability));
+ fixtures.repo.add_package(dev_package.clone()).unwrap();
+ fixtures
+ .repo
+ .add_package(prerelease_package.clone())
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![dev_package.get_id(), prerelease_package.get_id()];
+ let expected = vec![dev_package.get_id()];
+
+ let policy = DefaultPolicy::new(true, true, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest_prefers_prerelease_over_dev() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+
+ for stability in ["alpha1", "beta1", "RC1"] {
+ let mut fixtures = set_up();
+
+ let dev_package = get_package("A", "dev-master");
+ let prerelease_package = get_package("A", &format!("1.0.0-{}", stability));
+ fixtures.repo.add_package(dev_package.clone()).unwrap();
+ fixtures
+ .repo
+ .add_package(prerelease_package.clone())
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![prerelease_package.get_id(), dev_package.get_id()];
+ let expected = vec![prerelease_package.get_id()];
+
+ let policy = DefaultPolicy::new(true, true, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest_with_prefer_stable_still_prefers_stable() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ Platform::put_env("COMPOSER_PREFER_DEV_OVER_PRERELEASE", "1");
+ let stable_package = get_package("A", "1.0.0");
+ let dev_package = get_package("A", "dev-master");
+ fixtures.repo.add_package(stable_package.clone()).unwrap();
+ fixtures.repo.add_package(dev_package.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![stable_package.get_id(), dev_package.get_id()];
+ let expected = vec![stable_package.get_id()];
+
+ let policy = DefaultPolicy::new(true, true, None);
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_dev_picks_non_dev() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "dev-foo");
+ let package_a2 = get_package("A", "1.0.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_preferred_version_picks_preferred_version_if_available() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.1.0");
+ let package_a2b = get_package("A", "1.1.0");
+ let package_a3 = get_package("A", "1.2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures.repo.add_package(package_a2b.clone()).unwrap();
+ fixtures.repo.add_package(package_a3.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![
+ package_a1.get_id(),
+ package_a2.get_id(),
+ package_a2b.get_id(),
+ package_a3.get_id(),
+ ];
+ let expected = vec![package_a2.get_id(), package_a2b.get_id()];
+
+ let mut preferred = IndexMap::new();
+ preferred.insert("a".to_string(), "1.1.0.0".to_string());
+ let policy = DefaultPolicy::new(false, false, Some(preferred));
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_preferred_version_picks_newest_otherwise() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a2.get_id()];
+
+ let mut preferred = IndexMap::new();
+ preferred.insert("a".to_string(), "1.1.0.0".to_string());
+ let policy = DefaultPolicy::new(false, false, Some(preferred));
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_newest_with_preferred_version_picks_lowest_if_prefer_lowest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let package_a1 = get_package("A", "1.0.0");
+ let package_a2 = get_package("A", "1.2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a1.get_id()];
+
+ let mut preferred = IndexMap::new();
+ preferred.insert("a".to_string(), "1.1.0.0".to_string());
+ let policy = DefaultPolicy::new(false, true, Some(preferred));
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_repository_ordering_affects_priority() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let repo1 = ArrayRepository::new(vec![]).unwrap();
+ let repo2 = ArrayRepository::new(vec![]).unwrap();
+
+ let package1 = get_package("A", "1.0");
+ let package2 = get_package("A", "1.1");
+ let package3 = get_package("A", "1.1");
+ let package4 = get_package("A", "1.2");
+ repo1.add_package(package1.clone()).unwrap();
+ repo1.add_package(package2.clone()).unwrap();
+ repo2.add_package(package3.clone()).unwrap();
+ repo2.add_package(package4.clone()).unwrap();
+
+ let repo1_handle = RepositoryInterfaceHandle::new(repo1);
+ let repo2_handle = RepositoryInterfaceHandle::new(repo2);
+
+ fixtures
+ .repository_set
+ .add_repository(repo1_handle.clone())
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(repo2_handle.clone())
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![
+ package1.get_id(),
+ package2.get_id(),
+ package3.get_id(),
+ package4.get_id(),
+ ];
+ let expected = vec![package2.get_id()];
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals.clone(), None);
+
+ assert_eq!(expected, selected);
+
+ let mut repository_set = RepositorySet::new(
+ "dev",
+ IndexMap::new(),
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ repository_set.add_repository(repo2_handle).unwrap();
+ repository_set.add_repository(repo1_handle).unwrap();
+
+ let pool = repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let expected = vec![package4.get_id()];
+ let selected = fixtures
+ .policy
+ .select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_local_repos_first() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let repo_important = ArrayRepository::new(vec![]).unwrap();
+
+ let package_a = get_package("A", "dev-master");
+ let package_a_alias = CompleteAliasPackageHandle::new(
+ CompletePackageHandle::from_rc_unchecked(package_a.as_rc().clone()),
+ "2.1.9999999.9999999-dev".to_string(),
+ "2.1.x-dev".to_string(),
+ );
+ let package_a_important = get_package("A", "dev-feature-a");
+ let package_a_alias_important = CompleteAliasPackageHandle::new(
+ CompletePackageHandle::from_rc_unchecked(package_a_important.as_rc().clone()),
+ "2.1.9999999.9999999-dev".to_string(),
+ "2.1.x-dev".to_string(),
+ );
+ let package_a2_important = get_package("A", "dev-master");
+ let package_a2_alias_important = CompleteAliasPackageHandle::new(
+ CompletePackageHandle::from_rc_unchecked(package_a2_important.as_rc().clone()),
+ "2.1.9999999.9999999-dev".to_string(),
+ "2.1.x-dev".to_string(),
+ );
+ package_a_alias_important.set_root_package_alias(true);
+
+ fixtures.repo.add_package(package_a).unwrap();
+ fixtures
+ .repo
+ .add_package(package_a_alias.clone().into())
+ .unwrap();
+ repo_important.add_package(package_a_important).unwrap();
+ repo_important
+ .add_package(package_a_alias_important.clone().into())
+ .unwrap();
+ repo_important.add_package(package_a2_important).unwrap();
+ repo_important
+ .add_package(package_a2_alias_important.into())
+ .unwrap();
+
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(repo_important))
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+ fixtures
+ .repository_set
+ .add_repository(fixtures.repo_locked.clone().into())
+ .unwrap();
+
+ let mut pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let constraint = AnyConstraint::Simple(SimpleConstraint::new(
+ "=".to_string(),
+ "2.1.9999999.9999999-dev".to_string(),
+ None,
+ ));
+ let packages = pool.what_provides("a", Some(&constraint));
+ assert!(!packages.is_empty());
+ let mut literals = vec![];
+ for package in &packages {
+ literals.push(package.get_id());
+ }
+
+ let expected = vec![package_a_alias_important.get_id()];
+
+ 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_provides"]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_all_providers() {
let _tear_down = TearDown;
let _fixtures = set_up();
todo!()
}
+#[ignore = "set_provides/set_replaces only exist on RootPackage handles; CompletePackage from get_package has no set_replaces"]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_prefer_non_replacing_from_same_repo() {
let _tear_down = TearDown;
let _fixtures = set_up();
todo!()
}
+#[ignore = "set_replaces only exists on RootPackage handles; CompletePackage from get_package has no set_replaces"]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_prefer_replacing_package_from_same_vendor() {
let _tear_down = TearDown;
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (DefaultPolicy over a Pool; constraint parsing uses a look-around regex)"]
fn test_select_lowest() {
let _tear_down = TearDown;
- let _fixtures = set_up();
- todo!()
+ let mut fixtures = set_up();
+
+ let policy = DefaultPolicy::new(false, true, None);
+
+ let package_a1 = get_package("A", "1.0");
+ let package_a2 = get_package("A", "2.0");
+ fixtures.repo.add_package(package_a1.clone()).unwrap();
+ fixtures.repo.add_package(package_a2.clone()).unwrap();
+ fixtures
+ .repository_set
+ .add_repository(RepositoryInterfaceHandle::new(fixtures.repo))
+ .unwrap();
+
+ let pool = fixtures
+ .repository_set
+ .create_pool_for_package("A", Some(fixtures.repo_locked.clone()))
+ .unwrap();
+
+ let literals = vec![package_a1.get_id(), package_a2.get_id()];
+ let expected = vec![package_a1.get_id()];
+
+ let selected = policy.select_preferred_packages(&pool, literals, None);
+
+ assert_eq!(expected, selected);
}
diff --git a/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs b/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
index 617c7b9..4c72091 100644
--- a/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/pool_builder_test.rs
@@ -3,7 +3,7 @@
// testPoolBuilder is a large fixture-driven case that loads packages from test inputs and
// builds a Pool; constraint parsing uses a look-around regex the regex crate cannot compile.
#[test]
-#[ignore = "not yet ported (fixture-driven PoolBuilder; constraint parsing uses a look-around regex)"]
+#[ignore = "ArrayLoader::load (single-package, pub) and Pool::count are not exposed: the loadPackage closure calls $loader->load($data) per package and getPackageResultSet uses count($pool)"]
fn test_pool_builder() {
todo!()
}
diff --git a/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs b/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs
index a25aec6..408c191 100644
--- a/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/pool_optimizer_test.rs
@@ -1,9 +1,264 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php
-// testPoolOptimizer is a large fixture-driven case building and optimizing a Pool;
-// constraint parsing uses a look-around regex the regex crate cannot compile.
+use std::path::PathBuf;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::dependency_resolver::default_policy::DefaultPolicy;
+use shirabe::dependency_resolver::pool::Pool;
+use shirabe::dependency_resolver::pool_optimizer::PoolOptimizer;
+use shirabe::dependency_resolver::request::Request;
+use shirabe::json::JsonFile;
+use shirabe::package::BasePackageHandle;
+use shirabe::package::loader::{ArrayLoader, LoaderInterface};
+use shirabe::package::version::version_parser::VersionParser;
+use shirabe::repository::handle::LockArrayRepositoryHandle;
+use shirabe::repository::lock_array_repository::LockArrayRepository;
+use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_php_shim::PREG_SPLIT_DELIM_CAPTURE;
+use shirabe_php_shim::PhpMixed;
+
+fn load_package(package_data: &PhpMixed) -> BasePackageHandle {
+ let loader = ArrayLoader::new(None, false);
+ loader
+ .load(package_data.as_array().unwrap().clone(), None)
+ .unwrap()
+}
+
+fn load_packages(packages_data: &[PhpMixed]) -> Vec<BasePackageHandle> {
+ let mut packages: Vec<BasePackageHandle> = Vec::new();
+
+ for package_data in packages_data {
+ let package = load_package(package_data);
+ packages.push(package.clone());
+ if let Some(alias) = package.as_alias() {
+ packages.push(alias.get_alias_of().into());
+ }
+ }
+
+ packages
+}
+
+fn reduce_packages_info_for_comparison(packages: &[BasePackageHandle]) -> Vec<String> {
+ let mut packages_info: Vec<String> = Vec::new();
+
+ for package in packages {
+ let suffix = if let Some(alias) = package.as_alias() {
+ format!(" (alias of {})", alias.get_alias_of().get_version())
+ } else {
+ String::new()
+ };
+ packages_info.push(format!(
+ "{}@{}{}",
+ package.get_name(),
+ package.get_version(),
+ suffix
+ ));
+ }
+
+ packages_info.sort();
+
+ packages_info
+}
+
+fn read_test_file(file: &str, fixtures_dir: &str) -> IndexMap<String, String> {
+ let contents = shirabe_php_shim::file_get_contents(file).unwrap();
+ let tokens = Preg::split4(
+ r"#(?:^|\n*)--([A-Z-]+)--\n#",
+ &contents,
+ -1,
+ PREG_SPLIT_DELIM_CAPTURE,
+ );
+
+ let section_info: Vec<&str> = vec!["TEST", "REQUEST", "POOL-BEFORE", "POOL-AFTER"];
+
+ let mut section: Option<String> = None;
+ let mut data: IndexMap<String, String> = IndexMap::new();
+ for token in tokens {
+ if section.is_none() && token.is_empty() {
+ continue;
+ }
+
+ if section.is_none() {
+ if !section_info.contains(&token.as_str()) {
+ panic!(
+ "The test file \"{}\" must not contain a section named \"{}\".",
+ file.replace(&format!("{}/", fixtures_dir), ""),
+ token
+ );
+ }
+ section = Some(token);
+ continue;
+ }
+
+ let section_data = token;
+ data.insert(section.take().unwrap(), section_data);
+ }
+
+ for required_section in &section_info {
+ if !data.contains_key(*required_section) {
+ panic!(
+ "The test file \"{}\" must have a section named \"{}\".",
+ file.replace(&format!("{}/", fixtures_dir), ""),
+ required_section
+ );
+ }
+ }
+
+ data
+}
+
+fn collect_test_files(dir: &std::path::Path, out: &mut Vec<PathBuf>) {
+ for entry in std::fs::read_dir(dir).unwrap() {
+ let entry = entry.unwrap();
+ let path = entry.path();
+ if path.is_dir() {
+ collect_test_files(&path, out);
+ } else {
+ out.push(path);
+ }
+ }
+}
+
+fn provide_integration_tests() -> IndexMap<
+ String,
+ (
+ PhpMixed,
+ Vec<BasePackageHandle>,
+ Vec<BasePackageHandle>,
+ String,
+ ),
+> {
+ let fixtures_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
+ .join("../../composer/tests/Composer/Test/DependencyResolver/Fixtures/pooloptimizer");
+ let fixtures_dir = std::fs::canonicalize(&fixtures_dir).unwrap();
+ let fixtures_dir_str = fixtures_dir.to_str().unwrap().to_string();
+
+ let mut files: Vec<PathBuf> = Vec::new();
+ collect_test_files(&fixtures_dir, &mut files);
+
+ let mut tests: IndexMap<
+ String,
+ (
+ PhpMixed,
+ Vec<BasePackageHandle>,
+ Vec<BasePackageHandle>,
+ String,
+ ),
+ > = IndexMap::new();
+ for file in files {
+ let file = file.to_str().unwrap().to_string();
+
+ if !Preg::is_match(r"/\.test$/", &file) {
+ continue;
+ }
+
+ let test_data = read_test_file(&file, &fixtures_dir_str);
+ let message = test_data["TEST"].clone();
+ let request_data = JsonFile::parse_json(Some(&test_data["REQUEST"]), None).unwrap();
+ let packages_before = load_packages(
+ JsonFile::parse_json(Some(&test_data["POOL-BEFORE"]), None)
+ .unwrap()
+ .as_list()
+ .unwrap(),
+ );
+ let expected_packages = load_packages(
+ JsonFile::parse_json(Some(&test_data["POOL-AFTER"]), None)
+ .unwrap()
+ .as_list()
+ .unwrap(),
+ );
+
+ let basename = std::path::Path::new(&file)
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string();
+ tests.insert(
+ basename,
+ (request_data, packages_before, expected_packages, message),
+ );
+ }
+
+ tests
+}
+
+fn run_test_pool_optimizer(
+ request_data: &PhpMixed,
+ packages_before: Vec<BasePackageHandle>,
+ expected_packages: &[BasePackageHandle],
+ message: &str,
+) {
+ let request_data = request_data.as_array().unwrap();
+
+ let locked_repo = LockArrayRepositoryHandle::new(LockArrayRepository::new(vec![]).unwrap());
+
+ let mut request = Request::new(Some(locked_repo));
+ let parser = VersionParser::new();
+
+ if let Some(locked) = request_data.get("locked") {
+ for package in locked.as_list().unwrap() {
+ request.lock_package(load_package(package));
+ }
+ }
+ if let Some(fixed) = request_data.get("fixed") {
+ for package in fixed.as_list().unwrap() {
+ request.fix_package(load_package(package));
+ }
+ }
+
+ for (package, constraint) in request_data["require"].as_array().unwrap() {
+ request
+ .require_name(
+ package,
+ Some(
+ parser
+ .parse_constraints(constraint.as_string().unwrap())
+ .unwrap(),
+ ),
+ )
+ .unwrap();
+ }
+
+ let prefer_stable = request_data
+ .get("preferStable")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+ let prefer_lowest = request_data
+ .get("preferLowest")
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
+
+ let pool = Pool::new(
+ packages_before,
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let mut pool_optimizer = PoolOptimizer::new(Rc::new(DefaultPolicy::new(
+ prefer_stable,
+ prefer_lowest,
+ None,
+ )));
+
+ let pool = pool_optimizer.optimize(&request, &pool);
+
+ assert_eq!(
+ reduce_packages_info_for_comparison(expected_packages),
+ reduce_packages_info_for_comparison(pool.get_packages()),
+ "{}",
+ message
+ );
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (fixture-driven PoolOptimizer; constraint parsing uses a look-around regex)"]
fn test_pool_optimizer() {
- todo!()
+ let tests = provide_integration_tests();
+ for (_name, (request_data, packages_before, expected_packages, message)) in tests {
+ run_test_pool_optimizer(&request_data, packages_before, &expected_packages, &message);
+ }
}
diff --git a/crates/shirabe/tests/dependency_resolver/rule_set_test.rs b/crates/shirabe/tests/dependency_resolver/rule_set_test.rs
index 5620b2a..f1e573e 100644
--- a/crates/shirabe/tests/dependency_resolver/rule_set_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/rule_set_test.rs
@@ -3,10 +3,14 @@
use std::cell::RefCell;
use std::rc::Rc;
+use indexmap::IndexMap;
use shirabe::dependency_resolver::{
- GenericRule, RULE_LEARNED, RULE_ROOT_REQUIRE, ReasonData, Rule, RuleSet,
+ GenericRule, Pool, RULE_LEARNED, RULE_ROOT_REQUIRE, ReasonData, Request, Rule, RuleSet,
};
-use shirabe_semver::constraint::MatchAllConstraint;
+use shirabe::repository::RepositorySet;
+use shirabe_semver::constraint::{MatchAllConstraint, MatchNoneConstraint};
+
+use crate::test_case::get_package;
fn root_require_reason() -> ReasonData {
ReasonData::RootRequire {
@@ -156,10 +160,54 @@ fn test_get_iterator_without() {
assert!(Rc::ptr_eq(&iterator.current(), &rule2));
}
-// In PHP this mocks RepositorySet and Request to build the pretty string. The mocked
-// collaborators cannot be reproduced here, and add() also reaches hash_raw (todo!()).
+// The constraint is MatchNoneConstraint, so what_provides returns no packages and the
+// "No package found" branch is taken; the RepositorySet/Request collaborators are never
+// actually consulted (PHP mocks them with the constructor disabled).
#[test]
-#[ignore = "getPrettyString needs mocked RepositorySet/Request, and add() reaches hash_raw (todo!())"]
+#[ignore]
fn test_pretty_string() {
- todo!()
+ let p = get_package("foo", "2.1");
+ let mut pool = Pool::new(
+ vec![p.clone()],
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+
+ let repository_set = RepositorySet::new(
+ "stable",
+ IndexMap::new(),
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let request = Request::new(None);
+
+ let mut rule_set = RuleSet::new();
+ let literal = p.get_id();
+ let rule = Rc::new(RefCell::new(Rule::Generic(GenericRule::new(
+ vec![literal],
+ RULE_ROOT_REQUIRE,
+ ReasonData::RootRequire {
+ package_name: "foo/bar".to_string(),
+ constraint: MatchNoneConstraint::new(None).into(),
+ },
+ ))));
+
+ rule_set.add(rule, RuleSet::TYPE_REQUEST).unwrap();
+
+ let pretty = rule_set
+ .get_pretty_string(
+ Some(&repository_set),
+ Some(&request),
+ Some(&mut pool),
+ false,
+ )
+ .unwrap();
+ assert!(
+ pretty.contains("REQUEST : No package found to satisfy root composer.json require foo/bar")
+ );
}
diff --git a/crates/shirabe/tests/dependency_resolver/rule_test.rs b/crates/shirabe/tests/dependency_resolver/rule_test.rs
index 9806820..156931c 100644
--- a/crates/shirabe/tests/dependency_resolver/rule_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/rule_test.rs
@@ -1,8 +1,16 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/RuleTest.php
-use shirabe::dependency_resolver::{GenericRule, RULE_ROOT_REQUIRE, ReasonData, Rule, RuleSet};
+use indexmap::IndexMap;
+use shirabe::dependency_resolver::{
+ GenericRule, Pool, RULE_PACKAGE_REQUIRES, RULE_ROOT_REQUIRE, ReasonData, Request, Rule, RuleSet,
+};
+use shirabe::package::Link;
+use shirabe::repository::RepositorySet;
+use shirabe_php_shim::{PHP_VERSION_ID, hash_raw, unpack};
use shirabe_semver::constraint::MatchAllConstraint;
+use crate::test_case::get_package;
+
fn root_require_reason() -> ReasonData {
ReasonData::RootRequire {
package_name: String::new(),
@@ -18,10 +26,23 @@ fn generic_rule(literals: Vec<i64>) -> Rule {
))
}
+#[ignore]
#[test]
-#[ignore = "Rule::get_hash reaches shirabe_php_shim::hash_raw, which is todo!()"]
fn test_get_hash() {
- todo!()
+ let rule = generic_rule(vec![123]);
+
+ let algo = if PHP_VERSION_ID > 80100 {
+ "xxh3"
+ } else {
+ "sha1"
+ };
+ let binary = hash_raw(algo, "123");
+ let hash = unpack("ihash", &binary).unwrap();
+
+ assert_eq!(
+ hash.get("hash").unwrap().as_int(),
+ rule.get_hash().unwrap().as_int()
+ );
}
#[test]
@@ -85,10 +106,56 @@ fn test_is_assertions() {
assert!(rule2.is_assertion());
}
-// In PHP this mocks RepositorySet and Request and passes a Link reason to build the
-// pretty string. The mocked collaborators cannot be reproduced here.
+// PHP mocks RepositorySet and Request with the constructor disabled; the RULE_PACKAGE_REQUIRES
+// branch with a non-empty requires list never consults them, so real minimal instances suffice.
+#[ignore]
#[test]
-#[ignore = "getPrettyString needs mocked RepositorySet and Request; mocking is not available"]
fn test_pretty_string() {
- todo!()
+ let p1 = get_package("foo", "2.1");
+ let p2 = get_package("baz", "1.1");
+ let mut pool = Pool::new(
+ vec![p1.clone(), p2.clone()],
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+
+ let repository_set = RepositorySet::new(
+ "stable",
+ IndexMap::new(),
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let request = Request::new(None);
+
+ let empty_constraint = MatchAllConstraint::new(Some("*".to_string()));
+
+ let rule = Rule::Generic(GenericRule::new(
+ vec![p1.get_id(), -p2.get_id()],
+ RULE_PACKAGE_REQUIRES,
+ ReasonData::Link(Link::new(
+ "baz".to_string(),
+ "foo".to_string(),
+ empty_constraint.into(),
+ None,
+ "*".to_string(),
+ )),
+ ));
+
+ assert_eq!(
+ "baz 1.1 relates to foo * -> satisfiable by foo[2.1].",
+ rule.get_pretty_string(
+ &repository_set,
+ &request,
+ &mut pool,
+ false,
+ &IndexMap::new(),
+ &vec![],
+ )
+ .unwrap()
+ );
}
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 825d6b4..1232241 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
@@ -5,26 +5,105 @@
// crate cannot compile. The fixtures also build PackageRepository security-advisory data
// and run the Auditor.
+use indexmap::IndexMap;
+use shirabe::advisory::AuditConfig;
+use shirabe::advisory::Auditor;
+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;
+
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
+#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec<RepositoryInterfaceHandle>) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"]
fn test_filter_packages_by_advisories() {
todo!()
}
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
+#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec<RepositoryInterfaceHandle>) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"]
fn test_dont_filter_packages_by_ignored_advisories() {
todo!()
}
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
+#[ignore = "requires PackageRepository to implement RepositoryInterface (filter takes Vec<RepositoryInterfaceHandle>) and php-shim uniqid() used by generateSecurityAdvisory; neither exists"]
fn test_dont_filter_packages_with_block_insecure_disabled() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "filtering parses affectedVersions via a look-around regex the regex crate cannot compile"]
fn test_dont_filter_packages_with_abandoned_package() {
- todo!()
+ let package_name_ignore_abandoned = "acme/ignore-abandoned";
+ let mut ignore_abandoned: IndexMap<String, Option<String>> = IndexMap::new();
+ ignore_abandoned.insert(package_name_ignore_abandoned.to_string(), None);
+ 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(),
+ ignore_abandoned.clone(),
+ ignore_abandoned,
+ );
+ let filter = SecurityAdvisoryPoolFilter::new(Auditor, audit_config);
+
+ let abandoned_package = CompletePackageHandle::new(
+ "acme/package".to_string(),
+ "1.0.0.0".to_string(),
+ "1.0".to_string(),
+ );
+ abandoned_package.set_abandoned(PhpMixed::Bool(true));
+ let ignore_abandoned_package = CompletePackageHandle::new(
+ package_name_ignore_abandoned.to_string(),
+ "1.0.0.0".to_string(),
+ "1.0".to_string(),
+ );
+ ignore_abandoned_package.set_abandoned(PhpMixed::Bool(true));
+ let expected_package = PackageHandle::new(
+ "acme/other".to_string(),
+ "1.1.0.0".to_string(),
+ "1.1".to_string(),
+ );
+
+ let expected_package: PackageInterfaceHandle = expected_package.into();
+ let abandoned_package: PackageInterfaceHandle = abandoned_package.into();
+ let ignore_abandoned_package: PackageInterfaceHandle = ignore_abandoned_package.into();
+
+ let pool = Pool::new(
+ vec![
+ expected_package.clone(),
+ abandoned_package.clone(),
+ ignore_abandoned_package.clone(),
+ ],
+ vec![],
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ IndexMap::new(),
+ );
+ let filtered_pool = filter.filter(pool, vec![], &Request::new(None)).unwrap();
+
+ let packages = filtered_pool.get_packages();
+ assert_eq!(packages.len(), 2);
+ assert!(packages[0].ptr_eq(&expected_package));
+ assert!(packages[1].ptr_eq(&ignore_abandoned_package));
+ assert_eq!(
+ filtered_pool
+ .get_all_abandoned_removed_package_versions()
+ .len(),
+ 1
+ );
+ assert_eq!(
+ filtered_pool
+ .get_all_security_removed_package_versions()
+ .len(),
+ 0
+ );
}
diff --git a/crates/shirabe/tests/dependency_resolver/solver_test.rs b/crates/shirabe/tests/dependency_resolver/solver_test.rs
index b876c99..26f1312 100644
--- a/crates/shirabe/tests/dependency_resolver/solver_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/solver_test.rs
@@ -1,13 +1,22 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/SolverTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
use indexmap::IndexMap;
+use shirabe::dependency_resolver::PolicyInterface;
use shirabe::dependency_resolver::default_policy::DefaultPolicy;
use shirabe::dependency_resolver::request::Request;
+use shirabe::io::io_interface::IOInterface;
+use shirabe::io::null_io::NullIO;
+use shirabe::package::handle::PackageInterfaceHandle;
use shirabe::repository::array_repository::ArrayRepository;
-use shirabe::repository::handle::LockArrayRepositoryHandle;
+use shirabe::repository::handle::{LockArrayRepositoryHandle, RepositoryInterfaceHandle};
use shirabe::repository::lock_array_repository::LockArrayRepository;
use shirabe::repository::repository_set::RepositorySet;
+use crate::test_case::{get_alias_package, get_package, get_version_constraint};
+
#[allow(dead_code)]
struct Fixtures {
repo_set: RepositorySet,
@@ -41,285 +50,657 @@ fn set_up() -> Fixtures {
}
}
-// These run the dependency Solver over packages/requests built from version constraints,
-// whose parsing goes through a look-around regex the regex crate cannot compile; the setup
-// also mirrors the larger solver fixtures.
+/// One expected solver job. Mirrors the PHP `['job' => ..., 'package'|'from'|'to' => ...]` rows.
+enum ExpectedJob {
+ Single {
+ job: &'static str,
+ package: PackageInterfaceHandle,
+ },
+ Update {
+ from: PackageInterfaceHandle,
+ to: PackageInterfaceHandle,
+ },
+}
+
+/// ref: SolverTest::checkSolverResult (with reposComplete + createSolver folded in).
+fn check_solver_result(
+ mut repo_set: RepositorySet,
+ repo: ArrayRepository,
+ repo_locked: LockArrayRepositoryHandle,
+ mut request: Request,
+ expected: Vec<ExpectedJob>,
+) {
+ // reposComplete()
+ repo_set
+ .add_repository(RepositoryInterfaceHandle::new(repo))
+ .unwrap();
+ repo_set.add_repository(repo_locked.into()).unwrap();
+
+ // createSolver()
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let pool = repo_set
+ .create_pool(&mut request, io.clone(), None, None, vec![], None, None)
+ .unwrap();
+ let policy: Rc<dyn PolicyInterface> = Rc::new(DefaultPolicy::new(false, false, None));
+ let mut solver =
+ shirabe::dependency_resolver::solver::Solver::new(policy, Rc::new(RefCell::new(pool)), io);
+
+ let transaction = solver.solve(&request, None).unwrap();
+
+ // Build readable (unique-name) and identity (ptr) representations of the result and
+ // the expectation, mirroring the dual assertEquals in the PHP helper.
+ let mut result_readable: Vec<(String, String)> = Vec::new();
+ let mut result_ids: Vec<(String, Vec<usize>)> = Vec::new();
+ for operation in transaction.get_operations() {
+ if let Some(update) = operation.as_update_operation() {
+ let from = update.get_initial_package();
+ let to = update.get_target_package();
+ result_readable.push((
+ "update".to_string(),
+ format!("{} => {}", from.get_unique_name(), to.get_unique_name()),
+ ));
+ result_ids.push(("update".to_string(), vec![from.ptr_id(), to.ptr_id()]));
+ } else {
+ let op_type = operation.get_operation_type();
+ let job = match op_type.as_str() {
+ "markAliasInstalled" => "markAliasInstalled",
+ "markAliasUninstalled" => "markAliasUninstalled",
+ "uninstall" => "remove",
+ "install" => "install",
+ other => panic!("Unexpected operation: {}", other),
+ };
+ let package = operation.get_package();
+ result_readable.push((job.to_string(), package.get_unique_name()));
+ result_ids.push((job.to_string(), vec![package.ptr_id()]));
+ }
+ }
+
+ let mut expected_readable: Vec<(String, String)> = Vec::new();
+ let mut expected_ids: Vec<(String, Vec<usize>)> = Vec::new();
+ for job in &expected {
+ match job {
+ ExpectedJob::Single { job, package } => {
+ expected_readable.push((job.to_string(), package.get_unique_name()));
+ expected_ids.push((job.to_string(), vec![package.ptr_id()]));
+ }
+ ExpectedJob::Update { from, to } => {
+ expected_readable.push((
+ "update".to_string(),
+ format!("{} => {}", from.get_unique_name(), to.get_unique_name()),
+ ));
+ expected_ids.push(("update".to_string(), vec![from.ptr_id(), to.ptr_id()]));
+ }
+ }
+ }
+
+ assert_eq!(expected_readable, result_readable);
+ assert_eq!(expected_ids, result_ids);
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_single() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Single {
+ job: "install",
+ package: package_a,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_remove_if_not_requested() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ fixtures.request,
+ vec![ExpectedJob::Single {
+ job: "remove",
+ package: package_a,
+ }],
+ );
}
+#[ignore = "solve() error path discards SolverProblemsException (returns placeholder anyhow error); getProblems/getCode/getPrettyString not retrievable"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_non_existing_package_fails() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_same_package_from_different_repositories() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let mut repo_set = fixtures.repo_set;
+
+ let repo1 = ArrayRepository::new(vec![]).unwrap();
+ let repo2 = ArrayRepository::new(vec![]).unwrap();
+
+ let foo1 = get_package("foo", "1");
+ let foo2 = get_package("foo", "1");
+ repo1.add_package(foo1.clone()).unwrap();
+ repo2.add_package(foo2.clone()).unwrap();
+
+ repo_set
+ .add_repository(RepositoryInterfaceHandle::new(repo1))
+ .unwrap();
+ repo_set
+ .add_repository(RepositoryInterfaceHandle::new(repo2))
+ .unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("foo", None).unwrap();
+
+ // The two repos are already added here; the helper adds the (empty) default repos too.
+ check_solver_result(
+ repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Single {
+ job: "install",
+ package: foo1,
+ }],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_with_deps() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_honours_not_equal_operator() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_install_with_deps_in_order() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_multi_package_name_version_resolution_depends_on_require_order() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_multi_package_name_version_resolution_is_independent_of_require_order_if_ordered_descending_by_requirement()
{
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_fix_locked() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.fix_package(package_a.clone());
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_fix_locked_with_alternative() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ fixtures.repo.add_package(get_package("A", "1.0")).unwrap();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.fix_package(package_a.clone());
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_does_only_update() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_single() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let new_package_a = get_package("A", "1.1");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ }],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_all() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_current() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ fixtures
+ .repo_locked
+ .add_package(get_package("A", "1.0"))
+ .unwrap();
+ fixtures.repo.add_package(get_package("A", "1.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_only_updates_selected_package() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let package_b = get_package("B", "1.0");
+ fixtures.repo_locked.add_package(package_b.clone()).unwrap();
+ let package_a_newer = get_package("A", "1.1");
+ fixtures.repo.add_package(package_a_newer.clone()).unwrap();
+ let package_b_newer = get_package("B", "1.1");
+ fixtures.repo.add_package(package_b_newer.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+ request.fix_package(package_b.clone());
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: package_a_newer,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_constrained() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let new_package_a = get_package("A", "1.2");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+ fixtures.repo.add_package(get_package("A", "2.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("<", "2.0.0.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_fully_constrained() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let new_package_a = get_package("A", "1.2");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+ fixtures.repo.add_package(get_package("A", "2.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("<", "2.0.0.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ }],
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_update_fully_constrained_prunes_installed_packages() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo_locked.add_package(package_a.clone()).unwrap();
+ let package_b = get_package("B", "1.0");
+ fixtures.repo_locked.add_package(package_b.clone()).unwrap();
+ let new_package_a = get_package("A", "1.2");
+ fixtures.repo.add_package(new_package_a.clone()).unwrap();
+ fixtures.repo.add_package(get_package("A", "2.0")).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("<", "2.0.0.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![
+ ExpectedJob::Single {
+ job: "remove",
+ package: package_b,
+ },
+ ExpectedJob::Update {
+ from: package_a,
+ to: new_package_a,
+ },
+ ],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_all_jobs() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setConflicts not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_three_alternative_require_and_conflict() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_solver_obsolete() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_one_of_two_alternatives() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+ let package_b = get_package("A", "1.0");
+ fixtures.repo.add_package(package_b.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request.require_name("A", None).unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![ExpectedJob::Single {
+ job: "install",
+ package: package_a,
+ }],
+ );
}
+#[ignore = "setRequires/setProvides not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_provider() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_skip_replacer_of_existing_package() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_no_install_replacer_of_missing_package() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_skip_replaced_package_if_replacer_is_selected() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_pick_older_if_newer_conflicts() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_circular_require() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setProvides not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_alternative_with_circular_require() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_use_replacer_if_necessary() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_issue265() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setConflicts not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_conflict_result_empty() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle; also asserts SolverProblemsException details which solve() discards"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_unsatisfiable_requires() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle; also asserts SolverProblemsException details which solve() discards"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_require_mismatch_exception() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_learn_literals_with_sorted_rule_literals() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_recursive_alias_dependencies() {
let _fixtures = set_up();
todo!()
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_dev_alias() {
let _fixtures = set_up();
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_install_root_aliases_if_alias_of_is_installed() {
- let _fixtures = set_up();
- todo!()
+ let fixtures = set_up();
+
+ // root aliased, required
+ let package_a = get_package("A", "1.0");
+ fixtures.repo.add_package(package_a.clone()).unwrap();
+ let package_a_alias = get_alias_package(&package_a, "1.1");
+ fixtures.repo.add_package(package_a_alias.clone()).unwrap();
+ package_a_alias
+ .as_alias()
+ .unwrap()
+ .set_root_package_alias(true);
+ // root aliased, not required, should still be installed as it is root alias
+ let package_b = get_package("B", "1.0");
+ fixtures.repo.add_package(package_b.clone()).unwrap();
+ let package_b_alias = get_alias_package(&package_b, "1.1");
+ fixtures.repo.add_package(package_b_alias.clone()).unwrap();
+ package_b_alias
+ .as_alias()
+ .unwrap()
+ .set_root_package_alias(true);
+ // regular alias, not required, alias should not be installed
+ let package_c = get_package("C", "1.0");
+ fixtures.repo.add_package(package_c.clone()).unwrap();
+ let package_c_alias = get_alias_package(&package_c, "1.1");
+ fixtures.repo.add_package(package_c_alias.clone()).unwrap();
+
+ let mut request = fixtures.request;
+ request
+ .require_name("A", Some(get_version_constraint("==", "1.1")))
+ .unwrap();
+ request
+ .require_name("B", Some(get_version_constraint("==", "1.0")))
+ .unwrap();
+ request
+ .require_name("C", Some(get_version_constraint("==", "1.0")))
+ .unwrap();
+
+ check_solver_result(
+ fixtures.repo_set,
+ fixtures.repo,
+ fixtures.repo_locked,
+ request,
+ vec![
+ ExpectedJob::Single {
+ job: "install",
+ package: package_a,
+ },
+ ExpectedJob::Single {
+ job: "markAliasInstalled",
+ package: package_a_alias,
+ },
+ ExpectedJob::Single {
+ job: "install",
+ package: package_b,
+ },
+ ExpectedJob::Single {
+ job: "markAliasInstalled",
+ package: package_b_alias,
+ },
+ ExpectedJob::Single {
+ job: "install",
+ package: package_c,
+ },
+ ExpectedJob::Single {
+ job: "markAliasInstalled",
+ package: package_c_alias,
+ },
+ ],
+ );
}
+#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"]
#[test]
-#[ignore = "not yet ported (runs the Solver; constraint parsing uses a look-around regex)"]
fn test_learn_positive_literal() {
let _fixtures = set_up();
todo!()
diff --git a/crates/shirabe/tests/dependency_resolver/transaction_test.rs b/crates/shirabe/tests/dependency_resolver/transaction_test.rs
index 2ea74aa..a5ca310 100644
--- a/crates/shirabe/tests/dependency_resolver/transaction_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/transaction_test.rs
@@ -1,10 +1,7 @@
//! ref: composer/tests/Composer/Test/DependencyResolver/TransactionTest.php
-// Transaction::new sorts operations via shirabe_php_shim::uasort_map, which is todo!().
-// The fixture also calls setRequires/setProvides on non-root packages, which the public
-// handle API does not allow, so the scenario cannot be expressed faithfully yet.
#[test]
-#[ignore = "Transaction::new reaches uasort_map (todo!()); fixture needs link setters on non-root packages"]
+#[ignore = "CompletePackageHandle lacks set_type/set_requires/set_provides/set_extra; these setters exist only on RootPackageHandle, so the non-root package fixture cannot be expressed"]
fn test_transaction_generation_and_sorting() {
todo!()
}