Skip to content

Commit

Permalink
Merge pull request #167 from PHPCSStandards/feature/tests-new-preexis…
Browse files Browse the repository at this point in the history
…tingphpcsinstalledpathsconfig-test

Tests: add new `PreexistingPHPCSInstalledPathsConfigTest` + bug fix
  • Loading branch information
Potherca committed Apr 18, 2022
2 parents 27d906d + c01bd6f commit 30297a0
Show file tree
Hide file tree
Showing 2 changed files with 323 additions and 17 deletions.
47 changes: 30 additions & 17 deletions src/Plugin.php
Expand Up @@ -234,9 +234,9 @@ private function loadInstalledPaths()
{
if ($this->isPHPCodeSnifferInstalled() === true) {
$this->processExecutor->execute(
'phpcs --config-show',
$this->getPhpcsCommand() . ' --config-show',
$output,
$this->composer->getConfig()->get('bin-dir')
$this->getPHPCodeSnifferInstallPath()
);

$regex = sprintf(self::PHPCS_CONFIG_REGEX, self::PHPCS_CONFIG_KEY);
Expand Down Expand Up @@ -287,27 +287,16 @@ private function saveInstalledPaths()
self::PHPCS_CONFIG_KEY
);

// Determine the path to the main PHPCS file.
$phpcsPath = $this->getPHPCodeSnifferInstallPath();
if (file_exists($phpcsPath . '/bin/phpcs') === true) {
// PHPCS 3.x.
$phpcsExecutable = './bin/phpcs';
} else {
// PHPCS 2.x.
$phpcsExecutable = './scripts/phpcs';
}

// Okay, lets rock!
$command = vsprintf(
'%s %s %s',
'%s %s',
array(
'php executable' => $this->getPhpExecCommand(),
'phpcs executable' => $phpcsExecutable,
'arguments' => implode(' ', $arguments),
'phpcs command' => $this->getPhpcsCommand(),
'arguments' => implode(' ', $arguments),
)
);

$exitCode = $this->processExecutor->execute($command, $configResult, $phpcsPath);
$exitCode = $this->processExecutor->execute($command, $configResult, $this->getPHPCodeSnifferInstallPath());
if ($exitCode === 0) {
$exitCode = $this->verifySaveSuccess();
}
Expand Down Expand Up @@ -359,6 +348,30 @@ private function verifySaveSuccess()
return $exitCode;
}

/**
* Get the command to call PHPCS.
*/
protected function getPhpcsCommand()
{
// Determine the path to the main PHPCS file.
$phpcsPath = $this->getPHPCodeSnifferInstallPath();
if (file_exists($phpcsPath . '/bin/phpcs') === true) {
// PHPCS 3.x.
$phpcsExecutable = './bin/phpcs';
} else {
// PHPCS 2.x.
$phpcsExecutable = './scripts/phpcs';
}

return vsprintf(
'%s %s',
array(
'php executable' => $this->getPhpExecCommand(),
'phpcs executable' => $phpcsExecutable,
)
);
}

/**
* Get the path to the current PHP version being used.
*
Expand Down
293 changes: 293 additions & 0 deletions tests/IntegrationTest/PreexistingPHPCSInstalledPathsConfigTest.php
@@ -0,0 +1,293 @@
<?php

/**
* This file is part of the Dealerdirect PHP_CodeSniffer Standards
* Composer Installer Plugin package.
*
* @copyright 2022 PHPCodeSniffer Composer Installer Contributors
* @license MIT
*/

namespace Dealerdirect\Composer\Plugin\Installers\PHPCodeSniffer\Tests\IntegrationTest;

use Dealerdirect\Composer\Plugin\Installers\PHPCodeSniffer\Tests\PHPCSVersions;
use Dealerdirect\Composer\Plugin\Installers\PHPCodeSniffer\Tests\TestCase;
use RuntimeException;

