From e4c94dd41573f734b2dcdff9aed4e305b7c749d1 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 21 Oct 2011 14:44:24 +0200 Subject: [PATCH 1/5] Adding tests for the default policy specifying its desired behaviour --- .../DependencyResolver/DefaultPolicy.php | 3 +- .../DependencyResolver/PolicyInterface.php | 2 +- src/Composer/DependencyResolver/Solver.php | 2 +- .../DependencyResolver/DefaultPolicyTest.php | 101 ++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php diff --git a/src/Composer/DependencyResolver/DefaultPolicy.php b/src/Composer/DependencyResolver/DefaultPolicy.php index 921c30f70..fb90dd4f0 100644 --- a/src/Composer/DependencyResolver/DefaultPolicy.php +++ b/src/Composer/DependencyResolver/DefaultPolicy.php @@ -63,9 +63,8 @@ class DefaultPolicy implements PolicyInterface return true; } - public function selectPreferedPackages(Solver $solver, Pool $pool, RepositoryInterface $installed, array $literals) + public function selectPreferedPackages(Pool $pool, RepositoryInterface $installed, array $literals) { - // prefer installed, newest version, recommended, highest priority repository, ... $newest = $this->selectNewestPackages($installed, $literals); $selected = array(); diff --git a/src/Composer/DependencyResolver/PolicyInterface.php b/src/Composer/DependencyResolver/PolicyInterface.php index 1a7184204..41929c2ce 100644 --- a/src/Composer/DependencyResolver/PolicyInterface.php +++ b/src/Composer/DependencyResolver/PolicyInterface.php @@ -25,5 +25,5 @@ interface PolicyInterface function versionCompare(PackageInterface $a, PackageInterface $b, $operator); function findUpdatePackages(Solver $solver, Pool $pool, RepositoryInterface $repo, PackageInterface $package, $allowAll); function installable(Solver $solver, Pool $pool, RepositoryInterface $repo, PackageInterface $package); - function selectPreferedPackages(Solver $solver, Pool $pool, RepositoryInterface $installed, array $literals); + function selectPreferedPackages(Pool $pool, RepositoryInterface $installed, array $literals); } diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index c21918262..baf7f5d30 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -1411,7 +1411,7 @@ class Solver private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule) { // choose best package to install from decisionQueue - $literals = $this->policy->selectPreferedPackages($this, $this->pool, $this->installed, $decisionQueue); + $literals = $this->policy->selectPreferedPackages($this->pool, $this->installed, $decisionQueue); $selectedLiteral = array_shift($literals); diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php new file mode 100644 index 000000000..1558f14e4 --- /dev/null +++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php @@ -0,0 +1,101 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\DependencyResolver; + +use Composer\Repository\ArrayRepository; +use Composer\DependencyResolver\DefaultPolicy; +use Composer\DependencyResolver\Pool; +use Composer\DependencyResolver\Literal; +use Composer\Package\MemoryPackage; +use Composer\Package\Link; +use Composer\Package\LinkConstraint\VersionConstraint; + +class DefaultPolicyTest extends \PHPUnit_Framework_TestCase +{ + protected $pool; + protected $repo; + protected $repoInstalled; + protected $request; + protected $policy; + + public function setUp() + { + $this->pool = new Pool; + $this->repo = new ArrayRepository; + $this->repoInstalled = new ArrayRepository; + + $this->policy = new DefaultPolicy; + } + + public function testSelectSingle() + { + $this->repo->addPackage($packageA = new MemoryPackage('A', '1.0')); + $this->pool->addRepository($this->repo); + + $literals = array(new Literal($packageA, true)); + $expected = array(new Literal($packageA, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } + + public function testSelectNewest() + { + $this->repo->addPackage($packageA1 = new MemoryPackage('A', '1.0')); + $this->repo->addPackage($packageA2 = new MemoryPackage('A', '2.0')); + $this->pool->addRepository($this->repo); + + $literals = array(new Literal($packageA1, true), new Literal($packageA2, true)); + $expected = array(new Literal($packageA2, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } + + public function testSelectInstalled() + { + $this->repo->addPackage($packageA = new MemoryPackage('A', '1.0')); + $this->repoInstalled->addPackage($packageAInstalled = new MemoryPackage('A', '1.0')); + $this->pool->addRepository($this->repo); + $this->pool->addRepository($this->repoInstalled); + + $literals = array(new Literal($packageA, true), new Literal($packageAInstalled, true)); + $expected = array(new Literal($packageAInstalled, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } + + public function testSelectLastRepo() + { + $this->markTestIncomplete(); + + $this->repoImportant = new ArrayRepository; + + $this->repo->addPackage($packageA = new MemoryPackage('A', '1.0')); + $this->repoImportant->addPackage($packageAImportant = new MemoryPackage('A', '1.0')); + + $this->pool->addRepository($this->repo); + $this->pool->addRepository($this->repoImportant); + + $literals = array(new Literal($packageA, true), new Literal($packageAImportant, true)); + $expected = array(new Literal($packageAImportant, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } +} From 0c30610fdc7642bd607752730721109b4af7aa80 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 21 Oct 2011 14:58:31 +0200 Subject: [PATCH 2/5] Complete the policy tests with provider and replacement tests --- .../DependencyResolver/DefaultPolicyTest.php | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php index 1558f14e4..b987bc238 100644 --- a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php +++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php @@ -98,4 +98,43 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $selected); } + + public function testSelectAllProviders() + { + $this->markTestIncomplete(); + + $this->repo->addPackage($packageA = new MemoryPackage('A', '1.0')); + $this->repo->addPackage($packageB = new MemoryPackage('B', '2.0')); + + $packageA->setProvides(array(new Link('A', 'X', new VersionConstraint('==', '1.0'), 'provides'))); + $packageB->setProvides(array(new Link('B', 'X', new VersionConstraint('==', '1.0'), 'provides'))); + + $this->pool->addRepository($this->repo); + + $literals = array(new Literal($packageA, true), new Literal($packageB, true)); + $expected = $literals; + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } + + public function testSelectNonReplacingFromSameRepo() + { + $this->markTestIncomplete(); + + $this->repo->addPackage($packageA = new MemoryPackage('A', '1.0')); + $this->repo->addPackage($packageB = new MemoryPackage('B', '2.0')); + + $packageB->setReplaces(array(new Link('B', 'A', new VersionConstraint('==', '1.0'), 'replaces'))); + + $this->pool->addRepository($this->repo); + + $literals = array(new Literal($packageA, true), new Literal($packageB, true)); + $expected = array(new Literal($packageA, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } } From 55d5e55195098d1a63207d789aa6e844518162b5 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 21 Oct 2011 15:22:47 +0200 Subject: [PATCH 3/5] DefaultPolicy test: pick package providing newest virtual package version --- .../DependencyResolver/DefaultPolicyTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php index b987bc238..be96e315d 100644 --- a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php +++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php @@ -119,6 +119,26 @@ class DefaultPolicyTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $selected); } + public function testSelectNewestProvider() + { + $this->markTestIncomplete(); + + $this->repo->addPackage($packageA = new MemoryPackage('A', '1.0')); + $this->repo->addPackage($packageB = new MemoryPackage('B', '2.0')); + + $packageA->setProvides(array(new Link('A', 'X', new VersionConstraint('==', '2.0'), 'provides'))); + $packageB->setProvides(array(new Link('B', 'X', new VersionConstraint('==', '1.0'), 'provides'))); + + $this->pool->addRepository($this->repo); + + $literals = array(new Literal($packageA, true), new Literal($packageB, true)); + $expected = array(new Literal($packageA, true)); + + $selected = $this->policy->selectPreferedPackages($this->pool, $this->repoInstalled, $literals); + + $this->assertEquals($expected, $selected); + } + public function testSelectNonReplacingFromSameRepo() { $this->markTestIncomplete(); From 4d5655a604b82cb71ae510912968cbe009ae6bf6 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sat, 22 Oct 2011 12:48:53 +0200 Subject: [PATCH 4/5] Add basic specification of the default solver policy behaviour --- doc/DefaultPolicy.md | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 doc/DefaultPolicy.md diff --git a/doc/DefaultPolicy.md b/doc/DefaultPolicy.md new file mode 100644 index 000000000..635065b60 --- /dev/null +++ b/doc/DefaultPolicy.md @@ -0,0 +1,53 @@ +# Default Solver Policy + +A solver policy defines behaviour variables of the dependency solver. It decides +which versions are considered newer than others, which packages should be +prefered over others and whether operations like downgrades or uninstall are +allowed. + +## Selection of prefered Packages + +The following describe package pool situations with user requests and the +resulting order in which the solver will try to install them. + +The rules are to be applied in the order of these descriptions. + +### Package versions + +Packages: Av1, Av2, Av3 +Installed: Av2 + +Request: install A + +(Av3) + +### Repository priorities + +Packages Repo1.Av1, Repo2.Av1 + +priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1) +priority(Repo2) < priority(Repo2) => (Repo2.Av1, Repo1.Av1) + +### Virtual Packages (provides) + +Packages Av1, Bv1 +Av1 provides Xv1 +Bv1 provides Xv1 + +Request: install X + +priority(Av1.repo) >= priority(Bv1.repo) => (Av1, Bv1) +priority(Av1.repo) < priority(Bv1.repo) => (Bv1, Av1) + +### Package replacements + +Packages: Av1, Bv2 +Bv2 replaces Av1 + +Request: install A + +priority(Av1.repo) > priority(Bv2.repo) => (Av1, Bv2) +priority(Av1.repo) = priority(Bv2.repo) => (Av1, Bv2) +priority(Av1.repo) < priority(Bv2.repo) => (Bv2, Av1) + +Bv2.version is ignored, only the replacement version for A matters. From 755873183048e350d41fe910b7baf0a73636fc32 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sat, 22 Oct 2011 13:02:12 +0200 Subject: [PATCH 5/5] Fix documentation layout --- doc/DefaultPolicy.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/doc/DefaultPolicy.md b/doc/DefaultPolicy.md index 635065b60..4254e20bf 100644 --- a/doc/DefaultPolicy.md +++ b/doc/DefaultPolicy.md @@ -15,39 +15,42 @@ The rules are to be applied in the order of these descriptions. ### Package versions Packages: Av1, Av2, Av3 -Installed: Av2 + +* Installed: Av2 Request: install A -(Av3) +* (Av3) ### Repository priorities Packages Repo1.Av1, Repo2.Av1 -priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1) -priority(Repo2) < priority(Repo2) => (Repo2.Av1, Repo1.Av1) +* priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1) +* priority(Repo2) < priority(Repo2) => (Repo2.Av1, Repo1.Av1) ### Virtual Packages (provides) Packages Av1, Bv1 -Av1 provides Xv1 -Bv1 provides Xv1 + +* Av1 provides Xv1 +* Bv1 provides Xv1 Request: install X -priority(Av1.repo) >= priority(Bv1.repo) => (Av1, Bv1) -priority(Av1.repo) < priority(Bv1.repo) => (Bv1, Av1) +* priority(Av1.repo) >= priority(Bv1.repo) => (Av1, Bv1) +* priority(Av1.repo) < priority(Bv1.repo) => (Bv1, Av1) ### Package replacements Packages: Av1, Bv2 -Bv2 replaces Av1 + +* Bv2 replaces Av1 Request: install A -priority(Av1.repo) > priority(Bv2.repo) => (Av1, Bv2) -priority(Av1.repo) = priority(Bv2.repo) => (Av1, Bv2) -priority(Av1.repo) < priority(Bv2.repo) => (Bv2, Av1) +* priority(Av1.repo) > priority(Bv2.repo) => (Av1, Bv2) +* priority(Av1.repo) = priority(Bv2.repo) => (Av1, Bv2) +* priority(Av1.repo) < priority(Bv2.repo) => (Bv2, Av1) Bv2.version is ignored, only the replacement version for A matters.