Newer
Older

Adam G-H
committed
<?php
declare(strict_types = 1);

Adam G-H
committed
namespace Drupal\Tests\package_manager\Kernel;

Ted Bowman
committed
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
use Drupal\fixture_manipulator\FixtureManipulator;
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\InstalledPackagesList;
use Drupal\Tests\package_manager\Traits\InstalledPackagesListTrait;
use Drupal\package_manager\PathLocator;

Adam G-H
committed
/**

Ted Bowman
committed
* @coversDefaultClass \Drupal\fixture_manipulator\FixtureManipulator
*

Adam G-H
committed
* @group package_manager
*/

Ted Bowman
committed
class FixtureManipulatorTest extends PackageManagerKernelTestBase {

Adam G-H
committed
use InstalledPackagesListTrait;

Adam G-H
committed
/**
* The root directory of the test project.

Adam G-H
committed
*
* @var string
*/
private string $dir;

Ted Bowman
committed
/**
* The exception expected in ::tearDown() of this test.
*
* @var \Exception
*/
private \Exception $expectedTearDownException;

Ted Bowman
committed
/**
* The Composer inspector service.

Ted Bowman
committed
*
* @var \Drupal\package_manager\ComposerInspector

Ted Bowman
committed
*/
private ComposerInspector $inspector;

Ted Bowman
committed
/**
* The original fixture package list at the start of the test.

Ted Bowman
committed
*
* @var \Drupal\package_manager\InstalledPackagesList

Ted Bowman
committed
*/
private InstalledPackagesList $originalFixturePackages;

Ted Bowman
committed

Adam G-H
committed
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->dir = $this->container->get(PathLocator::class)->getProjectRoot();

Adam G-H
committed
$this->inspector = $this->container->get(ComposerInspector::class);

Ted Bowman
committed

Ted Bowman
committed
$manipulator = new ActiveFixtureManipulator();
$manipulator
->addPackage([
'name' => 'my/package',
'type' => 'library',

Wim Leers
committed
'version' => '1.2.3',

Ted Bowman
committed
])
->addPackage(
[
'name' => 'my/dev-package',
'version' => '2.1.0',
'type' => 'library',
],
TRUE
)
->commitChanges();
$this->originalFixturePackages = $this->inspector->getInstalledPackagesList($this->dir);

Adam G-H
committed
}
/**
* @covers ::addPackage
*/
public function testAddPackage(): void {
// Packages cannot be added without a name.

Ted Bowman
committed
foreach (['name', 'type'] as $require_key) {
// Make a package that is missing the required key.
$package = array_diff_key(
[
'name' => 'Any old name',
'type' => 'Any old type',
],
[$require_key => '']
);
try {
$manipulator = new ActiveFixtureManipulator();
$manipulator->addPackage($package)
->commitChanges();
$this->fail("Adding a package without the '$require_key' should raise an error.");
}
catch (\UnexpectedValueException $e) {
$this->assertSame("The '$require_key' is required when calling ::addPackage().", $e->getMessage());
}

Ted Bowman
committed
}
// We should get a helpful error if the name is not a valid package name.
try {
$manipulator = new ActiveFixtureManipulator();
$manipulator->addPackage([
'name' => 'my_drupal_module',
'type' => 'drupal-module',
])
->commitChanges();
$this->fail('Trying to add a package with an invalid name should raise an error.');
}
catch (\UnexpectedValueException $e) {
$this->assertSame("'my_drupal_module' is not a valid package name.", $e->getMessage());
}

Adam G-H
committed
// We should not be able to add an existing package.
try {

Ted Bowman
committed
$manipulator = new ActiveFixtureManipulator();
$manipulator->addPackage([

Ted Bowman
committed
'name' => 'my/package',
'type' => 'library',

Ted Bowman
committed
])
->commitChanges();

Adam G-H
committed
$this->fail('Trying to add an existing package should raise an error.');
}

Ted Bowman
committed
catch (\LogicException $e) {

Adam G-H
committed
$this->assertStringContainsString("Expected package 'my/package' to not be installed, but it was.", $e->getMessage());
}
// Ensure that none of the failed calls to ::addPackage() changed the installed
// packages.
$this->assertPackageListsEqual($this->originalFixturePackages, $this->inspector->getInstalledPackagesList($this->dir));
$root_info = $this->inspector->getRootPackageInfo($this->dir);
$this->assertSame(
['drupal/core-dev', 'my/dev-package'],
array_keys($root_info['devRequires'])
);

Adam G-H
committed
}
/**

omkar podey
committed
* @covers ::modifyPackageConfig

Adam G-H
committed
*/

