InstallerTest.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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;
  12. use Composer\Installer;
  13. use Composer\Config;
  14. use Composer\Json\JsonFile;
  15. use Composer\Repository\ArrayRepository;
  16. use Composer\Repository\RepositoryManager;
  17. use Composer\Repository\RepositoryInterface;
  18. use Composer\Package\PackageInterface;
  19. use Composer\Package\Link;
  20. use Composer\Package\Locker;
  21. use Composer\Test\Mock\FactoryMock;
  22. use Composer\Test\Mock\InstalledFilesystemRepositoryMock;
  23. use Composer\Test\Mock\InstallationManagerMock;
  24. use Composer\Test\Mock\WritableRepositoryMock;
  25. class InstallerTest extends TestCase
  26. {
  27. /**
  28. * @dataProvider provideInstaller
  29. */
  30. public function testInstaller(PackageInterface $rootPackage, $repositories, array $options)
  31. {
  32. $io = $this->getMock('Composer\IO\IOInterface');
  33. $downloadManager = $this->getMock('Composer\Downloader\DownloadManager');
  34. $config = $this->getMock('Composer\Config');
  35. $repositoryManager = new RepositoryManager($io, $config);
  36. $repositoryManager->setLocalRepository(new WritableRepositoryMock());
  37. $repositoryManager->setLocalDevRepository(new WritableRepositoryMock());
  38. if (!is_array($repositories)) {
  39. $repositories = array($repositories);
  40. }
  41. foreach ($repositories as $repository) {
  42. $repositoryManager->addRepository($repository);
  43. }
  44. $locker = $this->getMockBuilder('Composer\Package\Locker')->disableOriginalConstructor()->getMock();
  45. $installationManager = new InstallationManagerMock();
  46. $eventDispatcher = $this->getMockBuilder('Composer\Script\EventDispatcher')->disableOriginalConstructor()->getMock();
  47. $autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator');
  48. $installer = new Installer($io, clone $rootPackage, $downloadManager, $repositoryManager, $locker, $installationManager, $eventDispatcher, $autoloadGenerator);
  49. $result = $installer->run();
  50. $this->assertTrue($result);
  51. $expectedInstalled = isset($options['install']) ? $options['install'] : array();
  52. $expectedUpdated = isset($options['update']) ? $options['update'] : array();
  53. $expectedUninstalled = isset($options['uninstall']) ? $options['uninstall'] : array();
  54. $installed = $installationManager->getInstalledPackages();
  55. $this->assertSame($expectedInstalled, $installed);
  56. $updated = $installationManager->getUpdatedPackages();
  57. $this->assertSame($expectedUpdated, $updated);
  58. $uninstalled = $installationManager->getUninstalledPackages();
  59. $this->assertSame($expectedUninstalled, $uninstalled);
  60. }
  61. public function provideInstaller()
  62. {
  63. $cases = array();
  64. // when A requires B and B requires A, and A is a non-published root package
  65. // the install of B should succeed
  66. $a = $this->getPackage('A', '1.0.0');
  67. $a->setRequires(array(
  68. new Link('A', 'B', $this->getVersionConstraint('=', '1.0.0')),
  69. ));
  70. $b = $this->getPackage('B', '1.0.0');
  71. $b->setRequires(array(
  72. new Link('B', 'A', $this->getVersionConstraint('=', '1.0.0')),
  73. ));
  74. $cases[] = array(
  75. $a,
  76. new ArrayRepository(array($b)),
  77. array(
  78. 'install' => array($b)
  79. ),
  80. );
  81. // #480: when A requires B and B requires A, and A is a published root package
  82. // only B should be installed, as A is the root
  83. $a = $this->getPackage('A', '1.0.0');
  84. $a->setRequires(array(
  85. new Link('A', 'B', $this->getVersionConstraint('=', '1.0.0')),
  86. ));
  87. $b = $this->getPackage('B', '1.0.0');
  88. $b->setRequires(array(
  89. new Link('B', 'A', $this->getVersionConstraint('=', '1.0.0')),
  90. ));
  91. $cases[] = array(
  92. $a,
  93. new ArrayRepository(array($a, $b)),
  94. array(
  95. 'install' => array($b)
  96. ),
  97. );
  98. return $cases;
  99. }
  100. /**
  101. * @dataProvider getIntegrationTests
  102. */
  103. public function testIntegration($file, $message, $condition, $composer, $lock, $installed, $installedDev, $update, $dev, $expect)
  104. {
  105. if ($condition) {
  106. eval('$res = '.$condition.';');
  107. if (!$res) {
  108. $this->markTestSkipped($condition);
  109. }
  110. }
  111. $output = null;
  112. $io = $this->getMock('Composer\IO\IOInterface');
  113. $io->expects($this->any())
  114. ->method('write')
  115. ->will($this->returnCallback(function ($text, $newline) use (&$output) {
  116. $output .= $text . ($newline ? "\n":"");
  117. }));
  118. $composer = FactoryMock::create($io, $composer);
  119. $jsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
  120. $jsonMock->expects($this->any())
  121. ->method('read')
  122. ->will($this->returnValue($installed));
  123. $jsonMock->expects($this->any())
  124. ->method('exists')
  125. ->will($this->returnValue(true));
  126. $devJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
  127. $devJsonMock->expects($this->any())
  128. ->method('read')
  129. ->will($this->returnValue($installedDev));
  130. $devJsonMock->expects($this->any())
  131. ->method('exists')
  132. ->will($this->returnValue(true));
  133. $repositoryManager = $composer->getRepositoryManager();
  134. $repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock));
  135. $repositoryManager->setLocalDevRepository(new InstalledFilesystemRepositoryMock($devJsonMock));
  136. $lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
  137. $lockJsonMock->expects($this->any())
  138. ->method('read')
  139. ->will($this->returnValue($lock));
  140. $locker = new Locker($lockJsonMock, $repositoryManager, isset($lock['hash']) ? $lock['hash'] : '');
  141. $composer->setLocker($locker);
  142. $autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator');
  143. $installer = Installer::create(
  144. $io,
  145. $composer,
  146. null,
  147. $autoloadGenerator
  148. );
  149. $installer->setDevMode($dev)->setUpdate($update);
  150. $result = $installer->run();
  151. $this->assertTrue($result, $output);
  152. $expectedInstalled = isset($options['install']) ? $options['install'] : array();
  153. $expectedUpdated = isset($options['update']) ? $options['update'] : array();
  154. $expectedUninstalled = isset($options['uninstall']) ? $options['uninstall'] : array();
  155. $installationManager = $composer->getInstallationManager();
  156. $this->assertSame($expect, implode("\n", $installationManager->getTrace()));
  157. }
  158. public function getIntegrationTests()
  159. {
  160. $fixturesDir = realpath(__DIR__.'/Fixtures/installer/');
  161. $tests = array();
  162. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  163. if (!preg_match('/\.test$/', $file)) {
  164. continue;
  165. }
  166. $test = file_get_contents($file->getRealpath());
  167. $content = '(?:.(?!--[A-Z]))+';
  168. $pattern = '{^
  169. --TEST--\s*(?P<test>.*?)\s*
  170. (?:--CONDITION--\s*(?P<condition>'.$content.'))?\s*
  171. --COMPOSER--\s*(?P<composer>'.$content.')\s*
  172. (?:--LOCK--\s*(?P<lock>'.$content.'))?\s*
  173. (?:--INSTALLED--\s*(?P<installed>'.$content.'))?\s*
  174. (?:--INSTALLED:DEV--\s*(?P<installedDev>'.$content.'))?\s*
  175. --EXPECT(?P<update>:UPDATE)?(?P<dev>:DEV)?--\s*(?P<expect>.*?)\s*
  176. $}xs';
  177. $installed = array();
  178. $installedDev = array();
  179. $lock = array();
  180. if (preg_match($pattern, $test, $match)) {
  181. try {
  182. $message = $match['test'];
  183. $condition = !empty($match['condition']) ? $match['condition'] : null;
  184. $composer = JsonFile::parseJson($match['composer']);
  185. if (!empty($match['lock'])) {
  186. $lock = JsonFile::parseJson($match['lock']);
  187. }
  188. if (!empty($match['installed'])) {
  189. $installed = JsonFile::parseJson($match['installed']);
  190. }
  191. if (!empty($match['installedDev'])) {
  192. $installedDev = JsonFile::parseJson($match['installedDev']);
  193. }
  194. $update = !empty($match['update']);
  195. $dev = !empty($match['dev']);
  196. $expect = $match['expect'];
  197. } catch (\Exception $e) {
  198. die(sprintf('Test "%s" is not valid: '.$e->getMessage(), str_replace($fixturesDir.'/', '', $file)));
  199. }
  200. } else {
  201. die(sprintf('Test "%s" is not valid, did not match the expected format.', str_replace($fixturesDir.'/', '', $file)));
  202. }
  203. $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $composer, $lock, $installed, $installedDev, $update, $dev, $expect);
  204. }
  205. return $tests;
  206. }
  207. }