4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\EventDispatcher\Tests\Debug;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
16 use Symfony\Component\EventDispatcher\Debug\WrappedListener;
17 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19 use Symfony\Component\EventDispatcher\EventDispatcher;
20 use Symfony\Component\EventDispatcher\Event;
21 use Symfony\Component\Stopwatch\Stopwatch;
23 class TraceableEventDispatcherTest extends TestCase
25 public function testAddRemoveListener()
27 $dispatcher = new EventDispatcher();
28 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
30 $tdispatcher->addListener('foo', $listener = function () {});
31 $listeners = $dispatcher->getListeners('foo');
32 $this->assertCount(1, $listeners);
33 $this->assertSame($listener, $listeners[0]);
35 $tdispatcher->removeListener('foo', $listener);
36 $this->assertCount(0, $dispatcher->getListeners('foo'));
39 public function testGetListeners()
41 $dispatcher = new EventDispatcher();
42 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
44 $tdispatcher->addListener('foo', $listener = function () {});
45 $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo'));
48 public function testHasListeners()
50 $dispatcher = new EventDispatcher();
51 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
53 $this->assertFalse($dispatcher->hasListeners('foo'));
54 $this->assertFalse($tdispatcher->hasListeners('foo'));
56 $tdispatcher->addListener('foo', $listener = function () {});
57 $this->assertTrue($dispatcher->hasListeners('foo'));
58 $this->assertTrue($tdispatcher->hasListeners('foo'));
61 public function testGetListenerPriority()
63 $dispatcher = new EventDispatcher();
64 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
66 $tdispatcher->addListener('foo', function () {}, 123);
68 $listeners = $dispatcher->getListeners('foo');
69 $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
71 // Verify that priority is preserved when listener is removed and re-added
72 // in preProcess() and postProcess().
73 $tdispatcher->dispatch('foo', new Event());
74 $listeners = $dispatcher->getListeners('foo');
75 $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
78 public function testGetListenerPriorityReturnsZeroWhenWrappedMethodDoesNotExist()
80 $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
81 $traceableEventDispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
82 $traceableEventDispatcher->addListener('foo', function () {}, 123);
83 $listeners = $traceableEventDispatcher->getListeners('foo');
85 $this->assertSame(0, $traceableEventDispatcher->getListenerPriority('foo', $listeners[0]));
88 public function testAddRemoveSubscriber()
90 $dispatcher = new EventDispatcher();
91 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
93 $subscriber = new EventSubscriber();
95 $tdispatcher->addSubscriber($subscriber);
96 $listeners = $dispatcher->getListeners('foo');
97 $this->assertCount(1, $listeners);
98 $this->assertSame(array($subscriber, 'call'), $listeners[0]);
100 $tdispatcher->removeSubscriber($subscriber);
101 $this->assertCount(0, $dispatcher->getListeners('foo'));
105 * @dataProvider isWrappedDataProvider
107 * @param bool $isWrapped
109 public function testGetCalledListeners($isWrapped)
111 $dispatcher = new EventDispatcher();
112 $stopWatch = new Stopwatch();
113 $tdispatcher = new TraceableEventDispatcher($dispatcher, $stopWatch);
115 $listener = function () {};
117 $listener = new WrappedListener($listener, 'foo', $stopWatch, $dispatcher);
120 $tdispatcher->addListener('foo', $listener, 5);
122 $this->assertEquals(array(), $tdispatcher->getCalledListeners());
123 $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => 5)), $tdispatcher->getNotCalledListeners());
125 $tdispatcher->dispatch('foo');
127 $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => 5)), $tdispatcher->getCalledListeners());
128 $this->assertEquals(array(), $tdispatcher->getNotCalledListeners());
131 public function isWrappedDataProvider()
139 public function testGetCalledListenersNested()
142 $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
143 $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) {
144 $tdispatcher = $dispatcher;
145 $dispatcher->dispatch('bar');
147 $dispatcher->addListener('bar', function (Event $event) {});
148 $dispatcher->dispatch('foo');
149 $this->assertSame($dispatcher, $tdispatcher);
150 $this->assertCount(2, $dispatcher->getCalledListeners());
153 public function testLogger()
155 $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
157 $dispatcher = new EventDispatcher();
158 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
159 $tdispatcher->addListener('foo', $listener1 = function () {});
160 $tdispatcher->addListener('foo', $listener2 = function () {});
162 $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".');
163 $logger->expects($this->at(1))->method('debug')->with('Notified event "foo" to listener "closure".');
165 $tdispatcher->dispatch('foo');
168 public function testLoggerWithStoppedEvent()
170 $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
172 $dispatcher = new EventDispatcher();
173 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
174 $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); });
175 $tdispatcher->addListener('foo', $listener2 = function () {});
177 $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".');
178 $logger->expects($this->at(1))->method('debug')->with('Listener "closure" stopped propagation of the event "foo".');
179 $logger->expects($this->at(2))->method('debug')->with('Listener "closure" was not called for event "foo".');
181 $tdispatcher->dispatch('foo');
184 public function testDispatchCallListeners()
188 $dispatcher = new EventDispatcher();
189 $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
190 $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10);
191 $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20);
193 $tdispatcher->dispatch('foo');
195 $this->assertSame(array('foo2', 'foo1'), $called);
198 public function testDispatchNested()
200 $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
202 $dispatchedEvents = 0;
203 $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) {
206 $dispatcher->dispatch('foo');
209 $dispatcher->addListener('foo', function () use (&$dispatchedEvents) {
213 $dispatcher->dispatch('foo');
215 $this->assertSame(2, $dispatchedEvents);
218 public function testDispatchReusedEventNested()
221 $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
222 $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) {
223 $dispatcher->dispatch('bar', $e);
225 $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) {
229 $this->assertFalse($nestedCall);
230 $dispatcher->dispatch('foo');
231 $this->assertTrue($nestedCall);
234 public function testListenerCanRemoveItselfWhenExecuted()
236 $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
237 $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) {
238 $dispatcher->removeListener('foo', $listener1);
240 $eventDispatcher->addListener('foo', $listener1);
241 $eventDispatcher->addListener('foo', function () {});
242 $eventDispatcher->dispatch('foo');
244 $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
248 class EventSubscriber implements EventSubscriberInterface
250 public static function getSubscribedEvents()
252 return array('foo' => 'call');