From 2d6dba4055c239757c0d42dc09be955174ef7415 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 12 Oct 2021 11:27:15 +0200 Subject: [PATCH] [DX] Check php version features parameter type (#983) --- src/Php/PhpVersionProvider.php | 56 +++++++++++++++++++++-- src/ValueObject/PhpVersion.php | 4 +- templates/rector.php.dist | 2 +- tests/Php/PhpVersionProviderTest.php | 50 ++++++++++++++++---- tests/Php/config/invalid_input.php | 11 +++++ tests/Php/config/invalid_number_input.php | 11 +++++ tests/Php/config/invalid_php_4_number.php | 11 +++++ tests/Php/config/invalid_string_input.php | 11 +++++ tests/Php/config/valid_explicit_value.php | 11 +++++ tests/Php/config/valid_minus_value.php | 12 +++++ 10 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 tests/Php/config/invalid_input.php create mode 100644 tests/Php/config/invalid_number_input.php create mode 100644 tests/Php/config/invalid_php_4_number.php create mode 100644 tests/Php/config/invalid_string_input.php create mode 100644 tests/Php/config/valid_explicit_value.php create mode 100644 tests/Php/config/valid_minus_value.php diff --git a/src/Php/PhpVersionProvider.php b/src/Php/PhpVersionProvider.php index d9787ec8256..d95ffb935ce 100644 --- a/src/Php/PhpVersionProvider.php +++ b/src/Php/PhpVersionProvider.php @@ -4,8 +4,11 @@ declare(strict_types=1); namespace Rector\Core\Php; +use Nette\Utils\Strings; use Rector\Core\Configuration\Option; +use Rector\Core\Exception\Configuration\InvalidConfigurationException; use Rector\Core\Php\PhpVersionResolver\ProjectComposerJsonPhpVersionResolver; +use Rector\Core\ValueObject\PhpVersion; use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment; use Symplify\PackageBuilder\Parameter\ParameterProvider; @@ -14,6 +17,12 @@ use Symplify\PackageBuilder\Parameter\ParameterProvider; */ final class PhpVersionProvider { + /** + * @var string + * @see https://regex101.com/r/qBMnbl/1 + */ + private const VALID_PHP_VERSION_REGEX = '#^\d{5,6}$#'; + public function __construct( private ParameterProvider $parameterProvider, private ProjectComposerJsonPhpVersionResolver $projectComposerJsonPhpVersionResolver @@ -22,15 +31,17 @@ final class PhpVersionProvider public function provide(): int { - $phpVersionFeatures = $this->parameterProvider->provideIntParameter(Option::PHP_VERSION_FEATURES); + $phpVersionFeatures = $this->parameterProvider->provideParameter(Option::PHP_VERSION_FEATURES); + $this->validatePhpVersionFeaturesParameter($phpVersionFeatures); + if ($phpVersionFeatures > 0) { return $phpVersionFeatures; } // for tests if (StaticPHPUnitEnvironment::isPHPUnitRun()) { - // so we don't have to up - return 100000; + // so we don't have to keep with up with newest version + return PhpVersion::PHP_10; } $projectComposerJson = getcwd() . '/composer.json'; @@ -48,4 +59,43 @@ final class PhpVersionProvider { return $phpVersion <= $this->provide(); } + + private function validatePhpVersionFeaturesParameter(mixed $phpVersionFeatures): void + { + if ($phpVersionFeatures === null) { + return; + } + + if (PhpVersion::isValid($phpVersionFeatures)) { + return; + } + + if (! is_int($phpVersionFeatures)) { + $this->throwInvalidTypeException($phpVersionFeatures); + } + + if (Strings::match( + (string) $phpVersionFeatures, + self::VALID_PHP_VERSION_REGEX + ) && $phpVersionFeatures >= (PhpVersion::PHP_53 - 1)) { + return; + } + + $this->throwInvalidTypeException($phpVersionFeatures); + } + + private function throwInvalidTypeException(mixed $phpVersionFeatures): void + { + $errorMessage = sprintf( + 'Parameter "%s::%s" must be int, "%s" given.%sUse constant from "%s" to provide it, e.g. "%s::%s"', + Option::class, + 'PHP_VERSION_FEATURES', + (string) $phpVersionFeatures, + PHP_EOL, + PhpVersion::class, + PhpVersion::class, + 'PHP_80' + ); + throw new InvalidConfigurationException($errorMessage); + } } diff --git a/src/ValueObject/PhpVersion.php b/src/ValueObject/PhpVersion.php index ab10b38bacc..bd26ff2a496 100644 --- a/src/ValueObject/PhpVersion.php +++ b/src/ValueObject/PhpVersion.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace Rector\Core\ValueObject; -final class PhpVersion +use MyCLabs\Enum\Enum; + +final class PhpVersion extends Enum { /** * @api diff --git a/templates/rector.php.dist b/templates/rector.php.dist index 7ccd0c28d8f..75d4d52a8cf 100644 --- a/templates/rector.php.dist +++ b/templates/rector.php.dist @@ -15,7 +15,7 @@ return static function (ContainerConfigurator $containerConfigurator): void { ]); // Define what rule sets will be applied - $containerConfigurator->import(SetList::CODE_QUALITY); + $containerConfigurator->import(SetList::DEAD_CODE); // get services (needed for register a single rule) // $services = $containerConfigurator->services(); diff --git a/tests/Php/PhpVersionProviderTest.php b/tests/Php/PhpVersionProviderTest.php index be8ad5d2490..923e93875c7 100644 --- a/tests/Php/PhpVersionProviderTest.php +++ b/tests/Php/PhpVersionProviderTest.php @@ -4,22 +4,56 @@ declare(strict_types=1); namespace Rector\Core\Tests\Php; +use Iterator; +use Rector\Core\Exception\Configuration\InvalidConfigurationException; use Rector\Core\Php\PhpVersionProvider; use Rector\Testing\PHPUnit\AbstractTestCase; +use Symplify\SmartFileSystem\SmartFileInfo; final class PhpVersionProviderTest extends AbstractTestCase { - private PhpVersionProvider $phpVersionProvider; - - protected function setUp(): void + /** + * @doesNotPerformAssertions + * @dataProvider provideValidConfigData() + */ + public function testValidInput(SmartFileInfo $invalidFileInfo): void { - $this->boot(); - $this->phpVersionProvider = $this->getService(PhpVersionProvider::class); + $this->bootFromConfigFileInfos([$invalidFileInfo]); + + $phpVersionProvider = $this->getService(PhpVersionProvider::class); + $phpVersionProvider->provide(); } - public function test(): void + /** + * @return Iterator + */ + public function provideValidConfigData(): Iterator { - $phpVersion = $this->phpVersionProvider->provide(); - $this->assertSame(100000, $phpVersion); + yield [new SmartFileInfo(__DIR__ . '/config/valid_explicit_value.php')]; + yield [new SmartFileInfo(__DIR__ . '/config/valid_minus_value.php')]; + } + + /** + * @dataProvider provideInvalidConfigData() + */ + public function testInvalidInput(SmartFileInfo $invalidFileInfo): void + { + $this->expectException(InvalidConfigurationException::class); + + $this->bootFromConfigFileInfos([$invalidFileInfo]); + + $phpVersionProvider = $this->getService(PhpVersionProvider::class); + $phpVersionProvider->provide(); + } + + /** + * @return Iterator + */ + public function provideInvalidConfigData(): Iterator + { + yield [new SmartFileInfo(__DIR__ . '/config/invalid_input.php')]; + yield [new SmartFileInfo(__DIR__ . '/config/invalid_string_input.php')]; + yield [new SmartFileInfo(__DIR__ . '/config/invalid_number_input.php')]; + yield [new SmartFileInfo(__DIR__ . '/config/invalid_php_4_number.php')]; } } diff --git a/tests/Php/config/invalid_input.php b/tests/Php/config/invalid_input.php new file mode 100644 index 00000000000..6a44ae48bb4 --- /dev/null +++ b/tests/Php/config/invalid_input.php @@ -0,0 +1,11 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, '10000'); +}; diff --git a/tests/Php/config/invalid_number_input.php b/tests/Php/config/invalid_number_input.php new file mode 100644 index 00000000000..09ef0b38ae0 --- /dev/null +++ b/tests/Php/config/invalid_number_input.php @@ -0,0 +1,11 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, 291_084_902_184); +}; diff --git a/tests/Php/config/invalid_php_4_number.php b/tests/Php/config/invalid_php_4_number.php new file mode 100644 index 00000000000..331950b169a --- /dev/null +++ b/tests/Php/config/invalid_php_4_number.php @@ -0,0 +1,11 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, 40000); +}; diff --git a/tests/Php/config/invalid_string_input.php b/tests/Php/config/invalid_string_input.php new file mode 100644 index 00000000000..a008353e0d6 --- /dev/null +++ b/tests/Php/config/invalid_string_input.php @@ -0,0 +1,11 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, '7.3'); +}; diff --git a/tests/Php/config/valid_explicit_value.php b/tests/Php/config/valid_explicit_value.php new file mode 100644 index 00000000000..c168c4853cc --- /dev/null +++ b/tests/Php/config/valid_explicit_value.php @@ -0,0 +1,11 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, 100000); +}; diff --git a/tests/Php/config/valid_minus_value.php b/tests/Php/config/valid_minus_value.php new file mode 100644 index 00000000000..25af1f4a684 --- /dev/null +++ b/tests/Php/config/valid_minus_value.php @@ -0,0 +1,12 @@ +parameters(); + $parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::ARRAY_KEY_FIRST_LAST - 1); +};