summaryrefslogtreecommitdiff
path: root/tests/phpunit
diff options
context:
space:
mode:
Diffstat (limited to 'tests/phpunit')
-rw-r--r--tests/phpunit/Makefile17
-rw-r--r--tests/phpunit/MediaWikiLangTestCase.php6
-rw-r--r--tests/phpunit/MediaWikiPHPUnitCommand.php30
-rw-r--r--tests/phpunit/MediaWikiTestCase.php113
-rw-r--r--tests/phpunit/StructureTest.php56
-rw-r--r--tests/phpunit/data/db/mysql/functions.sql12
-rw-r--r--tests/phpunit/data/db/postgres/functions.sql12
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.13.sql (renamed from tests/phpunit/includes/db/sqlite/tables-1.13.sql)2
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.15.sql (renamed from tests/phpunit/includes/db/sqlite/tables-1.15.sql)4
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.16.sql (renamed from tests/phpunit/includes/db/sqlite/tables-1.16.sql)0
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.17.sql (renamed from tests/phpunit/includes/db/sqlite/tables-1.17.sql)0
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.18.sql535
-rw-r--r--tests/phpunit/data/media/80x60-2layers.xcfbin0 -> 1162 bytes
-rw-r--r--tests/phpunit/data/media/80x60-Greyscale.xcfbin0 -> 667 bytes
-rw-r--r--tests/phpunit/data/media/80x60-RGB.xcfbin0 -> 677 bytes
-rw-r--r--tests/phpunit/data/media/Toll_Texas_1.svg150
-rw-r--r--tests/phpunit/data/media/iptc-invalid-psir.jpgbin0 -> 9574 bytes
-rw-r--r--tests/phpunit/includes/ArticleTablesTest.php31
-rw-r--r--tests/phpunit/includes/ArticleTest.php14
-rw-r--r--tests/phpunit/includes/BlockTest.php17
-rw-r--r--tests/phpunit/includes/EditPageTest.php33
-rw-r--r--tests/phpunit/includes/ExtraParserTest.php64
-rw-r--r--tests/phpunit/includes/FormOptionsInitializationTest.php4
-rw-r--r--tests/phpunit/includes/FormOptionsTest.php4
-rw-r--r--tests/phpunit/includes/GlobalFunctions/GlobalTest.php524
-rw-r--r--tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php29
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php111
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php133
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php36
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php (renamed from tests/phpunit/includes/GlobalFunctions/wfExpandUrl.php)22
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php90
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php28
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php134
-rw-r--r--tests/phpunit/includes/HtmlTest.php277
-rw-r--r--tests/phpunit/includes/HttpTest.php556
-rw-r--r--tests/phpunit/includes/IPTest.php32
-rw-r--r--tests/phpunit/includes/LocalFileTest.php33
-rw-r--r--tests/phpunit/includes/MWNamespaceTest.php329
-rw-r--r--tests/phpunit/includes/MessageTest.php2
-rw-r--r--tests/phpunit/includes/ParserOptionsTest.php9
-rw-r--r--tests/phpunit/includes/PathRouterTest.php254
-rw-r--r--tests/phpunit/includes/Providers.php4
-rw-r--r--tests/phpunit/includes/ResourceLoaderTest.php2
-rw-r--r--tests/phpunit/includes/SanitizerTest.php43
-rw-r--r--tests/phpunit/includes/SanitizerValidateEmailTest.php (renamed from tests/phpunit/includes/UserIsValidEmailAddrTest.php)4
-rw-r--r--tests/phpunit/includes/SeleniumConfigurationTest.php24
-rw-r--r--tests/phpunit/includes/TemplateCategoriesTest.php38
-rw-r--r--tests/phpunit/includes/TitleMethodsTest.php78
-rw-r--r--tests/phpunit/includes/TitlePermissionTest.php34
-rw-r--r--tests/phpunit/includes/TitleTest.php4
-rw-r--r--tests/phpunit/includes/UserTest.php105
-rw-r--r--tests/phpunit/includes/WebRequestTest.php97
-rw-r--r--tests/phpunit/includes/XmlSelectTest.php4
-rw-r--r--tests/phpunit/includes/XmlTest.php99
-rw-r--r--tests/phpunit/includes/api/ApiBlockTest.php28
-rw-r--r--tests/phpunit/includes/api/ApiPurgeTest.php34
-rw-r--r--tests/phpunit/includes/api/ApiQueryTest.php8
-rw-r--r--tests/phpunit/includes/api/ApiTest.php36
-rw-r--r--tests/phpunit/includes/api/ApiTestCase.php51
-rw-r--r--tests/phpunit/includes/api/ApiTestCaseUpload.php40
-rw-r--r--tests/phpunit/includes/api/ApiTestUser.php2
-rw-r--r--tests/phpunit/includes/api/ApiUploadTest.php197
-rw-r--r--tests/phpunit/includes/api/ApiWatchTest.php5
-rw-r--r--tests/phpunit/includes/api/RandomImageGenerator.php124
-rw-r--r--tests/phpunit/includes/db/DatabaseSqliteTest.php14
-rw-r--r--tests/phpunit/includes/db/DatabaseTest.php32
-rw-r--r--tests/phpunit/includes/debug/MWDebugTest.php63
-rw-r--r--tests/phpunit/includes/filerepo/FileBackendTest.php1358
-rw-r--r--tests/phpunit/includes/filerepo/FileRepoTest.php41
-rw-r--r--tests/phpunit/includes/filerepo/StoreBatchTest.php122
-rw-r--r--tests/phpunit/includes/json/ServicesJsonTest.php93
-rw-r--r--tests/phpunit/includes/libs/JavaScriptMinifierTest.php43
-rw-r--r--tests/phpunit/includes/media/BitmapMetadataHandlerTest.php26
-rw-r--r--tests/phpunit/includes/media/BitmapScalingTest.php25
-rw-r--r--tests/phpunit/includes/media/ExifBitmapTest.php24
-rw-r--r--tests/phpunit/includes/media/ExifRotationTest.php59
-rw-r--r--tests/phpunit/includes/media/ExifTest.php9
-rw-r--r--tests/phpunit/includes/media/FormatMetadataTest.php39
-rw-r--r--tests/phpunit/includes/media/GIFMetadataExtractorTest.php1
-rw-r--r--tests/phpunit/includes/media/GIFTest.php31
-rw-r--r--tests/phpunit/includes/media/JpegMetadataExtractorTest.php10
-rw-r--r--tests/phpunit/includes/media/JpegTest.php18
-rw-r--r--tests/phpunit/includes/media/MediaHandlerTest.php (renamed from tests/phpunit/includes/ImageFunctionsTest.php)8
-rw-r--r--tests/phpunit/includes/media/PNGTest.php30
-rw-r--r--tests/phpunit/includes/media/SVGMetadataExtractorTest.php24
-rw-r--r--tests/phpunit/includes/media/TiffTest.php7
-rw-r--r--tests/phpunit/includes/media/XMPTest.php9
-rw-r--r--tests/phpunit/includes/media/XMPValidateTest.php47
-rw-r--r--tests/phpunit/includes/parser/MagicVariableTest.php10
-rw-r--r--tests/phpunit/includes/parser/MediaWikiParserTest.php12
-rw-r--r--tests/phpunit/includes/parser/NewParserTest.php414
-rw-r--r--tests/phpunit/includes/parser/ParserHelpers.php136
-rw-r--r--tests/phpunit/includes/parser/ParserPreloadTest.php67
-rw-r--r--tests/phpunit/includes/parser/PreprocessorTest.php102
-rw-r--r--tests/phpunit/includes/parser/TagHooksTest.php (renamed from tests/phpunit/includes/parser/TagHooks.php)0
-rw-r--r--tests/phpunit/includes/search/SearchEngineTest.php16
-rw-r--r--tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php79
-rw-r--r--tests/phpunit/includes/specials/SpecialRecentchangesTest.php (renamed from tests/phpunit/includes/specials/SpecialRecentchanges.php)16
-rw-r--r--tests/phpunit/includes/specials/SpecialSearchTest.php108
-rw-r--r--tests/phpunit/includes/upload/UploadFromUrlTest.php19
-rw-r--r--tests/phpunit/includes/upload/UploadStashTest.php53
-rw-r--r--tests/phpunit/includes/upload/UploadTest.php87
-rw-r--r--tests/phpunit/languages/LanguageAmTest.php33
-rw-r--r--tests/phpunit/languages/LanguageArTest.php78
-rw-r--r--tests/phpunit/languages/LanguageBeTest.php40
-rw-r--r--tests/phpunit/languages/LanguageBe_taraskTest.php35
-rw-r--r--tests/phpunit/languages/LanguageBhTest.php34
-rw-r--r--tests/phpunit/languages/LanguageBsTest.php41
-rw-r--r--tests/phpunit/languages/LanguageCsTest.php40
-rw-r--r--tests/phpunit/languages/LanguageCuTest.php41
-rw-r--r--tests/phpunit/languages/LanguageCyTest.php42
-rw-r--r--tests/phpunit/languages/LanguageDsbTest.php40
-rw-r--r--tests/phpunit/languages/LanguageFrTest.php34
-rw-r--r--tests/phpunit/languages/LanguageGaTest.php34
-rw-r--r--tests/phpunit/languages/LanguageGdTest.php38
-rw-r--r--tests/phpunit/languages/LanguageGvTest.php39
-rw-r--r--tests/phpunit/languages/LanguageHeTest.php48
-rw-r--r--tests/phpunit/languages/LanguageHiTest.php34
-rw-r--r--tests/phpunit/languages/LanguageHrTest.php41
-rw-r--r--tests/phpunit/languages/LanguageHsbTest.php40
-rw-r--r--tests/phpunit/languages/LanguageHyTest.php34
-rw-r--r--tests/phpunit/languages/LanguageKshTest.php34
-rw-r--r--tests/phpunit/languages/LanguageLnTest.php34
-rw-r--r--tests/phpunit/languages/LanguageLtTest.php53
-rw-r--r--tests/phpunit/languages/LanguageLvTest.php39
-rw-r--r--tests/phpunit/languages/LanguageMgTest.php35
-rw-r--r--tests/phpunit/languages/LanguageMkTest.php41
-rw-r--r--tests/phpunit/languages/LanguageMlTest.php43
-rw-r--r--tests/phpunit/languages/LanguageMoTest.php43
-rw-r--r--tests/phpunit/languages/LanguageMtTest.php72
-rw-r--r--tests/phpunit/languages/LanguageNlTest.php28
-rw-r--r--tests/phpunit/languages/LanguageNsoTest.php32
-rw-r--r--tests/phpunit/languages/LanguagePlTest.php72
-rw-r--r--tests/phpunit/languages/LanguageRoTest.php43
-rw-r--r--tests/phpunit/languages/LanguageRuTest.php54
-rw-r--r--tests/phpunit/languages/LanguageSeTest.php48
-rw-r--r--tests/phpunit/languages/LanguageSgsTest.php66
-rw-r--r--tests/phpunit/languages/LanguageShTest.php32
-rw-r--r--tests/phpunit/languages/LanguageSkTest.php40
-rw-r--r--tests/phpunit/languages/LanguageSlTest.php42
-rw-r--r--tests/phpunit/languages/LanguageSmaTest.php48
-rw-r--r--tests/phpunit/languages/LanguageSrTest.php199
-rw-r--r--tests/phpunit/languages/LanguageTest.php591
-rw-r--r--tests/phpunit/languages/LanguageTiTest.php32
-rw-r--r--tests/phpunit/languages/LanguageTlTest.php32
-rw-r--r--tests/phpunit/languages/LanguageTrTest.php9
-rw-r--r--tests/phpunit/languages/LanguageUkTest.php54
-rw-r--r--tests/phpunit/languages/LanguageWaTest.php32
-rw-r--r--tests/phpunit/phpunit.php4
-rw-r--r--tests/phpunit/skins/SideBarTest.php9
-rw-r--r--tests/phpunit/suite.xml19
-rw-r--r--tests/phpunit/suites/UploadFromUrlTestSuite.php74
152 files changed, 8682 insertions, 2054 deletions
diff --git a/tests/phpunit/Makefile b/tests/phpunit/Makefile
index 24536efc..8a55dae0 100644
--- a/tests/phpunit/Makefile
+++ b/tests/phpunit/Makefile
@@ -46,17 +46,26 @@ coverage:
parser:
${PU} --group Parser
+parserfuzz:
+ @echo "******************************************************************"
+ @echo "* This WILL kill your computer by eating all memory AND all swap *"
+ @echo "* *"
+ @echo "* If you are on a production machine. ABORT NOW!! *"
+ @echo "* Press control+C to stop *"
+ @echo "* *"
+ @echo "******************************************************************"
+ ${PU} --group Parser,ParserFuzz
noparser:
- ${PU} --exclude-group Parser,Broken,Stub
+ ${PU} --exclude-group Parser,Broken,ParserFuzz,Stub
safe:
- ${PU} --exclude-group Broken,Destructive,Stub
+ ${PU} --exclude-group Broken,ParserFuzz,Destructive,Stub
databaseless:
- ${PU} --exclude-group Broken,Destructive,Database,Stub
+ ${PU} --exclude-group Broken,ParserFuzz,Destructive,Database,Stub
database:
- ${PU} --exclude-group Broken,Destructive,Stub --group Database
+ ${PU} --exclude-group Broken,ParserFuzz,Destructive,Stub --group Database
list-groups:
${PU} --list-groups
diff --git a/tests/phpunit/MediaWikiLangTestCase.php b/tests/phpunit/MediaWikiLangTestCase.php
index 1cd6a3ba..783f0315 100644
--- a/tests/phpunit/MediaWikiLangTestCase.php
+++ b/tests/phpunit/MediaWikiLangTestCase.php
@@ -13,7 +13,11 @@ abstract class MediaWikiLangTestCase extends MediaWikiTestCase {
self::$oldLang = $wgLang;
self::$oldContLang = $wgContLang;
- if( $wgLanguageCode != $wgContLang->getCode() ) die("nooo!");
+ if( $wgLanguageCode != $wgContLang->getCode() ) {
+ throw new MWException("Error in MediaWikiLangTestCase::setUp(): " .
+ "\$wgLanguageCode ('$wgLanguageCode') is different from " .
+ "\$wgContLang->getCode() (" . $wgContLang->getCode() . ")" );
+ }
$wgLanguageCode = 'en'; # For mainpage to be 'Main Page'
diff --git a/tests/phpunit/MediaWikiPHPUnitCommand.php b/tests/phpunit/MediaWikiPHPUnitCommand.php
index c0d9f363..ea385ad9 100644
--- a/tests/phpunit/MediaWikiPHPUnitCommand.php
+++ b/tests/phpunit/MediaWikiPHPUnitCommand.php
@@ -5,7 +5,10 @@ class MediaWikiPHPUnitCommand extends PHPUnit_TextUI_Command {
static $additionalOptions = array(
'regex=' => false,
'file=' => false,
+ 'use-filebackend=' => false,
'keep-uploads' => false,
+ 'use-normal-tables' => false,
+ 'reuse-db' => false,
);
public function __construct() {
@@ -17,6 +20,28 @@ class MediaWikiPHPUnitCommand extends PHPUnit_TextUI_Command {
public static function main( $exit = true ) {
$command = new self;
+
+ if( wfIsWindows() ) {
+ # Windows does not come anymore with ANSI.SYS loaded by default
+ # PHPUnit uses the suite.xml parameters to enable/disable colors
+ # which can be then forced to be enabled with --colors.
+ # The below code inject a parameter just like if the user called
+ # phpunit with a --no-color option (which does not exist). It
+ # overrides the suite.xml setting.
+ # Probably fix bug 29226
+ $command->arguments['colors'] = false;
+ }
+
+ # Makes MediaWiki PHPUnit directory includable so the PHPUnit will
+ # be able to resolve relative files inclusion such as suites/*
+ # PHPUnit uses stream_resolve_include_path() internally
+ # See bug 32022
+ set_include_path(
+ dirname( __FILE__ )
+ .PATH_SEPARATOR
+ . get_include_path()
+ );
+
$command->run($_SERVER['argv'], $exit);
}
@@ -40,6 +65,11 @@ ParserTest-specific options:
--keep-uploads Re-use the same upload directory for each test, don't delete it
+Database options:
+ --use-normal-tables Use normal DB tables.
+ --reuse-db Init DB only if tables are missing and keep after finish.
+
+
EOT;
}
diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php
index 64cb486b..6ec8bdc7 100644
--- a/tests/phpunit/MediaWikiTestCase.php
+++ b/tests/phpunit/MediaWikiTestCase.php
@@ -11,6 +11,9 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
protected $db;
protected $oldTablePrefix;
protected $useTemporaryTables = true;
+ protected $reuseDB = false;
+ protected $tablesUsed = array(); // tables with data
+
private static $dbSetup = false;
/**
@@ -22,6 +25,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
protected $supportedDBs = array(
'mysql',
'sqlite',
+ 'postgres',
'oracle'
);
@@ -40,8 +44,10 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
ObjectCache::$instances[CACHE_DB] = new HashBagOStuff;
if( $this->needsDB() ) {
-
global $wgDBprefix;
+
+ $this->useTemporaryTables = !$this->getCliArg( 'use-normal-tables' );
+ $this->reuseDB = $this->getCliArg('reuse-db');
$this->db = wfGetDB( DB_MASTER );
@@ -81,6 +87,34 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
function addDBData() {}
private function addCoreDBData() {
+ # disabled for performance
+ #$this->tablesUsed[] = 'page';
+ #$this->tablesUsed[] = 'revision';
+
+ if ( $this->db->getType() == 'oracle' ) {
+
+ # Insert 0 user to prevent FK violations
+ # Anonymous user
+ $this->db->insert( 'user', array(
+ 'user_id' => 0,
+ 'user_name' => 'Anonymous' ), __METHOD__, array( 'IGNORE' ) );
+
+ # Insert 0 page to prevent FK violations
+ # Blank page
+ $this->db->insert( 'page', array(
+ 'page_id' => 0,
+ 'page_namespace' => 0,
+ 'page_title' => ' ',
+ 'page_restrictions' => NULL,
+ 'page_counter' => 0,
+ 'page_is_redirect' => 0,
+ 'page_is_new' => 0,
+ 'page_random' => 0,
+ 'page_touched' => $this->db->timestamp(),
+ 'page_latest' => 0,
+ 'page_len' => 0 ), __METHOD__, array( 'IGNORE' ) );
+
+ }
User::resetIdByNameCache();
@@ -98,12 +132,14 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
//Make 1 page with 1 revision
- $article = new Article( Title::newFromText( 'UTPage' ) );
- $article->doEdit( 'UTContent',
+ $page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
+ if ( !$page->getId() == 0 ) {
+ $page->doEdit( 'UTContent',
'UTPageSummary',
EDIT_NEW,
false,
User::newFromName( 'UTSysop' ) );
+ }
}
private function initDB() {
@@ -112,18 +148,20 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
throw new MWException( 'Cannot run unit tests, the database prefix is already "unittest_"' );
}
- $dbClone = new CloneDatabase( $this->db, $this->listTables(), $this->dbPrefix() );
+ $tablesCloned = $this->listTables();
+ $dbClone = new CloneDatabase( $this->db, $tablesCloned, $this->dbPrefix() );
$dbClone->useTemporaryTables( $this->useTemporaryTables );
- $dbClone->cloneTableStructure();
+
+ if ( ( $this->db->getType() == 'oracle' || !$this->useTemporaryTables ) && $this->reuseDB ) {
+ CloneDatabase::changePrefix( $this->dbPrefix() );
+ $this->resetDB();
+ return;
+ } else {
+ $dbClone->cloneTableStructure();
+ }
if ( $this->db->getType() == 'oracle' ) {
$this->db->query( 'BEGIN FILL_WIKI_INFO; END;' );
-
- # Insert 0 user to prevent FK violations
- # Anonymous user
- $this->db->insert( 'user', array(
- 'user_id' => 0,
- 'user_name' => 'Anonymous' ) );
}
}
@@ -132,35 +170,25 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
*/
private function resetDB() {
if( $this->db ) {
- foreach( $this->listTables() as $tbl ) {
- if( $tbl == 'interwiki' || $tbl == 'user' ) continue;
- $this->db->delete( $tbl, '*', __METHOD__ );
+ if ( $this->db->getType() == 'oracle' ) {
+ if ( $this->useTemporaryTables ) {
+ wfGetLB()->closeAll();
+ $this->db = wfGetDB( DB_MASTER );
+ } else {
+ foreach( $this->tablesUsed as $tbl ) {
+ if( $tbl == 'interwiki') continue;
+ $this->db->query( 'TRUNCATE TABLE '.$this->db->tableName($tbl), __METHOD__ );
+ }
+ }
+ } else {
+ foreach( $this->tablesUsed as $tbl ) {
+ if( $tbl == 'interwiki' || $tbl == 'user' ) continue;
+ $this->db->delete( $tbl, '*', __METHOD__ );
+ }
}
}
}
- protected function destroyDB() {
- if ( $this->useTemporaryTables || is_null( $this->db ) ) {
- # Don't need to do anything
- return;
- }
-
- $tables = $this->db->listTables( $this->dbPrefix(), __METHOD__ );
-
- foreach ( $tables as $table ) {
- try {
- $sql = $this->db->getType() == 'oracle' ? "DROP TABLE $table CASCADE CONSTRAINTS PURGE" : "DROP TABLE `$table`";
- $this->db->query( $sql, __METHOD__ );
- } catch( MWException $mwe ) {}
- }
-
- if ( $this->db->getType() == 'oracle' )
- $this->db->query( 'BEGIN FILL_WIKI_INFO; END;', __METHOD__ );
-
- CloneDatabase::changePrefix( $this->oldTablePrefix );
- }
-
-
function __call( $func, $args ) {
static $compatibility = array(
'assertInternalType' => 'assertType',
@@ -235,5 +263,16 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
public static function disableInterwikis( $prefix, &$data ) {
return false;
}
-}
+ /**
+ * Don't throw a warning if $function is deprecated and called later
+ *
+ * @param $function String
+ * @return null
+ */
+ function hideDeprecated( $function ) {
+ wfSuppressWarnings();
+ wfDeprecated( $function );
+ wfRestoreWarnings();
+ }
+}
diff --git a/tests/phpunit/StructureTest.php b/tests/phpunit/StructureTest.php
new file mode 100644
index 00000000..f967c18d
--- /dev/null
+++ b/tests/phpunit/StructureTest.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * The tests here verify the structure of the code. This is for outright bugs,
+ * not just style issues.
+ */
+
+class StructureTest extends MediaWikiTestCase {
+ /**
+ * Verify all files that appear to be tests have file names ending in
+ * Test. If the file names do not end in Test, they will not be run.
+ */
+ public function testUnitTestFileNamesEndWithTest() {
+ if ( wfIsWindows() ) {
+ $this->markTestSkipped( 'This test does not work on Windows' );
+ }
+ $rootPath = escapeshellarg( __DIR__ );
+ $testClassRegex = implode( '|', array(
+ 'ApiFormatTestBase',
+ 'ApiTestCase',
+ 'MediaWikiLangTestCase',
+ 'MediaWikiTestCase',
+ 'PHPUnit_Framework_TestCase',
+ ) );
+ $testClassRegex = "^class .* extends ($testClassRegex)";
+ $finder = "find $rootPath -name '*.php' '!' -name '*Test.php'" .
+ " | xargs grep -El '$testClassRegex|function suite\('";
+
+ $results = null;
+ $exitCode = null;
+ exec($finder, $results, $exitCode);
+
+ $this->assertEquals(
+ 0,
+ $exitCode,
+ 'Verify find/grep command succeeds.'
+ );
+
+ $results = array_filter(
+ $results,
+ array( $this, 'filterSuites' )
+ );
+
+ $this->assertEquals(
+ array(),
+ $results,
+ 'Unit test file names must end with Test.'
+ );
+ }
+
+ /**
+ * Filter to remove testUnitTestFileNamesEndWithTest false positives.
+ */
+ public function filterSuites( $filename ) {
+ return strpos( $filename, __DIR__ . '/suites/' ) !== 0;
+ }
+}
diff --git a/tests/phpunit/data/db/mysql/functions.sql b/tests/phpunit/data/db/mysql/functions.sql
new file mode 100644
index 00000000..9e5e470f
--- /dev/null
+++ b/tests/phpunit/data/db/mysql/functions.sql
@@ -0,0 +1,12 @@
+-- MySQL test file for DatabaseTest::testStoredFunctions()
+
+DELIMITER //
+
+CREATE FUNCTION mw_test_function()
+RETURNS int DETERMINISTIC
+BEGIN
+ SET @foo = 21;
+ RETURN @foo * 2;
+END//
+
+DELIMITER //
diff --git a/tests/phpunit/data/db/postgres/functions.sql b/tests/phpunit/data/db/postgres/functions.sql
new file mode 100644
index 00000000..3086d4d5
--- /dev/null
+++ b/tests/phpunit/data/db/postgres/functions.sql
@@ -0,0 +1,12 @@
+-- Postgres test file for DatabaseTest::testStoredFunctions()
+
+CREATE FUNCTION mw_test_function()
+RETURNS INTEGER
+LANGUAGE plpgsql AS
+$mw$
+DECLARE foo INTEGER;
+BEGIN
+ foo := 21;
+ RETURN foo * 2;
+END
+$mw$;
diff --git a/tests/phpunit/includes/db/sqlite/tables-1.13.sql b/tests/phpunit/data/db/sqlite/tables-1.13.sql
index a0dcb553..66847ab1 100644
--- a/tests/phpunit/includes/db/sqlite/tables-1.13.sql
+++ b/tests/phpunit/data/db/sqlite/tables-1.13.sql
@@ -123,7 +123,7 @@ CREATE TABLE /*$wgDBprefix*/site_stats (
ss_images INTEGER default '0') /*$wgDBTableOptions*/;
CREATE TABLE /*$wgDBprefix*/hitcounter (
- hc_id INTEGER
+ hc_id INTEGER
) ;
CREATE TABLE /*$wgDBprefix*/ipblocks (
diff --git a/tests/phpunit/includes/db/sqlite/tables-1.15.sql b/tests/phpunit/data/db/sqlite/tables-1.15.sql
index 901bac52..6b3a628e 100644
--- a/tests/phpunit/includes/db/sqlite/tables-1.15.sql
+++ b/tests/phpunit/data/db/sqlite/tables-1.15.sql
@@ -141,7 +141,7 @@ CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from);
CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60));
CREATE TABLE /*_*/langlinks (
ll_from int unsigned NOT NULL default 0,
-
+
ll_lang varbinary(20) NOT NULL default '',
ll_title varchar(255) binary NOT NULL default ''
) /*$wgDBTableOptions*/;
@@ -181,7 +181,7 @@ CREATE TABLE /*_*/ipblocks (
ipb_block_email bool NOT NULL default 0,
ipb_allow_usertalk bool NOT NULL default 0
) /*$wgDBTableOptions*/;
-
+
CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only);
CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user);
CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8));
diff --git a/tests/phpunit/includes/db/sqlite/tables-1.16.sql b/tests/phpunit/data/db/sqlite/tables-1.16.sql
index 6e56add2..6e56add2 100644
--- a/tests/phpunit/includes/db/sqlite/tables-1.16.sql
+++ b/tests/phpunit/data/db/sqlite/tables-1.16.sql
diff --git a/tests/phpunit/includes/db/sqlite/tables-1.17.sql b/tests/phpunit/data/db/sqlite/tables-1.17.sql
index 69ae3764..69ae3764 100644
--- a/tests/phpunit/includes/db/sqlite/tables-1.17.sql
+++ b/tests/phpunit/data/db/sqlite/tables-1.17.sql
diff --git a/tests/phpunit/data/db/sqlite/tables-1.18.sql b/tests/phpunit/data/db/sqlite/tables-1.18.sql
new file mode 100644
index 00000000..bedf6c33
--- /dev/null
+++ b/tests/phpunit/data/db/sqlite/tables-1.18.sql
@@ -0,0 +1,535 @@
+-- This is a copy of MediaWiki 1.18 schema shared by MySQL and SQLite.
+-- It is used for updater testing. Comments are stripped to decrease
+-- file size, as we don't need to maintain it.
+
+CREATE TABLE /*_*/user (
+ user_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ user_name varchar(255) binary NOT NULL default '',
+ user_real_name varchar(255) binary NOT NULL default '',
+ user_password tinyblob NOT NULL,
+ user_newpassword tinyblob NOT NULL,
+ user_newpass_time binary(14),
+ user_email tinytext NOT NULL,
+ user_options blob NOT NULL,
+ user_touched binary(14) NOT NULL default '',
+ user_token binary(32) NOT NULL default '',
+ user_email_authenticated binary(14),
+ user_email_token binary(32),
+ user_email_token_expires binary(14),
+ user_registration binary(14),
+ user_editcount int
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/user_name ON /*_*/user (user_name);
+CREATE INDEX /*i*/user_email_token ON /*_*/user (user_email_token);
+CREATE INDEX /*i*/user_email ON /*_*/user (user_email(50));
+CREATE TABLE /*_*/user_groups (
+ ug_user int unsigned NOT NULL default 0,
+ ug_group varbinary(16) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group);
+CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group);
+CREATE TABLE /*_*/user_former_groups (
+ ufg_user int unsigned NOT NULL default 0,
+ ufg_group varbinary(16) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group);
+CREATE TABLE /*_*/user_newtalk (
+ user_id int NOT NULL default 0,
+ user_ip varbinary(40) NOT NULL default '',
+ user_last_timestamp varbinary(14) NULL default NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/un_user_id ON /*_*/user_newtalk (user_id);
+CREATE INDEX /*i*/un_user_ip ON /*_*/user_newtalk (user_ip);
+CREATE TABLE /*_*/user_properties (
+ up_user int NOT NULL,
+ up_property varbinary(255) NOT NULL,
+ up_value blob
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/user_properties_user_property ON /*_*/user_properties (up_user,up_property);
+CREATE INDEX /*i*/user_properties_property ON /*_*/user_properties (up_property);
+CREATE TABLE /*_*/page (
+ page_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ page_namespace int NOT NULL,
+ page_title varchar(255) binary NOT NULL,
+ page_restrictions tinyblob NOT NULL,
+ page_counter bigint unsigned NOT NULL default 0,
+ page_is_redirect tinyint unsigned NOT NULL default 0,
+ page_is_new tinyint unsigned NOT NULL default 0,
+ page_random real unsigned NOT NULL,
+ page_touched binary(14) NOT NULL default '',
+ page_latest int unsigned NOT NULL,
+ page_len int unsigned NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title);
+CREATE INDEX /*i*/page_random ON /*_*/page (page_random);
+CREATE INDEX /*i*/page_len ON /*_*/page (page_len);
+CREATE TABLE /*_*/revision (
+ rev_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ rev_page int unsigned NOT NULL,
+ rev_text_id int unsigned NOT NULL,
+ rev_comment tinyblob NOT NULL,
+ rev_user int unsigned NOT NULL default 0,
+ rev_user_text varchar(255) binary NOT NULL default '',
+ rev_timestamp binary(14) NOT NULL default '',
+ rev_minor_edit tinyint unsigned NOT NULL default 0,
+ rev_deleted tinyint unsigned NOT NULL default 0,
+ rev_len int unsigned,
+ rev_parent_id int unsigned default NULL
+) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024;
+CREATE UNIQUE INDEX /*i*/rev_page_id ON /*_*/revision (rev_page, rev_id);
+CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp);
+CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp);
+CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp);
+CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp);
+CREATE TABLE /*_*/text (
+ old_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ old_text mediumblob NOT NULL,
+ old_flags tinyblob NOT NULL
+) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=10240;
+CREATE TABLE /*_*/archive (
+ ar_namespace int NOT NULL default 0,
+ ar_title varchar(255) binary NOT NULL default '',
+ ar_text mediumblob NOT NULL,
+ ar_comment tinyblob NOT NULL,
+ ar_user int unsigned NOT NULL default 0,
+ ar_user_text varchar(255) binary NOT NULL,
+ ar_timestamp binary(14) NOT NULL default '',
+ ar_minor_edit tinyint NOT NULL default 0,
+ ar_flags tinyblob NOT NULL,
+ ar_rev_id int unsigned,
+ ar_text_id int unsigned,
+ ar_deleted tinyint unsigned NOT NULL default 0,
+ ar_len int unsigned,
+ ar_page_id int unsigned,
+ ar_parent_id int unsigned default NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
+CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
+CREATE TABLE /*_*/pagelinks (
+ pl_from int unsigned NOT NULL default 0,
+ pl_namespace int NOT NULL default 0,
+ pl_title varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title);
+CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from);
+CREATE TABLE /*_*/templatelinks (
+ tl_from int unsigned NOT NULL default 0,
+ tl_namespace int NOT NULL default 0,
+ tl_title varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title);
+CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from);
+CREATE TABLE /*_*/imagelinks (
+ il_from int unsigned NOT NULL default 0,
+ il_to varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to);
+CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from);
+CREATE TABLE /*_*/categorylinks (
+ cl_from int unsigned NOT NULL default 0,
+ cl_to varchar(255) binary NOT NULL default '',
+ cl_sortkey varbinary(230) NOT NULL default '',
+ cl_sortkey_prefix varchar(255) binary NOT NULL default '',
+ cl_timestamp timestamp NOT NULL,
+ cl_collation varbinary(32) NOT NULL default '',
+ cl_type ENUM('page', 'subcat', 'file') NOT NULL default 'page'
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to);
+CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_sortkey,cl_from);
+CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp);
+CREATE INDEX /*i*/cl_collation ON /*_*/categorylinks (cl_collation);
+CREATE TABLE /*_*/category (
+ cat_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ cat_title varchar(255) binary NOT NULL,
+ cat_pages int signed NOT NULL default 0,
+ cat_subcats int signed NOT NULL default 0,
+ cat_files int signed NOT NULL default 0,
+ cat_hidden tinyint unsigned NOT NULL default 0
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title);
+CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages);
+CREATE TABLE /*_*/externallinks (
+ el_from int unsigned NOT NULL default 0,
+ el_to blob NOT NULL,
+ el_index blob NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40));
+CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from);
+CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60));
+CREATE TABLE /*_*/external_user (
+ eu_local_id int unsigned NOT NULL PRIMARY KEY,
+ eu_external_id varchar(255) binary NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id);
+CREATE TABLE /*_*/langlinks (
+ ll_from int unsigned NOT NULL default 0,
+ ll_lang varbinary(20) NOT NULL default '',
+ ll_title varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/ll_from ON /*_*/langlinks (ll_from, ll_lang);
+CREATE INDEX /*i*/ll_lang ON /*_*/langlinks (ll_lang, ll_title);
+CREATE TABLE /*_*/iwlinks (
+ iwl_from int unsigned NOT NULL default 0,
+ iwl_prefix varbinary(20) NOT NULL default '',
+ iwl_title varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/iwl_from ON /*_*/iwlinks (iwl_from, iwl_prefix, iwl_title);
+CREATE UNIQUE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from);
+CREATE TABLE /*_*/site_stats (
+ ss_row_id int unsigned NOT NULL,
+ ss_total_views bigint unsigned default 0,
+ ss_total_edits bigint unsigned default 0,
+ ss_good_articles bigint unsigned default 0,
+ ss_total_pages bigint default '-1',
+ ss_users bigint default '-1',
+ ss_active_users bigint default '-1',
+ ss_admins int default '-1',
+ ss_images int default 0
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id);
+CREATE TABLE /*_*/hitcounter (
+ hc_id int unsigned NOT NULL
+) ENGINE=HEAP MAX_ROWS=25000;
+CREATE TABLE /*_*/ipblocks (
+ ipb_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ ipb_address tinyblob NOT NULL,
+ ipb_user int unsigned NOT NULL default 0,
+ ipb_by int unsigned NOT NULL default 0,
+ ipb_by_text varchar(255) binary NOT NULL default '',
+ ipb_reason tinyblob NOT NULL,
+ ipb_timestamp binary(14) NOT NULL default '',
+ ipb_auto bool NOT NULL default 0,
+ ipb_anon_only bool NOT NULL default 0,
+ ipb_create_account bool NOT NULL default 1,
+ ipb_enable_autoblock bool NOT NULL default '1',
+ ipb_expiry varbinary(14) NOT NULL default '',
+ ipb_range_start tinyblob NOT NULL,
+ ipb_range_end tinyblob NOT NULL,
+ ipb_deleted bool NOT NULL default 0,
+ ipb_block_email bool NOT NULL default 0,
+ ipb_allow_usertalk bool NOT NULL default 0
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only);
+CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user);
+CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8));
+CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp);
+CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry);
+CREATE TABLE /*_*/image (
+ img_name varchar(255) binary NOT NULL default '' PRIMARY KEY,
+ img_size int unsigned NOT NULL default 0,
+ img_width int NOT NULL default 0,
+ img_height int NOT NULL default 0,
+ img_metadata mediumblob NOT NULL,
+ img_bits int NOT NULL default 0,
+ img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown",
+ img_minor_mime varbinary(100) NOT NULL default "unknown",
+ img_description tinyblob NOT NULL,
+ img_user int unsigned NOT NULL default 0,
+ img_user_text varchar(255) binary NOT NULL,
+ img_timestamp varbinary(14) NOT NULL default '',
+ img_sha1 varbinary(32) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp);
+CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
+CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp);
+CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1);
+CREATE TABLE /*_*/oldimage (
+ oi_name varchar(255) binary NOT NULL default '',
+ oi_archive_name varchar(255) binary NOT NULL default '',
+ oi_size int unsigned NOT NULL default 0,
+ oi_width int NOT NULL default 0,
+ oi_height int NOT NULL default 0,
+ oi_bits int NOT NULL default 0,
+ oi_description tinyblob NOT NULL,
+ oi_user int unsigned NOT NULL default 0,
+ oi_user_text varchar(255) binary NOT NULL,
+ oi_timestamp binary(14) NOT NULL default '',
+ oi_metadata mediumblob NOT NULL,
+ oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown",
+ oi_minor_mime varbinary(100) NOT NULL default "unknown",
+ oi_deleted tinyint unsigned NOT NULL default 0,
+ oi_sha1 varbinary(32) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp);
+CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14));
+CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1);
+CREATE TABLE /*_*/filearchive (
+ fa_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ fa_name varchar(255) binary NOT NULL default '',
+ fa_archive_name varchar(255) binary default '',
+ fa_storage_group varbinary(16),
+ fa_storage_key varbinary(64) default '',
+ fa_deleted_user int,
+ fa_deleted_timestamp binary(14) default '',
+ fa_deleted_reason text,
+ fa_size int unsigned default 0,
+ fa_width int default 0,
+ fa_height int default 0,
+ fa_metadata mediumblob,
+ fa_bits int default 0,
+ fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") default "unknown",
+ fa_minor_mime varbinary(100) default "unknown",
+ fa_description tinyblob,
+ fa_user int unsigned default 0,
+ fa_user_text varchar(255) binary,
+ fa_timestamp binary(14) default '',
+ fa_deleted tinyint unsigned NOT NULL default 0
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp);
+CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key);
+CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp);
+CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp);
+CREATE TABLE /*_*/uploadstash (
+ us_id int unsigned NOT NULL PRIMARY KEY auto_increment,
+ us_user int unsigned NOT NULL,
+ us_key varchar(255) NOT NULL,
+ us_orig_path varchar(255) NOT NULL,
+ us_path varchar(255) NOT NULL,
+ us_source_type varchar(50),
+ us_timestamp varbinary(14) not null,
+ us_status varchar(50) not null,
+ us_size int unsigned NOT NULL,
+ us_sha1 varchar(31) NOT NULL,
+ us_mime varchar(255),
+ us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
+ us_image_width int unsigned,
+ us_image_height int unsigned,
+ us_image_bits smallint unsigned
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/us_user ON /*_*/uploadstash (us_user);
+CREATE UNIQUE INDEX /*i*/us_key ON /*_*/uploadstash (us_key);
+CREATE INDEX /*i*/us_timestamp ON /*_*/uploadstash (us_timestamp);
+CREATE TABLE /*_*/recentchanges (
+ rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ rc_timestamp varbinary(14) NOT NULL default '',
+ rc_cur_time varbinary(14) NOT NULL default '',
+ rc_user int unsigned NOT NULL default 0,
+ rc_user_text varchar(255) binary NOT NULL,
+ rc_namespace int NOT NULL default 0,
+ rc_title varchar(255) binary NOT NULL default '',
+ rc_comment varchar(255) binary NOT NULL default '',
+ rc_minor tinyint unsigned NOT NULL default 0,
+ rc_bot tinyint unsigned NOT NULL default 0,
+ rc_new tinyint unsigned NOT NULL default 0,
+ rc_cur_id int unsigned NOT NULL default 0,
+ rc_this_oldid int unsigned NOT NULL default 0,
+ rc_last_oldid int unsigned NOT NULL default 0,
+ rc_type tinyint unsigned NOT NULL default 0,
+ rc_moved_to_ns tinyint unsigned NOT NULL default 0,
+ rc_moved_to_title varchar(255) binary NOT NULL default '',
+ rc_patrolled tinyint unsigned NOT NULL default 0,
+ rc_ip varbinary(40) NOT NULL default '',
+ rc_old_len int,
+ rc_new_len int,
+ rc_deleted tinyint unsigned NOT NULL default 0,
+ rc_logid int unsigned NOT NULL default 0,
+ rc_log_type varbinary(255) NULL default NULL,
+ rc_log_action varbinary(255) NULL default NULL,
+ rc_params blob NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
+CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
+CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp);
+CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
+CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text);
+CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp);
+CREATE TABLE /*_*/watchlist (
+ wl_user int unsigned NOT NULL,
+ wl_namespace int NOT NULL default 0,
+ wl_title varchar(255) binary NOT NULL default '',
+ wl_notificationtimestamp varbinary(14)
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/wl_user ON /*_*/watchlist (wl_user, wl_namespace, wl_title);
+CREATE INDEX /*i*/namespace_title ON /*_*/watchlist (wl_namespace, wl_title);
+CREATE TABLE /*_*/searchindex (
+ si_page int unsigned NOT NULL,
+ si_title varchar(255) NOT NULL default '',
+ si_text mediumtext NOT NULL
+) ENGINE=MyISAM;
+CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page);
+CREATE FULLTEXT INDEX /*i*/si_title ON /*_*/searchindex (si_title);
+CREATE FULLTEXT INDEX /*i*/si_text ON /*_*/searchindex (si_text);
+CREATE TABLE /*_*/interwiki (
+ iw_prefix varchar(32) NOT NULL,
+ iw_url blob NOT NULL,
+ iw_api blob NOT NULL,
+ iw_wikiid varchar(64) NOT NULL,
+ iw_local bool NOT NULL,
+ iw_trans tinyint NOT NULL default 0
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/iw_prefix ON /*_*/interwiki (iw_prefix);
+CREATE TABLE /*_*/querycache (
+ qc_type varbinary(32) NOT NULL,
+ qc_value int unsigned NOT NULL default 0,
+ qc_namespace int NOT NULL default 0,
+ qc_title varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/qc_type ON /*_*/querycache (qc_type,qc_value);
+CREATE TABLE /*_*/objectcache (
+ keyname varbinary(255) NOT NULL default '' PRIMARY KEY,
+ value mediumblob,
+ exptime datetime
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime);
+CREATE TABLE /*_*/transcache (
+ tc_url varbinary(255) NOT NULL,
+ tc_contents text,
+ tc_time binary(14) NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url);
+CREATE TABLE /*_*/logging (
+ log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ log_type varbinary(32) NOT NULL default '',
+ log_action varbinary(32) NOT NULL default '',
+ log_timestamp binary(14) NOT NULL default '19700101000000',
+ log_user int unsigned NOT NULL default 0,
+ log_user_text varchar(255) binary NOT NULL default '',
+ log_namespace int NOT NULL default 0,
+ log_title varchar(255) binary NOT NULL default '',
+ log_page int unsigned NULL,
+ log_comment varchar(255) NOT NULL default '',
+ log_params blob NOT NULL,
+ log_deleted tinyint unsigned NOT NULL default 0
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp);
+CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp);
+CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp);
+CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
+CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp);
+CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp);
+CREATE TABLE /*_*/log_search (
+ ls_field varbinary(32) NOT NULL,
+ ls_value varchar(255) NOT NULL,
+ ls_log_id int unsigned NOT NULL default 0
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/ls_field_val ON /*_*/log_search (ls_field,ls_value,ls_log_id);
+CREATE INDEX /*i*/ls_log_id ON /*_*/log_search (ls_log_id);
+CREATE TABLE /*_*/trackbacks (
+ tb_id int PRIMARY KEY AUTO_INCREMENT,
+ tb_page int REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+ tb_title varchar(255) NOT NULL,
+ tb_url blob NOT NULL,
+ tb_ex text,
+ tb_name varchar(255)
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/tb_page ON /*_*/trackbacks (tb_page);
+CREATE TABLE /*_*/job (
+ job_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ job_cmd varbinary(60) NOT NULL default '',
+ job_namespace int NOT NULL,
+ job_title varchar(255) binary NOT NULL,
+ job_params blob NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title, job_params(128));
+CREATE TABLE /*_*/querycache_info (
+ qci_type varbinary(32) NOT NULL default '',
+ qci_timestamp binary(14) NOT NULL default '19700101000000'
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/qci_type ON /*_*/querycache_info (qci_type);
+CREATE TABLE /*_*/redirect (
+ rd_from int unsigned NOT NULL default 0 PRIMARY KEY,
+ rd_namespace int NOT NULL default 0,
+ rd_title varchar(255) binary NOT NULL default '',
+ rd_interwiki varchar(32) default NULL,
+ rd_fragment varchar(255) binary default NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/rd_ns_title ON /*_*/redirect (rd_namespace,rd_title,rd_from);
+CREATE TABLE /*_*/querycachetwo (
+ qcc_type varbinary(32) NOT NULL,
+ qcc_value int unsigned NOT NULL default 0,
+ qcc_namespace int NOT NULL default 0,
+ qcc_title varchar(255) binary NOT NULL default '',
+ qcc_namespacetwo int NOT NULL default 0,
+ qcc_titletwo varchar(255) binary NOT NULL default ''
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/qcc_type ON /*_*/querycachetwo (qcc_type,qcc_value);
+CREATE INDEX /*i*/qcc_title ON /*_*/querycachetwo (qcc_type,qcc_namespace,qcc_title);
+CREATE INDEX /*i*/qcc_titletwo ON /*_*/querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo);
+CREATE TABLE /*_*/page_restrictions (
+ pr_page int NOT NULL,
+ pr_type varbinary(60) NOT NULL,
+ pr_level varbinary(60) NOT NULL,
+ pr_cascade tinyint NOT NULL,
+ pr_user int NULL,
+ pr_expiry varbinary(14) NULL,
+ pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions (pr_page,pr_type);
+CREATE INDEX /*i*/pr_typelevel ON /*_*/page_restrictions (pr_type,pr_level);
+CREATE INDEX /*i*/pr_level ON /*_*/page_restrictions (pr_level);
+CREATE INDEX /*i*/pr_cascade ON /*_*/page_restrictions (pr_cascade);
+CREATE TABLE /*_*/protected_titles (
+ pt_namespace int NOT NULL,
+ pt_title varchar(255) binary NOT NULL,
+ pt_user int unsigned NOT NULL,
+ pt_reason tinyblob,
+ pt_timestamp binary(14) NOT NULL,
+ pt_expiry varbinary(14) NOT NULL default '',
+ pt_create_perm varbinary(60) NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/pt_namespace_title ON /*_*/protected_titles (pt_namespace,pt_title);
+CREATE INDEX /*i*/pt_timestamp ON /*_*/protected_titles (pt_timestamp);
+CREATE TABLE /*_*/page_props (
+ pp_page int NOT NULL,
+ pp_propname varbinary(60) NOT NULL,
+ pp_value blob NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname);
+CREATE TABLE /*_*/updatelog (
+ ul_key varchar(255) NOT NULL PRIMARY KEY,
+ ul_value blob
+) /*$wgDBTableOptions*/;
+CREATE TABLE /*_*/change_tag (
+ ct_rc_id int NULL,
+ ct_log_id int NULL,
+ ct_rev_id int NULL,
+ ct_tag varchar(255) NOT NULL,
+ ct_params blob NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag);
+CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
+CREATE TABLE /*_*/tag_summary (
+ ts_rc_id int NULL,
+ ts_log_id int NULL,
+ ts_rev_id int NULL,
+ ts_tags blob NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id);
+CREATE TABLE /*_*/valid_tag (
+ vt_tag varchar(255) NOT NULL PRIMARY KEY
+) /*$wgDBTableOptions*/;
+CREATE TABLE /*_*/l10n_cache (
+ lc_lang varbinary(32) NOT NULL,
+ lc_key varchar(255) NOT NULL,
+ lc_value mediumblob NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/lc_lang_key ON /*_*/l10n_cache (lc_lang, lc_key);
+CREATE TABLE /*_*/msg_resource (
+ mr_resource varbinary(255) NOT NULL,
+ mr_lang varbinary(32) NOT NULL,
+ mr_blob mediumblob NOT NULL,
+ mr_timestamp binary(14) NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/mr_resource_lang ON /*_*/msg_resource (mr_resource, mr_lang);
+CREATE TABLE /*_*/msg_resource_links (
+ mrl_resource varbinary(255) NOT NULL,
+ mrl_message varbinary(255) NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/mrl_message_resource ON /*_*/msg_resource_links (mrl_message, mrl_resource);
+CREATE TABLE /*_*/module_deps (
+ md_module varbinary(255) NOT NULL,
+ md_skin varbinary(32) NOT NULL,
+ md_deps mediumblob NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE UNIQUE INDEX /*i*/md_module_skin ON /*_*/module_deps (md_module, md_skin);
+
diff --git a/tests/phpunit/data/media/80x60-2layers.xcf b/tests/phpunit/data/media/80x60-2layers.xcf
new file mode 100644
index 00000000..c51e980c
--- /dev/null
+++ b/tests/phpunit/data/media/80x60-2layers.xcf
Binary files differ
diff --git a/tests/phpunit/data/media/80x60-Greyscale.xcf b/tests/phpunit/data/media/80x60-Greyscale.xcf
new file mode 100644
index 00000000..84bf3e67
--- /dev/null
+++ b/tests/phpunit/data/media/80x60-Greyscale.xcf
Binary files differ
diff --git a/tests/phpunit/data/media/80x60-RGB.xcf b/tests/phpunit/data/media/80x60-RGB.xcf
new file mode 100644
index 00000000..1d58f16d
--- /dev/null
+++ b/tests/phpunit/data/media/80x60-RGB.xcf
Binary files differ
diff --git a/tests/phpunit/data/media/Toll_Texas_1.svg b/tests/phpunit/data/media/Toll_Texas_1.svg
new file mode 100644
index 00000000..73004e3e
--- /dev/null
+++ b/tests/phpunit/data/media/Toll_Texas_1.svg
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_svg "http://www.w3.org/2000/svg">
+ <!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
+]>
+<svg version="1.1" id="Layer_1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="385" height="385.0004883"
+ viewBox="0 0 385 385.0004883" overflow="visible" enable-background="new 0 0 385 385.0004883" xml:space="preserve">
+<g>
+ <g>
+ <g>
+ <path fill="#FFFFFF" d="M0.5,24.5c0-13.2548828,10.7451172-24,24-24h336c13.2548828,0,24,10.7451172,24,24v336.0004883
+ c0,13.2548828-10.7451172,24-24,24h-336c-13.2548828,0-24-10.7451172-24-24V24.5L0.5,24.5z"/>
+ <path fill="#FFFFFF" d="M192.5,192.5004883"/>
+ </g>
+ <g>
+ <path fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3.863693" d="M0.5,24.5
+ c0-13.2548828,10.7451172-24,24-24h336c13.2548828,0,24,10.7451172,24,24v336.0004883c0,13.2548828-10.7451172,24-24,24h-336
+ c-13.2548828,0-24-10.7451172-24-24V24.5L0.5,24.5z"/>
+ <path fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3.863693" d="
+ M192.5,192.5004883"/>
+ </g>
+ </g>
+ <g>
+ <path fill="#003882" d="M24.5,0.5h336c13.2548828,0,24,10.7451172,24,24v232.0004883H0.5V24.5
+ C0.5,11.2451172,11.2451172,0.5,24.5,0.5z"/>
+ </g>
+ <g>
+ <path fill="#FFFFFF" d="M10.5,24.5c0-7.7319336,6.2680664-14,14-14h336c7.7324219,0,14,6.2680664,14,14v222.0004883h-364V24.5z"/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#003882" points="93.809082,348.2397461 91.6787109,347.8666992
+ 89.5478516,347.7368164 85.2929688,347.7368164 83.1640625,347.8666992 78.9042969,348.6157227 76.7763672,349.1166992
+ 72.7666016,350.3706055 70.7631836,351.246582 68.8837891,352.121582 67.0053711,353.1254883 65.1254883,354.253418
+ 63.3740234,355.5063477 60.1210938,358.2602539 58.4926758,359.762207 57.1132813,361.2641602 55.7338867,362.8959961
+ 54.3603516,364.6459961 21.2949219,301.3999023 21.168457,301.3999023 22.5478516,299.6469727 23.9248047,298.0200195
+ 25.3022461,296.5180664 26.9296875,295.0141602 30.1875,292.2592773 31.9404297,291.0073242 33.8188477,289.8793945
+ 35.6972656,288.8774414 37.5761719,288.0004883 39.5791016,287.1245117 43.5878906,285.8706055 45.7148438,285.3706055
+ 49.9755859,284.6176758 52.1020508,284.4946289 56.3632813,284.4946289 58.4926758,284.6176758 60.6201172,284.9946289
+ 60.6201172,284.8696289 "/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" points="32.8154297,319.559082 45.0898438,312.4233398
+ 42.2080078,298.5209961 52.7299805,308.0375977 65.1254883,300.9008789 59.2421875,313.9243164 69.8867188,323.4428711
+ 55.7338867,321.9389648 49.8476563,334.965332 46.9677734,321.0629883 "/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#B01C2E" points="132.0053711,306.6606445 148.5385742,338.2211914
+ 147.4101563,339.7241211 146.1577148,341.2270508 144.9052734,342.6020508 143.5302734,343.9848633 142.1494141,345.2358398
+ 140.6484375,346.4868164 139.2705078,347.6157227 137.765625,348.6157227 136.1381836,349.6176758 134.6357422,350.621582
+ 133.0083008,351.3696289 131.3798828,352.246582 129.625,352.8745117 128,353.5024414 126.2441406,354.0004883
+ 124.4921875,354.5043945 122.737793,354.8774414 120.9853516,355.1293945 117.4785156,355.3793945 113.9707031,355.3793945
+ 112.09375,355.2543945 110.3408203,355.003418 108.5854492,354.6274414 106.9589844,354.253418 103.4501953,353.2485352
+ 101.8232422,352.6254883 100.0688477,351.871582 98.4428711,351.1235352 96.9389648,350.1176758 95.3095703,349.2426758
+ 93.809082,348.2397461 93.809082,348.1147461 93.809082,348.2397461 77.1523438,316.4282227 77.2753906,316.4282227
+ 77.2753906,316.5551758 78.78125,317.5581055 80.4057617,318.4350586 81.9116211,319.4360352 83.5395508,320.1860352
+ 85.2929688,320.9399414 86.9208984,321.5649414 90.4257813,322.5668945 92.0551758,322.9418945 93.809082,323.3188477
+ 95.5620117,323.5688477 97.4423828,323.6948242 100.9462891,323.6948242 102.6992188,323.5688477 104.4521484,323.4428711
+ 106.2060547,323.1928711 107.9609375,322.8168945 111.4682617,321.8168945 113.0947266,321.1889648 114.8481445,320.5639648
+ 116.4765625,319.6879883 118.1035156,318.9350586 119.6083984,317.934082 121.2363281,316.9301758 122.737793,315.9282227
+ 124.1152344,314.8012695 125.6196289,313.5483398 126.9960938,312.2983398 128.3759766,310.9194336 129.625,309.5424805
+ 130.8789063,308.0375977 132.0053711,306.5366211 132.1328125,306.5366211 "/>
+ </g>
+ <g>
+
+ <polyline fill="none" stroke="#003882" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3.863693" points="
+ 60.7441406,285.1196289 63,286.4956055 65.2529297,287.7485352 67.5068359,288.8774414 69.8867188,289.8793945
+ 72.3916016,290.6313477 74.8955078,291.3813477 77.4008789,291.7583008 80.0302734,292.1333008 82.5366211,292.2592773
+ 85.1655273,292.2592773 87.6708984,292.0083008 90.3022461,291.6313477 92.8066406,291.1313477 95.3095703,290.3793945
+ 97.6904297,289.5024414 100.0688477,288.5004883 102.3256836,287.2504883 104.578125,285.8706055 106.7070313,284.4946289
+ 108.7124023,282.8637695 110.5888672,281.1108398 112.3427734,279.2329102 114.0986328,277.2290039 115.5976563,275.1010742 "/>
+ </g>
+ <g>
+
+ <line fill="none" stroke="#003882" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3.863693" x1="115.4746094" y1="275.1010742" x2="131.8793945" y2="306.2836914"/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#003882" points="215.1650391,349.1166992 213.1601563,348.2397461
+ 211.2832031,347.237793 207.7773438,344.7329102 206.1503906,343.2319336 204.6435547,341.7270508 203.2685547,340.0991211
+ 202.0166016,338.347168 200.8867188,336.5942383 199.8857422,334.590332 199.0097656,332.7114258 198.2578125,330.7075195
+ 197.6328125,328.5776367 197.1289063,326.5756836 196.7548828,324.4458008 196.6318359,322.3168945 196.6318359,320.0629883
+ 196.7548828,317.934082 197.0058594,315.8041992 197.3818359,313.6743164 198.6357422,309.6665039 199.5107422,307.6635742
+ 200.5126953,305.7827148 201.6386719,303.9067383 202.890625,302.152832 204.2685547,300.3989258 205.6464844,298.8969727
+ 207.2744141,297.3920898 208.9023438,296.0161133 210.6572266,294.887207 212.5361328,293.7602539 214.4130859,292.7602539
+ 216.4179688,291.8833008 218.5449219,291.0073242 220.6767578,290.2543945 222.9306641,289.6274414 227.4384766,288.8774414
+ 229.6933594,288.6254883 231.9482422,288.5004883 234.2011719,288.5004883 236.4541016,288.6254883 238.7119141,288.8774414
+ 240.9638672,289.253418 243.21875,289.7543945 245.3476563,290.3793945 247.6025391,291.1313477 249.6054688,292.0083008
+ 251.7363281,293.0083008 251.7363281,292.8852539 253.6132813,294.137207 255.4931641,295.5151367 257.2460938,297.0161133
+ 258.8740234,298.6459961 260.5019531,300.3989258 261.8808594,302.277832 263.1328125,304.1577148 264.2578125,306.2836914
+ 266.0117188,310.543457 266.6386719,312.7983398 267.390625,317.3051758 267.5136719,319.6879883 267.390625,321.9418945
+ 267.265625,324.3188477 266.2626953,328.8286133 265.5117188,330.9575195 264.6347656,333.2114258 263.6318359,335.2163086
+ 262.5058594,337.2192383 261.1298828,339.0981445 259.625,340.9770508 258.1240234,342.6020508 256.3701172,344.1079102
+ 254.4902344,345.6098633 252.6142578,346.8618164 250.609375,347.9926758 248.4785156,348.9926758 246.3496094,349.8696289
+ 244.2216797,350.621582 242.0927734,351.246582 239.8359375,351.7485352 237.5830078,352.121582 235.3291016,352.3754883
+ 232.9501953,352.4985352 230.6933594,352.4985352 228.4414063,352.3754883 226.1865234,352.121582 223.9296875,351.7485352
+ 221.6777344,351.246582 219.421875,350.746582 217.2949219,349.9946289 "/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" points="219.9238281,303.6547852 221.9287109,301.5258789
+ 224.4335938,299.8999023 227.1904297,298.8969727 230.1943359,298.2700195 233.0742188,298.3959961 235.9550781,299.0219727
+ 238.7119141,300.2739258 241.0898438,301.9018555 243.0957031,304.1577148 244.5957031,306.5366211 245.9746094,308.9145508
+ 246.9765625,311.4204102 247.8535156,314.0512695 248.4785156,316.8051758 248.8535156,319.559082 248.9804688,322.3168945
+ 248.9804688,325.0727539 248.6035156,327.8256836 248.1035156,330.5805664 247.3496094,333.2114258 246.3496094,335.7172852
+ 244.9726563,337.8442383 243.34375,339.6000977 241.3408203,341.1020508 239.2109375,342.355957 236.8330078,343.2319336
+ 234.4511719,343.6049805 231.9482422,343.7319336 229.4414063,343.3579102 227.1904297,342.6020508 224.9326172,341.4770508
+ 222.9306641,340.0991211 221.1757813,338.347168 219.6748047,336.3422852 218.5449219,334.2114258 217.7949219,331.8334961
+ 217.0449219,329.7036133 216.0419922,325.4477539 215.7910156,323.1928711 215.6660156,320.9399414 215.6660156,318.684082
+ 215.9169922,316.4282227 216.1669922,314.300293 216.6679688,312.0454102 217.2949219,309.918457 218.0458984,307.7895508
+ 218.9208984,305.7827148 219.9238281,303.7817383 "/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#003882" points="150.4169922,290.0063477 196.3789063,289.7543945
+ 192.7470703,304.4067383 192.6220703,304.5307617 192.1210938,303.7817383 191.4960938,303.1567383 190.8681641,302.5288086
+ 190.1162109,302.027832 189.2421875,301.652832 188.4887695,301.2768555 187.6113281,301.0258789 186.7353516,300.7758789
+ 179.9741211,300.7758789 179.8481445,345.1098633 179.8481445,345.2358398 180.0966797,346.1118164 180.3486328,347.1157227
+ 180.7246094,347.9926758 181.1005859,348.7407227 181.6015625,349.6176758 182.8549805,351.1235352 183.6054688,351.7485352
+ 158.5556641,351.7485352 158.5556641,351.871582 159.3095703,351.246582 160.0595703,350.4956055 160.6845703,349.7426758
+ 161.1875,348.9926758 161.6879883,347.9926758 161.9384766,347.1157227 162.1894531,346.1118164 162.3144531,345.1098633
+ 162.4375,300.9008789 156.5527344,300.9008789 155.1767578,301.0258789 153.9248047,301.2768555 152.671875,301.5258789
+ 151.4204102,301.9018555 150.1660156,302.4008789 148.9135742,303.0297852 146.6601563,304.2797852 146.6601563,304.4067383 "/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#003882" points="275.7822266,344.3598633 276.03125,298.1450195
+ 275.90625,297.769043 275.90625,297.894043 275.7822266,296.7661133 275.5302734,295.7670898 275.15625,294.6391602
+ 274.7792969,293.637207 272.8984375,291.0073242 272.0234375,290.2543945 272.1484375,290.2543945 297.4492188,290.1313477
+ 296.4453125,290.8803711 295.5683594,291.6313477 294.6904297,292.5083008 294.0673828,293.5102539 293.5644531,294.6391602
+ 293.1904297,295.7670898 293.0644531,297.0161133 293.0644531,298.2700195 293.0644531,298.1450195 293.1904297,298.1450195
+ 293.0644531,340.7260742 292.9394531,340.7260742 294.8183594,341.3540039 296.8222656,341.8540039 298.7011719,342.1040039
+ 300.7050781,342.355957 302.7070313,342.4799805 304.5878906,342.355957 306.5917969,342.2299805 308.46875,341.8540039
+ 311.4746094,340.7260742 312.4765625,340.2231445 313.3535156,339.7241211 314.3535156,339.2241211 316.109375,337.972168
+ 311.8505859,351.621582 271.3984375,351.7485352 272.3994141,351.1235352 273.2753906,350.3706055 274.0292969,349.6176758
+ 275.2802734,347.6157227 275.53125,346.4868164 275.7822266,345.4858398 275.90625,344.2348633 "/>
+ </g>
+ <g>
+ <polygon fill-rule="evenodd" clip-rule="evenodd" fill="#003882" points="327.5058594,344.3598633 327.7539063,298.1450195
+ 327.6308594,297.769043 327.6308594,297.894043 327.5058594,296.7661133 327.2539063,295.7670898 326.8769531,294.6391602
+ 326.5029297,293.637207 324.6259766,291.0073242 323.7480469,290.2543945 323.8740234,290.2543945 349.171875,290.1313477
+ 348.1708984,290.8803711 347.2929688,291.6313477 346.4179688,292.5083008 345.7890625,293.5102539 345.2871094,294.6391602
+ 344.9121094,295.7670898 344.7890625,297.0161133 344.7890625,298.2700195 344.7890625,298.1450195 344.9121094,298.1450195
+ 344.7890625,340.7260742 344.6640625,340.7260742 346.5410156,341.3540039 348.5458984,341.8540039 350.4238281,342.1040039
+ 352.4277344,342.355957 354.4316406,342.4799805 356.3105469,342.355957 358.3144531,342.2299805 360.1933594,341.8540039
+ 361.1933594,341.4770508 363.1992188,340.7260742 364.2011719,340.2231445 365.078125,339.7241211 366.0820313,339.2241211
+ 367.8320313,337.972168 363.5751953,351.621582 323.1220703,351.7485352 324.125,351.1235352 325.0019531,350.3706055
+ 325.7519531,349.6176758 327.0058594,347.6157227 327.2539063,346.4868164 327.5058594,345.4858398 327.6308594,344.2348633 "/>
+ </g>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#003882" d="M188.4228516,211.0395508V89.7011719h-23.2304688V66.4711914
+ c7.4140625-0.3291016,13.8393555-2.3886719,19.2763672-6.1782227c5.4365234-3.7890625,9.3085938-8.7314453,11.6152344-14.8276367
+ h23.7236328v165.5742188H188.4228516z"/>
+</svg>
diff --git a/tests/phpunit/data/media/iptc-invalid-psir.jpg b/tests/phpunit/data/media/iptc-invalid-psir.jpg
new file mode 100644
index 00000000..01b9acf3
--- /dev/null
+++ b/tests/phpunit/data/media/iptc-invalid-psir.jpg
Binary files differ
diff --git a/tests/phpunit/includes/ArticleTablesTest.php b/tests/phpunit/includes/ArticleTablesTest.php
index 01776c95..02571b55 100644
--- a/tests/phpunit/includes/ArticleTablesTest.php
+++ b/tests/phpunit/includes/ArticleTablesTest.php
@@ -6,29 +6,28 @@
class ArticleTablesTest extends MediaWikiLangTestCase {
function testbug14404() {
- global $wgUser, $wgContLang, $wgLanguageCode, $wgLang;
-
- $title = Title::newFromText("Bug 14404");
- $article = new Article( $title );
- $wgUser = new User();
- $wgUser->mRights = array( 'createpage', 'edit', 'purge' );
+ global $wgContLang, $wgLanguageCode, $wgLang;
+
+ $title = Title::newFromText( 'Bug 14404' );
+ $page = WikiPage::factory( $title );
+ $user = new User();
+ $user->mRights = array( 'createpage', 'edit', 'purge' );
$wgLanguageCode = 'es';
$wgContLang = Language::factory( 'es' );
-
+
$wgLang = Language::factory( 'fr' );
- $status = $article->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', 0 );
- $templates1 = $article->getUsedTemplates();
+ $status = $page->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', 0, false, $user );
+ $templates1 = $page->getUsedTemplates();
$wgLang = Language::factory( 'de' );
- $article->mParserOptions = null; // Let it pick the new user language
- $article->mPreparedEdit = false; // In order to force the rerendering of the same wikitext
-
+ $page->mPreparedEdit = false; // In order to force the rerendering of the same wikitext
+
// We need an edit, a purge is not enough to regenerate the tables
- $status = $article->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', EDIT_UPDATE );
- $templates2 = $article->getUsedTemplates();
-
+ $status = $page->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', EDIT_UPDATE, false, $user );
+ $templates2 = $page->getUsedTemplates();
+
$this->assertEquals( $templates1, $templates2 );
$this->assertEquals( $templates1[0]->getFullText(), 'Historial' );
}
-
+
}
diff --git a/tests/phpunit/includes/ArticleTest.php b/tests/phpunit/includes/ArticleTest.php
index 285efee9..846d2b86 100644
--- a/tests/phpunit/includes/ArticleTest.php
+++ b/tests/phpunit/includes/ArticleTest.php
@@ -19,25 +19,25 @@ class ArticleTest extends MediaWikiTestCase {
}
- function testImplementsGetMagic() {
- $this->assertEquals( -1, $this->article->mCounter, "Article __get magic" );
+ function testImplementsGetMagic() {
+ $this->assertEquals( false, $this->article->mLatest, "Article __get magic" );
}
/**
* @depends testImplementsGetMagic
*/
function testImplementsSetMagic() {
-
- $this->article->mCounter = 2;
- $this->assertEquals( 2, $this->article->mCounter, "Article __set magic" );
+ $this->article->mLatest = 2;
+ $this->assertEquals( 2, $this->article->mLatest, "Article __set magic" );
}
/**
* @depends testImplementsSetMagic
*/
function testImplementsCallMagic() {
- $this->article->mCounter = 33;
- $this->assertEquals( 33, $this->article->getCount(), "Article __call magic" );
+ $this->article->mLatest = 33;
+ $this->article->mDataLoaded = true;
+ $this->assertEquals( 33, $this->article->getLatest(), "Article __call magic" );
}
function testGetOrSetOnNewProperty() {
diff --git a/tests/phpunit/includes/BlockTest.php b/tests/phpunit/includes/BlockTest.php
index 2f224ba8..749f40b4 100644
--- a/tests/phpunit/includes/BlockTest.php
+++ b/tests/phpunit/includes/BlockTest.php
@@ -2,11 +2,10 @@
/**
* @group Database
+ * @group Blocking
*/
class BlockTest extends MediaWikiLangTestCase {
- const REASON = "Some reason";
-
private $block, $madeAt;
/* variable used to save up the blockID we insert in this test suite */
@@ -36,8 +35,8 @@ class BlockTest extends MediaWikiLangTestCase {
$oldBlock->delete();
}
- $this->block = new Block( 'UTBlockee', 1, 0,
- self::REASON
+ $this->block = new Block( 'UTBlockee', $user->getID(), 0,
+ 'Parce que', 0, false, time() + 100500
);
$this->madeAt = wfTimestamp( TS_MW );
@@ -68,7 +67,7 @@ class BlockTest extends MediaWikiLangTestCase {
// $this->dumpBlocks();
$this->assertTrue( $this->block->equals( Block::newFromTarget('UTBlockee') ), "newFromTarget() returns the same block as the one that was made");
-
+
$this->assertTrue( $this->block->equals( Block::newFromID( $this->blockId ) ), "newFromID() returns the same block as the one that was made");
}
@@ -77,8 +76,9 @@ class BlockTest extends MediaWikiLangTestCase {
* per bug 26425
*/
function testBug26425BlockTimestampDefaultsToTime() {
-
- $this->assertEquals( $this->madeAt, $this->block->mTimestamp, "If no timestamp is specified, the block is recorded as time()");
+ // delta to stop one-off errors when things happen to go over a second mark.
+ $delta = abs( $this->madeAt - $this->block->mTimestamp );
+ $this->assertLessThan( 2, $delta, "If no timestamp is specified, the block is recorded as time()");
}
@@ -91,6 +91,8 @@ class BlockTest extends MediaWikiLangTestCase {
* @dataProvider dataBug29116
*/
function testBug29116LoadWithEmptyIp( $vagueTarget ) {
+ $this->hideDeprecated( 'Block::load' );
+
$uid = User::idFromName( 'UTBlockee' );
$this->assertTrue( ($uid > 0), 'Must be able to look up the target user during tests' );
@@ -121,4 +123,3 @@ class BlockTest extends MediaWikiLangTestCase {
);
}
}
-
diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php
new file mode 100644
index 00000000..e98e9707
--- /dev/null
+++ b/tests/phpunit/includes/EditPageTest.php
@@ -0,0 +1,33 @@
+<?php
+
+class EditPageTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider dataExtractSectionTitle
+ */
+ function testExtractSectionTitle( $section, $title ) {
+ $extracted = EditPage::extractSectionTitle( $section );
+ $this->assertEquals( $title, $extracted );
+ }
+
+ function dataExtractSectionTitle() {
+ return array(
+ array(
+ "== Test ==\n\nJust a test section.",
+ "Test"
+ ),
+ array(
+ "An initial section, no header.",
+ false
+ ),
+ array(
+ "An initial section with a fake heder (bug 32617)\n\n== Test == ??\nwtf",
+ false
+ ),
+ array(
+ "== Section ==\nfollowed by a fake == Non-section == ??\nnoooo",
+ "Section"
+ )
+ );
+ }
+}
diff --git a/tests/phpunit/includes/ExtraParserTest.php b/tests/phpunit/includes/ExtraParserTest.php
index 5b0aa98b..a9088cb2 100644
--- a/tests/phpunit/includes/ExtraParserTest.php
+++ b/tests/phpunit/includes/ExtraParserTest.php
@@ -10,11 +10,13 @@ class ExtraParserTest extends MediaWikiTestCase {
global $wgContLang;
global $wgShowDBErrorBacktrace;
global $wgLanguageCode;
+ global $wgAlwaysUseTidy;
$wgShowDBErrorBacktrace = true;
$wgLanguageCode = 'en';
$wgContLang = new Language( 'en' );
$wgMemc = new EmptyBagOStuff;
+ $wgAlwaysUseTidy = false;
$this->options = new ParserOptions;
$this->options->setTemplateCallback( array( __CLASS__, 'statelessFetchTemplate' ) );
@@ -61,20 +63,48 @@ class ExtraParserTest extends MediaWikiTestCase {
* cleanSig() makes all templates substs and removes tildes
*/
function testCleanSig() {
+ global $wgCleanSignatures;
+ $oldCleanSignature = $wgCleanSignatures;
+ $wgCleanSignatures = true;
+
$title = Title::newFromText( __FUNCTION__ );
$outputText = $this->parser->cleanSig( "{{Foo}} ~~~~" );
+
+ $wgCleanSignatures = $oldCleanSignature;
$this->assertEquals( "{{SUBST:Foo}} ", $outputText );
}
-
+
/**
- * cleanSigInSig() just removes tildes
+ * cleanSig() should do nothing if disabled
*/
- function testCleanSigInSig() {
+ function testCleanSigDisabled() {
+ global $wgCleanSignatures;
+ $oldCleanSignature = $wgCleanSignatures;
+ $wgCleanSignatures = false;
+
$title = Title::newFromText( __FUNCTION__ );
- $outputText = $this->parser->cleanSigInSig( "{{Foo}} ~~~~" );
+ $outputText = $this->parser->cleanSig( "{{Foo}} ~~~~" );
+
+ $wgCleanSignatures = $oldCleanSignature;
- $this->assertEquals( "{{Foo}} ", $outputText );
+ $this->assertEquals( "{{Foo}} ~~~~", $outputText );
+ }
+
+ /**
+ * cleanSigInSig() just removes tildes
+ * @dataProvider provideStringsForCleanSigInSig
+ */
+ function testCleanSigInSig( $in, $out ) {
+ $this->assertEquals( Parser::cleanSigInSig( $in), $out );
+ }
+
+ function provideStringsForCleanSigInSig() {
+ return array(
+ array( "{{Foo}} ~~~~", "{{Foo}} " ),
+ array( "~~~", "" ),
+ array( "~~~~~", "" ),
+ );
}
function testGetSection() {
@@ -110,4 +140,28 @@ class ExtraParserTest extends MediaWikiTestCase {
'finalTitle' => $title,
'deps' => $deps );
}
+
+ /**
+ * @group Database
+ */
+ function testTrackingCategory() {
+ $title = Title::newFromText( __FUNCTION__ );
+ $catName = wfMsgForContent( 'broken-file-category' );
+ $cat = Title::makeTitleSafe( NS_CATEGORY, $catName );
+ $expected = array( $cat->getDBkey() );
+ $parserOutput = $this->parser->parse( "[[file:nonexistent]]" , $title, $this->options );
+ $result = $parserOutput->getCategoryLinks();
+ $this->assertEquals( $expected, $result );
+ }
+
+ /**
+ * @group Database
+ */
+ function testTrackingCategorySpecial() {
+ // Special pages shouldn't have tracking cats.
+ $title = SpecialPage::getTitleFor( 'Contributions' );
+ $parserOutput = $this->parser->parse( "[[file:nonexistent]]" , $title, $this->options );
+ $result = $parserOutput->getCategoryLinks();
+ $this->assertEmpty( $result );
+ }
}
diff --git a/tests/phpunit/includes/FormOptionsInitializationTest.php b/tests/phpunit/includes/FormOptionsInitializationTest.php
index 85d76271..d86c95d7 100644
--- a/tests/phpunit/includes/FormOptionsInitializationTest.php
+++ b/tests/phpunit/includes/FormOptionsInitializationTest.php
@@ -25,9 +25,9 @@ class FormOptionsExposed extends FormOptions {
*
* Generated by PHPUnit on 2011-02-28 at 20:46:27.
*
- * Copyright © 2011, Ashar Voultoiz
+ * Copyright © 2011, Antoine Musso
*
- * @author Ashar Voultoiz
+ * @author Antoine Musso
*/
class FormOptionsInitializationTest extends MediaWikiTestCase {
/**
diff --git a/tests/phpunit/includes/FormOptionsTest.php b/tests/phpunit/includes/FormOptionsTest.php
index 86618d93..749343ec 100644
--- a/tests/phpunit/includes/FormOptionsTest.php
+++ b/tests/phpunit/includes/FormOptionsTest.php
@@ -12,9 +12,9 @@
* Test class for FormOptions methods.
* Generated by PHPUnit on 2011-02-28 at 20:46:27.
*
- * Copyright © 2011, Ashar Voultoiz
+ * Copyright © 2011, Antoine Musso
*
- * @author Ashar Voultoiz
+ * @author Antoine Musso
*/
class FormOptionsTest extends MediaWikiTestCase {
/**
diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
index 3d157d0a..3cb42f12 100644
--- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
@@ -94,24 +94,80 @@ class GlobalTest extends MediaWikiTestCase {
$this->assertTrue( $end > $start, "Time is running backwards!" );
}
- function testArrayToCGI() {
+ function dataArrayToCGI() {
+ return array(
+ array( array(), '' ), // empty
+ array( array( 'foo' => 'bar' ), 'foo=bar' ), // string test
+ array( array( 'foo' => '' ), 'foo=' ), // empty string test
+ array( array( 'foo' => 1 ), 'foo=1' ), // number test
+ array( array( 'foo' => true ), 'foo=1' ), // true test
+ array( array( 'foo' => false ), '' ), // false test
+ array( array( 'foo' => null ), '' ), // null test
+ array( array( 'foo' => 'A&B=5+6@!"\'' ), 'foo=A%26B%3D5%2B6%40%21%22%27' ), // urlencoding test
+ array( array( 'foo' => 'bar', 'baz' => 'is', 'asdf' => 'qwerty' ), 'foo=bar&baz=is&asdf=qwerty' ), // multi-item test
+ array( array( 'foo' => array( 'bar' => 'baz' ) ), 'foo%5Bbar%5D=baz' ),
+ array( array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ), 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf' ),
+ array( array( 'foo' => array( 'bar', 'baz' ) ), 'foo%5B0%5D=bar&foo%5B1%5D=baz' ),
+ array( array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ), 'foo%5Bbar%5D%5Bbar%5D=baz' ),
+ );
+ }
+
+ /**
+ * @dataProvider dataArrayToCGI
+ */
+ function testArrayToCGI( $array, $result ) {
+ $this->assertEquals( $result, wfArrayToCGI( $array ) );
+ }
+
+
+ function testArrayToCGI2() {
$this->assertEquals(
- "baz=AT%26T&foo=bar",
+ "baz=bar&foo=bar",
wfArrayToCGI(
- array( 'baz' => 'AT&T', 'ignore' => '' ),
+ array( 'baz' => 'bar' ),
array( 'foo' => 'bar', 'baz' => 'overridden value' ) ) );
- $this->assertEquals(
- "path%5B0%5D=wiki&path%5B1%5D=test&cfg%5Bservers%5D%5Bhttp%5D=localhost",
- wfArrayToCGI( array(
- 'path' => array( 'wiki', 'test' ),
- 'cfg' => array( 'servers' => array( 'http' => 'localhost' ) ) ) ) );
}
- function testCgiToArray() {
- $this->assertEquals(
- array( 'path' => array( 'wiki', 'test' ),
- 'cfg' => array( 'servers' => array( 'http' => 'localhost' ) ) ),
- wfCgiToArray( 'path%5B0%5D=wiki&path%5B1%5D=test&cfg%5Bservers%5D%5Bhttp%5D=localhost' ) );
+ function dataCgiToArray() {
+ return array(
+ array( '', array() ), // empty
+ array( 'foo=bar', array( 'foo' => 'bar' ) ), // string
+ array( 'foo=', array( 'foo' => '' ) ), // empty string
+ array( 'foo', array( 'foo' => '' ) ), // missing =
+ array( 'foo=bar&qwerty=asdf', array( 'foo' => 'bar', 'qwerty' => 'asdf' ) ), // multiple value
+ array( 'foo=A%26B%3D5%2B6%40%21%22%27', array( 'foo' => 'A&B=5+6@!"\'' ) ), // urldecoding test
+ array( 'foo%5Bbar%5D=baz', array( 'foo' => array( 'bar' => 'baz' ) ) ),
+ array( 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf', array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ) ),
+ array( 'foo%5B0%5D=bar&foo%5B1%5D=baz', array( 'foo' => array( 0 => 'bar', 1 => 'baz' ) ) ),
+ array( 'foo%5Bbar%5D%5Bbar%5D=baz', array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ) ),
+ );
+ }
+
+ /**
+ * @dataProvider dataCgiToArray
+ */
+ function testCgiToArray( $cgi, $result ) {
+ $this->assertEquals( $result, wfCgiToArray( $cgi ) );
+ }
+
+ function dataCgiRoundTrip() {
+ return array(
+ array( '' ),
+ array( 'foo=bar' ),
+ array( 'foo=' ),
+ array( 'foo=bar&baz=biz' ),
+ array( 'foo=A%26B%3D5%2B6%40%21%22%27' ),
+ array( 'foo%5Bbar%5D=baz' ),
+ array( 'foo%5B0%5D=bar&foo%5B1%5D=baz' ),
+ array( 'foo%5Bbar%5D%5Bbar%5D=baz' ),
+ );
+ }
+
+ /**
+ * @dataProvider dataCgiRoundTrip
+ */
+ function testCgiRoundTrip( $cgi ) {
+ $this->assertEquals( $cgi, wfArrayToCGI( wfCgiToArray( $cgi ) ) );
}
function testMimeTypeMatch() {
@@ -176,263 +232,6 @@ class GlobalTest extends MediaWikiTestCase {
array( 'text/*' => 1.0 ),
array( 'application/xhtml+xml' => 1.0 ) ) );
}
-
- function testTimestamp() {
- $t = gmmktime( 12, 34, 56, 1, 15, 2001 );
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, $t ),
- 'TS_UNIX to TS_MW' );
- $this->assertEquals(
- '19690115123456',
- wfTimestamp( TS_MW, -30281104 ),
- 'Negative TS_UNIX to TS_MW' );
- $this->assertEquals(
- 979562096,
- wfTimestamp( TS_UNIX, $t ),
- 'TS_UNIX to TS_UNIX' );
- $this->assertEquals(
- '2001-01-15 12:34:56',
- wfTimestamp( TS_DB, $t ),
- 'TS_UNIX to TS_DB' );
- $this->assertEquals(
- '20010115T123456Z',
- wfTimestamp( TS_ISO_8601_BASIC, $t ),
- 'TS_ISO_8601_BASIC to TS_DB' );
-
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, '20010115123456' ),
- 'TS_MW to TS_MW' );
- $this->assertEquals(
- 979562096,
- wfTimestamp( TS_UNIX, '20010115123456' ),
- 'TS_MW to TS_UNIX' );
- $this->assertEquals(
- '2001-01-15 12:34:56',
- wfTimestamp( TS_DB, '20010115123456' ),
- 'TS_MW to TS_DB' );
- $this->assertEquals(
- '20010115T123456Z',
- wfTimestamp( TS_ISO_8601_BASIC, '20010115123456' ),
- 'TS_MW to TS_ISO_8601_BASIC' );
-
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, '2001-01-15 12:34:56' ),
- 'TS_DB to TS_MW' );
- $this->assertEquals(
- 979562096,
- wfTimestamp( TS_UNIX, '2001-01-15 12:34:56' ),
- 'TS_DB to TS_UNIX' );
- $this->assertEquals(
- '2001-01-15 12:34:56',
- wfTimestamp( TS_DB, '2001-01-15 12:34:56' ),
- 'TS_DB to TS_DB' );
- $this->assertEquals(
- '20010115T123456Z',
- wfTimestamp( TS_ISO_8601_BASIC, '2001-01-15 12:34:56' ),
- 'TS_DB to TS_ISO_8601_BASIC' );
-
- # rfc2822 section 3.3
-
- $this->assertEquals(
- 'Mon, 15 Jan 2001 12:34:56 GMT',
- wfTimestamp( TS_RFC2822, '20010115123456' ),
- 'TS_MW to TS_RFC2822' );
-
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, 'Mon, 15 Jan 2001 12:34:56 GMT' ),
- 'TS_RFC2822 to TS_MW' );
-
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, ' Mon, 15 Jan 2001 12:34:56 GMT' ),
- 'TS_RFC2822 with leading space to TS_MW' );
-
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, '15 Jan 2001 12:34:56 GMT' ),
- 'TS_RFC2822 without optional day-of-week to TS_MW' );
-
- # FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space
- # obs-FWS = 1*WSP *(CRLF 1*WSP) ; Section 4.2
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, 'Mon, 15 Jan 2001 12:34:56 GMT' ),
- 'TS_RFC2822 to TS_MW' );
-
- # WSP = SP / HTAB ; rfc2234
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, "Mon, 15 Jan\x092001 12:34:56 GMT" ),
- 'TS_RFC2822 with HTAB to TS_MW' );
-
- $this->assertEquals(
- '20010115123456',
- wfTimestamp( TS_MW, "Mon, 15 Jan\x09 \x09 2001 12:34:56 GMT" ),
- 'TS_RFC2822 with HTAB and SP to TS_MW' );
-
- $this->assertEquals(
- '19941106084937',
- wfTimestamp( TS_MW, "Sun, 6 Nov 94 08:49:37 GMT" ),
- 'TS_RFC2822 with obsolete year to TS_MW' );
- }
-
- /**
- * This test checks wfTimestamp() with values outside.
- * It needs PHP 64 bits or PHP > 5.1.
- * See r74778 and bug 25451
- */
- function testOldTimestamps() {
- $this->assertEquals( 'Fri, 13 Dec 1901 20:45:54 GMT',
- wfTimestamp( TS_RFC2822, '19011213204554' ),
- 'Earliest time according to php documentation' );
-
- $this->assertEquals( 'Tue, 19 Jan 2038 03:14:07 GMT',
- wfTimestamp( TS_RFC2822, '20380119031407' ),
- 'Latest 32 bit time' );
-
- $this->assertEquals( '-2147483648',
- wfTimestamp( TS_UNIX, '19011213204552' ),
- 'Earliest 32 bit unix time' );
-
- $this->assertEquals( '2147483647',
- wfTimestamp( TS_UNIX, '20380119031407' ),
- 'Latest 32 bit unix time' );
-
- $this->assertEquals( 'Fri, 13 Dec 1901 20:45:52 GMT',
- wfTimestamp( TS_RFC2822, '19011213204552' ),
- 'Earliest 32 bit time' );
-
- $this->assertEquals( 'Fri, 13 Dec 1901 20:45:51 GMT',
- wfTimestamp( TS_RFC2822, '19011213204551' ),
- 'Earliest 32 bit time - 1' );
-
- $this->assertEquals( 'Tue, 19 Jan 2038 03:14:08 GMT',
- wfTimestamp( TS_RFC2822, '20380119031408' ),
- 'Latest 32 bit time + 1' );
-
- $this->assertEquals( '19011212000000',
- wfTimestamp(TS_MW, '19011212000000'),
- 'Convert to itself r74778#c10645' );
-
- $this->assertEquals( '-2147483649',
- wfTimestamp( TS_UNIX, '19011213204551' ),
- 'Earliest 32 bit unix time - 1' );
-
- $this->assertEquals( '2147483648',
- wfTimestamp( TS_UNIX, '20380119031408' ),
- 'Latest 32 bit unix time + 1' );
-
- $this->assertEquals( '19011213204551',
- wfTimestamp( TS_MW, '-2147483649' ),
- '1901 negative unix time to MediaWiki' );
-
- $this->assertEquals( '18010115123456',
- wfTimestamp( TS_MW, '-5331871504' ),
- '1801 negative unix time to MediaWiki' );
-
- $this->assertEquals( 'Tue, 09 Aug 0117 12:34:56 GMT',
- wfTimestamp( TS_RFC2822, '0117-08-09 12:34:56'),
- 'Death of Roman Emperor [[Trajan]]');
-
- /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */
-
- $this->assertEquals( 'Sun, 01 Jan 0101 00:00:00 GMT',
- wfTimestamp( TS_RFC2822, '-58979923200'),
- '1/1/101');
-
- $this->assertEquals( 'Mon, 01 Jan 0001 00:00:00 GMT',
- wfTimestamp( TS_RFC2822, '-62135596800'),
- 'Year 1');
-
- /* It is not clear if we should generate a year 0 or not
- * We are completely off RFC2822 requirement of year being
- * 1900 or later.
- */
- $this->assertEquals( 'Wed, 18 Oct 0000 00:00:00 GMT',
- wfTimestamp( TS_RFC2822, '-62142076800'),
- 'ISO 8601:2004 [[year 0]], also called [[1 BC]]');
- }
-
- function testHttpDate() {
- # The Resource Loader uses wfTimestamp() to convert timestamps
- # from If-Modified-Since header.
- # Thus it must be able to parse all rfc2616 date formats
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
-
- $this->assertEquals(
- '19941106084937',
- wfTimestamp( TS_MW, 'Sun, 06 Nov 1994 08:49:37 GMT' ),
- 'RFC 822 date' );
-
- $this->assertEquals(
- '19941106084937',
- wfTimestamp( TS_MW, 'Sunday, 06-Nov-94 08:49:37 GMT' ),
- 'RFC 850 date' );
-
- $this->assertEquals(
- '19941106084937',
- wfTimestamp( TS_MW, 'Sun Nov 6 08:49:37 1994' ),
- "ANSI C's asctime() format" );
-
- // See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html and r77171
- $this->assertEquals(
- '20101122141242',
- wfTimestamp( TS_MW, 'Mon, 22 Nov 2010 14:12:42 GMT; length=52626' ),
- "Netscape extension to HTTP/1.0" );
-
- }
-
- function testTimestampParameter() {
- // There are a number of assumptions in our codebase where wfTimestamp() should give
- // the current date but it is not given a 0 there. See r71751 CR
-
- $now = wfTimestamp( TS_UNIX );
- // We check that wfTimestamp doesn't return false (error) and use a LessThan assert
- // for the cases where the test is run in a second boundary.
-
- $zero = wfTimestamp( TS_UNIX, 0 );
- $this->assertNotEquals( false, $zero );
- $this->assertLessThan( 5, $zero - $now );
-
- $empty = wfTimestamp( TS_UNIX, '' );
- $this->assertNotEquals( false, $empty );
- $this->assertLessThan( 5, $empty - $now );
-
- $null = wfTimestamp( TS_UNIX, null );
- $this->assertNotEquals( false, $null );
- $this->assertLessThan( 5, $null - $now );
- }
-
- function testBasename() {
- $sets = array(
- '' => '',
- '/' => '',
- '\\' => '',
- '//' => '',
- '\\\\' => '',
- 'a' => 'a',
- 'aaaa' => 'aaaa',
- '/a' => 'a',
- '\\a' => 'a',
- '/aaaa' => 'aaaa',
- '\\aaaa' => 'aaaa',
- '/aaaa/' => 'aaaa',
- '\\aaaa\\' => 'aaaa',
- '\\aaaa\\' => 'aaaa',
- '/mnt/upload3/wikipedia/en/thumb/8/8b/Zork_Grand_Inquisitor_box_cover.jpg/93px-Zork_Grand_Inquisitor_box_cover.jpg' => '93px-Zork_Grand_Inquisitor_box_cover.jpg',
- 'C:\\Progra~1\\Wikime~1\\Wikipe~1\\VIEWER.EXE' => 'VIEWER.EXE',
- 'Östergötland_coat_of_arms.png' => 'Östergötland_coat_of_arms.png',
- );
- foreach ( $sets as $from => $to ) {
- $this->assertEquals( $to, wfBaseName( $from ),
- "wfBaseName('$from') => '$to'" );
- }
- }
-
function testFallbackMbstringFunctions() {
@@ -701,135 +500,6 @@ class GlobalTest extends MediaWikiTestCase {
);
}
-
- /**
- * test @see wfBCP47().
- * Please note the BCP explicitly state that language codes are case
- * insensitive, there are some exceptions to the rule :)
- * This test is used to verify our formatting against all lower and
- * all upper cases language code.
- *
- * @see http://tools.ietf.org/html/bcp47
- * @dataProvider provideLanguageCodes()
- */
- function testBCP47( $code, $expected ) {
- $code = strtolower( $code );
- $this->assertEquals( $expected, wfBCP47($code),
- "Applying BCP47 standard to lower case '$code'"
- );
-
- $code = strtoupper( $code );
- $this->assertEquals( $expected, wfBCP47($code),
- "Applying BCP47 standard to upper case '$code'"
- );
- }
-
- /**
- * Array format is ($code, $expected)
- */
- function provideLanguageCodes() {
- return array(
- // Extracted from BCP47 (list not exhaustive)
- # 2.1.1
- array( 'en-ca-x-ca' , 'en-CA-x-ca' ),
- array( 'sgn-be-fr' , 'sgn-BE-FR' ),
- array( 'az-latn-x-latn', 'az-Latn-x-latn' ),
- # 2.2
- array( 'sr-Latn-RS', 'sr-Latn-RS' ),
- array( 'az-arab-ir', 'az-Arab-IR' ),
-
- # 2.2.5
- array( 'sl-nedis' , 'sl-nedis' ),
- array( 'de-ch-1996', 'de-CH-1996' ),
-
- # 2.2.6
- array(
- 'en-latn-gb-boont-r-extended-sequence-x-private',
- 'en-Latn-GB-boont-r-extended-sequence-x-private'
- ),
-
- // Examples from BCP47 Appendix A
- # Simple language subtag:
- array( 'DE', 'de' ),
- array( 'fR', 'fr' ),
- array( 'ja', 'ja' ),
-
- # Language subtag plus script subtag:
- array( 'zh-hans', 'zh-Hans'),
- array( 'sr-cyrl', 'sr-Cyrl'),
- array( 'sr-latn', 'sr-Latn'),
-
- # Extended language subtags and their primary language subtag
- # counterparts:
- array( 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ),
- array( 'cmn-hans-cn' , 'cmn-Hans-CN' ),
- array( 'zh-yue-hk' , 'zh-yue-HK' ),
- array( 'yue-hk' , 'yue-HK' ),
-
- # Language-Script-Region:
- array( 'zh-hans-cn', 'zh-Hans-CN' ),
- array( 'sr-latn-RS', 'sr-Latn-RS' ),
-
- # Language-Variant:
- array( 'sl-rozaj' , 'sl-rozaj' ),
- array( 'sl-rozaj-biske', 'sl-rozaj-biske' ),
- array( 'sl-nedis' , 'sl-nedis' ),
-
- # Language-Region-Variant:
- array( 'de-ch-1901' , 'de-CH-1901' ),
- array( 'sl-it-nedis' , 'sl-IT-nedis' ),
-
- # Language-Script-Region-Variant:
- array( 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ),
-
- # Language-Region:
- array( 'de-de' , 'de-DE' ),
- array( 'en-us' , 'en-US' ),
- array( 'es-419', 'es-419'),
-
- # Private use subtags:
- array( 'de-ch-x-phonebk' , 'de-CH-x-phonebk' ),
- array( 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ),
- /**
- * Previous test does not reflect the BCP which states:
- * az-Arab-x-AZE-derbend
- * AZE being private, it should be lower case, hence the test above
- * should probably be:
- #array( 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ),
- */
-
- # Private use registry values:
- array( 'x-whatever', 'x-whatever' ),
- array( 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ),
- array( 'de-qaaa' , 'de-Qaaa' ),
- array( 'sr-latn-qm', 'sr-Latn-QM' ),
- array( 'sr-qaaa-rs', 'sr-Qaaa-RS' ),
-
- # Tags that use extensions
- array( 'en-us-u-islamcal', 'en-US-u-islamcal' ),
- array( 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ),
- array( 'en-a-myext-b-another', 'en-a-myext-b-another' ),
-
- # Invalid:
- // de-419-DE
- // a-DE
- // ar-a-aaa-b-bbb-a-ccc
-
- /*
- // ISO 15924 :
- array( 'sr-Cyrl', 'sr-Cyrl' ),
- # @todo FIXME: Fix our function?
- array( 'SR-lATN', 'sr-Latn' ),
- array( 'fr-latn', 'fr-Latn' ),
- // Use lowercase for single segment
- // ISO 3166-1-alpha-2 code
- array( 'US', 'us' ), # USA
- array( 'uS', 'us' ), # USA
- array( 'Fr', 'fr' ), # France
- array( 'va', 'va' ), # Holy See (Vatican City State)
- */);
- }
-
/**
* @dataProvider provideMakeUrlIndexes()
*/
@@ -886,7 +556,63 @@ class GlobalTest extends MediaWikiTestCase {
),
);
}
+
+ /**
+ * @dataProvider provideWfMatchesDomainList
+ */
+ function testWfMatchesDomainList( $url, $domains, $expected, $description ) {
+ $actual = wfMatchesDomainList( $url, $domains );
+ $this->assertEquals( $expected, $actual, $description );
+ }
+
+ function provideWfMatchesDomainList() {
+ $a = array();
+ $protocols = array( 'HTTP' => 'http:', 'HTTPS' => 'https:', 'protocol-relative' => '' );
+ foreach ( $protocols as $pDesc => $p ) {
+ $a = array_merge( $a, array(
+ array( "$p//www.example.com", array(), false, "No matches for empty domains array, $pDesc URL" ),
+ array( "$p//www.example.com", array( 'www.example.com' ), true, "Exact match in domains array, $pDesc URL" ),
+ array( "$p//www.example.com", array( 'example.com' ), true, "Match without subdomain in domains array, $pDesc URL" ),
+ array( "$p//www.example2.com", array( 'www.example.com', 'www.example2.com', 'www.example3.com' ), true, "Exact match with other domains in array, $pDesc URL" ),
+ array( "$p//www.example2.com", array( 'example.com', 'example2.com', 'example3,com' ), true, "Match without subdomain with other domains in array, $pDesc URL" ),
+ array( "$p//www.example4.com", array( 'example.com', 'example2.com', 'example3,com' ), false, "Domain not in array, $pDesc URL" ),
+
+ // FIXME: This is a bug in wfMatchesDomainList(). If and when this is fixed, update this test case
+ array( "$p//nds-nl.wikipedia.org", array( 'nl.wikipedia.org' ), true, "Substrings of domains match while they shouldn't, $pDesc URL" ),
+ ) );
+ }
+ return $a;
+ }
+ /**
+ * @dataProvider provideWfShellMaintenanceCmdList
+ */
+ function testWfShellMaintenanceCmd( $script, $parameters, $options, $expected, $description ) {
+ if( wfIsWindows() ) {
+ // Approximation that's good enough for our purposes just now
+ $expected = str_replace( "'", '"', $expected );
+ }
+ $actual = wfShellMaintenanceCmd( $script, $parameters, $options );
+ $this->assertEquals( $expected, $actual, $description );
+ }
+
+ function provideWfShellMaintenanceCmdList() {
+ global $wgPhpCli;
+ return array(
+ array( 'eval.php', array( '--help', '--test' ), array(),
+ "'$wgPhpCli' 'eval.php' '--help' '--test'",
+ "Called eval.php --help --test" ),
+ array( 'eval.php', array( '--help', '--test space' ), array('php' => 'php5'),
+ "'php5' 'eval.php' '--help' '--test space'",
+ "Called eval.php --help --test with php option" ),
+ array( 'eval.php', array( '--help', '--test', 'X' ), array('wrapper' => 'MWScript.php'),
+ "'$wgPhpCli' 'MWScript.php' 'eval.php' '--help' '--test' 'X'",
+ "Called eval.php --help --test with wrapper option" ),
+ array( 'eval.php', array( '--help', '--test', 'y' ), array('php' => 'php5', 'wrapper' => 'MWScript.php'),
+ "'php5' 'MWScript.php' 'eval.php' '--help' '--test' 'y'",
+ "Called eval.php --help --test with wrapper and php option" ),
+ );
+ }
/* TODO: many more! */
}
diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php
new file mode 100644
index 00000000..4879a38d
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @group Database
+ */
+class GlobalWithDBTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideWfIsBadImageList
+ */
+ function testWfIsBadImage( $name, $title, $blacklist, $expected, $desc ) {
+ $this->assertEquals( $expected, wfIsBadImage( $name, $title, $blacklist ), $desc );
+ }
+
+ function provideWfIsBadImageList() {
+ $blacklist = '* [[File:Bad.jpg]] except [[Nasty page]]';
+ return array(
+ array( 'Bad.jpg', false, $blacklist, true,
+ 'Called on a bad image' ),
+ array( 'Bad.jpg', Title::makeTitle( NS_MAIN, 'A page' ), $blacklist, true,
+ 'Called on a bad image' ),
+ array( 'NotBad.jpg', false, $blacklist, false,
+ 'Called on a non-bad image' ),
+ array( 'Bad.jpg', Title::makeTitle( NS_MAIN, 'Nasty page' ), $blacklist, false,
+ 'Called on a bad image but is on a whitelisted page' ),
+ array( 'File:Bad.jpg', false, $blacklist, false,
+ 'Called on a bad image with File:' ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php b/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php
new file mode 100644
index 00000000..be6c99e7
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Unit tests for wfAssembleUrl()
+ */
+
+class wfAssembleUrl extends MediaWikiTestCase {
+ /** @dataProvider provideURLParts */
+ public function testWfAssembleUrl( $parts, $output ) {
+ $partsDump = print_r( $parts, true );
+ $this->assertEquals(
+ $output,
+ wfAssembleUrl( $parts ),
+ "Testing $partsDump assembles to $output"
+ );
+ }
+
+ /**
+ * Provider of URL parts for testing wfAssembleUrl()
+ *
+ * @return array
+ */
+ public function provideURLParts() {
+ $schemes = array(
+ '' => array(),
+ '//' => array(
+ 'delimiter' => '//',
+ ),
+ 'http://' => array(
+ 'scheme' => 'http',
+ 'delimiter' => '://',
+ ),
+ );
+
+ $hosts = array(
+ '' => array(),
+ 'example.com' => array(
+ 'host' => 'example.com',
+ ),
+ 'example.com:123' => array(
+ 'host' => 'example.com',
+ 'port' => 123,
+ ),
+ 'id@example.com' => array(
+ 'user' => 'id',
+ 'host' => 'example.com',
+ ),
+ 'id@example.com:123' => array(
+ 'user' => 'id',
+ 'host' => 'example.com',
+ 'port' => 123,
+ ),
+ 'id:key@example.com' => array(
+ 'user' => 'id',
+ 'pass' => 'key',
+ 'host' => 'example.com',
+ ),
+ 'id:key@example.com:123' => array(
+ 'user' => 'id',
+ 'pass' => 'key',
+ 'host' => 'example.com',
+ 'port' => 123,
+ ),
+ );
+
+ $cases = array();
+ foreach ( $schemes as $scheme => $schemeParts ) {
+ foreach ( $hosts as $host => $hostParts ) {
+ foreach ( array( '', '/path' ) as $path ) {
+ foreach ( array( '', 'query' ) as $query ) {
+ foreach ( array( '', 'fragment' ) as $fragment ) {
+ $parts = array_merge(
+ $schemeParts,
+ $hostParts
+ );
+ $url = $scheme .
+ $host .
+ $path;
+
+ if ( $path ) {
+ $parts['path'] = $path;
+ }
+ if ( $query ) {
+ $parts['query'] = $query;
+ $url .= '?' . $query;
+ }
+ if( $fragment ) {
+ $parts['fragment'] = $fragment;
+ $url .= '#' . $fragment;
+ }
+
+
+ $cases[] = array(
+ $parts,
+ $url,
+ );
+ }
+ }
+ }
+ }
+ }
+
+ $complexURL = 'http://id:key@example.org:321' .
+ '/over/there?name=ferret&foo=bar#nose';
+ $cases[] = array(
+ wfParseUrl( $complexURL ),
+ $complexURL,
+ );
+
+ return $cases;
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php b/tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php
new file mode 100644
index 00000000..f4ec7a5f
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Unit tests for wfBCP47()
+ */
+class wfBCP47 extends MediaWikiTestCase {
+ /**
+ * test @see wfBCP47().
+ * Please note the BCP explicitly state that language codes are case
+ * insensitive, there are some exceptions to the rule :)
+ * This test is used to verify our formatting against all lower and
+ * all upper cases language code.
+ *
+ * @see http://tools.ietf.org/html/bcp47
+ * @dataProvider provideLanguageCodes()
+ */
+ function testBCP47( $code, $expected ) {
+ $code = strtolower( $code );
+ $this->assertEquals( $expected, wfBCP47($code),
+ "Applying BCP47 standard to lower case '$code'"
+ );
+
+ $code = strtoupper( $code );
+ $this->assertEquals( $expected, wfBCP47($code),
+ "Applying BCP47 standard to upper case '$code'"
+ );
+ }
+
+ /**
+ * Array format is ($code, $expected)
+ */
+ function provideLanguageCodes() {
+ return array(
+ // Extracted from BCP47 (list not exhaustive)
+ # 2.1.1
+ array( 'en-ca-x-ca' , 'en-CA-x-ca' ),
+ array( 'sgn-be-fr' , 'sgn-BE-FR' ),
+ array( 'az-latn-x-latn', 'az-Latn-x-latn' ),
+ # 2.2
+ array( 'sr-Latn-RS', 'sr-Latn-RS' ),
+ array( 'az-arab-ir', 'az-Arab-IR' ),
+
+ # 2.2.5
+ array( 'sl-nedis' , 'sl-nedis' ),
+ array( 'de-ch-1996', 'de-CH-1996' ),
+
+ # 2.2.6
+ array(
+ 'en-latn-gb-boont-r-extended-sequence-x-private',
+ 'en-Latn-GB-boont-r-extended-sequence-x-private'
+ ),
+
+ // Examples from BCP47 Appendix A
+ # Simple language subtag:
+ array( 'DE', 'de' ),
+ array( 'fR', 'fr' ),
+ array( 'ja', 'ja' ),
+
+ # Language subtag plus script subtag:
+ array( 'zh-hans', 'zh-Hans'),
+ array( 'sr-cyrl', 'sr-Cyrl'),
+ array( 'sr-latn', 'sr-Latn'),
+
+ # Extended language subtags and their primary language subtag
+ # counterparts:
+ array( 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ),
+ array( 'cmn-hans-cn' , 'cmn-Hans-CN' ),
+ array( 'zh-yue-hk' , 'zh-yue-HK' ),
+ array( 'yue-hk' , 'yue-HK' ),
+
+ # Language-Script-Region:
+ array( 'zh-hans-cn', 'zh-Hans-CN' ),
+ array( 'sr-latn-RS', 'sr-Latn-RS' ),
+
+ # Language-Variant:
+ array( 'sl-rozaj' , 'sl-rozaj' ),
+ array( 'sl-rozaj-biske', 'sl-rozaj-biske' ),
+ array( 'sl-nedis' , 'sl-nedis' ),
+
+ # Language-Region-Variant:
+ array( 'de-ch-1901' , 'de-CH-1901' ),
+ array( 'sl-it-nedis' , 'sl-IT-nedis' ),
+
+ # Language-Script-Region-Variant:
+ array( 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ),
+
+ # Language-Region:
+ array( 'de-de' , 'de-DE' ),
+ array( 'en-us' , 'en-US' ),
+ array( 'es-419', 'es-419'),
+
+ # Private use subtags:
+ array( 'de-ch-x-phonebk' , 'de-CH-x-phonebk' ),
+ array( 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ),
+ /**
+ * Previous test does not reflect the BCP which states:
+ * az-Arab-x-AZE-derbend
+ * AZE being private, it should be lower case, hence the test above
+ * should probably be:
+ #array( 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ),
+ */
+
+ # Private use registry values:
+ array( 'x-whatever', 'x-whatever' ),
+ array( 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ),
+ array( 'de-qaaa' , 'de-Qaaa' ),
+ array( 'sr-latn-qm', 'sr-Latn-QM' ),
+ array( 'sr-qaaa-rs', 'sr-Qaaa-RS' ),
+
+ # Tags that use extensions
+ array( 'en-us-u-islamcal', 'en-US-u-islamcal' ),
+ array( 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ),
+ array( 'en-a-myext-b-another', 'en-a-myext-b-another' ),
+
+ # Invalid:
+ // de-419-DE
+ // a-DE
+ // ar-a-aaa-b-bbb-a-ccc
+
+ /*
+ // ISO 15924 :
+ array( 'sr-Cyrl', 'sr-Cyrl' ),
+ # @todo FIXME: Fix our function?
+ array( 'SR-lATN', 'sr-Latn' ),
+ array( 'fr-latn', 'fr-Latn' ),
+ // Use lowercase for single segment
+ // ISO 3166-1-alpha-2 code
+ array( 'US', 'us' ), # USA
+ array( 'uS', 'us' ), # USA
+ array( 'Fr', 'fr' ), # France
+ array( 'va', 'va' ), # Holy See (Vatican City State)
+ */);
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php b/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php
new file mode 100644
index 00000000..59954b23
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Tests for wfBaseName()
+ */
+class wfBaseName extends MediaWikiTestCase {
+ /**
+ * @dataProvider providePaths
+ */
+ function testBaseName( $fullpath, $basename ) {
+ $this->assertEquals( $basename, wfBaseName( $fullpath ),
+ "wfBaseName('$fullpath') => '$basename'" );
+ }
+
+ function providePaths() {
+ return array(
+ array( '', '' ),
+ array( '/', '' ),
+ array( '\\', '' ),
+ array( '//', '' ),
+ array( '\\\\', '' ),
+ array( 'a', 'a' ),
+ array( 'aaaa', 'aaaa' ),
+ array( '/a', 'a' ),
+ array( '\\a', 'a' ),
+ array( '/aaaa', 'aaaa' ),
+ array( '\\aaaa', 'aaaa' ),
+ array( '/aaaa/', 'aaaa' ),
+ array( '\\aaaa\\', 'aaaa' ),
+ array( '\\aaaa\\', 'aaaa' ),
+ array( '/mnt/upload3/wikipedia/en/thumb/8/8b/Zork_Grand_Inquisitor_box_cover.jpg/93px-Zork_Grand_Inquisitor_box_cover.jpg',
+ '93px-Zork_Grand_Inquisitor_box_cover.jpg' ),
+ array( 'C:\\Progra~1\\Wikime~1\\Wikipe~1\\VIEWER.EXE', 'VIEWER.EXE' ),
+ array( 'Östergötland_coat_of_arms.png', 'Östergötland_coat_of_arms.png' ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfExpandUrl.php b/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php
index b388b266..192689f8 100644
--- a/tests/phpunit/includes/GlobalFunctions/wfExpandUrl.php
+++ b/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php
@@ -1,5 +1,5 @@
<?php
-/*
+/**
* Unit tests for wfExpandUrl()
*/
@@ -12,16 +12,16 @@ class wfExpandUrl extends MediaWikiTestCase {
$oldCanServer = $wgCanonicalServer;
$wgServer = $server;
$wgCanonicalServer = $canServer;
-
+
// Fake $_SERVER['HTTPS'] if needed
if ( $httpsMode ) {
$_SERVER['HTTPS'] = 'on';
} else {
unset( $_SERVER['HTTPS'] );
}
-
+
$this->assertEquals( $fullUrl, wfExpandUrl( $shortUrl, $defaultProto ), $message );
-
+
// Restore $wgServer and $wgCanonicalServer
$wgServer = $oldServer;
$wgCanonicalServer = $oldCanServer;
@@ -29,12 +29,14 @@ class wfExpandUrl extends MediaWikiTestCase {
/**
* Provider of URL examples for testing wfExpandUrl()
+ *
+ * @return array
*/
public function provideExpandableUrls() {
$modes = array( 'http', 'https' );
$servers = array( 'http' => 'http://example.com', 'https' => 'https://example.com', 'protocol-relative' => '//example.com' );
$defaultProtos = array( 'http' => PROTO_HTTP, 'https' => PROTO_HTTPS, 'protocol-relative' => PROTO_RELATIVE, 'current' => PROTO_CURRENT, 'canonical' => PROTO_CANONICAL );
-
+
$retval = array();
foreach ( $modes as $mode ) {
$httpsMode = $mode == 'https';
@@ -46,14 +48,14 @@ class wfExpandUrl extends MediaWikiTestCase {
$retval[] = array( 'https://example.com', 'https://example.com', $defaultProto, $server, $canServer, $httpsMode, "Testing fully qualified https URLs (no need to expand) (defaultProto: $protoDesc , wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" );
# Would be nice to support this, see fixme on wfExpandUrl()
$retval[] = array( "wiki/FooBar", 'wiki/FooBar', $defaultProto, $server, $canServer, $httpsMode, "Test non-expandable relative URLs (defaultProto: $protoDesc , wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" );
-
+
// Determine expected protocol
$p = $protoDesc . ':'; // default case
if ( $protoDesc == 'protocol-relative' ) {
$p = '';
- } else if ( $protoDesc == 'current' ) {
+ } elseif ( $protoDesc == 'current' ) {
$p = "$mode:";
- } else if ( $protoDesc == 'canonical' ) {
+ } elseif ( $protoDesc == 'canonical' ) {
$p = "$canServerMode:";
} else {
$p = $protoDesc . ':';
@@ -61,12 +63,12 @@ class wfExpandUrl extends MediaWikiTestCase {
// Determine expected server name
if ( $protoDesc == 'canonical' ) {
$srv = $canServer;
- } else if ( $serverDesc == 'protocol-relative' ) {
+ } elseif ( $serverDesc == 'protocol-relative' ) {
$srv = $p . $server;
} else {
$srv = $server;
}
-
+
$retval[] = array( "$p//wikipedia.org", '//wikipedia.org', $defaultProto, $server, $canServer, $httpsMode, "Test protocol-relative URL (defaultProto: $protoDesc, wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" );
$retval[] = array( "$srv/wiki/FooBar", '/wiki/FooBar', $defaultProto, $server, $canServer, $httpsMode, "Testing expanding URL beginning with / (defaultProto: $protoDesc , wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" );
}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php b/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php
new file mode 100644
index 00000000..1cf0e0fb
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Unit tests for wfRemoveDotSegments()
+ */
+
+class wfRemoveDotSegments extends MediaWikiTestCase {
+ /** @dataProvider providePaths */
+ public function testWfRemoveDotSegments( $inputPath, $outputPath ) {
+ $this->assertEquals(
+ $outputPath,
+ wfRemoveDotSegments( $inputPath ),
+ "Testing $inputPath expands to $outputPath"
+ );
+ }
+
+ /**
+ * Provider of URL paths for testing wfRemoveDotSegments()
+ *
+ * @return array
+ */
+ public function providePaths() {
+ return array(
+ array( '/a/b/c/./../../g', '/a/g' ),
+ array( 'mid/content=5/../6', 'mid/6' ),
+ array( '/a//../b', '/a/b' ),
+ array( '/.../a', '/.../a' ),
+ array( '.../a', '.../a' ),
+ array( '', '' ),
+ array( '/', '/' ),
+ array( '//', '//' ),
+ array( '.', '' ),
+ array( '..', '' ),
+ array( '...', '...' ),
+ array( '/.', '/' ),
+ array( '/..', '/' ),
+ array( './', '' ),
+ array( '../', '' ),
+ array( './a', 'a' ),
+ array( '../a', 'a' ),
+ array( '../../a', 'a' ),
+ array( '.././a', 'a' ),
+ array( './../a', 'a' ),
+ array( '././a', 'a' ),
+ array( '../../', '' ),
+ array( '.././', '' ),
+ array( './../', '' ),
+ array( '././', '' ),
+ array( '../..', '' ),
+ array( '../.', '' ),
+ array( './..', '' ),
+ array( './.', '' ),
+ array( '/../../a', '/a' ),
+ array( '/.././a', '/a' ),
+ array( '/./../a', '/a' ),
+ array( '/././a', '/a' ),
+ array( '/../../', '/' ),
+ array( '/.././', '/' ),
+ array( '/./../', '/' ),
+ array( '/././', '/' ),
+ array( '/../..', '/' ),
+ array( '/../.', '/' ),
+ array( '/./..', '/' ),
+ array( '/./.', '/' ),
+ array( 'b/../../a', '/a' ),
+ array( 'b/.././a', '/a' ),
+ array( 'b/./../a', '/a' ),
+ array( 'b/././a', 'b/a' ),
+ array( 'b/../../', '/' ),
+ array( 'b/.././', '/' ),
+ array( 'b/./../', '/' ),
+ array( 'b/././', 'b/' ),
+ array( 'b/../..', '/' ),
+ array( 'b/../.', '/' ),
+ array( 'b/./..', '/' ),
+ array( 'b/./.', 'b/' ),
+ array( '/b/../../a', '/a' ),
+ array( '/b/.././a', '/a' ),
+ array( '/b/./../a', '/a' ),
+ array( '/b/././a', '/b/a' ),
+ array( '/b/../../', '/' ),
+ array( '/b/.././', '/' ),
+ array( '/b/./../', '/' ),
+ array( '/b/././', '/b/' ),
+ array( '/b/../..', '/' ),
+ array( '/b/../.', '/' ),
+ array( '/b/./..', '/' ),
+ array( '/b/./.', '/b/' ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php b/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php
new file mode 100644
index 00000000..1df26d2c
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php
@@ -0,0 +1,28 @@
+<?php
+
+class wfShorthandToIntegerTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideABunchOfShorthands
+ */
+ function testWfShorthandToInteger( $input, $output, $description ) {
+ $this->assertEquals(
+ wfShorthandToInteger( $input ),
+ $output,
+ $description
+ );
+ }
+
+ function provideABunchOfShorthands() {
+ return array(
+ array( '', -1, 'Empty string' ),
+ array( ' ', -1, 'String of spaces' ),
+ array( '1G', 1024 * 1024 * 1024, 'One gig uppercased' ),
+ array( '1g', 1024 * 1024 * 1024, 'One gig lowercased' ),
+ array( '1M', 1024 * 1024, 'One meg uppercased' ),
+ array( '1m', 1024 * 1024, 'One meg lowercased' ),
+ array( '1K', 1024, 'One kb uppercased' ),
+ array( '1k', 1024, 'One kb lowercased' ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
new file mode 100644
index 00000000..505c28c7
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
@@ -0,0 +1,134 @@
+<?php
+
+/*
+ * Tests for wfTimestamp()
+ */
+class wfTimestamp extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideNormalTimestamps
+ */
+ function testNormalTimestamps( $input, $format, $output, $desc ) {
+ $this->assertEquals( $output, wfTimestamp( $format, $input ), $desc );
+ }
+
+ function provideNormalTimestamps() {
+ $t = gmmktime( 12, 34, 56, 1, 15, 2001 );
+ return array (
+ // TS_UNIX
+ array( $t, TS_MW, '20010115123456', 'TS_UNIX to TS_MW' ),
+ array( -30281104, TS_MW, '19690115123456', 'Negative TS_UNIX to TS_MW' ),
+ array( $t, TS_UNIX, 979562096, 'TS_UNIX to TS_UNIX' ),
+ array( $t, TS_DB, '2001-01-15 12:34:56', 'TS_UNIX to TS_DB' ),
+
+ array( $t, TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_ISO_8601_BASIC to TS_DB' ),
+
+ // TS_MW
+ array( '20010115123456', TS_MW, '20010115123456', 'TS_MW to TS_MW' ),
+ array( '20010115123456', TS_UNIX, 979562096, 'TS_MW to TS_UNIX' ),
+ array( '20010115123456', TS_DB, '2001-01-15 12:34:56', 'TS_MW to TS_DB' ),
+ array( '20010115123456', TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_MW to TS_ISO_8601_BASIC' ),
+
+ // TS_DB
+ array( '2001-01-15 12:34:56', TS_MW, '20010115123456', 'TS_DB to TS_MW' ),
+ array( '2001-01-15 12:34:56', TS_UNIX, 979562096, 'TS_DB to TS_UNIX' ),
+ array( '2001-01-15 12:34:56', TS_DB, '2001-01-15 12:34:56', 'TS_DB to TS_DB' ),
+ array( '2001-01-15 12:34:56', TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_DB to TS_ISO_8601_BASIC' ),
+
+ # rfc2822 section 3.3
+ array( '20010115123456', TS_RFC2822, 'Mon, 15 Jan 2001 12:34:56 GMT', 'TS_MW to TS_RFC2822' ),
+ array( 'Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 to TS_MW' ),
+ array( ' Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 with leading space to TS_MW' ),
+ array( '15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 without optional day-of-week to TS_MW' ),
+
+ # FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space
+ # obs-FWS = 1*WSP *(CRLF 1*WSP) ; Section 4.2
+ array( 'Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 to TS_MW' ),
+
+ # WSP = SP / HTAB ; rfc2234
+ array( "Mon, 15 Jan\x092001 12:34:56 GMT", TS_MW, '20010115123456', 'TS_RFC2822 with HTAB to TS_MW' ),
+ array( "Mon, 15 Jan\x09 \x09 2001 12:34:56 GMT", TS_MW, '20010115123456', 'TS_RFC2822 with HTAB and SP to TS_MW' ),
+ array( 'Sun, 6 Nov 94 08:49:37 GMT', TS_MW, '19941106084937', 'TS_RFC2822 with obsolete year to TS_MW' ),
+ );
+ }
+
+ /**
+ * This test checks wfTimestamp() with values outside.
+ * It needs PHP 64 bits or PHP > 5.1.
+ * See r74778 and bug 25451
+ * @dataProvider provideOldTimestamps
+ */
+ function testOldTimestamps( $input, $format, $output, $desc ) {
+ $this->assertEquals( $output, wfTimestamp( $format, $input ), $desc );
+ }
+
+ function provideOldTimestamps() {
+ return array (
+ array( '19011213204554', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:54 GMT', 'Earliest time according to php documentation' ),
+ array( '20380119031407', TS_RFC2822, 'Tue, 19 Jan 2038 03:14:07 GMT', 'Latest 32 bit time' ),
+ array( '19011213204552', TS_UNIX, '-2147483648', 'Earliest 32 bit unix time' ),
+ array( '20380119031407', TS_UNIX, '2147483647', 'Latest 32 bit unix time' ),
+ array( '19011213204552', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:52 GMT', 'Earliest 32 bit time' ),
+ array( '19011213204551', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:51 GMT', 'Earliest 32 bit time - 1' ),
+ array( '20380119031408', TS_RFC2822, 'Tue, 19 Jan 2038 03:14:08 GMT', 'Latest 32 bit time + 1' ),
+ array( '19011212000000', TS_MW, '19011212000000', 'Convert to itself r74778#c10645' ),
+ array( '19011213204551', TS_UNIX, '-2147483649', 'Earliest 32 bit unix time - 1' ),
+ array( '20380119031408', TS_UNIX, '2147483648', 'Latest 32 bit unix time + 1' ),
+ array( '-2147483649', TS_MW, '19011213204551', '1901 negative unix time to MediaWiki' ),
+ array( '-5331871504', TS_MW, '18010115123456', '1801 negative unix time to MediaWiki' ),
+ array( '0117-08-09 12:34:56', TS_RFC2822, 'Tue, 09 Aug 0117 12:34:56 GMT', 'Death of Roman Emperor [[Trajan]]' ),
+
+ /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */
+ array( '-58979923200', TS_RFC2822, 'Sun, 01 Jan 0101 00:00:00 GMT', '1/1/101' ),
+ array( '-62135596800', TS_RFC2822, 'Mon, 01 Jan 0001 00:00:00 GMT', 'Year 1' ),
+
+ /* It is not clear if we should generate a year 0 or not
+ * We are completely off RFC2822 requirement of year being
+ * 1900 or later.
+ */
+ array( '-62142076800', TS_RFC2822, 'Wed, 18 Oct 0000 00:00:00 GMT', 'ISO 8601:2004 [[year 0]], also called [[1 BC]]' ),
+ );
+ }
+
+ /**
+ * The Resource Loader uses wfTimestamp() to convert timestamps
+ * from If-Modified-Since header. Thus it must be able to parse all
+ * rfc2616 date formats
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
+ * @dataProvider provideHttpDates
+ */
+ function testHttpDate( $input, $output, $desc ) {
+ $this->assertEquals( $output, wfTimestamp( TS_MW, $input ), $desc );
+ }
+
+ function provideHttpDates() {
+ return array(
+ array( 'Sun, 06 Nov 1994 08:49:37 GMT', '19941106084937', 'RFC 822 date' ),
+ array( 'Sunday, 06-Nov-94 08:49:37 GMT', '19941106084937', 'RFC 850 date' ),
+ array( 'Sun Nov 6 08:49:37 1994', '19941106084937', "ANSI C's asctime() format" ),
+ // See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html and r77171
+ array( 'Mon, 22 Nov 2010 14:12:42 GMT; length=52626', '20101122141242', 'Netscape extension to HTTP/1.0' ),
+ );
+ }
+
+ /**
+ * There are a number of assumptions in our codebase where wfTimestamp()
+ * should give the current date but it is not given a 0 there. See r71751 CR
+ */
+ function testTimestampParameter() {
+ $now = wfTimestamp( TS_UNIX );
+ // We check that wfTimestamp doesn't return false (error) and use a LessThan assert
+ // for the cases where the test is run in a second boundary.
+
+ $zero = wfTimestamp( TS_UNIX, 0 );
+ $this->assertNotEquals( false, $zero );
+ $this->assertLessThan( 5, $zero - $now );
+
+ $empty = wfTimestamp( TS_UNIX, '' );
+ $this->assertNotEquals( false, $empty );
+ $this->assertLessThan( 5, $empty - $now );
+
+ $null = wfTimestamp( TS_UNIX, null );
+ $this->assertNotEquals( false, $null );
+ $this->assertLessThan( 5, $null - $now );
+ }
+}
diff --git a/tests/phpunit/includes/HtmlTest.php b/tests/phpunit/includes/HtmlTest.php
index 96bb1803..67b60d32 100644
--- a/tests/phpunit/includes/HtmlTest.php
+++ b/tests/phpunit/includes/HtmlTest.php
@@ -3,58 +3,90 @@
class HtmlTest extends MediaWikiTestCase {
private static $oldLang;
+ private static $oldContLang;
+ private static $oldLanguageCode;
+ private static $oldNamespaces;
public function setUp() {
- global $wgLang, $wgLanguageCode;
+ global $wgLang, $wgContLang, $wgLanguageCode;
self::$oldLang = $wgLang;
+ self::$oldContLang = $wgContLang;
+ self::$oldNamespaces = $wgContLang->getNamespaces();
+ self::$oldLanguageCode = $wgLanguageCode;
+
$wgLanguageCode = 'en';
- $wgLang = Language::factory( $wgLanguageCode );
+ $wgContLang = $wgLang = Language::factory( $wgLanguageCode );
+
+ // Hardcode namespaces during test runs,
+ // so that html output based on existing namespaces
+ // can be properly evaluated.
+ $wgContLang->setNamespaces( array(
+ -2 => 'Media',
+ -1 => 'Special',
+ 0 => '',
+ 1 => 'Talk',
+ 2 => 'User',
+ 3 => 'User_talk',
+ 4 => 'MyWiki',
+ 5 => 'MyWiki_Talk',
+ 6 => 'File',
+ 7 => 'File_talk',
+ 8 => 'MediaWiki',
+ 9 => 'MediaWiki_talk',
+ 10 => 'Template',
+ 11 => 'Template_talk',
+ 100 => 'Custom',
+ 101 => 'Custom_talk',
+ ) );
}
public function tearDown() {
- global $wgLang, $wgLanguageCode;
+ global $wgLang, $wgContLang, $wgLanguageCode;
+
+ $wgContLang->setNamespaces( self::$oldNamespaces );
$wgLang = self::$oldLang;
- $wgLanguageCode = $wgLang->getCode();
+ $wgContLang = self::$oldContLang;
+ $wgLanguageCode = self::$oldLanguageCode;
}
public function testExpandAttributesSkipsNullAndFalse() {
### EMPTY ########
$this->AssertEmpty(
- Html::expandAttributes( array( 'foo'=>null) ),
+ Html::expandAttributes( array( 'foo' => null ) ),
'skip keys with null value'
);
$this->AssertEmpty(
- Html::expandAttributes( array( 'foo'=>false) ),
+ Html::expandAttributes( array( 'foo' => false ) ),
'skip keys with false value'
);
$this->AssertNotEmpty(
- Html::expandAttributes( array( 'foo'=>'') ),
+ Html::expandAttributes( array( 'foo' => '' ) ),
'keep keys with an empty string'
);
}
public function testExpandAttributesForBooleans() {
+ global $wgHtml5;
$this->AssertEquals(
'',
- Html::expandAttributes( array( 'selected'=>false) ),
+ Html::expandAttributes( array( 'selected' => false ) ),
'Boolean attributes do not generates output when value is false'
);
$this->AssertEquals(
'',
- Html::expandAttributes( array( 'selected'=>null) ),
+ Html::expandAttributes( array( 'selected' => null ) ),
'Boolean attributes do not generates output when value is null'
);
- ### FIXME: maybe they should just output 'selected'
$this->AssertEquals(
- ' selected=""',
- Html::expandAttributes( array( 'selected'=>true ) ),
+ $wgHtml5 ? ' selected=""' : ' selected="selected"',
+ Html::expandAttributes( array( 'selected' => true ) ),
'Boolean attributes skip value output'
);
$this->AssertEquals(
- ' selected=""',
+ $wgHtml5 ? ' selected=""' : ' selected="selected"',
Html::expandAttributes( array( 'selected' ) ),
'Boolean attributes (ex: selected) do not need a value'
);
@@ -68,23 +100,234 @@ class HtmlTest extends MediaWikiTestCase {
### NOT EMPTY ####
$this->AssertEquals(
' empty_string=""',
- Html::expandAttributes( array( 'empty_string'=>'') ),
+ Html::expandAttributes( array( 'empty_string' => '' ) ),
'Value with an empty string'
);
$this->AssertEquals(
' key="value"',
- Html::expandAttributes( array( 'key'=>'value') ),
+ Html::expandAttributes( array( 'key' => 'value' ) ),
'Value is a string'
);
$this->AssertEquals(
' one="1"',
- Html::expandAttributes( array( 'one'=>1) ),
+ Html::expandAttributes( array( 'one' => 1 ) ),
'Value is a numeric one'
);
$this->AssertEquals(
' zero="0"',
- Html::expandAttributes( array( 'zero'=>0) ),
+ Html::expandAttributes( array( 'zero' => 0 ) ),
'Value is a numeric zero'
);
}
+
+ /**
+ * Html::expandAttributes has special features for HTML
+ * attributes that use space separated lists and also
+ * allows arrays to be used as values.
+ */
+ public function testExpandAttributesListValueAttributes() {
+ ### STRING VALUES
+ $this->AssertEquals(
+ ' class="redundant spaces here"',
+ Html::expandAttributes( array( 'class' => ' redundant spaces here ' ) ),
+ 'Normalization should strip redundant spaces'
+ );
+ $this->AssertEquals(
+ ' class="foo bar"',
+ Html::expandAttributes( array( 'class' => 'foo bar foo bar bar' ) ),
+ 'Normalization should remove duplicates in string-lists'
+ );
+ ### "EMPTY" ARRAY VALUES
+ $this->AssertEquals(
+ ' class=""',
+ Html::expandAttributes( array( 'class' => array() ) ),
+ 'Value with an empty array'
+ );
+ $this->AssertEquals(
+ ' class=""',
+ Html::expandAttributes( array( 'class' => array( null, '', ' ', ' ' ) ) ),
+ 'Array with null, empty string and spaces'
+ );
+ ### NON-EMPTY ARRAY VALUES
+ $this->AssertEquals(
+ ' class="foo bar"',
+ Html::expandAttributes( array( 'class' => array(
+ 'foo',
+ 'bar',
+ 'foo',
+ 'bar',
+ 'bar',
+ ) ) ),
+ 'Normalization should remove duplicates in the array'
+ );
+ $this->AssertEquals(
+ ' class="foo bar"',
+ Html::expandAttributes( array( 'class' => array(
+ 'foo bar',
+ 'bar foo',
+ 'foo',
+ 'bar bar',
+ ) ) ),
+ 'Normalization should remove duplicates in string-lists in the array'
+ );
+ }
+
+ /**
+ * Test feature added by r96188, let pass attributes values as
+ * a PHP array. Restricted to class,rel, accesskey.
+ */
+ function testExpandAttributesSpaceSeparatedAttributesWithBoolean() {
+ $this->assertEquals(
+ ' class="booltrue one"',
+ Html::expandAttributes( array( 'class' => array(
+ 'booltrue' => true,
+ 'one' => 1,
+
+ # Method use isset() internally, make sure we do discard
+ # attributes values which have been assigned well known values
+ 'emptystring' => '',
+ 'boolfalse' => false,
+ 'zero' => 0,
+ 'null' => null,
+ )))
+ );
+ }
+
+ /**
+ * How do we handle duplicate keys in HTML attributes expansion?
+ * We could pass a "class" the values: 'GREEN' and array( 'GREEN' => false )
+ * The later will take precedence.
+ *
+ * Feature added by r96188
+ */
+ function testValueIsAuthoritativeInSpaceSeparatedAttributesArrays() {
+ $this->assertEquals(
+ ' class=""',
+ Html::expandAttributes( array( 'class' => array(
+ 'GREEN',
+ 'GREEN' => false,
+ 'GREEN',
+ )))
+ );
+ }
+
+ function testNamespaceSelector() {
+ $this->assertEquals(
+ '<select id="namespace" name="namespace">' . "\n" .
+'<option value="0">(Main)</option>' . "\n" .
+'<option value="1">Talk</option>' . "\n" .
+'<option value="2">User</option>' . "\n" .
+'<option value="3">User talk</option>' . "\n" .
+'<option value="4">MyWiki</option>' . "\n" .
+'<option value="5">MyWiki Talk</option>' . "\n" .
+'<option value="6">File</option>' . "\n" .
+'<option value="7">File talk</option>' . "\n" .
+'<option value="8">MediaWiki</option>' . "\n" .
+'<option value="9">MediaWiki talk</option>' . "\n" .
+'<option value="10">Template</option>' . "\n" .
+'<option value="11">Template talk</option>' . "\n" .
+'<option value="100">Custom</option>' . "\n" .
+'<option value="101">Custom talk</option>' . "\n" .
+'</select>',
+ Html::namespaceSelector(),
+ 'Basic namespace selector without custom options'
+ );
+ $this->assertEquals(
+ '<label for="mw-test-namespace">Select a namespace:</label>&#160;' .
+'<select id="mw-test-namespace" name="wpNamespace">' . "\n" .
+'<option value="all">all</option>' . "\n" .
+'<option value="0">(Main)</option>' . "\n" .
+'<option value="1">Talk</option>' . "\n" .
+'<option value="2" selected="">User</option>' . "\n" .
+'<option value="3">User talk</option>' . "\n" .
+'<option value="4">MyWiki</option>' . "\n" .
+'<option value="5">MyWiki Talk</option>' . "\n" .
+'<option value="6">File</option>' . "\n" .
+'<option value="7">File talk</option>' . "\n" .
+'<option value="8">MediaWiki</option>' . "\n" .
+'<option value="9">MediaWiki talk</option>' . "\n" .
+'<option value="10">Template</option>' . "\n" .
+'<option value="11">Template talk</option>' . "\n" .
+'<option value="100">Custom</option>' . "\n" .
+'<option value="101">Custom talk</option>' . "\n" .
+'</select>',
+ Html::namespaceSelector(
+ array( 'selected' => '2', 'all' => 'all', 'label' => 'Select a namespace:' ),
+ array( 'name' => 'wpNamespace', 'id' => 'mw-test-namespace' )
+ ),
+ 'Basic namespace selector with custom values'
+ );
+ }
+
+ function testNamespaceSelectorIdAndNameDefaultsAttributes() {
+
+ $this->assertNsSelectorIdAndName(
+ 'namespace', 'namespace',
+ Html::namespaceSelector( array(), array(
+ # neither 'id' nor 'name' key given
+ )),
+ "Neither 'id' nor 'name' key given"
+ );
+
+ $this->assertNsSelectorIdAndName(
+ 'namespace', 'select_name',
+ Html::namespaceSelector( array(), array(
+ 'name' => 'select_name',
+ # no 'id' key given
+ )),
+ "No 'id' key given, 'name' given"
+ );
+
+ $this->assertNsSelectorIdAndName(
+ 'select_id', 'namespace',
+ Html::namespaceSelector( array(), array(
+ 'id' => 'select_id',
+ # no 'name' key given
+ )),
+ "'id' given, no 'name' key given"
+ );
+
+ $this->assertNsSelectorIdAndName(
+ 'select_id', 'select_name',
+ Html::namespaceSelector( array(), array(
+ 'id' => 'select_id',
+ 'name' => 'select_name',
+ )),
+ "Both 'id' and 'name' given"
+ );
+ }
+
+ /**
+ * Helper to verify <select> attributes generated by Html::namespaceSelector()
+ * This helper expect the Html method to use 'namespace' as a default value for
+ * both 'id' and 'name' attributes.
+ *
+ * @param String $expectedId <select> id attribute value
+ * @param String $expectedName <select> name attribute value
+ * @param String $html Output of a call to Html::namespaceSelector()
+ * @param String $msg Optional message (default: '')
+ */
+ function assertNsSelectorIdAndName( $expectedId, $expectedName, $html, $msg = '' ) {
+ $actualId = 'namespace';
+ if( 1 === preg_match( '/id="(.+?)"/', $html, $m ) ) {
+ $actualId = $m[1];
+ }
+
+ $actualName = 'namespace';
+ if( 1 === preg_match( '/name="(.+?)"/', $html, $m ) ) {
+ $actualName = $m[1];
+ }
+ $this->assertEquals(
+ array( #expected
+ 'id' => $expectedId,
+ 'name' => $expectedName,
+ ),
+ array( #actual
+ 'id' => $actualId,
+ 'name' => $actualName,
+ ),
+ 'Html::namespaceSelector() got wrong id and/or name attribute(s). ' . $msg
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/HttpTest.php b/tests/phpunit/includes/HttpTest.php
index 1a99af7d..263383f1 100644
--- a/tests/phpunit/includes/HttpTest.php
+++ b/tests/phpunit/includes/HttpTest.php
@@ -1,325 +1,12 @@
<?php
-
-class MockCookie extends Cookie {
- public function canServeDomain( $arg ) { return parent::canServeDomain( $arg ); }
- public function canServePath( $arg ) { return parent::canServePath( $arg ); }
- public function isUnExpired() { return parent::isUnExpired(); }
-}
-
/**
* @group Broken
*/
class HttpTest extends MediaWikiTestCase {
- static $content;
- static $headers;
- static $has_curl;
- static $has_fopen;
- static $has_proxy = false;
- static $proxy = "http://hulk:8080/";
- var $test_geturl = array(
- "http://en.wikipedia.org/robots.txt",
- "https://secure.wikimedia.org/",
- "http://pecl.php.net/feeds/pkg_apc.rss",
- "http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw",
- "http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&format=php",
- );
- var $test_requesturl = array( "http://en.wikipedia.org/wiki/Special:Export/User:MarkAHershberger" );
-
- var $test_posturl = array( "http://www.comp.leeds.ac.uk/cgi-bin/Perl/environment-example" => "review=test" );
-
- function setUp() {
- putenv( "http_proxy" ); /* Remove any proxy env var, so curl doesn't get confused */
- if ( is_array( self::$content ) ) {
- return;
- }
- self::$has_curl = function_exists( 'curl_init' );
- self::$has_fopen = wfIniGetBool( 'allow_url_fopen' );
-
- if ( !file_exists( "/usr/bin/curl" ) ) {
- $this->markTestIncomplete( "This test requires the curl binary at /usr/bin/curl. If you have curl, please file a bug on this test, or, better yet, provide a patch." );
- }
-
- $content = tempnam( wfTempDir(), "" );
- $headers = tempnam( wfTempDir(), "" );
- if ( !$content && !$headers ) {
- die( "Couldn't create temp file!" );
- }
-
- // This probably isn't the best test for a proxy, but it works on my system!
- system( "curl -0 -o $content -s " . self::$proxy );
- $out = file_get_contents( $content );
- if ( $out ) {
- self::$has_proxy = true;
- }
-
- /* Maybe use wget instead of curl here ... just to use a different codebase? */
- foreach ( $this->test_geturl as $u ) {
- system( "curl -0 -s -D $headers '$u' -o $content" );
- self::$content["GET $u"] = file_get_contents( $content );
- self::$headers["GET $u"] = file_get_contents( $headers );
- }
- foreach ( $this->test_requesturl as $u ) {
- system( "curl -0 -s -X POST -H 'Content-Length: 0' -D $headers '$u' -o $content" );
- self::$content["POST $u"] = file_get_contents( $content );
- self::$headers["POST $u"] = file_get_contents( $headers );
- }
- foreach ( $this->test_posturl as $u => $postData ) {
- system( "curl -0 -s -X POST -d '$postData' -D $headers '$u' -o $content" );
- self::$content["POST $u => $postData"] = file_get_contents( $content );
- self::$headers["POST $u => $postData"] = file_get_contents( $headers );
- }
- unlink( $content );
- unlink( $headers );
- }
-
-
- function testInstantiation() {
- Http::$httpEngine = false;
-
- $r = MWHttpRequest::factory( "http://www.example.com/" );
- if ( self::$has_curl ) {
- $this->assertThat( $r, $this->isInstanceOf( 'CurlHttpRequest' ) );
- } else {
- $this->assertThat( $r, $this->isInstanceOf( 'PhpHttpRequest' ) );
- }
- unset( $r );
-
- if ( !self::$has_fopen ) {
- $this->setExpectedException( 'MWException' );
- }
- Http::$httpEngine = 'php';
- $r = MWHttpRequest::factory( "http://www.example.com/" );
- $this->assertThat( $r, $this->isInstanceOf( 'PhpHttpRequest' ) );
- unset( $r );
-
- if ( !self::$has_curl ) {
- $this->setExpectedException( 'MWException' );
- }
- Http::$httpEngine = 'curl';
- $r = MWHttpRequest::factory( "http://www.example.com/" );
- if ( self::$has_curl ) {
- $this->assertThat( $r, $this->isInstanceOf( 'CurlHttpRequest' ) );
- }
- }
-
- function runHTTPFailureChecks() {
- // Each of the following requests should result in a failure.
-
- $timeout = 1;
- $start_time = time();
- $r = Http::get( "http://www.example.com:1/", $timeout );
- $end_time = time();
- $this->assertLessThan( $timeout + 2, $end_time - $start_time,
- "Request took less than {$timeout}s via " . Http::$httpEngine );
- $this->assertEquals( $r, false, "false -- what we get on error from Http::get()" );
-
- $r = Http::get( "http://www.mediawiki.org/xml/made-up-url", $timeout );
- $this->assertFalse( $r, "False on 404s" );
-
-
- $r = MWHttpRequest::factory( "http://www.mediawiki.org/xml/made-up-url" );
- $er = $r->execute();
- if ( $r instanceof PhpHttpRequest && version_compare( '5.2.10', phpversion(), '>' ) ) {
- $this->assertRegexp( "/HTTP request failed/", $er->getWikiText() );
- } else {
- $this->assertRegexp( "/404 Not Found/", $er->getWikiText() );
- }
- }
-
- function testFailureDefault() {
- Http::$httpEngine = false;
- $this->runHTTPFailureChecks();
- }
-
- function testFailurePhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- $this->runHTTPFailureChecks();
- }
-
- function testFailureCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- $this->runHTTPFailureChecks();
- }
-
- /* ./phase3/includes/Import.php:1108: $data = Http::request( $method, $url ); */
- /* ./includes/Import.php:1124: $link = Title::newFromText( "$interwiki:Special:Export/$page" ); */
- /* ./includes/Import.php:1134: return ImportStreamSource::newFromURL( $url, "POST" ); */
- function runHTTPRequests( $proxy = null ) {
- $opt = array();
-
- if ( $proxy ) {
- $opt['proxy'] = $proxy;
- } elseif ( $proxy === false ) {
- $opt['noProxy'] = true;
- }
-
- /* no postData here because the only request I could find in code so far didn't have any */
- foreach ( $this->test_requesturl as $u ) {
- $r = Http::request( "POST", $u, $opt );
- $this->assertEquals( self::$content["POST $u"], "$r", "POST $u with " . Http::$httpEngine );
- }
- }
-
- function testRequestDefault() {
- Http::$httpEngine = false;
- $this->runHTTPRequests();
- }
-
- function testRequestPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- $this->runHTTPRequests();
- }
-
- function testRequestCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- $this->runHTTPRequests();
- }
-
- function runHTTPGets( $proxy = null ) {
- $opt = array();
-
- if ( $proxy ) {
- $opt['proxy'] = $proxy;
- } elseif ( $proxy === false ) {
- $opt['noProxy'] = true;
- }
-
- foreach ( $this->test_geturl as $u ) {
- $r = Http::get( $u, 30, $opt ); /* timeout of 30s */
- $this->assertEquals( self::$content["GET $u"], "$r", "Get $u with " . Http::$httpEngine );
- }
- }
-
- function testGetDefault() {
- Http::$httpEngine = false;
- $this->runHTTPGets();
- }
-
- function testGetPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- $this->runHTTPGets();
- }
-
- function testGetCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- $this->runHTTPGets();
- }
-
- function runHTTPPosts( $proxy = null ) {
- $opt = array();
-
- if ( $proxy ) {
- $opt['proxy'] = $proxy;
- } elseif ( $proxy === false ) {
- $opt['noProxy'] = true;
- }
-
- foreach ( $this->test_posturl as $u => $postData ) {
- $opt['postData'] = $postData;
- $r = Http::post( $u, $opt );
- $this->assertEquals( self::$content["POST $u => $postData"], "$r",
- "POST $u (postData=$postData) with " . Http::$httpEngine );
- }
- }
-
- function testPostDefault() {
- Http::$httpEngine = false;
- $this->runHTTPPosts();
- }
-
- function testPostPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- $this->runHTTPPosts();
- }
-
- function testPostCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- $this->runHTTPPosts();
- }
-
- function runProxyRequests() {
- if ( !self::$has_proxy ) {
- $this->markTestIncomplete( "This test requires a proxy." );
- }
- $this->runHTTPGets( self::$proxy );
- $this->runHTTPPosts( self::$proxy );
- $this->runHTTPRequests( self::$proxy );
-
- // Set false here to do noProxy
- $this->runHTTPGets( false );
- $this->runHTTPPosts( false );
- $this->runHTTPRequests( false );
- }
-
- function testProxyDefault() {
- Http::$httpEngine = false;
- $this->runProxyRequests();
- }
-
- function testProxyPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = 'php';
- $this->runProxyRequests();
- }
-
- function testProxyCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = 'curl';
- $this->runProxyRequests();
- }
-
- function testIsLocalUrl() {
- }
-
- /* ./extensions/DonationInterface/payflowpro_gateway/payflowpro_gateway.body.php:559: $user_agent = Http::userAgent(); */
- function testUserAgent() {
- }
-
- function testIsValidUrl() {
- }
-
/**
* @dataProvider cookieDomains
*/
- function testValidateCookieDomain( $expected, $domain, $origin=null ) {
+ function testValidateCookieDomain( $expected, $domain, $origin = null ) {
if ( $origin ) {
$ok = Cookie::validateCookieDomain( $domain, $origin );
$msg = "$domain against origin $origin";
@@ -329,7 +16,7 @@ class HttpTest extends MediaWikiTestCase {
}
$this->assertEquals( $expected, $ok, $msg );
}
-
+
function cookieDomains() {
return array(
array( false, "org"),
@@ -359,189 +46,11 @@ class HttpTest extends MediaWikiTestCase {
);
}
- function testSetCooke() {
- $c = new MockCookie( "name", "value",
- array(
- "domain" => "ac.th",
- "path" => "/path/",
- ) );
- $this->assertFalse( $c->canServeDomain( "ac.th" ) );
-
- $c = new MockCookie( "name", "value",
- array(
- "domain" => "example.com",
- "path" => "/path/",
- ) );
-
- $this->assertTrue( $c->canServeDomain( "example.com" ) );
- $this->assertFalse( $c->canServeDomain( "www.example.com" ) );
-
- $c = new MockCookie( "name", "value",
- array(
- "domain" => ".example.com",
- "path" => "/path/",
- ) );
-
- $this->assertFalse( $c->canServeDomain( "www.example.net" ) );
- $this->assertFalse( $c->canServeDomain( "example.com" ) );
- $this->assertTrue( $c->canServeDomain( "www.example.com" ) );
-
- $this->assertFalse( $c->canServePath( "/" ) );
- $this->assertFalse( $c->canServePath( "/bogus/path/" ) );
- $this->assertFalse( $c->canServePath( "/path" ) );
- $this->assertTrue( $c->canServePath( "/path/" ) );
-
- $this->assertTrue( $c->isUnExpired() );
-
- $this->assertEquals( "", $c->serializeToHttpRequest( "/path/", "www.example.net" ) );
- $this->assertEquals( "", $c->serializeToHttpRequest( "/", "www.example.com" ) );
- $this->assertEquals( "name=value", $c->serializeToHttpRequest( "/path/", "www.example.com" ) );
-
- $c = new MockCookie( "name", "value",
- array(
- "domain" => "www.example.com",
- "path" => "/path/",
- ) );
- $this->assertFalse( $c->canServeDomain( "example.com" ) );
- $this->assertFalse( $c->canServeDomain( "www.example.net" ) );
- $this->assertTrue( $c->canServeDomain( "www.example.com" ) );
-
- $c = new MockCookie( "name", "value",
- array(
- "domain" => ".example.com",
- "path" => "/path/",
- "expires" => "-1 day",
- ) );
- $this->assertFalse( $c->isUnExpired() );
- $this->assertEquals( "", $c->serializeToHttpRequest( "/path/", "www.example.com" ) );
-
- $c = new MockCookie( "name", "value",
- array(
- "domain" => ".example.com",
- "path" => "/path/",
- "expires" => "+1 day",
- ) );
- $this->assertTrue( $c->isUnExpired() );
- $this->assertEquals( "name=value", $c->serializeToHttpRequest( "/path/", "www.example.com" ) );
- }
-
- function testCookieJarSetCookie() {
- $cj = new CookieJar;
- $cj->setCookie( "name", "value",
- array(
- "domain" => ".example.com",
- "path" => "/path/",
- ) );
- $cj->setCookie( "name2", "value",
- array(
- "domain" => ".example.com",
- "path" => "/path/sub",
- ) );
- $cj->setCookie( "name3", "value",
- array(
- "domain" => ".example.com",
- "path" => "/",
- ) );
- $cj->setCookie( "name4", "value",
- array(
- "domain" => ".example.net",
- "path" => "/path/",
- ) );
- $cj->setCookie( "name5", "value",
- array(
- "domain" => ".example.net",
- "path" => "/path/",
- "expires" => "-1 day",
- ) );
-
- $this->assertEquals( "name4=value", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) );
- $this->assertEquals( "name3=value", $cj->serializeToHttpRequest( "/", "www.example.com" ) );
- $this->assertEquals( "name=value; name3=value", $cj->serializeToHttpRequest( "/path/", "www.example.com" ) );
-
- $cj->setCookie( "name5", "value",
- array(
- "domain" => ".example.net",
- "path" => "/path/",
- "expires" => "+1 day",
- ) );
- $this->assertEquals( "name4=value; name5=value", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) );
-
- $cj->setCookie( "name4", "value",
- array(
- "domain" => ".example.net",
- "path" => "/path/",
- "expires" => "-1 day",
- ) );
- $this->assertEquals( "name5=value", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) );
- }
-
- function testParseResponseHeader() {
- $cj = new CookieJar;
-
- $h[] = "Set-Cookie: name4=value; domain=.example.com; path=/; expires=Mon, 09-Dec-2029 13:46:00 GMT";
- $cj->parseCookieResponseHeader( $h[0], "www.example.com" );
- $this->assertEquals( "name4=value", $cj->serializeToHttpRequest( "/", "www.example.com" ) );
-
- $h[] = "name4=value2; domain=.example.com; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT";
- $cj->parseCookieResponseHeader( $h[1], "www.example.com" );
- $this->assertEquals( "", $cj->serializeToHttpRequest( "/", "www.example.com" ) );
- $this->assertEquals( "name4=value2", $cj->serializeToHttpRequest( "/path/", "www.example.com" ) );
-
- $h[] = "name5=value3; domain=.example.com; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT";
- $cj->parseCookieResponseHeader( $h[2], "www.example.com" );
- $this->assertEquals( "name4=value2; name5=value3", $cj->serializeToHttpRequest( "/path/", "www.example.com" ) );
-
- $h[] = "name6=value3; domain=.example.net; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT";
- $cj->parseCookieResponseHeader( $h[3], "www.example.com" );
- $this->assertEquals( "", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) );
-
- $h[] = "name6=value0; domain=.example.net; path=/path/; expires=Mon, 09-Dec-1999 13:46:00 GMT";
- $cj->parseCookieResponseHeader( $h[4], "www.example.net" );
- $this->assertEquals( "", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) );
-
- $h[] = "name6=value4; domain=.example.net; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT";
- $cj->parseCookieResponseHeader( $h[5], "www.example.net" );
- $this->assertEquals( "name6=value4", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) );
- }
-
- function runCookieRequests() {
- $r = MWHttpRequest::factory( "http://www.php.net/manual", array( 'followRedirects' => true ) );
- $r->execute();
-
- $jar = $r->getCookieJar();
- $this->assertThat( $jar, $this->isInstanceOf( 'CookieJar' ) );
-
- $serialized = $jar->serializeToHttpRequest( "/search?q=test", "www.php.net" );
- $this->assertRegExp( '/\bCOUNTRY=[^=;]+/', $serialized );
- $this->assertRegExp( '/\bLAST_LANG=[^=;]+/', $serialized );
- $this->assertEquals( '', $jar->serializeToHttpRequest( "/search?q=test", "www.php.com" ) );
- }
-
- function testCookieRequestDefault() {
- Http::$httpEngine = false;
- $this->runCookieRequests();
- }
- function testCookieRequestPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = 'php';
- $this->runCookieRequests();
- }
- function testCookieRequestCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = 'curl';
- $this->runCookieRequests();
- }
-
/**
* Test Http::isValidURI()
- * @bug 27854 : Http::isValidURI is to lax
- *@dataProvider provideURI */
+ * @bug 27854 : Http::isValidURI is too lax
+ * @dataProvider provideURI
+ */
function testIsValidUri( $expect, $URI, $message = '' ) {
$this->assertEquals(
$expect,
@@ -567,7 +76,7 @@ class HttpTest extends MediaWikiTestCase {
array( false, '\\host\directory', 'CIFS share' ),
array( false, 'gopher://host/dir', 'Reject gopher scheme' ),
array( false, 'telnet://host', 'Reject telnet scheme' ),
-
+
# :\/\/ - double slashes
array( false, 'http//example.org', 'Reject missing colon in protocol' ),
array( false, 'http:/example.org', 'Reject missing slash in protocol' ),
@@ -615,4 +124,57 @@ class HttpTest extends MediaWikiTestCase {
);
}
+ /**
+ * Warning:
+ *
+ * These tests are for code that makes use of an artifact of how CURL
+ * handles header reporting on redirect pages, and will need to be
+ * rewritten when bug 29232 is taken care of (high-level handling of
+ * HTTP redirects).
+ */
+ function testRelativeRedirections() {
+ $h = new MWHttpRequestTester( 'http://oldsite/file.ext' );
+ # Forge a Location header
+ $h->setRespHeaders( 'location', array(
+ 'http://newsite/file.ext',
+ '/newfile.ext',
+ )
+ );
+ # Verify we correctly fix the Location
+ $this->assertEquals(
+ 'http://newsite/newfile.ext',
+ $h->getFinalUrl(),
+ "Relative file path Location: interpreted as full URL"
+ );
+
+ $h->setRespHeaders( 'location', array(
+ 'https://oldsite/file.ext'
+ )
+ );
+ $this->assertEquals(
+ 'https://oldsite/file.ext',
+ $h->getFinalUrl(),
+ "Location to the HTTPS version of the site"
+ );
+
+ $h->setRespHeaders( 'location', array(
+ '/anotherfile.ext',
+ 'http://anotherfile/hoster.ext',
+ 'https://anotherfile/hoster.ext'
+ )
+ );
+ $this->assertEquals(
+ 'https://anotherfile/hoster.ext',
+ $h->getFinalUrl( "Relative file path Location: should keep the latest host and scheme!")
+ );
+ }
+}
+
+/**
+ * Class to let us overwrite MWHttpREquest respHeaders variable
+ */
+class MWHttpRequestTester extends MWHttpRequest {
+ function setRespHeaders( $name, $value ) {
+ $this->respHeaders[$name] = $value ;
+ }
}
diff --git a/tests/phpunit/includes/IPTest.php b/tests/phpunit/includes/IPTest.php
index c77dd852..4397b879 100644
--- a/tests/phpunit/includes/IPTest.php
+++ b/tests/phpunit/includes/IPTest.php
@@ -1,5 +1,5 @@
<?php
-/*
+/**
* Tests for IP validity functions. Ported from /t/inc/IP.t by avar.
*/
@@ -43,20 +43,20 @@ class IPTest extends MediaWikiTestCase {
$this->assertFalse( IP::isIPv6( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
$this->assertFalse( IP::isIPv6( 'fc:300' ), 'IPv6 with only 2 words' );
$this->assertFalse( IP::isIPv6( 'fc:100:300' ), 'IPv6 with only 3 words' );
-
+
$this->assertTrue( IP::isIPv6( 'fc:100::' ) );
$this->assertTrue( IP::isIPv6( 'fc:100:a::' ) );
$this->assertTrue( IP::isIPv6( 'fc:100:a:d::' ) );
$this->assertTrue( IP::isIPv6( 'fc:100:a:d:1::' ) );
$this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e::' ) );
$this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac::' ) );
-
+
$this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' );
$this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' );
$this->assertFalse( IP::isIPv6( ':::' ) );
$this->assertFalse( IP::isIPv6( '::0:' ), 'IPv6 ending in a lone ":"' );
-
+
$this->assertTrue( IP::isIPv6( '::' ), 'IPv6 zero address' );
$this->assertTrue( IP::isIPv6( '::0' ) );
$this->assertTrue( IP::isIPv6( '::fc' ) );
@@ -66,14 +66,14 @@ class IPTest extends MediaWikiTestCase {
$this->assertTrue( IP::isIPv6( '::fc:100:a:d:1' ) );
$this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e' ) );
$this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e:ac' ) );
-
+
$this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
$this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
$this->assertFalse( IP::isIPv6( ':fc::100' ), 'IPv6 starting with lone ":"' );
$this->assertFalse( IP::isIPv6( 'fc::100:' ), 'IPv6 ending with lone ":"' );
$this->assertFalse( IP::isIPv6( 'fc:::100' ), 'IPv6 with ":::" in the middle' );
-
+
$this->assertTrue( IP::isIPv6( 'fc::100' ), 'IPv6 with "::" and 2 words' );
$this->assertTrue( IP::isIPv6( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
$this->assertTrue( IP::isIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ) );
@@ -83,7 +83,7 @@ class IPTest extends MediaWikiTestCase {
$this->assertTrue( IP::isIPv6( '2001::df'), 'IPv6 with "::" and 2 words' );
$this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df'), 'IPv6 with "::" and 5 words' );
$this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df:2'), 'IPv6 with "::" and 6 words' );
-
+
$this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
$this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
@@ -135,11 +135,11 @@ class IPTest extends MediaWikiTestCase {
$this->assertFalse( IP::isValid( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
$this->assertFalse( IP::isValid( 'fc:300' ), 'IPv6 with only 2 words' );
$this->assertFalse( IP::isValid( 'fc:100:300' ), 'IPv6 with only 3 words' );
-
+
$this->assertTrue( IP::isValid( 'fc:100::' ) );
$this->assertTrue( IP::isValid( 'fc:100:a:d:1:e::' ) );
$this->assertTrue( IP::isValid( 'fc:100:a:d:1:e:ac::' ) );
-
+
$this->assertTrue( IP::isValid( 'fc::100' ), 'IPv6 with "::" and 2 words' );
$this->assertTrue( IP::isValid( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
$this->assertTrue( IP::isValid( '2001::df'), 'IPv6 with "::" and 2 words' );
@@ -147,7 +147,7 @@ class IPTest extends MediaWikiTestCase {
$this->assertTrue( IP::isValid( '2001:5c0:1400:a::df:2'), 'IPv6 with "::" and 6 words' );
$this->assertTrue( IP::isValid( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' );
$this->assertTrue( IP::isValid( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' );
-
+
$this->assertFalse( IP::isValid( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' );
$this->assertFalse( IP::isValid( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' );
}
@@ -276,7 +276,7 @@ class IPTest extends MediaWikiTestCase {
foreach ( $private as $p ) {
$this->assertFalse( IP::isPublic( $p ), "$p is not a public IP address" );
}
- $public = array( '2001:5c0:1000:a::133', 'fc::3' );
+ $public = array( '2001:5c0:1000:a::133', 'fc::3', '00FC::' );
foreach ( $public as $p ) {
$this->assertTrue( IP::isPublic( $p ), "$p is a public IP address" );
}
@@ -332,7 +332,7 @@ class IPTest extends MediaWikiTestCase {
$this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF', IP::hexToOctet( 'FCCFFAFF' ) );
}
- /*
+ /**
* IP::parseCIDR() returns an array containing a signed IP address
* representing the network mask and the bit mask.
* @covers IP::parseCIDR
@@ -391,7 +391,7 @@ class IPTest extends MediaWikiTestCase {
}
/**
- * Issues there are most probably from IP::toHex() or IP::parseRange()
+ * Issues there are most probably from IP::toHex() or IP::parseRange()
* @covers IP::isInRange
* @dataProvider provideIPsAndRanges
*/
@@ -464,9 +464,9 @@ class IPTest extends MediaWikiTestCase {
*/
function testCombineHostAndPort( $expected, $input, $description ) {
list( $host, $port, $defaultPort ) = $input;
- $this->assertEquals(
- $expected,
- IP::combineHostAndPort( $host, $port, $defaultPort ),
+ $this->assertEquals(
+ $expected,
+ IP::combineHostAndPort( $host, $port, $defaultPort ),
$description );
}
diff --git a/tests/phpunit/includes/LocalFileTest.php b/tests/phpunit/includes/LocalFileTest.php
index e08d4d7e..5b26b89c 100644
--- a/tests/phpunit/includes/LocalFileTest.php
+++ b/tests/phpunit/includes/LocalFileTest.php
@@ -10,12 +10,21 @@ class LocalFileTest extends MediaWikiTestCase {
global $wgCapitalLinks;
$wgCapitalLinks = true;
+
$info = array(
- 'name' => 'test',
- 'directory' => '/testdir',
- 'url' => '/testurl',
- 'hashLevels' => 2,
+ 'name' => 'test',
+ 'directory' => '/testdir',
+ 'url' => '/testurl',
+ 'hashLevels' => 2,
'transformVia404' => false,
+ 'backend' => new FSFileBackend( array(
+ 'name' => 'local-backend',
+ 'lockManager' => 'fsLockManager',
+ 'containerPaths' => array(
+ 'cont1' => "/testdir/local-backend/tempimages/cont1",
+ 'cont2' => "/testdir/local-backend/tempimages/cont2"
+ )
+ ) )
);
$this->repo_hl0 = new LocalRepo( array( 'hashLevels' => 0 ) + $info );
$this->repo_hl2 = new LocalRepo( array( 'hashLevels' => 2 ) + $info );
@@ -44,17 +53,17 @@ class LocalFileTest extends MediaWikiTestCase {
}
function testGetArchivePath() {
- $this->assertEquals( '/testdir/archive', $this->file_hl0->getArchivePath() );
- $this->assertEquals( '/testdir/archive/a/a2', $this->file_hl2->getArchivePath() );
- $this->assertEquals( '/testdir/archive/!', $this->file_hl0->getArchivePath( '!' ) );
- $this->assertEquals( '/testdir/archive/a/a2/!', $this->file_hl2->getArchivePath( '!' ) );
+ $this->assertEquals( 'mwstore://local-backend/test-public/archive', $this->file_hl0->getArchivePath() );
+ $this->assertEquals( 'mwstore://local-backend/test-public/archive/a/a2', $this->file_hl2->getArchivePath() );
+ $this->assertEquals( 'mwstore://local-backend/test-public/archive/!', $this->file_hl0->getArchivePath( '!' ) );
+ $this->assertEquals( 'mwstore://local-backend/test-public/archive/a/a2/!', $this->file_hl2->getArchivePath( '!' ) );
}
function testGetThumbPath() {
- $this->assertEquals( '/testdir/thumb/Test!', $this->file_hl0->getThumbPath() );
- $this->assertEquals( '/testdir/thumb/a/a2/Test!', $this->file_hl2->getThumbPath() );
- $this->assertEquals( '/testdir/thumb/Test!/x', $this->file_hl0->getThumbPath( 'x' ) );
- $this->assertEquals( '/testdir/thumb/a/a2/Test!/x', $this->file_hl2->getThumbPath( 'x' ) );
+ $this->assertEquals( 'mwstore://local-backend/test-thumb/Test!', $this->file_hl0->getThumbPath() );
+ $this->assertEquals( 'mwstore://local-backend/test-thumb/a/a2/Test!', $this->file_hl2->getThumbPath() );
+ $this->assertEquals( 'mwstore://local-backend/test-thumb/Test!/x', $this->file_hl0->getThumbPath( 'x' ) );
+ $this->assertEquals( 'mwstore://local-backend/test-thumb/a/a2/Test!/x', $this->file_hl2->getThumbPath( 'x' ) );
}
function testGetArchiveUrl() {
diff --git a/tests/phpunit/includes/MWNamespaceTest.php b/tests/phpunit/includes/MWNamespaceTest.php
index 462afc24..6b231fc5 100644
--- a/tests/phpunit/includes/MWNamespaceTest.php
+++ b/tests/phpunit/includes/MWNamespaceTest.php
@@ -1,7 +1,7 @@
<?php
/**
- * @author Ashar Voultoiz
- * @copyright Copyright © 2011, Ashar Voultoiz
+ * @author Antoine Musso
+ * @copyright Copyright © 2011, Antoine Musso
* @file
*/
@@ -39,40 +39,55 @@ class MWNamespaceTest extends MediaWikiTestCase {
/**
* Please make sure to change testIsTalk() if you change the assertions below
*/
- public function testIsMain() {
+ public function testIsSubject() {
// Special namespaces
- $this->assertTrue( MWNamespace::isMain( NS_MEDIA ) );
- $this->assertTrue( MWNamespace::isMain( NS_SPECIAL ) );
+ $this->assertIsSubject( NS_MEDIA );
+ $this->assertIsSubject( NS_SPECIAL );
// Subject pages
- $this->assertTrue( MWNamespace::isMain( NS_MAIN ) );
- $this->assertTrue( MWNamespace::isMain( NS_USER ) );
- $this->assertTrue( MWNamespace::isMain( 100 ) ); # user defined
+ $this->assertIsSubject( NS_MAIN );
+ $this->assertIsSubject( NS_USER );
+ $this->assertIsSubject( 100 ); # user defined
// Talk pages
- $this->assertFalse( MWNamespace::isMain( NS_TALK ) );
- $this->assertFalse( MWNamespace::isMain( NS_USER_TALK ) );
- $this->assertFalse( MWNamespace::isMain( 101 ) ); # user defined
+ $this->assertIsNotSubject( NS_TALK );
+ $this->assertIsNotSubject( NS_USER_TALK );
+ $this->assertIsNotSubject( 101 ); # user defined
+
+ // Back compat
+ $this->assertTrue( MWNamespace::isMain( NS_MAIN ) == MWNamespace::isSubject( NS_MAIN ) );
+ $this->assertTrue( MWNamespace::isMain( NS_USER_TALK ) == MWNamespace::isSubject( NS_USER_TALK ) );
}
/**
- * Reverse of testIsMain().
- * Please update testIsMain() if you change assertions below
+ * Reverse of testIsSubject().
+ * Please update testIsSubject() if you change assertions below
*/
public function testIsTalk() {
// Special namespaces
- $this->assertFalse( MWNamespace::isTalk( NS_MEDIA ) );
- $this->assertFalse( MWNamespace::isTalk( NS_SPECIAL ) );
+ $this->assertIsNotTalk( NS_MEDIA );
+ $this->assertIsNotTalk( NS_SPECIAL );
// Subject pages
- $this->assertFalse( MWNamespace::isTalk( NS_MAIN ) );
- $this->assertFalse( MWNamespace::isTalk( NS_USER ) );
- $this->assertFalse( MWNamespace::isTalk( 100 ) ); # user defined
+ $this->assertIsNotTalk( NS_MAIN );
+ $this->assertIsNotTalk( NS_USER );
+ $this->assertIsNotTalk( 100 ); # user defined
// Talk pages
- $this->assertTrue( MWNamespace::isTalk( NS_TALK ) );
- $this->assertTrue( MWNamespace::isTalk( NS_USER_TALK ) );
- $this->assertTrue( MWNamespace::isTalk( 101 ) ); # user defined
+ $this->assertIsTalk( NS_TALK );
+ $this->assertIsTalk( NS_USER_TALK );
+ $this->assertIsTalk( 101 ); # user defined
+ }
+
+ /**
+ */
+ public function testGetSubject() {
+ // Special namespaces are their own subjects
+ $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) );
+ $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) );
+
+ $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) );
+ $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) );
}
/**
@@ -82,6 +97,9 @@ class MWNamespaceTest extends MediaWikiTestCase {
*/
public function testGetTalk() {
$this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_MAIN ) );
+ $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_TALK ) );
+ $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER ) );
+ $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER_TALK ) );
}
/**
@@ -93,7 +111,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
$this->assertNull( MWNamespace::getTalk( NS_MEDIA ) );
}
- /**
+ /**
* Exceptions with getTalk()
* NS_SPECIAL does not have talk pages. MediaWiki raise an exception for them.
* @expectedException MWException
@@ -108,7 +126,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
* the function testGetAssociatedExceptions()
*/
public function testGetAssociated() {
- $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) );
+ $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) );
$this->assertEquals( NS_MAIN, MWNamespace::getAssociated( NS_TALK ) );
}
@@ -131,80 +149,122 @@ class MWNamespaceTest extends MediaWikiTestCase {
}
/**
- */
- public function testGetSubject() {
- // Special namespaces are their own subjects
- $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) );
- $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) );
-
- $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) );
- $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) );
- }
-
- /**
* @todo Implement testExists().
*/
+/*
public function testExists() {
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.'
);
}
+*/
+
+ /**
+ * Test MWNamespace::equals
+ * Note if we add a namespace registration system with keys like 'MAIN'
+ * we should add tests here for equivilance on things like 'MAIN' == 0
+ * and 'MAIN' == NS_MAIN.
+ */
+ public function testEquals() {
+ $this->assertTrue( MWNamespace::equals( NS_MAIN, NS_MAIN ) );
+ $this->assertTrue( MWNamespace::equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN'
+ $this->assertTrue( MWNamespace::equals( NS_USER, NS_USER ) );
+ $this->assertTrue( MWNamespace::equals( NS_USER, 2 ) );
+ $this->assertTrue( MWNamespace::equals( NS_USER_TALK, NS_USER_TALK ) );
+ $this->assertTrue( MWNamespace::equals( NS_SPECIAL, NS_SPECIAL ) );
+ $this->assertFalse( MWNamespace::equals( NS_MAIN, NS_TALK ) );
+ $this->assertFalse( MWNamespace::equals( NS_USER, NS_USER_TALK ) );
+ $this->assertFalse( MWNamespace::equals( NS_PROJECT, NS_TEMPLATE ) );
+ }
+
+ /**
+ * Test MWNamespace::subjectEquals
+ */
+ public function testSubjectEquals() {
+ $this->assertSameSubject( NS_MAIN, NS_MAIN );
+ $this->assertSameSubject( NS_MAIN, 0 ); // In case we make NS_MAIN 'MAIN'
+ $this->assertSameSubject( NS_USER, NS_USER );
+ $this->assertSameSubject( NS_USER, 2 );
+ $this->assertSameSubject( NS_USER_TALK, NS_USER_TALK );
+ $this->assertSameSubject( NS_SPECIAL, NS_SPECIAL );
+ $this->assertSameSubject( NS_MAIN, NS_TALK );
+ $this->assertSameSubject( NS_USER, NS_USER_TALK );
+
+ $this->assertDifferentSubject( NS_PROJECT, NS_TEMPLATE );
+ $this->assertDifferentSubject( NS_SPECIAL, NS_MAIN );
+ }
+
+ public function testSpecialAndMediaAreDifferentSubjects() {
+ $this->assertDifferentSubject(
+ NS_MEDIA, NS_SPECIAL,
+ "NS_MEDIA and NS_SPECIAL are different subject namespaces"
+ );
+ $this->assertDifferentSubject(
+ NS_SPECIAL, NS_MEDIA,
+ "NS_SPECIAL and NS_MEDIA are different subject namespaces"
+ );
+
+ }
/**
* @todo Implement testGetCanonicalNamespaces().
*/
+/*
public function testGetCanonicalNamespaces() {
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.'
);
}
-
+*/
/**
* @todo Implement testGetCanonicalName().
*/
+/*
public function testGetCanonicalName() {
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.'
);
}
-
+*/
/**
* @todo Implement testGetCanonicalIndex().
*/
+/*
public function testGetCanonicalIndex() {
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.'
);
}
-
+*/
/**
* @todo Implement testGetValidNamespaces().
*/
+/*
public function testGetValidNamespaces() {
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.'
);
}
-
+*/
/**
*/
public function testCanTalk() {
- $this->assertFalse( MWNamespace::canTalk( NS_MEDIA ) );
- $this->assertFalse( MWNamespace::canTalk( NS_SPECIAL ) );
+ $this->assertCanNotTalk( NS_MEDIA );
+ $this->assertCanNotTalk( NS_SPECIAL );
- $this->assertTrue( MWNamespace::canTalk( NS_MAIN ) );
- $this->assertTrue( MWNamespace::canTalk( NS_TALK ) );
- $this->assertTrue( MWNamespace::canTalk( NS_USER ) );
- $this->assertTrue( MWNamespace::canTalk( NS_USER_TALK ) );
+ $this->assertCanTalk( NS_MAIN );
+ $this->assertCanTalk( NS_TALK );
+ $this->assertCanTalk( NS_USER );
+ $this->assertCanTalk( NS_USER_TALK );
// User defined namespaces
- $this->assertTrue( MWNamespace::canTalk( 100 ) );
- $this->assertTrue( MWNamespace::canTalk( 101 ) );
+ $this->assertCanTalk( 100 );
+ $this->assertCanTalk( 101 );
}
/**
@@ -212,16 +272,47 @@ class MWNamespaceTest extends MediaWikiTestCase {
public function testIsContent() {
// NS_MAIN is a content namespace per DefaultSettings.php
// and per function definition.
- $this->assertTrue( MWNamespace::isContent( NS_MAIN ) );
+ $this->assertIsContent( NS_MAIN );
+
+ global $wgContentNamespaces;
+
+ $saved = $wgContentNamespaces;
+
+ $wgContentNamespaces[] = NS_MAIN;
+ $this->assertIsContent( NS_MAIN );
// Other namespaces which are not expected to be content
- $this->assertFalse( MWNamespace::isContent( NS_MEDIA ) );
- $this->assertFalse( MWNamespace::isContent( NS_SPECIAL ) );
- $this->assertFalse( MWNamespace::isContent( NS_TALK ) );
- $this->assertFalse( MWNamespace::isContent( NS_USER ) );
- $this->assertFalse( MWNamespace::isContent( NS_CATEGORY ) );
- // User defined namespace:
- $this->assertFalse( MWNamespace::isContent( 100 ) );
+ if ( isset( $wgContentNamespaces[NS_MEDIA] ) ) {
+ unset( $wgContentNamespaces[NS_MEDIA] );
+ }
+ $this->assertIsNotContent( NS_MEDIA );
+
+ if ( isset( $wgContentNamespaces[NS_SPECIAL] ) ) {
+ unset( $wgContentNamespaces[NS_SPECIAL] );
+ }
+ $this->assertIsNotContent( NS_SPECIAL );
+
+ if ( isset( $wgContentNamespaces[NS_TALK] ) ) {
+ unset( $wgContentNamespaces[NS_TALK] );
+ }
+ $this->assertIsNotContent( NS_TALK );
+
+ if ( isset( $wgContentNamespaces[NS_USER] ) ) {
+ unset( $wgContentNamespaces[NS_USER] );
+ }
+ $this->assertIsNotContent( NS_USER );
+
+ if ( isset( $wgContentNamespaces[NS_CATEGORY] ) ) {
+ unset( $wgContentNamespaces[NS_CATEGORY] );
+ }
+ $this->assertIsNotContent( NS_CATEGORY );
+
+ if ( isset( $wgContentNamespaces[100] ) ) {
+ unset( $wgContentNamespaces[100] );
+ }
+ $this->assertIsNotContent( 100 );
+
+ $wgContentNamespaces = $saved;
}
/**
@@ -231,47 +322,47 @@ class MWNamespaceTest extends MediaWikiTestCase {
public function testIsContentWithAdditionsInWgContentNamespaces() {
// NS_MAIN is a content namespace per DefaultSettings.php
// and per function definition.
- $this->assertTrue( MWNamespace::isContent( NS_MAIN ) );
+ $this->assertIsContent( NS_MAIN );
// Tests that user defined namespace #252 is not content:
- $this->assertFalse( MWNamespace::isContent( 252 ) );
+ $this->assertIsNotContent( 252 );
# @todo FIXME: Is global saving really required for PHPUnit?
// Bless namespace # 252 as a content namespace
global $wgContentNamespaces;
$savedGlobal = $wgContentNamespaces;
$wgContentNamespaces[] = 252;
- $this->assertTrue( MWNamespace::isContent( 252 ) );
+ $this->assertIsContent( 252 );
// Makes sure NS_MAIN was not impacted
- $this->assertTrue( MWNamespace::isContent( NS_MAIN ) );
+ $this->assertIsContent( NS_MAIN );
// Restore global
$wgContentNamespaces = $savedGlobal;
// Verify namespaces after global restauration
- $this->assertTrue( MWNamespace::isContent( NS_MAIN ) );
- $this->assertFalse( MWNamespace::isContent( 252 ) );
+ $this->assertIsContent( NS_MAIN );
+ $this->assertIsNotContent( 252 );
}
public function testIsWatchable() {
// Specials namespaces are not watchable
- $this->assertFalse( MWNamespace::isWatchable( NS_MEDIA ) );
- $this->assertFalse( MWNamespace::isWatchable( NS_SPECIAL ) );
+ $this->assertIsNotWatchable( NS_MEDIA );
+ $this->assertIsNotWatchable( NS_SPECIAL );
// Core defined namespaces are watchables
- $this->assertTrue( MWNamespace::isWatchable( NS_MAIN ) );
- $this->assertTrue( MWNamespace::isWatchable( NS_TALK ) );
+ $this->assertIsWatchable( NS_MAIN );
+ $this->assertIsWatchable( NS_TALK );
// Additional, user defined namespaces are watchables
- $this->assertTrue( MWNamespace::isWatchable( 100 ) );
- $this->assertTrue( MWNamespace::isWatchable( 101 ) );
+ $this->assertIsWatchable( 100 );
+ $this->assertIsWatchable( 101 );
}
public function testHasSubpages() {
// Special namespaces:
- $this->assertFalse( MWNamespace::hasSubpages( NS_MEDIA ) );
- $this->assertFalse( MWNamespace::hasSubpages( NS_SPECIAL ) );
+ $this->assertHasNotSubpages( NS_MEDIA );
+ $this->assertHasNotSubpages( NS_SPECIAL );
// namespaces without subpages
# save up global
@@ -282,12 +373,12 @@ class MWNamespaceTest extends MediaWikiTestCase {
unset( $wgNamespacesWithSubpages[NS_MAIN] );
}
- $this->assertFalse( MWNamespace::hasSubpages( NS_MAIN ) );
+ $this->assertHasNotSubpages( NS_MAIN );
$wgNamespacesWithSubpages[NS_MAIN] = true;
- $this->assertTrue( MWNamespace::hasSubpages( NS_MAIN ) );
+ $this->assertHasSubpages( NS_MAIN );
$wgNamespacesWithSubpages[NS_MAIN] = false;
- $this->assertFalse( MWNamespace::hasSubpages( NS_MAIN ) );
+ $this->assertHasNotSubpages( NS_MAIN );
# restore global
if( $saved !== null ) {
@@ -295,9 +386,9 @@ class MWNamespaceTest extends MediaWikiTestCase {
}
// Some namespaces with subpages
- $this->assertTrue( MWNamespace::hasSubpages( NS_TALK ) );
- $this->assertTrue( MWNamespace::hasSubpages( NS_USER ) );
- $this->assertTrue( MWNamespace::hasSubpages( NS_USER_TALK ) );
+ $this->assertHasSubpages( NS_TALK );
+ $this->assertHasSubpages( NS_USER );
+ $this->assertHasSubpages( NS_USER_TALK );
}
/**
@@ -311,6 +402,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
global $wgContentNamespaces;
+ $saved = $wgContentNamespaces;
# test !is_array( $wgcontentNamespaces )
$wgContentNamespaces = '';
$this->assertEquals( NS_MAIN, MWNamespace::getcontentNamespaces() );
@@ -330,7 +422,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
$this->assertEquals(
array( NS_MAIN, NS_USER, NS_CATEGORY ),
MWNamespace::getcontentNamespaces(),
- 'NS_MAIN is forced in wgContentNamespaces even if unwanted'
+ 'NS_MAIN is forced in $wgContentNamespaces even if unwanted'
);
# test other cases, return $wgcontentNamespaces as is
@@ -346,6 +438,7 @@ class MWNamespaceTest extends MediaWikiTestCase {
MWNamespace::getcontentNamespaces()
);
+ $wgContentNamespaces = $saved;
}
/**
@@ -361,14 +454,14 @@ class MWNamespaceTest extends MediaWikiTestCase {
);
// Boths are capitalized by default
- $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIA ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_FILE ) );
+ $this->assertIsCapitalized( NS_MEDIA );
+ $this->assertIsCapitalized( NS_FILE );
// Always capitalized namespaces
// @see MWNamespace::$alwaysCapitalizedNamespaces
- $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) );
+ $this->assertIsCapitalized( NS_SPECIAL );
+ $this->assertIsCapitalized( NS_USER );
+ $this->assertIsCapitalized( NS_MEDIAWIKI );
}
/**
@@ -389,17 +482,17 @@ class MWNamespaceTest extends MediaWikiTestCase {
$savedGlobal = $wgCapitalLinks;
$wgCapitalLinks = true;
- $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT_TALK ) );
+ $this->assertIsCapitalized( NS_PROJECT );
+ $this->assertIsCapitalized( NS_PROJECT_TALK );
$wgCapitalLinks = false;
// hardcoded namespaces (see above function) are still capitalized:
- $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) );
+ $this->assertIsCapitalized( NS_SPECIAL );
+ $this->assertIsCapitalized( NS_USER );
+ $this->assertIsCapitalized( NS_MEDIAWIKI );
// setting is correctly applied
- $this->assertFalse( MWNamespace::isCapitalized( NS_PROJECT ) );
- $this->assertFalse( MWNamespace::isCapitalized( NS_PROJECT_TALK ) );
+ $this->assertIsNotCapitalized( NS_PROJECT );
+ $this->assertIsNotCapitalized( NS_PROJECT_TALK );
// reset global state:
$wgCapitalLinks = $savedGlobal;
@@ -417,28 +510,28 @@ class MWNamespaceTest extends MediaWikiTestCase {
$savedGlobal = $wgCapitalLinkOverrides;
// Test default settings
- $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT_TALK ) );
+ $this->assertIsCapitalized( NS_PROJECT );
+ $this->assertIsCapitalized( NS_PROJECT_TALK );
// hardcoded namespaces (see above function) are capitalized:
- $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) );
+ $this->assertIsCapitalized( NS_SPECIAL );
+ $this->assertIsCapitalized( NS_USER );
+ $this->assertIsCapitalized( NS_MEDIAWIKI );
// Hardcoded namespaces remains capitalized
$wgCapitalLinkOverrides[NS_SPECIAL] = false;
$wgCapitalLinkOverrides[NS_USER] = false;
$wgCapitalLinkOverrides[NS_MEDIAWIKI] = false;
- $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) );
- $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) );
+ $this->assertIsCapitalized( NS_SPECIAL );
+ $this->assertIsCapitalized( NS_USER );
+ $this->assertIsCapitalized( NS_MEDIAWIKI );
$wgCapitalLinkOverrides = $savedGlobal;
$wgCapitalLinkOverrides[NS_PROJECT] = false;
- $this->assertFalse( MWNamespace::isCapitalized( NS_PROJECT ) );
+ $this->assertIsNotCapitalized( NS_PROJECT );
$wgCapitalLinkOverrides[NS_PROJECT] = true ;
- $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) );
+ $this->assertIsCapitalized( NS_PROJECT );
unset( $wgCapitalLinkOverrides[NS_PROJECT] );
- $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) );
+ $this->assertIsCapitalized( NS_PROJECT );
// reset global state:
$wgCapitalLinkOverrides = $savedGlobal;
@@ -456,5 +549,45 @@ class MWNamespaceTest extends MediaWikiTestCase {
$this->assertFalse( MWNamespace::hasGenderDistinction( NS_TALK ) );
}
+
+ ####### HELPERS ###########################################################
+ function __call( $method, $args ) {
+ // Call the real method if it exists
+ if( method_exists($this, $method ) ) {
+ return $this->$method( $args );
+ }
+
+ if( preg_match( '/^assert(Has|Is|Can)(Not|)(Subject|Talk|Watchable|Content|Subpages|Capitalized)$/', $method, $m ) ) {
+ # Interprets arguments:
+ $ns = $args[0];
+ $msg = isset($args[1]) ? $args[1] : " dummy message";
+
+ # Forge the namespace constant name:
+ if( $ns === 0 ) {
+ $ns_name = "NS_MAIN";
+ } else {
+ $ns_name = "NS_" . strtoupper( MWNamespace::getCanonicalName( $ns ) );
+ }
+ # ... and the MWNamespace method name
+ $nsMethod = strtolower( $m[1] ) . $m[3];
+
+ $expect = ($m[2] === '');
+ $expect_name = $expect ? 'TRUE' : 'FALSE';
+
+ return $this->assertEquals( $expect,
+ MWNamespace::$nsMethod( $ns, $msg ),
+ "MWNamespace::$nsMethod( $ns_name ) should returns $expect_name"
+ );
+ }
+
+ throw new Exception( __METHOD__ . " could not find a method named $method\n" );
+ }
+
+ function assertSameSubject( $ns1, $ns2, $msg = '' ) {
+ $this->assertTrue( MWNamespace::subjectEquals( $ns1, $ns2, $msg ) );
+ }
+ function assertDifferentSubject( $ns1, $ns2, $msg = '' ) {
+ $this->assertFalse( MWNamespace::subjectEquals( $ns1, $ns2, $msg ) );
+ }
}
diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php
index 45c02bbe..295b6d74 100644
--- a/tests/phpunit/includes/MessageTest.php
+++ b/tests/phpunit/includes/MessageTest.php
@@ -47,7 +47,7 @@ class MessageTest extends MediaWikiLangTestCase {
$this->assertEquals( 'Main Page', wfMessage( 'mainpage' )->inContentLanguage()->plain(), 'ForceUIMsg disabled' );
$wgForceUIMsgAsContentMsg['testInContentLanguage'] = 'mainpage';
$this->assertEquals( 'Accueil', wfMessage( 'mainpage' )->inContentLanguage()->plain(), 'ForceUIMsg enabled' );
-
+
/* Restore globals */
$wgLang = $oldLang;
unset( $wgForceUIMsgAsContentMsg['testInContentLanguage'] );
diff --git a/tests/phpunit/includes/ParserOptionsTest.php b/tests/phpunit/includes/ParserOptionsTest.php
index 58c89146..59c955fe 100644
--- a/tests/phpunit/includes/ParserOptionsTest.php
+++ b/tests/phpunit/includes/ParserOptionsTest.php
@@ -6,10 +6,9 @@ class ParserOptionsTest extends MediaWikiTestCase {
private $pcache;
function setUp() {
- ParserTest::setUp(); //reuse setup from parser tests
global $wgContLang, $wgUser, $wgLanguageCode;
$wgContLang = Language::factory( $wgLanguageCode );
- $this->popts = new ParserOptions( $wgUser );
+ $this->popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
$this->pcache = ParserCache::singleton();
}
@@ -26,11 +25,11 @@ class ParserOptionsTest extends MediaWikiTestCase {
$wgUseDynamicDates = true;
$title = Title::newFromText( "Some test article" );
- $article = new Article( $title );
+ $page = WikiPage::factory( $title );
- $pcacheKeyBefore = $this->pcache->getKey( $article, $this->popts );
+ $pcacheKeyBefore = $this->pcache->getKey( $page, $this->popts );
$this->assertNotNull( $this->popts->getDateFormat() );
- $pcacheKeyAfter = $this->pcache->getKey( $article, $this->popts );
+ $pcacheKeyAfter = $this->pcache->getKey( $page, $this->popts );
$this->assertEquals( $pcacheKeyBefore, $pcacheKeyAfter );
}
}
diff --git a/tests/phpunit/includes/PathRouterTest.php b/tests/phpunit/includes/PathRouterTest.php
new file mode 100644
index 00000000..f6274584
--- /dev/null
+++ b/tests/phpunit/includes/PathRouterTest.php
@@ -0,0 +1,254 @@
+<?php
+/**
+ * Tests for the PathRouter parsing
+ */
+
+class PathRouterTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ $router = new PathRouter;
+ $router->add("/wiki/$1");
+ $this->basicRouter = $router;
+ }
+
+ /**
+ * Test basic path parsing
+ */
+ public function testBasic() {
+ $matches = $this->basicRouter->parse( "/wiki/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo" ) );
+ }
+
+ /**
+ * Test loose path auto-$1
+ */
+ public function testLoose() {
+ $router = new PathRouter;
+ $router->add("/"); # Should be the same as "/$1"
+ $matches = $router->parse( "/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo" ) );
+
+ $router = new PathRouter;
+ $router->add("/wiki"); # Should be the same as /wiki/$1
+ $matches = $router->parse( "/wiki/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo" ) );
+
+ $router = new PathRouter;
+ $router->add("/wiki/"); # Should be the same as /wiki/$1
+ $matches = $router->parse( "/wiki/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo" ) );
+ }
+
+ /**
+ * Test to ensure that path is based on specifity, not order
+ */
+ public function testOrder() {
+ $router = new PathRouter;
+ $router->add("/$1");
+ $router->add("/a/$1");
+ $router->add("/b/$1");
+ $matches = $router->parse( "/a/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo" ) );
+
+ $router = new PathRouter;
+ $router->add("/b/$1");
+ $router->add("/a/$1");
+ $router->add("/$1");
+ $matches = $router->parse( "/a/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo" ) );
+ }
+
+ /**
+ * Test the handling of key based arrays with a url parameter
+ */
+ public function testKeyParameter() {
+ $router = new PathRouter;
+ $router->add( array( 'edit' => "/edit/$1" ), array( 'action' => '$key' ) );
+ $matches = $router->parse( "/edit/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo", 'action' => 'edit' ) );
+ }
+
+ /**
+ * Test the handling of $2 inside paths
+ */
+ public function testAdditionalParameter() {
+ // Basic $2
+ $router = new PathRouter;
+ $router->add( '/$2/$1', array( 'test' => '$2' ) );
+ $matches = $router->parse( "/asdf/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo", 'test' => 'asdf' ) );
+ }
+
+ /**
+ * Test additional restricted value parameter
+ */
+ public function testRestrictedValue() {
+ $router = new PathRouter;
+ $router->add( '/$2/$1',
+ array( 'test' => '$2' ),
+ array( '$2' => array( 'a', 'b' ) )
+ );
+ $router->add( '/$2/$1',
+ array( 'test2' => '$2' ),
+ array( '$2' => 'c' )
+ );
+ $router->add( '/$1' );
+
+ $matches = $router->parse( "/asdf/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "asdf/Foo" ) );
+
+ $matches = $router->parse( "/a/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo", 'test' => 'a' ) );
+
+ $matches = $router->parse( "/c/Foo" );
+ $this->assertEquals( $matches, array( 'title' => "Foo", 'test2' => 'c' ) );
+ }
+
+ public function callbackForTest( &$matches, $data ) {
+ $matches['x'] = $data['$1'];
+ $matches['foo'] = $data['foo'];
+ }
+
+ public function testCallback() {
+ $router = new PathRouter;
+ $router->add( "/$1",
+ array( 'a' => 'b', 'data:foo' => 'bar' ),
+ array( 'callback' => array( $this, 'callbackForTest' ) )
+ );
+ $matches = $router->parse( '/Foo' );
+ $this->assertEquals( $matches, array(
+ 'title' => "Foo",
+ 'x' => 'Foo',
+ 'a' => 'b',
+ 'foo' => 'bar'
+ ) );
+ }
+
+ /**
+ * Test to ensure that matches are not made if a parameter expects nonexistent input
+ */
+ public function testFail() {
+ $router = new PathRouter;
+ $router->add( "/wiki/$1", array( 'title' => "$1$2" ) );
+ $matches = $router->parse( "/wiki/A" );
+ $this->assertEquals( array(), $matches );
+ }
+
+ /**
+ * Test to ensure weight of paths is handled correctly
+ */
+ public function testWeight() {
+ $router = new PathRouter;
+ $router->addStrict( "/Bar", array( 'ping' => 'pong' ) );
+ $router->add( "/asdf-$1", array( 'title' => 'qwerty-$1' ) );
+ $router->add( "/$1" );
+ $router->add( "/qwerty-$1", array( 'title' => 'asdf-$1' ) );
+ $router->addStrict( "/Baz", array( 'marco' => 'polo' ) );
+ $router->add( "/a/$1" );
+ $router->add( "/asdf/$1" );
+ $router->add( "/$2/$1", array( 'unrestricted' => '$2' ) );
+ $router->add( array( 'qwerty' => "/qwerty/$1" ), array( 'qwerty' => '$key' ) );
+ $router->add( "/$2/$1", array( 'restricted-to-y' => '$2' ), array( '$2' => 'y' ) );
+
+ foreach( array(
+ "/Foo" => array( 'title' => "Foo" ),
+ "/Bar" => array( 'ping' => 'pong' ),
+ "/Baz" => array( 'marco' => 'polo' ),
+ "/asdf-foo" => array( 'title' => "qwerty-foo" ),
+ "/qwerty-bar" => array( 'title' => "asdf-bar" ),
+ "/a/Foo" => array( 'title' => "Foo" ),
+ "/asdf/Foo" => array( 'title' => "Foo" ),
+ "/qwerty/Foo" => array( 'title' => "Foo", 'qwerty' => 'qwerty' ),
+ "/baz/Foo" => array( 'title' => "Foo", 'unrestricted' => 'baz' ),
+ "/y/Foo" => array( 'title' => "Foo", 'restricted-to-y' => 'y' ),
+ ) as $path => $result ) {
+ $this->assertEquals( $router->parse( $path ), $result );
+ }
+ }
+
+ /**
+ * Make sure the router handles titles like Special:Recentchanges correctly
+ */
+ public function testSpecial() {
+ $matches = $this->basicRouter->parse( "/wiki/Special:Recentchanges" );
+ $this->assertEquals( $matches, array( 'title' => "Special:Recentchanges" ) );
+ }
+
+ /**
+ * Make sure the router decodes urlencoding properly
+ */
+ public function testUrlencoding() {
+ $matches = $this->basicRouter->parse( "/wiki/Title_With%20Space" );
+ $this->assertEquals( $matches, array( 'title' => "Title_With Space" ) );
+ }
+
+ public function dataRegexpChars() {
+ return array(
+ array( "$" ),
+ array( "$1" ),
+ array( "\\" ),
+ array( "\\$1" ),
+ );
+ }
+
+ /**
+ * Make sure the router doesn't break on special characters like $ used in regexp replacements
+ * @dataProvider dataRegexpChars
+ */
+ public function testRegexpChars( $char ) {
+ $matches = $this->basicRouter->parse( "/wiki/$char" );
+ $this->assertEquals( $matches, array( 'title' => "$char" ) );
+ }
+
+ /**
+ * Make sure the router handles characters like +&() properly
+ */
+ public function testCharacters() {
+ $matches = $this->basicRouter->parse( "/wiki/Plus+And&Dollar\\Stuff();[]{}*" );
+ $this->assertEquals( $matches, array( 'title' => "Plus+And&Dollar\\Stuff();[]{}*" ) );
+ }
+
+ /**
+ * Make sure the router handles unicode characters correctly
+ * @depends testSpecial
+ * @depends testUrlencoding
+ * @depends testCharacters
+ */
+ public function testUnicode() {
+ $matches = $this->basicRouter->parse( "/wiki/Spécial:Modifications_récentes" );
+ $this->assertEquals( $matches, array( 'title' => "Spécial:Modifications_récentes" ) );
+
+ $matches = $this->basicRouter->parse( "/wiki/Sp%C3%A9cial:Modifications_r%C3%A9centes" );
+ $this->assertEquals( $matches, array( 'title' => "Spécial:Modifications_récentes" ) );
+ }
+
+ /**
+ * Ensure the router doesn't choke on long paths.
+ */
+ public function testLength() {
+ $matches = $this->basicRouter->parse( "/wiki/Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." );
+ $this->assertEquals( $matches, array( 'title' => "Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." ) );
+ }
+
+
+ /**
+ * Ensure that the php passed site of parameter values are not urldecoded
+ */
+ public function testPatternUrlencoding() {
+ $router = new PathRouter;
+ $router->add( "/wiki/$1", array( 'title' => '%20:$1' ) );
+ $matches = $router->parse( "/wiki/Foo" );
+ $this->assertEquals( $matches, array( 'title' => '%20:Foo' ) );
+ }
+
+ /**
+ * Ensure that raw parameter values do not have any variable replacements or urldecoding
+ */
+ public function testRawParamValue() {
+ $router = new PathRouter;
+ $router->add( "/wiki/$1", array( 'title' => array( 'value' => 'bar%20$1' ) ) );
+ $matches = $router->parse( "/wiki/Foo" );
+ $this->assertEquals( $matches, array( 'title' => 'bar%20$1' ) );
+ }
+
+}
diff --git a/tests/phpunit/includes/Providers.php b/tests/phpunit/includes/Providers.php
index 02898673..f451f8a0 100644
--- a/tests/phpunit/includes/Providers.php
+++ b/tests/phpunit/includes/Providers.php
@@ -2,8 +2,8 @@
/**
* Generic providers for the MediaWiki PHPUnit test suite
*
- * @author Ashar Voultoiz
- * @copyright Copyright © 2011, Ashar Voultoiz
+ * @author Antoine Musso
+ * @copyright Copyright © 2011, Antoine Musso
* @file
*/
diff --git a/tests/phpunit/includes/ResourceLoaderTest.php b/tests/phpunit/includes/ResourceLoaderTest.php
index 30a69c5e..ab704839 100644
--- a/tests/phpunit/includes/ResourceLoaderTest.php
+++ b/tests/phpunit/includes/ResourceLoaderTest.php
@@ -1,6 +1,6 @@
<?php
-class ResourceLoaderTest extends PHPUnit_Framework_TestCase {
+class ResourceLoaderTest extends MediaWikiTestCase {
protected static $resourceLoaderRegisterModulesHook;
diff --git a/tests/phpunit/includes/SanitizerTest.php b/tests/phpunit/includes/SanitizerTest.php
index 40d6cf77..b76aa5c7 100644
--- a/tests/phpunit/includes/SanitizerTest.php
+++ b/tests/phpunit/includes/SanitizerTest.php
@@ -109,5 +109,48 @@ class SanitizerTest extends MediaWikiTestCase {
$this->assertEquals( Sanitizer::decodeTagAttributes( 'foo=&amp;&quot;' ), array( 'foo' => '&"' ), 'Special chars can be provided as entities' );
$this->assertEquals( Sanitizer::decodeTagAttributes( 'foo=&foobar;' ), array( 'foo' => '&foobar;' ), 'Entity-like items are accepted' );
}
+
+ function testDeprecatedAttributes() {
+ $GLOBALS['wgCleanupPresentationalAttributes'] = true;
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'clear="left"', 'br' ), ' style="clear: left;"', 'Deprecated attributes are converted to styles when enabled.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'clear="all"', 'br' ), ' style="clear: both;"', 'clear=all is converted to clear: both; not clear: all;' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'CLEAR="ALL"', 'br' ), ' style="clear: both;"', 'clear=ALL is not treated differently from clear=all' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'width="100"', 'td' ), ' style="width: 100px;"', 'Numeric sizes use pixels instead of numbers.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'width="100%"', 'td' ), ' style="width: 100%;"', 'Units are allowed in sizes.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'WIDTH="100%"', 'td' ), ' style="width: 100%;"', 'Uppercase WIDTH is treated as lowercase width.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'WiDTh="100%"', 'td' ), ' style="width: 100%;"', 'Mixed case does not break WiDTh.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'nowrap="true"', 'td' ), ' style="white-space: nowrap;"', 'nowrap attribute is output as white-space: nowrap; not something else.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'nowrap=""', 'td' ), ' style="white-space: nowrap;"', 'nowrap="" is considered true, not false' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'NOWRAP="true"', 'td' ), ' style="white-space: nowrap;"', 'nowrap attribute works when uppercase.' );
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'NoWrAp="true"', 'td' ), ' style="white-space: nowrap;"', 'nowrap attribute works when mixed-case.' );
+ $GLOBALS['wgCleanupPresentationalAttributes'] = false;
+ $this->assertEquals( Sanitizer::fixTagAttributes( 'clear="left"', 'br' ), ' clear="left"', 'Deprecated attributes are not converted to styles when enabled.' );
+ }
+
+ /**
+ * @dataProvider provideCssCommentsFixtures
+ */
+ function testCssCommentsChecking( $expected, $css, $message = '' ) {
+ $this->assertEquals(
+ $expected,
+ Sanitizer::checkCss( $css ),
+ $message
+ );
+ }
+
+ function provideCssCommentsFixtures() {
+ /** array( <expected>, <css>, [message] ) */
+ return array(
+ array( ' ', '/**/' ),
+ array( ' ', '/****/' ),
+ array( ' ', '/* comment */' ),
+ array( ' ', "\\2f\\2a foo \\2a\\2f",
+ 'Backslash-escaped comments must be stripped (bug 28450)' ),
+ array( '', '/* unfinished comment structure',
+ 'Remove anything after a comment-start token' ),
+ array( '', "\\2f\\2a unifinished comment'",
+ 'Remove anything after a backslash-escaped comment-start token' ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/UserIsValidEmailAddrTest.php b/tests/phpunit/includes/SanitizerValidateEmailTest.php
index 99bf718e..14d799cf 100644
--- a/tests/phpunit/includes/UserIsValidEmailAddrTest.php
+++ b/tests/phpunit/includes/SanitizerValidateEmailTest.php
@@ -1,12 +1,12 @@
<?php
-class UserIsValidEmailAddrTest extends MediaWikiTestCase {
+class SanitizerValidateEmailTest extends MediaWikiTestCase {
private function checkEmail( $addr, $expected = true, $msg = '') {
if( $msg == '' ) { $msg = "Testing $addr"; }
$this->assertEquals(
$expected,
- User::isValidEmailAddr( $addr ),
+ Sanitizer::validateEmail( $addr ),
$msg
);
}
diff --git a/tests/phpunit/includes/SeleniumConfigurationTest.php b/tests/phpunit/includes/SeleniumConfigurationTest.php
index 750524eb..8589c188 100644
--- a/tests/phpunit/includes/SeleniumConfigurationTest.php
+++ b/tests/phpunit/includes/SeleniumConfigurationTest.php
@@ -2,13 +2,13 @@
class SeleniumConfigurationTest extends MediaWikiTestCase {
- /*
+ /**
* The file where the test temporarity stores the selenium config.
* This should be cleaned up as part of teardown.
*/
private $tempFileName;
- /*
+ /**
* String containing the a sample selenium settings
*/
private $testConfig0 =
@@ -32,14 +32,14 @@ runAgainstGrid = false
testSuite[SimpleSeleniumTestSuite] = "tests/selenium/SimpleSeleniumTestSuite.php"
testSuite[TestSuiteName] = "testSuitePath"
';
- /*
+ /**
* Array of expected browsers from $testConfig0
*/
private $testBrowsers0 = array( 'firefox' => '*firefox',
'iexplorer' => '*iexploreproxy',
'chrome' => '*chrome'
);
- /*
+ /**
* Array of expected selenium settings from $testConfig0
*/
private $testSettings0 = array(
@@ -55,7 +55,7 @@ testSuite[TestSuiteName] = "testSuitePath"
'jUnitLogFile' => null,
'runAgainstGrid' => null
);
- /*
+ /**
* Array of expected testSuites from $testConfig0
*/
private $testSuites0 = array(
@@ -64,7 +64,7 @@ testSuite[TestSuiteName] = "testSuitePath"
);
- /*
+ /**
* Another sample selenium settings file contents
*/
private $testConfig1 =
@@ -73,11 +73,11 @@ testSuite[TestSuiteName] = "testSuitePath"
host = "localhost"
testBrowser = "firefox"
';
- /*
+ /**
* Expected browsers from $testConfig1
*/
private $testBrowsers1 = null;
- /*
+ /**
* Expected selenium settings from $testConfig1
*/
private $testSettings1 = array(
@@ -93,7 +93,7 @@ testBrowser = "firefox"
'jUnitLogFile' => null,
'runAgainstGrid' => null
);
- /*
+ /**
* Expected test suites from $testConfig1
*/
private $testSuites1 = null;
@@ -105,7 +105,7 @@ testBrowser = "firefox"
}
}
- /*
+ /**
* Clean up the temporary file used to store the selenium settings.
*/
public function tearDown() {
@@ -199,7 +199,7 @@ testBrowser = "firefox"
}
- /*
+ /**
* create a temp file and write text to it.
* @param $testToWrite the text to write to the temp file
*/
@@ -210,7 +210,7 @@ testBrowser = "firefox"
fclose($tempFile);
}
- /*
+ /**
* Returns an array containing:
* The contents of the selenium cingiguration ini file
* The expected selenium configuration array that getSeleniumSettings should return
diff --git a/tests/phpunit/includes/TemplateCategoriesTest.php b/tests/phpunit/includes/TemplateCategoriesTest.php
new file mode 100644
index 00000000..de9d6dc6
--- /dev/null
+++ b/tests/phpunit/includes/TemplateCategoriesTest.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @group Database
+ */
+require dirname( __FILE__ ) . "/../../../maintenance/runJobs.php";
+
+class TemplateCategoriesTest extends MediaWikiLangTestCase {
+
+ function testTemplateCategories() {
+ global $wgUser;
+
+ $title = Title::newFromText( "Categorized from template" );
+ $article = new Article( $title );
+ $wgUser = new User();
+ $wgUser->mRights['*'] = array( 'createpage', 'edit', 'purge' );
+
+ $status = $article->doEdit( '{{Categorising template}}', 'Create a page with a template', 0 );
+ $this->assertEquals(
+ array()
+ , $title->getParentCategories()
+ );
+
+ $template = new Article( Title::newFromText( 'Template:Categorising template' ) );
+ $status = $template->doEdit( '[[Category:Solved bugs]]', 'Add a category through a template', 0 );
+
+ // Run the job queue
+ $jobs = new RunJobs;
+ $jobs->loadParamsAndArgs( null, array( 'quiet' => true ), null );
+ $jobs->execute();
+
+ $this->assertEquals(
+ array( 'Category:Solved_bugs' => $title->getPrefixedText() )
+ , $title->getParentCategories()
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/TitleMethodsTest.php b/tests/phpunit/includes/TitleMethodsTest.php
new file mode 100644
index 00000000..2f1103e8
--- /dev/null
+++ b/tests/phpunit/includes/TitleMethodsTest.php
@@ -0,0 +1,78 @@
+<?php
+
+class TitleMethodsTest extends MediaWikiTestCase {
+
+ public function dataEquals() {
+ return array(
+ array( 'Main Page', 'Main Page', true ),
+ array( 'Main Page', 'Not The Main Page', false ),
+ array( 'Main Page', 'Project:Main Page', false ),
+ array( 'File:Example.png', 'Image:Example.png', true ),
+ array( 'Special:Version', 'Special:Version', true ),
+ array( 'Special:Version', 'Special:Recentchanges', false ),
+ array( 'Special:Version', 'Main Page', false ),
+ );
+ }
+
+ /**
+ * @dataProvider dataEquals
+ */
+ public function testEquals( $titleA, $titleB, $expectedBool ) {
+ $titleA = Title::newFromText( $titleA );
+ $titleB = Title::newFromText( $titleB );
+
+ $this->assertEquals( $titleA->equals( $titleB ), $expectedBool );
+ $this->assertEquals( $titleB->equals( $titleA ), $expectedBool );
+ }
+
+ public function dataInNamespace() {
+ return array(
+ array( 'Main Page', NS_MAIN, true ),
+ array( 'Main Page', NS_TALK, false ),
+ array( 'Main Page', NS_USER, false ),
+ array( 'User:Foo', NS_USER, true ),
+ array( 'User:Foo', NS_USER_TALK, false ),
+ array( 'User:Foo', NS_TEMPLATE, false ),
+ array( 'User_talk:Foo', NS_USER_TALK, true ),
+ array( 'User_talk:Foo', NS_USER, false ),
+ );
+ }
+
+ /**
+ * @dataProvider dataInNamespace
+ */
+ public function testInNamespace( $title, $ns, $expectedBool ) {
+ $title = Title::newFromText( $title );
+ $this->assertEquals( $title->inNamespace( $ns ), $expectedBool );
+ }
+
+ public function testInNamespaces() {
+ $mainpage = Title::newFromText( 'Main Page' );
+ $this->assertTrue( $mainpage->inNamespaces( NS_MAIN, NS_USER ) );
+ $this->assertTrue( $mainpage->inNamespaces( array( NS_MAIN, NS_USER ) ) );
+ $this->assertTrue( $mainpage->inNamespaces( array( NS_USER, NS_MAIN ) ) );
+ $this->assertFalse( $mainpage->inNamespaces( array( NS_PROJECT, NS_TEMPLATE ) ) );
+ }
+
+ public function dataHasSubjectNamespace() {
+ return array(
+ array( 'Main Page', NS_MAIN, true ),
+ array( 'Main Page', NS_TALK, true ),
+ array( 'Main Page', NS_USER, false ),
+ array( 'User:Foo', NS_USER, true ),
+ array( 'User:Foo', NS_USER_TALK, true ),
+ array( 'User:Foo', NS_TEMPLATE, false ),
+ array( 'User_talk:Foo', NS_USER_TALK, true ),
+ array( 'User_talk:Foo', NS_USER, true ),
+ );
+ }
+
+ /**
+ * @dataProvider dataHasSubjectNamespace
+ */
+ public function testHasSubjectNamespace( $title, $ns, $expectedBool ) {
+ $title = Title::newFromText( $title );
+ $this->assertEquals( $title->hasSubjectNamespace( $ns ), $expectedBool );
+ }
+
+}
diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php
index 1b179686..f62ac5dd 100644
--- a/tests/phpunit/includes/TitlePermissionTest.php
+++ b/tests/phpunit/includes/TitlePermissionTest.php
@@ -5,12 +5,16 @@
*/
class TitlePermissionTest extends MediaWikiLangTestCase {
protected $title;
- protected $user;
- protected $anonUser;
- protected $userUser;
- protected $altUser;
- protected $userName;
- protected $altUserName;
+
+ /**
+ * @var User
+ */
+ protected $user, $anonUser, $userUser, $altUser;
+
+ /**
+ * @var string
+ */
+ protected $userName, $altUserName;
function setUp() {
global $wgLocaltimezone, $wgLocalTZoffset, $wgMemc, $wgContLang, $wgLang;
@@ -56,6 +60,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
}
function setUserPerm( $perm ) {
+ // Setting member variables is evil!!!
+
if ( is_array( $perm ) ) {
$this->user->mRights = $perm;
} else {
@@ -299,7 +305,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->assertEquals( $check[$action][3],
$this->title->userCan( $action, true ) );
$this->assertEquals( $check[$action][3],
- $this->title->quickUserCan( $action, false ) );
+ $this->title->quickUserCan( $action ) );
# count( User::getGroupsWithPermissions( $action ) ) < 1
}
@@ -451,7 +457,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->user ) );
$this->assertEquals( true,
- $this->title->quickUserCan( 'edit', false ) );
+ $this->title->quickUserCan( 'edit' ) );
$this->title->mRestrictions = array( "edit" => array( 'bogus', "sysop", "protect", "" ),
"bogus" => array( 'bogus', "sysop", "protect", "" ) );
@@ -491,9 +497,9 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->user ) );
$this->title->mCascadeRestriction = true;
$this->assertEquals( false,
- $this->title->quickUserCan( 'bogus', false ) );
+ $this->title->quickUserCan( 'bogus' ) );
$this->assertEquals( false,
- $this->title->quickUserCan( 'edit', false ) );
+ $this->title->quickUserCan( 'edit' ) );
$this->assertEquals( array( array( 'badaccess-group0' ),
array( 'protectedpagetext', 'bogus' ),
array( 'protectedpagetext', 'protect' ),
@@ -537,7 +543,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->setTitle( NS_MAIN, "test page" );
$this->title->mTitleProtection['pt_create_perm'] = '';
$this->title->mTitleProtection['pt_user'] = $this->user->getID();
- $this->title->mTitleProtection['pt_expiry'] = Block::infinity();
+ $this->title->mTitleProtection['pt_expiry'] = wfGetDB( DB_SLAVE )->getInfinity();
$this->title->mTitleProtection['pt_reason'] = 'test';
$this->title->mCascadeRestriction = false;
@@ -574,7 +580,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->title->userCan( 'move' ) );
$this->title->mInterwiki = "no";
- $this->assertEquals( array( array( 'immobile-page' ) ),
+ $this->assertEquals( array( array( 'immobile-source-page' ) ),
$this->title->getUserPermissionsErrors( 'move', $this->user ) );
$this->assertEquals( false,
$this->title->userCan( 'move' ) );
@@ -623,7 +629,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$prev = time();
$now = time() + 120;
$this->user->mBlockedby = $this->user->getId();
- $this->user->mBlock = new Block( '127.0.8.1', $this->user->getId(), $this->user->getId(),
+ $this->user->mBlock = new Block( '127.0.8.1', 0, $this->user->getId(),
'no reason given', $prev + 3600, 1, 0 );
$this->user->mBlock->mTimestamp = 0;
$this->assertEquals( array( array( 'autoblockedtext',
@@ -640,7 +646,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
global $wgLocalTZoffset;
$wgLocalTZoffset = -60;
$this->user->mBlockedby = $this->user->getName();
- $this->user->mBlock = new Block( '127.0.8.1', 2, 1, 'no reason given', $now, 0, 10 );
+ $this->user->mBlock = new Block( '127.0.8.1', 0, 1, 'no reason given', $now, 0, 10 );
$this->assertEquals( array( array( 'blockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
diff --git a/tests/phpunit/includes/TitleTest.php b/tests/phpunit/includes/TitleTest.php
index e7bb98ac..1c8be5f9 100644
--- a/tests/phpunit/includes/TitleTest.php
+++ b/tests/phpunit/includes/TitleTest.php
@@ -41,10 +41,10 @@ class TitleTest extends MediaWikiTestCase {
/**
* Auth-less test of Title::isValidMoveOperation
*
+ * @group Database
* @param string $source
* @param string $target
- * @param array|string|true $requiredErrors
- * @group Database
+ * @param array|string|true $expected Required error
* @dataProvider dataTestIsValidMoveOperation
*/
function testIsValidMoveOperation( $source, $target, $expected ) {
diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php
index df91aca8..ef03e835 100644
--- a/tests/phpunit/includes/UserTest.php
+++ b/tests/phpunit/includes/UserTest.php
@@ -1,47 +1,67 @@
<?php
+define( 'NS_UNITTEST', 5600 );
+define( 'NS_UNITTEST_TALK', 5601 );
+
+/**
+ * @group Database
+ */
class UserTest extends MediaWikiTestCase {
protected $savedGroupPermissions, $savedRevokedPermissions;
-
+
+ /**
+ * @var User
+ */
+ protected $user;
+
public function setUp() {
parent::setUp();
-
+
$this->savedGroupPermissions = $GLOBALS['wgGroupPermissions'];
$this->savedRevokedPermissions = $GLOBALS['wgRevokePermissions'];
-
+
$this->setUpPermissionGlobals();
+ $this->setUpUser();
}
private function setUpPermissionGlobals() {
global $wgGroupPermissions, $wgRevokePermissions;
-
+
+ # Data for regular $wgGroupPermissions test
$wgGroupPermissions['unittesters'] = array(
+ 'test' => true,
'runtest' => true,
'writetest' => false,
'nukeworld' => false,
);
$wgGroupPermissions['testwriters'] = array(
+ 'test' => true,
'writetest' => true,
'modifytest' => true,
);
-
+ # Data for regular $wgRevokePermissions test
$wgRevokePermissions['formertesters'] = array(
'runtest' => true,
);
}
+ private function setUpUser() {
+ $this->user = new User;
+ $this->user->addGroup( 'unittesters' );
+ }
+
public function tearDown() {
parent::tearDown();
-
+
$GLOBALS['wgGroupPermissions'] = $this->savedGroupPermissions;
$GLOBALS['wgRevokePermissions'] = $this->savedRevokedPermissions;
}
-
+
public function testGroupPermissions() {
$rights = User::getGroupPermissions( array( 'unittesters' ) );
$this->assertContains( 'runtest', $rights );
$this->assertNotContains( 'writetest', $rights );
$this->assertNotContains( 'modifytest', $rights );
$this->assertNotContains( 'nukeworld', $rights );
-
+
$rights = User::getGroupPermissions( array( 'unittesters', 'testwriters' ) );
$this->assertContains( 'runtest', $rights );
$this->assertContains( 'writetest', $rights );
@@ -53,6 +73,71 @@ class UserTest extends MediaWikiTestCase {
$this->assertNotContains( 'runtest', $rights );
$this->assertNotContains( 'writetest', $rights );
$this->assertNotContains( 'modifytest', $rights );
- $this->assertNotContains( 'nukeworld', $rights );
+ $this->assertNotContains( 'nukeworld', $rights );
+ }
+
+ public function testUserPermissions() {
+ $rights = $this->user->getRights();
+ $this->assertContains( 'runtest', $rights );
+ $this->assertNotContains( 'writetest', $rights );
+ $this->assertNotContains( 'modifytest', $rights );
+ $this->assertNotContains( 'nukeworld', $rights );
+ }
+
+ /**
+ * @dataProvider provideGetGroupsWithPermission
+ */
+ public function testGetGroupsWithPermission( $expected, $right ) {
+ $result = User::getGroupsWithPermission( $right );
+ sort( $result );
+ sort( $expected );
+
+ $this->assertEquals( $expected, $result, "Groups with permission $right" );
+ }
+
+ public function provideGetGroupsWithPermission() {
+ return array(
+ array(
+ array( 'unittesters', 'testwriters' ),
+ 'test'
+ ),
+ array(
+ array( 'unittesters' ),
+ 'runtest'
+ ),
+ array(
+ array( 'testwriters' ),
+ 'writetest'
+ ),
+ array(
+ array( 'testwriters' ),
+ 'modifytest'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideUserNames
+ */
+ public function testIsValidUserName( $username, $result, $message ) {
+ $this->assertEquals( $this->user->isValidUserName( $username ), $result, $message );
+ }
+
+ public function provideUserNames() {
+ return array(
+ array( '', false, 'Empty string' ),
+ array( ' ', false, 'Blank space' ),
+ array( 'abcd', false, 'Starts with small letter' ),
+ array( 'Ab/cd', false, 'Contains slash' ),
+ array( 'Ab cd' , true, 'Whitespace' ),
+ array( '192.168.1.1', false, 'IP' ),
+ array( 'User:Abcd', false, 'Reserved Namespace' ),
+ array( '12abcd232' , true , 'Starts with Numbers' ),
+ array( '?abcd' , true, 'Start with ? mark' ),
+ array( '#abcd', false, 'Start with #' ),
+ array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ),
+ array( 'ജോസ്‌തോമസ്', false, 'ZWNJ- Format control character' ),
+ array( 'Ab cd', false, ' Ideographic space' ),
+ );
}
-} \ No newline at end of file
+}
diff --git a/tests/phpunit/includes/WebRequestTest.php b/tests/phpunit/includes/WebRequestTest.php
index 1cfbd3fc..e72408f6 100644
--- a/tests/phpunit/includes/WebRequestTest.php
+++ b/tests/phpunit/includes/WebRequestTest.php
@@ -85,4 +85,101 @@ class WebRequestTest extends MediaWikiTestCase {
),
);
}
+
+ /**
+ * @dataProvider provideGetIP
+ */
+ function testGetIP( $expected, $input, $squid, $private, $description ) {
+ global $wgSquidServersNoPurge, $wgUsePrivateIPs;
+ $oldServer = $_SERVER;
+ $_SERVER = $input;
+ $wgSquidServersNoPurge = $squid;
+ $wgUsePrivateIPs = $private;
+ $request = new WebRequest();
+ $result = $request->getIP();
+ $_SERVER = $oldServer;
+ $this->assertEquals( $expected, $result, $description );
+ }
+
+ function provideGetIP() {
+ return array(
+ array(
+ '127.0.0.1',
+ array(
+ 'REMOTE_ADDR' => '127.0.0.1'
+ ),
+ array(),
+ false,
+ 'Simple IPv4'
+ ),
+ array(
+ '::1',
+ array(
+ 'REMOTE_ADDR' => '::1'
+ ),
+ array(),
+ false,
+ 'Simple IPv6'
+ ),
+ array(
+ '12.0.0.3',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.1',
+ 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
+ ),
+ array( '12.0.0.1', '12.0.0.2' ),
+ false,
+ 'With X-Forwaded-For'
+ ),
+ array(
+ '12.0.0.1',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.1',
+ 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
+ ),
+ array(),
+ false,
+ 'With X-Forwaded-For and disallowed server'
+ ),
+ array(
+ '12.0.0.2',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.1',
+ 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
+ ),
+ array( '12.0.0.1' ),
+ false,
+ 'With multiple X-Forwaded-For and only one allowed server'
+ ),
+ array(
+ '12.0.0.2',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.2',
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2'
+ ),
+ array( '12.0.0.1', '12.0.0.2' ),
+ false,
+ 'With X-Forwaded-For and private IP'
+ ),
+ array(
+ '10.0.0.3',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.2',
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2'
+ ),
+ array( '12.0.0.1', '12.0.0.2' ),
+ true,
+ 'With X-Forwaded-For and private IP (allowed)'
+ ),
+ );
+ }
+
+ /**
+ * @expectedException MWException
+ */
+ function testGetIpLackOfRemoteAddrThrowAnException() {
+ $request = new WebRequest();
+ # Next call throw an exception about lacking an IP
+ $request->getIP();
+ }
}
diff --git a/tests/phpunit/includes/XmlSelectTest.php b/tests/phpunit/includes/XmlSelectTest.php
index bf761e3d..2407c151 100644
--- a/tests/phpunit/includes/XmlSelectTest.php
+++ b/tests/phpunit/includes/XmlSelectTest.php
@@ -80,7 +80,7 @@ class XmlSelectTest extends MediaWikiTestCase {
$this->select->addOption( 'foo2' );
$this->assertEquals(
'<select><option value="foo1">foo1</option>' . "\n" .
-'<option value="bar1" selected="selected">bar1</option>' . "\n" .
+'<option value="bar1" selected="">bar1</option>' . "\n" .
'<option value="foo2">foo2</option></select>', $this->select->getHTML() );
}
@@ -96,7 +96,7 @@ class XmlSelectTest extends MediaWikiTestCase {
$this->select->setDefault( 'bar1' ); # setting default after adding options
$this->assertEquals(
'<select><option value="foo1">foo1</option>' . "\n" .
-'<option value="bar1" selected="selected">bar1</option>' . "\n" .
+'<option value="bar1" selected="">bar1</option>' . "\n" .
'<option value="foo2">foo2</option></select>', $this->select->getHTML() );
}
diff --git a/tests/phpunit/includes/XmlTest.php b/tests/phpunit/includes/XmlTest.php
index a6058ef6..1d9361f2 100644
--- a/tests/phpunit/includes/XmlTest.php
+++ b/tests/phpunit/includes/XmlTest.php
@@ -2,19 +2,43 @@
class XmlTest extends MediaWikiTestCase {
private static $oldLang;
+ private static $oldNamespaces;
public function setUp() {
- global $wgLang, $wgLanguageCode;
-
+ global $wgLang, $wgContLang;
+
self::$oldLang = $wgLang;
- $wgLanguageCode = 'en';
- $wgLang = Language::factory( $wgLanguageCode );
+ $wgLang = Language::factory( 'en' );
+
+ // Hardcode namespaces during test runs,
+ // so that html output based on existing namespaces
+ // can be properly evaluated.
+ self::$oldNamespaces = $wgContLang->getNamespaces();
+ $wgContLang->setNamespaces( array(
+ -2 => 'Media',
+ -1 => 'Special',
+ 0 => '',
+ 1 => 'Talk',
+ 2 => 'User',
+ 3 => 'User_talk',
+ 4 => 'MyWiki',
+ 5 => 'MyWiki_Talk',
+ 6 => 'File',
+ 7 => 'File_talk',
+ 8 => 'MediaWiki',
+ 9 => 'MediaWiki_talk',
+ 10 => 'Template',
+ 11 => 'Template_talk',
+ 100 => 'Custom',
+ 101 => 'Custom_talk',
+ ) );
}
-
+
public function tearDown() {
- global $wgLang, $wgLanguageCode;
+ global $wgLang, $wgContLang;
$wgLang = self::$oldLang;
- $wgLanguageCode = $wgLang->getCode();
+
+ $wgContLang->setNamespaces( self::$oldNamespaces );
}
public function testExpandAttributes() {
@@ -88,6 +112,9 @@ class XmlTest extends MediaWikiTestCase {
$this->assertEquals( '</element>', Xml::closeElement( 'element' ), 'closeElement() shortcut' );
}
+ /**
+ * @group Broken
+ */
public function testDateMenu( ) {
$curYear = intval(gmdate('Y'));
$prevYear = $curYear - 1;
@@ -98,11 +125,10 @@ class XmlTest extends MediaWikiTestCase {
$nextMonth = $curMonth + 1;
if( $nextMonth == 13 ) { $nextMonth = 1; }
-
$this->assertEquals(
'<label for="year">From year (and earlier):</label> <input name="year" size="4" value="2011" id="year" maxlength="4" /> <label for="month">From month (and earlier):</label> <select id="month" name="month" class="mw-month-selector"><option value="-1">all</option>' . "\n" .
'<option value="1">January</option>' . "\n" .
-'<option value="2" selected="selected">February</option>' . "\n" .
+'<option value="2" selected="">February</option>' . "\n" .
'<option value="3">March</option>' . "\n" .
'<option value="4">April</option>' . "\n" .
'<option value="5">May</option>' . "\n" .
@@ -139,7 +165,6 @@ class XmlTest extends MediaWikiTestCase {
"Date menu year is the current one when not specified"
);
- $this->markTestIncomplete( "Broken" );
// @todo FIXME: next month can be in the next year
// test failing because it is now december
$this->assertEquals(
@@ -163,11 +188,57 @@ class XmlTest extends MediaWikiTestCase {
'<option value="10">October</option>' . "\n" .
'<option value="11">November</option>' . "\n" .
'<option value="12">December</option></select>',
- Xml::dateMenu( '', ''),
+ Xml::dateMenu( '', '' ),
"Date menu with neither year or month"
);
}
+ function testNamespaceSelector() {
+ $this->assertEquals(
+ '<select class="namespaceselector" id="namespace" name="namespace">' . "\n" .
+'<option value="0">(Main)</option>' . "\n" .
+'<option value="1">Talk</option>' . "\n" .
+'<option value="2">User</option>' . "\n" .
+'<option value="3">User talk</option>' . "\n" .
+'<option value="4">MyWiki</option>' . "\n" .
+'<option value="5">MyWiki Talk</option>' . "\n" .
+'<option value="6">File</option>' . "\n" .
+'<option value="7">File talk</option>' . "\n" .
+'<option value="8">MediaWiki</option>' . "\n" .
+'<option value="9">MediaWiki talk</option>' . "\n" .
+'<option value="10">Template</option>' . "\n" .
+'<option value="11">Template talk</option>' . "\n" .
+'<option value="100">Custom</option>' . "\n" .
+'<option value="101">Custom talk</option>' . "\n" .
+'</select>',
+ Xml::namespaceSelector(),
+ 'Basic namespace selector without custom options'
+ );
+ $this->assertEquals(
+ '<label for="namespace">Select a namespace:</label>' .
+'&#160;<select class="namespaceselector" id="namespace" name="myname">' . "\n" .
+'<option value="all">all</option>' . "\n" .
+'<option value="0">(Main)</option>' . "\n" .
+'<option value="1">Talk</option>' . "\n" .
+'<option value="2" selected="">User</option>' . "\n" .
+'<option value="3">User talk</option>' . "\n" .
+'<option value="4">MyWiki</option>' . "\n" .
+'<option value="5">MyWiki Talk</option>' . "\n" .
+'<option value="6">File</option>' . "\n" .
+'<option value="7">File talk</option>' . "\n" .
+'<option value="8">MediaWiki</option>' . "\n" .
+'<option value="9">MediaWiki talk</option>' . "\n" .
+'<option value="10">Template</option>' . "\n" .
+'<option value="11">Template talk</option>' . "\n" .
+'<option value="100">Custom</option>' . "\n" .
+'<option value="101">Custom talk</option>' . "\n" .
+'</select>',
+ Xml::namespaceSelector( $selected = '2', $all = 'all', $element_name = 'myname', $label = 'Select a namespace:' ),
+ 'Basic namespace selector with custom values'
+ );
+ }
+
+
#
# textarea
#
@@ -255,12 +326,12 @@ class XmlTest extends MediaWikiTestCase {
function testEncodeJsVarArray() {
$this->assertEquals(
- '["a", 1]',
+ '["a",1]',
Xml::encodeJsVar( array( 'a', 1 ) ),
'encodeJsVar() with array'
);
$this->assertEquals(
- '{"a": "a", "b": 1}',
+ '{"a":"a","b":1}',
Xml::encodeJsVar( array( 'a' => 'a', 'b' => 1 ) ),
'encodeJsVar() with associative array'
);
@@ -268,7 +339,7 @@ class XmlTest extends MediaWikiTestCase {
function testEncodeJsVarObject() {
$this->assertEquals(
- '{"a": "a", "b": 1}',
+ '{"a":"a","b":1}',
Xml::encodeJsVar( (object)array( 'a' => 'a', 'b' => 1 ) ),
'encodeJsVar() with object'
);
diff --git a/tests/phpunit/includes/api/ApiBlockTest.php b/tests/phpunit/includes/api/ApiBlockTest.php
index 227555eb..b95d8214 100644
--- a/tests/phpunit/includes/api/ApiBlockTest.php
+++ b/tests/phpunit/includes/api/ApiBlockTest.php
@@ -15,24 +15,34 @@ class ApiBlockTest extends ApiTestCase {
}
function addDBData() {
- $user = User::newFromName( 'UTBlockee' );
+ $user = User::newFromName( 'UTApiBlockee' );
if ( $user->getId() == 0 ) {
$user->addToDatabase();
- $user->setPassword( 'UTBlockeePassword' );
+ $user->setPassword( 'UTApiBlockeePassword' );
$user->saveSettings();
}
}
+ /**
+ * This test has probably always been broken and use an invalid token
+ * Bug tracking brokenness is https://bugzilla.wikimedia.org/35646
+ *
+ * Root cause is https://gerrit.wikimedia.org/r/3434
+ * Which made the Block/Unblock API to actually verify the token
+ * previously always considered valid (bug 34212).
+ *
+ * @group Broken
+ */
function testMakeNormalBlock() {
$data = $this->getTokens();
- $user = User::newFromName( 'UTBlockee' );
+ $user = User::newFromName( 'UTApiBlockee' );
if ( !$user->getId() ) {
- $this->markTestIncomplete( "The user UTBlockee does not exist" );
+ $this->markTestIncomplete( "The user UTApiBlockee does not exist" );
}
if( !isset( $data[0]['query']['pages'] ) ) {
@@ -45,15 +55,15 @@ class ApiBlockTest extends ApiTestCase {
$data = $this->doApiRequest( array(
'action' => 'block',
- 'user' => 'UTBlockee',
- 'reason' => BlockTest::REASON,
- 'token' => $pageinfo['blocktoken'] ), $data );
+ 'user' => 'UTApiBlockee',
+ 'reason' => 'Some reason',
+ 'token' => $pageinfo['blocktoken'] ), $data, false, self::$users['sysop']->user );
- $block = Block::newFromTarget('UTBlockee');
+ $block = Block::newFromTarget('UTApiBlockee');
$this->assertTrue( !is_null( $block ), 'Block is valid' );
- $this->assertEquals( 'UTBlockee', (string)$block->getTarget() );
+ $this->assertEquals( 'UTApiBlockee', (string)$block->getTarget() );
$this->assertEquals( 'Some reason', $block->mReason );
$this->assertEquals( 'infinity', $block->mExpiry );
diff --git a/tests/phpunit/includes/api/ApiPurgeTest.php b/tests/phpunit/includes/api/ApiPurgeTest.php
index db1563e9..70c20746 100644
--- a/tests/phpunit/includes/api/ApiPurgeTest.php
+++ b/tests/phpunit/includes/api/ApiPurgeTest.php
@@ -9,33 +9,31 @@ class ApiPurgeTest extends ApiTestCase {
parent::setUp();
$this->doLogin();
}
-
+
+ /**
+ * @group Broken
+ */
function testPurgeMainPage() {
-
if ( !Title::newFromText( 'UTPage' )->exists() ) {
$this->markTestIncomplete( "The article [[UTPage]] does not exist" );
}
-
+
$somePage = mt_rand();
$data = $this->doApiRequest( array(
'action' => 'purge',
'titles' => 'UTPage|' . $somePage . '|%5D' ) );
-
- $this->assertArrayHasKey( 'purge', $data[0] );
-
- $this->assertArrayHasKey( 0, $data[0]['purge'] );
- $this->assertArrayHasKey( 'purged', $data[0]['purge'][0] );
- $this->assertEquals( 'UTPage', $data[0]['purge'][0]['title'] );
-
- $this->assertArrayHasKey( 1, $data[0]['purge'] );
- $this->assertArrayHasKey( 'missing', $data[0]['purge'][1] );
- $this->assertEquals( $somePage, $data[0]['purge'][1]['title'] );
-
- $this->assertArrayHasKey( 2, $data[0]['purge'] );
- $this->assertArrayHasKey( 'invalid', $data[0]['purge'][2] );
- $this->assertEquals( '%5D', $data[0]['purge'][2]['title'] );
-
+
+ $this->assertArrayHasKey( 'purge', $data[0],
+ "Must receive a 'purge' result from API" );
+
+ $this->assertEquals( 3, count( $data[0]['purge'] ),
+ "Purge request for three articles should give back three results received: " . var_export( $data[0]['purge'], true ) );
+
+ $pages = array( 'UTPage' => 'purged', $somePage => 'missing', '%5D' => 'invalid' );
+ foreach( $data[0]['purge'] as $v ) {
+ $this->assertArrayHasKey( $pages[$v['title']], $v );
+ }
}
}
diff --git a/tests/phpunit/includes/api/ApiQueryTest.php b/tests/phpunit/includes/api/ApiQueryTest.php
index 114eadf3..ae05a30a 100644
--- a/tests/phpunit/includes/api/ApiQueryTest.php
+++ b/tests/phpunit/includes/api/ApiQueryTest.php
@@ -22,10 +22,13 @@ class ApiQueryTest extends ApiTestCase {
$this->assertArrayHasKey( 'query', $data[0] );
$this->assertArrayHasKey( 'normalized', $data[0]['query'] );
+ // Forge a normalized title
+ $to = Title::newFromText( $wgMetaNamespace.':ArticleA' );
+
$this->assertEquals(
array(
'from' => 'Project:articleA',
- 'to' => $wgMetaNamespace . ':ArticleA'
+ 'to' => $to->getPrefixedText(),
),
$data[0]['query']['normalized'][0]
);
@@ -50,7 +53,6 @@ class ApiQueryTest extends ApiTestCase {
'action' => 'query',
'titles' => $title . '|Talk:' ) );
-
$this->assertArrayHasKey( 'query', $data[0] );
$this->assertArrayHasKey( 'pages', $data[0]['query'] );
$this->assertEquals( 2, count( $data[0]['query']['pages'] ) );
@@ -60,8 +62,6 @@ class ApiQueryTest extends ApiTestCase {
$this->assertArrayHasKey( 'missing', $data[0]['query']['pages'][-2] );
$this->assertArrayHasKey( 'invalid', $data[0]['query']['pages'][-1] );
-
-
}
}
diff --git a/tests/phpunit/includes/api/ApiTest.php b/tests/phpunit/includes/api/ApiTest.php
index a587e6b1..1d9c3238 100644
--- a/tests/phpunit/includes/api/ApiTest.php
+++ b/tests/phpunit/includes/api/ApiTest.php
@@ -96,7 +96,7 @@ class ApiTest extends ApiTestCase {
"lgtoken" => $token,
"lgname" => $user->username,
"lgpassword" => "badnowayinhell",
- )
+ ), $ret[2]
);
$result = $ret[0];
@@ -137,7 +137,7 @@ class ApiTest extends ApiTestCase {
"lgtoken" => $token,
"lgname" => $user->username,
"lgpassword" => $user->password,
- )
+ ), $ret[2]
);
$result = $ret[0];
@@ -148,6 +148,9 @@ class ApiTest extends ApiTestCase {
$this->assertEquals( "Success", $a );
}
+ /**
+ * @group Broken
+ */
function testApiGotCookie() {
$this->markTestIncomplete( "The server can't do external HTTP requests, and the internal one won't give cookies" );
@@ -192,24 +195,23 @@ class ApiTest extends ApiTestCase {
}
/**
- * @depends testApiGotCookie
+ * @todo Finish filling me out...what are we trying to test here?
*/
- function testApiListPages( CookieJar $cj ) {
- $this->markTestIncomplete( "Not done with this yet" );
+ function testApiListPages() {
global $wgServer;
-
- if ( $wgServer == "http://localhost" ) {
+ if ( !isset( $wgServer ) ) {
$this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
}
- $req = MWHttpRequest::factory( self::$apiUrl . "?action=query&format=xml&prop=revisions&" .
- "titles=Main%20Page&rvprop=timestamp|user|comment|content" );
- $req->setCookieJar( $cj );
- $req->execute();
- libxml_use_internal_errors( true );
- $sxe = simplexml_load_string( $req->getContent() );
- $this->assertNotInternalType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
- $a = $sxe->query[0]->pages[0]->page[0]->attributes();
+
+ $ret = $this->doApiRequest( array(
+ 'action' => 'query',
+ 'prop' => 'revisions',
+ 'titles' => 'Main Page',
+ 'rvprop' => 'timestamp|user|comment|content',
+ ) );
+
+ $result = $ret[0]['query']['pages'];
+ $this->markTestIncomplete( "Somebody needs to finish loving me" );
}
function testRunLogin() {
@@ -228,7 +230,7 @@ class ApiTest extends ApiTestCase {
'action' => 'login',
"lgtoken" => $token,
"lgname" => $sysopUser->username,
- "lgpassword" => $sysopUser->password ), $data );
+ "lgpassword" => $sysopUser->password ), $data[2] );
$this->assertArrayHasKey( "login", $data[0] );
$this->assertArrayHasKey( "result", $data[0]['login'] );
diff --git a/tests/phpunit/includes/api/ApiTestCase.php b/tests/phpunit/includes/api/ApiTestCase.php
index 2917c880..8801391f 100644
--- a/tests/phpunit/includes/api/ApiTestCase.php
+++ b/tests/phpunit/includes/api/ApiTestCase.php
@@ -7,6 +7,11 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
public static $users;
protected static $apiUrl;
+ /**
+ * @var ApiTestContext
+ */
+ protected $apiContext;
+
function setUp() {
global $wgContLang, $wgAuth, $wgMemc, $wgRequest, $wgUser, $wgServer;
@@ -21,31 +26,37 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
'sysop' => new ApiTestUser(
'Apitestsysop',
'Api Test Sysop',
- 'api_test_sysop@sample.com',
+ 'api_test_sysop@example.com',
array( 'sysop' )
),
'uploader' => new ApiTestUser(
'Apitestuser',
'Api Test User',
- 'api_test_user@sample.com',
+ 'api_test_user@example.com',
array()
)
);
$wgUser = self::$users['sysop']->user;
+ $this->apiContext = new ApiTestContext();
+
}
- protected function doApiRequest( $params, $session = null, $appendModule = false ) {
+ protected function doApiRequest( $params, $session = null, $appendModule = false, $user = null ) {
if ( is_null( $session ) ) {
$session = array();
}
- $request = new FauxRequest( $params, true, $session );
- $module = new ApiMain( $request, true );
+ $context = $this->apiContext->newTestContext( $params, $session, $user );
+ $module = new ApiMain( $context, true );
$module->execute();
- $results = array( $module->getResultData(), $request, $request->getSessionArray() );
+ $results = array(
+ $module->getResultData(),
+ $context->getRequest(),
+ $context->getRequest()->getSessionArray()
+ );
if( $appendModule ) {
$results[] = $module;
}
@@ -59,14 +70,15 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
* request, without actually requesting a "real" edit token
* @param $params: key-value API params
* @param $session: session array
+ * @param $user String|null A User object for the context
*/
- protected function doApiRequestWithToken( $params, $session ) {
+ protected function doApiRequestWithToken( $params, $session, $user = null ) {
if ( $session['wsToken'] ) {
// add edit token to fake session
$session['wsEditToken'] = $session['wsToken'];
// add token to request parameters
$params['token'] = md5( $session['wsToken'] ) . User::EDIT_TOKEN_SUFFIX;
- return $this->doApiRequest( $params, $session );
+ return $this->doApiRequest( $params, $session, false, $user );
} else {
throw new Exception( "request data not in right format" );
}
@@ -91,12 +103,11 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
}
protected function getTokenList( $user ) {
- $GLOBALS['wgUser'] = $user->user;
$data = $this->doApiRequest( array(
'action' => 'query',
'titles' => 'Main Page',
'intoken' => 'edit|delete|protect|move|block|unblock',
- 'prop' => 'info' ) );
+ 'prop' => 'info' ), false, $user->user );
return $data;
}
}
@@ -137,3 +148,23 @@ class MockApi extends ApiBase {
);
}
}
+
+class ApiTestContext extends RequestContext {
+
+ /**
+ * Returns a DerivativeContext with the request variables in place
+ *
+ * @param $params Array key-value API params
+ * @param $session Array session data
+ * @param $user User or null
+ * @return DerivativeContext
+ */
+ public function newTestContext( $params, $session, $user = null ) {
+ $context = new DerivativeContext( $this );
+ $context->setRequest( new FauxRequest( $params, true, $session ) );
+ if ( $user !== null ) {
+ $context->setUser( $user );
+ }
+ return $context;
+ }
+}
diff --git a/tests/phpunit/includes/api/ApiTestCaseUpload.php b/tests/phpunit/includes/api/ApiTestCaseUpload.php
index e51e7214..39c79547 100644
--- a/tests/phpunit/includes/api/ApiTestCaseUpload.php
+++ b/tests/phpunit/includes/api/ApiTestCaseUpload.php
@@ -19,6 +19,10 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
$this->clearFakeUploads();
}
+ public function tearDown() {
+ $this->clearTempUpload();
+ }
+
/**
* Helper function -- remove files and associated articles by Title
* @param $title Title: title to be removed
@@ -33,8 +37,8 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
if ( !$status->isGood() ) {
return false;
}
- $article = new Article( $title );
- $article->doDeleteArticle( "removing for test" );
+ $page = WikiPage::factory( $title );
+ $page->doDeleteArticle( "removing for test" );
// see if it now doesn't exist; reload
$title = Title::newFromText( $title->getText(), NS_FILE );
@@ -56,7 +60,7 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
* @param $filePath String: path to file on the filesystem
*/
public function deleteFileByContent( $filePath ) {
- $hash = File::sha1Base36( $filePath );
+ $hash = FSFile::getSha1Base36FromPath( $filePath );
$dupes = RepoGroup::singleton()->findBySha1( $hash );
$success = true;
foreach ( $dupes as $dupe ) {
@@ -100,6 +104,36 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
return true;
}
+ function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ){
+ $tmpName = tempnam( wfTempDir(), "" );
+ // copy the chunk data to temp location:
+ if ( !file_put_contents( $tmpName, $chunkData ) ) {
+ throw new Exception( "couldn't copy chunk data to $tmpName" );
+ }
+
+ clearstatcache();
+ $size = filesize( $tmpName );
+ if ( $size === false ) {
+ throw new Exception( "couldn't stat $tmpName" );
+ }
+
+ $_FILES[ $fieldName ] = array(
+ 'name' => $fileName,
+ 'type' => $type,
+ 'tmp_name' => $tmpName,
+ 'size' => $size,
+ 'error' => null
+ );
+ }
+
+ function clearTempUpload() {
+ if( isset( $_FILES['file']['tmp_name'] ) ) {
+ $tmp = $_FILES['file']['tmp_name'];
+ if( file_exists( $tmp ) ) {
+ unlink( $tmp );
+ }
+ }
+ }
/**
* Remove traces of previous fake uploads
diff --git a/tests/phpunit/includes/api/ApiTestUser.php b/tests/phpunit/includes/api/ApiTestUser.php
index df60682f..8d5f61a7 100644
--- a/tests/phpunit/includes/api/ApiTestUser.php
+++ b/tests/phpunit/includes/api/ApiTestUser.php
@@ -8,7 +8,7 @@ class ApiTestUser {
public $groups;
public $user;
- function __construct( $username, $realname = 'Real Name', $email = 'sample@sample.com', $groups = array() ) {
+ function __construct( $username, $realname = 'Real Name', $email = 'sample@example.com', $groups = array() ) {
$this->username = $username;
$this->realname = $realname;
$this->email = $email;
diff --git a/tests/phpunit/includes/api/ApiUploadTest.php b/tests/phpunit/includes/api/ApiUploadTest.php
index 5c929784..7a700326 100644
--- a/tests/phpunit/includes/api/ApiUploadTest.php
+++ b/tests/phpunit/includes/api/ApiUploadTest.php
@@ -19,6 +19,9 @@ require_once( 'ApiTestCaseUpload.php' );
/**
* @group Database
+ * @group Broken
+ * Broken test, reports false errors from time to time.
+ * See https://bugzilla.wikimedia.org/26169
*
* This is pretty sucky... needs to be prettified.
*/
@@ -54,6 +57,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$this->assertEquals( "Success", $result['login']['result'] );
$this->assertArrayHasKey( 'lgtoken', $result['login'] );
+ $this->assertNotEmpty( $session, 'API Login must return a session' );
return $session;
}
@@ -78,14 +82,11 @@ class ApiUploadTest extends ApiTestCaseUpload {
* @depends testLogin
*/
public function testUploadMissingParams( $session ) {
- global $wgUser;
- $wgUser = self::$users['uploader']->user;
-
$exception = false;
try {
$this->doApiRequestWithToken( array(
'action' => 'upload',
- ), $session );
+ ), $session, self::$users['uploader']->user );
} catch ( UsageException $e ) {
$exception = true;
$this->assertEquals( "One of the parameters filekey, file, url, statuskey is required",
@@ -99,20 +100,17 @@ class ApiUploadTest extends ApiTestCaseUpload {
* @depends testLogin
*/
public function testUpload( $session ) {
- global $wgUser;
- $wgUser = self::$users['uploader']->user;
-
$extension = 'png';
$mimeType = 'image/png';
try {
$randomImageGenerator = new RandomImageGenerator();
+ $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
}
catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
$filePath = $filePaths[0];
$fileSize = filesize( $filePath );
$fileName = basename( $filePath );
@@ -135,7 +133,8 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- list( $result, , ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -155,9 +154,6 @@ class ApiUploadTest extends ApiTestCaseUpload {
* @depends testLogin
*/
public function testUploadZeroLength( $session ) {
- global $wgUser;
- $wgUser = self::$users['uploader']->user;
-
$mimeType = 'image/png';
$filePath = tempnam( wfTempDir(), "" );
@@ -179,7 +175,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- $this->doApiRequestWithToken( $params, $session );
+ $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user );
} catch ( UsageException $e ) {
$this->assertContains( 'The file you submitted was empty', $e->getMessage() );
$exception = true;
@@ -196,20 +192,17 @@ class ApiUploadTest extends ApiTestCaseUpload {
* @depends testLogin
*/
public function testUploadSameFileName( $session ) {
- global $wgUser;
- $wgUser = self::$users['uploader']->user;
-
$extension = 'png';
$mimeType = 'image/png';
try {
$randomImageGenerator = new RandomImageGenerator();
+ $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() );
}
catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
- $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() );
// we'll reuse this filename
$fileName = basename( $filePaths[0] );
@@ -233,7 +226,8 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -249,7 +243,8 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- list( $result, , ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -270,19 +265,17 @@ class ApiUploadTest extends ApiTestCaseUpload {
* @depends testLogin
*/
public function testUploadSameContent( $session ) {
- global $wgUser;
- $wgUser = self::$users['uploader']->user;
-
$extension = 'png';
$mimeType = 'image/png';
try {
$randomImageGenerator = new RandomImageGenerator();
+ $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
}
catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
+
$fileNames[0] = basename( $filePaths[0] );
$fileNames[1] = "SameContentAs" . $fileNames[0];
@@ -307,7 +300,8 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -332,7 +326,8 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -354,19 +349,19 @@ class ApiUploadTest extends ApiTestCaseUpload {
*/
public function testUploadStash( $session ) {
global $wgUser;
- $wgUser = self::$users['uploader']->user;
+ $wgUser = self::$users['uploader']->user; // @todo FIXME: still used somewhere
$extension = 'png';
$mimeType = 'image/png';
try {
$randomImageGenerator = new RandomImageGenerator();
+ $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
}
catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
$filePath = $filePaths[0];
$fileSize = filesize( $filePath );
$fileName = basename( $filePath );
@@ -389,7 +384,8 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -417,17 +413,156 @@ class ApiUploadTest extends ApiTestCaseUpload {
$this->clearFakeUploads();
$exception = false;
try {
- list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session );
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
} catch ( UsageException $e ) {
$exception = true;
}
$this->assertTrue( isset( $result['upload'] ) );
$this->assertEquals( 'Success', $result['upload']['result'] );
- $this->assertFalse( $exception );
+ $this->assertFalse( $exception, "No UsageException exception." );
// clean up
$this->deleteFileByFilename( $fileName );
unlink( $filePath );
}
-}
+
+
+ /**
+ * @depends testLogin
+ */
+ public function testUploadChunks( $session ) {
+ global $wgUser;
+ $wgUser = self::$users['uploader']->user; // @todo FIXME: still used somewhere
+
+ $chunkSize = 1048576;
+ // Download a large image file
+ // ( using RandomImageGenerator for large files is not stable )
+ $mimeType = 'image/jpeg';
+ $url = 'http://upload.wikimedia.org/wikipedia/commons/e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
+ $filePath = wfTempDir() . '/Oberaargletscher_from_Oberaar.jpg';
+ try {
+ // Only download if the file is not avaliable in the temp location:
+ if( !is_file( $filePath ) ){
+ copy($url, $filePath);
+ }
+ }
+ catch ( Exception $e ) {
+ $this->markTestIncomplete( $e->getMessage() );
+ }
+ $fileSize = filesize( $filePath );
+ $fileName = basename( $filePath );
+
+ $this->deleteFileByFileName( $fileName );
+ $this->deleteFileByContent( $filePath );
+
+ // Base upload params:
+ $params = array(
+ 'action' => 'upload',
+ 'stash' => 1,
+ 'filename' => $fileName,
+ 'filesize' => $fileSize,
+ 'offset' => 0,
+ );
+
+ // Upload chunks
+ $chunkSessionKey = false;
+ $resultOffset = 0;
+ // Open the file:
+ $handle = @fopen ($filePath, "r");
+ if( $handle === false ){
+ $this->markTestIncomplete( "could not open file: $filePath" );
+ }
+ while (!feof ($handle)) {
+ // Get the current chunk
+ $chunkData = @fread( $handle, $chunkSize );
+
+ // Upload the current chunk into the $_FILE object:
+ $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
+
+ // Check for chunkSessionKey
+ if( !$chunkSessionKey ){
+ // Upload fist chunk ( and get the session key )
+ try {
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
+ } catch ( UsageException $e ) {
+ $this->markTestIncomplete( $e->getMessage() );
+ }
+ // Make sure we got a valid chunk continue:
+ $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertTrue( isset( $result['upload']['filekey'] ) );
+ // If we don't get a session key mark test incomplete.
+ if( ! isset( $result['upload']['filekey'] ) ){
+ $this->markTestIncomplete( "no filekey provided" );
+ }
+ $chunkSessionKey = $result['upload']['filekey'];
+ $this->assertEquals( 'Continue', $result['upload']['result'] );
+ // First chunk should have chunkSize == offset
+ $this->assertEquals( $chunkSize, $result['upload']['offset'] );
+ $resultOffset = $result['upload']['offset'];
+ continue;
+ }
+ // Filekey set to chunk session
+ $params['filekey'] = $chunkSessionKey;
+ // Update the offset ( always add chunkSize for subquent chunks should be in-sync with $result['upload']['offset'] )
+ $params['offset'] += $chunkSize;
+ // Make sure param offset is insync with resultOffset:
+ $this->assertEquals( $resultOffset, $params['offset'] );
+ // Upload current chunk
+ try {
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
+ } catch ( UsageException $e ) {
+ $this->markTestIncomplete( $e->getMessage() );
+ }
+ // Make sure we got a valid chunk continue:
+ $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertTrue( isset( $result['upload']['filekey'] ) );
+
+ // Check if we were on the last chunk:
+ if( $params['offset'] + $chunkSize >= $fileSize ){
+ $this->assertEquals( 'Success', $result['upload']['result'] );
+ break;
+ } else {
+ $this->assertEquals( 'Continue', $result['upload']['result'] );
+ // update $resultOffset
+ $resultOffset = $result['upload']['offset'];
+ }
+ }
+ fclose ($handle);
+
+ // Check that we got a valid file result:
+ wfDebug( __METHOD__ . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n");
+ $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
+ $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
+ $this->assertTrue( isset( $result['upload']['filekey'] ) );
+ $filekey = $result['upload']['filekey'];
+
+ // Now we should try to release the file from stash
+ $params = array(
+ 'action' => 'upload',
+ 'filekey' => $filekey,
+ 'filename' => $fileName,
+ 'comment' => 'dummy comment',
+ 'text' => "This is the page text for $fileName, altered",
+ );
+ $this->clearFakeUploads();
+ $exception = false;
+ try {
+ list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
+ self::$users['uploader']->user );
+ } catch ( UsageException $e ) {
+ $exception = true;
+ }
+ $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertEquals( 'Success', $result['upload']['result'] );
+ $this->assertFalse( $exception );
+
+ // clean up
+ $this->deleteFileByFilename( $fileName );
+ // don't remove downloaded temporary file for fast subquent tests.
+ //unlink( $filePath );
+ }
+}
diff --git a/tests/phpunit/includes/api/ApiWatchTest.php b/tests/phpunit/includes/api/ApiWatchTest.php
index 3c7ff304..b7803746 100644
--- a/tests/phpunit/includes/api/ApiWatchTest.php
+++ b/tests/phpunit/includes/api/ApiWatchTest.php
@@ -41,6 +41,7 @@ class ApiWatchTest extends ApiTestCase {
/**
* @depends testWatchEdit
+ * @group Broken
*/
function testWatchClear() {
@@ -92,7 +93,9 @@ class ApiWatchTest extends ApiTestCase {
$this->assertArrayHasKey( 'edit', $data[0]['protect']['protections'][0] );
}
-
+ /**
+ * @group Broken
+ */
function testGetRollbackToken() {
$data = $this->getTokens();
diff --git a/tests/phpunit/includes/api/RandomImageGenerator.php b/tests/phpunit/includes/api/RandomImageGenerator.php
index ae349978..86c0a828 100644
--- a/tests/phpunit/includes/api/RandomImageGenerator.php
+++ b/tests/phpunit/includes/api/RandomImageGenerator.php
@@ -1,6 +1,6 @@
<?php
-/*
+/**
* RandomImageGenerator -- does what it says on the tin.
* Requires Imagick, the ImageMagick library for PHP, or the command line equivalent (usually 'convert').
*
@@ -27,12 +27,11 @@
class RandomImageGenerator {
private $dictionaryFile;
- private $minWidth = 400;
- private $maxWidth = 800;
- private $minHeight = 400;
- private $maxHeight = 800;
- private $shapesToDraw = 5;
- private $imageWriteMethod;
+ private $minWidth = 400 ;
+ private $maxWidth = 800 ;
+ private $minHeight = 400 ;
+ private $maxHeight = 800 ;
+ private $shapesToDraw = 5 ;
/**
* Orientations: 0th row, 0th column, EXIF orientation code, rotation 2x2 matrix that is opposite of orientation
@@ -41,35 +40,35 @@ class RandomImageGenerator {
* (we also would need a non-symmetric shape for the images to test those, like a letter F)
*/
private static $orientations = array(
- array(
- '0thRow' => 'top',
- '0thCol' => 'left',
- 'exifCode' => 1,
- 'counterRotation' => array( array( 1, 0 ), array( 0, 1 ) )
+ array(
+ '0thRow' => 'top',
+ '0thCol' => 'left',
+ 'exifCode' => 1,
+ 'counterRotation' => array( array( 1, 0 ), array( 0, 1 ) )
),
- array(
+ array(
'0thRow' => 'bottom',
- '0thCol' => 'right',
- 'exifCode' => 3,
- 'counterRotation' => array( array( -1, 0 ), array( 0, -1 ) )
+ '0thCol' => 'right',
+ 'exifCode' => 3,
+ 'counterRotation' => array( array( -1, 0 ), array( 0, -1 ) )
),
- array(
- '0thRow' => 'right',
- '0thCol' => 'top',
- 'exifCode' => 6,
- 'counterRotation' => array( array( 0, 1 ), array( 1, 0 ) )
+ array(
+ '0thRow' => 'right',
+ '0thCol' => 'top',
+ 'exifCode' => 6,
+ 'counterRotation' => array( array( 0, 1 ), array( 1, 0 ) )
),
- array(
- '0thRow' => 'left',
- '0thCol' => 'bottom',
- 'exifCode' => 8,
- 'counterRotation' => array( array( 0, -1 ), array( -1, 0 ) )
+ array(
+ '0thRow' => 'left',
+ '0thCol' => 'bottom',
+ 'exifCode' => 8,
+ 'counterRotation' => array( array( 0, -1 ), array( -1, 0 ) )
)
);
public function __construct( $options = array() ) {
- foreach ( array( 'dictionaryFile', 'minWidth', 'minHeight', 'maxHeight', 'shapesToDraw' ) as $property ) {
+ foreach ( array( 'dictionaryFile', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight', 'shapesToDraw' ) as $property ) {
if ( isset( $options[$property] ) ) {
$this->$property = $options[$property];
}
@@ -77,10 +76,10 @@ class RandomImageGenerator {
// find the dictionary file, to generate random names
if ( !isset( $this->dictionaryFile ) ) {
- foreach ( array(
- '/usr/share/dict/words',
- '/usr/dict/words',
- dirname( __FILE__ ) . '/words.txt' )
+ foreach ( array(
+ '/usr/share/dict/words',
+ '/usr/dict/words',
+ dirname( __FILE__ ) . '/words.txt' )
as $dictionaryFile ) {
if ( is_file( $dictionaryFile ) and is_readable( $dictionaryFile ) ) {
$this->dictionaryFile = $dictionaryFile;
@@ -91,14 +90,6 @@ class RandomImageGenerator {
if ( !isset( $this->dictionaryFile ) ) {
throw new Exception( "RandomImageGenerator: dictionary file not found or not specified properly" );
}
-
- if ( !class_exists( 'Imagick' ) ) {
- throw new Exception( 'No Imagick extension' );
- }
- global $wgExiv2Command;
- if ( !$wgExiv2Command || !is_executable( $wgExiv2Command ) ) {
- throw new Exception( 'exiv2 not executable or $wgExiv2Command not set' );
- }
}
/**
@@ -125,15 +116,16 @@ class RandomImageGenerator {
*/
function getImageWriteMethod( $format ) {
global $wgUseImageMagick, $wgImageMagickConvertCommand;
- if ( $format === 'svg' ) {
+ if ( $format === 'svg' ) {
return 'writeSvg';
} else {
// figure out how to write images
- if ( class_exists( 'Imagick' ) ) {
+ global $wgExiv2Command;
+ if ( class_exists( 'Imagick' ) && $wgExiv2Command && is_executable( $wgExiv2Command ) ) {
return 'writeImageWithApi';
} elseif ( $wgUseImageMagick && $wgImageMagickConvertCommand && is_executable( $wgImageMagickConvertCommand ) ) {
return 'writeImageWithCommandLine';
- }
+ }
}
throw new Exception( "RandomImageGenerator: could not find a suitable method to write images in '$format' format" );
}
@@ -219,7 +211,7 @@ class RandomImageGenerator {
*/
static function shapePointsToString( $shape ) {
$points = array();
- foreach ( $shape as $point ) {
+ foreach ( $shape as $point ) {
$points[] = $point['x'] . ',' . $point['y'];
}
return join( " ", $points );
@@ -232,16 +224,16 @@ class RandomImageGenerator {
* @param $format: file format to write (which is obviously always svg here)
* @param $filename: filename to write to
*/
- public function writeSvg( $spec, $format, $filename ) {
+ public function writeSvg( $spec, $format, $filename ) {
$svg = new SimpleXmlElement( '<svg/>' );
$svg->addAttribute( 'xmlns', 'http://www.w3.org/2000/svg' );
- $svg->addAttribute( 'version', '1.1' );
- $svg->addAttribute( 'width', $spec['width'] );
- $svg->addAttribute( 'height', $spec['height'] );
+ $svg->addAttribute( 'version', '1.1' );
+ $svg->addAttribute( 'width', $spec['width'] );
+ $svg->addAttribute( 'height', $spec['height'] );
$g = $svg->addChild( 'g' );
foreach ( $spec['draws'] as $drawSpec ) {
$shape = $g->addChild( 'polygon' );
- $shape->addAttribute( 'fill', $drawSpec['fill'] );
+ $shape->addAttribute( 'fill', $drawSpec['fill'] );
$shape->addAttribute( 'points', self::shapePointsToString( $drawSpec['shape'] ) );
};
if ( ! $fh = fopen( $filename, 'w' ) ) {
@@ -260,20 +252,20 @@ class RandomImageGenerator {
* @param $filename: filename to write to
*/
public function writeImageWithApi( $spec, $format, $filename ) {
- // this is a hack because I can't get setImageOrientation() to work. See below.
+ // this is a hack because I can't get setImageOrientation() to work. See below.
global $wgExiv2Command;
$image = new Imagick();
/**
- * If the format is 'jpg', will also add a random orientation -- the image will be drawn rotated with triangle points
+ * If the format is 'jpg', will also add a random orientation -- the image will be drawn rotated with triangle points
* facing in some direction (0, 90, 180 or 270 degrees) and a countering rotation should turn the triangle points upward again
*/
$orientation = self::$orientations[0]; // default is normal orientation
if ( $format == 'jpg' ) {
$orientation = self::$orientations[ array_rand( self::$orientations ) ];
- $spec = self::rotateImageSpec( $spec, $orientation['counterRotation'] );
+ $spec = self::rotateImageSpec( $spec, $orientation['counterRotation'] );
}
-
+
$image->newImage( $spec['width'], $spec['height'], new ImagickPixel( $spec['fill'] ) );
foreach ( $spec['draws'] as $drawSpec ) {
@@ -296,7 +288,7 @@ class RandomImageGenerator {
$cmd = wfEscapeShellArg( $wgExiv2Command )
. " -M "
. wfEscapeShellArg( "set Exif.Image.Orientation " . $orientation['exifCode'] )
- . " "
+ . " "
. wfEscapeShellArg( $filename );
$retval = 0;
@@ -304,15 +296,13 @@ class RandomImageGenerator {
if ( $retval !== 0 ) {
print "Error with $cmd: $retval, $err\n";
}
- }
-
-
+ }
}
/**
* Given an image specification, produce rotated version
* This is used when simulating a rotated image capture with EXIF orientation
- * @param $spec Object returned by getImageSpec
+ * @param $spec Object returned by getImageSpec
* @param $matrix 2x2 transformation matrix
* @return transformed Spec
*/
@@ -323,8 +313,8 @@ class RandomImageGenerator {
$correctionY = 0;
if ( $dims['x'] < 0 ) {
$correctionX = abs( $dims['x'] );
- }
- if ( $dims['y'] < 0 ) {
+ }
+ if ( $dims['y'] < 0 ) {
$correctionY = abs( $dims['y'] );
}
$tSpec['width'] = abs( $dims['x'] );
@@ -332,7 +322,7 @@ class RandomImageGenerator {
$tSpec['fill'] = $spec['fill'];
$tSpec['draws'] = array();
foreach( $spec['draws'] as $draw ) {
- $tDraw = array(
+ $tDraw = array(
'fill' => $draw['fill'],
'shape' => array()
);
@@ -349,13 +339,13 @@ class RandomImageGenerator {
/**
* Given a matrix and a pair of images, return new position
- * @param $matrix: 2x2 rotation matrix
+ * @param $matrix: 2x2 rotation matrix
* @param $x: x-coordinate number
* @param $y: y-coordinate number
- * @return Array transformed with properties x, y
+ * @return Array transformed with properties x, y
*/
private static function matrixMultiply2x2( $matrix, $x, $y ) {
- return array(
+ return array(
'x' => $x * $matrix[0][0] + $y * $matrix[0][1],
'y' => $x * $matrix[1][0] + $y * $matrix[1][1]
);
@@ -366,10 +356,10 @@ class RandomImageGenerator {
* Based on an image specification, write such an image to disk, using the command line ImageMagick program ('convert').
*
* Sample command line:
- * $ convert -size 100x60 xc:rgb(90,87,45) \
- * -draw 'fill rgb(12,34,56) polygon 41,39 44,57 50,57 41,39' \
- * -draw 'fill rgb(99,123,231) circle 59,39 56,57' \
- * -draw 'fill rgb(240,12,32) circle 50,21 50,3' filename.png
+ * $ convert -size 100x60 xc:rgb(90,87,45) \
+ * -draw 'fill rgb(12,34,56) polygon 41,39 44,57 50,57 41,39' \
+ * -draw 'fill rgb(99,123,231) circle 59,39 56,57' \
+ * -draw 'fill rgb(240,12,32) circle 50,21 50,3' filename.png
*
* @param $spec: spec describing background and shapes to draw
* @param $format: file format to write (unused by this method but kept so it has the same signature as writeImageWithApi)
diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php
index 914ab27c..067c731a 100644
--- a/tests/phpunit/includes/db/DatabaseSqliteTest.php
+++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php
@@ -19,6 +19,7 @@ class MockDatabaseSqlite extends DatabaseSqliteStandalone {
/**
* @group sqlite
+ * @group Database
*/
class DatabaseSqliteTest extends MediaWikiTestCase {
var $db;
@@ -98,7 +99,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
$this->assertEquals( 'sqlite_master', $db->tableName( 'sqlite_master' ) );
$this->assertEquals( 'foobar', $db->tableName( 'bar' ) );
}
-
+
public function testDuplicateTableStructure() {
$db = new DatabaseSqliteStandalone( ':memory:' );
$db->query( 'CREATE TABLE foo(foo, barfoo)' );
@@ -119,7 +120,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
'Create a temporary duplicate only'
);
}
-
+
public function testDuplicateTableStructureVirtual() {
$db = new DatabaseSqliteStandalone( ':memory:' );
if ( $db->getFulltextSearchModule() != 'FTS3' ) {
@@ -191,13 +192,14 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
'1.15',
'1.16',
'1.17',
+ '1.18',
);
// Mismatches for these columns we can safely ignore
$ignoredColumns = array(
'user_newtalk.user_last_timestamp', // r84185
);
-
+
$currentDB = new DatabaseSqliteStandalone( ':memory:' );
$currentDB->sourceFile( "$IP/maintenance/tables.sql" );
$currentTables = $this->getTables( $currentDB );
@@ -254,9 +256,10 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
$maint = new FakeMaintenance();
$maint->loadParamsAndArgs( null, array( 'quiet' => 1 ) );
}
-
+
+ global $IP;
$db = new DatabaseSqliteStandalone( ':memory:' );
- $db->sourceFile( dirname( __FILE__ ) . "/sqlite/tables-$version.sql" );
+ $db->sourceFile( "$IP/tests/phpunit/data/db/sqlite/tables-$version.sql" );
$updater = DatabaseUpdater::newForDB( $db, false, $maint );
$updater->doUpdates( array( 'core' ) );
return $db;
@@ -266,6 +269,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
$list = array_flip( $db->listTables() );
$excluded = array(
'math', // moved out of core in 1.18
+ 'trackbacks', // removed from core in 1.19
'searchindex',
'searchindex_content',
'searchindex_segments',
diff --git a/tests/phpunit/includes/db/DatabaseTest.php b/tests/phpunit/includes/db/DatabaseTest.php
index d480ac6e..672e6645 100644
--- a/tests/phpunit/includes/db/DatabaseTest.php
+++ b/tests/phpunit/includes/db/DatabaseTest.php
@@ -2,12 +2,20 @@
/**
* @group Database
+ * @group DatabaseBase
*/
class DatabaseTest extends MediaWikiTestCase {
- var $db;
+ var $db, $functionTest = false;
function setUp() {
- $this->db = wfGetDB( DB_SLAVE );
+ $this->db = wfGetDB( DB_MASTER );
+ }
+
+ function tearDown() {
+ if ( $this->functionTest ) {
+ $this->dropFunctions();
+ $this->functionTest = false;
+ }
}
function testAddQuotesNull() {
@@ -90,6 +98,26 @@ class DatabaseTest extends MediaWikiTestCase {
$sql );
}
+ /**
+ * @group Broken
+ */
+ function testStoredFunctions() {
+ if ( !in_array( wfGetDB( DB_MASTER )->getType(), array( 'mysql', 'postgres' ) ) ) {
+ $this->markTestSkipped( 'MySQL or Postgres required' );
+ }
+ global $IP;
+ $this->dropFunctions();
+ $this->functionTest = true;
+ $this->assertTrue( $this->db->sourceFile( "$IP/tests/phpunit/data/db/{$this->db->getType()}/functions.sql" ) );
+ $res = $this->db->query( 'SELECT mw_test_function() AS test', __METHOD__ );
+ $this->assertEquals( 42, $res->fetchObject()->test );
+ }
+
+ private function dropFunctions() {
+ $this->db->query( 'DROP FUNCTION IF EXISTS mw_test_function'
+ . ( $this->db->getType() == 'postgres' ? '()' : '' )
+ );
+ }
}
diff --git a/tests/phpunit/includes/debug/MWDebugTest.php b/tests/phpunit/includes/debug/MWDebugTest.php
new file mode 100644
index 00000000..5a4e66d4
--- /dev/null
+++ b/tests/phpunit/includes/debug/MWDebugTest.php
@@ -0,0 +1,63 @@
+<?php
+
+class MWDebugTest extends MediaWikiTestCase {
+
+
+ function setUp() {
+ // Make sure MWDebug class is enabled
+ static $MWDebugEnabled = false;
+ if( !$MWDebugEnabled ) {
+ MWDebug::init();
+ $MWDebugEnabled = true;
+ }
+ /** Clear log before each test */
+ MWDebug::clearLog();
+ }
+
+ function testAddLog() {
+ MWDebug::log( 'logging a string' );
+ $this->assertEquals( array( array(
+ 'msg' => 'logging a string',
+ 'type' => 'log',
+ 'caller' => __METHOD__ ,
+ ) ),
+ MWDebug::getLog()
+ );
+ }
+
+ function testAddWarning() {
+ MWDebug::warning( 'Warning message' );
+ $this->assertEquals( array( array(
+ 'msg' => 'Warning message',
+ 'type' => 'warn',
+ 'caller' => 'MWDebug::warning',
+ ) ),
+ MWDebug::getLog()
+ );
+ }
+
+ function testAvoidDuplicateDeprecations() {
+ MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
+ MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
+
+ // assertCount() not available on WMF integration server
+ $this->assertEquals( 1,
+ count( MWDebug::getLog() ),
+ "Only one deprecated warning per function should be kept"
+ );
+ }
+
+ function testAvoidNonConsecutivesDuplicateDeprecations() {
+ MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
+ MWDebug::warning( 'some warning' );
+ MWDebug::log( 'we could have logged something too' );
+ // Another deprecation
+ MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
+
+ // assertCount() not available on WMF integration server
+ $this->assertEquals( 3,
+ count( MWDebug::getLog() ),
+ "Only one deprecated warning per function should be kept"
+ );
+ }
+}
diff --git a/tests/phpunit/includes/filerepo/FileBackendTest.php b/tests/phpunit/includes/filerepo/FileBackendTest.php
new file mode 100644
index 00000000..da44797a
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/FileBackendTest.php
@@ -0,0 +1,1358 @@
+<?php
+
+/**
+ * @group FileRepo
+ * @group FileBackend
+ */
+class FileBackendTest extends MediaWikiTestCase {
+ private $backend, $multiBackend;
+ private $filesToPrune = array();
+ private $dirsToPrune = array();
+ private static $backendToUse;
+
+ function setUp() {
+ global $wgFileBackends;
+ parent::setUp();
+ $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . time() . '-' . mt_rand();
+ if ( $this->getCliArg( 'use-filebackend=' ) ) {
+ if ( self::$backendToUse ) {
+ $this->singleBackend = self::$backendToUse;
+ } else {
+ $name = $this->getCliArg( 'use-filebackend=' );
+ $useConfig = array();
+ foreach ( $wgFileBackends as $conf ) {
+ if ( $conf['name'] == $name ) {
+ $useConfig = $conf;
+ }
+ }
+ $useConfig['name'] = 'localtesting'; // swap name
+ $class = $conf['class'];
+ self::$backendToUse = new $class( $useConfig );
+ $this->singleBackend = self::$backendToUse;
+ }
+ } else {
+ $this->singleBackend = new FSFileBackend( array(
+ 'name' => 'localtesting',
+ 'lockManager' => 'fsLockManager',
+ 'containerPaths' => array(
+ 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
+ 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
+ ) );
+ }
+ $this->multiBackend = new FileBackendMultiWrite( array(
+ 'name' => 'localtesting',
+ 'lockManager' => 'fsLockManager',
+ 'backends' => array(
+ array(
+ 'name' => 'localmutlitesting1',
+ 'class' => 'FSFileBackend',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array(
+ 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
+ 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
+ 'isMultiMaster' => false
+ ),
+ array(
+ 'name' => 'localmutlitesting2',
+ 'class' => 'FSFileBackend',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array(
+ 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
+ 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
+ 'isMultiMaster' => true
+ )
+ )
+ ) );
+ $this->filesToPrune = array();
+ }
+
+ private function baseStorePath() {
+ return 'mwstore://localtesting';
+ }
+
+ private function backendClass() {
+ return get_class( $this->backend );
+ }
+
+ /**
+ * @dataProvider provider_testIsStoragePath
+ */
+ public function testIsStoragePath( $path, $isStorePath ) {
+ $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ),
+ "FileBackend::isStoragePath on path '$path'" );
+ }
+
+ function provider_testIsStoragePath() {
+ return array(
+ array( 'mwstore://', true ),
+ array( 'mwstore://backend', true ),
+ array( 'mwstore://backend/container', true ),
+ array( 'mwstore://backend/container/', true ),
+ array( 'mwstore://backend/container/path', true ),
+ array( 'mwstore://backend//container/', true ),
+ array( 'mwstore://backend//container//', true ),
+ array( 'mwstore://backend//container//path', true ),
+ array( 'mwstore:///', true ),
+ array( 'mwstore:/', false ),
+ array( 'mwstore:', false ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_testSplitStoragePath
+ */
+ public function testSplitStoragePath( $path, $res ) {
+ $this->assertEquals( $res, FileBackend::splitStoragePath( $path ),
+ "FileBackend::splitStoragePath on path '$path'" );
+ }
+
+ function provider_testSplitStoragePath() {
+ return array(
+ array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
+ array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
+ array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
+ array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
+ array( 'mwstore://backend//container/path', array( null, null, null ) ),
+ array( 'mwstore://backend//container//path', array( null, null, null ) ),
+ array( 'mwstore://', array( null, null, null ) ),
+ array( 'mwstore://backend', array( null, null, null ) ),
+ array( 'mwstore:///', array( null, null, null ) ),
+ array( 'mwstore:/', array( null, null, null ) ),
+ array( 'mwstore:', array( null, null, null ) )
+ );
+ }
+
+ /**
+ * @dataProvider provider_normalizeStoragePath
+ */
+ public function testNormalizeStoragePath( $path, $res ) {
+ $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ),
+ "FileBackend::normalizeStoragePath on path '$path'" );
+ }
+
+ function provider_normalizeStoragePath() {
+ return array(
+ array( 'mwstore://backend/container', 'mwstore://backend/container' ),
+ array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
+ array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
+ array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
+ array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
+ array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj',
+ array( 'mwstore://', null ),
+ array( 'mwstore://backend', null ),
+ array( 'mwstore://backend//container/path', null ),
+ array( 'mwstore://backend//container//path', null ),
+ array( 'mwstore:///', null ),
+ array( 'mwstore:/', null ),
+ array( 'mwstore:', null ), )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testParentStoragePath
+ */
+ public function testParentStoragePath( $path, $res ) {
+ $this->assertEquals( $res, FileBackend::parentStoragePath( $path ),
+ "FileBackend::parentStoragePath on path '$path'" );
+ }
+
+ function provider_testParentStoragePath() {
+ return array(
+ array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
+ array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
+ array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
+ array( 'mwstore://backend/container', null ),
+ array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
+ array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
+ array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
+ array( 'mwstore://backend/container/', null ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_testExtensionFromPath
+ */
+ public function testExtensionFromPath( $path, $res ) {
+ $this->assertEquals( $res, FileBackend::extensionFromPath( $path ),
+ "FileBackend::extensionFromPath on path '$path'" );
+ }
+
+ function provider_testExtensionFromPath() {
+ return array(
+ array( 'mwstore://backend/container/path.txt', 'txt' ),
+ array( 'mwstore://backend/container/path.svg.png', 'png' ),
+ array( 'mwstore://backend/container/path', '' ),
+ array( 'mwstore://backend/container/path.', '' ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_testStore
+ */
+ public function testStore( $op ) {
+ $this->filesToPrune[] = $op['src'];
+
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestStore( $op );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestStore( $op );
+ $this->filesToPrune[] = $op['src']; # avoid file leaking
+ $this->tearDownFiles();
+ }
+
+ function doTestStore( $op ) {
+ $backendName = $this->backendClass();
+
+ $source = $op['src'];
+ $dest = $op['dst'];
+ $this->prepare( array( 'dir' => dirname( $dest ) ) );
+
+ file_put_contents( $source, "Unit test file" );
+
+ if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
+ $this->backend->store( $op );
+ }
+
+ $status = $this->backend->doOperation( $op );
+
+ $this->assertEquals( array(), $status->errors,
+ "Store from $source to $dest succeeded without warnings ($backendName)." );
+ $this->assertEquals( array(), $status->errors,
+ "Store from $source to $dest succeeded ($backendName)." );
+ $this->assertEquals( array( 0 => true ), $status->success,
+ "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
+ $this->assertEquals( true, file_exists( $source ),
+ "Source file $source still exists ($backendName)." );
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
+ "Destination file $dest exists ($backendName)." );
+
+ $this->assertEquals( filesize( $source ),
+ $this->backend->getFileSize( array( 'src' => $dest ) ),
+ "Destination file $dest has correct size ($backendName)." );
+
+ $props1 = FSFile::getPropsFromPath( $source );
+ $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
+ $this->assertEquals( $props1, $props2,
+ "Source and destination have the same props ($backendName)." );
+ }
+
+ public function provider_testStore() {
+ $cases = array();
+
+ $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
+ $toPath = $this->baseStorePath() . '/unittest-cont1/fun/obj1.txt';
+ $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
+ $cases[] = array(
+ $op, // operation
+ $tmpName, // source
+ $toPath, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwrite'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $tmpName, // source
+ $toPath, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $tmpName, // source
+ $toPath, // dest
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testCopy
+ */
+ public function testCopy( $op ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestCopy( $op );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestCopy( $op );
+ $this->tearDownFiles();
+ }
+
+ function doTestCopy( $op ) {
+ $backendName = $this->backendClass();
+
+ $source = $op['src'];
+ $dest = $op['dst'];
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+ $this->prepare( array( 'dir' => dirname( $dest ) ) );
+
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $source succeeded ($backendName)." );
+
+ if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
+ $this->backend->copy( $op );
+ }
+
+ $status = $this->backend->doOperation( $op );
+
+ $this->assertEquals( array(), $status->errors,
+ "Copy from $source to $dest succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Copy from $source to $dest succeeded ($backendName)." );
+ $this->assertEquals( array( 0 => true ), $status->success,
+ "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ),
+ "Source file $source still exists ($backendName)." );
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
+ "Destination file $dest exists after copy ($backendName)." );
+
+ $this->assertEquals(
+ $this->backend->getFileSize( array( 'src' => $source ) ),
+ $this->backend->getFileSize( array( 'src' => $dest ) ),
+ "Destination file $dest has correct size ($backendName)." );
+
+ $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
+ $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
+ $this->assertEquals( $props1, $props2,
+ "Source and destination have the same props ($backendName)." );
+ }
+
+ public function provider_testCopy() {
+ $cases = array();
+
+ $source = $this->baseStorePath() . '/unittest-cont1/file.txt';
+ $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt';
+
+ $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
+ $cases[] = array(
+ $op, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwrite'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testMove
+ */
+ public function testMove( $op ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestMove( $op );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestMove( $op );
+ $this->tearDownFiles();
+ }
+
+ private function doTestMove( $op ) {
+ $backendName = $this->backendClass();
+
+ $source = $op['src'];
+ $dest = $op['dst'];
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+ $this->prepare( array( 'dir' => dirname( $dest ) ) );
+
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $source succeeded ($backendName)." );
+
+ if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
+ $this->backend->copy( $op );
+ }
+
+ $status = $this->backend->doOperation( $op );
+ $this->assertEquals( array(), $status->errors,
+ "Move from $source to $dest succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Move from $source to $dest succeeded ($backendName)." );
+ $this->assertEquals( array( 0 => true ), $status->success,
+ "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
+ "Source file $source does not still exists ($backendName)." );
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
+ "Destination file $dest exists after move ($backendName)." );
+
+ $this->assertNotEquals(
+ $this->backend->getFileSize( array( 'src' => $source ) ),
+ $this->backend->getFileSize( array( 'src' => $dest ) ),
+ "Destination file $dest has correct size ($backendName)." );
+
+ $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
+ $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
+ $this->assertEquals( false, $props1['fileExists'],
+ "Source file does not exist accourding to props ($backendName)." );
+ $this->assertEquals( true, $props2['fileExists'],
+ "Destination file exists accourding to props ($backendName)." );
+ }
+
+ public function provider_testMove() {
+ $cases = array();
+
+ $source = $this->baseStorePath() . '/unittest-cont1/file.txt';
+ $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt';
+
+ $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
+ $cases[] = array(
+ $op, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwrite'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testDelete
+ */
+ public function testDelete( $op, $withSource, $okStatus ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestDelete( $op, $withSource, $okStatus );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestDelete( $op, $withSource, $okStatus );
+ $this->tearDownFiles();
+ }
+
+ private function doTestDelete( $op, $withSource, $okStatus ) {
+ $backendName = $this->backendClass();
+
+ $source = $op['src'];
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+
+ if ( $withSource ) {
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $source succeeded ($backendName)." );
+ }
+
+ $status = $this->backend->doOperation( $op );
+ if ( $okStatus ) {
+ $this->assertEquals( array(), $status->errors,
+ "Deletion of file at $source succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Deletion of file at $source succeeded ($backendName)." );
+ $this->assertEquals( array( 0 => true ), $status->success,
+ "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
+ } else {
+ $this->assertEquals( false, $status->isOK(),
+ "Deletion of file at $source failed ($backendName)." );
+ }
+
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
+ "Source file $source does not exist after move ($backendName)." );
+
+ $this->assertFalse(
+ $this->backend->getFileSize( array( 'src' => $source ) ),
+ "Source file $source has correct size (false) ($backendName)." );
+
+ $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
+ $this->assertFalse( $props1['fileExists'],
+ "Source file $source does not exist according to props ($backendName)." );
+ }
+
+ public function provider_testDelete() {
+ $cases = array();
+
+ $source = $this->baseStorePath() . '/unittest-cont1/myfacefile.txt';
+
+ $op = array( 'op' => 'delete', 'src' => $source );
+ $cases[] = array(
+ $op, // operation
+ true, // with source
+ true // succeeds
+ );
+
+ $cases[] = array(
+ $op, // operation
+ false, // without source
+ false // fails
+ );
+
+ $op['ignoreMissingSource'] = true;
+ $cases[] = array(
+ $op, // operation
+ false, // without source
+ true // succeeds
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testCreate
+ */
+ public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
+ $this->tearDownFiles();
+ }
+
+ private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
+ $backendName = $this->backendClass();
+
+ $dest = $op['dst'];
+ $this->prepare( array( 'dir' => dirname( $dest ) ) );
+
+ $oldText = 'blah...blah...waahwaah';
+ if ( $alreadyExists ) {
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $dest succeeded ($backendName)." );
+ }
+
+ $status = $this->backend->doOperation( $op );
+ if ( $okStatus ) {
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $dest succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Creation of file at $dest succeeded ($backendName)." );
+ $this->assertEquals( array( 0 => true ), $status->success,
+ "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
+ } else {
+ $this->assertEquals( false, $status->isOK(),
+ "Creation of file at $dest failed ($backendName)." );
+ }
+
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
+ "Destination file $dest exists after creation ($backendName)." );
+
+ $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
+ $this->assertEquals( true, $props1['fileExists'],
+ "Destination file $dest exists according to props ($backendName)." );
+ if ( $okStatus ) { // file content is what we saved
+ $this->assertEquals( $newSize, $props1['size'],
+ "Destination file $dest has expected size according to props ($backendName)." );
+ $this->assertEquals( $newSize,
+ $this->backend->getFileSize( array( 'src' => $dest ) ),
+ "Destination file $dest has correct size ($backendName)." );
+ } else { // file content is some other previous text
+ $this->assertEquals( strlen( $oldText ), $props1['size'],
+ "Destination file $dest has original size according to props ($backendName)." );
+ $this->assertEquals( strlen( $oldText ),
+ $this->backend->getFileSize( array( 'src' => $dest ) ),
+ "Destination file $dest has original size according to props ($backendName)." );
+ }
+ }
+
+ /**
+ * @dataProvider provider_testCreate
+ */
+ public function provider_testCreate() {
+ $cases = array();
+
+ $dest = $this->baseStorePath() . '/unittest-cont2/myspacefile.txt';
+
+ $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
+ $cases[] = array(
+ $op, // operation
+ false, // no dest already exists
+ true, // succeeds
+ strlen( $op['content'] )
+ );
+
+ $op2 = $op;
+ $op2['content'] = "\n";
+ $cases[] = array(
+ $op2, // operation
+ false, // no dest already exists
+ true, // succeeds
+ strlen( $op2['content'] )
+ );
+
+ $op2 = $op;
+ $op2['content'] = "fsf\n waf 3kt";
+ $cases[] = array(
+ $op2, // operation
+ true, // dest already exists
+ false, // fails
+ strlen( $op2['content'] )
+ );
+
+ $op2 = $op;
+ $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
+ $op2['overwrite'] = true;
+ $cases[] = array(
+ $op2, // operation
+ true, // dest already exists
+ true, // succeeds
+ strlen( $op2['content'] )
+ );
+
+ $op2 = $op;
+ $op2['content'] = "39qjmg3-qg";
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
+ true, // dest already exists
+ false, // succeeds
+ strlen( $op2['content'] )
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testConcatenate
+ */
+ public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
+ $this->filesToPrune[] = $op['dst'];
+
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
+ $this->filesToPrune[] = $op['dst']; # avoid file leaking
+ $this->tearDownFiles();
+ }
+
+ public function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
+ $backendName = $this->backendClass();
+
+ $expContent = '';
+ // Create sources
+ $ops = array();
+ foreach ( $srcs as $i => $source ) {
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+ $ops[] = array(
+ 'op' => 'create', // operation
+ 'dst' => $source, // source
+ 'content' => $srcsContent[$i]
+ );
+ $expContent .= $srcsContent[$i];
+ }
+ $status = $this->backend->doOperations( $ops );
+
+ $this->assertEquals( array(), $status->errors,
+ "Creation of source files succeeded ($backendName)." );
+
+ $dest = $params['dst'];
+ if ( $alreadyExists ) {
+ $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
+ $this->assertEquals( true, $ok,
+ "Creation of file at $dest succeeded ($backendName)." );
+ } else {
+ $ok = file_put_contents( $dest, '' ) !== false;
+ $this->assertEquals( true, $ok,
+ "Creation of 0-byte file at $dest succeeded ($backendName)." );
+ }
+
+ // Combine the files into one
+ $status = $this->backend->concatenate( $params );
+ if ( $okStatus ) {
+ $this->assertEquals( array(), $status->errors,
+ "Creation of concat file at $dest succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Creation of concat file at $dest succeeded ($backendName)." );
+ } else {
+ $this->assertEquals( false, $status->isOK(),
+ "Creation of concat file at $dest failed ($backendName)." );
+ }
+
+ if ( $okStatus ) {
+ $this->assertEquals( true, is_file( $dest ),
+ "Dest concat file $dest exists after creation ($backendName)." );
+ } else {
+ $this->assertEquals( true, is_file( $dest ),
+ "Dest concat file $dest exists after failed creation ($backendName)." );
+ }
+
+ $contents = file_get_contents( $dest );
+ $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
+
+ if ( $okStatus ) {
+ $this->assertEquals( $expContent, $contents,
+ "Concat file at $dest has correct contents ($backendName)." );
+ } else {
+ $this->assertNotEquals( $expContent, $contents,
+ "Concat file at $dest has correct contents ($backendName)." );
+ }
+ }
+
+ function provider_testConcatenate() {
+ $cases = array();
+
+ $rand = mt_rand( 0, 2000000000 ) . time();
+ $dest = wfTempDir() . "/randomfile!$rand.txt";
+ $srcs = array(
+ $this->baseStorePath() . '/unittest-cont1/file1.txt',
+ $this->baseStorePath() . '/unittest-cont1/file2.txt',
+ $this->baseStorePath() . '/unittest-cont1/file3.txt',
+ $this->baseStorePath() . '/unittest-cont1/file4.txt',
+ $this->baseStorePath() . '/unittest-cont1/file5.txt',
+ $this->baseStorePath() . '/unittest-cont1/file6.txt',
+ $this->baseStorePath() . '/unittest-cont1/file7.txt',
+ $this->baseStorePath() . '/unittest-cont1/file8.txt',
+ $this->baseStorePath() . '/unittest-cont1/file9.txt',
+ $this->baseStorePath() . '/unittest-cont1/file10.txt'
+ );
+ $content = array(
+ 'egfage',
+ 'ageageag',
+ 'rhokohlr',
+ 'shgmslkg',
+ 'kenga',
+ 'owagmal',
+ 'kgmae',
+ 'g eak;g',
+ 'lkaem;a',
+ 'legma'
+ );
+ $params = array( 'srcs' => $srcs, 'dst' => $dest );
+
+ $cases[] = array(
+ $params, // operation
+ $srcs, // sources
+ $content, // content for each source
+ false, // no dest already exists
+ true, // succeeds
+ );
+
+ $cases[] = array(
+ $params, // operation
+ $srcs, // sources
+ $content, // content for each source
+ true, // dest already exists
+ false, // succeeds
+ );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testGetFileStat
+ */
+ public function testGetFileStat( $path, $content, $alreadyExists ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestGetFileStat( $path, $content, $alreadyExists );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestGetFileStat( $path, $content, $alreadyExists );
+ $this->tearDownFiles();
+ }
+
+ private function doTestGetFileStat( $path, $content, $alreadyExists ) {
+ $backendName = $this->backendClass();
+
+ if ( $alreadyExists ) {
+ $this->prepare( array( 'dir' => dirname( $path ) ) );
+ $status = $this->backend->create( array( 'dst' => $path, 'content' => $content ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $path succeeded ($backendName)." );
+
+ $size = $this->backend->getFileSize( array( 'src' => $path ) );
+ $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
+ $stat = $this->backend->getFileStat( array( 'src' => $path ) );
+
+ $this->assertEquals( strlen( $content ), $size,
+ "Correct file size of '$path'" );
+ $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 5,
+ "Correct file timestamp of '$path'" );
+
+ $size = $stat['size'];
+ $time = $stat['mtime'];
+ $this->assertEquals( strlen( $content ), $size,
+ "Correct file size of '$path'" );
+ $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 5,
+ "Correct file timestamp of '$path'" );
+ } else {
+ $size = $this->backend->getFileSize( array( 'src' => $path ) );
+ $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
+ $stat = $this->backend->getFileStat( array( 'src' => $path ) );
+
+ $this->assertFalse( $size, "Correct file size of '$path'" );
+ $this->assertFalse( $time, "Correct file timestamp of '$path'" );
+ $this->assertFalse( $stat, "Correct file stat of '$path'" );
+ }
+ }
+
+ function provider_testGetFileStat() {
+ $cases = array();
+
+ $base = $this->baseStorePath();
+ $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents", true );
+ $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "", true );
+ $cases[] = array( "$base/unittest-cont1/b/some-diff_file.txt", null, false );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testGetFileContents
+ */
+ public function testGetFileContents( $source, $content ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestGetFileContents( $source, $content );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestGetFileContents( $source, $content );
+ $this->tearDownFiles();
+ }
+
+ public function doTestGetFileContents( $source, $content ) {
+ $backendName = $this->backendClass();
+
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $source succeeded ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Creation of file at $source succeeded with OK status ($backendName)." );
+
+ $newContents = $this->backend->getFileContents( array( 'src' => $source, 'latest' => 1 ) );
+ $this->assertNotEquals( false, $newContents,
+ "Read of file at $source succeeded ($backendName)." );
+
+ $this->assertEquals( $content, $newContents,
+ "Contents read match data at $source ($backendName)." );
+ }
+
+ function provider_testGetFileContents() {
+ $cases = array();
+
+ $base = $this->baseStorePath();
+ $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents" );
+ $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "more file contents" );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testGetLocalCopy
+ */
+ public function testGetLocalCopy( $source, $content ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestGetLocalCopy( $source, $content );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestGetLocalCopy( $source, $content );
+ $this->tearDownFiles();
+ }
+
+ public function doTestGetLocalCopy( $source, $content ) {
+ $backendName = $this->backendClass();
+
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $source succeeded ($backendName)." );
+
+ $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
+ $this->assertNotNull( $tmpFile,
+ "Creation of local copy of $source succeeded ($backendName)." );
+
+ $contents = file_get_contents( $tmpFile->getPath() );
+ $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
+ }
+
+ function provider_testGetLocalCopy() {
+ $cases = array();
+
+ $base = $this->baseStorePath();
+ $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" );
+ $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testGetLocalReference
+ */
+ public function testGetLocalReference( $source, $content ) {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestGetLocalReference( $source, $content );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestGetLocalReference( $source, $content );
+ $this->tearDownFiles();
+ }
+
+ private function doTestGetLocalReference( $source, $content ) {
+ $backendName = $this->backendClass();
+
+ $this->prepare( array( 'dir' => dirname( $source ) ) );
+
+ $status = $this->backend->doOperation(
+ array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of file at $source succeeded ($backendName)." );
+
+ $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
+ $this->assertNotNull( $tmpFile,
+ "Creation of local copy of $source succeeded ($backendName)." );
+
+ $contents = file_get_contents( $tmpFile->getPath() );
+ $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
+ }
+
+ function provider_testGetLocalReference() {
+ $cases = array();
+
+ $base = $this->baseStorePath();
+ $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" );
+ $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" );
+
+ return $cases;
+ }
+
+ /**
+ * @dataProvider provider_testPrepareAndClean
+ */
+ public function testPrepareAndClean( $path, $isOK ) {
+ $this->backend = $this->singleBackend;
+ $this->doTestPrepareAndClean( $path, $isOK );
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->doTestPrepareAndClean( $path, $isOK );
+ $this->tearDownFiles();
+ }
+
+ function provider_testPrepareAndClean() {
+ $base = $this->baseStorePath();
+ return array(
+ array( "$base/unittest-cont1/a/z/some_file1.txt", true ),
+ array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
+ # Specific to FS backend with no basePath field set
+ #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
+ );
+ }
+
+ function doTestPrepareAndClean( $path, $isOK ) {
+ $backendName = $this->backendClass();
+
+ $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
+ if ( $isOK ) {
+ $this->assertEquals( array(), $status->errors,
+ "Preparing dir $path succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Preparing dir $path succeeded ($backendName)." );
+ } else {
+ $this->assertEquals( false, $status->isOK(),
+ "Preparing dir $path failed ($backendName)." );
+ }
+
+ $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) );
+ if ( $isOK ) {
+ $this->assertEquals( array(), $status->errors,
+ "Cleaning dir $path succeeded without warnings ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Cleaning dir $path succeeded ($backendName)." );
+ } else {
+ $this->assertEquals( false, $status->isOK(),
+ "Cleaning dir $path failed ($backendName)." );
+ }
+ }
+
+ // @TODO: testSecure
+
+ public function testDoOperations() {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestDoOperations();
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestDoOperations();
+ $this->tearDownFiles();
+
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestDoOperationsFailing();
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestDoOperationsFailing();
+ $this->tearDownFiles();
+
+ // @TODO: test some cases where the ops should fail
+ }
+
+ function doTestDoOperations() {
+ $base = $this->baseStorePath();
+
+ $fileA = "$base/unittest-cont1/a/b/fileA.txt";
+ $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
+ $fileB = "$base/unittest-cont1/a/b/fileB.txt";
+ $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
+ $fileC = "$base/unittest-cont1/a/b/fileC.txt";
+ $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
+ $fileD = "$base/unittest-cont1/a/b/fileD.txt";
+
+ $this->prepare( array( 'dir' => dirname( $fileA ) ) );
+ $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
+ $this->prepare( array( 'dir' => dirname( $fileB ) ) );
+ $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
+ $this->prepare( array( 'dir' => dirname( $fileC ) ) );
+ $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
+
+ $status = $this->backend->doOperations( array(
+ array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
+ array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<empty>
+ array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
+ // Now: A:<A>, B:<B>, C:<empty>, D:<A>
+ array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
+ // Now: A:<A>, B:<empty>, C:<B>, D:<A>
+ array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
+ // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
+ array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
+ // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
+ array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
+ // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
+ array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
+ // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
+ array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
+ // Does nothing
+ array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
+ // Does nothing
+ array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
+ // Does nothing
+ array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
+ // Does nothing
+ array( 'op' => 'null' ),
+ // Does nothing
+ ) );
+
+ $this->assertEquals( array(), $status->errors, "Operation batch succeeded" );
+ $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
+ $this->assertEquals( 13, count( $status->success ),
+ "Operation batch has correct success array" );
+
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
+ "File does not exist at $fileA" );
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
+ "File does not exist at $fileB" );
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
+ "File does not exist at $fileD" );
+
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
+ "File exists at $fileC" );
+ $this->assertEquals( $fileBContents,
+ $this->backend->getFileContents( array( 'src' => $fileC ) ),
+ "Correct file contents of $fileC" );
+ $this->assertEquals( strlen( $fileBContents ),
+ $this->backend->getFileSize( array( 'src' => $fileC ) ),
+ "Correct file size of $fileC" );
+ $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
+ $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
+ "Correct file SHA-1 of $fileC" );
+ }
+
+ function doTestDoOperationsFailing() {
+ $base = $this->baseStorePath();
+
+ $fileA = "$base/unittest-cont2/a/b/fileA.txt";
+ $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
+ $fileB = "$base/unittest-cont2/a/b/fileB.txt";
+ $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
+ $fileC = "$base/unittest-cont2/a/b/fileC.txt";
+ $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
+ $fileD = "$base/unittest-cont2/a/b/fileD.txt";
+
+ $this->prepare( array( 'dir' => dirname( $fileA ) ) );
+ $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
+ $this->prepare( array( 'dir' => dirname( $fileB ) ) );
+ $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
+ $this->prepare( array( 'dir' => dirname( $fileC ) ) );
+ $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
+
+ $status = $this->backend->doOperations( array(
+ array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
+ array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<empty>
+ array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<B>
+ array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
+ array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
+ // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
+ array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
+ // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
+ array( 'op' => 'delete', 'src' => $fileD ),
+ // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
+ array( 'op' => 'null' ),
+ // Does nothing
+ ), array( 'force' => 1 ) );
+
+ $this->assertNotEquals( array(), $status->errors, "Operation had warnings" );
+ $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
+ $this->assertEquals( 8, count( $status->success ),
+ "Operation batch has correct success array" );
+
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
+ "File does not exist at $fileB" );
+ $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
+ "File does not exist at $fileD" );
+
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ),
+ "File does not exist at $fileA" );
+ $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
+ "File exists at $fileC" );
+ $this->assertEquals( $fileBContents,
+ $this->backend->getFileContents( array( 'src' => $fileA ) ),
+ "Correct file contents of $fileA" );
+ $this->assertEquals( strlen( $fileBContents ),
+ $this->backend->getFileSize( array( 'src' => $fileA ) ),
+ "Correct file size of $fileA" );
+ $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
+ $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ),
+ "Correct file SHA-1 of $fileA" );
+ }
+
+ public function testGetFileList() {
+ $this->backend = $this->singleBackend;
+ $this->tearDownFiles();
+ $this->doTestGetFileList();
+ $this->tearDownFiles();
+
+ $this->backend = $this->multiBackend;
+ $this->tearDownFiles();
+ $this->doTestGetFileList();
+ $this->tearDownFiles();
+ }
+
+ private function doTestGetFileList() {
+ $backendName = $this->backendClass();
+
+ $base = $this->baseStorePath();
+ $files = array(
+ "$base/unittest-cont1/test1.txt",
+ "$base/unittest-cont1/test2.txt",
+ "$base/unittest-cont1/test3.txt",
+ "$base/unittest-cont1/subdir1/test1.txt",
+ "$base/unittest-cont1/subdir1/test2.txt",
+ "$base/unittest-cont1/subdir2/test3.txt",
+ "$base/unittest-cont1/subdir2/test4.txt",
+ "$base/unittest-cont1/subdir2/subdir/test1.txt",
+ "$base/unittest-cont1/subdir2/subdir/test2.txt",
+ "$base/unittest-cont1/subdir2/subdir/test3.txt",
+ "$base/unittest-cont1/subdir2/subdir/test4.txt",
+ "$base/unittest-cont1/subdir2/subdir/test5.txt",
+ "$base/unittest-cont1/subdir2/subdir/sub/test0.txt",
+ "$base/unittest-cont1/subdir2/subdir/sub/120-px-file.txt",
+ );
+
+ // Add the files
+ $ops = array();
+ foreach ( $files as $file ) {
+ $this->prepare( array( 'dir' => dirname( $file ) ) );
+ $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
+ }
+ $status = $this->backend->doOperations( $ops );
+ $this->assertEquals( array(), $status->errors,
+ "Creation of files succeeded ($backendName)." );
+ $this->assertEquals( true, $status->isOK(),
+ "Creation of files succeeded with OK status ($backendName)." );
+
+ // Expected listing
+ $expected = array(
+ "test1.txt",
+ "test2.txt",
+ "test3.txt",
+ "subdir1/test1.txt",
+ "subdir1/test2.txt",
+ "subdir2/test3.txt",
+ "subdir2/test4.txt",
+ "subdir2/subdir/test1.txt",
+ "subdir2/subdir/test2.txt",
+ "subdir2/subdir/test3.txt",
+ "subdir2/subdir/test4.txt",
+ "subdir2/subdir/test5.txt",
+ "subdir2/subdir/sub/test0.txt",
+ "subdir2/subdir/sub/120-px-file.txt",
+ );
+ sort( $expected );
+
+ // Actual listing (no trailing slash)
+ $list = array();
+ $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
+ foreach ( $iter as $file ) {
+ $list[] = $file;
+ }
+ sort( $list );
+
+ $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
+
+ // Actual listing (with trailing slash)
+ $list = array();
+ $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
+ foreach ( $iter as $file ) {
+ $list[] = $file;
+ }
+ sort( $list );
+
+ $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
+
+ // Expected listing
+ $expected = array(
+ "test1.txt",
+ "test2.txt",
+ "test3.txt",
+ "test4.txt",
+ "test5.txt",
+ "sub/test0.txt",
+ "sub/120-px-file.txt",
+ );
+ sort( $expected );
+
+ // Actual listing (no trailing slash)
+ $list = array();
+ $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) );
+ foreach ( $iter as $file ) {
+ $list[] = $file;
+ }
+ sort( $list );
+
+ $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
+
+ // Actual listing (with trailing slash)
+ $list = array();
+ $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir/" ) );
+ foreach ( $iter as $file ) {
+ $list[] = $file;
+ }
+ sort( $list );
+
+ $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
+
+ // Actual listing (using iterator second time)
+ $list = array();
+ foreach ( $iter as $file ) {
+ $list[] = $file;
+ }
+ sort( $list );
+
+ $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
+
+ foreach ( $files as $file ) { // clean up
+ $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
+ }
+
+ $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
+ foreach ( $iter as $iter ) {} // no errors
+ }
+
+ // test helper wrapper for backend prepare() function
+ private function prepare( array $params ) {
+ $this->dirsToPrune[] = $params['dir'];
+ return $this->backend->prepare( $params );
+ }
+
+ function tearDownFiles() {
+ foreach ( $this->filesToPrune as $file ) {
+ @unlink( $file );
+ }
+ $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' );
+ foreach ( $containers as $container ) {
+ $this->deleteFiles( $container );
+ }
+ foreach ( $this->dirsToPrune as $dir ) {
+ $this->recursiveClean( $dir );
+ }
+ $this->filesToPrune = $this->dirsToPrune = array();
+ }
+
+ private function deleteFiles( $container ) {
+ $base = $this->baseStorePath();
+ $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) );
+ if ( $iter ) {
+ foreach ( $iter as $file ) {
+ $this->backend->delete( array( 'src' => "$base/$container/$file" ), array( 'force' => 1 ) );
+ }
+ }
+ }
+
+ private function recursiveClean( $dir ) {
+ do {
+ if ( !$this->backend->clean( array( 'dir' => $dir ) )->isOK() ) {
+ break;
+ }
+ } while ( $dir = FileBackend::parentStoragePath( $dir ) );
+ }
+
+ function tearDown() {
+ parent::tearDown();
+ }
+}
diff --git a/tests/phpunit/includes/filerepo/FileRepoTest.php b/tests/phpunit/includes/filerepo/FileRepoTest.php
new file mode 100644
index 00000000..0f023138
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/FileRepoTest.php
@@ -0,0 +1,41 @@
+<?php
+
+class FileRepoTest extends MediaWikiTestCase {
+
+ /**
+ * @expectedException MWException
+ */
+ function testFileRepoConstructionOptionCanNotBeNull() {
+ $f = new FileRepo();
+ }
+ /**
+ * @expectedException MWException
+ */
+ function testFileRepoConstructionOptionCanNotBeAnEmptyArray() {
+ $f = new FileRepo( array() );
+ }
+ /**
+ * @expectedException MWException
+ */
+ function testFileRepoConstructionOptionNeedNameKey() {
+ $f = new FileRepo( array(
+ 'backend' => 'foobar'
+ ) );
+ }
+ /**
+ * @expectedException MWException
+ */
+ function testFileRepoConstructionOptionNeedBackendKey() {
+ $f = new FileRepo( array(
+ 'name' => 'foobar'
+ ) );
+ }
+
+ function testFileRepoConstructionWithRequiredOptions() {
+ $f = new FileRepo( array(
+ 'name' => 'FileRepoTestRepository',
+ 'backend' => 'local-backend',
+ ));
+ $this->assertInstanceOf( 'FileRepo', $f );
+ }
+}
diff --git a/tests/phpunit/includes/filerepo/StoreBatchTest.php b/tests/phpunit/includes/filerepo/StoreBatchTest.php
new file mode 100644
index 00000000..6abceeb3
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/StoreBatchTest.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * @group FileRepo
+ */
+class StoreBatchTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ global $wgFileBackends;
+ parent::setUp();
+
+ # Forge a FSRepo object to not have to rely on local wiki settings
+ $tmpPrefix = wfTempDir() . '/storebatch-test-' . time() . '-' . mt_rand();
+ if ( $this->getCliArg( 'use-filebackend=' ) ) {
+ $name = $this->getCliArg( 'use-filebackend=' );
+ $useConfig = array();
+ foreach ( $wgFileBackends as $conf ) {
+ if ( $conf['name'] == $name ) {
+ $useConfig = $conf;
+ }
+ }
+ $useConfig['name'] = 'local-testing'; // swap name
+ $class = $useConfig['class'];
+ $backend = new $class( $useConfig );
+ } else {
+ $backend = new FSFileBackend( array(
+ 'name' => 'local-testing',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array(
+ 'unittests-public' => "{$tmpPrefix}-public",
+ 'unittests-thumb' => "{$tmpPrefix}-thumb",
+ 'unittests-temp' => "{$tmpPrefix}-temp",
+ 'unittests-deleted' => "{$tmpPrefix}-deleted",
+ )
+ ) );
+ }
+ $this->repo = new FileRepo( array(
+ 'name' => 'unittests',
+ 'backend' => $backend
+ ) );
+
+ $this->date = gmdate( "YmdHis" );
+ $this->createdFiles = array();
+ }
+
+ /**
+ * Store a file or virtual URL source into a media file name.
+ *
+ * @param $originalName string The title of the image
+ * @param $srcPath string The filepath or virtual URL
+ * @param $flags integer Flags to pass into repo::store().
+ */
+ private function storeit($originalName, $srcPath, $flags) {
+ $hashPath = $this->repo->getHashPath( $originalName );
+ $dstRel = "$hashPath{$this->date}!$originalName";
+ $dstUrlRel = $hashPath . $this->date . '!' . rawurlencode( $originalName );
+
+ $result = $this->repo->store( $srcPath, 'temp', $dstRel, $flags );
+ $result->value = $this->repo->getVirtualUrl( 'temp' ) . '/' . $dstUrlRel;
+ $this->createdFiles[] = $result->value;
+ return $result;
+ }
+
+ /**
+ * Test storing a file using different flags.
+ *
+ * @param $fn string The title of the image
+ * @param $infn string The name of the file (in the filesystem)
+ * @param $otherfn string The name of the different file (in the filesystem)
+ * @param $fromrepo logical 'true' if we want to copy from a virtual URL out of the Repo.
+ */
+ private function storecohort($fn, $infn, $otherfn, $fromrepo) {
+ $f = $this->storeit( $fn, $infn, 0 );
+ $this->assertTrue( $f->isOK(), 'failed to store a new file' );
+ $this->assertEquals( $f->failCount, 0, "counts wrong {$f->successCount} {$f->failCount}" );
+ $this->assertEquals( $f->successCount, 1 , "counts wrong {$f->successCount} {$f->failCount}" );
+ if ( $fromrepo ) {
+ $f = $this->storeit( "Other-$fn", $infn, FileRepo::OVERWRITE);
+ $infn = $f->value;
+ }
+ // This should work because we're allowed to overwrite
+ $f = $this->storeit( $fn, $infn, FileRepo::OVERWRITE );
+ $this->assertTrue( $f->isOK(), 'We should be allowed to overwrite' );
+ $this->assertEquals( $f->failCount, 0, "counts wrong {$f->successCount} {$f->failCount}" );
+ $this->assertEquals( $f->successCount, 1 , "counts wrong {$f->successCount} {$f->failCount}" );
+ // This should fail because we're overwriting.
+ $f = $this->storeit( $fn, $infn, 0 );
+ $this->assertFalse( $f->isOK(), 'We should not be allowed to overwrite' );
+ $this->assertEquals( $f->failCount, 1, "counts wrong {$f->successCount} {$f->failCount}" );
+ $this->assertEquals( $f->successCount, 0 , "counts wrong {$f->successCount} {$f->failCount}" );
+ // This should succeed because we're overwriting the same content.
+ $f = $this->storeit( $fn, $infn, FileRepo::OVERWRITE_SAME );
+ $this->assertTrue( $f->isOK(), 'We should be able to overwrite the same content' );
+ $this->assertEquals( $f->failCount, 0, "counts wrong {$f->successCount} {$f->failCount}" );
+ $this->assertEquals( $f->successCount, 1 , "counts wrong {$f->successCount} {$f->failCount}" );
+ // This should fail because we're overwriting different content.
+ if ( $fromrepo ) {
+ $f = $this->storeit( "Other-$fn", $otherfn, FileRepo::OVERWRITE);
+ $otherfn = $f->value;
+ }
+ $f = $this->storeit( $fn, $otherfn, FileRepo::OVERWRITE_SAME );
+ $this->assertFalse( $f->isOK(), 'We should not be allowed to overwrite different content' );
+ $this->assertEquals( $f->failCount, 1, "counts wrong {$f->successCount} {$f->failCount}" );
+ $this->assertEquals( $f->successCount, 0 , "counts wrong {$f->successCount} {$f->failCount}" );
+ }
+
+ public function teststore() {
+ global $IP;
+ $this->storecohort( "Test1.png", "$IP/skins/monobook/wiki.png", "$IP/skins/monobook/video.png", false );
+ $this->storecohort( "Test2.png", "$IP/skins/monobook/wiki.png", "$IP/skins/monobook/video.png", true );
+ }
+
+ public function tearDown() {
+ $this->repo->cleanupBatch( $this->createdFiles ); // delete files
+ foreach ( $this->createdFiles as $tmp ) { // delete dirs
+ $tmp = $this->repo->resolveVirtualUrl( $tmp );
+ while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) {
+ $this->repo->getBackend()->clean( array( 'dir' => $tmp ) );
+ }
+ }
+ parent::tearDown();
+ }
+}
diff --git a/tests/phpunit/includes/json/ServicesJsonTest.php b/tests/phpunit/includes/json/ServicesJsonTest.php
new file mode 100644
index 00000000..8f2421a2
--- /dev/null
+++ b/tests/phpunit/includes/json/ServicesJsonTest.php
@@ -0,0 +1,93 @@
+<?php
+/*
+ * Test cases for our Services_Json library. Requires PHP json support as well,
+ * so we can compare output
+ */
+class ServicesJsonTest extends MediaWikiTestCase {
+ /**
+ * Test to make sure core json_encode() and our Services_Json()->encode()
+ * produce the same output
+ *
+ * @dataProvider provideValuesToEncode
+ */
+ public function testJsonEncode( $input, $desc ) {
+ if ( !function_exists( 'json_encode' ) ) {
+ $this->markTestIncomplete( 'No PHP json support, unable to test' );
+ return;
+ } elseif( strtolower( json_encode( "\xf0\xa0\x80\x80" ) ) != '"\ud840\udc00"' ) {
+ $this->markTestIncomplete( 'Have buggy PHP json support, unable to test' );
+ return;
+ } else {
+ $jsonObj = new Services_JSON();
+ $this->assertEquals(
+ $jsonObj->encode( $input ),
+ json_encode( $input ),
+ $desc
+ );
+ }
+ }
+
+ /**
+ * Test to make sure core json_decode() and our Services_Json()->decode()
+ * produce the same output
+ *
+ * @dataProvider provideValuesToDecode
+ */
+ public function testJsonDecode( $input, $desc ) {
+ if ( !function_exists( 'json_decode' ) ) {
+ $this->markTestIncomplete( 'No PHP json support, unable to test' );
+ return;
+ } else {
+ $jsonObj = new Services_JSON();
+ $this->assertEquals(
+ $jsonObj->decode( $input ),
+ json_decode( $input ),
+ $desc
+ );
+ }
+ }
+
+ function provideValuesToEncode() {
+ $obj = new stdClass();
+ $obj->property = 'value';
+ $obj->property2 = null;
+ $obj->property3 = 1.234;
+ return array(
+ array( 1, 'basic integer' ),
+ array( -1, 'negative integer' ),
+ array( 1.1, 'basic float' ),
+ array( true, 'basic bool true' ),
+ array( false, 'basic bool false' ),
+ array( 'some string', 'basic string test' ),
+ array( "some string\nwith newline", 'newline string test' ),
+ array( '♥ü', 'unicode string test' ),
+ array( array( 'some', 'string', 'values' ), 'basic array of strings' ),
+ array( array( 'key1' => 'val1', 'key2' => 'val2' ), 'array with string keys' ),
+ array( array( 1 => 'val1', 3 => 'val2', '2' => 'val3' ), 'out of order numbered array test' ),
+ array( array(), 'empty array test' ),
+ array( $obj, 'basic object test' ),
+ array( new stdClass, 'empty object test' ),
+ array( null, 'null test' ),
+ );
+ }
+
+ function provideValuesToDecode() {
+ return array(
+ array( '1', 'basic integer' ),
+ array( '-1', 'negative integer' ),
+ array( '1.1', 'basic float' ),
+ array( '1.1e1', 'scientific float' ),
+ array( 'true', 'basic bool true' ),
+ array( 'false', 'basic bool false' ),
+ array( '"some string"', 'basic string test' ),
+ array( '"some string\nwith newline"', 'newline string test' ),
+ array( '"♥ü"', 'unicode character string test' ),
+ array( '"\u2665"', 'unicode \\u string test' ),
+ array( '["some","string","values"]', 'basic array of strings' ),
+ array( '[]', 'empty array test' ),
+ array( '{"key":"value"}', 'Basic key => value test' ),
+ array( '{}', 'empty object test' ),
+ array( 'null', 'null test' ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
index aa05500e..d2bfeedf 100644
--- a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
+++ b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
@@ -84,6 +84,13 @@ class JavaScriptMinifierTest extends MediaWikiTestCase {
// And also per spec unicode char escape values should work in identifiers,
// as long as it's a valid char. In future it might get normalized.
array( "var Ka\\u015dSkatolVal = {}", 'var Ka\\u015dSkatolVal={}'),
+
+ /* Some structures that might look invalid at first sight */
+ array( "var a = 5.;", "var a=5.;" ),
+ array( "5.0.toString();", "5.0.toString();" ),
+ array( "5..toString();", "5..toString();" ),
+ array( "5...toString();", false ),
+ array( "5.\n.toString();", '5..toString();' ),
);
}
@@ -102,4 +109,40 @@ class JavaScriptMinifierTest extends MediaWikiTestCase {
$this->assertEquals( $expectedOutput, $minified, "Minified output should be in the form expected." );
}
+
+ /**
+ * @dataProvider provideBug32548
+ */
+ function testBug32548Exponent($num) {
+ // Long line breaking was being incorrectly done between the base and
+ // exponent part of a number, causing a syntax error. The line should
+ // instead break at the start of the number.
+ $prefix = 'var longVarName' . str_repeat('_', 973) . '=';
+ $suffix = ',shortVarName=0;';
+
+ $input = $prefix . $num . $suffix;
+ $expected = $prefix . "\n" . $num . $suffix;
+
+ $minified = JavaScriptMinifier::minify( $input );
+
+ $this->assertEquals( $expected, $minified, "Line breaks must not occur in middle of exponent");
+ }
+
+ function provideBug32548() {
+ return array(
+ array(
+ // This one gets interpreted all together by the prior code;
+ // no break at the 'E' happens.
+ '1.23456789E55',
+ ),
+ array(
+ // This one breaks under the bad code; splits between 'E' and '+'
+ '1.23456789E+5',
+ ),
+ array(
+ // This one breaks under the bad code; splits between 'E' and '-'
+ '1.23456789E-5',
+ ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php b/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php
index a0d5cd86..f4f52dd8 100644
--- a/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php
+++ b/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php
@@ -14,10 +14,15 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase {
* translation (to en) where XMP should win.
*/
public function testMultilingualCascade() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestSkipped( "This test needs the exif extension." );
+ }
+ if ( !wfDl( 'xml' ) ) {
+ $this->markTestSkipped( "This test needs the xml extension." );
}
+ global $wgShowEXIF;
+ $oldExif = $wgShowEXIF;
+ $wgShowEXIF = true;
$meta = BitmapMetadataHandler::Jpeg( $this->filePath .
'/Xmp-exif-multilingual_test.jpg' );
@@ -32,6 +37,8 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase {
'Did not extract any ImageDescription info?!' );
$this->assertEquals( $expected, $meta['ImageDescription'] );
+
+ $wgShowEXIF = $oldExif;
}
/**
@@ -49,6 +56,16 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase {
$meta['JPEGFileComment'][0] );
}
+ /**
+ * Make sure a bad iptc block doesn't stop the other metadata
+ * from being extracted.
+ */
+ public function testBadIPTC() {
+ $meta = BitmapMetadataHandler::Jpeg( $this->filePath .
+ 'iptc-invalid-psir.jpg' );
+ $this->assertEquals( 'Created with GIMP', $meta['JPEGFileComment'][0] );
+ }
+
public function testIPTCDates() {
$meta = BitmapMetadataHandler::Jpeg( $this->filePath .
'iptc-timetest.jpg' );
@@ -95,6 +112,9 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase {
}
public function testPNGXMP() {
+ if ( !wfDl( 'xml' ) ) {
+ $this->markTestSkipped( "This test needs the xml extension." );
+ }
$handler = new BitmapMetadataHandler();
$result = $handler->png( $this->filePath . 'xmp.png' );
$expected = array (
diff --git a/tests/phpunit/includes/media/BitmapScalingTest.php b/tests/phpunit/includes/media/BitmapScalingTest.php
index 5bcd3232..11d9dc47 100644
--- a/tests/phpunit/includes/media/BitmapScalingTest.php
+++ b/tests/phpunit/includes/media/BitmapScalingTest.php
@@ -3,13 +3,16 @@
class BitmapScalingTest extends MediaWikiTestCase {
function setUp() {
- global $wgMaxImageArea;
+ global $wgMaxImageArea, $wgCustomConvertCommand;
$this->oldMaxImageArea = $wgMaxImageArea;
+ $this->oldCustomConvertCommand = $wgCustomConvertCommand;
$wgMaxImageArea = 1.25e7; // 3500x3500
+ $wgCustomConvertCommand = 'dummy'; // Set so that we don't get client side rendering
}
function tearDown() {
- global $wgMaxImageArea;
+ global $wgMaxImageArea, $wgCustomConvertCommand;
$wgMaxImageArea = $this->oldMaxImageArea;
+ $wgCustomConvertCommand = $this->oldCustomConvertCommand;
}
/**
* @dataProvider provideNormaliseParams
@@ -105,14 +108,22 @@ class BitmapScalingTest extends MediaWikiTestCase {
$file = new FakeDimensionFile( array( 4000, 4000 ) );
$handler = new BitmapHandler;
$params = array( 'width' => '3700' ); // Still bigger than max size.
- $this->assertFalse( $handler->normaliseParams( $file, $params ) );
+ $this->assertEquals( 'TransformParameterError',
+ get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) );
}
function testTooBigMustRenderImage() {
$file = new FakeDimensionFile( array( 4000, 4000 ) );
$file->mustRender = true;
$handler = new BitmapHandler;
$params = array( 'width' => '5000' ); // Still bigger than max size.
- $this->assertFalse( $handler->normaliseParams( $file, $params ) );
+ $this->assertEquals( 'TransformParameterError',
+ get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) );
+ }
+
+ function testImageArea() {
+ $file = new FakeDimensionFile( array( 7, 9 ) );
+ $handler = new BitmapHandler;
+ $this->assertEquals( 63, $handler->getImageArea( $file ) );
}
}
@@ -120,7 +131,8 @@ class FakeDimensionFile extends File {
public $mustRender = false;
public function __construct( $dimensions ) {
- parent::__construct( Title::makeTitle( NS_FILE, 'Test' ), null );
+ parent::__construct( Title::makeTitle( NS_FILE, 'Test' ),
+ new NullRepo( null ) );
$this->dimensions = $dimensions;
}
@@ -133,4 +145,7 @@ class FakeDimensionFile extends File {
public function mustRender() {
return $this->mustRender;
}
+ public function getPath() {
+ return '';
+ }
}
diff --git a/tests/phpunit/includes/media/ExifBitmapTest.php b/tests/phpunit/includes/media/ExifBitmapTest.php
index 4282d3c8..b2f6b7ba 100644
--- a/tests/phpunit/includes/media/ExifBitmapTest.php
+++ b/tests/phpunit/includes/media/ExifBitmapTest.php
@@ -1,4 +1,5 @@
<?php
+
class ExifBitmapTest extends MediaWikiTestCase {
public function setUp() {
@@ -17,42 +18,23 @@ class ExifBitmapTest extends MediaWikiTestCase {
}
public function testIsOldBroken() {
- if ( !wfDl( 'exif' ) ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$res = $this->handler->isMetadataValid( null, ExifBitmapHandler::OLD_BROKEN_FILE );
$this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res );
}
public function testIsBrokenFile() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$res = $this->handler->isMetadataValid( null, ExifBitmapHandler::BROKEN_FILE );
$this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res );
}
public function testIsInvalid() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$res = $this->handler->isMetadataValid( null, 'Something Invalid Here.' );
$this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res );
}
public function testGoodMetadata() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
$res = $this->handler->isMetadataValid( null, $meta );
$this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res );
}
public function testIsOldGood() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}';
$res = $this->handler->isMetadataValid( null, $meta );
$this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res );
@@ -60,10 +42,6 @@ class ExifBitmapTest extends MediaWikiTestCase {
// Handle metadata from paged tiff handler (gotten via instant commons)
// gracefully.
public function testPagedTiffHandledGracefully() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$meta = 'a:6:{s:9:"page_data";a:1:{i:1;a:5:{s:5:"width";i:643;s:6:"height";i:448;s:5:"alpha";s:4:"true";s:4:"page";i:1;s:6:"pixels";i:288064;}}s:10:"page_count";i:1;s:10:"first_page";i:1;s:9:"last_page";i:1;s:4:"exif";a:9:{s:10:"ImageWidth";i:643;s:11:"ImageLength";i:448;s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:4;s:12:"RowsPerStrip";i:50;s:19:"PlanarConfiguration";i:1;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}s:21:"TIFF_METADATA_VERSION";s:3:"1.4";}';
$res = $this->handler->isMetadataValid( null, $meta );
$this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res );
diff --git a/tests/phpunit/includes/media/ExifRotationTest.php b/tests/phpunit/includes/media/ExifRotationTest.php
index 639091d0..25149a05 100644
--- a/tests/phpunit/includes/media/ExifRotationTest.php
+++ b/tests/phpunit/includes/media/ExifRotationTest.php
@@ -5,15 +5,26 @@
*/
class ExifRotationTest extends MediaWikiTestCase {
+ /** track directories creations. Content will be deleted. */
+ private $createdDirs = array();
+
function setUp() {
parent::setUp();
- $this->filePath = dirname( __FILE__ ) . '/../../data/media/';
$this->handler = new BitmapHandler();
- $this->repo = new FSRepo(array(
- 'name' => 'temp',
- 'directory' => wfTempDir() . '/exif-test-' . time() . '-' . mt_rand(),
- 'url' => 'http://localhost/thumbtest'
- ));
+ $filePath = dirname( __FILE__ ) . '/../../data/media';
+
+ $tmpDir = wfTempDir() . '/exif-test-' . time() . '-' . mt_rand();
+ $this->createdDirs[] = $tmpDir;
+
+ $this->repo = new FSRepo( array(
+ 'name' => 'temp',
+ 'url' => 'http://localhost/thumbtest',
+ 'backend' => new FSFileBackend( array(
+ 'name' => 'localtesting',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array( 'temp-thumb' => $tmpDir, 'data' => $filePath )
+ ) )
+ ) );
if ( !wfDl( 'exif' ) ) {
$this->markTestSkipped( "This test needs the exif extension." );
}
@@ -25,10 +36,23 @@ class ExifRotationTest extends MediaWikiTestCase {
$this->oldAuto = $wgEnableAutoRotation;
$wgEnableAutoRotation = true;
}
+
public function tearDown() {
global $wgShowEXIF, $wgEnableAutoRotation;
$wgShowEXIF = $this->show;
$wgEnableAutoRotation = $this->oldAuto;
+
+ $this->tearDownFiles();
+ }
+
+ private function tearDownFiles() {
+ foreach( $this->createdDirs as $dir ) {
+ wfRecursiveRemoveDir( $dir );
+ }
+ }
+
+ function __destruct() {
+ $this->tearDownFiles();
}
/**
@@ -39,7 +63,7 @@ class ExifRotationTest extends MediaWikiTestCase {
if ( !BitmapHandler::canRotate() ) {
$this->markTestSkipped( "This test needs a rasterizer that can auto-rotate." );
}
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $name, $type );
+ $file = $this->dataFile( $name, $type );
$this->assertEquals( $info['width'], $file->getWidth(), "$name: width check" );
$this->assertEquals( $info['height'], $file->getHeight(), "$name: height check" );
}
@@ -66,13 +90,13 @@ class ExifRotationTest extends MediaWikiTestCase {
throw new MWException('bogus test data format ' . $size);
}
- $file = $this->localFile( $name, $type );
- $thumb = $file->transform( $params, File::RENDER_NOW );
+ $file = $this->dataFile( $name, $type );
+ $thumb = $file->transform( $params, File::RENDER_NOW | File::RENDER_FORCE );
$this->assertEquals( $out[0], $thumb->getWidth(), "$name: thumb reported width check for $size" );
$this->assertEquals( $out[1], $thumb->getHeight(), "$name: thumb reported height check for $size" );
- $gis = getimagesize( $thumb->getPath() );
+ $gis = getimagesize( $thumb->getLocalCopyPath() );
if ($out[0] > $info['width']) {
// Physical image won't be scaled bigger than the original.
$this->assertEquals( $info['width'], $gis[0], "$name: thumb actual width check for $size");
@@ -84,8 +108,9 @@ class ExifRotationTest extends MediaWikiTestCase {
}
}
- private function localFile( $name, $type ) {
- return new UnregisteredLocalFile( false, $this->repo, $this->filePath . $name, $type );
+ private function dataFile( $name, $type ) {
+ return new UnregisteredLocalFile( false, $this->repo,
+ "mwstore://localtesting/data/$name", $type );
}
function providerFiles() {
@@ -129,7 +154,7 @@ class ExifRotationTest extends MediaWikiTestCase {
global $wgEnableAutoRotation;
$wgEnableAutoRotation = false;
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $name, $type );
+ $file = $this->dataFile( $name, $type );
$this->assertEquals( $info['width'], $file->getWidth(), "$name: width check" );
$this->assertEquals( $info['height'], $file->getHeight(), "$name: height check" );
@@ -158,13 +183,13 @@ class ExifRotationTest extends MediaWikiTestCase {
throw new MWException('bogus test data format ' . $size);
}
- $file = $this->localFile( $name, $type );
- $thumb = $file->transform( $params, File::RENDER_NOW );
+ $file = $this->dataFile( $name, $type );
+ $thumb = $file->transform( $params, File::RENDER_NOW | File::RENDER_FORCE );
$this->assertEquals( $out[0], $thumb->getWidth(), "$name: thumb reported width check for $size" );
$this->assertEquals( $out[1], $thumb->getHeight(), "$name: thumb reported height check for $size" );
- $gis = getimagesize( $thumb->getPath() );
+ $gis = getimagesize( $thumb->getLocalCopyPath() );
if ($out[0] > $info['width']) {
// Physical image won't be scaled bigger than the original.
$this->assertEquals( $info['width'], $gis[0], "$name: thumb actual width check for $size");
@@ -242,7 +267,7 @@ class ExifRotationTest extends MediaWikiTestCase {
array(
270,
array( self::TEST_HEIGHT, self::TEST_WIDTH )
- ),
+ ),
);
}
}
diff --git a/tests/phpunit/includes/media/ExifTest.php b/tests/phpunit/includes/media/ExifTest.php
index 9b490e92..b39c15e4 100644
--- a/tests/phpunit/includes/media/ExifTest.php
+++ b/tests/phpunit/includes/media/ExifTest.php
@@ -4,6 +4,9 @@ class ExifTest extends MediaWikiTestCase {
public function setUp() {
$this->mediaPath = dirname( __FILE__ ) . '/../../data/media/';
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestSkipped( "This test needs the exif extension." );
+ }
global $wgShowEXIF;
$this->showExif = $wgShowEXIF;
$wgShowEXIF = true;
@@ -14,9 +17,6 @@ class ExifTest extends MediaWikiTestCase {
}
public function testGPSExtraction() {
- if ( !wfDl( 'exif' ) ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$filename = $this->mediaPath . 'exif-gps.jpg';
$seg = JpegMetadataExtractor::segmentSplitter( $filename );
@@ -32,9 +32,6 @@ class ExifTest extends MediaWikiTestCase {
$this->assertEquals( $expected, $data, '', 0.0000000001 );
}
public function testUnicodeUserComment() {
- if ( !wfDl( 'exif' ) ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$filename = $this->mediaPath . 'exif-user-comment.jpg';
$seg = JpegMetadataExtractor::segmentSplitter( $filename );
diff --git a/tests/phpunit/includes/media/FormatMetadataTest.php b/tests/phpunit/includes/media/FormatMetadataTest.php
index db36dea3..8a632f52 100644
--- a/tests/phpunit/includes/media/FormatMetadataTest.php
+++ b/tests/phpunit/includes/media/FormatMetadataTest.php
@@ -1,13 +1,31 @@
<?php
class FormatMetadataTest extends MediaWikiTestCase {
- public function testInvalidDate() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
+ public function setUp() {
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestSkipped( "This test needs the exif extension." );
}
-
- $file = UnregisteredLocalFile::newFromPath( dirname( __FILE__ ) .
- '/../../data/media/broken_exif_date.jpg', 'image/jpeg' );
+ $filePath = dirname( __FILE__ ) . '/../../data/media';
+ $this->backend = new FSFileBackend( array(
+ 'name' => 'localtesting',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array( 'data' => $filePath )
+ ) );
+ $this->repo = new FSRepo( array(
+ 'name' => 'temp',
+ 'url' => 'http://localhost/thumbtest',
+ 'backend' => $this->backend
+ ) );
+ global $wgShowEXIF;
+ $this->show = $wgShowEXIF;
+ $wgShowEXIF = true;
+ }
+ public function tearDown() {
+ global $wgShowEXIF;
+ $wgShowEXIF = $this->show;
+ }
+
+ public function testInvalidDate() {
+ $file = $this->dataFile( 'broken_exif_date.jpg', 'image/jpeg' );
// Throws an error if bug hit
$meta = $file->formatMetadata();
@@ -26,4 +44,9 @@ class FormatMetadataTest extends MediaWikiTestCase {
$meta['visible'][$dateIndex]['value'],
'File with invalid date metadata (bug 29471)' );
}
-} \ No newline at end of file
+
+ private function dataFile( $name, $type ) {
+ return new UnregisteredLocalFile( false, $this->repo,
+ "mwstore://localtesting/data/$name", $type );
+ }
+}
diff --git a/tests/phpunit/includes/media/GIFMetadataExtractorTest.php b/tests/phpunit/includes/media/GIFMetadataExtractorTest.php
index 59b30441..47fc368b 100644
--- a/tests/phpunit/includes/media/GIFMetadataExtractorTest.php
+++ b/tests/phpunit/includes/media/GIFMetadataExtractorTest.php
@@ -63,6 +63,7 @@ class GIFMetadataExtractorTest extends MediaWikiTestCase {
<?xpacket end='w'?>
EOF;
+ $xmpNugget = str_replace( "\r", '', $xmpNugget ); // Windows compat
return array(
array( 'nonanimated.gif', array(
diff --git a/tests/phpunit/includes/media/GIFTest.php b/tests/phpunit/includes/media/GIFTest.php
index 42c25ca5..36658358 100644
--- a/tests/phpunit/includes/media/GIFTest.php
+++ b/tests/phpunit/includes/media/GIFTest.php
@@ -2,12 +2,22 @@
class GIFHandlerTest extends MediaWikiTestCase {
public function setUp() {
- $this->filePath = dirname( __FILE__ ) . '/../../data/media/';
+ $this->filePath = dirname( __FILE__ ) . '/../../data/media';
+ $this->backend = new FSFileBackend( array(
+ 'name' => 'localtesting',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array( 'data' => $this->filePath )
+ ) );
+ $this->repo = new FSRepo( array(
+ 'name' => 'temp',
+ 'url' => 'http://localhost/thumbtest',
+ 'backend' => $this->backend
+ ) );
$this->handler = new GIFHandler();
}
public function testInvalidFile() {
- $res = $this->handler->getMetadata( null, $this->filePath . 'README' );
+ $res = $this->handler->getMetadata( null, $this->filePath . '/README' );
$this->assertEquals( GIFHandler::BROKEN_FILE, $res );
}
/**
@@ -16,8 +26,7 @@ class GIFHandlerTest extends MediaWikiTestCase {
* @dataProvider dataIsAnimated
*/
public function testIsAnimanted( $filename, $expected ) {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
- 'image/gif' );
+ $file = $this->dataFile( $filename, 'image/gif' );
$actual = $this->handler->isAnimatedImage( $file );
$this->assertEquals( $expected, $actual );
}
@@ -34,8 +43,7 @@ class GIFHandlerTest extends MediaWikiTestCase {
* @dataProvider dataGetImageArea
*/
public function testGetImageArea( $filename, $expected ) {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
- 'image/gif' );
+ $file = $this->dataFile( $filename, 'image/gif' );
$actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
$this->assertEquals( $expected, $actual );
}
@@ -71,15 +79,20 @@ class GIFHandlerTest extends MediaWikiTestCase {
* @dataProvider dataGetMetadata
*/
public function testGetMetadata( $filename, $expected ) {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
- 'image/gif' );
- $actual = $this->handler->getMetadata( $file, $this->filePath . $filename );
+ $file = $this->dataFile( $filename, 'image/gif' );
+ $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
$this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
}
+
public function dataGetMetadata() {
return array(
array( 'nonanimated.gif', 'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}' ),
array( 'animated-xmp.gif', 'a:4:{s:10:"frameCount";i:4;s:6:"looped";b:1;s:8:"duration";d:2.399999999999999911182158029987476766109466552734375;s:8:"metadata";a:5:{s:6:"Artist";s:7:"Bawolff";s:16:"ImageDescription";a:2:{s:9:"x-default";s:18:"A file to test GIF";s:5:"_type";s:4:"lang";}s:15:"SublocationDest";s:13:"The interwebs";s:14:"GIFFileComment";a:1:{i:0;s:16:"GIƒ·test·file";}s:15:"_MW_GIF_VERSION";i:1;}}' ),
);
}
+
+ private function dataFile( $name, $type ) {
+ return new UnregisteredLocalFile( false, $this->repo,
+ "mwstore://localtesting/data/$name", $type );
+ }
}
diff --git a/tests/phpunit/includes/media/JpegMetadataExtractorTest.php b/tests/phpunit/includes/media/JpegMetadataExtractorTest.php
index 61fc9c81..f48382a4 100644
--- a/tests/phpunit/includes/media/JpegMetadataExtractorTest.php
+++ b/tests/phpunit/includes/media/JpegMetadataExtractorTest.php
@@ -1,5 +1,5 @@
<?php
-/*
+/**
* @todo Could use a test of extended XMP segments. Hard to find programs that
* create example files, and creating my own in vim propbably wouldn't
* serve as a very good "test". (Adobe photoshop probably creates such files
@@ -59,7 +59,7 @@ class JpegMetadataExtractorTest extends MediaWikiTestCase {
public function testPSIRExtraction() {
$res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
$expected = '50686f746f73686f7020332e30003842494d04040000000000181c02190004746573741c02190003666f6f1c020000020004';
- $this->assertEquals( $expected, bin2hex( $res['PSIR'] ) );
+ $this->assertEquals( $expected, bin2hex( $res['PSIR'][0] ) );
}
public function testXMPExtractionAltAppId() {
$res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' );
@@ -70,19 +70,19 @@ class JpegMetadataExtractorTest extends MediaWikiTestCase {
public function testIPTCHashComparisionNoHash() {
$segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
- $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
$this->assertEquals( 'iptc-no-hash', $res );
}
public function testIPTCHashComparisionBadHash() {
$segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' );
- $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
$this->assertEquals( 'iptc-bad-hash', $res );
}
public function testIPTCHashComparisionGoodHash() {
$segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' );
- $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] );
$this->assertEquals( 'iptc-good-hash', $res );
}
diff --git a/tests/phpunit/includes/media/JpegTest.php b/tests/phpunit/includes/media/JpegTest.php
index 713a3410..ddabf5b8 100644
--- a/tests/phpunit/includes/media/JpegTest.php
+++ b/tests/phpunit/includes/media/JpegTest.php
@@ -3,22 +3,24 @@ class JpegTest extends MediaWikiTestCase {
public function setUp() {
$this->filePath = dirname( __FILE__ ) . '/../../data/media/';
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestSkipped( "This test needs the exif extension." );
+ }
+ global $wgShowEXIF;
+ $this->show = $wgShowEXIF;
+ $wgShowEXIF = true;
+ }
+ public function tearDown() {
+ global $wgShowEXIF;
+ $wgShowEXIF = $this->show;
}
public function testInvalidFile() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$jpeg = new JpegHandler;
$res = $jpeg->getMetadata( null, $this->filePath . 'README' );
$this->assertEquals( ExifBitmapHandler::BROKEN_FILE, $res );
}
public function testJpegMetadataExtraction() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- $this->markTestIncomplete( "This test needs the exif extension." );
- }
$h = new JpegHandler;
$res = $h->getMetadata( null, $this->filePath . 'test.jpg' );
$expected = 'a:7:{s:16:"ImageDescription";s:9:"Test file";s:11:"XResolution";s:4:"72/1";s:11:"YResolution";s:4:"72/1";s:14:"ResolutionUnit";i:2;s:16:"YCbCrPositioning";i:1;s:15:"JPEGFileComment";a:1:{i:0;s:17:"Created with GIMP";}s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
diff --git a/tests/phpunit/includes/ImageFunctionsTest.php b/tests/phpunit/includes/media/MediaHandlerTest.php
index cb7e67f3..99df4f80 100644
--- a/tests/phpunit/includes/ImageFunctionsTest.php
+++ b/tests/phpunit/includes/media/MediaHandlerTest.php
@@ -1,6 +1,6 @@
<?php
-class ImageFunctionsTest extends MediaWikiTestCase {
+class MediaHandlerTest extends MediaWikiTestCase {
function testFitBoxWidth() {
$vals = array(
array(
@@ -32,10 +32,12 @@ class ImageFunctionsTest extends MediaWikiTestCase {
17 => 4,
18 => 4 ) ) );
foreach ( $vals as $row ) {
- extract( $row );
+ $tests = $row['tests'];
+ $height = $row['height'];
+ $width = $row['width'];
foreach ( $tests as $max => $expected ) {
$y = round( $expected * $height / $width );
- $result = wfFitBoxWidth( $width, $height, $max );
+ $result = MediaHandler::fitBoxWidth( $width, $height, $max );
$y2 = round( $result * $height / $width );
$this->assertEquals( $expected,
$result,
diff --git a/tests/phpunit/includes/media/PNGTest.php b/tests/phpunit/includes/media/PNGTest.php
index b782918c..b6f911fd 100644
--- a/tests/phpunit/includes/media/PNGTest.php
+++ b/tests/phpunit/includes/media/PNGTest.php
@@ -2,12 +2,22 @@
class PNGHandlerTest extends MediaWikiTestCase {
public function setUp() {
- $this->filePath = dirname( __FILE__ ) . '/../../data/media/';
+ $this->filePath = dirname( __FILE__ ) . '/../../data/media';
+ $this->backend = new FSFileBackend( array(
+ 'name' => 'localtesting',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array( 'data' => $this->filePath )
+ ) );
+ $this->repo = new FSRepo( array(
+ 'name' => 'temp',
+ 'url' => 'http://localhost/thumbtest',
+ 'backend' => $this->backend
+ ) );
$this->handler = new PNGHandler();
}
public function testInvalidFile() {
- $res = $this->handler->getMetadata( null, $this->filePath . 'README' );
+ $res = $this->handler->getMetadata( null, $this->filePath . '/README' );
$this->assertEquals( PNGHandler::BROKEN_FILE, $res );
}
/**
@@ -16,8 +26,7 @@ class PNGHandlerTest extends MediaWikiTestCase {
* @dataProvider dataIsAnimated
*/
public function testIsAnimanted( $filename, $expected ) {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
- 'image/png' );
+ $file = $this->dataFile( $filename, 'image/png' );
$actual = $this->handler->isAnimatedImage( $file );
$this->assertEquals( $expected, $actual );
}
@@ -34,8 +43,7 @@ class PNGHandlerTest extends MediaWikiTestCase {
* @dataProvider dataGetImageArea
*/
public function testGetImageArea( $filename, $expected ) {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
- 'image/png' );
+ $file = $this->dataFile($filename, 'image/png' );
$actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
$this->assertEquals( $expected, $actual );
}
@@ -73,9 +81,8 @@ class PNGHandlerTest extends MediaWikiTestCase {
* @dataProvider dataGetMetadata
*/
public function testGetMetadata( $filename, $expected ) {
- $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
- 'image/png' );
- $actual = $this->handler->getMetadata( $file, $this->filePath . $filename );
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
// $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
$this->assertEquals( ( $expected ), ( $actual ) );
}
@@ -85,4 +92,9 @@ class PNGHandlerTest extends MediaWikiTestCase {
array( 'xmp.png', 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:1;s:9:"colorType";s:14:"index-coloured";s:8:"metadata";a:2:{s:12:"SerialNumber";s:9:"123456789";s:15:"_MW_PNG_VERSION";i:1;}}' ),
);
}
+
+ private function dataFile( $name, $type ) {
+ return new UnregisteredLocalFile( false, $this->repo,
+ "mwstore://localtesting/data/$name", $type );
+ }
}
diff --git a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php
index c2c81b98..526beae8 100644
--- a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php
+++ b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php
@@ -62,23 +62,33 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
'height' => 60
)
),
+ array(
+ "$base/Toll_Texas_1.svg",
+ // This file triggered bug 31719, needs entity expansion in the xmlns checks
+ array(
+ 'width' => 385,
+ 'height' => 385
+ )
+ )
);
}
function providerSvgFilesWithXMLMetadata() {
$base = dirname( __FILE__ ) . '/../../data/media';
- return array(
- array(
- "$base/US_states_by_total_state_tax_revenue.svg",
- array(
- 'height' => 593,
- 'metadata' =>
+ $metadata =
'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<ns4:Work xmlns:ns4="http://creativecommons.org/ns#" rdf:about="">
<ns5:format xmlns:ns5="http://purl.org/dc/elements/1.1/">image/svg+xml</ns5:format>
<ns5:type xmlns:ns5="http://purl.org/dc/elements/1.1/" rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
</ns4:Work>
- </rdf:RDF>',
+ </rdf:RDF>';
+ $metadata = str_replace( "\r", '', $metadata ); // Windows compat
+ return array(
+ array(
+ "$base/US_states_by_total_state_tax_revenue.svg",
+ array(
+ 'height' => 593,
+ 'metadata' => $metadata,
'width' => 959
)
),
diff --git a/tests/phpunit/includes/media/TiffTest.php b/tests/phpunit/includes/media/TiffTest.php
index 0a7e8e8c..d4cf503b 100644
--- a/tests/phpunit/includes/media/TiffTest.php
+++ b/tests/phpunit/includes/media/TiffTest.php
@@ -15,16 +15,15 @@ class TiffTest extends MediaWikiTestCase {
}
public function testInvalidFile() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
+ if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
$res = $this->handler->getMetadata( null, $this->filePath . 'README' );
$this->assertEquals( ExifBitmapHandler::BROKEN_FILE, $res );
}
+
public function testTiffMetadataExtraction() {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
+ if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
$res = $this->handler->getMetadata( null, $this->filePath . 'test.tiff' );
diff --git a/tests/phpunit/includes/media/XMPTest.php b/tests/phpunit/includes/media/XMPTest.php
index d1ec4767..c952b23c 100644
--- a/tests/phpunit/includes/media/XMPTest.php
+++ b/tests/phpunit/includes/media/XMPTest.php
@@ -1,6 +1,12 @@
<?php
class XMPTest extends MediaWikiTestCase {
+ function setUp() {
+ if ( !wfDl( 'xml' ) ) {
+ $this->markTestSkipped( 'Requires libxml to do XMP parsing' );
+ }
+ }
+
/**
* Put XMP in, compare what comes out...
*
@@ -11,9 +17,6 @@ class XMPTest extends MediaWikiTestCase {
* @dataProvider dataXMPParse
*/
public function testXMPParse( $xmp, $expected, $info ) {
- if ( !function_exists( 'xml_parser_create_ns' ) ) {
- $this->markIncomplete( 'Requires libxml to do XMP parsing' );
- }
if ( !is_string( $xmp ) || !is_array( $expected ) ) {
throw new Exception( "Invalid data provided to " . __METHOD__ );
}
diff --git a/tests/phpunit/includes/media/XMPValidateTest.php b/tests/phpunit/includes/media/XMPValidateTest.php
new file mode 100644
index 00000000..e2bb8d8d
--- /dev/null
+++ b/tests/phpunit/includes/media/XMPValidateTest.php
@@ -0,0 +1,47 @@
+<?php
+class XMPValidateTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider providerDate
+ */
+ function testValidateDate( $value, $expected ) {
+ // The method should modify $value.
+ XMPValidate::validateDate( array(), $value, true );
+ $this->assertEquals( $expected, $value );
+ }
+
+ function providerDate() {
+ /* For reference valid date formats are:
+ * YYYY
+ * YYYY-MM
+ * YYYY-MM-DD
+ * YYYY-MM-DDThh:mmTZD
+ * YYYY-MM-DDThh:mm:ssTZD
+ * YYYY-MM-DDThh:mm:ss.sTZD
+ * (Time zone is optional)
+ */
+ return array(
+ array( '1992', '1992' ),
+ array( '1992-04', '1992:04' ),
+ array( '1992-02-01', '1992:02:01' ),
+ array( '2011-09-29', '2011:09:29' ),
+ array( '1982-12-15T20:12', '1982:12:15 20:12' ),
+ array( '1982-12-15T20:12Z', '1982:12:15 20:12' ),
+ array( '1982-12-15T20:12+02:30', '1982:12:15 22:42' ),
+ array( '1982-12-15T01:12-02:30', '1982:12:14 22:42' ),
+ array( '1982-12-15T20:12:11', '1982:12:15 20:12:11' ),
+ array( '1982-12-15T20:12:11Z', '1982:12:15 20:12:11' ),
+ array( '1982-12-15T20:12:11+01:10', '1982:12:15 21:22:11' ),
+ array( '2045-12-15T20:12:11', '2045:12:15 20:12:11' ),
+ array( '1867-06-01T15:00:00', '1867:06:01 15:00:00' ),
+ /* some invalid ones */
+ array( '2001--12', null ),
+ array( '2001-5-12', null ),
+ array( '2001-5-12TZ', null ),
+ array( '2001-05-12T15', null ),
+ array( '2001-12T15:13', null ),
+ );
+
+ }
+
+}
diff --git a/tests/phpunit/includes/parser/MagicVariableTest.php b/tests/phpunit/includes/parser/MagicVariableTest.php
index a47653e3..31645313 100644
--- a/tests/phpunit/includes/parser/MagicVariableTest.php
+++ b/tests/phpunit/includes/parser/MagicVariableTest.php
@@ -6,8 +6,8 @@
* As of february 2011, it only tests some revisions and date related
* magic variables.
*
- * @author Ashar Voultoiz
- * @copyright Copyright © 2011, Ashar Voultoiz
+ * @author Antoine Musso
+ * @copyright Copyright © 2011, Antoine Musso
* @file
*/
@@ -38,6 +38,12 @@ class MagicVariableTest extends MediaWikiTestCase {
# initialize parser output
$this->testParser->clearState();
+
+ # Needs a title to do magic word stuff
+ $title = Title::newFromText( 'Tests' );
+ $title->mRedirect = false; # Else it needs a db connection just to check if it's a redirect (when deciding the page language)
+
+ $this->testParser->setTitle( $title );
}
/** destroy parser (TODO: is it really neded?)*/
diff --git a/tests/phpunit/includes/parser/MediaWikiParserTest.php b/tests/phpunit/includes/parser/MediaWikiParserTest.php
index 18510d9a..816c017a 100644
--- a/tests/phpunit/includes/parser/MediaWikiParserTest.php
+++ b/tests/phpunit/includes/parser/MediaWikiParserTest.php
@@ -1,10 +1,8 @@
<?php
-
-require_once( dirname( __FILE__ ) . '/ParserHelpers.php' );
require_once( dirname( __FILE__ ) . '/NewParserTest.php' );
/**
- * The UnitTest must be either a class that inherits from PHPUnit_Framework_TestCase
+ * The UnitTest must be either a class that inherits from MediaWikiTestCase
* or a class that provides a public static suite() method which returns
* an PHPUnit_Framework_Test object
*
@@ -20,9 +18,13 @@ class MediaWikiParserTest {
foreach ( $wgParserTestFiles as $filename ) {
$testsName = basename( $filename, '.txt' );
- $className = /*ucfirst( basename( dirname( $filename ) ) ) .*/ ucfirst( basename( $filename, '.txt' ) );
+ /* This used to be ucfirst( basename( dirname( $filename ) ) )
+ * and then was ucfirst( basename( $filename, '.txt' )
+ * but that didn't work with names like foo.tests.txt
+ */
+ $className = str_replace( '.', '_', ucfirst( basename( $filename, '.txt' ) ) );
- eval( "/** @group Database\n@group Parser\n*/ class $className extends NewParserTest { protected \$file = \"" . addslashes( $filename ) . "\"; } " );
+ eval( "/** @group Database\n@group Parser\n*/ class $className extends NewParserTest { protected \$file = '" . strtr( $filename, array( "'" => "\\'", '\\' => '\\\\' ) ) . "'; } " );
$parserTester = new $className( $testsName );
$suite->addTestSuite( new ReflectionClass ( $parserTester ) );
diff --git a/tests/phpunit/includes/parser/NewParserTest.php b/tests/phpunit/includes/parser/NewParserTest.php
index f4d5f757..d1221ca8 100644
--- a/tests/phpunit/includes/parser/NewParserTest.php
+++ b/tests/phpunit/includes/parser/NewParserTest.php
@@ -8,13 +8,12 @@
* @group Stub
*/
class NewParserTest extends MediaWikiTestCase {
-
static protected $articles = array(); // Array of test articles defined by the tests
/* The dataProvider is run on a different instance than the test, so it must be static
* When running tests from several files, all tests will see all articles.
*/
-
- public $uploadDir;
+ static protected $backendToUse;
+
public $keepUploads = false;
public $runDisabled = false;
public $regex = '';
@@ -31,16 +30,12 @@ class NewParserTest extends MediaWikiTestCase {
public $memoryLimit = 50;
protected $file = false;
-
- /*function __construct($a = null,$b = array(),$c = null ) {
- parent::__construct($a,$b,$c);
- }*/
-
+
function setUp() {
global $wgContLang, $wgNamespaceProtection, $wgNamespaceAliases;
global $wgHooks, $IP;
$wgContLang = Language::factory( 'en' );
-
+
//Setup CLI arguments
if ( $this->getCliArg( 'regex=' ) ) {
$this->regex = $this->getCliArg( 'regex=' );
@@ -48,11 +43,11 @@ class NewParserTest extends MediaWikiTestCase {
# Matches anything
$this->regex = '';
}
-
+
$this->keepUploads = $this->getCliArg( 'keep-uploads' );
-
+
$tmpGlobals = array();
-
+
$tmpGlobals['wgScript'] = '/index.php';
$tmpGlobals['wgScriptPath'] = '/';
$tmpGlobals['wgArticlePath'] = '/wiki/$1';
@@ -60,15 +55,14 @@ class NewParserTest extends MediaWikiTestCase {
$tmpGlobals['wgStylePath'] = '/skins';
$tmpGlobals['wgThumbnailScriptPath'] = false;
$tmpGlobals['wgLocalFileRepo'] = array(
- 'class' => 'LocalRepo',
- 'name' => 'local',
- 'directory' => wfTempDir() . '/test-repo',
- 'url' => 'http://example.com/images',
- 'deletedDir' => wfTempDir() . '/test-repo/delete',
- 'hashLevels' => 2,
+ 'class' => 'LocalRepo',
+ 'name' => 'local',
+ 'url' => 'http://example.com/images',
+ 'hashLevels' => 2,
'transformVia404' => false,
+ 'backend' => 'local-backend'
);
-
+ $tmpGlobals['wgForeignFileRepos'] = array();
$tmpGlobals['wgEnableParserCache'] = false;
$tmpGlobals['wgHooks'] = $wgHooks;
$tmpGlobals['wgDeferredUpdateList'] = array();
@@ -79,16 +73,16 @@ class NewParserTest extends MediaWikiTestCase {
// $tmpGlobals['wgContLang'] = new StubContLang;
$tmpGlobals['wgUser'] = new User;
$context = new RequestContext();
- $tmpGlobals['wgLang'] = $context->getLang();
+ $tmpGlobals['wgLang'] = $context->getLanguage();
$tmpGlobals['wgOut'] = $context->getOutput();
$tmpGlobals['wgParser'] = new StubObject( 'wgParser', $GLOBALS['wgParserConf']['class'], array( $GLOBALS['wgParserConf'] ) );
- $tmpGlobals['wgRequest'] = new WebRequest;
+ $tmpGlobals['wgRequest'] = $context->getRequest();
if ( $GLOBALS['wgStyleDirectory'] === false ) {
$tmpGlobals['wgStyleDirectory'] = "$IP/skins";
}
-
-
+
+
foreach ( $tmpGlobals as $var => $val ) {
if ( array_key_exists( $var, $GLOBALS ) ) {
$this->savedInitialGlobals[$var] = $GLOBALS[$var];
@@ -96,31 +90,38 @@ class NewParserTest extends MediaWikiTestCase {
$GLOBALS[$var] = $val;
}
-
+
$this->savedWeirdGlobals['mw_namespace_protection'] = $wgNamespaceProtection[NS_MEDIAWIKI];
$this->savedWeirdGlobals['image_alias'] = $wgNamespaceAliases['Image'];
$this->savedWeirdGlobals['image_talk_alias'] = $wgNamespaceAliases['Image_talk'];
-
+
$wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
$wgNamespaceAliases['Image'] = NS_FILE;
$wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
-
}
-
+
public function tearDown() {
-
foreach ( $this->savedInitialGlobals as $var => $val ) {
$GLOBALS[$var] = $val;
}
-
+
global $wgNamespaceProtection, $wgNamespaceAliases;
-
+
$wgNamespaceProtection[NS_MEDIAWIKI] = $this->savedWeirdGlobals['mw_namespace_protection'];
$wgNamespaceAliases['Image'] = $this->savedWeirdGlobals['image_alias'];
$wgNamespaceAliases['Image_talk'] = $this->savedWeirdGlobals['image_talk_alias'];
+
+ // Restore backends
+ RepoGroup::destroySingleton();
+ FileBackendGroup::destroySingleton();
}
-
+
function addDBData() {
+ $this->tablesUsed[] = 'site_stats';
+ $this->tablesUsed[] = 'interwiki';
+ # disabled for performance
+ #$this->tablesUsed[] = 'image';
+
# Hack: insert a few Wikipedia in-project interwiki prefixes,
# for testing inter-language links
$this->db->insert( 'interwiki', array(
@@ -158,17 +159,14 @@ class NewParserTest extends MediaWikiTestCase {
* @todo Fixme! Why are we inserting duplicate data here? Shouldn't
* need this IGNORE or shouldn't need the insert at all.
*/
- ), __METHOD__, array( 'IGNORE' ) );
+ ), __METHOD__, array( 'IGNORE' )
+ );
# Update certain things in site_stats
- $this->db->insert( 'site_stats',
+ $this->db->insert( 'site_stats',
array( 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ),
- __METHOD__,
- /**
- * @todo Fixme! Same as above!
- */
- array( 'IGNORE' )
+ __METHOD__
);
# Reinitialise the LocalisationCache to match the database state
@@ -177,50 +175,66 @@ class NewParserTest extends MediaWikiTestCase {
# Clear the message cache
MessageCache::singleton()->clear();
- $this->uploadDir = $this->setupUploadDir();
-
$user = User::newFromId( 0 );
LinkCache::singleton()->clear(); # Avoids the odd failure at creating the nullRevision
-
+
+ # Upload DB table entries for files.
+ # We will upload the actual files later. Note that if anything causes LocalFile::load()
+ # to be triggered before then, it will break via maybeUpgrade() setting the fileExists
+ # member to false and storing it in cache.
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.jpg' ) );
- $image->recordUpload2( '', 'Upload of some lame file', 'Some lame file', array(
- 'size' => 12345,
- 'width' => 1941,
- 'height' => 220,
- 'bits' => 24,
- 'media_type' => MEDIATYPE_BITMAP,
- 'mime' => 'image/jpeg',
- 'metadata' => serialize( array() ),
- 'sha1' => wfBaseConvert( '', 16, 36, 31 ),
- 'fileExists' => true
- ), $this->db->timestamp( '20010115123500' ), $user );
+ if ( !$this->db->selectField( 'image', '1', array( 'img_name' => $image->getName() ) ) ) {
+ $image->recordUpload2(
+ '', // archive name
+ 'Upload of some lame file',
+ 'Some lame file',
+ array(
+ 'size' => 12345,
+ 'width' => 1941,
+ 'height' => 220,
+ 'bits' => 24,
+ 'media_type' => MEDIATYPE_BITMAP,
+ 'mime' => 'image/jpeg',
+ 'metadata' => serialize( array() ),
+ 'sha1' => wfBaseConvert( '', 16, 36, 31 ),
+ 'fileExists' => true ),
+ $this->db->timestamp( '20010115123500' ), $user
+ );
+ }
# This image will be blacklisted in [[MediaWiki:Bad image list]]
$image = wfLocalFile( Title::makeTitle( NS_FILE, 'Bad.jpg' ) );
- $image->recordUpload2( '', 'zomgnotcensored', 'Borderline image', array(
- 'size' => 12345,
- 'width' => 320,
- 'height' => 240,
- 'bits' => 24,
- 'media_type' => MEDIATYPE_BITMAP,
- 'mime' => 'image/jpeg',
- 'metadata' => serialize( array() ),
- 'sha1' => wfBaseConvert( '', 16, 36, 31 ),
- 'fileExists' => true
- ), $this->db->timestamp( '20010115123500' ), $user );
-
+ if ( !$this->db->selectField( 'image', '1', array( 'img_name' => $image->getName() ) ) ) {
+ $image->recordUpload2(
+ '', // archive name
+ 'zomgnotcensored',
+ 'Borderline image',
+ array(
+ 'size' => 12345,
+ 'width' => 320,
+ 'height' => 240,
+ 'bits' => 24,
+ 'media_type' => MEDIATYPE_BITMAP,
+ 'mime' => 'image/jpeg',
+ 'metadata' => serialize( array() ),
+ 'sha1' => wfBaseConvert( '', 16, 36, 31 ),
+ 'fileExists' => true ),
+ $this->db->timestamp( '20010115123500' ), $user
+ );
+ }
}
-
-
-
-
+
+
+
+
//ParserTest setup/teardown functions
-
+
/**
* Set up the global variables for a consistent environment for each test.
* Ideally this should replace the global configuration entirely.
*/
protected function setupGlobals( $opts = '', $config = '' ) {
+ global $wgFileBackends;
# Find out values for some special options.
$lang =
self::getOptionValue( 'language', $opts, 'en' );
@@ -231,19 +245,48 @@ class NewParserTest extends MediaWikiTestCase {
$linkHolderBatchSize =
self::getOptionValue( 'wgLinkHolderBatchSize', $opts, 1000 );
+ $uploadDir = $this->getUploadDir();
+ if ( $this->getCliArg( 'use-filebackend=' ) ) {
+ if ( self::$backendToUse ) {
+ $backend = self::$backendToUse;
+ } else {
+ $name = $this->getCliArg( 'use-filebackend=' );
+ $useConfig = array();
+ foreach ( $wgFileBackends as $conf ) {
+ if ( $conf['name'] == $name ) {
+ $useConfig = $conf;
+ }
+ }
+ $useConfig['name'] = 'local-backend'; // swap name
+ $class = $conf['class'];
+ self::$backendToUse = new $class( $useConfig );
+ $backend = self::$backendToUse;
+ }
+ } else {
+ $backend = new FSFileBackend( array(
+ 'name' => 'local-backend',
+ 'lockManager' => 'nullLockManager',
+ 'containerPaths' => array(
+ 'local-public' => "$uploadDir",
+ 'local-thumb' => "$uploadDir/thumb",
+ )
+ ) );
+ }
+
$settings = array(
'wgServer' => 'http://Britney-Spears',
'wgScript' => '/index.php',
'wgScriptPath' => '/',
'wgArticlePath' => '/wiki/$1',
+ 'wgExtensionAssetsPath' => '/extensions',
'wgActionPaths' => array(),
'wgLocalFileRepo' => array(
- 'class' => 'LocalRepo',
- 'name' => 'local',
- 'directory' => $this->uploadDir,
- 'url' => 'http://example.com/images',
- 'hashLevels' => 2,
+ 'class' => 'LocalRepo',
+ 'name' => 'local',
+ 'url' => 'http://example.com/images',
+ 'hashLevels' => 2,
'transformVia404' => false,
+ 'backend' => $backend
),
'wgEnableUploads' => self::getOptionValue( 'wgEnableUploads', $opts, true ),
'wgStylePath' => '/skins',
@@ -262,7 +305,7 @@ class NewParserTest extends MediaWikiTestCase {
'wgThumbnailScriptPath' => false,
'wgUseImageResize' => false,
'wgUseTeX' => isset( $opts['math'] ),
- 'wgMathDirectory' => $this->uploadDir . '/math',
+ 'wgMathDirectory' => $uploadDir . '/math',
'wgLocaltimezone' => 'UTC',
'wgAllowExternalImages' => true,
'wgUseTidy' => false,
@@ -283,6 +326,7 @@ class NewParserTest extends MediaWikiTestCase {
'wgExternalLinkTarget' => false,
'wgAlwaysUseTidy' => false,
'wgHtml5' => true,
+ 'wgCleanupPresentationalAttributes' => true,
'wgWellFormedXml' => true,
'wgAllowMicrodataAttributes' => true,
'wgAdaptiveMessageCache' => true,
@@ -312,39 +356,41 @@ class NewParserTest extends MediaWikiTestCase {
$langObj = Language::factory( $lang );
$GLOBALS['wgContLang'] = $langObj;
$context = new RequestContext();
- $GLOBALS['wgLang'] = $context->getLang();
+ $GLOBALS['wgLang'] = $context->getLanguage();
$GLOBALS['wgMemc'] = new EmptyBagOStuff;
$GLOBALS['wgOut'] = $context->getOutput();
+ $GLOBALS['wgUser'] = $context->getUser();
global $wgHooks;
$wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
- $wgHooks['ParserTestParser'][] = 'ParserTestStaticParserHook::setup';
$wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
MagicWord::clearCache();
+ RepoGroup::destroySingleton();
+ FileBackendGroup::destroySingleton();
+
+ # Create dummy files in storage
+ $this->setupUploads();
# Publish the articles after we have the final language set
$this->publishTestArticles();
# The entries saved into RepoGroup cache with previous globals will be wrong.
RepoGroup::destroySingleton();
+ FileBackendGroup::destroySingleton();
MessageCache::singleton()->destroyInstance();
-
- global $wgUser;
- $wgUser = new User();
+
+ return $context;
}
/**
- * Create a dummy uploads directory which will contain a couple
- * of files in order to pass existence tests.
+ * Get an FS upload directory (only applies to FSFileBackend)
*
* @return String: the directory
*/
- protected function setupUploadDir() {
- global $IP;
-
+ protected function getUploadDir() {
if ( $this->keepUploads ) {
$dir = wfTempDir() . '/mwParser-images';
@@ -361,70 +407,67 @@ class NewParserTest extends MediaWikiTestCase {
return $dir;
}
- wfMkdirParents( $dir . '/3/3a' );
- copy( "$IP/skins/monobook/headbg.jpg", "$dir/3/3a/Foobar.jpg" );
- wfMkdirParents( $dir . '/0/09' );
- copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" );
-
return $dir;
}
-
+
+ /**
+ * Create a dummy uploads directory which will contain a couple
+ * of files in order to pass existence tests.
+ *
+ * @return String: the directory
+ */
+ protected function setupUploads() {
+ global $IP;
+
+ $base = $this->getBaseDir();
+ $backend = RepoGroup::singleton()->getLocalRepo()->getBackend();
+ $backend->prepare( array( 'dir' => "$base/local-public/3/3a" ) );
+ $backend->store( array(
+ 'src' => "$IP/skins/monobook/headbg.jpg", 'dst' => "$base/local-public/3/3a/Foobar.jpg"
+ ) );
+ $backend->prepare( array( 'dir' => "$base/local-public/0/09" ) );
+ $backend->store( array(
+ 'src' => "$IP/skins/monobook/headbg.jpg", 'dst' => "$base/local-public/0/09/Bad.jpg"
+ ) );
+ }
+
/**
* Restore default values and perform any necessary clean-up
* after each test runs.
*/
protected function teardownGlobals() {
- RepoGroup::destroySingleton();
- LinkCache::singleton()->clear();
+ $this->teardownUploads();
foreach ( $this->savedGlobals as $var => $val ) {
$GLOBALS[$var] = $val;
}
-
- $this->teardownUploadDir( $this->uploadDir );
+
+ RepoGroup::destroySingleton();
+ LinkCache::singleton()->clear();
}
/**
* Remove the dummy uploads directory
*/
- private function teardownUploadDir( $dir ) {
+ private function teardownUploads() {
if ( $this->keepUploads ) {
return;
}
+ $base = $this->getBaseDir();
// delete the files first, then the dirs.
self::deleteFiles(
array (
- "$dir/3/3a/Foobar.jpg",
- "$dir/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg",
- "$dir/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg",
- "$dir/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg",
- "$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg",
-
- "$dir/0/09/Bad.jpg",
+ "$base/local-public/3/3a/Foobar.jpg",
+ "$base/local-thumb/3/3a/Foobar.jpg/180px-Foobar.jpg",
+ "$base/local-thumb/3/3a/Foobar.jpg/200px-Foobar.jpg",
+ "$base/local-thumb/3/3a/Foobar.jpg/640px-Foobar.jpg",
+ "$base/local-thumb/3/3a/Foobar.jpg/120px-Foobar.jpg",
- "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png",
- )
- );
+ "$base/local-public/0/09/Bad.jpg",
+ "$base/local-thumb/0/09/Bad.jpg",
- self::deleteDirs(
- array (
- "$dir/3/3a",
- "$dir/3",
- "$dir/thumb/6/65",
- "$dir/thumb/6",
- "$dir/thumb/3/3a/Foobar.jpg",
- "$dir/thumb/3/3a",
- "$dir/thumb/3",
-
- "$dir/0/09/",
- "$dir/0/",
- "$dir/thumb",
- "$dir/math/f/a/5",
- "$dir/math/f/a",
- "$dir/math/f",
- "$dir/math",
- "$dir",
+ "$base/local-public/math/f/a/5/fa50b8b616463173474302ca3e63586b.png",
)
);
}
@@ -434,25 +477,24 @@ class NewParserTest extends MediaWikiTestCase {
* @param $files Array: full paths to files to delete.
*/
private static function deleteFiles( $files ) {
+ $backend = RepoGroup::singleton()->getLocalRepo()->getBackend();
foreach ( $files as $file ) {
- if ( file_exists( $file ) ) {
- unlink( $file );
+ $backend->delete( array( 'src' => $file ), array( 'force' => 1 ) );
+ }
+ foreach ( $files as $file ) {
+ $tmp = $file;
+ while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) {
+ if ( !$backend->clean( array( 'dir' => $tmp ) )->isOK() ) {
+ break;
+ }
}
}
}
- /**
- * Delete the specified directories, if they exist. Must be empty.
- * @param $dirs Array: full paths to directories to delete.
- */
- private static function deleteDirs( $dirs ) {
- foreach ( $dirs as $dir ) {
- if ( is_dir( $dir ) ) {
- rmdir( $dir );
- }
- }
+ protected function getBaseDir() {
+ return 'mwstore://local-backend';
}
-
+
public function parserTestProvider() {
if ( $this->file === false ) {
global $wgParserTestFiles;
@@ -460,25 +502,29 @@ class NewParserTest extends MediaWikiTestCase {
}
return new TestFileIterator( $this->file, $this );
}
-
+
/**
* Set the file from whose tests will be run by this instance
*/
public function setParserTestFile( $filename ) {
$this->file = $filename;
}
-
+
/** @dataProvider parserTestProvider */
public function testParserTest( $desc, $input, $result, $opts, $config ) {
- if ( !preg_match( '/' . $this->regex . '/', $desc ) ) return; //$this->markTestSkipped( 'Filtered out by the user' );
+ if ( $this->regex != '' && !preg_match( '/' . $this->regex . '/', $desc ) ) {
+ $this->assertTrue( true ); // XXX: don't flood output with "test made no assertions"
+ //$this->markTestSkipped( 'Filtered out by the user' );
+ return;
+ }
wfDebug( "Running parser test: $desc\n" );
$opts = $this->parseOptions( $opts );
- $this->setupGlobals( $opts, $config );
+ $context = $this->setupGlobals( $opts, $config );
- $user = new User();
- $options = ParserOptions::newFromUser( $user );
+ $user = $context->getUser();
+ $options = ParserOptions::newFromContext( $context );
if ( isset( $opts['title'] ) ) {
$titleText = $opts['title'];
@@ -490,7 +536,7 @@ class NewParserTest extends MediaWikiTestCase {
$local = isset( $opts['local'] );
$preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null;
$parser = $this->getParser( $preprocessor );
-
+
$title = Title::newFromText( $titleText );
if ( isset( $opts['pst'] ) ) {
@@ -505,8 +551,7 @@ class NewParserTest extends MediaWikiTestCase {
$replace = $opts['replace'][1];
$out = $parser->replaceSection( $input, $section, $replace );
} elseif ( isset( $opts['comment'] ) ) {
- $linker = $user->getSkin();
- $out = $linker->formatComment( $input, $title, $local );
+ $out = Linker::formatComment( $input, $title, $local );
} elseif ( isset( $opts['preload'] ) ) {
$out = $parser->getpreloadText( $input, $title, $options );
} else {
@@ -524,10 +569,9 @@ class NewParserTest extends MediaWikiTestCase {
if ( isset( $opts['ill'] ) ) {
$out = $this->tidy( implode( ' ', $output->getLanguageLinks() ) );
} elseif ( isset( $opts['cat'] ) ) {
- global $wgOut;
-
- $wgOut->addCategoryLinks( $output->getCategories() );
- $cats = $wgOut->getCategoryLinks();
+ $outputPage = $context->getOutput();
+ $outputPage->addCategoryLinks( $output->getCategories() );
+ $cats = $outputPage->getCategoryLinks();
if ( isset( $cats['normal'] ) ) {
$out = $this->tidy( implode( ' ', $cats['normal'] ) );
@@ -541,38 +585,41 @@ class NewParserTest extends MediaWikiTestCase {
}
$this->teardownGlobals();
-
+
$this->assertEquals( $result, $out, $desc );
}
-
+
/**
* Run a fuzz test series
* Draw input from a set of test files
+ *
+ * @todo @fixme Needs some work to not eat memory until the world explodes
+ *
+ * @group ParserFuzz
*/
function testFuzzTests() {
-
- $this->markTestIncomplete( "Somebody is serializing PDO objects, that's a no-no" );
-
global $wgParserTestFiles;
-
+
$files = $wgParserTestFiles;
-
+
if( $this->getCliArg( 'file=' ) ) {
$files = array( $this->getCliArg( 'file=' ) );
}
-
+
$dict = $this->getFuzzInput( $files );
$dictSize = strlen( $dict );
$logMaxLength = log( $this->maxFuzzTestLength );
+ ini_set( 'memory_limit', $this->memoryLimit * 1048576 );
+
$user = new User;
$opts = ParserOptions::newFromUser( $user );
$title = Title::makeTitle( NS_MAIN, 'Parser_test' );
$id = 1;
-
+
while ( true ) {
-
+
// Generate test input
mt_srand( ++$this->fuzzSeed );
$totalLength = mt_rand( 1, $this->maxFuzzTestLength );
@@ -594,7 +641,7 @@ class NewParserTest extends MediaWikiTestCase {
$this->assertTrue( true, "Test $id, fuzz seed {$this->fuzzSeed}" );
} catch ( Exception $exception ) {
$input_dump = sprintf( "string(%d) \"%s\"\n", strlen( $input ), $input );
-
+
$this->assertTrue( false, "Test $id, fuzz seed {$this->fuzzSeed}. \n\nInput: $input_dump\n\nError: {$exception->getMessage()}\n\nBacktrace: {$exception->getTraceAsString()}" );
}
@@ -611,18 +658,18 @@ class NewParserTest extends MediaWikiTestCase {
foreach ( $memStats as $name => $usage ) {
$ret .= "$name: $usage\n";
}
-
+
throw new MWException( $ret );
}
}
-
+
$id++;
-
+
}
}
//Various getter functions
-
+
/**
* Get an input dictionary from a set of parser test files
*/
@@ -640,7 +687,7 @@ class NewParserTest extends MediaWikiTestCase {
return $dict;
}
-
+
/**
* Get a memory usage breakdown
*/
@@ -675,7 +722,7 @@ class NewParserTest extends MediaWikiTestCase {
return $memStats;
}
-
+
/**
* Get a Parser object
*/
@@ -693,23 +740,20 @@ class NewParserTest extends MediaWikiTestCase {
//Various action functions
public function addArticle( $name, $text, $line ) {
- self::$articles[$name] = $text;
- }
-
+ self::$articles[$name] = array( $text, $line );
+ }
+
public function publishTestArticles() {
if ( empty( self::$articles ) ) {
return;
}
- foreach ( self::$articles as $name => $text ) {
- $title = Title::newFromText( $name );
-
- if ( $title->getArticleID( Title::GAID_FOR_UPDATE ) == 0 ) {
- ParserTest::addArticle( $name, $text );
- }
+ foreach ( self::$articles as $name => $info ) {
+ list( $text, $line ) = $info;
+ ParserTest::addArticle( $name, $text, $line, 'ignoreduplicate' );
}
}
-
+
/**
* Steal a callback function from the primary parser, save it for
* application to our scary parser. If the hook is not installed,
@@ -730,8 +774,8 @@ class NewParserTest extends MediaWikiTestCase {
return isset( $wgParser->mFunctionHooks[$name] );
}
//Various "cleanup" functions
-
- /*
+
+ /**
* Run the "tidy" command on text if the $wgUseTidy
* global is true
*
@@ -747,7 +791,7 @@ class NewParserTest extends MediaWikiTestCase {
return $text;
}
-
+
/**
* Remove last character if it is a newline
*/
@@ -760,12 +804,8 @@ class NewParserTest extends MediaWikiTestCase {
}
}
- public function showRunFile( $file ) {
- /* NOP */
- }
-
//Test options parser functions
-
+
protected function parseOptions( $instring ) {
$opts = array();
// foo
@@ -820,7 +860,7 @@ class NewParserTest extends MediaWikiTestCase {
}
return $opts;
}
-
+
protected function cleanupOption( $opt ) {
if ( substr( $opt, 0, 1 ) == '"' ) {
return substr( $opt, 1, -1 );
@@ -831,7 +871,7 @@ class NewParserTest extends MediaWikiTestCase {
}
return $opt;
}
-
+
/**
* Use a regex to find out the value of an option
* @param $key String: name of option val to retrieve
diff --git a/tests/phpunit/includes/parser/ParserHelpers.php b/tests/phpunit/includes/parser/ParserHelpers.php
deleted file mode 100644
index 4a6ce7c4..00000000
--- a/tests/phpunit/includes/parser/ParserHelpers.php
+++ /dev/null
@@ -1,136 +0,0 @@
-<?php
-
-class PHPUnitParserTest extends ParserTest {
- function showTesting( $desc ) {
- /* Do nothing since we don't want to show info during PHPUnit testing. */
- }
-
- public function showSuccess( $desc ) {
- PHPUnit_Framework_Assert::assertTrue( true, $desc );
- return true;
- }
-
- public function showFailure( $desc, $expected, $got ) {
- PHPUnit_Framework_Assert::assertEquals( $expected, $got, $desc );
- return false;
- }
-
- public function setupRecorder( $options ) {
- $this->recorder = new PHPUnitTestRecorder( $this );
- }
-}
-
-class ParserUnitTest extends MediaWikiTestCase {
- private $test = "";
-
- public function __construct( $suite, $test = null ) {
- parent::__construct();
- $this->test = $test;
- $this->suite = $suite;
- }
-
- function count() { return 1; }
-
- public function run( PHPUnit_Framework_TestResult $result = null ) {
- PHPUnit_Framework_Assert::resetCount();
- if ( $result === NULL ) {
- $result = new PHPUnit_Framework_TestResult;
- }
-
- $this->suite->publishTestArticles(); // Add articles needed by the tests.
- $backend = new ParserTestSuiteBackend;
- $result->startTest( $this );
-
- // Support the transition to PHPUnit 3.5 where PHPUnit_Util_Timer is replaced with PHP_Timer
- if ( class_exists( 'PHP_Timer' ) ) {
- PHP_Timer::start();
- } else {
- PHPUnit_Util_Timer::start();
- }
-
- $r = false;
- try {
- # Run the test.
- # On failure, the subclassed backend will throw an exception with
- # the details.
- $pt = new PHPUnitParserTest;
- $r = $pt->runTest( $this->test['test'], $this->test['input'],
- $this->test['result'], $this->test['options'], $this->test['config']
- );
- }
- catch ( PHPUnit_Framework_AssertionFailedError $e ) {
-
- // PHPUnit_Util_Timer -> PHP_Timer support (see above)
- if ( class_exists( 'PHP_Timer' ) ) {
- $result->addFailure( $this, $e, PHP_Timer::stop() );
- } else {
- $result->addFailure( $this, $e, PHPUnit_Util_Timer::stop() );
- }
- }
- catch ( Exception $e ) {
- // PHPUnit_Util_Timer -> PHP_Timer support (see above)
- if ( class_exists( 'PHP_Timer' ) ) {
- $result->addFailure( $this, $e, PHP_Timer::stop() );
- } else {
- $result->addFailure( $this, $e, PHPUnit_Util_Timer::stop() );
- }
- }
-
- // PHPUnit_Util_Timer -> PHP_Timer support (see above)
- if ( class_exists( 'PHP_Timer' ) ) {
- $result->endTest( $this, PHP_Timer::stop() );
- } else {
- $result->endTest( $this, PHPUnit_Util_Timer::stop() );
- }
-
- $backend->recorder->record( $this->test['test'], $r );
- $this->addToAssertionCount( PHPUnit_Framework_Assert::getCount() );
-
- return $result;
- }
-
- public function toString() {
- return $this->test['test'];
- }
-
-}
-
-class ParserTestSuiteBackend extends PHPUnit_FrameWork_TestSuite {
- public $recorder;
- public $term;
- static $usePHPUnit = false;
-
- function __construct() {
- parent::__construct();
- $this->setupRecorder(null);
- self::$usePHPUnit = method_exists('PHPUnit_Framework_Assert', 'assertEquals');
- }
-
- function showTesting( $desc ) {
- }
-
- function showRunFile( $path ) {
- }
-
- function showTestResult( $desc, $result, $out ) {
- if ( $result === $out ) {
- return self::showSuccess( $desc, $result, $out );
- } else {
- return self::showFailure( $desc, $result, $out );
- }
- }
-
- public function setupRecorder( $options ) {
- $this->recorder = new PHPUnitTestRecorder( $this );
- }
-}
-
-class PHPUnitTestRecorder extends TestRecorder {
- function record( $test, $result ) {
- $this->total++;
- $this->success += $result;
-
- }
-
- function reportPercentage( $success, $total ) { }
-}
diff --git a/tests/phpunit/includes/parser/ParserPreloadTest.php b/tests/phpunit/includes/parser/ParserPreloadTest.php
new file mode 100644
index 00000000..0e8ef530
--- /dev/null
+++ b/tests/phpunit/includes/parser/ParserPreloadTest.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Basic tests for Parser::getPreloadText
+ * @author Antoine Musso
+ */
+class ParserPreloadTest extends MediaWikiTestCase {
+ private $testParser;
+ private $testParserOptions;
+ private $title;
+
+ function setUp() {
+ $this->testParserOptions = new ParserOptions();
+
+ $this->testParser = new Parser();
+ $this->testParser->Options( $this->testParserOptions );
+ $this->testParser->clearState();
+
+ $this->title = Title::newFromText( 'Preload Test' );
+ }
+
+ function tearDown() {
+ unset( $this->testParser );
+ unset( $this->title );
+ }
+
+ /**
+ * @covers Parser::getPreloadText
+ */
+ function testPreloadSimpleText() {
+ $this->assertPreloaded( 'simple', 'simple' );
+ }
+
+ /**
+ * @covers Parser::getPreloadText
+ */
+ function testPreloadedPreIsUnstripped() {
+ $this->assertPreloaded(
+ '<pre>monospaced</pre>',
+ '<pre>monospaced</pre>',
+ '<pre> in preloaded text must be unstripped (bug 27467)'
+ );
+ }
+
+ /**
+ * @covers Parser::getPreloadText
+ */
+ function testPreloadedNowikiIsUnstripped() {
+ $this->assertPreloaded(
+ '<nowiki>[[Dummy title]]</nowiki>',
+ '<nowiki>[[Dummy title]]</nowiki>',
+ '<nowiki> in preloaded text must be unstripped (bug 27467)'
+ );
+ }
+
+ function assertPreloaded( $expected, $text, $msg='') {
+ $this->assertEquals(
+ $expected,
+ $this->testParser->getPreloadText(
+ $text,
+ $this->title,
+ $this->testParserOptions
+ ),
+ $msg
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/parser/PreprocessorTest.php b/tests/phpunit/includes/parser/PreprocessorTest.php
index 7a5948d4..9d3499a0 100644
--- a/tests/phpunit/includes/parser/PreprocessorTest.php
+++ b/tests/phpunit/includes/parser/PreprocessorTest.php
@@ -49,43 +49,45 @@ class PreprocessorTest extends MediaWikiTestCase {
array( "== Foo ==\n== Bar == \n", "<root><h level=\"2\" i=\"1\">== Foo ==</h>\n<h level=\"2\" i=\"2\">== Bar == </h>\n</root>" ),
array( "===========", "<root><h level=\"5\" i=\"1\">===========</h></root>" ),
array( "Foo\n=\n==\n=\n", "<root>Foo\n=\n==\n=\n</root>" ),
- array( "{{Foo}}", "<root><template lineStart=\"1\"><title>Foo</title></template></root>" ),
+ array( "{{Foo}}", "<root><template><title>Foo</title></template></root>" ),
array( "\n{{Foo}}", "<root>\n<template lineStart=\"1\"><title>Foo</title></template></root>" ),
- array( "{{Foo|bar}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template></root>" ),
- array( "{{Foo|bar}}a", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template>a</root>" ),
- array( "{{Foo|bar|baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></template></root>" ),
- array( "{{Foo|1=bar}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>1</name>=<value>bar</value></part></template></root>" ),
- array( "{{Foo|=bar}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name></name>=<value>bar</value></part></template></root>" ),
- array( "{{Foo|bar=baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>bar</name>=<value>baz</value></part></template></root>" ),
- array( "{{Foo|1=bar|baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name index=\"1\" /><value>baz</value></part></template></root>" ),
- array( "{{Foo|1=bar|2=baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name>2</name>=<value>baz</value></part></template></root>" ),
- array( "{{Foo|bar|foo=baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name>foo</name>=<value>baz</value></part></template></root>" ),
- array( "{{{1}}}", "<root><tplarg lineStart=\"1\"><title>1</title></tplarg></root>" ),
- array( "{{{1|}}}", "<root><tplarg lineStart=\"1\"><title>1</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ),
- array( "{{{Foo}}}", "<root><tplarg lineStart=\"1\"><title>Foo</title></tplarg></root>" ),
- array( "{{{Foo|}}}", "<root><tplarg lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ),
- array( "{{{Foo|bar|baz}}}", "<root><tplarg lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></tplarg></root>" ),
+ array( "{{Foo|bar}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template></root>" ),
+ array( "{{Foo|bar}}a", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template>a</root>" ),
+ array( "{{Foo|bar|baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></template></root>" ),
+ array( "{{Foo|1=bar}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part></template></root>" ),
+ array( "{{Foo|=bar}}", "<root><template><title>Foo</title><part><name></name>=<value>bar</value></part></template></root>" ),
+ array( "{{Foo|bar=baz}}", "<root><template><title>Foo</title><part><name>bar</name>=<value>baz</value></part></template></root>" ),
+ array( "{{Foo|{{bar}}=baz}}", "<root><template><title>Foo</title><part><name><template><title>bar</title></template></name>=<value>baz</value></part></template></root>" ),
+ array( "{{Foo|1=bar|baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name index=\"1\" /><value>baz</value></part></template></root>" ),
+ array( "{{Foo|1=bar|2=baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name>2</name>=<value>baz</value></part></template></root>" ),
+ array( "{{Foo|bar|foo=baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name>foo</name>=<value>baz</value></part></template></root>" ),
+ array( "{{{1}}}", "<root><tplarg><title>1</title></tplarg></root>" ),
+ array( "{{{1|}}}", "<root><tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ),
+ array( "{{{Foo}}}", "<root><tplarg><title>Foo</title></tplarg></root>" ),
+ array( "{{{Foo|}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ),
+ array( "{{{Foo|bar|baz}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></tplarg></root>" ),
array( "{<!-- -->{Foo}}", "<root>{<comment>&lt;!-- --&gt;</comment>{Foo}}</root>" ),
array( "{{{{Foobar}}}}", "<root>{<tplarg><title>Foobar</title></tplarg>}</root>" ),
- array( "{{{ {{Foo}} }}}", "<root><tplarg lineStart=\"1\"><title> <template><title>Foo</title></template> </title></tplarg></root>" ),
- array( "{{ {{{Foo}}} }}", "<root><template lineStart=\"1\"><title> <tplarg><title>Foo</title></tplarg> </title></template></root>" ),
- array( "{{{{{Foo}}}}}", "<root><template lineStart=\"1\"><title><tplarg><title>Foo</title></tplarg></title></template></root>" ),
- array( "{{{{{Foo}} }}}", "<root><tplarg lineStart=\"1\"><title><template><title>Foo</title></template> </title></tplarg></root>" ),
- array( "{{{{{{Foo}}}}}}", "<root><tplarg lineStart=\"1\"><title><tplarg><title>Foo</title></tplarg></title></tplarg></root>" ),
+ array( "{{{ {{Foo}} }}}", "<root><tplarg><title> <template><title>Foo</title></template> </title></tplarg></root>" ),
+ array( "{{ {{{Foo}}} }}", "<root><template><title> <tplarg><title>Foo</title></tplarg> </title></template></root>" ),
+ array( "{{{{{Foo}}}}}", "<root><template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ),
+ array( "{{{{{Foo}} }}}", "<root><tplarg><title><template><title>Foo</title></template> </title></tplarg></root>" ),
+ array( "{{{{{{Foo}}}}}}", "<root><tplarg><title><tplarg><title>Foo</title></tplarg></title></tplarg></root>" ),
array( "{{{{{{Foo}}}}}", "<root>{<template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ),
array( "[[[Foo]]", "<root>[[[Foo]]</root>" ),
- array( "{{Foo|[[[[bar]]|baz]]}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>[[[[bar]]|baz]]</value></part></template></root>" ), // This test is important, since it means the difference between having the [[ rule stacked or not
+ array( "{{Foo|[[[[bar]]|baz]]}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>[[[[bar]]|baz]]</value></part></template></root>" ), // This test is important, since it means the difference between having the [[ rule stacked or not
array( "{{Foo|[[[[bar]|baz]]}}", "<root>{{Foo|[[[[bar]|baz]]}}</root>" ),
array( "{{Foo|Foo [[[[bar]|baz]]}}", "<root>{{Foo|Foo [[[[bar]|baz]]}}</root>" ),
array( "Foo <display map>Bar</display map >Baz", "<root>Foo <ext><name>display map</name><attr></attr><inner>Bar</inner><close>&lt;/display map &gt;</close></ext>Baz</root>" ),
array( "Foo <display map foo>Bar</display map >Baz", "<root>Foo <ext><name>display map</name><attr> foo</attr><inner>Bar</inner><close>&lt;/display map &gt;</close></ext>Baz</root>" ),
array( "Foo <gallery bar=\"baz\" />", "<root>Foo <ext><name>gallery</name><attr> bar=&quot;baz&quot; </attr></ext></root>" ),
+ array( "Foo <gallery bar=\"1\" baz=2 />", "<root>Foo <ext><name>gallery</name><attr> bar=&quot;1&quot; baz=2 </attr></ext></root>" ),
array( "</foo>Foo<//foo>", "<root><ext><name>/foo</name><attr></attr><inner>Foo</inner><close>&lt;//foo&gt;</close></ext></root>" ), # Worth blacklisting IMHO
- array( "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "<root><template lineStart=\"1\"><title>#ifexpr: (<tplarg><title>1</title><part><name index=\"1\" /><value>1</value></part></tplarg> = 2) </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"),
- array( "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> <template><title>Bar</title></template> </value></part></template></root>"),
- array( "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> [[Bar]] </value></part></template></root>"),
- array( "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> [[Foo]] </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"),
- array( "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 1 </value></part><part><name index=\"2\" /><value> <template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 2 </value></part><part><name index=\"2\" /><value> 3 </value></part></template> </value></part></template></root>"),
+ array( "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "<root><template><title>#ifexpr: (<tplarg><title>1</title><part><name index=\"1\" /><value>1</value></part></tplarg> = 2) </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"),
+ array( "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> <template><title>Bar</title></template> </value></part></template></root>"),
+ array( "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> [[Bar]] </value></part></template></root>"),
+ array( "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> [[Foo]] </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"),
+ array( "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 1 </value></part><part><name index=\"2\" /><value> <template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 2 </value></part><part><name index=\"2\" /><value> 3 </value></part></template> </value></part></template></root>"),
array( "{{ {{Foo}}", "<root>{{ <template><title>Foo</title></template></root>"),
array( "{{Foobar {{Foo}} {{Bar}} {{Baz}} ", "<root>{{Foobar <template><title>Foo</title></template> <template><title>Bar</title></template> <template><title>Baz</title></template> </root>"),
array( "[[Foo]] |", "<root>[[Foo]] |</root>"),
@@ -97,19 +99,54 @@ class PreprocessorTest extends MediaWikiTestCase {
array( "{{Foo|bar=[[baz]}}", "<root>{{Foo|bar=[[baz]}}</root>"),
array( "{{foo|", "<root>{{foo|</root>"),
array( "{{foo|}", "<root>{{foo|}</root>"),
- array( "{{foo|} }}", "<root><template lineStart=\"1\"><title>foo</title><part><name index=\"1\" /><value>} </value></part></template></root>"),
+ array( "{{foo|} }}", "<root><template><title>foo</title><part><name index=\"1\" /><value>} </value></part></template></root>"),
array( "{{foo|bar=|}", "<root>{{foo|bar=|}</root>"),
array( "{{Foo|} Bar=", "<root>{{Foo|} Bar=</root>"),
- array( "{{Foo|} Bar=}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>} Bar</name>=<value></value></part></template></root>"),
+ array( "{{Foo|} Bar=}}", "<root><template><title>Foo</title><part><name>} Bar</name>=<value></value></part></template></root>"),
/* array( file_get_contents( dirname( __FILE__ ) . '/QuoteQuran.txt' ), file_get_contents( dirname( __FILE__ ) . '/QuoteQuranExpanded.txt' ) ), */
);
}
/**
+ * Get XML preprocessor tree from the preprocessor (which may not be the
+ * native XML-based one).
+ *
+ * @param string $wikiText
+ * @return string
+ */
+ function preprocessToXml( $wikiText ) {
+ if ( method_exists( $this->mPreprocessor, 'preprocessToXml' ) ) {
+ return $this->normalizeXml( $this->mPreprocessor->preprocessToXml( $wikiText ) );
+ }
+
+ $dom = $this->mPreprocessor->preprocessToObj( $wikiText );
+ if ( is_callable( array( $dom, 'saveXML' ) ) ) {
+ return $dom->saveXML();
+ } else {
+ return $this->normalizeXml( $dom->__toString() );
+ }
+ }
+
+ /**
+ * Normalize XML string to the form that a DOMDocument saves out.
+ *
+ * @param string $xml
+ * @return string
+ */
+ function normalizeXml( $xml ) {
+ return preg_replace( '!<([a-z]+)/>!', '<$1></$1>', str_replace( ' />', '/>', $xml ) );
+
+ $dom = new DOMDocument();
+ // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2 don't barf when the XML is >256 levels deep
+ $dom->loadXML( $xml, 1 << 19 );
+ return $dom->saveXML();
+ }
+
+ /**
* @dataProvider provideCases
*/
function testPreprocessorOutput( $wikiText, $expectedXml ) {
- $this->assertEquals( $expectedXml, $this->mPreprocessor->preprocessToXml( $wikiText ) );
+ $this->assertEquals( $this->normalizeXml( $expectedXml ), $this->preprocessToXml( $wikiText ) );
}
/**
@@ -130,11 +167,12 @@ class PreprocessorTest extends MediaWikiTestCase {
function testPreprocessorOutputFiles( $filename ) {
$folder = dirname( __FILE__ ) . "/../../../parser/preprocess";
$wikiText = file_get_contents( "$folder/$filename.txt" );
- $output = $this->mPreprocessor->preprocessToXml( $wikiText );
+ $output = $this->preprocessToXml( $wikiText );
$expectedFilename = "$folder/$filename.expected";
if ( file_exists( $expectedFilename ) ) {
- $this->assertStringEqualsFile( $expectedFilename, $output );
+ $expectedXml = $this->normalizeXml( file_get_contents( $expectedFilename ) );
+ $this->assertEquals( $expectedXml, $output );
} else {
$tempFilename = tempnam( $folder, "$filename." );
file_put_contents( $tempFilename, $output );
@@ -189,7 +227,7 @@ class PreprocessorTest extends MediaWikiTestCase {
* @dataProvider provideHeadings
*/
function testHeadings( $wikiText, $expectedXml ) {
- $this->assertEquals( $expectedXml, $this->mPreprocessor->preprocessToXml( $wikiText ) );
+ $this->assertEquals( $this->normalizeXml( $expectedXml ), $this->preprocessToXml( $wikiText ) );
}
}
diff --git a/tests/phpunit/includes/parser/TagHooks.php b/tests/phpunit/includes/parser/TagHooksTest.php
index 713ce846..713ce846 100644
--- a/tests/phpunit/includes/parser/TagHooks.php
+++ b/tests/phpunit/includes/parser/TagHooksTest.php
diff --git a/tests/phpunit/includes/search/SearchEngineTest.php b/tests/phpunit/includes/search/SearchEngineTest.php
index 1a0fcd31..957907c7 100644
--- a/tests/phpunit/includes/search/SearchEngineTest.php
+++ b/tests/phpunit/includes/search/SearchEngineTest.php
@@ -12,7 +12,7 @@ class SearchEngineTest extends MediaWikiTestCase {
unset( $this->search );
}
- /*
+ /**
* Checks for database type & version.
* Will skip current test if DB does not support search.
*/
@@ -64,8 +64,10 @@ class SearchEngineTest extends MediaWikiTestCase {
$this->assertTrue( is_object( $results ) );
$matches = array();
- while ( $row = $results->next() ) {
+ $row = $results->next();
+ while ( $row ) {
$matches[] = $row->getTitle()->getPrefixedText();
+ $row = $results->next();
}
$results->free();
# Search is not guaranteed to return results in a certain order;
@@ -83,20 +85,18 @@ class SearchEngineTest extends MediaWikiTestCase {
* @param $n Integer: unused
*/
function insertPage( $pageName, $text, $ns ) {
- $dbw = $this->db;
$title = Title::newFromText( $pageName );
$user = User::newFromName( 'WikiSysop' );
$comment = 'Search Test';
// avoid memory leak...?
- $linkCache = LinkCache::singleton();
- $linkCache->clear();
+ LinkCache::singleton()->clear();
- $article = new Article( $title );
- $article->doEdit( $text, $comment, 0, false, $user );
+ $page = WikiPage::factory( $title );
+ $page->doEdit( $text, $comment, 0, false, $user );
- $this->pageList[] = array( $title, $article->getId() );
+ $this->pageList[] = array( $title, $page->getId() );
return true;
}
diff --git a/tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php b/tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php
new file mode 100644
index 00000000..a33c7b68
--- /dev/null
+++ b/tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Test class to run the query of most of all our special pages
+ *
+ * Copyright © 2011, Antoine Musso
+ *
+ * @author Antoine Musso
+ * @group Database
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ die( 1 );
+}
+
+global $IP;
+require_once "$IP/includes/QueryPage.php"; // Needed to populate $wgQueryPages
+
+class QueryAllSpecialPagesTest extends MediaWikiTestCase {
+
+ /** List query pages that can not be tested automatically */
+ protected $manualTest = array(
+ 'LinkSearchPage'
+ );
+
+ /**
+ * Pages whose query use the same DB table more than once.
+ * This is used to skip testing those pages when run against a MySQL backend
+ * which does not support reopening a temporary table. See upstream bug:
+ * http://bugs.mysql.com/bug.php?id=10327
+ */
+ protected $reopensTempTable = array(
+ 'BrokenRedirects',
+ );
+
+ /**
+ * Initialize all query page objects
+ */
+ function __construct() {
+ parent::__construct();
+
+ global $wgQueryPages;
+ foreach( $wgQueryPages as $page ) {
+ $class = $page[0];
+ if( ! in_array( $class, $this->manualTest ) ) {
+ $this->queryPages[$class] = new $class;
+ }
+ }
+ }
+
+ /**
+ * Test SQL for each of our QueryPages objects
+ * @group Database
+ */
+ function testQuerypageSqlQuery() {
+ global $wgDBtype;
+
+ foreach( $this->queryPages as $page ) {
+
+ // With MySQL, skips special pages reopening a temporary table
+ // See http://bugs.mysql.com/bug.php?id=10327
+ if(
+ $wgDBtype === 'mysql'
+ && in_array( $page->getName(), $this->reopensTempTable )
+ ) {
+ $this->markTestSkipped( "SQL query for page {$page->getName()} can not be tested on MySQL backend (it reopens a temporary table)" );
+ continue;
+ }
+
+ $msg = "SQL query for page {$page->getName()} should give a result wrapper object" ;
+
+ $result = $page->reallyDoQuery( 50 );
+ if( $result instanceof ResultWrapper ) {
+ $this->assertTrue( true, $msg );
+ } else {
+ $this->assertFalse( false, $msg );
+ }
+ }
+ }
+}
diff --git a/tests/phpunit/includes/specials/SpecialRecentchanges.php b/tests/phpunit/includes/specials/SpecialRecentchangesTest.php
index a98e7c1a..2e4f4b09 100644
--- a/tests/phpunit/includes/specials/SpecialRecentchanges.php
+++ b/tests/phpunit/includes/specials/SpecialRecentchangesTest.php
@@ -2,9 +2,10 @@
/**
* Test class for SpecialRecentchanges class
*
- * Copyright © 2011, Ashar Voultoiz
+ * Copyright © 2011, Antoine Musso
*
- * @author Ashar Voultoiz
+ * @author Antoine Musso
+ * @group Database
*/
class SpecialRecentchangesTest extends MediaWikiTestCase {
@@ -18,13 +19,12 @@ class SpecialRecentchangesTest extends MediaWikiTestCase {
/** helper to test SpecialRecentchanges::buildMainQueryConds() */
private function assertConditions( $expected, $requestOptions = null, $message = '' ) {
- global $wgRequest;
- $savedGlobal = $wgRequest;
+ $context = new RequestContext;
+ $context->setRequest( new FauxRequest( $requestOptions ) );
- # Initialize a WebRequest object ...
- $wgRequest = new FauxRequest( $requestOptions );
- # ... then setup the rc object (which use wgRequest internally)
+ # setup the rc object
$this->rc = new SpecialRecentChanges();
+ $this->rc->setContext( $context );
$formOptions = $this->rc->setup( null );
# Filter out rc_timestamp conditions which depends on the test runtime
@@ -40,8 +40,6 @@ class SpecialRecentchangesTest extends MediaWikiTestCase {
$queryConditions,
$message
);
-
- $wgRequest = $savedGlobal;
}
/** return false if condition begin with 'rc_timestamp ' */
diff --git a/tests/phpunit/includes/specials/SpecialSearchTest.php b/tests/phpunit/includes/specials/SpecialSearchTest.php
new file mode 100644
index 00000000..ea9d5533
--- /dev/null
+++ b/tests/phpunit/includes/specials/SpecialSearchTest.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Test class for SpecialSearch class
+ * Copyright © 2012, Antoine Musso
+ *
+ * @author Antoine Musso
+ * @group Database
+ */
+
+class SpecialSearchTest extends MediaWikiTestCase {
+ private $search;
+
+ function setUp() { }
+ function tearDown() { }
+
+ /**
+ * @covers SpecialSearch::load
+ * @dataProvider provideSearchOptionsTests
+ * @param $requested Array Request parameters. For example array( 'ns5' => true, 'ns6' => true). NULL to use default options.
+ * @param $userOptions Array User options to test with. For example array('searchNs5' => 1 );. NULL to use default options.
+ * @param $expectedProfile An expected search profile name
+ * @param $expectedNs Array Expected namespaces
+ */
+ function testProfileAndNamespaceLoading(
+ $requested, $userOptions, $expectedProfile, $expectedNS,
+ $message = 'Profile name and namespaces mismatches!'
+ ) {
+ $context = new RequestContext;
+ $context->setUser(
+ $this->newUserWithSearchNS( $userOptions )
+ );
+ /*
+ $context->setRequest( new FauxRequest( array(
+ 'ns5'=>true,
+ 'ns6'=>true,
+ ) ));
+ */
+ $context->setRequest( new FauxRequest( $requested ));
+ $search = new SpecialSearch();
+ $search->setContext( $context );
+ $search->load();
+
+ /**
+ * Verify profile name and namespace in the same assertion to make
+ * sure we will be able to fully compare the above code. PHPUnit stop
+ * after an assertion fail.
+ */
+ $this->assertEquals(
+ array( /** Expected: */
+ 'ProfileName' => $expectedProfile,
+ 'Namespaces' => $expectedNS,
+ )
+ , array( /** Actual: */
+ 'ProfileName' => $search->getProfile(),
+ 'Namespaces' => $search->getNamespaces(),
+ )
+ , $message
+ );
+
+ }
+
+ function provideSearchOptionsTests() {
+ $defaultNS = SearchEngine::defaultNamespaces();
+ $EMPTY_REQUEST = array();
+ $NO_USER_PREF = null;
+
+ return array(
+ /**
+ * Parameters:
+ * <Web Request>, <User options>
+ * Followed by expected values:
+ * <ProfileName>, <NSList>
+ * Then an optional message.
+ */
+ array(
+ $EMPTY_REQUEST, $NO_USER_PREF,
+ 'default', $defaultNS,
+ 'Bug 33270: No request nor user preferences should give default profile'
+ ),
+ array(
+ array( 'ns5' => 1 ), $NO_USER_PREF,
+ 'advanced', array( 5),
+ 'Web request with specific NS should override user preference'
+ ),
+ array(
+ $EMPTY_REQUEST, array( 'searchNs2' => 1, 'searchNs14' => 1 ),
+ 'advanced', array( 2, 14 ),
+ 'Bug 33583: search with no option should honor User search preferences'
+ ),
+ );
+ }
+
+ /**
+ * Helper to create a new User object with given options
+ * User remains anonymous though
+ */
+ function newUserWithSearchNS( $opt = null ) {
+ $u = User::newFromId(0);
+ if( $opt === null ) {
+ return $u;
+ }
+ foreach($opt as $name => $value) {
+ $u->setOption( $name, $value );
+ }
+ return $u;
+ }
+}
+
diff --git a/tests/phpunit/includes/upload/UploadFromUrlTest.php b/tests/phpunit/includes/upload/UploadFromUrlTest.php
index 4722d408..d56cce31 100644
--- a/tests/phpunit/includes/upload/UploadFromUrlTest.php
+++ b/tests/phpunit/includes/upload/UploadFromUrlTest.php
@@ -20,7 +20,7 @@ class UploadFromUrlTest extends ApiTestCase {
}
}
- protected function doApiRequest( $params, $unused = null, $appendModule = false ) {
+ protected function doApiRequest( $params, $unused = null, $appendModule = false, $user = null ) {
$sessionId = session_id();
session_write_close();
@@ -36,7 +36,10 @@ class UploadFromUrlTest extends ApiTestCase {
* Ensure that the job queue is empty before continuing
*/
public function testClearQueue() {
- while ( $job = Job::pop() ) { }
+ $job = Job::pop();
+ while ( $job ) {
+ $job = Job::pop();
+ }
$this->assertFalse( $job );
}
@@ -73,7 +76,7 @@ class UploadFromUrlTest extends ApiTestCase {
* @depends testClearQueue
*/
public function testSetupUrlDownload( $data ) {
- $token = $this->user->editToken();
+ $token = $this->user->getEditToken();
$exception = false;
try {
@@ -147,7 +150,7 @@ class UploadFromUrlTest extends ApiTestCase {
* @depends testClearQueue
*/
public function testAsyncUpload( $data ) {
- $token = $this->user->editToken();
+ $token = $this->user->getEditToken();
$this->user->addGroup( 'users' );
@@ -166,7 +169,7 @@ class UploadFromUrlTest extends ApiTestCase {
* @depends testClearQueue
*/
public function testAsyncUploadWarning( $data ) {
- $token = $this->user->editToken();
+ $token = $this->user->getEditToken();
$this->user->addGroup( 'users' );
@@ -197,7 +200,7 @@ class UploadFromUrlTest extends ApiTestCase {
* @depends testClearQueue
*/
public function testSyncDownload( $data ) {
- $token = $this->user->editToken();
+ $token = $this->user->getEditToken();
$job = Job::pop();
$this->assertFalse( $job, 'Starting with an empty jobqueue' );
@@ -221,7 +224,7 @@ class UploadFromUrlTest extends ApiTestCase {
}
public function testLeaveMessage() {
- $token = $this->user->user->editToken();
+ $token = $this->user->user->getEditToken();
$talk = $this->user->user->getTalkPage();
if ( $talk->exists() ) {
@@ -274,7 +277,7 @@ class UploadFromUrlTest extends ApiTestCase {
return;
- /**
+ /*
// Broken until using leavemessage with ignorewarnings is supported
$job->run();
diff --git a/tests/phpunit/includes/upload/UploadStashTest.php b/tests/phpunit/includes/upload/UploadStashTest.php
index e644a259..c9dbb138 100644
--- a/tests/phpunit/includes/upload/UploadStashTest.php
+++ b/tests/phpunit/includes/upload/UploadStashTest.php
@@ -1,5 +1,7 @@
<?php
-
+/**
+ * @group Database
+ */
class UploadStashTest extends MediaWikiTestCase {
/**
* @var Array of UploadStashTestUser
@@ -8,49 +10,68 @@ class UploadStashTest extends MediaWikiTestCase {
public function setUp() {
parent::setUp();
-
+
// Setup a file for bug 29408
$this->bug29408File = dirname( __FILE__ ) . '/bug29408';
- file_put_contents( $this->bug29408File, "\x00" );
-
+ file_put_contents( $this->bug29408File, "\x00" );
+
self::$users = array(
'sysop' => new ApiTestUser(
'Uploadstashtestsysop',
'Upload Stash Test Sysop',
- 'upload_stash_test_sysop@sample.com',
+ 'upload_stash_test_sysop@example.com',
array( 'sysop' )
),
'uploader' => new ApiTestUser(
'Uploadstashtestuser',
'Upload Stash Test User',
- 'upload_stash_test_user@sample.com',
+ 'upload_stash_test_user@example.com',
array()
)
);
}
- /**
- * @group Database
- */
public function testBug29408() {
global $wgUser;
$wgUser = self::$users['uploader']->user;
-
+
$repo = RepoGroup::singleton()->getLocalRepo();
$stash = new UploadStash( $repo );
-
+
// Throws exception caught by PHPUnit on failure
$file = $stash->stashFile( $this->bug29408File );
// We'll never reach this point if we hit bug 29408
$this->assertTrue( true, 'Unrecognized file without extension' );
-
+
$stash->removeFile( $file->getFileKey() );
}
-
+
+ public function testValidRequest() {
+ $request = new FauxRequest( array( 'wpFileKey' => 'foo') );
+ $this->assertFalse( UploadFromStash::isValidRequest($request), 'Check failure on bad wpFileKey' );
+
+ $request = new FauxRequest( array( 'wpSessionKey' => 'foo') );
+ $this->assertFalse( UploadFromStash::isValidRequest($request), 'Check failure on bad wpSessionKey' );
+
+ $request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test') );
+ $this->assertTrue( UploadFromStash::isValidRequest($request), 'Check good wpFileKey' );
+
+ $request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test') );
+ $this->assertTrue( UploadFromStash::isValidRequest($request), 'Check good wpSessionKey' );
+
+ $request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test', 'wpSessionKey' => 'foo') );
+ $this->assertTrue( UploadFromStash::isValidRequest($request), 'Check key precedence' );
+ }
+
public function tearDown() {
parent::tearDown();
-
- unlink( $this->bug29408File . "." );
-
+
+ if( file_exists( $this->bug29408File . "." ) ) {
+ unlink( $this->bug29408File . "." );
+ }
+
+ if( file_exists( $this->bug29408File ) ) {
+ unlink( $this->bug29408File );
+ }
}
}
diff --git a/tests/phpunit/includes/upload/UploadTest.php b/tests/phpunit/includes/upload/UploadTest.php
index 69c29032..4293d23b 100644
--- a/tests/phpunit/includes/upload/UploadTest.php
+++ b/tests/phpunit/includes/upload/UploadTest.php
@@ -20,53 +20,14 @@ class UploadTest extends MediaWikiTestCase {
$wgHooks = $this->hooks;
}
- /**
- * Test various forms of valid and invalid titles that can be supplied.
- */
- public function testTitleValidation() {
-
-
- /* Test a valid title */
- $this->assertUploadTitleAndCode( 'ValidTitle.jpg',
- 'ValidTitle.jpg', UploadBase::OK,
- 'upload valid title' );
-
- /* A title with a slash */
- $this->assertUploadTitleAndCode( 'A/B.jpg',
- 'B.jpg', UploadBase::OK,
- 'upload title with slash' );
-
- /* A title with illegal char */
- $this->assertUploadTitleAndCode( 'A:B.jpg',
- 'A-B.jpg', UploadBase::OK,
- 'upload title with colon' );
-
- /* Stripping leading File: prefix */
- $this->assertUploadTitleAndCode( 'File:C.jpg',
- 'C.jpg', UploadBase::OK,
- 'upload title with File prefix' );
- /* Test illegal suggested title (r94601) */
- $this->assertUploadTitleAndCode( '%281%29.JPG',
- null, UploadBase::ILLEGAL_FILENAME,
- 'illegal title for upload' );
-
- /* A title without extension */
- $this->assertUploadTitleAndCode( 'A',
- null, UploadBase::FILETYPE_MISSING,
- 'upload title without extension' );
-
- /* A title with no basename */
- $this->assertUploadTitleAndCode( '.jpg',
- null, UploadBase::MIN_LENGTH_PARTNAME,
- 'upload title without basename' );
-
- }
/**
- * Helper function for testTitleValidation. First checks the return code
- * of UploadBase::getTitle() and then the actual returned titl
+ * First checks the return code
+ * of UploadBase::getTitle() and then the actual returned title
+ *
+ * @dataProvider dataTestTitleValidation
*/
- private function assertUploadTitleAndCode( $srcFilename, $dstFilename, $code, $msg ) {
+ public function testTitleValidation( $srcFilename, $dstFilename, $code, $msg ) {
/* Check the result code */
$this->assertEquals( $code,
$this->upload->testTitleValidation( $srcFilename ),
@@ -79,6 +40,41 @@ class UploadTest extends MediaWikiTestCase {
"$msg text" );
}
}
+
+ /**
+ * Test various forms of valid and invalid titles that can be supplied.
+ */
+ public function dataTestTitleValidation() {
+ return array(
+ /* Test a valid title */
+ array( 'ValidTitle.jpg', 'ValidTitle.jpg', UploadBase::OK,
+ 'upload valid title' ),
+ /* A title with a slash */
+ array( 'A/B.jpg', 'B.jpg', UploadBase::OK,
+ 'upload title with slash' ),
+ /* A title with illegal char */
+ array( 'A:B.jpg', 'A-B.jpg', UploadBase::OK,
+ 'upload title with colon' ),
+ /* Stripping leading File: prefix */
+ array( 'File:C.jpg', 'C.jpg', UploadBase::OK,
+ 'upload title with File prefix' ),
+ /* Test illegal suggested title (r94601) */
+ array( '%281%29.JPG', null, UploadBase::ILLEGAL_FILENAME,
+ 'illegal title for upload' ),
+ /* A title without extension */
+ array( 'A', null, UploadBase::FILETYPE_MISSING,
+ 'upload title without extension' ),
+ /* A title with no basename */
+ array( '.jpg', null, UploadBase::MIN_LENGTH_PARTNAME,
+ 'upload title without basename' ),
+ /* A title that is longer than 255 bytes */
+ array( str_repeat( 'a', 255 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG,
+ 'upload title longer than 255 bytes' ),
+ /* A title that is longer than 240 bytes */
+ array( str_repeat( 'a', 240 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG,
+ 'upload title longer than 240 bytes' ),
+ );
+ }
/**
* Test the upload verification functions
@@ -104,7 +100,7 @@ class UploadTest extends MediaWikiTestCase {
}
/**
- * test uploading a 100 bytes file with wgMaxUploadSize = 100
+ * test uploading a 100 bytes file with $wgMaxUploadSize = 100
*
* This method should be abstracted so we can test different settings.
*/
@@ -134,6 +130,7 @@ class UploadTestHandler extends UploadBase {
public function testTitleValidation( $name ) {
$this->mTitle = false;
$this->mDesiredDestName = $name;
+ $this->mTitleError = UploadBase::OK;
$this->getTitle();
return $this->mTitleError;
}
diff --git a/tests/phpunit/languages/LanguageAmTest.php b/tests/phpunit/languages/LanguageAmTest.php
new file mode 100644
index 00000000..3a648ded
--- /dev/null
+++ b/tests/phpunit/languages/LanguageAmTest.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageAm.php */
+class LanguageAmTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Am' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageArTest.php b/tests/phpunit/languages/LanguageArTest.php
new file mode 100644
index 00000000..b23e0534
--- /dev/null
+++ b/tests/phpunit/languages/LanguageArTest.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Based on LanguagMlTest
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageAr.php */
+class LanguageArTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Ar' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ function testFormatNum() {
+ $this->assertEquals( '١٬٢٣٤٬٥٦٧', $this->lang->formatNum( '1234567' ) );
+ $this->assertEquals( '-١٢٫٨٩', $this->lang->formatNum( -12.89 ) );
+ }
+
+ /**
+ * Mostly to test the raw ascii feature.
+ * @dataProvider providerSprintfDate
+ */
+ function testSprintfDate( $format, $date, $expected ) {
+ $this->assertEquals( $expected, $this->lang->sprintfDate( $format, $date ) );
+ }
+
+ function providerSprintfDate() {
+ return array(
+ array(
+ 'xg "vs" g',
+ '20120102030410',
+ 'يناير vs ٣'
+ ),
+ array(
+ 'xmY',
+ '20120102030410',
+ '١٤٣٣'
+ ),
+ array(
+ 'xnxmY',
+ '20120102030410',
+ '1433'
+ ),
+ array(
+ 'xN xmj xmn xN xmY',
+ '20120102030410',
+ ' 7 2 ١٤٣٣'
+ ),
+ );
+ }
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'zero', 'one', 'two', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providePlural() {
+ return array (
+ array( 'zero', 0 ),
+ array( 'one', 1 ),
+ array( 'two', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 9 ),
+ array( 'few', 110 ),
+ array( 'many', 11 ),
+ array( 'many', 15 ),
+ array( 'many', 99 ),
+ array( 'many', 9999 ),
+ array( 'other', 100 ),
+ array( 'other', 102 ),
+ array( 'other', 1000 ),
+ array( 'other', 1.7 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageBeTest.php b/tests/phpunit/languages/LanguageBeTest.php
new file mode 100644
index 00000000..735ccc63
--- /dev/null
+++ b/tests/phpunit/languages/LanguageBeTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageBe.php */
+class LanguageBeTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Be' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 1 ),
+ array( 'many', 11 ),
+ array( 'one', 91 ),
+ array( 'one', 121 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'few', 334 ),
+ array( 'many', 5 ),
+ array( 'many', 15 ),
+ array( 'many', 120 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageBe_taraskTest.php b/tests/phpunit/languages/LanguageBe_taraskTest.php
index e7fdb7ca..765cdb8f 100644
--- a/tests/phpunit/languages/LanguageBe_taraskTest.php
+++ b/tests/phpunit/languages/LanguageBe_taraskTest.php
@@ -27,4 +27,39 @@ class LanguageBeTaraskTest extends MediaWikiTestCase {
function testDoesNotCommafyFourDigitsNumber() {
$this->assertEquals( '1234', $this->lang->commafy( '1234' ) );
}
+ /** @dataProvider providePluralFourForms */
+ function testPluralFourForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePluralFourForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'many', 11 ),
+ array( 'one', 91 ),
+ array( 'one', 121 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'few', 334 ),
+ array( 'many', 5 ),
+ array( 'many', 15 ),
+ array( 'many', 120 ),
+ );
+ }
+ /** @dataProvider providePluralTwoForms */
+ function testPluralTwoForms( $result, $value ) {
+ $forms = array( 'one', 'several' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providePluralTwoForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'several', 11 ),
+ array( 'several', 91 ),
+ array( 'several', 121 ),
+ );
+ }
+
}
diff --git a/tests/phpunit/languages/LanguageBhTest.php b/tests/phpunit/languages/LanguageBhTest.php
new file mode 100644
index 00000000..e1e2a13e
--- /dev/null
+++ b/tests/phpunit/languages/LanguageBhTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageBh.php */
+class LanguageBhTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Bh' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageBsTest.php b/tests/phpunit/languages/LanguageBsTest.php
new file mode 100644
index 00000000..b6631c03
--- /dev/null
+++ b/tests/phpunit/languages/LanguageBsTest.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageBs.php */
+class LanguageBsTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Bs' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 4 ),
+ array( 'many', 5 ),
+ array( 'many', 11 ),
+ array( 'many', 20 ),
+ array( 'one', 21 ),
+ array( 'few', 24 ),
+ array( 'many', 25 ),
+ array( 'many', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageCsTest.php b/tests/phpunit/languages/LanguageCsTest.php
new file mode 100644
index 00000000..dda29f9a
--- /dev/null
+++ b/tests/phpunit/languages/LanguageCsTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/Languagecs.php */
+class LanguageCsTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'cs' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'other', 5 ),
+ array( 'other', 11 ),
+ array( 'other', 20 ),
+ array( 'other', 25 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageCuTest.php b/tests/phpunit/languages/LanguageCuTest.php
new file mode 100644
index 00000000..f8186d7b
--- /dev/null
+++ b/tests/phpunit/languages/LanguageCuTest.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageCu.php */
+class LanguageCuTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'cu' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'many', 3 ),
+ array( 'many', 4 ),
+ array( 'other', 5 ),
+ array( 'one', 11 ),
+ array( 'other', 20 ),
+ array( 'few', 22 ),
+ array( 'many', 223 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageCyTest.php b/tests/phpunit/languages/LanguageCyTest.php
new file mode 100644
index 00000000..e9f9e410
--- /dev/null
+++ b/tests/phpunit/languages/LanguageCyTest.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageCy.php */
+class LanguageCyTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'cy' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'zero', 'one', 'two', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'zero', 0 ),
+ array( 'one', 1 ),
+ array( 'two', 2 ),
+ array( 'few', 3 ),
+ array( 'many', 6 ),
+ array( 'other', 4 ),
+ array( 'other', 5 ),
+ array( 'other', 11 ),
+ array( 'other', 20 ),
+ array( 'other', 22 ),
+ array( 'other', 223 ),
+ array( 'other', 200.00 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageDsbTest.php b/tests/phpunit/languages/LanguageDsbTest.php
new file mode 100644
index 00000000..ab7f9313
--- /dev/null
+++ b/tests/phpunit/languages/LanguageDsbTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageDsb.php */
+class LanguageDsbTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'dsb' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'two', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'one', 101 ),
+ array( 'one', 90001 ),
+ array( 'two', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 203 ),
+ array( 'few', 4 ),
+ array( 'other', 99 ),
+ array( 'other', 555 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageFrTest.php b/tests/phpunit/languages/LanguageFrTest.php
new file mode 100644
index 00000000..8538744e
--- /dev/null
+++ b/tests/phpunit/languages/LanguageFrTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageFr.php */
+class LanguageFrTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'fr' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageGaTest.php b/tests/phpunit/languages/LanguageGaTest.php
new file mode 100644
index 00000000..fbd9f11d
--- /dev/null
+++ b/tests/phpunit/languages/LanguageGaTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageGa.php */
+class LanguageGaTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'ga' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'two', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'two', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageGdTest.php b/tests/phpunit/languages/LanguageGdTest.php
new file mode 100644
index 00000000..24574bda
--- /dev/null
+++ b/tests/phpunit/languages/LanguageGdTest.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageGd.php */
+class LanguageGdTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'gd' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ // The CLDR ticket for this plural forms is not same as mw plural forms. See http://unicode.org/cldr/trac/ticket/2883
+ $forms = array( 'Form 1', 'Form 2', 'Form 3', 'Form 4', 'Form 5', 'Form 6' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providerPlural() {
+ return array (
+ array( 'Form 6', 0 ),
+ array( 'Form 1', 1 ),
+ array( 'Form 2', 2 ),
+ array( 'Form 3', 11 ),
+ array( 'Form 4', 12 ),
+ array( 'Form 5', 3 ),
+ array( 'Form 5', 19 ),
+ array( 'Form 6', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageGvTest.php b/tests/phpunit/languages/LanguageGvTest.php
new file mode 100644
index 00000000..3d298b9b
--- /dev/null
+++ b/tests/phpunit/languages/LanguageGvTest.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageGv.php */
+class LanguageGvTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'gv' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ // This is not compatible with CLDR plural rules http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#gv
+ $forms = array( 'Form 1', 'Form 2', 'Form 3', 'Form 4' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providerPlural() {
+ return array (
+ array( 'Form 4', 0 ),
+ array( 'Form 2', 1 ),
+ array( 'Form 3', 2 ),
+ array( 'Form 4', 3 ),
+ array( 'Form 1', 20 ),
+ array( 'Form 2', 21 ),
+ array( 'Form 3', 22 ),
+ array( 'Form 4', 23 ),
+ array( 'Form 4', 50 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageHeTest.php b/tests/phpunit/languages/LanguageHeTest.php
new file mode 100644
index 00000000..9ac0f952
--- /dev/null
+++ b/tests/phpunit/languages/LanguageHeTest.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageHe.php */
+class LanguageHeTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'he' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPluralDual */
+ function testPluralDual( $result, $value ) {
+ $forms = array( 'one', 'many', 'two' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPluralDual() {
+ return array (
+ array( 'many', 0 ), // Zero -> plural
+ array( 'one', 1 ), // Singular
+ array( 'two', 2 ), // Dual
+ array( 'many', 3 ), // Plural
+ );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'many', 0 ), // Zero -> plural
+ array( 'one', 1 ), // Singular
+ array( 'many', 2 ), // Plural, no dual provided
+ array( 'many', 3 ), // Plural
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageHiTest.php b/tests/phpunit/languages/LanguageHiTest.php
new file mode 100644
index 00000000..ead9e020
--- /dev/null
+++ b/tests/phpunit/languages/LanguageHiTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageHi.php */
+class LanguageHiTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Hi' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageHrTest.php b/tests/phpunit/languages/LanguageHrTest.php
new file mode 100644
index 00000000..4f1c66bf
--- /dev/null
+++ b/tests/phpunit/languages/LanguageHrTest.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageHr.php */
+class LanguageHrTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'hr' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 4 ),
+ array( 'many', 5 ),
+ array( 'many', 11 ),
+ array( 'many', 20 ),
+ array( 'one', 21 ),
+ array( 'few', 24 ),
+ array( 'many', 25 ),
+ array( 'many', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageHsbTest.php b/tests/phpunit/languages/LanguageHsbTest.php
new file mode 100644
index 00000000..803c7721
--- /dev/null
+++ b/tests/phpunit/languages/LanguageHsbTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageHsb.php */
+class LanguageHsbTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'hsb' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'two', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'one', 101 ),
+ array( 'one', 90001 ),
+ array( 'two', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 203 ),
+ array( 'few', 4 ),
+ array( 'other', 99 ),
+ array( 'other', 555 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageHyTest.php b/tests/phpunit/languages/LanguageHyTest.php
new file mode 100644
index 00000000..7990bdfc
--- /dev/null
+++ b/tests/phpunit/languages/LanguageHyTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageHy.php */
+class LanguageHyTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'hy' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageKshTest.php b/tests/phpunit/languages/LanguageKshTest.php
new file mode 100644
index 00000000..ab889464
--- /dev/null
+++ b/tests/phpunit/languages/LanguageKshTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageKsh.php */
+class LanguageKshTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'ksh' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other', 'zero' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'zero', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageLnTest.php b/tests/phpunit/languages/LanguageLnTest.php
new file mode 100644
index 00000000..0fd9167e
--- /dev/null
+++ b/tests/phpunit/languages/LanguageLnTest.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageLn.php */
+class LanguageLnTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'ln' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageLtTest.php b/tests/phpunit/languages/LanguageLtTest.php
new file mode 100644
index 00000000..0d7c7d3e
--- /dev/null
+++ b/tests/phpunit/languages/LanguageLtTest.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageLt.php */
+class LanguageLtTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Lt' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider provideOneFewOtherCases */
+ function testOneFewOtherPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ /** @dataProvider provideOneFewCases */
+ function testOneFewPlural( $result, $value ) {
+ $forms = array( 'one', 'few' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function provideOneFewOtherCases() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 9 ),
+ array( 'other', 10 ),
+ array( 'other', 11 ),
+ array( 'other', 20 ),
+ array( 'one', 21 ),
+ array( 'few', 32 ),
+ array( 'one', 41 ),
+ array( 'one', 40001 ),
+ );
+ }
+
+ function provideOneFewCases() {
+ return array (
+ array( 'one', 1 ),
+ array( 'few', 15 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageLvTest.php b/tests/phpunit/languages/LanguageLvTest.php
new file mode 100644
index 00000000..0636da5f
--- /dev/null
+++ b/tests/phpunit/languages/LanguageLvTest.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageLv.php */
+class LanguageLvTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'lv' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ), #this must be zero form as per CLDR
+ array( 'one', 1 ),
+ array( 'other', 11 ),
+ array( 'one', 21 ),
+ array( 'other', 411 ),
+ array( 'other', 12.345 ),
+ array( 'other', 20 ),
+ array( 'one', 31 ),
+ array( 'other', 200 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageMgTest.php b/tests/phpunit/languages/LanguageMgTest.php
new file mode 100644
index 00000000..06b56547
--- /dev/null
+++ b/tests/phpunit/languages/LanguageMgTest.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageMg.php */
+class LanguageMgTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'mg' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 200 ),
+ array( 'other', 123.3434 ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/languages/LanguageMkTest.php b/tests/phpunit/languages/LanguageMkTest.php
new file mode 100644
index 00000000..cf5ec3d9
--- /dev/null
+++ b/tests/phpunit/languages/LanguageMkTest.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageMk.php */
+class LanguageMkTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'mk' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 11 ),
+ array( 'one', 21 ),
+ array( 'other', 411 ),
+ array( 'other', 12.345 ),
+ array( 'other', 20 ),
+ array( 'one', 31 ),
+ array( 'other', 200 ),
+ );
+ }
+
+
+}
diff --git a/tests/phpunit/languages/LanguageMlTest.php b/tests/phpunit/languages/LanguageMlTest.php
new file mode 100644
index 00000000..8c4b0b2f
--- /dev/null
+++ b/tests/phpunit/languages/LanguageMlTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2011, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageMl.php */
+class LanguageMlTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Ml' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** see bug 29495 */
+ /** @dataProvider providerFormatNum*/
+ function testFormatNum( $result, $value ) {
+ $this->assertEquals( $result, $this->lang->formatNum( $value ) );
+ }
+
+ function providerFormatNum() {
+ return array(
+ array( '12,34,567', '1234567' ),
+ array( '12,345', '12345' ),
+ array( '1', '1' ),
+ array( '123', '123' ) ,
+ array( '1,234', '1234' ),
+ array( '12,345.56', '12345.56' ),
+ array( '12,34,56,79,81,23,45,678', '12345679812345678' ),
+ array( '.12345', '.12345' ),
+ array( '-12,00,000', '-1200000' ),
+ array( '-98', '-98' ),
+ array( '-98', -98 ),
+ array( '-1,23,45,678', -12345678 ),
+ array( '', '' ),
+ array( '', null ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageMoTest.php b/tests/phpunit/languages/LanguageMoTest.php
new file mode 100644
index 00000000..533e590f
--- /dev/null
+++ b/tests/phpunit/languages/LanguageMoTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageMo.php */
+class LanguageMoTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'mo' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'few', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 19 ),
+ array( 'other', 20 ),
+ array( 'other', 99 ),
+ array( 'other', 100 ),
+ array( 'few', 101 ),
+ array( 'few', 119 ),
+ array( 'other', 120 ),
+ array( 'other', 200 ),
+ array( 'few', 201 ),
+ array( 'few', 219 ),
+ array( 'other', 220 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageMtTest.php b/tests/phpunit/languages/LanguageMtTest.php
new file mode 100644
index 00000000..421bb388
--- /dev/null
+++ b/tests/phpunit/languages/LanguageMtTest.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageMt.php */
+class LanguageMtTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'mt' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPluralAllForms */
+ function testPluralAllForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPluralAllForms() {
+ return array (
+ array( 'few', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 10 ),
+ array( 'many', 11 ),
+ array( 'many', 19 ),
+ array( 'other', 20 ),
+ array( 'other', 99 ),
+ array( 'other', 100 ),
+ array( 'other', 101 ),
+ array( 'few', 102 ),
+ array( 'few', 110 ),
+ array( 'many', 111 ),
+ array( 'many', 119 ),
+ array( 'other', 120 ),
+ array( 'other', 201 ),
+ );
+ }
+
+ /** @dataProvider providerPluralTwoForms */
+ function testPluralTwoForms( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPluralTwoForms() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ array( 'many', 10 ),
+ array( 'many', 11 ),
+ array( 'many', 19 ),
+ array( 'many', 20 ),
+ array( 'many', 99 ),
+ array( 'many', 100 ),
+ array( 'many', 101 ),
+ array( 'many', 102 ),
+ array( 'many', 110 ),
+ array( 'many', 111 ),
+ array( 'many', 119 ),
+ array( 'many', 120 ),
+ array( 'many', 201 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageNlTest.php b/tests/phpunit/languages/LanguageNlTest.php
new file mode 100644
index 00000000..cf979cd2
--- /dev/null
+++ b/tests/phpunit/languages/LanguageNlTest.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2011, Santhosh Thottingal
+ * @file
+ */
+
+/** Tests for MediaWiki languages/LanguageNl.php */
+class LanguageNlTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Nl' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ function testFormatNum() {
+ $this->assertEquals( '1.234.567', $this->lang->formatNum( '1234567' ) );
+ $this->assertEquals( '12.345', $this->lang->formatNum( '12345' ) );
+ $this->assertEquals( '1', $this->lang->formatNum( '1' ) );
+ $this->assertEquals( '123', $this->lang->formatNum( '123' ) );
+ $this->assertEquals( '1.234', $this->lang->formatNum( '1234' ) );
+ $this->assertEquals( '12.345,56', $this->lang->formatNum( '12345.56' ) );
+ $this->assertEquals( ',1234556', $this->lang->formatNum( '.1234556' ) );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageNsoTest.php b/tests/phpunit/languages/LanguageNsoTest.php
new file mode 100644
index 00000000..ea393628
--- /dev/null
+++ b/tests/phpunit/languages/LanguageNsoTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageNso.php */
+class LanguageNsoTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'nso' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguagePlTest.php b/tests/phpunit/languages/LanguagePlTest.php
new file mode 100644
index 00000000..e56d4b77
--- /dev/null
+++ b/tests/phpunit/languages/LanguagePlTest.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguagePl.php */
+class LanguagePlTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'pl' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPluralFourForms */
+ function testPluralFourForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPluralFourForms() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'many', 5 ),
+ array( 'many', 9 ),
+ array( 'many', 10 ),
+ array( 'many', 11 ),
+ array( 'many', 21 ),
+ array( 'few', 22 ),
+ array( 'few', 23 ),
+ array( 'few', 24 ),
+ array( 'many', 25 ),
+ array( 'many', 200 ),
+ array( 'many', 201 ),
+ );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ array( 'many', 3 ),
+ array( 'many', 4 ),
+ array( 'many', 5 ),
+ array( 'many', 9 ),
+ array( 'many', 10 ),
+ array( 'many', 11 ),
+ array( 'many', 21 ),
+ array( 'many', 22 ),
+ array( 'many', 23 ),
+ array( 'many', 24 ),
+ array( 'many', 25 ),
+ array( 'many', 200 ),
+ array( 'many', 201 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageRoTest.php b/tests/phpunit/languages/LanguageRoTest.php
new file mode 100644
index 00000000..5270f6fe
--- /dev/null
+++ b/tests/phpunit/languages/LanguageRoTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageRo.php */
+class LanguageRoTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'ro' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'few', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 19 ),
+ array( 'other', 20 ),
+ array( 'other', 99 ),
+ array( 'other', 100 ),
+ array( 'few', 101 ),
+ array( 'few', 119 ),
+ array( 'other', 120 ),
+ array( 'other', 200 ),
+ array( 'few', 201 ),
+ array( 'few', 219 ),
+ array( 'other', 220 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageRuTest.php b/tests/phpunit/languages/LanguageRuTest.php
new file mode 100644
index 00000000..7a1f193b
--- /dev/null
+++ b/tests/phpunit/languages/LanguageRuTest.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * based on LanguageBe_tarask.php
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageRu.php */
+class LanguageRuTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'ru' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePluralFourForms */
+ function testPluralFourForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePluralFourForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'many', 11 ),
+ array( 'one', 91 ),
+ array( 'one', 121 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'few', 334 ),
+ array( 'many', 5 ),
+ array( 'many', 15 ),
+ array( 'many', 120 ),
+ );
+ }
+ /** @dataProvider providePluralTwoForms */
+ function testPluralTwoForms( $result, $value ) {
+ $forms = array( 'one', 'several' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providePluralTwoForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'several', 11 ),
+ array( 'several', 91 ),
+ array( 'several', 121 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageSeTest.php b/tests/phpunit/languages/LanguageSeTest.php
new file mode 100644
index 00000000..065ec29e
--- /dev/null
+++ b/tests/phpunit/languages/LanguageSeTest.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageSe.php */
+class LanguageSeTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'se' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPluralThreeForms */
+ function testPluralThreeForms( $result, $value ) {
+ $forms = array( 'one', 'two', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPluralThreeForms() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'two', 2 ),
+ array( 'other', 3 ),
+ );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 3 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageSgsTest.php b/tests/phpunit/languages/LanguageSgsTest.php
new file mode 100644
index 00000000..931c82f0
--- /dev/null
+++ b/tests/phpunit/languages/LanguageSgsTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageSgs.php */
+class LanguageSgsTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Sgs' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePluralAllForms */
+ function testPluralAllForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePluralAllForms() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'other', 3 ),
+ array( 'many', 10 ),
+ array( 'many', 11 ),
+ array( 'many', 12 ),
+ array( 'many', 19 ),
+ array( 'other', 20 ),
+ array( 'many', 100 ),
+ array( 'one', 101 ),
+ array( 'many', 111 ),
+ array( 'many', 112 ),
+ );
+ }
+
+ /** @dataProvider providePluralTwoForms */
+ function testPluralTwoForms( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePluralTwoForms() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 3 ),
+ array( 'other', 10 ),
+ array( 'other', 11 ),
+ array( 'other', 12 ),
+ array( 'other', 19 ),
+ array( 'other', 20 ),
+ array( 'other', 100 ),
+ array( 'one', 101 ),
+ array( 'other', 111 ),
+ array( 'other', 112 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageShTest.php b/tests/phpunit/languages/LanguageShTest.php
new file mode 100644
index 00000000..b8169aed
--- /dev/null
+++ b/tests/phpunit/languages/LanguageShTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageSh.php */
+class LanguageShTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'sh' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'many', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageSkTest.php b/tests/phpunit/languages/LanguageSkTest.php
new file mode 100644
index 00000000..4cfd840e
--- /dev/null
+++ b/tests/phpunit/languages/LanguageSkTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * based on LanguageSkTest.php
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageSk.php */
+class LanguageSkTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'sk' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'few', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'other', 5 ),
+ array( 'other', 11 ),
+ array( 'other', 20 ),
+ array( 'other', 25 ),
+ array( 'other', 200 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageSlTest.php b/tests/phpunit/languages/LanguageSlTest.php
new file mode 100644
index 00000000..c1f75691
--- /dev/null
+++ b/tests/phpunit/languages/LanguageSlTest.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @author Santhosh Thottingal
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * based on LanguageSkTest.php
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageSl.php */
+class LanguageSlTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'sl' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'two', 'few', 'other', 'zero' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'zero', 0 ),
+ array( 'one', 1 ),
+ array( 'two', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'other', 5 ),
+ array( 'other', 99 ),
+ array( 'other', 100 ),
+ array( 'one', 101 ),
+ array( 'two', 102 ),
+ array( 'few', 103 ),
+ array( 'one', 201 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageSmaTest.php b/tests/phpunit/languages/LanguageSmaTest.php
new file mode 100644
index 00000000..b7e72e97
--- /dev/null
+++ b/tests/phpunit/languages/LanguageSmaTest.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageSma.php */
+class LanguageSmaTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'sma' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPluralThreeForms */
+ function testPluralThreeForms( $result, $value ) {
+ $forms = array( 'one', 'two', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPluralThreeForms() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'two', 2 ),
+ array( 'other', 3 ),
+ );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'other', 0 ),
+ array( 'one', 1 ),
+ array( 'other', 2 ),
+ array( 'other', 3 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageSrTest.php b/tests/phpunit/languages/LanguageSrTest.php
new file mode 100644
index 00000000..a50547c6
--- /dev/null
+++ b/tests/phpunit/languages/LanguageSrTest.php
@@ -0,0 +1,199 @@
+<?php
+/**
+ * PHPUnit tests for the Serbian language.
+ * The language can be represented using two scripts:
+ * - Latin (SR_el)
+ * - Cyrillic (SR_ec)
+ * Both representations seems to be bijective, hence MediaWiki can convert
+ * from one script to the other.
+ *
+ * @author Antoine Musso <hashar at free dot fr>
+ * @copyright Copyright © 2011, Antoine Musso <hashar at free dot fr>
+ * @file
+ */
+
+require_once dirname( dirname( __FILE__ ) ) . '/bootstrap.php';
+
+/** Tests for MediaWiki languages/LanguageTr.php */
+class LanguageSrTest extends MediaWikiTestCase {
+ /* Language object. Initialized before each test */
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'sr' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ ##### TESTS #######################################################
+
+ function testEasyConversions( ) {
+ $this->assertCyrillic(
+ 'шђчћжШЂЧЋЖ',
+ 'Cyrillic guessing characters'
+ );
+ $this->assertLatin(
+ 'šđč枊ĐČĆŽ',
+ 'Latin guessing characters'
+ );
+ }
+
+ function testMixedConversions() {
+ $this->assertCyrillic(
+ 'шђчћжШЂЧЋЖ - šđčćž',
+ 'Mostly cyrillic characters'
+ );
+ $this->assertLatin(
+ 'šđč枊ĐČĆŽ - шђчћж',
+ 'Mostly latin characters'
+ );
+ }
+
+ function testSameAmountOfLatinAndCyrillicGetConverted() {
+ $this->assertConverted(
+ '4 latin: šđčć | 4 cyrillic: шђчћ',
+ 'sr-ec'
+ );
+ $this->assertConverted(
+ '4 latin: šđčć | 4 cyrillic: шђчћ',
+ 'sr-el'
+ );
+ }
+
+ /**
+ * @author Nikola Smolenski
+ */
+ function testConversionToCyrillic() {
+ $this->assertEquals( 'абвг',
+ $this->convertToCyrillic( 'abvg' )
+ );
+ $this->assertEquals( 'абвг',
+ $this->convertToCyrillic( 'абвг' )
+ );
+ $this->assertEquals( 'abvgшђжчћ',
+ $this->convertToCyrillic( 'abvgшђжчћ' )
+ );
+ $this->assertEquals( 'абвгшђжчћ',
+ $this->convertToCyrillic( 'абвгšđžčć' )
+ );
+ // Roman numerals are not converted
+ $this->assertEquals( 'а I б II в III г IV шђжчћ',
+ $this->convertToCyrillic( 'a I b II v III g IV šđžčć' )
+ );
+ }
+
+ function testConversionToLatin() {
+ $this->assertEquals( 'abcd',
+ $this->convertToLatin( 'abcd' )
+ );
+ $this->assertEquals( 'abcd',
+ $this->convertToLatin( 'абцд' )
+ );
+ $this->assertEquals( 'abcdšđžčć',
+ $this->convertToLatin( 'abcdшђжчћ' )
+ );
+ $this->assertEquals( 'абцдšđžčć',
+ $this->convertToLatin( 'абцдšđžčć' )
+ );
+ }
+
+ /** @dataProvider providePluralFourForms */
+ function testPluralFourForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePluralFourForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'many', 11 ),
+ array( 'one', 91 ),
+ array( 'one', 121 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'few', 334 ),
+ array( 'many', 5 ),
+ array( 'many', 15 ),
+ array( 'many', 120 ),
+ );
+ }
+ /** @dataProvider providePluralTwoForms */
+ function testPluralTwoForms( $result, $value ) {
+ $forms = array( 'one', 'several' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providePluralTwoForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'several', 11 ),
+ array( 'several', 91 ),
+ array( 'several', 121 ),
+ );
+ }
+
+ ##### HELPERS #####################################################
+ /**
+ *Wrapper to verify text stay the same after applying conversion
+ * @param $text string Text to convert
+ * @param $variant string Language variant 'sr-ec' or 'sr-el'
+ * @param $msg string Optional message
+ */
+ function assertUnConverted( $text, $variant, $msg = '' ) {
+ $this->assertEquals(
+ $text,
+ $this->convertTo( $text, $variant ),
+ $msg
+ );
+ }
+ /**
+ * Wrapper to verify a text is different once converted to a variant.
+ * @param $text string Text to convert
+ * @param $variant string Language variant 'sr-ec' or 'sr-el'
+ * @param $msg string Optional message
+ */
+ function assertConverted( $text, $variant, $msg = '' ) {
+ $this->assertNotEquals(
+ $text,
+ $this->convertTo( $text, $variant ),
+ $msg
+ );
+ }
+
+ /**
+ * Verifiy the given Cyrillic text is not converted when using
+ * using the cyrillic variant and converted to Latin when using
+ * the Latin variant.
+ */
+ function assertCyrillic( $text, $msg = '' ) {
+ $this->assertUnConverted( $text, 'sr-ec', $msg );
+ $this->assertConverted( $text, 'sr-el', $msg );
+ }
+ /**
+ * Verifiy the given Latin text is not converted when using
+ * using the Latin variant and converted to Cyrillic when using
+ * the Cyrillic variant.
+ */
+ function assertLatin( $text, $msg = '' ) {
+ $this->assertUnConverted( $text, 'sr-el', $msg );
+ $this->assertConverted( $text, 'sr-ec', $msg );
+ }
+
+
+ /** Wrapper for converter::convertTo() method*/
+ function convertTo( $text, $variant ) {
+ return $this
+ ->lang
+ ->mConverter
+ ->convertTo(
+ $text, $variant
+ );
+ }
+ function convertToCyrillic( $text ) {
+ return $this->convertTo( $text, 'sr-ec' );
+ }
+ function convertToLatin( $text ) {
+ return $this->convertTo( $text, 'sr-el' );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageTest.php b/tests/phpunit/languages/LanguageTest.php
index aaad9c31..c83e01ea 100644
--- a/tests/phpunit/languages/LanguageTest.php
+++ b/tests/phpunit/languages/LanguageTest.php
@@ -1,6 +1,10 @@
<?php
class LanguageTest extends MediaWikiTestCase {
+
+ /**
+ * @var Language
+ */
private $lang;
function setUp() {
@@ -19,97 +23,46 @@ class LanguageTest extends MediaWikiTestCase {
'convertDoubleWidth() with the full alphabet and digits'
);
}
-
- function testFormatTimePeriod() {
- $this->assertEquals(
- "9.5s",
- $this->lang->formatTimePeriod( 9.45 ),
- 'formatTimePeriod() rounding (<10s)'
- );
-
- $this->assertEquals(
- "10s",
- $this->lang->formatTimePeriod( 9.95 ),
- 'formatTimePeriod() rounding (<10s)'
- );
-
- $this->assertEquals(
- "1m 0s",
- $this->lang->formatTimePeriod( 59.55 ),
- 'formatTimePeriod() rounding (<60s)'
- );
-
- $this->assertEquals(
- "2m 0s",
- $this->lang->formatTimePeriod( 119.55 ),
- 'formatTimePeriod() rounding (<1h)'
- );
-
- $this->assertEquals(
- "1h 0m 0s",
- $this->lang->formatTimePeriod( 3599.55 ),
- 'formatTimePeriod() rounding (<1h)'
- );
-
- $this->assertEquals(
- "2h 0m 0s",
- $this->lang->formatTimePeriod( 7199.55 ),
- 'formatTimePeriod() rounding (>=1h)'
- );
-
- $this->assertEquals(
- "2h 0m",
- $this->lang->formatTimePeriod( 7199.55, 'avoidseconds' ),
- 'formatTimePeriod() rounding (>=1h), avoidseconds'
- );
-
- $this->assertEquals(
- "2h 0m",
- $this->lang->formatTimePeriod( 7199.55, 'avoidminutes' ),
- 'formatTimePeriod() rounding (>=1h), avoidminutes'
- );
-
- $this->assertEquals(
- "48h 0m",
- $this->lang->formatTimePeriod( 172799.55, 'avoidseconds' ),
- 'formatTimePeriod() rounding (=48h), avoidseconds'
- );
-
- $this->assertEquals(
- "3d 0h",
- $this->lang->formatTimePeriod( 259199.55, 'avoidminutes' ),
- 'formatTimePeriod() rounding (>48h), avoidminutes'
- );
-
- $this->assertEquals(
- "2d 1h 0m",
- $this->lang->formatTimePeriod( 176399.55, 'avoidseconds' ),
- 'formatTimePeriod() rounding (>48h), avoidseconds'
- );
-
- $this->assertEquals(
- "2d 1h",
- $this->lang->formatTimePeriod( 176399.55, 'avoidminutes' ),
- 'formatTimePeriod() rounding (>48h), avoidminutes'
- );
-
- $this->assertEquals(
- "3d 0h 0m",
- $this->lang->formatTimePeriod( 259199.55, 'avoidseconds' ),
- 'formatTimePeriod() rounding (>48h), avoidminutes'
- );
-
- $this->assertEquals(
- "2d 0h 0m",
- $this->lang->formatTimePeriod( 172801.55, 'avoidseconds' ),
- 'formatTimePeriod() rounding, (>48h), avoidseconds'
- );
-
- $this->assertEquals(
- "2d 1h 1m 1s",
- $this->lang->formatTimePeriod( 176460.55 ),
- 'formatTimePeriod() rounding, recursion, (>48h)'
+
+ /** @dataProvider provideFormattableTimes */
+ function testFormatTimePeriod( $seconds, $format, $expected, $desc ) {
+ $this->assertEquals( $expected, $this->lang->formatTimePeriod( $seconds, $format ), $desc );
+ }
+
+ function provideFormattableTimes() {
+ return array(
+ array( 9.45, array(), '9.5s', 'formatTimePeriod() rounding (<10s)' ),
+ array( 9.45, array( 'noabbrevs' => true ), '9.5 seconds', 'formatTimePeriod() rounding (<10s)' ),
+ array( 9.95, array(), '10s', 'formatTimePeriod() rounding (<10s)' ),
+ array( 9.95, array( 'noabbrevs' => true ), '10 seconds', 'formatTimePeriod() rounding (<10s)' ),
+ array( 59.55, array(), '1m 0s', 'formatTimePeriod() rounding (<60s)' ),
+ array( 59.55, array( 'noabbrevs' => true ), '1 minute 0 seconds', 'formatTimePeriod() rounding (<60s)' ),
+ array( 119.55, array(), '2m 0s', 'formatTimePeriod() rounding (<1h)' ),
+ array( 119.55, array( 'noabbrevs' => true ), '2 minutes 0 seconds', 'formatTimePeriod() rounding (<1h)' ),
+ array( 3599.55, array(), '1h 0m 0s', 'formatTimePeriod() rounding (<1h)' ),
+ array( 3599.55, array( 'noabbrevs' => true ), '1 hour 0 minutes 0 seconds', 'formatTimePeriod() rounding (<1h)' ),
+ array( 7199.55, array(), '2h 0m 0s', 'formatTimePeriod() rounding (>=1h)' ),
+ array( 7199.55, array( 'noabbrevs' => true ), '2 hours 0 minutes 0 seconds', 'formatTimePeriod() rounding (>=1h)' ),
+ array( 7199.55, 'avoidseconds', '2h 0m', 'formatTimePeriod() rounding (>=1h), avoidseconds' ),
+ array( 7199.55, array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), '2 hours 0 minutes', 'formatTimePeriod() rounding (>=1h), avoidseconds' ),
+ array( 7199.55, 'avoidminutes', '2h 0m', 'formatTimePeriod() rounding (>=1h), avoidminutes' ),
+ array( 7199.55, array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ), '2 hours 0 minutes', 'formatTimePeriod() rounding (>=1h), avoidminutes' ),
+ array( 172799.55, 'avoidseconds', '48h 0m', 'formatTimePeriod() rounding (=48h), avoidseconds' ),
+ array( 172799.55, array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), '48 hours 0 minutes', 'formatTimePeriod() rounding (=48h), avoidseconds' ),
+ array( 259199.55, 'avoidminutes', '3d 0h', 'formatTimePeriod() rounding (>48h), avoidminutes' ),
+ array( 259199.55, array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ), '3 days 0 hours', 'formatTimePeriod() rounding (>48h), avoidminutes' ),
+ array( 176399.55, 'avoidseconds', '2d 1h 0m', 'formatTimePeriod() rounding (>48h), avoidseconds' ),
+ array( 176399.55, array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), '2 days 1 hour 0 minutes', 'formatTimePeriod() rounding (>48h), avoidseconds' ),
+ array( 176399.55, 'avoidminutes', '2d 1h', 'formatTimePeriod() rounding (>48h), avoidminutes' ),
+ array( 176399.55, array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ), '2 days 1 hour', 'formatTimePeriod() rounding (>48h), avoidminutes' ),
+ array( 259199.55, 'avoidseconds', '3d 0h 0m', 'formatTimePeriod() rounding (>48h), avoidseconds' ),
+ array( 259199.55, array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), '3 days 0 hours 0 minutes', 'formatTimePeriod() rounding (>48h), avoidseconds' ),
+ array( 172801.55, 'avoidseconds', '2d 0h 0m', 'formatTimePeriod() rounding, (>48h), avoidseconds' ),
+ array( 172801.55, array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), '2 days 0 hours 0 minutes', 'formatTimePeriod() rounding, (>48h), avoidseconds' ),
+ array( 176460.55, array(), '2d 1h 1m 1s', 'formatTimePeriod() rounding, recursion, (>48h)' ),
+ array( 176460.55, array( 'noabbrevs' => true ), '2 days 1 hour 1 minute 1 second', 'formatTimePeriod() rounding, recursion, (>48h)' ),
);
+
}
function testTruncate() {
@@ -243,4 +196,462 @@ class LanguageTest extends MediaWikiTestCase {
array( 'Be-x-old', 'With extension (two dashes)' ),
);
}
+
+ /**
+ * @dataProvider provideSprintfDateSamples
+ */
+ function testSprintfDate( $format, $ts, $expected, $msg ) {
+ $this->assertEquals(
+ $expected,
+ $this->lang->sprintfDate( $format, $ts ),
+ "sprintfDate('$format', '$ts'): $msg"
+ );
+ }
+ /**
+ * bug 33454. sprintfDate should always use UTC.
+ * @dataProvider provideSprintfDateSamples
+ */
+ function testSprintfDateTZ( $format, $ts, $expected, $msg ) {
+ $oldTZ = date_default_timezone_get();
+ $res = date_default_timezone_set( 'Asia/Seoul' );
+ if ( !$res ) {
+ $this->markTestSkipped( "Error setting Timezone" );
+ }
+
+ $this->assertEquals(
+ $expected,
+ $this->lang->sprintfDate( $format, $ts ),
+ "sprintfDate('$format', '$ts'): $msg"
+ );
+
+ date_default_timezone_set( $oldTZ );
+ }
+
+ function provideSprintfDateSamples() {
+ return array(
+ array(
+ 'xiY',
+ '20111212000000',
+ '1390', // note because we're testing English locale we get Latin-standard digits
+ 'Iranian calendar full year'
+ ),
+ array(
+ 'xiy',
+ '20111212000000',
+ '90',
+ 'Iranian calendar short year'
+ ),
+ array(
+ 'o',
+ '20120101235000',
+ '2011',
+ 'ISO 8601 (week) year'
+ ),
+ array(
+ 'W',
+ '20120101235000',
+ '52',
+ 'Week number'
+ ),
+ array(
+ 'W',
+ '20120102235000',
+ '1',
+ 'Week number'
+ ),
+ array(
+ 'o-\\WW-N',
+ '20091231235000',
+ '2009-W53-4',
+ 'leap week'
+ ),
+ // What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
+ array(
+ 'Y',
+ '20120102090705',
+ '2012',
+ 'Full year'
+ ),
+ array(
+ 'y',
+ '20120102090705',
+ '12',
+ '2 digit year'
+ ),
+ array(
+ 'L',
+ '20120102090705',
+ '1',
+ 'Leap year'
+ ),
+ array(
+ 'n',
+ '20120102090705',
+ '1',
+ 'Month index, not zero pad'
+ ),
+ array(
+ 'N',
+ '20120102090705',
+ '01',
+ 'Month index. Zero pad'
+ ),
+ array(
+ 'M',
+ '20120102090705',
+ 'Jan',
+ 'Month abbrev'
+ ),
+ array(
+ 'F',
+ '20120102090705',
+ 'January',
+ 'Full month'
+ ),
+ array(
+ 'xg',
+ '20120102090705',
+ 'January',
+ 'Genitive month name (same in EN)'
+ ),
+ array(
+ 'j',
+ '20120102090705',
+ '2',
+ 'Day of month (not zero pad)'
+ ),
+ array(
+ 'd',
+ '20120102090705',
+ '02',
+ 'Day of month (zero-pad)'
+ ),
+ array(
+ 'z',
+ '20120102090705',
+ '1',
+ 'Day of year (zero-indexed)'
+ ),
+ array(
+ 'D',
+ '20120102090705',
+ 'Mon',
+ 'Day of week (abbrev)'
+ ),
+ array(
+ 'l',
+ '20120102090705',
+ 'Monday',
+ 'Full day of week'
+ ),
+ array(
+ 'N',
+ '20120101090705',
+ '7',
+ 'Day of week (Mon=1, Sun=7)'
+ ),
+ array(
+ 'w',
+ '20120101090705',
+ '0',
+ 'Day of week (Sun=0, Sat=6)'
+ ),
+ array(
+ 'N',
+ '20120102090705',
+ '1',
+ 'Day of week'
+ ),
+ array(
+ 'a',
+ '20120102090705',
+ 'am',
+ 'am vs pm'
+ ),
+ array(
+ 'A',
+ '20120102120000',
+ 'PM',
+ 'AM vs PM'
+ ),
+ array(
+ 'a',
+ '20120102000000',
+ 'am',
+ 'AM vs PM'
+ ),
+ array(
+ 'g',
+ '20120102090705',
+ '9',
+ '12 hour, not Zero'
+ ),
+ array(
+ 'h',
+ '20120102090705',
+ '09',
+ '12 hour, zero padded'
+ ),
+ array(
+ 'G',
+ '20120102090705',
+ '9',
+ '24 hour, not zero'
+ ),
+ array(
+ 'H',
+ '20120102090705',
+ '09',
+ '24 hour, zero'
+ ),
+ array(
+ 'H',
+ '20120102110705',
+ '11',
+ '24 hour, zero'
+ ),
+ array(
+ 'i',
+ '20120102090705',
+ '07',
+ 'Minutes'
+ ),
+ array(
+ 's',
+ '20120102090705',
+ '05',
+ 'seconds'
+ ),
+ array(
+ 'U',
+ '20120102090705',
+ '1325495225',
+ 'unix time'
+ ),
+ array(
+ 't',
+ '20120102090705',
+ '31',
+ 'Days in current month'
+ ),
+ array(
+ 'c',
+ '20120102090705',
+ '2012-01-02T09:07:05+00:00',
+ 'ISO 8601 timestamp'
+ ),
+ array(
+ 'r',
+ '20120102090705',
+ 'Mon, 02 Jan 2012 09:07:05 +0000',
+ 'RFC 5322'
+ ),
+ array(
+ 'xmj xmF xmn xmY',
+ '20120102090705',
+ '7 Safar 2 1433',
+ 'Islamic'
+ ),
+ array(
+ 'xij xiF xin xiY',
+ '20120102090705',
+ '12 Dey 10 1390',
+ 'Iranian'
+ ),
+ array(
+ 'xjj xjF xjn xjY',
+ '20120102090705',
+ '7 Tevet 4 5772',
+ 'Hebrew'
+ ),
+ array(
+ 'xjt',
+ '20120102090705',
+ '29',
+ 'Hebrew number of days in month'
+ ),
+ array(
+ 'xjx',
+ '20120102090705',
+ 'Tevet',
+ 'Hebrew genitive month name (No difference in EN)'
+ ),
+ array(
+ 'xkY',
+ '20120102090705',
+ '2555',
+ 'Thai year'
+ ),
+ array(
+ 'xoY',
+ '20120102090705',
+ '101',
+ 'Minguo'
+ ),
+ array(
+ 'xtY',
+ '20120102090705',
+ '平成24',
+ 'nengo'
+ ),
+ array(
+ 'xrxkYY',
+ '20120102090705',
+ 'MMDLV2012',
+ 'Roman numerals'
+ ),
+ array(
+ 'xhxjYY',
+ '20120102090705',
+ 'ה\'תשע"ב2012',
+ 'Hebrew numberals'
+ ),
+ array(
+ 'xnY',
+ '20120102090705',
+ '2012',
+ 'Raw numerals (doesn\'t mean much in EN)'
+ ),
+ array(
+ '[[Y "(yea"\\r)]] \\"xx\\"',
+ '20120102090705',
+ '[[2012 (year)]] "x"',
+ 'Various escaping'
+ ),
+
+ );
+ }
+
+ /**
+ * @dataProvider provideFormatSizes
+ */
+ function testFormatSize( $size, $expected, $msg ) {
+ $this->assertEquals(
+ $expected,
+ $this->lang->formatSize( $size ),
+ "formatSize('$size'): $msg"
+ );
+ }
+
+ function provideFormatSizes() {
+ return array(
+ array(
+ 0,
+ "0 B",
+ "Zero bytes"
+ ),
+ array(
+ 1024,
+ "1 KB",
+ "1 kilobyte"
+ ),
+ array(
+ 1024 * 1024,
+ "1 MB",
+ "1,024 megabytes"
+ ),
+ array(
+ 1024 * 1024 * 1024,
+ "1 GB",
+ "1 gigabytes"
+ ),
+ array(
+ pow( 1024, 4 ),
+ "1 TB",
+ "1 terabyte"
+ ),
+ array(
+ pow( 1024, 5 ),
+ "1 PB",
+ "1 petabyte"
+ ),
+ array(
+ pow( 1024, 6 ),
+ "1 EB",
+ "1,024 exabyte"
+ ),
+ array(
+ pow( 1024, 7 ),
+ "1 ZB",
+ "1 zetabyte"
+ ),
+ array(
+ pow( 1024, 8 ),
+ "1 YB",
+ "1 yottabyte"
+ ),
+ // How big!? THIS BIG!
+ );
+ }
+
+ /**
+ * @dataProvider provideFormatBitrate
+ */
+ function testFormatBitrate( $bps, $expected, $msg ) {
+ $this->assertEquals(
+ $expected,
+ $this->lang->formatBitrate( $bps ),
+ "formatBitrate('$bps'): $msg"
+ );
+ }
+
+ function provideFormatBitrate() {
+ return array(
+ array(
+ 0,
+ "0bps",
+ "0 bits per second"
+ ),
+ array(
+ 999,
+ "999bps",
+ "999 bits per second"
+ ),
+ array(
+ 1000,
+ "1kbps",
+ "1 kilobit per second"
+ ),
+ array(
+ 1000 * 1000,
+ "1Mbps",
+ "1 megabit per second"
+ ),
+ array(
+ pow( 10, 9 ),
+ "1Gbps",
+ "1 gigabit per second"
+ ),
+ array(
+ pow( 10, 12 ),
+ "1Tbps",
+ "1 terabit per second"
+ ),
+ array(
+ pow( 10, 15 ),
+ "1Pbps",
+ "1 petabit per second"
+ ),
+ array(
+ pow( 10, 18 ),
+ "1Ebps",
+ "1 exabit per second"
+ ),
+ array(
+ pow( 10, 21 ),
+ "1Zbps",
+ "1 zetabit per second"
+ ),
+ array(
+ pow( 10, 24 ),
+ "1Ybps",
+ "1 yottabit per second"
+ ),
+ array(
+ pow( 10, 27 ),
+ "1,000Ybps",
+ "1,000 yottabits per second"
+ ),
+ );
+ }
}
diff --git a/tests/phpunit/languages/LanguageTiTest.php b/tests/phpunit/languages/LanguageTiTest.php
new file mode 100644
index 00000000..4bfaa009
--- /dev/null
+++ b/tests/phpunit/languages/LanguageTiTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageTi.php */
+class LanguageTiTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Ti' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageTlTest.php b/tests/phpunit/languages/LanguageTlTest.php
new file mode 100644
index 00000000..a1facd14
--- /dev/null
+++ b/tests/phpunit/languages/LanguageTlTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageTl.php */
+class LanguageTlTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Tl' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageTrTest.php b/tests/phpunit/languages/LanguageTrTest.php
index d2a5ff36..bda4c9d9 100644
--- a/tests/phpunit/languages/LanguageTrTest.php
+++ b/tests/phpunit/languages/LanguageTrTest.php
@@ -1,7 +1,7 @@
<?php
/**
- * @author Ashar Voultoiz
- * @copyright Copyright © 2011, Ashar Voultoiz
+ * @author Antoine Musso
+ * @copyright Copyright © 2011, Antoine Musso
* @file
*/
@@ -18,7 +18,10 @@ class LanguageTrTest extends MediaWikiTestCase {
/**
* See @bug 28040
- * Credits to #wikipedia-tr users berm, []LuCkY[] and Emperyan
+ * Credits to irc://irc.freenode.net/wikipedia-tr users:
+ * - berm
+ * - []LuCkY[]
+ * - Emperyan
* @see http://en.wikipedia.org/wiki/Dotted_and_dotless_I
* @dataProvider provideDottedAndDotlessI
*/
diff --git a/tests/phpunit/languages/LanguageUkTest.php b/tests/phpunit/languages/LanguageUkTest.php
new file mode 100644
index 00000000..60fafb0d
--- /dev/null
+++ b/tests/phpunit/languages/LanguageUkTest.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * based on LanguageBe_tarask.php
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageUk.php */
+class LanguageUkTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Uk' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providePluralFourForms */
+ function testPluralFourForms( $result, $value ) {
+ $forms = array( 'one', 'few', 'many', 'other' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providePluralFourForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'many', 11 ),
+ array( 'one', 91 ),
+ array( 'one', 121 ),
+ array( 'few', 2 ),
+ array( 'few', 3 ),
+ array( 'few', 4 ),
+ array( 'few', 334 ),
+ array( 'many', 5 ),
+ array( 'many', 15 ),
+ array( 'many', 120 ),
+ );
+ }
+ /** @dataProvider providePluralTwoForms */
+ function testPluralTwoForms( $result, $value ) {
+ $forms = array( 'one', 'several' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+ function providePluralTwoForms() {
+ return array (
+ array( 'one', 1 ),
+ array( 'several', 11 ),
+ array( 'several', 91 ),
+ array( 'several', 121 ),
+ );
+ }
+}
diff --git a/tests/phpunit/languages/LanguageWaTest.php b/tests/phpunit/languages/LanguageWaTest.php
new file mode 100644
index 00000000..172f19b9
--- /dev/null
+++ b/tests/phpunit/languages/LanguageWaTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @author Amir E. Aharoni
+ * @copyright Copyright © 2012, Amir E. Aharoni
+ * @file
+ */
+
+/** Tests for MediaWiki languages/classes/LanguageWa.php */
+class LanguageWaTest extends MediaWikiTestCase {
+ private $lang;
+
+ function setUp() {
+ $this->lang = Language::factory( 'Wa' );
+ }
+ function tearDown() {
+ unset( $this->lang );
+ }
+
+ /** @dataProvider providerPlural */
+ function testPlural( $result, $value ) {
+ $forms = array( 'one', 'many' );
+ $this->assertEquals( $result, $this->lang->convertPlural( $value, $forms ) );
+ }
+
+ function providerPlural() {
+ return array (
+ array( 'one', 0 ),
+ array( 'one', 1 ),
+ array( 'many', 2 ),
+ );
+ }
+}
diff --git a/tests/phpunit/phpunit.php b/tests/phpunit/phpunit.php
index 39cccf80..92eeffa2 100644
--- a/tests/phpunit/phpunit.php
+++ b/tests/phpunit/phpunit.php
@@ -46,8 +46,8 @@ require( RUN_MAINTENANCE_IF_MAIN );
if( !in_array( '--configuration', $_SERVER['argv'] ) ) {
//Hack to eliminate the need to use the Makefile (which sucks ATM)
- $_SERVER['argv'][] = '--configuration';
- $_SERVER['argv'][] = $IP . '/tests/phpunit/suite.xml';
+ array_splice( $_SERVER['argv'], 1, 0,
+ array( '--configuration', $IP . '/tests/phpunit/suite.xml' ) );
}
require_once( 'PHPUnit/Runner/Version.php' );
diff --git a/tests/phpunit/skins/SideBarTest.php b/tests/phpunit/skins/SideBarTest.php
index bf79e760..912d7602 100644
--- a/tests/phpunit/skins/SideBarTest.php
+++ b/tests/phpunit/skins/SideBarTest.php
@@ -37,6 +37,7 @@ class SideBarTest extends MediaWikiLangTestCase {
parent::setUp();
$this->initMessagesHref();
$this->skin = new SkinTemplate();
+ $this->skin->getContext()->setLanguage( Language::factory( 'en' ) );
}
function tearDown() {
parent::tearDown();
@@ -106,7 +107,7 @@ class SideBarTest extends MediaWikiLangTestCase {
}
/**
- * bug 33321
+ * bug 33321 - Make sure there's a | after transforming.
* @group Database
*/
function testTrickyPipe() {
@@ -168,7 +169,7 @@ class SideBarTest extends MediaWikiLangTestCase {
}
/**
- * Test wgNoFollowLinks in sidebar
+ * Test $wgNoFollowLinks in sidebar
*/
function testRespectWgnofollowlinks() {
global $wgNoFollowLinks;
@@ -177,7 +178,7 @@ class SideBarTest extends MediaWikiLangTestCase {
$attribs = $this->getAttribs();
$this->assertArrayNotHasKey( 'rel', $attribs,
- 'External URL in sidebar do not have rel=nofollow when wgNoFollowLinks = false'
+ 'External URL in sidebar do not have rel=nofollow when $wgNoFollowLinks = false'
);
// Restore global
@@ -185,7 +186,7 @@ class SideBarTest extends MediaWikiLangTestCase {
}
/**
- * Test wgExternaLinkTarget in sidebar
+ * Test $wgExternaLinkTarget in sidebar
*/
function testRespectExternallinktarget() {
global $wgExternalLinkTarget;
diff --git a/tests/phpunit/suite.xml b/tests/phpunit/suite.xml
index e6649beb..1227a17a 100644
--- a/tests/phpunit/suite.xml
+++ b/tests/phpunit/suite.xml
@@ -2,35 +2,42 @@
<!-- colors don't work on Windows! -->
<phpunit bootstrap="./bootstrap.php"
- colors="false"
+ colors="true"
backupGlobals="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false"
+ timeoutForSmallTests="2"
+ timeoutForMediumTests="10"
+ timeoutForLargeTests="60"
strict="true"
verbose="true">
<testsuites>
<testsuite name="includes">
- <directory>./includes</directory>
+ <directory>includes</directory>
</testsuite>
<testsuite name="languages">
- <directory>./languages</directory>
+ <directory>languages</directory>
</testsuite>
<testsuite name="skins">
- <directory>./skins</directory>
+ <directory>skins</directory>
+ </testsuite>
+ <testsuite name="structure">
+ <file>StructureTest.php</file>
</testsuite>
<testsuite name="uploadfromurl">
- <file>./suites/UploadFromUrlTestSuite.php</file>
+ <file>suites/UploadFromUrlTestSuite.php</file>
</testsuite>
<testsuite name="extensions">
- <file>./suites/ExtensionsTestSuite.php</file>
+ <file>suites/ExtensionsTestSuite.php</file>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>Utility</group>
<group>Broken</group>
+ <group>ParserFuzz</group>
<group>Stub</group>
</exclude>
</groups>
diff --git a/tests/phpunit/suites/UploadFromUrlTestSuite.php b/tests/phpunit/suites/UploadFromUrlTestSuite.php
index 9b666825..6779ad47 100644
--- a/tests/phpunit/suites/UploadFromUrlTestSuite.php
+++ b/tests/phpunit/suites/UploadFromUrlTestSuite.php
@@ -3,6 +3,8 @@
require_once( dirname( dirname( __FILE__ ) ) . '/includes/upload/UploadFromUrlTest.php' );
class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
+ public $savedGlobals = array();
+
public static function addTables( &$tables ) {
$tables[] = 'user_properties';
$tables[] = 'filearchive';
@@ -14,34 +16,49 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
}
function setUp() {
- global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
- $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
- $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
- $parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
- $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath;
-
- $wgScript = '/index.php';
- $wgScriptPath = '/';
- $wgArticlePath = '/wiki/$1';
- $wgStyleSheetPath = '/skins';
- $wgStylePath = '/skins';
- $wgThumbnailScriptPath = false;
- $wgLocalFileRepo = array(
- 'class' => 'LocalRepo',
- 'name' => 'local',
- 'directory' => wfTempDir() . '/test-repo',
- 'url' => 'http://example.com/images',
- 'deletedDir' => wfTempDir() . '/test-repo/delete',
- 'hashLevels' => 2,
+ global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
+ $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
+ $wgNamespaceAliases, $wgNamespaceProtection, $parserMemc;
+
+ $tmpGlobals = array();
+
+ $tmpGlobals['wgScript'] = '/index.php';
+ $tmpGlobals['wgScriptPath'] = '/';
+ $tmpGlobals['wgArticlePath'] = '/wiki/$1';
+ $tmpGlobals['wgStyleSheetPath'] = '/skins';
+ $tmpGlobals['wgStylePath'] = '/skins';
+ $tmpGlobals['wgThumbnailScriptPath'] = false;
+ $tmpGlobals['wgLocalFileRepo'] = array(
+ 'class' => 'LocalRepo',
+ 'name' => 'local',
+ 'url' => 'http://example.com/images',
+ 'hashLevels' => 2,
'transformVia404' => false,
+ 'backend' => new FSFileBackend( array(
+ 'name' => 'local-backend',
+ 'lockManager' => 'fsLockManager',
+ 'containerPaths' => array(
+ 'local-public' => wfTempDir() . '/test-repo/public',
+ 'local-thumb' => wfTempDir() . '/test-repo/thumb',
+ 'local-temp' => wfTempDir() . '/test-repo/temp',
+ 'local-deleted' => wfTempDir() . '/test-repo/delete',
+ )
+ ) ),
);
+ foreach ( $tmpGlobals as $var => $val ) {
+ if ( array_key_exists( $var, $GLOBALS ) ) {
+ $this->savedGlobals[$var] = $GLOBALS[$var];
+ }
+ $GLOBALS[$var] = $val;
+ }
+
$wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
$wgNamespaceAliases['Image'] = NS_FILE;
$wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
$wgEnableParserCache = false;
- $wgDeferredUpdateList = array();
+ DeferredUpdates::clearPendingUpdates();
$wgMemc = wfGetMainCache();
$messageMemc = wfGetMessageCacheStorage();
$parserMemc = wfGetParserCacheStorage();
@@ -49,18 +66,27 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
// $wgContLang = new StubContLang;
$wgUser = new User;
$context = new RequestContext;
- $wgLang = $context->getLang();
+ $wgLang = $context->getLanguage();
$wgOut = $context->getOutput();
$wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
- $wgRequest = new WebRequest;
+ $wgRequest = $context->getRequest();
if ( $wgStyleDirectory === false ) {
$wgStyleDirectory = "$IP/skins";
}
+ RepoGroup::destroySingleton();
+ FileBackendGroup::destroySingleton();
}
public function tearDown() {
+ foreach ( $this->savedGlobals as $var => $val ) {
+ $GLOBALS[$var] = $val;
+ }
+ // Restore backends
+ RepoGroup::destroySingleton();
+ FileBackendGroup::destroySingleton();
+
$this->teardownUploadDir( $this->uploadDir );
}
@@ -159,10 +185,10 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
return $dir;
}
- wfMkdirParents( $dir . '/3/3a' );
+ wfMkdirParents( $dir . '/3/3a', null, __METHOD__ );
copy( "$IP/skins/monobook/headbg.jpg", "$dir/3/3a/Foobar.jpg" );
- wfMkdirParents( $dir . '/0/09' );
+ wfMkdirParents( $dir . '/0/09', null, __METHOD__ );
copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" );
return $dir;