add tests for remaining Criteria classes

This commit is contained in:
Younes ENNAJI
2026-02-25 20:01:29 +00:00
parent 08c242b45a
commit 18c2233baa
6 changed files with 1315 additions and 0 deletions
@@ -0,0 +1,251 @@
<?php
declare(strict_types=1);
namespace Flasher\Tests\Prime\Storage\Filter\Criteria;
use Flasher\Prime\Notification\Envelope;
use Flasher\Prime\Notification\Notification;
use Flasher\Prime\Stamp\DelayStamp;
use Flasher\Prime\Storage\Filter\Criteria\DelayCriteria;
use PHPUnit\Framework\TestCase;
final class DelayCriteriaTest extends TestCase
{
public function testConstructorWithInteger(): void
{
$criteria = new DelayCriteria(5);
$this->assertInstanceOf(DelayCriteria::class, $criteria);
}
public function testConstructorWithArray(): void
{
$criteria = new DelayCriteria(['min' => 1, 'max' => 10]);
$this->assertInstanceOf(DelayCriteria::class, $criteria);
}
public function testConstructorWithInvalidTypeThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "delay"');
new DelayCriteria('invalid');
}
public function testConstructorWithNullThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "delay"');
new DelayCriteria(null);
}
public function testConstructorWithInvalidMinThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "delay"');
new DelayCriteria(['min' => 'invalid', 'max' => 10]);
}
public function testConstructorWithInvalidMaxThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "max" in criteria "delay"');
new DelayCriteria(['min' => 1, 'max' => 'invalid']);
}
public function testApplyWithMinimumDelay(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(3)]),
new Envelope(new Notification(), [new DelayStamp(7)]),
new Envelope(new Notification(), [new DelayStamp(10)]),
];
$criteria = new DelayCriteria(['min' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithMaximumDelay(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(3)]),
new Envelope(new Notification(), [new DelayStamp(7)]),
new Envelope(new Notification(), [new DelayStamp(10)]),
];
$criteria = new DelayCriteria(['min' => 0, 'max' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithRange(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(3)]),
new Envelope(new Notification(), [new DelayStamp(5)]),
new Envelope(new Notification(), [new DelayStamp(7)]),
new Envelope(new Notification(), [new DelayStamp(10)]),
];
$criteria = new DelayCriteria(['min' => 4, 'max' => 8]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithSingleValueAsMinimum(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(3)]),
new Envelope(new Notification(), [new DelayStamp(5)]),
new Envelope(new Notification(), [new DelayStamp(10)]),
];
$criteria = new DelayCriteria(5);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyFiltersEnvelopesWithoutDelayStamp(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(5)]),
new Envelope(new Notification()),
new Envelope(new Notification(), [new DelayStamp(10)]),
];
$criteria = new DelayCriteria(['min' => 1]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testMatchReturnsTrueForMatchingDelay(): void
{
$envelope = new Envelope(new Notification(), [new DelayStamp(5)]);
$criteria = new DelayCriteria(['min' => 3, 'max' => 7]);
$this->assertTrue($criteria->match($envelope));
}
public function testMatchReturnsFalseForNonMatchingDelay(): void
{
$envelope = new Envelope(new Notification(), [new DelayStamp(10)]);
$criteria = new DelayCriteria(['min' => 3, 'max' => 7]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchReturnsFalseForEnvelopeWithoutDelayStamp(): void
{
$envelope = new Envelope(new Notification());
$criteria = new DelayCriteria(['min' => 1]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithOnlyMinimum(): void
{
$envelope = new Envelope(new Notification(), [new DelayStamp(10)]);
$criteria = new DelayCriteria(['min' => 5]);
$this->assertTrue($criteria->match($envelope));
}
public function testMatchWithDelayBelowMinimum(): void
{
$envelope = new Envelope(new Notification(), [new DelayStamp(3)]);
$criteria = new DelayCriteria(['min' => 5]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithDelayAboveMaximum(): void
{
$envelope = new Envelope(new Notification(), [new DelayStamp(15)]);
$criteria = new DelayCriteria(['min' => 1, 'max' => 10]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithExactBoundary(): void
{
$envelope = new Envelope(new Notification(), [new DelayStamp(5)]);
$criteria = new DelayCriteria(['min' => 5, 'max' => 5]);
$this->assertTrue($criteria->match($envelope));
}
public function testApplyWithEmptyArray(): void
{
$criteria = new DelayCriteria(['min' => 1]);
$result = $criteria->apply([]);
$this->assertSame([], $result);
}
public function testApplyWithOnlyMinInArray(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(3)]),
new Envelope(new Notification(), [new DelayStamp(7)]),
];
$criteria = new DelayCriteria(['min' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithOnlyMaxInArray(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(3)]),
new Envelope(new Notification(), [new DelayStamp(7)]),
];
$criteria = new DelayCriteria(['max' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithZeroMinAndNullMax(): void
{
$envelopes = [
new Envelope(new Notification(), [new DelayStamp(0)]),
new Envelope(new Notification(), [new DelayStamp(5)]),
new Envelope(new Notification(), [new DelayStamp(10)]),
];
$criteria = new DelayCriteria(['min' => 0, 'max' => null]);
$result = $criteria->apply($envelopes);
$this->assertCount(3, $result);
}
}
@@ -0,0 +1,169 @@
<?php
declare(strict_types=1);
namespace Flasher\Tests\Prime\Storage\Filter\Criteria;
use Flasher\Prime\Notification\Envelope;
use Flasher\Prime\Notification\Notification;
use Flasher\Prime\Storage\Filter\Criteria\FilterCriteria;
use PHPUnit\Framework\TestCase;
final class FilterCriteriaTest extends TestCase
{
public function testConstructorWithClosure(): void
{
$criteria = new FilterCriteria(fn ($envelopes) => $envelopes);
$this->assertInstanceOf(FilterCriteria::class, $criteria);
}
public function testConstructorWithArrayOfClosures(): void
{
$criteria = new FilterCriteria([
fn ($envelopes) => $envelopes,
fn ($envelopes) => array_filter($envelopes),
]);
$this->assertInstanceOf(FilterCriteria::class, $criteria);
}
public function testConstructorWithInvalidTypeThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "filter"');
new FilterCriteria('not a closure');
}
public function testConstructorWithNullThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "filter"');
new FilterCriteria(null);
}
public function testConstructorWithArrayContainingNonClosureThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Each element must be a closure');
new FilterCriteria([fn ($e) => $e, 'not a closure']);
}
public function testApplyWithSingleClosure(): void
{
$envelopes = [
new Envelope(new Notification()),
new Envelope(new Notification()),
new Envelope(new Notification()),
];
$criteria = new FilterCriteria(fn ($e) => array_slice($e, 0, 2));
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithMultipleClosures(): void
{
$notification1 = new Notification();
$notification1->setType('success');
$notification2 = new Notification();
$notification2->setType('error');
$notification3 = new Notification();
$notification3->setType('success');
$envelopes = [
new Envelope($notification1),
new Envelope($notification2),
new Envelope($notification3),
];
$criteria = new FilterCriteria([
fn ($e) => array_filter($e, fn (Envelope $envelope) => 'success' === $envelope->getType()),
fn ($e) => array_slice($e, 0, 1),
]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
$this->assertSame('success', $result[0]->getType());
}
public function testApplyWithEmptyArray(): void
{
$criteria = new FilterCriteria(fn ($e) => $e);
$result = $criteria->apply([]);
$this->assertSame([], $result);
}
public function testApplyThatReturnsModifiedEnvelopes(): void
{
$envelopes = [
new Envelope(new Notification()),
new Envelope(new Notification()),
];
$criteria = new FilterCriteria(fn ($e) => []);
$result = $criteria->apply($envelopes);
$this->assertSame([], $result);
}
public function testClosureReceivesCorrectArguments(): void
{
$received = null;
$envelopes = [new Envelope(new Notification())];
$criteria = new FilterCriteria(function ($e) use (&$received) {
$received = $e;
return $e;
});
$criteria->apply($envelopes);
$this->assertSame($envelopes, $received);
}
public function testChainedFiltersAreAppliedInOrder(): void
{
$notification1 = new Notification();
$notification1->setMessage('first');
$notification2 = new Notification();
$notification2->setMessage('second');
$notification3 = new Notification();
$notification3->setMessage('third');
$envelopes = [
new Envelope($notification1),
new Envelope($notification2),
new Envelope($notification3),
];
$order = [];
$criteria = new FilterCriteria([
function ($e) use (&$order) {
$order[] = 'first';
return $e;
},
function ($e) use (&$order) {
$order[] = 'second';
return array_slice($e, 0, 2);
},
]);
$result = $criteria->apply($envelopes);
$this->assertSame(['first', 'second'], $order);
$this->assertCount(2, $result);
}
}
@@ -0,0 +1,232 @@
<?php
declare(strict_types=1);
namespace Flasher\Tests\Prime\Storage\Filter\Criteria;
use Flasher\Prime\Notification\Envelope;
use Flasher\Prime\Notification\Notification;
use Flasher\Prime\Stamp\HopsStamp;
use Flasher\Prime\Storage\Filter\Criteria\HopsCriteria;
use PHPUnit\Framework\TestCase;
final class HopsCriteriaTest extends TestCase
{
public function testConstructorWithInteger(): void
{
$criteria = new HopsCriteria(2);
$this->assertInstanceOf(HopsCriteria::class, $criteria);
}
public function testConstructorWithArray(): void
{
$criteria = new HopsCriteria(['min' => 1, 'max' => 3]);
$this->assertInstanceOf(HopsCriteria::class, $criteria);
}
public function testConstructorWithInvalidTypeThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "hops"');
new HopsCriteria('invalid');
}
public function testConstructorWithInvalidMinThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "hops"');
new HopsCriteria(['min' => 'invalid']);
}
public function testConstructorWithInvalidMaxThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "max" in criteria "hops"');
new HopsCriteria(['max' => 'invalid']);
}
public function testApplyWithMinimumHops(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification(), [new HopsStamp(2)]),
new Envelope(new Notification(), [new HopsStamp(3)]),
];
$criteria = new HopsCriteria(['min' => 2]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithMaximumHops(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification(), [new HopsStamp(2)]),
new Envelope(new Notification(), [new HopsStamp(5)]),
];
$criteria = new HopsCriteria(['min' => 0, 'max' => 3]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithRange(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification(), [new HopsStamp(2)]),
new Envelope(new Notification(), [new HopsStamp(3)]),
new Envelope(new Notification(), [new HopsStamp(5)]),
];
$criteria = new HopsCriteria(['min' => 2, 'max' => 3]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithSingleValueAsMinimum(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification(), [new HopsStamp(3)]),
];
$criteria = new HopsCriteria(2);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyFiltersEnvelopesWithoutHopsStamp(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification()),
new Envelope(new Notification(), [new HopsStamp(2)]),
];
$criteria = new HopsCriteria(['min' => 1]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testMatchReturnsTrueForMatchingHops(): void
{
$envelope = new Envelope(new Notification(), [new HopsStamp(2)]);
$criteria = new HopsCriteria(['min' => 1, 'max' => 3]);
$this->assertTrue($criteria->match($envelope));
}
public function testMatchReturnsFalseForNonMatchingHops(): void
{
$envelope = new Envelope(new Notification(), [new HopsStamp(10)]);
$criteria = new HopsCriteria(['min' => 1, 'max' => 3]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchReturnsFalseForEnvelopeWithoutHopsStamp(): void
{
$envelope = new Envelope(new Notification());
$criteria = new HopsCriteria(['min' => 1]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithHopsBelowMinimum(): void
{
$envelope = new Envelope(new Notification(), [new HopsStamp(1)]);
$criteria = new HopsCriteria(['min' => 3]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithHopsAboveMaximum(): void
{
$envelope = new Envelope(new Notification(), [new HopsStamp(10)]);
$criteria = new HopsCriteria(['min' => 1, 'max' => 5]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithExactBoundary(): void
{
$envelope = new Envelope(new Notification(), [new HopsStamp(5)]);
$criteria = new HopsCriteria(['min' => 5, 'max' => 5]);
$this->assertTrue($criteria->match($envelope));
}
public function testApplyWithEmptyArray(): void
{
$criteria = new HopsCriteria(['min' => 1]);
$result = $criteria->apply([]);
$this->assertSame([], $result);
}
public function testApplyWithOnlyMinInArray(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification(), [new HopsStamp(5)]),
];
$criteria = new HopsCriteria(['min' => 3]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithOnlyMaxInArray(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(1)]),
new Envelope(new Notification(), [new HopsStamp(5)]),
];
$criteria = new HopsCriteria(['max' => 3]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithZeroHops(): void
{
$envelopes = [
new Envelope(new Notification(), [new HopsStamp(0)]),
new Envelope(new Notification(), [new HopsStamp(1)]),
];
$criteria = new HopsCriteria(['min' => 0, 'max' => 0]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
}
@@ -0,0 +1,189 @@
<?php
declare(strict_types=1);
namespace Flasher\Tests\Prime\Storage\Filter\Criteria;
use Flasher\Prime\Notification\Envelope;
use Flasher\Prime\Notification\Notification;
use Flasher\Prime\Stamp\PresenterStamp;
use Flasher\Prime\Storage\Filter\Criteria\PresenterCriteria;
use PHPUnit\Framework\TestCase;
final class PresenterCriteriaTest extends TestCase
{
public function testConstructorWithString(): void
{
$criteria = new PresenterCriteria('html');
$this->assertInstanceOf(PresenterCriteria::class, $criteria);
}
public function testConstructorWithInvalidTypeThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("Invalid type for criteria 'presenter'");
new PresenterCriteria(123);
}
public function testConstructorWithNullThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("Invalid type for criteria 'presenter'");
new PresenterCriteria(null);
}
public function testConstructorWithArrayThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("Invalid type for criteria 'presenter'");
new PresenterCriteria(['html']);
}
public function testApplyFiltersByPresenterPattern(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
new Envelope(new Notification(), [new PresenterStamp('/json/')]),
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
];
$criteria = new PresenterCriteria('html');
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithExactMatch(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/^html$/')]),
new Envelope(new Notification(), [new PresenterStamp('/^json$/')]),
];
$criteria = new PresenterCriteria('html');
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithWildcardPattern(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/.*/')]),
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
];
$criteria = new PresenterCriteria('anything');
$result = $criteria->apply($envelopes);
// Only the first envelope matches because /.*/ matches anything
// The second requires 'html' in the presenter name
$this->assertCount(1, $result);
}
public function testApplyFiltersEnvelopesWithoutPresenterStamp(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
new Envelope(new Notification()),
new Envelope(new Notification(), [new PresenterStamp('/json/')]),
];
$criteria = new PresenterCriteria('html');
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithEmptyArray(): void
{
$criteria = new PresenterCriteria('html');
$result = $criteria->apply([]);
$this->assertSame([], $result);
}
public function testApplyWithCaseSensitivePattern(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/HTML/i')]),
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
];
$criteria = new PresenterCriteria('html');
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithComplexPattern(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/^(html|json)$/i')]),
new Envelope(new Notification(), [new PresenterStamp('/^html$/')]),
new Envelope(new Notification(), [new PresenterStamp('/^json$/')]),
];
$criteria = new PresenterCriteria('json');
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithNoMatch(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
new Envelope(new Notification(), [new PresenterStamp('/json/')]),
];
$criteria = new PresenterCriteria('html');
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
$stamp = $result[0]->get(PresenterStamp::class);
$this->assertSame('/html/', $stamp->getPattern());
}
public function testApplyWithInvalidPatternThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The provided regex pattern');
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/invalid[/')]),
];
$criteria = new PresenterCriteria('test');
$criteria->apply($envelopes);
}
public function testApplyWithEmptyPresenter(): void
{
$envelopes = [
new Envelope(new Notification(), [new PresenterStamp('/html/')]),
new Envelope(new Notification()),
];
$criteria = new PresenterCriteria('');
$result = $criteria->apply($envelopes);
// Envelope without stamp uses default pattern /.*/ which matches empty string
// Envelope with /html/ doesn't match empty string
$this->assertCount(1, $result);
}
}
@@ -0,0 +1,248 @@
<?php
declare(strict_types=1);
namespace Flasher\Tests\Prime\Storage\Filter\Criteria;
use Flasher\Prime\Notification\Envelope;
use Flasher\Prime\Notification\Notification;
use Flasher\Prime\Stamp\PriorityStamp;
use Flasher\Prime\Storage\Filter\Criteria\PriorityCriteria;
use PHPUnit\Framework\TestCase;
final class PriorityCriteriaTest extends TestCase
{
public function testConstructorWithInteger(): void
{
$criteria = new PriorityCriteria(5);
$this->assertInstanceOf(PriorityCriteria::class, $criteria);
}
public function testConstructorWithArray(): void
{
$criteria = new PriorityCriteria(['min' => 1, 'max' => 10]);
$this->assertInstanceOf(PriorityCriteria::class, $criteria);
}
public function testConstructorWithInvalidTypeThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "priority"');
new PriorityCriteria('invalid');
}
public function testConstructorWithInvalidMinThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "priority"');
new PriorityCriteria(['min' => 'invalid']);
}
public function testConstructorWithInvalidMaxThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "max" in criteria "priority"');
new PriorityCriteria(['max' => 'invalid']);
}
public function testApplyWithMinimumPriority(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(3)]),
new Envelope(new Notification(), [new PriorityStamp(7)]),
new Envelope(new Notification(), [new PriorityStamp(10)]),
];
$criteria = new PriorityCriteria(['min' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithMaximumPriority(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(3)]),
new Envelope(new Notification(), [new PriorityStamp(7)]),
new Envelope(new Notification(), [new PriorityStamp(10)]),
];
$criteria = new PriorityCriteria(['min' => 0, 'max' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithRange(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(1)]),
new Envelope(new Notification(), [new PriorityStamp(5)]),
new Envelope(new Notification(), [new PriorityStamp(7)]),
new Envelope(new Notification(), [new PriorityStamp(10)]),
];
$criteria = new PriorityCriteria(['min' => 3, 'max' => 8]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithSingleValueAsMinimum(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(3)]),
new Envelope(new Notification(), [new PriorityStamp(5)]),
new Envelope(new Notification(), [new PriorityStamp(10)]),
];
$criteria = new PriorityCriteria(5);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyFiltersEnvelopesWithoutPriorityStamp(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(5)]),
new Envelope(new Notification()),
new Envelope(new Notification(), [new PriorityStamp(10)]),
];
$criteria = new PriorityCriteria(['min' => 1]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testMatchReturnsTrueForMatchingPriority(): void
{
$envelope = new Envelope(new Notification(), [new PriorityStamp(5)]);
$criteria = new PriorityCriteria(['min' => 3, 'max' => 7]);
$this->assertTrue($criteria->match($envelope));
}
public function testMatchReturnsFalseForNonMatchingPriority(): void
{
$envelope = new Envelope(new Notification(), [new PriorityStamp(10)]);
$criteria = new PriorityCriteria(['min' => 3, 'max' => 7]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchReturnsFalseForEnvelopeWithoutPriorityStamp(): void
{
$envelope = new Envelope(new Notification());
$criteria = new PriorityCriteria(['min' => 1]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithPriorityBelowMinimum(): void
{
$envelope = new Envelope(new Notification(), [new PriorityStamp(3)]);
$criteria = new PriorityCriteria(['min' => 5]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithPriorityAboveMaximum(): void
{
$envelope = new Envelope(new Notification(), [new PriorityStamp(15)]);
$criteria = new PriorityCriteria(['min' => 1, 'max' => 10]);
$this->assertFalse($criteria->match($envelope));
}
public function testMatchWithExactBoundary(): void
{
$envelope = new Envelope(new Notification(), [new PriorityStamp(5)]);
$criteria = new PriorityCriteria(['min' => 5, 'max' => 5]);
$this->assertTrue($criteria->match($envelope));
}
public function testApplyWithEmptyArray(): void
{
$criteria = new PriorityCriteria(['min' => 1]);
$result = $criteria->apply([]);
$this->assertSame([], $result);
}
public function testApplyWithOnlyMinInArray(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(3)]),
new Envelope(new Notification(), [new PriorityStamp(7)]),
];
$criteria = new PriorityCriteria(['min' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithOnlyMaxInArray(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(3)]),
new Envelope(new Notification(), [new PriorityStamp(7)]),
];
$criteria = new PriorityCriteria(['max' => 5]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
public function testApplyWithNegativePriority(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(-5)]),
new Envelope(new Notification(), [new PriorityStamp(0)]),
new Envelope(new Notification(), [new PriorityStamp(5)]),
];
$criteria = new PriorityCriteria(['min' => -10, 'max' => 0]);
$result = $criteria->apply($envelopes);
$this->assertCount(2, $result);
}
public function testApplyWithZeroPriority(): void
{
$envelopes = [
new Envelope(new Notification(), [new PriorityStamp(0)]),
new Envelope(new Notification(), [new PriorityStamp(1)]),
];
$criteria = new PriorityCriteria(['min' => 0, 'max' => 0]);
$result = $criteria->apply($envelopes);
$this->assertCount(1, $result);
}
}
@@ -0,0 +1,226 @@
<?php
declare(strict_types=1);
namespace Flasher\Tests\Prime\Storage\Filter\Criteria;
use Flasher\Prime\Storage\Filter\Criteria\RangeExtractor;
use PHPUnit\Framework\TestCase;
final class RangeExtractorTest extends TestCase
{
private object $traitInstance;
protected function setUp(): void
{
parent::setUp();
$this->traitInstance = new class() {
use RangeExtractor;
public function testExtractRange(string $name, mixed $criteria): array
{
return $this->extractRange($name, $criteria);
}
};
}
public function testExtractRangeWithInteger(): void
{
$result = $this->traitInstance->testExtractRange('test', 5);
$this->assertSame(['min' => 5, 'max' => null], $result);
}
public function testExtractRangeWithZeroInteger(): void
{
$result = $this->traitInstance->testExtractRange('test', 0);
$this->assertSame(['min' => 0, 'max' => null], $result);
}
public function testExtractRangeWithNegativeInteger(): void
{
$result = $this->traitInstance->testExtractRange('test', -5);
$this->assertSame(['min' => -5, 'max' => null], $result);
}
public function testExtractRangeWithArrayContainingMin(): void
{
$result = $this->traitInstance->testExtractRange('test', ['min' => 3]);
$this->assertSame(['min' => 3, 'max' => null], $result);
}
public function testExtractRangeWithArrayContainingMax(): void
{
$result = $this->traitInstance->testExtractRange('test', ['max' => 10]);
$this->assertSame(['min' => null, 'max' => 10], $result);
}
public function testExtractRangeWithArrayContainingBoth(): void
{
$result = $this->traitInstance->testExtractRange('test', ['min' => 3, 'max' => 10]);
$this->assertSame(['min' => 3, 'max' => 10], $result);
}
public function testExtractRangeWithEmptyArray(): void
{
$result = $this->traitInstance->testExtractRange('test', []);
$this->assertSame(['min' => null, 'max' => null], $result);
}
public function testExtractRangeWithExtraKeys(): void
{
$result = $this->traitInstance->testExtractRange('test', ['min' => 1, 'max' => 5, 'extra' => 'ignored']);
$this->assertSame(['min' => 1, 'max' => 5], $result);
}
public function testExtractRangeWithNullMin(): void
{
$result = $this->traitInstance->testExtractRange('test', ['min' => null, 'max' => 5]);
$this->assertSame(['min' => null, 'max' => 5], $result);
}
public function testExtractRangeWithNullMax(): void
{
$result = $this->traitInstance->testExtractRange('test', ['min' => 5, 'max' => null]);
$this->assertSame(['min' => 5, 'max' => null], $result);
}
public function testExtractRangeWithInvalidTypeString(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "test"');
$this->expectExceptionMessage('Expected int or array, got "string"');
$this->traitInstance->testExtractRange('test', 'invalid');
}
public function testExtractRangeWithInvalidTypeFloat(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "test"');
$this->expectExceptionMessage('Expected int or array, got "float"');
$this->traitInstance->testExtractRange('test', 3.14);
}
public function testExtractRangeWithInvalidTypeNull(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "test"');
$this->expectExceptionMessage('Expected int or array, got "null"');
$this->traitInstance->testExtractRange('test', null);
}
public function testExtractRangeWithInvalidTypeBool(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "test"');
$this->expectExceptionMessage('Expected int or array, got "bool"');
$this->traitInstance->testExtractRange('test', true);
}
public function testExtractRangeWithInvalidTypeObject(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "test"');
$this->expectExceptionMessage('Expected int or array, got "stdClass"');
$this->traitInstance->testExtractRange('test', new \stdClass());
}
public function testExtractRangeWithInvalidMinTypeString(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "test"');
$this->expectExceptionMessage('Expected int, got "string"');
$this->traitInstance->testExtractRange('test', ['min' => 'invalid']);
}
public function testExtractRangeWithInvalidMinTypeFloat(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "test"');
$this->expectExceptionMessage('Expected int, got "float"');
$this->traitInstance->testExtractRange('test', ['min' => 3.14]);
}
public function testExtractRangeWithInvalidMinTypeArray(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "test"');
$this->expectExceptionMessage('Expected int, got "array"');
$this->traitInstance->testExtractRange('test', ['min' => [1, 2]]);
}
public function testExtractRangeWithInvalidMinTypeNullIsAllowed(): void
{
$result = $this->traitInstance->testExtractRange('test', ['min' => null]);
$this->assertNull($result['min']);
}
public function testExtractRangeWithInvalidMaxTypeString(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "max" in criteria "test"');
$this->expectExceptionMessage('Expected int, got "string"');
$this->traitInstance->testExtractRange('test', ['max' => 'invalid']);
}
public function testExtractRangeWithInvalidMaxTypeFloat(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "max" in criteria "test"');
$this->expectExceptionMessage('Expected int, got "float"');
$this->traitInstance->testExtractRange('test', ['max' => 3.14]);
}
public function testExtractRangeWithInvalidMaxTypeArray(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "max" in criteria "test"');
$this->expectExceptionMessage('Expected int, got "array"');
$this->traitInstance->testExtractRange('test', ['max' => [1, 2]]);
}
public function testExtractRangeWithInvalidMaxTypeNullIsAllowed(): void
{
$result = $this->traitInstance->testExtractRange('test', ['max' => null]);
$this->assertNull($result['max']);
}
public function testExtractRangeUsesNameInErrorMessage(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for criteria "custom_criteria_name"');
$this->traitInstance->testExtractRange('custom_criteria_name', 'invalid');
}
public function testExtractRangeWithMinInErrorMessage(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid type for "min" in criteria "priority"');
$this->traitInstance->testExtractRange('priority', ['min' => 'bad']);
}
}