diff --git a/tests/IntegrationTest/RegisterExternalStandardsTest.php b/tests/IntegrationTest/RegisterExternalStandardsTest.php index e2841dd6..63b5e62b 100644 --- a/tests/IntegrationTest/RegisterExternalStandardsTest.php +++ b/tests/IntegrationTest/RegisterExternalStandardsTest.php @@ -27,6 +27,22 @@ final class RegisterExternalStandardsTest extends TestCase ), ); + private $configOneStandardMultiRuleset = array( + 'name' => 'phpcs-composer-installer/register-external-stnds-multistnd', + 'require-dev' => array( + 'squizlabs/php_codesniffer' => null, + 'phpcs-composer-installer/multistandard' => '*', + ), + ); + + private $configOneStandardInSrcSubdir = array( + 'name' => 'phpcs-composer-installer/register-external-stnds-in-src-subdir', + 'require-dev' => array( + 'squizlabs/php_codesniffer' => null, + 'phpcs-composer-installer/dummy-src' => '*', + ), + ); + /** * Set up test environment before each test. */ @@ -188,4 +204,141 @@ public function dataRegisterOneStandard() $versions = PHPCSVersions::get(2, true, true); return PHPCSVersions::toDataprovider($versions); } + + /** + * Test registering one external standard with multiple rulesets. + * + * @dataProvider dataRegisterOneStandardMultipleRulesets + * + * @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 testRegisterOneStandardWithMultipleRulesets($phpcsVersion) + { + $config = $this->configOneStandardMultiRuleset; + $config['require-dev']['squizlabs/php_codesniffer'] = $phpcsVersion; + + $this->writeComposerJsonFile($config, static::$tempLocalPath); + + // Install the dependencies and verify that the plugin has run. + $expectedStdOut = $this->willPluginOutputShow() ? 'PHP CodeSniffer Config installed_paths set to ' : null; + $this->assertExecute( + sprintf('composer install -v --no-ansi --working-dir=%s', escapeshellarg(static::$tempLocalPath)), + 0, // Expected exit code. + $expectedStdOut, // Expectation for stdout. + null, // No stderr expectation. + 'Failed to install dependencies.' + ); + + // Verify that only the one path is registered. + $result = $this->executeCliCommand('"vendor/bin/phpcs" --config-show', static::$tempLocalPath); + $this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs --config-show" did not match 0'); + + $expected = array( + '/phpcs-composer-installer/multistandard', + ); + + $this->assertSame( + $expected, + $this->configShowToPathsArray($result['stdout']), + 'Paths as updated by the plugin does not contain the expected path' + ); + + // Verify that PHPCS sees all three external standards. + $result = $this->executeCliCommand('"vendor/bin/phpcs" -i', static::$tempLocalPath); + $this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs -i" did not match 0'); + + $expected = PHPCSVersions::getStandards($phpcsVersion); + $expected[] = 'MyFirstStandard'; + $expected[] = 'MySecondStandard'; + $expected[] = 'My-Third-Standard'; + sort($expected, \SORT_NATURAL); + + $this->assertSame( + $expected, + $this->standardsPhraseToArray($result['stdout']), + 'Installed standards do not match the expected standards.' + ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataRegisterOneStandardMultipleRulesets() + { + // Test against the highest and lowest supported PHPCS version of each major + PHPCS 4.x dev. + $versions = PHPCSVersions::getHighLowEachMajor(false, true); + return PHPCSVersions::toDataprovider($versions); + } + + /** + * Test registering an external standard which has the ruleset in a subdirectory nested in `src`. + * + * @dataProvider dataRandomPHPCSVersion + * + * @param string $phpcsVersion PHPCS version to use in this test. + * + * @return void + */ + public function testRegisterOneStandardInSrcSubdir($phpcsVersion) + { + $config = $this->configOneStandardInSrcSubdir; + $config['require-dev']['squizlabs/php_codesniffer'] = $phpcsVersion; + + $this->writeComposerJsonFile($config, static::$tempGlobalPath); + + // Install the dependencies and verify that the plugin has run. + $this->assertExecute( + 'composer global install -v --no-ansi', + 0, // Expected exit code. + 'PHP CodeSniffer Config installed_paths set to ', // Expectation for stdout. + null, // No stderr expectation. + 'Failed to install dependencies.' + ); + + // Verify that the path for the directory above the ruleset is registered. + $result = $this->executeCliCommand('"vendor/bin/phpcs" --config-show', static::$tempGlobalPath); + $this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs --config-show" did not match 0'); + + $expected = array( + '/phpcs-composer-installer/dummy-src/src', + ); + + $this->assertSame( + $expected, + $this->configShowToPathsArray($result['stdout']), + 'Paths as updated by the plugin does not contain the expected path' + ); + + // Verify that PHPCS sees the external standard. + $result = $this->executeCliCommand('"vendor/bin/phpcs" -i', static::$tempGlobalPath); + $this->assertSame(0, $result['exitcode'], 'Exitcode for "phpcs -i" did not match 0'); + + $expected = PHPCSVersions::getStandards($phpcsVersion); + $expected[] = 'DummySrcSubDir'; + sort($expected, \SORT_NATURAL); + + $this->assertSame( + $expected, + $this->standardsPhraseToArray($result['stdout']), + 'Installed standards do not match the expected standards.' + ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataRandomPHPCSVersion() + { + // Test against one random PHPCS version. + $versions = array(PHPCSVersions::getRandom(true, true)); + return PHPCSVersions::toDataprovider($versions); + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 57b00c04..540e9112 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -579,4 +579,47 @@ protected function standardsPhraseToArray($phrase) return $standards; } + + /** + * Retrieve a list of the paths registered with PHPCS based on the output of `phpcs --config-show`. + * + * @param string $configShow The `stdout` output of `phpcs --config-show`. + * + * @return array Numerically indexed array of paths, stripped of absolute/relative path differences, + * natural sort applied. + * + * @throws RuntimeException When the passed argument is not a string. + */ + protected function configShowToPathsArray($configShow) + { + if (is_string($configShow) === false) { + throw new RuntimeException('The config-show input must be a string.'); + } + + if (preg_match('`installed_paths:\s+([^\n\r]+)\s+`', $configShow, $matches) !== 1) { + return array(); + } + + $pathsAsArray = explode(',', $matches[1]); + $pathsAsArray = array_map( + function ($value) { + $search = array( + '`^[^\r\n]+/vendor/`', + '`^\.\./\.\./`', + ); + + $replaced = preg_replace($search, '/', $value); + if ($replaced === null) { + return $value; + } + + return trim($replaced); // Trim off whitespace just to be on the safe side. + }, + $pathsAsArray + ); + + sort($pathsAsArray, \SORT_NATURAL); + + return $pathsAsArray; + } } diff --git a/tests/fixtures/README.md b/tests/fixtures/README.md index 6a470872..92944a9c 100644 --- a/tests/fixtures/README.md +++ b/tests/fixtures/README.md @@ -40,3 +40,25 @@ An external PHPCS standard with the `ruleset.xml` file in a subdirectory ("norma | **Includes sniff(s):** | :heavy_checkmark: One sniff - `DummySubDir.Demo.Demo` - which is PHPCS cross-version compatible. | | **Requires the plugin:** | :x: | +### Package name: `phpcs-composer-installer/multistandard` + +**Description:** +An external PHPCS standard with multiple rulesets, each in a subdirectory ("normal" standard setup). + +| Characteristics | Notes | +|--------------------------|------------------------------------------------------------| +| **Standard(s):** | `MyFirstStandard`, `MySecondStandard`, `My-Third-Standard` | +| **Includes sniff(s):** | :x: | +| **Requires the plugin:** | :heavy_checkmark: | + +### Package name: `phpcs-composer-installer/dummy-src` + +**Description:** +An external PHPCS standard with the `ruleset.xml` file in a deeper nested subdirectory. + +| Characteristics | Notes | +|--------------------------|-------------------| +| **Standard(s):** | `DummySrcSubDir` | +| **Includes sniff(s):** | :x: | +| **Requires the plugin:** | :heavy_checkmark: | + diff --git a/tests/fixtures/dummy-src/composer.json b/tests/fixtures/dummy-src/composer.json new file mode 100644 index 00000000..9ded9e25 --- /dev/null +++ b/tests/fixtures/dummy-src/composer.json @@ -0,0 +1,16 @@ +{ + "name" : "phpcs-composer-installer/dummy-src", + "description" : "Dummy PHPCS standard with deeper nested subdirectory ruleset for use in the tests.", + "type" : "phpcodesniffer-standard", + "license" : "MIT", + "require" : { + "php" : ">=5.4", + "squizlabs/php_codesniffer" : "*", + "dealerdirect/phpcodesniffer-composer-installer" : "*" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/tests/fixtures/dummy-src/src/DummySrcSubDir/ruleset.xml b/tests/fixtures/dummy-src/src/DummySrcSubDir/ruleset.xml new file mode 100644 index 00000000..3e434f11 --- /dev/null +++ b/tests/fixtures/dummy-src/src/DummySrcSubDir/ruleset.xml @@ -0,0 +1,5 @@ + + + + Dummy PHPCS standard for testing. + diff --git a/tests/fixtures/multistandard/My-Third-Standard/ruleset.xml b/tests/fixtures/multistandard/My-Third-Standard/ruleset.xml new file mode 100644 index 00000000..ca6a9818 --- /dev/null +++ b/tests/fixtures/multistandard/My-Third-Standard/ruleset.xml @@ -0,0 +1,5 @@ + + + + Dummy PHPCS standard for testing. + diff --git a/tests/fixtures/multistandard/MyFirstStandard/ruleset.xml b/tests/fixtures/multistandard/MyFirstStandard/ruleset.xml new file mode 100644 index 00000000..424ac051 --- /dev/null +++ b/tests/fixtures/multistandard/MyFirstStandard/ruleset.xml @@ -0,0 +1,5 @@ + + + + Dummy PHPCS standard for testing. + diff --git a/tests/fixtures/multistandard/MySecondStandard/ruleset.xml b/tests/fixtures/multistandard/MySecondStandard/ruleset.xml new file mode 100644 index 00000000..462d4141 --- /dev/null +++ b/tests/fixtures/multistandard/MySecondStandard/ruleset.xml @@ -0,0 +1,5 @@ + + + + Dummy PHPCS standard for testing. + diff --git a/tests/fixtures/multistandard/composer.json b/tests/fixtures/multistandard/composer.json new file mode 100644 index 00000000..f56d04c3 --- /dev/null +++ b/tests/fixtures/multistandard/composer.json @@ -0,0 +1,16 @@ +{ + "name" : "phpcs-composer-installer/multistandard", + "description" : "Dummy PHPCS standard with multiple rulesets each in a subdirectory for use in the tests.", + "type" : "phpcodesniffer-standard", + "license" : "MIT", + "require" : { + "php" : ">=5.4", + "squizlabs/php_codesniffer" : "*", + "dealerdirect/phpcodesniffer-composer-installer" : "*" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +}