123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- <?php
- /*
- * This file is part of PHP CS Fixer.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- * Dariusz Rumiński <dariusz.ruminski@gmail.com>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- namespace PhpCsFixer\Tests\AutoReview;
- use PhpCsFixer\DocBlock\DocBlock;
- use PHPUnit\Framework\TestCase;
- use Symfony\Component\Finder\Finder;
- use Symfony\Component\Finder\SplFileInfo;
- /**
- * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
- *
- * @internal
- *
- * @coversNothing
- * @group auto-review
- */
- final class ProjectCodeTest extends TestCase
- {
- /**
- * This structure contains older classes that are not yet covered by tests.
- *
- * It may only shrink, never add anything to it.
- *
- * @var string[]
- */
- private static $classesWithoutTests = [
- \PhpCsFixer\Console\Command\SelfUpdateCommand::class,
- \PhpCsFixer\Console\Output\NullOutput::class,
- \PhpCsFixer\Differ\DiffConsoleFormatter::class,
- \PhpCsFixer\Doctrine\Annotation\Tokens::class,
- \PhpCsFixer\FileRemoval::class,
- \PhpCsFixer\FixerConfiguration\FixerOptionValidatorGenerator::class,
- \PhpCsFixer\FixerFileProcessedEvent::class,
- \PhpCsFixer\Fixer\Operator\AlignDoubleArrowFixerHelper::class,
- \PhpCsFixer\Fixer\Operator\AlignEqualsFixerHelper::class,
- \PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer::class,
- \PhpCsFixer\Indicator\PhpUnitIndicator::class,
- \PhpCsFixer\Linter\ProcessLintingResult::class,
- \PhpCsFixer\Linter\TokenizerLintingResult::class,
- \PhpCsFixer\Report\ReportSummary::class,
- \PhpCsFixer\Runner\FileCachingLintingIterator::class,
- \PhpCsFixer\Runner\FileFilterIterator::class,
- \PhpCsFixer\Runner\FileLintingIterator::class,
- \PhpCsFixer\StdinFileInfo::class,
- \PhpCsFixer\Test\Assert\AssertTokensTrait::class,
- \PhpCsFixer\Test\IntegrationCaseFactory::class,
- \PhpCsFixer\Tokenizer\Transformers::class,
- ];
- public function testThatClassesWithoutTestsVarIsProper()
- {
- $unknownClasses = array_filter(
- self::$classesWithoutTests,
- function ($class) { return !class_exists($class) && !trait_exists($class); }
- );
- $this->assertSame([], $unknownClasses);
- }
- /**
- * @param string $className
- *
- * @dataProvider provideSrcConcreteClasses
- */
- public function testThatSrcClassHaveTestClass($className)
- {
- $testClassName = str_replace('PhpCsFixer', 'PhpCsFixer\\Tests', $className).'Test';
- if (in_array($className, self::$classesWithoutTests, true)) {
- $this->assertFalse(class_exists($testClassName), sprintf('Class "%s" already has tests, so it should be removed from "%s::$classesWithoutTests".', $className, __CLASS__));
- $this->markTestIncomplete(sprintf('Class "%s" has no tests yet, please help and add it.', $className));
- }
- $this->assertTrue(class_exists($testClassName), sprintf('Expected test class "%s" for "%s" not found.', $testClassName, $className));
- $this->assertTrue(is_subclass_of($testClassName, TestCase::class), sprintf('Expected test class "%s" to be a subclass of "\PHPUnit\Framework\TestCase".', $testClassName));
- }
- /**
- * @param string $className
- *
- * @dataProvider provideSrcClasses
- */
- public function testThatSrcClassesNotAbuseInterfaces($className)
- {
- $rc = new \ReflectionClass($className);
- $doc = false !== $rc->getDocComment()
- ? new DocBlock($rc->getDocComment())
- : null;
- if (
- $rc->isInterface()
- || ($doc && count($doc->getAnnotationsOfType('internal')))
- || 0 === count($rc->getInterfaces())
- || in_array($className, [
- \PhpCsFixer\Finder::class,
- \PhpCsFixer\Test\AbstractFixerTestCase::class,
- \PhpCsFixer\Test\AbstractIntegrationTestCase::class,
- \PhpCsFixer\Tokenizer\Tokens::class,
- ], true)
- ) {
- return;
- }
- $allowedMethods = array_map(
- function (\ReflectionClass $interface) {
- return $this->getPublicMethodNames($interface);
- },
- $rc->getInterfaces()
- );
- if (count($allowedMethods)) {
- $allowedMethods = array_unique(array_merge(...array_values($allowedMethods)));
- }
- $allowedMethods[] = '__construct';
- $allowedMethods[] = '__destruct';
- $allowedMethods[] = '__wakeup';
- $exceptionMethods = [
- 'configure', // due to AbstractFixer::configure
- 'getConfigurationDefinition', // due to AbstractFixer::getDefaultConfiguration
- 'getDefaultConfiguration', // due to AbstractFixer::getDefaultConfiguration
- 'setWhitespacesConfig', // due to AbstractFixer::setWhitespacesConfig
- ];
- // @TODO: should be removed at 3.0
- $exceptionMethodsPerClass = [
- \PhpCsFixer\Config::class => ['create'],
- \PhpCsFixer\Fixer\FunctionNotation\MethodArgumentSpaceFixer::class => ['fixSpace'],
- ];
- $definedMethods = $this->getPublicMethodNames($rc);
- $extraMethods = array_diff(
- $definedMethods,
- $allowedMethods,
- $exceptionMethods,
- isset($exceptionMethodsPerClass[$className]) ? $exceptionMethodsPerClass[$className] : []
- );
- sort($extraMethods);
- $this->assertEmpty(
- $extraMethods,
- sprintf(
- "Class '%s' should not have public methods that are not part of implemented interfaces.\nViolations:\n%s",
- $className,
- implode("\n", array_map(function ($item) {
- return " * $item";
- }, $extraMethods))
- )
- );
- }
- /**
- * @param string $className
- *
- * @dataProvider provideSrcClasses
- */
- public function testThatSrcClassesNotExposeProperties($className)
- {
- $rc = new \ReflectionClass($className);
- if (\PhpCsFixer\Fixer\Alias\NoMixedEchoPrintFixer::class === $className) {
- $this->markTestIncomplete(sprintf(
- 'Public properties of fixer `%s` will be removed on 3.0.',
- \PhpCsFixer\Fixer\Alias\NoMixedEchoPrintFixer::class
- ));
- }
- $this->assertEmpty(
- $rc->getProperties(\ReflectionProperty::IS_PUBLIC),
- sprintf('Class \'%s\' should not have public properties.', $className)
- );
- if ($rc->isFinal()) {
- return;
- }
- $allowedProps = [];
- $definedProps = $rc->getProperties(\ReflectionProperty::IS_PROTECTED);
- if (false !== $rc->getParentClass()) {
- $allowedProps = $rc->getParentClass()->getProperties(\ReflectionProperty::IS_PROTECTED);
- }
- $allowedProps = array_map(function (\ReflectionProperty $item) {
- return $item->getName();
- }, $allowedProps);
- $definedProps = array_map(function (\ReflectionProperty $item) {
- return $item->getName();
- }, $definedProps);
- $exceptionPropsPerClass = [
- \PhpCsFixer\AbstractPhpdocTypesFixer::class => ['tags'],
- \PhpCsFixer\AbstractAlignFixerHelper::class => ['deepestLevel'],
- \PhpCsFixer\AbstractFixer::class => ['configuration', 'configurationDefinition', 'whitespacesConfig'],
- \PhpCsFixer\AbstractProxyFixer::class => ['proxyFixer'],
- \PhpCsFixer\Test\AbstractFixerTestCase::class => ['fixer', 'linter'],
- \PhpCsFixer\Test\AbstractIntegrationTestCase::class => ['linter'],
- ];
- $extraProps = array_diff(
- $definedProps,
- $allowedProps,
- isset($exceptionPropsPerClass[$className]) ? $exceptionPropsPerClass[$className] : []
- );
- sort($extraProps);
- $this->assertEmpty(
- $extraProps,
- sprintf(
- "Class '%s' should not have protected properties.\nViolations:\n%s",
- $className,
- implode("\n", array_map(function ($item) {
- return " * $item";
- }, $extraProps))
- )
- );
- }
- /**
- * @param string $className
- *
- * @dataProvider provideTestClasses
- */
- public function testThatTestClassesAreAbstractOrFinal($className)
- {
- $rc = new \ReflectionClass($className);
- $this->assertTrue(
- $rc->isAbstract() || $rc->isFinal(),
- sprintf('Test class %s should be abstract or final.', $className)
- );
- }
- /**
- * @param string $className
- *
- * @dataProvider provideTestClasses
- */
- public function testThatTestClassesAreInternal($className)
- {
- $rc = new \ReflectionClass($className);
- $doc = new DocBlock($rc->getDocComment());
- $this->assertNotEmpty(
- $doc->getAnnotationsOfType('internal'),
- sprintf('Test class %s should have internal annotation.', $className)
- );
- }
- public function provideSrcClasses()
- {
- return array_map(
- function ($item) {
- return [$item];
- },
- $this->getSrcClasses()
- );
- }
- public function provideSrcConcreteClasses()
- {
- return array_map(
- function ($item) { return [$item]; },
- array_filter(
- $this->getSrcClasses(),
- function ($className) {
- $rc = new \ReflectionClass($className);
- return !$rc->isAbstract() && !$rc->isInterface();
- }
- )
- );
- }
- public function provideTestClasses()
- {
- return array_map(
- function ($item) {
- return [$item];
- },
- $this->getTestClasses()
- );
- }
- private function getSrcClasses()
- {
- static $files;
- if (null !== $files) {
- return $files;
- }
- $finder = Finder::create()
- ->files()
- ->name('*.php')
- ->in(__DIR__.'/../../src')
- ->exclude([
- 'Resources',
- ])
- ;
- $names = array_map(
- function (SplFileInfo $file) {
- return sprintf(
- '%s\\%s%s%s',
- 'PhpCsFixer',
- strtr($file->getRelativePath(), DIRECTORY_SEPARATOR, '\\'),
- $file->getRelativePath() ? '\\' : '',
- $file->getBasename('.'.$file->getExtension())
- );
- },
- iterator_to_array($finder, false)
- );
- sort($names);
- return $names;
- }
- private function getTestClasses()
- {
- static $files;
- if (null !== $files) {
- return $files;
- }
- $finder = Finder::create()
- ->files()
- ->name('*.php')
- ->in(__DIR__.'/..')
- ->exclude([
- 'Fixtures',
- ])
- ;
- $names = array_map(
- function (SplFileInfo $file) {
- return sprintf(
- 'PhpCsFixer\\Tests\\%s%s%s',
- strtr($file->getRelativePath(), DIRECTORY_SEPARATOR, '\\'),
- $file->getRelativePath() ? '\\' : '',
- $file->getBasename('.'.$file->getExtension())
- );
- },
- iterator_to_array($finder, false)
- );
- sort($names);
- return $names;
- }
- /**
- * @param \ReflectionClass $rc
- *
- * @return string[]
- */
- private function getPublicMethodNames(\ReflectionClass $rc)
- {
- return array_map(
- function (\ReflectionMethod $rm) {
- return $rm->getName();
- },
- $rc->getMethods(\ReflectionMethod::IS_PUBLIC)
- );
- }
- }
|