Wim Leers
committed
public function testModifyPackageConfig(): void {
// Assert ::modifyPackage() works with a package in an existing fixture not
// created by ::addPackage().
$decode_composer_json = function ($package_name): array {
return json_decode(file_get_contents($this->dir . "/vendor/$package_name/composer.json"), TRUE, flags: JSON_THROW_ON_ERROR);
};
$original_composer_json = $decode_composer_json('my/dev-package');
(new ActiveFixtureManipulator())
// @see ::setUp()

Wim Leers
committed
->modifyPackageConfig('my/dev-package', '2.1.0', ['description' => 'something else'], TRUE)
->commitChanges();

Wim Leers
committed
// Verify that the package is indeed properly installed.
$this->assertSame('2.1.0', $this->inspector->getInstalledPackagesList($this->dir)['my/dev-package']?->version);

Wim Leers
committed
// Verify that the original exists, but has no description.
$this->assertSame('my/dev-package', $original_composer_json['name']);
$this->assertArrayNotHasKey('description', $original_composer_json);

Wim Leers
committed
// Verify that the description was updated.
$this->assertSame('something else', $decode_composer_json('my/dev-package')['description']);

Adam G-H
committed

Ted Bowman
committed
(new ActiveFixtureManipulator())
// Add a key to an existing package.

Wim Leers
committed
->modifyPackageConfig('my/package', '1.2.3', ['extra' => ['foo' => 'bar']])

Ted Bowman
committed
// Change a key in an existing package.
->setVersion('my/dev-package', '3.2.1', TRUE)

Ted Bowman
committed
->commitChanges();
$this->assertSame(['foo' => 'bar'], $decode_composer_json('my/package')['extra']);
$this->assertSame('3.2.1', $this->inspector->getInstalledPackagesList($this->dir)['my/dev-package']?->version);

Adam G-H
committed
}
/**
* @covers ::removePackage
*/
public function testRemovePackage(): void {
// We should not be able to remove a package that's not installed.
try {

Ted Bowman
committed
(new ActiveFixtureManipulator())
->removePackage('junk/drawer')
->commitChanges();

Adam G-H
committed
$this->fail('Removing a non-existent package should raise an error.');
}

Ted Bowman
committed
catch (\LogicException $e) {
$this->assertStringContainsString('junk/drawer is not required in your composer.json and has not been remove', $e->getMessage());

Adam G-H
committed
}
// Remove the 2 packages that were added in ::setUp().

Ted Bowman
committed
(new ActiveFixtureManipulator())
->removePackage('my/package')
->removePackage('my/dev-package', TRUE)

Ted Bowman
committed
->commitChanges();
$expected_packages = $this->originalFixturePackages->getArrayCopy();
unset($expected_packages['my/package'], $expected_packages['my/dev-package']);
$expected_list = new InstalledPackagesList($expected_packages);
$this->assertPackageListsEqual($expected_list, $this->inspector->getInstalledPackagesList($this->dir));
$root_info = $this->inspector->getRootPackageInfo($this->dir);
$this->assertSame(
['drupal/core-dev'],
array_keys($root_info['devRequires'])
);

Adam G-H
committed
}

Ted Bowman
committed
/**
* Test that an exception is thrown if ::commitChanges() is not called.
*/
public function testActiveManipulatorNoCommitError(): void {

Ted Bowman
committed
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('commitChanges() must be called.');
(new ActiveFixtureManipulator())
->setVersion('drupal/core', '1.2.3');
}

omkar podey
committed
/**
* @covers ::addDotGitFolder
*/
public function testAddDotGitFolder() {
$path_locator = $this->container->get(PathLocator::class);
$project_root = $path_locator->getProjectRoot();

omkar podey
committed
$this->assertFalse(is_dir($project_root . "/relative/path/.git"));
// We should not be able to add a git folder to a non-existing directory.
try {
(new FixtureManipulator())
->addDotGitFolder($project_root . "/relative/path")
->commitChanges($project_root);
$this->fail('Trying to create a .git directory that already exists should raise an error.');
}
catch (\LogicException $e) {
$this->assertSame('No directory exists at ' . $project_root . '/relative/path.', $e->getMessage());
}
mkdir($project_root . "/relative/path", 0777, TRUE);

omkar podey
committed
$fixture_manipulator = (new FixtureManipulator())
->addPackage([
'name' => 'relative/project_path',
'type' => 'drupal-module',
])
->addDotGitFolder($path_locator->getVendorDirectory() . "/relative/project_path")

omkar podey
committed
->addDotGitFolder($project_root . "/relative/path");
$this->assertTrue(!is_dir($project_root . "/relative/project_path/.git"));
$fixture_manipulator->commitChanges($project_root);
$this->assertTrue(is_dir($project_root . "/relative/path/.git"));
// We should not be able to create already existing directory.
try {
(new FixtureManipulator())
->addDotGitFolder($project_root . "/relative/path")
->commitChanges($project_root);
$this->fail('Trying to create a .git directory that already exists should raise an error.');
}
catch (\LogicException $e) {
$this->assertStringContainsString("A .git directory already exists at " . $project_root, $e->getMessage());
}
}

Ted Bowman
committed
/**
* Tests that the stage manipulator throws an exception if not committed.
*/
public function testStagedFixtureNotCommitted(): void {
$this->expectedTearDownException = new \LogicException('The StageFixtureManipulator has arguments that were not cleared. This likely means that the PostCreateEvent was never fired.');
$this->getStageFixtureManipulator()->setVersion('any-org/any-package', '3.2.1');
}
/**
* {@inheritdoc}

omkar podey
committed
*
* @todo Remove the line below when https://github.com/phpstan/phpstan-phpunit/issues/187 is fixed.
* @phpstan-ignore-next-line

Ted Bowman
committed
*/
protected function tearDown(): void {
try {
parent::tearDown();
}
catch (\Exception $exception) {
if (!(get_class($exception) === get_class($this->expectedTearDownException) && $exception->getMessage() === $this->expectedTearDownException->getMessage())) {
throw $exception;
}
}

Ted Bowman
committed
}