Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GreaterThanOrEqualToSemver Matcher implementation #231

Merged
merged 9 commits into from
May 3, 2024
28 changes: 28 additions & 0 deletions src/SplitIO/Grammar/Condition/Matcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
use SplitIO\Exception\UnsupportedMatcherException;
use SplitIO\Grammar\Condition\Matcher\All;
use SplitIO\Grammar\Condition\Matcher\Between;
use SplitIO\Grammar\Condition\Matcher\BetweenSemver;
use SplitIO\Grammar\Condition\Matcher\EqualTo;
use SplitIO\Grammar\Condition\Matcher\EqualToSemver;
use SplitIO\Grammar\Condition\Matcher\GreaterThanOrEqualTo;
use SplitIO\Grammar\Condition\Matcher\GreaterThanOrEqualToSemver;
use SplitIO\Grammar\Condition\Matcher\InListSemver;
use SplitIO\Grammar\Condition\Matcher\LessThanOrEqualTo;
use SplitIO\Grammar\Condition\Matcher\LessThanOrEqualToSemver;
use SplitIO\Grammar\Condition\Matcher\Segment;
use SplitIO\Grammar\Condition\Matcher\Whitelist;
use SplitIO\Grammar\Condition\Matcher\StartsWith;
Expand Down Expand Up @@ -42,6 +46,10 @@ class Matcher
const EQUAL_TO_BOOLEAN = 'EQUAL_TO_BOOLEAN';
const MATCHES_STRING = 'MATCHES_STRING';
const EQUAL_TO_SEMVER = 'EQUAL_TO_SEMVER';
const GREATER_THAN_OR_EQUAL_TO_SEMVER = 'GREATER_THAN_OR_EQUAL_TO_SEMVER';
const LESS_THAN_OR_EQUAL_TO_SEMVER = 'LESS_THAN_OR_EQUAL_TO_SEMVER';
const BETWEEN_SEMVER = 'BETWEEN_SEMVER';
const IN_LIST_SEMVER = 'IN_LIST_SEMVER';

public static function factory($matcher)
{
Expand Down Expand Up @@ -137,6 +145,26 @@ public static function factory($matcher)
is_string($matcher['stringMatcherData']) ?
$matcher['stringMatcherData'] : null;
return new EqualToSemver($data, $negate, $attribute);
case self::GREATER_THAN_OR_EQUAL_TO_SEMVER:
$data = isset($matcher['stringMatcherData']) &&
is_string($matcher['stringMatcherData']) ?
$matcher['stringMatcherData'] : null;
return new GreaterThanOrEqualToSemver($data, $negate, $attribute);
case self::LESS_THAN_OR_EQUAL_TO_SEMVER:
$data = isset($matcher['stringMatcherData']) &&
is_string($matcher['stringMatcherData']) ?
$matcher['stringMatcherData'] : null;
return new LessThanOrEqualToSemver($data, $negate, $attribute);
case self::BETWEEN_SEMVER:
$data = (isset($matcher['betweenStringMatcherData']) &&
is_array($matcher['betweenStringMatcherData']))
? $matcher['betweenStringMatcherData'] : null;
return new BetweenSemver($data, $negate, $attribute);
case self::IN_LIST_SEMVER:
$data = (isset($matcher['whitelistMatcherData']['whitelist']) &&
is_array($matcher['whitelistMatcherData']['whitelist']))
? $matcher['whitelistMatcherData']['whitelist'] : null;
return new InListSemver($data, $negate, $attribute);
// @codeCoverageIgnoreStart
default:
throw new UnsupportedMatcherException("Unable to create matcher for matcher type: " . $matcherType);
Expand Down
46 changes: 46 additions & 0 deletions src/SplitIO/Grammar/Condition/Matcher/BetweenSemver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
namespace SplitIO\Grammar\Condition\Matcher;

use SplitIO\Grammar\Condition\Matcher;
use SplitIO\Grammar\Semver\Semver;
use SplitIO\Grammar\Semver\SemverComparer;
use SplitIO\Split as SplitApp;

class BetweenSemver extends AbstractMatcher
{
protected $startTarget = null;
protected $endTarget = null;

public function __construct($data, $negate = false, $attribute = null)
{
parent::__construct(Matcher::BETWEEN_SEMVER, $negate, $attribute);

$this->startTarget = Semver::build($data['start']);
$this->endTarget = Semver::build($data['end']);
}

/**
*
* @param mixed $key
*/
protected function evalKey($key)
{
if ($key == null || !is_string($key) || $this->startTarget == null || $this->endTarget == null) {
return false;
}

$keySemver = Semver::build($key);
if ($keySemver == null) {
return false;
}

$result = SemverComparer::do($keySemver, $this->startTarget) >= 0
&& SemverComparer::do($keySemver, $this->endTarget) <= 0;

SplitApp::logger()->debug($this->startTarget->getVersion() . " <= "
. $keySemver->getVersion() . " <= " . $this->endTarget->getVersion()
. " | Result: " . $result);

return $result;
}
}
2 changes: 1 addition & 1 deletion src/SplitIO/Grammar/Condition/Matcher/EqualToSemver.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function evalKey($key)
return false;
}

