TraceableEventDispatcherTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\EventDispatcher\Tests\Debug;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
  13. use Symfony\Component\EventDispatcher\Event;
  14. use Symfony\Component\EventDispatcher\EventDispatcher;
  15. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  16. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  17. use Symfony\Component\Stopwatch\Stopwatch;
  18. class TraceableEventDispatcherTest extends TestCase
  19. {
  20. public function testAddRemoveListener()
  21. {
  22. $dispatcher = new EventDispatcher();
  23. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
  24. $tdispatcher->addListener('foo', $listener = function () {});
  25. $listeners = $dispatcher->getListeners('foo');
  26. $this->assertCount(1, $listeners);
  27. $this->assertSame($listener, $listeners[0]);
  28. $tdispatcher->removeListener('foo', $listener);
  29. $this->assertCount(0, $dispatcher->getListeners('foo'));
  30. }
  31. public function testGetListeners()
  32. {
  33. $dispatcher = new EventDispatcher();
  34. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
  35. $tdispatcher->addListener('foo', $listener = function () {});
  36. $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo'));
  37. }
  38. public function testHasListeners()
  39. {
  40. $dispatcher = new EventDispatcher();
  41. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
  42. $this->assertFalse($dispatcher->hasListeners('foo'));
  43. $this->assertFalse($tdispatcher->hasListeners('foo'));
  44. $tdispatcher->addListener('foo', $listener = function () {});
  45. $this->assertTrue($dispatcher->hasListeners('foo'));
  46. $this->assertTrue($tdispatcher->hasListeners('foo'));
  47. }
  48. public function testGetListenerPriority()
  49. {
  50. $dispatcher = new EventDispatcher();
  51. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
  52. $tdispatcher->addListener('foo', function () {}, 123);
  53. $listeners = $dispatcher->getListeners('foo');
  54. $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
  55. // Verify that priority is preserved when listener is removed and re-added
  56. // in preProcess() and postProcess().
  57. $tdispatcher->dispatch('foo', new Event());
  58. $listeners = $dispatcher->getListeners('foo');
  59. $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
  60. }
  61. public function testGetListenerPriorityWhileDispatching()
  62. {
  63. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  64. $priorityWhileDispatching = null;
  65. $listener = function () use ($tdispatcher, &$priorityWhileDispatching, &$listener) {
  66. $priorityWhileDispatching = $tdispatcher->getListenerPriority('bar', $listener);
  67. };
  68. $tdispatcher->addListener('bar', $listener, 5);
  69. $tdispatcher->dispatch('bar');
  70. $this->assertSame(5, $priorityWhileDispatching);
  71. }
  72. public function testAddRemoveSubscriber()
  73. {
  74. $dispatcher = new EventDispatcher();
  75. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
  76. $subscriber = new EventSubscriber();
  77. $tdispatcher->addSubscriber($subscriber);
  78. $listeners = $dispatcher->getListeners('foo');
  79. $this->assertCount(1, $listeners);
  80. $this->assertSame([$subscriber, 'call'], $listeners[0]);
  81. $tdispatcher->removeSubscriber($subscriber);
  82. $this->assertCount(0, $dispatcher->getListeners('foo'));
  83. }
  84. public function testGetCalledListeners()
  85. {
  86. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  87. $tdispatcher->addListener('foo', function () {}, 5);
  88. $listeners = $tdispatcher->getNotCalledListeners();
  89. $this->assertArrayHasKey('stub', $listeners[0]);
  90. unset($listeners[0]['stub']);
  91. $this->assertEquals([], $tdispatcher->getCalledListeners());
  92. $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners);
  93. $tdispatcher->dispatch('foo');
  94. $listeners = $tdispatcher->getCalledListeners();
  95. $this->assertArrayHasKey('stub', $listeners[0]);
  96. unset($listeners[0]['stub']);
  97. $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners);
  98. $this->assertEquals([], $tdispatcher->getNotCalledListeners());
  99. }
  100. public function testClearCalledListeners()
  101. {
  102. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  103. $tdispatcher->addListener('foo', function () {}, 5);
  104. $tdispatcher->dispatch('foo');
  105. $tdispatcher->reset();
  106. $listeners = $tdispatcher->getNotCalledListeners();
  107. $this->assertArrayHasKey('stub', $listeners[0]);
  108. unset($listeners[0]['stub']);
  109. $this->assertEquals([], $tdispatcher->getCalledListeners());
  110. $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners);
  111. }
  112. public function testDispatchAfterReset()
  113. {
  114. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  115. $tdispatcher->addListener('foo', function () {}, 5);
  116. $tdispatcher->reset();
  117. $tdispatcher->dispatch('foo');
  118. $listeners = $tdispatcher->getCalledListeners();
  119. $this->assertArrayHasKey('stub', $listeners[0]);
  120. }
  121. public function testGetCalledListenersNested()
  122. {
  123. $tdispatcher = null;
  124. $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  125. $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) {
  126. $tdispatcher = $dispatcher;
  127. $dispatcher->dispatch('bar');
  128. });
  129. $dispatcher->addListener('bar', function (Event $event) {});
  130. $dispatcher->dispatch('foo');
  131. $this->assertSame($dispatcher, $tdispatcher);
  132. $this->assertCount(2, $dispatcher->getCalledListeners());
  133. }
  134. public function testItReturnsNoOrphanedEventsWhenCreated()
  135. {
  136. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  137. $events = $tdispatcher->getOrphanedEvents();
  138. $this->assertEmpty($events);
  139. }
  140. public function testItReturnsOrphanedEventsAfterDispatch()
  141. {
  142. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  143. $tdispatcher->dispatch('foo');
  144. $events = $tdispatcher->getOrphanedEvents();
  145. $this->assertCount(1, $events);
  146. $this->assertEquals(['foo'], $events);
  147. }
  148. public function testItDoesNotReturnHandledEvents()
  149. {
  150. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  151. $tdispatcher->addListener('foo', function () {});
  152. $tdispatcher->dispatch('foo');
  153. $events = $tdispatcher->getOrphanedEvents();
  154. $this->assertEmpty($events);
  155. }
  156. public function testLogger()
  157. {
  158. $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
  159. $dispatcher = new EventDispatcher();
  160. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
  161. $tdispatcher->addListener('foo', $listener1 = function () {});
  162. $tdispatcher->addListener('foo', $listener2 = function () {});
  163. $logger->expects($this->at(0))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']);
  164. $logger->expects($this->at(1))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']);
  165. $tdispatcher->dispatch('foo');
  166. }
  167. public function testLoggerWithStoppedEvent()
  168. {
  169. $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
  170. $dispatcher = new EventDispatcher();
  171. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
  172. $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); });
  173. $tdispatcher->addListener('foo', $listener2 = function () {});
  174. $logger->expects($this->at(0))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']);
  175. $logger->expects($this->at(1))->method('debug')->with('Listener "{listener}" stopped propagation of the event "{event}".', ['event' => 'foo', 'listener' => 'closure']);
  176. $logger->expects($this->at(2))->method('debug')->with('Listener "{listener}" was not called for event "{event}".', ['event' => 'foo', 'listener' => 'closure']);
  177. $tdispatcher->dispatch('foo');
  178. }
  179. public function testDispatchCallListeners()
  180. {
  181. $called = [];
  182. $dispatcher = new EventDispatcher();
  183. $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
  184. $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10);
  185. $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20);
  186. $tdispatcher->dispatch('foo');
  187. $this->assertSame(['foo2', 'foo1'], $called);
  188. }
  189. public function testDispatchNested()
  190. {
  191. $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  192. $loop = 1;
  193. $dispatchedEvents = 0;
  194. $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) {
  195. ++$loop;
  196. if (2 == $loop) {
  197. $dispatcher->dispatch('foo');
  198. }
  199. });
  200. $dispatcher->addListener('foo', function () use (&$dispatchedEvents) {
  201. ++$dispatchedEvents;
  202. });
  203. $dispatcher->dispatch('foo');
  204. $this->assertSame(2, $dispatchedEvents);
  205. }
  206. public function testDispatchReusedEventNested()
  207. {
  208. $nestedCall = false;
  209. $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  210. $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) {
  211. $dispatcher->dispatch('bar', $e);
  212. });
  213. $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) {
  214. $nestedCall = true;
  215. });
  216. $this->assertFalse($nestedCall);
  217. $dispatcher->dispatch('foo');
  218. $this->assertTrue($nestedCall);
  219. }
  220. public function testListenerCanRemoveItselfWhenExecuted()
  221. {
  222. $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  223. $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) {
  224. $dispatcher->removeListener('foo', $listener1);
  225. };
  226. $eventDispatcher->addListener('foo', $listener1);
  227. $eventDispatcher->addListener('foo', function () {});
  228. $eventDispatcher->dispatch('foo');
  229. $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
  230. }
  231. public function testClearOrphanedEvents()
  232. {
  233. $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
  234. $tdispatcher->dispatch('foo');
  235. $events = $tdispatcher->getOrphanedEvents();
  236. $this->assertCount(1, $events);
  237. $tdispatcher->reset();
  238. $events = $tdispatcher->getOrphanedEvents();
  239. $this->assertCount(0, $events);
  240. }
  241. }
  242. class EventSubscriber implements EventSubscriberInterface
  243. {
  244. public static function getSubscribedEvents()
  245. {
  246. return ['foo' => 'call'];
  247. }
  248. }