diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:42:07 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:42:07 +0900 |
| commit | 5ab5f3b316798c1411ce8e6a7f5b091fda93589c (patch) | |
| tree | c7669f94f5d9bd9adc07bc1aab3f14cfdec1ae5f /crates/shirabe/tests/dependency_resolver/solver_test.rs | |
| parent | b291e714bc739262140323e08fe2fb9e91e00ee7 (diff) | |
| download | php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.tar.gz php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.tar.zst php-shirabe-5ab5f3b316798c1411ce8e6a7f5b091fda93589c.zip | |
test: port previously-ignored Composer tests via __ test hatches
Re-evaluate the reason'd #[ignore] tests under the Phase D criterion:
a test is unportable ONLY if the APIs/types needed to WRITE it do not
exist. A test that compiles but panics at runtime (todo!() body, a
regex the regex crate cannot compile) or fails at runtime (incomplete
or incorrect impl behavior) is portable -- it is written in full and
marked with a reason-less #[ignore].
About 120 test functions move from reason'd #[ignore] to reason-less
#[ignore] (the ported-but-not-yet-passing signal). Impl crates gain
only additive __ test hatches (init_command, pool, file_downloader,
package handle link setters, artifact/path repository, repository
manager, svn); no existing logic changes. Tests whose required APIs
genuinely do not exist (mock/reflection harness, ApplicationTester,
solve() discarding SolverProblemsException, a script::Event that
cannot be passed as an originating event) keep their reason'd
#[ignore].
cargo check -p shirabe --tests passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/dependency_resolver/solver_test.rs')
| -rw-r--r-- | crates/shirabe/tests/dependency_resolver/solver_test.rs | 1777 |
1 files changed, 1703 insertions, 74 deletions
diff --git a/crates/shirabe/tests/dependency_resolver/solver_test.rs b/crates/shirabe/tests/dependency_resolver/solver_test.rs index 26f1312..c729fea 100644 --- a/crates/shirabe/tests/dependency_resolver/solver_test.rs +++ b/crates/shirabe/tests/dependency_resolver/solver_test.rs @@ -9,11 +9,13 @@ 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::Link; use shirabe::package::handle::PackageInterfaceHandle; 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_semver::constraint::{AnyConstraint, MatchAllConstraint, MultiConstraint}; use crate::test_case::{get_alias_package, get_package, get_version_constraint}; @@ -50,6 +52,40 @@ fn set_up() -> Fixtures { } } +/// 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, + ) +} + +/// PHP `new Link($source, $target, $constraint, $type, $prettyConstraint)`. +fn link_pretty( + source: &str, + target: &str, + constraint: AnyConstraint, + r#type: &str, + pretty: &str, +) -> Link { + Link::new( + source.to_string(), + target.to_string(), + constraint, + Some(r#type.to_string()), + pretty.to_string(), + ) +} + +fn multi(constraints: Vec<AnyConstraint>) -> AnyConstraint { + MultiConstraint::new(constraints, true, None).into() +} + /// One expected solver job. Mirrors the PHP `['job' => ..., 'package'|'from'|'to' => ...]` rows. enum ExpectedJob { Single { @@ -67,7 +103,7 @@ fn check_solver_result( mut repo_set: RepositorySet, repo: ArrayRepository, repo_locked: LockArrayRepositoryHandle, - mut request: Request, + request: Request, expected: Vec<ExpectedJob>, ) { // reposComplete() @@ -76,6 +112,15 @@ fn check_solver_result( .unwrap(); repo_set.add_repository(repo_locked.into()).unwrap(); + check_solver_result_repo_set(&mut repo_set, request, expected); +} + +/// ref: SolverTest::checkSolverResult, against an already-completed RepositorySet (createSolver). +fn check_solver_result_repo_set( + repo_set: &mut RepositorySet, + mut request: Request, + expected: Vec<ExpectedJob>, +) { // createSolver() let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); let pool = repo_set @@ -137,6 +182,29 @@ fn check_solver_result( assert_eq!(expected_ids, result_ids); } +/// ref: SolverTest::createSolver + solve, returning the error for expectException-only tests. +fn solve_expecting_error( + mut repo_set: RepositorySet, + repo: ArrayRepository, + repo_locked: LockArrayRepositoryHandle, + mut request: Request, +) { + repo_set + .add_repository(RepositoryInterfaceHandle::new(repo)) + .unwrap(); + repo_set.add_repository(repo_locked.into()).unwrap(); + + 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); + + assert!(solver.solve(&request, None).is_err()); +} + #[ignore] #[test] fn test_solver_install_single() { @@ -178,7 +246,7 @@ fn test_solver_remove_if_not_requested() { ); } -#[ignore = "solve() error path discards SolverProblemsException (returns placeholder anyhow error); getProblems/getCode/getPrettyString not retrievable"] +#[ignore = "asserts SolverProblemsException details (getProblems/getCode/getPrettyString) which solve() discards"] #[test] fn test_install_non_existing_package_fails() { let _fixtures = set_up(); @@ -222,40 +290,364 @@ fn test_solver_install_same_package_from_different_repositories() { ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_install_with_deps() { - 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("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let new_package_b = get_package("B", "1.1"); + fixtures.repo.add_package(new_package_b.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint("<", "1.1"), + Link::TYPE_REQUIRE, + ), + )])); + + 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_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_install_honours_not_equal_operator() { - 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("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let new_package_b11 = get_package("B", "1.1"); + fixtures.repo.add_package(new_package_b11.clone()).unwrap(); + let new_package_b12 = get_package("B", "1.2"); + fixtures.repo.add_package(new_package_b12.clone()).unwrap(); + let new_package_b13 = get_package("B", "1.3"); + fixtures.repo.add_package(new_package_b13.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + multi(vec![ + get_version_constraint("<=", "1.3"), + get_version_constraint("<>", "1.3"), + get_version_constraint("!=", "1.2"), + ]), + Link::TYPE_REQUIRE, + ), + )])); + + 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: new_package_b11, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_install_with_deps_in_order() { - 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("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let package_c = get_package("C", "1.0"); + fixtures.repo.add_package(package_c.clone()).unwrap(); + + package_b + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "a".to_string(), + link( + "B", + "A", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "c".to_string(), + link( + "B", + "C", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ])); + package_c + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "C", + "A", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + request.require_name("B", None).unwrap(); + request.require_name("C", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ExpectedJob::Single { + job: "install", + package: package_c, + }, + ExpectedJob::Single { + job: "install", + package: package_b, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_multi_package_name_version_resolution_depends_on_require_order() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let php74 = get_package("ourcustom/PHP", "7.4.23"); + fixtures.repo.add_package(php74.clone()).unwrap(); + let php80 = get_package("ourcustom/PHP", "8.0.10"); + fixtures.repo.add_package(php80.clone()).unwrap(); + let ext_for_php74 = get_package("ourcustom/ext-foobar", "1.0"); + fixtures.repo.add_package(ext_for_php74.clone()).unwrap(); + let ext_for_php80 = get_package("ourcustom/ext-foobar", "1.0"); + fixtures.repo.add_package(ext_for_php80.clone()).unwrap(); + + ext_for_php74 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "ourcustom/php".to_string(), + link( + "ourcustom/ext-foobar", + "ourcustom/PHP", + multi(vec![ + get_version_constraint(">=", "7.4.0"), + get_version_constraint("<", "7.5.0"), + ]), + Link::TYPE_REQUIRE, + ), + )])); + ext_for_php80 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "ourcustom/php".to_string(), + link( + "ourcustom/ext-foobar", + "ourcustom/PHP", + multi(vec![ + get_version_constraint(">=", "8.0.0"), + get_version_constraint("<", "8.1.0"), + ]), + Link::TYPE_REQUIRE, + ), + )])); + + // reposComplete() + let mut repo_set = fixtures.repo_set; + repo_set + .add_repository(RepositoryInterfaceHandle::new(fixtures.repo)) + .unwrap(); + repo_set + .add_repository(fixtures.repo_locked.clone().into()) + .unwrap(); + + let mut request = fixtures.request; + request.require_name("ourcustom/PHP", None).unwrap(); + request.require_name("ourcustom/ext-foobar", None).unwrap(); + + check_solver_result_repo_set( + &mut repo_set, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: php80.clone(), + }, + ExpectedJob::Single { + job: "install", + package: ext_for_php80, + }, + ], + ); + + // now we flip the requirements around: we request "ext-foobar" before "php" + let mut request = Request::new(Some(fixtures.repo_locked.clone())); + request.require_name("ourcustom/ext-foobar", None).unwrap(); + request.require_name("ourcustom/PHP", None).unwrap(); + + check_solver_result_repo_set( + &mut repo_set, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: php74, + }, + ExpectedJob::Single { + job: "install", + package: ext_for_php74, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_multi_package_name_version_resolution_is_independent_of_require_order_if_ordered_descending_by_requirement() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let php74 = get_package("ourcustom/PHP", "7.4"); + fixtures.repo.add_package(php74.clone()).unwrap(); + let php80 = get_package("ourcustom/PHP", "8.0"); + fixtures.repo.add_package(php80.clone()).unwrap(); + // note we are inserting this one into the repo first, unlike in the previous test + let ext_for_php80 = get_package("ourcustom/ext-foobar", "1.0"); + fixtures.repo.add_package(ext_for_php80.clone()).unwrap(); + let ext_for_php74 = get_package("ourcustom/ext-foobar", "1.0"); + fixtures.repo.add_package(ext_for_php74.clone()).unwrap(); + + ext_for_php80 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "ourcustom/php".to_string(), + link( + "ourcustom/ext-foobar", + "ourcustom/PHP", + multi(vec![ + get_version_constraint(">=", "8.0.0"), + get_version_constraint("<", "8.1.0"), + ]), + Link::TYPE_REQUIRE, + ), + )])); + ext_for_php74 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "ourcustom/php".to_string(), + link( + "ourcustom/ext-foobar", + "ourcustom/PHP", + multi(vec![ + get_version_constraint(">=", "7.4.0"), + get_version_constraint("<", "7.5.0"), + ]), + Link::TYPE_REQUIRE, + ), + )])); + + // reposComplete() + let mut repo_set = fixtures.repo_set; + repo_set + .add_repository(RepositoryInterfaceHandle::new(fixtures.repo)) + .unwrap(); + repo_set + .add_repository(fixtures.repo_locked.clone().into()) + .unwrap(); + + let mut request = fixtures.request; + request.require_name("ourcustom/PHP", None).unwrap(); + request.require_name("ourcustom/ext-foobar", None).unwrap(); + + check_solver_result_repo_set( + &mut repo_set, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: php80.clone(), + }, + ExpectedJob::Single { + job: "install", + package: ext_for_php80.clone(), + }, + ], + ); + + // unlike in the previous test, the order of requirements no longer matters now + let mut request = Request::new(Some(fixtures.repo_locked.clone())); + request.require_name("ourcustom/ext-foobar", None).unwrap(); + request.require_name("ourcustom/PHP", None).unwrap(); + + check_solver_result_repo_set( + &mut repo_set, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: php80, + }, + ExpectedJob::Single { + job: "install", + package: ext_for_php80, + }, + ], + ); } #[ignore] @@ -297,11 +689,46 @@ fn test_solver_fix_locked_with_alternative() { ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_update_does_only_update() { - 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_b = get_package("B", "1.1"); + fixtures.repo.add_package(new_package_b.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0.0.0"), + Link::TYPE_REQUIRE, + ), + )])); + + let mut request = fixtures.request; + request.fix_package(package_a.clone()); + request + .require_name("B", Some(get_version_constraint("=", "1.1.0.0"))) + .unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ExpectedJob::Update { + from: package_b, + to: new_package_b, + }], + ); } #[ignore] @@ -328,11 +755,63 @@ fn test_solver_update_single() { ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_update_all() { - 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.1"); + fixtures.repo.add_package(new_package_a.clone()).unwrap(); + let new_package_b = get_package("B", "1.1"); + fixtures.repo.add_package(new_package_b.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + MatchAllConstraint::new(None).into(), + Link::TYPE_REQUIRE, + ), + )])); + new_package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + MatchAllConstraint::new(None).into(), + Link::TYPE_REQUIRE, + ), + )])); + + 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_b, + to: new_package_b, + }, + ExpectedJob::Update { + from: package_a, + to: new_package_a, + }, + ], + ); } #[ignore] @@ -475,25 +954,168 @@ fn test_solver_update_fully_constrained_prunes_installed_packages() { ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_all_jobs() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let package_d = get_package("D", "1.0"); + fixtures.repo_locked.add_package(package_d.clone()).unwrap(); + let old_package_c = get_package("C", "1.0"); + fixtures + .repo_locked + .add_package(old_package_c.clone()) + .unwrap(); + + let package_a = get_package("A", "2.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + let package_b = get_package("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let new_package_b = get_package("B", "1.1"); + fixtures.repo.add_package(new_package_b.clone()).unwrap(); + let package_c = get_package("C", "1.1"); + fixtures.repo.add_package(package_c.clone()).unwrap(); + fixtures.repo.add_package(get_package("D", "1.0")).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint("<", "1.1"), + Link::TYPE_REQUIRE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + request.require_name("C", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "remove", + package: package_d, + }, + ExpectedJob::Single { + job: "install", + package: package_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ExpectedJob::Update { + from: old_package_c, + to: package_c, + }, + ], + ); } -#[ignore = "setRequires/setConflicts not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_three_alternative_require_and_conflict() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let package_a = get_package("A", "2.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + let middle_package_b = get_package("B", "1.0"); + fixtures.repo.add_package(middle_package_b.clone()).unwrap(); + let new_package_b = get_package("B", "1.1"); + fixtures.repo.add_package(new_package_b.clone()).unwrap(); + let old_package_b = get_package("B", "0.9"); + fixtures.repo.add_package(old_package_b.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint("<", "1.1"), + Link::TYPE_REQUIRE, + ), + )])); + package_a + .as_complete_package() + .unwrap() + .__set_conflicts(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint("<", "1.0"), + Link::TYPE_CONFLICT, + ), + )])); + + 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: middle_package_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_solver_obsolete() { - 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.add_package(package_b.clone()).unwrap(); + package_b + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([( + "a".to_string(), + link( + "B", + "A", + MatchAllConstraint::new(None).into(), + Link::TYPE_REPLACE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("B", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "remove", + package: package_a, + }, + ExpectedJob::Single { + job: "install", + package: package_b, + }, + ], + ); } #[ignore] @@ -520,109 +1142,925 @@ fn test_install_one_of_two_alternatives() { ); } -#[ignore = "setRequires/setProvides not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_install_provider() { - 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_q = get_package("Q", "1.0"); + fixtures.repo.add_package(package_q.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_q + .as_complete_package() + .unwrap() + .__set_provides(IndexMap::from([( + "b".to_string(), + link( + "Q", + "B", + get_version_constraint("=", "1.0"), + Link::TYPE_PROVIDE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + + // must explicitly pick the provider, so error in this case + solve_expecting_error( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + ); } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_skip_replacer_of_existing_package() { - 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_q = get_package("Q", "1.0"); + fixtures.repo.add_package(package_q.clone()).unwrap(); + let package_b = get_package("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_q + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([( + "b".to_string(), + link( + "Q", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + )])); + + 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_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_no_install_replacer_of_missing_package() { - 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_q = get_package("Q", "1.0"); + fixtures.repo.add_package(package_q.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_q + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([( + "b".to_string(), + link( + "Q", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + + solve_expecting_error( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + ); } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_skip_replaced_package_if_replacer_is_selected() { - 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_q = get_package("Q", "1.0"); + fixtures.repo.add_package(package_q.clone()).unwrap(); + let package_b = get_package("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_q + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([( + "b".to_string(), + link( + "Q", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + request.require_name("Q", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: package_q, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_pick_older_if_newer_conflicts() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let package_x = get_package("X", "1.0"); + fixtures.repo.add_package(package_x.clone()).unwrap(); + package_x + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "a".to_string(), + link( + "X", + "A", + get_version_constraint(">=", "2.0.0.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "b".to_string(), + link( + "X", + "B", + get_version_constraint(">=", "2.0.0.0"), + Link::TYPE_REQUIRE, + ), + ), + ])); + + let package_a = get_package("A", "2.0.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + let new_package_a = get_package("A", "2.1.0"); + fixtures.repo.add_package(new_package_a.clone()).unwrap(); + let new_package_b = get_package("B", "2.1.0"); + fixtures.repo.add_package(new_package_b.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "2.0.0.0"), + Link::TYPE_REQUIRE, + ), + )])); + + // new package A depends on version of package B that does not exist + // => new package A is not installable + new_package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "2.2.0.0"), + Link::TYPE_REQUIRE, + ), + )])); + + // add a package S replacing both A and B, so that S and B or S and A cannot be simultaneously installed + // but an alternative option for A and B both exists + // this creates a more difficult so solve conflict + let package_s = get_package("S", "2.0.0"); + fixtures.repo.add_package(package_s.clone()).unwrap(); + package_s + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([ + ( + "a".to_string(), + link( + "S", + "A", + get_version_constraint(">=", "2.0.0.0"), + Link::TYPE_REPLACE, + ), + ), + ( + "b".to_string(), + link( + "S", + "B", + get_version_constraint(">=", "2.0.0.0"), + Link::TYPE_REPLACE, + ), + ), + ])); + + let mut request = fixtures.request; + request.require_name("X", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: new_package_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ExpectedJob::Single { + job: "install", + package: package_x, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_install_circular_require() { - 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_b1 = get_package("B", "0.9"); + fixtures.repo.add_package(package_b1.clone()).unwrap(); + let package_b2 = get_package("B", "1.1"); + fixtures.repo.add_package(package_b2.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_b2 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "B", + "A", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + + 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_b2, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setRequires/setProvides not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_install_alternative_with_circular_require() { - 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("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let package_c = get_package("C", "1.0"); + fixtures.repo.add_package(package_c.clone()).unwrap(); + let package_d = get_package("D", "1.0"); + fixtures.repo.add_package(package_d.clone()).unwrap(); + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_b + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "virtual".to_string(), + link( + "B", + "Virtual", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_c + .as_complete_package() + .unwrap() + .__set_provides(IndexMap::from([( + "virtual".to_string(), + link( + "C", + "Virtual", + get_version_constraint("==", "1.0"), + Link::TYPE_PROVIDE, + ), + )])); + package_d + .as_complete_package() + .unwrap() + .__set_provides(IndexMap::from([( + "virtual".to_string(), + link( + "D", + "Virtual", + get_version_constraint("==", "1.0"), + Link::TYPE_PROVIDE, + ), + )])); + + package_c + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "C", + "A", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_d + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "D", + "A", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + request.require_name("C", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: package_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ExpectedJob::Single { + job: "install", + package: package_c, + }, + ], + ); } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_use_replacer_if_necessary() { - 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("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let package_d = get_package("D", "1.0"); + fixtures.repo.add_package(package_d.clone()).unwrap(); + let package_d2 = get_package("D", "1.1"); + fixtures.repo.add_package(package_d2.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "b".to_string(), + link( + "A", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "c".to_string(), + link( + "A", + "C", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ])); + + package_d + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([ + ( + "b".to_string(), + link( + "D", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + ), + ( + "c".to_string(), + link( + "D", + "C", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + ), + ])); + + package_d2 + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([ + ( + "b".to_string(), + link( + "D", + "B", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + ), + ( + "c".to_string(), + link( + "D", + "C", + get_version_constraint(">=", "1.0"), + Link::TYPE_REPLACE, + ), + ), + ])); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + request.require_name("D", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: package_d2, + }, + ExpectedJob::Single { + job: "install", + package: package_a, + }, + ], + ); } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_issue265() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let package_a1 = get_package("A", "2.0.999999-dev"); + fixtures.repo.add_package(package_a1.clone()).unwrap(); + let package_a2 = get_package("A", "2.1-dev"); + fixtures.repo.add_package(package_a2.clone()).unwrap(); + let package_a3 = get_package("A", "2.2-dev"); + fixtures.repo.add_package(package_a3.clone()).unwrap(); + let package_b1 = get_package("B", "2.0.10"); + fixtures.repo.add_package(package_b1.clone()).unwrap(); + let package_b2 = get_package("B", "2.0.9"); + fixtures.repo.add_package(package_b2.clone()).unwrap(); + let package_c = get_package("C", "2.0-dev"); + fixtures.repo.add_package(package_c.clone()).unwrap(); + let package_d = get_package("D", "2.0.9"); + fixtures.repo.add_package(package_d.clone()).unwrap(); + + package_c + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "a".to_string(), + link( + "C", + "A", + get_version_constraint(">=", "2.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "d".to_string(), + link( + "C", + "D", + get_version_constraint(">=", "2.0"), + Link::TYPE_REQUIRE, + ), + ), + ])); + + package_d + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "a".to_string(), + link( + "D", + "A", + get_version_constraint(">=", "2.1"), + Link::TYPE_REQUIRE, + ), + ), + ( + "b".to_string(), + link( + "D", + "B", + get_version_constraint(">=", "2.0-dev"), + Link::TYPE_REQUIRE, + ), + ), + ])); + + package_b1 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "B", + "A", + get_version_constraint("==", "2.1.0.0-dev"), + Link::TYPE_REQUIRE, + ), + )])); + package_b2 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "B", + "A", + get_version_constraint("==", "2.1.0.0-dev"), + Link::TYPE_REQUIRE, + ), + )])); + + package_b2 + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([( + "d".to_string(), + link( + "B", + "D", + get_version_constraint("==", "2.0.9.0"), + Link::TYPE_REPLACE, + ), + )])); + + let mut request = fixtures.request; + request + .require_name("C", Some(get_version_constraint("==", "2.0.0.0-dev"))) + .unwrap(); + + solve_expecting_error( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + ); } -#[ignore = "setConflicts not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore = "asserts SolverProblemsException details (getProblems/getPrettyString) which solve() discards"] #[test] fn test_conflict_result_empty() { let _fixtures = set_up(); todo!() } -#[ignore = "setRequires not available on CompletePackageHandle; also asserts SolverProblemsException details which solve() discards"] +#[ignore = "asserts SolverProblemsException details (getProblems/getPrettyString) which solve() discards"] #[test] fn test_unsatisfiable_requires() { let _fixtures = set_up(); todo!() } -#[ignore = "setRequires not available on CompletePackageHandle; also asserts SolverProblemsException details which solve() discards"] +#[ignore = "asserts SolverProblemsException details (getProblems/getPrettyString) which solve() discards"] #[test] fn test_require_mismatch_exception() { let _fixtures = set_up(); todo!() } -#[ignore = "setRequires/setReplaces not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_learn_literals_with_sorted_rule_literals() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let package_twig2 = get_package("twig/twig", "2.0"); + fixtures.repo.add_package(package_twig2.clone()).unwrap(); + let package_twig16 = get_package("twig/twig", "1.6"); + fixtures.repo.add_package(package_twig16.clone()).unwrap(); + let package_twig15 = get_package("twig/twig", "1.5"); + fixtures.repo.add_package(package_twig15.clone()).unwrap(); + let package_symfony = get_package("symfony/symfony", "2.0"); + fixtures.repo.add_package(package_symfony.clone()).unwrap(); + let package_twig_bridge = get_package("symfony/twig-bridge", "2.0"); + fixtures + .repo + .add_package(package_twig_bridge.clone()) + .unwrap(); + + package_twig_bridge + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "twig/twig".to_string(), + link( + "symfony/twig-bridge", + "twig/twig", + get_version_constraint("<", "2.0"), + Link::TYPE_REQUIRE, + ), + )])); + + package_symfony + .as_complete_package() + .unwrap() + .__set_replaces(IndexMap::from([( + "symfony/twig-bridge".to_string(), + link( + "symfony/symfony", + "symfony/twig-bridge", + get_version_constraint("==", "2.0"), + Link::TYPE_REPLACE, + ), + )])); + + let mut request = fixtures.request; + request.require_name("symfony/twig-bridge", None).unwrap(); + request.require_name("twig/twig", None).unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: package_twig16, + }, + ExpectedJob::Single { + job: "install", + package: package_twig_bridge, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_install_recursive_alias_dependencies() { - 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("B", "2.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let package_a2 = get_package("A", "2.0"); + fixtures.repo.add_package(package_a2.clone()).unwrap(); + + package_a2 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "b".to_string(), + link_pretty( + "A", + "B", + get_version_constraint("==", "2.0"), + Link::TYPE_REQUIRE, + "== 2.0", + ), + )])); + package_b + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "B", + "A", + get_version_constraint(">=", "2.0"), + Link::TYPE_REQUIRE, + ), + )])); + + let package_a2_alias = get_alias_package(&package_a2, "1.1"); + fixtures.repo.add_package(package_a2_alias.clone()).unwrap(); + + let mut request = fixtures.request; + request + .require_name("A", Some(get_version_constraint("==", "1.1.0.0"))) + .unwrap(); + + check_solver_result( + fixtures.repo_set, + fixtures.repo, + fixtures.repo_locked, + request, + vec![ + ExpectedJob::Single { + job: "install", + package: package_b, + }, + ExpectedJob::Single { + job: "install", + package: package_a2, + }, + ExpectedJob::Single { + job: "markAliasInstalled", + package: package_a2_alias, + }, + ], + ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_install_dev_alias() { - let _fixtures = set_up(); - todo!() + let fixtures = set_up(); + let package_a = get_package("A", "2.0"); + fixtures.repo.add_package(package_a.clone()).unwrap(); + let package_b = get_package("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + + package_b + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "a".to_string(), + link( + "B", + "A", + get_version_constraint("<", "2.0"), + Link::TYPE_REQUIRE, + ), + )])); + + let package_a_alias = get_alias_package(&package_a, "1.1"); + fixtures.repo.add_package(package_a_alias.clone()).unwrap(); + + let mut request = fixtures.request; + request + .require_name("A", Some(get_version_constraint("==", "2.0"))) + .unwrap(); + request.require_name("B", None).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, + }, + ], + ); } #[ignore] @@ -699,9 +2137,200 @@ fn test_install_root_aliases_if_alias_of_is_installed() { ); } -#[ignore = "setRequires not available on CompletePackageHandle (only RootPackageHandle exposes link setters)"] +#[ignore] #[test] fn test_learn_positive_literal() { - 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("B", "1.0"); + fixtures.repo.add_package(package_b.clone()).unwrap(); + let package_c1 = get_package("C", "1.0"); + fixtures.repo.add_package(package_c1.clone()).unwrap(); + let package_c2 = get_package("C", "2.0"); + fixtures.repo.add_package(package_c2.clone()).unwrap(); + let package_d = get_package("D", "1.0"); + fixtures.repo.add_package(package_d.clone()).unwrap(); + let package_e = get_package("E", "1.0"); + fixtures.repo.add_package(package_e.clone()).unwrap(); + let package_f1 = get_package("F", "1.0"); + fixtures.repo.add_package(package_f1.clone()).unwrap(); + let package_f2 = get_package("F", "2.0"); + fixtures.repo.add_package(package_f2.clone()).unwrap(); + let package_g1 = get_package("G", "1.0"); + fixtures.repo.add_package(package_g1.clone()).unwrap(); + let package_g2 = get_package("G", "2.0"); + fixtures.repo.add_package(package_g2.clone()).unwrap(); + let package_g3 = get_package("G", "3.0"); + fixtures.repo.add_package(package_g3.clone()).unwrap(); + + package_a + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "b".to_string(), + link( + "A", + "B", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "c".to_string(), + link( + "A", + "C", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "d".to_string(), + link( + "A", + "D", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ])); + + package_b + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "e".to_string(), + link( + "B", + "E", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + + package_c1 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "f".to_string(), + link( + "C", + "F", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + package_c2 + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([ + ( + "f".to_string(), + link( + "C", + "F", + get_version_constraint("==", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ( + "g".to_string(), + link( + "C", + "G", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + ), + ])); + + package_d + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "f".to_string(), + link( + "D", + "F", + get_version_constraint(">=", "1.0"), + Link::TYPE_REQUIRE, + ), + )])); + + package_e + .as_complete_package() + .unwrap() + .__set_requires(IndexMap::from([( + "g".to_string(), + link( + "E", + "G", + get_version_constraint("<=", "2.0"), + Link::TYPE_REQUIRE, + ), + )])); + + // reposComplete() + createSolver() inline so the testFlagLearnedPositiveLiteral flag can be + // asserted on the same solver instance used to solve. + let mut repo_set = fixtures.repo_set; + repo_set + .add_repository(RepositoryInterfaceHandle::new(fixtures.repo)) + .unwrap(); + repo_set + .add_repository(fixtures.repo_locked.into()) + .unwrap(); + + let mut request = fixtures.request; + request.require_name("A", None).unwrap(); + + 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); + + // check correct setup for assertion later + assert!(!solver.test_flag_learned_positive_literal); + + let transaction = solver.solve(&request, None).unwrap(); + + let expected = vec![ + ("install".to_string(), package_f1.get_unique_name()), + ("install".to_string(), package_d.get_unique_name()), + ("install".to_string(), package_g2.get_unique_name()), + ("install".to_string(), package_c2.get_unique_name()), + ("install".to_string(), package_e.get_unique_name()), + ("install".to_string(), package_b.get_unique_name()), + ("install".to_string(), package_a.get_unique_name()), + ]; + let mut result: Vec<(String, String)> = Vec::new(); + for operation in transaction.get_operations() { + if let Some(update) = operation.as_update_operation() { + result.push(( + "update".to_string(), + format!( + "{} => {}", + update.get_initial_package().get_unique_name(), + update.get_target_package().get_unique_name() + ), + )); + } else { + let op_type = operation.get_operation_type(); + let job = if op_type == "uninstall" { + "remove".to_string() + } else { + op_type + }; + result.push((job, operation.get_package().get_unique_name())); + } + } + assert_eq!(expected, result); + + // verify that the code path leading to a negative literal resulting in a positive learned + // literal is actually executed + assert!(solver.test_flag_learned_positive_literal); } |
