From c1444f72764c395e34720f98386989f4bde8f4ac Mon Sep 17 00:00:00 2001 From: Christian Heel <66922325+heelc29@users.noreply.github.com> Date: Fri, 16 Aug 2024 08:22:30 +0200 Subject: [PATCH] add php8.3 to drone (#38) --- .drone.jsonnet | 3 +- .drone.yml | 22 +- Tests/AbstractEventTest.php | 312 ++-- .../DebugEventDispatcherCommandTest.php | 248 +-- Tests/DispatcherTest.php | 1391 ++++++++--------- Tests/EventImmutableTest.php | 84 +- Tests/EventTest.php | 352 ++--- Tests/LazyServiceEventListenerTest.php | 521 +++--- Tests/ListenersPriorityQueueTest.php | 323 ++-- Tests/Stubs/FirstListener.php | 50 +- Tests/Stubs/SecondListener.php | 30 +- Tests/Stubs/SomethingListener.php | 122 +- Tests/Stubs/ThirdListener.php | 30 +- 13 files changed, 1747 insertions(+), 1741 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index e13974c7..3e25ef82 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -25,7 +25,7 @@ local composer(phpversion, params) = { local phpunit(phpversion) = { name: "PHPUnit", image: "joomlaprojects/docker-images:php" + phpversion, - [if phpversion == "8.3" then "failure"]: "ignore", + [if phpversion == "8.4" then "failure"]: "ignore", commands: ["vendor/bin/phpunit"] }; @@ -103,4 +103,5 @@ local pipeline(name, phpversion, params) = { pipeline("8.1 lowest", "8.1", "--prefer-stable --prefer-lowest"), pipeline("8.1", "8.1", "--prefer-stable"), pipeline("8.2", "8.2", "--prefer-stable"), + pipeline("8.3", "8.3", "--prefer-stable"), ] diff --git a/.drone.yml b/.drone.yml index f20c452b..c852e68a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -109,7 +109,27 @@ volumes: path: /tmp/composer-cache name: composer-cache --- +kind: pipeline +name: PHP 8.3 +steps: +- commands: + - php -v + - composer update --prefer-stable + image: joomlaprojects/docker-images:php8.3 + name: composer + volumes: + - name: composer-cache + path: /tmp/composer-cache +- commands: + - vendor/bin/phpunit + image: joomlaprojects/docker-images:php8.3 + name: PHPUnit +volumes: +- host: + path: /tmp/composer-cache + name: composer-cache +--- kind: signature -hmac: 2bbb5bc788059cf5dd4cbb4fcc3f11adec8bfa59fc10526fd37c74d6ca472da7 +hmac: 44494eb95c9ccb71ac8b365e9422d0fd3e0dd946a21c606f70ac73952fe01bc6 ... diff --git a/Tests/AbstractEventTest.php b/Tests/AbstractEventTest.php index 50707a62..d905fba4 100644 --- a/Tests/AbstractEventTest.php +++ b/Tests/AbstractEventTest.php @@ -18,160 +18,160 @@ */ class AbstractEventTest extends TestCase { - /** - * @testdox The event's name can be retrieved - * - * @covers Joomla\Event\AbstractEvent - */ - public function testGetName() - { - $this->assertEquals('test', $this->createEventWithoutArguments()->getName()); - } - - /** - * @testdox A named event argument can be retrieved - * - * @covers Joomla\Event\AbstractEvent - */ - public function testGetArgument() - { - $event = $this->createEventWithArguments(); - - $this->assertFalse($event->getArgument('non-existing', false)); - $this->assertSame('bar', $event->getArgument('string')); - $this->assertInstanceOf(\stdClass::class, $event->getArgument('object')); - $this->assertIsArray($event->getArgument('array')); - } - - /** - * @testdox The event can be checked for a named argument - * - * @covers Joomla\Event\AbstractEvent - */ - public function testHasArgument() - { - $event = $this->createEventWithArguments(); - - $this->assertFalse($event->hasArgument('non-existing')); - $this->assertTrue($event->hasArgument('string')); - } - - /** - * @testdox The event arguments can be retrieved - * - * @covers Joomla\Event\AbstractEvent - */ - public function testGetArguments() - { - $this->assertEmpty($this->createEventWithoutArguments()->getArguments()); - } - - /** - * @testdox The event can be checked if its propagation has been stopped - * - * @covers Joomla\Event\AbstractEvent - */ - public function testIsStopped() - { - $this->assertFalse($this->createEventWithoutArguments()->isStopped()); - } - - /** - * @testdox An event's propagation can be stopped - * - * @covers Joomla\Event\AbstractEvent - */ - public function testStopPropagation() - { - $event = $this->createEventWithoutArguments(); - - $event->stopPropagation(); - $this->assertTrue($event->isStopped()); - } - - /** - * @testdox The event arguments can be counted - * - * @covers Joomla\Event\AbstractEvent - */ - public function testCount() - { - $this->assertCount(3, $this->createEventWithArguments()); - } - - /** - * @testdox The event can be serialized and unserialized - * - * @covers Joomla\Event\AbstractEvent - */ - public function testSerializeUnserialize() - { - $event = $this->createEventWithArguments(); - - $this->assertEquals($event, unserialize(serialize($event))); - } - - /** - * @testdox The event arguments can be checked for presence when accessing the event as an array - * - * @covers Joomla\Event\AbstractEvent - */ - public function testOffsetExists() - { - $event = $this->createEventWithArguments(); - - $this->assertFalse(isset($event['non-existing'])); - $this->assertTrue(isset($event['string'])); - } - - /** - * @testdox The event arguments can be retrieved when accessing the event as an array - * - * @covers Joomla\Event\AbstractEvent - */ - public function testOffsetGet() - { - $event = $this->createEventWithArguments(); - - $this->assertNull($event['non-existing']); - $this->assertSame('bar', $event['string']); - $this->assertInstanceOf(\stdClass::class, $event['object']); - $this->assertIsArray($event['array']); - } - - /** - * Creates an event without any arguments - * - * @return AbstractEvent|MockObject - */ - private function createEventWithoutArguments(): AbstractEvent - { - return $this->getMockForAbstractClass(AbstractEvent::class, ['test']); - } - - /** - * Creates an event with some arguments - * - * @return AbstractEvent|MockObject - */ - private function createEventWithArguments(): AbstractEvent - { - return $this->getMockForAbstractClass( - AbstractEvent::class, - [ - 'test', - [ - 'string' => 'bar', - 'object' => new \stdClass, - 'array' => [ - 'foo' => 'bar', - 'test' => [ - 'foo' => 'bar', - 'test' => 'test', - ], - ], - ], - ] - ); - } + /** + * @testdox The event's name can be retrieved + * + * @covers Joomla\Event\AbstractEvent + */ + public function testGetName() + { + $this->assertEquals('test', $this->createEventWithoutArguments()->getName()); + } + + /** + * @testdox A named event argument can be retrieved + * + * @covers Joomla\Event\AbstractEvent + */ + public function testGetArgument() + { + $event = $this->createEventWithArguments(); + + $this->assertFalse($event->getArgument('non-existing', false)); + $this->assertSame('bar', $event->getArgument('string')); + $this->assertInstanceOf(\stdClass::class, $event->getArgument('object')); + $this->assertIsArray($event->getArgument('array')); + } + + /** + * @testdox The event can be checked for a named argument + * + * @covers Joomla\Event\AbstractEvent + */ + public function testHasArgument() + { + $event = $this->createEventWithArguments(); + + $this->assertFalse($event->hasArgument('non-existing')); + $this->assertTrue($event->hasArgument('string')); + } + + /** + * @testdox The event arguments can be retrieved + * + * @covers Joomla\Event\AbstractEvent + */ + public function testGetArguments() + { + $this->assertEmpty($this->createEventWithoutArguments()->getArguments()); + } + + /** + * @testdox The event can be checked if its propagation has been stopped + * + * @covers Joomla\Event\AbstractEvent + */ + public function testIsStopped() + { + $this->assertFalse($this->createEventWithoutArguments()->isStopped()); + } + + /** + * @testdox An event's propagation can be stopped + * + * @covers Joomla\Event\AbstractEvent + */ + public function testStopPropagation() + { + $event = $this->createEventWithoutArguments(); + + $event->stopPropagation(); + $this->assertTrue($event->isStopped()); + } + + /** + * @testdox The event arguments can be counted + * + * @covers Joomla\Event\AbstractEvent + */ + public function testCount() + { + $this->assertCount(3, $this->createEventWithArguments()); + } + + /** + * @testdox The event can be serialized and unserialized + * + * @covers Joomla\Event\AbstractEvent + */ + public function testSerializeUnserialize() + { + $event = $this->createEventWithArguments(); + + $this->assertEquals($event, unserialize(serialize($event))); + } + + /** + * @testdox The event arguments can be checked for presence when accessing the event as an array + * + * @covers Joomla\Event\AbstractEvent + */ + public function testOffsetExists() + { + $event = $this->createEventWithArguments(); + + $this->assertFalse(isset($event['non-existing'])); + $this->assertTrue(isset($event['string'])); + } + + /** + * @testdox The event arguments can be retrieved when accessing the event as an array + * + * @covers Joomla\Event\AbstractEvent + */ + public function testOffsetGet() + { + $event = $this->createEventWithArguments(); + + $this->assertNull($event['non-existing']); + $this->assertSame('bar', $event['string']); + $this->assertInstanceOf(\stdClass::class, $event['object']); + $this->assertIsArray($event['array']); + } + + /** + * Creates an event without any arguments + * + * @return AbstractEvent|MockObject + */ + private function createEventWithoutArguments(): AbstractEvent + { + return $this->getMockForAbstractClass(AbstractEvent::class, ['test']); + } + + /** + * Creates an event with some arguments + * + * @return AbstractEvent|MockObject + */ + private function createEventWithArguments(): AbstractEvent + { + return $this->getMockForAbstractClass( + AbstractEvent::class, + [ + 'test', + [ + 'string' => 'bar', + 'object' => new \stdClass(), + 'array' => [ + 'foo' => 'bar', + 'test' => [ + 'foo' => 'bar', + 'test' => 'test', + ], + ], + ], + ] + ); + } } diff --git a/Tests/Command/DebugEventDispatcherCommandTest.php b/Tests/Command/DebugEventDispatcherCommandTest.php index ecf9c25c..14ce811f 100644 --- a/Tests/Command/DebugEventDispatcherCommandTest.php +++ b/Tests/Command/DebugEventDispatcherCommandTest.php @@ -19,128 +19,128 @@ */ class DebugEventDispatcherCommandTest extends TestCase { - /** - * @testdox The dispatcher can be described when empty - * - * @covers Joomla\Event\Command\DebugEventDispatcherCommand - * @uses Joomla\Event\Dispatcher - */ - public function testTheCommandIsExecutedWithAnEmptyDispatcher() - { - $dispatcher = new Dispatcher; - - $input = new ArrayInput( - [ - 'command' => 'debug:event-dispatcher', - ] - ); - $output = new BufferedOutput; - - $application = new Application($input, $output); - - $command = new DebugEventDispatcherCommand($dispatcher); - $command->setApplication($application); - - $this->assertSame(0, $command->execute($input, $output)); - - $screenOutput = $output->fetch(); - $this->assertStringContainsString('There are no listeners registered to the event dispatcher.', $screenOutput); - } - - /** - * @testdox The dispatcher can be described when it contains listeners - * - * @covers Joomla\Event\Command\DebugEventDispatcherCommand - * @uses Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTheCommandIsExecutedWithAConfiguredDispatcher() - { - $dispatcher = new Dispatcher; - $dispatcher->addSubscriber(new SomethingListener); - - $input = new ArrayInput( - [ - 'command' => 'debug:event-dispatcher', - ] - ); - $output = new BufferedOutput; - - $application = new Application($input, $output); - - $command = new DebugEventDispatcherCommand($dispatcher); - $command->setApplication($application); - - $this->assertSame(0, $command->execute($input, $output)); - - $screenOutput = $output->fetch(); - - $this->assertStringContainsString('Registered Listeners Grouped By Event', $screenOutput); - $this->assertStringContainsString('#1 Joomla\Event\Tests\Stubs\SomethingListener::onAfterSomething()', $screenOutput); - } - - /** - * @testdox The dispatcher can be described when it contains listeners for a single event - * - * @covers Joomla\Event\Command\DebugEventDispatcherCommand - * @uses Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTheCommandIsExecutedWithAConfiguredDispatcherForASingleEventWithListeners() - { - $dispatcher = new Dispatcher; - $dispatcher->addSubscriber(new SomethingListener); - - $input = new ArrayInput( - [ - 'command' => 'debug:event-dispatcher', - 'event' => 'onAfterSomething', - ] - ); - $output = new BufferedOutput; - - $application = new Application($input, $output); - - $command = new DebugEventDispatcherCommand($dispatcher); - $command->setApplication($application); - - $this->assertSame(0, $command->execute($input, $output)); - - $screenOutput = $output->fetch(); - - $this->assertStringContainsString('Registered Listeners for "onAfterSomething" Event', $screenOutput); - $this->assertStringContainsString('#1 Joomla\Event\Tests\Stubs\SomethingListener::onAfterSomething()', $screenOutput); - } - - /** - * @testdox The dispatcher can be described when it contains listeners and no listeners match a single event - * - * @covers Joomla\Event\Command\DebugEventDispatcherCommand - * @uses Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTheCommandIsExecutedWithAConfiguredDispatcherForASingleEventWithoutListeners() - { - $dispatcher = new Dispatcher; - $dispatcher->addSubscriber(new SomethingListener); - - $input = new ArrayInput( - [ - 'command' => 'debug:event-dispatcher', - 'event' => 'onAfterSomethingElse', - ] - ); - $output = new BufferedOutput; - - $application = new Application($input, $output); - - $command = new DebugEventDispatcherCommand($dispatcher); - $command->setApplication($application); - - $this->assertSame(0, $command->execute($input, $output)); - - $screenOutput = $output->fetch(); - - $this->assertStringContainsString('The event "onAfterSomethingElse" does not have any', $screenOutput); - } + /** + * @testdox The dispatcher can be described when empty + * + * @covers Joomla\Event\Command\DebugEventDispatcherCommand + * @uses Joomla\Event\Dispatcher + */ + public function testTheCommandIsExecutedWithAnEmptyDispatcher() + { + $dispatcher = new Dispatcher(); + + $input = new ArrayInput( + [ + 'command' => 'debug:event-dispatcher', + ] + ); + $output = new BufferedOutput(); + + $application = new Application($input, $output); + + $command = new DebugEventDispatcherCommand($dispatcher); + $command->setApplication($application); + + $this->assertSame(0, $command->execute($input, $output)); + + $screenOutput = $output->fetch(); + $this->assertStringContainsString('There are no listeners registered to the event dispatcher.', $screenOutput); + } + + /** + * @testdox The dispatcher can be described when it contains listeners + * + * @covers Joomla\Event\Command\DebugEventDispatcherCommand + * @uses Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTheCommandIsExecutedWithAConfiguredDispatcher() + { + $dispatcher = new Dispatcher(); + $dispatcher->addSubscriber(new SomethingListener()); + + $input = new ArrayInput( + [ + 'command' => 'debug:event-dispatcher', + ] + ); + $output = new BufferedOutput(); + + $application = new Application($input, $output); + + $command = new DebugEventDispatcherCommand($dispatcher); + $command->setApplication($application); + + $this->assertSame(0, $command->execute($input, $output)); + + $screenOutput = $output->fetch(); + + $this->assertStringContainsString('Registered Listeners Grouped By Event', $screenOutput); + $this->assertStringContainsString('#1 Joomla\Event\Tests\Stubs\SomethingListener::onAfterSomething()', $screenOutput); + } + + /** + * @testdox The dispatcher can be described when it contains listeners for a single event + * + * @covers Joomla\Event\Command\DebugEventDispatcherCommand + * @uses Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTheCommandIsExecutedWithAConfiguredDispatcherForASingleEventWithListeners() + { + $dispatcher = new Dispatcher(); + $dispatcher->addSubscriber(new SomethingListener()); + + $input = new ArrayInput( + [ + 'command' => 'debug:event-dispatcher', + 'event' => 'onAfterSomething', + ] + ); + $output = new BufferedOutput(); + + $application = new Application($input, $output); + + $command = new DebugEventDispatcherCommand($dispatcher); + $command->setApplication($application); + + $this->assertSame(0, $command->execute($input, $output)); + + $screenOutput = $output->fetch(); + + $this->assertStringContainsString('Registered Listeners for "onAfterSomething" Event', $screenOutput); + $this->assertStringContainsString('#1 Joomla\Event\Tests\Stubs\SomethingListener::onAfterSomething()', $screenOutput); + } + + /** + * @testdox The dispatcher can be described when it contains listeners and no listeners match a single event + * + * @covers Joomla\Event\Command\DebugEventDispatcherCommand + * @uses Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTheCommandIsExecutedWithAConfiguredDispatcherForASingleEventWithoutListeners() + { + $dispatcher = new Dispatcher(); + $dispatcher->addSubscriber(new SomethingListener()); + + $input = new ArrayInput( + [ + 'command' => 'debug:event-dispatcher', + 'event' => 'onAfterSomethingElse', + ] + ); + $output = new BufferedOutput(); + + $application = new Application($input, $output); + + $command = new DebugEventDispatcherCommand($dispatcher); + $command->setApplication($application); + + $this->assertSame(0, $command->execute($input, $output)); + + $screenOutput = $output->fetch(); + + $this->assertStringContainsString('The event "onAfterSomethingElse" does not have any', $screenOutput); + } } diff --git a/Tests/DispatcherTest.php b/Tests/DispatcherTest.php index 8776489f..a7225702 100644 --- a/Tests/DispatcherTest.php +++ b/Tests/DispatcherTest.php @@ -8,8 +8,8 @@ use Joomla\Event\Dispatcher; use Joomla\Event\Event; -use Joomla\Event\EventInterface; use Joomla\Event\EventImmutable; +use Joomla\Event\EventInterface; use Joomla\Event\Priority; use Joomla\Event\Tests\Stubs\FirstListener; use Joomla\Event\Tests\Stubs\SecondListener; @@ -22,699 +22,698 @@ */ class DispatcherTest extends TestCase { - /** - * Object being tested - * - * @var Dispatcher - */ - private $instance; - - /** - * Sets up the fixture. - * - * This method is called before a test is executed. - */ - protected function setUp(): void - { - $this->instance = new Dispatcher; - } - - /** - * @testdox A default event object can be set to the dispatcher for a named event - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\EventImmutable - */ - public function testSetEvent() - { - $event = new Event('onTest'); - $this->assertSame($this->instance, $this->instance->setEvent($event), 'The setEvent method has a fluent interface'); - $this->assertTrue($this->instance->hasEvent('onTest')); - $this->assertSame($event, $this->instance->getEvent('onTest')); - - $immutableEvent = new EventImmutable('onAfterSomething'); - $this->assertSame($this->instance, $this->instance->setEvent($immutableEvent), 'The setEvent method has a fluent interface'); - $this->assertTrue($this->instance->hasEvent('onAfterSomething')); - $this->assertSame($immutableEvent, $this->instance->getEvent('onAfterSomething')); - - // Setting an existing event will replace the old one. - $eventCopy = new Event('onTest'); - $this->assertSame($this->instance, $this->instance->setEvent($eventCopy), 'The setEvent method has a fluent interface'); - $this->assertTrue($this->instance->hasEvent('onTest')); - $this->assertSame($eventCopy, $this->instance->getEvent('onTest')); - } - - /** - * @testdox A default event object can be added to the dispatcher for a named event if one does not already exist - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\EventImmutable - */ - public function testAddEvent() - { - $event = new Event('onTest'); - $this->instance->addEvent($event); - $this->assertTrue($this->instance->hasEvent('onTest')); - $this->assertSame($event, $this->instance->getEvent('onTest')); - - $immutableEvent = new EventImmutable('onAfterSomething'); - $this->instance->addEvent($immutableEvent); - $this->assertTrue($this->instance->hasEvent('onAfterSomething')); - $this->assertSame($immutableEvent, $this->instance->getEvent('onAfterSomething')); - - // Adding an existing event will have no effect. - $eventCopy = new Event('onTest'); - $this->instance->addEvent($eventCopy); - $this->assertTrue($this->instance->hasEvent('onTest')); - $this->assertSame($event, $this->instance->getEvent('onTest')); - } - - /** - * @testdox The dispatcher can be checked for a default event object for a named event - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - */ - public function testHasEvent() - { - $this->assertFalse($this->instance->hasEvent('onTest')); - - $event = new Event('onTest'); - $this->instance->addEvent($event); - $this->assertTrue($this->instance->hasEvent($event)); - } - - /** - * @testdox A default event object can be retrieved from the dispatcher for a named event - * - * @covers Joomla\Event\Dispatcher - */ - public function testGetEventNonExisting() - { - $this->assertNull($this->instance->getEvent('non-existing')); - $this->assertFalse($this->instance->getEvent('non-existing', false)); - } - - /** - * @testdox A default event object can be removed from the dispatcher for a named event - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - */ - public function testRemoveEvent() - { - // No exception. - $this->instance->removeEvent('non-existing'); - - $event = new Event('onTest'); - $this->instance->addEvent($event); - - // Remove by passing the instance. - $this->instance->removeEvent($event); - $this->assertFalse($this->instance->hasEvent('onTest')); - - $this->instance->addEvent($event); - - // Remove by name. - $this->instance->removeEvent('onTest'); - $this->assertFalse($this->instance->hasEvent('onTest')); - } - - /** - * @testdox All known default event objects can be retrieved from the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - */ - public function testGetEvents() - { - $this->assertEmpty($this->instance->getEvents()); - - $event1 = new Event('onBeforeTest'); - $event2 = new Event('onTest'); - $event3 = new Event('onAfterTest'); - - $this->assertSame($this->instance, $this->instance->addEvent($event1), 'The addEvent method has a fluent interface'); - - $this->instance->addEvent($event2) - ->addEvent($event3); - - $this->assertSame( - [ - 'onBeforeTest' => $event1, - 'onTest' => $event2, - 'onAfterTest' => $event3, - ], - $this->instance->getEvents() - ); - } - - /** - * @testdox The default event objects can be cleared from the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - */ - public function testClearEvents() - { - $event1 = new Event('onBeforeTest'); - $event2 = new Event('onTest'); - $event3 = new Event('onAfterTest'); - - $this->assertSame($this->instance, $this->instance->addEvent($event1), 'The addEvent method has a fluent interface'); - - $this->instance->addEvent($event2) - ->addEvent($event3); - - $this->instance->clearEvents(); - - $this->assertFalse($this->instance->hasEvent('onBeforeTest')); - $this->assertFalse($this->instance->hasEvent('onTest')); - $this->assertFalse($this->instance->hasEvent('onAfterTest')); - $this->assertEmpty($this->instance->getEvents()); - } - - /** - * @testdox The default event objects can be counted - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - */ - public function testCountEvents() - { - $this->assertEquals(0, $this->instance->countEvents()); - - $event1 = new Event('onBeforeTest'); - $event2 = new Event('onTest'); - $event3 = new Event('onAfterTest'); - - $this->assertSame($this->instance, $this->instance->addEvent($event1), 'The addEvent method has a fluent interface'); - - $this->instance->addEvent($event2) - ->addEvent($event3); - - $this->assertEquals(3, $this->instance->countEvents()); - } - - /** - * @testdox Event listeners can be added to the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testAddListener() - { - // Add 3 listeners listening to the same events. - $listener1 = new SomethingListener; - $listener2 = new SomethingListener; - $listener3 = new SomethingListener; - - $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener1, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener2, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener3, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); - - $this->assertTrue($this->instance->hasListener([$listener1, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener1, 'onSomething'])); - $this->assertTrue($this->instance->hasListener([$listener1, 'onAfterSomething'])); - - $this->assertTrue($this->instance->hasListener([$listener2, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener2, 'onSomething'])); - $this->assertTrue($this->instance->hasListener([$listener2, 'onAfterSomething'])); - - $this->assertTrue($this->instance->hasListener([$listener3, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener3, 'onSomething'])); - $this->assertTrue($this->instance->hasListener([$listener3, 'onAfterSomething'])); - - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener1, 'onBeforeSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener1, 'onSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', [$listener1, 'onAfterSomething'])); - - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener2, 'onBeforeSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener2, 'onSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', [$listener2, 'onAfterSomething'])); - - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener3, 'onBeforeSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener3, 'onSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', [$listener3, 'onAfterSomething'])); - } - - /** - * @testdox Event listeners can be added to the dispatcher with specified priorities - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testAddListenerSpecifiedPriorities() - { - $listener = new SomethingListener; - - $this->instance->addListener('onBeforeSomething', [$listener, 'onBeforeSomething'], Priority::MIN); - $this->instance->addListener('onSomething', [$listener, 'onSomething'], Priority::ABOVE_NORMAL); - $this->instance->addListener('onAfterSomething', [$listener, 'onAfterSomething'], Priority::MAX); - - $this->assertTrue($this->instance->hasListener([$listener, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener, 'onSomething'])); - $this->assertTrue($this->instance->hasListener([$listener, 'onAfterSomething'])); - - $this->assertEquals(Priority::MIN, $this->instance->getListenerPriority('onBeforeSomething', [$listener, 'onBeforeSomething'])); - $this->assertEquals(Priority::ABOVE_NORMAL, $this->instance->getListenerPriority('onSomething', [$listener, 'onSomething'])); - $this->assertEquals(Priority::MAX, $this->instance->getListenerPriority('onAfterSomething', [$listener, 'onAfterSomething'])); - } - - /** - * @testdox Event listeners can be added to the dispatcher as Closures - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testAddClosureListener() - { - $listener = static function (EventInterface $event) { - - }; - - $this->instance->addListener('onSomething', $listener, Priority::HIGH); - $this->instance->addListener('onAfterSomething', $listener, Priority::NORMAL); - - $this->assertTrue($this->instance->hasListener($listener, 'onSomething')); - $this->assertTrue($this->instance->hasListener($listener, 'onAfterSomething')); - - $this->assertEquals(Priority::HIGH, $this->instance->getListenerPriority('onSomething', $listener)); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', $listener)); - } - - /** - * @testdox The priority for an event listener can be retrieved - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testGetListenerPriority() - { - $listener = new SomethingListener; - $this->instance->addListener('onSomething', [$listener, 'onSomething']); - - $this->assertEquals( - Priority::NORMAL, - $this->instance->getListenerPriority( - 'onSomething', - [$listener, 'onSomething'] - ) - ); - } - - /** - * @testdox The event listeners can be retrieved from the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testGetListeners() - { - $this->assertEmpty($this->instance->getListeners('onSomething')); - - // Add 3 listeners listening to the same events. - $listener1 = new SomethingListener; - $listener2 = new SomethingListener; - $listener3 = new SomethingListener; - - $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener1, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener2, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener3, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); - - $allListeners = [ - 'onBeforeSomething' => [ - [$listener1, 'onBeforeSomething'], - [$listener2, 'onBeforeSomething'], - [$listener3, 'onBeforeSomething'], - ], - 'onSomething' => [ - [$listener1, 'onSomething'], - [$listener2, 'onSomething'], - [$listener3, 'onSomething'], - ], - 'onAfterSomething' => [ - [$listener1, 'onAfterSomething'], - [$listener2, 'onAfterSomething'], - [$listener3, 'onAfterSomething'], - ], - ]; - - $onBeforeSomethingListeners = $this->instance->getListeners('onBeforeSomething'); - - $this->assertSame($allListeners['onBeforeSomething'], $this->instance->getListeners('onBeforeSomething')); - $this->assertSame($allListeners['onSomething'], $this->instance->getListeners('onSomething')); - $this->assertSame($allListeners['onAfterSomething'], $this->instance->getListeners('onAfterSomething')); - $this->assertSame($allListeners, $this->instance->getListeners()); - } - - /** - * @testdox The dispatcher can be checked to determine if a listener is registered - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testHasListener() - { - $listener = new SomethingListener; - $this->instance->addListener('onSomething', [$listener, 'onSomething']); - $this->assertTrue($this->instance->hasListener([$listener, 'onSomething'], 'onSomething')); - } - - /** - * @testdox Event listeners can be removed from the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testRemoveListeners() - { - // Add 3 listeners listening to the same events. - $listener1 = new SomethingListener; - $listener2 = new SomethingListener; - $listener3 = new SomethingListener; - - $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); - $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); - - // Remove the listener from a specific event. - $this->instance->removeListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - - $this->assertFalse($this->instance->hasListener([$listener1, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener2, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener3, 'onBeforeSomething'])); - } - - /** - * @testdox The event listeners can be cleared from the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testClearListeners() - { - // Add 3 listeners listening to the same events. - $listener1 = new SomethingListener; - $listener2 = new SomethingListener; - $listener3 = new SomethingListener; - - $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener1, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener2, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener3, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); - - // Test without specified event. - $this->instance->clearListeners(); - - $this->assertFalse($this->instance->hasListener([$listener1, 'onBeforeSomething'])); - $this->assertFalse($this->instance->hasListener([$listener2, 'onSomething'])); - $this->assertFalse($this->instance->hasListener([$listener3, 'onAfterSomething'])); - - // Test with an event specified. - - $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener1, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener2, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener3, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); - - $this->instance->clearListeners('onSomething'); - - $this->assertTrue($this->instance->hasListener([$listener1, 'onBeforeSomething'])); - $this->assertFalse($this->instance->hasListener([$listener2, 'onSomething'])); - $this->assertTrue($this->instance->hasListener([$listener3, 'onAfterSomething'])); - - $this->assertFalse($this->instance->hasListener([$listener1, 'onSomething'])); - $this->assertFalse($this->instance->hasListener([$listener3, 'onSomething'])); - } - - /** - * @testdox Event listeners can be counted - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testCountListeners() - { - $this->assertEquals(0, $this->instance->countListeners('onTest')); - - // Add 3 listeners listening to the same events. - $listener1 = new SomethingListener; - $listener2 = new SomethingListener; - $listener3 = new SomethingListener; - - $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener1, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener2, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); - $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); - $this->instance->addListener('onSomething', [$listener3, 'onSomething']); - $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); - - $this->assertEquals(3, $this->instance->countListeners('onSomething')); - } - - /** - * @testdox An event can be triggered when there are no listeners - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTriggerEventNoListeners() - { - $this->assertInstanceOf(Event::class, $this->instance->triggerEvent('onTest')); - - $event = new Event('onTest'); - $this->assertSame($event, $this->instance->triggerEvent($event), 'The event is returned after being dispatched'); - } - - /** - * @testdox Event listeners are executed in priority then FIFO order - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTriggerEventSamePriority() - { - $first = new FirstListener; - $second = new SecondListener; - $third = new ThirdListener; - - $fourth = static function (Event $event) { - $listeners = $event->getArgument('listeners'); - $listeners[] = 'fourth'; - $event->setArgument('listeners', $listeners); - }; - - $fifth = static function (Event $event) { - $listeners = $event->getArgument('listeners'); - $listeners[] = 'fifth'; - $event->setArgument('listeners', $listeners); - }; - - $this->instance->addListener('onSomething', [$first, 'onSomething']); - $this->instance->addListener('onSomething', [$second, 'onSomething']); - $this->instance->addListener('onSomething', [$third, 'onSomething']); - $this->instance->addListener('onSomething', $fourth, Priority::NORMAL); - $this->instance->addListener('onSomething', $fifth, Priority::NORMAL); - - // Inspect the event arguments to know the order of the listeners. - /** @var $event Event */ - $event = $this->instance->triggerEvent('onSomething'); - - $listeners = $event->getArgument('listeners'); - - $this->assertEquals( - $listeners, - ['first', 'second', 'third', 'fourth', 'fifth'] - ); - } - - /** - * @testdox Event listeners are executed in priority then FIFO order - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTriggerEventDifferentPriorities() - { - $first = new FirstListener; - $second = new SecondListener; - $third = new ThirdListener; - - $fourth = static function (Event $event) { - $listeners = $event->getArgument('listeners'); - $listeners[] = 'fourth'; - $event->setArgument('listeners', $listeners); - }; - - $fifth = static function (Event $event) { - $listeners = $event->getArgument('listeners'); - $listeners[] = 'fifth'; - $event->setArgument('listeners', $listeners); - }; - - $this->instance->addListener('onSomething', $fourth, Priority::BELOW_NORMAL); - $this->instance->addListener('onSomething', $fifth, Priority::BELOW_NORMAL); - $this->instance->addListener('onSomething', [$first, 'onSomething'], Priority::HIGH); - $this->instance->addListener('onSomething', [$second, 'onSomething'], Priority::HIGH); - $this->instance->addListener('onSomething', [$third, 'onSomething'], Priority::ABOVE_NORMAL); - - // Inspect the event arguments to know the order of the listeners. - /** @var $event Event */ - $event = $this->instance->triggerEvent('onSomething'); - - $listeners = $event->getArgument('listeners'); - - $this->assertEquals( - $listeners, - ['first', 'second', 'third', 'fourth', 'fifth'] - ); - } - - /** - * @testdox Event listeners are not executed after a listener stops propagation - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTriggerEventStopped() - { - $first = new FirstListener; - $second = new SecondListener; - $third = new ThirdListener; - - $stopper = static function (Event $event) { - $event->stop(); - }; - - $this->instance->addListener('onSomething', [$first, 'onSomething']); - $this->instance->addListener('onSomething', [$second, 'onSomething']); - $this->instance->addListener('onSomething', $stopper, Priority::NORMAL); - $this->instance->addListener('onSomething', [$third, 'onSomething']); - - /** @var $event Event */ - $event = $this->instance->triggerEvent('onSomething'); - - $listeners = $event->getArgument('listeners'); - - // The third listener was not called because the stopper stopped the event. - $this->assertEquals( - $listeners, - ['first', 'second'] - ); - } - - /** - * @testdox An event is triggered using a default event object - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\AbstractEvent - * @uses Joomla\Event\Event - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testTriggerEventRegistered() - { - $event = new Event('onSomething'); - - $listener = new class - { - public $triggered = false; - - public function onSomething(Event $event): void - { - $this->triggered = true; - } - }; - - - $this->instance->addEvent(new Event('onSomething')); - $this->instance->addListener('onSomething', [$listener, 'onSomething']); - $this->instance->triggerEvent('onSomething'); - $this->assertTrue($listener->triggered); - } - - /** - * @testdox An event subscriber is registered to the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testAddSubscriber() - { - $listener = new SomethingListener; - - // Add our event subscriber - $this->instance->addSubscriber($listener); - - $this->assertTrue($this->instance->hasListener([$listener, 'onBeforeSomething'])); - $this->assertTrue($this->instance->hasListener([$listener, 'onSomething'])); - $this->assertTrue($this->instance->hasListener([$listener, 'onAfterSomething'])); - - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener, 'onBeforeSomething'])); - $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener, 'onSomething'])); - $this->assertEquals(Priority::HIGH, $this->instance->getListenerPriority('onAfterSomething', [$listener, 'onAfterSomething'])); - } - - /** - * @testdox An event subscriber is removed from the dispatcher - * - * @covers Joomla\Event\Dispatcher - * @uses Joomla\Event\ListenersPriorityQueue - */ - public function testRemoveSubscriber() - { - $listener = new SomethingListener; - - // Add our event subscriber - $this->instance->addSubscriber($listener); - - // And now remove it - $this->instance->removeSubscriber($listener); - - $this->assertFalse($this->instance->hasListener([$listener, 'onBeforeSomething'])); - $this->assertFalse($this->instance->hasListener([$listener, 'onSomething'])); - $this->assertFalse($this->instance->hasListener([$listener, 'onAfterSomething'])); - } + /** + * Object being tested + * + * @var Dispatcher + */ + private $instance; + + /** + * Sets up the fixture. + * + * This method is called before a test is executed. + */ + protected function setUp(): void + { + $this->instance = new Dispatcher(); + } + + /** + * @testdox A default event object can be set to the dispatcher for a named event + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\EventImmutable + */ + public function testSetEvent() + { + $event = new Event('onTest'); + $this->assertSame($this->instance, $this->instance->setEvent($event), 'The setEvent method has a fluent interface'); + $this->assertTrue($this->instance->hasEvent('onTest')); + $this->assertSame($event, $this->instance->getEvent('onTest')); + + $immutableEvent = new EventImmutable('onAfterSomething'); + $this->assertSame($this->instance, $this->instance->setEvent($immutableEvent), 'The setEvent method has a fluent interface'); + $this->assertTrue($this->instance->hasEvent('onAfterSomething')); + $this->assertSame($immutableEvent, $this->instance->getEvent('onAfterSomething')); + + // Setting an existing event will replace the old one. + $eventCopy = new Event('onTest'); + $this->assertSame($this->instance, $this->instance->setEvent($eventCopy), 'The setEvent method has a fluent interface'); + $this->assertTrue($this->instance->hasEvent('onTest')); + $this->assertSame($eventCopy, $this->instance->getEvent('onTest')); + } + + /** + * @testdox A default event object can be added to the dispatcher for a named event if one does not already exist + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\EventImmutable + */ + public function testAddEvent() + { + $event = new Event('onTest'); + $this->instance->addEvent($event); + $this->assertTrue($this->instance->hasEvent('onTest')); + $this->assertSame($event, $this->instance->getEvent('onTest')); + + $immutableEvent = new EventImmutable('onAfterSomething'); + $this->instance->addEvent($immutableEvent); + $this->assertTrue($this->instance->hasEvent('onAfterSomething')); + $this->assertSame($immutableEvent, $this->instance->getEvent('onAfterSomething')); + + // Adding an existing event will have no effect. + $eventCopy = new Event('onTest'); + $this->instance->addEvent($eventCopy); + $this->assertTrue($this->instance->hasEvent('onTest')); + $this->assertSame($event, $this->instance->getEvent('onTest')); + } + + /** + * @testdox The dispatcher can be checked for a default event object for a named event + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + */ + public function testHasEvent() + { + $this->assertFalse($this->instance->hasEvent('onTest')); + + $event = new Event('onTest'); + $this->instance->addEvent($event); + $this->assertTrue($this->instance->hasEvent($event)); + } + + /** + * @testdox A default event object can be retrieved from the dispatcher for a named event + * + * @covers Joomla\Event\Dispatcher + */ + public function testGetEventNonExisting() + { + $this->assertNull($this->instance->getEvent('non-existing')); + $this->assertFalse($this->instance->getEvent('non-existing', false)); + } + + /** + * @testdox A default event object can be removed from the dispatcher for a named event + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + */ + public function testRemoveEvent() + { + // No exception. + $this->instance->removeEvent('non-existing'); + + $event = new Event('onTest'); + $this->instance->addEvent($event); + + // Remove by passing the instance. + $this->instance->removeEvent($event); + $this->assertFalse($this->instance->hasEvent('onTest')); + + $this->instance->addEvent($event); + + // Remove by name. + $this->instance->removeEvent('onTest'); + $this->assertFalse($this->instance->hasEvent('onTest')); + } + + /** + * @testdox All known default event objects can be retrieved from the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + */ + public function testGetEvents() + { + $this->assertEmpty($this->instance->getEvents()); + + $event1 = new Event('onBeforeTest'); + $event2 = new Event('onTest'); + $event3 = new Event('onAfterTest'); + + $this->assertSame($this->instance, $this->instance->addEvent($event1), 'The addEvent method has a fluent interface'); + + $this->instance->addEvent($event2) + ->addEvent($event3); + + $this->assertSame( + [ + 'onBeforeTest' => $event1, + 'onTest' => $event2, + 'onAfterTest' => $event3, + ], + $this->instance->getEvents() + ); + } + + /** + * @testdox The default event objects can be cleared from the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + */ + public function testClearEvents() + { + $event1 = new Event('onBeforeTest'); + $event2 = new Event('onTest'); + $event3 = new Event('onAfterTest'); + + $this->assertSame($this->instance, $this->instance->addEvent($event1), 'The addEvent method has a fluent interface'); + + $this->instance->addEvent($event2) + ->addEvent($event3); + + $this->instance->clearEvents(); + + $this->assertFalse($this->instance->hasEvent('onBeforeTest')); + $this->assertFalse($this->instance->hasEvent('onTest')); + $this->assertFalse($this->instance->hasEvent('onAfterTest')); + $this->assertEmpty($this->instance->getEvents()); + } + + /** + * @testdox The default event objects can be counted + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + */ + public function testCountEvents() + { + $this->assertEquals(0, $this->instance->countEvents()); + + $event1 = new Event('onBeforeTest'); + $event2 = new Event('onTest'); + $event3 = new Event('onAfterTest'); + + $this->assertSame($this->instance, $this->instance->addEvent($event1), 'The addEvent method has a fluent interface'); + + $this->instance->addEvent($event2) + ->addEvent($event3); + + $this->assertEquals(3, $this->instance->countEvents()); + } + + /** + * @testdox Event listeners can be added to the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testAddListener() + { + // Add 3 listeners listening to the same events. + $listener1 = new SomethingListener(); + $listener2 = new SomethingListener(); + $listener3 = new SomethingListener(); + + $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener1, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener2, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener3, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); + + $this->assertTrue($this->instance->hasListener([$listener1, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener1, 'onSomething'])); + $this->assertTrue($this->instance->hasListener([$listener1, 'onAfterSomething'])); + + $this->assertTrue($this->instance->hasListener([$listener2, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener2, 'onSomething'])); + $this->assertTrue($this->instance->hasListener([$listener2, 'onAfterSomething'])); + + $this->assertTrue($this->instance->hasListener([$listener3, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener3, 'onSomething'])); + $this->assertTrue($this->instance->hasListener([$listener3, 'onAfterSomething'])); + + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener1, 'onBeforeSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener1, 'onSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', [$listener1, 'onAfterSomething'])); + + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener2, 'onBeforeSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener2, 'onSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', [$listener2, 'onAfterSomething'])); + + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener3, 'onBeforeSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener3, 'onSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', [$listener3, 'onAfterSomething'])); + } + + /** + * @testdox Event listeners can be added to the dispatcher with specified priorities + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testAddListenerSpecifiedPriorities() + { + $listener = new SomethingListener(); + + $this->instance->addListener('onBeforeSomething', [$listener, 'onBeforeSomething'], Priority::MIN); + $this->instance->addListener('onSomething', [$listener, 'onSomething'], Priority::ABOVE_NORMAL); + $this->instance->addListener('onAfterSomething', [$listener, 'onAfterSomething'], Priority::MAX); + + $this->assertTrue($this->instance->hasListener([$listener, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener, 'onSomething'])); + $this->assertTrue($this->instance->hasListener([$listener, 'onAfterSomething'])); + + $this->assertEquals(Priority::MIN, $this->instance->getListenerPriority('onBeforeSomething', [$listener, 'onBeforeSomething'])); + $this->assertEquals(Priority::ABOVE_NORMAL, $this->instance->getListenerPriority('onSomething', [$listener, 'onSomething'])); + $this->assertEquals(Priority::MAX, $this->instance->getListenerPriority('onAfterSomething', [$listener, 'onAfterSomething'])); + } + + /** + * @testdox Event listeners can be added to the dispatcher as Closures + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testAddClosureListener() + { + $listener = static function (EventInterface $event) { + + }; + + $this->instance->addListener('onSomething', $listener, Priority::HIGH); + $this->instance->addListener('onAfterSomething', $listener, Priority::NORMAL); + + $this->assertTrue($this->instance->hasListener($listener, 'onSomething')); + $this->assertTrue($this->instance->hasListener($listener, 'onAfterSomething')); + + $this->assertEquals(Priority::HIGH, $this->instance->getListenerPriority('onSomething', $listener)); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onAfterSomething', $listener)); + } + + /** + * @testdox The priority for an event listener can be retrieved + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testGetListenerPriority() + { + $listener = new SomethingListener(); + $this->instance->addListener('onSomething', [$listener, 'onSomething']); + + $this->assertEquals( + Priority::NORMAL, + $this->instance->getListenerPriority( + 'onSomething', + [$listener, 'onSomething'] + ) + ); + } + + /** + * @testdox The event listeners can be retrieved from the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testGetListeners() + { + $this->assertEmpty($this->instance->getListeners('onSomething')); + + // Add 3 listeners listening to the same events. + $listener1 = new SomethingListener(); + $listener2 = new SomethingListener(); + $listener3 = new SomethingListener(); + + $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener1, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener2, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener3, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); + + $allListeners = [ + 'onBeforeSomething' => [ + [$listener1, 'onBeforeSomething'], + [$listener2, 'onBeforeSomething'], + [$listener3, 'onBeforeSomething'], + ], + 'onSomething' => [ + [$listener1, 'onSomething'], + [$listener2, 'onSomething'], + [$listener3, 'onSomething'], + ], + 'onAfterSomething' => [ + [$listener1, 'onAfterSomething'], + [$listener2, 'onAfterSomething'], + [$listener3, 'onAfterSomething'], + ], + ]; + + $onBeforeSomethingListeners = $this->instance->getListeners('onBeforeSomething'); + + $this->assertSame($allListeners['onBeforeSomething'], $this->instance->getListeners('onBeforeSomething')); + $this->assertSame($allListeners['onSomething'], $this->instance->getListeners('onSomething')); + $this->assertSame($allListeners['onAfterSomething'], $this->instance->getListeners('onAfterSomething')); + $this->assertSame($allListeners, $this->instance->getListeners()); + } + + /** + * @testdox The dispatcher can be checked to determine if a listener is registered + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testHasListener() + { + $listener = new SomethingListener(); + $this->instance->addListener('onSomething', [$listener, 'onSomething']); + $this->assertTrue($this->instance->hasListener([$listener, 'onSomething'], 'onSomething')); + } + + /** + * @testdox Event listeners can be removed from the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testRemoveListeners() + { + // Add 3 listeners listening to the same events. + $listener1 = new SomethingListener(); + $listener2 = new SomethingListener(); + $listener3 = new SomethingListener(); + + $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); + $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); + + // Remove the listener from a specific event. + $this->instance->removeListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + + $this->assertFalse($this->instance->hasListener([$listener1, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener2, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener3, 'onBeforeSomething'])); + } + + /** + * @testdox The event listeners can be cleared from the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testClearListeners() + { + // Add 3 listeners listening to the same events. + $listener1 = new SomethingListener(); + $listener2 = new SomethingListener(); + $listener3 = new SomethingListener(); + + $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener1, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener2, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener3, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); + + // Test without specified event. + $this->instance->clearListeners(); + + $this->assertFalse($this->instance->hasListener([$listener1, 'onBeforeSomething'])); + $this->assertFalse($this->instance->hasListener([$listener2, 'onSomething'])); + $this->assertFalse($this->instance->hasListener([$listener3, 'onAfterSomething'])); + + // Test with an event specified. + + $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener1, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener2, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener3, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); + + $this->instance->clearListeners('onSomething'); + + $this->assertTrue($this->instance->hasListener([$listener1, 'onBeforeSomething'])); + $this->assertFalse($this->instance->hasListener([$listener2, 'onSomething'])); + $this->assertTrue($this->instance->hasListener([$listener3, 'onAfterSomething'])); + + $this->assertFalse($this->instance->hasListener([$listener1, 'onSomething'])); + $this->assertFalse($this->instance->hasListener([$listener3, 'onSomething'])); + } + + /** + * @testdox Event listeners can be counted + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testCountListeners() + { + $this->assertEquals(0, $this->instance->countListeners('onTest')); + + // Add 3 listeners listening to the same events. + $listener1 = new SomethingListener(); + $listener2 = new SomethingListener(); + $listener3 = new SomethingListener(); + + $this->instance->addListener('onBeforeSomething', [$listener1, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener1, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener1, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener2, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener2, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener2, 'onAfterSomething']); + $this->instance->addListener('onBeforeSomething', [$listener3, 'onBeforeSomething']); + $this->instance->addListener('onSomething', [$listener3, 'onSomething']); + $this->instance->addListener('onAfterSomething', [$listener3, 'onAfterSomething']); + + $this->assertEquals(3, $this->instance->countListeners('onSomething')); + } + + /** + * @testdox An event can be triggered when there are no listeners + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTriggerEventNoListeners() + { + $this->assertInstanceOf(Event::class, $this->instance->triggerEvent('onTest')); + + $event = new Event('onTest'); + $this->assertSame($event, $this->instance->triggerEvent($event), 'The event is returned after being dispatched'); + } + + /** + * @testdox Event listeners are executed in priority then FIFO order + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTriggerEventSamePriority() + { + $first = new FirstListener(); + $second = new SecondListener(); + $third = new ThirdListener(); + + $fourth = static function (Event $event) { + $listeners = $event->getArgument('listeners'); + $listeners[] = 'fourth'; + $event->setArgument('listeners', $listeners); + }; + + $fifth = static function (Event $event) { + $listeners = $event->getArgument('listeners'); + $listeners[] = 'fifth'; + $event->setArgument('listeners', $listeners); + }; + + $this->instance->addListener('onSomething', [$first, 'onSomething']); + $this->instance->addListener('onSomething', [$second, 'onSomething']); + $this->instance->addListener('onSomething', [$third, 'onSomething']); + $this->instance->addListener('onSomething', $fourth, Priority::NORMAL); + $this->instance->addListener('onSomething', $fifth, Priority::NORMAL); + + // Inspect the event arguments to know the order of the listeners. + /** @var $event Event */ + $event = $this->instance->triggerEvent('onSomething'); + + $listeners = $event->getArgument('listeners'); + + $this->assertEquals( + $listeners, + ['first', 'second', 'third', 'fourth', 'fifth'] + ); + } + + /** + * @testdox Event listeners are executed in priority then FIFO order + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTriggerEventDifferentPriorities() + { + $first = new FirstListener(); + $second = new SecondListener(); + $third = new ThirdListener(); + + $fourth = static function (Event $event) { + $listeners = $event->getArgument('listeners'); + $listeners[] = 'fourth'; + $event->setArgument('listeners', $listeners); + }; + + $fifth = static function (Event $event) { + $listeners = $event->getArgument('listeners'); + $listeners[] = 'fifth'; + $event->setArgument('listeners', $listeners); + }; + + $this->instance->addListener('onSomething', $fourth, Priority::BELOW_NORMAL); + $this->instance->addListener('onSomething', $fifth, Priority::BELOW_NORMAL); + $this->instance->addListener('onSomething', [$first, 'onSomething'], Priority::HIGH); + $this->instance->addListener('onSomething', [$second, 'onSomething'], Priority::HIGH); + $this->instance->addListener('onSomething', [$third, 'onSomething'], Priority::ABOVE_NORMAL); + + // Inspect the event arguments to know the order of the listeners. + /** @var $event Event */ + $event = $this->instance->triggerEvent('onSomething'); + + $listeners = $event->getArgument('listeners'); + + $this->assertEquals( + $listeners, + ['first', 'second', 'third', 'fourth', 'fifth'] + ); + } + + /** + * @testdox Event listeners are not executed after a listener stops propagation + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTriggerEventStopped() + { + $first = new FirstListener(); + $second = new SecondListener(); + $third = new ThirdListener(); + + $stopper = static function (Event $event) { + $event->stop(); + }; + + $this->instance->addListener('onSomething', [$first, 'onSomething']); + $this->instance->addListener('onSomething', [$second, 'onSomething']); + $this->instance->addListener('onSomething', $stopper, Priority::NORMAL); + $this->instance->addListener('onSomething', [$third, 'onSomething']); + + /** @var $event Event */ + $event = $this->instance->triggerEvent('onSomething'); + + $listeners = $event->getArgument('listeners'); + + // The third listener was not called because the stopper stopped the event. + $this->assertEquals( + $listeners, + ['first', 'second'] + ); + } + + /** + * @testdox An event is triggered using a default event object + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\AbstractEvent + * @uses Joomla\Event\Event + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testTriggerEventRegistered() + { + $event = new Event('onSomething'); + + $listener = new class () { + public $triggered = false; + + public function onSomething(Event $event): void + { + $this->triggered = true; + } + }; + + + $this->instance->addEvent(new Event('onSomething')); + $this->instance->addListener('onSomething', [$listener, 'onSomething']); + $this->instance->triggerEvent('onSomething'); + $this->assertTrue($listener->triggered); + } + + /** + * @testdox An event subscriber is registered to the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testAddSubscriber() + { + $listener = new SomethingListener(); + + // Add our event subscriber + $this->instance->addSubscriber($listener); + + $this->assertTrue($this->instance->hasListener([$listener, 'onBeforeSomething'])); + $this->assertTrue($this->instance->hasListener([$listener, 'onSomething'])); + $this->assertTrue($this->instance->hasListener([$listener, 'onAfterSomething'])); + + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onBeforeSomething', [$listener, 'onBeforeSomething'])); + $this->assertEquals(Priority::NORMAL, $this->instance->getListenerPriority('onSomething', [$listener, 'onSomething'])); + $this->assertEquals(Priority::HIGH, $this->instance->getListenerPriority('onAfterSomething', [$listener, 'onAfterSomething'])); + } + + /** + * @testdox An event subscriber is removed from the dispatcher + * + * @covers Joomla\Event\Dispatcher + * @uses Joomla\Event\ListenersPriorityQueue + */ + public function testRemoveSubscriber() + { + $listener = new SomethingListener(); + + // Add our event subscriber + $this->instance->addSubscriber($listener); + + // And now remove it + $this->instance->removeSubscriber($listener); + + $this->assertFalse($this->instance->hasListener([$listener, 'onBeforeSomething'])); + $this->assertFalse($this->instance->hasListener([$listener, 'onSomething'])); + $this->assertFalse($this->instance->hasListener([$listener, 'onAfterSomething'])); + } } diff --git a/Tests/EventImmutableTest.php b/Tests/EventImmutableTest.php index aaa55b20..ef9345c7 100644 --- a/Tests/EventImmutableTest.php +++ b/Tests/EventImmutableTest.php @@ -14,52 +14,52 @@ */ class EventImmutableTest extends TestCase { - /** - * @testdox The constructor cannot be triggered multiple times - * - * @covers Joomla\Event\EventImmutable - * @uses Joomla\Event\AbstractEvent - */ - public function testCannotBeConstructedMultipleTimes() - { - $this->expectException(\BadMethodCallException::class); + /** + * @testdox The constructor cannot be triggered multiple times + * + * @covers Joomla\Event\EventImmutable + * @uses Joomla\Event\AbstractEvent + */ + public function testCannotBeConstructedMultipleTimes() + { + $this->expectException(\BadMethodCallException::class); - $this->createEventWithoutArguments()->__construct('foo'); - } + $this->createEventWithoutArguments()->__construct('foo'); + } - /** - * @testdox An argument cannot be set on the event after it is instantiated - * - * @covers Joomla\Event\EventImmutable - * @uses Joomla\Event\AbstractEvent - */ - public function testOffsetSet() - { - $this->expectException(\BadMethodCallException::class); + /** + * @testdox An argument cannot be set on the event after it is instantiated + * + * @covers Joomla\Event\EventImmutable + * @uses Joomla\Event\AbstractEvent + */ + public function testOffsetSet() + { + $this->expectException(\BadMethodCallException::class); - $this->createEventWithoutArguments()['foo'] = 'bar'; - } + $this->createEventWithoutArguments()['foo'] = 'bar'; + } - /** - * @testdox An argument cannot be removed from the event after it is instantiated - * - * @covers Joomla\Event\EventImmutable - * @uses Joomla\Event\AbstractEvent - */ - public function testOffsetUnSet() - { - $this->expectException(\BadMethodCallException::class); + /** + * @testdox An argument cannot be removed from the event after it is instantiated + * + * @covers Joomla\Event\EventImmutable + * @uses Joomla\Event\AbstractEvent + */ + public function testOffsetUnSet() + { + $this->expectException(\BadMethodCallException::class); - unset($this->createEventWithoutArguments()['foo']); - } + unset($this->createEventWithoutArguments()['foo']); + } - /** - * Creates an event without any arguments - * - * @return EventImmutable - */ - private function createEventWithoutArguments(): EventImmutable - { - return new EventImmutable('test'); - } + /** + * Creates an event without any arguments + * + * @return EventImmutable + */ + private function createEventWithoutArguments(): EventImmutable + { + return new EventImmutable('test'); + } } diff --git a/Tests/EventTest.php b/Tests/EventTest.php index 4206da59..2a9bef3c 100644 --- a/Tests/EventTest.php +++ b/Tests/EventTest.php @@ -14,180 +14,180 @@ */ class EventTest extends TestCase { - /** - * @testdox An argument can be added to the event - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testAddArgument() - { - $event = $this->createEventWithoutArguments(); - - $this->assertSame($event, $event->addArgument('foo', 'bar'), 'The addArgument method has a fluent interface'); - $this->assertTrue($event->hasArgument('foo')); - } - - /** - * @testdox When an argument already exists on an event, it should not be overwritten - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testAddArgumentExisting() - { - $event = $this->createEventWithoutArguments(); - - $this->assertSame($event, $event->addArgument('foo', 'bar'), 'The addArgument method has a fluent interface'); - $this->assertSame($event, $event->addArgument('foo', 'car'), 'The addArgument method has a fluent interface'); - $this->assertSame('bar', $event->getArgument('foo')); - } - - /** - * @testdox An argument can be set on the event - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testSetArgument() - { - $event = $this->createEventWithoutArguments(); - - $this->assertSame($event, $event->setArgument('foo', 'bar'), 'The setArgument method has a fluent interface'); - $this->assertTrue($event->hasArgument('foo')); - } - - /** - * @testdox When an argument already exists on an event, it is overwritten - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testSetArgumentExisting() - { - $event = $this->createEventWithoutArguments(); - - $this->assertSame($event, $event->setArgument('foo', 'bar'), 'The setArgument method has a fluent interface'); - $this->assertSame($event, $event->setArgument('foo', 'car'), 'The setArgument method has a fluent interface'); - $this->assertSame('car', $event->getArgument('foo')); - } - - /** - * @testdox An argument can be removed from an event - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testRemoveArgument() - { - $event = $this->createEventWithArguments(); - - $this->assertNull($event->removeArgument('non-existing'), 'When removing a non-existing argument, null is returned'); - $this->assertSame('bar', $event->removeArgument('string'), 'When removing an existing argument, the value is returned'); - $this->assertFalse($event->hasArgument('string')); - } - - /** - * @testdox The arguments can be cleared from an event - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testClearArguments() - { - $event = $this->createEventWithArguments(); - - $this->assertNotEmpty($event->clearArguments(), 'The event arguments should be returned when clearing them'); - $this->assertFalse($event->hasArgument('string')); - } - - /** - * @testdox An event can be stopped - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testStop() - { - $event = $this->createEventWithoutArguments(); - - $event->stop(); - $this->assertTrue($event->isStopped()); - } - - /** - * @testdox An argument can be set on the event when accessing the event as an array - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testOffsetSet() - { - $event = $this->createEventWithoutArguments(); - $event['foo'] = 'bar'; - - $this->assertTrue($event->hasArgument('foo')); - $this->assertEquals('bar', $event->getArgument('foo')); - } - - /** - * @testdox An argument requires a name when setting arguments on the event as an array - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testOffsetSetException() - { - $this->expectException(\InvalidArgumentException::class); - - $this->createEventWithoutArguments()[] = 'bar'; - } - - /** - * @testdox An argument can be removed from an event when accessing the event as an array - * - * @covers Joomla\Event\Event - * @uses Joomla\Event\AbstractEvent - */ - public function testOffsetUnset() - { - $event = $this->createEventWithArguments(); - - unset($event['string']); - - $this->assertFalse($event->hasArgument('string')); - } - - /** - * Creates an event without any arguments - * - * @return Event - */ - private function createEventWithoutArguments(): Event - { - return new Event('test'); - } - - /** - * Creates an event with some arguments - * - * @return Event - */ - private function createEventWithArguments(): Event - { - return new Event( - 'test', - [ - 'string' => 'bar', - 'object' => new \stdClass, - 'array' => [ - 'foo' => 'bar', - 'test' => [ - 'foo' => 'bar', - 'test' => 'test', - ], - ], - ] - ); - } + /** + * @testdox An argument can be added to the event + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testAddArgument() + { + $event = $this->createEventWithoutArguments(); + + $this->assertSame($event, $event->addArgument('foo', 'bar'), 'The addArgument method has a fluent interface'); + $this->assertTrue($event->hasArgument('foo')); + } + + /** + * @testdox When an argument already exists on an event, it should not be overwritten + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testAddArgumentExisting() + { + $event = $this->createEventWithoutArguments(); + + $this->assertSame($event, $event->addArgument('foo', 'bar'), 'The addArgument method has a fluent interface'); + $this->assertSame($event, $event->addArgument('foo', 'car'), 'The addArgument method has a fluent interface'); + $this->assertSame('bar', $event->getArgument('foo')); + } + + /** + * @testdox An argument can be set on the event + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testSetArgument() + { + $event = $this->createEventWithoutArguments(); + + $this->assertSame($event, $event->setArgument('foo', 'bar'), 'The setArgument method has a fluent interface'); + $this->assertTrue($event->hasArgument('foo')); + } + + /** + * @testdox When an argument already exists on an event, it is overwritten + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testSetArgumentExisting() + { + $event = $this->createEventWithoutArguments(); + + $this->assertSame($event, $event->setArgument('foo', 'bar'), 'The setArgument method has a fluent interface'); + $this->assertSame($event, $event->setArgument('foo', 'car'), 'The setArgument method has a fluent interface'); + $this->assertSame('car', $event->getArgument('foo')); + } + + /** + * @testdox An argument can be removed from an event + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testRemoveArgument() + { + $event = $this->createEventWithArguments(); + + $this->assertNull($event->removeArgument('non-existing'), 'When removing a non-existing argument, null is returned'); + $this->assertSame('bar', $event->removeArgument('string'), 'When removing an existing argument, the value is returned'); + $this->assertFalse($event->hasArgument('string')); + } + + /** + * @testdox The arguments can be cleared from an event + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testClearArguments() + { + $event = $this->createEventWithArguments(); + + $this->assertNotEmpty($event->clearArguments(), 'The event arguments should be returned when clearing them'); + $this->assertFalse($event->hasArgument('string')); + } + + /** + * @testdox An event can be stopped + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testStop() + { + $event = $this->createEventWithoutArguments(); + + $event->stop(); + $this->assertTrue($event->isStopped()); + } + + /** + * @testdox An argument can be set on the event when accessing the event as an array + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testOffsetSet() + { + $event = $this->createEventWithoutArguments(); + $event['foo'] = 'bar'; + + $this->assertTrue($event->hasArgument('foo')); + $this->assertEquals('bar', $event->getArgument('foo')); + } + + /** + * @testdox An argument requires a name when setting arguments on the event as an array + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testOffsetSetException() + { + $this->expectException(\InvalidArgumentException::class); + + $this->createEventWithoutArguments()[] = 'bar'; + } + + /** + * @testdox An argument can be removed from an event when accessing the event as an array + * + * @covers Joomla\Event\Event + * @uses Joomla\Event\AbstractEvent + */ + public function testOffsetUnset() + { + $event = $this->createEventWithArguments(); + + unset($event['string']); + + $this->assertFalse($event->hasArgument('string')); + } + + /** + * Creates an event without any arguments + * + * @return Event + */ + private function createEventWithoutArguments(): Event + { + return new Event('test'); + } + + /** + * Creates an event with some arguments + * + * @return Event + */ + private function createEventWithArguments(): Event + { + return new Event( + 'test', + [ + 'string' => 'bar', + 'object' => new \stdClass(), + 'array' => [ + 'foo' => 'bar', + 'test' => [ + 'foo' => 'bar', + 'test' => 'test', + ], + ], + ] + ); + } } diff --git a/Tests/LazyServiceEventListenerTest.php b/Tests/LazyServiceEventListenerTest.php index b08d0412..d89ae738 100644 --- a/Tests/LazyServiceEventListenerTest.php +++ b/Tests/LazyServiceEventListenerTest.php @@ -17,271 +17,258 @@ */ class LazyServiceEventListenerTest extends TestCase { - /** - * @testdox The listener can be instantiated without a method name - * - * @covers Joomla\Event\LazyServiceEventListener - * - * @doesNotPerformAssertions - */ - public function testListenerCanBeInstantiatedWithoutMethod() - { - $serviceId = 'lazy.object'; - - $container = $this->buildStubContainer(); - $container->set( - $serviceId, - static function (ContainerInterface $container) - { - return new \stdClass; - } - ); - - new LazyServiceEventListener($container, $serviceId); - } - - /** - * @testdox The listener cannot be instantiated without a service ID - * - * @covers Joomla\Event\LazyServiceEventListener - */ - public function testListenerCannotBeInstantiatedWithoutAServiceId() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage( - sprintf( - 'The $serviceId parameter cannot be empty in %s', - LazyServiceEventListener::class - ) - ); - - $container = $this->buildStubContainer(); - $container->set( - 'lazy.object', - static function (ContainerInterface $container) - { - return new \stdClass; - } - ); - - new LazyServiceEventListener($container, ''); - } - - /** - * @testdox The listener forwards a call to an invocable object - * - * @covers Joomla\Event\LazyServiceEventListener - */ - public function testListenerTriggersAnInvocableClass() - { - $serviceId = 'lazy.object'; - - $service = new class - { - private $triggered = false; - - public function __invoke(): void - { - $this->triggered = true; - } - - public function isTriggered(): bool - { - return $this->triggered; - } - }; - - $container = $this->buildStubContainer(); - $container->set( - $serviceId, - static function () use ($service) - { - return $service; - } - ); - - $event = $this->createMock(EventInterface::class); - - $listener = new LazyServiceEventListener($container, $serviceId); - $listener($event); - - $this->assertTrue($service->isTriggered()); - } - - /** - * @testdox The listener forwards a call to a named method on a class - * - * @covers Joomla\Event\LazyServiceEventListener - */ - public function testListenerTriggersAMethodOnAClass() - { - $serviceId = 'lazy.object'; - - $service = new class - { - private $triggered = false; - - public function isTriggered(): bool - { - return $this->triggered; - } - - public function trigger(): void - { - $this->triggered = true; - } - }; - - $container = $this->buildStubContainer(); - $container->set( - $serviceId, - static function () use ($service) - { - return $service; - } - ); - - $event = $this->createMock(EventInterface::class); - - $listener = new LazyServiceEventListener($container, $serviceId, 'trigger'); - $listener($event); - - $this->assertTrue($service->isTriggered()); - } - - /** - * @testdox The listener cannot forward a call to an unknown service - * - * @covers Joomla\Event\LazyServiceEventListener - */ - public function testListenerCannotTriggerAnUnknownService() - { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('The "lazy.object" service has not been registered to the service container'); - - $container = $this->buildStubContainer(); - - $event = $this->createMock(EventInterface::class); - - $listener = new LazyServiceEventListener($container, 'lazy.object'); - $listener($event); - } - - /** - * @testdox The listener cannot forward a call to an object when no method name is provided and the object is not invocable - * - * @covers Joomla\Event\LazyServiceEventListener - */ - public function testListenerCannotTriggerAMethodWhenMethodNameNotGivenAndClassNotInvocable() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage( - sprintf( - 'The $method argument is required when creating a "%s" to call a method from the "lazy.object" service.', - LazyServiceEventListener::class - ) - ); - - $serviceId = 'lazy.object'; - - $container = $this->buildStubContainer(); - $container->set( - $serviceId, - static function () - { - return new class - { - private $triggered = false; - - public function trigger(): void - { - $this->triggered = true; - } - }; - } - ); - - $event = $this->createMock(EventInterface::class); - - $listener = new LazyServiceEventListener($container, $serviceId); - $listener($event); - } - - /** - * @testdox The listener cannot forward a call to an object when the given method does not exist - * - * @covers Joomla\Event\LazyServiceEventListener - */ - public function testListenerCannotTriggerAMethodWhenTheGivenMethodNameDoesNotExist() - { - $service = new class - { - private $triggered = false; - - public function trigger(): void - { - $this->triggered = true; - } - }; - - $serviceId = 'lazy.object'; - - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage( - sprintf( - 'The "doIt" method does not exist on "%s" (from service "%s")', - \get_class($service), - $serviceId - ) - ); - - $container = $this->buildStubContainer(); - $container->set( - $serviceId, - static function () use ($service) - { - return $service; - } - ); - - $event = $this->createMock(EventInterface::class); - - $listener = new LazyServiceEventListener($container, $serviceId, 'doIt'); - $listener($event); - } - - private function buildStubContainer(): ContainerInterface - { - return new class implements ContainerInterface - { - private $services = []; - - public function get($id) - { - if (!$this->has($id)) - { - throw new class extends \InvalidArgumentException implements NotFoundExceptionInterface {}; - } - - return $this->services[$id]($this); - } - - public function has($id) - { - return isset($this->services[$id]); - } - - public function set($id, $value) - { - if (!is_callable($value)) - { - $value = static function () use ($value) { - return $value; - }; - } - - $this->services[$id] = $value; - } - }; - } + /** + * @testdox The listener can be instantiated without a method name + * + * @covers Joomla\Event\LazyServiceEventListener + * + * @doesNotPerformAssertions + */ + public function testListenerCanBeInstantiatedWithoutMethod() + { + $serviceId = 'lazy.object'; + + $container = $this->buildStubContainer(); + $container->set( + $serviceId, + static function (ContainerInterface $container) { + return new \stdClass(); + } + ); + + new LazyServiceEventListener($container, $serviceId); + } + + /** + * @testdox The listener cannot be instantiated without a service ID + * + * @covers Joomla\Event\LazyServiceEventListener + */ + public function testListenerCannotBeInstantiatedWithoutAServiceId() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage( + sprintf( + 'The $serviceId parameter cannot be empty in %s', + LazyServiceEventListener::class + ) + ); + + $container = $this->buildStubContainer(); + $container->set( + 'lazy.object', + static function (ContainerInterface $container) { + return new \stdClass(); + } + ); + + new LazyServiceEventListener($container, ''); + } + + /** + * @testdox The listener forwards a call to an invocable object + * + * @covers Joomla\Event\LazyServiceEventListener + */ + public function testListenerTriggersAnInvocableClass() + { + $serviceId = 'lazy.object'; + + $service = new class () { + private $triggered = false; + + public function __invoke(): void + { + $this->triggered = true; + } + + public function isTriggered(): bool + { + return $this->triggered; + } + }; + + $container = $this->buildStubContainer(); + $container->set( + $serviceId, + static function () use ($service) { + return $service; + } + ); + + $event = $this->createMock(EventInterface::class); + + $listener = new LazyServiceEventListener($container, $serviceId); + $listener($event); + + $this->assertTrue($service->isTriggered()); + } + + /** + * @testdox The listener forwards a call to a named method on a class + * + * @covers Joomla\Event\LazyServiceEventListener + */ + public function testListenerTriggersAMethodOnAClass() + { + $serviceId = 'lazy.object'; + + $service = new class () { + private $triggered = false; + + public function isTriggered(): bool + { + return $this->triggered; + } + + public function trigger(): void + { + $this->triggered = true; + } + }; + + $container = $this->buildStubContainer(); + $container->set( + $serviceId, + static function () use ($service) { + return $service; + } + ); + + $event = $this->createMock(EventInterface::class); + + $listener = new LazyServiceEventListener($container, $serviceId, 'trigger'); + $listener($event); + + $this->assertTrue($service->isTriggered()); + } + + /** + * @testdox The listener cannot forward a call to an unknown service + * + * @covers Joomla\Event\LazyServiceEventListener + */ + public function testListenerCannotTriggerAnUnknownService() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('The "lazy.object" service has not been registered to the service container'); + + $container = $this->buildStubContainer(); + + $event = $this->createMock(EventInterface::class); + + $listener = new LazyServiceEventListener($container, 'lazy.object'); + $listener($event); + } + + /** + * @testdox The listener cannot forward a call to an object when no method name is provided and the object is not invocable + * + * @covers Joomla\Event\LazyServiceEventListener + */ + public function testListenerCannotTriggerAMethodWhenMethodNameNotGivenAndClassNotInvocable() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage( + sprintf( + 'The $method argument is required when creating a "%s" to call a method from the "lazy.object" service.', + LazyServiceEventListener::class + ) + ); + + $serviceId = 'lazy.object'; + + $container = $this->buildStubContainer(); + $container->set( + $serviceId, + static function () { + return new class () { + private $triggered = false; + + public function trigger(): void + { + $this->triggered = true; + } + }; + } + ); + + $event = $this->createMock(EventInterface::class); + + $listener = new LazyServiceEventListener($container, $serviceId); + $listener($event); + } + + /** + * @testdox The listener cannot forward a call to an object when the given method does not exist + * + * @covers Joomla\Event\LazyServiceEventListener + */ + public function testListenerCannotTriggerAMethodWhenTheGivenMethodNameDoesNotExist() + { + $service = new class () { + private $triggered = false; + + public function trigger(): void + { + $this->triggered = true; + } + }; + + $serviceId = 'lazy.object'; + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage( + sprintf( + 'The "doIt" method does not exist on "%s" (from service "%s")', + \get_class($service), + $serviceId + ) + ); + + $container = $this->buildStubContainer(); + $container->set( + $serviceId, + static function () use ($service) { + return $service; + } + ); + + $event = $this->createMock(EventInterface::class); + + $listener = new LazyServiceEventListener($container, $serviceId, 'doIt'); + $listener($event); + } + + private function buildStubContainer(): ContainerInterface + { + return new class () implements ContainerInterface { + private $services = []; + + public function get($id) + { + if (!$this->has($id)) { + throw new class () extends \InvalidArgumentException implements NotFoundExceptionInterface {}; + } + + return $this->services[$id]($this); + } + + public function has($id) + { + return isset($this->services[$id]); + } + + public function set($id, $value) + { + if (!is_callable($value)) { + $value = static function () use ($value) { + return $value; + }; + } + + $this->services[$id] = $value; + } + }; + } } diff --git a/Tests/ListenersPriorityQueueTest.php b/Tests/ListenersPriorityQueueTest.php index 497b5994..5679d7b9 100644 --- a/Tests/ListenersPriorityQueueTest.php +++ b/Tests/ListenersPriorityQueueTest.php @@ -7,7 +7,6 @@ namespace Joomla\Event\Tests; use Joomla\Event\ListenersPriorityQueue; -use Joomla\Event\Tests\Stubs\EmptyListener; use PHPUnit\Framework\TestCase; /** @@ -15,165 +14,165 @@ */ class ListenersPriorityQueueTest extends TestCase { - /** - * Object being tested. - * - * @var ListenersPriorityQueue - */ - private $instance; - - /** - * Sets up the fixture. - * - * This method is called before a test is executed. - */ - protected function setUp(): void - { - $this->instance = new ListenersPriorityQueue; - } - - /** - * @testdox A listener can only be added a single time - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testAddExisting() - { - $listener = static function () {}; - - $this->assertSame($this->instance, $this->instance->add($listener, 5), 'The add method has a fluent interface'); - $this->assertSame($this->instance, $this->instance->add($listener, 0), 'The add method has a fluent interface'); - $this->assertTrue($this->instance->has($listener)); - $this->assertEquals(5, $this->instance->getPriority($listener)); - } - - /** - * @testdox The priority for a listener can be retrieved - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testGetPriorityNonExisting() - { - $listener = static function () {}; - - $this->assertSame($this->instance, $this->instance->add($listener, 0), 'The add method has a fluent interface'); - $this->assertSame(0, $this->instance->getPriority($listener)); - - $this->assertFalse( - $this->instance->getPriority( - static function () {}, - false - ), - 'If a listener is not registered, the default value should be returned' - ); - } - - /** - * @testdox A listener can be removed from the queue - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testAddAndRemove() - { - $listener1 = static function () {}; - - $listener2 = function () { - return false; - }; - - $this->assertSame($this->instance, $this->instance->add($listener1, 0), 'The add method has a fluent interface'); - $this->assertSame($this->instance, $this->instance->remove($listener2), 'The remove method has a fluent interface'); - $this->assertTrue($this->instance->has($listener1)); - $this->assertFalse($this->instance->has($listener2)); - - $this->assertSame($this->instance, $this->instance->add($listener2, 0), 'The add method has a fluent interface'); - $this->assertTrue($this->instance->has($listener2)); - - $this->assertSame($this->instance, $this->instance->remove($listener1), 'The remove method has a fluent interface'); - $this->assertFalse($this->instance->has($listener1)); - - $this->assertSame($this->instance, $this->instance->remove($listener2), 'The remove method has a fluent interface'); - $this->assertFalse($this->instance->has($listener2)); - } - - /** - * @testdox All listeners are retrieved from the queue in priority order - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testGetAll() - { - $this->assertEmpty($this->instance->getAll()); - - $listener1 = static function () {}; - - $listener2 = function () { - return false; - }; - - $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); - $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); - - $listeners = $this->instance->getAll(); - - $this->assertSame($listeners[0], $listener1); - $this->assertSame($listeners[1], $listener2); - } - - /** - * @testdox The queue can be iterated - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testGetIterator() - { - $listener1 = static function () {}; - - $listener2 = function () { - return false; - }; - - $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); - $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); - - $this->assertIsIterable($this->instance); - } - - /** - * @testdox The queue can be iterated multiple times - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testGetIteratorMultipleIterations() - { - $listener1 = static function () {}; - - $listener2 = function () { - return false; - }; - - $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); - $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); - - $this->assertEquals($this->instance->getIterator(), $this->instance->getIterator()); - } - - /** - * @testdox The queue can be counted - * - * @covers Joomla\Event\ListenersPriorityQueue - */ - public function testCount() - { - $listener1 = static function () {}; - - $listener2 = function () { - return false; - }; - - $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); - $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); - - $this->assertCount(2, $this->instance); - } + /** + * Object being tested. + * + * @var ListenersPriorityQueue + */ + private $instance; + + /** + * Sets up the fixture. + * + * This method is called before a test is executed. + */ + protected function setUp(): void + { + $this->instance = new ListenersPriorityQueue(); + } + + /** + * @testdox A listener can only be added a single time + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testAddExisting() + { + $listener = static function () {}; + + $this->assertSame($this->instance, $this->instance->add($listener, 5), 'The add method has a fluent interface'); + $this->assertSame($this->instance, $this->instance->add($listener, 0), 'The add method has a fluent interface'); + $this->assertTrue($this->instance->has($listener)); + $this->assertEquals(5, $this->instance->getPriority($listener)); + } + + /** + * @testdox The priority for a listener can be retrieved + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testGetPriorityNonExisting() + { + $listener = static function () {}; + + $this->assertSame($this->instance, $this->instance->add($listener, 0), 'The add method has a fluent interface'); + $this->assertSame(0, $this->instance->getPriority($listener)); + + $this->assertFalse( + $this->instance->getPriority( + static function () {}, + false + ), + 'If a listener is not registered, the default value should be returned' + ); + } + + /** + * @testdox A listener can be removed from the queue + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testAddAndRemove() + { + $listener1 = static function () {}; + + $listener2 = function () { + return false; + }; + + $this->assertSame($this->instance, $this->instance->add($listener1, 0), 'The add method has a fluent interface'); + $this->assertSame($this->instance, $this->instance->remove($listener2), 'The remove method has a fluent interface'); + $this->assertTrue($this->instance->has($listener1)); + $this->assertFalse($this->instance->has($listener2)); + + $this->assertSame($this->instance, $this->instance->add($listener2, 0), 'The add method has a fluent interface'); + $this->assertTrue($this->instance->has($listener2)); + + $this->assertSame($this->instance, $this->instance->remove($listener1), 'The remove method has a fluent interface'); + $this->assertFalse($this->instance->has($listener1)); + + $this->assertSame($this->instance, $this->instance->remove($listener2), 'The remove method has a fluent interface'); + $this->assertFalse($this->instance->has($listener2)); + } + + /** + * @testdox All listeners are retrieved from the queue in priority order + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testGetAll() + { + $this->assertEmpty($this->instance->getAll()); + + $listener1 = static function () {}; + + $listener2 = function () { + return false; + }; + + $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); + $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); + + $listeners = $this->instance->getAll(); + + $this->assertSame($listeners[0], $listener1); + $this->assertSame($listeners[1], $listener2); + } + + /** + * @testdox The queue can be iterated + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testGetIterator() + { + $listener1 = static function () {}; + + $listener2 = function () { + return false; + }; + + $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); + $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); + + $this->assertIsIterable($this->instance); + } + + /** + * @testdox The queue can be iterated multiple times + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testGetIteratorMultipleIterations() + { + $listener1 = static function () {}; + + $listener2 = function () { + return false; + }; + + $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); + $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); + + $this->assertEquals($this->instance->getIterator(), $this->instance->getIterator()); + } + + /** + * @testdox The queue can be counted + * + * @covers Joomla\Event\ListenersPriorityQueue + */ + public function testCount() + { + $listener1 = static function () {}; + + $listener2 = function () { + return false; + }; + + $this->assertSame($this->instance, $this->instance->add($listener1, 10), 'The add method has a fluent interface'); + $this->assertSame($this->instance, $this->instance->add($listener2, 3), 'The add method has a fluent interface'); + + $this->assertCount(2, $this->instance); + } } diff --git a/Tests/Stubs/FirstListener.php b/Tests/Stubs/FirstListener.php index a19c612a..e21bb5e4 100644 --- a/Tests/Stubs/FirstListener.php +++ b/Tests/Stubs/FirstListener.php @@ -16,30 +16,30 @@ */ class FirstListener { - /** - * Listen to `fooBar`. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function fooBar(Event $event) - { - } + /** + * Listen to `fooBar`. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function fooBar(Event $event) + { + } - /** - * Listen to onSomething. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function onSomething(Event $event) - { - $event->setArgument('listeners', array('first')); - } + /** + * Listen to onSomething. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function onSomething(Event $event) + { + $event->setArgument('listeners', ['first']); + } } diff --git a/Tests/Stubs/SecondListener.php b/Tests/Stubs/SecondListener.php index 9861d515..672d3698 100644 --- a/Tests/Stubs/SecondListener.php +++ b/Tests/Stubs/SecondListener.php @@ -16,21 +16,21 @@ */ class SecondListener { - /** - * Listen to onSomething. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function onSomething(Event $event) - { - $listeners = $event->getArgument('listeners'); + /** + * Listen to onSomething. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function onSomething(Event $event) + { + $listeners = $event->getArgument('listeners'); - $listeners[] = 'second'; + $listeners[] = 'second'; - $event->setArgument('listeners', $listeners); - } + $event->setArgument('listeners', $listeners); + } } diff --git a/Tests/Stubs/SomethingListener.php b/Tests/Stubs/SomethingListener.php index a7b9b896..a03a0844 100644 --- a/Tests/Stubs/SomethingListener.php +++ b/Tests/Stubs/SomethingListener.php @@ -17,68 +17,68 @@ */ class SomethingListener implements SubscriberInterface { - /** - * Listen to onBeforeSomething. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function onBeforeSomething(Event $event) - { - } + /** + * Listen to onBeforeSomething. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function onBeforeSomething(Event $event) + { + } - /** - * Listen to onSomething. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function onSomething(Event $event) - { - } + /** + * Listen to onSomething. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function onSomething(Event $event) + { + } - /** - * Listen to onAfterSomething. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function onAfterSomething(Event $event) - { - } + /** + * Listen to onAfterSomething. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function onAfterSomething(Event $event) + { + } - /** - * Returns an array of events this subscriber will listen to. - * - * The array keys are event names and the value can be: - * - * - The method name to call (priority defaults to 0) - * - An array composed of the method name to call and the priority - * - * For instance: - * - * * array('eventName' => 'methodName') - * * array('eventName' => array('methodName', $priority)) - * - * @return array - * - * @since 2.0.0-beta - */ - public static function getSubscribedEvents(): array - { - return [ - 'onBeforeSomething' => 'onBeforeSomething', - 'onSomething' => 'onSomething', - 'onAfterSomething' => ['onAfterSomething', Priority::HIGH] - ]; - } + /** + * Returns an array of events this subscriber will listen to. + * + * The array keys are event names and the value can be: + * + * - The method name to call (priority defaults to 0) + * - An array composed of the method name to call and the priority + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * + * @return array + * + * @since 2.0.0-beta + */ + public static function getSubscribedEvents(): array + { + return [ + 'onBeforeSomething' => 'onBeforeSomething', + 'onSomething' => 'onSomething', + 'onAfterSomething' => ['onAfterSomething', Priority::HIGH], + ]; + } } diff --git a/Tests/Stubs/ThirdListener.php b/Tests/Stubs/ThirdListener.php index 1e2b0426..3dc71936 100644 --- a/Tests/Stubs/ThirdListener.php +++ b/Tests/Stubs/ThirdListener.php @@ -16,21 +16,21 @@ */ class ThirdListener { - /** - * Listen to onSomething. - * - * @param Event $event The event. - * - * @return void - * - * @since 1.0 - */ - public function onSomething(Event $event) - { - $listeners = $event->getArgument('listeners'); + /** + * Listen to onSomething. + * + * @param Event $event The event. + * + * @return void + * + * @since 1.0 + */ + public function onSomething(Event $event) + { + $listeners = $event->getArgument('listeners'); - $listeners[] = 'third'; + $listeners[] = 'third'; - $event->setArgument('listeners', $listeners); - } + $event->setArgument('listeners', $listeners); + } }