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\Debug; Chris@0: Chris@0: use PHPUnit\Framework\TestCase; Chris@0: use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; Chris@17: use Symfony\Component\EventDispatcher\Event; Chris@17: use Symfony\Component\EventDispatcher\EventDispatcher; Chris@0: use Symfony\Component\EventDispatcher\EventDispatcherInterface; Chris@0: use Symfony\Component\EventDispatcher\EventSubscriberInterface; Chris@0: use Symfony\Component\Stopwatch\Stopwatch; Chris@0: Chris@0: class TraceableEventDispatcherTest extends TestCase Chris@0: { Chris@0: public function testAddRemoveListener() Chris@0: { Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); Chris@0: Chris@0: $tdispatcher->addListener('foo', $listener = function () {}); Chris@0: $listeners = $dispatcher->getListeners('foo'); Chris@0: $this->assertCount(1, $listeners); Chris@0: $this->assertSame($listener, $listeners[0]); Chris@0: Chris@0: $tdispatcher->removeListener('foo', $listener); Chris@0: $this->assertCount(0, $dispatcher->getListeners('foo')); Chris@0: } Chris@0: Chris@0: public function testGetListeners() Chris@0: { Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); Chris@0: Chris@0: $tdispatcher->addListener('foo', $listener = function () {}); Chris@0: $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); Chris@0: } Chris@0: Chris@0: public function testHasListeners() Chris@0: { Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); Chris@0: Chris@0: $this->assertFalse($dispatcher->hasListeners('foo')); Chris@0: $this->assertFalse($tdispatcher->hasListeners('foo')); Chris@0: Chris@0: $tdispatcher->addListener('foo', $listener = function () {}); Chris@0: $this->assertTrue($dispatcher->hasListeners('foo')); Chris@0: $this->assertTrue($tdispatcher->hasListeners('foo')); Chris@0: } Chris@0: Chris@0: public function testGetListenerPriority() Chris@0: { Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); Chris@0: Chris@0: $tdispatcher->addListener('foo', function () {}, 123); Chris@0: Chris@0: $listeners = $dispatcher->getListeners('foo'); Chris@0: $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0])); Chris@0: Chris@0: // Verify that priority is preserved when listener is removed and re-added Chris@0: // in preProcess() and postProcess(). Chris@0: $tdispatcher->dispatch('foo', new Event()); Chris@0: $listeners = $dispatcher->getListeners('foo'); Chris@0: $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0])); Chris@0: } Chris@0: Chris@0: public function testGetListenerPriorityWhileDispatching() Chris@0: { Chris@0: $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@0: $priorityWhileDispatching = null; Chris@0: Chris@0: $listener = function () use ($tdispatcher, &$priorityWhileDispatching, &$listener) { Chris@0: $priorityWhileDispatching = $tdispatcher->getListenerPriority('bar', $listener); Chris@0: }; Chris@0: Chris@0: $tdispatcher->addListener('bar', $listener, 5); Chris@0: $tdispatcher->dispatch('bar'); Chris@0: $this->assertSame(5, $priorityWhileDispatching); Chris@0: } Chris@0: Chris@0: public function testAddRemoveSubscriber() Chris@0: { Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); Chris@0: Chris@0: $subscriber = new EventSubscriber(); Chris@0: Chris@0: $tdispatcher->addSubscriber($subscriber); Chris@0: $listeners = $dispatcher->getListeners('foo'); Chris@0: $this->assertCount(1, $listeners); Chris@17: $this->assertSame([$subscriber, 'call'], $listeners[0]); Chris@0: Chris@0: $tdispatcher->removeSubscriber($subscriber); Chris@0: $this->assertCount(0, $dispatcher->getListeners('foo')); Chris@0: } Chris@0: Chris@12: public function testGetCalledListeners() Chris@0: { Chris@12: $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@12: $tdispatcher->addListener('foo', function () {}, 5); Chris@0: Chris@0: $listeners = $tdispatcher->getNotCalledListeners(); Chris@17: $this->assertArrayHasKey('stub', $listeners[0]); Chris@17: unset($listeners[0]['stub']); Chris@17: $this->assertEquals([], $tdispatcher->getCalledListeners()); Chris@17: $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); Chris@0: Chris@0: $tdispatcher->dispatch('foo'); Chris@0: Chris@0: $listeners = $tdispatcher->getCalledListeners(); Chris@17: $this->assertArrayHasKey('stub', $listeners[0]); Chris@17: unset($listeners[0]['stub']); Chris@17: $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); Chris@17: $this->assertEquals([], $tdispatcher->getNotCalledListeners()); Chris@0: } Chris@0: Chris@14: public function testClearCalledListeners() Chris@14: { Chris@14: $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@14: $tdispatcher->addListener('foo', function () {}, 5); Chris@14: Chris@14: $tdispatcher->dispatch('foo'); Chris@14: $tdispatcher->reset(); Chris@14: Chris@14: $listeners = $tdispatcher->getNotCalledListeners(); Chris@17: $this->assertArrayHasKey('stub', $listeners[0]); Chris@17: unset($listeners[0]['stub']); Chris@17: $this->assertEquals([], $tdispatcher->getCalledListeners()); Chris@17: $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); Chris@17: } Chris@17: Chris@17: public function testDispatchAfterReset() Chris@17: { Chris@17: $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@17: $tdispatcher->addListener('foo', function () {}, 5); Chris@17: Chris@17: $tdispatcher->reset(); Chris@17: $tdispatcher->dispatch('foo'); Chris@17: Chris@17: $listeners = $tdispatcher->getCalledListeners(); Chris@17: $this->assertArrayHasKey('stub', $listeners[0]); Chris@14: } Chris@14: Chris@0: public function testGetCalledListenersNested() Chris@0: { Chris@0: $tdispatcher = null; Chris@0: $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@0: $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) { Chris@0: $tdispatcher = $dispatcher; Chris@0: $dispatcher->dispatch('bar'); Chris@0: }); Chris@0: $dispatcher->addListener('bar', function (Event $event) {}); Chris@0: $dispatcher->dispatch('foo'); Chris@0: $this->assertSame($dispatcher, $tdispatcher); Chris@0: $this->assertCount(2, $dispatcher->getCalledListeners()); Chris@0: } Chris@0: Chris@0: public function testLogger() Chris@0: { Chris@0: $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); Chris@0: Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); Chris@0: $tdispatcher->addListener('foo', $listener1 = function () {}); Chris@0: $tdispatcher->addListener('foo', $listener2 = function () {}); Chris@0: Chris@17: $logger->expects($this->at(0))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']); Chris@17: $logger->expects($this->at(1))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']); Chris@0: Chris@0: $tdispatcher->dispatch('foo'); Chris@0: } Chris@0: Chris@0: public function testLoggerWithStoppedEvent() Chris@0: { Chris@0: $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); Chris@0: Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); Chris@0: $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); Chris@0: $tdispatcher->addListener('foo', $listener2 = function () {}); Chris@0: Chris@17: $logger->expects($this->at(0))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']); Chris@17: $logger->expects($this->at(1))->method('debug')->with('Listener "{listener}" stopped propagation of the event "{event}".', ['event' => 'foo', 'listener' => 'closure']); Chris@17: $logger->expects($this->at(2))->method('debug')->with('Listener "{listener}" was not called for event "{event}".', ['event' => 'foo', 'listener' => 'closure']); Chris@0: Chris@0: $tdispatcher->dispatch('foo'); Chris@0: } Chris@0: Chris@0: public function testDispatchCallListeners() Chris@0: { Chris@17: $called = []; Chris@0: Chris@0: $dispatcher = new EventDispatcher(); Chris@0: $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); Chris@0: $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10); Chris@0: $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20); Chris@0: Chris@0: $tdispatcher->dispatch('foo'); Chris@0: Chris@17: $this->assertSame(['foo2', 'foo1'], $called); Chris@0: } Chris@0: Chris@0: public function testDispatchNested() Chris@0: { Chris@0: $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@0: $loop = 1; Chris@0: $dispatchedEvents = 0; Chris@0: $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) { Chris@0: ++$loop; Chris@0: if (2 == $loop) { Chris@0: $dispatcher->dispatch('foo'); Chris@0: } Chris@0: }); Chris@0: $dispatcher->addListener('foo', function () use (&$dispatchedEvents) { Chris@0: ++$dispatchedEvents; Chris@0: }); Chris@0: Chris@0: $dispatcher->dispatch('foo'); Chris@0: Chris@0: $this->assertSame(2, $dispatchedEvents); Chris@0: } Chris@0: Chris@0: public function testDispatchReusedEventNested() Chris@0: { Chris@0: $nestedCall = false; Chris@0: $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@0: $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) { Chris@0: $dispatcher->dispatch('bar', $e); Chris@0: }); Chris@0: $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) { Chris@0: $nestedCall = true; Chris@0: }); Chris@0: Chris@0: $this->assertFalse($nestedCall); Chris@0: $dispatcher->dispatch('foo'); Chris@0: $this->assertTrue($nestedCall); Chris@0: } Chris@0: Chris@0: public function testListenerCanRemoveItselfWhenExecuted() Chris@0: { Chris@0: $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); Chris@0: $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) { Chris@0: $dispatcher->removeListener('foo', $listener1); Chris@0: }; Chris@0: $eventDispatcher->addListener('foo', $listener1); Chris@0: $eventDispatcher->addListener('foo', function () {}); Chris@0: $eventDispatcher->dispatch('foo'); Chris@0: Chris@0: $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); Chris@0: } Chris@0: } Chris@0: Chris@0: class EventSubscriber implements EventSubscriberInterface Chris@0: { Chris@0: public static function getSubscribedEvents() Chris@0: { Chris@17: return ['foo' => 'call']; Chris@0: } Chris@0: }