DocumentationTest.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\AutoReview;
  13. use PhpCsFixer\Documentation\DocumentationLocator;
  14. use PhpCsFixer\Documentation\FixerDocumentGenerator;
  15. use PhpCsFixer\Documentation\ListDocumentGenerator;
  16. use PhpCsFixer\Documentation\RuleSetDocumentationGenerator;
  17. use PhpCsFixer\Fixer\FixerInterface;
  18. use PhpCsFixer\FixerFactory;
  19. use PhpCsFixer\RuleSet\RuleSets;
  20. use PHPUnit\Framework\TestCase;
  21. use Symfony\Component\Finder\Finder;
  22. /**
  23. * @internal
  24. *
  25. * @covers \PhpCsFixer\Documentation\DocumentationLocator
  26. * @covers \PhpCsFixer\Documentation\FixerDocumentGenerator
  27. * @covers \PhpCsFixer\Documentation\ListDocumentGenerator
  28. * @covers \PhpCsFixer\Documentation\RstUtils
  29. * @covers \PhpCsFixer\Documentation\RuleSetDocumentationGenerator
  30. *
  31. * @group auto-review
  32. */
  33. final class DocumentationTest extends TestCase
  34. {
  35. /**
  36. * @dataProvider provideFixerDocumentationFileIsUpToDateCases
  37. */
  38. public function testFixerDocumentationFileIsUpToDate(FixerInterface $fixer): void
  39. {
  40. $locator = new DocumentationLocator();
  41. $generator = new FixerDocumentGenerator($locator);
  42. $path = $locator->getFixerDocumentationFilePath($fixer);
  43. self::assertFileExists($path);
  44. $expected = $generator->generateFixerDocumentation($fixer);
  45. $actual = file_get_contents($path);
  46. $expected = preg_replace_callback(
  47. '/
  48. # an example
  49. (?<before>
  50. Example\ \#\d\n
  51. ~+\n
  52. \n
  53. (?:\*Default\*\ configuration\.\n\n)?
  54. (?:With\ configuration:.*?\n\n)?
  55. )
  56. # with a diff that could not be generated
  57. \.\.\ error::\n
  58. \ \ \ Cannot\ generate\ diff\ for\ code\ sample\ \#\d\ of\ rule\ .+?:\n
  59. \ \ \ the\ sample\ is\ not\ suitable\ for\ current\ version\ of\ PHP\ \(.+?\).\n
  60. # followed by another title or end of file
  61. (?<after>
  62. \n
  63. [^ \n].*?
  64. \n
  65. |$
  66. )
  67. /x',
  68. static function (array $matches) use ($actual): string {
  69. $before = preg_quote($matches['before'], '/');
  70. $after = preg_quote($matches['after'], '/');
  71. $replacement = '[UNAVAILABLE EXAMPLE DIFF]';
  72. if (1 === preg_match("/{$before}(\\.\\. code-block:: diff.*?){$after}/s", $actual, $actualMatches)) {
  73. $replacement = $actualMatches[1];
  74. }
  75. return $matches[1].$replacement.$matches[2];
  76. },
  77. $expected
  78. );
  79. self::assertSame($expected, $actual);
  80. }
  81. public static function provideFixerDocumentationFileIsUpToDateCases(): iterable
  82. {
  83. foreach (self::getFixers() as $fixer) {
  84. yield $fixer->getName() => [$fixer];
  85. }
  86. }
  87. public function testFixersDocumentationIndexFileIsUpToDate(): void
  88. {
  89. $locator = new DocumentationLocator();
  90. $generator = new FixerDocumentGenerator($locator);
  91. self::assertFileEqualsString(
  92. $generator->generateFixersDocumentationIndex(self::getFixers()),
  93. $locator->getFixersDocumentationIndexFilePath()
  94. );
  95. }
  96. public function testFixersDocumentationDirectoryHasNoExtraFiles(): void
  97. {
  98. $generator = new DocumentationLocator();
  99. self::assertCount(
  100. \count(self::getFixers()) + 1,
  101. (new Finder())->files()->in($generator->getFixersDocumentationDirectoryPath())
  102. );
  103. }
  104. public function testRuleSetsDocumentationIsUpToDate(): void
  105. {
  106. $locator = new DocumentationLocator();
  107. $generator = new RuleSetDocumentationGenerator($locator);
  108. $fixers = self::getFixers();
  109. $paths = [];
  110. foreach (RuleSets::getSetDefinitions() as $name => $definition) {
  111. $paths[$name] = $path = $locator->getRuleSetsDocumentationFilePath($name);
  112. self::assertFileEqualsString(
  113. $generator->generateRuleSetsDocumentation($definition, $fixers),
  114. $path,
  115. sprintf('RuleSet documentation is generated (please see CONTRIBUTING.md), file "%s".', $path)
  116. );
  117. }
  118. $indexFilePath = $locator->getRuleSetsDocumentationIndexFilePath();
  119. self::assertFileEqualsString(
  120. $generator->generateRuleSetsDocumentationIndex($paths),
  121. $indexFilePath,
  122. sprintf('RuleSet documentation is generated (please CONTRIBUTING.md), file "%s".', $indexFilePath)
  123. );
  124. }
  125. public function testRuleSetsDocumentationDirectoryHasNoExtraFiles(): void
  126. {
  127. $generator = new DocumentationLocator();
  128. self::assertCount(
  129. \count(RuleSets::getSetDefinitions()) + 1,
  130. (new Finder())->files()->in($generator->getRuleSetsDocumentationDirectoryPath())
  131. );
  132. }
  133. public function testInstallationDocHasCorrectMinimumVersion(): void
  134. {
  135. $composerJsonContent = file_get_contents(__DIR__.'/../../composer.json');
  136. $composerJson = json_decode($composerJsonContent, true, 512, JSON_THROW_ON_ERROR);
  137. $phpVersion = $composerJson['require']['php'];
  138. $minimumVersion = ltrim(substr($phpVersion, 0, strpos($phpVersion, ' ')), '^');
  139. $minimumVersionInformation = sprintf('PHP needs to be a minimum version of PHP %s.', $minimumVersion);
  140. $installationDocPath = realpath(__DIR__.'/../../doc/installation.rst');
  141. self::assertStringContainsString(
  142. $minimumVersionInformation,
  143. file_get_contents($installationDocPath),
  144. sprintf('Files %s needs to contain information "%s"', $installationDocPath, $minimumVersionInformation)
  145. );
  146. }
  147. public function testListingDocumentationIsUpToDate(): void
  148. {
  149. $locator = new DocumentationLocator();
  150. $generator = new ListDocumentGenerator($locator);
  151. $fixers = self::getFixers();
  152. $listingFilePath = $locator->getListingFilePath();
  153. self::assertFileEqualsString(
  154. $generator->generateListingDocumentation($fixers),
  155. $listingFilePath,
  156. sprintf('Listing documentation is generated (please CONTRIBUTING.md), file "%s".', $listingFilePath)
  157. );
  158. }
  159. private static function assertFileEqualsString(string $expectedString, string $actualFilePath, string $message = ''): void
  160. {
  161. self::assertFileExists($actualFilePath, $message);
  162. self::assertSame($expectedString, file_get_contents($actualFilePath), $message);
  163. }
  164. /**
  165. * @return list<FixerInterface>
  166. */
  167. private static function getFixers(): array
  168. {
  169. $factory = new FixerFactory();
  170. $factory->registerBuiltInFixers();
  171. return $factory->getFixers();
  172. }
  173. }