* Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Test; use Composer\Autoload\ClassLoader; use Composer\InstalledVersions; use Composer\Semver\VersionParser; class InstalledVersionsTest extends TestCase { /** @var array */ private static $previousRegisteredLoaders; /** * @var string */ private $root; public static function setUpBeforeClass(): void { // disable multiple-ClassLoader-based checks of InstalledVersions by making it seem like no // class loaders are registered $prop = new \ReflectionProperty('Composer\Autoload\ClassLoader', 'registeredLoaders'); $prop->setAccessible(true); self::$previousRegisteredLoaders = $prop->getValue(); $prop->setValue(null, []); } public static function tearDownAfterClass(): void { $prop = new \ReflectionProperty('Composer\Autoload\ClassLoader', 'registeredLoaders'); $prop->setAccessible(true); $prop->setValue(null, self::$previousRegisteredLoaders); InstalledVersions::reload(null); // @phpstan-ignore argument.type } public function setUp(): void { $this->root = self::getUniqueTmpDirectory(); $dir = $this->root; InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed_relative.php'); } public function testGetInstalledPackages(): void { $names = [ '__root__', 'a/provider', 'a/provider2', 'b/replacer', 'c/c', 'foo/impl', 'foo/impl2', 'foo/replaced', 'meta/package', ]; $this->assertSame($names, InstalledVersions::getInstalledPackages()); } /** * @dataProvider isInstalledProvider */ public function testIsInstalled(bool $expected, string $name, bool $includeDevRequirements = true): void { $this->assertSame($expected, InstalledVersions::isInstalled($name, $includeDevRequirements)); } public static function isInstalledProvider(): array { return [ [true, 'foo/impl'], [true, 'foo/replaced'], [true, 'c/c'], [false, 'c/c', false], [true, '__root__'], [true, 'b/replacer'], [false, 'not/there'], [true, 'meta/package'], ]; } /** * @dataProvider satisfiesProvider */ public function testSatisfies(bool $expected, string $name, string $constraint): void { $this->assertSame($expected, InstalledVersions::satisfies(new VersionParser, $name, $constraint)); } public static function satisfiesProvider(): array { return [ [true, 'foo/impl', '1.5'], [true, 'foo/impl', '1.2'], [true, 'foo/impl', '^1.0'], [true, 'foo/impl', '^3 || ^2'], [false, 'foo/impl', '^3'], [true, 'foo/replaced', '3.5'], [true, 'foo/replaced', '^3.2'], [false, 'foo/replaced', '4.0'], [true, 'c/c', '3.0.0'], [true, 'c/c', '^3'], [false, 'c/c', '^3.1'], [true, '__root__', 'dev-master'], [true, '__root__', '^1.10'], [false, '__root__', '^2'], [true, 'b/replacer', '^2.1'], [false, 'b/replacer', '^2.3'], [true, 'a/provider2', '^1.2'], [true, 'a/provider2', '^1.4'], [false, 'a/provider2', '^1.5'], ]; } /** * @dataProvider getVersionRangesProvider */ public function testGetVersionRanges(string $expected, string $name): void { $this->assertSame($expected, InstalledVersions::getVersionRanges($name)); } public static function getVersionRangesProvider(): array { return [ ['dev-master || 1.10.x-dev', '__root__'], ['^1.1 || 1.2 || 1.4 || 2.0', 'foo/impl'], ['2.2 || 2.0', 'foo/impl2'], ['^3.0', 'foo/replaced'], ['1.1', 'a/provider'], ['1.2 || 1.4', 'a/provider2'], ['2.2', 'b/replacer'], ['3.0', 'c/c'], ]; } /** * @dataProvider getVersionProvider */ public function testGetVersion(?string $expected, string $name): void { $this->assertSame($expected, InstalledVersions::getVersion($name)); } public static function getVersionProvider(): array { return [ ['dev-master', '__root__'], [null, 'foo/impl'], [null, 'foo/impl2'], [null, 'foo/replaced'], ['1.1.0.0', 'a/provider'], ['1.2.0.0', 'a/provider2'], ['2.2.0.0', 'b/replacer'], ['3.0.0.0', 'c/c'], ]; } /** * @dataProvider getPrettyVersionProvider */ public function testGetPrettyVersion(?string $expected, string $name): void { $this->assertSame($expected, InstalledVersions::getPrettyVersion($name)); } public static function getPrettyVersionProvider(): array { return [ ['dev-master', '__root__'], [null, 'foo/impl'], [null, 'foo/impl2'], [null, 'foo/replaced'], ['1.1', 'a/provider'], ['1.2', 'a/provider2'], ['2.2', 'b/replacer'], ['3.0', 'c/c'], ]; } public function testGetVersionOutOfBounds(): void { self::expectException('OutOfBoundsException'); InstalledVersions::getVersion('not/installed'); } public function testGetRootPackage(): void { $this->assertSame([ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => 'sourceref-by-default', 'type' => 'library', 'install_path' => $this->root . '/./', 'aliases' => [ '1.10.x-dev', ], 'dev' => true, ], InstalledVersions::getRootPackage()); } /** * @group legacy */ public function testGetRawData(): void { $dir = $this->root; $this->assertSame(require __DIR__.'/Repository/Fixtures/installed_relative.php', InstalledVersions::getRawData()); } /** * @dataProvider getReferenceProvider */ public function testGetReference(?string $expected, string $name): void { $this->assertSame($expected, InstalledVersions::getReference($name)); } public static function getReferenceProvider(): array { return [ ['sourceref-by-default', '__root__'], [null, 'foo/impl'], [null, 'foo/impl2'], [null, 'foo/replaced'], ['distref-as-no-source', 'a/provider'], ['distref-as-installed-from-dist', 'a/provider2'], [null, 'b/replacer'], [null, 'c/c'], ]; } public function testGetInstalledPackagesByType(): void { $names = [ '__root__', 'a/provider', 'a/provider2', 'b/replacer', 'c/c', ]; $this->assertSame($names, \Composer\InstalledVersions::getInstalledPackagesByType('library')); } public function testGetInstallPath(): void { $this->assertSame(realpath($this->root), realpath(\Composer\InstalledVersions::getInstallPath('__root__'))); $this->assertSame('/foo/bar/vendor/c/c', \Composer\InstalledVersions::getInstallPath('c/c')); $this->assertNull(\Composer\InstalledVersions::getInstallPath('foo/impl')); } }