pax_global_header 0000666 0000000 0000000 00000000064 13615712565 0014525 g ustar 00root root 0000000 0000000 52 comment=ca5a8e43619cac75b3a9689d29a01c2b537e525b
php-composer-semver-1.5.1/ 0000775 0000000 0000000 00000000000 13615712565 0015444 5 ustar 00root root 0000000 0000000 php-composer-semver-1.5.1/.gitignore 0000664 0000000 0000000 00000000044 13615712565 0017432 0 ustar 00root root 0000000 0000000 vendor/
.php_cs.cache
composer.lock
php-composer-semver-1.5.1/.php_cs 0000664 0000000 0000000 00000003251 13615712565 0016722 0 ustar 00root root 0000000 0000000
For the full copyright and license information, please view
the LICENSE file that was distributed with this source code.
EOF;
$finder = Symfony\CS\Finder\DefaultFinder::create()
->files()
->name('*.php')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
;
/* fabpot/php-cs-fixer:^2.0-dev */
return Symfony\CS\Config\Config::create()
->setRules(array(
'@PSR2' => true,
'duplicate_semicolon' => true,
'extra_empty_lines' => true,
'header_comment' => array('header' => $header),
'include' => true,
'long_array_syntax' => true,
'method_separation' => true,
'multiline_array_trailing_comma' => true,
'namespace_no_leading_whitespace' => true,
'no_blank_lines_after_class_opening' => true,
'no_empty_lines_after_phpdocs' => true,
'object_operator' => true,
'operators_spaces' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
'phpdoc_no_package' => true,
'phpdoc_order' => true,
'phpdoc_scalar' => true,
'phpdoc_separation' => true,
'phpdoc_trim' => true,
'phpdoc_type_to_var' => true,
'return' => true,
'remove_leading_slash_use' => true,
'remove_lines_between_uses' => true,
'single_array_no_trailing_comma' => true,
'single_blank_line_before_namespace' => true,
'spaces_cast' => true,
'standardize_not_equal' => true,
'ternary_spaces' => true,
'unused_use' => true,
'whitespacy_lines' => true,
))
->finder($finder)
;
php-composer-semver-1.5.1/.travis.yml 0000664 0000000 0000000 00000001011 13615712565 0017546 0 ustar 00root root 0000000 0000000 language: php
dist: trusty
sudo: false
cache:
directories:
- $HOME/.composer/cache
- vendor
git:
depth: 5
php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4snapshot
- nightly
matrix:
include:
- dist: precise
php: 5.3
fast_finish: true
allow_failures:
- php: nightly
- php: 7.4snapshot
before_script:
- composer install --no-interaction --no-progress --prefer-dist --ansi
script:
- vendor/bin/phpunit --coverage-clover=coverage.xml
after_success:
- bash <(curl -s https://codecov.io/bash)
php-composer-semver-1.5.1/CHANGELOG.md 0000664 0000000 0000000 00000006636 13615712565 0017270 0 ustar 00root root 0000000 0000000 # Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### [1.5.1] 2020-01-13
* Fixed: Parsing of aliased version was not validating the alias to be a valid version
### [1.5.0] 2019-03-19
* Added: some support for date versions (e.g. 201903) in `~` operator
* Fixed: support for stabilities in `~` operator was inconsistent
### [1.4.2] 2016-08-30
* Fixed: collapsing of complex constraints lead to buggy constraints
### [1.4.1] 2016-06-02
* Changed: branch-like requirements no longer strip build metadata - [composer/semver#38](https://github.com/composer/semver/pull/38).
### [1.4.0] 2016-03-30
* Added: getters on MultiConstraint - [composer/semver#35](https://github.com/composer/semver/pull/35).
### [1.3.0] 2016-02-25
* Fixed: stability parsing - [composer/composer#1234](https://github.com/composer/composer/issues/4889).
* Changed: collapse contiguous constraints when possible.
### [1.2.0] 2015-11-10
* Changed: allow multiple numerical identifiers in 'pre-release' version part.
* Changed: add more 'v' prefix support.
### [1.1.0] 2015-11-03
* Changed: dropped redundant `test` namespace.
* Changed: minor adjustment in datetime parsing normalization.
* Changed: `ConstraintInterface` relaxed, setPrettyString is not required anymore.
* Changed: `AbstractConstraint` marked deprecated, will be removed in 2.0.
* Changed: `Constraint` is now extensible.
### [1.0.0] 2015-09-21
* Break: `VersionConstraint` renamed to `Constraint`.
* Break: `SpecificConstraint` renamed to `AbstractConstraint`.
* Break: `LinkConstraintInterface` renamed to `ConstraintInterface`.
* Break: `VersionParser::parseNameVersionPairs` was removed.
* Changed: `VersionParser::parseConstraints` allows (but ignores) build metadata now.
* Changed: `VersionParser::parseConstraints` allows (but ignores) prefixing numeric versions with a 'v' now.
* Changed: Fixed namespace(s) of test files.
* Changed: `Comparator::compare` no longer throws `InvalidArgumentException`.
* Changed: `Constraint` now throws `InvalidArgumentException`.
### [0.1.0] 2015-07-23
* Added: `Composer\Semver\Comparator`, various methods to compare versions.
* Added: various documents such as README.md, LICENSE, etc.
* Added: configuration files for Git, Travis, php-cs-fixer, phpunit.
* Break: the following namespaces were renamed:
- Namespace: `Composer\Package\Version` -> `Composer\Semver`
- Namespace: `Composer\Package\LinkConstraint` -> `Composer\Semver\Constraint`
- Namespace: `Composer\Test\Package\Version` -> `Composer\Test\Semver`
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer.
[1.5.1]: https://github.com/composer/semver/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/composer/semver/compare/1.4.2...1.5.0
[1.4.2]: https://github.com/composer/semver/compare/1.4.1...1.4.2
[1.4.1]: https://github.com/composer/semver/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/composer/semver/compare/1.3.0...1.4.0
[1.3.0]: https://github.com/composer/semver/compare/1.2.0...1.3.0
[1.2.0]: https://github.com/composer/semver/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/composer/semver/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/composer/semver/compare/0.1.0...1.0.0
[0.1.0]: https://github.com/composer/semver/compare/5e0b9a4da...0.1.0
php-composer-semver-1.5.1/CONTRIBUTING.md 0000664 0000000 0000000 00000002000 13615712565 0017665 0 ustar 00root root 0000000 0000000 Contributing to composer/semver
===============================
Please note that this project is released with a
[Contributor Code of Conduct](http://contributor-covenant.org/version/1/1/0/).
By participating in this project and its community you agree to abide by those terms.
Reporting Issues
----------------
When reporting issues, please try to be as descriptive as possible, and include
as much relevant information as you can. A step by step guide on how to
reproduce the issue will greatly increase the chances of your issue being
resolved in a timely manner.
Contributing Policy
-------------------
Fork the project, create a feature branch, and send us a pull request.
To ensure a consistent code base, you should make sure the code follows
the [PSR-2 Coding Standards](http://www.php-fig.org/psr/psr-2/). Run
[php-cs-fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to automatically "fix" files.
If you would like to help, take a look at the [list of issues](https://github.com/composer/semver/issues).
php-composer-semver-1.5.1/LICENSE 0000664 0000000 0000000 00000002034 13615712565 0016450 0 ustar 00root root 0000000 0000000 Copyright (C) 2015 Composer
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
php-composer-semver-1.5.1/README.md 0000664 0000000 0000000 00000003125 13615712565 0016724 0 ustar 00root root 0000000 0000000 composer/semver
===============
Semver library that offers utilities, version constraint parsing and validation.
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
[](https://travis-ci.org/composer/semver)
Installation
------------
Install the latest version with:
```bash
$ composer require composer/semver
```
Requirements
------------
* PHP 5.3.2 is required but using the latest version of PHP is highly recommended.
Version Comparison
------------------
For details on how versions are compared, refer to the [Versions](https://getcomposer.org/doc/articles/versions.md)
article in the documentation section of the [getcomposer.org](https://getcomposer.org) website.
Basic usage
-----------
### Comparator
The `Composer\Semver\Comparator` class provides the following methods for comparing versions:
* greaterThan($v1, $v2)
* greaterThanOrEqualTo($v1, $v2)
* lessThan($v1, $v2)
* lessThanOrEqualTo($v1, $v2)
* equalTo($v1, $v2)
* notEqualTo($v1, $v2)
Each function takes two version strings as arguments. For example:
```php
use Composer\Semver\Comparator;
Comparator::greaterThan('1.25.0', '1.24.0'); // 1.25.0 > 1.24.0
```
### Semver
The `Composer\Semver\Semver` class provides the following methods:
* satisfies($version, $constraints)
* satisfiedBy(array $versions, $constraint)
* sort($versions)
* rsort($versions)
License
-------
composer/semver is licensed under the MIT License, see the LICENSE file for details.
php-composer-semver-1.5.1/composer.json 0000664 0000000 0000000 00000002504 13615712565 0020167 0 ustar 00root root 0000000 0000000 {
"name": "composer/semver",
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"type": "library",
"license": "MIT",
"keywords": [
"semver",
"semantic",
"versioning",
"validation"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues"
},
"require": {
"php": "^5.3.2 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5"
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Composer\\Semver\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"scripts": {
"test": "phpunit"
}
}
php-composer-semver-1.5.1/phpunit.xml.dist 0000664 0000000 0000000 00000001022 13615712565 0020612 0 ustar 00root root 0000000 0000000
tests
src
php-composer-semver-1.5.1/src/ 0000775 0000000 0000000 00000000000 13615712565 0016233 5 ustar 00root root 0000000 0000000 php-composer-semver-1.5.1/src/Comparator.php 0000664 0000000 0000000 00000004773 13615712565 0021066 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
class Comparator
{
/**
* Evaluates the expression: $version1 > $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function greaterThan($version1, $version2)
{
return self::compare($version1, '>', $version2);
}
/**
* Evaluates the expression: $version1 >= $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function greaterThanOrEqualTo($version1, $version2)
{
return self::compare($version1, '>=', $version2);
}
/**
* Evaluates the expression: $version1 < $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function lessThan($version1, $version2)
{
return self::compare($version1, '<', $version2);
}
/**
* Evaluates the expression: $version1 <= $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function lessThanOrEqualTo($version1, $version2)
{
return self::compare($version1, '<=', $version2);
}
/**
* Evaluates the expression: $version1 == $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function equalTo($version1, $version2)
{
return self::compare($version1, '==', $version2);
}
/**
* Evaluates the expression: $version1 != $version2.
*
* @param string $version1
* @param string $version2
*
* @return bool
*/
public static function notEqualTo($version1, $version2)
{
return self::compare($version1, '!=', $version2);
}
/**
* Evaluates the expression: $version1 $operator $version2.
*
* @param string $version1
* @param string $operator
* @param string $version2
*
* @return bool
*/
public static function compare($version1, $operator, $version2)
{
$constraint = new Constraint($operator, $version2);
return $constraint->matches(new Constraint('==', $version1));
}
}
php-composer-semver-1.5.1/src/Constraint/ 0000775 0000000 0000000 00000000000 13615712565 0020357 5 ustar 00root root 0000000 0000000 php-composer-semver-1.5.1/src/Constraint/AbstractConstraint.php 0000664 0000000 0000000 00000003156 13615712565 0024705 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);
/**
* Base constraint class.
*/
abstract class AbstractConstraint implements ConstraintInterface
{
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof $this) {
// see note at bottom of this class declaration
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
// implementations must implement a method of this format:
// not declared abstract here because type hinting violates parameter coherence (TODO right word?)
// public function matchSpecific( $provider);
}
php-composer-semver-1.5.1/src/Constraint/Constraint.php 0000664 0000000 0000000 00000013426 13615712565 0023222 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines a constraint.
*/
class Constraint implements ConstraintInterface
{
/* operator integer values */
const OP_EQ = 0;
const OP_LT = 1;
const OP_LE = 2;
const OP_GT = 3;
const OP_GE = 4;
const OP_NE = 5;
/**
* Operator to integer translation table.
*
* @var array
*/
private static $transOpStr = array(
'=' => self::OP_EQ,
'==' => self::OP_EQ,
'<' => self::OP_LT,
'<=' => self::OP_LE,
'>' => self::OP_GT,
'>=' => self::OP_GE,
'<>' => self::OP_NE,
'!=' => self::OP_NE,
);
/**
* Integer to operator translation table.
*
* @var array
*/
private static $transOpInt = array(
self::OP_EQ => '==',
self::OP_LT => '<',
self::OP_LE => '<=',
self::OP_GT => '>',
self::OP_GE => '>=',
self::OP_NE => '!=',
);
/** @var string */
protected $operator;
/** @var string */
protected $version;
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof $this) {
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
/**
* Get all supported comparison operators.
*
* @return array
*/
public static function getSupportedOperators()
{
return array_keys(self::$transOpStr);
}
/**
* Sets operator and version to compare with.
*
* @param string $operator
* @param string $version
*
* @throws \InvalidArgumentException if invalid operator is given.
*/
public function __construct($operator, $version)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}
$this->operator = self::$transOpStr[$operator];
$this->version = $version;
}
/**
* @param string $a
* @param string $b
* @param string $operator
* @param bool $compareBranches
*
* @throws \InvalidArgumentException if invalid operator is given.
*
* @return bool
*/
public function versionCompare($a, $b, $operator, $compareBranches = false)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}
$aIsBranch = 'dev-' === substr($a, 0, 4);
$bIsBranch = 'dev-' === substr($b, 0, 4);
if ($aIsBranch && $bIsBranch) {
return $operator === '==' && $a === $b;
}
// when branches are not comparable, we make sure dev branches never match anything
if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
return false;
}
return version_compare($a, $b, $operator);
}
/**
* @param Constraint $provider
* @param bool $compareBranches
*
* @return bool
*/
public function matchSpecific(Constraint $provider, $compareBranches = false)
{
$noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
$providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
$isEqualOp = self::OP_EQ === $this->operator;
$isNonEqualOp = self::OP_NE === $this->operator;
$isProviderEqualOp = self::OP_EQ === $provider->operator;
$isProviderNonEqualOp = self::OP_NE === $provider->operator;
// '!=' operator is match when other operator is not '==' operator or version is not match
// these kinds of comparisons always have a solution
if ($isNonEqualOp || $isProviderNonEqualOp) {
return (!$isEqualOp && !$isProviderEqualOp)
|| $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
}
// an example for the condition is <= 2.0 & < 1.0
// these kinds of comparisons always have a solution
if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
return true;
}
if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
// special case, e.g. require >= 1.0 and provide < 1.0
// 1.0 >= 1.0 but 1.0 is outside of the provided interval
return !($provider->version === $this->version
&& self::$transOpInt[$provider->operator] === $providerNoEqualOp
&& self::$transOpInt[$this->operator] !== $noEqualOp);
}
return false;
}
/**
* @return string
*/
public function __toString()
{
return self::$transOpInt[$this->operator] . ' ' . $this->version;
}
}
php-composer-semver-1.5.1/src/Constraint/ConstraintInterface.php 0000664 0000000 0000000 00000001136 13615712565 0025036 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
interface ConstraintInterface
{
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider);
/**
* @return string
*/
public function getPrettyString();
/**
* @return string
*/
public function __toString();
}
php-composer-semver-1.5.1/src/Constraint/EmptyConstraint.php 0000664 0000000 0000000 00000002063 13615712565 0024234 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines the absence of a constraint.
*/
class EmptyConstraint implements ConstraintInterface
{
/** @var string */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
return true;
}
/**
* @param $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* @return string
*/
public function __toString()
{
return '[]';
}
}
php-composer-semver-1.5.1/src/Constraint/MultiConstraint.php 0000664 0000000 0000000 00000005041 13615712565 0024227 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines a conjunctive or disjunctive set of constraints.
*/
class MultiConstraint implements ConstraintInterface
{
/** @var ConstraintInterface[] */
protected $constraints;
/** @var string */
protected $prettyString;
/** @var bool */
protected $conjunctive;
/**
* @param ConstraintInterface[] $constraints A set of constraints
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
*/
public function __construct(array $constraints, $conjunctive = true)
{
$this->constraints = $constraints;
$this->conjunctive = $conjunctive;
}
/**
* @return ConstraintInterface[]
*/
public function getConstraints()
{
return $this->constraints;
}
/**
* @return bool
*/
public function isConjunctive()
{
return $this->conjunctive;
}
/**
* @return bool
*/
public function isDisjunctive()
{
return !$this->conjunctive;
}
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if (false === $this->conjunctive) {
foreach ($this->constraints as $constraint) {
if ($constraint->matches($provider)) {
return true;
}
}
return false;
}
foreach ($this->constraints as $constraint) {
if (!$constraint->matches($provider)) {
return false;
}
}
return true;
}
/**
* @param string $prettyString
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* @return string
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* @return string
*/
public function __toString()
{
$constraints = array();
foreach ($this->constraints as $constraint) {
$constraints[] = (string) $constraint;
}
return '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
}
}
php-composer-semver-1.5.1/src/Semver.php 0000664 0000000 0000000 00000006216 13615712565 0020212 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\Constraint;
class Semver
{
const SORT_ASC = 1;
const SORT_DESC = -1;
/** @var VersionParser */
private static $versionParser;
/**
* Determine if given version satisfies given constraints.
*
* @param string $version
* @param string $constraints
*
* @return bool
*/
public static function satisfies($version, $constraints)
{
if (null === self::$versionParser) {
self::$versionParser = new VersionParser();
}
$versionParser = self::$versionParser;
$provider = new Constraint('==', $versionParser->normalize($version));
$parsedConstraints = $versionParser->parseConstraints($constraints);
return $parsedConstraints->matches($provider);
}
/**
* Return all versions that satisfy given constraints.
*
* @param array $versions
* @param string $constraints
*
* @return array
*/
public static function satisfiedBy(array $versions, $constraints)
{
$versions = array_filter($versions, function ($version) use ($constraints) {
return Semver::satisfies($version, $constraints);
});
return array_values($versions);
}
/**
* Sort given array of versions.
*
* @param array $versions
*
* @return array
*/
public static function sort(array $versions)
{
return self::usort($versions, self::SORT_ASC);
}
/**
* Sort given array of versions in reverse.
*
* @param array $versions
*
* @return array
*/
public static function rsort(array $versions)
{
return self::usort($versions, self::SORT_DESC);
}
/**
* @param array $versions
* @param int $direction
*
* @return array
*/
private static function usort(array $versions, $direction)
{
if (null === self::$versionParser) {
self::$versionParser = new VersionParser();
}
$versionParser = self::$versionParser;
$normalized = array();
// Normalize outside of usort() scope for minor performance increase.
// Creates an array of arrays: [[normalized, key], ...]
foreach ($versions as $key => $version) {
$normalized[] = array($versionParser->normalize($version), $key);
}
usort($normalized, function (array $left, array $right) use ($direction) {
if ($left[0] === $right[0]) {
return 0;
}
if (Comparator::lessThan($left[0], $right[0])) {
return -$direction;
}
return $direction;
});
// Recreate input array, using the original indexes which are now in sorted order.
$sorted = array();
foreach ($normalized as $item) {
$sorted[] = $versions[$item[1]];
}
return $sorted;
}
}
php-composer-semver-1.5.1/src/VersionParser.php 0000664 0000000 0000000 00000046471 13615712565 0021562 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\ConstraintInterface;
use Composer\Semver\Constraint\EmptyConstraint;
use Composer\Semver\Constraint\MultiConstraint;
use Composer\Semver\Constraint\Constraint;
/**
* Version parser.
*
* @author Jordi Boggiano
*/
class VersionParser
{
/**
* Regex to match pre-release data (sort of).
*
* Due to backwards compatibility:
* - Instead of enforcing hyphen, an underscore, dot or nothing at all are also accepted.
* - Only stabilities as recognized by Composer are allowed to precede a numerical identifier.
* - Numerical-only pre-release identifiers are not supported, see tests.
*
* |--------------|
* [major].[minor].[patch] -[pre-release] +[build-metadata]
*
* @var string
*/
private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*+)?)?([.-]?dev)?';
/** @var array */
private static $stabilities = array('stable', 'RC', 'beta', 'alpha', 'dev');
/**
* Returns the stability of a version.
*
* @param string $version
*
* @return string
*/
public static function parseStability($version)
{
$version = preg_replace('{#.+$}i', '', $version);
if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
return 'dev';
}
preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
if (!empty($match[3])) {
return 'dev';
}
if (!empty($match[1])) {
if ('beta' === $match[1] || 'b' === $match[1]) {
return 'beta';
}
if ('alpha' === $match[1] || 'a' === $match[1]) {
return 'alpha';
}
if ('rc' === $match[1]) {
return 'RC';
}
}
return 'stable';
}
/**
* @param string $stability
*
* @return string
*/
public static function normalizeStability($stability)
{
$stability = strtolower($stability);
return $stability === 'rc' ? 'RC' : $stability;
}
/**
* Normalizes a version string to be able to perform comparisons on it.
*
* @param string $version
* @param string $fullVersion optional complete version string to give more context
*
* @throws \UnexpectedValueException
*
* @return string
*/
public function normalize($version, $fullVersion = null)
{
$version = trim($version);
if (null === $fullVersion) {
$fullVersion = $version;
}
// strip off aliasing
if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
// verify that the alias is a version without constraint
$this->normalize($match[2]);
$version = $match[1];
}
// match master-like branches
if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
return '9999999-dev';
}
// if requirement is branch-like, use full name
if (stripos($version, 'dev-') === 0) {
return 'dev-' . substr($version, 4);
}
// strip off build metadata
if (preg_match('{^([^,\s+]++)\+[^\s]++$}', $version, $match)) {
$version = $match[1];
}
// match classical versioning
if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = $matches[1]
. (!empty($matches[2]) ? $matches[2] : '.0')
. (!empty($matches[3]) ? $matches[3] : '.0')
. (!empty($matches[4]) ? $matches[4] : '.0');
$index = 5;
// match date(time) based versioning
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = preg_replace('{\D}', '.', $matches[1]);
$index = 2;
}
// add version modifiers if a version was matched
if (isset($index)) {
if (!empty($matches[$index])) {
if ('stable' === $matches[$index]) {
return $version;
}
$version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index + 1]) ? ltrim($matches[$index + 1], '.-') : '');
}
if (!empty($matches[$index + 2])) {
$version .= '-dev';
}
return $version;
}
// match dev branches
if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
try {
return $this->normalizeBranch($match[1]);
} catch (\Exception $e) {
}
}
$extraMessage = '';
if (preg_match('{ +as +' . preg_quote($version) . '$}', $fullVersion)) {
$extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
} elseif (preg_match('{^' . preg_quote($version) . ' +as +}', $fullVersion)) {
$extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
}
throw new \UnexpectedValueException('Invalid version string "' . $version . '"' . $extraMessage);
}
/**
* Extract numeric prefix from alias, if it is in numeric format, suitable for version comparison.
*
* @param string $branch Branch name (e.g. 2.1.x-dev)
*
* @return string|false Numeric prefix if present (e.g. 2.1.) or false
*/
public function parseNumericAliasPrefix($branch)
{
if (preg_match('{^(?P(\d++\\.)*\d++)(?:\.x)?-dev$}i', $branch, $matches)) {
return $matches['version'] . '.';
}
return false;
}
/**
* Normalizes a branch name to be able to perform comparisons on it.
*
* @param string $name
*
* @return string
*/
public function normalizeBranch($name)
{
$name = trim($name);
if (in_array($name, array('master', 'trunk', 'default'))) {
return $this->normalize($name);
}
if (preg_match('{^v?(\d++)(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?(\.(?:\d++|[xX*]))?$}i', $name, $matches)) {
$version = '';
for ($i = 1; $i < 5; ++$i) {
$version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
}
return str_replace('x', '9999999', $version) . '-dev';
}
return 'dev-' . $name;
}
/**
* Parses a constraint string into MultiConstraint and/or Constraint objects.
*
* @param string $constraints
*
* @return ConstraintInterface
*/
public function parseConstraints($constraints)
{
$prettyConstraint = $constraints;
if (preg_match('{^([^,\s]*?)@(' . implode('|', self::$stabilities) . ')$}i', $constraints, $match)) {
$constraints = empty($match[1]) ? '*' : $match[1];
}
if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
$constraints = $match[1];
}
$orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
$orGroups = array();
foreach ($orConstraints as $constraints) {
$andConstraints = preg_split('{(?< ,]) *(? 1) {
$constraintObjects = array();
foreach ($andConstraints as $constraint) {
foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
$constraintObjects[] = $parsedConstraint;
}
}
} else {
$constraintObjects = $this->parseConstraint($andConstraints[0]);
}
if (1 === count($constraintObjects)) {
$constraint = $constraintObjects[0];
} else {
$constraint = new MultiConstraint($constraintObjects);
}
$orGroups[] = $constraint;
}
if (1 === count($orGroups)) {
$constraint = $orGroups[0];
} elseif (2 === count($orGroups)
// parse the two OR groups and if they are contiguous we collapse
// them into one constraint
&& $orGroups[0] instanceof MultiConstraint
&& $orGroups[1] instanceof MultiConstraint
&& 2 === count($orGroups[0]->getConstraints())
&& 2 === count($orGroups[1]->getConstraints())
&& ($a = (string) $orGroups[0])
&& strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
&& ($b = (string) $orGroups[1])
&& strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
&& substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
) {
$constraint = new MultiConstraint(array(
new Constraint('>=', substr($a, 4, $posA - 5)),
new Constraint('<', substr($b, $posB + 2, -1)),
));
} else {
$constraint = new MultiConstraint($orGroups, false);
}
$constraint->setPrettyString($prettyConstraint);
return $constraint;
}
/**
* @param string $constraint
*
* @throws \UnexpectedValueException
*
* @return array
*/
private function parseConstraint($constraint)
{
if (preg_match('{^([^,\s]+?)@(' . implode('|', self::$stabilities) . ')$}i', $constraint, $match)) {
$constraint = $match[1];
if ($match[2] !== 'stable') {
$stabilityModifier = $match[2];
}
}
if (preg_match('{^v?[xX*](\.[xX*])*$}i', $constraint)) {
return array(new EmptyConstraint());
}
$versionRegex = 'v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.(\d++))?' . self::$modifierRegex . '(?:\+[^\s]+)?';
// Tilde Range
//
// Like wildcard constraints, unsuffixed tilde constraints say that they must be greater than the previous
// version, to ensure that unstable instances of the current version are allowed. However, if a stability
// suffix is added to the constraint, then a >= match on the current version is used instead.
if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
if (strpos($constraint, '~>') === 0) {
throw new \UnexpectedValueException(
'Could not parse version constraint ' . $constraint . ': ' .
'Invalid operator "~>", you probably meant to use the "~" operator'
);
}
// Work out which position in the version we are operating at
if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
$position = 4;
} elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
$position = 3;
} elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
$position = 2;
} else {
$position = 1;
}
// Calculate the stability suffix
$stabilitySuffix = '';
if (empty($matches[5]) && empty($matches[7])) {
$stabilitySuffix .= '-dev';
}
$lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
$lowerBound = new Constraint('>=', $lowVersion);
// For upper bound, we increment the position of one more significance,
// but highPosition = 0 would be illegal
$highPosition = max(1, $position - 1);
$highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
return array(
$lowerBound,
$upperBound,
);
}
// Caret Range
//
// Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple.
// In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for
// versions 0.X >=0.1.0, and no updates for versions 0.0.X
if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
// Work out which position in the version we are operating at
if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
$position = 1;
} elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
$position = 2;
} else {
$position = 3;
}
// Calculate the stability suffix
$stabilitySuffix = '';
if (empty($matches[5]) && empty($matches[7])) {
$stabilitySuffix .= '-dev';
}
$lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
$lowerBound = new Constraint('>=', $lowVersion);
// For upper bound, we increment the position of one more significance,
// but highPosition = 0 would be illegal
$highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
return array(
$lowerBound,
$upperBound,
);
}
// X Range
//
// Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
// A partial version range is treated as an X-Range, so the special character is in fact optional.
if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
$position = 3;
} elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
$position = 2;
} else {
$position = 1;
}
$lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
$highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
if ($lowVersion === '0.0.0.0-dev') {
return array(new Constraint('<', $highVersion));
}
return array(
new Constraint('>=', $lowVersion),
new Constraint('<', $highVersion),
);
}
// Hyphen Range
//
// Specifies an inclusive set. If a partial version is provided as the first version in the inclusive range,
// then the missing pieces are replaced with zeroes. If a partial version is provided as the second version in
// the inclusive range, then all versions that start with the supplied parts of the tuple are accepted, but
// nothing that would be greater than the provided tuple parts.
if (preg_match('{^(?P' . $versionRegex . ') +- +(?P' . $versionRegex . ')($)}i', $constraint, $matches)) {
// Calculate the stability suffix
$lowStabilitySuffix = '';
if (empty($matches[6]) && empty($matches[8])) {
$lowStabilitySuffix = '-dev';
}
$lowVersion = $this->normalize($matches['from']);
$lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
$empty = function ($x) {
return ($x === 0 || $x === '0') ? false : empty($x);
};
if ((!$empty($matches[11]) && !$empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
$highVersion = $this->normalize($matches['to']);
$upperBound = new Constraint('<=', $highVersion);
} else {
$highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
$highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 1 : 2, 1) . '-dev';
$upperBound = new Constraint('<', $highVersion);
}
return array(
$lowerBound,
$upperBound,
);
}
// Basic Comparators
if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
try {
$version = $this->normalize($matches[2]);
if (!empty($stabilityModifier) && self::parseStability($version) === 'stable') {
$version .= '-' . $stabilityModifier;
} elseif ('<' === $matches[1] || '>=' === $matches[1]) {
if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
if (strpos($matches[2], 'dev-') !== 0) {
$version .= '-dev';
}
}
}
return array(new Constraint($matches[1] ?: '=', $version));
} catch (\Exception $e) {
}
}
$message = 'Could not parse version constraint ' . $constraint;
if (isset($e)) {
$message .= ': ' . $e->getMessage();
}
throw new \UnexpectedValueException($message);
}
/**
* Increment, decrement, or simply pad a version number.
*
* Support function for {@link parseConstraint()}
*
* @param array $matches Array with version parts in array indexes 1,2,3,4
* @param int $position 1,2,3,4 - which segment of the version to increment/decrement
* @param int $increment
* @param string $pad The string to pad version parts after $position
*
* @return string The new version
*/
private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
{
for ($i = 4; $i > 0; --$i) {
if ($i > $position) {
$matches[$i] = $pad;
} elseif ($i === $position && $increment) {
$matches[$i] += $increment;
// If $matches[$i] was 0, carry the decrement
if ($matches[$i] < 0) {
$matches[$i] = $pad;
--$position;
// Return null on a carry overflow
if ($i === 1) {
return null;
}
}
}
}
return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
}
/**
* Expand shorthand stability string to long version.
*
* @param string $stability
*
* @return string
*/
private function expandStability($stability)
{
$stability = strtolower($stability);
switch ($stability) {
case 'a':
return 'alpha';
case 'b':
return 'beta';
case 'p':
case 'pl':
return 'patch';
case 'rc':
return 'RC';
default:
return $stability;
}
}
}
php-composer-semver-1.5.1/tests/ 0000775 0000000 0000000 00000000000 13615712565 0016606 5 ustar 00root root 0000000 0000000 php-composer-semver-1.5.1/tests/ComparatorTest.php 0000664 0000000 0000000 00000014640 13615712565 0022273 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Composer\Semver\Comparator
*/
class ComparatorTest extends TestCase
{
/**
* @covers ::greaterThan
* @dataProvider greaterThanProvider
*
* @uses \Composer\Semver\Comparator::compare
*
* @param string $version1
* @param string $version2
* @param bool $expected
*/
public function testGreaterThan($version1, $version2, $expected)
{
$this->assertEquals($expected, Comparator::greaterThan($version1, $version2));
}
/**
* @covers ::greaterThanOrEqualTo
* @dataProvider greaterThanOrEqualToProvider
*
* @uses \Composer\Semver\Comparator::compare
*
* @param string $version1
* @param string $version2
* @param bool $expected
*/
public function testGreaterThanOrEqualTo($version1, $version2, $expected)
{
$this->assertEquals($expected, Comparator::greaterThanOrEqualTo($version1, $version2));
}
/**
* @covers ::lessThan
* @dataProvider lessThanProvider
*
* @uses \Composer\Semver\Comparator::compare
*
* @param string $version1
* @param string $version2
* @param bool $expected
*/
public function testLessThan($version1, $version2, $expected)
{
$this->assertEquals($expected, Comparator::lessThan($version1, $version2));
}
/**
* @covers ::lessThanOrEqualTo
* @dataProvider lessThanOrEqualToProvider
*
* @uses \Composer\Semver\Comparator::compare
*
* @param string $version1
* @param string $version2
* @param bool $expected
*/
public function testLessThanOrEqualTo($version1, $version2, $expected)
{
$this->assertEquals($expected, Comparator::lessThanOrEqualTo($version1, $version2));
}
/**
* @covers ::equalTo
* @dataProvider equalToProvider
*
* @uses \Composer\Semver\Comparator::compare
*
* @param string $version1
* @param string $version2
* @param bool $expected
*/
public function testEqualTo($version1, $version2, $expected)
{
$this->assertEquals($expected, Comparator::equalTo($version1, $version2));
}
/**
* @covers ::notEqualTo
* @dataProvider notEqualToProvider
*
* @uses \Composer\Semver\Comparator::compare
*
* @param string $version1
* @param string $version2
* @param bool $expected
*/
public function testNotEqualTo($version1, $version2, $expected)
{
$this->assertEquals($expected, Comparator::notEqualTo($version1, $version2));
}
/**
* @covers ::compare
* @dataProvider compareProvider
*
* @param string $version1
* @param string $operator
* @param string $version2
* @param bool $expected
*/
public function testCompare($version1, $operator, $version2, $expected)
{
$this->assertEquals($expected, Comparator::compare($version1, $operator, $version2));
}
/**
* @return array
*/
public function greaterThanProvider()
{
return array(
array('1.25.0', '1.24.0', true),
array('1.25.0', '1.25.0', false),
array('1.25.0', '1.26.0', false),
);
}
/**
* @return array
*/
public function greaterThanOrEqualToProvider()
{
return array(
array('1.25.0', '1.24.0', true),
array('1.25.0', '1.25.0', true),
array('1.25.0', '1.26.0', false),
);
}
/**
* @return array
*/
public function lessThanProvider()
{
return array(
array('1.25.0', '1.24.0', false),
array('1.25.0', '1.25.0', false),
array('1.25.0', '1.26.0', true),
array('1.0.0', '1.2-dev', true),
);
}
/**
* @return array
*/
public function lessThanOrEqualToProvider()
{
return array(
array('1.25.0', '1.24.0', false),
array('1.25.0', '1.25.0', true),
array('1.25.0', '1.26.0', true),
);
}
/**
* @return array
*/
public function equalToProvider()
{
return array(
array('1.25.0', '1.24.0', false),
array('1.25.0', '1.25.0', true),
array('1.25.0', '1.26.0', false),
);
}
/**
* @return array
*/
public function notEqualToProvider()
{
return array(
array('1.25.0', '1.24.0', true),
array('1.25.0', '1.25.0', false),
array('1.25.0', '1.26.0', true),
);
}
/**
* @return array
*/
public function compareProvider()
{
return array(
array('1.25.0', '>', '1.24.0', true),
array('1.25.0', '>', '1.25.0', false),
array('1.25.0', '>', '1.26.0', false),
array('1.25.0', '>=', '1.24.0', true),
array('1.25.0', '>=', '1.25.0', true),
array('1.25.0', '>=', '1.26.0', false),
array('1.25.0', '<', '1.24.0', false),
array('1.25.0', '<', '1.25.0', false),
array('1.25.0', '<', '1.26.0', true),
array('1.25.0-beta2.1', '<', '1.25.0-b.3', true),
array('1.25.0-b2.1', '<', '1.25.0beta.3', true),
array('1.25.0-b-2.1', '<', '1.25.0-rc', true),
array('1.25.0', '<=', '1.24.0', false),
array('1.25.0', '<=', '1.25.0', true),
array('1.25.0', '<=', '1.26.0', true),
array('1.25.0', '==', '1.24.0', false),
array('1.25.0', '==', '1.25.0', true),
array('1.25.0', '==', '1.26.0', false),
array('1.25.0-beta2.1', '==', '1.25.0-b.2.1', true),
array('1.25.0beta2.1', '==', '1.25.0-b2.1', true),
array('1.25.0', '=', '1.24.0', false),
array('1.25.0', '=', '1.25.0', true),
array('1.25.0', '=', '1.26.0', false),
array('1.25.0', '!=', '1.24.0', true),
array('1.25.0', '!=', '1.25.0', false),
array('1.25.0', '!=', '1.26.0', true),
array('1.25.0', '<>', '1.24.0', true),
array('1.25.0', '<>', '1.25.0', false),
array('1.25.0', '<>', '1.26.0', true),
);
}
}
php-composer-semver-1.5.1/tests/Constraint/ 0000775 0000000 0000000 00000000000 13615712565 0020732 5 ustar 00root root 0000000 0000000 php-composer-semver-1.5.1/tests/Constraint/ConstraintTest.php 0000664 0000000 0000000 00000012537 13615712565 0024437 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
use PHPUnit\Framework\TestCase;
class ConstraintTest extends TestCase
{
public static function successfulVersionMatches()
{
return array(
// require provide
array('==', '1', '==', '1'),
array('>=', '1', '>=', '2'),
array('>=', '2', '>=', '1'),
array('>=', '2', '>', '1'),
array('<=', '2', '>=', '1'),
array('>=', '1', '<=', '2'),
array('==', '2', '>=', '2'),
array('!=', '1', '!=', '1'),
array('!=', '1', '==', '2'),
array('!=', '1', '<', '1'),
array('!=', '1', '<=', '1'),
array('!=', '1', '>', '1'),
array('!=', '1', '>=', '1'),
array('==', 'dev-foo-bar', '==', 'dev-foo-bar'),
array('==', 'dev-events+issue-17', '==', 'dev-events+issue-17'),
array('==', 'dev-foo-xyz', '==', 'dev-foo-xyz'),
array('>=', 'dev-foo-bar', '>=', 'dev-foo-xyz'),
array('<=', 'dev-foo-bar', '<', 'dev-foo-xyz'),
array('!=', 'dev-foo-bar', '<', 'dev-foo-xyz'),
array('>=', 'dev-foo-bar', '!=', 'dev-foo-bar'),
array('!=', 'dev-foo-bar', '!=', 'dev-foo-xyz'),
);
}
/**
* @dataProvider successfulVersionMatches
*/
public function testVersionMatchSucceeds($requireOperator, $requireVersion, $provideOperator, $provideVersion)
{
$versionRequire = new Constraint($requireOperator, $requireVersion);
$versionProvide = new Constraint($provideOperator, $provideVersion);
$this->assertTrue($versionRequire->matches($versionProvide));
}
public static function failingVersionMatches()
{
return array(
// require provide
array('==', '1', '==', '2'),
array('>=', '2', '<=', '1'),
array('>=', '2', '<', '2'),
array('<=', '2', '>', '2'),
array('>', '2', '<=', '2'),
array('<=', '1', '>=', '2'),
array('>=', '2', '<=', '1'),
array('==', '2', '<', '2'),
array('!=', '1', '==', '1'),
array('==', '1', '!=', '1'),
array('==', 'dev-foo-dist', '==', 'dev-foo-zist'),
array('==', 'dev-foo-bist', '==', 'dev-foo-aist'),
array('<=', 'dev-foo-bist', '>=', 'dev-foo-aist'),
array('>=', 'dev-foo-bist', '<', 'dev-foo-aist'),
array('<', '0.12', '==', 'dev-foo'), // branches are not comparable
array('>', '0.12', '==', 'dev-foo'), // branches are not comparable
);
}
/**
* @dataProvider failingVersionMatches
*/
public function testVersionMatchFails($requireOperator, $requireVersion, $provideOperator, $provideVersion)
{
$versionRequire = new Constraint($requireOperator, $requireVersion);
$versionProvide = new Constraint($provideOperator, $provideVersion);
$this->assertFalse($versionRequire->matches($versionProvide));
}
public function testInverseMatchingOtherConstraints()
{
$constraint = new Constraint('>', '1.0.0');
$multiConstraint = $this
->getMockBuilder('Composer\Semver\Constraint\MultiConstraint')
->disableOriginalConstructor()
->setMethods(array('matches'))
->getMock()
;
$emptyConstraint = $this
->getMockBuilder('Composer\Semver\Constraint\EmptyConstraint')
->setMethods(array('matches'))
->getMock()
;
foreach (array($multiConstraint, $emptyConstraint) as $mock) {
$mock
->expects($this->once())
->method('matches')
->with($constraint)
->willReturn(true)
;
}
$this->assertTrue($constraint->matches($multiConstraint));
$this->assertTrue($constraint->matches($emptyConstraint));
}
public function testComparableBranches()
{
$versionRequire = new Constraint('>', '0.12');
$versionProvide = new Constraint('==', 'dev-foo');
$this->assertFalse($versionRequire->matches($versionProvide));
$this->assertFalse($versionRequire->matchSpecific($versionProvide, true));
$versionRequire = new Constraint('<', '0.12');
$versionProvide = new Constraint('==', 'dev-foo');
$this->assertFalse($versionRequire->matches($versionProvide));
$this->assertTrue($versionRequire->matchSpecific($versionProvide, true));
}
/**
* @dataProvider invalidOperators
*
* @param string $version
* @param string $operator
* @param bool $expected
*/
public function testInvalidOperators($version, $operator, $expected)
{
$this->setExpectedException($expected);
new Constraint($operator, $version);
}
/**
* @return array
*/
public function invalidOperators()
{
return array(
array('1.2.3', 'invalid', 'InvalidArgumentException'),
array('1.2.3', '!', 'InvalidArgumentException'),
array('1.2.3', 'equals', 'InvalidArgumentException'),
);
}
}
php-composer-semver-1.5.1/tests/Constraint/MultiConstraintTest.php 0000664 0000000 0000000 00000003261 13615712565 0025444 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
use PHPUnit\Framework\TestCase;
class MultiConstraintTest extends TestCase
{
public function testMultiVersionMatchSucceeds()
{
$versionRequireStart = new Constraint('>', '1.0');
$versionRequireEnd = new Constraint('<', '1.2');
$versionProvide = new Constraint('==', '1.1');
$multiRequire = new MultiConstraint(array($versionRequireStart, $versionRequireEnd));
$this->assertTrue($multiRequire->matches($versionProvide));
}
public function testMultiVersionProvidedMatchSucceeds()
{
$versionRequireStart = new Constraint('>', '1.0');
$versionRequireEnd = new Constraint('<', '1.2');
$versionProvideStart = new Constraint('>=', '1.1');
$versionProvideEnd = new Constraint('<', '2.0');
$multiRequire = new MultiConstraint(array($versionRequireStart, $versionRequireEnd));
$multiProvide = new MultiConstraint(array($versionProvideStart, $versionProvideEnd));
$this->assertTrue($multiRequire->matches($multiProvide));
}
public function testMultiVersionMatchFails()
{
$versionRequireStart = new Constraint('>', '1.0');
$versionRequireEnd = new Constraint('<', '1.2');
$versionProvide = new Constraint('==', '1.2');
$multiRequire = new MultiConstraint(array($versionRequireStart, $versionRequireEnd));
$this->assertFalse($multiRequire->matches($versionProvide));
}
}
php-composer-semver-1.5.1/tests/SemverTest.php 0000664 0000000 0000000 00000020143 13615712565 0021420 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Composer\Semver\Semver
*/
class SemverTest extends TestCase
{
/**
* @covers ::satisfies
* @dataProvider satisfiesProvider
*
* @param bool $expected
* @param string $version
* @param string $constraint
*/
public function testSatisfies($expected, $version, $constraint)
{
$this->assertEquals($expected, Semver::satisfies($version, $constraint));
}
/**
* @covers ::satisfiedBy
* @dataProvider satisfiedByProvider
*
* @param string $constraint
* @param array $versions
* @param array $expected
*/
public function testSatisfiedBy($constraint, $versions, $expected)
{
$this->assertEquals($expected, Semver::satisfiedBy($versions, $constraint));
}
/**
* @covers ::sort
* @covers ::rsort
* @covers ::usort
* @dataProvider sortProvider
*
* @param array $versions
* @param array $sorted
* @param array $rsorted
*/
public function testSort(array $versions, array $sorted, array $rsorted)
{
$this->assertEquals($sorted, Semver::sort($versions));
$this->assertEquals($rsorted, Semver::rsort($versions));
}
/**
* @return array
*/
public function sortProvider()
{
return array(
array(
array('1.0', '0.1', '0.1', '3.2.1', '2.4.0-alpha', '2.4.0'),
array('0.1', '0.1', '1.0', '2.4.0-alpha', '2.4.0', '3.2.1'),
array('3.2.1', '2.4.0', '2.4.0-alpha', '1.0', '0.1', '0.1'),
),
);
}
/**
* @return array
*/
public function satisfiesProvider()
{
$positive = array_map(function ($array) {
array_unshift($array, true);
return $array;
}, $this->satisfiesProviderPositive());
$negative = array_map(function ($array) {
array_unshift($array, false);
return $array;
}, $this->satisfiesProviderNegative());
return array_merge($positive, $negative);
}
/**
* @return array
*/
public function satisfiesProviderPositive()
{
return array(
array('1.2.3', '1.0.0 - 2.0.0'),
array('1.2.3', '^1.2.3+build'),
array('1.3.0', '^1.2.3+build'),
array('2.4.3-alpha', '1.2.3+asdf - 2.4.3+asdf'),
array('1.3.0-beta', '>1.2'),
array('1.2.3-beta', '<=1.2.3'),
array('1.2.3-beta', '^1.2.3'),
array('1.2.3', '1.2.3+asdf - 2.4.3+asdf'),
array('1.0.0', '1.0.0'),
array('1.2.3', '*'),
array('v1.2.3', '*'),
array('1.0.0', '>=1.0.0'),
array('1.0.1', '>=1.0.0'),
array('1.1.0', '>=1.0.0'),
array('1.0.1', '>1.0.0'),
array('1.1.0', '>1.0.0'),
array('2.0.0', '<=2.0.0'),
array('1.9999.9999', '<=2.0.0'),
array('0.2.9', '<=2.0.0'),
array('1.9999.9999', '<2.0.0'),
array('0.2.9', '<2.0.0'),
array('1.0.0', '>= 1.0.0'),
array('1.0.1', '>= 1.0.0'),
array('1.1.0', '>= 1.0.0'),
array('1.0.1', '> 1.0.0'),
array('1.1.0', '> 1.0.0'),
array('2.0.0', '<= 2.0.0'),
array('1.9999.9999', '<= 2.0.0'),
array('0.2.9', '<= 2.0.0'),
array('1.9999.9999', '< 2.0.0'),
array('0.2.9', "<\t2.0.0"),
array('v0.1.97', '>=0.1.97'),
array('0.1.97', '>=0.1.97'),
array('1.2.4', '0.1.20 || 1.2.4'),
array('0.0.0', '>=0.2.3 || <0.0.1'),
array('0.2.3', '>=0.2.3 || <0.0.1'),
array('0.2.4', '>=0.2.3 || <0.0.1'),
array('2.1.3', '2.x.x'),
array('1.2.3', '1.2.x'),
array('2.1.3', '1.2.x || 2.x'),
array('1.2.3', '1.2.x || 2.x'),
array('1.2.3', 'x'),
array('2.1.3', '2.*.*'),
array('1.2.3', '1.2.*'),
array('2.1.3', '1.2.* || 2.*'),
array('1.2.3', '1.2.* || 2.*'),
array('1.2.3', '*'),
array('2.9.0', '~2.4'), // >=2.4.0 <3.0.0
array('2.4.5', '~2.4'),
array('1.2.3', '~1'), // >=1.0.0 <2.0.0
array('1.4.7', '~1.0'), // >=1.0.0 <2.0.0
array('1.0.0', '>=1'),
array('1.0.0', '>= 1'),
array('1.2.8', '>1.2'), // >1.2.0
array('1.1.1', '<1.2'), // <1.2.0
array('1.1.1', '< 1.2'),
array('1.2.3', '~1.2.1 >=1.2.3'),
array('1.2.3', '~1.2.1 =1.2.3'),
array('1.2.3', '~1.2.1 1.2.3'),
array('1.2.3', '~1.2.1 >=1.2.3 1.2.3'),
array('1.2.3', '~1.2.1 1.2.3 >=1.2.3'),
array('1.2.3', '~1.2.1 1.2.3'),
array('1.2.3', '>=1.2.1 1.2.3'),
array('1.2.3', '1.2.3 >=1.2.1'),
array('1.2.3', '>=1.2.3 >=1.2.1'),
array('1.2.3', '>=1.2.1 >=1.2.3'),
array('1.2.8', '>=1.2'),
array('1.8.1', '^1.2.3'),
array('0.1.2', '^0.1.2'),
array('0.1.2', '^0.1'),
array('1.4.2', '^1.2'),
array('1.4.2', '^1.2 ^1'),
array('0.0.1-beta', '^0.0.1-alpha'),
);
}
/**
* @return array
*/
public function satisfiesProviderNegative()
{
return array(
array('2.2.3', '1.0.0 - 2.0.0'),
array('2.0.0', '^1.2.3+build'),
array('1.2.0', '^1.2.3+build'),
array('1.0.0beta', '1'),
array('1.0.0beta', '<1'),
array('1.0.0beta', '< 1'),
array('1.0.1', '1.0.0'),
array('0.0.0', '>=1.0.0'),
array('0.0.1', '>=1.0.0'),
array('0.1.0', '>=1.0.0'),
array('0.0.1', '>1.0.0'),
array('0.1.0', '>1.0.0'),
array('3.0.0', '<=2.0.0'),
array('2.9999.9999', '<=2.0.0'),
array('2.2.9', '<=2.0.0'),
array('2.9999.9999', '<2.0.0'),
array('2.2.9', '<2.0.0'),
array('v0.1.93', '>=0.1.97'),
array('0.1.93', '>=0.1.97'),
array('1.2.3', '0.1.20 || 1.2.4'),
array('0.0.3', '>=0.2.3 || <0.0.1'),
array('0.2.2', '>=0.2.3 || <0.0.1'),
array('1.1.3', '2.x.x'),
array('3.1.3', '2.x.x'),
array('1.3.3', '1.2.x'),
array('3.1.3', '1.2.x || 2.x'),
array('1.1.3', '1.2.x || 2.x'),
array('1.1.3', '2.*.*'),
array('3.1.3', '2.*.*'),
array('1.3.3', '1.2.*'),
array('3.1.3', '1.2.* || 2.*'),
array('1.1.3', '1.2.* || 2.*'),
array('1.1.2', '2'),
array('2.4.1', '2.3'),
array('3.0.0', '~2.4'), // >=2.4.0 <3.0.0
array('2.3.9', '~2.4'),
array('0.2.3', '~1'), // >=1.0.0 <2.0.0
array('1.0.0', '<1'),
array('1.1.1', '>=1.2'),
array('2.0.0beta', '1'),
array('0.5.4-alpha', '~v0.5.4-beta'),
array('1.2.3-beta', '<1.2.3'),
array('2.0.0-alpha', '^1.2.3'),
array('1.2.2', '^1.2.3'),
array('1.1.9', '^1.2'),
);
}
/**
* @return array
*/
public function satisfiedByProvider()
{
return array(
array(
'~1.0',
array('1.0', '1.2', '1.9999.9999', '2.0', '2.1', '0.9999.9999'),
array('1.0', '1.2', '1.9999.9999'),
),
array(
'>1.0 <3.0 || >=4.0',
array('1.0', '1.1', '2.9999.9999', '3.0', '3.1', '3.9999.9999', '4.0', '4.1'),
array('1.1', '2.9999.9999', '4.0', '4.1'),
),
array(
'^0.2.0',
array('0.1.1', '0.1.9999', '0.2.0', '0.2.1', '0.3.0'),
array('0.2.0', '0.2.1'),
),
);
}
}
php-composer-semver-1.5.1/tests/VersionParserTest.php 0000664 0000000 0000000 00000064305 13615712565 0022771 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver;
use Composer\Semver\Constraint\EmptyConstraint;
use Composer\Semver\Constraint\MultiConstraint;
use Composer\Semver\Constraint\Constraint;
use PHPUnit\Framework\TestCase;
class VersionParserTest extends TestCase
{
/**
* @dataProvider numericAliasVersions
*/
public function testParseNumericAliasPrefix($input, $expected)
{
$parser = new VersionParser();
$this->assertSame($expected, $parser->parseNumericAliasPrefix($input));
}
public function numericAliasVersions()
{
return array(
array('0.x-dev', '0.'),
array('1.0.x-dev', '1.0.'),
array('1.x-dev', '1.'),
array('1.2.x-dev', '1.2.'),
array('1.2-dev', '1.2.'),
array('1-dev', '1.'),
array('dev-develop', false),
array('dev-master', false),
);
}
/**
* @dataProvider successfulNormalizedVersions
*/
public function testNormalizeSucceeds($input, $expected)
{
$parser = new VersionParser();
$this->assertSame($expected, $parser->normalize($input));
}
public function successfulNormalizedVersions()
{
return array(
'none' => array('1.0.0', '1.0.0.0'),
'none/2' => array('1.2.3.4', '1.2.3.4'),
'parses state' => array('1.0.0RC1dev', '1.0.0.0-RC1-dev'),
'CI parsing' => array('1.0.0-rC15-dev', '1.0.0.0-RC15-dev'),
'delimiters' => array('1.0.0.RC.15-dev', '1.0.0.0-RC15-dev'),
'RC uppercase' => array('1.0.0-rc1', '1.0.0.0-RC1'),
'patch replace' => array('1.0.0.pl3-dev', '1.0.0.0-patch3-dev'),
'forces w.x.y.z' => array('1.0-dev', '1.0.0.0-dev'),
'forces w.x.y.z/2' => array('0', '0.0.0.0'),
'parses long' => array('10.4.13-beta', '10.4.13.0-beta'),
'parses long/2' => array('10.4.13beta2', '10.4.13.0-beta2'),
'parses long/semver' => array('10.4.13beta.2', '10.4.13.0-beta2'),
'expand shorthand' => array('10.4.13-b', '10.4.13.0-beta'),
'expand shorthand/2' => array('10.4.13-b5', '10.4.13.0-beta5'),
'strips leading v' => array('v1.0.0', '1.0.0.0'),
'parses dates y-m as classical' => array('2010.01', '2010.01.0.0'),
'parses dates w/ . as classical' => array('2010.01.02', '2010.01.02.0'),
'parses dates y.m.Y as classical' => array('2010.1.555', '2010.1.555.0'),
'parses dates y.m.Y/2 as classical' => array('2010.10.200', '2010.10.200.0'),
'strips v/datetime' => array('v20100102', '20100102'),
'parses dates w/ -' => array('2010-01-02', '2010.01.02'),
'parses numbers' => array('2010-01-02.5', '2010.01.02.5'),
'parses dates y.m.Y' => array('2010.1.555', '2010.1.555.0'),
'parses datetime' => array('20100102-203040', '20100102.203040'),
'parses date dev' => array('20100102.x-dev', '20100102.9999999.9999999.9999999-dev'),
'parses datetime dev' => array('20100102.203040.x-dev', '20100102.203040.9999999.9999999-dev'),
'parses dt+number' => array('20100102203040-10', '20100102203040.10'),
'parses dt+patch' => array('20100102-203040-p1', '20100102.203040-patch1'),
'parses dt Ym' => array('201903.0', '201903.0'),
'parses dt Ym dev' => array('201903.x-dev', '201903.9999999.9999999.9999999-dev'),
'parses dt Ym+patch' => array('201903.0-p2', '201903.0-patch2'),
'parses master' => array('dev-master', '9999999-dev'),
'parses trunk' => array('dev-trunk', '9999999-dev'),
'parses branches' => array('1.x-dev', '1.9999999.9999999.9999999-dev'),
'parses arbitrary' => array('dev-feature-foo', 'dev-feature-foo'),
'parses arbitrary/2' => array('DEV-FOOBAR', 'dev-FOOBAR'),
'parses arbitrary/3' => array('dev-feature/foo', 'dev-feature/foo'),
'parses arbitrary/4' => array('dev-feature+issue-1', 'dev-feature+issue-1'),
'ignores aliases' => array('dev-master as 1.0.0', '9999999-dev'),
'semver metadata/2' => array('1.0.0-beta.5+foo', '1.0.0.0-beta5'),
'semver metadata/3' => array('1.0.0+foo', '1.0.0.0'),
'semver metadata/4' => array('1.0.0-alpha.3.1+foo', '1.0.0.0-alpha3.1'),
'semver metadata/5' => array('1.0.0-alpha2.1+foo', '1.0.0.0-alpha2.1'),
'semver metadata/6' => array('1.0.0-alpha-2.1-3+foo', '1.0.0.0-alpha2.1-3'),
// not supported for BC 'semver metadata/7' => array('1.0.0-0.3.7', '1.0.0.0-0.3.7'),
// not supported for BC 'semver metadata/8' => array('1.0.0-x.7.z.92', '1.0.0.0-x.7.z.92'),
'metadata w/ alias' => array('1.0.0+foo as 2.0', '1.0.0.0'),
);
}
/**
* @dataProvider failingNormalizedVersions
* @expectedException \UnexpectedValueException
*/
public function testNormalizeFails($input)
{
$parser = new VersionParser();
$parser->normalize($input);
}
public function failingNormalizedVersions()
{
return array(
'empty ' => array(''),
'invalid chars' => array('a'),
'invalid type' => array('1.0.0-meh'),
'too many bits' => array('1.0.0.0.0'),
'non-dev arbitrary' => array('feature-foo'),
'metadata w/ space' => array('1.0.0+foo bar'),
'maven style release' => array('1.0.1-SNAPSHOT'),
'Alias and caret' => array('1.0.0+foo as ^2.0'),
'Alias and tilde' => array('1.0.0+foo as ~2.0'),
'Alias and greater than' => array('1.0.0+foo as >2.0'),
'Alias and less than' => array('1.0.0+foo as <2.0'),
);
}
/**
* @dataProvider successfulNormalizedBranches
*/
public function testNormalizeBranch($input, $expected)
{
$parser = new VersionParser();
$this->assertSame((string) $expected, (string) $parser->normalizeBranch($input));
}
public function successfulNormalizedBranches()
{
return array(
'parses x' => array('v1.x', '1.9999999.9999999.9999999-dev'),
'parses *' => array('v1.*', '1.9999999.9999999.9999999-dev'),
'parses digits' => array('v1.0', '1.0.9999999.9999999-dev'),
'parses digits/2' => array('2.0', '2.0.9999999.9999999-dev'),
'parses long x' => array('v1.0.x', '1.0.9999999.9999999-dev'),
'parses long *' => array('v1.0.3.*', '1.0.3.9999999-dev'),
'parses long digits' => array('v2.4.0', '2.4.0.9999999-dev'),
'parses long digits/2' => array('2.4.4', '2.4.4.9999999-dev'),
'parses master' => array('master', '9999999-dev'),
'parses trunk' => array('trunk', '9999999-dev'),
'parses arbitrary' => array('feature-a', 'dev-feature-a'),
'parses arbitrary/2' => array('FOOBAR', 'dev-FOOBAR'),
'parses arbitrary/3' => array('feature+issue-1', 'dev-feature+issue-1'),
);
}
public function testParseConstraintsIgnoresStabilityFlag()
{
$parser = new VersionParser();
$this->assertSame((string) new Constraint('=', '1.0.0.0'), (string) $parser->parseConstraints('1.0@dev'));
}
public function testParseConstraintsIgnoresReferenceOnDevVersion()
{
$parser = new VersionParser();
$this->assertSame((string) new Constraint('=', '1.0.9999999.9999999-dev'), (string) $parser->parseConstraints('1.0.x-dev#abcd123'));
$this->assertSame((string) new Constraint('=', '1.0.9999999.9999999-dev'), (string) $parser->parseConstraints('1.0.x-dev#trunk/@123'));
}
/**
* @expectedException \UnexpectedValueException
*/
public function testParseConstraintsFailsOnBadReference()
{
$parser = new VersionParser();
$this->assertSame((string) new Constraint('=', '1.0.0.0'), (string) $parser->parseConstraints('1.0#abcd123'));
$this->assertSame((string) new Constraint('=', '1.0.0.0'), (string) $parser->parseConstraints('1.0#trunk/@123'));
}
/**
* @expectedException \UnexpectedValueException
* @expectedExceptionMessage Invalid operator "~>", you probably meant to use the "~" operator
*/
public function testParseConstraintsNudgesRubyDevsTowardsThePathOfRighteousness()
{
$parser = new VersionParser();
$parser->parseConstraints('~>1.2');
}
/**
* @dataProvider simpleConstraints
*
* @param string $input
* @param Constraint $expected
*/
public function testParseConstraintsSimple($input, $expected)
{
$parser = new VersionParser();
$this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
}
/**
* @return array
*/
public function simpleConstraints()
{
return array(
'match any' => array('*', new EmptyConstraint()),
'match any/2' => array('*.*', new EmptyConstraint()),
'match any/2v' => array('v*.*', new EmptyConstraint()),
'match any/3' => array('*.x.*', new EmptyConstraint()),
'match any/4' => array('x.X.x.*', new EmptyConstraint()),
'not equal' => array('<>1.0.0', new Constraint('<>', '1.0.0.0')),
'not equal/2' => array('!=1.0.0', new Constraint('!=', '1.0.0.0')),
'greater than' => array('>1.0.0', new Constraint('>', '1.0.0.0')),
'lesser than' => array('<1.2.3.4', new Constraint('<', '1.2.3.4-dev')),
'less/eq than' => array('<=1.2.3', new Constraint('<=', '1.2.3.0')),
'great/eq than' => array('>=1.2.3', new Constraint('>=', '1.2.3.0-dev')),
'equals' => array('=1.2.3', new Constraint('=', '1.2.3.0')),
'double equals' => array('==1.2.3', new Constraint('=', '1.2.3.0')),
'no op means eq' => array('1.2.3', new Constraint('=', '1.2.3.0')),
'completes version' => array('=1.0', new Constraint('=', '1.0.0.0')),
'shorthand beta' => array('1.2.3b5', new Constraint('=', '1.2.3.0-beta5')),
'shorthand alpha' => array('1.2.3a1', new Constraint('=', '1.2.3.0-alpha1')),
'shorthand patch' => array('1.2.3p1234', new Constraint('=', '1.2.3.0-patch1234')),
'shorthand patch/2' => array('1.2.3pl1234', new Constraint('=', '1.2.3.0-patch1234')),
'accepts spaces' => array('>= 1.2.3', new Constraint('>=', '1.2.3.0-dev')),
'accepts spaces/2' => array('< 1.2.3', new Constraint('<', '1.2.3.0-dev')),
'accepts spaces/3' => array('> 1.2.3', new Constraint('>', '1.2.3.0')),
'accepts master' => array('>=dev-master', new Constraint('>=', '9999999-dev')),
'accepts master/2' => array('dev-master', new Constraint('=', '9999999-dev')),
'accepts arbitrary' => array('dev-feature-a', new Constraint('=', 'dev-feature-a')),
'regression #550' => array('dev-some-fix', new Constraint('=', 'dev-some-fix')),
'regression #935' => array('dev-CAPS', new Constraint('=', 'dev-CAPS')),
'ignores aliases' => array('dev-master as 1.0.0', new Constraint('=', '9999999-dev')),
'lesser than override' => array('<1.2.3.4-stable', new Constraint('<', '1.2.3.4')),
'great/eq than override' => array('>=1.2.3.4-stable', new Constraint('>=', '1.2.3.4')),
);
}
/**
* @dataProvider wildcardConstraints
*
* @param string $input
* @param Constraint $min
* @param Constraint $max
*/
public function testParseConstraintsWildcard($input, $min, $max)
{
$parser = new VersionParser();
if ($min) {
$expected = new MultiConstraint(array($min, $max));
} else {
$expected = $max;
}
$this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
}
/**
* @return array
*/
public function wildcardConstraints()
{
return array(
array('v2.*', new Constraint('>=', '2.0.0.0-dev'), new Constraint('<', '3.0.0.0-dev')),
array('2.*.*', new Constraint('>=', '2.0.0.0-dev'), new Constraint('<', '3.0.0.0-dev')),
array('20.*', new Constraint('>=', '20.0.0.0-dev'), new Constraint('<', '21.0.0.0-dev')),
array('20.*.*', new Constraint('>=', '20.0.0.0-dev'), new Constraint('<', '21.0.0.0-dev')),
array('2.0.*', new Constraint('>=', '2.0.0.0-dev'), new Constraint('<', '2.1.0.0-dev')),
array('2.x', new Constraint('>=', '2.0.0.0-dev'), new Constraint('<', '3.0.0.0-dev')),
array('2.x.x', new Constraint('>=', '2.0.0.0-dev'), new Constraint('<', '3.0.0.0-dev')),
array('2.2.x', new Constraint('>=', '2.2.0.0-dev'), new Constraint('<', '2.3.0.0-dev')),
array('2.10.X', new Constraint('>=', '2.10.0.0-dev'), new Constraint('<', '2.11.0.0-dev')),
array('2.1.3.*', new Constraint('>=', '2.1.3.0-dev'), new Constraint('<', '2.1.4.0-dev')),
array('0.*', null, new Constraint('<', '1.0.0.0-dev')),
array('0.*.*', null, new Constraint('<', '1.0.0.0-dev')),
array('0.x', null, new Constraint('<', '1.0.0.0-dev')),
array('0.x.x', null, new Constraint('<', '1.0.0.0-dev')),
);
}
/**
* @dataProvider tildeConstraints
*
* @param string $input
* @param Constraint $min
* @param Constraint $max
*/
public function testParseTildeWildcard($input, $min, $max)
{
$parser = new VersionParser();
if ($min) {
$expected = new MultiConstraint(array($min, $max));
} else {
$expected = $max;
}
$this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
}
/**
* @return array
*/
public function tildeConstraints()
{
return array(
array('~v1', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '2.0.0.0-dev')),
array('~1.0', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '2.0.0.0-dev')),
array('~1.0.0', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '1.1.0.0-dev')),
array('~1.2', new Constraint('>=', '1.2.0.0-dev'), new Constraint('<', '2.0.0.0-dev')),
array('~1.2.3', new Constraint('>=', '1.2.3.0-dev'), new Constraint('<', '1.3.0.0-dev')),
array('~1.2.3.4', new Constraint('>=', '1.2.3.4-dev'), new Constraint('<', '1.2.4.0-dev')),
array('~1.2-beta',new Constraint('>=', '1.2.0.0-beta'), new Constraint('<', '2.0.0.0-dev')),
array('~1.2-b2', new Constraint('>=', '1.2.0.0-beta2'), new Constraint('<', '2.0.0.0-dev')),
array('~1.2-BETA2', new Constraint('>=', '1.2.0.0-beta2'), new Constraint('<', '2.0.0.0-dev')),
array('~1.2.2-dev', new Constraint('>=', '1.2.2.0-dev'), new Constraint('<', '1.3.0.0-dev')),
array('~1.2.2-stable', new Constraint('>=', '1.2.2.0'), new Constraint('<', '1.3.0.0-dev')),
array('~201903.0', new Constraint('>=', '201903.0-dev'), new Constraint('<', '201904.0.0.0-dev')),
array('~201903.0-beta', new Constraint('>=', '201903.0-beta'), new Constraint('<', '201904.0.0.0-dev')),
array('~201903.0-stable', new Constraint('>=', '201903.0'), new Constraint('<', '201904.0.0.0-dev')),
array('~201903.205830.1-stable', new Constraint('>=', '201903.205830.1'), new Constraint('<', '201903.205831.0.0-dev')),
);
}
/**
* @dataProvider caretConstraints
*
* @param string $input
* @param Constraint $min
* @param Constraint $max
*/
public function testParseCaretWildcard($input, $min, $max)
{
$parser = new VersionParser();
if ($min) {
$expected = new MultiConstraint(array($min, $max));
} else {
$expected = $max;
}
$this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
}
/**
* @return array
*/
public function caretConstraints()
{
return array(
array('^v1', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '2.0.0.0-dev')),
array('^0', new Constraint('>=', '0.0.0.0-dev'), new Constraint('<', '1.0.0.0-dev')),
array('^0.0', new Constraint('>=', '0.0.0.0-dev'), new Constraint('<', '0.1.0.0-dev')),
array('^1.2', new Constraint('>=', '1.2.0.0-dev'), new Constraint('<', '2.0.0.0-dev')),
array('^1.2.3-beta.2', new Constraint('>=', '1.2.3.0-beta2'), new Constraint('<', '2.0.0.0-dev')),
array('^1.2.3.4', new Constraint('>=', '1.2.3.4-dev'), new Constraint('<', '2.0.0.0-dev')),
array('^1.2.3', new Constraint('>=', '1.2.3.0-dev'), new Constraint('<', '2.0.0.0-dev')),
array('^0.2.3', new Constraint('>=', '0.2.3.0-dev'), new Constraint('<', '0.3.0.0-dev')),
array('^0.2', new Constraint('>=', '0.2.0.0-dev'), new Constraint('<', '0.3.0.0-dev')),
array('^0.2.0', new Constraint('>=', '0.2.0.0-dev'), new Constraint('<', '0.3.0.0-dev')),
array('^0.0.3', new Constraint('>=', '0.0.3.0-dev'), new Constraint('<', '0.0.4.0-dev')),
array('^0.0.3-alpha', new Constraint('>=', '0.0.3.0-alpha'), new Constraint('<', '0.0.4.0-dev')),
array('^0.0.3-dev', new Constraint('>=', '0.0.3.0-dev'), new Constraint('<', '0.0.4.0-dev')),
array('^0.0.3-stable', new Constraint('>=', '0.0.3.0'), new Constraint('<', '0.0.4.0-dev')),
array('^201903.0', new Constraint('>=', '201903.0-dev'), new Constraint('<', '201904.0.0.0-dev')),
array('^201903.0-beta', new Constraint('>=', '201903.0-beta'), new Constraint('<', '201904.0.0.0-dev')),
array('^201903.205830.1-stable', new Constraint('>=', '201903.205830.1'), new Constraint('<', '201904.0.0.0-dev')),
);
}
/**
* @dataProvider hyphenConstraints
*
* @param string $input
* @param Constraint $min
* @param Constraint $max
*/
public function testParseHyphen($input, $min, $max)
{
$parser = new VersionParser();
if ($min) {
$expected = new MultiConstraint(array($min, $max));
} else {
$expected = $max;
}
$this->assertSame((string) $expected, (string) $parser->parseConstraints($input));
}
/**
* @return array
*/
public function hyphenConstraints()
{
return array(
array('v1 - v2', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '3.0.0.0-dev')),
array('1.2.3 - 2.3.4.5', new Constraint('>=', '1.2.3.0-dev'), new Constraint('<=', '2.3.4.5')),
array('1.2-beta - 2.3', new Constraint('>=', '1.2.0.0-beta'), new Constraint('<', '2.4.0.0-dev')),
array('1.2-beta - 2.3-dev', new Constraint('>=', '1.2.0.0-beta'), new Constraint('<=', '2.3.0.0-dev')),
array('1.2-RC - 2.3.1', new Constraint('>=', '1.2.0.0-RC'), new Constraint('<=', '2.3.1.0')),
array('1.2.3-alpha - 2.3-RC', new Constraint('>=', '1.2.3.0-alpha'), new Constraint('<=', '2.3.0.0-RC')),
array('1 - 2.0', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '2.1.0.0-dev')),
array('1 - 2.1', new Constraint('>=', '1.0.0.0-dev'), new Constraint('<', '2.2.0.0-dev')),
array('1.2 - 2.1.0', new Constraint('>=', '1.2.0.0-dev'), new Constraint('<=', '2.1.0.0')),
array('1.3 - 2.1.3', new Constraint('>=', '1.3.0.0-dev'), new Constraint('<=', '2.1.3.0')),
);
}
public function testParseConstraintsMultiCollapsesContiguous()
{
$parser = new VersionParser();
$first = new Constraint('>=', '2.5.0.0-dev');
$second = new Constraint('<', '4.0.0.0-dev');
$multi = new MultiConstraint(array($first, $second));
$this->assertSame((string) $multi, (string) $parser->parseConstraints('^2.5 || ^3.0'));
}
public function testParseCaretConstraintsMultiDoesNotCollapseNonContiguousRange()
{
$parser = new VersionParser();
$first = new MultiConstraint(array(
new Constraint('>=', '0.2.0.0-dev'),
new Constraint('<', '0.3.0.0-dev'),
));
$second = new MultiConstraint(array(
new Constraint('>=', '1.0.0.0-dev'),
new Constraint('<', '2.0.0.0-dev'),
));
$multi = new MultiConstraint(array($first, $second), false);
$parsed = $parser->parseConstraints('^0.2 || ^1.0');
$this->assertSame((string) $multi, (string) $parsed);
}
public function testDoNotCollapseContiguousRangeIfOtherConstraintsAlsoApply()
{
$parser = new VersionParser();
$first = new MultiConstraint(array(
new Constraint('>=', '0.1.0.0-dev'),
new Constraint('<', '1.0.0.0-dev'),
));
$second = new MultiConstraint(array(
new Constraint('>=', '1.0.0.0-dev'),
new Constraint('<', '2.0.0.0-dev'),
new Constraint('!=', '1.0.1.0'),
));
$multi = new MultiConstraint(array($first, $second), false);
$version = new Constraint('=', '1.0.1.0');
$this->assertFalse($multi->matches($version), 'Generated expectation should not allow version "1.0.1.0"');
$parsed = $parser->parseConstraints('~0.1 || ~1.0 !=1.0.1');
$this->assertFalse($parsed->matches($version), '"~0.1 || ~1.0 !=1.0.1" should not allow version "1.0.1.0"');
$this->assertSame((string) $multi, (string) $parsed);
}
/**
* @dataProvider multiConstraintProvider
*/
public function testParseConstraintsMulti($constraint)
{
$parser = new VersionParser();
$first = new Constraint('>', '2.0.0.0');
$second = new Constraint('<=', '3.0.0.0');
$multi = new MultiConstraint(array($first, $second));
$this->assertSame((string) $multi, (string) $parser->parseConstraints($constraint));
}
/**
* @return array
*/
public function multiConstraintProvider()
{
return array(
array('>2.0,<=3.0'),
array('>2.0 <=3.0'),
array('>2.0 <=3.0'),
array('>2.0, <=3.0'),
array('>2.0 ,<=3.0'),
array('>2.0 , <=3.0'),
array('>2.0 , <=3.0'),
array('> 2.0 <= 3.0'),
array('> 2.0 , <= 3.0'),
array(' > 2.0 , <= 3.0 '),
);
}
public function testParseConstraintsMultiWithStabilitySuffix()
{
$parser = new VersionParser();
$first = new Constraint('>=', '1.1.0.0-alpha4');
$second = new Constraint('<', '1.2.9999999.9999999-dev');
$multi = new MultiConstraint(array($first, $second));
$this->assertSame((string) $multi, (string) $parser->parseConstraints('>=1.1.0-alpha4,<1.2.x-dev'));
$first = new Constraint('>=', '1.1.0.0-alpha4');
$second = new Constraint('<', '1.2.0.0-beta2');
$multi = new MultiConstraint(array($first, $second));
$this->assertSame((string) $multi, (string) $parser->parseConstraints('>=1.1.0-alpha4,<1.2-beta2'));
}
/**
* @dataProvider multiConstraintProvider2
*
* @param string $constraint
*/
public function testParseConstraintsMultiDisjunctiveHasPrioOverConjuctive($constraint)
{
$parser = new VersionParser();
$first = new Constraint('>', '2.0.0.0');
$second = new Constraint('<', '2.0.5.0-dev');
$third = new Constraint('>', '2.0.6.0');
$multi1 = new MultiConstraint(array($first, $second));
$multi2 = new MultiConstraint(array($multi1, $third), false);
$this->assertSame((string) $multi2, (string) $parser->parseConstraints($constraint));
}
/**
* @return array
*/
public function multiConstraintProvider2()
{
return array(
array('>2.0,<2.0.5 | >2.0.6'),
array('>2.0,<2.0.5 || >2.0.6'),
array('> 2.0 , <2.0.5 | > 2.0.6'),
);
}
public function testParseConstraintsMultiWithStabilities()
{
$parser = new VersionParser();
$first = new Constraint('>', '2.0.0.0');
$second = new Constraint('<=', '3.0.0.0-dev');
$multi = new MultiConstraint(array($first, $second));
$this->assertSame((string) $multi, (string) $parser->parseConstraints('>2.0@stable,<=3.0@dev'));
}
/**
* @dataProvider failingConstraints
* @expectedException \UnexpectedValueException
*
* @param string $input
*/
public function testParseConstraintsFails($input)
{
$parser = new VersionParser();
$parser->parseConstraints($input);
}
/**
* @return array
*/
public function failingConstraints()
{
return array(
'empty ' => array(''),
'invalid version' => array('1.0.0-meh'),
'operator abuse' => array('>2.0,,<=3.0'),
'operator abuse/2' => array('>2.0 ,, <=3.0'),
'operator abuse/3' => array('>2.0 ||| <=3.0'),
);
}
/**
* @dataProvider stabilityProvider
*
* @param string $expected
* @param string $version
*/
public function testParseStability($expected, $version)
{
$this->assertSame($expected, VersionParser::parseStability($version));
}
/**
* @return array
*/
public function stabilityProvider()
{
return array(
array('stable', '1'),
array('stable', '1.0'),
array('stable', '3.2.1'),
array('stable', 'v3.2.1'),
array('dev', 'v2.0.x-dev'),
array('dev', 'v2.0.x-dev#abc123'),
array('dev', 'v2.0.x-dev#trunk/@123'),
array('RC', '3.0-RC2'),
array('dev', 'dev-master'),
array('dev', '3.1.2-dev'),
array('dev', 'dev-feature+issue-1'),
array('stable', '3.1.2-p1'),
array('stable', '3.1.2-pl2'),
array('stable', '3.1.2-patch'),
array('alpha', '3.1.2-alpha5'),
array('beta', '3.1.2-beta'),
array('beta', '2.0B1'),
array('alpha', '1.2.0a1'),
array('alpha', '1.2_a1'),
array('RC', '2.0.0rc1'),
array('alpha', '1.0.0-alpha11+cs-1.1.0'),
);
}
}