From a37fd675864ff0280e446089bca96a34f091a708 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 15:04:50 +0100 Subject: [PATCH 1/3] Generators/Text: don't print title if there is no content This refactors the class to _retrieve_ the intended output, instead of echo-ing it out directly and validates whether it makes sense to print anything at all about a sniff before sending the output to screen. It deprecates the following methods, which will be removed in PHPCS 4.0: * `printTitle()` in favour of `getFormattedTitle()` * `printTextBlock()` in favour of `getFormattedTextBlock()` * `printCodeComparisonBlock()` in favour of `getFormattedCodeComparisonBlock()` --- src/Generators/Text.php | 125 ++++++++++++++---- .../ExpectedOutputStructureDocs.txt | 5 - ...edOutputUnsupportedElementAtWrongLevel.txt | 5 - ...xpectedOutputUnsupportedUnknownElement.txt | 5 - tests/Core/Generators/TextTest.php | 4 +- 5 files changed, 99 insertions(+), 45 deletions(-) delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt diff --git a/src/Generators/Text.php b/src/Generators/Text.php index e57556d08f..28606bdeb4 100644 --- a/src/Generators/Text.php +++ b/src/Generators/Text.php @@ -30,16 +30,19 @@ class Text extends Generator */ public function processSniff(DOMNode $doc) { - $this->printTitle($doc); - + $content = ''; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { - $this->printTextBlock($node); + $content .= $this->getFormattedTextBlock($node); } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); + $content .= $this->getFormattedCodeComparisonBlock($node); } } + if (trim($content) !== '') { + echo $this->getFormattedTitle($doc), $content; + } + }//end processSniff() @@ -50,22 +53,46 @@ public function processSniff(DOMNode $doc) * It represents the "documentation" tag in the XML * standard file. * + * @deprecated 3.12.0 Use Text::getFormattedTitle() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printTitle(DOMNode $doc) + { + echo $this->getFormattedTitle($doc); + + }//end printTitle() + + + /** + * Format the title area for a single sniff. + * + * @param \DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @since 3.12.0 Replaces the deprecated Text::printTitle() method. + * + * @return string + */ + protected function getFormattedTitle(DOMNode $doc) { $title = $this->getTitle($doc); $standard = $this->ruleset->name; $displayTitle = "$standard CODING STANDARD: $title"; $titleLength = strlen($displayTitle); - echo PHP_EOL; - echo str_repeat('-', ($titleLength + 4)); - echo strtoupper(PHP_EOL."| $displayTitle |".PHP_EOL); - echo str_repeat('-', ($titleLength + 4)); - echo PHP_EOL.PHP_EOL; + $output = PHP_EOL; + $output .= str_repeat('-', ($titleLength + 4)); + $output .= strtoupper(PHP_EOL."| $displayTitle |".PHP_EOL); + $output .= str_repeat('-', ($titleLength + 4)); + $output .= PHP_EOL.PHP_EOL; - }//end printTitle() + return $output; + + }//end getFormattedTitle() /** @@ -73,9 +100,29 @@ protected function printTitle(DOMNode $doc) * * @param \DOMNode $node The DOMNode object for the text block. * + * @deprecated 3.12.0 Use Text::getFormattedTextBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printTextBlock(DOMNode $node) + { + echo $this->getFormattedTextBlock($node); + + }//end printTextBlock() + + + /** + * Format a text block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the text block. + * + * @since 3.12.0 Replaces the deprecated Text::printTextBlock() method. + * + * @return string + */ + protected function getFormattedTextBlock(DOMNode $node) { $text = trim($node->nodeValue); $text = str_replace('', '*', $text); @@ -117,9 +164,9 @@ protected function printTextBlock(DOMNode $node) } }//end foreach - echo implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL; + return implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL; - }//end printTextBlock() + }//end getFormattedTextBlock() /** @@ -127,9 +174,29 @@ protected function printTextBlock(DOMNode $node) * * @param \DOMNode $node The DOMNode object for the code comparison block. * + * @deprecated 3.12.0 Use Text::getFormattedCodeComparisonBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printCodeComparisonBlock(DOMNode $node) + { + echo $this->getFormattedCodeComparisonBlock($node); + + }//end printCodeComparisonBlock() + + + /** + * Format a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @since 3.12.0 Replaces the deprecated Text::printCodeComparisonBlock() method. + * + * @return string + */ + protected function getFormattedCodeComparisonBlock(DOMNode $node) { $codeBlocks = $node->getElementsByTagName('code'); $first = trim($codeBlocks->item(0)->nodeValue); @@ -205,9 +272,9 @@ protected function printCodeComparisonBlock(DOMNode $node) $maxCodeLines = max(count($firstLines), count($secondLines)); $maxTitleLines = max(count($firstTitleLines), count($secondTitleLines)); - echo str_repeat('-', 41); - echo ' CODE COMPARISON '; - echo str_repeat('-', 42).PHP_EOL; + $output = str_repeat('-', 41); + $output .= ' CODE COMPARISON '; + $output .= str_repeat('-', 42).PHP_EOL; for ($i = 0; $i < $maxTitleLines; $i++) { if (isset($firstTitleLines[$i]) === true) { @@ -222,14 +289,14 @@ protected function printCodeComparisonBlock(DOMNode $node) $secondLineText = ''; } - echo '| '; - echo $firstLineText.str_repeat(' ', (46 - strlen($firstLineText))); - echo ' | '; - echo $secondLineText.str_repeat(' ', (47 - strlen($secondLineText))); - echo ' |'.PHP_EOL; + $output .= '| '; + $output .= $firstLineText.str_repeat(' ', (46 - strlen($firstLineText))); + $output .= ' | '; + $output .= $secondLineText.str_repeat(' ', (47 - strlen($secondLineText))); + $output .= ' |'.PHP_EOL; }//end for - echo str_repeat('-', 100).PHP_EOL; + $output .= str_repeat('-', 100).PHP_EOL; for ($i = 0; $i < $maxCodeLines; $i++) { if (isset($firstLines[$i]) === true) { @@ -244,16 +311,18 @@ protected function printCodeComparisonBlock(DOMNode $node) $secondLineText = ''; } - echo '| '; - echo $firstLineText.str_repeat(' ', max(0, (47 - strlen($firstLineText)))); - echo '| '; - echo $secondLineText.str_repeat(' ', max(0, (48 - strlen($secondLineText)))); - echo '|'.PHP_EOL; + $output .= '| '; + $output .= $firstLineText.str_repeat(' ', max(0, (47 - strlen($firstLineText)))); + $output .= '| '; + $output .= $secondLineText.str_repeat(' ', max(0, (48 - strlen($secondLineText)))); + $output .= '|'.PHP_EOL; }//end for - echo str_repeat('-', 100).PHP_EOL.PHP_EOL; + $output .= str_repeat('-', 100).PHP_EOL.PHP_EOL; - }//end printCodeComparisonBlock() + return $output; + + }//end getFormattedCodeComparisonBlock() }//end class diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt index dcb404eec5..4ca1dbcad2 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt +++ b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt @@ -1,9 +1,4 @@ ---------------------------------------------- -| GENERATORTEST CODING STANDARD: NO CONTENT | ---------------------------------------------- - - ------------------------------------------------------------------------------- | GENERATORTEST CODING STANDARD: CODE COMPARISON ONLY, MISSING STANDARD BLOCK | ------------------------------------------------------------------------------- diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt deleted file mode 100644 index 940832ced1..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt +++ /dev/null @@ -1,5 +0,0 @@ - --------------------------------------------------------------- -| GENERATORTEST CODING STANDARD: CODE ELEMENT AT WRONG LEVEL | --------------------------------------------------------------- - diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt deleted file mode 100644 index 3e2f564720..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.txt +++ /dev/null @@ -1,5 +0,0 @@ - --------------------------------------------------- -| GENERATORTEST CODING STANDARD: UNKNOWN ELEMENT | --------------------------------------------------- - diff --git a/tests/Core/Generators/TextTest.php b/tests/Core/Generators/TextTest.php index b0c5f2807f..5b157bd774 100644 --- a/tests/Core/Generators/TextTest.php +++ b/tests/Core/Generators/TextTest.php @@ -175,7 +175,7 @@ public static function dataDocSpecifics() ], 'Unsupported: element at the wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.txt', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], 'Unsupported: one correct elm, one at wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', @@ -187,7 +187,7 @@ public static function dataDocSpecifics() ], 'Unsupported: unknown element' => [ 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedUnknownElement.txt', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], ]; From 26192fe68980135764222f87361ec4d4d2dad3a8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 15:39:30 +0100 Subject: [PATCH 2/3] Generators/Markdown: don't print title if there is no content This refactors the class to _retrieve_ the intended output, instead of echo-ing it out directly and validates whether it makes sense to print anything at all about a sniff before sending the output to screen. It deprecates the following methods, which will be removed in PHPCS 4.0: * `printHeader()` in favour of `getFormattedHeader()` * `printFooter()` in favour of `getFormattedFooter()` * `printTextBlock()` in favour of `getFormattedTextBlock()` * `printCodeComparisonBlock()` in favour of `getFormattedCodeComparisonBlock()` --- src/Generators/Markdown.php | 149 ++++++++++++++---- .../ExpectedOutputStructureDocs.md | 3 - ...tedOutputUnsupportedElementAtWrongLevel.md | 6 - ...ExpectedOutputUnsupportedUnknownElement.md | 6 - .../Generators/Fixtures/MarkdownDouble.php | 20 +-- tests/Core/Generators/MarkdownTest.php | 24 +-- 6 files changed, 140 insertions(+), 68 deletions(-) delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md diff --git a/src/Generators/Markdown.php b/src/Generators/Markdown.php index 55ef3972bf..c2687e6dcd 100644 --- a/src/Generators/Markdown.php +++ b/src/Generators/Markdown.php @@ -32,8 +32,6 @@ public function generate() } ob_start(); - $this->printHeader(); - foreach ($this->docFiles as $file) { $doc = new DOMDocument(); $doc->load($file); @@ -41,11 +39,14 @@ public function generate() $this->processSniff($documentation); } - $this->printFooter(); $content = ob_get_contents(); ob_end_clean(); - echo $content; + if (trim($content) !== '') { + echo $this->getFormattedHeader(); + echo $content; + echo $this->getFormattedFooter(); + } }//end generate() @@ -53,32 +54,70 @@ public function generate() /** * Print the markdown header. * + * @deprecated 3.12.0 Use Markdown::getFormattedHeader() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printHeader() + { + echo $this->getFormattedHeader(); + + }//end printHeader() + + + /** + * Format the markdown header. + * + * @since 3.12.0 Replaces the deprecated Markdown::printHeader() method. + * + * @return string + */ + protected function getFormattedHeader() { $standard = $this->ruleset->name; - echo "# $standard Coding Standard".PHP_EOL; + return "# $standard Coding Standard".PHP_EOL; - }//end printHeader() + }//end getFormattedHeader() /** * Print the markdown footer. * + * @deprecated 3.12.0 Use Markdown::getFormattedFooter() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printFooter() + { + echo $this->getFormattedFooter(); + + }//end printFooter() + + + /** + * Format the markdown footer. + * + * @since 3.12.0 Replaces the deprecated Markdown::printFooter() method. + * + * @return string + */ + protected function getFormattedFooter() { // Turn off errors so we don't get timezone warnings if people // don't have their timezone set. $errorLevel = error_reporting(0); - echo PHP_EOL.'Documentation generated on '.date('r'); - echo ' by [PHP_CodeSniffer '.Config::VERSION.'](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; + $output = PHP_EOL.'Documentation generated on '.date('r'); + $output .= ' by [PHP_CodeSniffer '.Config::VERSION.'](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; error_reporting($errorLevel); - }//end printFooter() + return $output; + + }//end getFormattedFooter() /** @@ -92,17 +131,21 @@ protected function printFooter() */ protected function processSniff(DOMNode $doc) { - $title = $this->getTitle($doc); - echo PHP_EOL."## $title".PHP_EOL.PHP_EOL; - + $content = ''; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { - $this->printTextBlock($node); + $content .= $this->getFormattedTextBlock($node); } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); + $content .= $this->getFormattedCodeComparisonBlock($node); } } + if (trim($content) !== '') { + $title = $this->getTitle($doc); + echo PHP_EOL."## $title".PHP_EOL.PHP_EOL; + echo $content; + } + }//end processSniff() @@ -111,9 +154,29 @@ protected function processSniff(DOMNode $doc) * * @param \DOMNode $node The DOMNode object for the text block. * + * @deprecated 3.12.0 Use Markdown::getFormattedTextBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printTextBlock(DOMNode $node) + { + echo $this->getFormattedTextBlock($node); + + }//end printTextBlock() + + + /** + * Format a text block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the text block. + * + * @since 3.12.0 Replaces the deprecated Markdown::printTextBlock() method. + * + * @return string + */ + protected function getFormattedTextBlock(DOMNode $node) { $content = trim($node->nodeValue); $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); @@ -144,9 +207,9 @@ protected function printTextBlock(DOMNode $node) } } - echo implode(PHP_EOL, $lines).PHP_EOL; + return implode(PHP_EOL, $lines).PHP_EOL; - }//end printTextBlock() + }//end getFormattedTextBlock() /** @@ -154,9 +217,29 @@ protected function printTextBlock(DOMNode $node) * * @param \DOMNode $node The DOMNode object for the code comparison block. * + * @deprecated 3.12.0 Use Markdown::getFormattedCodeComparisonBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printCodeComparisonBlock(DOMNode $node) + { + echo $this->getFormattedCodeComparisonBlock($node); + + }//end printCodeComparisonBlock() + + + /** + * Format a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @since 3.12.0 Replaces the deprecated Markdown::printCodeComparisonBlock() method. + * + * @return string + */ + protected function getFormattedCodeComparisonBlock(DOMNode $node) { $codeBlocks = $node->getElementsByTagName('code'); @@ -174,22 +257,24 @@ protected function printCodeComparisonBlock(DOMNode $node) $second = str_replace('', '', $second); $second = str_replace('', '', $second); - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo ''.PHP_EOL; - echo ''.PHP_EOL; - echo ' '.PHP_EOL; - echo '
$firstTitle$secondTitle
'.PHP_EOL.PHP_EOL; - echo " $first".PHP_EOL.PHP_EOL; - echo ''.PHP_EOL.PHP_EOL; - echo " $second".PHP_EOL.PHP_EOL; - echo '
'.PHP_EOL; - - }//end printCodeComparisonBlock() + $output = ' '.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= " ".PHP_EOL; + $output .= " ".PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= ''.PHP_EOL; + $output .= ''.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= '
$firstTitle$secondTitle
'.PHP_EOL.PHP_EOL; + $output .= " $first".PHP_EOL.PHP_EOL; + $output .= ''.PHP_EOL.PHP_EOL; + $output .= " $second".PHP_EOL.PHP_EOL; + $output .= '
'.PHP_EOL; + + return $output; + + }//end getFormattedCodeComparisonBlock() }//end class diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md index fec8989451..fcbfcefe70 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md +++ b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md @@ -1,8 +1,5 @@ # GeneratorTest Coding Standard -## No Content - - ## Code Comparison Only, Missing Standard Block diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md deleted file mode 100644 index 048f028d57..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md +++ /dev/null @@ -1,6 +0,0 @@ -# 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/ExpectedOutputUnsupportedUnknownElement.md b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md deleted file mode 100644 index 211415225f..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.md +++ /dev/null @@ -1,6 +0,0 @@ -# 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/Fixtures/MarkdownDouble.php b/tests/Core/Generators/Fixtures/MarkdownDouble.php index ed2a5d8f58..e783f7dda7 100644 --- a/tests/Core/Generators/Fixtures/MarkdownDouble.php +++ b/tests/Core/Generators/Fixtures/MarkdownDouble.php @@ -14,23 +14,25 @@ class MarkdownDouble extends Markdown { /** - * Print the markdown footer without the date or version nr to make the expectation fixtures stable. + * Format the markdown footer without the date or version nr to make the expectation fixtures stable. * - * @return void + * @return string */ - protected function printFooter() + protected function getFormattedFooter() { - echo PHP_EOL.'Documentation generated on *REDACTED*'; - echo ' by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; + $output = PHP_EOL.'Documentation generated on *REDACTED*'; + $output .= ' by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; + + return $output; } /** - * Print the _real_ footer of the markdown page. + * Retrieve the _real_ footer of the markdown page. * - * @return void + * @return string */ - public function printRealFooter() + public function getRealFooter() { - parent::printFooter(); + return parent::getFormattedFooter(); } } diff --git a/tests/Core/Generators/MarkdownTest.php b/tests/Core/Generators/MarkdownTest.php index 54f60d075e..edc9db8c31 100644 --- a/tests/Core/Generators/MarkdownTest.php +++ b/tests/Core/Generators/MarkdownTest.php @@ -175,7 +175,7 @@ public static function dataDocSpecifics() ], 'Unsupported: element at the wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.md', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], 'Unsupported: one correct elm, one at wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', @@ -187,7 +187,7 @@ public static function dataDocSpecifics() ], 'Unsupported: unknown element' => [ 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedUnknownElement.md', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], ]; @@ -208,10 +208,16 @@ public function testFooter() $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); $generator = new MarkdownDouble($ruleset); - $generator->printRealFooter(); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } }//end testFooter() @@ -233,11 +239,8 @@ public function testFooterResetsErrorReportingToOriginalSetting() $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(); + $generator->getRealFooter(); $this->assertSame($expected, error_reporting()); @@ -275,11 +278,8 @@ public function testFooterDoesntThrowWarningOnMissingTimezone() $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(); + $generator->getRealFooter(); // Reset the timezone to its original state. ini_set('date.timezone', $originalIni); From 0f978c7978489814e7cba8ac4e7b7a8d86e70b41 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 4 Nov 2024 19:42:04 +0100 Subject: [PATCH 3/3] Generators/HTML: don't print title if there is no content This refactors the class to _retrieve_ the intended output, instead of echo-ing it out directly and validates whether it makes sense to print anything at all about a sniff before sending the output to screen. It deprecates the following methods, which will be removed in PHPCS 4.0: * `printHeader()` in favour of `getFormattedHeader()` * `printToc()` in favour of `getFormattedToc()` * `printFooter()` in favour of `getFormattedFooter()` * `printTextBlock()` in favour of `getFormattedTextBlock()` * `printCodeComparisonBlock()` in favour of `getFormattedCodeComparisonBlock()` --- src/Generators/HTML.php | 200 ++++++++++++++---- .../ExpectedOutputStructureDocs.html | 2 - ...dOutputUnsupportedElementAtWrongLevel.html | 77 ------- ...pectedOutputUnsupportedUnknownElement.html | 77 ------- tests/Core/Generators/Fixtures/HTMLDouble.php | 28 +-- tests/Core/Generators/HTMLTest.php | 24 +-- 6 files changed, 180 insertions(+), 228 deletions(-) delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html delete mode 100644 tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html diff --git a/src/Generators/HTML.php b/src/Generators/HTML.php index ba05d072df..1a4833c56c 100644 --- a/src/Generators/HTML.php +++ b/src/Generators/HTML.php @@ -108,9 +108,6 @@ public function generate() } ob_start(); - $this->printHeader(); - $this->printToc(); - foreach ($this->docFiles as $file) { $doc = new DOMDocument(); $doc->load($file); @@ -118,12 +115,15 @@ public function generate() $this->processSniff($documentation); } - $this->printFooter(); - $content = ob_get_contents(); ob_end_clean(); - echo $content; + if (trim($content) !== '') { + echo $this->getFormattedHeader(); + echo $this->getFormattedToc(); + echo $content; + echo $this->getFormattedFooter(); + } }//end generate() @@ -131,72 +131,132 @@ public function generate() /** * Print the header of the HTML page. * + * @deprecated 3.12.0 Use HTML::getFormattedHeader() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printHeader() { - $standard = $this->ruleset->name; - echo ''.PHP_EOL; - echo ' '.PHP_EOL; - echo " $standard Coding Standards".PHP_EOL; - echo ' '.str_replace("\n", PHP_EOL, self::STYLESHEET).PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo "

