Skip to content

Commit

Permalink
Add Intervals::isIntersectionOf and ensure it is acting the same as -…
Browse files Browse the repository at this point in the history
…>matches() on constraints
  • Loading branch information
Seldaek committed May 8, 2020
1 parent 0b0edb3 commit 5aef5c2
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 2 deletions.
17 changes: 16 additions & 1 deletion src/Intervals.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInte
return true;
}

public static function isIntersectionOf(ConstraintInterface $a, ConstraintInterface $b)
{
if ($a instanceof EmptyConstraint || $b instanceof EmptyConstraint) {
return true;
}

$intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), true), true);

return \count($intersectionIntervals['intervals']) > 0 || \count($intersectionIntervals['devConstraints']) > 0;
}

/**
* @return array
*/
Expand All @@ -92,7 +103,7 @@ public static function get(ConstraintInterface $constraint)
return self::$intervalsCache[$key];
}

private static function generateIntervals(ConstraintInterface $constraint)
private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false)
{
if ($constraint instanceof EmptyConstraint) {
return array('intervals' => array(array('start' => self::zero(), 'end' => self::positiveInfinity())), 'devConstraints' => array(self::anyDev()));
Expand Down Expand Up @@ -280,6 +291,10 @@ private static function generateIntervals(ConstraintInterface $constraint)
} else {
$intervals[$index]['end'] = new Constraint($border['operator'], $border['version']);
$index++;

if ($stopOnFirstValidInterval) {
break;
}
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion tests/Constraint/ConstraintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Composer\Semver\Constraint;

use PHPUnit\Framework\TestCase;
use Composer\Semver\Intervals;

class ConstraintTest extends TestCase
{
Expand Down Expand Up @@ -169,9 +170,11 @@ public function testVersionMatchSucceeds($requireOperator, $requireVersion, $pro

$this->assertTrue($versionRequire->matches($versionProvide));
$this->assertTrue($this->matchCompiled($versionRequire, $provideOperator, $provideVersion));
$this->assertTrue(Intervals::isIntersectionOf($versionRequire, $versionProvide));
// the operation should be commutative
$this->assertTrue($versionProvide->matches($versionRequire));
$this->assertTrue($this->matchCompiled($versionProvide, $requireOperator, $requireVersion));
$this->assertTrue(Intervals::isIntersectionOf($versionProvide, $versionRequire));
}

public static function failingVersionMatches()
Expand Down Expand Up @@ -338,6 +341,16 @@ public function testVersionMatchFails($requireOperator, $requireVersion, $provid
// the operation should be commutative
$this->assertFalse($versionProvide->matches($versionRequire));
$this->assertFalse($this->matchCompiled($versionProvide, $requireOperator, $requireVersion));

// do not test >/</>=/<= for dev versions as these are not supported
if (substr($requireVersion, 0, 4) === 'dev-' && $requireOperator !== '==' && $requireOperator !== '!=') {
return;
}
if (substr($provideVersion, 0, 4) === 'dev-' && $provideOperator !== '==' && $provideOperator !== '!=') {
return;
}
$this->assertFalse(Intervals::isIntersectionOf($versionRequire, $versionProvide));
$this->assertFalse(Intervals::isIntersectionOf($versionProvide, $versionRequire));
}

public function testInverseMatchingOtherConstraints()
Expand Down Expand Up @@ -378,12 +391,14 @@ public function testComparableBranches()

$this->assertFalse($versionRequire->matches($this->versionProvide));
$this->assertFalse($this->matchCompiled($versionRequire, '==', 'dev-foo'));
$this->assertFalse(Intervals::isIntersectionOf($versionRequire, $this->versionProvide));
$this->assertFalse($versionRequire->matchSpecific($this->versionProvide, true));

$versionRequire = new Constraint('<', '0.12');

$this->assertFalse($versionRequire->matches($this->versionProvide));
$this->assertFalse($this->matchCompiled($versionRequire, '==', 'dev-foo'));
$this->assertFalse(Intervals::isIntersectionOf($versionRequire, $this->versionProvide));
$this->assertTrue($versionRequire->matchSpecific($this->versionProvide, true));
}

Expand Down Expand Up @@ -486,7 +501,16 @@ public function testCompile($requireOperator, $requireVersion, $provideOperator,
$provide = new Constraint($provideOperator, $provideVersion);

// Asserts Compiled version returns the same result than standard
$this->assertSame($require->matches($provide), $this->matchCompiled($require, $provideOperator, $provideVersion));
$this->assertSame($m = $require->matches($provide), $this->matchCompiled($require, $provideOperator, $provideVersion));

// do not test >/</>=/<= for dev versions as these are not supported
if (substr($requireVersion, 0, 4) === 'dev-' && $requireOperator !== '==' && $requireOperator !== '!=') {
return;
}
if (substr($provideVersion, 0, 4) === 'dev-' && $provideOperator !== '==' && $provideOperator !== '!=') {
return;
}
$this->assertSame($m, Intervals::isIntersectionOf($require, $provide));
}

public function matrix()
Expand Down
5 changes: 5 additions & 0 deletions tests/Constraint/MultiConstraintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Composer\Semver\VersionParser;
use PHPUnit\Framework\TestCase;
use Composer\Semver\Intervals;

class MultiConstraintTest extends TestCase
{
Expand Down Expand Up @@ -54,6 +55,7 @@ public function testMultiVersionMatchSucceeds()
$this->assertTrue($multiRequire->matches($versionProvide));
$this->assertTrue($versionProvide->matches($multiRequire));
$this->assertTrue($this->matchCompiled($multiRequire, '==', 1.1));
$this->assertTrue(Intervals::isIntersectionOf($multiRequire, $versionProvide));
}

public function testMultiVersionProvidedMatchSucceeds()
Expand Down Expand Up @@ -89,6 +91,7 @@ public function testMultiVersionMatchFails()
$this->assertFalse($multiRequire->matches($versionProvide));
$this->assertFalse($versionProvide->matches($multiRequire));
$this->assertFalse($this->matchCompiled($multiRequire, '==', 1.2));
$this->assertFalse(Intervals::isIntersectionOf($multiRequire, $versionProvide));
}

public function testGetPrettyString()
Expand Down Expand Up @@ -406,6 +409,7 @@ public function testMultiConstraintNotconjunctiveFillWithFalse()
$this->assertFalse($multiRequire->matches($versionProvide));
$this->assertFalse($versionProvide->matches($multiRequire));
$this->assertFalse($this->matchCompiled($multiRequire, '==', 1.1));
$this->assertFalse(Intervals::isIntersectionOf($multiRequire, $versionProvide));
}

public function testMultiConstraintConjunctiveFillWithTrue()
Expand All @@ -419,6 +423,7 @@ public function testMultiConstraintConjunctiveFillWithTrue()
$this->assertTrue($multiRequire->matches($versionProvide));
$this->assertTrue($versionProvide->matches($multiRequire));
$this->assertTrue($this->matchCompiled($multiRequire, '!=', 1.1));
$this->assertTrue(Intervals::isIntersectionOf($multiRequire, $versionProvide));
}

private function matchCompiled(CompilableConstraintInterface $constraint, $operator, $version)
Expand Down

0 comments on commit 5aef5c2

Please sign in to comment.