EventEmitterTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of Evenement.
  4. *
  5. * (c) Igor Wiedler <igor@wiedler.ch>
  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 Evenement\Tests;
  11. use Evenement\EventEmitter;
  12. use InvalidArgumentException;
  13. use PHPUnit\Framework\TestCase;
  14. class EventEmitterTest extends TestCase
  15. {
  16. private $emitter;
  17. public function setUp()
  18. {
  19. $this->emitter = new EventEmitter();
  20. }
  21. public function testAddListenerWithLambda()
  22. {
  23. $this->emitter->on('foo', function () {});
  24. }
  25. public function testAddListenerWithMethod()
  26. {
  27. $listener = new Listener();
  28. $this->emitter->on('foo', [$listener, 'onFoo']);
  29. }
  30. public function testAddListenerWithStaticMethod()
  31. {
  32. $this->emitter->on('bar', ['Evenement\Tests\Listener', 'onBar']);
  33. }
  34. public function testAddListenerWithInvalidListener()
  35. {
  36. try {
  37. $this->emitter->on('foo', 'not a callable');
  38. $this->fail();
  39. } catch (\Exception $e) {
  40. } catch (\TypeError $e) {
  41. }
  42. }
  43. public function testOnce()
  44. {
  45. $listenerCalled = 0;
  46. $this->emitter->once('foo', function () use (&$listenerCalled) {
  47. $listenerCalled++;
  48. });
  49. $this->assertSame(0, $listenerCalled);
  50. $this->emitter->emit('foo');
  51. $this->assertSame(1, $listenerCalled);
  52. $this->emitter->emit('foo');
  53. $this->assertSame(1, $listenerCalled);
  54. }
  55. public function testOnceWithArguments()
  56. {
  57. $capturedArgs = [];
  58. $this->emitter->once('foo', function ($a, $b) use (&$capturedArgs) {
  59. $capturedArgs = array($a, $b);
  60. });
  61. $this->emitter->emit('foo', array('a', 'b'));
  62. $this->assertSame(array('a', 'b'), $capturedArgs);
  63. }
  64. public function testEmitWithoutArguments()
  65. {
  66. $listenerCalled = false;
  67. $this->emitter->on('foo', function () use (&$listenerCalled) {
  68. $listenerCalled = true;
  69. });
  70. $this->assertSame(false, $listenerCalled);
  71. $this->emitter->emit('foo');
  72. $this->assertSame(true, $listenerCalled);
  73. }
  74. public function testEmitWithOneArgument()
  75. {
  76. $test = $this;
  77. $listenerCalled = false;
  78. $this->emitter->on('foo', function ($value) use (&$listenerCalled, $test) {
  79. $listenerCalled = true;
  80. $test->assertSame('bar', $value);
  81. });
  82. $this->assertSame(false, $listenerCalled);
  83. $this->emitter->emit('foo', ['bar']);
  84. $this->assertSame(true, $listenerCalled);
  85. }
  86. public function testEmitWithTwoArguments()
  87. {
  88. $test = $this;
  89. $listenerCalled = false;
  90. $this->emitter->on('foo', function ($arg1, $arg2) use (&$listenerCalled, $test) {
  91. $listenerCalled = true;
  92. $test->assertSame('bar', $arg1);
  93. $test->assertSame('baz', $arg2);
  94. });
  95. $this->assertSame(false, $listenerCalled);
  96. $this->emitter->emit('foo', ['bar', 'baz']);
  97. $this->assertSame(true, $listenerCalled);
  98. }
  99. public function testEmitWithNoListeners()
  100. {
  101. $this->emitter->emit('foo');
  102. $this->emitter->emit('foo', ['bar']);
  103. $this->emitter->emit('foo', ['bar', 'baz']);
  104. }
  105. public function testEmitWithTwoListeners()
  106. {
  107. $listenersCalled = 0;
  108. $this->emitter->on('foo', function () use (&$listenersCalled) {
  109. $listenersCalled++;
  110. });
  111. $this->emitter->on('foo', function () use (&$listenersCalled) {
  112. $listenersCalled++;
  113. });
  114. $this->assertSame(0, $listenersCalled);
  115. $this->emitter->emit('foo');
  116. $this->assertSame(2, $listenersCalled);
  117. }
  118. public function testRemoveListenerMatching()
  119. {
  120. $listenersCalled = 0;
  121. $listener = function () use (&$listenersCalled) {
  122. $listenersCalled++;
  123. };
  124. $this->emitter->on('foo', $listener);
  125. $this->emitter->removeListener('foo', $listener);
  126. $this->assertSame(0, $listenersCalled);
  127. $this->emitter->emit('foo');
  128. $this->assertSame(0, $listenersCalled);
  129. }
  130. public function testRemoveListenerNotMatching()
  131. {
  132. $listenersCalled = 0;
  133. $listener = function () use (&$listenersCalled) {
  134. $listenersCalled++;
  135. };
  136. $this->emitter->on('foo', $listener);
  137. $this->emitter->removeListener('bar', $listener);
  138. $this->assertSame(0, $listenersCalled);
  139. $this->emitter->emit('foo');
  140. $this->assertSame(1, $listenersCalled);
  141. }
  142. public function testRemoveAllListenersMatching()
  143. {
  144. $listenersCalled = 0;
  145. $this->emitter->on('foo', function () use (&$listenersCalled) {
  146. $listenersCalled++;
  147. });
  148. $this->emitter->removeAllListeners('foo');
  149. $this->assertSame(0, $listenersCalled);
  150. $this->emitter->emit('foo');
  151. $this->assertSame(0, $listenersCalled);
  152. }
  153. public function testRemoveAllListenersNotMatching()
  154. {
  155. $listenersCalled = 0;
  156. $this->emitter->on('foo', function () use (&$listenersCalled) {
  157. $listenersCalled++;
  158. });
  159. $this->emitter->removeAllListeners('bar');
  160. $this->assertSame(0, $listenersCalled);
  161. $this->emitter->emit('foo');
  162. $this->assertSame(1, $listenersCalled);
  163. }
  164. public function testRemoveAllListenersWithoutArguments()
  165. {
  166. $listenersCalled = 0;
  167. $this->emitter->on('foo', function () use (&$listenersCalled) {
  168. $listenersCalled++;
  169. });
  170. $this->emitter->on('bar', function () use (&$listenersCalled) {
  171. $listenersCalled++;
  172. });
  173. $this->emitter->removeAllListeners();
  174. $this->assertSame(0, $listenersCalled);
  175. $this->emitter->emit('foo');
  176. $this->emitter->emit('bar');
  177. $this->assertSame(0, $listenersCalled);
  178. }
  179. public function testCallablesClosure()
  180. {
  181. $calledWith = null;
  182. $this->emitter->on('foo', function ($data) use (&$calledWith) {
  183. $calledWith = $data;
  184. });
  185. $this->emitter->emit('foo', ['bar']);
  186. self::assertSame('bar', $calledWith);
  187. }
  188. public function testCallablesClass()
  189. {
  190. $listener = new Listener();
  191. $this->emitter->on('foo', [$listener, 'onFoo']);
  192. $this->emitter->emit('foo', ['bar']);
  193. self::assertSame(['bar'], $listener->getData());
  194. }
  195. public function testCallablesClassInvoke()
  196. {
  197. $listener = new Listener();
  198. $this->emitter->on('foo', $listener);
  199. $this->emitter->emit('foo', ['bar']);
  200. self::assertSame(['bar'], $listener->getMagicData());
  201. }
  202. public function testCallablesStaticClass()
  203. {
  204. $this->emitter->on('foo', '\Evenement\Tests\Listener::onBar');
  205. $this->emitter->emit('foo', ['bar']);
  206. self::assertSame(['bar'], Listener::getStaticData());
  207. }
  208. public function testCallablesFunction()
  209. {
  210. $this->emitter->on('foo', '\Evenement\Tests\setGlobalTestData');
  211. $this->emitter->emit('foo', ['bar']);
  212. self::assertSame('bar', $GLOBALS['evenement-evenement-test-data']);
  213. unset($GLOBALS['evenement-evenement-test-data']);
  214. }
  215. public function testListeners()
  216. {
  217. $onA = function () {};
  218. $onB = function () {};
  219. $onC = function () {};
  220. $onceA = function () {};
  221. $onceB = function () {};
  222. $onceC = function () {};
  223. self::assertCount(0, $this->emitter->listeners('event'));
  224. $this->emitter->on('event', $onA);
  225. self::assertCount(1, $this->emitter->listeners('event'));
  226. self::assertSame([$onA], $this->emitter->listeners('event'));
  227. $this->emitter->once('event', $onceA);
  228. self::assertCount(2, $this->emitter->listeners('event'));
  229. self::assertSame([$onA, $onceA], $this->emitter->listeners('event'));
  230. $this->emitter->once('event', $onceB);
  231. self::assertCount(3, $this->emitter->listeners('event'));
  232. self::assertSame([$onA, $onceA, $onceB], $this->emitter->listeners('event'));
  233. $this->emitter->on('event', $onB);
  234. self::assertCount(4, $this->emitter->listeners('event'));
  235. self::assertSame([$onA, $onB, $onceA, $onceB], $this->emitter->listeners('event'));
  236. $this->emitter->removeListener('event', $onceA);
  237. self::assertCount(3, $this->emitter->listeners('event'));
  238. self::assertSame([$onA, $onB, $onceB], $this->emitter->listeners('event'));
  239. $this->emitter->once('event', $onceC);
  240. self::assertCount(4, $this->emitter->listeners('event'));
  241. self::assertSame([$onA, $onB, $onceB, $onceC], $this->emitter->listeners('event'));
  242. $this->emitter->on('event', $onC);
  243. self::assertCount(5, $this->emitter->listeners('event'));
  244. self::assertSame([$onA, $onB, $onC, $onceB, $onceC], $this->emitter->listeners('event'));
  245. $this->emitter->once('event', $onceA);
  246. self::assertCount(6, $this->emitter->listeners('event'));
  247. self::assertSame([$onA, $onB, $onC, $onceB, $onceC, $onceA], $this->emitter->listeners('event'));
  248. $this->emitter->removeListener('event', $onB);
  249. self::assertCount(5, $this->emitter->listeners('event'));
  250. self::assertSame([$onA, $onC, $onceB, $onceC, $onceA], $this->emitter->listeners('event'));
  251. $this->emitter->emit('event');
  252. self::assertCount(2, $this->emitter->listeners('event'));
  253. self::assertSame([$onA, $onC], $this->emitter->listeners('event'));
  254. }
  255. public function testOnceCallIsNotRemovedWhenWorkingOverOnceListeners()
  256. {
  257. $aCalled = false;
  258. $aCallable = function () use (&$aCalled) {
  259. $aCalled = true;
  260. };
  261. $bCalled = false;
  262. $bCallable = function () use (&$bCalled, $aCallable) {
  263. $bCalled = true;
  264. $this->emitter->once('event', $aCallable);
  265. };
  266. $this->emitter->once('event', $bCallable);
  267. self::assertFalse($aCalled);
  268. self::assertFalse($bCalled);
  269. $this->emitter->emit('event');
  270. self::assertFalse($aCalled);
  271. self::assertTrue($bCalled);
  272. $this->emitter->emit('event');
  273. self::assertTrue($aCalled);
  274. self::assertTrue($bCalled);
  275. }
  276. public function testEventNameMustBeStringOn()
  277. {
  278. self::expectException(InvalidArgumentException::class);
  279. self::expectExceptionMessage('event name must not be null');
  280. $this->emitter->on(null, function () {});
  281. }
  282. public function testEventNameMustBeStringOnce()
  283. {
  284. self::expectException(InvalidArgumentException::class);
  285. self::expectExceptionMessage('event name must not be null');
  286. $this->emitter->once(null, function () {});
  287. }
  288. public function testEventNameMustBeStringRemoveListener()
  289. {
  290. self::expectException(InvalidArgumentException::class);
  291. self::expectExceptionMessage('event name must not be null');
  292. $this->emitter->removeListener(null, function () {});
  293. }
  294. public function testEventNameMustBeStringEmit()
  295. {
  296. self::expectException(InvalidArgumentException::class);
  297. self::expectExceptionMessage('event name must not be null');
  298. $this->emitter->emit(null);
  299. }
  300. public function testListenersGetAll()
  301. {
  302. $a = function () {};
  303. $b = function () {};
  304. $c = function () {};
  305. $d = function () {};
  306. $this->emitter->once('event2', $c);
  307. $this->emitter->on('event', $a);
  308. $this->emitter->once('event', $b);
  309. $this->emitter->on('event', $c);
  310. $this->emitter->once('event', $d);
  311. self::assertSame(
  312. [
  313. 'event' => [
  314. $a,
  315. $c,
  316. $b,
  317. $d,
  318. ],
  319. 'event2' => [
  320. $c,
  321. ],
  322. ],
  323. $this->emitter->listeners()
  324. );
  325. }
  326. public function testOnceNestedCallRegression()
  327. {
  328. $first = 0;
  329. $second = 0;
  330. $this->emitter->once('event', function () use (&$first, &$second) {
  331. $first++;
  332. $this->emitter->once('event', function () use (&$second) {
  333. $second++;
  334. });
  335. $this->emitter->emit('event');
  336. });
  337. $this->emitter->emit('event');
  338. self::assertSame(1, $first);
  339. self::assertSame(1, $second);
  340. }
  341. }