PoolBuilderTest.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. for ($i = 1, $count = count($pool); $i <= $count; $i++) {
  81. $result[] = $pool->packageById($i);
  82. }
  83. $result = array_map(function ($package) use ($packageIds) {
  84. if ($id = array_search($package, $packageIds, true)) {
  85. return $id;
  86. }
  87. if ($package instanceof AliasPackage && $id = array_search($package->getAliasOf(), $packageIds, true)) {
  88. return (string) $package->getName().'-'.$package->getVersion() .' alias of '.$id;
  89. }
  90. return (string) $package;
  91. }, $result);
  92. $this->assertSame($expect, $result);
  93. }
  94. public function getIntegrationTests()
  95. {
  96. $fixturesDir = realpath(__DIR__.'/Fixtures/poolbuilder/');
  97. $tests = array();
  98. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
  99. if (!preg_match('/\.test$/', $file)) {
  100. continue;
  101. }
  102. try {
  103. $testData = $this->readTestFile($file, $fixturesDir);
  104. $message = $testData['TEST'];
  105. $request = JsonFile::parseJson($testData['REQUEST']);
  106. $root = !empty($testData['ROOT']) ? JsonFile::parseJson($testData['ROOT']) : array();
  107. $packages = JsonFile::parseJson($testData['PACKAGES']);
  108. $fixed = array();
  109. if (!empty($testData['FIXED'])) {
  110. $fixed = JsonFile::parseJson($testData['FIXED']);
  111. }
  112. $expect = JsonFile::parseJson($testData['EXPECT']);
  113. } catch (\Exception $e) {
  114. die(sprintf('Test "%s" is not valid: '.$e->getMessage(), str_replace($fixturesDir.'/', '', $file)));
  115. }
  116. $tests[basename($file)] = array(str_replace($fixturesDir.'/', '', $file), $message, $expect, $root, $request, $packages, $fixed);
  117. }
  118. return $tests;
  119. }
  120. protected function readTestFile(\SplFileInfo $file, $fixturesDir)
  121. {
  122. $tokens = preg_split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), null, PREG_SPLIT_DELIM_CAPTURE);
  123. $sectionInfo = array(
  124. 'TEST' => true,
  125. 'ROOT' => false,
  126. 'REQUEST' => true,
  127. 'FIXED' => false,
  128. 'PACKAGES' => true,
  129. 'EXPECT' => true,
  130. );
  131. $section = null;
  132. foreach ($tokens as $i => $token) {
  133. if (null === $section && empty($token)) {
  134. continue; // skip leading blank
  135. }
  136. if (null === $section) {
  137. if (!isset($sectionInfo[$token])) {
  138. throw new \RuntimeException(sprintf(
  139. 'The test file "%s" must not contain a section named "%s".',
  140. str_replace($fixturesDir.'/', '', $file),
  141. $token
  142. ));
  143. }
  144. $section = $token;
  145. continue;
  146. }
  147. $sectionData = $token;
  148. $data[$section] = $sectionData;
  149. $section = $sectionData = null;
  150. }
  151. foreach ($sectionInfo as $section => $required) {
  152. if ($required && !isset($data[$section])) {
  153. throw new \RuntimeException(sprintf(
  154. 'The test file "%s" must have a section named "%s".',
  155. str_replace($fixturesDir.'/', '', $file),
  156. $section
  157. ));
  158. }
  159. }
  160. return $data;
  161. }
  162. }