$standard Coding Standards

".PHP_EOL; + echo $this->getFormattedHeader(); }//end printHeader() + /** + * Format the header of the HTML page. + * + * @since 3.12.0 Replaces the deprecated HTML::printHeader() method. + * + * @return string + */ + protected function getFormattedHeader() + { + $standard = $this->ruleset->name; + $output = ''.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= " $standard Coding Standards".PHP_EOL; + $output .= ' '.str_replace("\n", PHP_EOL, self::STYLESHEET).PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= "

$standard Coding Standards

".PHP_EOL; + + return $output; + + }//end getFormattedHeader() + + /** * Print the table of contents for the standard. * - * The TOC is just an unordered list of bookmarks to sniffs on the page. + * @deprecated 3.12.0 Use HTML::getFormattedToc() instead. + * + * @codeCoverageIgnore * * @return void */ protected function printToc() + { + echo $this->getFormattedToc(); + + }//end printToc() + + + /** + * Format the table of contents for the standard. + * + * The TOC is just an unordered list of bookmarks to sniffs on the page. + * + * @since 3.12.0 Replaces the deprecated HTML::printToc() method. + * + * @return string + */ + protected function getFormattedToc() { // Only show a TOC when there are two or more docs to display. if (count($this->docFiles) < 2) { - return; + return ''; } - echo '

