%PDF- %PDF-
| Direktori : /home/vacivi36/code/vendor/friendsofphp/php-cs-fixer/src/Fixer/PhpUnit/ |
| Current File : /home/vacivi36/code/vendor/friendsofphp/php-cs-fixer/src/Fixer/PhpUnit/PhpUnitSizeClassFixer.php |
<?php
declare(strict_types=1);
/*
* 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\Fixer\PhpUnit;
use PhpCsFixer\DocBlock\Annotation;
use PhpCsFixer\DocBlock\DocBlock;
use PhpCsFixer\DocBlock\Line;
use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* @author Jefersson Nathan <malukenho.dev@gmail.com>
*/
final class PhpUnitSizeClassFixer extends AbstractPhpUnitFixer implements WhitespacesAwareFixerInterface, ConfigurableFixerInterface
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'All PHPUnit test cases should have `@small`, `@medium` or `@large` annotation to enable run time limits.',
[
new CodeSample("<?php\nclass MyTest extends TestCase {}\n"),
new CodeSample("<?php\nclass MyTest extends TestCase {}\n", ['group' => 'medium']),
],
'The special groups [small, medium, large] provides a way to identify tests that are taking long to be executed.'
);
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('group', 'Define a specific group to be used in case no group is already in use'))
->setAllowedValues(['small', 'medium', 'large'])
->setDefault('small')
->getOption(),
]);
}
/**
* {@inheritdoc}
*/
protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
{
$classIndex = $tokens->getPrevTokenOfKind($startIndex, [[T_CLASS]]);
if ($this->isAbstractClass($tokens, $classIndex)) {
return;
}
$docBlockIndex = $this->getDocBlockIndex($tokens, $classIndex);
if ($this->isPHPDoc($tokens, $docBlockIndex)) {
$this->updateDocBlockIfNeeded($tokens, $docBlockIndex);
} else {
$this->createDocBlock($tokens, $docBlockIndex);
}
}
private function isAbstractClass(Tokens $tokens, int $i): bool
{
$typeIndex = $tokens->getPrevMeaningfulToken($i);
return $tokens[$typeIndex]->isGivenKind(T_ABSTRACT);
}
private function createDocBlock(Tokens $tokens, int $docBlockIndex): void
{
$lineEnd = $this->whitespacesConfig->getLineEnding();
$originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
$group = $this->configuration['group'];
$toInsert = [
new Token([T_DOC_COMMENT, '/**'.$lineEnd."{$originalIndent} * @".$group.$lineEnd."{$originalIndent} */"]),
new Token([T_WHITESPACE, $lineEnd.$originalIndent]),
];
$index = $tokens->getNextMeaningfulToken($docBlockIndex);
$tokens->insertAt($index, $toInsert);
}
private function updateDocBlockIfNeeded(Tokens $tokens, int $docBlockIndex): void
{
$doc = new DocBlock($tokens[$docBlockIndex]->getContent());
if (0 !== \count($this->filterDocBlock($doc))) {
return;
}
$doc = $this->makeDocBlockMultiLineIfNeeded($doc, $tokens, $docBlockIndex);
$lines = $this->addSizeAnnotation($doc, $tokens, $docBlockIndex);
$lines = implode('', $lines);
$tokens[$docBlockIndex] = new Token([T_DOC_COMMENT, $lines]);
}
/**
* @return Line[]
*/
private function addSizeAnnotation(DocBlock $docBlock, Tokens $tokens, int $docBlockIndex): array
{
$lines = $docBlock->getLines();
$originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $docBlockIndex);
$lineEnd = $this->whitespacesConfig->getLineEnding();
$group = $this->configuration['group'];
array_splice($lines, -1, 0, $originalIndent.' *'.$lineEnd.$originalIndent.' * @'.$group.$lineEnd);
return $lines;
}
private function makeDocBlockMultiLineIfNeeded(DocBlock $doc, Tokens $tokens, int $docBlockIndex): DocBlock
{
$lines = $doc->getLines();
if (1 === \count($lines) && 0 === \count($this->filterDocBlock($doc))) {
$lines = $this->splitUpDocBlock($lines, $tokens, $docBlockIndex);
return new DocBlock(implode('', $lines));
}
return $doc;
}
/**
* Take a one line doc block, and turn it into a multi line doc block.
*
* @param Line[] $lines
*
* @return Line[]
*/
private function splitUpDocBlock(array $lines, Tokens $tokens, int $docBlockIndex): array
{
$lineContent = $this->getSingleLineDocBlockEntry($lines[0]);
$lineEnd = $this->whitespacesConfig->getLineEnding();
$originalIndent = WhitespacesAnalyzer::detectIndent($tokens, $tokens->getNextNonWhitespace($docBlockIndex));
return [
new Line('/**'.$lineEnd),
new Line($originalIndent.' * '.$lineContent.$lineEnd),
new Line($originalIndent.' */'),
];
}
/**
* @todo check whether it's doable to use \PhpCsFixer\DocBlock\DocBlock::getSingleLineDocBlockEntry instead
*/
private function getSingleLineDocBlockEntry(Line $line): string
{
$line = $line->getContent();
$line = str_replace('*/', '', $line);
$line = trim($line);
$line = str_split($line);
$i = \count($line);
do {
--$i;
} while ('*' !== $line[$i] && '*' !== $line[$i - 1] && '/' !== $line[$i - 2]);
if (' ' === $line[$i]) {
++$i;
}
$line = \array_slice($line, $i);
return implode('', $line);
}
/**
* @return Annotation[][]
*/
private function filterDocBlock(DocBlock $doc): array
{
return array_filter([
$doc->getAnnotationsOfType('small'),
$doc->getAnnotationsOfType('large'),
$doc->getAnnotationsOfType('medium'),
]);
}
}