2022-02-23 15:58:18 +00:00
< ? php declare ( strict_types = 1 );
2020-10-01 14:42:02 +00:00
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Composer\Test\DependencyResolver ;
use Composer\DependencyResolver\DefaultPolicy ;
use Composer\DependencyResolver\Pool ;
use Composer\DependencyResolver\PoolOptimizer ;
use Composer\DependencyResolver\Request ;
use Composer\Json\JsonFile ;
use Composer\Package\AliasPackage ;
use Composer\Package\BasePackage ;
use Composer\Package\Loader\ArrayLoader ;
use Composer\Package\Version\VersionParser ;
2021-12-07 10:03:51 +00:00
use Composer\Pcre\Preg ;
2020-10-01 14:42:02 +00:00
use Composer\Repository\LockArrayRepository ;
use Composer\Test\TestCase ;
class PoolOptimizerTest extends TestCase
{
/**
* @ dataProvider provideIntegrationTests
* @ param mixed [] $requestData
* @ param BasePackage [] $packagesBefore
* @ param BasePackage [] $expectedPackages
* @ param string $message
*/
2022-02-22 15:47:09 +00:00
public function testPoolOptimizer ( array $requestData , array $packagesBefore , array $expectedPackages , string $message ) : void
2020-10-01 14:42:02 +00:00
{
$lockedRepo = new LockArrayRepository ();
$request = new Request ( $lockedRepo );
$parser = new VersionParser ();
if ( isset ( $requestData [ 'locked' ])) {
foreach ( $requestData [ 'locked' ] as $package ) {
$request -> lockPackage ( $this -> loadPackage ( $package ));
}
}
if ( isset ( $requestData [ 'fixed' ])) {
foreach ( $requestData [ 'fixed' ] as $package ) {
$request -> fixPackage ( $this -> loadPackage ( $package ));
}
}
foreach ( $requestData [ 'require' ] as $package => $constraint ) {
$request -> requireName ( $package , $parser -> parseConstraints ( $constraint ));
}
2022-02-18 08:09:58 +00:00
$preferStable = $requestData [ 'preferStable' ] ? ? false ;
$preferLowest = $requestData [ 'preferLowest' ] ? ? false ;
2020-10-01 14:42:02 +00:00
$pool = new Pool ( $packagesBefore );
$poolOptimizer = new PoolOptimizer ( new DefaultPolicy ( $preferStable , $preferLowest ));
$pool = $poolOptimizer -> optimize ( $request , $pool );
$this -> assertSame (
$this -> reducePackagesInfoForComparison ( $expectedPackages ),
$this -> reducePackagesInfoForComparison ( $pool -> getPackages ()),
$message
);
}
2022-02-21 12:42:28 +00:00
public function provideIntegrationTests () : array
2020-10-01 14:42:02 +00:00
{
$fixturesDir = realpath ( __DIR__ . '/Fixtures/pooloptimizer/' );
$tests = array ();
foreach ( new \RecursiveIteratorIterator ( new \RecursiveDirectoryIterator ( $fixturesDir ), \RecursiveIteratorIterator :: LEAVES_ONLY ) as $file ) {
2022-02-23 15:57:47 +00:00
$file = ( string ) $file ;
2021-12-07 10:03:51 +00:00
if ( ! Preg :: isMatch ( '/\.test$/' , $file )) {
2020-10-01 14:42:02 +00:00
continue ;
}
try {
$testData = $this -> readTestFile ( $file , $fixturesDir );
$message = $testData [ 'TEST' ];
$requestData = JsonFile :: parseJson ( $testData [ 'REQUEST' ]);
$packagesBefore = $this -> loadPackages ( JsonFile :: parseJson ( $testData [ 'POOL-BEFORE' ]));
$expectedPackages = $this -> loadPackages ( JsonFile :: parseJson ( $testData [ 'POOL-AFTER' ]));
} catch ( \Exception $e ) {
die ( sprintf ( 'Test "%s" is not valid: ' . $e -> getMessage (), str_replace ( $fixturesDir . '/' , '' , $file )));
}
$tests [ basename ( $file )] = array ( $requestData , $packagesBefore , $expectedPackages , $message );
}
return $tests ;
}
/**
* @ return mixed []
*/
2022-02-23 15:57:47 +00:00
protected function readTestFile ( string $file , string $fixturesDir ) : array
2020-10-01 14:42:02 +00:00
{
2022-02-23 15:57:47 +00:00
$tokens = Preg :: split ( '#(?:^|\n*)--([A-Z-]+)--\n#' , file_get_contents ( $file ), - 1 , PREG_SPLIT_DELIM_CAPTURE );
2020-10-01 14:42:02 +00:00
/** @var array<string, bool> $sectionInfo */
$sectionInfo = array (
'TEST' => true ,
'REQUEST' => true ,
'POOL-BEFORE' => true ,
'POOL-AFTER' => true ,
);
$section = null ;
$data = array ();
foreach ( $tokens as $i => $token ) {
if ( null === $section && empty ( $token )) {
continue ; // skip leading blank
}
if ( null === $section ) {
if ( ! isset ( $sectionInfo [ $token ])) {
throw new \RuntimeException ( sprintf (
'The test file "%s" must not contain a section named "%s".' ,
str_replace ( $fixturesDir . '/' , '' , $file ),
$token
));
}
$section = $token ;
continue ;
}
$sectionData = $token ;
$data [ $section ] = $sectionData ;
$section = $sectionData = null ;
}
foreach ( $sectionInfo as $section => $required ) {
if ( $required && ! isset ( $data [ $section ])) {
throw new \RuntimeException ( sprintf (
'The test file "%s" must have a section named "%s".' ,
str_replace ( $fixturesDir . '/' , '' , $file ),
$section
));
}
}
return $data ;
}
/**
* @ param BasePackage [] $packages
* @ return string []
*/
2022-02-18 10:22:01 +00:00
private function reducePackagesInfoForComparison ( array $packages ) : array
2020-10-01 14:42:02 +00:00
{
$packagesInfo = array ();
foreach ( $packages as $package ) {
$packagesInfo [] = $package -> getName () . '@' . $package -> getVersion () . ( $package instanceof AliasPackage ? ' (alias of ' . $package -> getAliasOf () -> getVersion () . ')' : '' );
}
sort ( $packagesInfo );
return $packagesInfo ;
}
/**
* @ param mixed [][] $packagesData
* @ return BasePackage []
*/
2022-02-18 10:22:01 +00:00
private function loadPackages ( array $packagesData ) : array
2020-10-01 14:42:02 +00:00
{
$packages = array ();
foreach ( $packagesData as $packageData ) {
$packages [] = $package = $this -> loadPackage ( $packageData );
if ( $package instanceof AliasPackage ) {
$packages [] = $package -> getAliasOf ();
}
}
return $packages ;
}
/**
* @ param mixed [] $packageData
* @ return BasePackage
*/
2022-02-18 10:22:01 +00:00
private function loadPackage ( array $packageData ) : BasePackage
2020-10-01 14:42:02 +00:00
{
$loader = new ArrayLoader ();
2022-02-18 07:50:11 +00:00
2020-10-01 14:42:02 +00:00
return $loader -> load ( $packageData );
}
}