Table of Contents

'.PHP_EOL; - echo '
    '.PHP_EOL; + $output = '

    Table of Contents

    '.PHP_EOL; + $output .= '
      '.PHP_EOL; foreach ($this->docFiles as $file) { $doc = new DOMDocument(); $doc->load($file); $documentation = $doc->getElementsByTagName('documentation')->item(0); $title = $this->getTitle($documentation); - echo '
    • $title
    • ".PHP_EOL; + $output .= '
    • '.$title.'
    • '.PHP_EOL; } - echo '
    '.PHP_EOL; + $output .= '
'.PHP_EOL; - }//end printToc() + return $output; + + }//end getFormattedToc() /** * Print the footer of the HTML page. * + * @deprecated 3.12.0 Use HTML::getFormattedFooter() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printFooter() + { + echo $this->getFormattedFooter(); + + }//end printFooter() + + + /** + * Format the footer of the HTML page. + * + * @since 3.12.0 Replaces the deprecated HTML::printFooter() method. + * + * @return string + */ + protected function getFormattedFooter() { // Turn off errors so we don't get timezone warnings if people // don't have their timezone set. $errorLevel = error_reporting(0); - echo '
'; - echo 'Documentation generated on '.date('r'); - echo ' by PHP_CodeSniffer '.Config::VERSION.''; - echo '
'.PHP_EOL; + $output = '
'; + $output .= 'Documentation generated on '.date('r'); + $output .= ' by PHP_CodeSniffer '.Config::VERSION.''; + $output .= '
'.PHP_EOL; error_reporting($errorLevel); - echo ' '.PHP_EOL; - echo ''.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= ''.PHP_EOL; - }//end printFooter() + return $output; + + }//end getFormattedFooter() /** @@ -210,18 +270,22 @@ protected function printFooter() */ public function processSniff(DOMNode $doc) { - $title = $this->getTitle($doc); - echo ' '.PHP_EOL; - echo "

