Root Zanli
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
cpanel
/
ea-wappspector
/
vendor
/
squizlabs
/
php_codesniffer
/
tests
/
Core
/
Generators
/
Filename :
HTMLTest.php
back
Copy
<?php /** * Tests the HTML documentation generation. * * @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/HEAD/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Generators; use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Tests\Core\Generators\Fixtures\HTMLDouble; use PHPUnit\Framework\TestCase; /** * Test the HTML documentation generation. * * @covers \PHP_CodeSniffer\Generators\HTML * @group Windows */ final class HTMLTest extends TestCase { /** * Test the generated docs. * * @param string $standard The standard to use for the test. * @param string $pathToExpected Path to a file containing the expected function output. * * @dataProvider dataDocs * * @return void */ public function testDocs($standard, $pathToExpected) { // Set up the ruleset. $config = new ConfigDouble(["--standard=$standard"]); $ruleset = new Ruleset($config); $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 testDocs() /** * Data provider. * * @return array<string, array<string, string>> */ 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.html', ], 'Standard with multiple doc files' => [ 'standard' => __DIR__.'/StructureDocsTest.xml', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.html', ], ]; }//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 HTMLDouble($ruleset); $generator->generate(); }//end testDocSpecifics() /** * Data provider. * * @return array<string, array<string, string>> */ 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', ], 'Documentation title: fallback to file name' => [ 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.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', ], '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', ], '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', ], 'Unsupported: <code> element at the wrong level' => [ 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', ], '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/ExpectedOutputEmpty.txt', ], 'Invalid: code comparison mismatched code elms' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html', ], 'Invalid: code comparison only has one code elm' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html', ], 'Invalid: code elements have no content' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html', ], 'Invalid: code comparison element has no content' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html', ], 'Invalid: code comparison two code elms, one empty' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html', ], 'Invalid: code comparison two empty code elms' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html', ], 'Invalid: code title attributes are empty' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html', ], 'Invalid: code title attributes missing' => [ 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.html', ], 'Invalid: documentation title attribute is empty' => [ 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html', ], 'Invalid: documentation title attribute missing' => [ 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html', ], 'Invalid: standard element has no content' => [ 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.html', ], ]; }//end dataDocSpecifics() /** * Test anchor links in the generated docs are slugified and unique. * * @return void */ public function testAnchorLinks() { // Set up the ruleset. $standard = __DIR__.'/AnchorLinksTest.xml'; $config = new ConfigDouble(["--standard=$standard"]); $ruleset = new Ruleset($config); $pathToExpected = __DIR__.'/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html'; $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 testAnchorLinks() /** * 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 = '`^ <div class="tag-line">'; $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 <a href="https://github\.com/PHPCSStandards/PHP_CodeSniffer">PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+</a>'; $regex .= '</div>\R </body>\R</html>\R$`'; $generator = new HTMLDouble($ruleset); $footer = $generator->getRealFooter(); if (method_exists($this, 'assertMatchesRegularExpression') === true) { $this->assertMatchesRegularExpression($regex, $footer); } else { // PHPUnit < 9.1.0. $this->assertRegExp($regex, $footer); } }//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); $generator = new HTMLDouble($ruleset); $generator->getRealFooter(); $this->assertSame($expected, error_reporting()); }//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); $generator = new HTMLDouble($ruleset); $generator->getRealFooter(); // Reset the timezone to its original state. ini_set('date.timezone', $originalIni); }//end testFooterDoesntThrowWarningOnMissingTimezone() /** * Perfunctory test to verify that extenders which call deprecated methods will see a deprecation notice. * * Note: not all deprecated methods are tested as some need arguments. * * @param string $methodName Name of the deprecated method to test. * * @dataProvider dataCallingDeprecatedMethodThrowsDeprecationNotice * * @return void */ public function testCallingDeprecatedMethodThrowsDeprecationNotice($methodName) { $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; if (class_exists($exceptionClass) === false) { $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; } $regex = '`^The PHP_CodeSniffer\\\\Generators\\\\HTML::%s\(\) method is deprecated\. Use "echo [^\s]+::%s\(\)" instead\.$`'; $regex = sprintf($regex, preg_quote($methodName, '`'), str_replace('print', 'getFormatted', $methodName)); if (method_exists($this, 'expectExceptionMessageMatches') === true) { $this->expectException($exceptionClass); $this->expectExceptionMessageMatches($regex); } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { // PHPUnit < 8.4.0. $this->expectException($exceptionClass); $this->expectExceptionMessageRegExp($regex); } else { // PHPUnit < 5.2.0. $this->setExpectedExceptionRegExp($exceptionClass, $regex); } // Set up the ruleset. $standard = __DIR__.'/OneDocTest.xml'; $config = new ConfigDouble(["--standard=$standard"]); $ruleset = new Ruleset($config); $generator = new HTMLDouble($ruleset); $generator->$methodName(); }//end testCallingDeprecatedMethodThrowsDeprecationNotice() /** * Data provider. * * @return array<string, array<string, string>> */ public static function dataCallingDeprecatedMethodThrowsDeprecationNotice() { return [ 'printHeader()' => ['printHeader'], 'printToc()' => ['printToc'], 'printFooter()' => ['printFooter'], ]; }//end dataCallingDeprecatedMethodThrowsDeprecationNotice() }//end class