EventDispatcherTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Test\EventDispatcher;
  12. use Composer\EventDispatcher\Event;
  13. use Composer\Installer\InstallerEvents;
  14. use Composer\Config;
  15. use Composer\Composer;
  16. use Composer\TestCase;
  17. use Composer\IO\BufferIO;
  18. use Composer\Script\ScriptEvents;
  19. use Composer\Script\CommandEvent;
  20. use Composer\Util\ProcessExecutor;
  21. use Symfony\Component\Console\Output\OutputInterface;
  22. class EventDispatcherTest extends TestCase
  23. {
  24. /**
  25. * @expectedException RuntimeException
  26. */
  27. public function testListenerExceptionsAreCaught()
  28. {
  29. $io = $this->getMock('Composer\IO\IOInterface');
  30. $dispatcher = $this->getDispatcherStubForListenersTest(array(
  31. 'Composer\Test\EventDispatcher\EventDispatcherTest::call',
  32. ), $io);
  33. $io->expects($this->at(0))
  34. ->method('isVerbose')
  35. ->willReturn(0);
  36. $io->expects($this->at(1))
  37. ->method('writeError')
  38. ->with('> Composer\Test\EventDispatcher\EventDispatcherTest::call');
  39. $io->expects($this->at(2))
  40. ->method('writeError')
  41. ->with('<error>Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception</error>');
  42. $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
  43. }
  44. /**
  45. * @expectedException PHPUnit_Framework_Error_Deprecated
  46. */
  47. public function testDispatcherCanConvertScriptEventToCommandEventForListener()
  48. {
  49. $io = $this->getMock('Composer\IO\IOInterface');
  50. $dispatcher = $this->getDispatcherStubForListenersTest(array(
  51. 'Composer\Test\EventDispatcher\EventDispatcherTest::expectsCommandEvent',
  52. ), $io);
  53. $this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false));
  54. }
  55. public function testDispatcherDoesNotAttemptConversionForListenerWithoutTypehint()
  56. {
  57. $io = $this->getMock('Composer\IO\IOInterface');
  58. $dispatcher = $this->getDispatcherStubForListenersTest(array(
  59. 'Composer\Test\EventDispatcher\EventDispatcherTest::expectsVariableEvent',
  60. ), $io);
  61. $this->assertEquals(1, $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false));
  62. }
  63. /**
  64. * @dataProvider getValidCommands
  65. * @param string $command
  66. */
  67. public function testDispatcherCanExecuteSingleCommandLineScript($command)
  68. {
  69. $process = $this->getMock('Composer\Util\ProcessExecutor');
  70. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  71. ->setConstructorArgs(array(
  72. $this->createComposerInstance(),
  73. $this->getMock('Composer\IO\IOInterface'),
  74. $process,
  75. ))
  76. ->setMethods(array('getListeners'))
  77. ->getMock();
  78. $listener = array($command);
  79. $dispatcher->expects($this->atLeastOnce())
  80. ->method('getListeners')
  81. ->will($this->returnValue($listener));
  82. $process->expects($this->once())
  83. ->method('execute')
  84. ->with($command)
  85. ->will($this->returnValue(0));
  86. $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
  87. }
  88. public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack()
  89. {
  90. $process = $this->getMock('Composer\Util\ProcessExecutor');
  91. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  92. ->setConstructorArgs(array(
  93. $this->createComposerInstance(),
  94. $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE),
  95. $process,
  96. ))
  97. ->setMethods(array(
  98. 'getListeners',
  99. ))
  100. ->getMock();
  101. $process->expects($this->exactly(2))
  102. ->method('execute')
  103. ->will($this->returnValue(0));
  104. $listeners = array(
  105. 'echo -n foo',
  106. 'Composer\\Test\\EventDispatcher\\EventDispatcherTest::someMethod',
  107. 'echo -n bar',
  108. );
  109. $dispatcher->expects($this->atLeastOnce())
  110. ->method('getListeners')
  111. ->will($this->returnValue($listeners));
  112. $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
  113. $expected = '> post-install-cmd: echo -n foo'.PHP_EOL.
  114. '> post-install-cmd: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'.PHP_EOL.
  115. '> post-install-cmd: echo -n bar'.PHP_EOL;
  116. $this->assertEquals($expected, $io->getOutput());
  117. }
  118. public function testDispatcherCanExecuteComposerScriptGroups()
  119. {
  120. $process = $this->getMock('Composer\Util\ProcessExecutor');
  121. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  122. ->setConstructorArgs(array(
  123. $composer = $this->createComposerInstance(),
  124. $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE),
  125. $process,
  126. ))
  127. ->setMethods(array(
  128. 'getListeners',
  129. ))
  130. ->getMock();
  131. $process->expects($this->exactly(3))
  132. ->method('execute')
  133. ->will($this->returnValue(0));
  134. $dispatcher->expects($this->atLeastOnce())
  135. ->method('getListeners')
  136. ->will($this->returnCallback(function (Event $event) {
  137. if ($event->getName() === 'root') {
  138. return array('@group');
  139. } elseif ($event->getName() === 'group') {
  140. return array('echo -n foo', '@subgroup', 'echo -n bar');
  141. } elseif ($event->getName() === 'subgroup') {
  142. return array('echo -n baz');
  143. }
  144. return array();
  145. }));
  146. $dispatcher->dispatch('root', new CommandEvent('root', $composer, $io));
  147. $expected = '> root: @group'.PHP_EOL.
  148. '> group: echo -n foo'.PHP_EOL.
  149. '> group: @subgroup'.PHP_EOL.
  150. '> subgroup: echo -n baz'.PHP_EOL.
  151. '> group: echo -n bar'.PHP_EOL;
  152. $this->assertEquals($expected, $io->getOutput());
  153. }
  154. /**
  155. * @expectedException RuntimeException
  156. */
  157. public function testDispatcherDetectInfiniteRecursion()
  158. {
  159. $process = $this->getMock('Composer\Util\ProcessExecutor');
  160. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  161. ->setConstructorArgs(array(
  162. $composer = $this->createComposerInstance(),
  163. $io = $this->getMock('Composer\IO\IOInterface'),
  164. $process,
  165. ))
  166. ->setMethods(array(
  167. 'getListeners',
  168. ))
  169. ->getMock();
  170. $dispatcher->expects($this->atLeastOnce())
  171. ->method('getListeners')
  172. ->will($this->returnCallback(function (Event $event) {
  173. if ($event->getName() === 'root') {
  174. return array('@recurse');
  175. } elseif ($event->getName() === 'recurse') {
  176. return array('@root');
  177. }
  178. return array();
  179. }));
  180. $dispatcher->dispatch('root', new CommandEvent('root', $composer, $io));
  181. }
  182. private function getDispatcherStubForListenersTest($listeners, $io)
  183. {
  184. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  185. ->setConstructorArgs(array(
  186. $this->createComposerInstance(),
  187. $io,
  188. ))
  189. ->setMethods(array('getListeners'))
  190. ->getMock();
  191. $dispatcher->expects($this->atLeastOnce())
  192. ->method('getListeners')
  193. ->will($this->returnValue($listeners));
  194. return $dispatcher;
  195. }
  196. public function getValidCommands()
  197. {
  198. return array(
  199. array('phpunit'),
  200. array('echo foo'),
  201. array('echo -n foo'),
  202. );
  203. }
  204. public function testDispatcherOutputsCommand()
  205. {
  206. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  207. ->setConstructorArgs(array(
  208. $this->createComposerInstance(),
  209. $io = $this->getMock('Composer\IO\IOInterface'),
  210. new ProcessExecutor,
  211. ))
  212. ->setMethods(array('getListeners'))
  213. ->getMock();
  214. $listener = array('echo foo');
  215. $dispatcher->expects($this->atLeastOnce())
  216. ->method('getListeners')
  217. ->will($this->returnValue($listener));
  218. $io->expects($this->once())
  219. ->method('writeError')
  220. ->with($this->equalTo('> echo foo'));
  221. ob_start();
  222. $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
  223. $this->assertEquals('foo', trim(ob_get_clean()));
  224. }
  225. public function testDispatcherOutputsErrorOnFailedCommand()
  226. {
  227. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  228. ->setConstructorArgs(array(
  229. $this->createComposerInstance(),
  230. $io = $this->getMock('Composer\IO\IOInterface'),
  231. new ProcessExecutor,
  232. ))
  233. ->setMethods(array('getListeners'))
  234. ->getMock();
  235. $code = 'exit 1';
  236. $listener = array($code);
  237. $dispatcher->expects($this->atLeastOnce())
  238. ->method('getListeners')
  239. ->will($this->returnValue($listener));
  240. $io->expects($this->at(0))
  241. ->method('isVerbose')
  242. ->willReturn(0);
  243. $io->expects($this->at(1))
  244. ->method('writeError')
  245. ->willReturn('> exit 1');
  246. $io->expects($this->at(2))
  247. ->method('writeError')
  248. ->with($this->equalTo('<error>Script '.$code.' handling the post-install-cmd event returned with an error</error>'));
  249. $this->setExpectedException('RuntimeException');
  250. $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
  251. }
  252. public function testDispatcherInstallerEvents()
  253. {
  254. $process = $this->getMock('Composer\Util\ProcessExecutor');
  255. $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
  256. ->setConstructorArgs(array(
  257. $this->createComposerInstance(),
  258. $this->getMock('Composer\IO\IOInterface'),
  259. $process,
  260. ))
  261. ->setMethods(array('getListeners'))
  262. ->getMock();
  263. $dispatcher->expects($this->atLeastOnce())
  264. ->method('getListeners')
  265. ->will($this->returnValue(array()));
  266. $policy = $this->getMock('Composer\DependencyResolver\PolicyInterface');
  267. $pool = $this->getMockBuilder('Composer\DependencyResolver\Pool')->disableOriginalConstructor()->getMock();
  268. $installedRepo = $this->getMockBuilder('Composer\Repository\CompositeRepository')->disableOriginalConstructor()->getMock();
  269. $request = $this->getMockBuilder('Composer\DependencyResolver\Request')->disableOriginalConstructor()->getMock();
  270. $dispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, true, $policy, $pool, $installedRepo, $request);
  271. $dispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, true, $policy, $pool, $installedRepo, $request, array());
  272. }
  273. public static function call()
  274. {
  275. throw new \RuntimeException();
  276. }
  277. public static function expectsCommandEvent(CommandEvent $event)
  278. {
  279. return false;
  280. }
  281. public static function expectsVariableEvent($event)
  282. {
  283. return false;
  284. }
  285. public static function someMethod()
  286. {
  287. return true;
  288. }
  289. private function createComposerInstance()
  290. {
  291. $composer = new Composer;
  292. $config = new Config;
  293. $composer->setConfig($config);
  294. return $composer;
  295. }
  296. }