/**
* Test correctly handling a pre-existing PHPCS configuration file, which includes a valid `installed_paths` setting.
*
* These tests verify:
* - That the plugin does not remove or alter any valid paths which already existed in `installed_paths`.
* - That the plugin removes invalid paths which already existed in `installed_paths`.
*
* Note: it is important to run these tests against multiple PHPCS versions, as the output returned
* by the `--config-show` command has changed across versions and we need to make sure that
* the plugin handles this correctly in all supported PHPCS versions.
*/
final class PreexistingPHPCSInstalledPathsConfigTest extends TestCase
{
private $tempExtraStndsSubdir = '/extrastnds/dummy-subdir';

private $tempExtraStndsPath;

private $composerConfig = array(
'name' => 'phpcs-composer-installer/preexisting-config-test',
'require-dev' => array(
'squizlabs/php_codesniffer' => null,
'dealerdirect/phpcodesniffer-composer-installer' => '*',
),
);

/**
* Set up test environment before each test.
*/
protected function set_up()
{
$this->createTestEnvironment();

/*
* Create an extra directory in the test environment, but outside of the directory used
* in the test (where Composer is run) and copy an external standard fixture to it.
*/
$this->tempExtraStndsPath = static::$tempDir . $this->tempExtraStndsSubdir;

// Create all needed subdirectories in one go.
$path = $this->tempExtraStndsPath . '/DummySubDir';
if (mkdir($path, 0766, true) === false || is_dir($path) === false) {
throw new RuntimeException("Failed to create the $path directory for the test");
}

// We only need the ruleset.xml file for the standard to be valid.
copy(
dirname(__DIR__) . '/fixtures/dummy-subdir/DummySubDir/ruleset.xml',
$this->tempExtraStndsPath . '/DummySubDir/ruleset.xml'
);
}

/**
* Clean up after each test.
*/
protected function tear_down()
{
$this->removeTestEnvironment();
}

/**
* Test correctly handling a pre-existing PHPCS configuration file which includes a pre-set,
* valid `installed_paths`.
*
* @dataProvider dataPHPCSVersions
*
* @param string $phpcsVersion PHPCS version to use in this test.
* This version is randomly selected from the PHPCS versions compatible
* with the PHP version used in the test.
*
* @return void
*/
public function testPreexistingValidInstalledPathsConfigIsKeptIntact($phpcsVersion)
{
$config = $this->composerConfig;
$config['require-dev']['squizlabs/php_codesniffer'] = $phpcsVersion;

$this->writeComposerJsonFile($config, static::$tempGlobalPath);

/*
* 1. Install PHPCS and the plugin.
*/
$this->assertExecute(
'composer global install',
0, // Expected exit code.
null, // No stdout expectation.
null, // No stderr expectation.
'Failed to install PHPCS.'
);

/*
* 2. Set the installed_paths and verify it is registered correctly.
*/
$command = sprintf(
'"vendor/bin/phpcs" --config-set installed_paths %s',
escapeshellarg($this->tempExtraStndsPath)
);
$result = $this->executeCliCommand($command, static::$tempGlobalPath);
$this->assertSame(
0,
$result['exitcode'],
'Exitcode for "phpcs --config-set installed_paths" did not match 0'
);

// Verify that the config contains the newly set value.
$result = $this->executeCliCommand('"vendor/bin/phpcs" --config-show', static::$tempGlobalPath);
$this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs --config-show" did not match 0 (first run)');

$expected = array(
$this->tempExtraStndsPath,
);

$this->assertSame(
$expected,
$this->configShowToPathsArray($result['stdout']),
'PHPCS configuration does not show the manually set installed_paths correctly'
);

/*
* 3. Install an external standard.
*/
$expectedStdOut = $this->willPluginOutputShow() ? 'PHP CodeSniffer Config installed_paths set to ' : null;
$command = 'composer global require --dev phpcs-composer-installer/dummy-subdir --no-ansi -v';
$this->assertExecute(
$command,
0, // Expected exit code.
$expectedStdOut, // Expectation for stdout.
null, // No stderr expectation.
'Failed to install Dummy subdir standard.'
);

// Verify that the originally set path is retained and the new standard is registered correctly as well.
$result = $this->executeCliCommand('"vendor/bin/phpcs" --config-show', static::$tempGlobalPath);
$this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs --config-show" did not match 0 (second run)');


$expected = array(
$this->tempExtraStndsPath,
'/phpcs-composer-installer/dummy-subdir',
);
sort($expected, \SORT_NATURAL);

$this->assertSame(
$expected,
$this->configShowToPathsArray($result['stdout']),
'Paths as updated by the plugin does not contain the expected paths'
);
}

/**
* Test correctly handling a pre-existing PHPCS configuration file which includes both
* a pre-set, valid path, as well as an invalid path in `installed_paths`.
*
* @dataProvider dataPHPCSVersions
*
* @param string $phpcsVersion PHPCS version to use in this test.
* This version is randomly selected from the PHPCS versions compatible
* with the PHP version used in the test.
*
* @return void
*/
public function testPreexistingInvalidInstalledPathsConfigIsRemoved($phpcsVersion)
{
$config = $this->composerConfig;
$config['require-dev']['squizlabs/php_codesniffer'] = $phpcsVersion;

$this->writeComposerJsonFile($config, static::$tempLocalPath);

/*
* 1. Install PHPCS and the plugin.
*/
$this->assertExecute(
sprintf('composer install -v --working-dir=%s', escapeshellarg(static::$tempLocalPath)),
0, // Expected exit code.
null, // No stdout expectation.
null, // No stderr expectation.
'Failed to install PHPCS.'
);

/*
* 2. Set the installed_paths and verify it is registered correctly.
*/
$command = sprintf(
'"vendor/bin/phpcs" --config-set installed_paths %s',
escapeshellarg($this->tempExtraStndsPath)
);
$result = $this->executeCliCommand($command, static::$tempLocalPath);
$this->assertSame(
0,
$result['exitcode'],
'Exitcode for "phpcs --config-set installed_paths" did not match 0'
);

/*
* Manipulate the value of installed_paths as registered in PHPCS.
*
* Note: for the test we do this "manually". In real life, this may be a standard which
* used to be installed, but was removed without the installed_paths having been updated
* in PHPCS (prior to the plugin being used).
*
* Also note: depending on the OS and the PHP version, passing an invalid path to `--config-set`
* will error on an exception from the DirectoryIterator as used by PHPCS itself.
* The manual setting prevents this exception, but still allows us to test this use-case.
*/
$confFile = static::$tempLocalPath . '/vendor/squizlabs/php_codesniffer/CodeSniffer.conf';
$confContents = file_get_contents($confFile);
$this->assertNotFalse($confContents);
$confContents = str_replace(
$this->tempExtraStndsSubdir,
$this->tempExtraStndsSubdir . ',path/to/somecloned-stnd',
$confContents
);
$this->assertNotFalse(file_put_contents($confFile, $confContents));

// Verify that the config contains the newly set value.
$result = $this->executeCliCommand('"vendor/bin/phpcs" --config-show', static::$tempLocalPath);
$this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs --config-show" did not match 0 (first run)');

$expected = array(
$this->tempExtraStndsPath,
'path/to/somecloned-stnd',
);
sort($expected, \SORT_NATURAL);

$this->assertSame(
$expected,
$this->configShowToPathsArray($result['stdout']),
'PHPCS configuration does not show the manually set installed_paths correctly'
);

/*
* 3. Install an external standard.
*/
$expectedStdOut = $this->willPluginOutputShow() ? 'PHP CodeSniffer Config installed_paths set to ' : null;
$command = sprintf(
'composer require --dev phpcs-composer-installer/dummy-subdir --no-ansi -v --working-dir=%s',
escapeshellarg(static::$tempLocalPath)
);
$this->assertExecute(
$command,
0, // Expected exit code.
$expectedStdOut, // Expectation for stdout.
null, // No stderr expectation.
'Failed to install Dummy subdir standard.'
);

/*
* Verify that the valid preset path is retained, that the invalid path is removed
* and the new standard is registered correctly.
*/
$result = $this->executeCliCommand('"vendor/bin/phpcs" --config-show', static::$tempLocalPath);
$this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs --config-show" did not match 0 (second run)');

$expected = array(
$this->tempExtraStndsPath,
'/phpcs-composer-installer/dummy-subdir',
);
sort($expected, \SORT_NATURAL);

$this->assertSame(
$expected,
$this->configShowToPathsArray($result['stdout']),
'Paths as updated by the plugin does not contain the expected paths'
);
}

/**
* Data provider.
*
* @return array
*/
public function dataPHPCSVersions()
{
// Test against the highest and lowest supported PHPCS version for each major + `master` + PHPCS 4.x dev.
$versions = PHPCSVersions::getHighLowEachMajor(true, true);
return PHPCSVersions::toDataprovider($versions);
}
}

0 comments on commit 30297a0

Please sign in to comment.