$title

".PHP_EOL; - + $content = ''; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { - $this->printTextBlock($node); + $content .= $this->getFormattedTextBlock($node); } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); + $content .= $this->getFormattedCodeComparisonBlock($node); } } + if (trim($content) !== '') { + $title = $this->getTitle($doc); + echo '
'.PHP_EOL; + echo '

'.$title.'

'.PHP_EOL; + echo $content; + } + }//end processSniff() @@ -230,9 +294,29 @@ public function processSniff(DOMNode $doc) * * @param \DOMNode $node The DOMNode object for the text block. * + * @deprecated 3.12.0 Use HTML::getFormattedTextBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printTextBlock(DOMNode $node) + { + echo $this->getFormattedTextBlock($node); + + }//end printTextBlock() + + + /** + * Format a text block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the text block. + * + * @since 3.12.0 Replaces the deprecated HTML::printTextBlock() method. + * + * @return string + */ + protected function getFormattedTextBlock(DOMNode $node) { $content = trim($node->nodeValue); $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); @@ -265,9 +349,9 @@ protected function printTextBlock(DOMNode $node) } } - echo '

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

'.PHP_EOL; + return '

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

'.PHP_EOL; - }//end printTextBlock() + }//end getFormattedTextBlock() /** @@ -275,9 +359,29 @@ protected function printTextBlock(DOMNode $node) * * @param \DOMNode $node The DOMNode object for the code comparison block. * + * @deprecated 3.12.0 Use HTML::getFormattedCodeComparisonBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printCodeComparisonBlock(DOMNode $node) + { + echo $this->getFormattedCodeComparisonBlock($node); + + }//end printCodeComparisonBlock() + + + /** + * Format a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @since 3.12.0 Replaces the deprecated HTML::printCodeComparisonBlock() method. + * + * @return string + */ + protected function getFormattedCodeComparisonBlock(DOMNode $node) { $codeBlocks = $node->getElementsByTagName('code'); @@ -299,18 +403,20 @@ protected function printCodeComparisonBlock(DOMNode $node) $second = str_replace('', '', $second); $second = str_replace('', '', $second); - echo '
'.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo '
$firstTitle$secondTitle
$first$second
'.PHP_EOL; + $output = ' '.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= " ".PHP_EOL; + $output .= " ".PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= " ".PHP_EOL; + $output .= " ".PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= '
$firstTitle$secondTitle
$first$second
'.PHP_EOL; - }//end printCodeComparisonBlock() + return $output; + + }//end getFormattedCodeComparisonBlock() }//end class diff --git a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html index db1f3a9a92..c959dcac4a 100644 --- a/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html +++ b/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html @@ -81,8 +81,6 @@

