From 46259381b84d3f858e59a0e46e3d5eda64a8343a Mon Sep 17 00:00:00 2001 From: Dan Wallis Date: Mon, 29 Jul 2024 23:15:20 +0100 Subject: [PATCH 001/192] Correct error code in Squiz.ControlStructures.ForEachLoopDeclaration From what we can determine, this is a typographical error / mistake. It seems that the intention here was to use the same error code for both sides of this if/else block. --- .../Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php b/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php index bd51b265f4..456886b369 100644 --- a/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php +++ b/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php @@ -90,7 +90,7 @@ public function process(File $phpcsFile, $stackPtr) $this->requiredSpacesAfterOpen, $spaceAfterOpen, ]; - $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterOpen', $data); + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterOpen', $data); if ($fix === true) { $padding = str_repeat(' ', $this->requiredSpacesAfterOpen); if ($spaceAfterOpen === 0) { From 40f1a5513399aef5da01dfb280e06e7e39330562 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 31 Jul 2024 05:20:50 +0200 Subject: [PATCH 002/192] :sparkles: New `Generic.WhiteSpace.HereNowdocIdentifierSpacing` sniff New `Generic.WhiteSpace.HereNowdocIdentifierSpacing` sniff which forbids whitespace between the `<<<` and the identifier string in heredoc/nowdoc start tokens. Includes fixer. Includes tests. Includes XML docs. --- .../HereNowdocIdentifierSpacingStandard.xml | 23 +++++++ .../HereNowdocIdentifierSpacingSniff.php | 66 +++++++++++++++++++ .../HereNowdocIdentifierSpacingUnitTest.inc | 25 +++++++ ...eNowdocIdentifierSpacingUnitTest.inc.fixed | 25 +++++++ .../HereNowdocIdentifierSpacingUnitTest.php | 58 ++++++++++++++++ 5 files changed, 197 insertions(+) create mode 100644 src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml create mode 100644 src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php create mode 100644 src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc create mode 100644 src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc.fixed create mode 100644 src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.php diff --git a/src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml b/src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml new file mode 100644 index 0000000000..17cad50f69 --- /dev/null +++ b/src/Standards/Generic/Docs/WhiteSpace/HereNowdocIdentifierSpacingStandard.xml @@ -0,0 +1,23 @@ + + + + + + + << +some text +EOD; + ]]> + + + <<< END +some text +END; + ]]> + + + diff --git a/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php b/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php new file mode 100644 index 0000000000..2296525f3f --- /dev/null +++ b/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php @@ -0,0 +1,66 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; + +class HereNowdocIdentifierSpacingSniff implements Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return [ + T_START_HEREDOC, + T_START_NOWDOC, + ]; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (strpos($tokens[$stackPtr]['content'], ' ') === false + && strpos($tokens[$stackPtr]['content'], "\t") === false + ) { + // Nothing to do. + return; + } + + $error = 'There should be no space between the <<< and the heredoc/nowdoc identifier string'; + $data = [$tokens[$stackPtr]['content']]; + + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceFound', $data); + if ($fix === true) { + $replacement = str_replace([' ', "\t"], '', $tokens[$stackPtr]['content']); + $phpcsFile->fixer->replaceToken($stackPtr, $replacement); + } + + }//end process() + + +}//end class diff --git a/src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc b/src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc new file mode 100644 index 0000000000..0121118a57 --- /dev/null +++ b/src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc @@ -0,0 +1,25 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Tests\WhiteSpace; + +use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; + +/** + * Unit test class for the LanguageConstructSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\HereNowdocIdentifierSpacingSniff + */ +final class HereNowdocIdentifierSpacingUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array + */ + public function getErrorList() + { + return [ + 11 => 1, + 15 => 1, + 19 => 1, + 23 => 1, + ]; + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @return array + */ + public function getWarningList() + { + return []; + + }//end getWarningList() + + +}//end class From a57d5f956bb866a5c3aeaa58e51e4c81d902e513 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 29 Sep 2024 23:58:25 +0200 Subject: [PATCH 003/192] README/Changelog: fix a few URLs which have changed Fix a few URLs which were being redirected. Includes: * Replacing badges from poser.pugx.org with badges using img.shields.io. * Adding PHP 8.4 to the "tested on" badge. --- CHANGELOG.md | 2 +- README.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 777e59b795..77ea3f1c56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,7 @@ _Nothing yet._ [#608]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/608 [ghcli]: https://cli.github.com/ -[ghattest]: https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds +[ghattest]: https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds ## [3.10.2] - 2024-07-22 diff --git a/README.md b/README.md index 6c7c073beb..207cf226a7 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ '.PHP_EOL; + echo ' '.PHP_EOL; + echo ''.PHP_EOL; + } + + /** + * Print the _real_ footer of the HTML page. + * + * @return void + */ + public function printRealFooter() + { + parent::printFooter(); + } +} diff --git a/tests/Core/Generators/Fixtures/MarkdownDouble.php b/tests/Core/Generators/Fixtures/MarkdownDouble.php new file mode 100644 index 0000000000..6f51f3ec4c --- /dev/null +++ b/tests/Core/Generators/Fixtures/MarkdownDouble.php @@ -0,0 +1,36 @@ +getTitle($doc), PHP_EOL; + } +} diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml new file mode 100644 index 0000000000..83afee8e83 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml new file mode 100644 index 0000000000..ca8290f1b4 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml new file mode 100644 index 0000000000..c2af9098a5 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml @@ -0,0 +1,14 @@ + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml new file mode 100644 index 0000000000..c3ce35cd71 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml new file mode 100644 index 0000000000..fc014949e7 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml new file mode 100644 index 0000000000..19559e6720 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml @@ -0,0 +1,31 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml new file mode 100644 index 0000000000..f5f621ecdc --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml new file mode 100644 index 0000000000..a5b3a3216e --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml @@ -0,0 +1,24 @@ + + + + + + + Code {} + ]]> + + + Comparison {} + ]]> + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml new file mode 100644 index 0000000000..540ac7eaf7 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml @@ -0,0 +1,48 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/DummySniff.php b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/DummySniff.php new file mode 100644 index 0000000000..1a2546b111 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/DummySniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/tests/Core/Generators/GeneratorTest.php b/tests/Core/Generators/GeneratorTest.php new file mode 100644 index 0000000000..30536518f6 --- /dev/null +++ b/tests/Core/Generators/GeneratorTest.php @@ -0,0 +1,241 @@ + $expected The expected list of found docs. + * + * @dataProvider dataConstructor + * + * @return void + */ + public function testConstructor($standard, array $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MockGenerator($ruleset); + $this->assertSame($expected, $generator->docFiles); + + }//end testConstructor() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataConstructor() + { + $pathToDocsInFixture = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'StandardWithDocs'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => [], + ], + 'Standard with an invalid doc file' => [ + 'standard' => __DIR__.'/NoValidDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoDocumentationElementStandard.xml', + ], + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + ], + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoContentStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneCodeComparisonNoStandardStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockTwoCodeComparisonsStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksOneCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksThreeCodeComparisonsStandard.xml', + ], + ], + ]; + + }//end dataConstructor() + + + /** + * Verify that an XML doc which isn't valid documentation yields an Exception to warn devs. + * + * This should not be hidden via defensive coding! + * + * @return void + */ + public function testGeneratingInvalidDocsResultsInException() + { + // Set up the ruleset. + $standard = __DIR__.'/NoValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + if (PHP_VERSION_ID >= 80000) { + $exception = 'TypeError'; + $message = 'processSniff(): Argument #1 ($doc) must be of type DOMNode, null given'; + } else if (PHP_VERSION_ID >= 70000) { + $exception = 'TypeError'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } else { + $exception = 'PHPUnit_Framework_Error'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } + + if (method_exists($this, 'expectExceptionMessage') === true) { + // PHPUnit 5.2.0+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // Ancient PHPUnit. + $this->setExpectedException($exception, $message); + } + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingInvalidDocsResultsInException() + + + /** + * Verify the wiring for the generate() function. + * + * @param string $standard The standard to use for the test. + * @param string $expected The expected function output. + * + * @dataProvider dataGeneratingDocs + * + * @return void + */ + public function testGeneratingDocs($standard, $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $this->expectOutputString($expected); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGeneratingDocs() + { + $multidocExpected = []; + $multidocExpected[] = 'No Content'; + $multidocExpected[] = 'Code Comparison Only, Missing Standard Block'; + $multidocExpected[] = 'One Standard Block, Code Comparison'; + $multidocExpected[] = 'One Standard Block, No Code'; + $multidocExpected[] = 'One Standard Block, Two Code Comparisons'; + $multidocExpected[] = 'Two Standard Blocks, No Code'; + $multidocExpected[] = 'Two Standard Blocks, One Code Comparison'; + $multidocExpected[] = 'Two Standard Blocks, Three Code Comparisons'; + $multidocExpected = implode(PHP_EOL, $multidocExpected).PHP_EOL; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => '', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => 'One Standard Block, No Code'.PHP_EOL, + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => $multidocExpected, + ], + ]; + + }//end dataGeneratingDocs() + + + /** + * Test that the documentation for each standard passed on the command-line is shown separately. + * + * @covers \PHP_CodeSniffer\Runner::runPHPCS + * + * @return void + */ + public function testGeneratorWillShowEachStandardSeparately() + { + $standard = __DIR__.'/OneDocTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '--generator=Text', + "--standard=$standard,PSR1", + '--report-width=80', + ]; + + $regex = '`^ + \R* # Optional blank line at the start. + (?: + (?P-+\R) # Line with dashes. + \|[ ]GENERATORTEST[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for first standard. + (?P>delimiter) # Line with dashes. + .+?\R{2} # Standard description. + ) # Only expect this group once. + (?: + (?P>delimiter) # Line with dashes. + \|[ ]PSR1[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for second standard. + (?P>delimiter) # Line with dashes. + .+?\R+ # Standard description. + (?: + -+[ ]CODE[ ]COMPARISON[ ]-+\R # Code Comparison starter line with dashes. + (?:.+?(?P>delimiter)\R){2} # Arbitrary text followed by a delimiter line. + )* # Code comparison is optional and can exist multiple times. + \R+ + ){3,} # This complete group should occur at least three times. + `sx'; + + $this->expectOutputRegex($regex); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testGeneratorWillShowEachStandardSeparately() + + +}//end class diff --git a/tests/Core/Generators/HTMLTest.php b/tests/Core/Generators/HTMLTest.php new file mode 100644 index 0000000000..4140937ab7 --- /dev/null +++ b/tests/Core/Generators/HTMLTest.php @@ -0,0 +1,104 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputNoDocs.html', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.html', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.html', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^
'; + $regex .= 'Documentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+'; + $regex .= '
\R \R\R$`'; + $this->expectOutputRegex($regex); + + $generator = new HTMLDouble($ruleset); + $generator->printRealFooter(); + + }//end testFooter() + + +}//end class diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php new file mode 100644 index 0000000000..9a3e540044 --- /dev/null +++ b/tests/Core/Generators/MarkdownTest.php @@ -0,0 +1,102 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputNoDocs.md', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.md', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.md', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^Documentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by \[PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+\]\(https://github\.com/PHPCSStandards/PHP_CodeSniffer\)\R$`'; + $this->expectOutputRegex($regex); + + $generator = new MarkdownDouble($ruleset); + $generator->printRealFooter(); + + }//end testFooter() + + +}//end class diff --git a/tests/Core/Generators/NoDocsTest.xml b/tests/Core/Generators/NoDocsTest.xml new file mode 100644 index 0000000000..51df8395c0 --- /dev/null +++ b/tests/Core/Generators/NoDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Core/Generators/NoValidDocsTest.xml b/tests/Core/Generators/NoValidDocsTest.xml new file mode 100644 index 0000000000..94dda4e714 --- /dev/null +++ b/tests/Core/Generators/NoValidDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Core/Generators/OneDocTest.xml b/tests/Core/Generators/OneDocTest.xml new file mode 100644 index 0000000000..83ca4384e5 --- /dev/null +++ b/tests/Core/Generators/OneDocTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Core/Generators/StructureDocsTest.xml b/tests/Core/Generators/StructureDocsTest.xml new file mode 100644 index 0000000000..45811bee67 --- /dev/null +++ b/tests/Core/Generators/StructureDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php new file mode 100644 index 0000000000..40544557f2 --- /dev/null +++ b/tests/Core/Generators/TextTest.php @@ -0,0 +1,80 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.txt', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.txt', + ], + ]; + + }//end dataDocs() + + +}//end class From 3d64cb24a7a4d78531b91bce41cea8c27736a51c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 14 Nov 2024 01:29:08 +0100 Subject: [PATCH 093/192] RuleInclusionAbsoluteWindowsTest: minor tweaks * Switching the test skipping from an inline condition to a PHPUnit annotation. * Adding the `@group Windows` annotation to ensure this test will run for code coverage on Windows in CI. --- .../Ruleset/RuleInclusionAbsoluteWindowsTest.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php b/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php index cba45ee399..9dd0370b28 100644 --- a/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php +++ b/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php @@ -16,7 +16,9 @@ /** * Tests for the \PHP_CodeSniffer\Ruleset class using a Windows-style absolute path to include a sniff. * - * @covers \PHP_CodeSniffer\Ruleset + * @covers \PHP_CodeSniffer\Ruleset + * @requires OS ^WIN.*. + * @group Windows */ final class RuleInclusionAbsoluteWindowsTest extends TestCase { @@ -52,10 +54,6 @@ final class RuleInclusionAbsoluteWindowsTest extends TestCase */ public function initializeConfigAndRuleset() { - if (DIRECTORY_SEPARATOR === '/') { - $this->markTestSkipped('Windows specific test'); - } - $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -85,9 +83,7 @@ public function initializeConfigAndRuleset() */ public function resetRuleset() { - if (DIRECTORY_SEPARATOR !== '/') { - file_put_contents($this->standard, $this->contents); - } + file_put_contents($this->standard, $this->contents); }//end resetRuleset() From 76927ef412ea9534dc0939698593686f909e5c26 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 00:50:07 +0100 Subject: [PATCH 094/192] Generators/Generator: minor tweak * Predefine the find/replace values as these don't change within the loop. * Only call `str_replace()` once with arrays for find/replace. --- src/Generators/Generator.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Generators/Generator.php b/src/Generators/Generator.php index ab81baed76..873ac3f3fa 100644 --- a/src/Generators/Generator.php +++ b/src/Generators/Generator.php @@ -6,7 +6,9 @@ * in a standard. * * @author Greg Sherwood + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ @@ -46,14 +48,18 @@ public function __construct(Ruleset $ruleset) { $this->ruleset = $ruleset; + $find = [ + DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR, + 'Sniff.php', + ]; + $replace = [ + DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR, + 'Standard.xml', + ]; + foreach ($ruleset->sniffs as $className => $sniffClass) { $file = Autoload::getLoadedFileName($className); - $docFile = str_replace( - DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR, - $file - ); - $docFile = str_replace('Sniff.php', 'Standard.xml', $docFile); + $docFile = str_replace($find, $replace, $file); if (is_file($docFile) === true) { $this->docFiles[] = $docFile; From 36e674617cca09ae73f958ed032549ad0843c3d2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 08:58:43 +0100 Subject: [PATCH 095/192] Generators HTML/Markdown: don't print header/footer when there are no docs As things were, the Markdown/HTML header and footer would always be printed, even if there were no docs to display. In my opinion, there should be no output if there are no docs. This is in line with the `Text` output, which would already not generate any output when there are no docs. Includes updated test expectations. --- src/Generators/HTML.php | 4 + src/Generators/Markdown.php | 4 + .../Expectations/ExpectedOutputNoDocs.html | 78 ------------------- .../Expectations/ExpectedOutputNoDocs.md | 2 - tests/Core/Generators/HTMLTest.php | 2 +- tests/Core/Generators/MarkdownTest.php | 2 +- 6 files changed, 10 insertions(+), 82 deletions(-) delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputNoDocs.html delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputNoDocs.md diff --git a/src/Generators/HTML.php b/src/Generators/HTML.php index 0fce7c99ae..f2f2e64bdd 100644 --- a/src/Generators/HTML.php +++ b/src/Generators/HTML.php @@ -103,6 +103,10 @@ class HTML extends Generator */ public function generate() { + if (empty($this->docFiles) === true) { + return; + } + ob_start(); $this->printHeader(); $this->printToc(); diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index de207ec601..8739961697 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -27,6 +27,10 @@ class Markdown extends Generator */ public function generate() { + if (empty($this->docFiles) === true) { + return; + } + ob_start(); $this->printHeader(); diff --git a/tests/Core/Generators/Expectations/ExpectedOutputNoDocs.html b/tests/Core/Generators/Expectations/ExpectedOutputNoDocs.html deleted file mode 100644 index 060de7aa63..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputNoDocs.html +++ /dev/null @@ -1,78 +0,0 @@ - - - GeneratorTest Coding Standards - - - -

GeneratorTest Coding Standards

-

Table of Contents

-
    -
-
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
- - diff --git a/tests/Core/Generators/Expectations/ExpectedOutputNoDocs.md b/tests/Core/Generators/Expectations/ExpectedOutputNoDocs.md deleted file mode 100644 index ece2692187..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputNoDocs.md +++ /dev/null @@ -1,2 +0,0 @@ -# GeneratorTest Coding Standard -Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/HTMLTest.php b/tests/Core/Generators/HTMLTest.php index 4140937ab7..17ef7c9bcf 100644 --- a/tests/Core/Generators/HTMLTest.php +++ b/tests/Core/Generators/HTMLTest.php @@ -62,7 +62,7 @@ public static function dataDocs() return [ 'Standard without docs' => [ 'standard' => __DIR__.'/NoDocsTest.xml', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputNoDocs.html', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], 'Standard with one doc file' => [ 'standard' => __DIR__.'/OneDocTest.xml', diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index 9a3e540044..1a89b7e8ee 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -62,7 +62,7 @@ public static function dataDocs() return [ 'Standard without docs' => [ 'standard' => __DIR__.'/NoDocsTest.xml', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputNoDocs.md', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], 'Standard with one doc file' => [ 'standard' => __DIR__.'/OneDocTest.xml', From 382069574e9cfada9244ddd2a106d6c7ca35a9aa Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 16:36:10 +0100 Subject: [PATCH 096/192] Generators/Markdown: reset error_reporting to original value As things were, the `Markdown` class changes the PHP error level (to prevent potentially getting a warning about the timezone not being set), but doesn't reset the error level back to the original error level once the "risky" code has been executed. Fixed now. This was previously already fixed for the `HTML` class in PR squizlabs/PHP_CodeSniffer 488 Includes adding a test to safeguard this for both classes. These tests need to be run in isolation so as not get interference from the fact that the code is run in a test environment. I.e. without the `@runInSeparateProcess`, the test wouldn't fail when it should. --- src/Generators/Markdown.php | 3 ++- tests/Core/Generators/HTMLTest.php | 28 ++++++++++++++++++++++++++ tests/Core/Generators/MarkdownTest.php | 28 ++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index de207ec601..97e8717c1f 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -69,9 +69,10 @@ protected function printFooter() { // Turn off errors so we don't get timezone warnings if people // don't have their timezone set. - error_reporting(0); + $errorLevel = error_reporting(0); echo 'Documentation generated on '.date('r'); echo ' by [PHP_CodeSniffer '.Config::VERSION.'](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; + error_reporting($errorLevel); }//end printFooter() diff --git a/tests/Core/Generators/HTMLTest.php b/tests/Core/Generators/HTMLTest.php index 4140937ab7..211d8c446e 100644 --- a/tests/Core/Generators/HTMLTest.php +++ b/tests/Core/Generators/HTMLTest.php @@ -101,4 +101,32 @@ public function testFooter() }//end testFooter() + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // We know there will be output, but we're not interested in the output for this test. + ob_start(); + $generator = new HTMLDouble($ruleset); + $generator->printRealFooter(); + ob_end_clean(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + }//end class diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index 9a3e540044..394b0ce5c1 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -99,4 +99,32 @@ public function testFooter() }//end testFooter() + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // We know there will be output, but we're not interested in the output for this test. + ob_start(); + $generator = new MarkdownDouble($ruleset); + $generator->printRealFooter(); + ob_end_clean(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + }//end class From 78d3d3d9db029209ad96c8ec2c7a86c32ddf65b5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 15 Nov 2024 16:15:31 +0100 Subject: [PATCH 097/192] RuleInclusionTest: record code coverage Code executed during "before class" methods is not recorded for code coverage, while code executed in "before" methods is, but the "before" method is executed before _every_ test in the class, not just once before the tests in the class run. So, to record code coverage, while still maintaining the performance benefits of only creating the Config and Ruleset objects once, the code still sets a static property and will only run if that static property has not been filled yet. --- tests/Core/Ruleset/RuleInclusionTest.php | 38 +++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/tests/Core/Ruleset/RuleInclusionTest.php b/tests/Core/Ruleset/RuleInclusionTest.php index ef3ad83cac..175febf30a 100644 --- a/tests/Core/Ruleset/RuleInclusionTest.php +++ b/tests/Core/Ruleset/RuleInclusionTest.php @@ -47,35 +47,37 @@ final class RuleInclusionTest extends TestCase /** * Initialize the config and ruleset objects based on the `RuleInclusionTest.xml` ruleset file. * - * @beforeClass + * @before * * @return void */ public static function initializeConfigAndRuleset() { - $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; - self::$standard = $standard; + if (self::$standard === '') { + $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; + self::$standard = $standard; - // On-the-fly adjust the ruleset test file to be able to test - // sniffs included with relative paths. - $contents = file_get_contents($standard); - self::$contents = $contents; + // On-the-fly adjust the ruleset test file to be able to test + // sniffs included with relative paths. + $contents = file_get_contents($standard); + self::$contents = $contents; - $repoRootDir = basename(dirname(dirname(dirname(__DIR__)))); + $repoRootDir = basename(dirname(dirname(dirname(__DIR__)))); - $newPath = $repoRootDir; - if (DIRECTORY_SEPARATOR === '\\') { - $newPath = str_replace('\\', '/', $repoRootDir); - } + $newPath = $repoRootDir; + if (DIRECTORY_SEPARATOR === '\\') { + $newPath = str_replace('\\', '/', $repoRootDir); + } - $adjusted = str_replace('%path_root_dir%', $newPath, $contents); + $adjusted = str_replace('%path_root_dir%', $newPath, $contents); - if (file_put_contents($standard, $adjusted) === false) { - self::markTestSkipped('On the fly ruleset adjustment failed'); - } + if (file_put_contents($standard, $adjusted) === false) { + self::markTestSkipped('On the fly ruleset adjustment failed'); + } - $config = new ConfigDouble(["--standard=$standard"]); - self::$ruleset = new Ruleset($config); + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + }//end if }//end initializeConfigAndRuleset() From 7e29324efefc6db1efe3ea0b2e733254f22345d8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 15 Nov 2024 16:04:43 +0100 Subject: [PATCH 098/192] RuleInclusionTest: add test with directory include --- tests/Core/Ruleset/RuleInclusionTest.php | 10 +++++++++- tests/Core/Ruleset/RuleInclusionTest.xml | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/Core/Ruleset/RuleInclusionTest.php b/tests/Core/Ruleset/RuleInclusionTest.php index 175febf30a..3f6a7180d6 100644 --- a/tests/Core/Ruleset/RuleInclusionTest.php +++ b/tests/Core/Ruleset/RuleInclusionTest.php @@ -103,7 +103,7 @@ public function resetRuleset() */ public function testHasSniffCodes() { - $this->assertCount(48, self::$ruleset->sniffCodes); + $this->assertCount(49, self::$ruleset->sniffCodes); }//end testHasSniffCodes() @@ -320,6 +320,10 @@ public static function dataRegisteredSniffCodes() 'Generic.Metrics.CyclomaticComplexity', 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', ], + [ + 'Squiz.Files.FileExtension', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff', + ], [ 'Generic.NamingConventions.CamelCapsFunctionName', 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', @@ -470,6 +474,10 @@ public static function dataSettingInvalidPropertiesOnStandardsAndCategoriesSilen 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', 'propertyName' => 'setforallincategory', ], + 'Set property for all sniffs in included category directory' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff', + 'propertyName' => 'setforsquizfilessniffs', + ], ]; }//end dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() diff --git a/tests/Core/Ruleset/RuleInclusionTest.xml b/tests/Core/Ruleset/RuleInclusionTest.xml index 8275fe0111..6b5c0a970b 100644 --- a/tests/Core/Ruleset/RuleInclusionTest.xml +++ b/tests/Core/Ruleset/RuleInclusionTest.xml @@ -27,6 +27,14 @@ + + + + + + + + @@ -39,6 +47,7 @@ + From 168c0d1bf200c435b47dabcdf59c17bbd17cbe45 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 12 Nov 2024 12:20:43 +0100 Subject: [PATCH 099/192] Changelog for the 3.11.1 release --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e15f42e726..5a4ba6aedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,25 @@ The file documents changes to the PHP_CodeSniffer project. _Nothing yet._ +## [3.11.1] - 2024-11-16 + +### Changed +- Output from the `--generator=...` feature will respect the OS-expected EOL char in more places. [#671] + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Various housekeeping, including improvements to the tests and documentation. + - Thanks to [Bartosz Dziewoński][@MatmaRex] and [Juliette Reinders Folmer][@jrfnl] for their contributions. + +### Fixed +- Fixed bug [#674] : Generic.WhiteSpace.HereNowdocIdentifierSpacing broken XML documentation + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Fixed bug [#675] : InvalidArgumentException when a ruleset includes a sniff by file name and the included sniff does not comply with the PHPCS naming conventions. + - Notwithstanding this fix, it is strongly recommended to ensure custom sniff classes comply with the PHPCS naming conventions. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. + +[#671]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/671 +[#674]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/674 +[#675]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/675 + ## [3.11.0] - 2024-11-12 ### Added @@ -7133,6 +7152,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo --> [Unreleased]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/master...HEAD +[3.11.1]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.0...3.11.1 [3.11.0]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.3...3.11.0 [3.10.3]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.2...3.10.3 [3.10.2]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.1...3.10.2 @@ -7370,6 +7390,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo [@maryo]: https://github.com/maryo [@MasterOdin]: https://github.com/MasterOdin [@mathroc]: https://github.com/mathroc +[@MatmaRex]: https://github.com/MatmaRex [@maxgalbu]: https://github.com/maxgalbu [@mcuelenaere]: https://github.com/mcuelenaere [@mhujer]: https://github.com/mhujer From 98c89728cd2cf2de6d966821f098204af5a3f274 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 16 Nov 2024 13:34:59 +0100 Subject: [PATCH 100/192] Config: update version nr to next --- src/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Config.php b/src/Config.php index e954c140ed..dda15a5553 100644 --- a/src/Config.php +++ b/src/Config.php @@ -85,7 +85,7 @@ class Config * * @var string */ - const VERSION = '3.11.1'; + const VERSION = '3.11.2'; /** * Package stability; either stable, beta or alpha. From dfce5e2767b076a8de43faf82dda5b87eef37501 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 18 Nov 2024 18:53:49 +0100 Subject: [PATCH 101/192] Generators HTML/Markdown: add extra test around error silencing Follow up on 688, which safeguarded/fixed that the `error_reporting` would be reset to its original value, this commit now adds tests to cover the original situation which caused the error silencing to be introduced in the first place. --- tests/Core/Generators/HTMLTest.php | 43 ++++++++++++++++++++++++++ tests/Core/Generators/MarkdownTest.php | 43 ++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/tests/Core/Generators/HTMLTest.php b/tests/Core/Generators/HTMLTest.php index 758b9a8133..e8724a0544 100644 --- a/tests/Core/Generators/HTMLTest.php +++ b/tests/Core/Generators/HTMLTest.php @@ -129,4 +129,47 @@ public function testFooterResetsErrorReportingToOriginalSetting() }//end testFooterResetsErrorReportingToOriginalSetting() + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // We know there will be output, but we're not interested in the output for this test. + ob_start(); + $generator = new HTMLDouble($ruleset); + $generator->printRealFooter(); + ob_end_clean(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + }//end class diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index c76cd153d3..adba19518f 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -127,4 +127,47 @@ public function testFooterResetsErrorReportingToOriginalSetting() }//end testFooterResetsErrorReportingToOriginalSetting() + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // We know there will be output, but we're not interested in the output for this test. + ob_start(); + $generator = new MarkdownDouble($ruleset); + $generator->printRealFooter(); + ob_end_clean(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + }//end class From a52c354504de019fd65eef66d806c617ea9fd103 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 18 Nov 2024 04:45:21 +0100 Subject: [PATCH 102/192] ShowSniffDeprecationsTest: fix bug in tests Wasn't noticeable, still a bug. --- tests/Core/Ruleset/ShowSniffDeprecationsTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php index 8e81f96a25..43f850f051 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -146,7 +146,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDepre ]; foreach ($sniffs as $sniffCode) { $parts = explode('.', strtolower($sniffCode)); - $sniffName = $parts[0].'\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; $restrictions[strtolower($sniffName)] = true; } @@ -158,7 +158,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDepre $sniffFiles[] = $sniffFile; } - $ruleset->registerSniffs($allSniffs, $restrictions, []); + $ruleset->registerSniffs($sniffFiles, $restrictions, []); $ruleset->populateTokenListeners(); $this->expectOutputString(''); @@ -195,7 +195,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExc ]; foreach ($exclude as $sniffCode) { $parts = explode('.', strtolower($sniffCode)); - $sniffName = $parts[0].'\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; $exclusions[strtolower($sniffName)] = true; } @@ -207,7 +207,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExc $sniffFiles[] = $sniffFile; } - $ruleset->registerSniffs($allSniffs, [], $exclusions); + $ruleset->registerSniffs($sniffFiles, [], $exclusions); $ruleset->populateTokenListeners(); $this->expectOutputString(''); From 2a045d31d0d3099bf024022613a48aacbd77aef9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 5 Nov 2024 01:47:08 +0100 Subject: [PATCH 103/192] Generators/HTML: only display a TOC when there is more than one doc --- src/Generators/HTML.php | 5 +++++ tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Generators/HTML.php b/src/Generators/HTML.php index f2f2e64bdd..0f3733b984 100644 --- a/src/Generators/HTML.php +++ b/src/Generators/HTML.php @@ -156,6 +156,11 @@ protected function printHeader() */ protected function printToc() { + // Only show a TOC when there are two or more docs to display. + if (count($this->docFiles) < 2) { + return; + } + echo '

Table of Contents

'.PHP_EOL; echo '
    '.PHP_EOL; diff --git a/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html b/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html index 772d3861ec..2100809e71 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html @@ -70,10 +70,6 @@

    GeneratorTest Coding Standards

    -

    Table of Contents

    -

    One Standard Block, No Code

    Documentation contains one standard block and no code comparison.

    From 12235bda7805484c8ffe4fd9a53df5bfbaa5e63f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 16:13:12 +0100 Subject: [PATCH 104/192] Generators/Markdown: fix footer not parsing As things were, if the output of the Markdown doc generation would be used in a Markdown-friendly environment, the footer would not be interpreted as markdown and would not display correctly. Fixed now by adding a blank line at the start of the footer. Includes updated test expectations. --- src/Generators/Markdown.php | 2 +- tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md | 1 + .../Core/Generators/Expectations/ExpectedOutputStructureDocs.md | 1 + tests/Core/Generators/Fixtures/MarkdownDouble.php | 2 +- tests/Core/Generators/MarkdownTest.php | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index d8e700b8ca..ab30cd59a7 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -74,7 +74,7 @@ protected function printFooter() // Turn off errors so we don't get timezone warnings if people // don't have their timezone set. $errorLevel = error_reporting(0); - echo 'Documentation generated on '.date('r'); + echo PHP_EOL.'Documentation generated on '.date('r'); echo ' by [PHP_CodeSniffer '.Config::VERSION.'](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; error_reporting($errorLevel); diff --git a/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md b/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md index f8deb0ce20..0cc0ecceae 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md @@ -2,4 +2,5 @@ ## One Standard Block, No Code Documentation contains one standard block and no code comparison. + Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md index d613df2951..116af5df1e 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md @@ -168,4 +168,5 @@ This is standard block two. + Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Fixtures/MarkdownDouble.php b/tests/Core/Generators/Fixtures/MarkdownDouble.php index 6f51f3ec4c..ed2a5d8f58 100644 --- a/tests/Core/Generators/Fixtures/MarkdownDouble.php +++ b/tests/Core/Generators/Fixtures/MarkdownDouble.php @@ -20,7 +20,7 @@ class MarkdownDouble extends Markdown */ protected function printFooter() { - echo 'Documentation generated on *REDACTED*'; + echo PHP_EOL.'Documentation generated on *REDACTED*'; echo ' by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; } diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index adba19518f..0610678dbe 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -89,7 +89,7 @@ public function testFooter() $config = new ConfigDouble(["--standard=$standard"]); $ruleset = new Ruleset($config); - $regex = '`^Documentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex = '`^\RDocumentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; $regex .= ' by \[PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+\]\(https://github\.com/PHPCSStandards/PHP_CodeSniffer\)\R$`'; $this->expectOutputRegex($regex); From 8c08a1de329bff95d10e2999b449ad483e497a36 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 16 Nov 2024 23:29:14 +0100 Subject: [PATCH 105/192] Tests/Ruleset/XML fixtures: add direct link between fixture and test using the fixture Small tweak to make sure the XML rulesets used for specific tests are directly linked to those tests via the XML ruleset name - this should make the tests more self-documenting. --- tests/Core/Ruleset/ExplainTest.php | 2 +- tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml | 2 +- .../Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml | 2 +- tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml | 2 +- ...pertyAppliesPropertyToMultipleSniffsInCategoryTest.xml | 2 +- ...tThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml | 2 +- ...tThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml | 2 +- .../Ruleset/SetPropertyNotAllowedViaAttributeTest.xml | 2 +- .../SetPropertyThrowsErrorOnInvalidPropertyTest.xml | 2 +- .../ShowSniffDeprecationsEmptyDeprecationVersionTest.xml | 2 +- .../ShowSniffDeprecationsEmptyRemovalVersionTest.xml | 2 +- ...ShowSniffDeprecationsInvalidDeprecationMessageTest.xml | 2 +- ...ShowSniffDeprecationsInvalidDeprecationVersionTest.xml | 2 +- .../ShowSniffDeprecationsInvalidRemovalVersionTest.xml | 2 +- tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml | 2 +- .../Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml | 2 +- tests/Core/Ruleset/ShowSniffDeprecationsTest.php | 8 ++++---- tests/Core/Ruleset/ShowSniffDeprecationsTest.xml | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/Core/Ruleset/ExplainTest.php b/tests/Core/Ruleset/ExplainTest.php index 5438c65cfc..0d899608df 100644 --- a/tests/Core/Ruleset/ExplainTest.php +++ b/tests/Core/Ruleset/ExplainTest.php @@ -185,7 +185,7 @@ public function testExplainWithDeprecatedSniffs() $ruleset = new Ruleset($config); $expected = PHP_EOL; - $expected .= 'The SniffDeprecationTest standard contains 9 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'The ShowSniffDeprecationsTest standard contains 9 sniffs'.PHP_EOL.PHP_EOL; $expected .= 'Fixtures (9 sniffs)'.PHP_EOL; $expected .= '-------------------'.PHP_EOL; diff --git a/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml b/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml index 5840d0c362..89005ad2d1 100644 --- a/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml +++ b/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml b/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml index 7ff2178247..deb6944d08 100644 --- a/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml +++ b/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml b/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml index 387f419e8d..475ba5cff3 100644 --- a/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml +++ b/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml b/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml index 7c4ca4fd35..67fcca351d 100644 --- a/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml +++ b/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml b/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml index 979b48f522..a678c91555 100644 --- a/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml +++ b/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml b/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml index 48a36a8313..8ce97e2dd3 100644 --- a/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml +++ b/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml b/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml index 7caae3d393..da5423913c 100644 --- a/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml +++ b/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml b/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml index 5dca1a010d..a1742618a2 100644 --- a/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml +++ b/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml index 5e2480bf2f..f10654fc40 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml index 6e667375af..0298571804 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml index d325167994..295d7b998a 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml index 89d83ab528..c7accdf29f 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml index c1eb062e1c..c5abf66da8 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml index 3ce96ce89f..6e3f6be53e 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml index 9f1cc85155..8a7870a585 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php index 43f850f051..bef388bcbc 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -234,7 +234,7 @@ public function testDeprecatedSniffsWarning() $config = new ConfigDouble(["--standard=$standard", '--no-colors']); $ruleset = new Ruleset($config); - $expected = 'WARNING: The SniffDeprecationTest standard uses 5 deprecated sniffs'.PHP_EOL; + $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 5 deprecated sniffs'.PHP_EOL; $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; $expected .= '- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; @@ -321,13 +321,13 @@ public function testReportWidthIsRespected($reportWidth, $expectedOutput) */ public static function dataReportWidthIsRespected() { - $summaryLine = 'WARNING: The SniffDeprecationTest standard uses 1 deprecated sniff'.PHP_EOL; + $summaryLine = 'WARNING: The ShowSniffDeprecationsTest standard uses 1 deprecated sniff'.PHP_EOL; // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. return [ 'Report width small: 40; with truncated sniff name and wrapped header and footer lines' => [ 'reportWidth' => 40, - 'expectedOutput' => 'WARNING: The SniffDeprecationTest'.PHP_EOL + 'expectedOutput' => 'WARNING: The ShowSniffDeprecationsTest'.PHP_EOL .'standard uses 1 deprecated sniff'.PHP_EOL .'----------------------------------------'.PHP_EOL .'- Fixtures.Deprecated.WithLongRepla...'.PHP_EOL @@ -409,7 +409,7 @@ public function testDeprecatedSniffsAreListedAlphabetically() $config = new ConfigDouble(["--standard=$standard", '--no-colors']); $ruleset = new Ruleset($config); - $expected = 'WARNING: The SniffDeprecationTest standard uses 2 deprecated sniffs'.PHP_EOL; + $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 2 deprecated sniffs'.PHP_EOL; $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml index 4c1dec2203..4665f439b5 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml @@ -1,5 +1,5 @@ - + From 80b5656d6cef3a7a8d2cc82472caa128c33abecf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 14 Nov 2024 01:58:05 +0100 Subject: [PATCH 106/192] Tests/Ruleset/fixtures: move existing fixtures to subdirectory For some new tests, some test fixtures outside a standard directory structure and/or in a seperate standard directory structure are needed. This commit moves the pre-existing sniff test fixtures to a subdirectory to allow for the upcoming additional test fixtures. Includes updating the standard/ruleset to have a namespace prefix ("Fixtures"), so that aspect of things can now also be tested. --- tests/Core/Ruleset/ExplainTest.php | 22 ++++---- .../Deprecated/WithLongReplacementSniff.php | 2 +- ...eplacementContainingLinuxNewlinesSniff.php | 2 +- ...WithReplacementContainingNewlinesSniff.php | 2 +- .../Deprecated/WithReplacementSniff.php | 2 +- .../Deprecated/WithoutReplacementSniff.php | 2 +- .../EmptyDeprecationVersionSniff.php | 2 +- .../EmptyRemovalVersionSniff.php | 2 +- .../InvalidDeprecationMessageSniff.php | 2 +- .../InvalidDeprecationVersionSniff.php | 2 +- .../InvalidRemovalVersionSniff.php | 2 +- .../SetProperty/AllowedAsDeclaredSniff.php | 2 +- .../AllowedViaMagicMethodSniff.php | 2 +- .../SetProperty/AllowedViaStdClassSniff.php | 2 +- .../NotAllowedViaAttributeSniff.php | 2 +- .../Ruleset/Fixtures/TestStandard/ruleset.xml | 4 ++ tests/Core/Ruleset/Fixtures/ruleset.xml | 4 -- .../SetPropertyAllowedAsDeclaredTest.xml | 2 +- .../SetPropertyAllowedViaMagicMethodTest.xml | 2 +- .../SetPropertyAllowedViaStdClassTest.xml | 2 +- .../SetPropertyNotAllowedViaAttributeTest.xml | 2 +- tests/Core/Ruleset/SetSniffPropertyTest.php | 16 +++--- ...eprecationsEmptyDeprecationVersionTest.xml | 4 +- ...iffDeprecationsEmptyRemovalVersionTest.xml | 4 +- ...recationsInvalidDeprecationMessageTest.xml | 4 +- ...recationsInvalidDeprecationVersionTest.xml | 4 +- ...fDeprecationsInvalidRemovalVersionTest.xml | 4 +- .../ShowSniffDeprecationsOrderTest.xml | 6 +-- .../ShowSniffDeprecationsReportWidthTest.xml | 4 +- .../Ruleset/ShowSniffDeprecationsTest.php | 50 +++++++++---------- .../Ruleset/ShowSniffDeprecationsTest.xml | 6 +-- 31 files changed, 84 insertions(+), 84 deletions(-) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/Deprecated/WithLongReplacementSniff.php (96%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php (95%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php (95%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/Deprecated/WithReplacementSniff.php (93%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/Deprecated/WithoutReplacementSniff.php (93%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php (92%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php (92%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php (92%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php (92%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php (92%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/SetProperty/AllowedAsDeclaredSniff.php (89%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php (92%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/SetProperty/AllowedViaStdClassSniff.php (88%) rename tests/Core/Ruleset/Fixtures/{ => TestStandard}/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php (89%) create mode 100644 tests/Core/Ruleset/Fixtures/TestStandard/ruleset.xml delete mode 100644 tests/Core/Ruleset/Fixtures/ruleset.xml diff --git a/tests/Core/Ruleset/ExplainTest.php b/tests/Core/Ruleset/ExplainTest.php index 0d899608df..48df24f473 100644 --- a/tests/Core/Ruleset/ExplainTest.php +++ b/tests/Core/Ruleset/ExplainTest.php @@ -187,17 +187,17 @@ public function testExplainWithDeprecatedSniffs() $expected = PHP_EOL; $expected .= 'The ShowSniffDeprecationsTest standard contains 9 sniffs'.PHP_EOL.PHP_EOL; - $expected .= 'Fixtures (9 sniffs)'.PHP_EOL; - $expected .= '-------------------'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithLongReplacement *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithoutReplacement *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithReplacement *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.AllowedAsDeclared'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.AllowedViaMagicMethod'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.AllowedViaStdClass'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.NotAllowedViaAttribute'.PHP_EOL.PHP_EOL; + $expected .= 'TestStandard (9 sniffs)'.PHP_EOL; + $expected .= '-----------------------'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithLongReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithoutReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedAsDeclared'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedViaMagicMethod'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedViaStdClass'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL.PHP_EOL; $expected .= '* Sniffs marked with an asterix are deprecated.'.PHP_EOL; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php similarity index 96% rename from tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php index 40c23113d5..659d89ee2a 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php similarity index 95% rename from tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php index 0363927db7..d870cbf7e4 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php similarity index 95% rename from tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php index e9e76c8c0e..2516d7cd2e 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementSniff.php similarity index 93% rename from tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementSniff.php index a633982817..1953448672 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithoutReplacementSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithoutReplacementSniff.php similarity index 93% rename from tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithoutReplacementSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithoutReplacementSniff.php index d6d3887106..888e08fd13 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithoutReplacementSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithoutReplacementSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php similarity index 92% rename from tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php index 8d3dcd4218..4e26b7b761 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php similarity index 92% rename from tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php index 828b169284..cdf15c3031 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php similarity index 92% rename from tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php index a6819825f7..368bd4140b 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php similarity index 92% rename from tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php index d51aa876ca..b8218ad57e 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php similarity index 92% rename from tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php index a10997bbcd..1177e73338 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedAsDeclaredSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedAsDeclaredSniff.php similarity index 89% rename from tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedAsDeclaredSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedAsDeclaredSniff.php index c26160b279..a8f0364c54 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedAsDeclaredSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedAsDeclaredSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest */ -namespace Fixtures\Sniffs\SetProperty; +namespace Fixtures\TestStandard\Sniffs\SetProperty; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php similarity index 92% rename from tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php index 04097bb91a..98eb22c573 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaMagicMethodSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest */ -namespace Fixtures\Sniffs\SetProperty; +namespace Fixtures\TestStandard\Sniffs\SetProperty; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaStdClassSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php similarity index 88% rename from tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaStdClassSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php index 30418729dc..0f58b2e001 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaStdClassSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/AllowedViaStdClassSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest */ -namespace Fixtures\Sniffs\SetProperty; +namespace Fixtures\TestStandard\Sniffs\SetProperty; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; diff --git a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php similarity index 89% rename from tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php rename to tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php index e895a87a8b..bb52355827 100644 --- a/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/NotAllowedViaAttributeSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SetSniffPropertyTest */ -namespace Fixtures\Sniffs\SetProperty; +namespace Fixtures\TestStandard\Sniffs\SetProperty; use AllowDynamicProperties; use PHP_CodeSniffer\Files\File; diff --git a/tests/Core/Ruleset/Fixtures/TestStandard/ruleset.xml b/tests/Core/Ruleset/Fixtures/TestStandard/ruleset.xml new file mode 100644 index 0000000000..345c4837eb --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/TestStandard/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/Core/Ruleset/Fixtures/ruleset.xml b/tests/Core/Ruleset/Fixtures/ruleset.xml deleted file mode 100644 index 11a899adae..0000000000 --- a/tests/Core/Ruleset/Fixtures/ruleset.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml b/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml index 89005ad2d1..88eaa5ebf9 100644 --- a/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml +++ b/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml @@ -1,7 +1,7 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml b/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml index deb6944d08..e8502e7ff6 100644 --- a/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml +++ b/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml @@ -1,7 +1,7 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml b/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml index 475ba5cff3..bfbfaf5e6f 100644 --- a/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml +++ b/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml @@ -1,7 +1,7 @@ - + diff --git a/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml b/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml index da5423913c..c6a14c259c 100644 --- a/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml +++ b/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml @@ -1,7 +1,7 @@ - + diff --git a/tests/Core/Ruleset/SetSniffPropertyTest.php b/tests/Core/Ruleset/SetSniffPropertyTest.php index 36e6f0097b..51bd0e2989 100644 --- a/tests/Core/Ruleset/SetSniffPropertyTest.php +++ b/tests/Core/Ruleset/SetSniffPropertyTest.php @@ -34,8 +34,8 @@ final class SetSniffPropertyTest extends TestCase */ public function testSniffPropertiesGetSetWhenAllowed($name) { - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; $properties = [ 'arbitrarystring' => 'arbitraryvalue', 'arbitraryarray' => [ @@ -163,7 +163,7 @@ public function testSetPropertyThrowsErrorOnInvalidProperty() public function testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() { $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - $exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff Fixtures.SetProperty.NotAllowedViaAttribute'; + $exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff TestStandard.SetProperty.NotAllowedViaAttribute'; if (method_exists($this, 'expectException') === true) { $this->expectException($exceptionClass); $this->expectExceptionMessage($exceptionMsg); @@ -225,8 +225,8 @@ public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCateg public function testDirectCallWithNewArrayFormatSetsProperty() { $name = 'AllowedAsDeclared'; - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; // Set up the ruleset. $standard = __DIR__."/SetProperty{$name}Test.xml"; @@ -276,8 +276,8 @@ public function testDirectCallWithNewArrayFormatSetsProperty() public function testDirectCallWithOldArrayFormatSetsProperty($propertyValue) { $name = 'AllowedAsDeclared'; - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; // Set up the ruleset. $standard = __DIR__."/SetProperty{$name}Test.xml"; @@ -383,7 +383,7 @@ public function testDirectCallWithOldArrayFormatThrowsDeprecationNotice() } $name = 'AllowedAsDeclared'; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; // Set up the ruleset. $standard = __DIR__."/SetProperty{$name}Test.xml"; diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml index f10654fc40..75527e2b1d 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml @@ -1,8 +1,8 @@ - + - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml index 0298571804..150fc3e526 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml @@ -1,8 +1,8 @@ - + - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml index 295d7b998a..973e065a13 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml @@ -1,8 +1,8 @@ - + - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml index c7accdf29f..493adfd1ef 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml @@ -1,8 +1,8 @@ - + - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml index c5abf66da8..358cb0df5f 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml @@ -1,8 +1,8 @@ - + - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml index 6e3f6be53e..fbc0cb7b74 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml @@ -1,10 +1,10 @@ - + - - + + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml index 8a7870a585..86cc615c4e 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml @@ -1,8 +1,8 @@ - + - + diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php index bef388bcbc..c31f7b4a83 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -141,8 +141,8 @@ public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDepre $restrictions = []; $sniffs = [ - 'Fixtures.SetProperty.AllowedAsDeclared', - 'Fixtures.SetProperty.AllowedViaStdClass', + 'TestStandard.SetProperty.AllowedAsDeclared', + 'TestStandard.SetProperty.AllowedViaStdClass', ]; foreach ($sniffs as $sniffCode) { $parts = explode('.', strtolower($sniffCode)); @@ -187,11 +187,11 @@ public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExc $exclusions = []; $exclude = [ - 'Fixtures.Deprecated.WithLongReplacement', - 'Fixtures.Deprecated.WithoutReplacement', - 'Fixtures.Deprecated.WithReplacement', - 'Fixtures.Deprecated.WithReplacementContainingLinuxNewlines', - 'Fixtures.Deprecated.WithReplacementContainingNewlines', + 'TestStandard.Deprecated.WithLongReplacement', + 'TestStandard.Deprecated.WithoutReplacement', + 'TestStandard.Deprecated.WithReplacement', + 'TestStandard.Deprecated.WithReplacementContainingLinuxNewlines', + 'TestStandard.Deprecated.WithReplacementContainingNewlines', ]; foreach ($exclude as $sniffCode) { $parts = explode('.', strtolower($sniffCode)); @@ -236,7 +236,7 @@ public function testDeprecatedSniffsWarning() $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 5 deprecated sniffs'.PHP_EOL; $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL; $expected .= ' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL; @@ -247,12 +247,12 @@ public function testDeprecatedSniffsWarning() $expected .= ' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL; $expected .= ' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL; $expected .= ' libero.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; @@ -262,7 +262,7 @@ public function testDeprecatedSniffsWarning() $expected .= ' eros sapien at sem.'.PHP_EOL; $expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL; $expected .= ' lectus at egestas.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacementContainingNewlines'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacementContainingNewlines'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; @@ -330,7 +330,7 @@ public static function dataReportWidthIsRespected() 'expectedOutput' => 'WARNING: The ShowSniffDeprecationsTest'.PHP_EOL .'standard uses 1 deprecated sniff'.PHP_EOL .'----------------------------------------'.PHP_EOL - .'- Fixtures.Deprecated.WithLongRepla...'.PHP_EOL + .'- TestStandard.Deprecated.WithLongR...'.PHP_EOL .' This sniff has been deprecated since'.PHP_EOL .' v3.8.0 and will be removed in'.PHP_EOL .' v4.0.0. Lorem ipsum dolor sit amet,'.PHP_EOL @@ -358,7 +358,7 @@ public static function dataReportWidthIsRespected() 'Report width default: 80' => [ 'reportWidth' => 80, 'expectedOutput' => $summaryLine.str_repeat('-', 80).PHP_EOL - .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL .' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL .' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL @@ -376,7 +376,7 @@ public static function dataReportWidthIsRespected() // Length = 4 padding + 75 base line + 587 custom message. 'reportWidth' => 666, 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL - .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' .PHP_EOL.PHP_EOL .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, @@ -384,7 +384,7 @@ public static function dataReportWidthIsRespected() 'Report width wide: 1000; delimiter line length should match longest line' => [ 'reportWidth' => 1000, 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL - .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' .PHP_EOL.PHP_EOL .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, @@ -411,9 +411,9 @@ public function testDeprecatedSniffsAreListedAlphabetically() $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 2 deprecated sniffs'.PHP_EOL; $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL.PHP_EOL; $expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL; @@ -426,12 +426,12 @@ public function testDeprecatedSniffsAreListedAlphabetically() // Verify that the sniffs have been registered to run. $this->assertCount(2, $ruleset->sniffCodes, 'Incorrect number of sniff codes registered'); $this->assertArrayHasKey( - 'Fixtures.Deprecated.WithoutReplacement', + 'TestStandard.Deprecated.WithoutReplacement', $ruleset->sniffCodes, 'WithoutReplacement sniff not registered' ); $this->assertArrayHasKey( - 'Fixtures.Deprecated.WithReplacement', + 'TestStandard.Deprecated.WithReplacement', $ruleset->sniffCodes, 'WithReplacement sniff not registered' ); @@ -484,23 +484,23 @@ public static function dataExceptionIsThrownOnIncorrectlyImplementedInterface() return [ 'getDeprecationVersion() does not return a string' => [ 'standard' => 'ShowSniffDeprecationsInvalidDeprecationVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double', + 'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double', ], 'getRemovalVersion() does not return a string' => [ 'standard' => 'ShowSniffDeprecationsInvalidRemovalVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array', + 'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array', ], 'getDeprecationMessage() does not return a string' => [ 'standard' => 'ShowSniffDeprecationsInvalidDeprecationMessageTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object', + 'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object', ], 'getDeprecationVersion() returns an empty string' => [ 'standard' => 'ShowSniffDeprecationsEmptyDeprecationVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""', + 'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""', ], 'getRemovalVersion() returns an empty string' => [ 'standard' => 'ShowSniffDeprecationsEmptyRemovalVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""', + 'exceptionMessage' => 'The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""', ], ]; diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml index 4665f439b5..38c7e02221 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml @@ -1,10 +1,10 @@ - + - - + + From 4e36c11f8e67d159ab24f9a31dd638140791fc31 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 16 Nov 2024 22:44:14 +0100 Subject: [PATCH 107/192] Ruleset: add tests for custom property type handling Add tests specifically aimed at testing the type handling of sniff properties set via a ruleset and via inline annotations. The current tests document the existing behaviour, which contains some oddities, but fixing these could be considered a breaking change, so should wait until PHPCS 4.0. --- tests/Core/Ruleset/ExplainTest.php | 9 +- .../Fixtures/PropertyTypeHandlingInline.inc | 26 ++ .../SetProperty/PropertyTypeHandlingSniff.php | 125 ++++++++++ .../PropertyTypeHandlingInlineTest.xml | 6 + .../Core/Ruleset/PropertyTypeHandlingTest.php | 234 ++++++++++++++++++ .../Core/Ruleset/PropertyTypeHandlingTest.xml | 44 ++++ 6 files changed, 440 insertions(+), 4 deletions(-) create mode 100644 tests/Core/Ruleset/Fixtures/PropertyTypeHandlingInline.inc create mode 100644 tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff.php create mode 100644 tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml create mode 100644 tests/Core/Ruleset/PropertyTypeHandlingTest.php create mode 100644 tests/Core/Ruleset/PropertyTypeHandlingTest.xml diff --git a/tests/Core/Ruleset/ExplainTest.php b/tests/Core/Ruleset/ExplainTest.php index 48df24f473..db52b3cd22 100644 --- a/tests/Core/Ruleset/ExplainTest.php +++ b/tests/Core/Ruleset/ExplainTest.php @@ -185,10 +185,10 @@ public function testExplainWithDeprecatedSniffs() $ruleset = new Ruleset($config); $expected = PHP_EOL; - $expected .= 'The ShowSniffDeprecationsTest standard contains 9 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'The ShowSniffDeprecationsTest standard contains 10 sniffs'.PHP_EOL.PHP_EOL; - $expected .= 'TestStandard (9 sniffs)'.PHP_EOL; - $expected .= '-----------------------'.PHP_EOL; + $expected .= 'TestStandard (10 sniffs)'.PHP_EOL; + $expected .= '------------------------'.PHP_EOL; $expected .= ' TestStandard.Deprecated.WithLongReplacement *'.PHP_EOL; $expected .= ' TestStandard.Deprecated.WithoutReplacement *'.PHP_EOL; $expected .= ' TestStandard.Deprecated.WithReplacement *'.PHP_EOL; @@ -197,7 +197,8 @@ public function testExplainWithDeprecatedSniffs() $expected .= ' TestStandard.SetProperty.AllowedAsDeclared'.PHP_EOL; $expected .= ' TestStandard.SetProperty.AllowedViaMagicMethod'.PHP_EOL; $expected .= ' TestStandard.SetProperty.AllowedViaStdClass'.PHP_EOL; - $expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL.PHP_EOL; + $expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.PropertyTypeHandling'.PHP_EOL.PHP_EOL; $expected .= '* Sniffs marked with an asterix are deprecated.'.PHP_EOL; diff --git a/tests/Core/Ruleset/Fixtures/PropertyTypeHandlingInline.inc b/tests/Core/Ruleset/Fixtures/PropertyTypeHandlingInline.inc new file mode 100644 index 0000000000..984f8cd2c2 --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/PropertyTypeHandlingInline.inc @@ -0,0 +1,26 @@ +string,10=>10,float=>1.5,null=>null,true=>true,false=>false + +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithOnlyValues[] string, 10, 1.5, null, true, false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithKeysAndValues[] string=>string,10=>10,float=>1.5,null=>null,true=>true,false=>false + +echo 'hello!'; diff --git a/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff.php new file mode 100644 index 0000000000..be4c2147db --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff.php @@ -0,0 +1,125 @@ + + */ + public $expectsArrayWithOnlyValues; + + /** + * Used to verify that array properties with keys get parsed to a proper array. + * + * @var array + */ + public $expectsArrayWithKeysAndValues; + + /** + * Used to verify that array properties passed as a string get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithOnlyValues; + + /** + * Used to verify that array properties passed as a string with keys get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithKeysAndValues; + + public function register() + { + return [T_ECHO]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml b/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml new file mode 100644 index 0000000000..0bdadc7de0 --- /dev/null +++ b/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/Core/Ruleset/PropertyTypeHandlingTest.php b/tests/Core/Ruleset/PropertyTypeHandlingTest.php new file mode 100644 index 0000000000..4c5cd516a7 --- /dev/null +++ b/tests/Core/Ruleset/PropertyTypeHandlingTest.php @@ -0,0 +1,234 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the handling of property value types for properties set via the ruleset and inline. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty + */ +final class PropertyTypeHandlingTest extends TestCase +{ + + /** + * Sniff code for the sniff used in these tests. + * + * @var string + */ + const SNIFF_CODE = 'TestStandard.SetProperty.PropertyTypeHandling'; + + /** + * Class name of the sniff used in these tests. + * + * @var string + */ + const SNIFF_CLASS = 'Fixtures\\TestStandard\\Sniffs\\SetProperty\\PropertyTypeHandlingSniff'; + + + /** + * Test the value type handling for properties set via a ruleset. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * + * @return void + */ + public function testTypeHandlingWhenSetViaRuleset($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectForRuleset(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetViaRuleset() + + + /** + * Test the value type handling for properties set inline in a test case file. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * + * @return void + */ + public function testTypeHandlingWhenSetInline($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectAfterProcessingFile(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetInline() + + + /** + * Data provider. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return array> + */ + public static function dataTypeHandling() + { + $expectedArrayOnlyValues = [ + 'string', + '10', + '1.5', + 'null', + 'true', + 'false', + ]; + $expectedArrayKeysAndValues = [ + 'string' => 'string', + 10 => '10', + 'float' => '1.5', + 'null' => 'null', + 'true' => 'true', + 'false' => 'false', + ]; + + return [ + 'String value (default)' => [ + 'propertyName' => 'expectsString', + 'expected' => 'arbitraryvalue', + ], + 'String with whitespace only value becomes null' => [ + 'propertyName' => 'emptyStringBecomesNull', + 'expected' => null, + ], + 'Integer value gets set as string' => [ + 'propertyName' => 'expectsIntButAcceptsString', + 'expected' => '12345', + ], + 'Float value gets set as string' => [ + 'propertyName' => 'expectsFloatButAcceptsString', + 'expected' => '12.345', + ], + 'Null value gets set as string' => [ + 'propertyName' => 'expectsNull', + 'expected' => 'null', + ], + 'Null (uppercase) value gets set as string' => [ + 'propertyName' => 'expectsNullCase', + 'expected' => 'NULL', + ], + 'True value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrue', + 'expected' => true, + ], + 'True (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanTrueCase', + 'expected' => 'True', + ], + 'False value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalse', + 'expected' => false, + ], + 'False (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanFalseCase', + 'expected' => 'fALSe', + ], + 'Array with only values (new style)' => [ + 'propertyName' => 'expectsArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (new style)' => [ + 'propertyName' => 'expectsArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Array with only values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + ]; + + }//end dataTypeHandling() + + + /** + * Test Helper. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectForRuleset() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__."/PropertyTypeHandlingTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + } + + return $sniffObject; + + }//end getSniffObjectForRuleset() + + + /** + * Test Helper + * + * @see self::testTypeHandlingWhenSetInline() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectAfterProcessingFile() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__."/PropertyTypeHandlingInlineTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + + // Process the file with inline phpcs:set annotations. + $testFile = realpath(__DIR__.'/Fixtures/PropertyTypeHandlingInline.inc'); + $this->assertNotFalse($testFile); + + $phpcsFile = new LocalFile($testFile, $ruleset, $config); + $phpcsFile->process(); + } + + return $sniffObject; + + }//end getSniffObjectAfterProcessingFile() + + +}//end class diff --git a/tests/Core/Ruleset/PropertyTypeHandlingTest.xml b/tests/Core/Ruleset/PropertyTypeHandlingTest.xml new file mode 100644 index 0000000000..76817837e7 --- /dev/null +++ b/tests/Core/Ruleset/PropertyTypeHandlingTest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bed42db81566e9e25f62fffb974a62304aaef724 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Nov 2024 18:56:15 +0100 Subject: [PATCH 108/192] Tests: set up mechanism to allow for testing CBF specific code See the description of how this works in the `CONTRIBUTING` file for more information. Includes adjustments to the GH Actions workflows to ensure the CBF specific tests are: * Always run for the `quicktest` and "normal" test runs. * Run for code coverage and that the code coverage reports are send in a way that they can be merged correctly. Includes adding a "requires CS mode" condition to a few tests which would otherwise fail in CBF mode. --- .github/CONTRIBUTING.md | 30 ++++++++++++ .github/workflows/quicktest.yml | 5 ++ .github/workflows/test.yml | 32 ++++++++++++- phpunit.xml.dist | 10 ++++ tests/Core/Generators/GeneratorTest.php | 4 ++ tests/Core/Ruleset/ExplainTest.php | 4 ++ .../Ruleset/ShowSniffDeprecationsTest.php | 48 +++++++++++++++++-- tests/bootstrap.php | 21 +++++++- 8 files changed, 147 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 27b1aa42ba..8dd294c50c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -346,6 +346,36 @@ However, there are a few places which include OS-specific conditions, most notab Tests which cover code which have Windows specific conditions should be marked with a `@group Windows` annotation to allow for running those tests separately/selectively in CI. +#### Tests covering code which has CS/CBF specific behaviour + +There are a few places in PHPCS where code uses a global `PHP_CODESNIFFER_CBF` constant to determine what to do. +This makes testing this code more complicated. + +Tests which will only work correctly when `PHP_CODESNIFFER_CBF === false` should get the following test skip condition at the top of the test method: +```php +if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); +} +``` + +Tests which are specifically intended to cover code run when `PHP_CODESNIFFER_CBF === true` should: +1. Be annotated with `@group CBF`. +2. Have a test skip condition at the top of the test method like so: + ```php + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + ``` + +By default, the tests are run with the `PHP_CODESNIFFER_CBF` constant set to `false` and tests in the `@group CBF` will not be run. + +To run the tests specific to the use of `PHP_CODESNIFFER_CBF === true`: +1. Set `` in a `phpunit.xml` file or set the ENV variable on an OS-level. +2. Run the tests like so: + ```bash + vendor/bin/phpunit --group CBF --exclude-group nothing + ``` + ### Submitting Your Pull Request diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index ed24bec539..5edde2a41a 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -76,6 +76,11 @@ jobs: if: ${{ matrix.os == 'windows-latest' }} run: php "vendor/bin/phpunit" tests/AllTests.php --group Windows --no-coverage + - name: 'PHPUnit: run select tests in CBF mode' + run: php "vendor/bin/phpunit" tests/AllTests.php --group CBF --exclude-group nothing --no-coverage + env: + PHP_CODESNIFFER_CBF: '1' + # Note: The code style check is run as an integration test. - name: 'PHPCS: check code style without cache, no parallel' run: php "bin/phpcs" --no-cache --parallel=1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0113b7e8a7..e84fad9571 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -183,6 +183,11 @@ jobs: if: ${{ matrix.skip_tests != true }} run: php "vendor/bin/phpunit" tests/AllTests.php --no-coverage + - name: 'PHPUnit: run select tests in CBF mode' + run: php "vendor/bin/phpunit" tests/AllTests.php --group CBF --exclude-group nothing --no-coverage + env: + PHP_CODESNIFFER_CBF: '1' + - name: 'PHPCS: check code style without cache, no parallel' if: ${{ matrix.custom_ini == false && matrix.php != '7.4' }} run: php "bin/phpcs" --no-cache --parallel=1 @@ -311,6 +316,22 @@ jobs: if: ${{ matrix.os != 'windows-latest' && steps.phpunit_version.outputs.VERSION >= '9.3' }} run: php "vendor/bin/phpunit" tests/AllTests.php --coverage-cache ./build/phpunit-cache + - name: "Run select tests in CBF mode with code coverage (PHPUnit < 9.3)" + if: ${{ matrix.os != 'windows-latest' && steps.phpunit_version.outputs.VERSION < '9.3' }} + run: > + php "vendor/bin/phpunit" tests/AllTests.php + --group CBF --exclude-group nothing --coverage-clover build/logs/clover-cbf.xml + env: + PHP_CODESNIFFER_CBF: '1' + + - name: "Run select tests in CBF mode with code coverage (PHPUnit 9.3+)" + if: ${{ matrix.os != 'windows-latest' && steps.phpunit_version.outputs.VERSION >= '9.3' }} + run: > + php "vendor/bin/phpunit" tests/AllTests.php --coverage-cache ./build/phpunit-cache + --group CBF --exclude-group nothing --coverage-clover build/logs/clover-cbf.xml + env: + PHP_CODESNIFFER_CBF: '1' + - name: "Run the unit tests which may have different outcomes on Windows with code coverage (PHPUnit < 9.3)" if: ${{ matrix.os == 'windows-latest' && steps.phpunit_version.outputs.VERSION < '9.3' }} run: php "vendor/bin/phpunit" tests/AllTests.php --group Windows @@ -319,7 +340,7 @@ jobs: if: ${{ matrix.os == 'windows-latest' && steps.phpunit_version.outputs.VERSION >= '9.3' }} run: php "vendor/bin/phpunit" tests/AllTests.php --group Windows --coverage-cache ./build/phpunit-cache - - name: Upload coverage results to Coveralls + - name: "Upload coverage results to Coveralls (normal run)" if: ${{ success() }} uses: coverallsapp/github-action@v2 with: @@ -328,6 +349,15 @@ jobs: flag-name: os-${{ matrix.os }}-php-${{ matrix.php }}-custom-ini-${{ matrix.custom_ini }} parallel: true + - name: "Upload coverage results to Coveralls (CBF run)" + if: ${{ matrix.os != 'windows-latest' && success() }} + uses: coverallsapp/github-action@v2 + with: + format: clover + file: build/logs/clover-cbf.xml + flag-name: cbf-os-${{ matrix.os }}-ubuntu-latest-php-${{ matrix.php }}-custom-ini-${{ matrix.custom_ini }} + parallel: true + coveralls-finish: needs: coverage if: always() && needs.coverage.result == 'success' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1402588f20..cf2b588c86 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,6 +18,12 @@ + + + CBF + + + ./src @@ -32,4 +38,8 @@ + + + + diff --git a/tests/Core/Generators/GeneratorTest.php b/tests/Core/Generators/GeneratorTest.php index 30536518f6..441c499874 100644 --- a/tests/Core/Generators/GeneratorTest.php +++ b/tests/Core/Generators/GeneratorTest.php @@ -201,6 +201,10 @@ public static function dataGeneratingDocs() */ public function testGeneratorWillShowEachStandardSeparately() { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + $standard = __DIR__.'/OneDocTest.xml'; $_SERVER['argv'] = [ 'phpcs', diff --git a/tests/Core/Ruleset/ExplainTest.php b/tests/Core/Ruleset/ExplainTest.php index 48df24f473..4ec5b48317 100644 --- a/tests/Core/Ruleset/ExplainTest.php +++ b/tests/Core/Ruleset/ExplainTest.php @@ -217,6 +217,10 @@ public function testExplainWithDeprecatedSniffs() */ public function testExplainWillExplainEachStandardSeparately() { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + $standard = __DIR__.'/ExplainSingleSniffTest.xml'; $_SERVER['argv'] = [ 'phpcs', diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php index c31f7b4a83..2a36c34c65 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -67,7 +67,7 @@ public static function dataHasSniffDeprecations() /** - * Test that the listing with deprecated sniffs will not show when specific command-line options are being used. + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used [1]. * * @param string $standard The standard to use for the test. * @param array $additionalArgs Optional. Additional arguments to pass. @@ -102,24 +102,62 @@ public function testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs=[ public static function dataDeprecatedSniffsListDoesNotShow() { return [ - 'Standard not using deprecated sniffs: PSR1' => [ + 'Standard not using deprecated sniffs: PSR1' => [ 'standard' => 'PSR1', ], - 'Standard using deprecated sniffs; explain mode' => [ + 'Standard using deprecated sniffs; explain mode' => [ 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', 'additionalArgs' => ['-e'], ], - 'Standard using deprecated sniffs; quiet mode' => [ + 'Standard using deprecated sniffs; quiet mode' => [ 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', 'additionalArgs' => ['-q'], ], + ]; + + }//end dataDeprecatedSniffsListDoesNotShow() + + + /** + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used [2]. + * + * {@internal Separate test method for the same thing as this test will only work in CS mode.} + * + * @param string $standard The standard to use for the test. + * @param array $additionalArgs Optional. Additional arguments to pass. + * + * @dataProvider dataDeprecatedSniffsListDoesNotShowNeedsCsMode + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowNeedsCsMode($standard, $additionalArgs=[]) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs); + + }//end testDeprecatedSniffsListDoesNotShowNeedsCsMode() + + + /** + * Data provider. + * + * @see testDeprecatedSniffsListDoesNotShowNeedsCsMode() + * + * @return array>> + */ + public static function dataDeprecatedSniffsListDoesNotShowNeedsCsMode() + { + return [ 'Standard using deprecated sniffs; documentation is requested' => [ 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', 'additionalArgs' => ['--generator=text'], ], ]; - }//end dataDeprecatedSniffsListDoesNotShow() + }//end dataDeprecatedSniffsListDoesNotShowNeedsCsMode() /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index cf4936daa8..e8ebdbbdd0 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -11,8 +11,27 @@ define('PHP_CODESNIFFER_IN_TESTS', true); } +/* + * Determine whether the test suite should be run in CBF mode. + * + * Use `` in a `phpunit.xml` file + * or set the ENV variable at an OS-level to enable CBF mode. + * + * To run the CBF specific tests, use the following command: + * vendor/bin/phpunit --group CBF --exclude-group nothing + * + * If the ENV variable has not been set, or is set to "false", the tests will run in CS mode. + */ + if (defined('PHP_CODESNIFFER_CBF') === false) { - define('PHP_CODESNIFFER_CBF', false); + $cbfMode = getenv('PHP_CODESNIFFER_CBF'); + if ($cbfMode === '1') { + define('PHP_CODESNIFFER_CBF', true); + echo 'Note: Tests are running in "CBF" mode'.PHP_EOL.PHP_EOL; + } else { + define('PHP_CODESNIFFER_CBF', false); + echo 'Note: Tests are running in "CS" mode'.PHP_EOL.PHP_EOL; + } } if (defined('PHP_CODESNIFFER_VERBOSITY') === false) { From a25d8cf6770fea45ae0b86cb2375b39ac1b25411 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 19 Nov 2024 21:11:05 +0100 Subject: [PATCH 109/192] Tests/Ruleset: introduce an abstract base TestCase Introduce an abstract base TestCase with some helper methods specifically for tests testing aspects of the `Ruleset` class. --- .../Core/Ruleset/AbstractRulesetTestCase.php | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 tests/Core/Ruleset/AbstractRulesetTestCase.php diff --git a/tests/Core/Ruleset/AbstractRulesetTestCase.php b/tests/Core/Ruleset/AbstractRulesetTestCase.php new file mode 100644 index 0000000000..41c6394431 --- /dev/null +++ b/tests/Core/Ruleset/AbstractRulesetTestCase.php @@ -0,0 +1,115 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractRulesetTestCase extends TestCase +{ + + /** + * The fully qualified name of the PHPCS runtime exception class. + * + * @var string + */ + const RUNTIME_EXCEPTION = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + + /** + * Asserts that an object has a specified property in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectHasProperty') === true) { + $this->assertObjectHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectHasProperty() + + + /** + * Asserts that an object does not have a specified property + * in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectNotHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectNotHasProperty') === true) { + $this->assertObjectNotHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectNotHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectNotHasProperty() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException with a certain message + * in a PHPUnit cross-version compatible manner. + * + * @param string $message The expected exception message. + * + * @return void + */ + protected function expectRuntimeExceptionMessage($message) + { + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException(self::RUNTIME_EXCEPTION, $message); + } + + }//end expectRuntimeExceptionMessage() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException which matches a regex patten + * in a PHPUnit cross-version compatible manner. + * + * @param string $regex The regex which should match. + * + * @return void + */ + protected function expectRuntimeExceptionRegex($regex) + { + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp(self::RUNTIME_EXCEPTION, $regex); + } + + }//end expectRuntimeExceptionRegex() + + +}//end class From db02f0d9935fde609c39fc35272871e2b904e326 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 19 Nov 2024 21:14:56 +0100 Subject: [PATCH 110/192] Tests/Ruleset: start using the new `AbstractRulesetTestCase` Start using the new `AbstractRulesetTestCase` in pre-existing `Ruleset` tests. --- tests/Core/Ruleset/RuleInclusionTest.php | 15 +++-------- tests/Core/Ruleset/SetSniffPropertyTest.php | 26 +++++-------------- .../Ruleset/ShowSniffDeprecationsTest.php | 14 +++------- 3 files changed, 13 insertions(+), 42 deletions(-) diff --git a/tests/Core/Ruleset/RuleInclusionTest.php b/tests/Core/Ruleset/RuleInclusionTest.php index 3f6a7180d6..e016a7ea1a 100644 --- a/tests/Core/Ruleset/RuleInclusionTest.php +++ b/tests/Core/Ruleset/RuleInclusionTest.php @@ -11,15 +11,14 @@ use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; -use PHPUnit\Framework\TestCase; -use ReflectionObject; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; /** * Tests for the \PHP_CodeSniffer\Ruleset class. * * @covers \PHP_CodeSniffer\Ruleset */ -final class RuleInclusionTest extends TestCase +final class RuleInclusionTest extends AbstractRulesetTestCase { /** @@ -352,10 +351,7 @@ public static function dataRegisteredSniffCodes() public function testSettingProperties($sniffClass, $propertyName, $expectedValue) { $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs); - - $hasProperty = (new ReflectionObject(self::$ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); - $errorMsg = sprintf('Property %s does not exist on sniff class %s', $propertyName, $sniffClass); - $this->assertTrue($hasProperty, $errorMsg); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]); $actualValue = self::$ruleset->sniffs[$sniffClass]->$propertyName; $this->assertSame($expectedValue, $actualValue); @@ -444,10 +440,7 @@ public static function dataSettingProperties() public function testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails($sniffClass, $propertyName) { $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); - - $hasProperty = (new ReflectionObject(self::$ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); - $errorMsg = sprintf('Property %s registered for sniff %s which does not support it', $propertyName, $sniffClass); - $this->assertFalse($hasProperty, $errorMsg); + $this->assertXObjectNotHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]); }//end testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() diff --git a/tests/Core/Ruleset/SetSniffPropertyTest.php b/tests/Core/Ruleset/SetSniffPropertyTest.php index 51bd0e2989..ed902b9084 100644 --- a/tests/Core/Ruleset/SetSniffPropertyTest.php +++ b/tests/Core/Ruleset/SetSniffPropertyTest.php @@ -11,7 +11,7 @@ use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; use ReflectionObject; /** @@ -19,7 +19,7 @@ * * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty */ -final class SetSniffPropertyTest extends TestCase +final class SetSniffPropertyTest extends AbstractRulesetTestCase { @@ -135,15 +135,8 @@ public function testSetPropertyAppliesPropertyToMultipleSniffsInCategory() */ public function testSetPropertyThrowsErrorOnInvalidProperty() { - $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - $exceptionMsg = 'Ruleset invalid. Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent'; - if (method_exists($this, 'expectException') === true) { - $this->expectException($exceptionClass); - $this->expectExceptionMessage($exceptionMsg); - } else { - // PHPUnit < 5.2.0. - $this->setExpectedException($exceptionClass, $exceptionMsg); - } + $exceptionMsg = 'Ruleset invalid. Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent'; + $this->expectRuntimeExceptionMessage($exceptionMsg); // Set up the ruleset. $standard = __DIR__.'/SetPropertyThrowsErrorOnInvalidPropertyTest.xml'; @@ -162,15 +155,8 @@ public function testSetPropertyThrowsErrorOnInvalidProperty() */ public function testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() { - $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - $exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff TestStandard.SetProperty.NotAllowedViaAttribute'; - if (method_exists($this, 'expectException') === true) { - $this->expectException($exceptionClass); - $this->expectExceptionMessage($exceptionMsg); - } else { - // PHPUnit < 5.2.0. - $this->setExpectedException($exceptionClass, $exceptionMsg); - } + $exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff TestStandard.SetProperty.NotAllowedViaAttribute'; + $this->expectRuntimeExceptionMessage($exceptionMsg); // Set up the ruleset. $standard = __DIR__.'/SetPropertyNotAllowedViaAttributeTest.xml'; diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php index c31f7b4a83..0c142d9772 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.php +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -11,7 +11,7 @@ use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; /** * Tests PHPCS native handling of sniff deprecations. @@ -19,7 +19,7 @@ * @covers \PHP_CodeSniffer\Ruleset::hasSniffDeprecations * @covers \PHP_CodeSniffer\Ruleset::showSniffDeprecations */ -final class ShowSniffDeprecationsTest extends TestCase +final class ShowSniffDeprecationsTest extends AbstractRulesetTestCase { @@ -452,15 +452,7 @@ public function testDeprecatedSniffsAreListedAlphabetically() */ public function testExceptionIsThrownOnIncorrectlyImplementedInterface($standard, $exceptionMessage) { - $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - if (method_exists($this, 'expectException') === true) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($exceptionMessage); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $exceptionMessage); - } + $this->expectRuntimeExceptionMessage($exceptionMessage); // Set up the ruleset. $standard = __DIR__.'/'.$standard; From b5a81c6a08ae46855c4fdef0df191137562f9a3f Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:01:54 +0100 Subject: [PATCH 111/192] Ruleset::getIgnorePatterns(): add tests (#705) --- tests/Core/Ruleset/GetIgnorePatternsTest.php | 111 +++++++++++++++++++ tests/Core/Ruleset/GetIgnorePatternsTest.xml | 19 ++++ 2 files changed, 130 insertions(+) create mode 100644 tests/Core/Ruleset/GetIgnorePatternsTest.php create mode 100644 tests/Core/Ruleset/GetIgnorePatternsTest.xml diff --git a/tests/Core/Ruleset/GetIgnorePatternsTest.php b/tests/Core/Ruleset/GetIgnorePatternsTest.php new file mode 100644 index 0000000000..ae6b8bea50 --- /dev/null +++ b/tests/Core/Ruleset/GetIgnorePatternsTest.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIgnorePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIgnorePatterns + */ +final class GetIgnorePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIgnorePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving ignore patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIgnorePatterns + * + * @return void + */ + public function testGetIgnorePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIgnorePatterns($listener)); + + }//end testGetIgnorePatterns() + + + /** + * Data provider. + * + * @see self::testGetIgnorePatterns() + * + * @return array>|null>> + */ + public static function dataGetIgnorePatterns() + { + return [ + 'All ignore patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + './tests/' => 'absolute', + './vendor/*' => 'absolute', + '*/node-modules/*' => 'relative', + ], + ], + 'Ignore patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Ignore patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Ignore patterns for sniff without ignore patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIgnorePatterns() + + +}//end class diff --git a/tests/Core/Ruleset/GetIgnorePatternsTest.xml b/tests/Core/Ruleset/GetIgnorePatternsTest.xml new file mode 100644 index 0000000000..7fcfdc237d --- /dev/null +++ b/tests/Core/Ruleset/GetIgnorePatternsTest.xml @@ -0,0 +1,19 @@ + + + + ./tests/ + ./vendor/* + */node-modules/* + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + From a480170b38aca33442f11edbb7d4ee18af17475c Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:21:53 +0100 Subject: [PATCH 112/192] Ruleset::getIncludePatterns(): add tests (#706) --- tests/Core/Ruleset/GetIncludePatternsTest.php | 108 ++++++++++++++++++ tests/Core/Ruleset/GetIncludePatternsTest.xml | 15 +++ 2 files changed, 123 insertions(+) create mode 100644 tests/Core/Ruleset/GetIncludePatternsTest.php create mode 100644 tests/Core/Ruleset/GetIncludePatternsTest.xml diff --git a/tests/Core/Ruleset/GetIncludePatternsTest.php b/tests/Core/Ruleset/GetIncludePatternsTest.php new file mode 100644 index 0000000000..a38401b614 --- /dev/null +++ b/tests/Core/Ruleset/GetIncludePatternsTest.php @@ -0,0 +1,108 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIncludePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIncludePatterns + */ +final class GetIncludePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIncludePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving include patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIncludePatterns + * + * @return void + */ + public function testGetIncludePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIncludePatterns($listener)); + + }//end testGetIncludePatterns() + + + /** + * Data provider. + * + * @see self::testGetIncludePatterns() + * + * @return array>|null>> + */ + public static function dataGetIncludePatterns() + { + return [ + 'All include patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + ], + ], + 'Include patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Include patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Include patterns for sniff without include patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIncludePatterns() + + +}//end class diff --git a/tests/Core/Ruleset/GetIncludePatternsTest.xml b/tests/Core/Ruleset/GetIncludePatternsTest.xml new file mode 100644 index 0000000000..c24f93f548 --- /dev/null +++ b/tests/Core/Ruleset/GetIncludePatternsTest.xml @@ -0,0 +1,15 @@ + + + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + From 9ed4ae8a9349f0319f5db9b76e9234c824926d5b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Nov 2024 20:43:16 +0100 Subject: [PATCH 113/192] GH Actions/test: allow concurrency for build against "main" branches The `concurrency` setting will cancel running workflows is a new push to the same branch is seen. This is useful to prevent unnecessary workflow runs (as the previous push was superseded, so the outcome is no longer relevant). However, for the "main" branches (`master` and `4.0`), this workflow cancelling means that if multiple PRs are merged in succession, only the code coverage for the _last_ merge is recorded in Coveralls as the workflow runs on `master` for the previous merges will have been cancelled. While in practice, it's not a biggie, it does make it more difficult to identify which commit/merge added or decreased code coverage. With this in mind, I'm making a small change to the `concurrency` setting for the `test` workflow only to allow those to always finish when the workflow is run for the "main" branches. --- .github/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e84fad9571..1ea04c9384 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,11 +14,13 @@ on: # Allow manually triggering the workflow. workflow_dispatch: -# Cancels all previous workflow runs for the same branch that have not yet completed. +# Cancels all previous workflow runs for the same branch that have not yet completed, +# but don't cancel when it's one of the "main" branches as that prevents +# accurate monitoring of code coverage. concurrency: # The concurrency group contains the workflow name and the branch name. group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref_name != 'master' && github.ref_name != '4.0' }} jobs: build: From 8b8aa2e4b11fb60ddea76fae6d2a6b5fbcffa8f8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 00:03:59 +0100 Subject: [PATCH 114/192] Generators: add tests for handling documentation titles This adds dedicated tests for specific issues which can be encountered with the `title` attribute for `` elements. This initial set of tests for this documents the current behaviour. This behaviour may not always be the desired behaviour, in which case, this will be fixed in follow-up commits. --- tests/Core/Generators/AllValidDocsTest.xml | 10 +++ .../ExpectedOutputDocumentationTitleCase.html | 78 +++++++++++++++++++ .../ExpectedOutputDocumentationTitleCase.md | 6 ++ .../ExpectedOutputDocumentationTitleCase.txt | 7 ++ ...xpectedOutputDocumentationTitleLength.html | 78 +++++++++++++++++++ .../ExpectedOutputDocumentationTitleLength.md | 6 ++ ...ExpectedOutputDocumentationTitleLength.txt | 7 ++ .../DocumentationTitleCaseStandard.xml | 7 ++ .../DocumentationTitleLengthStandard.xml | 7 ++ .../Content/DocumentationTitleCaseSniff.php | 12 +++ .../Content/DocumentationTitleLengthSniff.php | 12 +++ tests/Core/Generators/HTMLTest.php | 61 +++++++++++++++ tests/Core/Generators/MarkdownTest.php | 61 +++++++++++++++ tests/Core/Generators/TextTest.php | 61 +++++++++++++++ 14 files changed, 413 insertions(+) create mode 100644 tests/Core/Generators/AllValidDocsTest.xml create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/DocumentationTitleCaseSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/DocumentationTitleLengthSniff.php diff --git a/tests/Core/Generators/AllValidDocsTest.xml b/tests/Core/Generators/AllValidDocsTest.xml new file mode 100644 index 0000000000..71a0c7f7a5 --- /dev/null +++ b/tests/Core/Generators/AllValidDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html new file mode 100644 index 0000000000..98184e1e85 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html @@ -0,0 +1,78 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    +
    +

    lowercase title

    +

    This is a standard block.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md new file mode 100644 index 0000000000..d0464a4efa --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md @@ -0,0 +1,6 @@ +# GeneratorTest Coding Standard + +## lowercase title +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt new file mode 100644 index 0000000000..c762a01d96 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------- +| GENERATORTEST CODING STANDARD: LOWERCASE TITLE | +-------------------------------------------------- + +This is a standard block. + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html new file mode 100644 index 0000000000..e94beac1ca --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html @@ -0,0 +1,78 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    This is a very very very very very very very very very very very long title

    +

    This is a standard block.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md new file mode 100644 index 0000000000..29f5972a7c --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md @@ -0,0 +1,6 @@ +# GeneratorTest Coding Standard + +## This is a very very very very very very very very very very very long title +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt new file mode 100644 index 0000000000..2787b8cdfe --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: THIS IS A VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY LONG TITLE | +-------------------------------------------------------------------------------------------------------------- + +This is a standard block. + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml new file mode 100644 index 0000000000..a4078e3dee --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml new file mode 100644 index 0000000000..2448927640 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/DocumentationTitleCaseSniff.php b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/DocumentationTitleCaseSniff.php new file mode 100644 index 0000000000..09ffdac68e --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/DocumentationTitleCaseSniff.php @@ -0,0 +1,12 @@ + true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.html', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.html', + ], + ]; + + }//end dataDocSpecifics() + + /** * Test the generated footer. * diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index 0610678dbe..b7ba2f5fb1 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -77,6 +77,67 @@ public static function dataDocs() }//end dataDocs() + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.md', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.md', + ], + ]; + + }//end dataDocSpecifics() + + /** * Test the generated footer. * diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php index 40544557f2..f571aff71d 100644 --- a/tests/Core/Generators/TextTest.php +++ b/tests/Core/Generators/TextTest.php @@ -77,4 +77,65 @@ public static function dataDocs() }//end dataDocs() + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.txt', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.txt', + ], + ]; + + }//end dataDocSpecifics() + + }//end class From 3f33a50bc30ad101c79cce94a7395ea6556062c3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 09:57:22 +0100 Subject: [PATCH 115/192] Generators: add tests for handling element This adds dedicated tests for specific issues which can be encountered in a `` XML element. This initial set of tests for this documents the current behaviour. This behaviour may not always be the desired behaviour, in which case, this will be fixed in follow-up commits. --- .../ExpectedOutputStandardBlankLines.html | 82 +++++++++++++++++++ .../ExpectedOutputStandardBlankLines.md | 10 +++ .../ExpectedOutputStandardBlankLines.txt | 11 +++ .../ExpectedOutputStandardEncoding.html | 79 ++++++++++++++++++ .../ExpectedOutputStandardEncoding.md | 7 ++ .../ExpectedOutputStandardEncoding.txt | 9 ++ .../ExpectedOutputStandardIndent.html | 81 ++++++++++++++++++ .../ExpectedOutputStandardIndent.md | 9 ++ .../ExpectedOutputStandardIndent.txt | 10 +++ .../ExpectedOutputStandardLineWrapping.html | 80 ++++++++++++++++++ .../ExpectedOutputStandardLineWrapping.md | 8 ++ .../ExpectedOutputStandardLineWrapping.txt | 11 +++ .../Content/StandardBlankLinesStandard.xml | 13 +++ .../Docs/Content/StandardEncodingStandard.xml | 8 ++ .../Docs/Content/StandardIndentStandard.xml | 10 +++ .../Content/StandardLineWrappingStandard.xml | 9 ++ .../Content/StandardBlankLinesSniff.php | 12 +++ .../Sniffs/Content/StandardEncodingSniff.php | 12 +++ .../Sniffs/Content/StandardIndentSniff.php | 12 +++ .../Content/StandardLineWrappingSniff.php | 12 +++ tests/Core/Generators/HTMLTest.php | 20 ++++- tests/Core/Generators/MarkdownTest.php | 20 ++++- tests/Core/Generators/TextTest.php | 20 ++++- 23 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardBlankLinesSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardEncodingSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardIndentSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardLineWrappingSniff.php diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html new file mode 100644 index 0000000000..5c6539d0ca --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html @@ -0,0 +1,82 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Standard Element, blank line handling

    +

    There is a blank line at the start of this standard. + + And the above blank line is also deliberate to test part of the logic. + + Let's also end on a blank line to test that too.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md new file mode 100644 index 0000000000..43ba99d2db --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md @@ -0,0 +1,10 @@ +# GeneratorTest Coding Standard + +## Standard Element, blank line handling +There is a blank line at the start of this standard. + + And the above blank line is also deliberate to test part of the logic. + + Let's also end on a blank line to test that too. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt new file mode 100644 index 0000000000..1cdad0b11a --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt @@ -0,0 +1,11 @@ + +------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, BLANK LINE HANDLING | +------------------------------------------------------------------------ + +There is a blank line at the start of this standard. + +And the above blank line is also deliberate to test part of the logic. + +Let's also end on a blank line to test that too. + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html new file mode 100644 index 0000000000..5b1c8ca3c3 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html @@ -0,0 +1,79 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Standard Element, handling of HTML tags

    +

    The use of tags in standard descriptions is allowed and their handling should be safeguarded. + Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md new file mode 100644 index 0000000000..f04de7f096 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Standard Element, handling of HTML tags +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. + Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt new file mode 100644 index 0000000000..a464b86e29 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt @@ -0,0 +1,9 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, HANDLING OF HTML TAGS | +-------------------------------------------------------------------------- + +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. +Other tags, like link, bold, are not allowed +and will be encoded for display when the HTML or Markdown report is used. + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html new file mode 100644 index 0000000000..4c4bcb54ac --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html @@ -0,0 +1,81 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Standard Element, indentation should be ignored

    +

    This line has no indentation. + This line has 4 spaces indentation. + This line has 8 spaces indentation. + This line has 4 spaces indentation.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md new file mode 100644 index 0000000000..77c7244a12 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md @@ -0,0 +1,9 @@ +# GeneratorTest Coding Standard + +## Standard Element, indentation should be ignored +This line has no indentation. + This line has 4 spaces indentation. + This line has 8 spaces indentation. + This line has 4 spaces indentation. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt new file mode 100644 index 0000000000..fef00b9dc9 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt @@ -0,0 +1,10 @@ + +---------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, INDENTATION SHOULD BE IGNORED | +---------------------------------------------------------------------------------- + +This line has no indentation. +This line has 4 spaces indentation. +This line has 8 spaces indentation. +This line has 4 spaces indentation. + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html new file mode 100644 index 0000000000..8ca982efc1 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html @@ -0,0 +1,80 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Standard Element, line wrapping handling

    +

    This line has to be exactly 99 chars to test part of the logic.------------------------------------ + And this line has to be exactly 100 chars.---------------------------------------------------------- + And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md new file mode 100644 index 0000000000..68703400cc --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md @@ -0,0 +1,8 @@ +# GeneratorTest Coding Standard + +## Standard Element, line wrapping handling +This line has to be exactly 99 chars to test part of the logic.------------------------------------ + And this line has to be exactly 100 chars.---------------------------------------------------------- + And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt new file mode 100644 index 0000000000..6f09fbe335 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt @@ -0,0 +1,11 @@ + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, LINE WRAPPING HANDLING | +--------------------------------------------------------------------------- + +This line has to be exactly 99 chars to test part of the logic.------------------------------------ +And this line has to be exactly 100 chars.---------------------------------------------------------- +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum +dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi +ultrices in odio pharetra commodo. + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml new file mode 100644 index 0000000000..10c47bf46a --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml new file mode 100644 index 0000000000..3e34c3f9f7 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml @@ -0,0 +1,8 @@ + + + tags in standard descriptions is allowed and their handling should be safeguarded. + Other tags, like link, bold, are not allowed and will be encoded for display when the HTML or Markdown report is used. + ]]> + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml new file mode 100644 index 0000000000..b2ec6c5e3c --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml new file mode 100644 index 0000000000..66bbb96275 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardBlankLinesSniff.php b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardBlankLinesSniff.php new file mode 100644 index 0000000000..dfd4b57001 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/StandardBlankLinesSniff.php @@ -0,0 +1,12 @@ + [ + 'Documentation title: case' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.html', ], - 'Documentation title: length' => [ + 'Documentation title: length' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.html', ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.html', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.html', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.html', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.html', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index b7ba2f5fb1..c93beb4416 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -125,14 +125,30 @@ public function testDocSpecifics($sniffs, $pathToExpected) public static function dataDocSpecifics() { return [ - 'Documentation title: case' => [ + 'Documentation title: case' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.md', ], - 'Documentation title: length' => [ + 'Documentation title: length' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.md', ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.md', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.md', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.md', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.md', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php index f571aff71d..d9740bda22 100644 --- a/tests/Core/Generators/TextTest.php +++ b/tests/Core/Generators/TextTest.php @@ -125,14 +125,30 @@ public function testDocSpecifics($sniffs, $pathToExpected) public static function dataDocSpecifics() { return [ - 'Documentation title: case' => [ + 'Documentation title: case' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.txt', ], - 'Documentation title: length' => [ + 'Documentation title: length' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.txt', ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.txt', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.txt', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.txt', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.txt', + ], ]; }//end dataDocSpecifics() From 65d57b134b60be9669d58add1211edfb7db091a4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 5 Nov 2024 00:25:49 +0100 Subject: [PATCH 116/192] Generators HTML/Markdown: consistent encoding cross-PHP The default value for the `$flags` parameter of the `htmlspecialchars()` function changed in PHP 8.1.0. Previously, the default was `ENT_COMPAT`. Now the default is `ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401`. The most notable differences are: * Single quotes will be encoded. * Invalid code unit sequences will be replace by a Unicode Replacement Character. For consistent output cross-version PHP, it is advised to always explicitly pass the `$flags` parameter` and not rely on the default value. Fixed now and using the _new_ `$flags` default value as the parameter value. This commit allows for the tests to have the same output expectations cross-version PHP. For end-users, the differences shouldn't have been noticeable. --- src/Generators/HTML.php | 2 +- src/Generators/Markdown.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generators/HTML.php b/src/Generators/HTML.php index 0f3733b984..0ca4496963 100644 --- a/src/Generators/HTML.php +++ b/src/Generators/HTML.php @@ -235,7 +235,7 @@ public function processSniff(DOMNode $doc) protected function printTextBlock(DOMNode $node) { $content = trim($node->nodeValue); - $content = htmlspecialchars($content); + $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); // Use the correct line endings based on the OS. $content = str_replace("\n", PHP_EOL, $content); diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index ab30cd59a7..6df243a459 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -116,7 +116,7 @@ protected function processSniff(DOMNode $doc) protected function printTextBlock(DOMNode $node) { $content = trim($node->nodeValue); - $content = htmlspecialchars($content); + $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); // Use the correct line endings based on the OS. $content = str_replace("\n", PHP_EOL, $content); From 02fe7005958cacbb003934650e5cf21a2a58d6b6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 19:59:07 +0100 Subject: [PATCH 117/192] Generators: add tests for handling code sample titles This adds dedicated tests for specific issues which can be encountered with the `title` attribute for `` elements. This initial set of tests for this documents the current behaviour. This behaviour may not always be the desired behaviour, in which case, this will be fixed in follow-up commits. --- .../ExpectedOutputCodeTitleLineWrapping.html | 118 ++++++++++++++++++ .../ExpectedOutputCodeTitleLineWrapping.md | 78 ++++++++++++ .../ExpectedOutputCodeTitleLineWrapping.txt | 33 +++++ .../ExpectedOutputCodeTitleWhitespace.html | 98 +++++++++++++++ .../ExpectedOutputCodeTitleWhitespace.md | 43 +++++++ .../ExpectedOutputCodeTitleWhitespace.txt | 22 ++++ .../Content/CodeTitleLineWrappingStandard.xml | 55 ++++++++ .../Content/CodeTitleWhitespaceStandard.xml | 32 +++++ .../Content/CodeTitleLineWrappingSniff.php | 12 ++ .../Content/CodeTitleWhitespaceSniff.php | 12 ++ tests/Core/Generators/HTMLTest.php | 8 ++ tests/Core/Generators/MarkdownTest.php | 8 ++ tests/Core/Generators/TextTest.php | 8 ++ 13 files changed, 527 insertions(+) create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeTitleLineWrappingSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeTitleWhitespaceSniff.php diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html new file mode 100644 index 0000000000..fc35fdf0bf --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html @@ -0,0 +1,118 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code Title, line wrapping

    +

    This is a standard block.

    + + + + + + + + + +
    Valid: exactly 45 character long description.Invalid: exactly 45 char long description---.
    // Dummy.// Dummy.
    + + + + + + + + + +
    Valid: exactly 46 character long description-.Invalid: exactly 46 character long description
    // Dummy.// Dummy.
    + + + + + + + + + +
    Valid: exactly 47 character long description--.Invalid: exactly 47 character long description.
    // Dummy.// Dummy.
    + + + + + + + + + +
    Valid: this description is longer than 46 characters and will wrap.Invalid: this description is longer than 46 characters and will wrap.
    // Dummy.// Dummy.
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md new file mode 100644 index 0000000000..e5b7251aa2 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md @@ -0,0 +1,78 @@ +# GeneratorTest Coding Standard + +## Code Title, line wrapping +This is a standard block. + + + + + + + + + +
    Valid: exactly 45 character long description.Invalid: exactly 45 char long description---.
    + + // Dummy. + + + + // Dummy. + +
    + + + + + + + + + +
    Valid: exactly 46 character long description-.Invalid: exactly 46 character long description
    + + // Dummy. + + + + // Dummy. + +
    + + + + + + + + + +
    Valid: exactly 47 character long description--.Invalid: exactly 47 character long description.
    + + // Dummy. + + + + // Dummy. + +
    + + + + + + + + + +
    Valid: this description is longer than 46 characters and will wrap.Invalid: this description is longer than 46 characters and will wrap.
    + + // Dummy. + + + + // Dummy. + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt new file mode 100644 index 0000000000..11925c4cbb --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt @@ -0,0 +1,33 @@ + +------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, LINE WRAPPING | +------------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 45 character long description. | Invalid: exactly 45 char long description---. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 46 character long description-. | Invalid: exactly 46 character long description | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 47 character long | Invalid: exactly 47 character long | +| description--. | description. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: this description is longer than 46 | Invalid: this description is longer than 46 | +| characters and will wrap. | characters and will wrap. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html new file mode 100644 index 0000000000..a64cdb4deb --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html @@ -0,0 +1,98 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code Title, whitespace handling

    +

    This is a standard block.

    + + + + + + + + + +
    Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
    // Dummy.// Dummy.
    + + + + + + + + + +
    Valid: spaces at start + end of description. Invalid: spaces ' ' in description.
    // Note: description above without the
    // trailing whitespace fits in 46 chars.
    // Dummy.
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md new file mode 100644 index 0000000000..509abf6720 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md @@ -0,0 +1,43 @@ +# GeneratorTest Coding Standard + +## Code Title, whitespace handling +This is a standard block. + + + + + + + + + +
    Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
    + + // Dummy. + + + + // Dummy. + +
    + + + + + + + + + +
    Valid: spaces at start + end of description. Invalid: spaces ' ' in description.
    + + // Note: description above without the + // trailing whitespace fits in 46 chars. + + + + // Dummy. + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt new file mode 100644 index 0000000000..80a6cc690b --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt @@ -0,0 +1,22 @@ + +------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, WHITESPACE HANDLING | +------------------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: spaces at start of description. | Invalid: spaces at end making line > 46 chars. | +| | | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: spaces at start + end of description. | Invalid: spaces ' ' in description. | +| | | +---------------------------------------------------------------------------------------------------- +| // Note: description above without the | // Dummy. | +| // trailing whitespace fits in 46 chars. | | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml new file mode 100644 index 0000000000..b773f7a88c --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml new file mode 100644 index 0000000000..2829720259 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeTitleLineWrappingSniff.php b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeTitleLineWrappingSniff.php new file mode 100644 index 0000000000..560b7884c2 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeTitleLineWrappingSniff.php @@ -0,0 +1,12 @@ + 'StandardWithDocs.Content.StandardLineWrapping', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.html', ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.html', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.html', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index c93beb4416..9612b36b84 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -149,6 +149,14 @@ public static function dataDocSpecifics() 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.md', ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.md', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.md', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php index d9740bda22..2e0c48035e 100644 --- a/tests/Core/Generators/TextTest.php +++ b/tests/Core/Generators/TextTest.php @@ -149,6 +149,14 @@ public static function dataDocSpecifics() 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.txt', ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.txt', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.txt', + ], ]; }//end dataDocSpecifics() From 87d50300a9e23547dae82c118bbe9adaad598b49 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 23:43:45 +0100 Subject: [PATCH 118/192] Generators: add tests for handling code samples This adds dedicated tests for specific issues which can be encountered with the contents of `` elements. This initial set of tests for this documents the current behaviour. This behaviour may not always be the desired behaviour, in which case, this will be fixed in follow-up commits. --- ...xpectedOutputCodeComparisonBlankLines.html | 88 +++++++++++++++++ .../ExpectedOutputCodeComparisonBlankLines.md | 34 +++++++ ...ExpectedOutputCodeComparisonBlankLines.txt | 18 ++++ ...pectedOutputCodeComparisonBlockLength.html | 98 +++++++++++++++++++ ...ExpectedOutputCodeComparisonBlockLength.md | 46 +++++++++ ...xpectedOutputCodeComparisonBlockLength.txt | 23 +++++ .../ExpectedOutputCodeComparisonEncoding.html | 88 +++++++++++++++++ .../ExpectedOutputCodeComparisonEncoding.md | 47 +++++++++ .../ExpectedOutputCodeComparisonEncoding.txt | 26 +++++ ...xpectedOutputCodeComparisonLineLength.html | 89 +++++++++++++++++ .../ExpectedOutputCodeComparisonLineLength.md | 30 ++++++ ...ExpectedOutputCodeComparisonLineLength.txt | 18 ++++ .../CodeComparisonBlankLinesStandard.xml | 33 +++++++ .../CodeComparisonBlockLengthStandard.xml | 35 +++++++ .../CodeComparisonEncodingStandard.xml | 42 ++++++++ .../CodeComparisonLineLengthStandard.xml | 25 +++++ .../Content/CodeComparisonBlankLinesSniff.php | 12 +++ .../CodeComparisonBlockLengthSniff.php | 12 +++ .../Content/CodeComparisonEncodingSniff.php | 12 +++ .../Content/CodeComparisonLineLengthSniff.php | 12 +++ tests/Core/Generators/HTMLTest.php | 16 +++ tests/Core/Generators/MarkdownTest.php | 16 +++ tests/Core/Generators/TextTest.php | 16 +++ 23 files changed, 836 insertions(+) create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlockLengthSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonEncodingSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonLineLengthSniff.php diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html new file mode 100644 index 0000000000..788ef612d8 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html @@ -0,0 +1,88 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code Comparison, blank lines

    +

    This is a standard block.

    + + + + + + + + + +
    Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
    // First line of the code sample is
    // deliberately empty.

    // We also have a blank line in the middle.

    // And a blank line at the end.
    // First line of the code sample is
    // deliberately empty.

    // We also have a blank line in the middle.

    // And a blank line at the end.
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md new file mode 100644 index 0000000000..79efd01775 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md @@ -0,0 +1,34 @@ +# GeneratorTest Coding Standard + +## Code Comparison, blank lines +This is a standard block. + + + + + + + + + +
    Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
    + + // First line of the code sample is + // deliberately empty. + + // We also have a blank line in the middle. + + // And a blank line at the end. + + + + // First line of the code sample is + // deliberately empty. + + // We also have a blank line in the middle. + + // And a blank line at the end. + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt new file mode 100644 index 0000000000..a7fd41d901 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt @@ -0,0 +1,18 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, BLANK LINES | +--------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| // First line of the code sample is | // First line of the code sample is | +| // deliberately empty. | // deliberately empty. | +| | | +| // We also have a blank line in the middle. | // We also have a blank line in the middle. | +| | | +| // And a blank line at the end. | // And a blank line at the end. | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html new file mode 100644 index 0000000000..a8bfc97f7c --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html @@ -0,0 +1,98 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code Comparison, block length

    +

    This is a standard block.

    + + + + + + + + + +
    Valid: code sample A has more lines than B.Invalid: shorter.
    // This code sample has more lines
    // than the "invalid" one.
    $one = 10;
    $a = 10;
    + + + + + + + + + +
    Valid: shorter.Invalid: code sample B has more lines than A.
    echo $foo;// This code sample has more lines
    // than the "valid" one.
    print $foo;
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md new file mode 100644 index 0000000000..b9b64b31c6 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md @@ -0,0 +1,46 @@ +# GeneratorTest Coding Standard + +## Code Comparison, block length +This is a standard block. + + + + + + + + + +
    Valid: code sample A has more lines than B.Invalid: shorter.
    + + // This code sample has more lines + // than the "invalid" one. + $one = 10; + + + + $a = 10; + +
    + + + + + + + + + +
    Valid: shorter.Invalid: code sample B has more lines than A.
    + + echo $foo; + + + + // This code sample has more lines + // than the "valid" one. + print $foo; + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt new file mode 100644 index 0000000000..c2fb737f45 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt @@ -0,0 +1,23 @@ + +---------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, BLOCK LENGTH | +---------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: code sample A has more lines than B. | Invalid: shorter. | +---------------------------------------------------------------------------------------------------- +| // This code sample has more lines | $a = 10; | +| // than the "invalid" one. | | +| $one = 10; | | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: shorter. | Invalid: code sample B has more lines than A. | +---------------------------------------------------------------------------------------------------- +| echo $foo; | // This code sample has more lines | +| | // than the "valid" one. | +| | print $foo; | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html new file mode 100644 index 0000000000..ff9f6df12b --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html @@ -0,0 +1,88 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code Comparison, char encoding

    +

    This is a standard block.

    + + + + + + + + + +
    Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
    <?php

    // The above PHP tag is specifically testing
    // handling of that in generated HTML doc.

    // Now let's also check the handling of
    // comparison operators in code samples...
    $a = $b < $c;
    $d = $e > $f;
    $g = $h <= $i;
    $j = $k >= $l;
    $m = $n <=> $o;
    <?php

    // The above PHP tag is specifically testing
    // handling of that in generated HTML doc.

    // Now let's also check the handling of
    // comparison operators in code samples
    // in combination with "em" tags.
    $a = $b < $c;
    $d = $e > $f;
    $g = $h <= $i;
    $j = $k >= $l;
    $m = $n <=> $o;
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md new file mode 100644 index 0000000000..4c3832fa3f --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md @@ -0,0 +1,47 @@ +# GeneratorTest Coding Standard + +## Code Comparison, char encoding +This is a standard block. + + + + + + + + + +
    Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
    + + $f; + $g = $h <= $i; + $j = $k >= $l; + $m = $n <=> $o; + + + + $f; + $g = $h <= $i; + $j = $k >= $l; + $m = $n <=> $o; + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt new file mode 100644 index 0000000000..7ffcf4df51 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt @@ -0,0 +1,26 @@ + +----------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, CHAR ENCODING | +----------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| $f; | $a = $b < $c; | +| $g = $h <= $i; | $d = $e > $f; | +| $j = $k >= $l; | $g = $h <= $i; | +| $m = $n <=> $o; | $j = $k >= $l; | +| | $m = $n <=> $o; | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html new file mode 100644 index 0000000000..2f7abc69a4 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html @@ -0,0 +1,89 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code Comparison, line length

    +

    Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". + Ref: squizlabs/PHP_CodeSniffer#2522

    + + + + + + + + + +
    Valid: contains line which is too long.Invalid: contains line which is too long.
    class Foo extends Bar implements Countable, Serializable
    {
    }
    class Foo extends Bar
    {
        public static function foobar($param1, $param2) {}
    }
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md new file mode 100644 index 0000000000..f695814ba8 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md @@ -0,0 +1,30 @@ +# GeneratorTest Coding Standard + +## Code Comparison, line length +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". + Ref: squizlabs/PHP_CodeSniffer#2522 + + + + + + + + + +
    Valid: contains line which is too long.Invalid: contains line which is too long.
    + + class Foo extends Bar implements Countable, Serializable + { + } + + + + class Foo extends Bar + { + public static function foobar($param1, $param2) {} + } + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt new file mode 100644 index 0000000000..e8a665cd45 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt @@ -0,0 +1,18 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, LINE LENGTH | +--------------------------------------------------------------- + +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to +0". +Ref: squizlabs/PHP_CodeSniffer#2522 + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: contains line which is too long. | Invalid: contains line which is too long. | +---------------------------------------------------------------------------------------------------- +| class Foo extends Bar implements Countable, Serializable| class Foo extends Bar | +| { | { | +| } | public static function foobar($param1, $param2) {}| +| | } | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml new file mode 100644 index 0000000000..bcaf82bbb6 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml new file mode 100644 index 0000000000..c479a7fd0f --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml @@ -0,0 +1,35 @@ + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml new file mode 100644 index 0000000000..c366553f3e --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml @@ -0,0 +1,42 @@ + + + + + + + $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + + +// The above PHP tag is specifically testing +// handling of that in generated HTML doc. + +// Now let's also check the handling of +// comparison operators in code samples +// in combination with "em" tags. +$a = $b < $c; +$d = $e > $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml new file mode 100644 index 0000000000..b4431ea84d --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml @@ -0,0 +1,25 @@ + + + + + + + Countable, Serializable +{ +} + ]]> + + + foobar($param1, $param2) {} +} + ]]> + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php new file mode 100644 index 0000000000..1e56bf9cf8 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php @@ -0,0 +1,12 @@ + 'StandardWithDocs.Content.CodeTitleWhitespace', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.html', ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.html', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.html', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.html', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.html', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index 9612b36b84..515b832c59 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -157,6 +157,22 @@ public static function dataDocSpecifics() 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.md', ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.md', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.md', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.md', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.md', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php index 2e0c48035e..fd7388d256 100644 --- a/tests/Core/Generators/TextTest.php +++ b/tests/Core/Generators/TextTest.php @@ -157,6 +157,22 @@ public static function dataDocSpecifics() 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.txt', ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.txt', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.txt', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.txt', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.txt', + ], ]; }//end dataDocSpecifics() From fe3111c308aa51acd2873b58e69e381b27d109ec Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 23 Nov 2024 03:37:48 +0100 Subject: [PATCH 119/192] GH Actions: tweak auto-label configuration * Handle the new `Core Component: Generators` label. * Improve regex to identify documentation changes (prevent confusion over tests). --- .github/labeler.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index bd6a522938..3dd66bbb81 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -21,6 +21,10 @@ labels: draft: false files: - "src/Fixer.php$" + - label: "Core Component: Generators" + draft: false + files: + - "src/Generators/.*" - label: "Core Component: Reports" draft: false files: @@ -90,7 +94,7 @@ labels: - label: "Type: documentation" draft: false files: - - '/Docs/[A-Za-z0-9-]*/.*Standard.xml$' + - 'src/Standards/.*/Docs/[A-Za-z0-9-]*/.*Standard.xml$' - label: "Type: documentation" draft: false files: From e2dcc7f6da2fa98a1553fe563d90f6bcda440c05 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 13:19:18 +0100 Subject: [PATCH 120/192] Generators: add tests covering handling of unsupported doc structures This adds a set of dedicated tests to safeguard how XML docs which don't follow the specification are handled. This initial set of tests for this documents the current behaviour. This behaviour may not always be the desired behaviour, in which case, this will be fixed in follow-up commits. --- ...dOutputUnsupportedElementAtWrongLevel.html | 77 ++++++++++++++++ ...tedOutputUnsupportedElementAtWrongLevel.md | 5 ++ ...edOutputUnsupportedElementAtWrongLevel.txt | 5 ++ ...edOutputUnsupportedOneElmAtWrongLevel.html | 78 ++++++++++++++++ ...ctedOutputUnsupportedOneElmAtWrongLevel.md | 6 ++ ...tedOutputUnsupportedOneElmAtWrongLevel.txt | 7 ++ ...tputUnsupportedSuperfluousCodeElement.html | 88 +++++++++++++++++++ ...OutputUnsupportedSuperfluousCodeElement.md | 24 +++++ ...utputUnsupportedSuperfluousCodeElement.txt | 13 +++ ...pectedOutputUnsupportedUnknownElement.html | 77 ++++++++++++++++ ...ExpectedOutputUnsupportedUnknownElement.md | 5 ++ ...xpectedOutputUnsupportedUnknownElement.txt | 5 ++ .../ElementAtWrongLevelStandard.xml | 8 ++ .../OneElmAtWrongLevelStandard.xml | 13 +++ .../SuperfluousCodeElementStandard.xml | 24 +++++ .../Unsupported/UnknownElementStandard.xml | 7 ++ .../Unsupported/ElementAtWrongLevelSniff.php | 12 +++ .../Unsupported/OneElmAtWrongLevelSniff.php | 12 +++ .../SuperfluousCodeElementSniff.php | 12 +++ .../Unsupported/UnknownElementSniff.php | 12 +++ tests/Core/Generators/HTMLTest.php | 16 ++++ tests/Core/Generators/MarkdownTest.php | 16 ++++ tests/Core/Generators/TextTest.php | 16 ++++ 23 files changed, 538 insertions(+) create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md create mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/ElementAtWrongLevelSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/OneElmAtWrongLevelSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/SuperfluousCodeElementSniff.php create mode 100644 tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/UnknownElementSniff.php diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html new file mode 100644 index 0000000000..dfa5670f0e --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html @@ -0,0 +1,77 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Code element at wrong level

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md new file mode 100644 index 0000000000..669ea0f4c6 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md @@ -0,0 +1,5 @@ +# GeneratorTest Coding Standard + +## Code element at wrong level + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt new file mode 100644 index 0000000000..940832ced1 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt @@ -0,0 +1,5 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE ELEMENT AT WRONG LEVEL | +-------------------------------------------------------------- + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html new file mode 100644 index 0000000000..dc86a6c42f --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html @@ -0,0 +1,78 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    One element correct, one element wrong level

    +

    This is a standard block at the correct level.

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md new file mode 100644 index 0000000000..f6eda21036 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md @@ -0,0 +1,6 @@ +# GeneratorTest Coding Standard + +## One element correct, one element wrong level +This is a standard block at the correct level. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt new file mode 100644 index 0000000000..4d1aaeaa12 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt @@ -0,0 +1,7 @@ + +------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE ELEMENT CORRECT, ONE ELEMENT WRONG LEVEL | +------------------------------------------------------------------------------- + +This is a standard block at the correct level. + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html new file mode 100644 index 0000000000..967381e3a9 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html @@ -0,0 +1,88 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Superfluous code element

    +

    This is a standard block.

    + + + + + + + + + +
    Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
    $valid = true;$invalid = true;
    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md new file mode 100644 index 0000000000..131c6cc45a --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md @@ -0,0 +1,24 @@ +# GeneratorTest Coding Standard + +## Superfluous code element +This is a standard block. + + + + + + + + + +
    Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
    + + $valid = true; + + + + $invalid = true; + +
    + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt new file mode 100644 index 0000000000..1307eebfd1 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt @@ -0,0 +1,13 @@ + +----------------------------------------------------------- +| GENERATORTEST CODING STANDARD: SUPERFLUOUS CODE ELEMENT | +----------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| $valid = true; | $invalid = true; | +---------------------------------------------------------------------------------------------------- + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html new file mode 100644 index 0000000000..770d08bbc7 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html @@ -0,0 +1,77 @@ + + + GeneratorTest Coding Standards + + + +

    GeneratorTest Coding Standards

    + +

    Unknown element

    +
    + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md new file mode 100644 index 0000000000..a8be8f9928 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md @@ -0,0 +1,5 @@ +# GeneratorTest Coding Standard + +## Unknown element + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt new file mode 100644 index 0000000000..3e2f564720 --- /dev/null +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt @@ -0,0 +1,5 @@ + +-------------------------------------------------- +| GENERATORTEST CODING STANDARD: UNKNOWN ELEMENT | +-------------------------------------------------- + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml new file mode 100644 index 0000000000..68519dd2be --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml new file mode 100644 index 0000000000..6c1dd164aa --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml new file mode 100644 index 0000000000..333786a337 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml new file mode 100644 index 0000000000..c9ec3227fa --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/ElementAtWrongLevelSniff.php b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/ElementAtWrongLevelSniff.php new file mode 100644 index 0000000000..6ed5c2be69 --- /dev/null +++ b/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Unsupported/ElementAtWrongLevelSniff.php @@ -0,0 +1,12 @@ + 'StandardWithDocs.Content.CodeComparisonLineLength', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.html', ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedUnknownElement.html', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index 515b832c59..54f60d075e 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -173,6 +173,22 @@ public static function dataDocSpecifics() 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.md', ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedUnknownElement.md', + ], ]; }//end dataDocSpecifics() diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php index fd7388d256..b0c5f2807f 100644 --- a/tests/Core/Generators/TextTest.php +++ b/tests/Core/Generators/TextTest.php @@ -173,6 +173,22 @@ public static function dataDocSpecifics() 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.txt', ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedUnknownElement.txt', + ], ]; }//end dataDocSpecifics() From 9780e28bee398fabc13c2f05819626c91802a0d8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 5 Nov 2024 02:07:08 +0100 Subject: [PATCH 121/192] Generators/Markdown: add blank line after title As per the guidelines for cross-flavour markdown, it is best to always have a blank line below a header. Ref: * https://www.markdownguide.org/basic-syntax/#heading-best-practices --- src/Generators/Markdown.php | 2 +- .../ExpectedOutputCodeComparisonBlankLines.md | 1 + .../ExpectedOutputCodeComparisonBlockLength.md | 1 + .../Expectations/ExpectedOutputCodeComparisonEncoding.md | 1 + .../ExpectedOutputCodeComparisonLineLength.md | 1 + .../Expectations/ExpectedOutputCodeTitleLineWrapping.md | 1 + .../Expectations/ExpectedOutputCodeTitleWhitespace.md | 1 + .../Expectations/ExpectedOutputDocumentationTitleCase.md | 1 + .../ExpectedOutputDocumentationTitleLength.md | 1 + .../Core/Generators/Expectations/ExpectedOutputOneDoc.md | 1 + .../Expectations/ExpectedOutputStandardBlankLines.md | 1 + .../Expectations/ExpectedOutputStandardEncoding.md | 1 + .../Expectations/ExpectedOutputStandardIndent.md | 1 + .../Expectations/ExpectedOutputStandardLineWrapping.md | 1 + .../Expectations/ExpectedOutputStructureDocs.md | 8 ++++++++ .../ExpectedOutputUnsupportedElementAtWrongLevel.md | 1 + .../ExpectedOutputUnsupportedOneElmAtWrongLevel.md | 1 + .../ExpectedOutputUnsupportedSuperfluousCodeElement.md | 1 + .../ExpectedOutputUnsupportedUnknownElement.md | 1 + 19 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index 6df243a459..76dbb0605f 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -93,7 +93,7 @@ protected function printFooter() protected function processSniff(DOMNode $doc) { $title = $this->getTitle($doc); - echo PHP_EOL."## $title".PHP_EOL; + echo PHP_EOL."## $title".PHP_EOL.PHP_EOL; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md index 79efd01775..ef25f893c4 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Code Comparison, blank lines + This is a standard block. diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md index b9b64b31c6..526f110b34 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Code Comparison, block length + This is a standard block.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md index 4c3832fa3f..052d3cb3e0 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Code Comparison, char encoding + This is a standard block.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md index f695814ba8..89ae055bfb 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Code Comparison, line length + Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". Ref: squizlabs/PHP_CodeSniffer#2522
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md index e5b7251aa2..a0d6a8e6a2 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Code Title, line wrapping + This is a standard block.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md index 509abf6720..2d04562c7e 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Code Title, whitespace handling + This is a standard block.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md index d0464a4efa..0d63b04a95 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## lowercase title + This is a standard block. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md index 29f5972a7c..252f5fca69 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## This is a very very very very very very very very very very very long title + This is a standard block. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md b/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md index 0cc0ecceae..f6130736ff 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## One Standard Block, No Code + Documentation contains one standard block and no code comparison. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md index 43ba99d2db..6b3d6ed107 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Standard Element, blank line handling + There is a blank line at the start of this standard. And the above blank line is also deliberate to test part of the logic. diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md index f04de7f096..f682daf611 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Standard Element, handling of HTML tags + The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used. diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md index 77c7244a12..1f3916153e 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Standard Element, indentation should be ignored + This line has no indentation. This line has 4 spaces indentation. This line has 8 spaces indentation. diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md index 68703400cc..1a2cd9f19c 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Standard Element, line wrapping handling + This line has to be exactly 99 chars to test part of the logic.------------------------------------ And this line has to be exactly 100 chars.---------------------------------------------------------- And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo. diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md index 116af5df1e..fec8989451 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md @@ -2,7 +2,9 @@ ## No Content + ## Code Comparison Only, Missing Standard Block +
    @@ -23,6 +25,7 @@
    Valid: Lorem ipsum dolor sit amet.
    ## One Standard Block, Code Comparison + Documentation contains one standard block and one code comparison. @@ -44,9 +47,11 @@ Documentation contains one standard block and one code comparison.
    ## One Standard Block, No Code + Documentation contains one standard block and no code comparison. ## One Standard Block, Two Code Comparisons + Documentation contains one standard block and two code comparisons. @@ -86,10 +91,12 @@ Documentation contains one standard block and two code comparisons.
    ## Two Standard Blocks, No Code + This is standard block one. This is standard block two. ## Two Standard Blocks, One Code Comparison + This is standard block one. @@ -112,6 +119,7 @@ This is standard block one. This is standard block two. ## Two Standard Blocks, Three Code Comparisons + This is standard block one.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md index 669ea0f4c6..048f028d57 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md @@ -2,4 +2,5 @@ ## Code element at wrong level + Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md index f6eda21036..aa9cc47279 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## One element correct, one element wrong level + This is a standard block at the correct level. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md index 131c6cc45a..f6cdad9467 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md @@ -1,6 +1,7 @@ # GeneratorTest Coding Standard ## Superfluous code element + This is a standard block.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md index a8be8f9928..211415225f 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md @@ -2,4 +2,5 @@ ## Unknown element + Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) From baec97ea62e91f51d881636ca2f73e368855935b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 19:20:44 +0100 Subject: [PATCH 122/192] Generators/HTML: fix line break handling As things were, line breaks in a `` block were not respected for proper display in HTML. This has now been fixed by: * Recognizing a blank line after a text line as an indicator that the next line should be a new paragraph. * In all other cases, a line break will be translated to an HTML line break. Includes updated test expectations. --- src/Generators/HTML.php | 31 ++++++++++++++++--- ...xpectedOutputCodeComparisonLineLength.html | 4 +-- .../ExpectedOutputStandardBlankLines.html | 8 ++--- .../ExpectedOutputStandardEncoding.html | 4 +-- .../ExpectedOutputStandardIndent.html | 8 ++--- .../ExpectedOutputStandardLineWrapping.html | 6 ++-- 6 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/Generators/HTML.php b/src/Generators/HTML.php index 0ca4496963..8e2001e2e5 100644 --- a/src/Generators/HTML.php +++ b/src/Generators/HTML.php @@ -237,14 +237,35 @@ protected function printTextBlock(DOMNode $node) $content = trim($node->nodeValue); $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); - // Use the correct line endings based on the OS. - $content = str_replace("\n", PHP_EOL, $content); - - // Allow em tags only. + // Allow only em tags. $content = str_replace('<em>', '', $content); $content = str_replace('</em>', '', $content); - echo "

    $content

    ".PHP_EOL; + $nodeLines = explode("\n", $content); + $lineCount = count($nodeLines); + $lines = []; + + for ($i = 0; $i < $lineCount; $i++) { + $currentLine = trim($nodeLines[$i]); + + if (isset($nodeLines[($i + 1)]) === false) { + // We're at the end of the text, just add the line. + $lines[] = $currentLine; + } else { + $nextLine = trim($nodeLines[($i + 1)]); + if ($nextLine === '') { + // Next line is a blank line, end the paragraph and start a new one. + // Also skip over the blank line. + $lines[] = $currentLine.'

    '.PHP_EOL.'

    '; + ++$i; + } else { + // Next line is not blank, so just add a line break. + $lines[] = $currentLine.'
    '.PHP_EOL; + } + } + } + + echo '

    '.implode('', $lines).'

    '.PHP_EOL; }//end printTextBlock() diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html index 2f7abc69a4..b876e6b1e9 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html @@ -72,8 +72,8 @@

    GeneratorTest Coding Standards

    Code Comparison, line length

    -

    Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". - Ref: squizlabs/PHP_CodeSniffer#2522

    +

    Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0".
    +Ref: squizlabs/PHP_CodeSniffer#2522

    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html index 5c6539d0ca..4c45757b57 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html @@ -72,11 +72,9 @@

    GeneratorTest Coding Standards

    Standard Element, blank line handling

    -

    There is a blank line at the start of this standard. - - And the above blank line is also deliberate to test part of the logic. - - Let's also end on a blank line to test that too.

    +

    There is a blank line at the start of this standard.

    +

    And the above blank line is also deliberate to test part of the logic.

    +

    Let's also end on a blank line to test that too.

    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html index 5b1c8ca3c3..106e835a74 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html @@ -72,8 +72,8 @@

    GeneratorTest Coding Standards

    Standard Element, handling of HTML tags

    -

    The use of tags in standard descriptions is allowed and their handling should be safeguarded. - Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used.

    +

    The use of tags in standard descriptions is allowed and their handling should be safeguarded.
    +Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used.

    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html index 4c4bcb54ac..b3aad7f45c 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html @@ -72,10 +72,10 @@

    GeneratorTest Coding Standards

    Standard Element, indentation should be ignored

    -

    This line has no indentation. - This line has 4 spaces indentation. - This line has 8 spaces indentation. - This line has 4 spaces indentation.

    +

    This line has no indentation.
    +This line has 4 spaces indentation.
    +This line has 8 spaces indentation.
    +This line has 4 spaces indentation.

    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html index 8ca982efc1..d54d94c38f 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html @@ -72,9 +72,9 @@

    GeneratorTest Coding Standards

    Standard Element, line wrapping handling

    -

    This line has to be exactly 99 chars to test part of the logic.------------------------------------ - And this line has to be exactly 100 chars.---------------------------------------------------------- - And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo.

    +

    This line has to be exactly 99 chars to test part of the logic.------------------------------------
    +And this line has to be exactly 100 chars.----------------------------------------------------------
    +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo.

    From aed8d933745e84ec7d1983c813a94a0a762e6f44 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 00:55:28 +0100 Subject: [PATCH 123/192] Generators/Text::printTitle(): minor tweaks Just removing some duplicate function calls. --- src/Generators/Text.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Generators/Text.php b/src/Generators/Text.php index ce419ba118..419bcc3d56 100644 --- a/src/Generators/Text.php +++ b/src/Generators/Text.php @@ -5,7 +5,9 @@ * Output is designed to be displayed in a terminal and is wrapped to 100 characters. * * @author Greg Sherwood + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ @@ -52,13 +54,15 @@ public function processSniff(DOMNode $doc) */ protected function printTitle(DOMNode $doc) { - $title = $this->getTitle($doc); - $standard = $this->ruleset->name; + $title = $this->getTitle($doc); + $standard = $this->ruleset->name; + $displayTitle = "$standard CODING STANDARD: $title"; + $titleLength = strlen($displayTitle); echo PHP_EOL; - echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); - echo strtoupper(PHP_EOL."| $standard CODING STANDARD: $title |".PHP_EOL); - echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); + echo str_repeat('-', ($titleLength + 4)); + echo strtoupper(PHP_EOL."| $displayTitle |".PHP_EOL); + echo str_repeat('-', ($titleLength + 4)); echo PHP_EOL.PHP_EOL; }//end printTitle() From 08f41dfa4b7d7aa50b6b4f1dcda7b1c6daeabdbf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 24 Nov 2024 18:12:48 +0100 Subject: [PATCH 124/192] Util/HelpTest: test CBF-only code Now PR 703 has unblocked testing of PHPCBF-only code, the `// @codeCoverageIgnore` annotation for this CBF-only code in the `Util\Help` class can be removed and this code can now be tested. This commit adjusts the relevant test method to ensure that the CBF-only code is also tested. --- src/Util/Help.php | 2 +- tests/Core/Util/Help/HelpTest.php | 52 ++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/Util/Help.php b/src/Util/Help.php index 5a686a97aa..a6a64eedb7 100644 --- a/src/Util/Help.php +++ b/src/Util/Help.php @@ -270,7 +270,7 @@ private function printUsage() { $command = 'phpcs'; if (defined('PHP_CODESNIFFER_CBF') === true && PHP_CODESNIFFER_CBF === true) { - $command = 'phpcbf'; // @codeCoverageIgnore + $command = 'phpcbf'; } $this->printCategoryHeader('Usage'); diff --git a/tests/Core/Util/Help/HelpTest.php b/tests/Core/Util/Help/HelpTest.php index f09a4c1799..b3d51a5c78 100644 --- a/tests/Core/Util/Help/HelpTest.php +++ b/tests/Core/Util/Help/HelpTest.php @@ -3,7 +3,7 @@ * Tests to verify that the "help" command functions as expected. * * @author Juliette Reinders Folmer - * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ @@ -386,7 +386,7 @@ public static function dataOptionFilteringSpacerHandling() /** - * Test that if no short/long options are passed, only usage information is displayed (and displayed correctly). + * Test that if no short/long options are passed, only usage information is displayed (CS mode). * * @param array $cliArgs Command line arguments. * @param string $expectedRegex Regex to validate expected output. @@ -395,7 +395,51 @@ public static function dataOptionFilteringSpacerHandling() * * @return void */ - public function testDisplayUsage($cliArgs, $expectedRegex) + public function testDisplayUsageCS($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcs', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCS() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CBF mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * @group CBF + * + * @return void + */ + public function testDisplayUsageCBF($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcbf', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCBF() + + + /** + * Helper method to test that if no short/long options are passed, only usage information is displayed + * (and displayed correctly). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @return void + */ + private function verifyDisplayUsage($cliArgs, $expectedRegex) { $help = new Help(new ConfigDouble($cliArgs), []); @@ -403,7 +447,7 @@ public function testDisplayUsage($cliArgs, $expectedRegex) $help->display(); - }//end testDisplayUsage() + }//end verifyDisplayUsage() /** From 609ac109d19d61f97ce572f5a806274801a024ac Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 26 Nov 2024 00:16:35 -0300 Subject: [PATCH 125/192] Generic/LowercasedFilename: improve code coverage (#681) Includes adding a test for handling STDIN per suggestion during code review. --- .../Files/LowercasedFilenameUnitTest.php | 45 +++++++++++++++++++ .../Files/lowercased_filename_unit_test.inc | 1 + 2 files changed, 46 insertions(+) create mode 100644 src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc diff --git a/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php b/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php index 894a86dfed..ea7d5aa8b2 100644 --- a/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php +++ b/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php @@ -9,6 +9,9 @@ namespace PHP_CodeSniffer\Standards\Generic\Tests\Files; +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; /** @@ -20,6 +23,24 @@ final class LowercasedFilenameUnitTest extends AbstractSniffUnitTest { + /** + * Get a list of all test files to check. + * + * @param string $testFileBase The base path that the unit tests files will have. + * + * @return string[] + */ + protected function getTestFiles($testFileBase) + { + $testFileDir = dirname($testFileBase); + $testFiles = parent::getTestFiles($testFileBase); + $testFiles[] = $testFileDir.DIRECTORY_SEPARATOR.'lowercased_filename_unit_test.inc'; + + return $testFiles; + + }//end getTestFiles() + + /** * Returns the lines where errors should occur. * @@ -58,4 +79,28 @@ public function getWarningList() }//end getWarningList() + /** + * Test the sniff bails early when handling STDIN. + * + * @return void + */ + public function testStdIn() + { + $config = new ConfigDouble(); + $config->standards = ['Generic']; + $config->sniffs = ['Generic.Files.LowercasedFilename']; + + $ruleset = new Ruleset($config); + + $content = 'process(); + + $this->assertSame(0, $file->getErrorCount()); + $this->assertSame(0, $file->getWarningCount()); + $this->assertCount(0, $file->getErrors()); + + }//end testStdIn() + + }//end class diff --git a/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc b/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc new file mode 100644 index 0000000000..b3d9bbc7f3 --- /dev/null +++ b/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc @@ -0,0 +1 @@ + Date: Thu, 25 Apr 2024 14:01:48 -0300 Subject: [PATCH 126/192] Generic/EmptyPHPStatement: remove some unreachable code * Removed two unreachable conditions. `$prevNonEmpty` will never be `false` as there will always be at least a PHP open tag token before the semicolon token. * Removed unreachable default case `$tokens[$stackPtr]['type']` will always be either `T_SEMICOLON` or `T_CLOSE_TAG` as those are the two tokens that this sniff listens for. So, the default case will never be reached. --- .../Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php b/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php index 4ecf630378..eb7c50ce85 100644 --- a/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php +++ b/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php @@ -53,10 +53,6 @@ public function process(File $phpcsFile, $stackPtr) case 'T_SEMICOLON': $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($prevNonEmpty === false) { - return; - } - if ($tokens[$prevNonEmpty]['code'] !== T_SEMICOLON && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO @@ -128,9 +124,8 @@ public function process(File $phpcsFile, $stackPtr) case 'T_CLOSE_TAG': $prevNonEmpty = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($prevNonEmpty === false - || ($tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO) + if ($tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO ) { return; } @@ -150,10 +145,6 @@ public function process(File $phpcsFile, $stackPtr) $phpcsFile->fixer->endChangeset(); } break; - - default: - // Deliberately left empty. - break; }//end switch }//end process() From 498ecdaa1e066eb14de82631f65a6be837f1e3c6 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 20 Nov 2024 17:20:21 -0300 Subject: [PATCH 127/192] Generic/EmptyPHPStatement: rename test case file Doing this to be able to create another test file to test the sniff with the short open tag. --- ...st.inc => EmptyPHPStatementUnitTest.1.inc} | 0 ... => EmptyPHPStatementUnitTest.1.inc.fixed} | 0 .../EmptyPHPStatementUnitTest.php | 51 +++++++++++-------- 3 files changed, 29 insertions(+), 22 deletions(-) rename src/Standards/Generic/Tests/CodeAnalysis/{EmptyPHPStatementUnitTest.inc => EmptyPHPStatementUnitTest.1.inc} (100%) rename src/Standards/Generic/Tests/CodeAnalysis/{EmptyPHPStatementUnitTest.inc.fixed => EmptyPHPStatementUnitTest.1.inc.fixed} (100%) diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc similarity index 100% rename from src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc rename to src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc.fixed b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed similarity index 100% rename from src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc.fixed rename to src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php index 1b31b5f288..66db633e52 100644 --- a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php @@ -41,31 +41,38 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 9 => 1, - 12 => 1, - 15 => 1, - 18 => 1, - 21 => 1, - 22 => 1, - 31 => 1, - 33 => 1, - 43 => 1, - 45 => 1, - 49 => 1, - 50 => 1, - 57 => 1, - 59 => 1, - 61 => 1, - 63 => 2, - 71 => 1, - 72 => 1, - 80 => 1, - ]; + switch ($testFile) { + case 'EmptyPHPStatementUnitTest.1.inc': + return [ + 9 => 1, + 12 => 1, + 15 => 1, + 18 => 1, + 21 => 1, + 22 => 1, + 31 => 1, + 33 => 1, + 43 => 1, + 45 => 1, + 49 => 1, + 50 => 1, + 57 => 1, + 59 => 1, + 61 => 1, + 63 => 2, + 71 => 1, + 72 => 1, + 80 => 1, + ]; + default: + return []; + }//end switch }//end getWarningList() From 6105bf7d66d65b34a4fb6ba8bd0df0a03d9304a1 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 20 Nov 2024 17:55:05 -0300 Subject: [PATCH 128/192] Generic/EmptyPHPStatement: add tests for the short open tag --- .../EmptyPHPStatementUnitTest.2.inc | 27 +++++++++++++++++ .../EmptyPHPStatementUnitTest.2.inc.fixed | 23 ++++++++++++++ .../EmptyPHPStatementUnitTest.php | 30 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc create mode 100644 src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc new file mode 100644 index 0000000000..a9f895d71b --- /dev/null +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc @@ -0,0 +1,27 @@ + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + + diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed new file mode 100644 index 0000000000..fd27d0a25c --- /dev/null +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed @@ -0,0 +1,23 @@ + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php index 66db633e52..1e59c0a398 100644 --- a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php @@ -20,6 +20,27 @@ final class EmptyPHPStatementUnitTest extends AbstractSniffUnitTest { + /** + * Get a list of all test files to check. + * + * @param string $testFileBase The base path that the unit tests files will have. + * + * @return string[] + */ + protected function getTestFiles($testFileBase) + { + $testFiles = [$testFileBase.'1.inc']; + + $option = (bool) ini_get('short_open_tag'); + if ($option === true) { + $testFiles[] = $testFileBase.'2.inc'; + } + + return $testFiles; + + }//end getTestFiles() + + /** * Returns the lines where errors should occur. * @@ -70,6 +91,15 @@ public function getWarningList($testFile='') 72 => 1, 80 => 1, ]; + case 'EmptyPHPStatementUnitTest.2.inc': + return [ + 3 => 1, + 4 => 1, + 13 => 1, + 15 => 1, + 25 => 1, + 27 => 1, + ]; default: return []; }//end switch From eb7c3a9a355ba9c010b9cc46e6fbf7ccaa9b0aea Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 25 Nov 2024 15:50:51 -0300 Subject: [PATCH 129/192] Generic/EmptyPHPStatement: minor tweaks to test case file * Updated tests to have more examples with more than one superfluous semicolon. * Minor test comment punctuation tweaks. --- .../Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc | 8 ++++---- .../CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed | 4 ++-- .../Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc index 080dda9382..83e071bf42 100644 --- a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc @@ -19,7 +19,7 @@ function_call(); ?> - + /* * Test empty statement: no code between PHP open and close tag. @@ -42,7 +42,7 @@ function_call(); --> - + @@ -53,7 +53,7 @@ function_call(); // Guard against false positives for two consecutive semicolons in a for statement. for ( $i = 0; ; $i++ ) {} -// Test for useless semicolons +// Test for useless semicolons. for ( $i = 0; ; $i++ ) {}; if (true) {}; @@ -80,7 +80,7 @@ if ($foo) { ; } -// Do not remove semicolon after match +// Do not remove semicolon after match. $c = match ($a) { 1 => true, }; diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed index 7f16742288..6bf8b21261 100644 --- a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed @@ -48,7 +48,7 @@ function_call(); // Guard against false positives for two consecutive semicolons in a for statement. for ( $i = 0; ; $i++ ) {} -// Test for useless semicolons +// Test for useless semicolons. for ( $i = 0; ; $i++ ) {} if (true) {} @@ -74,7 +74,7 @@ echo $a{0}; if ($foo) { } -// Do not remove semicolon after match +// Do not remove semicolon after match. $c = match ($a) { 1 => true, }; diff --git a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php index 1e59c0a398..77542acbaa 100644 --- a/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php +++ b/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php @@ -76,11 +76,11 @@ public function getWarningList($testFile='') 15 => 1, 18 => 1, 21 => 1, - 22 => 1, + 22 => 2, 31 => 1, 33 => 1, 43 => 1, - 45 => 1, + 45 => 2, 49 => 1, 50 => 1, 57 => 1, From 715242ed676306b616cba8a8acfb549ee1663386 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 25 Nov 2024 03:36:48 +0100 Subject: [PATCH 130/192] Generic//EmptyPHPStatement: reduce complexity/nesting levels Follow up on #699 Commit 529bcba7a42ec35873c31459ae61bee67852e956 removed the unreachable `default` case from the `switch`, but even when it is not explicitly there, this still leaves an unreachable branch in the code flow. This commit takes the previous change one step further and removes the `switch` completely in favour of two separate `private` functions which each handle one specific token. N.B.: this commit will be easier to review while ignoring whitespace changes. --- .../CodeAnalysis/EmptyPHPStatementSniff.php | 188 ++++++++++-------- 1 file changed, 109 insertions(+), 79 deletions(-) diff --git a/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php b/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php index eb7c50ce85..6fbfdc0b2b 100644 --- a/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php +++ b/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php @@ -48,106 +48,136 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - switch ($tokens[$stackPtr]['type']) { - // Detect `something();;`. - case 'T_SEMICOLON': - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - - if ($tokens[$prevNonEmpty]['code'] !== T_SEMICOLON - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO + if ($tokens[$stackPtr]['code'] === T_SEMICOLON) { + $this->processSemicolon($phpcsFile, $stackPtr); + } else { + $this->processCloseTag($phpcsFile, $stackPtr); + } + + }//end process() + + + /** + * Detect `something();;`. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + private function processSemicolon(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] !== T_SEMICOLON + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO + ) { + if (isset($tokens[$prevNonEmpty]['scope_condition']) === false) { + return; + } + + if ($tokens[$prevNonEmpty]['scope_opener'] !== $prevNonEmpty + && $tokens[$prevNonEmpty]['code'] !== T_CLOSE_CURLY_BRACKET ) { - if (isset($tokens[$prevNonEmpty]['scope_condition']) === false) { - return; - } + return; + } - if ($tokens[$prevNonEmpty]['scope_opener'] !== $prevNonEmpty - && $tokens[$prevNonEmpty]['code'] !== T_CLOSE_CURLY_BRACKET - ) { - return; - } + $scopeOwner = $tokens[$tokens[$prevNonEmpty]['scope_condition']]['code']; + if ($scopeOwner === T_CLOSURE || $scopeOwner === T_ANON_CLASS || $scopeOwner === T_MATCH) { + return; + } - $scopeOwner = $tokens[$tokens[$prevNonEmpty]['scope_condition']]['code']; - if ($scopeOwner === T_CLOSURE || $scopeOwner === T_ANON_CLASS || $scopeOwner === T_MATCH) { - return; - } + // Else, it's something like `if (foo) {};` and the semicolon is not needed. + } - // Else, it's something like `if (foo) {};` and the semicolon is not needed. + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $nested = $tokens[$stackPtr]['nested_parenthesis']; + $lastCloser = array_pop($nested); + if (isset($tokens[$lastCloser]['parenthesis_owner']) === true + && $tokens[$tokens[$lastCloser]['parenthesis_owner']]['code'] === T_FOR + ) { + // Empty for() condition. + return; } + } - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $nested = $tokens[$stackPtr]['nested_parenthesis']; - $lastCloser = array_pop($nested); - if (isset($tokens[$lastCloser]['parenthesis_owner']) === true - && $tokens[$tokens[$lastCloser]['parenthesis_owner']]['code'] === T_FOR - ) { - // Empty for() condition. - return; + $fix = $phpcsFile->addFixableWarning( + 'Empty PHP statement detected: superfluous semicolon.', + $stackPtr, + 'SemicolonWithoutCodeDetected' + ); + + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + if ($tokens[$prevNonEmpty]['code'] === T_OPEN_TAG + || $tokens[$prevNonEmpty]['code'] === T_OPEN_TAG_WITH_ECHO + ) { + // Check for superfluous whitespace after the semicolon which should be + // removed as the `fixer->replaceToken(($stackPtr + 1), $replacement); } } - $fix = $phpcsFile->addFixableWarning( - 'Empty PHP statement detected: superfluous semicolon.', - $stackPtr, - 'SemicolonWithoutCodeDetected' - ); - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); - - if ($tokens[$prevNonEmpty]['code'] === T_OPEN_TAG - || $tokens[$prevNonEmpty]['code'] === T_OPEN_TAG_WITH_ECHO + for ($i = $stackPtr; $i > $prevNonEmpty; $i--) { + if ($tokens[$i]['code'] !== T_SEMICOLON + && $tokens[$i]['code'] !== T_WHITESPACE ) { - // Check for superfluous whitespace after the semicolon which will be - // removed as the `fixer->replaceToken(($stackPtr + 1), $replacement); - } + break; } - for ($i = $stackPtr; $i > $prevNonEmpty; $i--) { - if ($tokens[$i]['code'] !== T_SEMICOLON - && $tokens[$i]['code'] !== T_WHITESPACE - ) { - break; - } + $phpcsFile->fixer->replaceToken($i, ''); + } - $phpcsFile->fixer->replaceToken($i, ''); - } + $phpcsFile->fixer->endChangeset(); + }//end if - $phpcsFile->fixer->endChangeset(); - }//end if - break; + }//end processSemicolon() - // Detect ``. - case 'T_CLOSE_TAG': - $prevNonEmpty = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO - ) { - return; - } + /** + * Detect ``. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + private function processCloseTag(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); - $fix = $phpcsFile->addFixableWarning( - 'Empty PHP open/close tag combination detected.', - $prevNonEmpty, - 'EmptyPHPOpenCloseTagsDetected' - ); - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); + $prevNonEmpty = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO + ) { + return; + } - for ($i = $prevNonEmpty; $i <= $stackPtr; $i++) { - $phpcsFile->fixer->replaceToken($i, ''); - } + $fix = $phpcsFile->addFixableWarning( + 'Empty PHP open/close tag combination detected.', + $prevNonEmpty, + 'EmptyPHPOpenCloseTagsDetected' + ); - $phpcsFile->fixer->endChangeset(); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($i = $prevNonEmpty; $i <= $stackPtr; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); } - break; - }//end switch - }//end process() + $phpcsFile->fixer->endChangeset(); + } + + }//end processCloseTag() }//end class From 1a84fdac1b5558d9e89ccdffb8ac992198757473 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 26 Nov 2024 05:18:48 +0100 Subject: [PATCH 131/192] GH Actions: run phar building test more selectively This workflow is a safeguard to ensure that the PHAR files can be build against any of the supported PHP versions. There are only a few files involved in building the PHAR files, so there isn't really any need to run this workflow for every PR and every merge. It only really needs to run when any of the involved files have changed. Also, keep in mind that the PHAR which is distributed for releases is build on PHP 8.0 and will still be build in the `test` workflow for every PR and every merge, so the functionality of the distribution PHARs is still guaranteed either way. --- .github/workflows/build-phar.yml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-phar.yml b/.github/workflows/build-phar.yml index 403be803cb..b091e24c45 100644 --- a/.github/workflows/build-phar.yml +++ b/.github/workflows/build-phar.yml @@ -1,14 +1,31 @@ name: Build PHARs on: - # Run on pushes to master and on all pull requests. + # Run on pushes to master and on pull requests which touch files used when building the PHARs. # Prevent the build from running when there are only irrelevant changes. push: branches: - master - paths-ignore: - - '**.md' + paths: + - '.github/workflows/build-phar.yml' + - 'scripts/build-phar.php' + - 'autoload.php' + - 'src/Config.php' + - 'src/Exceptions/RuntimeException.php' + - 'src/Exceptions/TokenizerException.php' + - 'src/Tokenizers/PHP.php' + - 'src/Util/Tokens.php' pull_request: + paths: + - '.github/workflows/build-phar.yml' + - 'scripts/build-phar.php' + - 'autoload.php' + - 'src/Config.php' + - 'src/Exceptions/RuntimeException.php' + - 'src/Exceptions/TokenizerException.php' + - 'src/Tokenizers/PHP.php' + - 'src/Util/Tokens.php' + # Allow manually triggering the workflow. workflow_dispatch: From 243aaf4d674d45f966ea296fee11b2c453bc6ae2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 26 Nov 2024 15:36:12 +0100 Subject: [PATCH 132/192] GH Actions: fix snafu with code coverage Follow up on commit 755f0bc35a466e063f55fa7e7697a05e1289c644, which simplified the `custom_ini` setting for the code coverage builds, but did so incorrectly, meaning that code which needs the `short_open_tag=On` setting was no longer being recorded as covered. Fixed now. --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1ea04c9384..d295e91204 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -256,8 +256,8 @@ jobs: shell: bash run: | # Set the "short_open_tag" ini to make sure specific conditions are tested. - if [[ ${{ matrix.custom_ini }} == true && "${{ matrix.php }}" == '5.4' ]]; then - echo 'PHP_INI=, date.timezone=Australia/Sydney, short_open_tag=On, asp_tags=On' >> "$GITHUB_OUTPUT" + if [[ ${{ matrix.custom_ini }} == true && "${{ matrix.php }}" == '7.2' ]]; then + echo 'PHP_INI=, date.timezone=Australia/Sydney, short_open_tag=On' >> "$GITHUB_OUTPUT" fi - name: Install PHP From f8ed72b9768797c7db92db0f002a64d65b6478d8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 27 Nov 2024 08:00:21 +0100 Subject: [PATCH 133/192] GH Actions/test: allow concurrency for code coverage builds - take two Follow up on 710, which was added with the following reasoning: > The `concurrency` setting will cancel running workflows if a new push to the same branch is seen. This is useful to prevent unnecessary workflow runs (as the previous push was superseded, so the outcome is no longer relevant). > > However, for the "main" branches (`master` and `4.0`), this workflow cancelling means that if multiple PRs are merged in succession, only the code coverage for the _last_ merge is recorded in Coveralls as the workflow runs on `master` for the previous merges will have been cancelled. > > While in practice, it's not a biggie, it does make it more difficult to identify which commit/merge added or decreased code coverage. Let's try this again. The previous attempt to prevent cancelling code coverage builds for merges to the "main" branches is not working as intended and is still cancelling builds. This is likely due to the way GH looks at concurrency groups: > By default, GitHub Actions allows multiple jobs within the same workflow, multiple workflow runs within the same repository, and multiple workflow runs across a repository owner's account to run concurrently. This means that multiple workflow runs, jobs, or steps can run at the same time. > > You can use `*.concurrency` to ensure that only a single job or workflow using the same concurrency group will run at a time. > > This means that there can be at most one running and one pending job in a concurrency group at any time. When a concurrent job or workflow is queued, if another job or workflow using the same concurrency group in the repository is in progress, the queued job or workflow will be `pending`. Any existing `pending` job or workflow in the same concurrency group, if it exists, will be canceled and the new queued job or workflow will take its place. Interpreting this strictly, this appears to mean that, as soon as a `concurrency` `group` name is defined, there can now only be - at most - two builds for that group - one running, one queued -, while without the `concurrency` `group` name being associated with a build, there can be unlimited concurrent builds. This means that code coverage builds for merges in quick succession are still being killed off. This new attempt now moves the `concurrency` setting from the workflow level to the "job" level and adds the `job` name to the `group` key. This should hopefully still allow for cancelling in progress builds for the `build` and `test` jobs, while leaving the `coverage` (and `coveralls-finish`) jobs alone. The down-side of this change (providing it works) is that it can't be limited to the "main" branches, which means that the `coverage` jobs will now continue running for _every_ push to an open pull request as well. While a little wasteful, that appears to be the price to pay. Refs: * https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs --- .github/workflows/test.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d295e91204..212798b30f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,16 +14,14 @@ on: # Allow manually triggering the workflow. workflow_dispatch: -# Cancels all previous workflow runs for the same branch that have not yet completed, -# but don't cancel when it's one of the "main" branches as that prevents -# accurate monitoring of code coverage. -concurrency: - # The concurrency group contains the workflow name and the branch name. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref_name != 'master' && github.ref_name != '4.0' }} - jobs: build: + # Cancels all previous runs of this particular job for the same branch that have not yet completed. + concurrency: + # The concurrency group contains the workflow name, job name and the branch name. + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true + runs-on: ubuntu-latest name: "Build Phar on PHP: 8.0" @@ -82,6 +80,12 @@ jobs: run: php phpcbf.phar ./scripts test: + # Cancels all previous runs of this particular job for the same branch that have not yet completed. + concurrency: + # The concurrency group contains the workflow name, job name, job index and the branch name. + group: ${{ github.workflow }}-${{ github.job }}-${{ strategy.job-index }}-${{ github.ref }} + cancel-in-progress: true + runs-on: ubuntu-latest needs: build @@ -215,6 +219,8 @@ jobs: run: php phpcs.phar coverage: + # Explicitly *NOT* setting "concurrency" for this job to allow for monitoring code coverage for all merges. + runs-on: ${{ matrix.os }} strategy: @@ -256,8 +262,8 @@ jobs: shell: bash run: | # Set the "short_open_tag" ini to make sure specific conditions are tested. - if [[ ${{ matrix.custom_ini }} == true && "${{ matrix.php }}" == '7.2' ]]; then - echo 'PHP_INI=, date.timezone=Australia/Sydney, short_open_tag=On' >> "$GITHUB_OUTPUT" + if [[ ${{ matrix.custom_ini }} == true && "${{ matrix.php }}" == '7.2' ]]; then + echo 'PHP_INI=, date.timezone=Australia/Sydney, short_open_tag=On' >> "$GITHUB_OUTPUT" fi - name: Install PHP From a60ed631b1c1ec6d36ed12a0fd929b4f3a49d226 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 5 Nov 2024 20:10:43 -0300 Subject: [PATCH 134/192] Generic/UpperCaseConstantName: handle unconventional spacing and comments after `define(` This commit fixes false negatives in the sniff when handling unconventional spacing and comments after `define(`. When checking for the constant name after the opening parenthesis, the sniff would incorrectly exclude only whitespaces while comments can also be placed between the opening parenthesis and the constant name. Looking for the constant name by getting the next non-empty token after the opening parenthesis fixes this problem. The added tests also include comments between `define` and the opening parenthesis but that was already handled correctly by the sniff. --- .../NamingConventions/UpperCaseConstantNameSniff.php | 4 ++-- .../UpperCaseConstantNameUnitTest.inc | 10 ++++++++++ .../UpperCaseConstantNameUnitTest.php | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index f62cfe94bd..5be892e880 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -103,8 +103,8 @@ public function process(File $phpcsFile, $stackPtr) return; } - // The next non-whitespace token must be the constant name. - $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); + // The next non-empty token must be the constant name. + $constPtr = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true); if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc index 20bbf90e26..60bb415cf9 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc @@ -41,3 +41,13 @@ class TypedConstants { const FALSE false = false; // Yes, false can be used as a constant name, don't ask. const array ARRAY = array(); // Same goes for array. } + +define /* comment */ ( /* comment */ 'CommentsInUnconventionalPlaces', 'value' ); + +define +// comment +( + // phpcs:ignore Stnd.Cat.SniffName -- for reasons. + 'CommentsInUnconventionalPlaces', + 'value' +); diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php index afe3625589..4394951012 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php @@ -40,6 +40,8 @@ public function getErrorList() 30 => 1, 40 => 1, 41 => 1, + 45 => 1, + 47 => 1, ]; }//end getErrorList() From 67ae15447a4313175adebb94c02d3ee5d66666f4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 6 Nov 2024 11:33:23 -0300 Subject: [PATCH 135/192] Generic/UpperCaseConstantName: handle unconventional spacing and comments before `define` This commit fixes false positives in the sniff when handling unconventional spacing and comments before `define`. When checking to see if the `define` found is not a method call, the sniff would incorrectly exclude only whitespaces. But comments can also be placed between `define` and one of the tokens the sniff looks for (T_OBJECT_OPERATOR, T_DOUBLE_COLON or T_NULLSAFE_OBJECT_OPERATOR). Looking for the first non-empty token before `define` fixes this problem. --- .../Sniffs/NamingConventions/UpperCaseConstantNameSniff.php | 2 +- .../NamingConventions/UpperCaseConstantNameUnitTest.inc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index 5be892e880..a2c22ecb73 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -88,7 +88,7 @@ public function process(File $phpcsFile, $stackPtr) } // Make sure this is not a method call. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR || $tokens[$prev]['code'] === T_DOUBLE_COLON || $tokens[$prev]['code'] === T_NULLSAFE_OBJECT_OPERATOR diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc index 60bb415cf9..6531b8d49a 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc @@ -51,3 +51,8 @@ define 'CommentsInUnconventionalPlaces', 'value' ); + +$foo-> /* comment */ define('bar'); +$foo?-> +// phpcs:ignore Stnd.Cat.SniffName -- for reasons. +define('bar'); From fb13110e0a20acded44ad5de61c375f0ac3d1b7a Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 6 Nov 2024 12:07:58 -0300 Subject: [PATCH 136/192] Generic/UpperCaseConstantName: false positives when constant name is "DEFINE" This commit fixes false positives when the sniff encounters a constant named "DEFINE". When looking for calls to `define()`, the code was checking only if there was a non-empty token after `define`. Instead, it should check if the next non-empty token after `define` is `T_OPEN_PARENTHESIS`. --- .../Sniffs/NamingConventions/UpperCaseConstantNameSniff.php | 2 +- .../Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index a2c22ecb73..3b59343cd0 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -99,7 +99,7 @@ public function process(File $phpcsFile, $stackPtr) // If the next non-whitespace token after this token // is not an opening parenthesis then it is not a function call. $openBracket = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($openBracket === false) { + if ($openBracket === false || $tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { return; } diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc index 6531b8d49a..7ca6196c78 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc @@ -56,3 +56,5 @@ $foo-> /* comment */ define('bar'); $foo?-> // phpcs:ignore Stnd.Cat.SniffName -- for reasons. define('bar'); + +const DEFINE = 'value'; From 66837c3367f64544431757ad6912bd503a2ec454 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 6 Nov 2024 12:07:58 -0300 Subject: [PATCH 137/192] Generic/UpperCaseConstantName: fix attributes false positive This commit fixes false positives in the sniff when handling attributes called `define`. Before this change the sniff was not taking into account that `define` is a valid name for an attribute, and it would incorrectly handle these cases as calls to the `define()` function. --- .../NamingConventions/UpperCaseConstantNameSniff.php | 5 +++++ .../NamingConventions/UpperCaseConstantNameUnitTest.inc | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index 3b59343cd0..6a0e39b49f 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -96,6 +96,11 @@ public function process(File $phpcsFile, $stackPtr) return; } + // Make sure this is not an attribute. + if (empty($tokens[$stackPtr]['nested_attributes']) === false) { + return; + } + // If the next non-whitespace token after this token // is not an opening parenthesis then it is not a function call. $openBracket = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc index 7ca6196c78..1680676fb6 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc @@ -58,3 +58,12 @@ $foo?-> define('bar'); const DEFINE = 'value'; + +#[Define('some param')] +class MyClass {} + +#[ + AttributeA, + define('some param') +] +class MyClass {} From 0ac027f5c7f3d7d1f4eb683158cd294bc5bc0712 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 5 Nov 2024 20:40:50 -0300 Subject: [PATCH 138/192] Generic/UpperCaseConstantName: minor improvement to the error message and metrics This commit implements a minor improvement to the error message and metric recording when handling calls to `define()`. Now the line of the error or the line recorded in the metric will be the line of the constant name. Before it was the line of the T_DEFINE token. --- .../NamingConventions/UpperCaseConstantNameSniff.php | 8 ++++---- .../NamingConventions/UpperCaseConstantNameUnitTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index 6a0e39b49f..f129aa6ef2 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -133,9 +133,9 @@ public function process(File $phpcsFile, $stackPtr) if (strtoupper($constName) !== $constName) { if (strtolower($constName) === $constName) { - $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'lower'); + $phpcsFile->recordMetric($constPtr, 'Constant name case', 'lower'); } else { - $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'mixed'); + $phpcsFile->recordMetric($constPtr, 'Constant name case', 'mixed'); } $error = 'Constants must be uppercase; expected %s but found %s'; @@ -143,9 +143,9 @@ public function process(File $phpcsFile, $stackPtr) $prefix.strtoupper($constName), $prefix.$constName, ]; - $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); + $phpcsFile->addError($error, $constPtr, 'ConstantNotUpperCase', $data); } else { - $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'upper'); + $phpcsFile->recordMetric($constPtr, 'Constant name case', 'upper'); } }//end process() diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php index 4394951012..797627ae7f 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php @@ -41,7 +41,7 @@ public function getErrorList() 40 => 1, 41 => 1, 45 => 1, - 47 => 1, + 51 => 1, ]; }//end getErrorList() From d129e9b60292f8106c028ab744e83ef42b62bba2 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 11 Nov 2024 11:43:44 -0300 Subject: [PATCH 139/192] Generic/UpperCaseConstantName: remove special case for double-colon In early versions of this sniff, constant names were checked not only when defined, but also when used. At that time, code was added to handle the dynamic retrieval of class constants in calls to `constant()` by checking if the constant name contained a double-colon (see https://github.com/squizlabs/PHP_CodeSniffer/commit/610b0cc3f1584ccd050a4970ab80843832c46d73 and https://pear.php.net/bugs/bug.php?id=18670). If so, the sniff would enforce upper case only for the substring after the double-colon. Later, another commit removed support for constant usage (https://github.com/squizlabs/PHP_CodeSniffer/commit/4af13118b1fedd89faadd78b9bc and https://pear.php.net/bugs/bug.php?id=20090). It seems to me that the code that is removed in this commit, should have been removed when support for constant usage was removed. The removed code is only triggered when a constant is defined using `define()`. As far as I can tell, over time, PHP changed how it behaves when a double-colon is passed as part of the first parameter of `define()`. However, never in a way that justifies special treatment in the context of this sniff (https://3v4l.org/erZcK). At least not since PHP 5.0 (I'm assuming it is not needed to check PHP 4). --- .../NamingConventions/UpperCaseConstantNameSniff.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index f129aa6ef2..c06695c105 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -115,14 +115,7 @@ public function process(File $phpcsFile, $stackPtr) } $constName = $tokens[$constPtr]['content']; - - // Check for constants like self::CONSTANT. - $prefix = ''; - $splitPos = strpos($constName, '::'); - if ($splitPos !== false) { - $prefix = substr($constName, 0, ($splitPos + 2)); - $constName = substr($constName, ($splitPos + 2)); - } + $prefix = ''; // Strip namespace from constant like /foo/bar/CONSTANT. $splitPos = strrpos($constName, '\\'); From 17b916441acf2ea9d38c4ad999ca004e8cd0b2c9 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 5 Nov 2024 08:27:27 -0300 Subject: [PATCH 140/192] Generic/UpperCaseConstantName: rename test case file Doing this to be able to create tests with syntax errors on separate files. --- ...nc => UpperCaseConstantNameUnitTest.1.inc} | 0 .../UpperCaseConstantNameUnitTest.php | 35 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) rename src/Standards/Generic/Tests/NamingConventions/{UpperCaseConstantNameUnitTest.inc => UpperCaseConstantNameUnitTest.1.inc} (100%) diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc similarity index 100% rename from src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.inc rename to src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php index 797627ae7f..aafe62a56b 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php @@ -26,23 +26,30 @@ final class UpperCaseConstantNameUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 8 => 1, - 10 => 1, - 12 => 1, - 14 => 1, - 19 => 1, - 28 => 1, - 30 => 1, - 40 => 1, - 41 => 1, - 45 => 1, - 51 => 1, - ]; + switch ($testFile) { + case 'UpperCaseConstantNameUnitTest.1.inc': + return [ + 8 => 1, + 10 => 1, + 12 => 1, + 14 => 1, + 19 => 1, + 28 => 1, + 30 => 1, + 40 => 1, + 41 => 1, + 45 => 1, + 51 => 1, + ]; + default: + return []; + } }//end getErrorList() From 2e6885061f28fe311862055f762fa6398847db19 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 8 Nov 2024 11:22:04 -0300 Subject: [PATCH 141/192] Generic/UpperCaseConstantName: `findNext()` may return `false` This commit takes into account that `findNext()` may return `false` and properly handles this case in the modified `if` condition. There were no issues without this extra check, as when `$constPtr` is `false`, `$tokens[$constPrt]` evaluates to the first token in the stack and the first token can never be `T_CONSTANT_ENCAPSED_STRING`, so the sniff would bail early anyway. --- .../NamingConventions/UpperCaseConstantNameSniff.php | 2 +- .../NamingConventions/UpperCaseConstantNameUnitTest.2.inc | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index c06695c105..8461a1abaf 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -110,7 +110,7 @@ public function process(File $phpcsFile, $stackPtr) // The next non-empty token must be the constant name. $constPtr = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true); - if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { + if ($constPtr === false || $tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc new file mode 100644 index 0000000000..4136912dc9 --- /dev/null +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc @@ -0,0 +1,7 @@ + Date: Wed, 6 Nov 2024 10:51:23 -0300 Subject: [PATCH 142/192] Generic/UpperCaseConstantName: improve code coverage Includes updating a sniff code comment to better describe what it does. Some of the cases described were not covered by tests before the changes in this commit. --- .../UpperCaseConstantNameSniff.php | 5 ++++- .../UpperCaseConstantNameUnitTest.1.inc | 19 ++++++++++++++++--- .../UpperCaseConstantNameUnitTest.3.inc | 7 +++++++ .../UpperCaseConstantNameUnitTest.4.inc | 7 +++++++ .../UpperCaseConstantNameUnitTest.php | 2 ++ 5 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.3.inc create mode 100644 src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.4.inc diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index 8461a1abaf..ad4d936b96 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -108,7 +108,10 @@ public function process(File $phpcsFile, $stackPtr) return; } - // The next non-empty token must be the constant name. + // Bow out if next non-empty token after the opening parenthesis is not a string (the + // constant name). This could happen when live coding, if the constant is a variable or an + // expression, or if handling a first-class callable or a function definition outside the + // global scope. $constPtr = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true); if ($constPtr === false || $tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc index 1680676fb6..cb60d04986 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc @@ -5,7 +5,7 @@ namespace foo\bar; namespace bar\foo\baz; define('VALID_NAME', true); -define('invalidName', true); +DEFINE('invalidName', true); define("VALID_NAME", true); define("invalidName", true); define('bar\foo\baz\VALID_NAME_WITH_NAMESPACE', true); @@ -37,9 +37,9 @@ class TypedConstants { const MISSING_VALUE; // Parse error. const MyClass MYCONST = new MyClass; const int VALID_NAME = 0; - const INT invalid_name = 0; + final public const INT invalid_name = 0; const FALSE false = false; // Yes, false can be used as a constant name, don't ask. - const array ARRAY = array(); // Same goes for array. + final protected const array ARRAY = array(); // Same goes for array. } define /* comment */ ( /* comment */ 'CommentsInUnconventionalPlaces', 'value' ); @@ -67,3 +67,16 @@ class MyClass {} define('some param') ] class MyClass {} + +const MixedCase = 1; + +define('lower_case_name', 'value'); +define($var, 'sniff should bow out'); +define(constantName(), 'sniff should bow out'); +define($obj->constantName(), 'sniff should bow out'); +define(MyClass::constantName(), 'sniff should bow out'); +define(condition() ? 'name1' : 'name2', 'sniff should bow out'); + +// Valid if outside the global namespace. Sniff should bow out. +function define($param) {} +$callable = define(...); diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.3.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.3.inc new file mode 100644 index 0000000000..5808142144 --- /dev/null +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.3.inc @@ -0,0 +1,7 @@ + 1, 45 => 1, 51 => 1, + 71 => 1, + 73 => 1, ]; default: return []; From 60803038e5e997f0b4868e9c8747effffcdbf0b2 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 26 Nov 2024 15:33:41 -0300 Subject: [PATCH 143/192] Improve tests based on feedback from PR review --- .../UpperCaseConstantNameUnitTest.1.inc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc index cb60d04986..93a8835c01 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc @@ -77,6 +77,13 @@ define($obj->constantName(), 'sniff should bow out'); define(MyClass::constantName(), 'sniff should bow out'); define(condition() ? 'name1' : 'name2', 'sniff should bow out'); +$callable = define(...); + // Valid if outside the global namespace. Sniff should bow out. function define($param) {} -$callable = define(...); + +class MyClass { + public function define($param) {} +} + +$a = ($cond) ? DEFINE : SOMETHING_ELSE; From fe50ba77278628fc0e38d3bed6114e864ec3b198 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 26 Nov 2024 15:44:11 -0300 Subject: [PATCH 144/192] Generic/UpperCaseConstantName: fix false positive for class instantiation This commit fixes a false positive that would trigger an error when this sniff encountered the instantiation of a class named `Define`. --- .../Sniffs/NamingConventions/UpperCaseConstantNameSniff.php | 3 ++- .../NamingConventions/UpperCaseConstantNameUnitTest.1.inc | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index ad4d936b96..259fa2963d 100644 --- a/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -87,11 +87,12 @@ public function process(File $phpcsFile, $stackPtr) return; } - // Make sure this is not a method call. + // Make sure this is not a method call or class instantiation. $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR || $tokens[$prev]['code'] === T_DOUBLE_COLON || $tokens[$prev]['code'] === T_NULLSAFE_OBJECT_OPERATOR + || $tokens[$prev]['code'] === T_NEW ) { return; } diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc index 93a8835c01..7c1dc41a04 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc @@ -87,3 +87,5 @@ class MyClass { } $a = ($cond) ? DEFINE : SOMETHING_ELSE; + +$object = new Define('value'); From 829c9da3acb1f5ed824dbe0b558f0ecbdaf9b14e Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 26 Nov 2024 15:48:31 -0300 Subject: [PATCH 145/192] Generic/UpperCaseConstantName: move parse error test to its own file --- .../UpperCaseConstantNameUnitTest.1.inc | 2 +- .../UpperCaseConstantNameUnitTest.5.inc | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.5.inc diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc index 7c1dc41a04..c5af2349cb 100644 --- a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc @@ -34,7 +34,7 @@ $foo->getBar()?->define('foo'); // PHP 8.3 introduces typed constants. class TypedConstants { - const MISSING_VALUE; // Parse error. + const MyClass MYCONST = new MyClass; const int VALID_NAME = 0; final public const INT invalid_name = 0; diff --git a/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.5.inc b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.5.inc new file mode 100644 index 0000000000..96e36a3b1a --- /dev/null +++ b/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.5.inc @@ -0,0 +1,9 @@ + Date: Thu, 21 Nov 2024 08:55:34 -0300 Subject: [PATCH 146/192] Generic/OpeningFunctionBraceKernighanRichie: remove repeated call to findPrevious() This commit removes a repeated call to findPrevious() to get the pointer to the end of the function declaration. The same `$prev` variable that was defined a few lines above can be reused and there is no need to define it again calling `findPrevious()` with exactly the same parameters. --- .../Functions/OpeningFunctionBraceKernighanRitchieSniff.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php index ca259854e7..3b6c8227b5 100644 --- a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php +++ b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php @@ -99,7 +99,6 @@ public function process(File $phpcsFile, $stackPtr) $error = 'Opening brace should be on the same line as the declaration'; $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceOnNewLine'); if ($fix === true) { - $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), $closeBracket, true); $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->addContent($prev, ' {'); $phpcsFile->fixer->replaceToken($openingBrace, ''); From a375eeace776843826d768c872ab2610bc1472d4 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Nov 2024 15:31:34 -0300 Subject: [PATCH 147/192] Generic/OpeningFunctionBraceKernighanRichie: improve handling of tabs in a fixer This commit makes a tiny performance improvement to the sniff when handling fixing code with tabs. Before this change, the sniff would need two passes of the fixer for code with one tab before the opening brace. First, it would add a space between the tab and the opening brace. Then, on a second pass, it would replace the tab and the space with just one space. Now, it replaces the tab with the space directly without the need for a second pass. --- .../Functions/OpeningFunctionBraceKernighanRitchieSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php index 3b6c8227b5..f8fa07582d 100644 --- a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php +++ b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php @@ -167,7 +167,7 @@ public function process(File $phpcsFile, $stackPtr) $data = [$length]; $fix = $phpcsFile->addFixableError($error, $openingBrace, 'SpaceBeforeBrace', $data); if ($fix === true) { - if ($length === 0 || $length === '\t') { + if ($length === 0) { $phpcsFile->fixer->addContentBefore($openingBrace, ' '); } else { $phpcsFile->fixer->replaceToken(($openingBrace - 1), ' '); From 111d8515795a703b26fce6d1f58fa12e281481f0 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Nov 2024 07:50:56 -0300 Subject: [PATCH 148/192] Generic/OpeningFunctionBraceKernighanRichie: rename test case file Doing this to be able to create tests with syntax errors on separate files. --- ...nctionBraceKernighanRitchieUnitTest.1.inc} | 0 ...BraceKernighanRitchieUnitTest.1.inc.fixed} | 0 ...gFunctionBraceKernighanRitchieUnitTest.php | 69 ++++++++++--------- 3 files changed, 38 insertions(+), 31 deletions(-) rename src/Standards/Generic/Tests/Functions/{OpeningFunctionBraceKernighanRitchieUnitTest.inc => OpeningFunctionBraceKernighanRitchieUnitTest.1.inc} (100%) rename src/Standards/Generic/Tests/Functions/{OpeningFunctionBraceKernighanRitchieUnitTest.inc.fixed => OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed} (100%) diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc similarity index 100% rename from src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc rename to src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc.fixed b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed similarity index 100% rename from src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc.fixed rename to src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php index f98430768f..30e74ce105 100644 --- a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php @@ -26,40 +26,47 @@ final class OpeningFunctionBraceKernighanRitchieUnitTest extends AbstractSniffUn * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 9 => 1, - 13 => 1, - 17 => 1, - 29 => 1, - 33 => 1, - 37 => 1, - 53 => 1, - 58 => 1, - 63 => 1, - 77 => 1, - 82 => 1, - 87 => 1, - 104 => 1, - 119 => 1, - 123 => 1, - 127 => 1, - 132 => 1, - 137 => 1, - 142 => 1, - 157 => 1, - 162 => 1, - 171 => 1, - 181 => 1, - 191 => 1, - 197 => 1, - 203 => 1, - 213 => 1, - 214 => 1, - ]; + switch ($testFile) { + case 'OpeningFunctionBraceKernighanRitchieUnitTest.1.inc': + return [ + 9 => 1, + 13 => 1, + 17 => 1, + 29 => 1, + 33 => 1, + 37 => 1, + 53 => 1, + 58 => 1, + 63 => 1, + 77 => 1, + 82 => 1, + 87 => 1, + 104 => 1, + 119 => 1, + 123 => 1, + 127 => 1, + 132 => 1, + 137 => 1, + 142 => 1, + 157 => 1, + 162 => 1, + 171 => 1, + 181 => 1, + 191 => 1, + 197 => 1, + 203 => 1, + 213 => 1, + 214 => 1, + ]; + default: + return []; + }//end switch }//end getErrorList() From 195346f36e4ad32b00584c63576f93b7053802ca Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 21 Nov 2024 08:51:33 -0300 Subject: [PATCH 149/192] Generic/OpeningFunctionBraceKernighanRichie: improve test coverage Includes removing unnecessary trailing spaces from empty lines in the test file. --- ...unctionBraceKernighanRitchieUnitTest.1.inc | 30 +++++++++++++---- ...nBraceKernighanRitchieUnitTest.1.inc.fixed | 32 +++++++++++++++---- ...unctionBraceKernighanRitchieUnitTest.2.inc | 11 +++++++ ...nBraceKernighanRitchieUnitTest.2.inc.fixed | 11 +++++++ ...unctionBraceKernighanRitchieUnitTest.3.inc | 7 ++++ ...gFunctionBraceKernighanRitchieUnitTest.php | 25 +++++++++++++++ 6 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc create mode 100644 src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc.fixed create mode 100644 src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.3.inc diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc index 6c937a823b..2e76d62155 100644 --- a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc @@ -23,16 +23,16 @@ class myClass // Good. function myFunction() { } - + // Brace should be on same line. function myFunction() { } - + // Too many spaces. function myFunction() { } - + // Uses tab. function myFunction() { } @@ -70,18 +70,18 @@ class myClass function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Brace should be on same line. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Too many spaces. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Uses tab. function myFunction($variable1, $variable2, $variable3, $variable4) { @@ -212,3 +212,21 @@ function myFunction($a, $lot, $of, $params) function myFunction() {} function myFunction() {} // Too many spaces with an empty function. function myFunction() {} // Too many spaces (tab) with an empty function. + +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 0 +function shouldBeIgnored() +{} +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 1 + +function dnfReturnType(): (Response&SuccessResponse)|AnotherResponse|string +{} + +function commentAfterOpeningBrace() { // Some comment. +} + +function variableAssignmentAfterOpeningBrace() { $a = 1; +} + +abstract class MyClass { + abstract public function abstractMethod(); +} diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed index bfb2283844..14e62eae90 100644 --- a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed @@ -22,15 +22,15 @@ class myClass // Good. function myFunction() { } - + // Brace should be on same line. function myFunction() { } - + // Too many spaces. function myFunction() { } - + // Uses tab. function myFunction() { } @@ -67,17 +67,17 @@ class myClass function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Brace should be on same line. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Too many spaces. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Uses tab. function myFunction($variable1, $variable2, $variable3, $variable4) { @@ -200,3 +200,23 @@ function myFunction($a, $lot, $of, $params) function myFunction() {} function myFunction() {} // Too many spaces with an empty function. function myFunction() {} // Too many spaces (tab) with an empty function. + +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 0 +function shouldBeIgnored() +{} +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 1 + +function dnfReturnType(): (Response&SuccessResponse)|AnotherResponse|string { +} + +function commentAfterOpeningBrace() { + // Some comment. +} + +function variableAssignmentAfterOpeningBrace() { + $a = 1; +} + +abstract class MyClass { + abstract public function abstractMethod(); +} diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc new file mode 100644 index 0000000000..a145bb9efe --- /dev/null +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc @@ -0,0 +1,11 @@ +tabWidth = 4; + } + + }//end setCliValues() + + /** * Returns the lines where errors should occur. * @@ -63,6 +80,14 @@ public function getErrorList($testFile='') 203 => 1, 213 => 1, 214 => 1, + 222 => 1, + 224 => 1, + 227 => 1, + ]; + case 'OpeningFunctionBraceKernighanRitchieUnitTest.2.inc': + return [ + 6 => 1, + 10 => 1, ]; default: return []; From 286cd814b8e105a472d64d68a9aba524862809a7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 26 Nov 2024 16:54:28 -0300 Subject: [PATCH 150/192] Generic/OpeningFunctionBraceKernighanRitchie: simplify logic to find end of the function signature When finding the end of the function signature, the sniff had an unnecessary block of code to change the `$end` parameter passed to `findPrevious()` when handling a closure with a `use` statement. Since we are looking for the first non-empty token before the opening curly brace, it is not necessary to change the value of the `$end` parameter. Actually, we don't even need to limit the search and we can pass `null` (the default value). The returned first non-empty token will be the same anyway regardless if `$end` is the closing parenthesis before `use`, after `use` or `null`. --- .../OpeningFunctionBraceKernighanRitchieSniff.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php index f8fa07582d..1e2df37d86 100644 --- a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php +++ b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php @@ -72,17 +72,9 @@ public function process(File $phpcsFile, $stackPtr) } $openingBrace = $tokens[$stackPtr]['scope_opener']; - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); - if ($use !== false) { - $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - } - } // Find the end of the function declaration. - $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), $closeBracket, true); + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), null, true); $functionLine = $tokens[$prev]['line']; $braceLine = $tokens[$openingBrace]['line']; From 6b106cc18458f14c95ff6e6e435f61926c285c5c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 27 Nov 2024 10:36:56 +0100 Subject: [PATCH 151/192] Generic/OpeningFunctionBraceKernighanRitchie: improve error message Follow up on 707 When there are multiple tabs between the end of the function signature and the open brace, the "found: $length" part of the error message would refer to the number of tabs found. This is inconsistent with other sniffs and confusing. This commit fixes this, while still maintaining the previous behaviour - as introduced via https://github.com/squizlabs/PHP_CodeSniffer/commit/c4b9807cdb661635b71d5c1950e05c5189904a70 - of special casing the messaging for a single tab - independently of whether or not tab replacement is in effect. Example for line 10 of test case file 2: ``` // Before: Expected 1 space before opening brace; found 3 // After: Expected 1 space before opening brace; found 11 ``` Covered via pre-existing tests in both test case files + some additional new tests. --- ...ningFunctionBraceKernighanRitchieSniff.php | 20 +++++++++++-------- ...unctionBraceKernighanRitchieUnitTest.2.inc | 8 ++++++++ ...nBraceKernighanRitchieUnitTest.2.inc.fixed | 8 ++++++++ ...gFunctionBraceKernighanRitchieUnitTest.php | 2 ++ 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php index 1e2df37d86..d5a84982cd 100644 --- a/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php +++ b/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php @@ -138,22 +138,26 @@ public function process(File $phpcsFile, $stackPtr) return; } - // We are looking for tabs, even if they have been replaced, because - // we enforce a space here. - if (isset($tokens[($openingBrace - 1)]['orig_content']) === true) { - $spacing = $tokens[($openingBrace - 1)]['orig_content']; - } else { - $spacing = $tokens[($openingBrace - 1)]['content']; - } - + // Enforce a single space. Tabs not allowed. + $spacing = $tokens[($openingBrace - 1)]['content']; if ($tokens[($openingBrace - 1)]['code'] !== T_WHITESPACE) { $length = 0; } else if ($spacing === "\t") { + // Tab without tab-width set, so no tab replacement has taken place. $length = '\t'; } else { $length = strlen($spacing); } + // If tab replacement is on, avoid confusing the user with a "expected 1 space, found 1" + // message when the "1" found is actually a tab, not a space. + if ($length === 1 + && isset($tokens[($openingBrace - 1)]['orig_content']) === true + && $tokens[($openingBrace - 1)]['orig_content'] === "\t" + ) { + $length = '\t'; + } + if ($length !== 1) { $error = 'Expected 1 space before opening brace; found %s'; $data = [$length]; diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc index a145bb9efe..36b5e8187d 100644 --- a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc @@ -9,3 +9,11 @@ function myFunction() { // Uses three tabs. function myFunction() { } + +// Uses one tab in a way that it translates to exactly one space with tab replacement. +function oneT() { +} + +// Mixed tabs and spaces. +function mixed() { +} diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc.fixed b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc.fixed index 515a93e50a..a3c47435de 100644 --- a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc.fixed +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc.fixed @@ -9,3 +9,11 @@ function myFunction() { // Uses three tabs. function myFunction() { } + +// Uses one tab in a way that it translates to exactly one space with tab replacement. +function oneT() { +} + +// Mixed tabs and spaces. +function mixed() { +} diff --git a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php index 0c1a99300a..747d54d84c 100644 --- a/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php +++ b/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.php @@ -88,6 +88,8 @@ public function getErrorList($testFile='') return [ 6 => 1, 10 => 1, + 14 => 1, + 18 => 1, ]; default: return []; From ca4081cc4333d34e631d22cf9d3aad4bbd669ef8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 18:52:23 +0100 Subject: [PATCH 152/192] Generators/Markdown: fix line break and indentation handling As things were, line breaks in a `` block were not respected for proper display in markdown. As a side-effect of this, an indented text line in a `` block directly after a blank line, would unintentionally cause the markdown to display the line as a code block (via the indentation). This has now been fixed by: * Trimming indentation off each line. * Adding two spaces to the end of each line as long as the line is not followed by a blank line or at the end of the standard block. The two spaces will ensure markdown will recognize the line break (in most markdown flavours). Includes updated test expectations. Refs: * https://www.markdownguide.org/basic-syntax/#paragraph-best-practices * https://www.markdownguide.org/basic-syntax/#line-break-best-practices * https://daringfireball.net/projects/markdown/syntax#p --- src/Generators/Markdown.php | 30 +++++++++++++++---- .../ExpectedOutputCodeComparisonLineLength.md | 4 +-- .../ExpectedOutputStandardBlankLines.md | 4 +-- .../ExpectedOutputStandardEncoding.md | 4 +-- .../ExpectedOutputStandardIndent.md | 8 ++--- .../ExpectedOutputStandardLineWrapping.md | 6 ++-- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index 76dbb0605f..eb51b60c77 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -117,14 +117,34 @@ protected function printTextBlock(DOMNode $node) { $content = trim($node->nodeValue); $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); - - // Use the correct line endings based on the OS. - $content = str_replace("\n", PHP_EOL, $content); - $content = str_replace('<em>', '*', $content); $content = str_replace('</em>', '*', $content); - echo $content.PHP_EOL; + $nodeLines = explode("\n", $content); + $lineCount = count($nodeLines); + $lines = []; + + for ($i = 0; $i < $lineCount; $i++) { + $currentLine = trim($nodeLines[$i]); + if ($currentLine === '') { + // The text contained a blank line. Respect this. + $lines[] = ''; + continue; + } + + // Check if the _next_ line is blank. + if (isset($nodeLines[($i + 1)]) === false + || trim($nodeLines[($i + 1)]) === '' + ) { + // Next line is blank, just add the line. + $lines[] = $currentLine; + } else { + // Ensure that line breaks are respected in markdown. + $lines[] = $currentLine.' '; + } + } + + echo implode(PHP_EOL, $lines).PHP_EOL; }//end printTextBlock() diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md index 89ae055bfb..8dbf564261 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md @@ -2,8 +2,8 @@ ## Code Comparison, line length -Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". - Ref: squizlabs/PHP_CodeSniffer#2522 +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". +Ref: squizlabs/PHP_CodeSniffer#2522
    Valid: contains line which is too long.
    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md index 6b3d6ed107..f8663f14f3 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md @@ -4,8 +4,8 @@ There is a blank line at the start of this standard. - And the above blank line is also deliberate to test part of the logic. +And the above blank line is also deliberate to test part of the logic. - Let's also end on a blank line to test that too. +Let's also end on a blank line to test that too. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md index f682daf611..6183dc0037 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md @@ -2,7 +2,7 @@ ## Standard Element, handling of HTML tags -The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. - Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used. +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. +Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md index 1f3916153e..46bea4c349 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md @@ -2,9 +2,9 @@ ## Standard Element, indentation should be ignored -This line has no indentation. - This line has 4 spaces indentation. - This line has 8 spaces indentation. - This line has 4 spaces indentation. +This line has no indentation. +This line has 4 spaces indentation. +This line has 8 spaces indentation. +This line has 4 spaces indentation. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md index 1a2cd9f19c..c94bed46b5 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md @@ -2,8 +2,8 @@ ## Standard Element, line wrapping handling -This line has to be exactly 99 chars to test part of the logic.------------------------------------ - And this line has to be exactly 100 chars.---------------------------------------------------------- - And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo. +This line has to be exactly 99 chars to test part of the logic.------------------------------------ +And this line has to be exactly 100 chars.---------------------------------------------------------- +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo. Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) From 5a36502160c3c6fe115a1f2fa50cce7347cc6a96 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 20:26:51 +0100 Subject: [PATCH 153/192] Generators/Text: trim code titles As things were, whitespace at the start/end of a title could cause unnecessary line wrapping of the title. Fixed now. Includes updated test expectations. --- src/Generators/Text.php | 4 ++-- .../Expectations/ExpectedOutputCodeTitleWhitespace.txt | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Generators/Text.php b/src/Generators/Text.php index 419bcc3d56..e57556d08f 100644 --- a/src/Generators/Text.php +++ b/src/Generators/Text.php @@ -133,7 +133,7 @@ protected function printCodeComparisonBlock(DOMNode $node) { $codeBlocks = $node->getElementsByTagName('code'); $first = trim($codeBlocks->item(0)->nodeValue); - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); + $firstTitle = trim($codeBlocks->item(0)->getAttribute('title')); $firstTitleLines = []; $tempTitle = ''; @@ -168,7 +168,7 @@ protected function printCodeComparisonBlock(DOMNode $node) $firstLines = explode("\n", $first); $second = trim($codeBlocks->item(1)->nodeValue); - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); + $secondTitle = trim($codeBlocks->item(1)->getAttribute('title')); $secondTitleLines = []; $tempTitle = ''; diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt index 80a6cc690b..0db5a7dfae 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt @@ -6,15 +6,13 @@ This is a standard block. ----------------------------------------- CODE COMPARISON ------------------------------------------ -| Valid: spaces at start of description. | Invalid: spaces at end making line > 46 chars. | -| | | +| Valid: spaces at start of description. | Invalid: spaces at end making line > 46 chars. | ---------------------------------------------------------------------------------------------------- | // Dummy. | // Dummy. | ---------------------------------------------------------------------------------------------------- ----------------------------------------- CODE COMPARISON ------------------------------------------ -| Valid: spaces at start + end of description. | Invalid: spaces ' ' in description. | -| | | +| Valid: spaces at start + end of description. | Invalid: spaces ' ' in description. | ---------------------------------------------------------------------------------------------------- | // Note: description above without the | // Dummy. | | // trailing whitespace fits in 46 chars. | | From f2fedfbb0f6c6556583f36767d480b06efed762d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 3 Nov 2024 23:23:07 +0100 Subject: [PATCH 154/192] Generators HTML/Markdown: fix whitespace handling in code title If there were multiple spaces next to each other in the title, this would be folded into one space for the display in HTML and Markdown. This could mangle the code title, so fixed now. Includes updated test expectations. --- src/Generators/HTML.php | 6 ++++-- src/Generators/Markdown.php | 6 ++++-- .../Expectations/ExpectedOutputCodeTitleWhitespace.html | 8 ++++---- .../Expectations/ExpectedOutputCodeTitleWhitespace.md | 8 ++++---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Generators/HTML.php b/src/Generators/HTML.php index 8e2001e2e5..ba05d072df 100644 --- a/src/Generators/HTML.php +++ b/src/Generators/HTML.php @@ -281,7 +281,8 @@ protected function printCodeComparisonBlock(DOMNode $node) { $codeBlocks = $node->getElementsByTagName('code'); - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); + $firstTitle = trim($codeBlocks->item(0)->getAttribute('title')); + $firstTitle = str_replace(' ', '  ', $firstTitle); $first = trim($codeBlocks->item(0)->nodeValue); $first = str_replace('', $first); @@ -289,7 +290,8 @@ protected function printCodeComparisonBlock(DOMNode $node) $first = str_replace('', '', $first); $first = str_replace('', '', $first); - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); + $secondTitle = trim($codeBlocks->item(1)->getAttribute('title')); + $secondTitle = str_replace(' ', '  ', $secondTitle); $second = trim($codeBlocks->item(1)->nodeValue); $second = str_replace('', $second); diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index 76dbb0605f..77807b55e0 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -140,13 +140,15 @@ protected function printCodeComparisonBlock(DOMNode $node) { $codeBlocks = $node->getElementsByTagName('code'); - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); + $firstTitle = trim($codeBlocks->item(0)->getAttribute('title')); + $firstTitle = str_replace(' ', '  ', $firstTitle); $first = trim($codeBlocks->item(0)->nodeValue); $first = str_replace("\n", PHP_EOL.' ', $first); $first = str_replace('', '', $first); $first = str_replace('', '', $first); - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); + $secondTitle = trim($codeBlocks->item(1)->getAttribute('title')); + $secondTitle = str_replace(' ', '  ', $secondTitle); $second = trim($codeBlocks->item(1)->nodeValue); $second = str_replace("\n", PHP_EOL.' ', $second); $second = str_replace('', '', $second); diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html index a64cdb4deb..fe1c15bb47 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html @@ -75,8 +75,8 @@

    Code Title, whitespace handling

    This is a standard block.

    Valid: contains line which is too long.
    - - + + @@ -85,8 +85,8 @@

    Code Title, whitespace handling

    Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars. Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
    // Dummy.
    - - + + diff --git a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md index 2d04562c7e..e623ba98dd 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md @@ -5,8 +5,8 @@ This is a standard block.
    Valid: spaces at start + end of description. Invalid: spaces ' ' in description.Valid: spaces at start + end of description.Invalid: spaces '     ' in description.
    // Note: description above without the
    // trailing whitespace fits in 46 chars.
    - - + +
    Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars. Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
    @@ -23,8 +23,8 @@ This is a standard block.
    - - + +
    Valid: spaces at start + end of description. Invalid: spaces ' ' in description.Valid: spaces at start + end of description.Invalid: spaces '     ' in description.
    From 66d3ac5d9404e4731b807ec882116b377635a660 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 27 Nov 2024 13:06:28 +0100 Subject: [PATCH 155/192] Squiz ruleset: update property format The Squiz ruleset was still using the deprecated property setting array format for the `Generic.Debug.ClosureLinter` sniff. Fixed now. --- src/Standards/Squiz/ruleset.xml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Standards/Squiz/ruleset.xml b/src/Standards/Squiz/ruleset.xml index 87ab4c3e8a..82f5270ada 100644 --- a/src/Standards/Squiz/ruleset.xml +++ b/src/Standards/Squiz/ruleset.xml @@ -74,8 +74,14 @@ - - + + + + + + + + From e66802a1e0c6991c2aa7f5ee620bd1fa6320e5b7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Nov 2024 02:22:11 +0100 Subject: [PATCH 156/192] Ruleset::processRuleset(): add tests for handling of broken rulesets --- ...ocessRulesetBrokenRulesetEmptyFileTest.xml | 0 ...cessRulesetBrokenRulesetMultiErrorTest.xml | 10 ++ ...essRulesetBrokenRulesetSingleErrorTest.xml | 2 + .../ProcessRulesetBrokenRulesetTest.php | 92 +++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php diff --git a/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml new file mode 100644 index 0000000000..64294b9b78 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml new file mode 100644 index 0000000000..e9c5bd7e47 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php new file mode 100644 index 0000000000..95f67c21df --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php @@ -0,0 +1,92 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of broken ruleset files. + * + * Note: these tests need to run in separate processes as otherwise they run into + * some weirdness with the libxml_get_errors()/libxml_clear_errors() functions + * (duplicate error messages). + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetBrokenRulesetTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an informative error message when an empty XML ruleset file is encountered. + * + * @return void + */ + public function testBrokenRulesetEmptyFile() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetEmptyFileTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^Ruleset \S+ProcessRulesetBrokenRulesetEmptyFileTest\.xml is not valid\R$`'; + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetEmptyFile() + + + /** + * Test displaying an informative error message for a broken XML ruleset with a single XML error. + * + * @return void + */ + public function testBrokenRulesetSingleError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetSingleErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^Ruleset \S+ProcessRulesetBrokenRulesetSingleErrorTest\.xml is not valid\R'; + $regex .= '- On line 3, column 1: Premature end of data in tag ruleset line 2\R$`'; + + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetSingleError() + + + /** + * Test displaying an informative error message for a broken XML ruleset with multiple XML errors. + * + * @return void + */ + public function testBrokenRulesetMultiError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetMultiErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^Ruleset \S+ProcessRulesetBrokenRulesetMultiErrorTest\.xml is not valid\R'; + $regex .= '- On line 8, column 12: Opening and ending tag mismatch: property line 7 and rule\R'; + $regex .= '- On line 10, column 11: Opening and ending tag mismatch: properties line 5 and ruleset\R'; + $regex .= '- On line 11, column 1: Premature end of data in tag rule line 4\R$`'; + + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetMultiError() + + +}//end class From 0a364dcaa9dc1333fc8901d237f82acdf59bffcf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 18 Nov 2024 06:27:19 +0100 Subject: [PATCH 157/192] Ruleset::processRule(): add test for handling of invalid `` directives --- .../Ruleset/ProcessRuleInvalidTypeTest.php | 43 +++++++++++++++++++ .../Ruleset/ProcessRuleInvalidTypeTest.xml | 9 ++++ 2 files changed, 52 insertions(+) create mode 100644 tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php create mode 100644 tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml diff --git a/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php b/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php new file mode 100644 index 0000000000..08a2e6b822 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php @@ -0,0 +1,43 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of invalid type elements. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + */ +final class ProcessRuleInvalidTypeTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an informative error message when an invalid type is given. + * + * @return void + */ + public function testInvalidTypeHandling() + { + $standard = __DIR__.'/ProcessRuleInvalidTypeTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'Message type "notice" is invalid; must be "error" or "warning"'; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testInvalidTypeHandling() + + +}//end class diff --git a/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml b/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml new file mode 100644 index 0000000000..63c2aaf3c8 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml @@ -0,0 +1,9 @@ + + + + + + notice + + + From 0c2d6d4d37cf3f7df269c7d61ded72639ae23728 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 14 Nov 2024 08:52:18 -0300 Subject: [PATCH 158/192] Generic/CyclomaticComplexity: rename test case file Doing this to be able to create tests with syntax errors on separate files. --- ...inc => CyclomaticComplexityUnitTest.1.inc} | 0 .../Metrics/CyclomaticComplexityUnitTest.php | 42 ++++++++++++------- 2 files changed, 28 insertions(+), 14 deletions(-) rename src/Standards/Generic/Tests/Metrics/{CyclomaticComplexityUnitTest.inc => CyclomaticComplexityUnitTest.1.inc} (100%) diff --git a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc similarity index 100% rename from src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc rename to src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc diff --git a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php index 950ba3eec3..f7c75f79ca 100644 --- a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php +++ b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php @@ -26,11 +26,18 @@ final class CyclomaticComplexityUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [118 => 1]; + switch ($testFile) { + case 'CyclomaticComplexityUnitTest.1.inc': + return [118 => 1]; + default: + return []; + } }//end getErrorList() @@ -41,21 +48,28 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 45 => 1, - 72 => 1, - 189 => 1, - 237 => 1, - 285 => 1, - 333 => 1, - 381 => 1, - 417 => 1, - 445 => 1, - ]; + switch ($testFile) { + case 'CyclomaticComplexityUnitTest.1.inc': + return [ + 45 => 1, + 72 => 1, + 189 => 1, + 237 => 1, + 285 => 1, + 333 => 1, + 381 => 1, + 417 => 1, + 445 => 1, + ]; + default: + return []; + } }//end getWarningList() From 2371b0ae53e19e598a55ddaf7da62aa8d15d500f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 14 Nov 2024 09:02:51 -0300 Subject: [PATCH 159/192] Generic/CyclomaticComplexity: improve code coverage --- .../Metrics/CyclomaticComplexitySniff.php | 2 +- .../CyclomaticComplexityUnitTest.1.inc | 32 +++++++++++-------- .../CyclomaticComplexityUnitTest.2.inc | 7 ++++ .../CyclomaticComplexityUnitTest.3.inc | 7 ++++ 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc create mode 100644 src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.3.inc diff --git a/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php b/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php index 8cba81daf2..c37140a990 100644 --- a/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php +++ b/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php @@ -60,7 +60,7 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - // Ignore abstract methods. + // Ignore abstract and interface methods. Bail early when live coding. if (isset($tokens[$stackPtr]['scope_opener']) === false) { return; } diff --git a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc index 494dcc7694..9ee638b0cb 100644 --- a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc +++ b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc @@ -46,7 +46,7 @@ function complexityEleven() { while ($condition === true) { if ($condition) { - } else if ($cond) { + } elseif ($cond) { } } @@ -61,11 +61,11 @@ function complexityEleven() echo 'hi'; } break; - case '3': - break; default: break; } + + foreach ($array as $element) {} } @@ -136,14 +136,6 @@ function complexityTwentyOne() echo 'hi'; } break; - case '3': - switch ($cond) { - case '1': - break; - case '2': - break; - } - break; case '4': do { if ($condition) { @@ -159,8 +151,16 @@ function complexityTwentyOne() } break; } -} + try { + for ($i = 0; $i < 10; $i++) { + if ($i % 2) { + doSomething(); + } + } + } catch (Exception $e) { + } +} function complexityTenWithTernaries() { @@ -451,4 +451,10 @@ function complexityElevenWithNullSafeOperator() $bits = $object5->getX()?->getY()?->getZ(); } -?> +abstract class AbstractClass { + abstract public function sniffShouldIgnoreAbstractMethods(); +} + +interface MyInterface { + public function sniffShouldIgnoreInterfaceMethods(); +} diff --git a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc new file mode 100644 index 0000000000..9658af3005 --- /dev/null +++ b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc @@ -0,0 +1,7 @@ + Date: Mon, 2 Dec 2024 10:02:06 -0300 Subject: [PATCH 160/192] Generic/CyclomaticComplexity: ensure the sniff bails if `scope_closer` is not set Quoting @jrfnl: "Only checking for the scope_opener, when accessing/using both the scope_opener and scope_closer indexes, is probably fine in practical terms. However, the part of the code base which sets these indexes is not sufficiently covered by tests, nor does it document that those indexes will only be set if both can be set, so there may be edge case exceptions" (https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/684#discussion_r1865313147). The sniff was already working fine before this change. Checking if `scope_closer` is just an extra precaution to err on the side of caution. --- .../Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php b/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php index c37140a990..a6b17d1315 100644 --- a/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php +++ b/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php @@ -61,7 +61,7 @@ public function process(File $phpcsFile, $stackPtr) $tokens = $phpcsFile->getTokens(); // Ignore abstract and interface methods. Bail early when live coding. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { return; } From cb96819a180340e00ff1e73b66f7eb159a8017d8 Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:52:55 +0100 Subject: [PATCH 161/192] Ruleset: add tests for handling of `php[cs|cbf]-only` attributes within a `` (#711) Add tests specifically aimed at verifying `phpcs-only` and `phpcbf-only` attributes for elements within a `` are read and handled correctly. --- ...ProcessRulesetShouldProcessElementTest.php | 388 ++++++++++++++++++ ...ProcessRulesetShouldProcessElementTest.xml | 54 +++ 2 files changed, 442 insertions(+) create mode 100644 tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php create mode 100644 tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml diff --git a/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php b/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php new file mode 100644 index 0000000000..cd04ae78dc --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php @@ -0,0 +1,388 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at ruleset level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRulesetShouldProcessElementTest extends TestCase +{ + + /** + * Cache to store the original ini values for ini settings being changed in these tests. + * + * @var array + */ + private static $originalIniValues = [ + 'bcmath.scale' => null, + 'docref_root' => null, + 'user_agent' => null, + ]; + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Tests\ConfigDouble + */ + private static $config; + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Store the original ini values to allow for restoring them after the tests. + * + * @beforeClass + * + * @return void + */ + public static function saveOriginalIniValues() + { + foreach (self::$originalIniValues as $name => $null) { + $value = ini_get($name); + if ($value !== false) { + self::$originalIniValues[$name] = $value; + } + } + + }//end saveOriginalIniValues() + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetShouldProcessElementTest.xml'; + self::$config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset(self::$config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Destroy the Config object and restor the ini values after the tests. + * + * @afterClass + * + * @return void + */ + public static function restoreOriginalValues() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + if (isset(self::$config) === true) { + self::$config->__destruct(); + } + + foreach (self::$originalIniValues as $name => $value) { + if ($value === null) { + continue; + } + + ini_set($name, $value); + } + + }//end restoreOriginalValues() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessConfigCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame('true', Config::getConfigData('csOnly'), 'CS-only config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('cbfOnly'), 'CBF-only config directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessConfigCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessConfigCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('csOnly'), 'CS-only config directive was applied, while it shouldn\'t have been.'); + $this->assertSame('true', Config::getConfigData('cbfOnly'), 'CBF-only config directive was not applied.'); + + }//end testShouldProcessConfigCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessArgCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['full' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertTrue(self::$config->colors, 'CS-only arg directive was not applied.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessArgCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessArgCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['summary' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertFalse(self::$config->colors, 'CS-only arg directive was applied, while it shouldn\'t have been.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was not applied.'); + + }//end testShouldProcessArgCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessIniCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('path/to/docs/', ini_get('docref_root'), 'CS-only ini directive was not applied.'); + $this->assertSame('', ini_get('user_agent'), 'CBF-only ini directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessIniCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessIniCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('', ini_get('docref_root'), 'CS-only ini directive was applied, while it shouldn\'t have been..'); + $this->assertSame('Never mind', ini_get('user_agent'), 'CBF-only ini directive was not applied.'); + + }//end testShouldProcessIniCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './vendor/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './node-modules/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCbfonly() + + + /** + * Verify that in CS mode, phpcs-only in directives are respected and phpcbf-only in + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleExcludeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.Indent' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only in directives are respected and phpcs-only in + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleExcludeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.EqualSignLine' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCbfonly() + + +}//end class diff --git a/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml b/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml new file mode 100644 index 0000000000..62ea0e62f5 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml @@ -0,0 +1,54 @@ + + + + . + + + + + + + + ./tests/ + + + + + + + + + ./vendor/ + + + + + + + + + + + + + ./node-modules/ + + + + + + + + From 585602f01659a1689c84efab6bbe91d33ad36c31 Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:54:41 +0100 Subject: [PATCH 162/192] Ruleset: add tests for handling of `php[cs|cbf]-only` attributes within a `` (#712) Add tests specifically aimed at verifying `phpcs-only` and `phpcbf-only` attributes for elements within a `` are read and handled correctly. --- .../ProcessRuleShouldProcessElementTest.php | 660 ++++++++++++++++++ .../ProcessRuleShouldProcessElementTest.xml | 100 +++ 2 files changed, 760 insertions(+) create mode 100644 tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php create mode 100644 tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml diff --git a/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php b/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php new file mode 100644 index 0000000000..7de34c1210 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php @@ -0,0 +1,660 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at rule level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRuleShouldProcessElementTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRuleShouldProcessElementTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessSeverityCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame(2, $sniffCode, $key); + + // Verify that the CBF-only severity directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessSeverityCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessSeverityCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only severity directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame(4, $sniffCode, $key); + + }//end testShouldProcessSeverityCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessTypeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CBF-only type directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessTypeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessTypeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only type directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('error', $sniffCode, $key); + + }//end testShouldProcessTypeCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessMessageCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('A different warning but only for phpcs', $sniffCode, $key); + + // Verify that the CBF-only message directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessMessageCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessMessageCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only message directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('A different warning but only for phpcbf', $sniffCode, $key); + + }//end testShouldProcessMessageCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessIncludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive IS applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only include-pattern directive is NOT applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessIncludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessIncludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive is NOT applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only include-pattern directive is IS applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessIncludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive IS applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only exclude-pattern directive is NOT applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive is NOT applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only exclude-pattern directive is IS applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertiesCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive IS applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertiesCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertiesCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive is NOT applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertiesCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertyCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive IS applied. + $propertyName = 'indent'; + $expected = '2'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $propertyName = 'tabIndent'; + $expectedDefault = false; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertyCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertyCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive is NOT applied. + $propertyName = 'indent'; + $expectedDefault = 4; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $propertyName = 'tabIndent'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertyCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessElementCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcs-only element directive. + 'T_CLASS', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcs-only element directive via `extend`. + 'T_INTERFACE', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessElementCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcbf-only element directive. + 'T_ENUM', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcbf-only element directive via `extend`. + 'T_TRAIT', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCbfonly() + + + /** + * Verify that directives are set correctly. + * + * @param array $expected Expected sniff property value. + * + * @return void + */ + private function verifyShouldProcessElement($expected) + { + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + // Verify the target property exists. + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $propertyName = 'ignoreIndentationTokens'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + + // Verify the value. + $actualValue = $sniffObject->$propertyName; + $this->assertSame($expected, $actualValue, 'Selective element directives not applied correctly'); + + }//end verifyShouldProcessElement() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property has a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertHasRulesetDirective($sniffCode, $key) + { + $this->assertArrayHasKey($sniffCode, self::$ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array(self::$ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, self::$ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + + }//end assertHasRulesetDirective() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property does NOT have a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertNotHasRulesetDirective($sniffCode, $key) + { + if (isset(self::$ruleset->ruleset[$sniffCode]) === true + && is_array(self::$ruleset->ruleset[$sniffCode]) === true + && isset(self::$ruleset->ruleset[$sniffCode][$key]) === true + ) { + $this->fail("Directive $key is registered for sniff $sniffCode"); + } + + }//end assertNotHasRulesetDirective() + + + /** + * Custom assertion to verify that the value of a certain directive for a certain sniff code on the ruleset is correct. + * + * @param mixed $expected Expected value. + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertRulesetPropertySame($expected, $sniffCode, $key) + { + $this->assertHasRulesetDirective($sniffCode, $key); + + $actual = self::$ruleset->ruleset[$sniffCode][$key]; + $this->assertSame($expected, $actual, "Value for $key on sniff $sniffCode does not meet expectations"); + + }//end assertRulesetPropertySame() + + +}//end class diff --git a/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml b/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml new file mode 100644 index 0000000000..73a8116110 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml @@ -0,0 +1,100 @@ + + + + + + 3 + warning + A different warning message + + + + ./vendor/ + + + + ./tests/ + + + + + + + 2 + warning + A different warning but only for phpcs + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + 4 + error + A different warning but only for phpcbf + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c942e6ac8187c05c32cc2eae4aeb5dd4277cf8c5 Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:55:55 +0100 Subject: [PATCH 163/192] Ruleset::processRuleset(): add tests for handling `` directives (#715) Add tests specifically aimed at verifying `` elements are read and handled correctly. Note: as `autoload` directive are not stored in the ruleset, but directly lead to a file include using `include_once`, these tests need to run in a separate process to circumvent the possibility of test cross-contamination. --- .../ProcessRulesetAutoloadLoadAlways.1.php | 8 + .../ProcessRulesetAutoloadLoadAlways.2.php | 8 + .../ProcessRulesetAutoloadLoadAlways.3.php | 8 + .../ProcessRulesetAutoloadLoadAlways.4.php | 8 + .../ProcessRulesetAutoloadLoadPhpcbfOnly.php | 8 + .../ProcessRulesetAutoloadLoadPhpcsOnly.php | 8 + ...ProcessRulesetAutoloadFileNotFoundTest.xml | 8 + .../Ruleset/ProcessRulesetAutoloadTest.php | 164 ++++++++++++++++++ .../Ruleset/ProcessRulesetAutoloadTest.xml | 37 ++++ 9 files changed, 257 insertions(+) create mode 100644 tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php create mode 100644 tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php create mode 100644 tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php create mode 100644 tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php create mode 100644 tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php create mode 100644 tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php create mode 100644 tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetAutoloadTest.php create mode 100644 tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml diff --git a/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php b/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php new file mode 100644 index 0000000000..2b1fadaf5e --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php @@ -0,0 +1,8 @@ + + + + ./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php b/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php new file mode 100644 index 0000000000..a6a0dd4afe --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php @@ -0,0 +1,164 @@ + instructions. + * + * @author Juliette Reinders Folmer + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of instructions. + * + * Note: these tests need to run in separate processes as otherwise we cannot + * reliably determine whether or not the correct files were loaded as the + * underlying code uses `include_once`. + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetAutoloadTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessAutoloadCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + + }//end testShouldProcessAutoloadCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessAutoloadCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was not loaded' + ); + + }//end testShouldProcessAutoloadCbfonly() + + + /** + * Test an exception is thrown when the directive points to a file which doesn't exist. + * + * @return void + */ + public function testFileNotFoundException() + { + $exceptionMsg = 'The specified autoload file "./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php" does not exist'; + $this->expectRuntimeExceptionMessage($exceptionMsg); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadFileNotFoundTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testFileNotFoundException() + + +}//end class diff --git a/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml b/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml new file mode 100644 index 0000000000..450de65079 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml @@ -0,0 +1,37 @@ + + + + . + + + + ./Fixtures/ProcessRulesetAutoloadLoadAlways.1.php + Fixtures/ProcessRulesetAutoloadLoadAlways.2.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php + tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php + + + + + From 130180d7ad841337478607141d60d98ee095672f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 30 Nov 2024 14:56:11 +0100 Subject: [PATCH 164/192] GH Actions: change PHAR building to reusable workflow The workflows currently contain two jobs which build the PHAR files. In PHPCS 4.0, a third job will be added (in relation to 530), which will also need to build the PHAR files. This means that any changes to the steps in these jobs would then have to be made in three places. With this in mind, it makes sense to change the PHAR building to a reusable workflow, which can then be used by all three jobs. With this change, any changes to the steps of the job will only need to be made in one place. This commit makes it so. --- .github/workflows/build-phar.yml | 32 ++------- .github/workflows/reusable-build-phar.yml | 81 +++++++++++++++++++++++ .github/workflows/test.yml | 52 ++------------- 3 files changed, 92 insertions(+), 73 deletions(-) create mode 100644 .github/workflows/reusable-build-phar.yml diff --git a/.github/workflows/build-phar.yml b/.github/workflows/build-phar.yml index b091e24c45..d1d37f5a70 100644 --- a/.github/workflows/build-phar.yml +++ b/.github/workflows/build-phar.yml @@ -8,6 +8,7 @@ on: - master paths: - '.github/workflows/build-phar.yml' + - '.github/workflows/reusable-build-phar.yml' - 'scripts/build-phar.php' - 'autoload.php' - 'src/Config.php' @@ -18,6 +19,7 @@ on: pull_request: paths: - '.github/workflows/build-phar.yml' + - '.github/workflows/reusable-build-phar.yml' - 'scripts/build-phar.php' - 'autoload.php' - 'src/Config.php' @@ -37,35 +39,13 @@ concurrency: jobs: build: - runs-on: ubuntu-latest - strategy: matrix: # Deliberately missing PHP 8.0 as that PHAR is build and used in the test workflow. - php: ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.1', '8.2', '8.3', '8.4', '8.5'] + php: ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.1', '8.2', '8.3', '8.4', 'nightly'] name: "Build Phar on PHP: ${{ matrix.php }}" - continue-on-error: ${{ matrix.php == '8.5' }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - ini-values: phar.readonly=Off, error_reporting=-1, display_errors=On - - - name: Build the phars - run: php scripts/build-phar.php - - # Both the below only check a file which is rarely changed and therefore unlikely to have issues. - # This test is about testing that the phars are functional, *not* about whether the code style complies. - - name: 'PHPCS: check code style using the Phar file to test the Phar is functional' - run: php phpcs.phar ./scripts - - - name: 'PHPCBF: fix code style using the Phar file to test the Phar is functional' - run: php phpcbf.phar ./scripts + uses: ./.github/workflows/reusable-build-phar.yml + with: + phpVersion: ${{ matrix.php }} diff --git a/.github/workflows/reusable-build-phar.yml b/.github/workflows/reusable-build-phar.yml new file mode 100644 index 0000000000..bac53d77ee --- /dev/null +++ b/.github/workflows/reusable-build-phar.yml @@ -0,0 +1,81 @@ +name: Build PHAR files + +on: + workflow_call: + inputs: + phpVersion: + description: "The PHP version to use. Defaults to PHP 8.0 as used for the releases." + type: string + required: false + default: '8.0' + uploadArtifacts: + description: "Whether or not to upload the artifacts. Defaults to false." + type: boolean + required: false + default: false + retentionDays: + description: "How long uploaded artifacts should remain available (in days). Defaults to 1 day." + type: string + required: false + default: 1 + createAttestations: + description: "Whether or not to create attestations for the artifacts. Defaults to false." + type: boolean + required: false + default: false + +jobs: + build: + runs-on: ubuntu-latest + name: "Build Phar on PHP: ${{ inputs.phpVersion }}" + + continue-on-error: ${{ inputs.phpVersion == 'nightly' }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ inputs.phpVersion }} + coverage: none + ini-values: phar.readonly=Off, error_reporting=-1, display_errors=On + + - name: Build the phar files + run: php scripts/build-phar.php + + # Provide provenance for generated binaries. + - name: Generate artifact attestations + if: ${{ inputs.createAttestations == true }} + uses: actions/attest-build-provenance@v1 + with: + subject-path: | + ${{ github.workspace }}/phpcs.phar + ${{ github.workspace }}/phpcbf.phar + + - name: Upload the PHPCS phar + if: ${{ inputs.uploadArtifacts == true }} + uses: actions/upload-artifact@v4 + with: + name: phpcs-phar + path: ./phpcs.phar + if-no-files-found: error + retention-days: ${{ inputs.retentionDays }} + + - name: Upload the PHPCBF phar + if: ${{ inputs.uploadArtifacts == true }} + uses: actions/upload-artifact@v4 + with: + name: phpcbf-phar + path: ./phpcbf.phar + if-no-files-found: error + retention-days: ${{ inputs.retentionDays }} + + # Both the below only check a file which is rarely changed and therefore unlikely to have issues. + # This test is about testing that the phars are functional, *not* about whether the code style complies. + - name: 'PHPCS: check code style using the Phar file to test the Phar is functional' + run: php phpcs.phar ./scripts + + - name: 'PHPCBF: fix code style using the Phar file to test the Phar is functional' + run: php phpcbf.phar ./scripts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 212798b30f..3d9d758301 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,6 @@ jobs: group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} cancel-in-progress: true - runs-on: ubuntu-latest name: "Build Phar on PHP: 8.0" permissions: @@ -30,54 +29,13 @@ jobs: contents: read attestations: write - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.0' - coverage: none - ini-values: phar.readonly=Off, error_reporting=-1, display_errors=On - - - name: Build the phar - run: php scripts/build-phar.php - - # Provide provenance for generated binaries. + uses: ./.github/workflows/reusable-build-phar.yml + with: + uploadArtifacts: true + retentionDays: 28 # Only attests the build artifacts which will be used in the published releases as per the guidelines in "what to attest". # https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds - - name: Generate artifact attestations - if: ${{ github.ref_type == 'tag' }} - uses: actions/attest-build-provenance@v1 - with: - subject-path: | - ${{ github.workspace }}/phpcs.phar - ${{ github.workspace }}/phpcbf.phar - - - name: Upload the PHPCS phar - uses: actions/upload-artifact@v4 - with: - name: phpcs-phar - path: ./phpcs.phar - if-no-files-found: error - retention-days: 28 - - - name: Upload the PHPCBF phar - uses: actions/upload-artifact@v4 - with: - name: phpcbf-phar - path: ./phpcbf.phar - if-no-files-found: error - retention-days: 28 - - # Both the below only check a file which is rarely changed and therefore unlikely to have issues. - # This test is about testing that the phars are functional, *not* about whether the code style complies. - - name: 'PHPCS: check code style using the Phar file to test the Phar is functional' - run: php phpcs.phar ./scripts - - - name: 'PHPCBF: fix code style using the Phar file to test the Phar is functional' - run: php phpcbf.phar ./scripts + createAttestations: ${{ github.ref_type == 'tag' }} test: # Cancels all previous runs of this particular job for the same branch that have not yet completed. From cd617bf50c0bbd45106b546f1eb856b43faa5122 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 20 Nov 2024 03:11:10 +0100 Subject: [PATCH 165/192] Ruleset::expandSniffDirectory(): add test --- .../Core/Ruleset/ExpandSniffDirectoryTest.php | 78 +++++++++++++++++++ .../Core/Ruleset/ExpandSniffDirectoryTest.xml | 8 ++ .../.hidden/HiddenDirShouldBeIgnoredSniff.php | 15 ++++ .../src/MyStandard/AbstractSniff.php | 12 +++ .../src/MyStandard/DummySniff.php | 25 ++++++ .../.hidden/HiddenDirShouldBeIgnoredSniff.php | 15 ++++ .../src/MyStandard/Sniffs/AbstractSniff.php | 12 +++ .../Sniffs/CategoryA/.HiddenFileSniff.php | 12 +++ .../CategoryA/.hidden/DoNotFindMeSniff.txt | 0 .../.hidden/HiddenDirShouldBeIgnoredSniff.php | 15 ++++ .../Sniffs/CategoryA/DoNotFindMeSniff.txt | 12 +++ .../Sniffs/CategoryA/FindMeSniff.php | 12 +++ .../CategoryA/IncorrectFileExtensionSniff.inc | 12 +++ .../Sniffs/CategoryA/MissingSniffSuffix.php | 12 +++ .../IncorrectLevelShouldStillBeFoundSniff.php | 12 +++ .../Sniffs/CategoryB/AnotherAbstractSniff.php | 12 +++ .../Sniffs/CategoryB/FindMeSniff.php | 12 +++ .../IncorrectFileExtensionSniff.php3 | 12 +++ .../IncorrectLevelShouldStillBeFoundSniff.php | 12 +++ .../MyStandard/Utils/NotInSniffsDirSniff.php | 12 +++ .../Utils/SubDir/NotInSniffsDirSniff.php | 12 +++ .../.hiddenAbove/src/MyStandard/ruleset.xml | 4 + 22 files changed, 328 insertions(+) create mode 100644 tests/Core/Ruleset/ExpandSniffDirectoryTest.php create mode 100644 tests/Core/Ruleset/ExpandSniffDirectoryTest.xml create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/AbstractSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/DummySniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/.hidden/HiddenDirShouldBeIgnoredSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/AbstractSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/.HiddenFileSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/.hidden/DoNotFindMeSniff.txt create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/.hidden/HiddenDirShouldBeIgnoredSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/DoNotFindMeSniff.txt create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/FindMeSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/IncorrectFileExtensionSniff.inc create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/MissingSniffSuffix.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryA/Subdir/IncorrectLevelShouldStillBeFoundSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/AnotherAbstractSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/FindMeSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/IncorrectFileExtensionSniff.php3 create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/IncorrectLevelShouldStillBeFoundSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/NotInSniffsDirSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/SubDir/NotInSniffsDirSniff.php create mode 100644 tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/ruleset.xml diff --git a/tests/Core/Ruleset/ExpandSniffDirectoryTest.php b/tests/Core/Ruleset/ExpandSniffDirectoryTest.php new file mode 100644 index 0000000000..8f7f4f93f6 --- /dev/null +++ b/tests/Core/Ruleset/ExpandSniffDirectoryTest.php @@ -0,0 +1,78 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::expandSniffDirectory() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandSniffDirectory + */ +final class ExpandSniffDirectoryTest extends TestCase +{ + + + /** + * Test finding sniff files based on a given directory. + * + * This test verifies that: + * - Hidden (sub)directories are ignored, but the given directory is allowed to be within a hidden directory. + * - Hidden files are ignored. + * - Files without a "php" extension are ignored. + * - Files without a "Sniff" suffix in the file name are ignored. + * + * Note: the "[Another]AbstractSniff" files will be found and included in the return value + * from `Ruleset::expandSniffDirectory()`. + * Those are filtered out later in the `Ruleset::registerSniffs()` method. + * + * @return void + */ + public function testExpandSniffDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandSniffDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expectedPathToRuleset = __DIR__.'/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/ruleset.xml'; + $expectedPathToRuleset = realpath($expectedPathToRuleset); + $this->assertNotFalse($expectedPathToRuleset, 'Ruleset file could not be found'); + $this->assertContains($expectedPathToRuleset, $ruleset->paths, 'Ruleset file not included in the "seen ruleset paths"'); + + /* + * Take note: the expectation includes some "undesirables" related to the convoluted directory structure + * in the "standard" used as a test fixture. + * + * That is okay as (for now) non-standard directory layouts are supported. + * + * This test is not about the standard directory layout. + */ + + $expectedSniffCodes = [ + '.Sniffs.IncorrectLevelShouldStillBeFound' => 'MyStandard\\Sniffs\\IncorrectLevelShouldStillBeFoundSniff', + 'MyStandard.CategoryA.FindMe' => 'MyStandard\\Sniffs\\CategoryA\\FindMeSniff', + 'MyStandard.CategoryB.FindMe' => 'MyStandard\\Sniffs\\CategoryB\\FindMeSniff', + 'Sniffs.SubDir.IncorrectLevelShouldStillBeFound' => 'MyStandard\\Sniffs\\CategoryA\\SubDir\\IncorrectLevelShouldStillBeFoundSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation'); + + }//end testExpandSniffDirectory() + + +}//end class diff --git a/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml b/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml new file mode 100644 index 0000000000..f2646da02a --- /dev/null +++ b/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php b/tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php new file mode 100644 index 0000000000..3ee64dbba6 --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/.hidden/HiddenDirShouldBeIgnoredSniff.php @@ -0,0 +1,15 @@ + + + + From 48c5e81c546413bc150ee30317a2b0ad95d60cc7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 18 Nov 2024 20:57:53 +0100 Subject: [PATCH 166/192] Ruleset::setSniffProperty(): add test for edge case / unused sniff I haven't been able to come up with a _real_ situation in which [this condition](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/15db7232015d4fc1e023ef1eff0e65777a906f2c/src/Ruleset.php#L1476-L1479) could result in an early return - either via reading an XML ruleset or via inline `phpcs:set` annotation. Having said that, the method is `public` and is regularly used in test frameworks for external standards, so this code should remain in place. This commit now safeguards the behaviour via a test. --- tests/Core/Ruleset/SetSniffPropertyTest.php | 33 +++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/Core/Ruleset/SetSniffPropertyTest.php b/tests/Core/Ruleset/SetSniffPropertyTest.php index ed902b9084..b974844c0c 100644 --- a/tests/Core/Ruleset/SetSniffPropertyTest.php +++ b/tests/Core/Ruleset/SetSniffPropertyTest.php @@ -202,6 +202,39 @@ public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCateg }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory() + /** + * Test that attempting to set a property for a sniff which isn't registered will be ignored. + * + * @return void + */ + public function testDirectCallIgnoredPropertyForUnusedSniff() + { + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Formatting\\SpaceAfterCastSniff'; + + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + $ruleset = new Ruleset($config); + + $ruleset->setSniffProperty( + $sniffClass, + 'ignoreNewlines', + [ + 'scope' => 'sniff', + 'value' => true, + ] + ); + + // Verify that there are sniffs registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has NOT been registered after attempting to set the property. + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, 'Unused sniff was registered in sniffCodes, but shouldn\'t have been'); + $this->assertArrayNotHasKey($sniffClass, $ruleset->sniffs, 'Unused sniff was registered in sniffs, but shouldn\'t have been'); + + }//end testDirectCallIgnoredPropertyForUnusedSniff() + + /** * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method * sets the property correctly when using the new $settings array format. From a0ef0325f3e80ba1025565ce176472d585b38bc3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 20 Nov 2024 01:42:14 +0100 Subject: [PATCH 167/192] Ruleset::processRuleset(); add various tests for things not already covered Mostly testing error handling and the handling of edge cases. --- .../Fixtures/InvalidNoSniffsDir/Sniffs | 0 .../Fixtures/InvalidNoSniffsDir/ruleset.xml | 4 + ...ssRulesetAutoExpandSniffsDirectoryTest.xml | 8 + .../ProcessRulesetExcludeSniffGroupTest.xml | 11 + .../ProcessRulesetInvalidNoSniffsDirTest.xml | 10 + tests/Core/Ruleset/ProcessRulesetMiscTest.xml | 25 ++ tests/Core/Ruleset/ProcessRulesetTest.php | 263 ++++++++++++++++++ 7 files changed, 321 insertions(+) create mode 100644 tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs create mode 100644 tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetMiscTest.xml create mode 100644 tests/Core/Ruleset/ProcessRulesetTest.php diff --git a/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs b/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml b/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml new file mode 100644 index 0000000000..b85e7486e8 --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml b/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml new file mode 100644 index 0000000000..6968808664 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml b/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml new file mode 100644 index 0000000000..a83347ce8d --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml b/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml new file mode 100644 index 0000000000..daa07f2e2a --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetMiscTest.xml b/tests/Core/Ruleset/ProcessRulesetMiscTest.xml new file mode 100644 index 0000000000..56bf689818 --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetMiscTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Core/Ruleset/ProcessRulesetTest.php b/tests/Core/Ruleset/ProcessRulesetTest.php new file mode 100644 index 0000000000..d53889a88c --- /dev/null +++ b/tests/Core/Ruleset/ProcessRulesetTest.php @@ -0,0 +1,263 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test various aspects of the Ruleset::processRuleset() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetTest extends TestCase +{ + + + /** + * Verify that a registered standard which doesn't have a "Sniffs" directory, but does have a file + * called "Sniffs" doesn't result in any errors being thrown. + * + * @return void + */ + public function testSniffsFileNotDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetInvalidNoSniffsDirTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testSniffsFileNotDirectory() + + + /** + * Verify that all sniffs in a registered standard included in a ruleset automatically get added. + * + * @return void + */ + public function testAutoExpandSniffsDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoExpandSniffsDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $std = 'TestStandard'; + $sniffDir = 'Fixtures\TestStandard\Sniffs'; + $expected = [ + "$std.Deprecated.WithLongReplacement" => "$sniffDir\Deprecated\WithLongReplacementSniff", + "$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff", + "$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff", + "$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff", + "$std.Deprecated.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff", + "$std.DeprecatedInvalid.EmptyDeprecationVersion" => "$sniffDir\DeprecatedInvalid\EmptyDeprecationVersionSniff", + "$std.DeprecatedInvalid.EmptyRemovalVersion" => "$sniffDir\DeprecatedInvalid\EmptyRemovalVersionSniff", + "$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff", + "$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff", + "$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff", + "$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff", + "$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff", + "$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff", + "$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff", + "$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff", + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testAutoExpandSniffsDirectory() + + + /** + * Verify handling of exclusions of groups of sniffs after inclusion via an even larger "group". + * + * @return void + */ + public function testExcludeSniffGroup() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetExcludeSniffGroupTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'PSR1.Classes.ClassDeclaration' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', + 'PSR1.Methods.CamelCapsMethodName' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testExcludeSniffGroup() + + + /* + * No test for without "name" as there is nothing we can assert to verify it's being ignored. + */ + + + /** + * Test that an `` directive without a "value" attribute will be set to the ini equivalent of `true`. + * + * @return void + */ + public function testIniWithoutValue() + { + $originalValue = ini_get('user_agent'); + + // Set up the ruleset. + $this->getMiscRuleset(); + + $actualValue = ini_get('user_agent'); + // Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state. + if ($originalValue !== false) { + ini_set('user_agent', $originalValue); + } + + $this->assertSame('1', $actualValue); + + }//end testIniWithoutValue() + + + /** + * Verify that inclusion of a single error code: + * - Includes the sniff, but sets "severity" for the sniff to 0; + * - Sets "severity" for the specific error code included to 5.; + * + * @return void + */ + public function testIncludeSingleErrorCode() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'Generic.PHP.RequireStrictTypes'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testIncludeSingleErrorCode() + + + /** + * Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional + * error code from that same sniff will be respected. + * + * @return void + */ + public function testErrorCodeIncludeAfterExclude() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'PEAR.Files.IncludingFile'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.UseRequire'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testErrorCodeIncludeAfterExclude() + + + /** + * Verify that a element without a "ref" is completely ignored. + * + * @return void + */ + public function testRuleWithoutRefIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleWithoutRefIsIgnored() + + + /** + * Verify that no "ruleset adjustments" are registered via an `` without a "name". + * + * @return void + */ + public function testRuleExcludeWithoutNameIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.PHP.BacktickOperator'; + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + $sniffCode = 'Generic.PHP.BacktickOperator.Found'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleExcludeWithoutNameIsIgnored() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getMiscRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetMiscTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getMiscRuleset() + + +}//end class From 856219c8b4c512f36224019bdd97b3488ef26030 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 25 Jun 2024 15:32:54 -0300 Subject: [PATCH 168/192] Squiz/ArrayDeclaration: improves test coverage This commit adds tests that were previously missing. There are still some uncovered lines in this sniff, those lines might be unreachable, but I did not investigate this at this time. There is also potentially some more relevant tests that could be added for lines that are already covered. This is also not addressed in this commit. --- .../Tests/Arrays/ArrayDeclarationUnitTest.1.inc | 13 ++++++++++++- .../Arrays/ArrayDeclarationUnitTest.1.inc.fixed | 10 ++++++++++ .../Tests/Arrays/ArrayDeclarationUnitTest.2.inc | 11 +++++++++++ .../Arrays/ArrayDeclarationUnitTest.2.inc.fixed | 10 ++++++++++ .../Tests/Arrays/ArrayDeclarationUnitTest.3.inc | 7 +++++++ .../Squiz/Tests/Arrays/ArrayDeclarationUnitTest.php | 4 ++++ 6 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc index cdbfff6c33..6a25ab9072 100644 --- a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc @@ -19,7 +19,7 @@ class TestClass 'height' => '', ); - private $_bad = Array( + private $_bad = ARRAY( 'width' => '', 'height' => '' ); @@ -547,3 +547,14 @@ $x = array( 1, static::helloWorld(), $class instanceof static, 2, ); + +$noSpaceBeforeDoubleArrow = array( + 'width'=> '', + 'height' => '', + ); + +$newlineAfterDoubleArrow = array( + 'width' => + '', + 'height' => '', + ); diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed index 6f8fe216a3..048f898c8d 100644 --- a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed @@ -586,3 +586,13 @@ $x = array( $class instanceof static, 2, ); + +$noSpaceBeforeDoubleArrow = array( + 'width' => '', + 'height' => '', + ); + +$newlineAfterDoubleArrow = array( + 'width' => '', + 'height' => '', + ); diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc index 90b026f023..f5f4c84234 100644 --- a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc @@ -536,3 +536,14 @@ $x = [ 1, static::helloWorld(), $class instanceof static, 2, ]; + +$noSpaceBeforeDoubleArrow = [ + 'width'=> '', + 'height' => '', + ]; + +$newlineAfterDoubleArrow = [ + 'width' => + '', + 'height' => '', + ]; diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed index 533be16a65..6ef97d6434 100644 --- a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed @@ -573,3 +573,13 @@ $x = [ $class instanceof static, 2, ]; + +$noSpaceBeforeDoubleArrow = [ + 'width' => '', + 'height' => '', + ]; + +$newlineAfterDoubleArrow = [ + 'width' => '', + 'height' => '', + ]; diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc new file mode 100644 index 0000000000..beb5ae1aec --- /dev/null +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc @@ -0,0 +1,7 @@ + 1, 540 => 1, 547 => 2, + 552 => 1, + 557 => 1, ]; case 'ArrayDeclarationUnitTest.2.inc': return [ @@ -229,6 +231,8 @@ public function getErrorList($testFile='') 526 => 1, 529 => 1, 536 => 2, + 541 => 1, + 546 => 1, ]; default: return []; From 8e0074ace15f690f20b46c37be3ef9dfb94f4008 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 20 Nov 2024 12:05:58 -0300 Subject: [PATCH 169/192] Squiz/ArrayDeclaration: improve handling of short lists inside a foreach This commit improves how the `Squiz.Arrays.ArrayDeclaration` sniff handles short lists inside a foreach and fixes a false positive. See https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527 --- .../Sniffs/Arrays/ArrayDeclarationSniff.php | 20 +++++++++++++++++++ .../Arrays/ArrayDeclarationUnitTest.2.inc | 6 ++++++ .../ArrayDeclarationUnitTest.2.inc.fixed | 6 ++++++ .../Arrays/ArrayDeclarationUnitTest.4.inc | 8 ++++++++ .../ArrayDeclarationUnitTest.4.inc.fixed | 8 ++++++++ .../Tests/Arrays/ArrayDeclarationUnitTest.php | 3 +++ 6 files changed, 51 insertions(+) create mode 100644 src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.4.inc create mode 100644 src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.4.inc.fixed diff --git a/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php b/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php index 89cd7bd57f..efad97e4b3 100644 --- a/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php +++ b/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php @@ -45,6 +45,26 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); + // Prevent acting on short lists inside a foreach (see + // https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527). + if ($tokens[$stackPtr]['code'] === T_OPEN_SHORT_ARRAY + && isset($tokens[$stackPtr]['nested_parenthesis']) === true + ) { + $nestedParens = $tokens[$stackPtr]['nested_parenthesis']; + $lastParenthesisCloser = end($nestedParens); + $lastParenthesisOpener = key($nestedParens); + + if (isset($tokens[$lastParenthesisCloser]['parenthesis_owner']) === true + && $tokens[$tokens[$lastParenthesisCloser]['parenthesis_owner']]['code'] === T_FOREACH + ) { + $asKeyword = $phpcsFile->findNext(T_AS, ($lastParenthesisOpener + 1), $lastParenthesisCloser); + + if ($asKeyword !== false && $asKeyword < $stackPtr) { + return; + } + } + } + if ($tokens[$stackPtr]['code'] === T_ARRAY) { $phpcsFile->recordMetric($stackPtr, 'Short array syntax used', 'no'); diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc index f5f4c84234..415042d89e 100644 --- a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc @@ -547,3 +547,9 @@ $newlineAfterDoubleArrow = [ '', 'height' => '', ]; + +// Sniff should ignore short lists when inside a foreach. +// https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527 +foreach ($data as [, , $value]) {} +foreach ($array as $k => [$v1, , $v3]) {} +foreach ([$a ,$b] as $c) {} // Not a short list. Sniff should handle it. diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed index 6ef97d6434..d835064ba1 100644 --- a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed @@ -583,3 +583,9 @@ $newlineAfterDoubleArrow = [ 'width' => '', 'height' => '', ]; + +// Sniff should ignore short lists when inside a foreach. +// https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527 +foreach ($data as [, , $value]) {} +foreach ($array as $k => [$v1, , $v3]) {} +foreach ([$a, $b] as $c) {} // Not a short list. Sniff should handle it. diff --git a/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.4.inc b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.4.inc new file mode 100644 index 0000000000..9d87a6e7fe --- /dev/null +++ b/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.4.inc @@ -0,0 +1,8 @@ + 2, 541 => 1, 546 => 1, + 555 => 2, ]; + case 'ArrayDeclarationUnitTest.4.inc': + return [8 => 1]; default: return []; }//end switch From 21dc8739143a4a5f3344e03a9f68310e20fd3c0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 05:56:48 +0000 Subject: [PATCH 170/192] GH Actions: Bump actions/attest-build-provenance from 1 to 2 Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 1 to 2. - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/v1...v2) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/reusable-build-phar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-build-phar.yml b/.github/workflows/reusable-build-phar.yml index bac53d77ee..3b42a20056 100644 --- a/.github/workflows/reusable-build-phar.yml +++ b/.github/workflows/reusable-build-phar.yml @@ -48,7 +48,7 @@ jobs: # Provide provenance for generated binaries. - name: Generate artifact attestations if: ${{ inputs.createAttestations == true }} - uses: actions/attest-build-provenance@v1 + uses: actions/attest-build-provenance@v2 with: subject-path: | ${{ github.workspace }}/phpcs.phar From 50216b19d064b1671b322f8b4ee2dd923d72bd4f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 9 Dec 2024 14:40:52 -0300 Subject: [PATCH 171/192] Generic/NestingLevel: ensure the sniff bails if `scope_closer` is not set Quoting @jrfnl: "Only checking for the scope_opener, when accessing/using both the scope_opener and scope_closer indexes, is probably fine in practical terms. However, the part of the code base which sets these indexes is not sufficiently covered by tests, nor does it document that those indexes will only be set if both can be set, so there may be edge case exceptions" (#684 (comment)). The sniff was already working fine before this change. Checking if `scope_closer` is just an extra precaution to err on the side of caution. This commit also updates the related code comment to better reflect what the if condition does. --- src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php b/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php index 3c086c7fe4..d2672b5eeb 100644 --- a/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php +++ b/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php @@ -56,8 +56,8 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - // Ignore abstract methods. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { + // Ignore abstract and interface methods. Bail early when live coding. + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { return; } From c1c85177660cb3dc97b81a767cf7bf6435680e72 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 19 Nov 2024 11:23:35 -0300 Subject: [PATCH 172/192] Generic/NestingLevel: rename test case file Doing this to be able to create tests with syntax errors on separate files. --- ...nitTest.inc => NestingLevelUnitTest.1.inc} | 0 .../Tests/Metrics/NestingLevelUnitTest.php | 28 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) rename src/Standards/Generic/Tests/Metrics/{NestingLevelUnitTest.inc => NestingLevelUnitTest.1.inc} (100%) diff --git a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.inc b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc similarity index 100% rename from src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.inc rename to src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc diff --git a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.php b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.php index fda8d461c7..c26ca45692 100644 --- a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.php +++ b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.php @@ -26,11 +26,18 @@ final class NestingLevelUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [73 => 1]; + switch ($testFile) { + case 'NestingLevelUnitTest.1.inc': + return [73 => 1]; + default: + return []; + } }//end getErrorList() @@ -41,14 +48,21 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 27 => 1, - 46 => 1, - ]; + switch ($testFile) { + case 'NestingLevelUnitTest.1.inc': + return [ + 27 => 1, + 46 => 1, + ]; + default: + return []; + } }//end getWarningList() From 9794ed89907fae02a4164839b3ee7109e82a86d7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 9 Dec 2024 14:50:56 -0300 Subject: [PATCH 173/192] Generic/NestingLevel: improve code coverage --- .../Generic/Tests/Metrics/NestingLevelUnitTest.1.inc | 8 +++++++- .../Generic/Tests/Metrics/NestingLevelUnitTest.2.inc | 7 +++++++ .../Generic/Tests/Metrics/NestingLevelUnitTest.3.inc | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc create mode 100644 src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.3.inc diff --git a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc index 9708792418..5f8c1b1dcb 100644 --- a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc +++ b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc @@ -99,4 +99,10 @@ function nestingEleven() } } -?> +abstract class AbstractClass { + abstract public function sniffShouldIgnoreAbstractMethods(); +} + +interface MyInterface { + public function sniffShouldIgnoreInterfaceMethods(); +} diff --git a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc new file mode 100644 index 0000000000..9658af3005 --- /dev/null +++ b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc @@ -0,0 +1,7 @@ + Date: Mon, 9 Dec 2024 16:33:02 -0300 Subject: [PATCH 174/192] Generic/NestingLevel: improve tests by adding more tokens This commit improves the tests by adding more tokens that increase the nesting level and are already considered by the sniff, but were not being used in the tests. --- .../Tests/Metrics/NestingLevelUnitTest.1.inc | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc index 5f8c1b1dcb..3f1dd92617 100644 --- a/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc +++ b/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc @@ -27,16 +27,16 @@ function nestingFive() function nestingSix() { if ($condition) { - echo 'hi'; - switch ($condition) - { + } else { + switch ($condition) { case '1': if ($condition === '1') { - if ($cond) { + } elseif ($condition === '2') { + do { foreach ($conds as $cond) { echo 'hi'; } - } + } while ($cond > 5); } break; } @@ -79,19 +79,19 @@ function nestingEleven() case '1': if ($condition === '1') { if ($cond) { - switch ($cond) { - case '1': - if ($cond === '1') { - foreach ($conds as $cond) { - if ($cond === 'hi') { - if ($cond !== 'bye') { - echo 'hi'; - } + try { + if ( $cond === '1' ) { + for ( $i = 0; $i < 10; $i ++ ) { + while ($i < 5) { + if ( $cond === 'hi' ) { + match ( $cond ) { + 'hi' => 'something', + }; } } } - break; - } + } + } catch (Exception $e) {} } } break; From 9bb88c4069594fa005bd50d9fd7cffc6645d13c4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 8 Dec 2024 20:57:34 +0100 Subject: [PATCH 175/192] GH Actions: automate release verification steps While the actual releasing can not be fully automated (due to security concerns related to signing releases in a GHA workflow), there are a number of verification checks which are part of the release workflow, which _can_ be automated. These checks were previously done as manual spot-checks. With the new workflow, they will now be executed structurally and automatically whenever a release is published on GitHub. The checks which are automated via this workflow are as follows: * For the PHAR files which can be downloaded from the GH "releases" page, the (unversioned) PHAR files published on the GH Pages website and the versioned PHAR files published on the GH Pages website for Phive (but which can also be downloaded manually), the following checks will now be run automatically: - Is the PHAR file available and can it be downloaded ? - Is the ASC (detached signature) file available and can it be downloaded ? - Verify the PHAR file via the attestation (which was created when the PHAR was created for a tag). - Verify the PHAR file is GPG signed and the signature matches. - Verify the PHAR file is functional (simple command runs without problems). - Verify the version with which the PHAR file identifies itself is the expected version. * For Phive: - Install via Phive. This will automatically also check the PHAR file is signed and the signature matches. - Verify the Phive installed PHAR file via the attestation. - Verify the Phive installed PHAR file is functional (simple command runs without problems). - Verify the version with which the PHAR file identifies itself is the expected version. Note: these checks will only run for releases from this repo. If a fork of the repo would publish their own releases, the workflow would fail anyhow (as the releases wouldn't be published to the website, nor accessible via Phive), so may as well prevent the workflow from running altogether. --- .github/workflows/verify-release.yml | 203 +++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 .github/workflows/verify-release.yml diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml new file mode 100644 index 0000000000..99f611526a --- /dev/null +++ b/.github/workflows/verify-release.yml @@ -0,0 +1,203 @@ +name: Verify release + +on: + # Run whenever a release is published. + release: + types: [published] + # And whenever this workflow is updated. + push: + paths: + - '.github/workflows/verify-release.yml' + pull_request: + paths: + - '.github/workflows/verify-release.yml' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + ################################################################################## + # Verify the release is available in all the right places and works as expected. # + ################################################################################## + verify-available-downloads: + runs-on: ubuntu-latest + + # Only run this workflow in the context of this repo. + if: github.repository_owner == 'PHPCSStandards' + + strategy: + fail-fast: false + matrix: + download_flavour: + - "Release assets" + - "Unversioned web" + - "Versioned web" + pharfile: + - 'phpcs' + - 'phpcbf' + + name: "${{ matrix.download_flavour }}: ${{ matrix.pharfile }}" + + steps: + - name: Retrieve latest release info + uses: octokit/request-action@v2.x + id: get_latest_release + with: + route: GET /repos/PHPCSStandards/PHP_CodeSniffer/releases/latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "DEBUG: Show API request failure status" + if: ${{ failure() }} + run: "echo No release found. Request failed with status ${{ steps.get_latest_release.outputs.status }}" + + - name: Grab latest tag name from API response + id: version + run: | + echo "TAG=${{ fromJson(steps.get_latest_release.outputs.data).tag_name }}" >> "$GITHUB_OUTPUT" + + - name: "DEBUG: Show tag name found in API response" + run: "echo ${{ steps.version.outputs.TAG }}" + + - name: Set source URL and file name + id: source + shell: bash + run: | + if [[ "${{ matrix.download_flavour }}" == "Release assets" ]]; then + echo 'SRC=https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/latest/download/' >> "$GITHUB_OUTPUT" + echo "FILE=${{ matrix.pharfile }}.phar" >> "$GITHUB_OUTPUT" + elif [[ "${{ matrix.download_flavour }}" == "Unversioned web" ]]; then + echo 'SRC=https://phars.phpcodesniffer.com/' >> "$GITHUB_OUTPUT" + echo "FILE=${{ matrix.pharfile }}.phar" >> "$GITHUB_OUTPUT" + else + echo 'SRC=https://phars.phpcodesniffer.com/phars/' >> "$GITHUB_OUTPUT" + echo "FILE=${{ matrix.pharfile }}-${{ steps.version.outputs.TAG }}.phar" >> "$GITHUB_OUTPUT" + fi + + - name: Verify PHAR file is available and download + run: "wget -O ${{ steps.source.outputs.FILE }} ${{ steps.source.outputs.SRC }}${{ steps.source.outputs.FILE }}" + + - name: Verify signature file is available and download + run: "wget -O ${{ steps.source.outputs.FILE }}.asc ${{ steps.source.outputs.SRC }}${{ steps.source.outputs.FILE }}.asc" + + - name: "DEBUG: List files" + run: ls -Rlh + + - name: Verify attestation of the PHAR file + run: gh attestation verify ${{ steps.source.outputs.FILE }} -o PHPCSStandards + env: + GH_TOKEN: ${{ github.token }} + + - name: Download public key + env: + FINGERPRINT: "0x689DAD778FF08760E046228BA978220305CD5C32" + run: gpg --keyserver "hkps://keys.openpgp.org" --recv-keys "$FINGERPRINT" + + - name: Verify signature of the PHAR file + run: gpg --verify ${{ steps.source.outputs.FILE }}.asc ${{ steps.source.outputs.FILE }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 'latest' + ini-values: error_reporting=-1, display_errors=On + coverage: none + + # Note: the `.` is in the command to make it work for both PHPCS as well PHPCBF. + - name: Verify the PHAR is nominally functional + run: php ${{ steps.source.outputs.FILE }} . -e --standard=PSR12 + + - name: Grab the version + id: asset_version + env: + FILE_NAME: ${{ steps.source.outputs.FILE }} + # yamllint disable-line rule:line-length + run: echo "VERSION=$(php "$FILE_NAME" --version | grep --only-matching --max-count=1 --extended-regexp '\b[0-9]+(\.[0-9]+)+')" >> "$GITHUB_OUTPUT" + + - name: "DEBUG: Show grabbed version" + run: echo ${{ steps.asset_version.outputs.VERSION }} + + - name: Fail the build if the PHAR is not the correct version + if: ${{ steps.asset_version.outputs.VERSION != steps.version.outputs.TAG }} + run: exit 1 + + # ######################################### + # Verify install via PHIVE. + # ######################################### + verify-phive: + runs-on: ubuntu-latest + + # Only run this workflow in the context of this repo. + if: github.repository_owner == 'PHPCSStandards' + + strategy: + fail-fast: false + matrix: + pharfile: + - 'phpcs' + - 'phpcbf' + + name: "PHIVE: ${{ matrix.pharfile }}" + + steps: + - name: Retrieve latest release info + uses: octokit/request-action@v2.x + id: get_latest_release + with: + route: GET /repos/PHPCSStandards/PHP_CodeSniffer/releases/latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "DEBUG: Show API request failure status" + if: ${{ failure() }} + run: "echo No release found. Request failed with status ${{ steps.get_latest_release.outputs.status }}" + + - name: Grab latest tag name from API response + id: version + run: | + echo "TAG=${{ fromJson(steps.get_latest_release.outputs.data).tag_name }}" >> "$GITHUB_OUTPUT" + + - name: "DEBUG: Show tag name found in API response" + run: "echo ${{ steps.version.outputs.TAG }}" + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 'latest' + ini-values: error_reporting=-1, display_errors=On + coverage: none + tools: phive + + - name: Install + run: phive install ${{ matrix.pharfile }} --copy --trust-gpg-keys 689DAD778FF08760E046228BA978220305CD5C32 + + - name: "DEBUG: List files" + run: ls -R + + - name: Verify attestation of the PHAR file + run: gh attestation verify ./tools/${{ matrix.pharfile }} -o PHPCSStandards + env: + GH_TOKEN: ${{ github.token }} + + # Note: the `.` is in the command to make it work for both PHPCS as well PHPCBF. + - name: Verify the PHAR is nominally functional + run: php ./tools/${{ matrix.pharfile }} . -e --standard=PSR12 + + - name: Grab the version + id: asset_version + env: + FILE_NAME: ./tools/${{ matrix.pharfile }} + # yamllint disable-line rule:line-length + run: echo "VERSION=$(php "$FILE_NAME" --version | grep --only-matching --max-count=1 --extended-regexp '\b[0-9]+(\.[0-9]+)+')" >> "$GITHUB_OUTPUT" + + - name: "DEBUG: Show grabbed version" + run: echo ${{ steps.asset_version.outputs.VERSION }} + + - name: Fail the build if the PHAR is not the correct version + if: ${{ steps.asset_version.outputs.VERSION != steps.version.outputs.TAG }} + run: exit 1 From 224a57f7cea0bb5ead5edcb429dc725edd806cdb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 8 Dec 2024 21:11:52 +0100 Subject: [PATCH 176/192] Add release checklist I've been using and fine-tuning this release checklist over the past year. As part of the efforts to document the processes and policies for this repo, I'm now publishing the checklist for transparency and to make this knowledge transferable. Note: some of the steps which this list previously included in my local copy have now been automated via the "verify-release" GH Actions workflow. These steps have been removed from this checklist. Fixes 32 --- .github/release-checklist.md | 126 +++++++++++++++++++++++++++++++++++ .remarkrc | 3 +- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 .github/release-checklist.md diff --git a/.github/release-checklist.md b/.github/release-checklist.md new file mode 100644 index 0000000000..a57baeb50a --- /dev/null +++ b/.github/release-checklist.md @@ -0,0 +1,126 @@ +# Release checklist + +## Before Release + +### General + +- [ ] Verify, and if necessary, update the version constraints for dependencies in the `composer.json` - PR #xxx +- [ ] Verify that any new functions have type declarations (ClassName/array/callable) whenever possible. +- [ ] Verify that the license tags all refer to the _new_ organisation and no longer to Squizlabs. (easily overlooked in new files) +- [ ] Verify that `@copyright` tags in new files use `@copyright 20xx PHPCSStandards and contributors`. + +### Wiki + +- [ ] Fetch changes and check against vandalism. +- [ ] Verify that any new `public` properties are listed on the Customizable Properties page in the Wiki. +- [ ] Verify that any new sniffs which have `public` properties are listed on the Customizable Properties page in the Wiki. +- [ ] Verify that any new CLI options are listed in the Wiki. +- [ ] Verify that any new Reports have a section in the Reports page in the Wiki. + +### Majors only + +- [ ] Move old changelog entries to `CHANGELOG_OLD.md` file. +- [ ] Verify that everything deprecated during the previous major was removed. +- [ ] Update the wiki for any references to anything deprecated/removed. +- [ ] Change `Config::STABILITY` from "dev" to "stable" for the branch for the new major. - PR #xxx + +### Prepare changelog + +- [ ] Prepare changelog for the release and submit the PR. - PR #xxx + - Based on the tickets in the milestone. + - Double-check that any issues which were closed by PRs included in the release, have the milestone set. + - Compare with auto-generated release notes to ensure nothing is missed. + - :pencil2: Remember to add a release link at the bottom! +- [ ] Prepare extra sections for the GH release notes. + - Use "New contributors" list from the auto-generated notes. + - Use the milestone to gather the stats. + - Add sponsor link. + - Remove square brackets from all ticket links or make them proper full links (as GH markdown parser doesn't parse these correctly). + - Change all contributor links to full inline links (as GH markdown parser on the Releases page doesn't parse these correctly). + ```md +--- + +### New Contributors + +The PHP_CodeSniffer project is happy to welcome the following new contributors: +@...., @.... + +### Statistics + +**Closed**: # issues +**Merged**: ## pull requests + +If you like to stay informed about releases and more, follow [@phpcs on Mastodon](https://phpc.social/@phpcs) or [@PHP_CodeSniffer on X](https://x.com/PHP_CodeSniffer). + +Please consider [funding the PHP_CodeSniffer project](https://opencollective.com/php_codesniffer). If you already do so: thank you! + ``` + +### Milestone + +- [ ] Close the milestone +- [ ] Open a new milestone for the next release +- [ ] If any open PRs/issues which were milestoned for this release did not make it into the release, update their milestone. + + +## Release + +- [ ] Merge the changelog PR. + For now, cherrypick the changelog to the 4.0 branch. +- [ ] Make sure all CI builds for `master` are green. +- [ ] Create a tag for the release & push it. +- [ ] Make sure all CI builds are green. +- [ ] Download the PHAR files from the GH Actions test build page. +- [ ] Sign the PHAR files using: + ```bash + gpg -u my@email.com --detach-sign --output phpcs.phar.asc phpcs.phar + gpg -u my@email.com --detach-sign --output phpcbf.phar.asc phpcbf.phar + gpg -u my@email.com --detach-sign --output phpcs-x.x.x.phar.asc phpcs-x.x.x.phar + gpg -u my@email.com --detach-sign --output phpcbf-x.x.x.phar.asc phpcbf-x.x.x.phar + ``` + - If, for whatever reason, the key is no longer available or has expired: + -> generate a new key following the steps here: . + -> upload the new key following the steps here: . + -> update the key information in the README x 3. + -> update the key info in the verify-release GHA workflow. +- [ ] Get the SHA of the files for the phive.xml file + ```bash + # Linux + sha256sum ./phpcs-x.x.x.phar + sha256sum ./phpcbf-x.x.x.phar + + # Windows + certutil -hashfile ./phpcs-x.x.x.phar SHA256 + certutil -hashfile ./phpcbf-x.x.x.phar SHA256 + ``` +- Update the `gh-pages` branch: + - [ ] Add the new release to the `phive.xml` file. + - [ ] Add the versioned PHAR files + keys in PHAR dir. + - [ ] Add the unversioned PHAR files + keys in root dir. + - [ ] Verify the attestations of the PHAR files. + ```bash + gh attestation verify phpcs.phar -o PHPCSStandards + gh attestation verify phpcbf.phar -o PHPCSStandards + gh attestation verify phars/phpcs-x.x.x.phar -o PHPCSStandards + gh attestation verify phars/phpcbf-x.x.x.phar -o PHPCSStandards + ``` + - [ ] Commit & push the changes. + - [ ] Verify that the website regenerated correctly and that the phars can be downloaded. +- [ ] Create a release & copy & paste the changelog to it. + - [ ] Upload the unversioned PHAR files + asc files to the release. + - [ ] Announce the release in the discussions forum by checking the checkbox at the bottom of the release page. +- [ ] Make sure all CI builds are green, including the verify-release workflow. + + +## After Release + +- [ ] Update the version number in the `Config::VERSION` class constant in the `src/Config.php` file to the _next_ (patch) version. + This can always be adjusted again later if needs be if it is decided that the next version will be a minor/major, but at least for dev + it should clearly show that this is bleeding edge/unreleased. +- [ ] Close release announcement in the "Discussions" for previous minors (leave the announcements related to the current minor open). + + +### Publicize + +- [ ] Post on Mastodon about the release (official account). +- [ ] Post on X about the release (official account). +- [ ] Post on LinkedIn (personal account). diff --git a/.remarkrc b/.remarkrc index 038f7b6287..9c6cbc7b2b 100644 --- a/.remarkrc +++ b/.remarkrc @@ -13,7 +13,8 @@ { "skipUrlPatterns": [ "^https?://github\\.com/PHPCSStandards/PHP_CodeSniffer/compare/[0-9\\.]+?\\.{3}[0-9\\.]+", - "^https?://github\\.com/[A-Za-z0-9-]+" + "^https?://github\\.com/[A-Za-z0-9-]+", + "^https?://x\\.com/PHP_CodeSniffer" ] } ], From 644fc294d76540049f569cb8174f958d4c1c3c39 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 16 Nov 2024 13:05:28 +0100 Subject: [PATCH 177/192] Changelog for the 3.11.2 release For release this Wednesday (or earlier). --- CHANGELOG.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a4ba6aedf..4f05515907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,61 @@ The file documents changes to the PHP_CodeSniffer project. _Nothing yet._ +## [3.11.2] - 2024-12-11 + +### Changed +- Generators/HTML + Markdown: the output will now be empty (no page header/footer) when there are no docs to display. [#687] + - This is in line with the Text Generator which already didn't produce output if there are no docs. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Generators/HTML: only display a Table of Contents when there is more than one sniff with documentation. [#697] + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Generators/HTML: improved handling of line breaks in `` blocks. [#723] + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Generators/Markdown: improved compatibility with the variety of available markdown parsers. [#722] + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Generators/Markdown: improved handling of line breaks in `` blocks. [#737] + - This prevents additional paragraphs from being displayed as code blocks. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Generic.NamingConventions.UpperCaseConstantName: the exact token containing the non-uppercase constant name will now be identified with more accuracy. [#665] + - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch. +- Generic.Functions.OpeningFunctionBraceKernighanRitchie: minor improvement to the error message wording. [#736] + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Various housekeeping, including improvements to the tests and documentation. + - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions. + +### Fixed +- Fixed bug [#527] : Squiz.Arrays.ArrayDeclaration: short lists within a foreach condition should be ignored. + - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch. +- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positives and false negatives when code uses unconventional spacing and comments when calling `define()`. + - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch. +- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positive when a constant named `DEFINE` is encountered. + - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch. +- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positive for attribute class called `define`. + - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch. +- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positive when handling the instantiation of a class named `define`. + - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch. +- Fixed bug [#688] : Generators/Markdown could leave error_reporting in an incorrect state. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Fixed bug [#698] : Generators/Markdown : link in the documentation footer would not parse as a link. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Fixed bug [#738] : Generators/Text: stray blank lines after code sample titles. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. +- Fixed bug [#739] : Generators/HTML + Markdown: multi-space whitespace within a code sample title was folded into a single space. + - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. + +[#527]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527 +[#665]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/665 +[#687]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/687 +[#688]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/688 +[#697]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/697 +[#698]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/698 +[#722]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/722 +[#723]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/723 +[#736]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/736 +[#737]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/737 +[#738]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/738 +[#739]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/739 + ## [3.11.1] - 2024-11-16 ### Changed @@ -337,7 +392,7 @@ _Nothing yet._ - Squiz.WhiteSpace.MemberVarSpacing - Squiz.WhiteSpace.ScopeClosingBrace - Squiz.WhiteSpace.SuperfluousWhitespace - - Thanks to [Jay McPartland][@jonmcp] and [Rodrigo Primo][@rodrigoprimo] for the patches. + - Thanks to [Jay McPartland][@jaymcp] and [Rodrigo Primo][@rodrigoprimo] for the patches. ### Changed - The following sniffs have received performance related improvements: @@ -350,7 +405,7 @@ _Nothing yet._ - External standards with sniff tests using the PHP_CodeSniffer native test framework will also benefit from these changes. - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch. - Various housekeeping, including improvements to the tests and documentation. - - Thanks to [Jay McPartland][@jonmcp], [João Pedro Oliveira][@jpoliveira08], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions. + - Thanks to [Jay McPartland][@jaymcp], [João Pedro Oliveira][@jpoliveira08], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions. ### Fixed - Fixed bug [#289] : Squiz.WhiteSpace.OperatorSpacing and PSR12.Operators.OperatorSpacing : improved fixer conflict protection by more strenuously avoiding handling operators in declare statements. @@ -7152,6 +7207,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo --> [Unreleased]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/master...HEAD +[3.11.2]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.1...3.11.2 [3.11.1]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.0...3.11.1 [3.11.0]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.3...3.11.0 [3.10.3]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.2...3.10.3 @@ -7350,6 +7406,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo [@ivuorinen]: https://github.com/ivuorinen [@jasonmccreary]: https://github.com/jasonmccreary [@javer]: https://github.com/javer +[@jaymcp]: https://github.com/jaymcp [@JDGrimes]: https://github.com/JDGrimes [@jedgell]: https://github.com/jedgell [@jeffslofish]: https://github.com/jeffslofish @@ -7360,7 +7417,6 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo [@johanderuijter]: https://github.com/johanderuijter [@johnmaguire]: https://github.com/johnmaguire [@johnpbloch]: https://github.com/johnpbloch -[@jonmcp]: https://github.com/jonmcp [@JorisDebonnet]: https://github.com/JorisDebonnet [@josephzidell]: https://github.com/josephzidell [@joshdavis11]: https://github.com/joshdavis11 From 855f26176ae5bb2681c797a6cc22fa0124e06d90 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 11 Dec 2024 18:17:42 +0100 Subject: [PATCH 178/192] Config: update version nr to next --- src/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Config.php b/src/Config.php index dda15a5553..2bcc78e6ec 100644 --- a/src/Config.php +++ b/src/Config.php @@ -85,7 +85,7 @@ class Config * * @var string */ - const VERSION = '3.11.2'; + const VERSION = '3.11.3'; /** * Package stability; either stable, beta or alpha. From 98a0c4e47afc1d442700cce8b69f2edc30ceff9a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 12 Dec 2024 09:04:31 +0100 Subject: [PATCH 179/192] GH Actions/verify-release: show output for release attestations Apparently, by default, the GH CLI doesn't show any output when run from a GH Actions step. This can be confusing and it makes debugging the workflow harder as, in case of failure, it is unclear what the step failed on. The `GH_FORCE_TTY` environment variable (set to any value) should enable the normal output for the GH CLI command, which should fix this. Refs: * https://github.com/cli/cli/issues/10047 * https://cli.github.com/manual/gh_help_environment --- .github/workflows/verify-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml index 99f611526a..7dcfac8fda 100644 --- a/.github/workflows/verify-release.yml +++ b/.github/workflows/verify-release.yml @@ -92,6 +92,7 @@ jobs: run: gh attestation verify ${{ steps.source.outputs.FILE }} -o PHPCSStandards env: GH_TOKEN: ${{ github.token }} + GH_FORCE_TTY: true - name: Download public key env: @@ -183,6 +184,7 @@ jobs: run: gh attestation verify ./tools/${{ matrix.pharfile }} -o PHPCSStandards env: GH_TOKEN: ${{ github.token }} + GH_FORCE_TTY: true # Note: the `.` is in the command to make it work for both PHPCS as well PHPCBF. - name: Verify the PHAR is nominally functional From d7ecf7e051f125021447a1e5716739fa196ea9a2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 20 Nov 2024 08:43:16 +0100 Subject: [PATCH 180/192] Ruleset::registerSniffs(): add tests --- tests/Core/Ruleset/RegisterSniffsTest.php | 293 ++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 tests/Core/Ruleset/RegisterSniffsTest.php diff --git a/tests/Core/Ruleset/RegisterSniffsTest.php b/tests/Core/Ruleset/RegisterSniffsTest.php new file mode 100644 index 0000000000..706d6b8b5b --- /dev/null +++ b/tests/Core/Ruleset/RegisterSniffsTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::registerSniffs() method. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + /** + * Original value of the $sniffs property on the Ruleset. + * + * @var array + */ + private static $originalSniffs = []; + + /** + * List of Standards dir relative sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffFiles = [ + 'Generic/Sniffs/Files/ByteOrderMarkSniff.php', + 'Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic/Sniffs/PHP/DisallowAlternativePHPTagsSniff.php', + 'Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'PSR1/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR1/Sniffs/Files/SideEffectsSniff.php', + 'PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', + 'Squiz/Sniffs/Classes/ValidClassNameSniff.php', + ]; + + /** + * Absolute paths to the sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffAbsolutePaths = []; + + + /** + * Initialize the config and ruleset objects which will be used for some of these tests. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + self::$ruleset = new Ruleset($config); + + // Remember the original value of the Ruleset::$sniff property as the tests adjust it. + self::$originalSniffs = self::$ruleset->sniffs; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + ksort(self::$originalSniffs); + + // Update the sniff file list. + $standardsDir = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR; + $standardsDir .= 'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + + self::$psr1SniffAbsolutePaths = self::relativeToAbsoluteSniffFiles($standardsDir, self::$psr1SniffFiles); + + }//end initializeConfigAndRuleset() + + + /** + * Convert relative paths to absolute paths and ensure the paths use the correct OS-specific directory separator. + * + * @param string $baseDir Directory to which these paths are relative to. Including trailing slash. + * @param array $relativePaths Relative paths. + * + * @return array + */ + public static function relativeToAbsoluteSniffFiles($baseDir, $relativePaths) + { + $fileList = []; + foreach ($relativePaths as $sniffName) { + $sniffFile = str_replace('/', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = $baseDir.$sniffFile; + $fileList[] = $sniffFile; + } + + return $fileList; + + }//end relativeToAbsoluteSniffFiles() + + + /** + * Clear out the Ruleset::$sniffs property. + * + * @before + * + * @return void + */ + protected function clearOutSniffs() + { + // Clear out the Ruleset::$sniffs property. + self::$ruleset->sniffs = []; + + }//end clearOutSniffs() + + + /** + * Test that registering sniffs works as expected (simple base test case). + * + * @return void + */ + public function testRegisteredSniffsShouldBeTheSame() + { + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsShouldBeTheSame() + + + /** + * Test that if only specific sniffs are requested, only those are registered. + * + * {@internal Can't test this via the CLI arguments due to some code in the Ruleset class + * related to sniff tests.} + * + * @return void + */ + public function testRegisteredSniffsWithRestrictions() + { + $restrictions = [ + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'psr1\\sniffs\\files\\sideeffectssniff' => true, + 'psr1\\sniffs\\methods\\camelcapsmethodnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, []); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsWithRestrictions() + + + /** + * Test that sniffs excluded via the CLI are not registered. + * + * @return void + */ + public function testRegisteredSniffsWithExclusions() + { + // Set up the ruleset. + $args = [ + '--standard=PSR1', + '--exclude=PSR1.Classes.ClassDeclaration,PSR1.Files.SideEffects,PSR1.Methods.CamelCapsMethodName', + ]; + $config = new ConfigDouble($args); + $ruleset = new Ruleset($config); + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testRegisteredSniffsWithExclusions() + + + /** + * Test combining requesting specific sniffs and excluding a subset of those. + * + * @return void + */ + public function testRegisteredSniffsBothRestrictionsAndExclusions() + { + $restrictions = [ + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\php\\disallowshortopentagsniff' => true, + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + ]; + + $exclusions = [ + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, $exclusions); + + $this->assertEquals($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsBothRestrictionsAndExclusions() + + + /** + * Verify that abstract sniffs are filtered out and not registered. + * + * @return void + */ + public function testRegisterSniffsFiltersOutAbstractClasses() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/AbstractSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/AnotherAbstractSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisterSniffsFiltersOutAbstractClasses() + + + /** + * Test that sniff files not in a "/Sniffs/" directory are filtered out and not registered. + * + * @return void + */ + public function testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/NotInSniffsDirSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/SubDir/NotInSniffsDirSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + + +}//end class From d6bbff928ca3228e43e3755f797cbd128a6ccb77 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 24 Oct 2024 23:18:46 +0200 Subject: [PATCH 181/192] Tokenizer/PHP: add extra tests for DNF type tokenization Tests taken from https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/630#issuecomment-2418664762 Props michalbundyra --- tests/Core/Tokenizers/PHP/DNFTypesTest.inc | 44 ++++++++- tests/Core/Tokenizers/PHP/DNFTypesTest.php | 106 +++++++++++++++------ 2 files changed, 121 insertions(+), 29 deletions(-) diff --git a/tests/Core/Tokenizers/PHP/DNFTypesTest.inc b/tests/Core/Tokenizers/PHP/DNFTypesTest.inc index 5043ab7db5..cd27474eb2 100644 --- a/tests/Core/Tokenizers/PHP/DNFTypesTest.inc +++ b/tests/Core/Tokenizers/PHP/DNFTypesTest.inc @@ -13,6 +13,12 @@ $a = $var ? $something : CONST_C | ( CONST_A & CONST_B ); /* testParensNoOwnerInShortTernary */ $a = $var ?: ( CONST_A & CONST_B ); +/* testFnCallParensNoOwnerInTernaryA */ +$var1 ? \X\call8() : /* testFnCallParensNoOwnerInTernaryB */ \Y\call9(); + +/* testPFnCallarensNoOwnerInShortTernary */ +$var2 ?: \Z\call10(); + /* testParensOwnerFunctionAmpersandInDefaultValue */ function defaultValueLooksLikeDNF( mixed $param = (CONST_A&CONST_B) ) {} @@ -53,6 +59,20 @@ callMe(label: CONST_A | CONST_B); /* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */ callMe(label: CONST_A & CONST_B); +\Z1\call11( + /* testParensNoOwnerFunctionCallInNamedParam */ + param1: \Z2\call12(), + /* testParensOwnerArrowFunctionInNamedParam */ + param2: fn (): /* testDNFTypeArrowFnReturnInNamedParam */ int|(\Countable&\Iterable) + /* testParensNoOwnerFunctionCallInArrowFnReturn */ + => \Z3\call13(), + /* testParensOwnerClosureInNamedParam */ + param3: function (): /* testDNFTypeClosureReturnInNamedParam */ int|(\DateTime&\ArrayObject) { + /* testParensNoOwnerFunctionCallInClosureReturn */ + return \Z4\call14(); + }, +); + /* testSwitchControlStructureCondition */ switch (CONST_A | CONST_B) { /* testFunctionCallInSwitchCaseCondition */ @@ -70,17 +90,37 @@ switch (CONST_A | CONST_B) { /* testIfAlternativeSyntaxCondition */ if (true): /* testFunctionCallInIfBody */ - \B\call(); + \B\call(); /* testElseIfAlternativeSyntaxCondition */ elseif (10): /* testFunctionCallInElseIfBody */ - C\call(); + C\call(); +else: + /* testFunctionCallInElseBody */ + \C\call3(); endif; gotolabel: /* testFunctionCallInGotoBody */ \doSomething(); +/* testWhileAlternativeSyntaxCondition */ +while ($c3): + /* testFunctionCallInWhileBody */ + \D\call4(); +endwhile; + +/* testForAlternativeSyntaxCondition */ +for ($i = 0; $i < 10; $i++): + /* testFunctionCallInForBody */ + \F\call5(); +endfor; + +/* testForEachAlternativeSyntaxCondition */ +foreach ($array as $key => $value): + /* testFunctionCallInForeachBody */ + \G\call6(); +endforeach; /* * DNF parentheses. diff --git a/tests/Core/Tokenizers/PHP/DNFTypesTest.php b/tests/Core/Tokenizers/PHP/DNFTypesTest.php index 75e1b1dbdc..e72dd41596 100644 --- a/tests/Core/Tokenizers/PHP/DNFTypesTest.php +++ b/tests/Core/Tokenizers/PHP/DNFTypesTest.php @@ -113,6 +113,15 @@ public static function dataNormalParentheses() 'parens without owner in short ternary' => [ 'testMarker' => '/* testParensNoOwnerInShortTernary */', ], + 'parens without owner in ternary then (fn call in inline then)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryA */', + ], + 'parens without owner in ternary then (fn call in inline else)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryB */', + ], + 'parens without owner in short ternary (fn call)' => [ + 'testMarker' => '/* testPFnCallarensNoOwnerInShortTernary */', + ], 'parens with owner: function; & in default value' => [ 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', ], @@ -158,6 +167,69 @@ public static function dataNormalParentheses() 'parens without owner, function call, named param + bitwise and' => [ 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */', ], + 'parens without owner, function call in named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInNamedParam */', + ], + 'parens with owner: fn; in named param' => [ + 'testMarker' => '/* testParensOwnerArrowFunctionInNamedParam */', + ], + 'parens without owner, function call in named param arrow return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInArrowFnReturn */', + ], + 'parens with owner: closure; in named param' => [ + 'testMarker' => '/* testParensOwnerClosureInNamedParam */', + ], + 'parens without owner, function call, named param closure return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInClosureReturn */', + ], + 'parens with owner: switch condition' => [ + 'testMarker' => '/* testSwitchControlStructureCondition */', + ], + 'parens without owner in switch-case condition' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseCondition */', + ], + 'parens without owner in switch-case body' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseBody */', + ], + 'parens without owner in switch-default body' => [ + 'testMarker' => '/* testFunctionCallInSwitchDefaultBody */', + ], + 'parens with owner: if condition, alternative syntax' => [ + 'testMarker' => '/* testIfAlternativeSyntaxCondition */', + ], + 'parens without owner in if body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInIfBody */', + ], + 'parens with owner: elseif condition, alternative syntax' => [ + 'testMarker' => '/* testElseIfAlternativeSyntaxCondition */', + ], + 'parens without owner in elseif body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseIfBody */', + ], + 'parens without owner in else body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseBody */', + ], + 'parens without owner in goto body' => [ + 'testMarker' => '/* testFunctionCallInGotoBody */', + ], + 'parens with owner: while condition, alternative syntax' => [ + 'testMarker' => '/* testWhileAlternativeSyntaxCondition */', + ], + 'parens without owner in while body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInWhileBody */', + ], + 'parens with owner: for condition, alternative syntax' => [ + 'testMarker' => '/* testForAlternativeSyntaxCondition */', + ], + 'parens without owner in for body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForBody */', + ], + 'parens with owner: foreach condition, alternative syntax' => [ + 'testMarker' => '/* testForEachAlternativeSyntaxCondition */', + ], + 'parens without owner in foreach body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForeachBody */', + ], 'parens without owner in OO const default value' => [ 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', @@ -193,33 +265,6 @@ public static function dataNormalParentheses() 'parens without owner in arrow function return expression' => [ 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', ], - 'parens with owner: switch condition' => [ - 'testMarker' => '/* testSwitchControlStructureCondition */', - ], - 'parens without owner in switch-case condition' => [ - 'testMarker' => '/* testFunctionCallInSwitchCaseCondition */', - ], - 'parens without owner in switch-case body' => [ - 'testMarker' => '/* testFunctionCallInSwitchCaseBody */', - ], - 'parens without owner in switch-default body' => [ - 'testMarker' => '/* testFunctionCallInSwitchDefaultBody */', - ], - 'parens with owner: if condition, alternative syntax' => [ - 'testMarker' => '/* testIfAlternativeSyntaxCondition */', - ], - 'parens without owner in if body, alternative syntax' => [ - 'testMarker' => '/* testFunctionCallInIfBody */', - ], - 'parens with owner: elseif condition, alternative syntax' => [ - 'testMarker' => '/* testElseIfAlternativeSyntaxCondition */', - ], - 'parens without owner in elseif body, alternative syntax' => [ - 'testMarker' => '/* testFunctionCallInElseIfBody */', - ], - 'parens without owner in goto body' => [ - 'testMarker' => '/* testFunctionCallInGotoBody */', - ], ]; }//end dataNormalParentheses() @@ -340,6 +385,13 @@ public function testDNFTypeParentheses($testMarker) public static function dataDNFTypeParentheses() { return [ + 'arrow function return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeArrowFnReturnInNamedParam */', + ], + 'closure return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeClosureReturnInNamedParam */', + ], + 'OO const type: unqualified classes' => [ 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', ], From 3d14d004265ac6e38f3e161316cf51b7b4812414 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Thu, 12 Dec 2024 17:43:01 -0300 Subject: [PATCH 182/192] Config: add tests for the `--generator=` argument (#765) --- tests/Core/Config/GeneratorArgTest.php | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/Core/Config/GeneratorArgTest.php diff --git a/tests/Core/Config/GeneratorArgTest.php b/tests/Core/Config/GeneratorArgTest.php new file mode 100644 index 0000000000..f0b52db157 --- /dev/null +++ b/tests/Core/Config/GeneratorArgTest.php @@ -0,0 +1,79 @@ +assertSame($generatorName, $config->generator); + + }//end testGenerators() + + + /** + * Data provider for testGenerators(). + * + * @see self::testGenerators() + * + * @return array> + */ + public static function dataGeneratorNames() + { + return [ + ['Text'], + ['HTML'], + ['Markdown'], + ]; + + }//end dataGeneratorNames() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--generator=Text', + '--generator=HTML', + '--generator=InvalidGenerator', + ] + ); + + $this->assertSame('Text', $config->generator); + + }//end testOnlySetOnce() + + +}//end class From 142ad8efa14994d82947464e10c94319e61d0feb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 14 Dec 2024 12:23:14 +0100 Subject: [PATCH 183/192] Ruleset::__construct(): add tests --- .../Core/Ruleset/ConstructorNoSniffsTest.xml | 6 + tests/Core/Ruleset/ConstructorTest.php | 293 ++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 tests/Core/Ruleset/ConstructorNoSniffsTest.xml create mode 100644 tests/Core/Ruleset/ConstructorTest.php diff --git a/tests/Core/Ruleset/ConstructorNoSniffsTest.xml b/tests/Core/Ruleset/ConstructorNoSniffsTest.xml new file mode 100644 index 0000000000..77ae02580b --- /dev/null +++ b/tests/Core/Ruleset/ConstructorNoSniffsTest.xml @@ -0,0 +1,6 @@ + + + + . + + diff --git a/tests/Core/Ruleset/ConstructorTest.php b/tests/Core/Ruleset/ConstructorTest.php new file mode 100644 index 0000000000..a0b3ab3088 --- /dev/null +++ b/tests/Core/Ruleset/ConstructorTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Autoload; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::__construct() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::__construct + */ +final class ConstructorTest extends AbstractRulesetTestCase +{ + + + /** + * Test setting the ruleset name. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param string $expected The expected set ruleset name. + * + * @dataProvider dataHandlingStandardsPassedViaCLI + * + * @return void + */ + public function testHandlingStandardsPassedViaCLI($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->name); + + }//end testHandlingStandardsPassedViaCLI() + + + /** + * Data provider. + * + * @see testHandlingStandardsPassedViaCLI() + * + * @return array>> + */ + public static function dataHandlingStandardsPassedViaCLI() + { + return [ + 'Single standard passed' => [ + 'cliArgs' => ['--standard=PSR1'], + 'expected' => 'PSR1', + ], + 'Multiple standards passed' => [ + 'cliArgs' => ['--standard=PSR1,Zend'], + 'expected' => 'PSR1, Zend', + ], + 'Absolute path to standard directory passed' => [ + 'cliArgs' => [ + '--standard='.__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard', + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => 'TestStandard', + ], + ]; + + }//end dataHandlingStandardsPassedViaCLI() + + + /** + * Verify that standards are registered with the Autoloader. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param array $expected Minimum set of standards expected to be registered with the autoloader. + * + * @dataProvider dataStandardsAreRegisteredWithAutoloader + * + * @return void + */ + public function testStandardsAreRegisteredWithAutoloader($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + new Ruleset($config); + + $autoloadPaths = Autoload::getSearchPaths(); + + // Note: doing a full comparison of the Autoloader registered standards would make this test unstable + // as the `CodeSniffer.conf` of the user running the tests could interfer if they have additional + // external standards registered. + // Also note that `--runtime-set` is being used to set `installed_paths` to prevent making any changes to + // the `CodeSniffer.conf` file of the user running the tests. + foreach ($expected as $path => $namespacedStandardName) { + $this->assertArrayHasKey($path, $autoloadPaths, "Path $path has not been registered with the autoloader"); + $this->assertSame($namespacedStandardName, $autoloadPaths[$path], 'Expected (namespaced) standard name does not match'); + } + + }//end testStandardsAreRegisteredWithAutoloader() + + + /** + * Data provider. + * + * @see testStandardsAreRegisteredWithAutoloader() + * + * @return array>> + */ + public static function dataStandardsAreRegisteredWithAutoloader() + { + $basePath = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + $defaultPaths = [ + $basePath.'MySource' => 'MySource', + $basePath.'PEAR' => 'PEAR', + $basePath.'PSR1' => 'PSR1', + $basePath.'PSR12' => 'PSR12', + $basePath.'PSR2' => 'PSR2', + $basePath.'Squiz' => 'Squiz', + $basePath.'Zend' => 'Zend', + ]; + + $data = [ + 'Default standards' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--runtime-set installed_paths .', + ], + 'expected' => $defaultPaths, + ], + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'DirectoryExpansion'; + $extraInstalledPath .= DIRECTORY_SEPARATOR.'.hiddenAbove'.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'MyStandard'; + $data['Additional non-namespaced standard'] = [ + 'cliArgs' => [ + '--standard=MyStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'MyStandard']), + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard'; + $data['Additional namespaced standard'] = [ + 'cliArgs' => [ + '--standard=TestStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'Fixtures\TestStandard']), + ]; + + return $data; + + }//end dataStandardsAreRegisteredWithAutoloader() + + + /** + * Verify handling of sniff restrictions in combination with the caching setting. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param bool $cache Whether to turn the cache on or off. + * @param array $expected Sniffs which are expected to have been registered. + * + * @dataProvider dataCachingVersusRestrictions + * + * @return void + */ + public function testCachingVersusRestrictions($cliArgs, $cache, $expected) + { + $config = new ConfigDouble($cliArgs); + + // Overrule the cache setting (which is being ignored in the Config when the tests are running). + $config->cache = $cache; + + $ruleset = new Ruleset($config); + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testCachingVersusRestrictions() + + + /** + * Data provider. + * + * Note: the test cases only use `--exclude` to restrict, + * + * @see testCachingVersusRestrictions() + * + * @return array>> + */ + public static function dataCachingVersusRestrictions() + { + $completeSet = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + return [ + 'No restrictions, cache off' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => false, + 'expected' => $completeSet, + ], + 'Has exclusions, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ], + ], + 'Has sniff selection, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--sniffs=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + ], + ], + 'No restrictions, cache on' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => true, + 'expected' => $completeSet, + ], + 'Has exclusions, cache on' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowAlternativePHPTags,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects', + ], + 'cache' => true, + 'expected' => $completeSet, + ], + + /* + * "Has sniff selection, cache on" case cannot be tested due to the `Ruleset` class + * containing special handling of sniff selection when the tests are running. + */ + + ]; + + }//end dataCachingVersusRestrictions() + + + /** + * Test an exception is thrown when no sniffs have been registered via the ruleset. + * + * @return void + */ + public function testNoSniffsRegisteredException() + { + $standard = __DIR__.'/ConstructorNoSniffsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'No sniffs were registered'; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testNoSniffsRegisteredException() + + +}//end class From 46b9a59532e2e2b4be04b884e075feaf8c470f2f Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:28:17 +0100 Subject: [PATCH 184/192] Ruleset::populateTokenListeners(): add tests (#757) --- tests/Core/Ruleset/ExplainTest.php | 7 +- .../InvalidSniffs/RegisterNoArraySniff.php | 25 + .../ValidSniffs/RegisterEmptyArraySniff.php | 25 + ...ulateTokenListenersRegisterNoArrayTest.xml | 8 + .../Ruleset/PopulateTokenListenersTest.php | 548 ++++++++++++++++++ .../Ruleset/PopulateTokenListenersTest.xml | 45 ++ ...ssRulesetAutoExpandSniffsDirectoryTest.xml | 4 +- tests/Core/Ruleset/ProcessRulesetTest.php | 1 + .../Ruleset/ShowSniffDeprecationsTest.xml | 1 + 9 files changed, 660 insertions(+), 4 deletions(-) create mode 100644 tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffs/RegisterNoArraySniff.php create mode 100644 tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/ValidSniffs/RegisterEmptyArraySniff.php create mode 100644 tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml create mode 100644 tests/Core/Ruleset/PopulateTokenListenersTest.php create mode 100644 tests/Core/Ruleset/PopulateTokenListenersTest.xml diff --git a/tests/Core/Ruleset/ExplainTest.php b/tests/Core/Ruleset/ExplainTest.php index 48866cc345..a0da428c9a 100644 --- a/tests/Core/Ruleset/ExplainTest.php +++ b/tests/Core/Ruleset/ExplainTest.php @@ -185,9 +185,9 @@ public function testExplainWithDeprecatedSniffs() $ruleset = new Ruleset($config); $expected = PHP_EOL; - $expected .= 'The ShowSniffDeprecationsTest standard contains 10 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'The ShowSniffDeprecationsTest standard contains 11 sniffs'.PHP_EOL.PHP_EOL; - $expected .= 'TestStandard (10 sniffs)'.PHP_EOL; + $expected .= 'TestStandard (11 sniffs)'.PHP_EOL; $expected .= '------------------------'.PHP_EOL; $expected .= ' TestStandard.Deprecated.WithLongReplacement *'.PHP_EOL; $expected .= ' TestStandard.Deprecated.WithoutReplacement *'.PHP_EOL; @@ -198,7 +198,8 @@ public function testExplainWithDeprecatedSniffs() $expected .= ' TestStandard.SetProperty.AllowedViaMagicMethod'.PHP_EOL; $expected .= ' TestStandard.SetProperty.AllowedViaStdClass'.PHP_EOL; $expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL; - $expected .= ' TestStandard.SetProperty.PropertyTypeHandling'.PHP_EOL.PHP_EOL; + $expected .= ' TestStandard.SetProperty.PropertyTypeHandling'.PHP_EOL; + $expected .= ' TestStandard.ValidSniffs.RegisterEmptyArray'.PHP_EOL.PHP_EOL; $expected .= '* Sniffs marked with an asterix are deprecated.'.PHP_EOL; diff --git a/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffs/RegisterNoArraySniff.php b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffs/RegisterNoArraySniff.php new file mode 100644 index 0000000000..a77ac24fa5 --- /dev/null +++ b/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffs/RegisterNoArraySniff.php @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/tests/Core/Ruleset/PopulateTokenListenersTest.php b/tests/Core/Ruleset/PopulateTokenListenersTest.php new file mode 100644 index 0000000000..c0abfffd54 --- /dev/null +++ b/tests/Core/Ruleset/PopulateTokenListenersTest.php @@ -0,0 +1,548 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\Tokens; +use ReflectionObject; +use ReflectionProperty; + +/** + * Test the Ruleset::populateTokenListeners() method. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Test an exception is thrown when the register() method of a sniff doesn't return an array. + * + * @return void + */ + public function testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + { + $standard = __DIR__.'/PopulateTokenListenersRegisterNoArrayTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $sniffClass = 'Fixtures\\TestStandard\\Sniffs\\InvalidSniffs\\RegisterNoArraySniff'; + $message = "Sniff $sniffClass register() method must return an array"; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + + + /** + * Test that a sniff not registering any tokens is not listed as a listener. + * + * @return void + */ + public function testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + { + $target = 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + $this->assertArrayNotHasKey( + $target, + $listeners, + sprintf('Found the %s sniff registered for token %s', $target, Tokens::tokenName($token)) + ); + } + + }//end testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + + + /** + * Tests that sniffs registering tokens, will end up listening to these tokens. + * + * @param string $sniffClass The FQN for the sniff class to check. + * @param int $expectedCount Expected number of tokens to which the sniff should be listening. + * + * @dataProvider dataSniffListensToTokenss + * + * @return void + */ + public function testRegistersSniffsToListenToTokens($sniffClass, $expectedCount) + { + $counter = 0; + + foreach (self::$ruleset->tokenListeners as $listeners) { + if (isset($listeners[$sniffClass]) === true) { + ++$counter; + } + } + + $this->assertSame($expectedCount, $counter); + + }//end testRegistersSniffsToListenToTokens() + + + /** + * Data provider. + * + * @see testSniffListensToTokens() + * + * @return array> + */ + public static function dataSniffListensToTokenss() + { + return [ + 'Generic.Files.EndFileNewline' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\EndFileNewlineSniff', + 'expectedCount' => 2, + ], + 'Generic.NamingConventions.UpperCaseConstantName' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'expectedCount' => 2, + ], + 'PSR1.Files.SideEffects' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'expectedCount' => 1, + ], + 'PSR12.ControlStructures.BooleanOperatorPlacement' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'expectedCount' => 5, + ], + 'Squiz.ControlStructures.ForEachLoopDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'expectedCount' => 1, + ], + 'TestStandard.Deprecated.WithReplacement' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\Deprecated\\WithReplacementSniff', + 'expectedCount' => 1, + ], + 'TestStandard.ValidSniffs.RegisterEmptyArray' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'expectedCount' => 0, + ], + ]; + + }//end dataSniffListensToTokenss() + + + /** + * Test that deprecated sniffs get recognized and added to the $deprecatedSniffs list. + * + * @return void + */ + public function testRegistersWhenADeprecatedSniffIsLoaded() + { + $property = new ReflectionProperty(self::$ruleset, 'deprecatedSniffs'); + $property->setAccessible(true); + $actualValue = $property->getValue(self::$ruleset); + $property->setAccessible(false); + + // Only verify there is one deprecated sniff registered. + // There are other tests which test the deprecated sniff handling in more detail. + $this->assertTrue(is_array($actualValue)); + $this->assertCount(1, $actualValue); + + }//end testRegistersWhenADeprecatedSniffIsLoaded() + + + /** + * Verify that the setting of properties on a sniff was not triggered when there are no properties being set. + * + * @return void + */ + public function testDoesntTriggerPropertySettingForNoProperties() + { + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $reflection = new ReflectionObject($sniffObject); + + // Just making sure there are no properties on the sniff object (which doesn't have declared properties). + $this->assertSame([], $reflection->getProperties(), "Unexpected properties found on sniff class $sniffClass"); + + }//end testDoesntTriggerPropertySettingForNoProperties() + + + /** + * Verify that the setting of properties on a sniff was triggered. + * + * @param string $sniffClass The FQN for the sniff class on which the property should be set. + * @param string $propertyName The property name. + * @param string $expected The expected property value. + * + * @dataProvider dataTriggersPropertySettingWhenPropertiesProvided + * + * @return void + */ + public function testTriggersPropertySettingWhenPropertiesProvided($sniffClass, $propertyName, $expected) + { + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify the property has been set. + $this->assertSame($expected, $sniffObject->$propertyName, "Property on sniff class $sniffClass set to unexpected value"); + + }//end testTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Data provider. + * + * @see testTriggersPropertySettingWhenPropertiesProvided() + * + * @return array> + */ + public static function dataTriggersPropertySettingWhenPropertiesProvided() + { + return [ + 'Sniff with single property being set' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'propertyName' => 'allowOnly', + 'expected' => 'first', + ], + 'Sniff with multiple properties being set - first property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesAfterOpen', + 'expected' => '3', + ], + 'Sniff with multiple properties being set - second property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesBeforeClose', + 'expected' => '8', + ], + ]; + + }//end dataTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Verifies that the "class" and "source" indexes get set. + * + * @return void + */ + public function testSetsClassAndSourceIndexes() + { + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + $this->assertArrayHasKey( + 'class', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $className, + $details['class'], + sprintf('Unexpected value for "class" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertArrayHasKey( + 'source', + $details, + sprintf('"source" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertTrue( + is_string($details['source']), + sprintf('Value for "source" key is not a string for token %s', Tokens::tokenName($token)) + ); + + $expected = '.'.substr($className, (strrpos($className, '\\') + 1), -5); + + $this->assertStringEndsWith( + $expected, + $details['source'], + sprintf('Unexpected value for "source" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + }//end foreach + }//end foreach + + }//end testSetsClassAndSourceIndexes() + + + /** + * Verifies that sniffs by default are listening for PHP files only. + * + * @return void + */ + public function testSetsSupportedTokenizersToPHPByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\EndFileNewlineSniff'; + $expected = ['PHP' => 'PHP']; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'tokenizers', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + $details['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsSupportedTokenizersToPHPByDefault() + + + /** + * Test that if a sniff has the $supportedTokenizers property set, the tokenizers listed there + * will be registered in the listeners array. + * + * @param int $token The token constant for which the sniff should be registered. + * + * @dataProvider dataSetsSupportedTokenizersWhenProvidedBySniff + * + * @return void + */ + public function testSetsSupportedTokenizersWhenProvidedBySniff($token) + { + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\EndFileNewlineSniff'; + $expected = [ + 'PHP' => 'PHP', + 'JS' => 'JS', + 'CSS' => 'CSS', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + 'tokenizers', + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"tokenizers" key missing for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass]['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Data provider. + * + * @see testSetsSupportedTokenizersWhenProvidedBySniff() + * + * @return array> + */ + public static function dataSetsSupportedTokenizersWhenProvidedBySniff() + { + return [ + 'T_OPEN_TAG' => [T_OPEN_TAG], + 'T_OPEN_TAG_WITH_ECHO' => [T_OPEN_TAG_WITH_ECHO], + ]; + + }//end dataSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Verifies that by default no explicit include patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIncludePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'include', + $details, + sprintf('"include" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['include'], + sprintf('Unexpected value for "include" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIncludePatternsToEmptyArrayByDefault() + + + /** + * Verifies that by default no explicit ignore patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIgnorePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'ignore', + $details, + sprintf('"ignore" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['ignore'], + sprintf('Unexpected value for "ignore" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIgnorePatternsToEmptyArrayByDefault() + + + /** + * Tests that if there are <[include|exclude]-pattern> directives set on a sniff, these are set for the relevant listeners. + * + * Includes verification that the transformation of "regex"-like patterns is handled correctly. + * + * @param int|string $token A token constant on which the sniff should be registered. + * @param string $sniffClass The FQN for the sniff class on which the patterns should be registered. + * @param string $patternType The type of patterns expected to be registered for the sniff. + * + * @dataProvider dataSetsIncludeAndIgnorePatterns + * + * @return void + */ + public function testSetsIncludeAndIgnorePatterns($token, $sniffClass, $patternType) + { + $expected = [ + '/no-transformation/', + '/simple.*transformation/.*', + '/escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css', + '/pat?tern(is|regex)\\.php$', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $patternType, + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"%s" key missing for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass][$patternType], + sprintf('Unexpected value for "%s" key for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsIncludeAndIgnorePatterns() + + + /** + * Data provider. + * + * @see testSetsIncludeAndIgnorePatterns() + * + * @return array> + */ + public static function dataSetsIncludeAndIgnorePatterns() + { + return [ + 'Sniff with s in the ruleset - first token' => [ + 'token' => T_STRING, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset - second token' => [ + 'token' => T_CONST, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset' => [ + 'token' => T_OPEN_TAG, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'patternType' => 'ignore', + ], + ]; + + }//end dataSetsIncludeAndIgnorePatterns() + + +}//end class diff --git a/tests/Core/Ruleset/PopulateTokenListenersTest.xml b/tests/Core/Ruleset/PopulateTokenListenersTest.xml new file mode 100644 index 0000000000..f61ab500d0 --- /dev/null +++ b/tests/Core/Ruleset/PopulateTokenListenersTest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + diff --git a/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml b/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml index 6968808664..579b9485d2 100644 --- a/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml +++ b/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml @@ -3,6 +3,8 @@ - + + + diff --git a/tests/Core/Ruleset/ProcessRulesetTest.php b/tests/Core/Ruleset/ProcessRulesetTest.php index d53889a88c..c18173b476 100644 --- a/tests/Core/Ruleset/ProcessRulesetTest.php +++ b/tests/Core/Ruleset/ProcessRulesetTest.php @@ -72,6 +72,7 @@ public function testAutoExpandSniffsDirectory() "$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff", "$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff", "$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff", + "$std.ValidSniffs.RegisterEmptyArray" => "$sniffDir\ValidSniffs\RegisterEmptyArraySniff", ]; // Sort the value to make the tests stable as different OSes will read directories diff --git a/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml b/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml index 38c7e02221..802bd3c0a9 100644 --- a/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml +++ b/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml @@ -5,6 +5,7 @@ + From a9b6fa09169de4640a527e574d046dcf6ea4e6cb Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 4 Oct 2024 15:23:00 -0300 Subject: [PATCH 185/192] Generic/InlineControlStructure: stop listening for T_SWITCH tokens There is no inline version of a `switch` in PHP and JS so there is no reason for this sniff to listen to `T_SWITCH` tokens. Before this change, the sniff would bail early on the line below as a switch always has a scope opener, so this change should not impact in any way the behavior of the sniff. https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/9a0c2546ea2fa7aac19881da7b655cc5f022bc10/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php#L71 The InlineControlStructure sniff started listening for `T_SWITCH` tokens since the commit that added it to PHPCS: https://github.com/PHPCSStandards/PHP_CodeSniffer/commit/ad96eb#diff-e1ea4eabd79d6324057bbf726a27074250478f87d92c11a3725a97f0afbd5513R50 Some of the sniff tests using the `T_SWITCH` token were added to protect against regressions for changes in the tokenizer. For those, dedicated tokenizer tests will be created in subsequent commits. Those commits will also update the related sniff tests to use different control structures other than `T_SWITCH` when appropriate. The modified JS test lost part of its value over time as now the sniff bails early if there is no opening parenthesis after the control structure. Ideally, it should be moved to a tokenizer test, but since there are no tests for the JS tokenizer and support will be dropped in PHPCS 4.0, I opted to simply use a control structure other than T_SWITCH. This test was originally added in b3f4f83. References: - PHP: https://www.php.net/manual/en/control-structures.switch.php - JS: https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html --- .../Sniffs/ControlStructures/InlineControlStructureSniff.php | 1 - .../Tests/ControlStructures/InlineControlStructureUnitTest.1.js | 2 +- .../ControlStructures/InlineControlStructureUnitTest.1.js.fixed | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php b/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php index ff1738328f..1efb15c7be 100644 --- a/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php +++ b/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php @@ -48,7 +48,6 @@ public function register() T_FOREACH, T_WHILE, T_DO, - T_SWITCH, T_FOR, ]; diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js index ca6dae13a0..763c1c1c1c 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js @@ -20,7 +20,7 @@ do { do i++; while (i < 5); -SomeClass.prototype.switch = function() { +SomeClass.prototype.for = function() { // do something }; diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed index d410cfb122..050a406bba 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed @@ -26,7 +26,7 @@ do { do { i++; } while (i < 5); -SomeClass.prototype.switch = function() { +SomeClass.prototype.for = function() { // do something }; From 4c92408c42aef9a0d756a5ca6abdbcbea10595a5 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Wed, 22 May 2024 11:47:12 -0300 Subject: [PATCH 186/192] Tests/Tokenizer: tests to ensure scope is set correctly for T_SWITCH This commit copies, with some non-structural modifications, a sniff test to the tokenizer tests. The original test was added in b24b96b, part of https://github.com/squizlabs/PHP_CodeSniffer/issues/497. b24b96b introduced a test to InlineControlStructureUnitTest.php as there were no Tokenizer tests back then. It was added to ensure that Tokenizer::recurseScopeMap() would correctly add scope information to the `T_SWITCH` token when handling a `switch` that uses the alternative syntax. This commit also adds a test to ensure the scope is correctly set when using the normal switch syntax. This was not part of b24b96b, but it is relevant anyway, as no other tokenizer test covers this part. Since the InlineControlStructure sniff doesn't listen for the `T_SWITCH` token anymore (see baa4f65), the original test added in b24b96b became useless and thus was refactored to use a different control structure. The sniff test was kept as testing code that uses a control structure, and opening and closing PHP tags is an interesting case not covered in other tests. --- .../InlineControlStructureUnitTest.1.inc | 16 +-- ...InlineControlStructureUnitTest.1.inc.fixed | 16 +-- .../RecurseScopeMapSwitchTokenScopeTest.inc | 24 ++++ .../RecurseScopeMapSwitchTokenScopeTest.php | 113 ++++++++++++++++++ 4 files changed, 153 insertions(+), 16 deletions(-) create mode 100644 tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc create mode 100644 tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc index 739ba40a6d..11b4912153 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc @@ -79,14 +79,14 @@ if ($a) error): - case Shop_Customer :: ERROR_INVALID_GENDER: ?> - Ungültiges Geschlecht! - - Die eingetragene E-Mail-Adresse ist bereits registriert. - + Error one! + + Error two! +allowShopping !== true): if ($this->status != Shop_Cart :: OK): diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed index 9a89b0e387..7e2e628ae3 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed @@ -91,14 +91,14 @@ if ($a) { error): - case Shop_Customer :: ERROR_INVALID_GENDER: ?> - Ungültiges Geschlecht! - - Die eingetragene E-Mail-Adresse ist bereits registriert. - + Error one! + + Error two! +allowShopping !== true): if ($this->status != Shop_Cart :: OK): diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc new file mode 100644 index 0000000000..682e1f46ee --- /dev/null +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc @@ -0,0 +1,24 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapSwitchTokenScopeTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_SWITCH token (normal and alternative syntax). + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-b24b96b + * + * @dataProvider dataSwitchScope + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchScope($testMarker, $expectedTokens, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $switchIndex = $this->getTargetToken($testMarker, [T_SWITCH]); + $tokenArray = $tokens[$switchIndex]; + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $switchIndex; + $expectedScopeOpener = $this->getTargetToken($testMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_SWITCH, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testSwitchScope() + + + /** + * Data provider. + * + * @see testSwitchScope() + * + * @return array>> + */ + public static function dataSwitchScope() + { + return [ + 'switch normal syntax' => [ + 'testMarker' => '/* testSwitchNormalSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + ], + 'switch alternative syntax' => [ + 'testMarker' => '/* testSwitchAlternativeSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testCloserMarker' => '/* testSwitchAlternativeSyntaxEnd */', + ], + ]; + + }//end dataSwitchScope() + + +}//end class From b9809c7b16b686cea25de0d60e1d95fe6c7e17ae Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 26 Jul 2024 10:50:27 +0200 Subject: [PATCH 187/192] Tests/Tokenizer: tests for T_CASE and T_IF scope condition This commit copies, with some non-structural modifications, a sniff test to the tokenizer tests. Two new tokenizer tests are created as the result of this copy. One to ensure that the scope of `T_CASE` is correctly set when the case shares the scope closer with `T_SWITCH` (no `T_BREAK`). And another to ensure that the scope of `T_IF` is correctly set when there is a nested `T_SWITCH` and `T_CASE` without a `T_BREAK`. The original sniff test was added in fddc61a, which is part of https://github.com/squizlabs/PHP_CodeSniffer/issues/497. fddc61a introduced a test to InlineControlStructureUnitTest.php as there were no Tokenizer tests back then. The test was added to ensure that Tokenizer::recurseScopeMap() correctly adds scope information to the `T_CASE` token when it shares the closer with `T_SWITCH` and to `T_IF` when a nested `T_CASE` shares the scope closer with T_SWITCH`. Since the InlineControlStructure sniff doesn't listen for the `T_SWITCH` token anymore (see baa4f65), the original test added in fddc61a became useless and thus was refactored to use a different control structure. This new version of the sniff test was kept as testing code that uses nested alternative syntax control structures is still valid and is not covered in other tests. --- .../InlineControlStructureUnitTest.1.inc | 12 +-- ...InlineControlStructureUnitTest.1.inc.fixed | 12 +-- ...curseScopeMapCaseKeywordConditionsTest.inc | 7 ++ ...curseScopeMapCaseKeywordConditionsTest.php | 1 + ...RecurseScopeMapIfKeywordConditionsTest.inc | 13 ++++ ...RecurseScopeMapIfKeywordConditionsTest.php | 76 +++++++++++++++++++ 6 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc create mode 100644 tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.php diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc index 11b4912153..e662111322 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc @@ -88,17 +88,17 @@ if ($error === ERROR_ONE): ?> -if ($this->allowShopping !== true): - if ($this->status != Shop_Cart :: OK): - switch ($this->status): - case Shop_Cart :: NOT_FOUND: - echo 'foo'; - endswitch; +if ($value): + if ($anotherValue): + foreach ($array as $element): + echo (function($element): string { return $element; } )($element); + endforeach; endif; else: echo 'foo'; endif; + // ELSE IF split over multiple lines (not inline) if ($test) { } else diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed index 7e2e628ae3..00c9d664fe 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed @@ -100,17 +100,17 @@ if ($error === ERROR_ONE): ?> -if ($this->allowShopping !== true): - if ($this->status != Shop_Cart :: OK): - switch ($this->status): - case Shop_Cart :: NOT_FOUND: - echo 'foo'; - endswitch; +if ($value): + if ($anotherValue): + foreach ($array as $element): + echo (function($element): string { return $element; } )($element); + endforeach; endif; else: echo 'foo'; endif; + // ELSE IF split over multiple lines (not inline) if ($test) { } else diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc index 13b87242e1..54a017b3d7 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -93,3 +93,10 @@ enum Foo: string { /* testKeywordAsEnumCaseNameShouldBeString7 */ case ARRAY = 'array'; } + +// Test for https://github.com/squizlabs/PHP_CodeSniffer/issues/497 +switch ($value): + /* testSwitchCaseScopeCloserSharedWithSwitch */ + case 1: + echo 'one'; +endswitch; diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php index 7fa4ba5567..321d04fcb8 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -106,6 +106,7 @@ public static function dataNotEnumCases() 'switch case with constant, keyword in mixed case' => ['/* testIsNotEnumCaseIsCaseInsensitive */'], 'switch case, body in curlies declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], 'switch case, body after semicolon declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], + 'switch case, shared closer with switch' => ['/* testSwitchCaseScopeCloserSharedWithSwitch */'], ]; }//end dataNotEnumCases() diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc new file mode 100644 index 0000000000..e303c38500 --- /dev/null +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc @@ -0,0 +1,13 @@ + + * @author Rodrigo Primo + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapIfKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_IF token with nested case statement missing break statement. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-fddc61a + * + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIfElseWithNestedCaseMissingBreakSharedClosers() + { + + $tokens = $this->phpcsFile->getTokens(); + $ifTestMarker = '/* testIfElseWithNestedCaseMissingBreak */'; + $ifCloserTestMarker = '/* testIfElseWithNestedCaseMissingBreakCloser */'; + $ifTokenIndex = $this->getTargetToken($ifTestMarker, T_IF); + $tokenArray = $tokens[$ifTokenIndex]; + + $expectedScopeCondition = $ifTokenIndex; + $expectedScopeOpener = $this->getTargetToken($ifTestMarker, T_COLON); + $expectedScopeCloser = $this->getTargetToken($ifCloserTestMarker, T_ELSE); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_IF, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testIfElseWithNestedCaseMissingBreakSharedClosers() + + +}//end class From 954677560104cd596bab1e4fc16bea2f76f7dd2f Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 12 Aug 2024 19:25:18 -0300 Subject: [PATCH 188/192] Tests/Tokenizer: scope opener is set correctly for T_SWITCH This commit copies, with some modifications, a sniff test to the tokenizer tests. It ensures that the scope opener is set correctly for T_SWITCH when there is a closure in the condition. This safeguards against regressions related to 30c618e, which fixed https://github .com/squizlabs/PHP_CodeSniffer/issues/543. 30c618e originally added a test to InlineControlStructureUnitTest.php as there were no Tokenizer tests back then. Since the InlineControlStructure sniff doesn't listen for the `T_SWITCH` token anymore (see baa4f65), the original test added in 30c618e became useless and thus was refactored to use a different control structure. This new version of the sniff test was kept as testing code that uses a closure in the condition is still an interesting case and is not covered in other tests. --- .../InlineControlStructureUnitTest.1.inc | 14 +++++------ ...InlineControlStructureUnitTest.1.inc.fixed | 15 +++++------ .../InlineControlStructureUnitTest.php | 1 + .../RecurseScopeMapSwitchTokenScopeTest.inc | 9 +++++++ .../RecurseScopeMapSwitchTokenScopeTest.php | 25 ++++++++++++++++--- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc index e662111322..c7b2a939b6 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc @@ -106,15 +106,15 @@ if ($test) { } else { } -switch($response = \Bar::baz('bat', function ($foo) { +if ((function () { return 'bar'; -})) { - case 1: - return 'test'; +})()) + echo 'one'; + + + + - case 2: - return 'other'; -} $stuff = [1,2,3]; foreach($stuff as $num) diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed index 00c9d664fe..c6099f4a89 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed @@ -118,16 +118,17 @@ if ($test) { } else { } -switch($response = \Bar::baz('bat', function ($foo) { +if ((function () { return 'bar'; -})) { - case 1: - return 'test'; - - case 2: - return 'other'; +})()) { + echo 'one'; } + + + + + $stuff = [1,2,3]; foreach($stuff as $num) { if ($num %2 ) { diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php index afcaa3a335..19c78e0f96 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php @@ -48,6 +48,7 @@ public function getErrorList($testFile='') 62 => 1, 66 => 1, 78 => 1, + 109 => 1, 120 => 1, 128 => 1, 134 => 1, diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc index 682e1f46ee..71ef02897a 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc @@ -22,3 +22,12 @@ switch ($value): break; /* testSwitchAlternativeSyntaxEnd */ endswitch; + +// Test for https://github.com/squizlabs/PHP_CodeSniffer/issues/543 +/* testSwitchClosureWithinCondition */ +switch((function () { + return 'bar'; +})()) /* testSwitchClosureWithinConditionScopeOpener */ { + case 1: + return 'test'; +} diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php index e80f7f5134..0977c0365c 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php @@ -20,6 +20,8 @@ final class RecurseScopeMapSwitchTokenScopeTest extends AbstractTokenizerTestCas * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testOpenerMarker Optional. The comment which prefaces the scope opener if different + * from the test marker. * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different * from the test marker. * @@ -30,19 +32,24 @@ final class RecurseScopeMapSwitchTokenScopeTest extends AbstractTokenizerTestCas * * @return void */ - public function testSwitchScope($testMarker, $expectedTokens, $testCloserMarker=null) + public function testSwitchScope($testMarker, $expectedTokens, $testOpenerMarker=null, $testCloserMarker=null) { $tokens = $this->phpcsFile->getTokens(); $switchIndex = $this->getTargetToken($testMarker, [T_SWITCH]); $tokenArray = $tokens[$switchIndex]; + $scopeOpenerMarker = $testMarker; + if (isset($testOpenerMarker) === true) { + $scopeOpenerMarker = $testOpenerMarker; + } + $scopeCloserMarker = $testMarker; if (isset($testCloserMarker) === true) { $scopeCloserMarker = $testCloserMarker; } $expectedScopeCondition = $switchIndex; - $expectedScopeOpener = $this->getTargetToken($testMarker, $expectedTokens['scope_opener']); + $expectedScopeOpener = $this->getTargetToken($scopeOpenerMarker, $expectedTokens['scope_opener']); $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); @@ -90,21 +97,31 @@ public function testSwitchScope($testMarker, $expectedTokens, $testCloserMarker= public static function dataSwitchScope() { return [ - 'switch normal syntax' => [ + 'switch normal syntax' => [ 'testMarker' => '/* testSwitchNormalSyntax */', 'expectedTokens' => [ 'scope_opener' => T_OPEN_CURLY_BRACKET, 'scope_closer' => T_CLOSE_CURLY_BRACKET, ], ], - 'switch alternative syntax' => [ + 'switch alternative syntax' => [ 'testMarker' => '/* testSwitchAlternativeSyntax */', 'expectedTokens' => [ 'scope_opener' => T_COLON, 'scope_closer' => T_ENDSWITCH, ], + 'testOpenerMarker' => null, 'testCloserMarker' => '/* testSwitchAlternativeSyntaxEnd */', ], + 'switch with closure in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithinConditionScopeOpener */', + ], ]; }//end dataSwitchScope() From 82fae8e57e10f6a7000daf53910394d109064736 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 12 Aug 2024 17:02:22 -0300 Subject: [PATCH 189/192] Tests/Tokenizer: expand `recurseScopeMap()` tests for the case keyword This commit expands the existing `Tokenizer::recurseScopeMap()` tests for the `case` keyword when used in a switch statement to check the value of the `scope_condition`, `scope_opener` and `scope_closer` indexes besides checking if they are set. This is needed for a new test case that will be added in a subsequent commit. --- ...curseScopeMapCaseKeywordConditionsTest.inc | 3 + ...curseScopeMapCaseKeywordConditionsTest.php | 120 ++++++++++++++++-- 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc index 54a017b3d7..a4bb911997 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -62,6 +62,7 @@ switch (true) { case CONSTANT = 1: /* testIsNotEnumCaseIsCaseInsensitive */ cAsE CONSTANT: +/* testCaseConstantCloserMarker */ } switch ($x) { @@ -69,11 +70,13 @@ switch ($x) { case 'a': { enum Foo {} break; + /* testCaseInSwitchWhenCreatingEnumInSwitch1CloserMarker */ } /* testCaseInSwitchWhenCreatingEnumInSwitch2 */ case 'b'; enum Bar {} + /* testCaseInSwitchWhenCreatingEnumInSwitch2CloserMarker */ break; } diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php index 321d04fcb8..7144289147 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -66,25 +66,65 @@ public static function dataEnumCases() /** * Test that "case" that is not enum case is still tokenized as `T_CASE`. * - * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. * * @dataProvider dataNotEnumCases * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap * * @return void */ - public function testNotEnumCases($testMarker) + public function testNotEnumCases($testMarker, $expectedTokens, $testCloserMarker=null) { $tokens = $this->phpcsFile->getTokens(); - $case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); - $tokenArray = $tokens[$case]; + $caseIndex = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$caseIndex]; + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $caseIndex; + $expectedScopeOpener = $this->getTargetToken($testMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); // Make sure we're looking at the right token. $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_CASE, found %s.', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s.', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s.', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); }//end testNotEnumCases() @@ -94,19 +134,73 @@ public function testNotEnumCases($testMarker) * * @see testNotEnumCases() * - * @return array> + * @return array>> */ public static function dataNotEnumCases() { return [ - 'switch case with constant, semicolon condition end' => ['/* testCaseWithSemicolonIsNotEnumCase */'], - 'switch case with constant, colon condition end' => ['/* testCaseWithConstantIsNotEnumCase */'], - 'switch case with constant, comparison' => ['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'], - 'switch case with constant, assignment' => ['/* testCaseWithAssigmentToConstantIsNotEnumCase */'], - 'switch case with constant, keyword in mixed case' => ['/* testIsNotEnumCaseIsCaseInsensitive */'], - 'switch case, body in curlies declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], - 'switch case, body after semicolon declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], - 'switch case, shared closer with switch' => ['/* testSwitchCaseScopeCloserSharedWithSwitch */'], + 'switch case with constant, semicolon condition end' => [ + 'testMarker' => '/* testCaseWithSemicolonIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + ], + 'switch case with constant, colon condition end' => [ + 'testMarker' => '/* testCaseWithConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, comparison' => [ + 'testMarker' => '/* testCaseWithConstantAndIdenticalIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, assignment' => [ + 'testMarker' => '/* testCaseWithAssigmentToConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, keyword in mixed case' => [ + 'testMarker' => '/* testIsNotEnumCaseIsCaseInsensitive */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case, body in curlies declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1 */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1CloserMarker */', + ], + 'switch case, body after semicolon declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2 */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_BREAK, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2CloserMarker */', + ], + 'switch case, shared closer with switch' => [ + 'testMarker' => '/* testSwitchCaseScopeCloserSharedWithSwitch */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + ], ]; }//end dataNotEnumCases() From 61b9e9b4ec2af6471eb7e56c18b2da931245b88c Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 13 Aug 2024 11:15:55 -0300 Subject: [PATCH 190/192] Tests/Tokenizer: test to ensure scope closer is set correctly for T_CASE This commit copies a sniff test from InlineControlStructureUnitTest.php to the `Tokenizer::recurseScopeMap()` tests for the case keyword. This test was added in b498dbe before the Tokenizer tests were created. It ensures that the scope for the `T_CASE` token is correctly set when there is an if/elseif/else with and without braces inside it. Note that this test currently does not fail even when the changes to the tokenizer applied in b498dbe are reverted. I'm assuming that a subsequent commit further improved the tokenizer and made the changes from b498dbe redundant, but I was not able to find the specific commit using `git bissect`. That being said, I was able to confirm that before b498dbe, the scope closer for the `T_CASE` token was incorrectly set to `T_RETURN` instead of `T_BREAK`. The original sniff test was kept without any modification as testing if/elseif/else with and without curly braces inside another control structure is still valid. --- ...curseScopeMapCaseKeywordConditionsTest.inc | 14 +++++++++++ ...curseScopeMapCaseKeywordConditionsTest.php | 23 ++++++++++++------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc index a4bb911997..6c71d80db0 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -103,3 +103,17 @@ switch ($value): case 1: echo 'one'; endswitch; + +// Test for https://github.com/squizlabs/PHP_CodeSniffer/issues/879 +switch ($type) { + /* testSwitchCaseNestedIfWithAndWithoutBraces */ + case 1: + if ($foo) { + return true; + } elseif ($baz) + return true; + else { + echo 'else'; + } + break; +} diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php index 7144289147..8b651c6d43 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -139,14 +139,14 @@ public function testNotEnumCases($testMarker, $expectedTokens, $testCloserMarker public static function dataNotEnumCases() { return [ - 'switch case with constant, semicolon condition end' => [ + 'switch case with constant, semicolon condition end' => [ 'testMarker' => '/* testCaseWithSemicolonIsNotEnumCase */', 'expectedTokens' => [ 'scope_opener' => T_SEMICOLON, 'scope_closer' => T_CLOSE_CURLY_BRACKET, ], ], - 'switch case with constant, colon condition end' => [ + 'switch case with constant, colon condition end' => [ 'testMarker' => '/* testCaseWithConstantIsNotEnumCase */', 'expectedTokens' => [ 'scope_opener' => T_COLON, @@ -154,7 +154,7 @@ public static function dataNotEnumCases() ], 'testCloserMarker' => '/* testCaseConstantCloserMarker */', ], - 'switch case with constant, comparison' => [ + 'switch case with constant, comparison' => [ 'testMarker' => '/* testCaseWithConstantAndIdenticalIsNotEnumCase */', 'expectedTokens' => [ 'scope_opener' => T_COLON, @@ -162,7 +162,7 @@ public static function dataNotEnumCases() ], 'testCloserMarker' => '/* testCaseConstantCloserMarker */', ], - 'switch case with constant, assignment' => [ + 'switch case with constant, assignment' => [ 'testMarker' => '/* testCaseWithAssigmentToConstantIsNotEnumCase */', 'expectedTokens' => [ 'scope_opener' => T_COLON, @@ -170,7 +170,7 @@ public static function dataNotEnumCases() ], 'testCloserMarker' => '/* testCaseConstantCloserMarker */', ], - 'switch case with constant, keyword in mixed case' => [ + 'switch case with constant, keyword in mixed case' => [ 'testMarker' => '/* testIsNotEnumCaseIsCaseInsensitive */', 'expectedTokens' => [ 'scope_opener' => T_COLON, @@ -178,7 +178,7 @@ public static function dataNotEnumCases() ], 'testCloserMarker' => '/* testCaseConstantCloserMarker */', ], - 'switch case, body in curlies declares enum' => [ + 'switch case, body in curlies declares enum' => [ 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1 */', 'expectedTokens' => [ 'scope_opener' => T_OPEN_CURLY_BRACKET, @@ -186,7 +186,7 @@ public static function dataNotEnumCases() ], 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1CloserMarker */', ], - 'switch case, body after semicolon declares enum' => [ + 'switch case, body after semicolon declares enum' => [ 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2 */', 'expectedTokens' => [ 'scope_opener' => T_SEMICOLON, @@ -194,13 +194,20 @@ public static function dataNotEnumCases() ], 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2CloserMarker */', ], - 'switch case, shared closer with switch' => [ + 'switch case, shared closer with switch' => [ 'testMarker' => '/* testSwitchCaseScopeCloserSharedWithSwitch */', 'expectedTokens' => [ 'scope_opener' => T_COLON, 'scope_closer' => T_ENDSWITCH, ], ], + 'switch case, nested inline if/elseif/else with and without braces' => [ + 'testMarker' => '/* testSwitchCaseNestedIfWithAndWithoutBraces */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], ]; }//end dataNotEnumCases() From 105b4bec79443173d1a10a598614b1537cef42f7 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Mon, 12 Aug 2024 17:16:12 -0300 Subject: [PATCH 191/192] Tests/Tokenizer: test related to setting the scope for T_CASE This commit copies a sniff test from InlineControlStructureUnitTest.php to the Tokenizer::recurseScopeMap() tests for the `case` keyword. The copied test was added in 65ef053 before the Tokenizer tests were created. It ensures that the scope for the `T_CASE` token is correctly set when there is an inline control structure inside it with more than three lines. The original sniff test was modified to use `T_FOR` instead of `T_SWITCH`, but its purpose was not altered. The test is about adding braces to an `if` that returns a nested function call. --- .../InlineControlStructureUnitTest.1.inc | 20 +++++++++--------- ...InlineControlStructureUnitTest.1.inc.fixed | 21 ++++++++++--------- .../InlineControlStructureUnitTest.php | 3 ++- ...curseScopeMapCaseKeywordConditionsTest.inc | 13 ++++++++++++ ...curseScopeMapCaseKeywordConditionsTest.php | 7 +++++++ 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc index c7b2a939b6..ada26fb7ff 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc @@ -201,16 +201,16 @@ if (true) catch(Exception $e) { } -switch ($num) { - case 0: - if (1 > $num) - return bar( - baz( - "foobarbaz" - ) - ); - break; -} +for ($i = 0; $i <= 4; $i++) + if ($i % 2) + return bar( + baz( + "foobarbaz" + ) + ); + + + do { $i++; diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed index c6099f4a89..53c6f0952c 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed @@ -230,18 +230,19 @@ if (true) { } } -switch ($num) { - case 0: - if (1 > $num) { - return bar( - baz( - "foobarbaz" - ) - ); - } - break; +for ($i = 0; $i <= 4; $i++) { + if ($i % 2) { + return bar( + baz( + "foobarbaz" + ) + ); + } } + + + do { $i++; } diff --git a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php index 19c78e0f96..22eeb075cc 100644 --- a/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php +++ b/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php @@ -70,7 +70,8 @@ public function getErrorList($testFile='') 191 => 1, 195 => 1, 198 => 1, - 206 => 1, + 204 => 1, + 205 => 1, 222 => 1, 232 => 1, 235 => 1, diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc index 6c71d80db0..8df21a6c35 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -117,3 +117,16 @@ switch ($type) { } break; } + +// Test for https://github.com/squizlabs/PHP_CodeSniffer/issues/1590 +switch ($num) { + /* testSwitchCaseNestedInlineIfWithMoreThanThreeLines */ + case 0: + if (1 > $num) + return bar( + baz( + "foobarbaz" + ) + ); + break; +} diff --git a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php index 8b651c6d43..a4f3c3f089 100644 --- a/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php +++ b/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -208,6 +208,13 @@ public static function dataNotEnumCases() 'scope_closer' => T_BREAK, ], ], + 'switch case, nested inline if' => [ + 'testMarker' => '/* testSwitchCaseNestedInlineIfWithMoreThanThreeLines */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], ]; }//end dataNotEnumCases() From c06284d42e7b3a7bfbdd9b2161c594a92b4f9714 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Jan 2025 01:58:53 +0000 Subject: [PATCH 192/192] Squiz/FileComment: update year in test case fixed file --- .../Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed | 2 +- .../Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed b/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed index f584c55276..dbf8865458 100644 --- a/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed +++ b/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed @@ -25,7 +25,7 @@ * @author * @copyright 1997 Squiz Pty Ltd (ABN 77 084 670 600) * @copyright 1994-1997 Squiz Pty Ltd (ABN 77 084 670 600) -* @copyright 2024 Squiz Pty Ltd (ABN 77 084 670 600) +* @copyright 2025 Squiz Pty Ltd (ABN 77 084 670 600) * @license http://www.php.net/license/3_0.txt * @summary An unknown summary tag * diff --git a/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed b/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed index c7f54ffdf9..44ff449ac3 100644 --- a/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed +++ b/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed @@ -25,7 +25,7 @@ * @author * @copyright 1997 Squiz Pty Ltd (ABN 77 084 670 600) * @copyright 1994-1997 Squiz Pty Ltd (ABN 77 084 670 600) -* @copyright 2024 Squiz Pty Ltd (ABN 77 084 670 600) +* @copyright 2025 Squiz Pty Ltd (ABN 77 084 670 600) * @license http://www.php.net/license/3_0.txt * @summary An unknown summary tag *