PoolBuilderTest.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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\DependencyResolver;
  12. use Composer\IO\NullIO;
  13. use Composer\Repository\ArrayRepository;
  14. use Composer\Repository\LockArrayRepository;
  15. use Composer\DependencyResolver\DefaultPolicy;
  16. use Composer\DependencyResolver\Pool;
  17. use Composer\DependencyResolver\PoolBuilder;
  18. use Composer\DependencyResolver\Request;
  19. use Composer\DependencyResolver\Solver;
  20. use Composer\DependencyResolver\SolverProblemsException;
  21. use Composer\Package\BasePackage;
  22. use Composer\Package\AliasPackage;
  23. use Composer\Json\JsonFile;
  24. use Composer\Package\Loader\ArrayLoader;
  25. use Composer\Package\Version\VersionParser;
  26. use Composer\Repository\InstalledArrayRepository;
  27. use Composer\Repository\RepositorySet;
  28. use Composer\Test\TestCase;
  29. use Composer\Semver\Constraint\MultiConstraint;
  30. class PoolBuilderTest extends TestCase
  31. {
  32. /**
  33. * @dataProvider getIntegrationTests
  34. */
  35. public function testPoolBuilder($file, $message, $expect, $root, $requestData, $packages, $fixed)
  36. {
  37. $rootAliases = !empty($root['aliases']) ? $root['aliases'] : array();
  38. $minimumStability = !empty($root['minimum-stability']) ? $root['minimum-stability'] : 'stable';
  39. $stabilityFlags = !empty($root['stability-flags']) ? $root['stability-flags'] : array();
  40. $stabilityFlags = array_map(function ($stability) {
  41. return BasePackage::$stabilities[$stability];
  42. }, $stabilityFlags);
  43. $parser = new VersionParser();
  44. $normalizedAliases = array();
  45. foreach ($rootAliases as $alias) {
  46. $normalizedAliases[$alias['package']][$parser->normalize($alias['version'])] = array(
  47. 'alias' => $alias['alias'],
  48. 'alias_normalized' => $parser->normalize($alias['alias']),
  49. );
  50. }
  51. $loader = new ArrayLoader();
  52. $packageIds = array();
  53. $loadPackage = function ($data) use ($loader, &$packageIds) {
  54. if (!empty($data['id'])) {
  55. $id = $data['id'];
  56. unset($data['id']);
  57. }
  58. $pkg = $loader->load($data);
  59. if (!empty($id)) {
  60. if (!empty($packageIds[$id])) {
  61. throw new \LogicException('Duplicate package id '.$id.' defined');
  62. }
  63. $packageIds[$id] = $pkg;
  64. }
  65. return $pkg;
  66. };
  67. $repositorySet = new RepositorySet($minimumStability, $stabilityFlags, $normalizedAliases);
  68. $repositorySet->addRepository($repo = new ArrayRepository());
  69. foreach ($packages as $package) {
  70. $repo->addPackage($loadPackage($package));
  71. }
  72. $request = new Request();
  73. foreach ($requestData as $package => $constraint) {
  74. $request->requireName($package, $parser->parseConstraints($constraint));
  75. }
  76. foreach ($fixed as $fixedPackage) {
  77. $request->fixPackage($loadPackage($fixedPackage));
  78. }
  79. $pool = $repositorySet->createPool($request, new NullIO());
  80. $result = array();
  81. for ($i = 1, $count = count($pool); $i <= $count; $i++) {
  82. $result[] = $pool->packageById($i);
  83. }
  84. $result = array_map(function ($package) use ($packageIds) {
  85. if ($id = array_search($package, $packageIds, true)) {
  86. return $id;
  87. }
  88. if ($package instanceof AliasPackage && $id = array_search($package->getAliasOf(), $packageIds, true)) {
  89. return (string) $package->getName().'-'.$package->getVersion() .' alias of '.$id;
  90. }
  91. return (string) $package;
  92. }, $result);
  93. $this->assertSame($expect, $result);
  94. }
  95. public function getIntegrationTests()
  96. {
  97. $fixturesDir = realpath(__DIR__.'/Fixtures/poolbuilder/');
  98. $tests = array();
  99. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  100. if (!preg_match('/\.test$/', $file)) {
  101. continue;
  102. }
  103. try {
  104. $testData = $this->readTestFile($file, $fixturesDir);
  105. $message = $testData['TEST'];
  106. $request = JsonFile::parseJson($testData['REQUEST']);
  107. $root = !empty($testData['ROOT']) ? JsonFile::parseJson($testData['ROOT']) : array();
  108. $packages = JsonFile::parseJson($testData['PACKAGES']);
  109. $fixed = array();
  110. if (!empty($testData['FIXED'])) {
  111. $fixed = JsonFile::parseJson($testData['FIXED']);
  112. }
  113. $expect = JsonFile::parseJson($testData['EXPECT']);
  114. } catch (\Exception $e) {
  115. die(sprintf('Test "%s" is not valid: '.$e->getMessage(), str_replace($fixturesDir.'/', '', $file)));
  116. }
  117. $tests[basename($file)] = array(str_replace($fixturesDir.'/', '', $file), $message, $expect, $root, $request, $packages, $fixed);
  118. }
  119. return $tests;
  120. }
  121. protected function readTestFile(\SplFileInfo $file, $fixturesDir)
  122. {
  123. $tokens = preg_split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), null, PREG_SPLIT_DELIM_CAPTURE);
  124. $sectionInfo = array(
  125. 'TEST' => true,
  126. 'ROOT' => false,
  127. 'REQUEST' => true,
  128. 'FIXED' => false,
  129. 'PACKAGES' => true,
  130. 'EXPECT' => true,
  131. );
  132. $section = null;
  133. $data = array();
  134. foreach ($tokens as $i => $token) {
  135. if (null === $section && empty($token)) {
  136. continue; // skip leading blank
  137. }
  138. if (null === $section) {
  139. if (!isset($sectionInfo[$token])) {
  140. throw new \RuntimeException(sprintf(
  141. 'The test file "%s" must not contain a section named "%s".',
  142. str_replace($fixturesDir.'/', '', $file),
  143. $token
  144. ));
  145. }
  146. $section = $token;
  147. continue;
  148. }
  149. $sectionData = $token;
  150. $data[$section] = $sectionData;
  151. $section = $sectionData = null;
  152. }
  153. foreach ($sectionInfo as $section => $required) {
  154. if ($required && !isset($data[$section])) {
  155. throw new \RuntimeException(sprintf(
  156. 'The test file "%s" must have a section named "%s".',
  157. str_replace($fixturesDir.'/', '', $file),
  158. $section
  159. ));
  160. }
  161. }
  162. return $data;
  163. }
  164. }