2012-01-09 22:33:00 +00:00
|
|
|
<?php
|
|
|
|
|
/**
|
2013-05-24 12:56:06 +00:00
|
|
|
* Helper code for the MediaWiki parser test suite. Some code is duplicated
|
|
|
|
|
* in PHPUnit's NewParserTests.php, so you'll probably want to update both
|
|
|
|
|
* at the same time.
|
2012-10-02 20:24:33 +00:00
|
|
|
*
|
|
|
|
|
* Copyright © 2004, 2010 Brion Vibber <brion@pobox.com>
|
2014-03-20 15:45:01 +00:00
|
|
|
* https://www.mediawiki.org/
|
2012-10-02 20:24:33 +00:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*
|
2012-01-09 22:33:00 +00:00
|
|
|
* @todo Make this more independent of the configuration (and if possible the database)
|
|
|
|
|
* @todo document
|
|
|
|
|
* @file
|
|
|
|
|
* @ingroup Testing
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @ingroup Testing
|
|
|
|
|
*/
|
|
|
|
|
class ParserTest {
|
|
|
|
|
/**
|
2013-10-22 23:50:38 +00:00
|
|
|
* @var bool $color whereas output should be colorized
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private $color;
|
|
|
|
|
|
|
|
|
|
/**
|
2013-10-22 23:50:38 +00:00
|
|
|
* @var bool $showOutput Show test output
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private $showOutput;
|
|
|
|
|
|
|
|
|
|
/**
|
2013-10-22 23:50:38 +00:00
|
|
|
* @var bool $useTemporaryTables Use temporary tables for the temporary database
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private $useTemporaryTables = true;
|
|
|
|
|
|
|
|
|
|
/**
|
2013-10-22 23:50:38 +00:00
|
|
|
* @var bool $databaseSetupDone True if the database has been set up
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private $databaseSetupDone = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Our connection to the database
|
|
|
|
|
* @var DatabaseBase
|
|
|
|
|
*/
|
|
|
|
|
private $db;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Database clone helper
|
|
|
|
|
* @var CloneDatabase
|
|
|
|
|
*/
|
|
|
|
|
private $dbClone;
|
|
|
|
|
|
2013-12-18 17:56:15 +00:00
|
|
|
/**
|
|
|
|
|
* @var DjVuSupport
|
|
|
|
|
*/
|
|
|
|
|
private $djVuSupport;
|
|
|
|
|
|
2014-05-18 07:17:25 +00:00
|
|
|
/**
|
|
|
|
|
* @var TidySupport
|
|
|
|
|
*/
|
|
|
|
|
private $tidySupport;
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
private $maxFuzzTestLength = 300;
|
|
|
|
|
private $fuzzSeed = 0;
|
|
|
|
|
private $memoryLimit = 50;
|
|
|
|
|
private $uploadDir = null;
|
|
|
|
|
|
|
|
|
|
public $regex = "";
|
|
|
|
|
private $savedGlobals = array();
|
2013-02-14 11:22:13 +00:00
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
/**
|
|
|
|
|
* Sets terminal colorization and diff/quick modes depending on OS and
|
|
|
|
|
* command-line options (--color and --quick).
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param array $options
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
public function __construct( $options = array() ) {
|
|
|
|
|
# Only colorize output if stdout is a terminal.
|
|
|
|
|
$this->color = !wfIsWindows() && Maintenance::posix_isatty( 1 );
|
|
|
|
|
|
|
|
|
|
if ( isset( $options['color'] ) ) {
|
2013-02-14 11:22:13 +00:00
|
|
|
switch ( $options['color'] ) {
|
|
|
|
|
case 'no':
|
|
|
|
|
$this->color = false;
|
|
|
|
|
break;
|
|
|
|
|
case 'yes':
|
|
|
|
|
default:
|
|
|
|
|
$this->color = true;
|
|
|
|
|
break;
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->term = $this->color
|
|
|
|
|
? new AnsiTermColorer()
|
|
|
|
|
: new DummyTermColorer();
|
|
|
|
|
|
|
|
|
|
$this->showDiffs = !isset( $options['quick'] );
|
|
|
|
|
$this->showProgress = !isset( $options['quiet'] );
|
|
|
|
|
$this->showFailure = !(
|
|
|
|
|
isset( $options['quiet'] )
|
2013-02-14 11:22:13 +00:00
|
|
|
&& ( isset( $options['record'] )
|
2012-01-09 22:33:00 +00:00
|
|
|
|| isset( $options['compare'] ) ) ); // redundant output
|
|
|
|
|
|
|
|
|
|
$this->showOutput = isset( $options['show-output'] );
|
|
|
|
|
|
|
|
|
|
if ( isset( $options['filter'] ) ) {
|
|
|
|
|
$options['regex'] = $options['filter'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isset( $options['regex'] ) ) {
|
|
|
|
|
if ( isset( $options['record'] ) ) {
|
|
|
|
|
echo "Warning: --record cannot be used with --regex, disabling --record\n";
|
|
|
|
|
unset( $options['record'] );
|
|
|
|
|
}
|
|
|
|
|
$this->regex = $options['regex'];
|
|
|
|
|
} else {
|
|
|
|
|
# Matches anything
|
|
|
|
|
$this->regex = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->setupRecorder( $options );
|
|
|
|
|
$this->keepUploads = isset( $options['keep-uploads'] );
|
|
|
|
|
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
if ( $this->keepUploads ) {
|
|
|
|
|
$this->uploadDir = wfTempDir() . '/mwParser-images';
|
|
|
|
|
} else {
|
|
|
|
|
$this->uploadDir = wfTempDir() . "/mwParser-" . mt_rand() . "-images";
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( isset( $options['seed'] ) ) {
|
|
|
|
|
$this->fuzzSeed = intval( $options['seed'] ) - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->runDisabled = isset( $options['run-disabled'] );
|
2013-02-23 04:26:08 +00:00
|
|
|
$this->runParsoid = isset( $options['run-parsoid'] );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
2013-12-18 17:56:15 +00:00
|
|
|
$this->djVuSupport = new DjVuSupport();
|
2014-05-18 07:17:25 +00:00
|
|
|
$this->tidySupport = new TidySupport();
|
|
|
|
|
if ( !$this->tidySupport->isEnabled() ) {
|
|
|
|
|
echo "Warning: tidy is not installed, skipping some tests\n";
|
|
|
|
|
}
|
2013-12-18 17:56:15 +00:00
|
|
|
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
if ( !extension_loaded( 'gd' ) ) {
|
|
|
|
|
echo "Warning: GD extension is not present, thumbnailing tests will probably fail\n";
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
$this->hooks = array();
|
|
|
|
|
$this->functionHooks = array();
|
2014-06-20 15:36:08 +00:00
|
|
|
$this->transparentHooks = array();
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
$this->setUp();
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
function setUp() {
|
2012-01-09 22:33:00 +00:00
|
|
|
global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
|
2015-05-19 21:47:33 +00:00
|
|
|
$wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory,
|
2013-10-02 19:28:37 +00:00
|
|
|
$wgExtraNamespaces, $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
|
2014-07-21 02:35:50 +00:00
|
|
|
$wgExtraInterlanguageLinkPrefixes, $wgLocalInterwikis,
|
2012-01-09 22:33:00 +00:00
|
|
|
$parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
|
2013-05-07 23:32:21 +00:00
|
|
|
$wgArticlePath, $wgScript, $wgStylePath, $wgExtensionAssetsPath,
|
2012-03-20 00:28:30 +00:00
|
|
|
$wgMainCacheType, $wgMessageCacheType, $wgParserCacheType, $wgLockManagers;
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
$wgScript = '/index.php';
|
|
|
|
|
$wgScriptPath = '/';
|
|
|
|
|
$wgArticlePath = '/wiki/$1';
|
|
|
|
|
$wgStylePath = '/skins';
|
|
|
|
|
$wgExtensionAssetsPath = '/extensions';
|
|
|
|
|
$wgThumbnailScriptPath = false;
|
2012-03-20 00:28:30 +00:00
|
|
|
$wgLockManagers = array( array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'name' => 'fsLockManager',
|
|
|
|
|
'class' => 'FSLockManager',
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
'lockDirectory' => $this->uploadDir . '/lockdir',
|
2013-02-08 18:23:36 +00:00
|
|
|
), array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'name' => 'nullLockManager',
|
|
|
|
|
'class' => 'NullLockManager',
|
2012-03-20 00:28:30 +00:00
|
|
|
) );
|
2012-01-09 22:33:00 +00:00
|
|
|
$wgLocalFileRepo = array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'class' => 'LocalRepo',
|
|
|
|
|
'name' => 'local',
|
|
|
|
|
'url' => 'http://example.com/images',
|
|
|
|
|
'hashLevels' => 2,
|
2012-01-09 22:33:00 +00:00
|
|
|
'transformVia404' => false,
|
2013-02-14 11:22:13 +00:00
|
|
|
'backend' => new FSFileBackend( array(
|
|
|
|
|
'name' => 'local-backend',
|
2013-12-03 20:55:44 +00:00
|
|
|
'wikiId' => wfWikiId(),
|
2012-01-09 22:33:00 +00:00
|
|
|
'containerPaths' => array(
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
'local-public' => $this->uploadDir . '/public',
|
|
|
|
|
'local-thumb' => $this->uploadDir . '/thumb',
|
|
|
|
|
'local-temp' => $this->uploadDir . '/temp',
|
|
|
|
|
'local-deleted' => $this->uploadDir . '/deleted',
|
2012-01-09 22:33:00 +00:00
|
|
|
)
|
|
|
|
|
) )
|
|
|
|
|
);
|
|
|
|
|
$wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
|
|
|
|
|
$wgNamespaceAliases['Image'] = NS_FILE;
|
|
|
|
|
$wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
|
2013-10-02 19:28:37 +00:00
|
|
|
# add a namespace shadowing a interwiki link, to test
|
|
|
|
|
# proper precedence when resolving links. (bug 51680)
|
|
|
|
|
$wgExtraNamespaces[100] = 'MemoryAlpha';
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
// XXX: tests won't run without this (for CACHE_DB)
|
|
|
|
|
if ( $wgMainCacheType === CACHE_DB ) {
|
|
|
|
|
$wgMainCacheType = CACHE_NONE;
|
|
|
|
|
}
|
|
|
|
|
if ( $wgMessageCacheType === CACHE_DB ) {
|
|
|
|
|
$wgMessageCacheType = CACHE_NONE;
|
|
|
|
|
}
|
|
|
|
|
if ( $wgParserCacheType === CACHE_DB ) {
|
|
|
|
|
$wgParserCacheType = CACHE_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeferredUpdates::clearPendingUpdates();
|
|
|
|
|
$wgMemc = wfGetMainCache(); // checks $wgMainCacheType
|
|
|
|
|
$messageMemc = wfGetMessageCacheStorage();
|
|
|
|
|
$parserMemc = wfGetParserCacheStorage();
|
|
|
|
|
|
|
|
|
|
$wgUser = new User;
|
|
|
|
|
$context = new RequestContext;
|
|
|
|
|
$wgLang = $context->getLanguage();
|
|
|
|
|
$wgOut = $context->getOutput();
|
|
|
|
|
$wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
|
|
|
|
|
$wgRequest = $context->getRequest();
|
|
|
|
|
|
|
|
|
|
if ( $wgStyleDirectory === false ) {
|
2013-02-14 11:22:13 +00:00
|
|
|
$wgStyleDirectory = "$IP/skins";
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
2014-07-21 02:35:50 +00:00
|
|
|
|
|
|
|
|
self::setupInterwikis();
|
|
|
|
|
$wgLocalInterwikis = array( 'local', 'mi' );
|
2014-06-26 21:50:46 +00:00
|
|
|
// "extra language links"
|
|
|
|
|
// see https://gerrit.wikimedia.org/r/111390
|
|
|
|
|
array_push( $wgExtraInterlanguageLinkPrefixes, 'mul' );
|
2013-05-20 13:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert hardcoded interwiki in the lookup table.
|
|
|
|
|
*
|
|
|
|
|
* This function insert a set of well known interwikis that are used in
|
|
|
|
|
* the parser tests. They can be considered has fixtures are injected in
|
|
|
|
|
* the interwiki cache by using the 'InterwikiLoadPrefix' hook.
|
|
|
|
|
* Since we are not interested in looking up interwikis in the database,
|
|
|
|
|
* the hook completely replace the existing mechanism (hook returns false).
|
|
|
|
|
*/
|
|
|
|
|
public static function setupInterwikis() {
|
|
|
|
|
# Hack: insert a few Wikipedia in-project interwiki prefixes,
|
|
|
|
|
# for testing inter-language links
|
|
|
|
|
Hooks::register( 'InterwikiLoadPrefix', function ( $prefix, &$iwData ) {
|
|
|
|
|
static $testInterwikis = array(
|
2014-07-21 02:35:50 +00:00
|
|
|
'local' => array(
|
|
|
|
|
'iw_url' => 'http://doesnt.matter.org/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 0 ),
|
2013-05-20 13:21:02 +00:00
|
|
|
'wikipedia' => array(
|
|
|
|
|
'iw_url' => 'http://en.wikipedia.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 0 ),
|
|
|
|
|
'meatball' => array(
|
|
|
|
|
'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 0 ),
|
2013-10-02 19:28:37 +00:00
|
|
|
'memoryalpha' => array(
|
|
|
|
|
'iw_url' => 'http://www.memory-alpha.org/en/index.php/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 0 ),
|
2013-05-20 13:21:02 +00:00
|
|
|
'zh' => array(
|
|
|
|
|
'iw_url' => 'http://zh.wikipedia.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 1 ),
|
|
|
|
|
'es' => array(
|
|
|
|
|
'iw_url' => 'http://es.wikipedia.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 1 ),
|
|
|
|
|
'fr' => array(
|
|
|
|
|
'iw_url' => 'http://fr.wikipedia.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 1 ),
|
|
|
|
|
'ru' => array(
|
|
|
|
|
'iw_url' => 'http://ru.wikipedia.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 1 ),
|
2014-07-21 02:35:50 +00:00
|
|
|
'mi' => array(
|
|
|
|
|
'iw_url' => 'http://mi.wikipedia.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 1 ),
|
2014-06-26 21:50:46 +00:00
|
|
|
'mul' => array(
|
|
|
|
|
'iw_url' => 'http://wikisource.org/wiki/$1',
|
|
|
|
|
'iw_api' => '',
|
|
|
|
|
'iw_wikiid' => '',
|
|
|
|
|
'iw_local' => 1 ),
|
2013-05-20 13:21:02 +00:00
|
|
|
);
|
2013-08-24 15:06:25 +00:00
|
|
|
if ( array_key_exists( $prefix, $testInterwikis ) ) {
|
2013-05-20 13:21:02 +00:00
|
|
|
$iwData = $testInterwikis[$prefix];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We only want to rely on the above fixtures
|
|
|
|
|
return false;
|
|
|
|
|
} );// hooks::register
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
2013-08-22 18:38:50 +00:00
|
|
|
/**
|
|
|
|
|
* Remove the hardcoded interwiki lookup table.
|
|
|
|
|
*/
|
|
|
|
|
public static function tearDownInterwikis() {
|
|
|
|
|
Hooks::clear( 'InterwikiLoadPrefix' );
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-14 11:22:13 +00:00
|
|
|
public function setupRecorder( $options ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( isset( $options['record'] ) ) {
|
|
|
|
|
$this->recorder = new DbTestRecorder( $this );
|
|
|
|
|
$this->recorder->version = isset( $options['setversion'] ) ?
|
2013-02-14 11:22:13 +00:00
|
|
|
$options['setversion'] : SpecialVersion::getVersion();
|
2012-01-09 22:33:00 +00:00
|
|
|
} elseif ( isset( $options['compare'] ) ) {
|
|
|
|
|
$this->recorder = new DbTestPreviewer( $this );
|
|
|
|
|
} else {
|
|
|
|
|
$this->recorder = new TestRecorder( $this );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove last character if it is a newline
|
|
|
|
|
* @group utility
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $s
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return string
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
2013-02-12 21:32:09 +00:00
|
|
|
public static function chomp( $s ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( substr( $s, -1 ) === "\n" ) {
|
|
|
|
|
return substr( $s, 0, -1 );
|
2013-02-14 11:22:13 +00:00
|
|
|
} else {
|
2012-01-09 22:33:00 +00:00
|
|
|
return $s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Run a fuzz test series
|
|
|
|
|
* Draw input from a set of test files
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param array $filenames
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
function fuzzTest( $filenames ) {
|
|
|
|
|
$GLOBALS['wgContLang'] = Language::factory( 'en' );
|
|
|
|
|
$dict = $this->getFuzzInput( $filenames );
|
|
|
|
|
$dictSize = strlen( $dict );
|
|
|
|
|
$logMaxLength = log( $this->maxFuzzTestLength );
|
|
|
|
|
$this->setupDatabase();
|
|
|
|
|
ini_set( 'memory_limit', $this->memoryLimit * 1048576 );
|
|
|
|
|
|
|
|
|
|
$numTotal = 0;
|
|
|
|
|
$numSuccess = 0;
|
|
|
|
|
$user = new User;
|
|
|
|
|
$opts = ParserOptions::newFromUser( $user );
|
|
|
|
|
$title = Title::makeTitle( NS_MAIN, 'Parser_test' );
|
|
|
|
|
|
|
|
|
|
while ( true ) {
|
|
|
|
|
// Generate test input
|
|
|
|
|
mt_srand( ++$this->fuzzSeed );
|
|
|
|
|
$totalLength = mt_rand( 1, $this->maxFuzzTestLength );
|
|
|
|
|
$input = '';
|
|
|
|
|
|
|
|
|
|
while ( strlen( $input ) < $totalLength ) {
|
|
|
|
|
$logHairLength = mt_rand( 0, 1000000 ) / 1000000 * $logMaxLength;
|
|
|
|
|
$hairLength = min( intval( exp( $logHairLength ) ), $dictSize );
|
|
|
|
|
$offset = mt_rand( 0, $dictSize - $hairLength );
|
|
|
|
|
$input .= substr( $dict, $offset, $hairLength );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->setupGlobals();
|
|
|
|
|
$parser = $this->getParser();
|
|
|
|
|
|
|
|
|
|
// Run the test
|
|
|
|
|
try {
|
|
|
|
|
$parser->parse( $input, $title, $opts );
|
|
|
|
|
$fail = false;
|
|
|
|
|
} catch ( Exception $exception ) {
|
|
|
|
|
$fail = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $fail ) {
|
|
|
|
|
echo "Test failed with seed {$this->fuzzSeed}\n";
|
|
|
|
|
echo "Input:\n";
|
|
|
|
|
printf( "string(%d) \"%s\"\n\n", strlen( $input ), $input );
|
|
|
|
|
echo "$exception\n";
|
|
|
|
|
} else {
|
|
|
|
|
$numSuccess++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$numTotal++;
|
|
|
|
|
$this->teardownGlobals();
|
|
|
|
|
$parser->__destruct();
|
|
|
|
|
|
|
|
|
|
if ( $numTotal % 100 == 0 ) {
|
|
|
|
|
$usage = intval( memory_get_usage( true ) / $this->memoryLimit / 1048576 * 100 );
|
|
|
|
|
echo "{$this->fuzzSeed}: $numSuccess/$numTotal (mem: $usage%)\n";
|
|
|
|
|
if ( $usage > 90 ) {
|
|
|
|
|
echo "Out of memory:\n";
|
|
|
|
|
$memStats = $this->getMemoryBreakdown();
|
|
|
|
|
|
|
|
|
|
foreach ( $memStats as $name => $usage ) {
|
|
|
|
|
echo "$name: $usage\n";
|
|
|
|
|
}
|
|
|
|
|
$this->abort();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get an input dictionary from a set of parser test files
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param array $filenames
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return string
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
function getFuzzInput( $filenames ) {
|
|
|
|
|
$dict = '';
|
|
|
|
|
|
|
|
|
|
foreach ( $filenames as $filename ) {
|
|
|
|
|
$contents = file_get_contents( $filename );
|
2014-04-24 09:15:42 +00:00
|
|
|
preg_match_all(
|
|
|
|
|
'/!!\s*(input|wikitext)\n(.*?)\n!!\s*(result|html|html\/\*|html\/php)/s',
|
|
|
|
|
$contents,
|
|
|
|
|
$matches
|
|
|
|
|
);
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
foreach ( $matches[1] as $match ) {
|
|
|
|
|
$dict .= $match . "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $dict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a memory usage breakdown
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return array
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
function getMemoryBreakdown() {
|
|
|
|
|
$memStats = array();
|
|
|
|
|
|
|
|
|
|
foreach ( $GLOBALS as $name => $value ) {
|
|
|
|
|
$memStats['$' . $name] = strlen( serialize( $value ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$classes = get_declared_classes();
|
|
|
|
|
|
|
|
|
|
foreach ( $classes as $class ) {
|
|
|
|
|
$rc = new ReflectionClass( $class );
|
|
|
|
|
$props = $rc->getStaticProperties();
|
|
|
|
|
$memStats[$class] = strlen( serialize( $props ) );
|
|
|
|
|
$methods = $rc->getMethods();
|
|
|
|
|
|
|
|
|
|
foreach ( $methods as $method ) {
|
|
|
|
|
$memStats[$class] += strlen( serialize( $method->getStaticVariables() ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$functions = get_defined_functions();
|
|
|
|
|
|
|
|
|
|
foreach ( $functions['user'] as $function ) {
|
|
|
|
|
$rf = new ReflectionFunction( $function );
|
|
|
|
|
$memStats["$function()"] = strlen( serialize( $rf->getStaticVariables() ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
asort( $memStats );
|
|
|
|
|
|
|
|
|
|
return $memStats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function abort() {
|
|
|
|
|
$this->abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Run a series of tests listed in the given text files.
|
|
|
|
|
* Each test consists of a brief description, wikitext input,
|
|
|
|
|
* and the expected HTML output.
|
|
|
|
|
*
|
|
|
|
|
* Prints status updates on stdout and counts up the total
|
|
|
|
|
* number and percentage of passed tests.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param array $filenames Array of strings
|
|
|
|
|
* @return bool True if passed all tests, false if any tests failed.
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
public function runTestsFromFiles( $filenames ) {
|
|
|
|
|
$ok = false;
|
2013-07-30 13:12:12 +00:00
|
|
|
|
|
|
|
|
// be sure, ParserTest::addArticle has correct language set,
|
|
|
|
|
// so that system messages gets into the right language cache
|
|
|
|
|
$GLOBALS['wgLanguageCode'] = 'en';
|
2012-01-09 22:33:00 +00:00
|
|
|
$GLOBALS['wgContLang'] = Language::factory( 'en' );
|
2013-07-30 13:12:12 +00:00
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
$this->recorder->start();
|
|
|
|
|
try {
|
|
|
|
|
$this->setupDatabase();
|
|
|
|
|
$ok = true;
|
|
|
|
|
|
|
|
|
|
foreach ( $filenames as $filename ) {
|
|
|
|
|
$tests = new TestFileIterator( $filename, $this );
|
|
|
|
|
$ok = $this->runTests( $tests ) && $ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->teardownDatabase();
|
|
|
|
|
$this->recorder->report();
|
2013-02-14 11:22:13 +00:00
|
|
|
} catch ( DBError $e ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
echo $e->getMessage();
|
|
|
|
|
}
|
|
|
|
|
$this->recorder->end();
|
|
|
|
|
|
|
|
|
|
return $ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function runTests( $tests ) {
|
|
|
|
|
$ok = true;
|
|
|
|
|
|
|
|
|
|
foreach ( $tests as $t ) {
|
|
|
|
|
$result =
|
|
|
|
|
$this->runTest( $t['test'], $t['input'], $t['result'], $t['options'], $t['config'] );
|
|
|
|
|
$ok = $ok && $result;
|
|
|
|
|
$this->recorder->record( $t['test'], $result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $this->showProgress ) {
|
|
|
|
|
print "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a Parser object
|
2013-08-22 22:22:03 +00:00
|
|
|
*
|
|
|
|
|
* @param string $preprocessor
|
|
|
|
|
* @return Parser
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
function getParser( $preprocessor = null ) {
|
|
|
|
|
global $wgParserConf;
|
|
|
|
|
|
|
|
|
|
$class = $wgParserConf['class'];
|
|
|
|
|
$parser = new $class( array( 'preprocessorClass' => $preprocessor ) + $wgParserConf );
|
|
|
|
|
|
|
|
|
|
foreach ( $this->hooks as $tag => $callback ) {
|
|
|
|
|
$parser->setHook( $tag, $callback );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ( $this->functionHooks as $tag => $bits ) {
|
|
|
|
|
list( $callback, $flags ) = $bits;
|
|
|
|
|
$parser->setFunctionHook( $tag, $callback, $flags );
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-20 15:36:08 +00:00
|
|
|
foreach ( $this->transparentHooks as $tag => $callback ) {
|
|
|
|
|
$parser->setTransparentTagHook( $tag, $callback );
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-12 22:47:31 +00:00
|
|
|
Hooks::run( 'ParserTestParser', array( &$parser ) );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
return $parser;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Run a given wikitext input through a freshly-constructed wiki parser,
|
|
|
|
|
* and compare the output against the expected results.
|
|
|
|
|
* Prints status and explanatory messages to stdout.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $desc Test's description
|
|
|
|
|
* @param string $input Wikitext to try rendering
|
|
|
|
|
* @param string $result Result to output
|
|
|
|
|
* @param array $opts Test's options
|
|
|
|
|
* @param string $config Overrides for global variables, one per line
|
|
|
|
|
* @return bool
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
public function runTest( $desc, $input, $result, $opts, $config ) {
|
|
|
|
|
if ( $this->showProgress ) {
|
|
|
|
|
$this->showTesting( $desc );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$opts = $this->parseOptions( $opts );
|
|
|
|
|
$context = $this->setupGlobals( $opts, $config );
|
|
|
|
|
|
|
|
|
|
$user = $context->getUser();
|
|
|
|
|
$options = ParserOptions::newFromContext( $context );
|
|
|
|
|
|
2013-12-18 17:56:15 +00:00
|
|
|
if ( isset( $opts['djvu'] ) ) {
|
|
|
|
|
if ( !$this->djVuSupport->isEnabled() ) {
|
|
|
|
|
return $this->showSkipped();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-16 18:26:52 +00:00
|
|
|
if ( isset( $opts['tidy'] ) ) {
|
|
|
|
|
if ( !$this->tidySupport->isEnabled() ) {
|
|
|
|
|
return $this->showSkipped();
|
|
|
|
|
} else {
|
|
|
|
|
$options->setTidy( true );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( isset( $opts['title'] ) ) {
|
|
|
|
|
$titleText = $opts['title'];
|
2013-02-14 11:22:13 +00:00
|
|
|
} else {
|
2012-01-09 22:33:00 +00:00
|
|
|
$titleText = 'Parser test';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$local = isset( $opts['local'] );
|
|
|
|
|
$preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null;
|
|
|
|
|
$parser = $this->getParser( $preprocessor );
|
|
|
|
|
$title = Title::newFromText( $titleText );
|
|
|
|
|
|
|
|
|
|
if ( isset( $opts['pst'] ) ) {
|
|
|
|
|
$out = $parser->preSaveTransform( $input, $title, $user, $options );
|
|
|
|
|
} elseif ( isset( $opts['msg'] ) ) {
|
|
|
|
|
$out = $parser->transformMsg( $input, $options, $title );
|
|
|
|
|
} elseif ( isset( $opts['section'] ) ) {
|
|
|
|
|
$section = $opts['section'];
|
|
|
|
|
$out = $parser->getSection( $input, $section );
|
|
|
|
|
} elseif ( isset( $opts['replace'] ) ) {
|
|
|
|
|
$section = $opts['replace'][0];
|
|
|
|
|
$replace = $opts['replace'][1];
|
|
|
|
|
$out = $parser->replaceSection( $input, $section, $replace );
|
|
|
|
|
} elseif ( isset( $opts['comment'] ) ) {
|
|
|
|
|
$out = Linker::formatComment( $input, $title, $local );
|
|
|
|
|
} elseif ( isset( $opts['preload'] ) ) {
|
2013-03-22 16:44:34 +00:00
|
|
|
$out = $parser->getPreloadText( $input, $title, $options );
|
2012-01-09 22:33:00 +00:00
|
|
|
} else {
|
|
|
|
|
$output = $parser->parse( $input, $title, $options, true, true, 1337 );
|
2013-08-22 22:22:03 +00:00
|
|
|
$output->setTOCEnabled( !isset( $opts['notoc'] ) );
|
2012-01-09 22:33:00 +00:00
|
|
|
$out = $output->getText();
|
2014-05-18 07:17:25 +00:00
|
|
|
if ( isset( $opts['tidy'] ) ) {
|
2014-08-25 17:16:36 +00:00
|
|
|
$out = preg_replace( '/\s+$/', '', $out );
|
2014-05-18 07:17:25 +00:00
|
|
|
}
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
if ( isset( $opts['showtitle'] ) ) {
|
|
|
|
|
if ( $output->getTitleText() ) {
|
|
|
|
|
$title = $output->getTitleText();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$out = "$title\n$out";
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-02 20:08:43 +00:00
|
|
|
if ( isset( $opts['showindicators'] ) ) {
|
|
|
|
|
$indicators = '';
|
|
|
|
|
foreach ( $output->getIndicators() as $id => $content ) {
|
|
|
|
|
$indicators .= "$id=$content\n";
|
|
|
|
|
}
|
|
|
|
|
$out = $indicators . $out;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( isset( $opts['ill'] ) ) {
|
2014-05-18 07:17:25 +00:00
|
|
|
$out = implode( ' ', $output->getLanguageLinks() );
|
2012-01-09 22:33:00 +00:00
|
|
|
} elseif ( isset( $opts['cat'] ) ) {
|
|
|
|
|
$outputPage = $context->getOutput();
|
|
|
|
|
$outputPage->addCategoryLinks( $output->getCategories() );
|
|
|
|
|
$cats = $outputPage->getCategoryLinks();
|
|
|
|
|
|
|
|
|
|
if ( isset( $cats['normal'] ) ) {
|
2014-05-18 07:17:25 +00:00
|
|
|
$out = implode( ' ', $cats['normal'] );
|
2012-01-09 22:33:00 +00:00
|
|
|
} else {
|
|
|
|
|
$out = '';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->teardownGlobals();
|
2013-03-19 14:00:44 +00:00
|
|
|
|
|
|
|
|
$testResult = new ParserTestResult( $desc );
|
|
|
|
|
$testResult->expected = $result;
|
|
|
|
|
$testResult->actual = $out;
|
|
|
|
|
|
|
|
|
|
return $this->showTestResult( $testResult );
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-03-19 14:00:44 +00:00
|
|
|
* Refactored in 1.22 to use ParserTestResult
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param ParserTestResult $testResult
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return bool
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
2013-03-19 14:00:44 +00:00
|
|
|
function showTestResult( ParserTestResult $testResult ) {
|
|
|
|
|
if ( $testResult->isSuccess() ) {
|
|
|
|
|
$this->showSuccess( $testResult );
|
2012-01-09 22:33:00 +00:00
|
|
|
return true;
|
|
|
|
|
} else {
|
2013-03-19 14:00:44 +00:00
|
|
|
$this->showFailure( $testResult );
|
2012-01-09 22:33:00 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Use a regex to find out the value of an option
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $key Name of option val to retrieve
|
|
|
|
|
* @param array $opts Options array to look in
|
|
|
|
|
* @param mixed $default Default value returned if not found
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return mixed
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private static function getOptionValue( $key, $opts, $default ) {
|
|
|
|
|
$key = strtolower( $key );
|
|
|
|
|
|
|
|
|
|
if ( isset( $opts[$key] ) ) {
|
|
|
|
|
return $opts[$key];
|
|
|
|
|
} else {
|
|
|
|
|
return $default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function parseOptions( $instring ) {
|
|
|
|
|
$opts = array();
|
|
|
|
|
// foo
|
|
|
|
|
// foo=bar
|
|
|
|
|
// foo="bar baz"
|
|
|
|
|
// foo=[[bar baz]]
|
|
|
|
|
// foo=bar,"baz quux"
|
2014-02-19 17:14:08 +00:00
|
|
|
// foo={...json...}
|
|
|
|
|
$defs = '(?(DEFINE)
|
|
|
|
|
(?<qstr> # Quoted string
|
|
|
|
|
"
|
|
|
|
|
(?:[^\\\\"] | \\\\.)*
|
|
|
|
|
"
|
|
|
|
|
)
|
|
|
|
|
(?<json>
|
|
|
|
|
\{ # Open bracket
|
|
|
|
|
(?:
|
|
|
|
|
[^"{}] | # Not a quoted string or object, or
|
|
|
|
|
(?&qstr) | # A quoted string, or
|
|
|
|
|
(?&json) # A json object (recursively)
|
|
|
|
|
)*
|
|
|
|
|
\} # Close bracket
|
|
|
|
|
)
|
2015-09-26 19:48:17 +00:00
|
|
|
(?<value>
|
2014-02-19 17:14:08 +00:00
|
|
|
(?:
|
|
|
|
|
(?&qstr) # Quoted val
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
|
\[\[
|
|
|
|
|
[^]]* # Link target
|
|
|
|
|
\]\]
|
|
|
|
|
|
|
|
|
|
|
[\w-]+ # Plain word
|
2014-02-19 17:14:08 +00:00
|
|
|
|
|
|
|
|
|
(?&json) # JSON object
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)';
|
2014-03-20 18:59:20 +00:00
|
|
|
$regex = '/' . $defs . '\b
|
2014-02-19 17:14:08 +00:00
|
|
|
(?<k>[\w-]+) # Key
|
|
|
|
|
\b
|
|
|
|
|
(?:\s*
|
|
|
|
|
= # First sub-value
|
|
|
|
|
\s*
|
|
|
|
|
(?<v>
|
|
|
|
|
(?&value)
|
|
|
|
|
(?:\s*
|
|
|
|
|
, # Sub-vals 1..N
|
|
|
|
|
\s*
|
|
|
|
|
(?&value)
|
|
|
|
|
)*
|
2012-01-09 22:33:00 +00:00
|
|
|
)
|
|
|
|
|
)?
|
|
|
|
|
/x';
|
2014-03-20 18:59:20 +00:00
|
|
|
$valueregex = '/' . $defs . '(?&value)/x';
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
if ( preg_match_all( $regex, $instring, $matches, PREG_SET_ORDER ) ) {
|
|
|
|
|
foreach ( $matches as $bits ) {
|
2014-07-21 12:47:42 +00:00
|
|
|
$key = strtolower( $bits['k'] );
|
|
|
|
|
if ( !isset( $bits['v'] ) ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
$opts[$key] = true;
|
|
|
|
|
} else {
|
2014-07-21 12:47:42 +00:00
|
|
|
preg_match_all( $valueregex, $bits['v'], $vmatches );
|
2014-02-19 17:14:08 +00:00
|
|
|
$opts[$key] = array_map( array( $this, 'cleanupOption' ), $vmatches[0] );
|
|
|
|
|
if ( count( $opts[$key] ) == 1 ) {
|
|
|
|
|
$opts[$key] = $opts[$key][0];
|
|
|
|
|
}
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $opts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function cleanupOption( $opt ) {
|
|
|
|
|
if ( substr( $opt, 0, 1 ) == '"' ) {
|
2014-02-19 17:14:08 +00:00
|
|
|
return stripcslashes( substr( $opt, 1, -1 ) );
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( substr( $opt, 0, 2 ) == '[[' ) {
|
|
|
|
|
return substr( $opt, 2, -2 );
|
|
|
|
|
}
|
2014-02-19 17:14:08 +00:00
|
|
|
|
|
|
|
|
if ( substr( $opt, 0, 1 ) == '{' ) {
|
|
|
|
|
return FormatJson::decode( $opt, true );
|
|
|
|
|
}
|
2012-01-09 22:33:00 +00:00
|
|
|
return $opt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set up the global variables for a consistent environment for each test.
|
|
|
|
|
* Ideally this should replace the global configuration entirely.
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $opts
|
|
|
|
|
* @param string $config
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return RequestContext
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private function setupGlobals( $opts = '', $config = '' ) {
|
2014-05-18 07:17:25 +00:00
|
|
|
global $IP;
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
# Find out values for some special options.
|
|
|
|
|
$lang =
|
|
|
|
|
self::getOptionValue( 'language', $opts, 'en' );
|
|
|
|
|
$variant =
|
|
|
|
|
self::getOptionValue( 'variant', $opts, false );
|
|
|
|
|
$maxtoclevel =
|
|
|
|
|
self::getOptionValue( 'wgMaxTocLevel', $opts, 999 );
|
|
|
|
|
$linkHolderBatchSize =
|
|
|
|
|
self::getOptionValue( 'wgLinkHolderBatchSize', $opts, 1000 );
|
|
|
|
|
|
|
|
|
|
$settings = array(
|
2013-02-25 23:37:43 +00:00
|
|
|
'wgServer' => 'http://example.org',
|
2014-05-06 09:31:24 +00:00
|
|
|
'wgServerName' => 'example.org',
|
2012-01-09 22:33:00 +00:00
|
|
|
'wgScript' => '/index.php',
|
|
|
|
|
'wgScriptPath' => '/',
|
|
|
|
|
'wgArticlePath' => '/wiki/$1',
|
|
|
|
|
'wgActionPaths' => array(),
|
2013-02-08 18:23:36 +00:00
|
|
|
'wgLockManagers' => array( array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'name' => 'fsLockManager',
|
|
|
|
|
'class' => 'FSLockManager',
|
2012-03-20 00:28:30 +00:00
|
|
|
'lockDirectory' => $this->uploadDir . '/lockdir',
|
2013-02-08 18:23:36 +00:00
|
|
|
), array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'name' => 'nullLockManager',
|
|
|
|
|
'class' => 'NullLockManager',
|
2013-02-08 18:23:36 +00:00
|
|
|
) ),
|
2012-01-09 22:33:00 +00:00
|
|
|
'wgLocalFileRepo' => array(
|
|
|
|
|
'class' => 'LocalRepo',
|
|
|
|
|
'name' => 'local',
|
|
|
|
|
'url' => 'http://example.com/images',
|
|
|
|
|
'hashLevels' => 2,
|
|
|
|
|
'transformVia404' => false,
|
2013-02-14 11:22:13 +00:00
|
|
|
'backend' => new FSFileBackend( array(
|
|
|
|
|
'name' => 'local-backend',
|
2013-12-03 20:55:44 +00:00
|
|
|
'wikiId' => wfWikiId(),
|
2012-01-09 22:33:00 +00:00
|
|
|
'containerPaths' => array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'local-public' => $this->uploadDir,
|
|
|
|
|
'local-thumb' => $this->uploadDir . '/thumb',
|
|
|
|
|
'local-temp' => $this->uploadDir . '/temp',
|
2012-01-09 22:33:00 +00:00
|
|
|
'local-deleted' => $this->uploadDir . '/delete',
|
|
|
|
|
)
|
|
|
|
|
) )
|
|
|
|
|
),
|
|
|
|
|
'wgEnableUploads' => self::getOptionValue( 'wgEnableUploads', $opts, true ),
|
2014-08-08 19:44:01 +00:00
|
|
|
'wgUploadNavigationUrl' => false,
|
2012-01-09 22:33:00 +00:00
|
|
|
'wgStylePath' => '/skins',
|
|
|
|
|
'wgSitename' => 'MediaWiki',
|
|
|
|
|
'wgLanguageCode' => $lang,
|
|
|
|
|
'wgDBprefix' => $this->db->getType() != 'oracle' ? 'parsertest_' : 'pt_',
|
2013-07-10 22:10:14 +00:00
|
|
|
'wgRawHtml' => self::getOptionValue( 'wgRawHtml', $opts, false ),
|
2012-01-09 22:33:00 +00:00
|
|
|
'wgLang' => null,
|
|
|
|
|
'wgContLang' => null,
|
|
|
|
|
'wgNamespacesWithSubpages' => array( 0 => isset( $opts['subpage'] ) ),
|
|
|
|
|
'wgMaxTocLevel' => $maxtoclevel,
|
|
|
|
|
'wgCapitalLinks' => true,
|
|
|
|
|
'wgNoFollowLinks' => true,
|
|
|
|
|
'wgNoFollowDomainExceptions' => array(),
|
|
|
|
|
'wgThumbnailScriptPath' => false,
|
Initial stab at responsive images for screen densities.
* adds $wgResponsiveImages setting, defaulting to true, to enable the feature
* adds 'srcset' attribute with 1.5x and 2x URLs to image links and image thumbs
* adds jquery.hidpi plugin to check pixel density and implement partial 'srcset' polyfill
** $.devicePixelRatio() returns window.devicePixelRatio, with compat fallback for IE 10
** $().hidpi() performs a 'srcset' polyfill for browsers with no native 'srcset' support
* adds mediawiki.hidpi RL script to trigger hidpi loads after main images load
Note that this is a work in progress. There will be places where this doesn't yet work which output their imgs differently. If moving from a low to high-DPI screen on a MacBook Pro Retina display, you won't see images load until you reload.
Confirmed basic images and thumbs in wikitext appear to work in Safari 6, Chrome 21, Firefox 18 nightly on MacBook Pro Retina display, and IE 10 in Windows 8 at 150% zoom, 200% zoom, and 140% and 180%-ratio Metro tablet sizes.
Internally this is still a bit of a hack; Linker::makeImageLink and Linker::makeThumbLink explicitly ask for 1.5x and 2x scaled versions and insert their URLs, if different, into the original thumbnail object which (in default handler) outputs the srcset. This means that a number of places that handle images differently won't see the higher-resolution versions, such as <gallery> and the large thumbnail on the File: description page.
At some point we may wish to redo some of how the MediaHandler stuff works so that requesting a single thumbnail automatically produces the extra sizes in all circumstances. We might also consider outputting a 'srcset' or multiple src sizes in 'imageinfo' API requests, which would make ApiForeignRepo/InstantCommons more efficient. (Currently it has to make three requests for each image to get the three sizes.)
Change-Id: Id80ebd07a1a9f401a2c2bfeb21aae987e5aa863b
2012-09-18 07:18:50 +00:00
|
|
|
'wgUseImageResize' => true,
|
2013-05-24 12:56:06 +00:00
|
|
|
'wgSVGConverter' => 'null',
|
|
|
|
|
'wgSVGConverters' => array( 'null' => 'echo "1">$output' ),
|
2012-01-09 22:33:00 +00:00
|
|
|
'wgLocaltimezone' => 'UTC',
|
2013-07-10 22:10:14 +00:00
|
|
|
'wgAllowExternalImages' => self::getOptionValue( 'wgAllowExternalImages', $opts, true ),
|
2014-03-19 18:51:21 +00:00
|
|
|
'wgThumbLimits' => array( self::getOptionValue( 'thumbsize', $opts, 180 ) ),
|
2012-01-09 22:33:00 +00:00
|
|
|
'wgDefaultLanguageVariant' => $variant,
|
|
|
|
|
'wgVariantArticlePath' => false,
|
|
|
|
|
'wgGroupPermissions' => array( '*' => array(
|
|
|
|
|
'createaccount' => true,
|
2013-02-14 11:22:13 +00:00
|
|
|
'read' => true,
|
|
|
|
|
'edit' => true,
|
|
|
|
|
'createpage' => true,
|
|
|
|
|
'createtalk' => true,
|
2012-01-09 22:33:00 +00:00
|
|
|
) ),
|
|
|
|
|
'wgNamespaceProtection' => array( NS_MEDIAWIKI => 'editinterface' ),
|
|
|
|
|
'wgDefaultExternalStore' => array(),
|
|
|
|
|
'wgForeignFileRepos' => array(),
|
|
|
|
|
'wgLinkHolderBatchSize' => $linkHolderBatchSize,
|
|
|
|
|
'wgExperimentalHtmlIds' => false,
|
|
|
|
|
'wgExternalLinkTarget' => false,
|
|
|
|
|
'wgHtml5' => true,
|
|
|
|
|
'wgWellFormedXml' => true,
|
|
|
|
|
'wgAllowMicrodataAttributes' => true,
|
|
|
|
|
'wgAdaptiveMessageCache' => true,
|
|
|
|
|
'wgDisableLangConversion' => false,
|
|
|
|
|
'wgDisableTitleConversion' => false,
|
2014-05-18 07:17:25 +00:00
|
|
|
// Tidy options.
|
2015-03-16 18:26:52 +00:00
|
|
|
'wgUseTidy' => isset( $opts['tidy'] ),
|
2015-08-31 04:42:55 +00:00
|
|
|
'wgTidyConfig' => null,
|
2014-05-18 07:17:25 +00:00
|
|
|
'wgDebugTidy' => false,
|
2015-08-31 04:42:55 +00:00
|
|
|
'wgTidyConf' => $IP . '/includes/tidy/tidy.conf',
|
2014-05-18 07:17:25 +00:00
|
|
|
'wgTidyOpts' => '',
|
|
|
|
|
'wgTidyInternal' => $this->tidySupport->isInternal(),
|
2012-01-09 22:33:00 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ( $config ) {
|
|
|
|
|
$configLines = explode( "\n", $config );
|
|
|
|
|
|
|
|
|
|
foreach ( $configLines as $line ) {
|
|
|
|
|
list( $var, $value ) = explode( '=', $line, 2 );
|
|
|
|
|
|
|
|
|
|
$settings[$var] = eval( "return $value;" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->savedGlobals = array();
|
|
|
|
|
|
2012-08-20 14:55:28 +00:00
|
|
|
/** @since 1.20 */
|
2014-12-12 22:47:31 +00:00
|
|
|
Hooks::run( 'ParserTestGlobals', array( &$settings ) );
|
2012-08-20 14:55:28 +00:00
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
foreach ( $settings as $var => $val ) {
|
|
|
|
|
if ( array_key_exists( $var, $GLOBALS ) ) {
|
|
|
|
|
$this->savedGlobals[$var] = $GLOBALS[$var];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$GLOBALS[$var] = $val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$GLOBALS['wgContLang'] = Language::factory( $lang );
|
|
|
|
|
$GLOBALS['wgMemc'] = new EmptyBagOStuff;
|
|
|
|
|
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
$GLOBALS['wgLang'] = $context->getLanguage();
|
|
|
|
|
$GLOBALS['wgOut'] = $context->getOutput();
|
2014-03-19 18:51:21 +00:00
|
|
|
$GLOBALS['wgUser'] = $context->getUser();
|
2012-01-09 22:33:00 +00:00
|
|
|
|
2014-03-19 18:51:21 +00:00
|
|
|
// We (re)set $wgThumbLimits to a single-element array above.
|
|
|
|
|
$context->getUser()->setOption( 'thumbsize', 0 );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
global $wgHooks;
|
|
|
|
|
|
|
|
|
|
$wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
|
|
|
|
|
$wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
|
|
|
|
|
|
|
|
|
|
MagicWord::clearCache();
|
2015-08-31 04:42:55 +00:00
|
|
|
MWTidy::destroySingleton();
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
RepoGroup::destroySingleton();
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
return $context;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* List of temporary tables to create, without prefix.
|
|
|
|
|
* Some of these probably aren't necessary.
|
2014-08-25 16:50:35 +00:00
|
|
|
* @return array
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private function listTables() {
|
|
|
|
|
$tables = array( 'user', 'user_properties', 'user_former_groups', 'page', 'page_restrictions',
|
|
|
|
|
'protected_titles', 'revision', 'text', 'pagelinks', 'imagelinks',
|
|
|
|
|
'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'iwlinks',
|
2014-07-30 20:56:20 +00:00
|
|
|
'site_stats', 'ipblocks', 'image', 'oldimage',
|
2012-01-09 22:33:00 +00:00
|
|
|
'recentchanges', 'watchlist', 'interwiki', 'logging',
|
|
|
|
|
'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo',
|
|
|
|
|
'archive', 'user_groups', 'page_props', 'category', 'msg_resource', 'msg_resource_links'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ( in_array( $this->db->getType(), array( 'mysql', 'sqlite', 'oracle' ) ) ) {
|
|
|
|
|
array_push( $tables, 'searchindex' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allow extensions to add to the list of tables to duplicate;
|
|
|
|
|
// may be necessary if they hook into page save or other code
|
|
|
|
|
// which will require them while running tests.
|
2014-12-12 22:47:31 +00:00
|
|
|
Hooks::run( 'ParserTestTables', array( &$tables ) );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
return $tables;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set up a temporary set of wiki tables to work with for the tests.
|
|
|
|
|
* Currently this will only be done once per run, and any changes to
|
|
|
|
|
* the db will be visible to later tests in the run.
|
|
|
|
|
*/
|
|
|
|
|
public function setupDatabase() {
|
|
|
|
|
global $wgDBprefix;
|
|
|
|
|
|
|
|
|
|
if ( $this->databaseSetupDone ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->db = wfGetDB( DB_MASTER );
|
|
|
|
|
$dbType = $this->db->getType();
|
|
|
|
|
|
|
|
|
|
if ( $wgDBprefix === 'parsertest_' || ( $dbType == 'oracle' && $wgDBprefix === 'pt_' ) ) {
|
|
|
|
|
throw new MWException( 'setupDatabase should be called before setupGlobals' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->databaseSetupDone = true;
|
|
|
|
|
|
|
|
|
|
# SqlBagOStuff broke when using temporary tables on r40209 (bug 15892).
|
|
|
|
|
# It seems to have been fixed since (r55079?), but regressed at some point before r85701.
|
|
|
|
|
# This works around it for now...
|
|
|
|
|
ObjectCache::$instances[CACHE_DB] = new HashBagOStuff;
|
|
|
|
|
|
|
|
|
|
# CREATE TEMPORARY TABLE breaks if there is more than one server
|
|
|
|
|
if ( wfGetLB()->getServerCount() != 1 ) {
|
|
|
|
|
$this->useTemporaryTables = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$temporary = $this->useTemporaryTables || $dbType == 'postgres';
|
|
|
|
|
$prefix = $dbType != 'oracle' ? 'parsertest_' : 'pt_';
|
|
|
|
|
|
|
|
|
|
$this->dbClone = new CloneDatabase( $this->db, $this->listTables(), $prefix );
|
|
|
|
|
$this->dbClone->useTemporaryTables( $temporary );
|
|
|
|
|
$this->dbClone->cloneTableStructure();
|
|
|
|
|
|
|
|
|
|
if ( $dbType == 'oracle' ) {
|
|
|
|
|
$this->db->query( 'BEGIN FILL_WIKI_INFO; END;' );
|
|
|
|
|
# Insert 0 user to prevent FK violations
|
|
|
|
|
|
|
|
|
|
# Anonymous user
|
|
|
|
|
$this->db->insert( 'user', array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'user_id' => 0,
|
|
|
|
|
'user_name' => 'Anonymous' ) );
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Update certain things in site_stats
|
2013-07-16 18:06:04 +00:00
|
|
|
$this->db->insert( 'site_stats',
|
|
|
|
|
array( 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ) );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
# Reinitialise the LocalisationCache to match the database state
|
|
|
|
|
Language::getLocalisationCache()->unloadAll();
|
|
|
|
|
|
|
|
|
|
# Clear the message cache
|
|
|
|
|
MessageCache::singleton()->clear();
|
|
|
|
|
|
2013-05-24 12:56:06 +00:00
|
|
|
// Remember to update newParserTests.php after changing the below
|
|
|
|
|
// (and it uses a slightly different syntax just for teh lulz)
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
$this->setupUploadDir();
|
2012-01-09 22:33:00 +00:00
|
|
|
$user = User::createNew( 'WikiSysop' );
|
|
|
|
|
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.jpg' ) );
|
2013-02-27 00:12:12 +00:00
|
|
|
# note that the size/width/height/bits/etc of the file
|
|
|
|
|
# are actually set by inspecting the file itself; the arguments
|
|
|
|
|
# to recordUpload2 have no effect. That said, we try to make things
|
|
|
|
|
# match up so it is less confusing to readers of the code & tests.
|
2012-01-09 22:33:00 +00:00
|
|
|
$image->recordUpload2( '', 'Upload of some lame file', 'Some lame file', array(
|
2013-02-27 00:12:12 +00:00
|
|
|
'size' => 7881,
|
2013-02-14 11:22:13 +00:00
|
|
|
'width' => 1941,
|
|
|
|
|
'height' => 220,
|
2013-02-27 00:12:12 +00:00
|
|
|
'bits' => 8,
|
2013-02-14 11:22:13 +00:00
|
|
|
'media_type' => MEDIATYPE_BITMAP,
|
|
|
|
|
'mime' => 'image/jpeg',
|
|
|
|
|
'metadata' => serialize( array() ),
|
2013-02-27 00:12:12 +00:00
|
|
|
'sha1' => wfBaseConvert( '1', 16, 36, 31 ),
|
2013-02-14 11:22:13 +00:00
|
|
|
'fileExists' => true
|
|
|
|
|
), $this->db->timestamp( '20010115123500' ), $user );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
2013-02-27 00:12:12 +00:00
|
|
|
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'Thumb.png' ) );
|
|
|
|
|
# again, note that size/width/height below are ignored; see above.
|
|
|
|
|
$image->recordUpload2( '', 'Upload of some lame thumbnail', 'Some lame thumbnail', array(
|
|
|
|
|
'size' => 22589,
|
|
|
|
|
'width' => 135,
|
|
|
|
|
'height' => 135,
|
|
|
|
|
'bits' => 8,
|
|
|
|
|
'media_type' => MEDIATYPE_BITMAP,
|
|
|
|
|
'mime' => 'image/png',
|
|
|
|
|
'metadata' => serialize( array() ),
|
|
|
|
|
'sha1' => wfBaseConvert( '2', 16, 36, 31 ),
|
|
|
|
|
'fileExists' => true
|
|
|
|
|
), $this->db->timestamp( '20130225203040' ), $user );
|
|
|
|
|
|
2013-05-24 12:56:06 +00:00
|
|
|
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.svg' ) );
|
|
|
|
|
$image->recordUpload2( '', 'Upload of some lame SVG', 'Some lame SVG', array(
|
|
|
|
|
'size' => 12345,
|
|
|
|
|
'width' => 240,
|
|
|
|
|
'height' => 180,
|
2014-06-03 19:44:53 +00:00
|
|
|
'bits' => 0,
|
2013-05-24 12:56:06 +00:00
|
|
|
'media_type' => MEDIATYPE_DRAWING,
|
|
|
|
|
'mime' => 'image/svg+xml',
|
|
|
|
|
'metadata' => serialize( array() ),
|
|
|
|
|
'sha1' => wfBaseConvert( '', 16, 36, 31 ),
|
|
|
|
|
'fileExists' => true
|
|
|
|
|
), $this->db->timestamp( '20010115123500' ), $user );
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
# This image will be blacklisted in [[MediaWiki:Bad image list]]
|
|
|
|
|
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'Bad.jpg' ) );
|
|
|
|
|
$image->recordUpload2( '', 'zomgnotcensored', 'Borderline image', array(
|
2013-02-14 11:22:13 +00:00
|
|
|
'size' => 12345,
|
|
|
|
|
'width' => 320,
|
|
|
|
|
'height' => 240,
|
|
|
|
|
'bits' => 24,
|
|
|
|
|
'media_type' => MEDIATYPE_BITMAP,
|
|
|
|
|
'mime' => 'image/jpeg',
|
|
|
|
|
'metadata' => serialize( array() ),
|
2013-02-27 00:12:12 +00:00
|
|
|
'sha1' => wfBaseConvert( '3', 16, 36, 31 ),
|
2013-02-14 11:22:13 +00:00
|
|
|
'fileExists' => true
|
|
|
|
|
), $this->db->timestamp( '20010115123500' ), $user );
|
2013-12-18 17:56:15 +00:00
|
|
|
|
|
|
|
|
# A DjVu file
|
|
|
|
|
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'LoremIpsum.djvu' ) );
|
|
|
|
|
$image->recordUpload2( '', 'Upload a DjVu', 'A DjVu', array(
|
|
|
|
|
'size' => 3249,
|
|
|
|
|
'width' => 2480,
|
|
|
|
|
'height' => 3508,
|
2014-06-03 19:44:53 +00:00
|
|
|
'bits' => 0,
|
2013-12-18 17:56:15 +00:00
|
|
|
'media_type' => MEDIATYPE_BITMAP,
|
|
|
|
|
'mime' => 'image/vnd.djvu',
|
|
|
|
|
'metadata' => '<?xml version="1.0" ?>
|
|
|
|
|
<!DOCTYPE DjVuXML PUBLIC "-//W3C//DTD DjVuXML 1.1//EN" "pubtext/DjVuXML-s.dtd">
|
|
|
|
|
<DjVuXML>
|
|
|
|
|
<HEAD></HEAD>
|
|
|
|
|
<BODY><OBJECT height="3508" width="2480">
|
|
|
|
|
<PARAM name="DPI" value="300" />
|
|
|
|
|
<PARAM name="GAMMA" value="2.2" />
|
|
|
|
|
</OBJECT>
|
|
|
|
|
<OBJECT height="3508" width="2480">
|
|
|
|
|
<PARAM name="DPI" value="300" />
|
|
|
|
|
<PARAM name="GAMMA" value="2.2" />
|
|
|
|
|
</OBJECT>
|
|
|
|
|
<OBJECT height="3508" width="2480">
|
|
|
|
|
<PARAM name="DPI" value="300" />
|
|
|
|
|
<PARAM name="GAMMA" value="2.2" />
|
|
|
|
|
</OBJECT>
|
|
|
|
|
<OBJECT height="3508" width="2480">
|
|
|
|
|
<PARAM name="DPI" value="300" />
|
|
|
|
|
<PARAM name="GAMMA" value="2.2" />
|
|
|
|
|
</OBJECT>
|
|
|
|
|
<OBJECT height="3508" width="2480">
|
|
|
|
|
<PARAM name="DPI" value="300" />
|
|
|
|
|
<PARAM name="GAMMA" value="2.2" />
|
|
|
|
|
</OBJECT>
|
|
|
|
|
</BODY>
|
|
|
|
|
</DjVuXML>',
|
|
|
|
|
'sha1' => wfBaseConvert( '', 16, 36, 31 ),
|
|
|
|
|
'fileExists' => true
|
|
|
|
|
), $this->db->timestamp( '20010115123600' ), $user );
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function teardownDatabase() {
|
|
|
|
|
if ( !$this->databaseSetupDone ) {
|
|
|
|
|
$this->teardownGlobals();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$this->teardownUploadDir( $this->uploadDir );
|
|
|
|
|
|
|
|
|
|
$this->dbClone->destroy();
|
|
|
|
|
$this->databaseSetupDone = false;
|
|
|
|
|
|
|
|
|
|
if ( $this->useTemporaryTables ) {
|
2013-02-14 11:22:13 +00:00
|
|
|
if ( $this->db->getType() == 'sqlite' ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
# Under SQLite the searchindex table is virtual and need
|
|
|
|
|
# to be explicitly destroyed. See bug 29912
|
|
|
|
|
# See also MediaWikiTestCase::destroyDB()
|
|
|
|
|
wfDebug( __METHOD__ . " explicitly destroying sqlite virtual table parsertest_searchindex\n" );
|
|
|
|
|
$this->db->query( "DROP TABLE `parsertest_searchindex`" );
|
|
|
|
|
}
|
|
|
|
|
# Don't need to do anything
|
|
|
|
|
$this->teardownGlobals();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$tables = $this->listTables();
|
|
|
|
|
|
|
|
|
|
foreach ( $tables as $table ) {
|
2013-07-16 18:06:04 +00:00
|
|
|
if ( $this->db->getType() == 'oracle' ) {
|
|
|
|
|
$this->db->query( "DROP TABLE pt_$table DROP CONSTRAINTS" );
|
|
|
|
|
} else {
|
|
|
|
|
$this->db->query( "DROP TABLE `parsertest_$table`" );
|
|
|
|
|
}
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
2013-02-14 11:22:13 +00:00
|
|
|
if ( $this->db->getType() == 'oracle' ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
$this->db->query( 'BEGIN FILL_WIKI_INFO; END;' );
|
2013-02-14 11:22:13 +00:00
|
|
|
}
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
$this->teardownGlobals();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a dummy uploads directory which will contain a couple
|
|
|
|
|
* of files in order to pass existence tests.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @return string The directory
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private function setupUploadDir() {
|
|
|
|
|
global $IP;
|
|
|
|
|
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
$dir = $this->uploadDir;
|
|
|
|
|
if ( $this->keepUploads && is_dir( $dir ) ) {
|
|
|
|
|
return;
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// wfDebug( "Creating upload directory $dir\n" );
|
|
|
|
|
if ( file_exists( $dir ) ) {
|
|
|
|
|
wfDebug( "Already exists!\n" );
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
return;
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wfMkdirParents( $dir . '/3/3a', null, __METHOD__ );
|
2014-05-26 09:55:07 +00:00
|
|
|
copy( "$IP/tests/phpunit/data/parser/headbg.jpg", "$dir/3/3a/Foobar.jpg" );
|
2013-02-27 00:12:12 +00:00
|
|
|
wfMkdirParents( $dir . '/e/ea', null, __METHOD__ );
|
2014-05-26 09:55:07 +00:00
|
|
|
copy( "$IP/tests/phpunit/data/parser/wiki.png", "$dir/e/ea/Thumb.png" );
|
2012-01-09 22:33:00 +00:00
|
|
|
wfMkdirParents( $dir . '/0/09', null, __METHOD__ );
|
2014-05-26 09:55:07 +00:00
|
|
|
copy( "$IP/tests/phpunit/data/parser/headbg.jpg", "$dir/0/09/Bad.jpg" );
|
2013-05-24 12:56:06 +00:00
|
|
|
wfMkdirParents( $dir . '/f/ff', null, __METHOD__ );
|
|
|
|
|
file_put_contents( "$dir/f/ff/Foobar.svg",
|
|
|
|
|
'<?xml version="1.0" encoding="utf-8"?>' .
|
2014-03-18 17:00:11 +00:00
|
|
|
'<svg xmlns="http://www.w3.org/2000/svg"' .
|
|
|
|
|
' version="1.1" width="240" height="180"/>' );
|
2013-12-18 17:56:15 +00:00
|
|
|
wfMkdirParents( $dir . '/5/5f', null, __METHOD__ );
|
2014-05-26 09:55:07 +00:00
|
|
|
copy( "$IP/tests/phpunit/data/parser/LoremIpsum.djvu", "$dir/5/5f/LoremIpsum.djvu" );
|
2013-12-18 17:56:15 +00:00
|
|
|
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
return;
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Restore default values and perform any necessary clean-up
|
|
|
|
|
* after each test runs.
|
|
|
|
|
*/
|
|
|
|
|
private function teardownGlobals() {
|
|
|
|
|
RepoGroup::destroySingleton();
|
2012-03-20 00:28:30 +00:00
|
|
|
FileBackendGroup::destroySingleton();
|
2013-01-25 20:19:57 +00:00
|
|
|
LockManagerGroup::destroySingletons();
|
2012-01-09 22:33:00 +00:00
|
|
|
LinkCache::singleton()->clear();
|
2015-08-31 04:42:55 +00:00
|
|
|
MWTidy::destroySingleton();
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
foreach ( $this->savedGlobals as $var => $val ) {
|
|
|
|
|
$GLOBALS[$var] = $val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove the dummy uploads directory
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $dir
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private function teardownUploadDir( $dir ) {
|
|
|
|
|
if ( $this->keepUploads ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete the files first, then the dirs.
|
|
|
|
|
self::deleteFiles(
|
2013-02-14 11:22:13 +00:00
|
|
|
array(
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir/3/3a/Foobar.jpg",
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
"$dir/thumb/3/3a/Foobar.jpg/*.jpg",
|
2013-02-27 00:12:12 +00:00
|
|
|
"$dir/e/ea/Thumb.png",
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir/0/09/Bad.jpg",
|
2013-12-18 17:56:15 +00:00
|
|
|
"$dir/5/5f/LoremIpsum.djvu",
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
"$dir/thumb/5/5f/LoremIpsum.djvu/*-LoremIpsum.djvu.jpg",
|
2013-05-24 12:56:06 +00:00
|
|
|
"$dir/f/ff/Foobar.svg",
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
"$dir/thumb/f/ff/Foobar.svg/*-Foobar.svg.png",
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png",
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
self::deleteDirs(
|
2013-02-14 11:22:13 +00:00
|
|
|
array(
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir/3/3a",
|
|
|
|
|
"$dir/3",
|
|
|
|
|
"$dir/thumb/3/3a/Foobar.jpg",
|
|
|
|
|
"$dir/thumb/3/3a",
|
|
|
|
|
"$dir/thumb/3",
|
2013-02-27 00:12:12 +00:00
|
|
|
"$dir/e/ea",
|
|
|
|
|
"$dir/e",
|
2013-05-24 12:56:06 +00:00
|
|
|
"$dir/f/ff/",
|
|
|
|
|
"$dir/f/",
|
|
|
|
|
"$dir/thumb/f/ff/Foobar.svg",
|
|
|
|
|
"$dir/thumb/f/ff/",
|
|
|
|
|
"$dir/thumb/f/",
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir/0/09/",
|
|
|
|
|
"$dir/0/",
|
2013-12-18 17:56:15 +00:00
|
|
|
"$dir/5/5f",
|
|
|
|
|
"$dir/5",
|
|
|
|
|
"$dir/thumb/5/5f/LoremIpsum.djvu",
|
|
|
|
|
"$dir/thumb/5/5f",
|
|
|
|
|
"$dir/thumb/5",
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir/thumb",
|
|
|
|
|
"$dir/math/f/a/5",
|
|
|
|
|
"$dir/math/f/a",
|
|
|
|
|
"$dir/math/f",
|
|
|
|
|
"$dir/math",
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
"$dir/lockdir",
|
2012-01-09 22:33:00 +00:00
|
|
|
"$dir",
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete the specified files, if they exist.
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param array $files Full paths to files to delete.
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private static function deleteFiles( $files ) {
|
In parserTests.php, fix upload directory handling
Instead of having two conflicting filerepo configurations, one at
/tmp/test-repo and another at a randomized path, and populating the one
that isn't used with files, let's just have a single upload directory,
populate it with files, and then actually use those files.
This fixes a set of confusing system-dependent parser test failures. In
the failure scenario, the file upload would be recorded, but then
invalid JPEG metadata would trigger LocalFile::loadFromFile(), which
would look for the file in the wrong place and mark it missing. Then
parser tests would fail due to image links being broken (red).
This is probably not as nice as the fake in-memory repo used by
NewParserTest, but this approach does provide a richer integration test.
This is a conservative fix that just fixes the things that are terribly
broken rather than making new things.
Also:
* Clear the RepoGroup singleton, for completeness, since it doesn't
make sense to set $wgLocalRepo without clearing it. Since we now set up
a similar repo at initialisation to the one set up with each test, it
probably doesn't have any effect.
* Warn if gd is not present since this causes 49 test failures.
* Use glob patterns in teardownUploadDir() instead of requiring every
file to be individually listed. This fixes an error due to failure to
delete a 240px file.
Change-Id: I56a0e0d1cb363b40cf19c735e00cbb8929c1401a
2015-09-07 06:10:12 +00:00
|
|
|
foreach ( $files as $pattern ) {
|
|
|
|
|
foreach ( glob( $pattern ) as $file ) {
|
|
|
|
|
if ( file_exists( $file ) ) {
|
|
|
|
|
unlink( $file );
|
|
|
|
|
}
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete the specified directories, if they exist. Must be empty.
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param array $dirs Full paths to directories to delete.
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private static function deleteDirs( $dirs ) {
|
|
|
|
|
foreach ( $dirs as $dir ) {
|
|
|
|
|
if ( is_dir( $dir ) ) {
|
|
|
|
|
rmdir( $dir );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* "Running test $desc..."
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $desc
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
protected function showTesting( $desc ) {
|
|
|
|
|
print "Running test $desc... ";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Print a happy success message.
|
|
|
|
|
*
|
2013-03-19 14:00:44 +00:00
|
|
|
* Refactored in 1.22 to use ParserTestResult
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param ParserTestResult $testResult
|
|
|
|
|
* @return bool
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
2013-03-19 14:00:44 +00:00
|
|
|
protected function showSuccess( ParserTestResult $testResult ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( $this->showProgress ) {
|
|
|
|
|
print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Print a failure message and provide some explanatory output
|
|
|
|
|
* about what went wrong if so configured.
|
|
|
|
|
*
|
2013-03-19 14:00:44 +00:00
|
|
|
* Refactored in 1.22 to use ParserTestResult
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param ParserTestResult $testResult
|
|
|
|
|
* @return bool
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
2013-03-19 14:00:44 +00:00
|
|
|
protected function showFailure( ParserTestResult $testResult ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
if ( $this->showFailure ) {
|
|
|
|
|
if ( !$this->showProgress ) {
|
|
|
|
|
# In quiet mode we didn't show the 'Testing' message before the
|
|
|
|
|
# test, in case it succeeded. Show it now:
|
2013-03-19 14:00:44 +00:00
|
|
|
$this->showTesting( $testResult->description );
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print $this->term->color( '31' ) . 'FAILED!' . $this->term->reset() . "\n";
|
|
|
|
|
|
|
|
|
|
if ( $this->showOutput ) {
|
2013-03-19 14:00:44 +00:00
|
|
|
print "--- Expected ---\n{$testResult->expected}\n";
|
|
|
|
|
print "--- Actual ---\n{$testResult->actual}\n";
|
2012-01-09 22:33:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $this->showDiffs ) {
|
2013-03-19 14:00:44 +00:00
|
|
|
print $this->quickDiff( $testResult->expected, $testResult->actual );
|
|
|
|
|
if ( !$this->wellFormed( $testResult->actual ) ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
print "XML error: $this->mXmlError\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-18 17:56:15 +00:00
|
|
|
/**
|
|
|
|
|
* Print a skipped message.
|
|
|
|
|
*
|
2014-08-13 17:54:49 +00:00
|
|
|
* @return bool
|
2013-12-18 17:56:15 +00:00
|
|
|
*/
|
|
|
|
|
protected function showSkipped() {
|
|
|
|
|
if ( $this->showProgress ) {
|
|
|
|
|
print $this->term->color( '1;33' ) . 'SKIPPED' . $this->term->reset() . "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
/**
|
|
|
|
|
* Run given strings through a diff and return the (colorized) output.
|
|
|
|
|
* Requires writable /tmp directory and a 'diff' command in the PATH.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $input
|
|
|
|
|
* @param string $output
|
|
|
|
|
* @param string $inFileTail Tailing for the input file name
|
|
|
|
|
* @param string $outFileTail Tailing for the output file name
|
|
|
|
|
* @return string
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
2013-07-16 18:06:04 +00:00
|
|
|
protected function quickDiff( $input, $output,
|
|
|
|
|
$inFileTail = 'expected', $outFileTail = 'actual'
|
|
|
|
|
) {
|
2012-01-09 22:33:00 +00:00
|
|
|
# Windows, or at least the fc utility, is retarded
|
|
|
|
|
$slash = wfIsWindows() ? '\\' : '/';
|
|
|
|
|
$prefix = wfTempDir() . "{$slash}mwParser-" . mt_rand();
|
|
|
|
|
|
|
|
|
|
$infile = "$prefix-$inFileTail";
|
|
|
|
|
$this->dumpToFile( $input, $infile );
|
|
|
|
|
|
|
|
|
|
$outfile = "$prefix-$outFileTail";
|
|
|
|
|
$this->dumpToFile( $output, $outfile );
|
|
|
|
|
|
2013-02-14 11:22:13 +00:00
|
|
|
$shellInfile = wfEscapeShellArg( $infile );
|
|
|
|
|
$shellOutfile = wfEscapeShellArg( $outfile );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
global $wgDiff3;
|
|
|
|
|
// we assume that people with diff3 also have usual diff
|
2013-04-26 15:45:18 +00:00
|
|
|
$shellCommand = ( wfIsWindows() && !$wgDiff3 ) ? 'fc' : 'diff -au';
|
|
|
|
|
|
|
|
|
|
$diff = wfShellExec( "$shellCommand $shellInfile $shellOutfile" );
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
unlink( $infile );
|
|
|
|
|
unlink( $outfile );
|
|
|
|
|
|
|
|
|
|
return $this->colorDiff( $diff );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write the given string to a file, adding a final newline.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $data
|
|
|
|
|
* @param string $filename
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
private function dumpToFile( $data, $filename ) {
|
|
|
|
|
$file = fopen( $filename, "wt" );
|
|
|
|
|
fwrite( $file, $data . "\n" );
|
|
|
|
|
fclose( $file );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Colorize unified diff output if set for ANSI color output.
|
|
|
|
|
* Subtractions are colored blue, additions red.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $text
|
|
|
|
|
* @return string
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
protected function colorDiff( $text ) {
|
|
|
|
|
return preg_replace(
|
|
|
|
|
array( '/^(-.*)$/m', '/^(\+.*)$/m' ),
|
|
|
|
|
array( $this->term->color( 34 ) . '$1' . $this->term->reset(),
|
2013-02-14 11:22:13 +00:00
|
|
|
$this->term->color( 31 ) . '$1' . $this->term->reset() ),
|
2012-01-09 22:33:00 +00:00
|
|
|
$text );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Show "Reading tests from ..."
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $path
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
public function showRunFile( $path ) {
|
|
|
|
|
print $this->term->color( 1 ) .
|
|
|
|
|
"Reading tests from \"$path\"..." .
|
|
|
|
|
$this->term->reset() .
|
|
|
|
|
"\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert a temporary test article
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $name The title, including any prefix
|
|
|
|
|
* @param string $text The article text
|
2014-12-24 13:49:20 +00:00
|
|
|
* @param int|string $line The input line number, for reporting errors
|
|
|
|
|
* @param bool|string $ignoreDuplicate Whether to silently ignore duplicate pages
|
|
|
|
|
* @throws Exception
|
|
|
|
|
* @throws MWException
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
2013-02-12 21:32:09 +00:00
|
|
|
public static function addArticle( $name, $text, $line = 'unknown', $ignoreDuplicate = '' ) {
|
2012-01-09 22:33:00 +00:00
|
|
|
global $wgCapitalLinks;
|
|
|
|
|
|
|
|
|
|
$oldCapitalLinks = $wgCapitalLinks;
|
|
|
|
|
$wgCapitalLinks = true; // We only need this from SetupGlobals() See r70917#c8637
|
|
|
|
|
|
|
|
|
|
$text = self::chomp( $text );
|
|
|
|
|
$name = self::chomp( $name );
|
|
|
|
|
|
|
|
|
|
$title = Title::newFromText( $name );
|
|
|
|
|
|
|
|
|
|
if ( is_null( $title ) ) {
|
|
|
|
|
throw new MWException( "invalid title '$name' at line $line\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$page = WikiPage::factory( $title );
|
|
|
|
|
$page->loadPageData( 'fromdbmaster' );
|
|
|
|
|
|
|
|
|
|
if ( $page->exists() ) {
|
|
|
|
|
if ( $ignoreDuplicate == 'ignoreduplicate' ) {
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
throw new MWException( "duplicate article '$name' at line $line\n" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-28 13:58:36 +00:00
|
|
|
$page->doEditContent( ContentHandler::makeContent( $text, $title ), '', EDIT_NEW );
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
$wgCapitalLinks = $oldCapitalLinks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Steal a callback function from the primary parser, save it for
|
|
|
|
|
* application to our scary parser. If the hook is not installed,
|
|
|
|
|
* abort processing of this file.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $name
|
|
|
|
|
* @return bool True if tag hook is present
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
public function requireHook( $name ) {
|
|
|
|
|
global $wgParser;
|
|
|
|
|
|
2013-02-14 11:22:13 +00:00
|
|
|
$wgParser->firstCallInit(); // make sure hooks are loaded.
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
if ( isset( $wgParser->mTagHooks[$name] ) ) {
|
|
|
|
|
$this->hooks[$name] = $wgParser->mTagHooks[$name];
|
|
|
|
|
} else {
|
|
|
|
|
echo " This test suite requires the '$name' hook extension, skipping.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Steal a callback function from the primary parser, save it for
|
|
|
|
|
* application to our scary parser. If the hook is not installed,
|
|
|
|
|
* abort processing of this file.
|
|
|
|
|
*
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string $name
|
|
|
|
|
* @return bool True if function hook is present
|
2012-01-09 22:33:00 +00:00
|
|
|
*/
|
|
|
|
|
public function requireFunctionHook( $name ) {
|
|
|
|
|
global $wgParser;
|
|
|
|
|
|
2013-02-14 11:22:13 +00:00
|
|
|
$wgParser->firstCallInit(); // make sure hooks are loaded.
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
if ( isset( $wgParser->mFunctionHooks[$name] ) ) {
|
|
|
|
|
$this->functionHooks[$name] = $wgParser->mFunctionHooks[$name];
|
|
|
|
|
} else {
|
|
|
|
|
echo " This test suite requires the '$name' function hook extension, skipping.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-20 15:36:08 +00:00
|
|
|
/**
|
|
|
|
|
* Steal a callback function from the primary parser, save it for
|
|
|
|
|
* application to our scary parser. If the hook is not installed,
|
|
|
|
|
* abort processing of this file.
|
|
|
|
|
*
|
|
|
|
|
* @param string $name
|
|
|
|
|
* @return bool True if function hook is present
|
|
|
|
|
*/
|
|
|
|
|
public function requireTransparentHook( $name ) {
|
|
|
|
|
global $wgParser;
|
|
|
|
|
|
|
|
|
|
$wgParser->firstCallInit(); // make sure hooks are loaded.
|
|
|
|
|
|
|
|
|
|
if ( isset( $wgParser->mTransparentTagHooks[$name] ) ) {
|
|
|
|
|
$this->transparentHooks[$name] = $wgParser->mTransparentTagHooks[$name];
|
|
|
|
|
} else {
|
|
|
|
|
echo " This test suite requires the '$name' transparent hook extension, skipping.\n";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-09 22:33:00 +00:00
|
|
|
private function wellFormed( $text ) {
|
|
|
|
|
$html =
|
|
|
|
|
Sanitizer::hackDocType() .
|
2013-02-14 11:22:13 +00:00
|
|
|
'<html>' .
|
|
|
|
|
$text .
|
|
|
|
|
'</html>';
|
2012-01-09 22:33:00 +00:00
|
|
|
|
|
|
|
|
$parser = xml_parser_create( "UTF-8" );
|
|
|
|
|
|
|
|
|
|
# case folding violates XML standard, turn it off
|
|
|
|
|
xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
|
|
|
|
|
|
|
|
|
|
if ( !xml_parse( $parser, $html, true ) ) {
|
|
|
|
|
$err = xml_error_string( xml_get_error_code( $parser ) );
|
|
|
|
|
$position = xml_get_current_byte_index( $parser );
|
|
|
|
|
$fragment = $this->extractFragment( $html, $position );
|
|
|
|
|
$this->mXmlError = "$err at byte $position:\n$fragment";
|
|
|
|
|
xml_parser_free( $parser );
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xml_parser_free( $parser );
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function extractFragment( $text, $position ) {
|
|
|
|
|
$start = max( 0, $position - 10 );
|
|
|
|
|
$before = $position - $start;
|
|
|
|
|
$fragment = '...' .
|
|
|
|
|
$this->term->color( 34 ) .
|
|
|
|
|
substr( $text, $start, $before ) .
|
|
|
|
|
$this->term->color( 0 ) .
|
|
|
|
|
$this->term->color( 31 ) .
|
|
|
|
|
$this->term->color( 1 ) .
|
|
|
|
|
substr( $text, $position, 1 ) .
|
|
|
|
|
$this->term->color( 0 ) .
|
|
|
|
|
$this->term->color( 34 ) .
|
|
|
|
|
substr( $text, $position + 1, 9 ) .
|
|
|
|
|
$this->term->color( 0 ) .
|
|
|
|
|
'...';
|
|
|
|
|
$display = str_replace( "\n", ' ', $fragment );
|
|
|
|
|
$caret = ' ' .
|
|
|
|
|
str_repeat( ' ', $before ) .
|
|
|
|
|
$this->term->color( 31 ) .
|
|
|
|
|
'^' .
|
|
|
|
|
$this->term->color( 0 );
|
|
|
|
|
|
|
|
|
|
return "$display\n$caret";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static function getFakeTimestamp( &$parser, &$ts ) {
|
2015-09-11 13:44:59 +00:00
|
|
|
$ts = 123; // parsed as '1970-01-01T00:02:03Z'
|
2012-01-09 22:33:00 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|