$result = SemverComparer::Equals($this->toCompare, $keySemver);
$result = SemverComparer::equals($this->toCompare, $keySemver);

SplitApp::logger()->debug($this->toCompare->getVersion() . " == "
. $keySemver->getVersion() . " | Result: " . $result);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
namespace SplitIO\Grammar\Condition\Matcher;

use SplitIO\Grammar\Condition\Matcher;
use SplitIO\Grammar\Semver\Semver;
use SplitIO\Grammar\Semver\SemverComparer;
use SplitIO\Split as SplitApp;

class GreaterThanOrEqualToSemver extends AbstractMatcher
{
private $target;

public function __construct($toCompare, $negate = false, $attribute = null)
{
parent::__construct(Matcher::GREATER_THAN_OR_EQUAL_TO_SEMVER, $negate, $attribute);

$this->target = Semver::build($toCompare);
}

/**
*
* @param mixed $key
*/
protected function evalKey($key)
{
if ($key == null || $this->target == null || !is_string($key)) {
return false;
}

$keySemver = Semver::build($key);
if ($keySemver == null) {
return false;
}

$result = SemverComparer::do($keySemver, $this->target) >= 0;

SplitApp::logger()->debug($this->target->getVersion() . " >= "
. $keySemver->getVersion() . " | Result: " . $result);

return $result;
}
}
51 changes: 51 additions & 0 deletions src/SplitIO/Grammar/Condition/Matcher/InListSemver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
namespace SplitIO\Grammar\Condition\Matcher;

use SplitIO\Grammar\Condition\Matcher;
use SplitIO\Grammar\Semver\Semver;
use SplitIO\Grammar\Semver\SemverComparer;

class InListSemver extends AbstractMatcher
{
private $targetList;

public function __construct($targetList, $negate = false, $attribute = null)
{
$this->targetList = array();
parent::__construct(Matcher::IN_LIST_SEMVER, $negate, $attribute);

if (is_array($targetList)) {
foreach ($targetList as $item) {
$toAdd = Semver::build($item);

if ($toAdd != null) {
array_push($this->targetList, $toAdd);
}
}
}
}

/**
*
* @param mixed $key
*/
protected function evalKey($key)
{
if ($key == null || !is_string($key) || count($this->targetList) == 0) {
return false;
}

$keySemver = Semver::build($key);
if ($keySemver == null) {
return false;
}

foreach ($this->targetList as $item) {
if (SemverComparer::equals($keySemver, $item)) {
return true;
}
}

return false;
}
}
42 changes: 42 additions & 0 deletions src/SplitIO/Grammar/Condition/Matcher/LessThanOrEqualToSemver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
namespace SplitIO\Grammar\Condition\Matcher;

use SplitIO\Grammar\Condition\Matcher;
use SplitIO\Grammar\Semver\Semver;
use SplitIO\Grammar\Semver\SemverComparer;
use SplitIO\Split as SplitApp;

class LessThanOrEqualToSemver extends AbstractMatcher
{
private $target;

public function __construct($toCompare, $negate = false, $attribute = null)
{
parent::__construct(Matcher::LESS_THAN_OR_EQUAL_TO_SEMVER, $negate, $attribute);

$this->target = Semver::build($toCompare);
}

/**
*
* @param mixed $key
*/
protected function evalKey($key)
{
if ($key == null || $this->target == null || !is_string($key)) {
return false;
}

$keySemver = Semver::build($key);
if ($keySemver == null) {
return false;
}

$result = SemverComparer::do($keySemver, $this->target) <= 0;

SplitApp::logger()->debug($this->target->getVersion() . " <= "
. $keySemver->getVersion() . " | Result: " . $result);

return $result;
}
}
123 changes: 123 additions & 0 deletions tests/Suite/Matchers/MatchersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,129 @@ public function testEqualToSemverMatcher()
$this->assertFalse($matcher->evaluate('2.2.2'));
}

