'CopyJobQueue' => __DIR__ . '/maintenance/copyJobQueue.php',
'CoreParserFunctions' => __DIR__ . '/includes/parser/CoreParserFunctions.php',
'CoreTagHooks' => __DIR__ . '/includes/parser/CoreTagHooks.php',
- 'CoreVersionChecker' => __DIR__ . '/includes/registration/CoreVersionChecker.php',
'CreateAndPromote' => __DIR__ . '/maintenance/createAndPromote.php',
'CreateFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/CreateFileOp.php',
'CreditsAction' => __DIR__ . '/includes/actions/CreditsAction.php',
'UzConverter' => __DIR__ . '/languages/classes/LanguageUz.php',
'VFormHTMLForm' => __DIR__ . '/includes/htmlform/VFormHTMLForm.php',
'ValidateRegistrationFile' => __DIR__ . '/maintenance/validateRegistrationFile.php',
+ 'VersionChecker' => __DIR__ . '/includes/registration/VersionChecker.php',
'ViewAction' => __DIR__ . '/includes/actions/ViewAction.php',
'ViewCLI' => __DIR__ . '/maintenance/view.php',
'VirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTService.php',
},
"requires": {
"type": "object",
- "description": "Indicates what versions of MediaWiki core are required. This syntax may be extended in the future, for example to check dependencies between other extensions.",
+ "description": "Indicates what versions of MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.",
"properties": {
"MediaWiki": {
"type": "string",
"description": "Version constraint string against MediaWiki core."
+ },
+ "extensions": {
+ "type": "object",
+ "description": "Set of version constraint strings against specific extensions."
+ },
+ "skins": {
+ "type": "object",
+ "description": "Set of version constraint strings against specific skins."
}
}
},
protected function formatListParam( array $params, $listType, $format ) {
if ( !isset( self::$listTypeMap[$listType] ) ) {
$warning = 'Invalid list type for message "' . $this->getKey() . '": ' .
- htmlspecialchars( serialize( $param ) );
+ htmlspecialchars( serialize( $params )
+ );
trigger_error( $warning, E_USER_WARNING );
$e = new Exception;
wfDebugLog( 'Bug58676', $warning . "\n" . $e->getTraceAsString() );
'names' => [ 2 => null ],
'min' => 2,
'max' => 2,
- ]
+ ],
+ '-{' => [
+ 'end' => '}-',
+ 'names' => [ 1 => null ],
+ 'min' => 1,
+ 'max' => 1,
+ ],
];
/**
* @return string
*/
public function preprocessToXml( $text, $flags = 0 ) {
+ global $wgDisableLangConversion;
+
$forInclusion = $flags & Parser::PTD_FOR_INCLUSION;
$xmlishElements = $this->parser->getStripList();
$stack = new PPDStack;
$searchBase = "[{<\n"; # }
+ if ( !$wgDisableLangConversion ) {
+ $searchBase .= '-';
+ }
+
// For fast reverse searches
$revText = strrev( $text );
$lengthText = strlen( $text );
break;
}
} else {
- $curChar = $text[$i];
+ $curChar = $curTwoChar = $text[$i];
+ if ( ( $i + 1 ) < $lengthText ) {
+ $curTwoChar .= $text[$i + 1];
+ }
if ( $curChar == '|' ) {
$found = 'pipe';
} elseif ( $curChar == '=' ) {
} else {
$found = 'line-start';
}
+ } elseif ( $curTwoChar == $currentClosing ) {
+ $found = 'close';
+ $curChar = $curTwoChar;
} elseif ( $curChar == $currentClosing ) {
$found = 'close';
+ } elseif ( isset( $this->rules[$curTwoChar] ) ) {
+ $curChar = $curTwoChar;
+ $found = 'open';
+ $rule = $this->rules[$curChar];
} elseif ( isset( $this->rules[$curChar] ) ) {
$found = 'open';
$rule = $this->rules[$curChar];
+ } elseif ( $curChar == '-' ) {
+ $found = 'dash';
} else {
# Some versions of PHP have a strcspn which stops on null characters
# Ignore and continue
// input pointer.
} elseif ( $found == 'open' ) {
# count opening brace characters
- $count = strspn( $text, $curChar, $i );
+ $curLen = strlen( $curChar );
+ $count = ( $curLen > 1 ) ? 1 : strspn( $text, $curChar, $i );
# we need to add to stack only if opening brace count is enough for one of the rules
if ( $count >= $rule['min'] ) {
# Add literal brace(s)
$accum .= htmlspecialchars( str_repeat( $curChar, $count ) );
}
- $i += $count;
+ $i += $curLen * $count;
} elseif ( $found == 'close' ) {
$piece = $stack->top;
# lets check if there are enough characters for closing brace
$maxCount = $piece->count;
- $count = strspn( $text, $curChar, $i, $maxCount );
+ $curLen = strlen( $curChar );
+ $count = ( $curLen > 1 ) ? 1 : strspn( $text, $curChar, $i, $maxCount );
# check for maximum matching characters (if there are 5 closing
# characters, we will probably need only 3 - depending on the rules)
# No matching element found in callback array
# Output a literal closing brace and continue
$accum .= htmlspecialchars( str_repeat( $curChar, $count ) );
- $i += $count;
+ $i += $curLen * $count;
continue;
}
$name = $rule['names'][$matchingCount];
}
# Advance input pointer
- $i += $matchingCount;
+ $i += $curLen * $matchingCount;
# Unwind the stack
$stack->pop();
$stack->getCurrentPart()->eqpos = strlen( $accum );
$accum .= '=';
++$i;
+ } elseif ( $found == 'dash' ) {
+ $accum .= '-';
+ ++$i;
}
}
* @return PPNode_Hash_Tree
*/
public function preprocessToObj( $text, $flags = 0 ) {
+ global $wgDisableLangConversion;
+
$tree = $this->cacheGetTree( $text, $flags );
if ( $tree !== false ) {
$store = json_decode( $tree );
$stack = new PPDStack_Hash;
$searchBase = "[{<\n";
+ if ( !$wgDisableLangConversion ) {
+ $searchBase .= '-';
+ }
+
// For fast reverse searches
$revText = strrev( $text );
$lengthText = strlen( $text );
break;
}
} else {
- $curChar = $text[$i];
+ $curChar = $curTwoChar = $text[$i];
+ if ( ( $i + 1 ) < $lengthText ) {
+ $curTwoChar .= $text[$i + 1];
+ }
if ( $curChar == '|' ) {
$found = 'pipe';
} elseif ( $curChar == '=' ) {
} else {
$found = 'line-start';
}
+ } elseif ( $curTwoChar == $currentClosing ) {
+ $found = 'close';
+ $curChar = $curTwoChar;
} elseif ( $curChar == $currentClosing ) {
$found = 'close';
+ } elseif ( isset( $this->rules[$curTwoChar] ) ) {
+ $curChar = $curTwoChar;
+ $found = 'open';
+ $rule = $this->rules[$curChar];
} elseif ( isset( $this->rules[$curChar] ) ) {
$found = 'open';
$rule = $this->rules[$curChar];
+ } elseif ( $curChar == '-' ) {
+ $found = 'dash';
} else {
# Some versions of PHP have a strcspn which stops on null characters
# Ignore and continue
// input pointer.
} elseif ( $found == 'open' ) {
# count opening brace characters
- $count = strspn( $text, $curChar, $i );
+ $curLen = strlen( $curChar );
+ $count = ( $curLen > 1 ) ? 1 : strspn( $text, $curChar, $i );
# we need to add to stack only if opening brace count is enough for one of the rules
if ( $count >= $rule['min'] ) {
# Add literal brace(s)
self::addLiteral( $accum, str_repeat( $curChar, $count ) );
}
- $i += $count;
+ $i += $curLen * $count;
} elseif ( $found == 'close' ) {
$piece = $stack->top;
# lets check if there are enough characters for closing brace
$maxCount = $piece->count;
- $count = strspn( $text, $curChar, $i, $maxCount );
+ $curLen = strlen( $curChar );
+ $count = ( $curLen > 1 ) ? 1 : strspn( $text, $curChar, $i, $maxCount );
# check for maximum matching characters (if there are 5 closing
# characters, we will probably need only 3 - depending on the rules)
# No matching element found in callback array
# Output a literal closing brace and continue
self::addLiteral( $accum, str_repeat( $curChar, $count ) );
- $i += $count;
+ $i += $curLen * $count;
continue;
}
$name = $rule['names'][$matchingCount];
}
# Advance input pointer
- $i += $matchingCount;
+ $i += $curLen * $matchingCount;
# Unwind the stack
$stack->pop();
$accum[] = [ 'equals', [ '=' ] ];
$stack->getCurrentPart()->eqpos = count( $accum ) - 1;
++$i;
+ } elseif ( $found == 'dash' ) {
+ self::addLiteral( $accum, '-' );
+ ++$i;
}
}
+++ /dev/null
-<?php
-
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-use Composer\Semver\VersionParser;
-use Composer\Semver\Constraint\Constraint;
-
-/**
- * @since 1.26
- */
-class CoreVersionChecker {
-
- /**
- * @var Constraint|bool representing $wgVersion
- */
- private $coreVersion = false;
-
- /**
- * @var VersionParser
- */
- private $versionParser;
-
- /**
- * @param string $coreVersion Current version of core
- */
- public function __construct( $coreVersion ) {
- $this->versionParser = new VersionParser();
- try {
- $this->coreVersion = new Constraint(
- '==',
- $this->versionParser->normalize( $coreVersion )
- );
- } catch ( UnexpectedValueException $e ) {
- // Non-parsable version, don't fatal.
- }
- }
-
- /**
- * Check that the provided constraint is compatible with the current version of core
- *
- * @param string $constraint Something like ">= 1.26"
- * @return bool
- */
- public function check( $constraint ) {
- if ( $this->coreVersion === false ) {
- // Couldn't parse the core version, so we can't check anything
- return true;
- }
-
- return $this->versionParser->parseConstraints( $constraint )
- ->matches( $this->coreVersion );
- }
-}
}
public function getRequirements( array $info ) {
- $requirements = [];
- $key = ExtensionRegistry::MEDIAWIKI_CORE;
- if ( isset( $info['requires'][$key] ) ) {
- $requirements[$key] = $info['requires'][$key];
- }
-
- return $requirements;
+ return isset( $info['requires'] ) ? $info['requires'] : [];
}
protected function extractHooks( array $info ) {
/**
* Bump whenever the registration cache needs resetting
*/
- const CACHE_VERSION = 4;
+ const CACHE_VERSION = 5;
/**
* Special key that defines the merge strategy
$autoloadClasses = [];
$autoloaderPaths = [];
$processor = new ExtensionProcessor();
+ $versionChecker = new VersionChecker( $wgVersion );
+ $extDependencies = [];
$incompatible = [];
- $coreVersionParser = new CoreVersionChecker( $wgVersion );
foreach ( $queue as $path => $mtime ) {
$json = file_get_contents( $path );
if ( $json === false ) {
throw new Exception( "$path is not a valid JSON file." );
}
- // Check any constraints against MediaWiki core
- $requires = $processor->getRequirements( $info );
- if ( isset( $requires[self::MEDIAWIKI_CORE] )
- && !$coreVersionParser->check( $requires[self::MEDIAWIKI_CORE] )
- ) {
- // Doesn't match, mark it as incompatible.
- $incompatible[] = "{$info['name']} is not compatible with the current "
- . "MediaWiki core (version {$wgVersion}), it requires: " . $requires[self::MEDIAWIKI_CORE]
- . '.';
- continue;
- }
-
if ( !isset( $info['manifest_version'] ) ) {
// For backwards-compatability, assume a version of 1
$info['manifest_version'] = 1;
}
$version = $info['manifest_version'];
if ( $version < self::OLDEST_MANIFEST_VERSION || $version > self::MANIFEST_VERSION ) {
- throw new Exception( "$path: unsupported manifest_version: {$version}" );
+ $incompatible[] = "$path: unsupported manifest_version: {$version}";
}
$autoload = $this->processAutoLoader( dirname( $path ), $info );
$GLOBALS['wgAutoloadClasses'] += $autoload;
$autoloadClasses += $autoload;
+ // get all requirements/dependencies for this extension
+ $requires = $processor->getRequirements( $info );
+
+ // validate the information needed and add the requirements
+ if ( is_array( $requires ) && $requires && isset( $info['name'] ) ) {
+ $extDependencies[$info['name']] = $requires;
+ }
+
// Get extra paths for later inclusion
$autoloaderPaths = array_merge( $autoloaderPaths,
$processor->getExtraAutoloaderPaths( dirname( $path ), $info ) );
// Compatible, read and extract info
$processor->extractInfo( $path, $info, $version );
}
+ $data = $processor->getExtractedInfo();
+
+ // check for incompatible extensions
+ $incompatible = array_merge(
+ $incompatible,
+ $versionChecker
+ ->setLoadedExtensionsAndSkins( $data['credits'] )
+ ->checkArray( $extDependencies )
+ );
+
if ( $incompatible ) {
if ( count( $incompatible ) === 1 ) {
throw new Exception( $incompatible[0] );
throw new Exception( implode( "\n", $incompatible ) );
}
}
- $data = $processor->getExtractedInfo();
+
// Need to set this so we can += to it later
$data['globals']['wgAutoloadClasses'] = [];
$data['autoload'] = $autoloadClasses;
--- /dev/null
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @author Legoktm
+ * @author Florian Schmidt
+ */
+
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\Constraint;
+
+/**
+ * Provides functions to check a set of extensions with dependencies against
+ * a set of loaded extensions and given version information.
+ *
+ * @since 1.29
+ */
+class VersionChecker {
+ /**
+ * @var Constraint|bool representing $wgVersion
+ */
+ private $coreVersion = false;
+
+ /**
+ * @var array Loaded extensions
+ */
+ private $loaded = [];
+
+ /**
+ * @var VersionParser
+ */
+ private $versionParser;
+
+ /**
+ * @param string $coreVersion Current version of core
+ */
+ public function __construct( $coreVersion ) {
+ $this->versionParser = new VersionParser();
+ $this->setCoreVersion( $coreVersion );
+ }
+
+ /**
+ * Set an array with credits of all loaded extensions and skins.
+ *
+ * @param array $credits An array of installed extensions with credits of them
+ * @return VersionChecker $this
+ */
+ public function setLoadedExtensionsAndSkins( array $credits ) {
+ $this->loaded = $credits;
+
+ return $this;
+ }
+
+ /**
+ * Set MediaWiki core version.
+ *
+ * @param string $coreVersion Current version of core
+ */
+ private function setCoreVersion( $coreVersion ) {
+ try {
+ $this->coreVersion = new Constraint(
+ '==',
+ $this->versionParser->normalize( $coreVersion )
+ );
+ $this->coreVersion->setPrettyString( $coreVersion );
+ } catch ( UnexpectedValueException $e ) {
+ // Non-parsable version, don't fatal.
+ }
+ }
+
+ /**
+ * Check all given dependencies if they are compatible with the named
+ * installed extensions in the $credits array.
+ *
+ * Example $extDependencies:
+ * {
+ * 'FooBar' => {
+ * 'MediaWiki' => '>= 1.25.0',
+ * 'extensions' => {
+ * 'FooBaz' => '>= 1.25.0'
+ * },
+ * 'skins' => {
+ * 'BazBar' => '>= 1.0.0'
+ * }
+ * }
+ * }
+ *
+ * @param array $extDependencies All extensions that depend on other ones
+ * @return array
+ */
+ public function checkArray( array $extDependencies ) {
+ $errors = [];
+ foreach ( $extDependencies as $extension => $dependencies ) {
+ foreach ( $dependencies as $dependencyType => $values ) {
+ switch ( $dependencyType ) {
+ case ExtensionRegistry::MEDIAWIKI_CORE:
+ $mwError = $this->handleMediaWikiDependency( $values, $extension );
+ if ( $mwError !== false ) {
+ $errors[] = $mwError;
+ }
+ break;
+ case 'extensions':
+ case 'skin':
+ foreach ( $values as $dependency => $constraint ) {
+ $extError = $this->handleExtensionDependency( $dependency, $constraint, $extension );
+ if ( $extError !== false ) {
+ $errors[] = $extError;
+ }
+ }
+ break;
+ default:
+ throw new UnexpectedValueException( 'Dependency type ' . $dependencyType .
+ ' unknown in ' . $extension );
+ }
+ }
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Handle a dependency to MediaWiki core. It will check, if a MediaWiki version constraint was
+ * set with self::setCoreVersion before this call (if not, it will return an empty array) and
+ * checks the version constraint given against it.
+ *
+ * @param string $constraint The required version constraint for this dependency
+ * @param string $checkedExt The Extension, which depends on this dependency
+ * @return bool|string false if no error, or a string with the message
+ */
+ private function handleMediaWikiDependency( $constraint, $checkedExt ) {
+ if ( $this->coreVersion === false ) {
+ // Couldn't parse the core version, so we can't check anything
+ return false;
+ }
+
+ // if the installed and required version are compatible, return an empty array
+ if ( $this->versionParser->parseConstraints( $constraint )
+ ->matches( $this->coreVersion ) ) {
+ return false;
+ }
+ // otherwise mark this as incompatible.
+ return "{$checkedExt} is not compatible with the current "
+ . "MediaWiki core (version {$this->coreVersion->getPrettyString()}), it requires: "
+ . "$constraint.";
+ }
+
+ /**
+ * Handle a dependency to another extension.
+ *
+ * @param string $dependencyName The name of the dependency
+ * @param string $constraint The required version constraint for this dependency
+ * @param string $checkedExt The Extension, which depends on this dependency
+ * @return bool|string false for no errors, or a string message
+ */
+ private function handleExtensionDependency( $dependencyName, $constraint, $checkedExt ) {
+ // Check if the dependency is even installed
+ if ( !isset( $this->loaded[$dependencyName] ) ) {
+ return "{$checkedExt} requires {$dependencyName} to be installed.";
+ }
+ // Check if the dependency has specified a version
+ if ( !isset( $this->loaded[$dependencyName]['version'] ) ) {
+ // If we depend upon any version, and none is set, that's fine.
+ if ( $constraint === '*' ) {
+ wfDebug( "{$dependencyName} does not expose it's version, but {$checkedExt}
+ mentions it with constraint '*'. Assume it's ok so." );
+ return false;
+ } else {
+ // Otherwise, mark it as incompatible.
+ return "{$dependencyName} does not expose it's version, but {$checkedExt}
+ requires: {$constraint}.";
+ }
+ } else {
+ // Try to get a constraint for the dependency version
+ try {
+ $installedVersion = new Constraint(
+ '==',
+ $this->versionParser->normalize( $this->loaded[$dependencyName]['version'] )
+ );
+ } catch ( UnexpectedValueException $e ) {
+ // Non-parsable version, output an error message that the version
+ // string is invalid
+ return "$dependencyName does not have a valid version string.";
+ }
+ // Check if the constraint actually matches...
+ if (
+ !$this->versionParser->parseConstraints( $constraint )->matches( $installedVersion )
+ ) {
+ return "{$checkedExt} is not compatible with the current "
+ . "installed version of {$dependencyName} "
+ . "({$this->loaded[$dependencyName]['version']}), "
+ . "it requires: " . $constraint . '.';
+ }
+ }
+
+ return false;
+ }
+}
public $dateFormatStrings = [];
public $mExtendedSpecialPageAliases;
- protected $namespaceNames, $mNamespaceIds, $namespaceAliases;
+ /** @var array|null */
+ protected $namespaceNames;
+ protected $mNamespaceIds, $namespaceAliases;
/**
* ReplacementArray object caches
if ( is_null( $this->namespaceNames ) ) {
global $wgMetaNamespace, $wgMetaNamespaceTalk, $wgExtraNamespaces;
- $this->namespaceNames = self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
$validNamespaces = MWNamespace::getCanonicalNamespaces();
- /** @suppress PhanTypeInvalidLeftOperand */
- $this->namespaceNames = $wgExtraNamespaces + $this->namespaceNames + $validNamespaces;
+ $this->namespaceNames = $wgExtraNamespaces +
+ self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
+ $this->namespaceNames += $validNamespaces;
$this->namespaceNames[NS_PROJECT] = $wgMetaNamespace;
if ( $wgMetaNamespaceTalk ) {
</p>
!! end
+!! test
+T146304: Don't break template parsing if language converter markup is in the parameter.
+!! options
+language=sr variant=sr-ec
+!! wikitext
+{{echo|-{R|foo}-}}
+!! html/php
+<p>foo
+</p>
+!! end
+
# FIXME: This test is currently broken in the PHP parser (bug 52661)
!! test
Don't break image parsing if language converter markup is in the caption.
+++ /dev/null
-<?php
-
-/**
- * @covers CoreVersionChecker
- */
-class CoreVersionCheckerTest extends PHPUnit_Framework_TestCase {
- /**
- * @dataProvider provideCheck
- */
- public function testCheck( $coreVersion, $constraint, $expected ) {
- $checker = new CoreVersionChecker( $coreVersion );
- $this->assertEquals( $expected, $checker->check( $constraint ) );
- }
-
- public static function provideCheck() {
- return [
- // [ $wgVersion, constraint, expected ]
- [ '1.25alpha', '>= 1.26', false ],
- [ '1.25.0', '>= 1.26', false ],
- [ '1.26alpha', '>= 1.26', true ],
- [ '1.26alpha', '>= 1.26.0', true ],
- [ '1.26alpha', '>= 1.26.0-stable', false ],
- [ '1.26.0', '>= 1.26.0-stable', true ],
- [ '1.26.1', '>= 1.26.0-stable', true ],
- [ '1.27.1', '>= 1.26.0-stable', true ],
- [ '1.26alpha', '>= 1.26.1', false ],
- [ '1.26alpha', '>= 1.26alpha', true ],
- [ '1.26alpha', '>= 1.25', true ],
- [ '1.26.0-alpha.14', '>= 1.26.0-alpha.15', false ],
- [ '1.26.0-alpha.14', '>= 1.26.0-alpha.10', true ],
- [ '1.26.1', '>= 1.26.2, <=1.26.0', false ],
- [ '1.26.1', '^1.26.2', false ],
- // Accept anything for un-parsable version strings
- [ '1.26mwf14', '== 1.25alpha', true ],
- [ 'totallyinvalid', '== 1.0', true ],
- ];
- }
-}
--- /dev/null
+<?php
+
+/**
+ * @covers VersionChecker
+ */
+class VersionCheckerTest extends PHPUnit_Framework_TestCase {
+ /**
+ * @dataProvider provideCheck
+ */
+ public function testCheck( $coreVersion, $constraint, $expected ) {
+ $checker = new VersionChecker( $coreVersion );
+ $this->assertEquals( $expected, !(bool)$checker->checkArray( [
+ 'FakeExtension' => [
+ 'MediaWiki' => $constraint,
+ ],
+ ] )
+ );
+ }
+
+ public static function provideCheck() {
+ return [
+ // [ $wgVersion, constraint, expected ]
+ [ '1.25alpha', '>= 1.26', false ],
+ [ '1.25.0', '>= 1.26', false ],
+ [ '1.26alpha', '>= 1.26', true ],
+ [ '1.26alpha', '>= 1.26.0', true ],
+ [ '1.26alpha', '>= 1.26.0-stable', false ],
+ [ '1.26.0', '>= 1.26.0-stable', true ],
+ [ '1.26.1', '>= 1.26.0-stable', true ],
+ [ '1.27.1', '>= 1.26.0-stable', true ],
+ [ '1.26alpha', '>= 1.26.1', false ],
+ [ '1.26alpha', '>= 1.26alpha', true ],
+ [ '1.26alpha', '>= 1.25', true ],
+ [ '1.26.0-alpha.14', '>= 1.26.0-alpha.15', false ],
+ [ '1.26.0-alpha.14', '>= 1.26.0-alpha.10', true ],
+ [ '1.26.1', '>= 1.26.2, <=1.26.0', false ],
+ [ '1.26.1', '^1.26.2', false ],
+ // Accept anything for un-parsable version strings
+ [ '1.26mwf14', '== 1.25alpha', true ],
+ [ 'totallyinvalid', '== 1.0', true ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideType
+ */
+ public function testType( $given, $expected ) {
+ $checker = new VersionChecker( '1.0.0' );
+ $checker
+ ->setLoadedExtensionsAndSkins( [
+ 'FakeDependency' => [
+ 'version' => '1.0.0',
+ ],
+ ] );
+ $this->assertEquals( $expected, $checker->checkArray( [
+ 'FakeExtension' => $given,
+ ] )
+ );
+ }
+
+ public static function provideType() {
+ return [
+ // valid type
+ [
+ [
+ 'extensions' => [
+ 'FakeDependency' => '1.0.0'
+ ]
+ ],
+ []
+ ],
+ [
+ [
+ 'MediaWiki' => '1.0.0'
+ ],
+ []
+ ],
+ ];
+ }
+
+ /**
+ * Check, if a non-parsable version constraint does not throw an exception or
+ * returns any error message.
+ */
+ public function testInvalidConstraint() {
+ $checker = new VersionChecker( '1.0.0' );
+ $checker
+ ->setLoadedExtensionsAndSkins( [
+ 'FakeDependency' => [
+ 'version' => 'not really valid',
+ ],
+ ] );
+ $this->assertEquals( [ "FakeDependency does not have a valid version string." ],
+ $checker->checkArray( [
+ 'FakeExtension' => [
+ 'extensions' => [
+ 'FakeDependency' => '1.24.3',
+ ],
+ ],
+ ] )
+ );
+
+ $checker = new VersionChecker( '1.0.0' );
+ $checker
+ ->setLoadedExtensionsAndSkins( [
+ 'FakeDependency' => [
+ 'version' => '1.24.3',
+ ],
+ ] );
+
+ $this->setExpectedException( 'UnexpectedValueException' );
+ $checker->checkArray( [
+ 'FakeExtension' => [
+ 'FakeDependency' => 'not really valid',
+ ]
+ ] );
+ }
+}