From 574fb63bc975af1be8c1ae6783052fa089b1d565 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sat, 20 Jun 2026 11:04:33 +0200 Subject: [PATCH 1/2] Use sebastian/version-requirement --- README.md | 1 + build.xml | 7 ++ composer.json | 2 + composer.lock | 75 ++++++++++++++- src/Metadata/Api/Requirements.php | 6 +- .../InvalidVersionRequirementException.php | 19 ---- src/Metadata/Metadata.php | 2 +- src/Metadata/Parser/AttributeParser.php | 6 +- src/Metadata/RequiresPhp.php | 2 +- src/Metadata/RequiresPhpExtension.php | 2 +- src/Metadata/RequiresPhpunit.php | 2 +- .../Version/ComparisonRequirement.php | 45 --------- .../Version/ConstraintRequirement.php | 55 ----------- .../Version/InvalidVersionRequirement.php | 44 --------- src/Metadata/Version/Requirement.php | 57 ------------ src/TextUI/Configuration/Registry.php | 2 +- .../Configuration/Value/TestDirectory.php | 2 +- src/TextUI/Configuration/Value/TestFile.php | 2 +- src/TextUI/Configuration/Xml/Loader.php | 2 +- .../InvalidVersionOperatorException.php | 31 ------- src/Util/VersionComparisonOperator.php | 57 ------------ .../unit/Metadata/MetadataCollectionTest.php | 4 +- tests/unit/Metadata/MetadataTest.php | 4 +- .../Parser/AttributeParserTestCase.php | 4 +- .../Version/InvalidVersionRequirementTest.php | 35 ------- .../unit/Metadata/Version/RequirementTest.php | 92 ------------------- .../Value/TestDirectoryCollectionTest.php | 2 +- .../Configuration/Value/TestDirectoryTest.php | 2 +- .../Value/TestFileCollectionTest.php | 2 +- .../Configuration/Value/TestFileTest.php | 2 +- .../Util/VersionComparisonOperatorTest.php | 59 ------------ 31 files changed, 107 insertions(+), 520 deletions(-) delete mode 100644 src/Metadata/Exception/InvalidVersionRequirementException.php delete mode 100644 src/Metadata/Version/ComparisonRequirement.php delete mode 100644 src/Metadata/Version/ConstraintRequirement.php delete mode 100644 src/Metadata/Version/InvalidVersionRequirement.php delete mode 100644 src/Metadata/Version/Requirement.php delete mode 100644 src/Util/Exception/InvalidVersionOperatorException.php delete mode 100644 src/Util/VersionComparisonOperator.php delete mode 100644 tests/unit/Metadata/Version/InvalidVersionRequirementTest.php delete mode 100644 tests/unit/Metadata/Version/RequirementTest.php delete mode 100644 tests/unit/Util/VersionComparisonOperatorTest.php diff --git a/README.md b/README.md index d75fb0204c4..1768ef1e471 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Here is a list of all components that are primarily developed and maintained by * [sebastian/recursion-context](https://github.com/sebastianbergmann/recursion-context) * [sebastian/type](https://github.com/sebastianbergmann/type) * [sebastian/version](https://github.com/sebastianbergmann/version) +* [sebastian/version-requirement](https://github.com/sebastianbergmann/version-requirement) A very special thanks to everyone who has contributed to the [PHPUnit Manual](https://github.com/sebastianbergmann/phpunit-documentation-english). diff --git a/build.xml b/build.xml index d8b84f68c52..8fc78889271 100644 --- a/build.xml +++ b/build.xml @@ -303,6 +303,13 @@ + + + + + + + diff --git a/composer.json b/composer.json index 58ba7e0d066..68ce9012e52 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "security": "https://github.com/sebastianbergmann/phpunit/security/policy" }, "prefer-stable": true, + "minimum-stability": "dev", "require": { "php": ">=8.4.1", "ext-dom": "*", @@ -55,6 +56,7 @@ "sebastian/recursion-context": "^8.0.0", "sebastian/type": "^7.0.1", "sebastian/version": "^7.0.0", + "sebastian/version-requirement": "^1.0", "staabm/side-effects-detector": "^1.0.5" }, "config": { diff --git a/composer.lock b/composer.lock index 9e7067479cc..3ed67ce81dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fdd1cf0b879485ea837501dd977847ec", + "content-hash": "ce29f3be7009692e093af4b0ebb7bc68", "packages": [ { "name": "myclabs/deep-copy", @@ -1732,6 +1732,77 @@ ], "time": "2026-02-06T04:52:52+00:00" }, + { + "name": "sebastian/version-requirement", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version-requirement.git", + "reference": "7662b2811918858a5421fbbaebdfa87f68f39190" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version-requirement/zipball/7662b2811918858a5421fbbaebdfa87f68f39190", + "reference": "7662b2811918858a5421fbbaebdfa87f68f39190", + "shasum": "" + }, + "require": { + "phar-io/version": "^3.2.1", + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.2.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for working with version requirements", + "homepage": "https://github.com/sebastianbergmann/version-requirement", + "support": { + "issues": "https://github.com/sebastianbergmann/version-requirement/issues", + "security": "https://github.com/sebastianbergmann/version-requirement/security/policy", + "source": "https://github.com/sebastianbergmann/version-requirement/tree/main" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/version-requirement", + "type": "tidelift" + } + ], + "time": "2026-06-20T08:35:21+00:00" + }, { "name": "staabm/side-effects-detector", "version": "1.0.5", @@ -1837,7 +1908,7 @@ ], "packages-dev": [], "aliases": [], - "minimum-stability": "stable", + "minimum-stability": "dev", "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, diff --git a/src/Metadata/Api/Requirements.php b/src/Metadata/Api/Requirements.php index a1198206ef7..c634f5c09a5 100644 --- a/src/Metadata/Api/Requirements.php +++ b/src/Metadata/Api/Requirements.php @@ -37,11 +37,11 @@ use PHPUnit\Metadata\RequiresPhpunit; use PHPUnit\Metadata\RequiresPhpunitExtension; use PHPUnit\Metadata\RequiresSetting; -use PHPUnit\Metadata\Version\ComparisonRequirement; -use PHPUnit\Metadata\Version\InvalidVersionRequirement; -use PHPUnit\Metadata\Version\Requirement; use PHPUnit\Runner\Version; use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use SebastianBergmann\VersionRequirement\ComparisonRequirement; +use SebastianBergmann\VersionRequirement\InvalidVersionRequirement; +use SebastianBergmann\VersionRequirement\Requirement; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/Metadata/Exception/InvalidVersionRequirementException.php b/src/Metadata/Exception/InvalidVersionRequirementException.php deleted file mode 100644 index 359f723c1dc..00000000000 --- a/src/Metadata/Exception/InvalidVersionRequirementException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata; - -use RuntimeException; - -/** - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - */ -final class InvalidVersionRequirementException extends RuntimeException implements Exception -{ -} diff --git a/src/Metadata/Metadata.php b/src/Metadata/Metadata.php index 9ef0fff102a..92b716bf9f6 100644 --- a/src/Metadata/Metadata.php +++ b/src/Metadata/Metadata.php @@ -10,8 +10,8 @@ namespace PHPUnit\Metadata; use Closure; -use PHPUnit\Metadata\Version\Requirement; use PHPUnit\Runner\Extension\Extension; +use SebastianBergmann\VersionRequirement\Requirement; /** * @immutable diff --git a/src/Metadata/Parser/AttributeParser.php b/src/Metadata/Parser/AttributeParser.php index d0409eaf167..f3405f05ff9 100644 --- a/src/Metadata/Parser/AttributeParser.php +++ b/src/Metadata/Parser/AttributeParser.php @@ -93,13 +93,13 @@ use PHPUnit\Framework\Attributes\UsesTrait; use PHPUnit\Framework\Attributes\WithEnvironmentVariable; use PHPUnit\Framework\Attributes\WithoutErrorHandler; -use PHPUnit\Metadata\InvalidVersionRequirementException; use PHPUnit\Metadata\Metadata; use PHPUnit\Metadata\MetadataCollection; -use PHPUnit\Metadata\Version\InvalidVersionRequirement; -use PHPUnit\Metadata\Version\Requirement; use ReflectionClass; use ReflectionMethod; +use SebastianBergmann\VersionRequirement\InvalidVersionRequirement; +use SebastianBergmann\VersionRequirement\InvalidVersionRequirementException; +use SebastianBergmann\VersionRequirement\Requirement; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/Metadata/RequiresPhp.php b/src/Metadata/RequiresPhp.php index a5805013bc3..b1c9d4f6880 100644 --- a/src/Metadata/RequiresPhp.php +++ b/src/Metadata/RequiresPhp.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\Metadata; -use PHPUnit\Metadata\Version\Requirement; +use SebastianBergmann\VersionRequirement\Requirement; /** * @immutable diff --git a/src/Metadata/RequiresPhpExtension.php b/src/Metadata/RequiresPhpExtension.php index fd7d4243586..45932037c58 100644 --- a/src/Metadata/RequiresPhpExtension.php +++ b/src/Metadata/RequiresPhpExtension.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\Metadata; -use PHPUnit\Metadata\Version\Requirement; +use SebastianBergmann\VersionRequirement\Requirement; /** * @immutable diff --git a/src/Metadata/RequiresPhpunit.php b/src/Metadata/RequiresPhpunit.php index f0c08c57fc9..fa40f9776c0 100644 --- a/src/Metadata/RequiresPhpunit.php +++ b/src/Metadata/RequiresPhpunit.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\Metadata; -use PHPUnit\Metadata\Version\Requirement; +use SebastianBergmann\VersionRequirement\Requirement; /** * @immutable diff --git a/src/Metadata/Version/ComparisonRequirement.php b/src/Metadata/Version/ComparisonRequirement.php deleted file mode 100644 index b87222fd0d3..00000000000 --- a/src/Metadata/Version/ComparisonRequirement.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata\Version; - -use function version_compare; -use PHPUnit\Util\VersionComparisonOperator; - -/** - * @immutable - * - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - */ -final readonly class ComparisonRequirement extends Requirement -{ - private string $version; - private VersionComparisonOperator $operator; - - public function __construct(string $version, VersionComparisonOperator $operator) - { - $this->version = $version; - $this->operator = $operator; - } - - public function isSatisfiedBy(string $version): bool - { - return version_compare($version, $this->version, $this->operator->asString()); - } - - public function asString(): string - { - return $this->operator->asString() . ' ' . $this->version; - } - - public function version(): string - { - return $this->version; - } -} diff --git a/src/Metadata/Version/ConstraintRequirement.php b/src/Metadata/Version/ConstraintRequirement.php deleted file mode 100644 index 752fe7b6d19..00000000000 --- a/src/Metadata/Version/ConstraintRequirement.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata\Version; - -use function assert; -use function preg_replace; -use PharIo\Version\Version; -use PharIo\Version\VersionConstraint; - -/** - * @immutable - * - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - */ -final readonly class ConstraintRequirement extends Requirement -{ - private VersionConstraint $constraint; - - public function __construct(VersionConstraint $constraint) - { - $this->constraint = $constraint; - } - - public function isSatisfiedBy(string $version): bool - { - return $this->constraint->complies( - new Version($this->sanitize($version)), - ); - } - - public function asString(): string - { - return $this->constraint->asString(); - } - - private function sanitize(string $version): string - { - $sanitized = preg_replace( - '/^(\d+\.\d+(?:.\d+)?).*$/', - '$1', - $version, - ); - - assert($sanitized !== null); - - return $sanitized; - } -} diff --git a/src/Metadata/Version/InvalidVersionRequirement.php b/src/Metadata/Version/InvalidVersionRequirement.php deleted file mode 100644 index 9f3e370068d..00000000000 --- a/src/Metadata/Version/InvalidVersionRequirement.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata\Version; - -/** - * @immutable - * - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - */ -final readonly class InvalidVersionRequirement extends Requirement -{ - /** - * @var non-empty-string - */ - private string $message; - - /** - * @param non-empty-string $message - */ - public function __construct(string $message) - { - $this->message = $message; - } - - public function isSatisfiedBy(string $version): bool - { - return false; - } - - /** - * @return non-empty-string - */ - public function asString(): string - { - return $this->message; - } -} diff --git a/src/Metadata/Version/Requirement.php b/src/Metadata/Version/Requirement.php deleted file mode 100644 index 01f98f7310f..00000000000 --- a/src/Metadata/Version/Requirement.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata\Version; - -use function preg_match; -use PharIo\Version\UnsupportedVersionConstraintException; -use PharIo\Version\VersionConstraintParser; -use PHPUnit\Metadata\InvalidVersionRequirementException; -use PHPUnit\Util\InvalidVersionOperatorException; -use PHPUnit\Util\VersionComparisonOperator; - -/** - * @immutable - * - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - */ -abstract readonly class Requirement -{ - private const string VERSION_COMPARISON = "/(?P!=|<|<=|<>|=|==|>|>=)?\s*(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m"; - - /** - * @throws InvalidVersionOperatorException - * @throws InvalidVersionRequirementException - */ - public static function from(string $versionRequirement): self - { - try { - return new ConstraintRequirement( - (new VersionConstraintParser)->parse( - $versionRequirement, - ), - ); - } catch (UnsupportedVersionConstraintException) { - if (preg_match(self::VERSION_COMPARISON, $versionRequirement, $matches) > 0) { - return new ComparisonRequirement( - $matches['version'], - new VersionComparisonOperator( - $matches['operator'] !== '' ? $matches['operator'] : '>=', - ), - ); - } - } - - throw new InvalidVersionRequirementException; - } - - abstract public function isSatisfiedBy(string $version): bool; - - abstract public function asString(): string; -} diff --git a/src/TextUI/Configuration/Registry.php b/src/TextUI/Configuration/Registry.php index f29bc80f72b..de07aec4d4f 100644 --- a/src/TextUI/Configuration/Registry.php +++ b/src/TextUI/Configuration/Registry.php @@ -18,7 +18,7 @@ use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\CliArguments\Exception; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; /** * CLI options and XML configuration are static within a single PHPUnit process. diff --git a/src/TextUI/Configuration/Value/TestDirectory.php b/src/TextUI/Configuration/Value/TestDirectory.php index 2997fd7b477..d037d212aae 100644 --- a/src/TextUI/Configuration/Value/TestDirectory.php +++ b/src/TextUI/Configuration/Value/TestDirectory.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\TextUI\Configuration; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/TextUI/Configuration/Value/TestFile.php b/src/TextUI/Configuration/Value/TestFile.php index e658ff88437..7b9f548a70b 100644 --- a/src/TextUI/Configuration/Value/TestFile.php +++ b/src/TextUI/Configuration/Value/TestFile.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\TextUI\Configuration; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/TextUI/Configuration/Xml/Loader.php b/src/TextUI/Configuration/Xml/Loader.php index 0b4f464d195..892396b4919 100644 --- a/src/TextUI/Configuration/Xml/Loader.php +++ b/src/TextUI/Configuration/Xml/Loader.php @@ -77,11 +77,11 @@ use PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; -use PHPUnit\Util\VersionComparisonOperator; use PHPUnit\Util\Xml\Loader as XmlLoader; use PHPUnit\Util\Xml\XmlException; use SebastianBergmann\CodeCoverage\Report\Html\Colors; use SebastianBergmann\CodeCoverage\Report\Thresholds; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; use Throwable; /** diff --git a/src/Util/Exception/InvalidVersionOperatorException.php b/src/Util/Exception/InvalidVersionOperatorException.php deleted file mode 100644 index bc2fe9a0ed5..00000000000 --- a/src/Util/Exception/InvalidVersionOperatorException.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Util; - -use function sprintf; -use RuntimeException; - -/** - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - * - * @internal This class is not covered by the backward compatibility promise for PHPUnit - */ -final class InvalidVersionOperatorException extends RuntimeException implements Exception -{ - public function __construct(string $operator) - { - parent::__construct( - sprintf( - '"%s" is not a valid version_compare() operator', - $operator, - ), - ); - } -} diff --git a/src/Util/VersionComparisonOperator.php b/src/Util/VersionComparisonOperator.php deleted file mode 100644 index 9dcba3c32a3..00000000000 --- a/src/Util/VersionComparisonOperator.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Util; - -use function in_array; - -/** - * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit - * - * @immutable - */ -final readonly class VersionComparisonOperator -{ - /** - * @var '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' - */ - private string $operator; - - /** - * @param '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' $operator - * - * @throws InvalidVersionOperatorException - */ - public function __construct(string $operator) - { - $this->ensureOperatorIsValid($operator); - - $this->operator = $operator; - } - - /** - * @return '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' - */ - public function asString(): string - { - return $this->operator; - } - - /** - * @param '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' $operator - * - * @throws InvalidVersionOperatorException - */ - private function ensureOperatorIsValid(string $operator): void - { - if (!in_array($operator, ['<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq', '!=', '<>', 'ne'], true)) { - throw new InvalidVersionOperatorException($operator); - } - } -} diff --git a/tests/unit/Metadata/MetadataCollectionTest.php b/tests/unit/Metadata/MetadataCollectionTest.php index 591b811d8bc..e6ade592134 100644 --- a/tests/unit/Metadata/MetadataCollectionTest.php +++ b/tests/unit/Metadata/MetadataCollectionTest.php @@ -14,8 +14,8 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use PHPUnit\Metadata\Version\ComparisonRequirement; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\ComparisonRequirement; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; use stdClass; #[CoversClass(MetadataCollection::class)] diff --git a/tests/unit/Metadata/MetadataTest.php b/tests/unit/Metadata/MetadataTest.php index 5b0f6620742..f6e81c4d29b 100644 --- a/tests/unit/Metadata/MetadataTest.php +++ b/tests/unit/Metadata/MetadataTest.php @@ -14,9 +14,9 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\TestCase; -use PHPUnit\Metadata\Version\ComparisonRequirement; use PHPUnit\TestFixture\Metadata\Attribute\ExampleTrait; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\ComparisonRequirement; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; #[CoversClass(Metadata::class)] #[CoversClassesThatExtendClass(Metadata::class)] diff --git a/tests/unit/Metadata/Parser/AttributeParserTestCase.php b/tests/unit/Metadata/Parser/AttributeParserTestCase.php index d6bbeacd24b..47265d53c39 100644 --- a/tests/unit/Metadata/Parser/AttributeParserTestCase.php +++ b/tests/unit/Metadata/Parser/AttributeParserTestCase.php @@ -23,8 +23,6 @@ use PHPUnit\Metadata\RequiresPhpunitExtension; use PHPUnit\Metadata\RequiresSetting; use PHPUnit\Metadata\Retry; -use PHPUnit\Metadata\Version\ComparisonRequirement; -use PHPUnit\Metadata\Version\ConstraintRequirement; use PHPUnit\Metadata\WithEnvironmentVariable; use PHPUnit\TestFixture\Metadata\Attribute\AllowMockObjectsWithoutExpectationsOnClassTest; use PHPUnit\TestFixture\Metadata\Attribute\AllowMockObjectsWithoutExpectationsOnMethodTest; @@ -72,6 +70,8 @@ use PHPUnit\TestFixture\Metadata\Attribute\UsesTest; use PHPUnit\TestFixture\Metadata\Attribute\WithEnvironmentVariableTest; use PHPUnit\TestFixture\Metadata\Attribute\WithoutErrorHandlerTest; +use SebastianBergmann\VersionRequirement\ComparisonRequirement; +use SebastianBergmann\VersionRequirement\ConstraintRequirement; abstract class AttributeParserTestCase extends TestCase { diff --git a/tests/unit/Metadata/Version/InvalidVersionRequirementTest.php b/tests/unit/Metadata/Version/InvalidVersionRequirementTest.php deleted file mode 100644 index 975054679a4..00000000000 --- a/tests/unit/Metadata/Version/InvalidVersionRequirementTest.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata\Version; - -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\Small; -use PHPUnit\Framework\TestCase; - -#[CoversClass(InvalidVersionRequirement::class)] -#[Small] -#[Group('metadata')] -final class InvalidVersionRequirementTest extends TestCase -{ - public function testCanBeRepresentedAsString(): void - { - $requirement = new InvalidVersionRequirement('message'); - - $this->assertSame('message', $requirement->asString()); - } - - public function testIsNeverSatisfied(): void - { - $requirement = new InvalidVersionRequirement('message'); - - $this->assertFalse($requirement->isSatisfiedBy('1.0.0')); - } -} diff --git a/tests/unit/Metadata/Version/RequirementTest.php b/tests/unit/Metadata/Version/RequirementTest.php deleted file mode 100644 index f94a05bd45a..00000000000 --- a/tests/unit/Metadata/Version/RequirementTest.php +++ /dev/null @@ -1,92 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Metadata; - -use PharIo\Version\VersionConstraintParser; -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\Small; -use PHPUnit\Framework\Attributes\UsesClass; -use PHPUnit\Framework\TestCase; -use PHPUnit\Metadata\Version\ComparisonRequirement; -use PHPUnit\Metadata\Version\ConstraintRequirement; -use PHPUnit\Metadata\Version\Requirement; -use PHPUnit\Util\VersionComparisonOperator; - -#[CoversClass(ComparisonRequirement::class)] -#[CoversClass(ConstraintRequirement::class)] -#[CoversClass(Requirement::class)] -#[UsesClass(VersionComparisonOperator::class)] -#[Small] -#[Group('metadata')] -final class RequirementTest extends TestCase -{ - /** - * @return non-empty-list - */ - public static function constraintProvider(): array - { - return [ - [ - true, - '1.0.0', - new ConstraintRequirement( - (new VersionConstraintParser)->parse('1.0.0'), - ), - ], - ]; - } - - /** - * @return non-empty-list - */ - public static function comparisonProvider(): array - { - return [ - [true, '1.0.0', new ComparisonRequirement('1.0.0', new VersionComparisonOperator('='))], - ]; - } - - public function testCanBeCreatedFromStringWithVersionConstraint(): void - { - $requirement = Requirement::from('^1.0'); - - $this->assertInstanceOf(ConstraintRequirement::class, $requirement); - $this->assertSame('^1.0', $requirement->asString()); - } - - #[DataProvider('constraintProvider')] - public function testVersionRequirementCanBeCheckedUsingVersionConstraint(bool $expected, string $version, ConstraintRequirement $requirement): void - { - $this->assertSame($expected, $requirement->isSatisfiedBy($version)); - } - - public function testCanBeCreatedFromStringWithSimpleComparison(): void - { - $requirement = Requirement::from('>= 1.0'); - - $this->assertInstanceOf(ComparisonRequirement::class, $requirement); - $this->assertSame('>= 1.0', $requirement->asString()); - } - - #[DataProvider('comparisonProvider')] - public function testVersionRequirementCanBeCheckedUsingSimpleComparison(bool $expected, string $version, ComparisonRequirement $requirement): void - { - $this->assertSame($expected, $requirement->isSatisfiedBy($version)); - } - - public function testCannotBeCreatedFromInvalidString(): void - { - $this->expectException(InvalidVersionRequirementException::class); - - Requirement::from('invalid'); - } -} diff --git a/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php index 928b67dd850..a0f205dfa59 100644 --- a/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; #[CoversClass(TestDirectoryCollection::class)] #[CoversClass(TestDirectoryCollectionIterator::class)] diff --git a/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php b/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php index e1ebcbfa84f..c9437b58298 100644 --- a/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\TestCase; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; #[CoversClass(TestDirectory::class)] #[Small] diff --git a/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php index 43cd4c56bd6..2dda3e971a9 100644 --- a/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; #[CoversClass(TestFileCollection::class)] #[CoversClass(TestFileCollectionIterator::class)] diff --git a/tests/unit/TextUI/Configuration/Value/TestFileTest.php b/tests/unit/TextUI/Configuration/Value/TestFileTest.php index 31db4d9c7c3..1cf5523bfb6 100644 --- a/tests/unit/TextUI/Configuration/Value/TestFileTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestFileTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\TestCase; -use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator; #[CoversClass(TestFile::class)] #[Small] diff --git a/tests/unit/Util/VersionComparisonOperatorTest.php b/tests/unit/Util/VersionComparisonOperatorTest.php deleted file mode 100644 index 39745275a9d..00000000000 --- a/tests/unit/Util/VersionComparisonOperatorTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace PHPUnit\Util; - -use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\Small; -use PHPUnit\Framework\Attributes\TestDox; -use PHPUnit\Framework\TestCase; - -#[CoversClass(VersionComparisonOperator::class)] -#[CoversClass(InvalidVersionOperatorException::class)] -#[Small] -final class VersionComparisonOperatorTest extends TestCase -{ - /** - * @return non-empty-list> - */ - public static function validValues(): array - { - return [ - ['<'], - ['lt'], - ['<='], - ['le'], - ['>'], - ['gt'], - ['>='], - ['ge'], - ['=='], - ['='], - ['eq'], - ['!='], - ['<>'], - ['ne'], - ]; - } - - #[DataProvider('validValues')] - #[TestDox('Can be created from "$string"')] - public function testCanBeCreatedFromValidString(string $string): void - { - $this->assertSame($string, new VersionComparisonOperator($string)->asString()); - } - - public function testCannotBeCreatedFromInvalidString(): void - { - $this->expectException(InvalidVersionOperatorException::class); - - new VersionComparisonOperator(''); - } -} From 661729203a48e86be148e7ec11ee8e27ccacbdcf Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sun, 21 Jun 2026 07:47:17 +0200 Subject: [PATCH 2/2] Use sebastian/version-requirement without leaking it to event consumers The version-requirement parsing, operator validation, and satisfaction checking are delegated to sebastian/version-requirement, but the package is fully encapsulated behind PHPUnit-owned value objects. The value objects exposed through events (Requirement and its subtypes via test metadata, VersionComparisonOperator via the configuration) are now pure data transfer objects: they hold only scalar values, aggregate no objects from the package, and carry no behavior. The satisfaction check (isSatisfiedBy()) has moved to Metadata\Api\Requirements, which is where the package is used. As the value objects no longer hold package objects, they serialize cleanly across separate-process test runs. The package is referenced at exactly three boundaries: Requirement::from() (parsing), VersionComparisonOperator (operator validation), and Requirements::isSatisfiedBy() (satisfaction checking). Package exceptions are converted to PHPUnit exceptions at those boundaries so they do not leak either. --- src/Metadata/Api/Requirements.php | 24 ++++++-- .../InvalidVersionRequirementException.php | 19 ++++++ src/Metadata/Metadata.php | 2 +- src/Metadata/Parser/AttributeParser.php | 6 +- src/Metadata/RequiresPhp.php | 2 +- src/Metadata/RequiresPhpExtension.php | 2 +- src/Metadata/RequiresPhpunit.php | 2 +- .../Version/ComparisonRequirement.php | 39 ++++++++++++ .../Version/ConstraintRequirement.php | 30 ++++++++++ .../Version/InvalidVersionRequirement.php | 39 ++++++++++++ src/Metadata/Version/Requirement.php | 56 ++++++++++++++++++ src/TextUI/Configuration/Registry.php | 2 +- .../Configuration/Value/TestDirectory.php | 2 +- src/TextUI/Configuration/Value/TestFile.php | 2 +- src/TextUI/Configuration/Xml/Loader.php | 2 +- .../InvalidVersionOperatorException.php | 31 ++++++++++ src/Util/VersionComparisonOperator.php | 46 +++++++++++++++ .../unit/Metadata/MetadataCollectionTest.php | 13 +--- tests/unit/Metadata/MetadataTest.php | 33 +++-------- .../Parser/AttributeParserTestCase.php | 4 +- .../Version/InvalidVersionRequirementTest.php | 28 +++++++++ .../unit/Metadata/Version/RequirementTest.php | 53 +++++++++++++++++ .../Value/TestDirectoryCollectionTest.php | 2 +- .../Configuration/Value/TestDirectoryTest.php | 2 +- .../Value/TestFileCollectionTest.php | 2 +- .../Configuration/Value/TestFileTest.php | 2 +- .../Util/VersionComparisonOperatorTest.php | 59 +++++++++++++++++++ 27 files changed, 445 insertions(+), 59 deletions(-) create mode 100644 src/Metadata/Exception/InvalidVersionRequirementException.php create mode 100644 src/Metadata/Version/ComparisonRequirement.php create mode 100644 src/Metadata/Version/ConstraintRequirement.php create mode 100644 src/Metadata/Version/InvalidVersionRequirement.php create mode 100644 src/Metadata/Version/Requirement.php create mode 100644 src/Util/Exception/InvalidVersionOperatorException.php create mode 100644 src/Util/VersionComparisonOperator.php create mode 100644 tests/unit/Metadata/Version/InvalidVersionRequirementTest.php create mode 100644 tests/unit/Metadata/Version/RequirementTest.php create mode 100644 tests/unit/Util/VersionComparisonOperatorTest.php diff --git a/src/Metadata/Api/Requirements.php b/src/Metadata/Api/Requirements.php index c634f5c09a5..5f15be49192 100644 --- a/src/Metadata/Api/Requirements.php +++ b/src/Metadata/Api/Requirements.php @@ -37,11 +37,12 @@ use PHPUnit\Metadata\RequiresPhpunit; use PHPUnit\Metadata\RequiresPhpunitExtension; use PHPUnit\Metadata\RequiresSetting; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Metadata\Version\InvalidVersionRequirement; +use PHPUnit\Metadata\Version\Requirement; use PHPUnit\Runner\Version; use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; -use SebastianBergmann\VersionRequirement\ComparisonRequirement; -use SebastianBergmann\VersionRequirement\InvalidVersionRequirement; -use SebastianBergmann\VersionRequirement\Requirement; +use SebastianBergmann\VersionRequirement\Requirement as RequirementImplementation; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit @@ -68,7 +69,7 @@ public function requirementsNotSatisfiedFor(string $className, string $methodNam $this->warnAboutIncompleteVersion($metadata->versionRequirement(), $className, $methodName); - if (!$versionRequirement->isSatisfiedBy(PHP_VERSION)) { + if (!$this->isSatisfiedBy($versionRequirement, PHP_VERSION)) { $notSatisfied[] = sprintf( 'PHP %s is required.', $versionRequirement->asString(), @@ -91,7 +92,7 @@ public function requirementsNotSatisfiedFor(string $className, string $methodNam if (!extension_loaded($metadata->extension()) || ($metadata->hasVersionRequirement() && - !$metadata->versionRequirement()->isSatisfiedBy($extensionVersion))) { + !$this->isSatisfiedBy($metadata->versionRequirement(), $extensionVersion))) { $notSatisfied[] = sprintf( 'PHP extension %s%s is required.', $metadata->extension(), @@ -107,7 +108,7 @@ public function requirementsNotSatisfiedFor(string $className, string $methodNam $this->warnAboutIncompleteVersion($metadata->versionRequirement(), $className, $methodName); - if (!$versionRequirement->isSatisfiedBy(Version::id())) { + if (!$this->isSatisfiedBy($versionRequirement, Version::id())) { $notSatisfied[] = sprintf( 'PHPUnit %s is required.', $versionRequirement->asString(), @@ -269,6 +270,17 @@ public function requiresXdebug(string $className, string $methodName): bool return false; } + private function isSatisfiedBy(Requirement $versionRequirement, string $version): bool + { + $requirement = $versionRequirement->asString(); + + if ($versionRequirement instanceof InvalidVersionRequirement || $requirement === '') { + return false; + } + + return RequirementImplementation::from($requirement)->isSatisfiedBy($version); + } + /** * @param class-string $className * @param non-empty-string $methodName diff --git a/src/Metadata/Exception/InvalidVersionRequirementException.php b/src/Metadata/Exception/InvalidVersionRequirementException.php new file mode 100644 index 00000000000..359f723c1dc --- /dev/null +++ b/src/Metadata/Exception/InvalidVersionRequirementException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidVersionRequirementException extends RuntimeException implements Exception +{ +} diff --git a/src/Metadata/Metadata.php b/src/Metadata/Metadata.php index 92b716bf9f6..9ef0fff102a 100644 --- a/src/Metadata/Metadata.php +++ b/src/Metadata/Metadata.php @@ -10,8 +10,8 @@ namespace PHPUnit\Metadata; use Closure; +use PHPUnit\Metadata\Version\Requirement; use PHPUnit\Runner\Extension\Extension; -use SebastianBergmann\VersionRequirement\Requirement; /** * @immutable diff --git a/src/Metadata/Parser/AttributeParser.php b/src/Metadata/Parser/AttributeParser.php index f3405f05ff9..d0409eaf167 100644 --- a/src/Metadata/Parser/AttributeParser.php +++ b/src/Metadata/Parser/AttributeParser.php @@ -93,13 +93,13 @@ use PHPUnit\Framework\Attributes\UsesTrait; use PHPUnit\Framework\Attributes\WithEnvironmentVariable; use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Metadata\InvalidVersionRequirementException; use PHPUnit\Metadata\Metadata; use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Metadata\Version\InvalidVersionRequirement; +use PHPUnit\Metadata\Version\Requirement; use ReflectionClass; use ReflectionMethod; -use SebastianBergmann\VersionRequirement\InvalidVersionRequirement; -use SebastianBergmann\VersionRequirement\InvalidVersionRequirementException; -use SebastianBergmann\VersionRequirement\Requirement; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/Metadata/RequiresPhp.php b/src/Metadata/RequiresPhp.php index b1c9d4f6880..a5805013bc3 100644 --- a/src/Metadata/RequiresPhp.php +++ b/src/Metadata/RequiresPhp.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\Metadata; -use SebastianBergmann\VersionRequirement\Requirement; +use PHPUnit\Metadata\Version\Requirement; /** * @immutable diff --git a/src/Metadata/RequiresPhpExtension.php b/src/Metadata/RequiresPhpExtension.php index 45932037c58..fd7d4243586 100644 --- a/src/Metadata/RequiresPhpExtension.php +++ b/src/Metadata/RequiresPhpExtension.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\Metadata; -use SebastianBergmann\VersionRequirement\Requirement; +use PHPUnit\Metadata\Version\Requirement; /** * @immutable diff --git a/src/Metadata/RequiresPhpunit.php b/src/Metadata/RequiresPhpunit.php index fa40f9776c0..f0c08c57fc9 100644 --- a/src/Metadata/RequiresPhpunit.php +++ b/src/Metadata/RequiresPhpunit.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\Metadata; -use SebastianBergmann\VersionRequirement\Requirement; +use PHPUnit\Metadata\Version\Requirement; /** * @immutable diff --git a/src/Metadata/Version/ComparisonRequirement.php b/src/Metadata/Version/ComparisonRequirement.php new file mode 100644 index 00000000000..936080b8403 --- /dev/null +++ b/src/Metadata/Version/ComparisonRequirement.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use PHPUnit\Util\VersionComparisonOperator; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonRequirement extends Requirement +{ + private string $version; + private VersionComparisonOperator $operator; + + public function __construct(string $version, VersionComparisonOperator $operator) + { + $this->version = $version; + $this->operator = $operator; + } + + public function asString(): string + { + return $this->operator->asString() . ' ' . $this->version; + } + + public function version(): string + { + return $this->version; + } +} diff --git a/src/Metadata/Version/ConstraintRequirement.php b/src/Metadata/Version/ConstraintRequirement.php new file mode 100644 index 00000000000..0ba6f50b97e --- /dev/null +++ b/src/Metadata/Version/ConstraintRequirement.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConstraintRequirement extends Requirement +{ + private string $constraint; + + public function __construct(string $constraint) + { + $this->constraint = $constraint; + } + + public function asString(): string + { + return $this->constraint; + } +} diff --git a/src/Metadata/Version/InvalidVersionRequirement.php b/src/Metadata/Version/InvalidVersionRequirement.php new file mode 100644 index 00000000000..deb04fcb541 --- /dev/null +++ b/src/Metadata/Version/InvalidVersionRequirement.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class InvalidVersionRequirement extends Requirement +{ + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(string $message) + { + $this->message = $message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return $this->message; + } +} diff --git a/src/Metadata/Version/Requirement.php b/src/Metadata/Version/Requirement.php new file mode 100644 index 00000000000..321b8b5a186 --- /dev/null +++ b/src/Metadata/Version/Requirement.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function assert; +use function explode; +use PHPUnit\Metadata\InvalidVersionRequirementException; +use PHPUnit\Util\VersionComparisonOperator; +use SebastianBergmann\VersionRequirement\ComparisonRequirement as ComparisonRequirementImplementation; +use SebastianBergmann\VersionRequirement\ConstraintRequirement as ConstraintRequirementImplementation; +use SebastianBergmann\VersionRequirement\Exception; +use SebastianBergmann\VersionRequirement\Requirement as RequirementImplementation; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Requirement +{ + /** + * @param non-empty-string $versionRequirement + * + * @throws InvalidVersionRequirementException + */ + public static function from(string $versionRequirement): self + { + try { + $requirement = RequirementImplementation::from($versionRequirement); + } catch (Exception) { + throw new InvalidVersionRequirementException; + } + + if ($requirement instanceof ComparisonRequirementImplementation) { + return new ComparisonRequirement( + $requirement->version(), + new VersionComparisonOperator( + explode(' ', $requirement->asString(), 2)[0], + ), + ); + } + + assert($requirement instanceof ConstraintRequirementImplementation); + + return new ConstraintRequirement($requirement->asString()); + } + + abstract public function asString(): string; +} diff --git a/src/TextUI/Configuration/Registry.php b/src/TextUI/Configuration/Registry.php index de07aec4d4f..f29bc80f72b 100644 --- a/src/TextUI/Configuration/Registry.php +++ b/src/TextUI/Configuration/Registry.php @@ -18,7 +18,7 @@ use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\CliArguments\Exception; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; /** * CLI options and XML configuration are static within a single PHPUnit process. diff --git a/src/TextUI/Configuration/Value/TestDirectory.php b/src/TextUI/Configuration/Value/TestDirectory.php index d037d212aae..2997fd7b477 100644 --- a/src/TextUI/Configuration/Value/TestDirectory.php +++ b/src/TextUI/Configuration/Value/TestDirectory.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\TextUI\Configuration; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/TextUI/Configuration/Value/TestFile.php b/src/TextUI/Configuration/Value/TestFile.php index 7b9f548a70b..e658ff88437 100644 --- a/src/TextUI/Configuration/Value/TestFile.php +++ b/src/TextUI/Configuration/Value/TestFile.php @@ -9,7 +9,7 @@ */ namespace PHPUnit\TextUI\Configuration; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit diff --git a/src/TextUI/Configuration/Xml/Loader.php b/src/TextUI/Configuration/Xml/Loader.php index 892396b4919..0b4f464d195 100644 --- a/src/TextUI/Configuration/Xml/Loader.php +++ b/src/TextUI/Configuration/Xml/Loader.php @@ -77,11 +77,11 @@ use PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; +use PHPUnit\Util\VersionComparisonOperator; use PHPUnit\Util\Xml\Loader as XmlLoader; use PHPUnit\Util\Xml\XmlException; use SebastianBergmann\CodeCoverage\Report\Html\Colors; use SebastianBergmann\CodeCoverage\Report\Thresholds; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; use Throwable; /** diff --git a/src/Util/Exception/InvalidVersionOperatorException.php b/src/Util/Exception/InvalidVersionOperatorException.php new file mode 100644 index 00000000000..bc2fe9a0ed5 --- /dev/null +++ b/src/Util/Exception/InvalidVersionOperatorException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidVersionOperatorException extends RuntimeException implements Exception +{ + public function __construct(string $operator) + { + parent::__construct( + sprintf( + '"%s" is not a valid version_compare() operator', + $operator, + ), + ); + } +} diff --git a/src/Util/VersionComparisonOperator.php b/src/Util/VersionComparisonOperator.php new file mode 100644 index 00000000000..0b0d7befcba --- /dev/null +++ b/src/Util/VersionComparisonOperator.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use SebastianBergmann\VersionRequirement\InvalidVersionOperatorException as InvalidVersionOperatorExceptionImplementation; +use SebastianBergmann\VersionRequirement\VersionComparisonOperator as VersionComparisonOperatorImplementation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class VersionComparisonOperator +{ + /** + * @var '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' + */ + private string $operator; + + /** + * @throws InvalidVersionOperatorException + */ + public function __construct(string $operator) + { + try { + $this->operator = new VersionComparisonOperatorImplementation($operator)->asString(); + } catch (InvalidVersionOperatorExceptionImplementation) { + throw new InvalidVersionOperatorException($operator); + } + } + + /** + * @return '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' + */ + public function asString(): string + { + return $this->operator; + } +} diff --git a/tests/unit/Metadata/MetadataCollectionTest.php b/tests/unit/Metadata/MetadataCollectionTest.php index e6ade592134..0df5fdaa91c 100644 --- a/tests/unit/Metadata/MetadataCollectionTest.php +++ b/tests/unit/Metadata/MetadataCollectionTest.php @@ -14,8 +14,7 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use SebastianBergmann\VersionRequirement\ComparisonRequirement; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Metadata\Version\Requirement; use stdClass; #[CoversClass(MetadataCollection::class)] @@ -640,16 +639,10 @@ private function collectionWithOneOfEach(): MetadataCollection Metadata::requiresOperatingSystemOnClass(''), Metadata::requiresPhpExtensionOnClass('', null), Metadata::requiresPhpOnClass( - new ComparisonRequirement( - '8.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 8.0.0'), ), Metadata::requiresPhpunitOnClass( - new ComparisonRequirement( - '10.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 10.0.0'), ), Metadata::requiresPhpunitExtensionOnClass(stdClass::class), Metadata::requiresEnvironmentVariableOnClass('foo', 'bar'), diff --git a/tests/unit/Metadata/MetadataTest.php b/tests/unit/Metadata/MetadataTest.php index f6e81c4d29b..28e6878b2ea 100644 --- a/tests/unit/Metadata/MetadataTest.php +++ b/tests/unit/Metadata/MetadataTest.php @@ -14,9 +14,8 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Version\Requirement; use PHPUnit\TestFixture\Metadata\Attribute\ExampleTrait; -use SebastianBergmann\VersionRequirement\ComparisonRequirement; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; #[CoversClass(Metadata::class)] #[CoversClassesThatExtendClass(Metadata::class)] @@ -3662,10 +3661,7 @@ public function testCanBeRequiresOperatingSystemFamilyOnMethod(): void public function testCanBeRequiresPhpOnClass(): void { $metadata = Metadata::requiresPhpOnClass( - new ComparisonRequirement( - '8.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 8.0.0'), ); $this->assertFalse($metadata->isAfter()); @@ -3736,10 +3732,7 @@ public function testCanBeRequiresPhpOnClass(): void public function testCanBeRequiresPhpOnMethod(): void { $metadata = Metadata::requiresPhpOnMethod( - new ComparisonRequirement( - '8.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 8.0.0'), ); $this->assertFalse($metadata->isAfter()); @@ -3884,10 +3877,7 @@ public function testCanBeRequiresPhpExtensionWithVersionOnClass(): void { $metadata = Metadata::requiresPhpExtensionOnClass( 'test', - new ComparisonRequirement( - '1.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 1.0.0'), ); $this->assertFalse($metadata->isAfter()); @@ -4034,10 +4024,7 @@ public function testCanBeRequiresPhpExtensionWithVersionOnMethod(): void { $metadata = Metadata::requiresPhpExtensionOnMethod( 'test', - new ComparisonRequirement( - '1.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 1.0.0'), ); $this->assertFalse($metadata->isAfter()); @@ -4110,10 +4097,7 @@ public function testCanBeRequiresPhpExtensionWithVersionOnMethod(): void public function testCanBeRequiresPhpunitOnClass(): void { $metadata = Metadata::requiresPhpunitOnClass( - new ComparisonRequirement( - '10.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 10.0.0'), ); $this->assertFalse($metadata->isAfter()); @@ -4253,10 +4237,7 @@ public function testCanBeRequiresPhpunitExtensionOnClass(): void public function testCanBeRequiresPhpunitOnMethod(): void { $metadata = Metadata::requiresPhpunitOnMethod( - new ComparisonRequirement( - '10.0.0', - new VersionComparisonOperator('>='), - ), + Requirement::from('>= 10.0.0'), ); $this->assertFalse($metadata->isAfter()); diff --git a/tests/unit/Metadata/Parser/AttributeParserTestCase.php b/tests/unit/Metadata/Parser/AttributeParserTestCase.php index 47265d53c39..d6bbeacd24b 100644 --- a/tests/unit/Metadata/Parser/AttributeParserTestCase.php +++ b/tests/unit/Metadata/Parser/AttributeParserTestCase.php @@ -23,6 +23,8 @@ use PHPUnit\Metadata\RequiresPhpunitExtension; use PHPUnit\Metadata\RequiresSetting; use PHPUnit\Metadata\Retry; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Metadata\Version\ConstraintRequirement; use PHPUnit\Metadata\WithEnvironmentVariable; use PHPUnit\TestFixture\Metadata\Attribute\AllowMockObjectsWithoutExpectationsOnClassTest; use PHPUnit\TestFixture\Metadata\Attribute\AllowMockObjectsWithoutExpectationsOnMethodTest; @@ -70,8 +72,6 @@ use PHPUnit\TestFixture\Metadata\Attribute\UsesTest; use PHPUnit\TestFixture\Metadata\Attribute\WithEnvironmentVariableTest; use PHPUnit\TestFixture\Metadata\Attribute\WithoutErrorHandlerTest; -use SebastianBergmann\VersionRequirement\ComparisonRequirement; -use SebastianBergmann\VersionRequirement\ConstraintRequirement; abstract class AttributeParserTestCase extends TestCase { diff --git a/tests/unit/Metadata/Version/InvalidVersionRequirementTest.php b/tests/unit/Metadata/Version/InvalidVersionRequirementTest.php new file mode 100644 index 00000000000..8b1742b19bf --- /dev/null +++ b/tests/unit/Metadata/Version/InvalidVersionRequirementTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(InvalidVersionRequirement::class)] +#[Small] +#[Group('metadata')] +final class InvalidVersionRequirementTest extends TestCase +{ + public function testCanBeRepresentedAsString(): void + { + $requirement = new InvalidVersionRequirement('message'); + + $this->assertSame('message', $requirement->asString()); + } +} diff --git a/tests/unit/Metadata/Version/RequirementTest.php b/tests/unit/Metadata/Version/RequirementTest.php new file mode 100644 index 00000000000..6eb4c378e21 --- /dev/null +++ b/tests/unit/Metadata/Version/RequirementTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Metadata\Version\ConstraintRequirement; +use PHPUnit\Metadata\Version\Requirement; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(ComparisonRequirement::class)] +#[CoversClass(ConstraintRequirement::class)] +#[CoversClass(Requirement::class)] +#[UsesClass(VersionComparisonOperator::class)] +#[Small] +#[Group('metadata')] +final class RequirementTest extends TestCase +{ + public function testCanBeCreatedFromStringWithVersionConstraint(): void + { + $requirement = Requirement::from('^1.0'); + + $this->assertInstanceOf(ConstraintRequirement::class, $requirement); + $this->assertSame('^1.0', $requirement->asString()); + } + + public function testCanBeCreatedFromStringWithSimpleComparison(): void + { + $requirement = Requirement::from('>= 1.0.0'); + + $this->assertInstanceOf(ComparisonRequirement::class, $requirement); + $this->assertSame('>= 1.0.0', $requirement->asString()); + $this->assertSame('1.0.0', $requirement->version()); + } + + public function testCannotBeCreatedFromInvalidString(): void + { + $this->expectException(InvalidVersionRequirementException::class); + + Requirement::from('invalid'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php index a0f205dfa59..928b67dd850 100644 --- a/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; #[CoversClass(TestDirectoryCollection::class)] #[CoversClass(TestDirectoryCollectionIterator::class)] diff --git a/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php b/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php index c9437b58298..e1ebcbfa84f 100644 --- a/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\TestCase; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; #[CoversClass(TestDirectory::class)] #[Small] diff --git a/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php index 2dda3e971a9..43cd4c56bd6 100644 --- a/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\UsesClass; use PHPUnit\Framework\TestCase; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; #[CoversClass(TestFileCollection::class)] #[CoversClass(TestFileCollectionIterator::class)] diff --git a/tests/unit/TextUI/Configuration/Value/TestFileTest.php b/tests/unit/TextUI/Configuration/Value/TestFileTest.php index 1cf5523bfb6..31db4d9c7c3 100644 --- a/tests/unit/TextUI/Configuration/Value/TestFileTest.php +++ b/tests/unit/TextUI/Configuration/Value/TestFileTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\TestCase; -use SebastianBergmann\VersionRequirement\VersionComparisonOperator; +use PHPUnit\Util\VersionComparisonOperator; #[CoversClass(TestFile::class)] #[Small] diff --git a/tests/unit/Util/VersionComparisonOperatorTest.php b/tests/unit/Util/VersionComparisonOperatorTest.php new file mode 100644 index 00000000000..39745275a9d --- /dev/null +++ b/tests/unit/Util/VersionComparisonOperatorTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(VersionComparisonOperator::class)] +#[CoversClass(InvalidVersionOperatorException::class)] +#[Small] +final class VersionComparisonOperatorTest extends TestCase +{ + /** + * @return non-empty-list> + */ + public static function validValues(): array + { + return [ + ['<'], + ['lt'], + ['<='], + ['le'], + ['>'], + ['gt'], + ['>='], + ['ge'], + ['=='], + ['='], + ['eq'], + ['!='], + ['<>'], + ['ne'], + ]; + } + + #[DataProvider('validValues')] + #[TestDox('Can be created from "$string"')] + public function testCanBeCreatedFromValidString(string $string): void + { + $this->assertSame($string, new VersionComparisonOperator($string)->asString()); + } + + public function testCannotBeCreatedFromInvalidString(): void + { + $this->expectException(InvalidVersionOperatorException::class); + + new VersionComparisonOperator(''); + } +}