Given any versions constraint for requirements in a composer.json
, I would like to verify that a given version is supported by the requirement definition. Let's say a composer.json
requires "php": "^7.4"
. Then I would expect that checking version 7.4
will succeed and 8.0
will fail.
My implementation so far is using composer/semver
.
version-checker.php
use Composer\Semver\Comparator;
use Composer\Semver\VersionParser;
require_once __DIR__ . '/vendor/autoload.php';
$expectations = [
[true, '7.3.0', '^7.3 || ~8.0.0 || ~8.1.0'],
[true, '7.3.0', '^7.3 || ^8.0'],
[false, '7.3.0', '^7.2'],
[false, '7.3.0', '^7.1'],
[false, '7.3.0', '^5.6 || ^7.0'],
[true, '8.1.0', '^7.3 || ~8.0.0 || ~8.1.0'],
[true, '8.1.0', '>=7.2.5'],
[false, '8.1.0', '^7.3 || ^8.0'],
[false, '8.1.0', '^7.2'],
[false, '8.1.0', '^7.1'],
[false, '8.1.0', '^5.6 || ^7.0'],
];
$versionParser = new VersionParser();
foreach ($expectations as [$expected, $requiredVersion, $actualVersion]) {
$constraint = $versionParser->parseConstraints($actualVersion);
$lowerVersion = $constraint->getLowerBound()->getVersion();
$compareResult = Comparator::greaterThanOrEqualTo($lowerVersion, $requiredVersion);
if ($expected !== $compareResult) {
printf(
'Failed to assert that required version (%s) with actual version (%s) is %s.' . PHP_EOL,
$requiredVersion,
$actualVersion,
var_export($expected, true)
);
}
}
The output is:
Failed to assert that required version (8.1.0) with actual version (^7.3 || ~8.0.0 || ~8.1.0) is true.
Failed to assert that required version (8.1.0) with actual version (>=7.2.5) is true.
How can proper verification be achieved?
CodePudding user response:
You have two problems.
First, wrong expectations.
These four, are wrong:
[
[false, '7.3.0', '^7.2'],
[false, '7.3.0', '^7.1'],
[false, '7.3.0', '^5.6 || ^7.0'],
[false, '8.1.0', '^7.3 || ^8.0'],
]
Those constraints do match the version.
Here you have the docs for caret version range. Basically, ^7.2
is equal to >=7.2 && < 8
(etc).
The second problem is that you are using the wrong way of checking the validity of the constraints:
Instead of using this:
$compareResult = Comparator::greaterThanOrEqualTo($lowerVersion, $requiredVersion);
(and note that you are using the operands the wrong way around, since this would be equivalent of saying $lowerVersion >= $requiredVersion
, which does not make sense).
You should be doing:
$actualConstraint = $versionParser->parseConstraints($actualVersion);
$compareResult = $actualConstraint->matches($requiredConstraint);
The whole thing put together would be:
use Composer\Semver\VersionParser;
require_once __DIR__ . '/vendor/autoload.php';
$expectations = [
[true, '7.3.0', '^7.3 || ~8.0.0 || ~8.1.0'],
[true, '7.3.0', '^7.3 || ^8.0'],
[true, '8.1.0', '^7.3 || ~8.0.0 || ~8.1.0'],
[true, '8.1.0', '>=7.2.5'],
[true, '7.3.0', '^7.2'],
[true, '7.3.0', '^7.1'],
[true, '7.3.0', '^5.6 || ^7.0'],
[true, '8.1.0', '^7.3 || ^8.0'],
[false, '8.1.0', '^7.2'],
[false, '8.1.0', '^7.1'],
[false, '8.1.0', '^5.6 || ^7.0'],
];
$versionParser = new VersionParser();
foreach ($expectations as [$expected, $requiredVersion, $actualVersion]) {
$actualConstraint = $versionParser->parseConstraints($actualVersion);
$requiredConstraint = $versionParser->parseConstraints($requiredVersion);
$compareResult = $actualConstraint->matches($requiredConstraint);
if ($expected !== $compareResult) {
printf(
'Failed to assert that required version (%s) with actual version (%s) is %s.' . PHP_EOL,
$requiredVersion,
$actualVersion,
var_export($expected, true)
);
}
}