Table of Contents

  • Two Standard Blocks, One Code Comparison
  • Two Standard Blocks, Three Code Comparisons
  • - -

    No Content

    Code Comparison Only, Missing Standard Block

    diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html deleted file mode 100644 index dfa5670f0e..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html +++ /dev/null @@ -1,77 +0,0 @@ - - - GeneratorTest Coding Standards - - - -

    GeneratorTest Coding Standards

    - -

    Code element at wrong level

    -
    - - diff --git a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html b/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html deleted file mode 100644 index 770d08bbc7..0000000000 --- a/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedUnknownElement.html +++ /dev/null @@ -1,77 +0,0 @@ - - - GeneratorTest Coding Standards - - - -

    GeneratorTest Coding Standards

    - -

    Unknown element

    -
    - - diff --git a/tests/Core/Generators/Fixtures/HTMLDouble.php b/tests/Core/Generators/Fixtures/HTMLDouble.php index 9203724085..e3d797c118 100644 --- a/tests/Core/Generators/Fixtures/HTMLDouble.php +++ b/tests/Core/Generators/Fixtures/HTMLDouble.php @@ -14,27 +14,29 @@ class HTMLDouble extends HTML { /** - * Print the footer of the HTML page without the date or version nr to make the expectation fixtures stable. + * Format the footer of the HTML page without the date or version nr to make the expectation fixtures stable. * - * @return void + * @return string */ - protected function printFooter() + protected function getFormattedFooter() { - echo '
    '; - echo 'Documentation generated on #REDACTED#'; - echo ' by PHP_CodeSniffer #VERSION#'; - echo '
    '.PHP_EOL; - echo ' '.PHP_EOL; - echo ''.PHP_EOL; + $output = '
    '; + $output .= 'Documentation generated on #REDACTED#'; + $output .= ' by PHP_CodeSniffer #VERSION#'; + $output .= '
    '.PHP_EOL; + $output .= ' '.PHP_EOL; + $output .= ''.PHP_EOL; + + return $output; } /** - * Print the _real_ footer of the HTML page. + * Retrieve the _real_ footer of the HTML page. * - * @return void + * @return string */ - public function printRealFooter() + public function getRealFooter() { - parent::printFooter(); + return parent::getFormattedFooter(); } } diff --git a/tests/Core/Generators/HTMLTest.php b/tests/Core/Generators/HTMLTest.php index 9cec58e74a..b48d6e6d71 100644 --- a/tests/Core/Generators/HTMLTest.php +++ b/tests/Core/Generators/HTMLTest.php @@ -175,7 +175,7 @@ public static function dataDocSpecifics() ], 'Unsupported: element at the wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedElementAtWrongLevel.html', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], 'Unsupported: one correct elm, one at wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', @@ -187,7 +187,7 @@ public static function dataDocSpecifics() ], 'Unsupported: unknown element' => [ 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', - 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedUnknownElement.html', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], ]; @@ -210,10 +210,16 @@ public function testFooter() $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(); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } }//end testFooter() @@ -235,11 +241,8 @@ public function testFooterResetsErrorReportingToOriginalSetting() $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(); + $generator->getRealFooter(); $this->assertSame($expected, error_reporting()); @@ -277,11 +280,8 @@ public function testFooterDoesntThrowWarningOnMissingTimezone() $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(); + $generator->getRealFooter(); // Reset the timezone to its original state. ini_set('date.timezone', $originalIni);