PoolBuilderTest.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. foreach ($rootAliases as $index => $alias) {
  45. $rootAliases[$index]['version'] = $parser->normalize($alias['version']);
  46. $rootAliases[$index]['alias_normalized'] = $parser->normalize($alias['alias']);
  47. }
  48. $loader = new ArrayLoader();
  49. $packageIds = array();
  50. $loadPackage = function ($data) use ($loader, &$packageIds) {
  51. if (!empty($data['id'])) {
  52. $id = $data['id'];
  53. unset($data['id']);
  54. }
  55. $pkg = $loader->load($data);
  56. if (!empty($id)) {
  57. if (!empty($packageIds[$id])) {
  58. throw new \LogicException('Duplicate package id '.$id.' defined');
  59. }
  60. $packageIds[$id] = $pkg;
  61. }
  62. return $pkg;
  63. };
  64. $repositorySet = new RepositorySet($minimumStability, $stabilityFlags, $rootAliases);
  65. $repositorySet->addRepository($repo = new ArrayRepository());
  66. foreach ($packages as $package) {
  67. $repo->addPackage($loadPackage($package));
  68. }
  69. $request = new Request();
  70. foreach ($requestData as $package => $constraint) {
  71. $request->requireName($package, $parser->parseConstraints($constraint));
  72. }
  73. foreach ($fixed as $fixedPackage) {
  74. $request->fixPackage($loadPackage($fixedPackage));
  75. }
  76. $pool = $repositorySet->createPool($request, new NullIO());
  77. $result = array();
  78. for ($i = 1, $count = count($pool); $i <= $count; $i++) {
  79. $result[] = $pool->packageById($i);
  80. }
  81. $result = array_map(function ($package) use ($packageIds) {
  82. if ($id = array_search($package, $packageIds, true)) {
  83. return $id;
  84. }
  85. if ($package instanceof AliasPackage && $id = array_search($package->getAliasOf(), $packageIds, true)) {
  86. return (string) $package->getName().'-'.$package->getVersion() .' alias of '.$id;
  87. }
  88. return (string) $package;
  89. }, $result);
  90. $this->assertSame($expect, $result);
  91. }
  92. public function getIntegrationTests()
  93. {
  94. $fixturesDir = realpath(__DIR__.'/Fixtures/poolbuilder/');
  95. $tests = array();
  96. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  97. if (!preg_match('/\.test$/', $file)) {
  98. continue;
  99. }
  100. try {
  101. $testData = $this->readTestFile($file, $fixturesDir);
  102. $message = $testData['TEST'];
  103. $request = JsonFile::parseJson($testData['REQUEST']);
  104. $root = !empty($testData['ROOT']) ? JsonFile::parseJson($testData['ROOT']) : array();
  105. $packages = JsonFile::parseJson($testData['PACKAGES']);
  106. $fixed = array();
  107. if (!empty($testData['FIXED'])) {
  108. $fixed = JsonFile::parseJson($testData['FIXED']);
  109. }
  110. $expect = JsonFile::parseJson($testData['EXPECT']);
  111. } catch (\Exception $e) {
  112. die(sprintf('Test "%s" is not valid: '.$e->getMessage(), str_replace($fixturesDir.'/', '', $file)));
  113. }
  114. $tests[basename($file)] = array(str_replace($fixturesDir.'/', '', $file), $message, $expect, $root, $request, $packages, $fixed);
  115. }
  116. return $tests;
  117. }
  118. protected function readTestFile(\SplFileInfo $file, $fixturesDir)
  119. {
  120. $tokens = preg_split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), null, PREG_SPLIT_DELIM_CAPTURE);
  121. $sectionInfo = array(
  122. 'TEST' => true,
  123. 'ROOT' => false,
  124. 'REQUEST' => true,
  125. 'FIXED' => false,
  126. 'PACKAGES' => true,
  127. 'EXPECT' => true,
  128. );
  129. $section = null;
  130. $data = array();
  131. foreach ($tokens as $i => $token) {
  132. if (null === $section && empty($token)) {
  133. continue; // skip leading blank
  134. }
  135. if (null === $section) {
  136. if (!isset($sectionInfo[$token])) {
  137. throw new \RuntimeException(sprintf(
  138. 'The test file "%s" must not contain a section named "%s".',
  139. str_replace($fixturesDir.'/', '', $file),
  140. $token
  141. ));
  142. }
  143. $section = $token;
  144. continue;
  145. }
  146. $sectionData = $token;
  147. $data[$section] = $sectionData;
  148. $section = $sectionData = null;
  149. }
  150. foreach ($sectionInfo as $section => $required) {
  151. if ($required && !isset($data[$section])) {
  152. throw new \RuntimeException(sprintf(
  153. 'The test file "%s" must have a section named "%s".',
  154. str_replace($fixturesDir.'/', '', $file),
  155. $section
  156. ));
  157. }
  158. }
  159. return $data;
  160. }
  161. }