Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\EventDispatcher\Tests; Chris@0: Chris@0: use PHPUnit\Framework\TestCase; Chris@0: use Symfony\Component\EventDispatcher\Event; Chris@0: use Symfony\Component\EventDispatcher\EventDispatcher; Chris@0: use Symfony\Component\EventDispatcher\EventSubscriberInterface; Chris@0: Chris@0: abstract class AbstractEventDispatcherTest extends TestCase Chris@0: { Chris@0: /* Some pseudo events */ Chris@0: const preFoo = 'pre.foo'; Chris@0: const postFoo = 'post.foo'; Chris@0: const preBar = 'pre.bar'; Chris@0: const postBar = 'post.bar'; Chris@0: Chris@0: /** Chris@0: * @var EventDispatcher Chris@0: */ Chris@0: private $dispatcher; Chris@0: Chris@0: private $listener; Chris@0: Chris@0: protected function setUp() Chris@0: { Chris@0: $this->dispatcher = $this->createEventDispatcher(); Chris@0: $this->listener = new TestEventListener(); Chris@0: } Chris@0: Chris@0: protected function tearDown() Chris@0: { Chris@0: $this->dispatcher = null; Chris@0: $this->listener = null; Chris@0: } Chris@0: Chris@0: abstract protected function createEventDispatcher(); Chris@0: Chris@0: public function testInitialState() Chris@0: { Chris@0: $this->assertEquals(array(), $this->dispatcher->getListeners()); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); Chris@0: } Chris@0: Chris@0: public function testAddListener() Chris@0: { Chris@0: $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); Chris@0: $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); Chris@0: $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); Chris@0: $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); Chris@0: $this->assertCount(2, $this->dispatcher->getListeners()); Chris@0: } Chris@0: Chris@0: public function testGetListenersSortsByPriority() Chris@0: { Chris@0: $listener1 = new TestEventListener(); Chris@0: $listener2 = new TestEventListener(); Chris@0: $listener3 = new TestEventListener(); Chris@0: $listener1->name = '1'; Chris@0: $listener2->name = '2'; Chris@0: $listener3->name = '3'; Chris@0: Chris@0: $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); Chris@0: $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); Chris@0: $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); Chris@0: Chris@0: $expected = array( Chris@0: array($listener2, 'preFoo'), Chris@0: array($listener3, 'preFoo'), Chris@0: array($listener1, 'preFoo'), Chris@0: ); Chris@0: Chris@0: $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); Chris@0: } Chris@0: Chris@0: public function testGetAllListenersSortsByPriority() Chris@0: { Chris@0: $listener1 = new TestEventListener(); Chris@0: $listener2 = new TestEventListener(); Chris@0: $listener3 = new TestEventListener(); Chris@0: $listener4 = new TestEventListener(); Chris@0: $listener5 = new TestEventListener(); Chris@0: $listener6 = new TestEventListener(); Chris@0: Chris@0: $this->dispatcher->addListener('pre.foo', $listener1, -10); Chris@0: $this->dispatcher->addListener('pre.foo', $listener2); Chris@0: $this->dispatcher->addListener('pre.foo', $listener3, 10); Chris@0: $this->dispatcher->addListener('post.foo', $listener4, -10); Chris@0: $this->dispatcher->addListener('post.foo', $listener5); Chris@0: $this->dispatcher->addListener('post.foo', $listener6, 10); Chris@0: Chris@0: $expected = array( Chris@0: 'pre.foo' => array($listener3, $listener2, $listener1), Chris@0: 'post.foo' => array($listener6, $listener5, $listener4), Chris@0: ); Chris@0: Chris@0: $this->assertSame($expected, $this->dispatcher->getListeners()); Chris@0: } Chris@0: Chris@0: public function testGetListenerPriority() Chris@0: { Chris@0: $listener1 = new TestEventListener(); Chris@0: $listener2 = new TestEventListener(); Chris@0: Chris@0: $this->dispatcher->addListener('pre.foo', $listener1, -10); Chris@0: $this->dispatcher->addListener('pre.foo', $listener2); Chris@0: Chris@0: $this->assertSame(-10, $this->dispatcher->getListenerPriority('pre.foo', $listener1)); Chris@0: $this->assertSame(0, $this->dispatcher->getListenerPriority('pre.foo', $listener2)); Chris@0: $this->assertNull($this->dispatcher->getListenerPriority('pre.bar', $listener2)); Chris@0: $this->assertNull($this->dispatcher->getListenerPriority('pre.foo', function () {})); Chris@0: } Chris@0: Chris@0: public function testDispatch() Chris@0: { Chris@0: $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); Chris@0: $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); Chris@0: $this->dispatcher->dispatch(self::preFoo); Chris@0: $this->assertTrue($this->listener->preFooInvoked); Chris@0: $this->assertFalse($this->listener->postFooInvoked); Chris@0: $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); Chris@0: $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); Chris@0: $event = new Event(); Chris@0: $return = $this->dispatcher->dispatch(self::preFoo, $event); Chris@0: $this->assertSame($event, $return); Chris@0: } Chris@0: Chris@0: public function testDispatchForClosure() Chris@0: { Chris@0: $invoked = 0; Chris@0: $listener = function () use (&$invoked) { Chris@0: ++$invoked; Chris@0: }; Chris@0: $this->dispatcher->addListener('pre.foo', $listener); Chris@0: $this->dispatcher->addListener('post.foo', $listener); Chris@0: $this->dispatcher->dispatch(self::preFoo); Chris@0: $this->assertEquals(1, $invoked); Chris@0: } Chris@0: Chris@0: public function testStopEventPropagation() Chris@0: { Chris@0: $otherListener = new TestEventListener(); Chris@0: Chris@0: // postFoo() stops the propagation, so only one listener should Chris@0: // be executed Chris@0: // Manually set priority to enforce $this->listener to be called first Chris@0: $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); Chris@0: $this->dispatcher->addListener('post.foo', array($otherListener, 'preFoo')); Chris@0: $this->dispatcher->dispatch(self::postFoo); Chris@0: $this->assertTrue($this->listener->postFooInvoked); Chris@0: $this->assertFalse($otherListener->postFooInvoked); Chris@0: } Chris@0: Chris@0: public function testDispatchByPriority() Chris@0: { Chris@0: $invoked = array(); Chris@0: $listener1 = function () use (&$invoked) { Chris@0: $invoked[] = '1'; Chris@0: }; Chris@0: $listener2 = function () use (&$invoked) { Chris@0: $invoked[] = '2'; Chris@0: }; Chris@0: $listener3 = function () use (&$invoked) { Chris@0: $invoked[] = '3'; Chris@0: }; Chris@0: $this->dispatcher->addListener('pre.foo', $listener1, -10); Chris@0: $this->dispatcher->addListener('pre.foo', $listener2); Chris@0: $this->dispatcher->addListener('pre.foo', $listener3, 10); Chris@0: $this->dispatcher->dispatch(self::preFoo); Chris@0: $this->assertEquals(array('3', '2', '1'), $invoked); Chris@0: } Chris@0: Chris@0: public function testRemoveListener() Chris@0: { Chris@0: $this->dispatcher->addListener('pre.bar', $this->listener); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); Chris@0: $this->dispatcher->removeListener('pre.bar', $this->listener); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); Chris@0: $this->dispatcher->removeListener('notExists', $this->listener); Chris@0: } Chris@0: Chris@0: public function testAddSubscriber() Chris@0: { Chris@0: $eventSubscriber = new TestEventSubscriber(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); Chris@0: } Chris@0: Chris@0: public function testAddSubscriberWithPriorities() Chris@0: { Chris@0: $eventSubscriber = new TestEventSubscriber(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: Chris@0: $eventSubscriber = new TestEventSubscriberWithPriorities(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: Chris@0: $listeners = $this->dispatcher->getListeners('pre.foo'); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertCount(2, $listeners); Chris@0: $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); Chris@0: } Chris@0: Chris@0: public function testAddSubscriberWithMultipleListeners() Chris@0: { Chris@0: $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: Chris@0: $listeners = $this->dispatcher->getListeners('pre.foo'); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertCount(2, $listeners); Chris@0: $this->assertEquals('preFoo2', $listeners[0][1]); Chris@0: } Chris@0: Chris@0: public function testRemoveSubscriber() Chris@0: { Chris@0: $eventSubscriber = new TestEventSubscriber(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); Chris@0: $this->dispatcher->removeSubscriber($eventSubscriber); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); Chris@0: } Chris@0: Chris@0: public function testRemoveSubscriberWithPriorities() Chris@0: { Chris@0: $eventSubscriber = new TestEventSubscriberWithPriorities(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->dispatcher->removeSubscriber($eventSubscriber); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); Chris@0: } Chris@0: Chris@0: public function testRemoveSubscriberWithMultipleListeners() Chris@0: { Chris@0: $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); Chris@0: $this->dispatcher->addSubscriber($eventSubscriber); Chris@0: $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); Chris@0: $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); Chris@0: $this->dispatcher->removeSubscriber($eventSubscriber); Chris@0: $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); Chris@0: } Chris@0: Chris@0: public function testEventReceivesTheDispatcherInstanceAsArgument() Chris@0: { Chris@0: $listener = new TestWithDispatcher(); Chris@0: $this->dispatcher->addListener('test', array($listener, 'foo')); Chris@0: $this->assertNull($listener->name); Chris@0: $this->assertNull($listener->dispatcher); Chris@0: $this->dispatcher->dispatch('test'); Chris@0: $this->assertEquals('test', $listener->name); Chris@0: $this->assertSame($this->dispatcher, $listener->dispatcher); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @see https://bugs.php.net/bug.php?id=62976 Chris@0: * Chris@0: * This bug affects: Chris@0: * - The PHP 5.3 branch for versions < 5.3.18 Chris@0: * - The PHP 5.4 branch for versions < 5.4.8 Chris@0: * - The PHP 5.5 branch is not affected Chris@0: */ Chris@0: public function testWorkaroundForPhpBug62976() Chris@0: { Chris@0: $dispatcher = $this->createEventDispatcher(); Chris@0: $dispatcher->addListener('bug.62976', new CallableClass()); Chris@0: $dispatcher->removeListener('bug.62976', function () {}); Chris@0: $this->assertTrue($dispatcher->hasListeners('bug.62976')); Chris@0: } Chris@0: Chris@0: public function testHasListenersWhenAddedCallbackListenerIsRemoved() Chris@0: { Chris@0: $listener = function () {}; Chris@0: $this->dispatcher->addListener('foo', $listener); Chris@0: $this->dispatcher->removeListener('foo', $listener); Chris@0: $this->assertFalse($this->dispatcher->hasListeners()); Chris@0: } Chris@0: Chris@0: public function testGetListenersWhenAddedCallbackListenerIsRemoved() Chris@0: { Chris@0: $listener = function () {}; Chris@0: $this->dispatcher->addListener('foo', $listener); Chris@0: $this->dispatcher->removeListener('foo', $listener); Chris@0: $this->assertSame(array(), $this->dispatcher->getListeners()); Chris@0: } Chris@0: Chris@0: public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() Chris@0: { Chris@0: $this->assertFalse($this->dispatcher->hasListeners('foo')); Chris@0: $this->assertFalse($this->dispatcher->hasListeners()); Chris@0: } Chris@0: } Chris@0: Chris@0: class CallableClass Chris@0: { Chris@0: public function __invoke() Chris@0: { Chris@0: } Chris@0: } Chris@0: Chris@0: class TestEventListener Chris@0: { Chris@0: public $preFooInvoked = false; Chris@0: public $postFooInvoked = false; Chris@0: Chris@0: /* Listener methods */ Chris@0: Chris@0: public function preFoo(Event $e) Chris@0: { Chris@0: $this->preFooInvoked = true; Chris@0: } Chris@0: Chris@0: public function postFoo(Event $e) Chris@0: { Chris@0: $this->postFooInvoked = true; Chris@0: Chris@0: $e->stopPropagation(); Chris@0: } Chris@0: } Chris@0: Chris@0: class TestWithDispatcher Chris@0: { Chris@0: public $name; Chris@0: public $dispatcher; Chris@0: Chris@0: public function foo(Event $e, $name, $dispatcher) Chris@0: { Chris@0: $this->name = $name; Chris@0: $this->dispatcher = $dispatcher; Chris@0: } Chris@0: } Chris@0: Chris@0: class TestEventSubscriber implements EventSubscriberInterface Chris@0: { Chris@0: public static function getSubscribedEvents() Chris@0: { Chris@0: return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); Chris@0: } Chris@0: } Chris@0: Chris@0: class TestEventSubscriberWithPriorities implements EventSubscriberInterface Chris@0: { Chris@0: public static function getSubscribedEvents() Chris@0: { Chris@0: return array( Chris@0: 'pre.foo' => array('preFoo', 10), Chris@0: 'post.foo' => array('postFoo'), Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface Chris@0: { Chris@0: public static function getSubscribedEvents() Chris@0: { Chris@0: return array('pre.foo' => array( Chris@0: array('preFoo1'), Chris@0: array('preFoo2', 10), Chris@0: )); Chris@0: } Chris@0: }