diff --git a/Dockerfile b/Dockerfile index 26cca2dac37..f6395618c20 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,7 @@ RUN if [ ! -z "$DOCKER_GROUP_ID" ] && [ ! getent group "${DOCKER_GROUP_ID}" > /d && if [ ! -z "$DOCKER_USER_ID" ] && [ ! -z "$DOCKER_GROUP_ID" ] && [ ! getent passwd "${DOCKER_USER_ID}" > /dev/null ]; \ then adduser -S -u "${DOCKER_USER_ID}" -G "$(getent group "${DOCKER_GROUP_ID}" | awk -F: '{printf $1}')" dev; \ fi \ + && apk add git \ # php extensions && curl --location --output /usr/local/bin/install-php-extensions https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions \ && chmod +x /usr/local/bin/install-php-extensions \ diff --git a/composer.json b/composer.json index 8489e4824f2..989f20f2c7a 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,6 @@ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", "phpunit/phpunit": "^9.6", - "symfony/phpunit-bridge": "^6.3.8 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { diff --git a/dev-tools/phpstan/baseline.php b/dev-tools/phpstan/baseline.php index f5996765a62..cbe253599f4 100644 --- a/dev-tools/phpstan/baseline.php +++ b/dev-tools/phpstan/baseline.php @@ -221,21 +221,6 @@ 'count' => 1, 'path' => __DIR__ . '/../../src/Fixer/Import/GlobalNamespaceImportFixer.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method PhpCsFixer\\\\Fixer\\\\Import\\\\GlobalNamespaceImportFixer\\:\\:filterUseDeclarations\\(\\) return type has no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Import/GlobalNamespaceImportFixer.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method PhpCsFixer\\\\Fixer\\\\Import\\\\GlobalNamespaceImportFixer\\:\\:insertImports\\(\\) has parameter \\$imports with no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Import/GlobalNamespaceImportFixer.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method PhpCsFixer\\\\Fixer\\\\Import\\\\GlobalNamespaceImportFixer\\:\\:prepareImports\\(\\) has parameter \\$global with no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/../../src/Fixer/Import/GlobalNamespaceImportFixer.php', -]; $ignoreErrors[] = [ 'message' => '#^Method PhpCsFixer\\\\Fixer\\\\Import\\\\OrderedImportsFixer\\:\\:getNewOrder\\(\\) return type has no value type specified in iterable type array\\.$#', 'count' => 1, @@ -422,7 +407,7 @@ 'path' => __DIR__ . '/../../src/Tokenizer/Tokens.php', ]; $ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$array \\(array\\\\) of method PhpCsFixer\\\\Tokenizer\\\\Tokens\\:\\:fromArray\\(\\) should be contravariant with parameter \\$array \\(array\\\\) of method SplFixedArray\\\\:\\:fromArray\\(\\)$#', + 'message' => '#^Parameter \\#1 \\$array \\(array\\\\) of method PhpCsFixer\\\\Tokenizer\\\\Tokens\\:\\:fromArray\\(\\) should be contravariant with parameter \\$array \\(array\\\\) of method SplFixedArray\\\\:\\:fromArray\\(\\)$#', 'count' => 1, 'path' => __DIR__ . '/../../src/Tokenizer/Tokens.php', ]; diff --git a/doc/rules/import/fully_qualified_strict_types.rst b/doc/rules/import/fully_qualified_strict_types.rst index 09afc46e288..ed9f59a61da 100644 --- a/doc/rules/import/fully_qualified_strict_types.rst +++ b/doc/rules/import/fully_qualified_strict_types.rst @@ -10,6 +10,15 @@ interfaces. Configuration ------------- +``import_symbols`` +~~~~~~~~~~~~~~~~~~ + +Whether FQCNs found during analysis should be automatically imported. + +Allowed types: ``bool`` + +Default value: ``false`` + ``leading_backslash_in_global_namespace`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -122,6 +131,46 @@ With configuration: ``['leading_backslash_in_global_namespace' => true]``. } } +Example #4 +~~~~~~~~~~ + +With configuration: ``['import_symbols' => true]``. + +.. code-block:: diff + + --- Original + +++ New + - - - - diff --git a/src/AbstractFunctionReferenceFixer.php b/src/AbstractFunctionReferenceFixer.php index 97a92deff10..dfddeb51672 100644 --- a/src/AbstractFunctionReferenceFixer.php +++ b/src/AbstractFunctionReferenceFixer.php @@ -43,7 +43,7 @@ public function isRisky(): bool * Looks up Tokens sequence for suitable candidates and delivers boundaries information, * which can be supplied by other methods in this abstract class. * - * @return null|int[] returns $functionName, $openParenthesis, $closeParenthesis packed into array + * @return ?array{int, int, int} returns $functionName, $openParenthesis, $closeParenthesis packed into array */ protected function find(string $functionNameToSearch, Tokens $tokens, int $start = 0, ?int $end = null): ?array { diff --git a/src/AbstractPhpdocToTypeDeclarationFixer.php b/src/AbstractPhpdocToTypeDeclarationFixer.php index ef1dfb85727..17ab4fde8b3 100644 --- a/src/AbstractPhpdocToTypeDeclarationFixer.php +++ b/src/AbstractPhpdocToTypeDeclarationFixer.php @@ -103,7 +103,7 @@ protected function findFunctionDocComment(Tokens $tokens, int $index): ?int } /** - * @return Annotation[] + * @return list */ protected function getAnnotationsFromDocComment(string $name, Tokens $tokens, int $docCommentIndex): array { @@ -123,7 +123,7 @@ protected function getAnnotationsFromDocComment(string $name, Tokens $tokens, in } /** - * @return Token[] + * @return list */ protected function createTypeDeclarationTokens(string $type, bool $isNullable): array { diff --git a/src/AbstractPhpdocTypesFixer.php b/src/AbstractPhpdocTypesFixer.php index c7266c6d21f..8482883d0b4 100644 --- a/src/AbstractPhpdocTypesFixer.php +++ b/src/AbstractPhpdocTypesFixer.php @@ -31,7 +31,7 @@ abstract class AbstractPhpdocTypesFixer extends AbstractFixer /** * The annotation tags search inside. * - * @var string[] + * @var list */ protected array $tags; @@ -93,17 +93,16 @@ private function fixTypes(Annotation $annotation): void } /** - * @param string[] $types + * @param list $types * - * @return string[] + * @return list */ private function normalizeTypes(array $types): array { - foreach ($types as $index => $type) { - $types[$index] = $this->normalizeType($type); - } - - return $types; + return array_map( + fn (string $type): string => $this->normalizeType($type), + $types + ); } /** diff --git a/src/Cache/Cache.php b/src/Cache/Cache.php index dfa70634aa6..1f53fd2baf6 100644 --- a/src/Cache/Cache.php +++ b/src/Cache/Cache.php @@ -75,7 +75,7 @@ public function toJson(): string 'hashes' => $this->hashes, ]); - if (JSON_ERROR_NONE !== json_last_error()) { + if (JSON_ERROR_NONE !== json_last_error() || false === $json) { throw new \UnexpectedValueException(sprintf( 'Cannot encode cache signature to JSON, error: "%s". If you have non-UTF8 chars in your signature, like in license for `header_comment`, consider enabling `ext-mbstring` or install `symfony/polyfill-mbstring`.', json_last_error_msg() diff --git a/src/Console/Command/DescribeCommand.php b/src/Console/Command/DescribeCommand.php index 2f7f45d40aa..bcc5272684f 100644 --- a/src/Console/Command/DescribeCommand.php +++ b/src/Console/Command/DescribeCommand.php @@ -56,7 +56,7 @@ final class DescribeCommand extends Command protected static $defaultName = 'describe'; /** - * @var string[] + * @var ?list */ private $setNames; @@ -400,7 +400,7 @@ private function getFixers(): array } /** - * @return string[] + * @return list */ private function getSetNames(): array { diff --git a/src/Console/ConfigurationResolver.php b/src/Console/ConfigurationResolver.php index 5b2a398f833..7fec9445d69 100644 --- a/src/Console/ConfigurationResolver.php +++ b/src/Console/ConfigurationResolver.php @@ -531,7 +531,7 @@ public function configFinderIsOverridden(): bool /** * Compute file candidates for config file. * - * @return string[] + * @return list */ private function computeConfigFiles(): array { diff --git a/src/Console/WarningsDetector.php b/src/Console/WarningsDetector.php index f5ce04c28d3..0f15baf41a4 100644 --- a/src/Console/WarningsDetector.php +++ b/src/Console/WarningsDetector.php @@ -60,7 +60,7 @@ public function detectOldVendor(): void } /** - * @return string[] + * @return list */ public function getWarnings(): array { diff --git a/src/DocBlock/Annotation.php b/src/DocBlock/Annotation.php index c4a0444c7f3..12f1ae8b449 100644 --- a/src/DocBlock/Annotation.php +++ b/src/DocBlock/Annotation.php @@ -29,7 +29,7 @@ final class Annotation /** * All the annotation tag names with types. * - * @var string[] + * @var list */ private static array $tags = [ 'method', @@ -81,7 +81,7 @@ final class Annotation /** * The cached types. * - * @var null|string[] + * @var null|list */ private $types; @@ -125,7 +125,7 @@ public function __toString(): string /** * Get all the annotation tag names with types. * - * @return string[] + * @return list */ public static function getTagsWithTypes(): array { @@ -192,7 +192,7 @@ public function getVariableName() /** * Get the types associated with this annotation. * - * @return string[] + * @return list */ public function getTypes(): array { @@ -209,7 +209,7 @@ public function getTypes(): array /** * Set the types associated with this annotation. * - * @param string[] $types + * @param list $types */ public function setTypes(array $types): void { @@ -223,7 +223,7 @@ public function setTypes(array $types): void /** * Get the normalized types associated with this annotation, so they can easily be compared. * - * @return string[] + * @return list */ public function getNormalizedTypes(): array { diff --git a/src/DocBlock/TypeExpression.php b/src/DocBlock/TypeExpression.php index 505e0b3d3a1..89d75c6447c 100644 --- a/src/DocBlock/TypeExpression.php +++ b/src/DocBlock/TypeExpression.php @@ -210,7 +210,7 @@ public function toString(): string } /** - * @return string[] + * @return list */ public function getTypes(): array { @@ -594,7 +594,7 @@ private function normalize(string $type): string } /** - * @return array + * @return array */ private function getAliases(): array { diff --git a/src/Doctrine/Annotation/DocLexer.php b/src/Doctrine/Annotation/DocLexer.php index b451d00bfac..ef1878ea241 100644 --- a/src/Doctrine/Annotation/DocLexer.php +++ b/src/Doctrine/Annotation/DocLexer.php @@ -75,7 +75,7 @@ final class DocLexer private int $peek = 0; - private ?string $regex; + private ?string $regex = null; public function setInput(string $input): void { diff --git a/src/Error/ErrorsManager.php b/src/Error/ErrorsManager.php index 3d787a3f4f6..d1d9e0cfc04 100644 --- a/src/Error/ErrorsManager.php +++ b/src/Error/ErrorsManager.php @@ -24,14 +24,14 @@ final class ErrorsManager { /** - * @var Error[] + * @var list */ private array $errors = []; /** * Returns errors reported during linting before fixing. * - * @return Error[] + * @return list */ public function getInvalidErrors(): array { @@ -41,7 +41,7 @@ public function getInvalidErrors(): array /** * Returns errors reported during fixing. * - * @return Error[] + * @return list */ public function getExceptionErrors(): array { @@ -51,7 +51,7 @@ public function getExceptionErrors(): array /** * Returns errors reported during linting after fixing. * - * @return Error[] + * @return list */ public function getLintErrors(): array { diff --git a/src/Fixer/Alias/BacktickToShellExecFixer.php b/src/Fixer/Alias/BacktickToShellExecFixer.php index 351cdad72a1..b59457eae9b 100644 --- a/src/Fixer/Alias/BacktickToShellExecFixer.php +++ b/src/Fixer/Alias/BacktickToShellExecFixer.php @@ -96,8 +96,7 @@ private function fixBackticks(Tokens $tokens, array $backtickTokens): void // Track indices for final override ksort($backtickTokens); $openingBacktickIndex = key($backtickTokens); - end($backtickTokens); - $closingBacktickIndex = key($backtickTokens); + $closingBacktickIndex = array_key_last($backtickTokens); // Strip enclosing backticks array_shift($backtickTokens); diff --git a/src/Fixer/Alias/PowToExponentiationFixer.php b/src/Fixer/Alias/PowToExponentiationFixer.php index a56385e6866..d626a93061c 100644 --- a/src/Fixer/Alias/PowToExponentiationFixer.php +++ b/src/Fixer/Alias/PowToExponentiationFixer.php @@ -205,7 +205,7 @@ private function isParenthesisNeeded(Tokens $tokens, int $argumentStartIndex, in } /** - * @return int[] + * @return list */ private function getAllowedKinds(): array { diff --git a/src/Fixer/Casing/MagicMethodCasingFixer.php b/src/Fixer/Casing/MagicMethodCasingFixer.php index 4a20390640c..544d2cbb9a4 100644 --- a/src/Fixer/Casing/MagicMethodCasingFixer.php +++ b/src/Fixer/Casing/MagicMethodCasingFixer.php @@ -24,7 +24,7 @@ final class MagicMethodCasingFixer extends AbstractFixer { /** - * @var array + * @var array */ private static array $magicNames = [ '__call' => '__call', diff --git a/src/Fixer/Casing/NativeTypeDeclarationCasingFixer.php b/src/Fixer/Casing/NativeTypeDeclarationCasingFixer.php index f2c0ce965b5..726fd398494 100644 --- a/src/Fixer/Casing/NativeTypeDeclarationCasingFixer.php +++ b/src/Fixer/Casing/NativeTypeDeclarationCasingFixer.php @@ -119,15 +119,15 @@ final class NativeTypeDeclarationCasingFixer extends AbstractFixer private FunctionsAnalyzer $functionsAnalyzer; /** - * @var list> + * @var list|string> */ - private array $propertyTypeModifiers; + private array $beforePropertyTypeTokens; public function __construct() { parent::__construct(); - $this->propertyTypeModifiers = [[T_PRIVATE], [T_PROTECTED], [T_PUBLIC], [T_VAR]]; + $this->beforePropertyTypeTokens = ['{', ';', [T_PRIVATE], [T_PROTECTED], [T_PUBLIC], [T_VAR]]; $this->functionTypeHints = [ 'array' => true, @@ -152,7 +152,7 @@ public function __construct() if (\PHP_VERSION_ID >= 8_01_00) { $this->functionTypeHints['never'] = true; - $this->propertyTypeModifiers[] = [T_READONLY]; + $this->beforePropertyTypeTokens[] = [T_READONLY]; } if (\PHP_VERSION_ID >= 8_02_00) { @@ -296,7 +296,7 @@ private function getConstNameIndex(Tokens $tokens, int $index): int private function getNativeTypeHintCandidatesForProperty(Tokens $tokens, int $index): iterable { $propertyNameIndex = $index; - $index = $tokens->getPrevTokenOfKind($index, $this->propertyTypeModifiers); + $index = $tokens->getPrevTokenOfKind($index, $this->beforePropertyTypeTokens); $index = $this->getFirstIndexOfType($tokens, $index); diff --git a/src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.php b/src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.php index ec20f3cad03..e656cfc9e44 100644 --- a/src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.php +++ b/src/Fixer/ClassNotation/SingleTraitInsertPerStatementFixer.php @@ -95,7 +95,7 @@ private function fixTraitUse(Tokens $tokens, int $useTraitIndex, array $candidat } /** - * @return int[] + * @return list */ private function getCandidates(Tokens $tokens, int $index): array { diff --git a/src/Fixer/DeprecatedFixerInterface.php b/src/Fixer/DeprecatedFixerInterface.php index 6d7d7e840d8..eded1614893 100644 --- a/src/Fixer/DeprecatedFixerInterface.php +++ b/src/Fixer/DeprecatedFixerInterface.php @@ -22,7 +22,7 @@ interface DeprecatedFixerInterface extends FixerInterface /** * Returns names of fixers to use instead, if any. * - * @return string[] + * @return list */ public function getSuccessorsNames(): array; } diff --git a/src/Fixer/FunctionNotation/FopenFlagOrderFixer.php b/src/Fixer/FunctionNotation/FopenFlagOrderFixer.php index edf0bf6c502..3bf72e223f4 100644 --- a/src/Fixer/FunctionNotation/FopenFlagOrderFixer.php +++ b/src/Fixer/FunctionNotation/FopenFlagOrderFixer.php @@ -85,9 +85,9 @@ protected function fixFopenFlagToken(Tokens $tokens, int $argumentStartIndex, in } /** - * @param string[] $flags + * @param list $flags * - * @return string[] + * @return list */ private function sortFlags(array $flags): array { diff --git a/src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php b/src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php index 22f180effc9..d852339eef6 100644 --- a/src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php +++ b/src/Fixer/FunctionNotation/NoSpacesAfterFunctionNameFixer.php @@ -133,7 +133,7 @@ private function getBraceAfterVariableKinds(): array /** * Gets the token kinds which can work as function calls. * - * @return int[] Token names + * @return list Token names */ private function getFunctionyTokenKinds(): array { diff --git a/src/Fixer/FunctionNotation/VoidReturnFixer.php b/src/Fixer/FunctionNotation/VoidReturnFixer.php index 65e8268dade..150931dd400 100644 --- a/src/Fixer/FunctionNotation/VoidReturnFixer.php +++ b/src/Fixer/FunctionNotation/VoidReturnFixer.php @@ -220,7 +220,7 @@ private function fixFunctionDefinition(Tokens $tokens, int $index): void * * @param int $index The index of the function token * - * @return Annotation[] + * @return list */ private function findReturnAnnotations(Tokens $tokens, int $index): array { diff --git a/src/Fixer/Import/FullyQualifiedStrictTypesFixer.php b/src/Fixer/Import/FullyQualifiedStrictTypesFixer.php index eeeceecc16d..b306d1fe384 100644 --- a/src/Fixer/Import/FullyQualifiedStrictTypesFixer.php +++ b/src/Fixer/Import/FullyQualifiedStrictTypesFixer.php @@ -16,6 +16,7 @@ use PhpCsFixer\AbstractFixer; use PhpCsFixer\Fixer\ConfigurableFixerInterface; +use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; use PhpCsFixer\FixerConfiguration\FixerOptionBuilder; @@ -27,6 +28,7 @@ use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer; use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer; use PhpCsFixer\Tokenizer\CT; +use PhpCsFixer\Tokenizer\Processor\ImportProcessor; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; @@ -36,8 +38,17 @@ * @author Greg Korba * @author SpacePossum */ -final class FullyQualifiedStrictTypesFixer extends AbstractFixer implements ConfigurableFixerInterface +final class FullyQualifiedStrictTypesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface { + /** + * @var array{ + * const?: array, + * class?: array, + * function?: array + * } + */ + private array $symbolsForImport = []; + public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( @@ -113,6 +124,26 @@ class SomeClass implements \Foo\Bar\Baz ', ['leading_backslash_in_global_namespace' => true] ), + new CodeSample( + ' true] + ), ] ); } @@ -120,7 +151,7 @@ class SomeClass implements \Foo\Bar\Baz /** * {@inheritdoc} * - * Must run before NoSuperfluousPhpdocTagsFixer. + * Must run before NoSuperfluousPhpdocTagsFixer, OrderedImportsFixer, StatementIndentationFixer. * Must run after PhpdocToReturnTypeFixer. */ public function getPriority(): int @@ -150,6 +181,13 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn ->setAllowedTypes(['bool']) ->setDefault(false) ->getOption(), + (new FixerOptionBuilder( + 'import_symbols', + 'Whether FQCNs found during analysis should be automatically imported.' + )) + ->setAllowedTypes(['bool']) + ->setDefault(false) + ->getOption(), ]); } @@ -161,9 +199,11 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void foreach ($tokens->getNamespaceDeclarations() as $namespace) { $namespaceName = strtolower($namespace->getFullName()); $uses = []; + $lastUse = null; foreach ($namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace) as $use) { - $uses[strtolower(ltrim($use->getFullName(), '\\'))] = $use->getShortName(); + $uses[$this->normaliseSymbolName($use->getFullName())] = $use->getShortName(); + $lastUse = $use; } for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) { @@ -181,6 +221,15 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void $this->fixPhpDoc($tokens, $index, $uses, $namespaceName); } } + + if (true === $this->configuration['import_symbols'] && [] !== $this->symbolsForImport) { + $atIndex = (null !== $lastUse) ? $lastUse->getEndIndex() + 1 : $namespace->getEndIndex() + 1; + + // Insert all registered FQCNs + $this->createImportProcessor()->insertImports($tokens, $this->symbolsForImport, $atIndex); + + $this->symbolsForImport = []; + } } } @@ -221,6 +270,10 @@ private function fixPhpDoc(Tokens $tokens, int $index, array $uses, string $name continue; } + if (true === $this->configuration['import_symbols'] && isset($matches[2][0])) { + $this->registerSymbolForImport('class', $matches[2][0], $uses, $namespaceName); + } + $shortTokens = $this->determineShortType($typeName, $uses, $namespaceName); if (null !== $shortTokens) { @@ -245,6 +298,8 @@ private function fixPhpDoc(Tokens $tokens, int $index, array $uses, string $name */ private function fixExtendsImplements(Tokens $tokens, int $index, array $uses, string $namespaceName): void { + // We handle `extends` and `implements` with similar logic, but we need to exit the loop under different conditions. + $isExtends = $tokens[$index]->equals([T_EXTENDS]); $index = $tokens->getNextMeaningfulToken($index); $extend = ['content' => '', 'tokens' => []]; @@ -252,7 +307,7 @@ private function fixExtendsImplements(Tokens $tokens, int $index, array $uses, s if ($tokens[$index]->equalsAny([',', '{', [T_IMPLEMENTS]])) { $this->shortenClassIfPossible($tokens, $extend, $uses, $namespaceName); - if ($tokens[$index]->equals('{')) { + if ($tokens[$index]->equalsAny($isExtends ? [[T_IMPLEMENTS], '{'] : ['{'])) { break; } @@ -328,6 +383,10 @@ private function shortenClassIfPossible(Tokens $tokens, array $class, array $use { $longTypeContent = $class['content']; + if (true === $this->configuration['import_symbols']) { + $this->registerSymbolForImport('class', $longTypeContent, $uses, $namespaceName); + } + if (str_starts_with($longTypeContent, '\\')) { $typeName = substr($longTypeContent, 1); $typeNameLower = strtolower($typeName); @@ -382,6 +441,10 @@ private function replaceByShortType(Tokens $tokens, TypeAnalysis $type, array $u return; } + if (true === $this->configuration['import_symbols']) { + $this->registerSymbolForImport('class', $typeName, $uses, $namespaceName); + } + $shortType = $this->determineShortType($typeName, $uses, $namespaceName); if (null !== $shortType) { @@ -531,7 +594,7 @@ private function getTypes(Tokens $tokens, int $index, int $endIndex): iterable } /** - * @return Token[] + * @return list */ private function namespacedStringToTokens(string $input, bool $withLeadingBackslash = false): array { @@ -552,4 +615,60 @@ private function namespacedStringToTokens(string $input, bool $withLeadingBacksl return $tokens; } + + /** + * We need to create import processor dynamically (not in costructor), because actual whitespace configuration + * is set later, not when fixer's instance is created. + */ + private function createImportProcessor(): ImportProcessor + { + return new ImportProcessor($this->whitespacesConfig); + } + + /** + * @param "class"|"const"|"function" $kind + * @param class-string $symbol + * @param array $uses + */ + private function registerSymbolForImport(string $kind, string $symbol, array &$uses, string $namespaceName): void + { + $normalisedName = $this->normaliseSymbolName($symbol); + + // Do NOT register symbol for importing if: + if ( + // we already have the symbol in existing imports + isset($uses[$normalisedName]) + // or if the symbol is not a FQCN + || !str_starts_with($symbol, '\\') + // or if it's a global symbol + || strpos($symbol, '\\') === strrpos($symbol, '\\') + ) { + return; + } + + $shortSymbol = substr($symbol, strrpos($symbol, '\\') + 1); + $importedShortNames = array_map( + static fn (string $name): string => strtolower($name), + array_values($uses) + ); + + // If symbol + if (\in_array(strtolower($shortSymbol), $importedShortNames, true)) { + return; + } + + $this->symbolsForImport[$kind][$normalisedName] = ltrim($symbol, '\\'); + ksort($this->symbolsForImport[$kind], SORT_NATURAL); + + // We must fake that the symbol is imported, so that it can be shortened. + $uses[$normalisedName] = $shortSymbol; + } + + /** + * @param class-string $name + */ + private function normaliseSymbolName(string $name): string + { + return strtolower(ltrim($name, '\\')); + } } diff --git a/src/Fixer/Import/GlobalNamespaceImportFixer.php b/src/Fixer/Import/GlobalNamespaceImportFixer.php index 16447192cfd..9d2e528fe1c 100644 --- a/src/Fixer/Import/GlobalNamespaceImportFixer.php +++ b/src/Fixer/Import/GlobalNamespaceImportFixer.php @@ -31,6 +31,7 @@ use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer; use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer; use PhpCsFixer\Tokenizer\CT; +use PhpCsFixer\Tokenizer\Processor\ImportProcessor; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; use PhpCsFixer\Tokenizer\TokensAnalyzer; @@ -40,6 +41,15 @@ */ final class GlobalNamespaceImportFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface { + private ImportProcessor $importProcessor; + + public function __construct() + { + parent::__construct(); + + $this->importProcessor = new ImportProcessor($this->whitespacesConfig); + } + public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( @@ -90,7 +100,7 @@ public function getDefinition(): FixerDefinitionInterface /** * {@inheritdoc} * - * Must run before NoUnusedImportsFixer, OrderedImportsFixer. + * Must run before NoUnusedImportsFixer, OrderedImportsFixer, StatementIndentationFixer. * Must run after NativeConstantInvocationFixer, NativeFunctionInvocationFixer. */ public function getPriority(): int @@ -139,7 +149,15 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void $newImports = array_filter($newImports); if (\count($newImports) > 0) { - $this->insertImports($tokens, $newImports, $useDeclarations); + if (\count($useDeclarations) > 0) { + $useDeclaration = end($useDeclarations); + $atIndex = $useDeclaration->getEndIndex() + 1; + } else { + $namespace = $tokens->getNamespaceDeclarations()[0]; + $atIndex = $namespace->getEndIndex() + 1; + } + + $this->importProcessor->insertImports($tokens, $newImports, $atIndex); } } @@ -391,16 +409,17 @@ private function importClasses(Tokens $tokens, array $useDeclarations): array } } - return $imports + $this->prepareImports($tokens, $indices, $global, $other, false); + return array_merge($imports, $this->prepareImports($tokens, $indices, $global, $other, false)); } /** * Removes the leading slash at the given indices (when the name is not already used). * - * @param int[] $indices - * @param array $other + * @param int[] $indices + * @param array $global + * @param array $other * - * @return array array keys contain the names that must be imported + * @return array array keys contain the names that must be imported */ private function prepareImports(Tokens $tokens, array $indices, array $global, array $other, bool $caseSensitive): array { @@ -426,49 +445,6 @@ private function prepareImports(Tokens $tokens, array $indices, array $global, a return $imports; } - /** - * @param NamespaceUseAnalysis[] $useDeclarations - */ - private function insertImports(Tokens $tokens, array $imports, array $useDeclarations): void - { - if (\count($useDeclarations) > 0) { - $useDeclaration = end($useDeclarations); - $index = $useDeclaration->getEndIndex() + 1; - } else { - $namespace = $tokens->getNamespaceDeclarations()[0]; - $index = $namespace->getEndIndex() + 1; - } - - $lineEnding = $this->whitespacesConfig->getLineEnding(); - - if (!$tokens[$index]->isWhitespace() || !str_contains($tokens[$index]->getContent(), "\n")) { - $tokens->insertAt($index, new Token([T_WHITESPACE, $lineEnding])); - } - - foreach ($imports as $type => $typeImports) { - foreach ($typeImports as $name) { - $items = [ - new Token([T_WHITESPACE, $lineEnding]), - new Token([T_USE, 'use']), - new Token([T_WHITESPACE, ' ']), - ]; - - if ('const' === $type) { - $items[] = new Token([CT::T_CONST_IMPORT, 'const']); - $items[] = new Token([T_WHITESPACE, ' ']); - } elseif ('function' === $type) { - $items[] = new Token([CT::T_FUNCTION_IMPORT, 'function']); - $items[] = new Token([T_WHITESPACE, ' ']); - } - - $items[] = new Token([T_STRING, $name]); - $items[] = new Token(';'); - - $tokens->insertAt($index, $items); - } - } - } - /** * @param NamespaceUseAnalysis[] $useDeclarations */ @@ -480,7 +456,7 @@ private function fullyQualifyConstants(Tokens $tokens, array $useDeclarations): [$global] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isConstant() && !$declaration->isAliased(), true); - if (!$global) { + if ([] === $global) { return; } @@ -520,7 +496,7 @@ private function fullyQualifyFunctions(Tokens $tokens, array $useDeclarations): [$global] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isFunction() && !$declaration->isAliased(), false); - if (!$global) { + if ([] === $global) { return; } @@ -560,7 +536,7 @@ private function fullyQualifyClasses(Tokens $tokens, array $useDeclarations): vo [$global] = $this->filterUseDeclarations($useDeclarations, static fn (NamespaceUseAnalysis $declaration): bool => $declaration->isClass() && !$declaration->isAliased(), false); - if (!$global) { + if ([] === $global) { return; } @@ -609,6 +585,8 @@ private function fullyQualifyClasses(Tokens $tokens, array $useDeclarations): vo /** * @param NamespaceUseAnalysis[] $declarations + * + * @return array{0: array, 1: array} */ private function filterUseDeclarations(array $declarations, callable $callback, bool $caseSensitive): array { diff --git a/src/Fixer/Import/OrderedImportsFixer.php b/src/Fixer/Import/OrderedImportsFixer.php index 4036774691e..e23dd7118ab 100644 --- a/src/Fixer/Import/OrderedImportsFixer.php +++ b/src/Fixer/Import/OrderedImportsFixer.php @@ -175,7 +175,7 @@ public function getDefinition(): FixerDefinitionInterface * {@inheritdoc} * * Must run before BlankLineBetweenImportGroupsFixer. - * Must run after GlobalNamespaceImportFixer, NoLeadingImportSlashFixer. + * Must run after FullyQualifiedStrictTypesFixer, GlobalNamespaceImportFixer, NoLeadingImportSlashFixer. */ public function getPriority(): int { diff --git a/src/Fixer/Import/SingleImportPerStatementFixer.php b/src/Fixer/Import/SingleImportPerStatementFixer.php index 2ced868cc9f..1e071157631 100644 --- a/src/Fixer/Import/SingleImportPerStatementFixer.php +++ b/src/Fixer/Import/SingleImportPerStatementFixer.php @@ -143,7 +143,7 @@ private function getGroupDeclaration(Tokens $tokens, int $index): array } /** - * @return string[] + * @return list */ private function getGroupStatements(Tokens $tokens, string $groupPrefix, int $groupOpenIndex, int $groupCloseIndex, string $comment): array { diff --git a/src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php b/src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php index 10e19180fad..5a15c9e6b6c 100644 --- a/src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php +++ b/src/Fixer/LanguageConstruct/CombineConsecutiveIssetsFixer.php @@ -104,7 +104,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void } /** - * @param int[] $indices + * @param list $indices */ private function clearTokens(Tokens $tokens, array $indices): void { @@ -146,9 +146,9 @@ private function getIssetInfo(Tokens $tokens, int $index): array } /** - * @param int[] $indices + * @param list $indices * - * @return Token[] + * @return list */ private function getTokenClones(Tokens $tokens, array $indices): array { diff --git a/src/Fixer/PhpTag/EchoTagSyntaxFixer.php b/src/Fixer/PhpTag/EchoTagSyntaxFixer.php index ed09a485424..7c61daadc45 100644 --- a/src/Fixer/PhpTag/EchoTagSyntaxFixer.php +++ b/src/Fixer/PhpTag/EchoTagSyntaxFixer.php @@ -226,7 +226,7 @@ private function isComplexCode(Tokens $tokens, int $index): bool /** * Builds the list of tokens that replace a long echo sequence. * - * @return Token[] + * @return list */ private function buildLongToShortTokens(Tokens $tokens, int $openTagIndex, int $echoTagIndex): array { diff --git a/src/Fixer/PhpUnit/PhpUnitConstructFixer.php b/src/Fixer/PhpUnit/PhpUnitConstructFixer.php index a3b8cf7efb4..58c2c7f6820 100644 --- a/src/Fixer/PhpUnit/PhpUnitConstructFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitConstructFixer.php @@ -33,7 +33,7 @@ final class PhpUnitConstructFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface { /** - * @var array + * @var array */ private static array $assertionFixers = [ 'assertSame' => 'fixAssertPositive', diff --git a/src/Fixer/PhpUnit/PhpUnitStrictFixer.php b/src/Fixer/PhpUnit/PhpUnitStrictFixer.php index 4d5325661c5..5d3d565f1e9 100644 --- a/src/Fixer/PhpUnit/PhpUnitStrictFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitStrictFixer.php @@ -34,7 +34,7 @@ final class PhpUnitStrictFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface { /** - * @var array + * @var array */ private static array $assertionMap = [ 'assertAttributeEquals' => 'assertAttributeSame', diff --git a/src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php b/src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php index abee1f2ee58..3ae0ca06a28 100644 --- a/src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitTestAnnotationFixer.php @@ -225,7 +225,7 @@ private function createDocBlock(Tokens $tokens, int $docBlockIndex): void } /** - * @return Line[] + * @return list */ private function updateDocBlock(Tokens $tokens, int $docBlockIndex): array { @@ -236,9 +236,9 @@ private function updateDocBlock(Tokens $tokens, int $docBlockIndex): array } /** - * @param Line[] $lines + * @param list $lines * - * @return Line[] + * @return list */ private function updateLines(array $lines, Tokens $tokens, int $docBlockIndex): array { diff --git a/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php b/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php index 692389c8563..53c380a51d0 100644 --- a/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php +++ b/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php @@ -51,7 +51,7 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i public const CALL_TYPE_STATIC = 'static'; /** - * @var array + * @var array */ private array $staticMethods = [ // Assert methods @@ -100,11 +100,11 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i 'assertDirectoryNotIsWritable' => true, 'assertDoesNotMatchRegularExpression' => true, 'assertEmpty' => true, - 'assertEqualXMLStructure' => true, 'assertEquals' => true, 'assertEqualsCanonicalizing' => true, 'assertEqualsIgnoringCase' => true, 'assertEqualsWithDelta' => true, + 'assertEqualXMLStructure' => true, 'assertFalse' => true, 'assertFileDoesNotExist' => true, 'assertFileEquals' => true, @@ -115,6 +115,8 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i 'assertFileIsNotWritable' => true, 'assertFileIsReadable' => true, 'assertFileIsWritable' => true, + 'assertFileMatchesFormat' => true, + 'assertFileMatchesFormatFile' => true, 'assertFileNotEquals' => true, 'assertFileNotEqualsCanonicalizing' => true, 'assertFileNotEqualsIgnoringCase' => true, @@ -134,6 +136,7 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i 'assertIsFloat' => true, 'assertIsInt' => true, 'assertIsIterable' => true, + 'assertIsList' => true, 'assertIsNotArray' => true, 'assertIsNotBool' => true, 'assertIsNotCallable' => true, @@ -196,11 +199,13 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i 'assertSameSize' => true, 'assertStringContainsString' => true, 'assertStringContainsStringIgnoringCase' => true, + 'assertStringContainsStringIgnoringLineEndings' => true, 'assertStringEndsNotWith' => true, 'assertStringEndsWith' => true, 'assertStringEqualsFile' => true, 'assertStringEqualsFileCanonicalizing' => true, 'assertStringEqualsFileIgnoringCase' => true, + 'assertStringEqualsStringIgnoringLineEndings' => true, 'assertStringMatchesFormat' => true, 'assertStringMatchesFormatFile' => true, 'assertStringNotContainsString' => true, @@ -250,6 +255,7 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i 'isInfinite' => true, 'isInstanceOf' => true, 'isJson' => true, + 'isList' => true, 'isNan' => true, 'isNull' => true, 'isReadable' => true, @@ -272,6 +278,7 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i 'resetCount' => true, 'stringContains' => true, 'stringEndsWith' => true, + 'stringEqualsStringIgnoringLineEndings' => true, 'stringStartsWith' => true, // TestCase methods @@ -295,7 +302,7 @@ final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer i ]; /** - * @var array + * @var array */ private array $allowedValues = [ self::CALL_TYPE_THIS => true, diff --git a/src/Fixer/Phpdoc/PhpdocParamOrderFixer.php b/src/Fixer/Phpdoc/PhpdocParamOrderFixer.php index fb3f41240d0..3f534dba95e 100644 --- a/src/Fixer/Phpdoc/PhpdocParamOrderFixer.php +++ b/src/Fixer/Phpdoc/PhpdocParamOrderFixer.php @@ -164,7 +164,7 @@ private function rewriteDocBlock(DocBlock $doc, array $paramNames, array $paramA * @param Token[] $funcParamNames * @param Annotation[] $paramAnnotations * - * @return string[] + * @return list */ private function sortParamAnnotations(array $funcParamNames, array $paramAnnotations): array { @@ -199,7 +199,7 @@ private function sortParamAnnotations(array $funcParamNames, array $paramAnnotat * * @param Annotation[] $paramAnnotations * - * @return string[] + * @return list */ private function getOtherAnnotationsBetweenParams(DocBlock $doc, array $paramAnnotations): array { diff --git a/src/Fixer/Phpdoc/PhpdocTypesFixer.php b/src/Fixer/Phpdoc/PhpdocTypesFixer.php index 761f0b55bb5..c4376d8e807 100644 --- a/src/Fixer/Phpdoc/PhpdocTypesFixer.php +++ b/src/Fixer/Phpdoc/PhpdocTypesFixer.php @@ -35,7 +35,7 @@ final class PhpdocTypesFixer extends AbstractPhpdocTypesFixer implements Configu /** * Available types, grouped. * - * @var array + * @var array */ private const POSSIBLE_TYPES = [ 'simple' => [ diff --git a/src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php b/src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php index 7cd26008904..7b52985c1de 100644 --- a/src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php +++ b/src/Fixer/Phpdoc/PhpdocTypesOrderFixer.php @@ -165,7 +165,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void } /** - * @return string[] + * @return list */ private function sortTypes(TypeExpression $typeExpression): array { diff --git a/src/Fixer/Whitespace/StatementIndentationFixer.php b/src/Fixer/Whitespace/StatementIndentationFixer.php index d22d50dd496..d15f56c8aad 100644 --- a/src/Fixer/Whitespace/StatementIndentationFixer.php +++ b/src/Fixer/Whitespace/StatementIndentationFixer.php @@ -64,7 +64,7 @@ public function getDefinition(): FixerDefinitionInterface * {@inheritdoc} * * Must run before HeredocIndentationFixer. - * Must run after BracesPositionFixer, ClassAttributesSeparationFixer, CurlyBracesPositionFixer, MethodArgumentSpaceFixer, NoUselessElseFixer, YieldFromArrayToYieldsFixer. + * Must run after BracesPositionFixer, ClassAttributesSeparationFixer, CurlyBracesPositionFixer, FullyQualifiedStrictTypesFixer, GlobalNamespaceImportFixer, MethodArgumentSpaceFixer, NoUselessElseFixer, YieldFromArrayToYieldsFixer. */ public function getPriority(): int { diff --git a/src/FixerFactory.php b/src/FixerFactory.php index 7ee99bf2560..c49c614659f 100644 --- a/src/FixerFactory.php +++ b/src/FixerFactory.php @@ -83,6 +83,7 @@ public function registerBuiltInFixers(): self static $builtInFixers = null; if (null === $builtInFixers) { + /** @var list> */ $builtInFixers = []; /** @var SplFileInfo $file */ @@ -94,7 +95,9 @@ public function registerBuiltInFixers(): self } foreach ($builtInFixers as $class) { - $this->registerFixer(new $class(), false); + /** @var FixerInterface */ + $fixer = new $class(); + $this->registerFixer($fixer, false); } return $this; @@ -195,7 +198,7 @@ public function hasRule(string $name): bool } /** - * @return string[] + * @return list */ private function getFixersConflicts(FixerInterface $fixer): array { diff --git a/src/RuleSet/DeprecatedRuleSetDescriptionInterface.php b/src/RuleSet/DeprecatedRuleSetDescriptionInterface.php index bde2401831c..ae52441d554 100644 --- a/src/RuleSet/DeprecatedRuleSetDescriptionInterface.php +++ b/src/RuleSet/DeprecatedRuleSetDescriptionInterface.php @@ -22,7 +22,7 @@ interface DeprecatedRuleSetDescriptionInterface extends RuleSetDescriptionInterf /** * Returns names of rule sets to use instead, if any. * - * @return string[] + * @return list */ public function getSuccessorsNames(): array; } diff --git a/src/RuleSet/RuleSet.php b/src/RuleSet/RuleSet.php index 7370db763a4..6fb130d31e8 100644 --- a/src/RuleSet/RuleSet.php +++ b/src/RuleSet/RuleSet.php @@ -29,10 +29,10 @@ final class RuleSet implements RuleSetInterface /** * Group of rules generated from input set. * - * The key is name of rule, value is bool if the rule/set should be used. + * The key is name of rule, value is configuration array or true. * The key must not point to any set. * - * @var array|bool> + * @var array|true> */ private array $rules; diff --git a/src/RuleSet/RuleSetInterface.php b/src/RuleSet/RuleSetInterface.php index eb83b6b4aed..024248258ba 100644 --- a/src/RuleSet/RuleSetInterface.php +++ b/src/RuleSet/RuleSetInterface.php @@ -38,7 +38,7 @@ public function getRuleConfiguration(string $rule): ?array; /** * Get all rules from rules set. * - * @return array|bool> + * @return array|true> */ public function getRules(): array; diff --git a/src/RuleSet/RuleSets.php b/src/RuleSet/RuleSets.php index d10ff8c6f1a..54cf276978d 100644 --- a/src/RuleSet/RuleSets.php +++ b/src/RuleSet/RuleSets.php @@ -24,7 +24,7 @@ final class RuleSets { /** - * @var array + * @var array */ private static $setDefinitions; @@ -50,7 +50,7 @@ public static function getSetDefinitions(): array } /** - * @return string[] + * @return list */ public static function getSetDefinitionNames(): array { diff --git a/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php b/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php index a332b244271..27bf893f384 100644 --- a/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php +++ b/src/Tokenizer/Analyzer/Analysis/TypeAnalysis.php @@ -57,7 +57,7 @@ final class TypeAnalysis implements StartEndTokenAwareAnalysis private int $endIndex; - private bool $nullable; + private bool $nullable = false; /** * @param ($startIndex is null ? null : int) $endIndex @@ -65,7 +65,6 @@ final class TypeAnalysis implements StartEndTokenAwareAnalysis public function __construct(string $name, int $startIndex = null, int $endIndex = null) { $this->name = $name; - $this->nullable = false; if (str_starts_with($name, '?')) { $this->name = substr($name, 1); diff --git a/src/Tokenizer/Analyzer/SwitchAnalyzer.php b/src/Tokenizer/Analyzer/SwitchAnalyzer.php index b6142f697f1..d57f580a0de 100644 --- a/src/Tokenizer/Analyzer/SwitchAnalyzer.php +++ b/src/Tokenizer/Analyzer/SwitchAnalyzer.php @@ -41,7 +41,7 @@ public static function belongsToSwitch(Tokens $tokens, int $index): bool } /** - * @return int[] + * @return list */ private static function getColonIndicesForSwitch(Tokens $tokens): array { diff --git a/src/Tokenizer/CodeHasher.php b/src/Tokenizer/CodeHasher.php index ec316615b2d..86a4a68ade8 100644 --- a/src/Tokenizer/CodeHasher.php +++ b/src/Tokenizer/CodeHasher.php @@ -28,6 +28,8 @@ private function __construct() /** * Calculate hash for code. + * + * @return non-empty-string */ public static function calculateCodeHash(string $code): string { diff --git a/src/Tokenizer/Processor/ImportProcessor.php b/src/Tokenizer/Processor/ImportProcessor.php new file mode 100644 index 00000000000..35fb0f9d420 --- /dev/null +++ b/src/Tokenizer/Processor/ImportProcessor.php @@ -0,0 +1,101 @@ + + * Dariusz Rumiński + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace PhpCsFixer\Tokenizer\Processor; + +use PhpCsFixer\Tokenizer\CT; +use PhpCsFixer\Tokenizer\Token; +use PhpCsFixer\Tokenizer\Tokens; +use PhpCsFixer\WhitespacesFixerConfig; + +/** + * @author Greg Korba + */ +final class ImportProcessor +{ + private WhitespacesFixerConfig $whitespacesConfig; + + public function __construct(WhitespacesFixerConfig $whitespacesConfig) + { + $this->whitespacesConfig = $whitespacesConfig; + } + + /** + * @param array{ + * const?: array, + * class?: array, + * function?: array + * } $imports + */ + public function insertImports(Tokens $tokens, array $imports, int $atIndex): void + { + $lineEnding = $this->whitespacesConfig->getLineEnding(); + + if (!$tokens[$atIndex]->isWhitespace() || !str_contains($tokens[$atIndex]->getContent(), "\n")) { + $tokens->insertAt($atIndex, new Token([T_WHITESPACE, $lineEnding])); + } + + foreach ($imports as $type => $typeImports) { + sort($typeImports); + + $items = []; + + foreach ($typeImports as $name) { + $items = array_merge($items, [ + new Token([T_WHITESPACE, $lineEnding]), + new Token([T_USE, 'use']), + new Token([T_WHITESPACE, ' ']), + ]); + + if ('const' === $type) { + $items[] = new Token([CT::T_CONST_IMPORT, 'const']); + $items[] = new Token([T_WHITESPACE, ' ']); + } elseif ('function' === $type) { + $items[] = new Token([CT::T_FUNCTION_IMPORT, 'function']); + $items[] = new Token([T_WHITESPACE, ' ']); + } + + $items = array_merge($items, self::tokenizeName($name)); + $items[] = new Token(';'); + } + + $tokens->insertAt($atIndex, $items); + } + } + + /** + * @param class-string $name + * + * @return list + */ + public static function tokenizeName(string $name): array + { + $parts = explode('\\', $name); + $newTokens = []; + + if ('' === $parts[0]) { + $newTokens[] = new Token([T_NS_SEPARATOR, '\\']); + array_shift($parts); + } + + foreach ($parts as $part) { + $newTokens[] = new Token([T_STRING, $part]); + $newTokens[] = new Token([T_NS_SEPARATOR, '\\']); + } + + array_pop($newTokens); + + return $newTokens; + } +} diff --git a/src/Tokenizer/Token.php b/src/Tokenizer/Token.php index 1009717cbb1..213644c67bb 100644 --- a/src/Tokenizer/Token.php +++ b/src/Tokenizer/Token.php @@ -14,6 +14,8 @@ namespace PhpCsFixer\Tokenizer; +use PhpCsFixer\Utils; + /** * Representation of single token. * As a token prototype you should understand a single element generated by token_get_all. @@ -209,13 +211,20 @@ public function equalsAny(array $others, bool $caseSensitive = true): bool /** * A helper method used to find out whether a certain input token has to be case-sensitively matched. * - * @param bool|list $caseSensitive global case sensitiveness or an array of booleans, whose keys should match - * the ones used in $sequence. If any is missing, the default case-sensitive - * comparison is used - * @param int $key the key of the token that has to be looked up + * @param array|bool $caseSensitive global case sensitiveness or an array of booleans, whose keys should match + * the ones used in $sequence. If any is missing, the default case-sensitive + * comparison is used + * @param int $key the key of the token that has to be looked up + * + * @deprecated */ public static function isKeyCaseSensitive($caseSensitive, int $key): bool { + Utils::triggerDeprecation(new \InvalidArgumentException(sprintf( + 'Method "%s" is deprecated and will be removed in the next major version.', + __METHOD__ + ))); + if (\is_array($caseSensitive)) { return $caseSensitive[$key] ?? true; } @@ -242,6 +251,8 @@ public function getPrototype() * Get token's content. * * It shall be used only for getting the content of token, not for checking it against excepted value. + * + * @return non-empty-string */ public function getContent(): string { diff --git a/src/Tokenizer/Tokens.php b/src/Tokenizer/Tokens.php index a7e2e9ce655..a9ae539234c 100644 --- a/src/Tokenizer/Tokens.php +++ b/src/Tokenizer/Tokens.php @@ -52,7 +52,7 @@ class Tokens extends \SplFixedArray /** * Static class cache. * - * @var array + * @var array */ private static array $cache = []; @@ -72,6 +72,8 @@ class Tokens extends \SplFixedArray /** * A MD5 hash of the code string. + * + * @var ?non-empty-string */ private ?string $codeHash = null; @@ -89,7 +91,7 @@ class Tokens extends \SplFixedArray * was ever seen inside the collection (but may not be part of it any longer). * The key is token kind and the value is always true. * - * @var array + * @var array */ private array $foundTokenKinds = []; @@ -111,7 +113,7 @@ public function __clone() /** * Clear cache - one position or all of them. * - * @param null|string $key position to clear, when null clear all + * @param null|non-empty-string $key position to clear, when null clear all */ public static function clearCache(?string $key = null): void { @@ -127,8 +129,6 @@ public static function clearCache(?string $key = null): void /** * Detect type of block. * - * @param Token $token token - * * @return null|array{type: self::BLOCK_TYPE_*, isStart: bool} */ public static function detectBlockType(Token $token): ?array @@ -149,8 +149,8 @@ public static function detectBlockType(Token $token): ?array /** * Create token collection from array. * - * @param Token[] $array the array to import - * @param ?bool $saveIndices save the numeric indices used in the original array, default is yes + * @param array $array the array to import + * @param ?bool $saveIndices save the numeric indices used in the original array, default is yes */ public static function fromArray($array, $saveIndices = null): self { @@ -457,11 +457,11 @@ public function findBlockStart(int $type, int $searchIndex): int } /** - * @param int|list $possibleKind kind or array of kinds - * @param int $start optional offset - * @param null|int $end optional limit + * @param int|non-empty-list $possibleKind kind or array of kinds + * @param int $start optional offset + * @param null|int $end optional limit * - * @return array>|array + * @return ($possibleKind is int ? array : array>) */ public function findGivenKind($possibleKind, int $start = 0, ?int $end = null): array { @@ -718,14 +718,14 @@ public function getPrevMeaningfulToken(int $index): ?int /** * Find a sequence of meaningful tokens and returns the array of their locations. * - * @param list $sequence an array of token (kinds) - * @param int $start start index, defaulting to the start of the file - * @param null|int $end end index, defaulting to the end of the file - * @param array|bool $caseSensitive global case sensitiveness or a list of booleans, whose keys should match - * the ones used in $sequence. If any is missing, the default case-sensitive - * comparison is used + * @param non-empty-list $sequence an array of token (kinds) + * @param int $start start index, defaulting to the start of the file + * @param null|int $end end index, defaulting to the end of the file + * @param array|bool $caseSensitive global case sensitiveness or a list of booleans, whose keys should match + * the ones used in $sequence. If any is missing, the default case-sensitive + * comparison is used * - * @return null|array an array containing the tokens matching the sequence elements, indexed by their position + * @return null|non-empty-array an array containing the tokens matching the sequence elements, indexed by their position */ public function findSequence(array $sequence, int $start = 0, ?int $end = null, $caseSensitive = true): ?array { @@ -774,7 +774,7 @@ public function findSequence(array $sequence, int $start = 0, ?int $end = null, // remove the first token from the sequence, so we can freely iterate through the sequence after a match to // the first one is found $key = key($sequence); - $firstCs = Token::isKeyCaseSensitive($caseSensitive, $key); + $firstCs = self::isKeyCaseSensitive($caseSensitive, $key); $firstToken = $sequence[$key]; unset($sequence[$key]); @@ -803,7 +803,7 @@ public function findSequence(array $sequence, int $start = 0, ?int $end = null, return null; } - if (!$this[$currIdx]->equals($token, Token::isKeyCaseSensitive($caseSensitive, $key))) { + if (!$this[$currIdx]->equals($token, self::isKeyCaseSensitive($caseSensitive, $key))) { // not a match, restart the outer loop continue 2; } @@ -1307,6 +1307,8 @@ private function findOppositeBlockEdge(int $type, int $searchIndex, bool $findEn /** * Calculate hash for code. + * + * @return non-empty-string */ private static function calculateCodeHash(string $code): string { @@ -1316,7 +1318,7 @@ private static function calculateCodeHash(string $code): string /** * Get cache value for given key. * - * @param string $key item key + * @param non-empty-string $key item key */ private static function getCache(string $key): self { @@ -1330,7 +1332,7 @@ private static function getCache(string $key): self /** * Check if given key exists in cache. * - * @param string $key item key + * @param non-empty-string $key item key */ private static function hasCache(string $key): bool { @@ -1338,8 +1340,8 @@ private static function hasCache(string $key): bool } /** - * @param string $key item key - * @param Tokens $value item value + * @param non-empty-string $key item key + * @param Tokens $value item value */ private static function setCache(string $key, self $value): void { @@ -1351,7 +1353,7 @@ private static function setCache(string $key, self $value): void * * Remove old cache and set new one. * - * @param string $codeHash new code hash + * @param non-empty-string $codeHash new code hash */ private function changeCodeHash(string $codeHash): void { @@ -1371,6 +1373,7 @@ private function changeCodeHash(string $codeHash): void private function registerFoundToken($token): void { // inlined extractTokenKind() call on the hot path + /** @var non-empty-string */ $tokenKind = $token instanceof Token ? ($token->isArray() ? $token->getId() : $token->getContent()) : (\is_array($token) ? $token[0] : $token); @@ -1387,6 +1390,7 @@ private function registerFoundToken($token): void private function unregisterFoundToken($token): void { // inlined extractTokenKind() call on the hot path + /** @var non-empty-string */ $tokenKind = $token instanceof Token ? ($token->isArray() ? $token->getId() : $token->getContent()) : (\is_array($token) ? $token[0] : $token); @@ -1401,7 +1405,7 @@ private function unregisterFoundToken($token): void /** * @param array{int}|string|Token $token token prototype * - * @return int|string + * @return int|non-empty-string */ private function extractTokenKind($token) { @@ -1431,4 +1435,21 @@ private function getTokenNotOfKind(int $index, int $direction, callable $filter) return $index; } } + + /** + * A helper method used to find out whether a certain input token has to be case-sensitively matched. + * + * @param array|bool $caseSensitive global case sensitiveness or an array of booleans, whose keys should match + * the ones used in $sequence. If any is missing, the default case-sensitive + * comparison is used + * @param int $key the key of the token that has to be looked up + */ + private static function isKeyCaseSensitive($caseSensitive, int $key): bool + { + if (\is_array($caseSensitive)) { + return $caseSensitive[$key] ?? true; + } + + return $caseSensitive; + } } diff --git a/src/Tokenizer/Transformer/NameQualifiedTransformer.php b/src/Tokenizer/Transformer/NameQualifiedTransformer.php index b0521954e84..ed8353c8d79 100644 --- a/src/Tokenizer/Transformer/NameQualifiedTransformer.php +++ b/src/Tokenizer/Transformer/NameQualifiedTransformer.php @@ -15,6 +15,7 @@ namespace PhpCsFixer\Tokenizer\Transformer; use PhpCsFixer\Tokenizer\AbstractTransformer; +use PhpCsFixer\Tokenizer\Processor\ImportProcessor; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; @@ -51,38 +52,15 @@ public function getCustomTokens(): array private function transformQualified(Tokens $tokens, Token $token, int $index): void { - $parts = explode('\\', $token->getContent()); - $newTokens = []; - - if ('' === $parts[0]) { - $newTokens[] = new Token([T_NS_SEPARATOR, '\\']); - array_shift($parts); - } - - foreach ($parts as $part) { - $newTokens[] = new Token([T_STRING, $part]); - $newTokens[] = new Token([T_NS_SEPARATOR, '\\']); - } - - array_pop($newTokens); + $newTokens = ImportProcessor::tokenizeName($token->getContent()); $tokens->overrideRange($index, $index, $newTokens); } private function transformRelative(Tokens $tokens, Token $token, int $index): void { - $parts = explode('\\', $token->getContent()); - $newTokens = [ - new Token([T_NAMESPACE, array_shift($parts)]), - new Token([T_NS_SEPARATOR, '\\']), - ]; - - foreach ($parts as $part) { - $newTokens[] = new Token([T_STRING, $part]); - $newTokens[] = new Token([T_NS_SEPARATOR, '\\']); - } - - array_pop($newTokens); + $newTokens = ImportProcessor::tokenizeName($token->getContent()); + $newTokens[0] = new Token([T_NAMESPACE, 'namespace']); $tokens->overrideRange($index, $index, $newTokens); } diff --git a/src/Utils.php b/src/Utils.php index b89d4e186f3..fb3573bb468 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -74,9 +74,9 @@ public static function calculateTrailingWhitespaceIndent(Token $token): string * * Stability is ensured by using Schwartzian transform. * - * @param mixed[] $elements - * @param callable $getComparedValue a callable that takes a single element and returns the value to compare - * @param callable $compareValues a callable that compares two values + * @param list $elements + * @param callable $getComparedValue a callable that takes a single element and returns the value to compare + * @param callable $compareValues a callable that compares two values * * @return mixed[] */ @@ -102,9 +102,9 @@ public static function stableSort(array $elements, callable $getComparedValue, c /** * Sort fixers by their priorities. * - * @param FixerInterface[] $fixers + * @param list $fixers * - * @return FixerInterface[] + * @return list */ public static function sortFixers(array $fixers): array { diff --git a/tests/AutoReview/DocumentationTest.php b/tests/AutoReview/DocumentationTest.php index 1599a14d933..af9b41ac7d1 100644 --- a/tests/AutoReview/DocumentationTest.php +++ b/tests/AutoReview/DocumentationTest.php @@ -22,7 +22,6 @@ use PhpCsFixer\FixerFactory; use PhpCsFixer\RuleSet\RuleSets; use PhpCsFixer\Tests\TestCase; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Finder\Finder; /** @@ -35,8 +34,6 @@ */ final class DocumentationTest extends TestCase { - use ExpectDeprecationTrait; - /** * @dataProvider provideFixerDocumentationFileIsUpToDateCases */ diff --git a/tests/AutoReview/FixerFactoryTest.php b/tests/AutoReview/FixerFactoryTest.php index d56333fcdb7..adf952ffe32 100644 --- a/tests/AutoReview/FixerFactoryTest.php +++ b/tests/AutoReview/FixerFactoryTest.php @@ -448,6 +448,8 @@ private static function getFixersPriorityGraph(): array ], 'fully_qualified_strict_types' => [ 'no_superfluous_phpdoc_tags', + 'ordered_imports', + 'statement_indentation', ], 'function_declaration' => [ 'method_argument_space', @@ -476,6 +478,7 @@ private static function getFixersPriorityGraph(): array 'global_namespace_import' => [ 'no_unused_imports', 'ordered_imports', + 'statement_indentation', ], 'header_comment' => [ 'blank_lines_before_namespace', diff --git a/tests/AutoReview/ProjectCodeTest.php b/tests/AutoReview/ProjectCodeTest.php index b6616c7c21f..e418dc5736c 100644 --- a/tests/AutoReview/ProjectCodeTest.php +++ b/tests/AutoReview/ProjectCodeTest.php @@ -51,6 +51,11 @@ final class ProjectCodeTest extends TestCase */ private static ?array $srcClassCases = null; + /** + * @var array + */ + private static array $fileTokensCache = []; + /** * This structure contains older classes that are not yet covered by tests. * @@ -73,6 +78,7 @@ public static function tearDownAfterClass(): void { self::$srcClassCases = null; self::$testClassCases = null; + self::$fileTokensCache = []; } public function testThatClassesWithoutTestsVarIsProper(): void @@ -177,6 +183,7 @@ public function testThatSrcClassesNotExposeProperties(string $className): void $exceptionPropsPerClass = [ \PhpCsFixer\AbstractPhpdocTypesFixer::class => ['tags'], \PhpCsFixer\AbstractFixer::class => ['configuration', 'configurationDefinition', 'whitespacesConfig'], + \PhpCsFixer\Console\Command\FixCommand::class => ['defaultDescription', 'defaultName'], AbstractProxyFixer::class => ['proxyFixers'], ]; @@ -768,7 +775,11 @@ private function createTokensForClass(string $className): Tokens $file = preg_replace('#^PhpCsFixer\\\#', 'src\\', $file); $file = str_replace('\\', \DIRECTORY_SEPARATOR, $file).'.php'; - return Tokens::fromCode(file_get_contents($file)); + if (!isset(self::$fileTokensCache[$file])) { + self::$fileTokensCache[$file] = Tokens::fromCode(file_get_contents($file)); + } + + return self::$fileTokensCache[$file]; } /** diff --git a/tests/Console/Command/DescribeCommandTest.php b/tests/Console/Command/DescribeCommandTest.php index eb7d64328e4..4e1b640bd6d 100644 --- a/tests/Console/Command/DescribeCommandTest.php +++ b/tests/Console/Command/DescribeCommandTest.php @@ -450,18 +450,18 @@ public function testCommandDescribesCustomFixer(): void } /** - * @param CodeSampleInterface[] $samples + * @param list $samples */ private static function createFixerWithSamplesDouble(array $samples): FixerInterface { return new class($samples) extends AbstractFixer { /** - * @var CodeSampleInterface[] + * @var list */ private $samples; /** - * @param CodeSampleInterface[] $samples + * @param list $samples */ public function __construct( array $samples @@ -503,7 +503,7 @@ public function applyFix(\SplFileInfo $file, Tokens $tokens): void private function createConfigurableDeprecatedFixerDouble(): FixerInterface { return new class() implements ConfigurableFixerInterface, DeprecatedFixerInterface { - /** @var array */ + /** @var array */ private array $configuration; public function configure(array $configuration): void diff --git a/tests/DocBlock/TagComparatorTest.php b/tests/DocBlock/TagComparatorTest.php index cdd5db758ce..8a25c986f7c 100644 --- a/tests/DocBlock/TagComparatorTest.php +++ b/tests/DocBlock/TagComparatorTest.php @@ -39,7 +39,7 @@ public function testComparatorTogether(string $first, string $second, bool $expe $tag1 = new Tag(new Line('* @'.$first)); $tag2 = new Tag(new Line('* @'.$second)); - $this->expectDeprecation('%AMethod PhpCsFixer\DocBlock\TagComparator::shouldBeTogether is deprecated and will be removed in version 4.0.'); + $this->expectDeprecation('Method PhpCsFixer\DocBlock\TagComparator::shouldBeTogether is deprecated and will be removed in version 4.0.'); self::assertSame($expected, TagComparator::shouldBeTogether($tag1, $tag2)); } @@ -77,7 +77,7 @@ public function testComparatorTogetherWithDefinedGroups(array $groups, string $f $tag1 = new Tag(new Line('* @'.$first)); $tag2 = new Tag(new Line('* @'.$second)); - $this->expectDeprecation('%AMethod PhpCsFixer\DocBlock\TagComparator::shouldBeTogether is deprecated and will be removed in version 4.0.'); + $this->expectDeprecation('Method PhpCsFixer\DocBlock\TagComparator::shouldBeTogether is deprecated and will be removed in version 4.0.'); self::assertSame( $expected, diff --git a/tests/FileRemovalTest.php b/tests/FileRemovalTest.php index 0533ca6775c..60f9cb4c050 100644 --- a/tests/FileRemovalTest.php +++ b/tests/FileRemovalTest.php @@ -127,6 +127,8 @@ public function testWakeup(): void * * @runInSeparateProcess * + * @preserveGlobalState disabled + * * @doesNotPerformAssertions */ public function testShutdownRemovesObservedFilesSetup(): void diff --git a/tests/Fixer/Casing/NativeTypeDeclarationCasingFixerTest.php b/tests/Fixer/Casing/NativeTypeDeclarationCasingFixerTest.php index 8f4e959d3cc..335e772b7d5 100644 --- a/tests/Fixer/Casing/NativeTypeDeclarationCasingFixerTest.php +++ b/tests/Fixer/Casing/NativeTypeDeclarationCasingFixerTest.php @@ -246,6 +246,11 @@ class D{} var $bar; }', ]; + + yield 'static property without type' => [ + ' $config + * + * @dataProvider provideInvalidConfigurationCases + */ + public function testInvalidConfiguration(array $config, string $expectedMessage): void { $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches('#^\[cast_spaces\] Invalid configuration: The option "a" does not exist\. Defined options are: "space"\.$#'); + $this->expectExceptionMessageMatches($expectedMessage); - $this->fixer->configure(['a' => 1]); + $this->fixer->configure($config); } - public function testInvalidConfigValue(): void + /** + * @return iterable, string}> + */ + public static function provideInvalidConfigurationCases(): iterable { - $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches('#^\[cast_spaces\] Invalid configuration: The option "space" with value "double" is invalid\. Accepted values are: "none", "single"\.$#'); + yield 'missing key' => [ + ['a' => 1], + '#^\[cast_spaces\] Invalid configuration: The option "a" does not exist\. Defined options are: "space"\.$#', + ]; - $this->fixer->configure(['space' => 'double']); + yield 'invalid value' => [ + ['space' => 'double'], + '#^\[cast_spaces\] Invalid configuration: The option "space" with value "double" is invalid\. Accepted values are: "none", "single"\.$#', + ]; } /** - * @dataProvider provideFixCastsCases + * @param array $configuration + * + * @dataProvider provideFixCases */ - public function testFixCastsWithDefaultConfiguration(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } /** - * @dataProvider provideFixCastsCases + * @return iterable */ - public function testFixCastsSingleSpace(string $expected, ?string $input = null): void - { - $this->fixer->configure(['space' => 'single']); - $this->doTest($expected, $input); - } - - public static function provideFixCastsCases(): iterable + public static function provideFixCases(): iterable { yield [ 'fixer->configure(['space' => 'none']); - $this->doTest($expected, $input); - } - - public static function provideFixCastsNoneSpaceCases(): iterable - { yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; yield [ ' 'none'], ]; } } diff --git a/tests/Fixer/CastNotation/LowercaseCastFixerTest.php b/tests/Fixer/CastNotation/LowercaseCastFixerTest.php index 7644b3f6656..bc0221cd128 100644 --- a/tests/Fixer/CastNotation/LowercaseCastFixerTest.php +++ b/tests/Fixer/CastNotation/LowercaseCastFixerTest.php @@ -32,34 +32,52 @@ public function testFix(string $expected, ?string $input = null): void } /** - * @dataProvider provideFix74DeprecatedCases - * - * @group legacy + * @return iterable + */ + public static function provideFixCases(): iterable + { + $types = ['boolean', 'bool', 'integer', 'int', 'double', 'float', 'float', 'string', 'array', 'object', 'binary']; + + foreach ($types as $from) { + yield from self::createCasesFor($from); + } + } + + /** + * @dataProvider provideFixPre80Cases * * @requires PHP <8.0 */ - public function testFix74Deprecated(string $expected, ?string $input = null): void + public function testFixPre80(string $expected, string $input = null): void { - $this->expectDeprecation('%AThe (real) cast is deprecated, use (float) instead'); - $this->doTest($expected, $input); } - public static function provideFixCases(): iterable + /** + * @return iterable + */ + public static function provideFixPre80Cases(): iterable { - $types = ['boolean', 'bool', 'integer', 'int', 'double', 'float', 'float', 'string', 'array', 'object', 'binary']; + yield from self::createCasesFor('unset'); + } - if (\PHP_VERSION_ID < 8_00_00) { - $types[] = 'unset'; - } + /** + * @dataProvider provideFix74DeprecatedCases + * + * @group legacy + * + * @requires PHP <8.0 + */ + public function testFix74Deprecated(string $expected, ?string $input = null): void + { + $this->expectDeprecation('The (real) cast is deprecated, use (float) instead'); - foreach ($types as $from) { - foreach (self::createCasesFor($from) as $case) { - yield $case; - } - } + $this->doTest($expected, $input); } + /** + * @return iterable + */ public static function provideFix74DeprecatedCases(): iterable { return self::createCasesFor('real'); diff --git a/tests/Fixer/CastNotation/ModernizeTypesCastingFixerTest.php b/tests/Fixer/CastNotation/ModernizeTypesCastingFixerTest.php index f6a828b4350..863a30a32f6 100644 --- a/tests/Fixer/CastNotation/ModernizeTypesCastingFixerTest.php +++ b/tests/Fixer/CastNotation/ModernizeTypesCastingFixerTest.php @@ -226,14 +226,8 @@ public static function provideFixPre80Cases(): iterable 'doTest( + yield [ 'doTest($expected, $input); } - /** - * @dataProvider provideFix74DeprecatedCases - * - * @group legacy - * - * @requires PHP <8.0 - */ - public function testFix74Deprecated(string $expected, ?string $input = null): void - { - $this->expectDeprecation('%AThe (real) cast is deprecated, use (float) instead'); - - $this->doTest($expected, $input); - } - public static function provideFixCases(): iterable { foreach (['boolean' => 'bool', 'integer' => 'int', 'double' => 'float', 'binary' => 'string'] as $from => $to) { - foreach (self::createCasesFor($from, $to) as $case) { - yield $case; - } + yield from self::createCasesFor($from, $to); } - } - public static function provideFix74DeprecatedCases(): iterable - { - return self::createCasesFor('real', 'float'); + $types = ['string', 'array', 'object']; + + foreach ($types as $cast) { + yield [sprintf('doTest($expected); + $this->doTest($expected, $input); } - public static function provideNoFixCases(): iterable + /** + * @return iterable + */ + public static function provideFixPre80Cases(): iterable { - $types = ['string', 'array', 'object']; + yield ['expectDeprecation('The (real) cast is deprecated, use (float) instead'); - yield [sprintf('doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFix74DeprecatedCases(): iterable + { + yield from self::createCasesFor('real', 'float'); } /** diff --git a/tests/Fixer/ClassNotation/ClassAttributesSeparationFixerTest.php b/tests/Fixer/ClassNotation/ClassAttributesSeparationFixerTest.php index 589a04fc434..084c56a97a8 100644 --- a/tests/Fixer/ClassNotation/ClassAttributesSeparationFixerTest.php +++ b/tests/Fixer/ClassNotation/ClassAttributesSeparationFixerTest.php @@ -27,10 +27,13 @@ final class ClassAttributesSeparationFixerTest extends AbstractFixerTestCase { /** + * @param array $configuration + * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -246,138 +249,7 @@ public function pass($a, $b) { } ', ]; - } - - /** - * @param array $elements - * - * @dataProvider provideInvalidElementsCases - */ - public function testInvalidElements(array $elements): void - { - $this->expectException(InvalidFixerConfigurationException::class); - $this->fixer->configure(['elements' => $elements]); - } - - public static function provideInvalidElementsCases(): iterable - { - yield 'numeric keys' => [['method', 'property']]; - - yield 'wrong key name' => [['methods' => 'one']]; - - yield 'wrong key value' => [['method' => 'two']]; - } - - /** - * @dataProvider provideCommentBlockStartDetectionCases - */ - public function testCommentBlockStartDetection(int $expected, string $code, int $index): void - { - Tokens::clearCache(); - $tokens = Tokens::fromCode($code); - $method = new \ReflectionMethod($this->fixer, 'findCommentBlockStart'); - $method->setAccessible(true); - - $result = $method->invoke($this->fixer, $tokens, $index, 0); - self::assertSame( - $expected, - $result, - sprintf('Expected index %d (%s) got index %d (%s).', $expected, $tokens[$expected]->toJson(), $result, $tokens[$result]->toJson()) - ); - } - - public static function provideCommentBlockStartDetectionCases(): iterable - { - yield [ - 4, - 'doTest($expected, $input); - } - - public static function provideFixClassesCases(): iterable - { yield ['doTest($expected, $input); - } - public static function provideFixTraitsCases(): iterable - { // do not touch well formatted traits yield [ 'doTest($expected, $input); - } - public static function provideFixInterfaceCases(): iterable - { yield [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); - - $this->doTest($expected, $input); - } - - public static function provideMessyWhitespacesCases(): iterable - { - yield [ - " $config - * - * @dataProvider provideWithConfigCases - */ - public function testWithConfig(string $expected, ?string $input, array $config): void - { - $this->fixer->configure($config); - $this->doTest($expected, $input); - } - - public static function provideWithConfigCases(): iterable - { yield 'multi line property' => [ ' ['property' => 'none', 'trait_import' => 'none']], ]; - } - /** - * @dataProvider provideFix71Cases - */ - public function testFix71(string $expected, string $input): void - { - $this->fixer->configure([ - 'elements' => ['method' => 'one', 'const' => 'one'], - ]); - $this->doTest($expected, $input); - } - - public static function provideFix71Cases(): iterable - { yield [ ' $config - * - * @dataProvider provideFix74Cases - */ - public function testFix74(string $expected, ?string $input = null, array $config = []): void - { - $this->fixer->configure($config); - - $this->doTest($expected, $input); - } - public static function provideFix74Cases(): iterable - { yield [ ' ['property' => 'only_if_meta']], ]; + + yield [ + ' $config * - * @dataProvider provideFixPhp80Cases + * @dataProvider provideFix80Cases * * @requires PHP 8.0 */ - public function testFixPhp80(string $expected, ?string $input, array $config = []): void + public function testFix80(string $expected, ?string $input, array $config = []): void { $this->fixer->configure($config); $this->doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'attributes' => [ 'doTest($expected, $input); - } - - public static function provideFixClassesWithTraitsCases(): iterable - { - yield [ - ' $config * @@ -2405,4 +2178,147 @@ class X }', ]; } + + /** + * @dataProvider provideWithWhitespacesConfigCases + */ + public function testWithWhitespacesConfig(string $expected, ?string $input = null): void + { + $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); + + $this->doTest($expected, $input); + } + + public static function provideWithWhitespacesConfigCases(): iterable + { + yield [ + " $elements + * + * @dataProvider provideInvalidConfigurationCases + */ + public function testInvalidConfiguration(array $elements): void + { + $this->expectException(InvalidFixerConfigurationException::class); + $this->fixer->configure(['elements' => $elements]); + } + + public static function provideInvalidConfigurationCases(): iterable + { + yield 'numeric keys' => [['method', 'property']]; + + yield 'wrong key name' => [['methods' => 'one']]; + + yield 'wrong key value' => [['method' => 'two']]; + } + + /** + * @dataProvider provideCommentBlockStartDetectionCases + */ + public function testCommentBlockStartDetection(int $expected, string $code, int $index): void + { + Tokens::clearCache(); + $tokens = Tokens::fromCode($code); + $method = new \ReflectionMethod($this->fixer, 'findCommentBlockStart'); + $method->setAccessible(true); + + $result = $method->invoke($this->fixer, $tokens, $index, 0); + self::assertSame( + $expected, + $result, + sprintf('Expected index %d (%s) got index %d (%s).', $expected, $tokens[$expected]->toJson(), $result, $tokens[$result]->toJson()) + ); + } + + public static function provideCommentBlockStartDetectionCases(): iterable + { + yield [ + 4, + ' true, @@ -46,79 +46,46 @@ public function testConfigureDefaultToFalse(): void } /** - * @param string $expected PHP source code - * @param string $input PHP source code - * @param array $config + * @param array $config * - * @dataProvider provideFixingAnonymousClassesCases + * @dataProvider provideInvalidConfigurationCases */ - public function testFixingAnonymousClasses(string $expected, string $input, array $config = []): void + public function testInvalidConfiguration(array $config, string $exceptionExpression): void { - $this->fixer->configure($config); - $this->doTest($expected, $input); - } - - /** - * @dataProvider provideFixingClassesCases - */ - public function testFixingClasses(string $expected, string $input): void - { - $this->fixer->configure([]); - $this->doTest($expected, $input); - } + $this->expectException(InvalidFixerConfigurationException::class); + $this->expectExceptionMessageMatches($exceptionExpression); - /** - * @param array $config - * - * @dataProvider provideFixingClassesWithConfigCases - */ - public function testFixingClassesWithConfig(string $expected, string $input, array $config): void - { $this->fixer->configure($config); - $this->doTest($expected, $input); } /** - * @dataProvider provideFixingInterfacesCases + * @return iterable, string}> */ - public function testFixingInterfaces(string $expected, string $input): void + public static function provideInvalidConfigurationCases(): iterable { - $this->fixer->configure([]); - $this->doTest($expected, $input); + yield 'invalid configuration key' => [ + ['a' => false], + '/^\[class_definition\] Invalid configuration: The option "a" does not exist\. Defined options are: "inline_constructor_arguments", "multi_line_extends_each_single_line", "single_item_single_line", "single_line", "space_before_parenthesis"\.$/', + ]; + + yield 'invalid configuration value' => [ + ['single_line' => 'z'], + '/^\[class_definition\] Invalid configuration: The option "single_line" with value "z" is expected to be of type "bool", but is of type "string"\.$/', + ]; } /** - * @dataProvider provideFixingTraitsCases + * @param array $configuration + * + * @dataProvider provideFixCases */ - public function testFixingTraits(string $expected, string $input): void + public function testFix(string $expected, string $input, array $configuration = []): void { - $this->fixer->configure([]); + $this->fixer->configure($configuration); $this->doTest($expected, $input); } - public function testInvalidConfigurationKey(): void - { - $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches( - '/^\[class_definition\] Invalid configuration: The option "a" does not exist\. Defined options are: "inline_constructor_arguments", "multi_line_extends_each_single_line", "single_item_single_line", "single_line", "space_before_parenthesis"\.$/' - ); - - $fixer = new ClassDefinitionFixer(); - $fixer->configure(['a' => false]); - } - - public function testInvalidConfigurationValueType(): void - { - $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches( - '/^\[class_definition\] Invalid configuration: The option "single_line" with value "z" is expected to be of type "bool", but is of type "string"\.$/' - ); - - $fixer = new ClassDefinitionFixer(); - $fixer->configure(['single_line' => 'z']); - } - - public static function provideFixingAnonymousClassesCases(): iterable + public static function provideFixCases(): iterable { yield [ 'bar()) ,baz() ) {};', ['space_before_parenthesis' => true, 'inline_constructor_arguments' => false], ]; - } - public static function provideFixingClassesCases(): iterable - { - return array_merge( - self::provideClassyCases('class'), - self::provideClassyExtendingCases('class'), - self::provideClassyImplementsCases() - ); - } + yield from self::provideClassyCases('class'); + + yield from self::provideClassyExtendingCases('class'); + + yield from self::provideClassyImplementsCases(); - public static function provideFixingClassesWithConfigCases(): iterable - { yield [ " true, ], ]; - } - public static function provideFixingInterfacesCases(): iterable - { - yield from array_merge( - self::provideClassyCases('interface'), - self::provideClassyExtendingCases('interface') - ); + yield from self::provideClassyCases('interface'); + + yield from self::provideClassyExtendingCases('interface'); yield [ '', + '', + ]; + + yield [ + ' 5, 'numberOfImplements' => 3, 'multiLine' => false], ]; - if (\PHP_VERSION_ID < 8_00_00) { - $multiLine = true; - $code = 'test(); -}'; - } else { - $multiLine = false; - $code = 'test(); -}'; - } - - yield [ - $code, +}', 'numberOfImplements', - ['start' => 36, 'numberOfImplements' => 2, 'multiLine' => $multiLine], + ['start' => 36, 'numberOfImplements' => 2, 'multiLine' => false], ]; yield [ @@ -669,74 +642,55 @@ public function test() } /** - * @dataProvider provideFixCases + * @param array $expected + * + * @dataProvider provideClassyInheritanceInfoPre80Cases + * + * @requires PHP <8.0 */ - public function testFix(string $expected, ?string $input = null): void + public function testClassyInheritanceInfoPre80(string $source, string $label, array $expected): void { - $this->fixer->configure([]); - $this->doTest($expected, $input); + $this->doTestClassyInheritanceInfo($source, $label, $expected); } - public static function provideFixCases(): iterable + public static function provideClassyInheritanceInfoPre80Cases(): iterable { yield [ '', - '', - ]; +namespace { + class B{} - yield [ - 'test(); +}', + 'numberOfImplements', + ['start' => 36, 'numberOfImplements' => 2, 'multiLine' => true], ]; } /** - * @dataProvider provideMessyWhitespacesCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testMessyWhitespaces(string $expected, ?string $input = null): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); - $this->fixer->configure([]); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ " $expected - */ - private static function assertConfigurationSame(array $expected, ClassDefinitionFixer $fixer): void - { - $reflectionProperty = new \ReflectionProperty($fixer, 'configuration'); - $reflectionProperty->setAccessible(true); - - self::assertSame($expected, $reflectionProperty->getValue($fixer)); - } - /** * @param array $expected */ @@ -889,6 +832,17 @@ private function doTestClassyInheritanceInfo(string $source, string $label, arra self::assertSame($expected, $result); } + /** + * @param array $expected + */ + private static function assertConfigurationSame(array $expected, ClassDefinitionFixer $fixer): void + { + $reflectionProperty = new \ReflectionProperty($fixer, 'configuration'); + $reflectionProperty->setAccessible(true); + + self::assertSame($expected, $reflectionProperty->getValue($fixer)); + } + private static function provideClassyCases(string $classy): iterable { return [ diff --git a/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php b/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php index 66cb8382be1..c14d25cbcb4 100644 --- a/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php +++ b/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php @@ -25,13 +25,13 @@ final class FinalInternalClassFixerTest extends AbstractFixerTestCase { /** - * @param string $expected PHP source code - * @param null|string $input PHP source code + * @param array $configuration * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -186,21 +186,7 @@ class Foo {} class Bar {} ', ]; - } - /** - * @param array $config - * - * @dataProvider provideFixWithConfigCases - */ - public function testFixWithConfig(string $expected, string $input, array $config): void - { - $this->fixer->configure($config); - $this->doTest($expected, $input); - } - - public static function provideFixWithConfigCases(): iterable - { yield [ " ['Hello'], ], ]; - } - - /** - * @param string $expected PHP source code - * @param null|string $input PHP source code - * - * @dataProvider provideAnonymousClassesCases - */ - public function testAnonymousClasses(string $expected, ?string $input = null): void - { - $this->doTest($expected, $input); - } - /** - * @return iterable - */ - public static function provideAnonymousClassesCases(): iterable - { yield [ 'expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches( - sprintf('#^%s$#', preg_quote('[final_internal_class] Annotation cannot be used in both "include" and "exclude" list, got duplicates: "internal123".', '#')) - ); - - $this->fixer->configure([ - 'include' => ['@internal123', 'a'], - 'exclude' => ['@internal123', 'b'], - ]); - } - /** * @group legacy + * + * @param array $config + * + * @dataProvider provideInvalidConfigurationCases */ - public function testConfigureBothNewAndOldIncludeSet(): void + public function testInvalidConfiguration(array $config, string $exceptionExpression, ?string $deprecationMessage = null): void { $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches(sprintf('#^%s$#', preg_quote('[final_internal_class] Configuration cannot contain deprecated option "annotation_include" and new option "include".', '#'))); - $this->expectDeprecation('Option "annotation_include" for rule "final_internal_class" is deprecated and will be removed in version 4.0. Use "include" to configure PHPDoc annotations tags and attributes.'); + $this->expectExceptionMessageMatches($exceptionExpression); + if (null !== $deprecationMessage) { + $this->expectDeprecation($deprecationMessage); + } - $this->fixer->configure([ - 'annotation_include' => ['@internal', 'a'], - 'include' => ['@internal', 'b'], - ]); + $this->fixer->configure($config); } /** - * @group legacy + * @return iterable, string, 2?: string}> */ - public function testConfigureBothNewAndOldExcludeSet(): void + public static function provideInvalidConfigurationCases(): iterable { - $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches(sprintf('#^%s$#', preg_quote('[final_internal_class] Configuration cannot contain deprecated option "annotation_exclude" and new option "exclude".', '#'))); - $this->expectDeprecation('Option "annotation_exclude" for rule "final_internal_class" is deprecated and will be removed in version 4.0. Use "exclude" to configure PHPDoc annotations tags and attributes.'); + yield 'same annotation in both lists' => [ + [ + 'include' => ['@internal123', 'a'], + 'exclude' => ['@internal123', 'b'], + ], + sprintf('#^%s$#', preg_quote('[final_internal_class] Annotation cannot be used in both "include" and "exclude" list, got duplicates: "internal123".', '#')), + ]; + + yield 'both new and old include set' => [ + [ + 'annotation_include' => ['@internal', 'a'], + 'include' => ['@internal', 'b'], + ], + sprintf('#^%s$#', preg_quote('[final_internal_class] Configuration cannot contain deprecated option "annotation_include" and new option "include".', '#')), + 'Option "annotation_include" for rule "final_internal_class" is deprecated and will be removed in version 4.0. Use "include" to configure PHPDoc annotations tags and attributes.', + ]; - $this->fixer->configure([ - 'annotation_exclude' => ['@internal', 'a'], - 'exclude' => ['@internal', 'b'], - ]); + yield 'both new and old exclude set' => [ + [ + 'annotation_exclude' => ['@internal', 'a'], + 'exclude' => ['@internal', 'b'], + ], + sprintf('#^%s$#', preg_quote('[final_internal_class] Configuration cannot contain deprecated option "annotation_exclude" and new option "exclude".', '#')), + 'Option "annotation_exclude" for rule "final_internal_class" is deprecated and will be removed in version 4.0. Use "exclude" to configure PHPDoc annotations tags and attributes.', + ]; } /** diff --git a/tests/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixerTest.php b/tests/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixerTest.php index ea47103d9f6..332d0f46393 100644 --- a/tests/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixerTest.php +++ b/tests/Fixer/ClassNotation/NoBlankLinesAfterClassOpeningFixerTest.php @@ -34,14 +34,6 @@ public function testFix(string $expected, ?string $input = null): void $this->doTest($expected, $input); } - /** - * @dataProvider provideFixTraitsCases - */ - public function testFixTraits(string $expected, ?string $input = null): void - { - $this->doTest($expected, $input); - } - public static function provideFixCases(): iterable { yield [ @@ -158,10 +150,7 @@ function bar() {} } ', ]; - } - public static function provideFixTraitsCases(): iterable - { yield [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "doTest($expected, $input); } - public static function provideFixPrePHP80Cases(): iterable + public static function provideFixPre80Cases(): iterable { yield [ 'doTest(' ', ]; - } - - /** - * @dataProvider provideSimpleClassCases - */ - public function testSimpleClass(string $expected, ?string $input = null): void - { - $this->doTest($expected, $input); - } - public static function provideSimpleClassCases(): iterable - { - yield [ + yield 'simple class 1' => [ <<<'EOF' [ <<<'EOF' [<<<'EOF' doTest($expected); - } - - public function testNamespaces2(): void - { - $expected = <<<'EOF' + yield 'namespace 2' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testNamespaceGlobal(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + doTest($expected, $input); - } + EOF + ]; - public function testPhp5Only(): void - { - $expected = <<<'EOF' + yield 'PHP 5 only' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testPhp4Only(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + doTest($expected, $input); - } + EOF + ]; - public function testBothTheRightWay1(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + __construct(); + } - class Foo - { - /** - * Constructor - */ - public function __construct() - { - var_dump(1); + public function bar() + { + var_dump(3); + } } + EOF, + ]; + + yield 'both the right way 2' => [ + <<<'EOF' + __construct(); + /** + * Constructor + */ + public function __construct($bar) + { + var_dump(1); + } + + public function bar() + { + var_dump(3); + } } + EOF, + <<<'EOF' + doTest($expected, $input); - } + /** + * PHP-4 Constructor + */ + function Foo($bar) + { + // Call PHP5! + $this->__construct($bar); + } - public function testBothTheRightWay2(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + __construct($bar, $baz); + } - class Foo - { - /** - * Constructor - */ - public function __construct($bar) - { - var_dump(1); + public function bar() + { + var_dump(3); + } } + EOF + ]; - /** - * PHP-4 Constructor - */ - function Foo($bar) - { - // Call PHP5! - $this->__construct($bar); - } + yield 'both the other way around 1' => [ + <<<'EOF' + doTest($expected, $input); - } - public function testBothTheRightWay3(): void - { - $expected = <<<'EOF' - Foo($bar); + } - $input = <<<'EOF' - __construct($bar, $baz); - } + yield 'PHP 4 parent' => [ + <<<'EOF' + doTest($expected, $input); - } - - public function testBothTheOtherWayAround(): void - { - $expected = <<<'EOF' - Foo($bar); + function bar() + { + var_dump(3); + } } + EOF, + <<<'EOF' + doTest($expected, $input); - } + EOF + ]; - public function testPhp4Parent(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + doTest($expected, $input); - } + EOF + ]; - public function testPhp4ParentInit(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + doTest($expected, $input); - } + EOF + ]; - public function testMixedParent(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + FooParenT(1); + var_dump(9); + } - function bar() - { - var_dump(3); + function bar() + { + var_dump(3); + } } - } - EOF; - - $this->doTest($expected, $input); - } + EOF + ]; - public function testMixedParent2(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + FooParenT(1); - var_dump(9); - } + /** + * Constructor + */ + function Foo($bar) + { + $this->FooParent(1); + var_dump(9); + } - function bar() - { - var_dump(3); + function bar() + { + var_dump(3); + } } - } - EOF; - - $this->doTest($expected, $input); - } + EOF + ]; - public function testParentOther(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + FooParent(1); - var_dump(9); - } + /** + * Constructor + */ + function Foo($bar) + { + FooParent::FooParent(1); + var_dump(9); + } - function bar() - { - var_dump(3); + function bar() + { + var_dump(3); + } } - } - EOF; + EOF + ]; - $this->doTest($expected, $input); - } + yield 'class with anonymous' => [ + <<<'EOF' + bar = function () {}; + } } + EOF, + <<<'EOF' + bar = function () {}; + } } - } - EOF; + EOF + ]; - $input = <<<'EOF' - [ + <<<'EOF' + doTest($expected, $input); - } - - public function testClassWithAnonymous(): void - { - $expected = <<<'EOF' - bar = function () {}; + Foo { + public function /* test */ Foo($param) { } - } - EOF; - - $input = <<<'EOF' - bar = function () {}; } - } - EOF; - $this->doTest($expected, $input); - } - - public function testClassWithComments(): void - { - $expected = <<<'EOF' - doTest($expected, $input); - } + EOF + ]; - public function testAlphaBeta(): void - { - $expected = <<<'EOF' + yield 'alpha beta' => [<<<'EOF' doTest($expected); - } - - public function testAlphaBetaTrick1(): void - { - $expected = <<<'EOF' + yield 'alpha beta trick 1' => [<<<'EOF' doTest($expected); - } - - public function testAlphaBetaTrick2(): void - { - $expected = <<<'EOF' + yield 'alpha beta trick 2' => [<<<'EOF' doTest($expected); - } - - public function testAlphaBetaTrick3(): void - { - $expected = <<<'EOF' + yield 'alpha beta trick 3' => [<<<'EOF' doTest($expected); - } - - public function testAlphaBetaTrick4WithAnotherClass(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + Foo(); - // Do something more! - echo 'beta'; + public function Foo() + { + echo 'alpha'; + } + public function __construct() + { + $this->Foo(); + // Do something more! + echo 'beta'; + } } - } - Class Bar - { - function __construct() + Class Bar { - $this->foo = 1; + function __construct() + { + $this->foo = 1; + } } - } - EOF; - - $input = <<<'EOF' - Foo(); - // Do something more! - echo 'beta'; + public function Foo() + { + echo 'alpha'; + } + public function __construct() + { + $this->Foo(); + // Do something more! + echo 'beta'; + } } - } - Class Bar - { - function bar() + Class Bar { - $this->foo = 1; + function bar() + { + $this->foo = 1; + } } - } - EOF; - - $this->doTest($expected, $input); - } + EOF + ]; - public function testAbstract(): void - { - $expected = <<<'EOF' + yield 'abstract' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testAbstractTrick(): void - { - $expected = <<<'EOF' + yield 'abstract trick' => [<<<'EOF' baz = 1; } } - EOF; - - $this->doTest($expected); - } + EOF]; - public function testParentMultipleClasses(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + - EOF; - - $input = <<<'EOF' - + EOF, + <<<'EOF' + Parent1(); - echo "something"; + function __construct($foo) + { + $this->Parent1(); + echo "something"; + } } - } - class Class2 extends Parent2 - { - function __construct($foo) + class Class2 extends Parent2 { - echo "something"; + function __construct($foo) + { + echo "something"; + } } - } - ?> - EOF; - - $this->doTest($expected, $input); - } + ?> + EOF + ]; - public function testInfiniteRecursion(): void - { - $expected = <<<'EOF' - [ + <<<'EOF' + - EOF; - - $input = <<<'EOF' - + EOF, + <<<'EOF' + __construct(); - echo "something"; + function Class1($foo) + { + $this->__construct(); + echo "something"; + } } - } - ?> - EOF; - - $this->doTest($expected, $input); + ?> + EOF + ]; } /** - * @dataProvider provideFixPhp80Cases + * @dataProvider provideFix80Cases * * @requires PHP 8.0 */ - public function testFixPhp80(string $expected, ?string $input = null): void + public function testFix80(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield [ <<<'EOF' diff --git a/tests/Fixer/ClassNotation/NoUnneededFinalMethodFixerTest.php b/tests/Fixer/ClassNotation/NoUnneededFinalMethodFixerTest.php index 0a5f454ba72..f2d9a9474ce 100644 --- a/tests/Fixer/ClassNotation/NoUnneededFinalMethodFixerTest.php +++ b/tests/Fixer/ClassNotation/NoUnneededFinalMethodFixerTest.php @@ -27,9 +27,12 @@ final class NoUnneededFinalMethodFixerTest extends AbstractFixerTestCase { /** * @dataProvider provideFixCases + * + * @param array $configuration */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -366,21 +369,7 @@ private function bar2(){ echo 1; } private final function bar3(){ echo 2; } }', ]; - } - - /** - * @param array $config - * - * @dataProvider provideFixConfigCases - */ - public function testFixConfig(string $expected, string $input, array $config): void - { - $this->fixer->configure($config); - $this->doTest($expected, $input); - } - public static function provideFixConfigCases(): iterable - { yield [ ' $configuration */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -55,7 +58,8 @@ class Bar class Foo { const C1 = 1; protected $abc = 'abc'; public function baz($y, $z) {} private function bar1($x) { return 1; } } EOT - , <<<'EOT' + , + <<<'EOT' $configuration - * - * @dataProvider provideFixWithConfigurationCases - */ - public function testFixWithConfiguration(array $configuration, string $expected, string $input): void - { - $this->fixer->configure(['order' => $configuration]); - $this->doTest($expected, $input); - } - - public static function provideFixWithConfigurationCases(): iterable - { yield [ - ['use_trait', 'constant', 'property', 'construct', 'method', 'destruct'], <<<'EOT' ['use_trait', 'constant', 'property', 'construct', 'method', 'destruct']], ]; yield [ - ['public', 'protected', 'private'], <<<'EOT' ['public', 'protected', 'private']], ]; yield [ - [ - 'use_trait', - 'constant', - 'property_public_static', - 'property_protected_static', - 'property_private_static', - 'property_public', - 'property_protected', - 'property_private', - 'construct', - 'destruct', - 'magic', - 'method_public_static', - 'method_protected_static', - 'method_private_static', - 'method_public', - 'method_protected', - 'method_private', - ], <<<'EOT' [ + 'use_trait', + 'constant', + 'property_public_static', + 'property_protected_static', + 'property_private_static', + 'property_public', + 'property_protected', + 'property_private', + 'construct', + 'destruct', + 'magic', + 'method_public_static', + 'method_protected_static', + 'method_private_static', + 'method_public', + 'method_protected', + 'method_private', + ], + ], ]; yield [ - ['use_trait', 'constant', 'property', 'construct', 'method', 'destruct'], <<<'EOT' ['use_trait', 'constant', 'property', 'construct', 'method', 'destruct']], ]; yield [ - ['public', 'protected', 'private'], <<<'EOT' ['public', 'protected', 'private']], ]; yield [ - [ - 'use_trait', - 'constant', - 'property_public_static', - 'property_protected_static', - 'property_private_static', - 'property_public', - 'property_protected', - 'property_private', - 'construct', - 'destruct', - 'magic', - 'method_public_static', - 'method_public_abstract_static', - 'method_protected_static', - 'method_protected_abstract_static', - 'method_private_static', - 'method_public', - 'method_public_abstract', - 'method_protected', - 'method_protected_abstract', - 'method_private', - ], <<<'EOT' [ + 'use_trait', + 'constant', + 'property_public_static', + 'property_protected_static', + 'property_private_static', + 'property_public', + 'property_protected', + 'property_private', + 'construct', + 'destruct', + 'magic', + 'method_public_static', + 'method_public_abstract_static', + 'method_protected_static', + 'method_protected_abstract_static', + 'method_private_static', + 'method_public', + 'method_public_abstract', + 'method_protected', + 'method_protected_abstract', + 'method_private', + ], + ], ]; yield [ - [ - 'method_public', - 'method_abstract', - ], <<<'EOT' [ + 'method_public', + 'method_abstract', + ], + ], ]; yield [ - [ - 'construct', - 'method:__invoke', - 'destruct', - 'method_public_static', - 'method:custom1', - 'method_public_abstract_static', - 'method_protected_static', - 'method_protected_abstract_static', - 'method_private_static', - 'method_public', - 'method:custom3', - 'method_public_abstract', - 'method_protected', - 'method_protected_abstract', - 'method_private', - 'method:custom2', - 'magic', - ], <<<'EOT' [ + 'construct', + 'method:__invoke', + 'destruct', + 'method_public_static', + 'method:custom1', + 'method_public_abstract_static', + 'method_protected_static', + 'method_protected_abstract_static', + 'method_private_static', + 'method_public', + 'method:custom3', + 'method_public_abstract', + 'method_protected', + 'method_protected_abstract', + 'method_private', + 'method:custom2', + 'magic', + ], + ], ]; yield [ - [ - 'method:foo', - 'method_public', - 'method:bar', - 'method:baz', - 'magic', - ], <<<'EOT' $configuration - * - * @dataProvider provideFixWithSortingAlgorithmCases - */ - public function testFixWithSortingAlgorithm(array $configuration, string $expected, string $input): void - { - $this->fixer->configure($configuration); - $this->doTest($expected, $input); - } - - public static function provideFixWithSortingAlgorithmCases(): iterable - { - yield [ [ 'order' => [ - 'property_public_static', + 'method:foo', 'method_public', - 'method_private', + 'method:bar', + 'method:baz', + 'magic', ], - 'sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA, ], + ]; + + yield [ <<<'EOT' [ - 'use_trait', - 'constant', 'property_public_static', - 'property_protected_static', - 'property_private_static', - 'property_public', - 'property_protected', - 'property_private', - 'construct', - 'destruct', - 'magic', - 'method_public_static', - 'method_protected_static', - 'method_private_static', 'method_public', - 'method_protected', 'method_private', ], 'sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA, ], + ]; + + yield [ <<<'EOT' [ 'use_trait', @@ -1214,18 +1179,17 @@ protected static function protStatFunc() {} 'destruct', 'magic', 'method_public_static', - 'method_public_abstract_static', 'method_protected_static', - 'method_protected_abstract_static', 'method_private_static', 'method_public', - 'method_public_abstract', 'method_protected', - 'method_protected_abstract', 'method_private', ], 'sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA, ], + ]; + + yield [ <<<'EOT' [ + 'use_trait', + 'constant', + 'property_public_static', + 'property_protected_static', + 'property_private_static', + 'property_public', + 'property_protected', + 'property_private', + 'construct', + 'destruct', + 'magic', + 'method_public_static', + 'method_public_abstract_static', + 'method_protected_static', + 'method_protected_abstract_static', + 'method_private_static', + 'method_public', + 'method_public_abstract', + 'method_protected', + 'method_protected_abstract', + 'method_private', + ], + 'sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA, + ], ]; yield [ - [], <<<'EOT' OrderedClassElementsFixer::SORT_ALPHA], <<<'EOT' OrderedClassElementsFixer::SORT_ALPHA], ]; yield [ - ['sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA], <<<'EOT' OrderedClassElementsFixer::SORT_ALPHA], ]; yield [ - ['sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA, 'case_sensitive' => true], <<<'EOT' OrderedClassElementsFixer::SORT_ALPHA, 'case_sensitive' => true], ]; + + // test with no candidate + $template = ' ['use_trait'], 'sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA], + ]; + } } /** * @param array $configuration * - * @dataProvider provideFix74Cases + * @dataProvider provideFixPre80Cases */ - public function testFix74(string $expected, ?string $input = null, array $configuration = []): void + public function testFixPre80(string $expected, ?string $input = null, array $configuration = []): void { $this->fixer->configure($configuration); $this->doTest($expected, $input); } - public static function provideFix74Cases(): iterable + public static function provideFixPre80Cases(): iterable { yield [ 'expectException(InvalidFixerConfigurationException::class); $this->expectExceptionMessageMatches('/^\[ordered_class_elements\] Invalid configuration: The option "order" .*\.$/'); @@ -1483,35 +1492,6 @@ public function testWrongConfig(): void $this->fixer->configure(['order' => ['foo']]); } - /** - * @dataProvider provideWithConfigWithNoCandidateCases - */ - public function testWithConfigWithNoCandidate(string $methodName1, string $methodName2): void - { - $template = 'fixer->configure(['order' => ['use_trait'], 'sort_algorithm' => OrderedClassElementsFixer::SORT_ALPHA]); - $this->doTest( - sprintf($template, $methodName2, $methodName1), - sprintf($template, $methodName1, $methodName2) - ); - } - - public static function provideWithConfigWithNoCandidateCases(): iterable - { - yield ['z', '__construct']; - - yield ['z', '__destruct']; - - yield ['z', '__sleep']; - - yield ['z', 'abc']; - } - /** * @dataProvider provideFix80Cases * diff --git a/tests/Fixer/ClassNotation/OrderedInterfacesFixerTest.php b/tests/Fixer/ClassNotation/OrderedInterfacesFixerTest.php index b03767a8b3e..57f74a250c2 100644 --- a/tests/Fixer/ClassNotation/OrderedInterfacesFixerTest.php +++ b/tests/Fixer/ClassNotation/OrderedInterfacesFixerTest.php @@ -27,14 +27,17 @@ final class OrderedInterfacesFixerTest extends AbstractFixerTestCase { /** - * @dataProvider provideFixAlphaCases + * @dataProvider provideFixCases + * + * @param array $configuration */ - public function testFixAlpha(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } - public static function provideFixAlphaCases(): iterable + public static function provideFixCases(): iterable { yield 'single' => [ 'fixer->configure([OrderedInterfacesFixer::OPTION_DIRECTION => OrderedInterfacesFixer::DIRECTION_DESCEND]); - $this->doTest($expected, $input); - } - public static function provideFixAlphaDescendCases(): iterable - { - yield 'single' => [ + yield 'descend single' => [ ' OrderedInterfacesFixer::DIRECTION_DESCEND], ]; - yield 'multiple' => [ + yield 'descend multiple' => [ ' OrderedInterfacesFixer::DIRECTION_DESCEND], ]; - yield 'mixed' => [ + yield 'descend mixed' => [ ' OrderedInterfacesFixer::DIRECTION_DESCEND], ]; - } - - /** - * @dataProvider provideFixLengthCases - */ - public function testFixLength(string $expected, ?string $input = null): void - { - $this->fixer->configure([OrderedInterfacesFixer::OPTION_ORDER => OrderedInterfacesFixer::ORDER_LENGTH]); - $this->doTest($expected, $input); - } - public static function provideFixLengthCases(): iterable - { - yield 'single' => [ + yield 'length single' => [ ' OrderedInterfacesFixer::ORDER_LENGTH], ]; - yield 'multiple' => [ + yield 'length multiple' => [ ' OrderedInterfacesFixer::ORDER_LENGTH], ]; - yield 'mixed' => [ + yield 'length mixed' => [ ' OrderedInterfacesFixer::ORDER_LENGTH], ]; - yield 'normalized' => [ + yield 'length normalized' => [ ' OrderedInterfacesFixer::ORDER_LENGTH], ]; - } - - /** - * @dataProvider provideFixLengthDescendCases - */ - public function testFixLengthDescend(string $expected, ?string $input = null): void - { - $this->fixer->configure([ - OrderedInterfacesFixer::OPTION_ORDER => OrderedInterfacesFixer::ORDER_LENGTH, - OrderedInterfacesFixer::OPTION_DIRECTION => OrderedInterfacesFixer::DIRECTION_DESCEND, - ]); - $this->doTest($expected, $input); - } - public static function provideFixLengthDescendCases(): iterable - { - yield 'single' => [ + yield 'length, descend single' => [ ' OrderedInterfacesFixer::ORDER_LENGTH, + OrderedInterfacesFixer::OPTION_DIRECTION => OrderedInterfacesFixer::DIRECTION_DESCEND, + ], ]; - yield 'multiple' => [ + yield 'length, descend multiple' => [ ' OrderedInterfacesFixer::ORDER_LENGTH, + OrderedInterfacesFixer::OPTION_DIRECTION => OrderedInterfacesFixer::DIRECTION_DESCEND, + ], ]; - yield 'mixed' => [ + yield 'length, descend mixed' => [ ' OrderedInterfacesFixer::ORDER_LENGTH, + OrderedInterfacesFixer::OPTION_DIRECTION => OrderedInterfacesFixer::DIRECTION_DESCEND, + ], ]; - yield 'normalized' => [ + yield 'length, descend normalized' => [ ' OrderedInterfacesFixer::ORDER_LENGTH, + OrderedInterfacesFixer::OPTION_DIRECTION => OrderedInterfacesFixer::DIRECTION_DESCEND, + ], ]; - } - - /** - * @dataProvider provideFixCaseSensitiveAlphaCases - */ - public function testFixCaseSensitiveAlpha(string $expected, ?string $input = null): void - { - $this->fixer->configure([ - OrderedInterfacesFixer::OPTION_ORDER => OrderedInterfacesFixer::ORDER_ALPHA, - 'case_sensitive' => true, - ]); - $this->doTest($expected, $input); - } - public static function provideFixCaseSensitiveAlphaCases(): iterable - { - return [ - 'single' => [ - ' [ + ' OrderedInterfacesFixer::ORDER_ALPHA, + 'case_sensitive' => true, ], - 'multiple' => [ - ' [ + ' OrderedInterfacesFixer::ORDER_ALPHA, + 'case_sensitive' => true, ], - 'mixed' => [ - ' [ + ' OrderedInterfacesFixer::ORDER_ALPHA, + 'case_sensitive' => true, ], - 'normalized' => [ - ' [ + ' OrderedInterfacesFixer::ORDER_ALPHA, + 'case_sensitive' => true, ], ]; } diff --git a/tests/Fixer/ClassNotation/OrderedTraitsFixerTest.php b/tests/Fixer/ClassNotation/OrderedTraitsFixerTest.php index 5215f7fd012..acdc49c31a0 100644 --- a/tests/Fixer/ClassNotation/OrderedTraitsFixerTest.php +++ b/tests/Fixer/ClassNotation/OrderedTraitsFixerTest.php @@ -25,9 +25,12 @@ final class OrderedTraitsFixerTest extends AbstractFixerTestCase { /** * @dataProvider provideFixCases + * + * @param array $configuration */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -317,24 +320,7 @@ class User use TestA, Test\B; }', ]; - } - - /** - * @param array $configuration - * - * @dataProvider provideFixWithConfigurationCases - */ - public function testFixWithConfiguration(string $expected, string $input = null, array $configuration): void - { - $this->fixer->configure($configuration); - $this->doTest($expected, $input); - } - /** - * @return iterable}> - */ - public static function provideFixWithConfigurationCases(): iterable - { yield 'with case sensitive order' => [ ' $config * * @requires PHP 8.0 */ - public function testFixPhp80(string $expected, ?string $input = null, ?array $config = null): void + public function testFix80(string $expected, ?string $input = null, ?array $config = null): void { if (null !== $config) { $this->fixer->configure($config); @@ -162,9 +162,9 @@ public function testFixPhp80(string $expected, ?string $input = null, ?array $co } /** - * @return iterable}> + * @return iterable}> */ - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'sort alpha, null none' => [ " 'none', 'null_adjustment' => 'none'], ]; - } - - /** - * @dataProvider provideFixDefaultCases - * - * @requires PHP 8.0 - */ - public function testFixDefault(string $expected, ?string $input = null): void - { - $this->doTest($expected, $input); - } - /** - * @return iterable - */ - public static function provideFixDefaultCases(): iterable - { yield [ "fixer->configure([ - 'sort_algorithm' => 'alpha', - 'null_adjustment' => 'always_last', - ]); - - $this->doTest($expected, $input); - } - - /** - * @return iterable}> - */ - public static function provideFixWithAlphaAlgorithmAndNullAlwaysLastCases(): iterable - { yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ ' 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ ' $number;', ' $number;', + ['sort_algorithm' => 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ " 'alpha', 'null_adjustment' => 'always_last'], ]; yield [ @@ -427,102 +405,98 @@ protected function bar(string $str, ?array $config = null): callable {} return $e; } ', + null, + ['sort_algorithm' => 'alpha', 'null_adjustment' => 'always_last'], ]; - } - /** - * @dataProvider provideFixWithAlphaAlgorithmOnlyCases - * - * @requires PHP 8.0 - */ - public function testFixWithAlphaAlgorithmOnly(string $expected, ?string $input = null): void - { - $this->fixer->configure([ - 'sort_algorithm' => 'alpha', - 'null_adjustment' => 'none', - ]); - - $this->doTest($expected, $input); - } - - /** - * @return iterable - */ - public static function provideFixWithAlphaAlgorithmOnlyCases(): iterable - { yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ ' 'alpha', 'null_adjustment' => 'none'], ]; yield [ ' $number;', ' $number;', + ['sort_algorithm' => 'alpha', 'null_adjustment' => 'none'], ]; yield [ " 'alpha', 'null_adjustment' => 'none'], ]; yield [ @@ -543,28 +517,10 @@ protected function bar(string $str, ?array $config = null): callable {} return $e; } ', + null, + ['sort_algorithm' => 'alpha', 'null_adjustment' => 'none'], ]; - } - /** - * @dataProvider provideFixWithSandwichedWhitespaceOrCommentInTypeCases - * - * @requires PHP 8.0 - */ - public function testFixWithSandwichedWhitespaceOrCommentInType(string $expected, ?string $input = null): void - { - // The current design of the fixer uses the `TypeAnalysis` class which collects the - // types and ignores whitespaces and comments. These ignored tokens are not accounted - // during instantiation of the TypeAnalysis class, thus we have no way of recovering - // those token information. This test case mainly proves this fact. - $this->doTest($expected, $input); - } - - /** - * @return iterable - */ - public static function provideFixWithSandwichedWhitespaceOrCommentInTypeCases(): iterable - { yield [ " [ + " true], + ]; } /** - * @dataProvider provideFixPhp81Cases + * @dataProvider provideFix81Cases * * @param null|array $config * * @requires PHP 8.1 */ - public function testFixPhp81(string $expected, ?string $input = null, ?array $config = null): void + public function testFix81(string $expected, ?string $input = null, ?array $config = null): void { if (null !== $config) { $this->fixer->configure($config); @@ -605,7 +567,7 @@ public function testFixPhp81(string $expected, ?string $input = null, ?array $co /** * @return iterable}> */ - public static function provideFixPhp81Cases(): iterable + public static function provideFix81Cases(): iterable { yield [ " $config * * @requires PHP 8.2 */ - public function testFixPhp82(string $expected, ?string $input = null, ?array $config = null): void + public function testFix82(string $expected, ?string $input = null, ?array $config = null): void { if (null !== $config) { $this->fixer->configure($config); @@ -662,7 +624,7 @@ public function testFixPhp82(string $expected, ?string $input = null, ?array $co /** * @return iterable}> */ - public static function provideFixPhp82Cases(): iterable + public static function provideFix82Cases(): iterable { yield [ " 'alpha'], ]; } - - /** - * @dataProvider provideFixWithCaseSensitiveCases - * - * @requires PHP 8.0 - */ - public function testFixWithCaseSensitive(string $expected, ?string $input = null): void - { - $this->fixer->configure([ - 'case_sensitive' => true, - ]); - - $this->doTest($expected, $input); - } - - /** - * @return iterable - */ - public static function provideFixWithCaseSensitiveCases(): iterable - { - yield [ - " $configuration + * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -711,104 +714,78 @@ class Token { var array $foo, $bar; }', ]; - } - - /** - * @param array $configuration - * - * @dataProvider provideFixWithConfigurationCases - */ - public function testFixWithConfiguration(array $configuration, string $expected): void - { - static $input = <<<'EOT' - fixer->configure(['elements' => $configuration]); - $this->doTest($expected, $input); - } - public static function provideFixWithConfigurationCases(): iterable - { yield [ - ['const', 'property'], <<<'EOT' - ['const', 'property']], ]; yield [ - ['property'], <<<'EOT' - expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches('/^\[single_class_element_per_statement\] Invalid configuration: The option "elements" .*\.$/'); + class Foo + { + const SOME_CONST = 'a'; + const OTHER_CONST = 'b'; + protected static $foo = 1, $bar = 2; + } + EOT, + <<<'EOT' + fixer->configure(['elements' => ['foo']]); - } + class Foo + { + const SOME_CONST = 'a', OTHER_CONST = 'b'; + protected static $foo = 1, $bar = 2; + } + EOT, + ['elements' => ['const']], + ]; - /** - * @dataProvider provideMessyWhitespacesCases - */ - public function testMessyWhitespaces(string $expected, ?string $input = null): void - { - $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); + yield [ + <<<'EOT' + doTest($expected, $input); - } + class Foo + { + const SOME_CONST = 'a', OTHER_CONST = 'b'; + protected static $foo = 1; + protected static $bar = 2; + } + EOT, + <<<'EOT' + ['property']], ]; - } - public function testAnonymousClassFixing(): void - { - $this->doTest( + yield 'anonymous class' => [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); + + $this->doTest( + "expectException(InvalidFixerConfigurationException::class); + $this->expectExceptionMessageMatches('/^\[single_class_element_per_statement\] Invalid configuration: The option "elements" .*\.$/'); + + $this->fixer->configure(['elements' => ['foo']]); + } } diff --git a/tests/Fixer/ClassNotation/SingleTraitInsertPerStatementFixerTest.php b/tests/Fixer/ClassNotation/SingleTraitInsertPerStatementFixerTest.php index deb5b5c975a..c04d6981077 100644 --- a/tests/Fixer/ClassNotation/SingleTraitInsertPerStatementFixerTest.php +++ b/tests/Fixer/ClassNotation/SingleTraitInsertPerStatementFixerTest.php @@ -254,13 +254,10 @@ class Talker { } }', ]; - } - public function testAnonymousClassFixing(): void - { - $this->doTest( + yield 'anonymous class' => [ '', - '' - ); + '', + ]; } } diff --git a/tests/Fixer/ClassNotation/VisibilityRequiredFixerTest.php b/tests/Fixer/ClassNotation/VisibilityRequiredFixerTest.php index ed168b48351..832ca73a4cb 100644 --- a/tests/Fixer/ClassNotation/VisibilityRequiredFixerTest.php +++ b/tests/Fixer/ClassNotation/VisibilityRequiredFixerTest.php @@ -26,77 +26,73 @@ */ final class VisibilityRequiredFixerTest extends AbstractFixerTestCase { - public function testFixProperties(): void - { - $expected = <<<'EOF' - doTest($expected, $input); - } - - public function testFixPropertiesAfterMethod(): void - { - $input = <<<'EOF' - doTest($expected, $input); - } - /** - * @dataProvider provideFixMethodsCases + * @param array $configuration + * + * @dataProvider provideFixCases */ - public function testFixMethods(string $expected, string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } - public static function provideFixMethodsCases(): iterable + public static function provideFixCases(): iterable { - yield [ + yield 'properties' => [ + <<<'EOF' + [ + <<<'EOF' + [ <<<'EOF' [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneWithVariablesMatchingOopWords(): void - { - $expected = <<<'EOF' + yield 'leave functions alone with variables matching OOP words' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneInsideConditionals(): void - { - $expected = <<<'EOF' + yield 'leave functions alone inside conditionals' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneInsideConditionalsWithOopWordInComment(): void - { - $expected = <<<'EOF' + yield 'leave functions alone inside conditionals with OOP word in comment' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneWithOopWordInComment(): void - { - $expected = <<<'EOF' + yield 'leave functions alone with OOP word in comment' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneOutsideClassesWithOopWordInInlineHtml(): void - { - $expected = <<<'EOF' + yield 'leave functions alone outside classes with OOP word in inline HTML' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneOutsideClassesWithOopWordInStringValue(): void - { - $expected = <<<'EOF' + yield 'leave functions alone outside classes with OOP word in string value' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneOutsideClassesWithOopWordInFunctionName(): void - { - $expected = <<<'EOF' + yield 'leave functions alone outside classes with OOP word in function name' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveFunctionsAloneAfterClass(): void - { - $expected = <<<'EOF' + yield 'leave functions alone after class' => [<<<'EOF' doTest($expected); - } - - public function testCurlyOpenSyntax(): void - { - $expected = <<<'EOF' + yield 'curly open syntax' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testDollarOpenCurlyBracesSyntax(): void - { - $expected = <<<'EOF' + yield 'dollar open curly braces syntax' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testLeaveJavascriptOutsidePhpAlone(): void - { - $expected = <<<'EOF' + yield 'leave JavaScript outside PHP alone' => [<<<'EOF' - EOF; - - $this->doTest($expected); - } + EOF]; - public function testLeaveJavascriptInStringAlone(): void - { - $expected = <<<'EOF' + yield 'leave JavaScript in string alone' => [<<<'EOF' '; } - EOF; - - $this->doTest($expected); - } + EOF]; - public function testLeaveJavascriptInVariableAlone(): void - { - $expected = <<<'EOF' + yield 'leave JavaScript in variable alone' => [<<<'EOF' doTest($expected); - } + EOF]; - public function testFixCommaSeparatedProperty(): void - { - $expected = <<<'EOF' + yield 'comma separated properties' => [<<<'EOF' doTest($expected, $input); - } + EOF, + <<<'EOF' + [<<<'EOF' doTest($expected, $input); - } - - public function testInvalidConfigurationType(): void - { - $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches('/^\[visibility_required\] Invalid configuration: The option "elements" .*\.$/'); - - $this->fixer->configure(['elements' => [null]]); - } - - public function testInvalidConfigurationValue(): void - { - $this->expectException(InvalidFixerConfigurationException::class); - $this->expectExceptionMessageMatches('/^\[visibility_required\] Invalid configuration: The option "elements" .*\.$/'); - - $this->fixer->configure(['elements' => ['_unknown_']]); - } - - /** - * @dataProvider provideFixClassConstCases - */ - public function testFixClassConst(string $expected, string $input): void - { - $this->fixer->configure(['elements' => ['const']]); - $this->doTest($expected, $input); - } + EOF, + <<<'EOF' + ['const']], ]; yield [ @@ -540,11 +432,13 @@ public static function provideFixClassConstCases(): iterable ' ['const']], ]; yield [ ' ['const']], ]; yield [ @@ -566,12 +460,11 @@ class foo const SENTENCE = "The value of THREE is ".self::THREE; } ', + ['elements' => ['const']], ]; - } - public function testComment(): void - { - $expected = ' [ + 'doTest($expected, $input); - } + ', + ]; - public function testAnonymousClassFixing(): void - { - $this->doTest( + yield 'anonymous class' => [ 'doTest( + yield 'removing newlines between keywords' => [ 'fixer->configure(['elements' => ['property', 'method', 'const']]); - $this->doTest( + yield 'keeping comment' => [ ' ['property', 'method', 'const']], + ]; - public function testFixingWithAllKeywords(): void - { - $this->doTest( + yield 'fixing with all keywords' => [ 'doTest($expected, $input); - } + ', + ]; - public static function provideFixCases(): iterable - { yield [ ' $config + * + * @dataProvider provideInvalidConfigurationCases + */ + public function testInvalidConfiguration(array $config, string $expectedMessage): void + { + $this->expectException(InvalidFixerConfigurationException::class); + $this->expectExceptionMessageMatches($expectedMessage); + + $this->fixer->configure($config); + } + + /** + * @return iterable, string}> + */ + public static function provideInvalidConfigurationCases(): iterable + { + yield 'invalid type' => [ + ['elements' => [null]], + '/^\[visibility_required\] Invalid configuration: The option "elements" .*\.$/', + ]; + + yield 'invalid value' => [ + ['elements' => ['_unknown_']], + '/^\[visibility_required\] Invalid configuration: The option "elements" .*\.$/', + ]; + } } diff --git a/tests/Fixer/ControlStructure/ControlStructureContinuationPositionFixerTest.php b/tests/Fixer/ControlStructure/ControlStructureContinuationPositionFixerTest.php index ed0652d4e1a..025f95fde1d 100644 --- a/tests/Fixer/ControlStructure/ControlStructureContinuationPositionFixerTest.php +++ b/tests/Fixer/ControlStructure/ControlStructureContinuationPositionFixerTest.php @@ -271,9 +271,9 @@ public static function provideFixCases(): iterable /** * @param null|array $configuration * - * @dataProvider provideFixWithWindowsLineEndingsCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testFixWithWindowsLineEndings(string $expected, ?string $input = null, array $configuration = null): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null, array $configuration = null): void { if (null !== $configuration) { $this->fixer->configure($configuration); @@ -286,7 +286,7 @@ public function testFixWithWindowsLineEndings(string $expected, ?string $input = $this->doTest($expected, $input); } - public static function provideFixWithWindowsLineEndingsCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { foreach (self::provideFixCases() as $label => $case) { yield $label => [ diff --git a/tests/Fixer/ControlStructure/EmptyLoopBodyFixerTest.php b/tests/Fixer/ControlStructure/EmptyLoopBodyFixerTest.php index 8e9687b24c2..7ab4b2def3c 100644 --- a/tests/Fixer/ControlStructure/EmptyLoopBodyFixerTest.php +++ b/tests/Fixer/ControlStructure/EmptyLoopBodyFixerTest.php @@ -26,9 +26,9 @@ final class EmptyLoopBodyFixerTest extends AbstractFixerTestCase /** * @param array $config * - * @dataProvider provideFixConfigCases + * @dataProvider provideFixCases */ - public function testFixConfig(string $expected, ?string $input = null, array $config = []): void + public function testFix(string $expected, ?string $input = null, array $config = []): void { if ([] === $config) { $this->doTest($expected, $input); @@ -46,7 +46,7 @@ public function testFixConfig(string $expected, ?string $input = null, array $co } } - public static function provideFixConfigCases(): iterable + public static function provideFixCases(): iterable { yield 'simple "while"' => [ ' $config * - * @dataProvider provideFixConfigCases + * @dataProvider provideFixCases */ - public function testFixConfig(string $expected, ?string $input = null, array $config = []): void + public function testFix(string $expected, ?string $input = null, array $config = []): void { $this->fixer->configure($config); $this->doTest($expected, $input); } - public static function provideFixConfigCases(): iterable + public static function provideFixCases(): iterable { yield 'from `for` to `while`' => [ ' $configuration + * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -129,39 +132,7 @@ public function getBar(): array } ', ]; - } - /** - * @dataProvider provideFixPre80Cases - * - * @requires PHP <8.0 - */ - public function testFixPre80(string $expected, string $input = null): void - { - $this->doTest($expected, $input); - } - - public static function provideFixPre80Cases(): iterable - { - yield 'no fixes, offset access syntax with curly braces' => [ - 'fixer->configure(['namespaces' => true]); - $this->doTest($expected, $input); - } - - public static function provideFixNamespaceCases(): iterable - { yield [ ' true], ]; yield [ @@ -183,6 +155,8 @@ function AA(){} namespace B6 { function BB(){} }', + null, + ['namespaces' => true], ]; yield [ @@ -194,6 +168,7 @@ function Bar(){} namespace Foo7 { function Bar(){} }', + ['namespaces' => true], ]; yield [ @@ -205,6 +180,27 @@ function Bar(){} namespace Foo8\\A\t \t { function Bar(){} } ?>", + ['namespaces' => true], + ]; + } + + /** + * @dataProvider provideFixPre80Cases + * + * @requires PHP <8.0 + */ + public function testFixPre80(string $expected, string $input = null): void + { + $this->doTest($expected, $input); + } + + public static function provideFixPre80Cases(): iterable + { + yield 'no fixes, offset access syntax with curly braces' => [ + 'fixer->configure($config); $this->doTest($expected, $input); @@ -102,57 +102,41 @@ public static function provideFixCases(): iterable ', ['b_mode' => false], ]; + + foreach (self::provideDoNotFixCodeSamples() as $name => $code) { + yield $name.' with b_mode' => [$code]; + + yield $name.' without b_mode' => [$code, null, ['b_mode' => false]]; + } } /** - * @dataProvider provideDoNotFixCases + * @return iterable */ - public function testDoNotFix(string $expected): void - { - $this->doTest($expected); - $this->fixer->configure(['b_mode' => false]); - $this->doTest($expected); - } - - public static function provideDoNotFixCases(): iterable + private static function provideDoNotFixCodeSamples(): iterable { - yield 'not simple flags' => [ - ' ' [ - ' ' [ - ' ' [ - ' ' [ - ' ' [ - 'fopen($foo, "r+");', - ]; + yield 'method call' => 'fopen($foo, "r+");'; - yield 'comments, PHPDoc and literal' => [ - ' ' [ - ' ' ' + * @var array */ private static $configurationClosureSpacingNone = ['closure_function_spacing' => FunctionDeclarationFixer::SPACING_NONE]; /** - * @var array + * @var array */ private static $configurationArrowSpacingNone = ['closure_fn_spacing' => FunctionDeclarationFixer::SPACING_NONE]; diff --git a/tests/Fixer/FunctionNotation/LambdaNotUsedImportFixerTest.php b/tests/Fixer/FunctionNotation/LambdaNotUsedImportFixerTest.php index 78acdc8787a..d3a90dcf6b9 100644 --- a/tests/Fixer/FunctionNotation/LambdaNotUsedImportFixerTest.php +++ b/tests/Fixer/FunctionNotation/LambdaNotUsedImportFixerTest.php @@ -26,7 +26,7 @@ final class LambdaNotUsedImportFixerTest extends AbstractFixerTestCase /** * @dataProvider provideFixCases */ - public function testFix(string $expected, string $input): void + public function testFix(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } @@ -125,18 +125,7 @@ public static function provideFixCases(): iterable new class("bar") {}; };', ]; - } - /** - * @dataProvider provideDoNotFixCases - */ - public function testDoNotFix(string $expected): void - { - $this->doTest($expected); - } - - public static function provideDoNotFixCases(): iterable - { yield 'reference' => [ '', ]; diff --git a/tests/Fixer/FunctionNotation/NativeFunctionInvocationFixerTest.php b/tests/Fixer/FunctionNotation/NativeFunctionInvocationFixerTest.php index 891725a1249..f658c4bdcd5 100644 --- a/tests/Fixer/FunctionNotation/NativeFunctionInvocationFixerTest.php +++ b/tests/Fixer/FunctionNotation/NativeFunctionInvocationFixerTest.php @@ -588,33 +588,44 @@ public function & strlen($name) { 'include' => [NativeFunctionInvocationFixer::SET_ALL], ], ]; + } + + /** + * @param array $configuration + * + * @dataProvider provideFixPre80Cases + * + * @requires PHP <8.0 + */ + public function testFixPre80(string $expected, ?string $input = null, array $configuration = []): void + { + $this->fixer->configure($configuration); + $this->doTest($expected, $input); + } - if (\PHP_VERSION_ID < 8_00_00) { - yield 'include @compiler_optimized with strict enabled' => [ - '}> + */ + public static function provideFixPre80Cases(): iterable + { + yield 'include @compiler_optimized with strict enabled' => [ + ' [NativeFunctionInvocationFixer::SET_COMPILER_OPTIMIZED], - 'strict' => true, - ], - ]; - } - } + [ + 'include' => [NativeFunctionInvocationFixer::SET_COMPILER_OPTIMIZED], + 'strict' => true, + ], + ]; - /** - * @requires PHP <8.0 - */ - public function testFixPrePHP80(): void - { - $this->doTest( + yield [ ' @@ -27,14 +26,17 @@ final class NullableTypeDeclarationForDefaultNullValueFixerTest extends AbstractFixerTestCase { /** - * @dataProvider provideDoNotFixCases + * @param array $configuration + * + * @dataProvider provideFixCases */ - public function testDoNotFix(string $expected): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { - $this->doTest($expected); + $this->fixer->configure($configuration); + $this->doTest($expected, $input); } - public static function provideDoNotFixCases(): iterable + public static function provideFixCases(): iterable { yield ['doTest($expected, $input); + yield from self::createBothWaysCases(self::provideBothWaysCases()); + + yield [ + ' false], + ]; + + yield [ + ' false], + ]; + + yield [ + ' false], + ]; } /** - * @dataProvider provideInvertedFixCases - * @dataProvider provideInverseOnlyFixCases + * @param array $configuration + * + * @dataProvider provideFix80Cases + * + * @requires PHP 8.0 */ - public function testFixInverse(string $expected, string $input): void + public function testFix80(string $expected, ?string $input = null, array $configuration = []): void { - $this->fixer->configure(['use_nullable_type_declaration' => false]); + $this->fixer->configure($configuration); $this->doTest($expected, $input); } - public static function provideFixCases(): iterable + public static function provideFix80Cases(): iterable { + yield from self::createBothWaysCases(self::provideBothWays80Cases()); + yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; + } - yield [ - ' $configuration + * + * @requires PHP <8.0 + * + * @dataProvider provideFixPre81Cases + */ + public function testFixPre81(string $expected, ?string $input = null, array $configuration = []): void + { + $this->fixer->configure($configuration); - yield [ - 'doTest($expected, $input); + } + + public static function provideFixPre81Cases(): iterable + { + yield 'do not fix pre PHP 8.1' => [ + ' false], ]; + } + + /** + * @param array $config + * + * @dataProvider provideFix81Cases + * + * @requires PHP 8.1 + */ + public function testFix81(string $expected, array $config = []): void + { + $this->fixer->configure($config); + $this->doTest($expected); + } + + public static function provideFix81Cases(): iterable + { yield [ - ' false], ]; + } + + /** + * @param array $configuration + * + * @dataProvider provideFix82Cases + * + * @requires PHP 8.2 + */ + public function testFix82(string $expected, ?string $input = null, array $configuration = []): void + { + $this->fixer->configure($configuration); + $this->doTest($expected, $input); + } + + public static function provideFix82Cases(): iterable + { + yield from self::createBothWaysCases(self::provideBothWays82Cases()); yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; yield [ - ' false], ]; + } + private static function provideBothWaysCases(): iterable + { yield [ - 'doTest($expected, $input); - } + yield [ + 'fixer->configure(['use_nullable_type_declaration' => false]); - $this->doTest($expected, $input); - } + yield [ + ' null;', ' null;', @@ -422,34 +644,7 @@ public static function provideFixPhp74Cases(): iterable ]; } - public static function provideFixInversePhp74Cases(): iterable - { - return TestCaseUtils::swapExpectedInputTestCases(self::provideFixPhp74Cases()); - } - - /** - * @dataProvider provideFix80Cases - * - * @requires PHP 8.0 - */ - public function testFix80(string $expected, ?string $input = null): void - { - $this->doTest($expected, $input); - } - - /** - * @dataProvider provideFixInverse80Cases - * @dataProvider provideInverseOnlyFix80Cases - * - * @requires PHP 8.0 - */ - public function testFixInverse80(string $expected, ?string $input = null): void - { - $this->fixer->configure(['use_nullable_type_declaration' => false]); - $this->doTest($expected, $input); - } - - public static function provideFix80Cases(): iterable + private static function provideBothWays80Cases(): iterable { yield [ ' $configuration - * - * @requires PHP <8.0 - * - * @dataProvider provideFixPre81Cases - */ - public function testFixPre81(string $expected, ?string $input = null, array $configuration = []): void - { - $this->fixer->configure($configuration); - - $this->doTest($expected, $input); - } - - public static function provideFixPre81Cases(): iterable - { - yield 'do not fix pre PHP 8.1' => [ - ' false]]; - } - - /** - * @param array $config - * - * @dataProvider provideFix81Cases - * - * @requires PHP 8.1 - */ - public function testFix81(string $expected, array $config = []): void - { - $this->fixer->configure($config); - - $this->doTest($expected); - } - - public static function provideFix81Cases(): iterable - { - yield [ - ' false], - ]; - } - - /** - * @dataProvider provideFix82Cases - * - * @requires PHP 8.2 - */ - public function testFix82(string $expected, ?string $input = null): void - { - $this->doTest($expected, $input); - } - - public static function provideFix82Cases(): iterable + private static function provideBothWays82Cases(): iterable { yield 'Skip standalone null types' => [ ' $cases * - * @requires PHP 8.2 + * @return iterable}> */ - public function testFix82Inverse(string $expected, ?string $input = null): void + private static function createBothWaysCases(iterable $cases): iterable { - $this->fixer->configure(['use_nullable_type_declaration' => false]); - $this->doTest($expected, $input); - } + foreach ($cases as $key => $case) { + yield $key => $case; - public static function provideFix82InverseCases(): iterable - { - yield from TestCaseUtils::swapExpectedInputTestCases(self::provideFix82Cases()); + if (\count($case) > 2) { + throw new \BadMethodCallException(sprintf('Method "%s" does not support handling "configuration" input yet, please implement it.', __METHOD__)); + } - yield [ - ' [ + $reversed[0], + $reversed[1] ?? null, + ['use_nullable_type_declaration' => false], + ]; + } } } diff --git a/tests/Fixer/FunctionNotation/PhpdocToParamTypeFixerTest.php b/tests/Fixer/FunctionNotation/PhpdocToParamTypeFixerTest.php index f93c4915edc..de20d94a64a 100644 --- a/tests/Fixer/FunctionNotation/PhpdocToParamTypeFixerTest.php +++ b/tests/Fixer/FunctionNotation/PhpdocToParamTypeFixerTest.php @@ -518,16 +518,16 @@ function my_foo($bar) {}', } /** - * @dataProvider provideFixPhp80Cases + * @dataProvider provideFix80Cases * * @requires PHP 8.0 */ - public function testFixPhp80(string $expected, ?string $input = null): void + public function testFix80(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'non-root class with mixed type of param for php >= 8' => [ 'doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'fix mixed type' => [ 'doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'static' => [ 'doTest($expected, $input); } - public static function provideFixPhpPre81Cases(): iterable + public static function provideFixPre81Cases(): iterable { yield 'skip never type' => [ 'doTest($expected, $input); } - public static function provideFixPhp81Cases(): iterable + public static function provideFix81Cases(): iterable { yield 'never type' => [ ' [ - ' [ 'c)(1, 2); @@ -241,6 +230,31 @@ public static function createFromFactory(...$args) { ]; } + /** + * @dataProvider provideFixPre80Cases + * + * @requires PHP <8.0 + */ + public function testFixPre80(string $expected, ?string $input = null): void + { + $this->doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFixPre80Cases(): iterable + { + yield 'call by variable' => [ + 'doTest($expected); - } - - public static function provideDoNotFixCases(): iterable - { yield [ ' var_dump($a);', ]; + + $excluded = ['__clone', '__construct', '__debugInfo', '__destruct', '__isset', '__serialize', '__set_state', '__sleep', '__toString']; + + foreach (self::provideMagicMethodsDefinitions() as $magicMethodsDefinition) { + $name = $magicMethodsDefinition[0]; + $arguments = $magicMethodsDefinition[1] ?? 0; + $isStatic = $magicMethodsDefinition[2] ?? false; + $code = sprintf( + ' sprintf('$x%d', $n), + array_keys(array_fill(0, $arguments ?? 0, true)), + )) + ); + + $input = sprintf($code, ''); + $expected = sprintf($code, \in_array($name, $excluded, true) ? '' : ': void'); + + yield sprintf('Test if magic method %s is handled without causing syntax error', $name) => [ + $expected, + $expected === $input ? null : $input, + ]; + } } /** @@ -312,28 +336,9 @@ function test() {}; } /** - * Test if magic method is handled without causing syntax error. - * - * @dataProvider provideMethodWillNotCauseSyntaxErrorCases + * @return iterable */ - public function testMethodWillNotCauseSyntaxError(string $method, int $arguments = 0, bool $static = false): void - { - $tokens = Tokens::fromCode(sprintf( - ' sprintf('$x%d', $n), - array_keys(array_fill(0, $arguments, true)), - )) - )); - - $this->fixer->fix(new \SplFileInfo(__FILE__), $tokens); - - self::assertNull($this->lintSource($tokens->generateCode())); - } - - public static function provideMethodWillNotCauseSyntaxErrorCases(): iterable + private static function provideMagicMethodsDefinitions(): iterable { // List: https://www.php.net/manual/en/language.oop5.magic.php yield ['__construct']; diff --git a/tests/Fixer/Import/FullyQualifiedStrictTypesFixerTest.php b/tests/Fixer/Import/FullyQualifiedStrictTypesFixerTest.php index efaccd94d49..ecdd54e2f64 100644 --- a/tests/Fixer/Import/FullyQualifiedStrictTypesFixerTest.php +++ b/tests/Fixer/Import/FullyQualifiedStrictTypesFixerTest.php @@ -15,6 +15,7 @@ namespace PhpCsFixer\Tests\Fixer\Import; use PhpCsFixer\Tests\Test\AbstractFixerTestCase; +use PhpCsFixer\WhitespacesFixerConfig; /** * @author VeeWee @@ -30,9 +31,22 @@ final class FullyQualifiedStrictTypesFixerTest extends AbstractFixerTestCase * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null, array $config = []): void - { + public function testFix( + string $expected, + ?string $input = null, + array $config = [], + ?WhitespacesFixerConfig $whitespaceConfig = null + ): void { $this->fixer->configure($config); + + if (null !== $whitespaceConfig) { + $this->fixer->setWhitespacesConfig($whitespaceConfig); + $expected = str_replace("\n", $whitespaceConfig->getLineEnding(), $expected); + if (null !== $input) { + $input = str_replace("\n", $whitespaceConfig->getLineEnding(), $input); + } + } + $this->doTest($expected, $input); } @@ -355,6 +369,151 @@ function A(\Z\B\C\DE\Foo $fix) {} ', null, ]; + + yield 'import new symbols from all supported places' => [ + ' true], + ]; + + yield 'import new symbols under already existing imports' => [ + ' true], + ]; + + yield 'import new symbols within multiple namespaces' => [ + ' true], + ]; + + yield 'import new symbols with custom whitespace config' => [ + ' true], + new WhitespacesFixerConfig("\t", "\r\n"), + ]; + + yield 'ignore importing if there is name conflict' => [ + ' true], + ]; + + yield 'ignore importing if symbol is not a FQN' => [ + ' true], + ]; + + yield 'ignore global FQNs (there is GlobalNamespaceImportFixer for that)' => [ + ' true], + ]; } /** diff --git a/tests/Fixer/Import/GlobalNamespaceImportFixerTest.php b/tests/Fixer/Import/GlobalNamespaceImportFixerTest.php index 8c842594654..eda8ed48986 100644 --- a/tests/Fixer/Import/GlobalNamespaceImportFixerTest.php +++ b/tests/Fixer/Import/GlobalNamespaceImportFixerTest.php @@ -81,8 +81,8 @@ public static function provideFixImportConstantsCases(): iterable <<<'EXPECTED' doTest($expected, $input); } - public static function provideFixPrePHP80Cases(): iterable + public static function provideFixPre80Cases(): iterable { yield [ 'doTest( 'doTest($expected); - } - - public static function provideFixPhp81Cases(): iterable - { yield [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "doTest( + yield 'anonymous class' => [ 'isset()) {} - ' - ); + ', + ]; } } diff --git a/tests/Fixer/LanguageConstruct/DeclareEqualNormalizeFixerTest.php b/tests/Fixer/LanguageConstruct/DeclareEqualNormalizeFixerTest.php index 4e9e53bf5cf..0ae5de1ebe3 100644 --- a/tests/Fixer/LanguageConstruct/DeclareEqualNormalizeFixerTest.php +++ b/tests/Fixer/LanguageConstruct/DeclareEqualNormalizeFixerTest.php @@ -112,9 +112,9 @@ public static function provideFixCases(): iterable /** * @param array $config * - * @dataProvider provideInvalidConfigCases + * @dataProvider provideInvalidConfigurationCases */ - public function testInvalidConfig(array $config, string $expectedMessage): void + public function testInvalidConfiguration(array $config, string $expectedMessage): void { $this->expectException(InvalidFixerConfigurationException::class); $this->expectExceptionMessage(sprintf('[declare_equal_normalize] Invalid configuration: %s', $expectedMessage)); @@ -122,7 +122,7 @@ public function testInvalidConfig(array $config, string $expectedMessage): void $this->fixer->configure($config); } - public static function provideInvalidConfigCases(): iterable + public static function provideInvalidConfigurationCases(): iterable { yield [ [1, 2], diff --git a/tests/Fixer/LanguageConstruct/DirConstantFixerTest.php b/tests/Fixer/LanguageConstruct/DirConstantFixerTest.php index b7841a73e09..a07ada0e02b 100644 --- a/tests/Fixer/LanguageConstruct/DirConstantFixerTest.php +++ b/tests/Fixer/LanguageConstruct/DirConstantFixerTest.php @@ -185,7 +185,7 @@ public function &dirname($a); /** * @requires PHP <8.0 */ - public function testFixPrePHP80(): void + public function testFixPre80(): void { $this->doTest( 'property[array_search(\Types::TYPE_RANDOM, $this->property)]);', ]; - if (\PHP_VERSION_ID < 8_00_00) { - yield 'It does not replace unsets on arrays with special notation' => [ - 'foo{0});', - ]; - } - yield 'It does not break complex expressions' => [ 'bar = null ;', 'bar , );', ]; - - if (\PHP_VERSION_ID < 8_00_00) { - yield 'It does not replace unsets on arrays with special notation 1' => [ - 'foo{0},);', - ]; - } } /** @@ -249,8 +237,19 @@ public function testFixPre80(string $expected, string $input = null): void $this->doTest($expected, $input); } + /** + * @return iterable + */ public static function provideFixPre80Cases(): iterable { + yield 'It does not replace unsets on arrays with special notation' => [ + 'foo{0});', + ]; + + yield 'It does not replace unsets on arrays with special notation 1' => [ + 'foo{0},);', + ]; + yield 'It does not break curly access expressions' => [ 'doTest($expected, $input); } @@ -38,7 +38,7 @@ public function testDefaultFix(string $expected, ?string $input = null): void /** * @return iterable */ - public static function provideDefaultFixCases(): iterable + public static function provideFixCases(): iterable { yield 'scalar with null' => [ "fixer->configure(['syntax' => 'union']); @@ -115,7 +115,7 @@ public function testFixWithUnionSyntax(string $expected, ?string $input = null): /** * @return iterable */ - public static function provideFixWithUnionSyntaxCases(): iterable + public static function provideFix80Cases(): iterable { yield 'scalar with null' => [ " $config * - * @dataProvider provideFixPhp81Cases + * @dataProvider provideFix81Cases * * @requires PHP 8.1 */ - public function testFixPhp81(string $expected, ?string $input = null, ?array $config = null): void + public function testFix81(string $expected, ?string $input = null, ?array $config = null): void { if (null !== $config) { $this->fixer->configure($config); @@ -211,7 +211,7 @@ public function testFixPhp81(string $expected, ?string $input = null, ?array $co /** * @return iterable}> */ - public static function provideFixPhp81Cases(): iterable + public static function provideFix81Cases(): iterable { yield 'readonly property' => [ ' $config * - * @dataProvider provideFixPhp82Cases + * @dataProvider provideFix82Cases * * @requires PHP 8.2 */ - public function testFixPhp82(string $expected, ?string $input = null, ?array $config = null): void + public function testFix82(string $expected, ?string $input = null, ?array $config = null): void { if (null !== $config) { $this->fixer->configure($config); @@ -264,7 +264,7 @@ public function testFixPhp82(string $expected, ?string $input = null, ?array $co /** * @return iterable}> */ - public static function provideFixPhp82Cases(): iterable + public static function provideFix82Cases(): iterable { yield 'skips DNF types' => [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "', ]; - if (\PHP_VERSION_ID < 8_00_00) { - yield 'mixed array' => [ - ' [ - ' [ - ' [ @@ -272,4 +247,43 @@ public function bar($i) }', ]; } + + /** + * @dataProvider provideFixPre80Cases + * + * @requires PHP <8.0 + */ + public function testFixPre80(string $expected, ?string $input = null): void + { + $this->doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFixPre80Cases(): iterable + { + yield 'mixed array' => [ + ' [ + ' [ + '$b::$c->${$d}->${$e}::f(1 + 2 * 3)->$g::$h;', - '$b::$c->${$d}->${$e}::f(1 + 2 * 3)->$g::$h++;', - ]; - - yield [ - '{$b."foo"}->bar[$c]->$baz;', - '{$b."foo"}->bar[$c]->$baz++;', - ]; - } + /** + * @dataProvider provideFixPre80Cases + * + * @requires PHP <8.0 + */ + public function testFixPre80(string $expected, ?string $input = null): void + { + $this->doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFixPre80Cases(): iterable + { + yield [ + '$b::$c->${$d}->${$e}::f(1 + 2 * 3)->$g::$h;', + '$b::$c->${$d}->${$e}::f(1 + 2 * 3)->$g::$h++;', + ]; + + yield [ + '{$b."foo"}->bar[$c]->$baz;', + '{$b."foo"}->bar[$c]->$baz++;', + ]; } } diff --git a/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php b/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php index f24cd23c14e..03da8ed28eb 100644 --- a/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php +++ b/tests/Fixer/Operator/LongToShorthandOperatorFixerTest.php @@ -452,14 +452,14 @@ public function bar(int $i): int /** * @requires PHP <8.0 * - * @dataProvider provideFixPrePHP80Cases + * @dataProvider provideFixPre80Cases */ - public function testFixPrePHP80(string $expected, ?string $input = null): void + public function testFixPre80(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } - public static function provideFixPrePHP80Cases(): iterable + public static function provideFixPre80Cases(): iterable { yield [ 'doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFix80Cases(): iterable + { + yield 'handle ?-> operator' => [ + ' $bar; + ', + ' + $bar; + ', + ]; + } + /** * @return iterable}> */ @@ -493,10 +520,6 @@ function () { $operators[] = '??'; $operators[] = '<=>'; - if (\PHP_VERSION_ID >= 8_00_00) { - $operators[] = '?->'; - } - foreach ($operators as $operator) { yield sprintf('handle %s operator', $operator) => [ sprintf('doTest($input); } - public static function provideDoNotFix80Cases(): iterable + public static function provideFix80Cases(): iterable { yield ['fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "doTest($expected, $input); } @@ -205,7 +205,7 @@ public function testFix7(string $expected, ?string $input = null): void /** * @return iterable */ - public static function provideFix7Cases(): iterable + public static function provideFixPre80Cases(): iterable { yield 'data provider with return type namespaced class starting with iterable' => self::mapToTemplate( ': iterable \ Foo', diff --git a/tests/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixerTest.php b/tests/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixerTest.php index 9afe68b1d6e..59eb848157b 100644 --- a/tests/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixerTest.php +++ b/tests/Fixer/PhpUnit/PhpUnitDedicateAssertInternalTypeFixerTest.php @@ -26,14 +26,14 @@ final class PhpUnitDedicateAssertInternalTypeFixerTest extends AbstractFixerTestCase { /** - * @dataProvider provideFixInternalTypeCases + * @dataProvider provideFixCases */ - public function testFixInternalType(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } - public static function provideFixInternalTypeCases(): iterable + public static function provideFixCases(): iterable { yield 'skip cases' => [ 'doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { $expectedTemplate = ' diff --git a/tests/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixerTest.php b/tests/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixerTest.php index 830e7b302eb..f113c6b1308 100644 --- a/tests/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixerTest.php +++ b/tests/Fixer/PhpUnit/PhpUnitFqcnAnnotationFixerTest.php @@ -25,64 +25,69 @@ */ final class PhpUnitFqcnAnnotationFixerTest extends AbstractFixerTestCase { - public function testFix(): void + /** + * @dataProvider provideFixCases + */ + public function testFix(string $expected, ?string $input = null): void + { + $this->doTest($expected, $input); + } + + public static function provideFixCases(): iterable { - $expected = <<<'EOF' - doTest($expected, $input); - } - - public function testIgnoringNonPhpUnitClass(): void - { - $this->doTest(' -doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ ' $config * - * @dataProvider provideMessyWhitespacesCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testMessyWhitespaces(string $expected, ?string $input = null, array $config = []): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null, array $config = []): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->fixer->configure($config); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ 'doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ ' $config * - * @dataProvider provideFixPhp80Cases + * @dataProvider provideFix80Cases * * @requires PHP 8.0 */ - public function testFixPhp80(string $expected, ?string $input = null, array $config = []): void + public function testFix80(string $expected, ?string $input = null, array $config = []): void { $this->fixer->configure($config); $this->doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'static return' => [ '> $data + * @var string $input + * @var \Closure $fn + * @var \Closure(bool):int $fn2 + * @var Closure $fn3 + * @var Closure(string):string $fn4 + * @var array> $data */ /** - * @param string $input - * @param \Closure $fn - * @param \Closure(bool):int $fn2 - * @param Closure $fn3 - * @param Closure(string):string $fn4 - * @param array> $data + * @param string $input + * @param \Closure $fn + * @param \Closure(bool):int $fn2 + * @param Closure $fn3 + * @param Closure(string):string $fn4 + * @param array> $data */ /** * @var string $value @@ -1211,12 +1211,12 @@ class Foo {} * @param Closure(int): bool $callback2 */ /** - * @var Closure(array): bool $callback1 - * @var \Closure(string): string $callback2 + * @var Closure(array): bool $callback1 + * @var \Closure(string): string $callback2 */ /** - * @param Closure(array): bool $callback1 - * @param \Closure(string): string $callback2 + * @param Closure(array): bool $callback1 + * @param \Closure(string): string $callback2 */ ', ]; diff --git a/tests/Fixer/Phpdoc/PhpdocIndentFixerTest.php b/tests/Fixer/Phpdoc/PhpdocIndentFixerTest.php index d30166f8060..0c25811c8c2 100644 --- a/tests/Fixer/Phpdoc/PhpdocIndentFixerTest.php +++ b/tests/Fixer/Phpdoc/PhpdocIndentFixerTest.php @@ -26,14 +26,14 @@ final class PhpdocIndentFixerTest extends AbstractFixerTestCase { /** - * @dataProvider provideFixIndentCases + * @dataProvider provideFixCases */ - public function testFixIndent(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } - public static function provideFixIndentCases(): iterable + public static function provideFixCases(): iterable { yield ['']; diff --git a/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php b/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php index a0c62cb07fb..76cdc5f3849 100644 --- a/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php +++ b/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php @@ -403,7 +403,7 @@ public static function provideFixCases(): iterable ]; } - public function testConfigureWithInvalidTagType(): void + public function testInvalidConfiguration(): void { $this->expectException(InvalidFixerConfigurationException::class); $this->expectExceptionMessageMatches('#^\[phpdoc_tag_type\] Invalid configuration: Unknown tag type "foo"\.#'); diff --git a/tests/Fixer/Phpdoc/PhpdocToCommentFixerTest.php b/tests/Fixer/Phpdoc/PhpdocToCommentFixerTest.php index 1b18bfffafb..6dc3f06b217 100644 --- a/tests/Fixer/Phpdoc/PhpdocToCommentFixerTest.php +++ b/tests/Fixer/Phpdoc/PhpdocToCommentFixerTest.php @@ -28,8 +28,6 @@ final class PhpdocToCommentFixerTest extends AbstractFixerTestCase /** * @param array $config * - * @dataProvider provideDocblocksCases - * @dataProvider provideTraitsCases * @dataProvider provideFixCases */ public function testFix(string $expected, ?string $input = null, array $config = []): void @@ -39,7 +37,7 @@ public function testFix(string $expected, ?string $input = null, array $config = $this->doTest($expected, $input); } - public static function provideDocblocksCases(): iterable + public static function provideFixCases(): iterable { yield [ ' true], ]; - } - public static function provideTraitsCases(): iterable - { yield [ 'expectException(InvalidFixerConfigurationException::class); $this->expectExceptionMessageMatches('/^\[phpdoc_types\] Invalid configuration: The option "groups" .*\.$/'); diff --git a/tests/Fixer/Strict/DeclareStrictTypesFixerTest.php b/tests/Fixer/Strict/DeclareStrictTypesFixerTest.php index 315f377677b..709d5045654 100644 --- a/tests/Fixer/Strict/DeclareStrictTypesFixerTest.php +++ b/tests/Fixer/Strict/DeclareStrictTypesFixerTest.php @@ -129,34 +129,23 @@ class A { 'doTest($input); - } - - public static function provideDoNotFixCases(): iterable - { yield [' fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ " $configuration + * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null): void + public function testFix(string $expected, ?string $input = null, array $configuration = []): void { + $this->fixer->configure($configuration); $this->doTest($expected, $input); } @@ -146,25 +149,11 @@ public static function provideFixCases(): iterable fixer->configure([ - 'strings_containing_single_quote_chars' => true, - ]); - $this->doTest($expected, $input); - } - - public static function provideSingleQuoteFixCases(): iterable - { yield [ ' true], ]; yield [ @@ -188,6 +177,7 @@ public static function provideSingleQuoteFixCases(): iterable $c = "start \\\\' end"; EOT , + ['strings_containing_single_quote_chars' => true], ]; yield [ @@ -199,6 +189,8 @@ public static function provideSingleQuoteFixCases(): iterable $b = "start \\\' end"; EOT , + null, + ['strings_containing_single_quote_chars' => true], ]; } } diff --git a/tests/Fixer/StringNotation/StringLineEndingFixerTest.php b/tests/Fixer/StringNotation/StringLineEndingFixerTest.php index a488542c1c2..f393ed38593 100644 --- a/tests/Fixer/StringNotation/StringLineEndingFixerTest.php +++ b/tests/Fixer/StringNotation/StringLineEndingFixerTest.php @@ -113,7 +113,7 @@ public static function provideFixCases(): iterable ]; } - public function testWithDifferentLineEndingConfiguration(): void + public function testWithWhitespacesConfig(): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); diff --git a/tests/Fixer/Whitespace/ArrayIndentationFixerTest.php b/tests/Fixer/Whitespace/ArrayIndentationFixerTest.php index a906b7a1a2e..e2e839b7c08 100644 --- a/tests/Fixer/Whitespace/ArrayIndentationFixerTest.php +++ b/tests/Fixer/Whitespace/ArrayIndentationFixerTest.php @@ -897,15 +897,15 @@ class="link" } /** - * @dataProvider provideFixWithTabsCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testFixWithTabs(string $expected, ?string $input = null): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t")); $this->doTest($expected, $input); } - public static function provideFixWithTabsCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield from self::withLongArraySyntaxCases([ [ @@ -990,16 +990,16 @@ public static function provideFixWithTabsCases(): iterable } /** - * @dataProvider provideFixPhp80Cases + * @dataProvider provideFix80Cases * * @requires PHP 8.0 */ - public function testFixPhp80(string $expected, ?string $input = null): void + public function testFix80(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield 'attribute' => [ 'doTest($expected, $input); } - public static function provideFixTypesOrderAndNewlinesCases(): iterable + public static function provideFixCases(): iterable { yield [ 'doTest($expected, $input); } - public static function provideFixPre80Cases(): iterable + public static function provideFix80Cases(): iterable { yield [ 'fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t")); diff --git a/tests/Fixer/Whitespace/LineEndingFixerTest.php b/tests/Fixer/Whitespace/LineEndingFixerTest.php index 92efb2c5862..8c1516279c8 100644 --- a/tests/Fixer/Whitespace/LineEndingFixerTest.php +++ b/tests/Fixer/Whitespace/LineEndingFixerTest.php @@ -73,16 +73,16 @@ public static function provideFixCases(): iterable } /** - * @dataProvider provideMessyWhitespacesCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testMessyWhitespaces(string $expected, ?string $input = null): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield from array_map(static fn (array $case): array => array_reverse($case), self::provideCommonCases()); diff --git a/tests/Fixer/Whitespace/MethodChainingIndentationFixerTest.php b/tests/Fixer/Whitespace/MethodChainingIndentationFixerTest.php index 8a8e607760a..0a089065a67 100644 --- a/tests/Fixer/Whitespace/MethodChainingIndentationFixerTest.php +++ b/tests/Fixer/Whitespace/MethodChainingIndentationFixerTest.php @@ -461,15 +461,15 @@ public static function provideFixCases(): iterable } /** - * @dataProvider provideWindowsWhitespacesCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testWindowsWhitespaces(string $expected, ?string $input = null): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideWindowsWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "setEmail('voff.web@gmail.com')\r\n\t->setPassword('233434')\r\n\t->setEmailConfirmed(false)\r\n\t->setEmailConfirmationCode('123456')\r\n\t->setHashsalt('1234')\r\n\t->setTncAccepted(true);", diff --git a/tests/Fixer/Whitespace/NoExtraBlankLinesFixerTest.php b/tests/Fixer/Whitespace/NoExtraBlankLinesFixerTest.php index dfc85ec941f..5f94a7347a8 100644 --- a/tests/Fixer/Whitespace/NoExtraBlankLinesFixerTest.php +++ b/tests/Fixer/Whitespace/NoExtraBlankLinesFixerTest.php @@ -818,12 +818,6 @@ public static function provideOneOrInLineCases(): iterable yield [ "doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFixPre80Cases(): iterable + { + yield [ + " $config * diff --git a/tests/Fixer/Whitespace/NoSpacesAroundOffsetFixerTest.php b/tests/Fixer/Whitespace/NoSpacesAroundOffsetFixerTest.php index 457b0e78b0a..e1cca42073e 100644 --- a/tests/Fixer/Whitespace/NoSpacesAroundOffsetFixerTest.php +++ b/tests/Fixer/Whitespace/NoSpacesAroundOffsetFixerTest.php @@ -184,31 +184,6 @@ public static function provideFixSpaceOutsideOffsetCases(): iterable [1] [2] = 3;', ]; - - if (\PHP_VERSION_ID < 8_00_00) { - yield [ - ' $configuration + * @param array{positions: list} $configuration * * @dataProvider provideFixWithConfigurationCases */ - public function testFixWithConfiguration(array $configuration, string $expected, string $input): void + public function testFixWithConfiguration(string $expected, string $input, array $configuration): void { - $this->fixer->configure(['positions' => $configuration]); + $this->fixer->configure($configuration); $this->doTest($expected, $input); } + /** + * @return iterable}> + */ public static function provideFixWithConfigurationCases(): iterable { - $tests = [ - [ - ['inside', 'outside'], - <<<'EOT' - $test) { - if (\PHP_VERSION_ID >= 8_00_00) { - $test[1] = str_replace('{', '[', $test[1]); - $test[1] = str_replace('}', ']', $test[1]); - $test[2] = str_replace('{', '[', $test[2]); - $test[2] = str_replace('}', ']', $test[2]); - } - - yield $index => $test; - } - yield 'Config "default".' => [ - ['inside', 'outside'], 'attributes->get(1)) { return false; @@ -388,9 +312,79 @@ public static function provideFixWithConfigurationCases(): iterable [ $class , $method ] = $this->splitControllerClassAndMethod($controllerName); $a = $b [0]; ', + ['positions' => ['inside', 'outside']], ]; } + /** + * @param array{positions?: list} $configuration + * + * @dataProvider provideFixPre80Cases + * + * @requires PHP <8.0 + */ + public function testFixPre80(string $expected, ?string $input = null, array $configuration = []): void + { + $this->fixer->configure($configuration); + $this->doTest($expected, $input); + } + + public static function provideFixPre80Cases(): iterable + { + yield [ + '} $configuration + * + * @dataProvider provideFix80Cases + * + * @requires PHP 8.0 + */ + public function testFix80(string $expected, ?string $input, array $configuration): void + { + $this->fixer->configure($configuration); + $this->doTest($expected, $input); + } + + /** + * @return iterable}> + */ + public static function provideFix80Cases(): iterable + { + foreach (self::provideMultiDimensionalArrayCases() as $index => $test) { + $test[0] = str_replace('{', '[', $test[0]); + $test[0] = str_replace('}', ']', $test[0]); + $test[1] = str_replace('{', '[', $test[1]); + $test[1] = str_replace('}', ']', $test[1]); + + yield $index => $test; + } + } + public function testWrongConfig(): void { $this->expectException(InvalidFixerConfigurationException::class); @@ -398,4 +392,38 @@ public function testWrongConfig(): void $this->fixer->configure(['positions' => ['foo']]); } + + /** + * @return iterable}}> + */ + private static function provideMultiDimensionalArrayCases(): iterable + { + yield [ + <<<'EOT' + ['inside']], + ]; + + yield [ + <<<'EOT' + ['outside']], + ]; + } } diff --git a/tests/Fixer/Whitespace/NoWhitespaceInBlankLineFixerTest.php b/tests/Fixer/Whitespace/NoWhitespaceInBlankLineFixerTest.php index f24ae1411f5..8627197b415 100644 --- a/tests/Fixer/Whitespace/NoWhitespaceInBlankLineFixerTest.php +++ b/tests/Fixer/Whitespace/NoWhitespaceInBlankLineFixerTest.php @@ -157,16 +157,16 @@ public static function provideFixCases(): iterable } /** - * @dataProvider provideMessyWhitespacesCases + * @dataProvider provideWithWhitespacesConfigCases */ - public function testMessyWhitespaces(string $expected, ?string $input = null): void + public function testWithWhitespacesConfig(string $expected, ?string $input = null): void { $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n")); $this->doTest($expected, $input); } - public static function provideMessyWhitespacesCases(): iterable + public static function provideWithWhitespacesConfigCases(): iterable { yield [ "doTest($expected, $input); } @@ -365,7 +365,7 @@ public function testFixPhp80(string $expected, string $input): void /** * @return iterable */ - public static function provideFixPhp80Cases(): iterable + public static function provideFix80Cases(): iterable { yield [ 'doTest($expected, $input); } @@ -414,7 +414,7 @@ public function testFixPhp81(string $expected, ?string $input = null): void /** * @return iterable */ - public static function provideFixPhp81Cases(): iterable + public static function provideFix81Cases(): iterable { yield [ 'doTest($expected, $input); } @@ -440,7 +440,7 @@ public function testFixPhp82(string $expected, ?string $input = null): void /** * @return iterable */ - public static function provideFixPhp82Cases(): iterable + public static function provideFix82Cases(): iterable { yield [ ' [\PHP_VERSION_ID, true]; + yield 'is-satisfied' => [100, true]; - yield 'is-not-satisfied' => [\PHP_VERSION_ID, false]; + yield 'is-not-satisfied' => [100, false]; } private function createVersionSpecificationDouble(bool $isSatisfied = true): VersionSpecificationInterface diff --git a/tests/FixerDefinition/VersionSpecificationTest.php b/tests/FixerDefinition/VersionSpecificationTest.php index 6fa6ae2f254..719e4d3d942 100644 --- a/tests/FixerDefinition/VersionSpecificationTest.php +++ b/tests/FixerDefinition/VersionSpecificationTest.php @@ -34,43 +34,29 @@ public function testConstructorRequiresEitherMinimumOrMaximum(): void } /** - * @dataProvider provideInvalidVersionCases + * @dataProvider provideConstructorRejectsInvalidValuesCases */ - public function testConstructorRejectsInvalidMinimum(int $minimum): void - { - $this->expectException(\InvalidArgumentException::class); - - new VersionSpecification($minimum); - } - - /** - * @dataProvider provideInvalidVersionCases - */ - public function testConstructorRejectsInvalidMaximum(int $maximum): void + public function testConstructorRejectsInvalidValues(?int $minimum = null, ?int $maximum = null): void { $this->expectException(\InvalidArgumentException::class); new VersionSpecification( - \PHP_VERSION_ID, + $minimum, $maximum ); } - public static function provideInvalidVersionCases(): iterable + public static function provideConstructorRejectsInvalidValuesCases(): iterable { - yield 'negative' => [-1]; + yield 'minimum is negative' => [-1, null]; - yield 'zero' => [0]; - } + yield 'minimum is zero ' => [0, null]; - public function testConstructorRejectsMaximumLessThanMinimum(): void - { - $this->expectException(\InvalidArgumentException::class); + yield 'maximum is negative' => [null, -1]; - new VersionSpecification( - \PHP_VERSION_ID, - \PHP_VERSION_ID - 1 - ); + yield 'maximum is zero ' => [null, 0]; + + yield 'maximum less than minimum' => [32, 31]; } /** @@ -88,13 +74,13 @@ public function testIsSatisfiedByReturnsTrue(?int $minimum, ?int $maximum, int $ public static function provideIsSatisfiedByReturnsTrueCases(): iterable { - yield 'version-same-as-maximum' => [null, \PHP_VERSION_ID, \PHP_VERSION_ID]; + yield 'version-same-as-maximum' => [null, 100, 100]; - yield 'version-same-as-minimum' => [\PHP_VERSION_ID, null, \PHP_VERSION_ID]; + yield 'version-same-as-minimum' => [200, null, 200]; - yield 'version-between-minimum-and-maximum' => [\PHP_VERSION_ID - 1, \PHP_VERSION_ID + 1, \PHP_VERSION_ID]; + yield 'version-between-minimum-and-maximum' => [299, 301, 300]; - yield 'version-same-as-minimum-and-maximum' => [\PHP_VERSION_ID, \PHP_VERSION_ID, \PHP_VERSION_ID]; + yield 'version-same-as-minimum-and-maximum' => [400, 400, 400]; } /** @@ -112,8 +98,8 @@ public function testIsSatisfiedByReturnsFalse(?int $minimum, ?int $maximum, int public static function provideIsSatisfiedByReturnsFalseCases(): iterable { - yield 'version-greater-than-maximum' => [null, \PHP_VERSION_ID, \PHP_VERSION_ID + 1]; + yield 'version-greater-than-maximum' => [null, 1000, 1001]; - yield 'version-less-than-minimum' => [\PHP_VERSION_ID, null, \PHP_VERSION_ID - 1]; + yield 'version-less-than-minimum' => [2000, null, 1999]; } } diff --git a/tests/Fixtures/Integration/priority/fully_qualified_strict_types,ordered_imports.test b/tests/Fixtures/Integration/priority/fully_qualified_strict_types,ordered_imports.test new file mode 100644 index 00000000000..edef98a3322 --- /dev/null +++ b/tests/Fixtures/Integration/priority/fully_qualified_strict_types,ordered_imports.test @@ -0,0 +1,26 @@ +--TEST-- +Integration of fixers: fully_qualified_strict_types,ordered_imports. +--RULESET-- +{"fully_qualified_strict_types": {"import_symbols": true}, "ordered_imports": true} +--EXPECT-- + ['', null, PregException::class]; - yield 'invalid_open' => ["\1", null, PregException::class, "'\1' found"]; + yield 'invalid_open' => ["\1", null, PregException::class, "/'\x01' found/"]; yield 'valid_control_character_delimiter' => ["\1\1", true]; - yield 'invalid_control_character_modifier' => ["\1\1\1", null, PregException::class, ' Unknown modifier ']; + yield 'invalid_control_character_modifier' => ["\1\1\1", null, PregException::class, '/ Unknown modifier /']; yield 'valid_slate' => ['//', true]; yield 'valid_paired' => ['()', true]; - yield 'paired_non_utf8_only' => ["((*UTF8)\xFF)", null, PregException::class, 'UTF-8']; + yield 'paired_non_utf8_only' => ["((*UTF8)\xFF)", null, PregException::class, '/UTF-8/']; yield 'valid_paired_non_utf8_only' => ["(\xFF)", true]; - yield 'php_version_dependent' => ['([\\R])', false, PregException::class, 'Compilation failed: escape sequence is invalid ']; + yield 'php_version_dependent' => ['([\\R])', false, PregException::class, '/Compilation failed: escape sequence is invalid/']; - $nullByteMessage = \PHP_VERSION_ID >= 8_02_00 ? 'NUL is not a valid modifier' : 'Null byte in regex'; - - yield 'null_byte_injection' => ['()'."\0", null, PregException::class, " {$nullByteMessage} "]; + yield 'null_byte_injection' => ['()'."\0", null, PregException::class, ' (NUL is not a valid modifier|Null byte in regex) ']; } /** @@ -86,7 +84,7 @@ public function testPatternValidation(string $pattern, ?bool $expected = null, ? if (null !== $expectedMessage) { ++$i; - $this->expectExceptionMessage($expectedMessage); + $this->expectExceptionMessageMatches($expectedMessage); } return (bool) $i; @@ -126,7 +124,7 @@ public function testPatternsValidation(string $pattern, ?bool $expected = null, if (null !== $expectedMessage) { ++$i; - $this->expectExceptionMessage($expectedMessage); + $this->expectExceptionMessageMatches($expectedMessage); } return (bool) $i; diff --git a/tests/RuleSet/RuleSetTest.php b/tests/RuleSet/RuleSetTest.php index a376b49ef84..84869f8cbcd 100644 --- a/tests/RuleSet/RuleSetTest.php +++ b/tests/RuleSet/RuleSetTest.php @@ -47,7 +47,7 @@ final class RuleSetTest extends TestCase ]; /** - * @param array|bool $ruleConfig + * @param array|true $ruleConfig * * @dataProvider provideAllRulesFromSetsCases */ @@ -79,7 +79,7 @@ public function testIfAllRulesInSetsExists(string $setName, string $ruleName, $r } /** - * @param array|bool $ruleConfig + * @param array|true $ruleConfig * * @dataProvider provideAllRulesFromSetsCases */ @@ -369,6 +369,9 @@ public function testDuplicateRuleConfigurationInSetDefinitions(RuleSetDescriptio foreach ($set->getRules() as $ruleName => $ruleConfig) { if (str_starts_with($ruleName, '@')) { + if (true !== $ruleConfig && false !== $ruleConfig) { + throw new \LogicException('Disallowed configuration for RuleSet.'); + } $setRules = array_merge($setRules, $this->resolveSet($ruleName, $ruleConfig)); } else { $rules[$ruleName] = $ruleConfig; @@ -494,7 +497,7 @@ private function doSort(array &$data, string $path): void } /** - * @param array $values + * @param array $values */ private function allInteger(array $values): bool { diff --git a/tests/Runner/RunnerTest.php b/tests/Runner/RunnerTest.php index 13c9c57516f..c1195119a21 100644 --- a/tests/Runner/RunnerTest.php +++ b/tests/Runner/RunnerTest.php @@ -166,7 +166,7 @@ public function testThatDiffedFileIsPassedToDiffer(): void private function createDifferDouble(): DifferInterface { return new class() implements DifferInterface { - public ?\SplFileInfo $passedFile; + public ?\SplFileInfo $passedFile = null; public function diff(string $old, string $new, \SplFileInfo $file = null): string { diff --git a/tests/Smoke/InstallViaComposerTest.php b/tests/Smoke/InstallViaComposerTest.php index 4e52c40db1f..013884774a7 100644 --- a/tests/Smoke/InstallViaComposerTest.php +++ b/tests/Smoke/InstallViaComposerTest.php @@ -99,6 +99,8 @@ protected function setUp(): void protected function tearDown(): void { $this->fs = null; + + parent::tearDown(); } public function testInstallationViaPathIsPossible(): void diff --git a/tests/Test/AbstractFixerTestCase.php b/tests/Test/AbstractFixerTestCase.php index 1bcf850e43a..01269dc6a6a 100644 --- a/tests/Test/AbstractFixerTestCase.php +++ b/tests/Test/AbstractFixerTestCase.php @@ -66,7 +66,7 @@ abstract class AbstractFixerTestCase extends TestCase /** * do not modify this structure without prior discussion. * - * @var array + * @var array */ private array $allowedFixersWithoutDefaultCodeSample = [ 'general_phpdoc_annotation_remove' => true, @@ -207,8 +207,7 @@ final public function testFixerDefinitions(): void if ($fixerIsConfigurable) { if (isset($configSamplesProvided['default'])) { - reset($configSamplesProvided); - self::assertSame('default', key($configSamplesProvided), sprintf('[%s] First sample must be for the default configuration.', $fixerName)); + self::assertSame('default', array_key_first($configSamplesProvided), sprintf('[%s] First sample must be for the default configuration.', $fixerName)); } elseif (!isset($this->allowedFixersWithoutDefaultCodeSample[$fixerName])) { self::assertArrayHasKey($fixerName, $this->allowedRequiredOptions, sprintf('[%s] Has no sample for default configuration.', $fixerName)); } @@ -267,7 +266,13 @@ final public function testDeprecatedFixersHaveCorrectSummary(): void public function testFixerUseInsertSlicesWhenOnlyInsertionsArePerformed(): void { $reflection = new \ReflectionClass($this->fixer); - $tokens = Tokens::fromCode(file_get_contents($reflection->getFileName())); + + $filePath = $reflection->getFileName(); + if (false === $filePath) { + throw new \RuntimeException('Cannot determine sourcefile for class.'); + } + + $tokens = Tokens::fromCode(file_get_contents($filePath)); $sequences = $this->findAllTokenSequences($tokens, [[T_VARIABLE, '$tokens'], [T_OBJECT_OPERATOR], [T_STRING]]); @@ -378,62 +383,109 @@ final public function testProperMethodNaming(): void self::markTestSkipped('Not worth refactoring tests for deprecated fixers.'); } - $exceptionGroup = [ - 'CastNotation', - 'ClassNotation', - 'ClassUsage', - 'Comment', - 'ConstantNotation', - 'ControlStructure', - 'DoctrineAnnotation', - 'FunctionNotation', - 'Import', - 'LanguageConstruct', - 'ListNotation', - 'NamespaceNotation', - 'Naming', - 'Operator', - 'PhpTag', - 'PhpUnit', - 'Phpdoc', - 'ReturnNotation', - 'Semicolon', - 'Strict', - 'StringNotation', - 'Whitespace', + // should only shrink, baseline of classes violating method naming + $exceptionClasses = [ + \PhpCsFixer\Tests\Fixer\ClassNotation\ClassAttributesSeparationFixerTest::class, + \PhpCsFixer\Tests\Fixer\ClassNotation\ClassDefinitionFixerTest::class, + \PhpCsFixer\Tests\Fixer\Comment\HeaderCommentFixerTest::class, + \PhpCsFixer\Tests\Fixer\Comment\NoEmptyCommentFixerTest::class, + \PhpCsFixer\Tests\Fixer\Comment\SingleLineCommentStyleFixerTest::class, + \PhpCsFixer\Tests\Fixer\ConstantNotation\NativeConstantInvocationFixerTest::class, + \PhpCsFixer\Tests\Fixer\ControlStructure\NoBreakCommentFixerTest::class, + \PhpCsFixer\Tests\Fixer\ControlStructure\NoUnneededControlParenthesesFixerTest::class, + \PhpCsFixer\Tests\Fixer\ControlStructure\NoUselessElseFixerTest::class, + \PhpCsFixer\Tests\Fixer\ControlStructure\YodaStyleFixerTest::class, + \PhpCsFixer\Tests\Fixer\DoctrineAnnotation\DoctrineAnnotationArrayAssignmentFixerTest::class, + \PhpCsFixer\Tests\Fixer\DoctrineAnnotation\DoctrineAnnotationBracesFixerTest::class, + \PhpCsFixer\Tests\Fixer\DoctrineAnnotation\DoctrineAnnotationIndentationFixerTest::class, + \PhpCsFixer\Tests\Fixer\DoctrineAnnotation\DoctrineAnnotationSpacesFixerTest::class, + \PhpCsFixer\Tests\Fixer\FunctionNotation\FunctionDeclarationFixerTest::class, + \PhpCsFixer\Tests\Fixer\FunctionNotation\MethodArgumentSpaceFixerTest::class, + \PhpCsFixer\Tests\Fixer\FunctionNotation\NativeFunctionInvocationFixerTest::class, + \PhpCsFixer\Tests\Fixer\FunctionNotation\ReturnTypeDeclarationFixerTest::class, + \PhpCsFixer\Tests\Fixer\Import\FullyQualifiedStrictTypesFixerTest::class, + \PhpCsFixer\Tests\Fixer\Import\GlobalNamespaceImportFixerTest::class, + \PhpCsFixer\Tests\Fixer\Import\OrderedImportsFixerTest::class, + \PhpCsFixer\Tests\Fixer\Import\SingleImportPerStatementFixerTest::class, + \PhpCsFixer\Tests\Fixer\LanguageConstruct\FunctionToConstantFixerTest::class, + \PhpCsFixer\Tests\Fixer\LanguageConstruct\SingleSpaceAroundConstructFixerTest::class, + \PhpCsFixer\Tests\Fixer\ListNotation\ListSyntaxFixerTest::class, + \PhpCsFixer\Tests\Fixer\NamespaceNotation\BlankLinesBeforeNamespaceFixerTest::class, + \PhpCsFixer\Tests\Fixer\Operator\BinaryOperatorSpacesFixerTest::class, + \PhpCsFixer\Tests\Fixer\Operator\ConcatSpaceFixerTest::class, + \PhpCsFixer\Tests\Fixer\Operator\IncrementStyleFixerTest::class, + \PhpCsFixer\Tests\Fixer\Operator\NewWithParenthesesFixerTest::class, + \PhpCsFixer\Tests\Fixer\Operator\NoUselessConcatOperatorFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpTag\EchoTagSyntaxFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpTag\NoClosingTagFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpUnit\PhpUnitConstructFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpUnit\PhpUnitDedicateAssertFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpUnit\PhpUnitMethodCasingFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpUnit\PhpUnitStrictFixerTest::class, + \PhpCsFixer\Tests\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\AlignMultilineCommentFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\GeneralPhpdocTagRenameFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\NoBlankLinesAfterPhpdocFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocAddMissingParamAnnotationFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocNoAccessFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocNoAliasTagFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocNoEmptyReturnFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocNoPackageFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocOrderByValueFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocOrderFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocParamOrderFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocReturnSelfReferenceFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocSeparationFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocSummaryFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocTrimFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocTypesOrderFixerTest::class, + \PhpCsFixer\Tests\Fixer\Phpdoc\PhpdocVarWithoutNameFixerTest::class, + \PhpCsFixer\Tests\Fixer\ReturnNotation\ReturnAssignmentFixerTest::class, + \PhpCsFixer\Tests\Fixer\Semicolon\MultilineWhitespaceBeforeSemicolonsFixerTest::class, + \PhpCsFixer\Tests\Fixer\Semicolon\NoEmptyStatementFixerTest::class, + \PhpCsFixer\Tests\Fixer\Semicolon\SemicolonAfterInstructionFixerTest::class, + \PhpCsFixer\Tests\Fixer\Semicolon\SpaceAfterSemicolonFixerTest::class, + \PhpCsFixer\Tests\Fixer\Whitespace\BlankLineBeforeStatementFixerTest::class, + \PhpCsFixer\Tests\Fixer\Whitespace\IndentationTypeFixerTest::class, + \PhpCsFixer\Tests\Fixer\Whitespace\NoExtraBlankLinesFixerTest::class, + \PhpCsFixer\Tests\Fixer\Whitespace\NoSpacesAroundOffsetFixerTest::class, + \PhpCsFixer\Tests\Fixer\Whitespace\SpacesInsideParenthesesFixerTest::class, + \PhpCsFixer\Tests\Fixer\Whitespace\StatementIndentationFixerTest::class, ]; - $fixerGroup = explode('\\', static::class)[3]; - - if (\in_array($fixerGroup, $exceptionGroup, true)) { - self::markTestSkipped('Not covered yet.'); - } - - self::assertTrue(method_exists($this, 'testFix'), 'Method testFix does not exist.'); - self::assertTrue(method_exists($this, 'provideFixCases'), 'Method provideFixCases does not exist.'); - - $names = ['Fix', 'FixPre80', 'Fix80', 'Fix81', 'Fix82', 'Fix83', 'InvalidConfiguration']; + $names = ['Fix', 'Fix74Deprecated', 'FixPre80', 'Fix80', 'FixPre81', 'Fix81', 'Fix82', 'Fix83', 'WithWhitespacesConfig', 'InvalidConfiguration']; $methodNames = ['testConfigure']; foreach ($names as $name) { $methodNames[] = 'test'.$name; $methodNames[] = 'provide'.$name.'Cases'; } - $class = new \ReflectionObject($this); + $reflectionClass = new \ReflectionObject($this); $extraMethods = array_map( static fn (\ReflectionMethod $method): string => $method->getName(), array_filter( - $class->getMethods(\ReflectionMethod::IS_PUBLIC), - static fn (\ReflectionMethod $method): bool => $method->getDeclaringClass()->getName() === $class->getName() + $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC), + static fn (\ReflectionMethod $method): bool => $method->getDeclaringClass()->getName() === $reflectionClass->getName() && !\in_array($method->getName(), $methodNames, true) ) ); + if (\in_array(static::class, $exceptionClasses, true)) { + self::assertNotSame( + [], + $extraMethods, + sprintf('Class "%s" have correct method names, remove it from exceptions list.', static::class), + ); + self::markTestSkipped('Not covered yet.'); + } + + self::assertTrue(method_exists($this, 'testFix'), sprintf('Method testFix does not exist in %s.', static::class)); + self::assertTrue(method_exists($this, 'provideFixCases'), sprintf('Method provideFixCases does not exist in %s.', static::class)); self::assertSame( [], $extraMethods, - sprintf('Methods "%s" should not be present.', implode('". "', $extraMethods)), + sprintf('Methods "%s" should not be present in %s.', implode('". "', $extraMethods), static::class), ); } @@ -568,7 +620,7 @@ private static function assertValidDescription(string $fixerName, string $descri /** * @param list $sequence * - * @return list> + * @return list> */ private function findAllTokenSequences(Tokens $tokens, array $sequence): array { diff --git a/tests/Test/TokensWithObservedTransformers.php b/tests/Test/TokensWithObservedTransformers.php index 5dc9ab6a00b..f884ad6a7df 100644 --- a/tests/Test/TokensWithObservedTransformers.php +++ b/tests/Test/TokensWithObservedTransformers.php @@ -27,7 +27,7 @@ class TokensWithObservedTransformers extends Tokens public $currentTransformer; /** - * @var array> + * @var array> */ public $observedModificationsPerTransformer = []; diff --git a/tests/TestCase.php b/tests/TestCase.php index 72da70e130a..bf7c862c2e8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -15,7 +15,6 @@ namespace PhpCsFixer\Tests; use PHPUnit\Framework\TestCase as BaseTestCase; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; /** * @author Dariusz Rumiński @@ -24,7 +23,25 @@ */ abstract class TestCase extends BaseTestCase { - use ExpectDeprecationTrait; + /** @var null|callable */ + private $previouslyDefinedErrorHandler; + + /** @var list */ + private array $expectedDeprecations = []; + + /** @var list */ + private array $actualDeprecations = []; + + protected function tearDown(): void + { + if (null !== $this->previouslyDefinedErrorHandler) { + foreach ($this->expectedDeprecations as $expectedDeprecation) { + self::assertContains($expectedDeprecation, $this->actualDeprecations); + } + + restore_error_handler(); + } + } final public function testNotDefiningConstructor(): void { @@ -35,4 +52,27 @@ final public function testNotDefiningConstructor(): void $reflection->getName(), ); } + + /** + * @TODO change access to protected and pass the parameter when PHPUnit 9 support is dropped + */ + public function expectDeprecation(/* string $message */): void + { + $this->expectedDeprecations[] = func_get_arg(0); + + if (null === $this->previouslyDefinedErrorHandler) { + $this->previouslyDefinedErrorHandler = set_error_handler( + function ( + int $code, + string $message + ) { + if (E_USER_DEPRECATED === $code || E_DEPRECATED === $code) { + $this->actualDeprecations[] = $message; + } + + return true; + } + ); + } + } } diff --git a/tests/Tokenizer/Analyzer/Analysis/TypeAnalysisTest.php b/tests/Tokenizer/Analyzer/Analysis/TypeAnalysisTest.php index 8ad4aac6329..db4e6f89676 100644 --- a/tests/Tokenizer/Analyzer/Analysis/TypeAnalysisTest.php +++ b/tests/Tokenizer/Analyzer/Analysis/TypeAnalysisTest.php @@ -110,6 +110,9 @@ public function testIsNullable(bool $expected, string $input): void self::assertSame($expected, $analysis->isNullable()); } + /** + * @return iterable + */ public static function provideIsNullableCases(): iterable { yield [false, 'string']; @@ -123,75 +126,120 @@ public static function provideIsNullableCases(): iterable yield [false, '\foo\bar']; yield [true, '?\foo\bar']; + } - if (\PHP_VERSION_ID >= 8_00_00) { - yield [false, 'string|int']; + /** + * @dataProvider provideIsNullable80Cases + * + * @requires PHP 8.0 + */ + public function testIsNullable80(bool $expected, string $input): void + { + $analysis = new TypeAnalysis($input, 1, 2); + self::assertSame($expected, $analysis->isNullable()); + } - yield [true, 'string|null']; + /** + * @return iterable + */ + public static function provideIsNullable80Cases(): iterable + { + yield [false, 'string|int']; - yield [true, 'null|string']; + yield [true, 'string|null']; - yield [true, 'string|NULL']; + yield [true, 'null|string']; - yield [true, 'NULL|string']; + yield [true, 'string|NULL']; - yield [true, 'string|int|null']; + yield [true, 'NULL|string']; - yield [true, 'null|string|int']; + yield [true, 'string|int|null']; - yield [true, 'string|null|int']; + yield [true, 'null|string|int']; - yield [true, 'string|int|NULL']; + yield [true, 'string|null|int']; - yield [true, 'NULL|string|int']; + yield [true, 'string|int|NULL']; - yield [true, 'string|NULL|int']; + yield [true, 'NULL|string|int']; - yield [false, 'string|\foo\bar']; + yield [true, 'string|NULL|int']; - yield [true, 'string|\foo\bar|null']; + yield [false, 'string|\foo\bar']; - yield [true, 'null|string|\foo\bar']; + yield [true, 'string|\foo\bar|null']; - yield [true, 'string|null|\foo\bar']; + yield [true, 'null|string|\foo\bar']; - yield [true, 'string |null| int']; + yield [true, 'string|null|\foo\bar']; - yield [true, 'string| null |int']; + yield [true, 'string |null| int']; - yield [true, 'string | null | int']; + yield [true, 'string| null |int']; - yield [false, 'Null2|int']; + yield [true, 'string | null | int']; - yield [false, 'string|Null2']; + yield [false, 'Null2|int']; - yield [false, 'string |Null2']; + yield [false, 'string|Null2']; - yield [false, 'Null2| int']; + yield [false, 'string |Null2']; - yield [false, 'string | Null2 | int']; - } + yield [false, 'Null2| int']; - if (\PHP_VERSION_ID >= 8_01_00) { - yield [false, '\foo\bar&\foo\baz']; + yield [false, 'string | Null2 | int']; + } - yield [false, '\foo\bar & \foo\baz']; + /** + * @dataProvider provideIsNullable81Cases + * + * @requires PHP 8.1 + */ + public function testIsNullable81(bool $expected, string $input): void + { + $analysis = new TypeAnalysis($input, 1, 2); + self::assertSame($expected, $analysis->isNullable()); + } + + /** + * @return iterable + */ + public static function provideIsNullable81Cases(): iterable + { + yield [false, '\foo\bar&\foo\baz']; - yield [false, '\foo\bar&Null2']; - } + yield [false, '\foo\bar & \foo\baz']; - if (\PHP_VERSION_ID >= 8_02_00) { - yield [true, '(\foo\bar&\foo\baz)|null']; + yield [false, '\foo\bar&Null2']; + } + + /** + * @dataProvider provideIsNullable82Cases + * + * @requires PHP 8.2 + */ + public function testIsNullable82(bool $expected, string $input): void + { + $analysis = new TypeAnalysis($input, 1, 2); + self::assertSame($expected, $analysis->isNullable()); + } + + /** + * @return iterable + */ + public static function provideIsNullable82Cases(): iterable + { + yield [true, '(\foo\bar&\foo\baz)|null']; - yield [true, '(\foo\bar&\foo\baz) | null']; + yield [true, '(\foo\bar&\foo\baz) | null']; - yield [false, '(\foo\bar&\foo\baz)|Null2']; + yield [false, '(\foo\bar&\foo\baz)|Null2']; - yield [true, 'null']; + yield [true, 'null']; - yield [true, 'Null']; + yield [true, 'Null']; - yield [true, 'NULL']; - } + yield [true, 'NULL']; } } diff --git a/tests/Tokenizer/Analyzer/FunctionsAnalyzerTest.php b/tests/Tokenizer/Analyzer/FunctionsAnalyzerTest.php index cd87d423600..01ecd33d80c 100644 --- a/tests/Tokenizer/Analyzer/FunctionsAnalyzerTest.php +++ b/tests/Tokenizer/Analyzer/FunctionsAnalyzerTest.php @@ -39,6 +39,9 @@ public function testIsGlobalFunctionCall(string $code, array $indices): void self::assertIsGlobalFunctionCall($indices, $code); } + /** + * @return iterable}> + */ public static function provideIsGlobalFunctionCallCases(): iterable { yield [ @@ -266,16 +269,32 @@ public function A() {} '}> + */ + public static function provideIsGlobalFunctionCallPre80Cases(): iterable + { + yield [ + '}> */ - public function testFunctionReturnTypeInfo(string $code, int $methodIndex, ?TypeAnalysis $expected): void - { - $tokens = Tokens::fromCode($code); - $analyzer = new FunctionsAnalyzer(); - $actual = $analyzer->getFunctionReturnType($tokens, $methodIndex); - - self::assertSame(serialize($expected), serialize($actual)); - } - public static function provideFunctionArgumentInfoCases(): iterable { yield [' null;', 1, [ - '$a' => new ArgumentAnalysis( - '$a', - 9, - null, - new TypeAnalysis( - '\Foo\Bar', - 3, - 7 - ) - ), - ]]; - - yield [' new ArgumentAnalysis( - '$a', - 9, - null, - new TypeAnalysis( - '\Foo\Bar', - 3, - 7 - ) - ), - ]]; - } + /** + * @param array $expected + * + * @dataProvider provideFunctionArgumentInfoPre80Cases + * + * @requires PHP <8.0 + */ + public function testFunctionArgumentInfoPre80(string $code, int $methodIndex, array $expected): void + { + $tokens = Tokens::fromCode($code); + $analyzer = new FunctionsAnalyzer(); + + self::assertSame(serialize($expected), serialize($analyzer->getFunctionArguments($tokens, $methodIndex))); } + /** + * @return iterable}> + */ + public static function provideFunctionArgumentInfoPre80Cases(): iterable + { + yield [' null;', 1, [ + '$a' => new ArgumentAnalysis( + '$a', + 9, + null, + new TypeAnalysis( + '\Foo\Bar', + 3, + 7 + ) + ), + ]]; + + yield [' new ArgumentAnalysis( + '$a', + 9, + null, + new TypeAnalysis( + '\Foo\Bar', + 3, + 7 + ) + ), + ]]; + } + + /** + * @dataProvider provideFunctionReturnTypeInfoCases + */ + public function testFunctionReturnTypeInfo(string $code, int $methodIndex, ?TypeAnalysis $expected): void + { + $tokens = Tokens::fromCode($code); + $analyzer = new FunctionsAnalyzer(); + $actual = $analyzer->getFunctionReturnType($tokens, $methodIndex); + + self::assertSame(serialize($expected), serialize($actual)); + } + + /** + * @return iterable + */ public static function provideFunctionReturnTypeInfoCases(): iterable { yield [' null;', 1, null]; yield [' null;', 1, null]; @@ -618,10 +658,30 @@ public static function provideFunctionReturnTypeInfoCases(): iterable yield [' null;', 1, new TypeAnalysis('\Foo\Bar', 7, 10)]; yield [' null;', 1, new TypeAnalysis('array', 8, 8)]; + } - if (\PHP_VERSION_ID < 8_00_00) { - yield [' null;', 1, new TypeAnalysis('\Foo\Bar', 7, 11)]; - } + /** + * @dataProvider provideFunctionReturnTypeInfoPre80Cases + * + * @requires PHP <8.0 + */ + public function testFunctionReturnTypeInfoPre80(string $code, int $methodIndex, ?TypeAnalysis $expected): void + { + $tokens = Tokens::fromCode($code); + $analyzer = new FunctionsAnalyzer(); + $actual = $analyzer->getFunctionReturnType($tokens, $methodIndex); + + self::assertSame(serialize($expected), serialize($actual)); + } + + /** + * @return iterable + */ + public static function provideFunctionReturnTypeInfoPre80Cases(): iterable + { + yield [' null;', 1, new TypeAnalysis('\Foo\Bar', 7, 11)]; } /** @@ -635,6 +695,9 @@ public function testIsTheSameClassCall(bool $isTheSameClassCall, string $code, i self::assertSame($isTheSameClassCall, $analyzer->isTheSameClassCall($tokens, $index)); } + /** + * @return iterable + */ public static function provideIsTheSameClassCallCases(): iterable { $template = '= 8_00_00) { - yield [ - true, - sprintf($template, '$this?->'), - 24, - ]; - } - yield [ true, sprintf($template, '$this::'), @@ -706,6 +761,37 @@ public function methodOne() { ]; } + /** + * @dataProvider provideIsTheSameClassCall80Cases + * + * @requires PHP 8.0 + */ + public function testIsTheSameClassCall80(bool $isTheSameClassCall, string $code, int $index): void + { + $tokens = Tokens::fromCode($code); + $analyzer = new FunctionsAnalyzer(); + + self::assertSame($isTheSameClassCall, $analyzer->isTheSameClassCall($tokens, $index)); + } + + /** + * @return iterable + */ + public static function provideIsTheSameClassCall80Cases(): iterable + { + yield [ + true, + 'otherMethod(1, 2, 3); + } + } + ', + 24, + ]; + } + /** * @param array $expected * diff --git a/tests/Tokenizer/Analyzer/GotoLabelAnalyzerTest.php b/tests/Tokenizer/Analyzer/GotoLabelAnalyzerTest.php index cad5e5606c2..c7caacaf7e6 100644 --- a/tests/Tokenizer/Analyzer/GotoLabelAnalyzerTest.php +++ b/tests/Tokenizer/Analyzer/GotoLabelAnalyzerTest.php @@ -28,9 +28,9 @@ final class GotoLabelAnalyzerTest extends TestCase /** * @param int[] $expectedTrue * - * @dataProvider provideGotoLabelAnalyzerTestCases + * @dataProvider provideGotoLabelCases */ - public function testGotoLabelAnalyzerTest(string $source, array $expectedTrue): void + public function testGotoLabel(string $source, array $expectedTrue): void { $tokens = Tokens::fromCode($source); $analyzer = new GotoLabelAnalyzer(); @@ -43,7 +43,10 @@ public function testGotoLabelAnalyzerTest(string $source, array $expectedTrue): } } - public static function provideGotoLabelAnalyzerTestCases(): iterable + /** + * @return iterable}> + */ + public static function provideGotoLabelCases(): iterable { yield 'no candidates' => [ '= 8_00_00) { - yield [ - ' $isClassy) { + self::assertSame( + \in_array($index, $expectedTrue, true), + $analyzer->belongsToGoToLabel($tokens, $index) + ); } } + + /** + * @return iterable}> + */ + public static function provideGotoLabel80Cases(): iterable + { + yield [ + ' + * @return array */ private static function getConstants(): array { diff --git a/tests/Tokenizer/Processor/ImportProcessorTest.php b/tests/Tokenizer/Processor/ImportProcessorTest.php new file mode 100644 index 00000000000..36a39902886 --- /dev/null +++ b/tests/Tokenizer/Processor/ImportProcessorTest.php @@ -0,0 +1,128 @@ + + * Dariusz Rumiński + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace PhpCsFixer\Tests\Tokenizer\Processor; + +use PhpCsFixer\Tests\TestCase; +use PhpCsFixer\Tokenizer\Processor\ImportProcessor; +use PhpCsFixer\Tokenizer\Token; +use PhpCsFixer\Tokenizer\Tokens; +use PhpCsFixer\WhitespacesFixerConfig; + +/** + * @internal + * + * @covers \PhpCsFixer\Tokenizer\Processor\ImportProcessor + */ +final class ImportProcessorTest extends TestCase +{ + /** + * @param class-string $symbol + * + * @dataProvider provideTokenizeNameCases + */ + public function testTokenizeName(string $symbol): void + { + self::assertSame( + $symbol, + implode( + '', + array_map( + static fn (Token $token): string => $token->getContent(), + ImportProcessor::tokenizeName($symbol) + ) + ) + ); + } + + /** + * @return iterable + */ + public static function provideTokenizeNameCases(): iterable + { + yield [__CLASS__]; + + yield ['Foo\\Bar']; + + yield ['\\Foo\\Bar']; + + yield ['FooBar']; + + yield ['\\FooBar']; + + yield ['\\Foo\\Bar\\Baz\\Buzz']; + + yield ['\\Foo1\\Bar_\\baz\\buzz']; + } + + /** + * @param array{ + * const?: array, + * class?: array, + * function?: array + * } $imports + * + * @dataProvider provideInsertImportsCases + */ + public function testInsertImports(string $expected, string $input, array $imports, int $atIndex): void + { + $processor = new ImportProcessor(new WhitespacesFixerConfig()); + $tokens = Tokens::fromCode($input); + $processor->insertImports($tokens, $imports, $atIndex); + + self::assertSame($expected, $tokens->generateCode()); + } + + /** + * @return iterable, const?: list, function?: list}, 3: int}> + */ + public static function provideInsertImportsCases(): iterable + { + yield 'class import in single namespace' => [ + ' ['Other\\A', 'Other\\B'], + ], + 6, + ]; + + yield 'class import in single {} namespace' => [ + ' ['Other\\A', 'Other\\B'], + ], + 7, + ]; + } +} diff --git a/tests/Tokenizer/TokenTest.php b/tests/Tokenizer/TokenTest.php index 15cc7628df7..397002a14f8 100644 --- a/tests/Tokenizer/TokenTest.php +++ b/tests/Tokenizer/TokenTest.php @@ -307,7 +307,8 @@ public static function provideIsWhitespaceCases(): iterable } /** - * @param mixed $prototype + * @param mixed $prototype + * @param ?class-string<\Throwable> $expectedExceptionClass * * @dataProvider provideCreatingTokenCases */ @@ -468,9 +469,12 @@ public static function provideEqualsAnyCases(): iterable * @param bool|list $caseSensitive * * @dataProvider provideIsKeyCaseSensitiveCases + * + * @group legacy */ public function testIsKeyCaseSensitive(bool $isKeyCaseSensitive, $caseSensitive, int $key): void { + $this->expectDeprecation('Method "PhpCsFixer\Tokenizer\Token::isKeyCaseSensitive" is deprecated and will be removed in the next major version.'); self::assertSame($isKeyCaseSensitive, Token::isKeyCaseSensitive($caseSensitive, $key)); } diff --git a/tests/Tokenizer/TokensAnalyzerTest.php b/tests/Tokenizer/TokensAnalyzerTest.php index 7c304ccb21d..64208b04c9d 100644 --- a/tests/Tokenizer/TokensAnalyzerTest.php +++ b/tests/Tokenizer/TokensAnalyzerTest.php @@ -730,6 +730,9 @@ public function testIsAnonymousClass(array $expected, string $source): void } } + /** + * @return iterable, string}> + */ public static function provideIsAnonymousClassCases(): iterable { yield [ @@ -761,44 +764,104 @@ public static function provideIsAnonymousClassCases(): iterable [1 => false], '= 8_00_00) { - yield [ - [11 => true], - ' $expected + * + * @dataProvider provideIsAnonymousClass80Cases + * + * @requires PHP 8.0 + */ + public function testIsAnonymousClass80(array $expected, string $source): void + { + $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source)); - yield [ - [27 => true], - ' $expectedValue) { + self::assertSame($expectedValue, $tokensAnalyzer->isAnonymousClass($index)); } + } - if (\PHP_VERSION_ID >= 8_01_00) { - yield [ - [1 => false], - ', string}> + */ + public static function provideIsAnonymousClass80Cases(): iterable + { + yield [ + [11 => true], + ' true], + ' $expected + * + * @dataProvider provideIsAnonymousClass81Cases + * + * @requires PHP 8.1 + */ + public function testIsAnonymousClass81(array $expected, string $source): void + { + $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source)); + + foreach ($expected as $index => $expectedValue) { + self::assertSame($expectedValue, $tokensAnalyzer->isAnonymousClass($index)); } + } - if (\PHP_VERSION_ID >= 8_03_00) { - yield 'simple readonly anonymous class' => [ - [9 => true], - ', string}> + */ + public static function provideIsAnonymousClass81Cases(): iterable + { + yield [ + [1 => false], + ' [ - [13 => true], - ' $expected + * + * @dataProvider provideIsAnonymousClass83Cases + * + * @requires PHP 8.3 + */ + public function testIsAnonymousClass83(array $expected, string $source): void + { + $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source)); - yield 'readonly anonymous class with multiple attributes' => [ - [17 => true], - ' $expectedValue) { + self::assertSame($expectedValue, $tokensAnalyzer->isAnonymousClass($index)); } } + /** + * @return iterable, string}> + */ + public static function provideIsAnonymousClass83Cases(): iterable + { + yield 'simple readonly anonymous class' => [ + [9 => true], + ' [ + [13 => true], + ' [ + [17 => true], + ' $expected * diff --git a/tests/Tokenizer/Transformer/TypeIntersectionTransformerTest.php b/tests/Tokenizer/Transformer/TypeIntersectionTransformerTest.php index d76b4b5b9e8..240f353dcd6 100644 --- a/tests/Tokenizer/Transformer/TypeIntersectionTransformerTest.php +++ b/tests/Tokenizer/Transformer/TypeIntersectionTransformerTest.php @@ -63,7 +63,7 @@ function foo(){} ', ]; - if (\PHP_VERSION_ID >= 8_01_00) { + if (\defined('T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG')) { // @TODO: drop condition when PHP 8.1+ is required yield 'ensure T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG is not modified' => [ 'originalValueOfFutureMode}"); + + parent::tearDown(); } /**