public function testGreaterThanOrEqualToSemverMatcher()
{
$this->setupSplitApp();

$condition = array(
'matcherType' => 'GREATER_THAN_OR_EQUAL_TO_SEMVER',
'stringMatcherData' => '2.2.2'
);

$matcher = Matcher::factory($condition);
$this->assertTrue($matcher->evaluate('2.2.2'));
$this->assertTrue($matcher->evaluate('2.2.3'));
$this->assertTrue($matcher->evaluate('2.3.2'));
$this->assertTrue($matcher->evaluate('3.2.2'));
$this->assertFalse($matcher->evaluate('1.2.2'));
$this->assertFalse($matcher->evaluate('2.1.2'));
$this->assertFalse($matcher->evaluate('2.2.2-rc.1'));
$this->assertFalse($matcher->evaluate(null));
$this->assertFalse($matcher->evaluate(''));

$condition = array(
'matcherType' => 'GREATER_THAN_OR_EQUAL_TO_SEMVER',
'stringMatcherData' => null
);

$matcher = Matcher::factory($condition);
$this->assertFalse($matcher->evaluate('2.2.2'));
}

public function testLessThanOrEqualToSemverMatcher()
{
$this->setupSplitApp();

$condition = array(
'matcherType' => 'LESS_THAN_OR_EQUAL_TO_SEMVER',
'stringMatcherData' => '2.2.2'
);

$matcher = Matcher::factory($condition);
$this->assertTrue($matcher->evaluate('1.2.2'));
$this->assertTrue($matcher->evaluate('2.1.2'));
$this->assertTrue($matcher->evaluate('2.2.2-rc.1'));
$this->assertTrue($matcher->evaluate('0.2.2'));
$this->assertTrue($matcher->evaluate('2.2.1'));
$this->assertTrue($matcher->evaluate('2.2.2'));
$this->assertFalse($matcher->evaluate('2.2.3'));
$this->assertFalse($matcher->evaluate('2.3.2'));
$this->assertFalse($matcher->evaluate('3.2.2'));
$this->assertFalse($matcher->evaluate(null));
$this->assertFalse($matcher->evaluate(''));

$condition = array(
'matcherType' => 'GREATER_THAN_OR_EQUAL_TO_SEMVER',
'stringMatcherData' => null
);

$matcher = Matcher::factory($condition);
$this->assertFalse($matcher->evaluate('2.2.2'));
}

public function testBetweenSemverMatcher()
{
$this->setupSplitApp();

$condition = array(
'matcherType' => 'BETWEEN_SEMVER',
'betweenStringMatcherData' => array(
'start' => '11.11.11',
'end' => '22.22.22',
)
);

$matcher = Matcher::factory($condition);
$this->assertTrue($matcher->evaluate('20.2.2'));
$this->assertTrue($matcher->evaluate('16.5.6'));
$this->assertTrue($matcher->evaluate('19.0.1'));
$this->assertFalse($matcher->evaluate(null));
$this->assertFalse($matcher->evaluate(''));
$this->assertFalse($matcher->evaluate('22.22.25'));
$this->assertFalse($matcher->evaluate('10.0.0'));

$condition = array(
'matcherType' => 'BETWEEN_SEMVER',
'betweenStringMatcherData' => null
);

$matcher = Matcher::factory($condition);
$this->assertFalse($matcher->evaluate('2.2.2'));
}

public function testInListSemverMatcher()
{
$this->setupSplitApp();

$condition = array(
'matcherType' => 'IN_LIST_SEMVER',
'whitelistMatcherData' => array(
'whitelist' => array(
'1.1.1',
'2.2.2',
'3.3.3',
)
)
);

$matcher = Matcher::factory($condition);
$this->assertTrue($matcher->evaluate('1.1.1'));
$this->assertTrue($matcher->evaluate('2.2.2'));
$this->assertTrue($matcher->evaluate('3.3.3'));
$this->assertFalse($matcher->evaluate(null));
$this->assertFalse($matcher->evaluate(''));
$this->assertFalse($matcher->evaluate('4.22.25'));
$this->assertFalse($matcher->evaluate('10.0.0'));

$condition = array(
'matcherType' => 'IN_LIST_SEMVER',
'whitelistMatcherData' => null
);

$matcher = Matcher::factory($condition);
$this->assertFalse($matcher->evaluate('2.2.2'));
}

public static function tearDownAfterClass(): void
{
Utils\Utils::cleanCache();
Expand Down
Loading