summaryrefslogtreecommitdiff
path: root/tests/phpunit/includes
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2015-06-04 07:31:04 +0200
committerPierre Schmitz <pierre@archlinux.de>2015-06-04 07:58:39 +0200
commitf6d65e533c62f6deb21342d4901ece24497b433e (patch)
treef28adf0362d14bcd448f7b65a7aaf38650f923aa /tests/phpunit/includes
parentc27b2e832fe25651ef2410fae85b41072aae7519 (diff)
Update to MediaWiki 1.25.1
Diffstat (limited to 'tests/phpunit/includes')
-rw-r--r--tests/phpunit/includes/BlockTest.php12
-rw-r--r--tests/phpunit/includes/EditPageTest.php7
-rw-r--r--tests/phpunit/includes/GitInfoTest.php2
-rw-r--r--tests/phpunit/includes/GlobalFunctions/GlobalTest.php78
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php67
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php43
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php104
-rw-r--r--tests/phpunit/includes/HtmlFormatterTest.php14
-rw-r--r--tests/phpunit/includes/HtmlTest.php28
-rw-r--r--tests/phpunit/includes/HttpTest.php321
-rw-r--r--tests/phpunit/includes/ImportTest.php68
-rw-r--r--tests/phpunit/includes/LanguageConverterTest.php187
-rw-r--r--tests/phpunit/includes/LinkerTest.php56
-rw-r--r--tests/phpunit/includes/MWTimestampTest.php26
-rw-r--r--tests/phpunit/includes/MediaWikiVersionFetcherTest.php1
-rw-r--r--tests/phpunit/includes/MessageTest.php407
-rw-r--r--tests/phpunit/includes/MovePageTest.php63
-rw-r--r--tests/phpunit/includes/OutputPageTest.php45
-rw-r--r--tests/phpunit/includes/PrefixSearchTest.php306
-rw-r--r--tests/phpunit/includes/SampleTest.php2
-rw-r--r--tests/phpunit/includes/SanitizerTest.php29
-rw-r--r--tests/phpunit/includes/StatusTest.php15
-rw-r--r--tests/phpunit/includes/TemplateParserTest.php63
-rw-r--r--tests/phpunit/includes/TestUser.php126
-rw-r--r--tests/phpunit/includes/TestingAccessWrapper.php50
-rw-r--r--tests/phpunit/includes/TestingAccessWrapperTest.php34
-rw-r--r--tests/phpunit/includes/TitleMethodsTest.php41
-rw-r--r--tests/phpunit/includes/TitlePermissionTest.php28
-rw-r--r--tests/phpunit/includes/TitleTest.php54
-rw-r--r--tests/phpunit/includes/UserTest.php91
-rw-r--r--tests/phpunit/includes/XmlSelectTest.php2
-rw-r--r--tests/phpunit/includes/XmlTest.php12
-rw-r--r--tests/phpunit/includes/actions/ActionTest.php12
-rw-r--r--tests/phpunit/includes/api/ApiContinuationManagerTest.php195
-rw-r--r--tests/phpunit/includes/api/ApiErrorFormatterTest.php351
-rw-r--r--tests/phpunit/includes/api/ApiLoginTest.php3
-rw-r--r--tests/phpunit/includes/api/ApiMainTest.php68
-rw-r--r--tests/phpunit/includes/api/ApiMessageTest.php103
-rw-r--r--tests/phpunit/includes/api/ApiOptionsTest.php28
-rw-r--r--tests/phpunit/includes/api/ApiResultTest.php1563
-rw-r--r--tests/phpunit/includes/api/ApiTestCase.php24
-rw-r--r--tests/phpunit/includes/api/ApiTestCaseUpload.php22
-rw-r--r--tests/phpunit/includes/api/ApiUploadTest.php65
-rw-r--r--tests/phpunit/includes/api/MockApi.php3
-rw-r--r--tests/phpunit/includes/api/MockApiQueryBase.php8
-rw-r--r--tests/phpunit/includes/api/PrefixUniquenessTest.php2
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatDbgTest.php55
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatDumpTest.php63
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatJsonTest.php106
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatNoneTest.php38
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatPhpTest.php139
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatTestBase.php70
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatTxtTest.php55
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatWddxTest.php74
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatXmlTest.php119
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryBasicTest.php2
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinue2Test.php5
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinueTest.php26
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php5
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryTest.php56
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryTestBase.php22
-rw-r--r--tests/phpunit/includes/cache/GenderCacheTest.php8
-rw-r--r--tests/phpunit/includes/cache/LocalisationCacheTest.php54
-rw-r--r--tests/phpunit/includes/cache/RedisBloomCacheTest.php71
-rw-r--r--tests/phpunit/includes/changes/EnhancedChangesListTest.php13
-rw-r--r--tests/phpunit/includes/changes/OldChangesListTest.php1
-rw-r--r--tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php1
-rw-r--r--tests/phpunit/includes/changes/RecentChangeTest.php65
-rw-r--r--tests/phpunit/includes/changes/TestRecentChangesHelper.php1
-rw-r--r--tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php1
-rw-r--r--tests/phpunit/includes/config/GlobalVarConfigTest.php24
-rw-r--r--tests/phpunit/includes/config/HashConfigTest.php2
-rw-r--r--tests/phpunit/includes/content/ContentHandlerTest.php15
-rw-r--r--tests/phpunit/includes/content/JsonContentTest.php142
-rw-r--r--tests/phpunit/includes/content/TextContentTest.php21
-rw-r--r--tests/phpunit/includes/context/RequestContextTest.php (renamed from tests/phpunit/includes/RequestContextTest.php)8
-rw-r--r--tests/phpunit/includes/db/DatabaseMysqlBaseTest.php1
-rw-r--r--tests/phpunit/includes/db/DatabaseSQLTest.php80
-rw-r--r--tests/phpunit/includes/db/DatabaseSqliteTest.php45
-rw-r--r--tests/phpunit/includes/db/LBFactoryTest.php1
-rw-r--r--tests/phpunit/includes/db/ORMRowTest.php1
-rw-r--r--tests/phpunit/includes/db/ORMTableTest.php19
-rw-r--r--tests/phpunit/includes/db/TestORMRowTest.php37
-rw-r--r--tests/phpunit/includes/debug/MWDebugTest.php5
-rw-r--r--tests/phpunit/includes/debug/logging/LegacyLoggerTest.php122
-rw-r--r--tests/phpunit/includes/deferred/LinksUpdateTest.php (renamed from tests/phpunit/includes/LinksUpdateTest.php)0
-rw-r--r--tests/phpunit/includes/deferred/SearchUpdateTest.php (renamed from tests/phpunit/includes/search/SearchUpdateTest.php)6
-rw-r--r--tests/phpunit/includes/diff/ArrayDiffFormatterTest.php1
-rw-r--r--tests/phpunit/includes/diff/DiffOpTest.php5
-rw-r--r--tests/phpunit/includes/diff/DiffTest.php1
-rw-r--r--tests/phpunit/includes/diff/DifferenceEngineTest.php1
-rw-r--r--tests/phpunit/includes/exception/BadTitleErrorTest.php17
-rw-r--r--tests/phpunit/includes/exception/ErrorPageErrorTest.php24
-rw-r--r--tests/phpunit/includes/exception/MWExceptionHandlerTest.php2
-rw-r--r--tests/phpunit/includes/exception/ThrottledErrorTest.php17
-rw-r--r--tests/phpunit/includes/externalstore/ExternalStoreTest.php (renamed from tests/phpunit/includes/ExternalStoreTest.php)0
-rw-r--r--tests/phpunit/includes/filebackend/FileBackendTest.php68
-rw-r--r--tests/phpunit/includes/filerepo/StoreBatchTest.php19
-rw-r--r--tests/phpunit/includes/filerepo/file/LocalFileTest.php (renamed from tests/phpunit/includes/LocalFileTest.php)1
-rw-r--r--tests/phpunit/includes/installer/DatabaseUpdaterTest.php279
-rw-r--r--tests/phpunit/includes/installer/InstallDocFormatterTest.php15
-rw-r--r--tests/phpunit/includes/jobqueue/JobQueueTest.php9
-rw-r--r--tests/phpunit/includes/jobqueue/JobTest.php67
-rw-r--r--tests/phpunit/includes/json/FormatJsonTest.php116
-rw-r--r--tests/phpunit/includes/libs/ArrayUtilsTest.php (renamed from tests/phpunit/includes/ArrayUtilsTest.php)2
-rw-r--r--tests/phpunit/includes/libs/CSSMinTest.php49
-rw-r--r--tests/phpunit/includes/libs/DeferredStringifierTest.php50
-rw-r--r--tests/phpunit/includes/libs/GenericArrayObjectTest.php3
-rw-r--r--tests/phpunit/includes/libs/HashRingTest.php2
-rw-r--r--tests/phpunit/includes/libs/IEUrlExtensionTest.php2
-rw-r--r--tests/phpunit/includes/libs/IPSetTest.php2
-rw-r--r--tests/phpunit/includes/libs/JavaScriptMinifierTest.php11
-rw-r--r--tests/phpunit/includes/libs/MWMessagePackTest.php2
-rw-r--r--tests/phpunit/includes/libs/ObjectFactoryTest.php60
-rw-r--r--tests/phpunit/includes/libs/ProcessCacheLRUTest.php50
-rw-r--r--tests/phpunit/includes/libs/RunningStatTest.php2
-rw-r--r--tests/phpunit/includes/libs/StringUtilsTest.php (renamed from tests/phpunit/includes/utils/StringUtilsTest.php)2
-rw-r--r--tests/phpunit/includes/libs/XhprofTest.php320
-rw-r--r--tests/phpunit/includes/libs/XmlTypeCheckTest.php (renamed from tests/phpunit/includes/XmlTypeCheckTest.php)2
-rw-r--r--tests/phpunit/includes/libs/composer/ComposerJsonTest.php57
-rw-r--r--tests/phpunit/includes/libs/composer/ComposerLockTest.php62
-rw-r--r--tests/phpunit/includes/logging/LogFormatterTest.php53
-rw-r--r--tests/phpunit/includes/mail/MailAddressTest.php7
-rw-r--r--tests/phpunit/includes/media/BitmapScalingTest.php4
-rw-r--r--tests/phpunit/includes/media/FormatMetadataTest.php32
-rw-r--r--tests/phpunit/includes/media/MediaHandlerTest.php82
-rw-r--r--tests/phpunit/includes/media/SVGMetadataExtractorTest.php5
-rw-r--r--tests/phpunit/includes/normal/CleanUpTest.php409
-rw-r--r--tests/phpunit/includes/objectcache/BagOStuffTest.php14
-rw-r--r--tests/phpunit/includes/page/ArticleTablesTest.php (renamed from tests/phpunit/includes/ArticleTablesTest.php)0
-rw-r--r--tests/phpunit/includes/page/ArticleTest.php (renamed from tests/phpunit/includes/ArticleTest.php)0
-rw-r--r--tests/phpunit/includes/page/ImagePage404Test.php (renamed from tests/phpunit/includes/ImagePage404Test.php)0
-rw-r--r--tests/phpunit/includes/page/ImagePageTest.php (renamed from tests/phpunit/includes/ImagePageTest.php)0
-rw-r--r--tests/phpunit/includes/page/WikiPageTest.php (renamed from tests/phpunit/includes/WikiPageTest.php)4
-rw-r--r--tests/phpunit/includes/page/WikiPageTestContentHandlerUseDB.php (renamed from tests/phpunit/includes/WikiPageTestContentHandlerUseDB.php)0
-rw-r--r--tests/phpunit/includes/parser/NewParserTest.php38
-rw-r--r--tests/phpunit/includes/parser/ParserOutputTest.php5
-rw-r--r--tests/phpunit/includes/parser/TagHooksTest.php2
-rw-r--r--tests/phpunit/includes/password/PasswordTest.php (renamed from tests/phpunit/includes/PasswordTest.php)6
-rw-r--r--tests/phpunit/includes/password/PasswordTestCase.php7
-rw-r--r--tests/phpunit/includes/registration/ExtensionProcessorTest.php374
-rw-r--r--tests/phpunit/includes/registration/ExtensionRegistryTest.php195
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php247
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php162
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php122
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php61
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php (renamed from tests/phpunit/includes/resourceloader/ResourceLoaderStartupModuleTest.php)86
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderTest.php185
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php84
-rw-r--r--tests/phpunit/includes/resourceloader/templates/template.html1
-rw-r--r--tests/phpunit/includes/resourceloader/templates/template2.html1
-rw-r--r--tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars1
-rw-r--r--tests/phpunit/includes/search/SearchEngineTest.php67
-rw-r--r--tests/phpunit/includes/site/CachingSiteStoreTest.php161
-rw-r--r--tests/phpunit/includes/site/DBSiteStoreTest.php133
-rw-r--r--tests/phpunit/includes/site/FileBasedSiteLookupTest.php101
-rw-r--r--tests/phpunit/includes/site/HashSiteStoreTest.php105
-rw-r--r--tests/phpunit/includes/site/MediaWikiSiteTest.php1
-rw-r--r--tests/phpunit/includes/site/SiteExporterTest.php147
-rw-r--r--tests/phpunit/includes/site/SiteImporterTest.php200
-rw-r--r--tests/phpunit/includes/site/SiteImporterTest.xml19
-rw-r--r--tests/phpunit/includes/site/SiteListTest.php1
-rw-r--r--tests/phpunit/includes/site/SiteSQLStoreTest.php106
-rw-r--r--tests/phpunit/includes/site/SiteTest.php1
-rw-r--r--tests/phpunit/includes/site/SitesCacheFileBuilderTest.php135
-rw-r--r--tests/phpunit/includes/site/TestSites.php3
-rw-r--r--tests/phpunit/includes/skins/SkinTemplateTest.php1
-rw-r--r--tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php62
-rw-r--r--tests/phpunit/includes/specialpage/SpecialPageTest.php (renamed from tests/phpunit/includes/SpecialPageTest.php)1
-rw-r--r--tests/phpunit/includes/specialpage/SpecialPageTestHelper.php24
-rw-r--r--tests/phpunit/includes/specials/SpecialBooksourcesTest.php36
-rw-r--r--tests/phpunit/includes/specials/SpecialMIMESearchTest.php4
-rw-r--r--tests/phpunit/includes/title/ForeignTitleTest.php103
-rw-r--r--tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php1
-rw-r--r--tests/phpunit/includes/title/MediaWikiTitleCodecTest.php11
-rw-r--r--tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php91
-rw-r--r--tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php89
-rw-r--r--tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php89
-rw-r--r--tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php77
-rw-r--r--tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php86
-rw-r--r--tests/phpunit/includes/title/TitleValueTest.php1
-rw-r--r--tests/phpunit/includes/upload/UploadBaseTest.php41
-rw-r--r--tests/phpunit/includes/upload/UploadFromUrlTest.php5
-rw-r--r--tests/phpunit/includes/utils/CdbTest.php90
-rw-r--r--tests/phpunit/includes/utils/IPTest.php2
-rw-r--r--tests/phpunit/includes/utils/MWCryptHKDFTest.php6
-rw-r--r--tests/phpunit/includes/utils/MWFunctionTest.php (renamed from tests/phpunit/includes/MWFunctionTest.php)1
-rw-r--r--tests/phpunit/includes/utils/UIDGeneratorTest.php6
-rw-r--r--tests/phpunit/includes/utils/ZipDirectoryReaderTest.php2
189 files changed, 9869 insertions, 2055 deletions
diff --git a/tests/phpunit/includes/BlockTest.php b/tests/phpunit/includes/BlockTest.php
index b248d24e..19741621 100644
--- a/tests/phpunit/includes/BlockTest.php
+++ b/tests/phpunit/includes/BlockTest.php
@@ -133,6 +133,7 @@ class BlockTest extends MediaWikiLangTestCase {
$username = 'BlockedUserToCreateAccountWith';
$u = User::newFromName( $username );
$u->setPassword( 'NotRandomPass' );
+ $u->setId( 14146 );
$u->addToDatabase();
unset( $u );
@@ -200,6 +201,12 @@ class BlockTest extends MediaWikiLangTestCase {
$oldBlock->delete();
}
+ // Local perspective (blockee on current wiki)...
+ $user = User::newFromName( 'UserOnForeignWiki' );
+ $user->addToDatabase();
+ // Set user ID to match the test value
+ $this->db->update( 'user', array( 'user_id' => 14146 ), array( 'user_id' => $user->getId() ) );
+
// Foreign perspective (blockee not on current wiki)...
$block = new Block(
/* $address */ 'UserOnForeignWiki',
@@ -221,11 +228,6 @@ class BlockTest extends MediaWikiLangTestCase {
$res = $block->insert( $this->db );
$this->assertTrue( (bool)$res['id'], 'Block succeeded' );
- // Local perspective (blockee on current wiki)...
- $user = User::newFromName( 'UserOnForeignWiki' );
- $user->addToDatabase();
- // Set user ID to match the test value
- $this->db->update( 'user', array( 'user_id' => 14146 ), array( 'user_id' => $user->getId() ) );
$user = null; // clear
$block = Block::newFromID( $res['id'] );
diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php
index 702fce4c..15778e40 100644
--- a/tests/phpunit/includes/EditPageTest.php
+++ b/tests/phpunit/includes/EditPageTest.php
@@ -217,7 +217,8 @@ class EditPageTest extends MediaWikiLangTestCase {
EditPage::AS_SUCCESS_NEW_ARTICLE,
''
),
- array( 'expected registered MediaWiki: page whose default content is empty not being created if empty',
+ array( 'expected registered MediaWiki: page whose default content is empty'
+ . ' not being created if empty',
'MediaWiki:Ipb-default-expiry',
'UTSysop',
'',
@@ -246,7 +247,9 @@ class EditPageTest extends MediaWikiLangTestCase {
* @dataProvider provideCreatePages
* @covers EditPage
*/
- public function testCreatePage( $desc, $pageTitle, $user, $editText, $expectedCode, $expectedText, $ignoreBlank = false ) {
+ public function testCreatePage(
+ $desc, $pageTitle, $user, $editText, $expectedCode, $expectedText, $ignoreBlank = false
+ ) {
$edit = array( 'wpTextbox1' => $editText );
if ( $ignoreBlank ) {
$edit['wpIgnoreBlankArticle'] = 1;
diff --git a/tests/phpunit/includes/GitInfoTest.php b/tests/phpunit/includes/GitInfoTest.php
index e22f5050..c3539d0e 100644
--- a/tests/phpunit/includes/GitInfoTest.php
+++ b/tests/phpunit/includes/GitInfoTest.php
@@ -10,7 +10,7 @@ class GitInfoTest extends MediaWikiTestCase {
}
public function testValidJsonData() {
- $dir = $GLOBALS['IP'] . '/testValidJsonData';
+ $dir = $GLOBALS['IP'] . DIRECTORY_SEPARATOR . 'testValidJsonData';
$fixture = new GitInfo( $dir );
$this->assertTrue( $fixture->cacheIsComplete() );
diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
index 3acc48e2..1e30273e 100644
--- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
@@ -7,7 +7,7 @@ class GlobalTest extends MediaWikiTestCase {
protected function setUp() {
parent::setUp();
- $readOnlyFile = tempnam( wfTempDir(), "mwtest_readonly" );
+ $readOnlyFile = $this->getNewTempFile();
unlink( $readOnlyFile );
$this->setMwGlobals( array(
@@ -22,16 +22,6 @@ class GlobalTest extends MediaWikiTestCase {
) );
}
- protected function tearDown() {
- global $wgReadOnlyFile;
-
- if ( file_exists( $wgReadOnlyFile ) ) {
- unlink( $wgReadOnlyFile );
- }
-
- parent::tearDown();
- }
-
/**
* @dataProvider provideForWfArrayDiff2
* @covers ::wfArrayDiff2
@@ -312,46 +302,42 @@ class GlobalTest extends MediaWikiTestCase {
* @covers ::wfDebugMem
*/
public function testDebugFunctionTest() {
+ $debugLogFile = $this->getNewTempFile();
- global $wgDebugLogFile, $wgDebugTimestamps;
-
- $old_log_file = $wgDebugLogFile;
- $wgDebugLogFile = tempnam( wfTempDir(), 'mw-' );
- # @todo FIXME: $wgDebugTimestamps should be tested
- $old_wgDebugTimestamps = $wgDebugTimestamps;
- $wgDebugTimestamps = false;
+ $this->setMwGlobals( array(
+ 'wgDebugLogFile' => $debugLogFile,
+ # @todo FIXME: $wgDebugTimestamps should be tested
+ 'wgDebugTimestamps' => false
+ ) );
wfDebug( "This is a normal string" );
- $this->assertEquals( "This is a normal string", file_get_contents( $wgDebugLogFile ) );
- unlink( $wgDebugLogFile );
+ $this->assertEquals( "This is a normal string\n", file_get_contents( $debugLogFile ) );
+ unlink( $debugLogFile );
wfDebug( "This is nöt an ASCII string" );
- $this->assertEquals( "This is nöt an ASCII string", file_get_contents( $wgDebugLogFile ) );
- unlink( $wgDebugLogFile );
+ $this->assertEquals( "This is nöt an ASCII string\n", file_get_contents( $debugLogFile ) );
+ unlink( $debugLogFile );
wfDebug( "\00305This has böth UTF and control chars\003" );
$this->assertEquals(
- " 05This has böth UTF and control chars ",
- file_get_contents( $wgDebugLogFile )
+ " 05This has böth UTF and control chars \n",
+ file_get_contents( $debugLogFile )
);
- unlink( $wgDebugLogFile );
+ unlink( $debugLogFile );
wfDebugMem();
$this->assertGreaterThan(
1000,
- preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) )
+ preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) )
);
- unlink( $wgDebugLogFile );
+ unlink( $debugLogFile );
wfDebugMem( true );
$this->assertGreaterThan(
1000000,
- preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) )
+ preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) )
);
- unlink( $wgDebugLogFile );
-
- $wgDebugLogFile = $old_log_file;
- $wgDebugTimestamps = $old_wgDebugTimestamps;
+ unlink( $debugLogFile );
}
/**
@@ -389,24 +375,6 @@ class GlobalTest extends MediaWikiTestCase {
}
/**
- * @covers ::swap
- */
- public function testSwapVarsTest() {
- $this->hideDeprecated( 'swap' );
-
- $var1 = 1;
- $var2 = 2;
-
- $this->assertEquals( $var1, 1, 'var1 is set originally' );
- $this->assertEquals( $var2, 2, 'var1 is set originally' );
-
- swap( $var1, $var2 );
-
- $this->assertEquals( $var1, 2, 'var1 is swapped' );
- $this->assertEquals( $var2, 1, 'var2 is swapped' );
- }
-
- /**
* @covers ::wfPercent
*/
public function testWfPercentTest() {
@@ -705,21 +673,21 @@ class GlobalTest extends MediaWikiTestCase {
}
/**
- * @dataProvider provideWfShellMaintenanceCmdList
- * @covers ::wfShellMaintenanceCmd
+ * @dataProvider provideWfShellWikiCmdList
+ * @covers ::wfShellWikiCmd
*/
- public function testWfShellMaintenanceCmd( $script, $parameters, $options,
+ public function testWfShellWikiCmd( $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 );
+ $actual = wfShellWikiCmd( $script, $parameters, $options );
$this->assertEquals( $expected, $actual, $description );
}
- public static function provideWfShellMaintenanceCmdList() {
+ public static function provideWfShellWikiCmdList() {
global $wgPhpCli;
return array(
diff --git a/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php b/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php
new file mode 100644
index 00000000..54e1f896
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfAppendQuery
+ */
+class WfAppendQueryTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideAppendQuery
+ */
+ public function testAppendQuery( $url, $query, $expected, $message = null ) {
+ $this->assertEquals( $expected, wfAppendQuery( $url, $query ), $message );
+ }
+
+ public static function provideAppendQuery() {
+ return array(
+ array(
+ 'http://www.example.org/index.php',
+ '',
+ 'http://www.example.org/index.php',
+ 'No query'
+ ),
+ array(
+ 'http://www.example.org/index.php',
+ array( 'foo' => 'bar' ),
+ 'http://www.example.org/index.php?foo=bar',
+ 'Set query array'
+ ),
+ array(
+ 'http://www.example.org/index.php?foz=baz',
+ 'foo=bar',
+ 'http://www.example.org/index.php?foz=baz&foo=bar',
+ 'Set query string'
+ ),
+ array(
+ 'http://www.example.org/index.php?foo=bar',
+ '',
+ 'http://www.example.org/index.php?foo=bar',
+ 'Empty string with query'
+ ),
+ array(
+ 'http://www.example.org/index.php?foo=bar',
+ array( 'baz' => 'quux' ),
+ 'http://www.example.org/index.php?foo=bar&baz=quux',
+ 'Add query array'
+ ),
+ array(
+ 'http://www.example.org/index.php?foo=bar',
+ 'baz=quux',
+ 'http://www.example.org/index.php?foo=bar&baz=quux',
+ 'Add query string'
+ ),
+ array(
+ 'http://www.example.org/index.php?foo=bar',
+ array( 'baz' => 'quux', 'foo' => 'baz' ),
+ 'http://www.example.org/index.php?foo=bar&baz=quux&foo=baz',
+ 'Modify query array'
+ ),
+ array(
+ 'http://www.example.org/index.php?foo=bar',
+ 'baz=quux&foo=baz',
+ 'http://www.example.org/index.php?foo=bar&baz=quux&foo=baz',
+ 'Modify query string'
+ )
+ );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php b/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php
new file mode 100644
index 00000000..cb334d2f
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfEscapeShellArg
+ */
+class wfEscapeShellArgTest extends MediaWikiTestCase {
+ public function testSingleInput() {
+ if ( wfIsWindows() ) {
+ $expected = '"blah"';
+ } else {
+ $expected = "'blah'";
+ }
+
+ $actual = wfEscapeShellArg( 'blah' );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testMultipleArgs() {
+ if ( wfIsWindows() ) {
+ $expected = '"foo" "bar" "baz"';
+ } else {
+ $expected = "'foo' 'bar' 'baz'";
+ }
+
+ $actual = wfEscapeShellArg( 'foo', 'bar', 'baz' );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testMultipleArgsAsArray() {
+ if ( wfIsWindows() ) {
+ $expected = '"foo" "bar" "baz"';
+ } else {
+ $expected = "'foo' 'bar' 'baz'";
+ }
+
+ $actual = wfEscapeShellArg( array( 'foo', 'bar', 'baz' ) );
+
+ $this->assertEquals( $expected, $actual );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php b/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php
new file mode 100644
index 00000000..448250a6
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfThumbIsStandard
+ */
+class WfThumbIsStandardTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgThumbLimits' => array(
+ 100,
+ 401
+ ),
+ 'wgImageLimits' => array(
+ array( 300, 225 ),
+ array( 800, 600 ),
+ ),
+ 'wgMediaHandlers' => array(
+ 'unknown/unknown' => 'MockBitmapHandler',
+ ),
+ ) );
+ }
+
+ public static function provideThumbParams() {
+ return array(
+ // Thumb limits
+ array(
+ 'Standard thumb width',
+ true,
+ array( 'width' => 100 ),
+ ),
+ array(
+ 'Standard thumb width',
+ true,
+ array( 'width' => 401 ),
+ ),
+ // wfThumbIsStandard should match Linker::processResponsiveImages
+ // in its rounding behaviour.
+ array(
+ 'Standard thumb width (HiDPI 1.5x) - incorrect rounding',
+ false,
+ array( 'width' => 601 ),
+ ),
+ array(
+ 'Standard thumb width (HiDPI 1.5x)',
+ true,
+ array( 'width' => 602 ),
+ ),
+ array(
+ 'Standard thumb width (HiDPI 2x)',
+ true,
+ array( 'width' => 802 ),
+ ),
+ array(
+ 'Non-standard thumb width',
+ false,
+ array( 'width' => 300 ),
+ ),
+ // Image limits
+ // Note: Image limits are measured as pairs. Individual values
+ // may be non-standard based on the aspect ratio.
+ array(
+ 'Standard image width/height pair',
+ true,
+ array( 'width' => 250, 'height' => 225 ),
+ ),
+ array(
+ 'Standard image width/height pair',
+ true,
+ array( 'width' => 667, 'height' => 600 ),
+ ),
+ array(
+ 'Standard image width where image does not fit aspect ratio',
+ false,
+ array( 'width' => 300 ),
+ ),
+ array(
+ 'Implicit width from image width/height pair aspect ratio fit',
+ true,
+ // 2000x1800 fit inside 300x225 makes w=250
+ array( 'width' => 250 ),
+ ),
+ array(
+ 'Height-only is always non-standard',
+ false,
+ array( 'height' => 225 ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideThumbParams
+ */
+ public function testIsStandard( $message, $expected, $params ) {
+ $this->assertSame(
+ $expected,
+ wfThumbIsStandard( new FakeDimensionFile( array( 2000, 1800 ) ), $params ),
+ $message
+ );
+ }
+}
diff --git a/tests/phpunit/includes/HtmlFormatterTest.php b/tests/phpunit/includes/HtmlFormatterTest.php
index 9dbfa452..1c3e8539 100644
--- a/tests/phpunit/includes/HtmlFormatterTest.php
+++ b/tests/phpunit/includes/HtmlFormatterTest.php
@@ -4,6 +4,20 @@
* @group HtmlFormatter
*/
class HtmlFormatterTest extends MediaWikiTestCase {
+
+ /**
+ * Use TidySupport to check whether we should use $wgTidyInternal.
+ *
+ * The Tidy extension in HHVM does not support error text return, so it is
+ * nominally usable, but does not pass tests which require error text from
+ * Tidy.
+ */
+ protected function setUp() {
+ parent::setUp();
+ $tidySupport = new TidySupport();
+ $this->setMwGlobals( 'wgTidyInternal', $tidySupport->isInternal() );
+ }
+
/**
* @dataProvider getHtmlData
*
diff --git a/tests/phpunit/includes/HtmlTest.php b/tests/phpunit/includes/HtmlTest.php
index a8829cd8..c5797c4f 100644
--- a/tests/phpunit/includes/HtmlTest.php
+++ b/tests/phpunit/includes/HtmlTest.php
@@ -637,7 +637,7 @@ class HtmlTest extends MediaWikiTestCase {
. 'Depending on compatibility mode IE might use "button", instead.',
);
- # <select> specifc handling
+ # <select> specific handling
$cases[] = array( '<select multiple></select>',
'select', array( 'size' => '4', 'multiple' => true ),
);
@@ -715,7 +715,7 @@ class HtmlTest extends MediaWikiTestCase {
'Input wrapper with type and value.'
);
$this->assertEquals(
- '<input name=testname class=mw-ui-input>',
+ '<input name=testname>',
Html::input( 'testname' ),
'Input wrapper with all default values.'
);
@@ -764,6 +764,30 @@ class HtmlTest extends MediaWikiTestCase {
'Label wrapper'
);
}
+
+ public static function provideSrcSetImages() {
+ return array(
+ array( array(), '', 'when there are no images, return empty string' ),
+ array(
+ array( '1x' => '1x.png', '1.5x' => '1_5x.png', '2x' => '2x.png' ),
+ '1x.png 1x, 1_5x.png 1.5x, 2x.png 2x',
+ 'pixel depth keys may include a trailing "x"'
+ ),
+ array(
+ array( '1' => '1x.png', '1.5' => '1_5x.png', '2' => '2x.png' ),
+ '1x.png 1x, 1_5x.png 1.5x, 2x.png 2x',
+ 'pixel depth keys may omit a trailing "x"'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSrcSetImages
+ * @covers Html::srcSet
+ */
+ public function testSrcSet( $images, $expected, $message ) {
+ $this->assertEquals( Html::srcSet( $images ), $expected, $message );
+ }
}
class HtmlTestValue {
diff --git a/tests/phpunit/includes/HttpTest.php b/tests/phpunit/includes/HttpTest.php
index 9b53381e..8a0dff78 100644
--- a/tests/phpunit/includes/HttpTest.php
+++ b/tests/phpunit/includes/HttpTest.php
@@ -1,6 +1,7 @@
<?php
+
/**
- * @group Broken
+ * @group Http
*/
class HttpTest extends MediaWikiTestCase {
/**
@@ -92,8 +93,10 @@ class HttpTest extends MediaWikiTestCase {
array( true, 'http://user:pass@host', 'Username and password provided' ),
# (\S+) - host part is made of anything not whitespaces
- array( false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ),
- array( false, 'http://exam:ple.org/', 'hostname can not use colons!' ),
+ // commented these out in order to remove @group Broken
+ // @todo are these valid tests? if so, fix Http::isValidURI so it can handle them
+ //array( false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ),
+ //array( false, 'http://exam:ple.org/', 'hostname can not use colons!' ),
# (:[0-9]+)? - port number
array( true, 'http://example.org:80/' ),
@@ -135,7 +138,7 @@ class HttpTest extends MediaWikiTestCase {
* HTTP redirects).
*/
public function testRelativeRedirections() {
- $h = MWHttpRequestTester::factory( 'http://oldsite/file.ext' );
+ $h = MWHttpRequestTester::factory( 'http://oldsite/file.ext', array(), __METHOD__ );
# Forge a Location header
$h->setRespHeaders( 'location', array(
@@ -171,6 +174,310 @@ class HttpTest extends MediaWikiTestCase {
$h->getFinalUrl( "Relative file path Location: should keep the latest host and scheme!" )
);
}
+
+ /**
+ * Constant values are from PHP 5.3.28 using cURL 7.24.0
+ * @see http://php.net/manual/en/curl.constants.php
+ *
+ * All constant values are present so that developers don’t need to remember
+ * to add them if added at a later date. The commented out constants were
+ * not found anywhere in the MediaWiki core code.
+ *
+ * Commented out constants that were not available in:
+ * HipHop VM 3.3.0 (rel)
+ * Compiler: heads/master-0-g08810d920dfff59e0774cf2d651f92f13a637175
+ * Repo schema: 3214fc2c684a4520485f715ee45f33f2182324b1
+ * Extension API: 20140829
+ *
+ * Commented out constants that were removed in PHP 5.6.0
+ *
+ * @covers CurlHttpRequest::execute
+ */
+ public function provideCurlConstants() {
+ return array(
+ array( 'CURLAUTH_ANY' ),
+ array( 'CURLAUTH_ANYSAFE' ),
+ array( 'CURLAUTH_BASIC' ),
+ array( 'CURLAUTH_DIGEST' ),
+ array( 'CURLAUTH_GSSNEGOTIATE' ),
+ array( 'CURLAUTH_NTLM' ),
+ // array( 'CURLCLOSEPOLICY_CALLBACK' ), // removed in PHP 5.6.0
+ // array( 'CURLCLOSEPOLICY_LEAST_RECENTLY_USED' ), // removed in PHP 5.6.0
+ // array( 'CURLCLOSEPOLICY_LEAST_TRAFFIC' ), // removed in PHP 5.6.0
+ // array( 'CURLCLOSEPOLICY_OLDEST' ), // removed in PHP 5.6.0
+ // array( 'CURLCLOSEPOLICY_SLOWEST' ), // removed in PHP 5.6.0
+ array( 'CURLE_ABORTED_BY_CALLBACK' ),
+ array( 'CURLE_BAD_CALLING_ORDER' ),
+ array( 'CURLE_BAD_CONTENT_ENCODING' ),
+ array( 'CURLE_BAD_FUNCTION_ARGUMENT' ),
+ array( 'CURLE_BAD_PASSWORD_ENTERED' ),
+ array( 'CURLE_COULDNT_CONNECT' ),
+ array( 'CURLE_COULDNT_RESOLVE_HOST' ),
+ array( 'CURLE_COULDNT_RESOLVE_PROXY' ),
+ array( 'CURLE_FAILED_INIT' ),
+ array( 'CURLE_FILESIZE_EXCEEDED' ),
+ array( 'CURLE_FILE_COULDNT_READ_FILE' ),
+ array( 'CURLE_FTP_ACCESS_DENIED' ),
+ array( 'CURLE_FTP_BAD_DOWNLOAD_RESUME' ),
+ array( 'CURLE_FTP_CANT_GET_HOST' ),
+ array( 'CURLE_FTP_CANT_RECONNECT' ),
+ array( 'CURLE_FTP_COULDNT_GET_SIZE' ),
+ array( 'CURLE_FTP_COULDNT_RETR_FILE' ),
+ array( 'CURLE_FTP_COULDNT_SET_ASCII' ),
+ array( 'CURLE_FTP_COULDNT_SET_BINARY' ),
+ array( 'CURLE_FTP_COULDNT_STOR_FILE' ),
+ array( 'CURLE_FTP_COULDNT_USE_REST' ),
+ array( 'CURLE_FTP_PORT_FAILED' ),
+ array( 'CURLE_FTP_QUOTE_ERROR' ),
+ array( 'CURLE_FTP_SSL_FAILED' ),
+ array( 'CURLE_FTP_USER_PASSWORD_INCORRECT' ),
+ array( 'CURLE_FTP_WEIRD_227_FORMAT' ),
+ array( 'CURLE_FTP_WEIRD_PASS_REPLY' ),
+ array( 'CURLE_FTP_WEIRD_PASV_REPLY' ),
+ array( 'CURLE_FTP_WEIRD_SERVER_REPLY' ),
+ array( 'CURLE_FTP_WEIRD_USER_REPLY' ),
+ array( 'CURLE_FTP_WRITE_ERROR' ),
+ array( 'CURLE_FUNCTION_NOT_FOUND' ),
+ array( 'CURLE_GOT_NOTHING' ),
+ array( 'CURLE_HTTP_NOT_FOUND' ),
+ array( 'CURLE_HTTP_PORT_FAILED' ),
+ array( 'CURLE_HTTP_POST_ERROR' ),
+ array( 'CURLE_HTTP_RANGE_ERROR' ),
+ array( 'CURLE_LDAP_CANNOT_BIND' ),
+ array( 'CURLE_LDAP_INVALID_URL' ),
+ array( 'CURLE_LDAP_SEARCH_FAILED' ),
+ array( 'CURLE_LIBRARY_NOT_FOUND' ),
+ array( 'CURLE_MALFORMAT_USER' ),
+ array( 'CURLE_OBSOLETE' ),
+ array( 'CURLE_OK' ),
+ array( 'CURLE_OPERATION_TIMEOUTED' ),
+ array( 'CURLE_OUT_OF_MEMORY' ),
+ array( 'CURLE_PARTIAL_FILE' ),
+ array( 'CURLE_READ_ERROR' ),
+ array( 'CURLE_RECV_ERROR' ),
+ array( 'CURLE_SEND_ERROR' ),
+ array( 'CURLE_SHARE_IN_USE' ),
+ // array( 'CURLE_SSH' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLE_SSL_CACERT' ),
+ array( 'CURLE_SSL_CERTPROBLEM' ),
+ array( 'CURLE_SSL_CIPHER' ),
+ array( 'CURLE_SSL_CONNECT_ERROR' ),
+ array( 'CURLE_SSL_ENGINE_NOTFOUND' ),
+ array( 'CURLE_SSL_ENGINE_SETFAILED' ),
+ array( 'CURLE_SSL_PEER_CERTIFICATE' ),
+ array( 'CURLE_TELNET_OPTION_SYNTAX' ),
+ array( 'CURLE_TOO_MANY_REDIRECTS' ),
+ array( 'CURLE_UNKNOWN_TELNET_OPTION' ),
+ array( 'CURLE_UNSUPPORTED_PROTOCOL' ),
+ array( 'CURLE_URL_MALFORMAT' ),
+ array( 'CURLE_URL_MALFORMAT_USER' ),
+ array( 'CURLE_WRITE_ERROR' ),
+ array( 'CURLFTPAUTH_DEFAULT' ),
+ array( 'CURLFTPAUTH_SSL' ),
+ array( 'CURLFTPAUTH_TLS' ),
+ // array( 'CURLFTPMETHOD_MULTICWD' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLFTPMETHOD_NOCWD' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLFTPMETHOD_SINGLECWD' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLFTPSSL_ALL' ),
+ array( 'CURLFTPSSL_CONTROL' ),
+ array( 'CURLFTPSSL_NONE' ),
+ array( 'CURLFTPSSL_TRY' ),
+ // array( 'CURLINFO_CERTINFO' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLINFO_CONNECT_TIME' ),
+ array( 'CURLINFO_CONTENT_LENGTH_DOWNLOAD' ),
+ array( 'CURLINFO_CONTENT_LENGTH_UPLOAD' ),
+ array( 'CURLINFO_CONTENT_TYPE' ),
+ array( 'CURLINFO_EFFECTIVE_URL' ),
+ array( 'CURLINFO_FILETIME' ),
+ array( 'CURLINFO_HEADER_OUT' ),
+ array( 'CURLINFO_HEADER_SIZE' ),
+ array( 'CURLINFO_HTTP_CODE' ),
+ array( 'CURLINFO_NAMELOOKUP_TIME' ),
+ array( 'CURLINFO_PRETRANSFER_TIME' ),
+ array( 'CURLINFO_PRIVATE' ),
+ array( 'CURLINFO_REDIRECT_COUNT' ),
+ array( 'CURLINFO_REDIRECT_TIME' ),
+ // array( 'CURLINFO_REDIRECT_URL' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLINFO_REQUEST_SIZE' ),
+ array( 'CURLINFO_SIZE_DOWNLOAD' ),
+ array( 'CURLINFO_SIZE_UPLOAD' ),
+ array( 'CURLINFO_SPEED_DOWNLOAD' ),
+ array( 'CURLINFO_SPEED_UPLOAD' ),
+ array( 'CURLINFO_SSL_VERIFYRESULT' ),
+ array( 'CURLINFO_STARTTRANSFER_TIME' ),
+ array( 'CURLINFO_TOTAL_TIME' ),
+ array( 'CURLMSG_DONE' ),
+ array( 'CURLM_BAD_EASY_HANDLE' ),
+ array( 'CURLM_BAD_HANDLE' ),
+ array( 'CURLM_CALL_MULTI_PERFORM' ),
+ array( 'CURLM_INTERNAL_ERROR' ),
+ array( 'CURLM_OK' ),
+ array( 'CURLM_OUT_OF_MEMORY' ),
+ array( 'CURLOPT_AUTOREFERER' ),
+ array( 'CURLOPT_BINARYTRANSFER' ),
+ array( 'CURLOPT_BUFFERSIZE' ),
+ array( 'CURLOPT_CAINFO' ),
+ array( 'CURLOPT_CAPATH' ),
+ // array( 'CURLOPT_CERTINFO' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLOPT_CLOSEPOLICY' ), // removed in PHP 5.6.0
+ array( 'CURLOPT_CONNECTTIMEOUT' ),
+ array( 'CURLOPT_CONNECTTIMEOUT_MS' ),
+ array( 'CURLOPT_COOKIE' ),
+ array( 'CURLOPT_COOKIEFILE' ),
+ array( 'CURLOPT_COOKIEJAR' ),
+ array( 'CURLOPT_COOKIESESSION' ),
+ array( 'CURLOPT_CRLF' ),
+ array( 'CURLOPT_CUSTOMREQUEST' ),
+ array( 'CURLOPT_DNS_CACHE_TIMEOUT' ),
+ array( 'CURLOPT_DNS_USE_GLOBAL_CACHE' ),
+ array( 'CURLOPT_EGDSOCKET' ),
+ array( 'CURLOPT_ENCODING' ),
+ array( 'CURLOPT_FAILONERROR' ),
+ array( 'CURLOPT_FILE' ),
+ array( 'CURLOPT_FILETIME' ),
+ array( 'CURLOPT_FOLLOWLOCATION' ),
+ array( 'CURLOPT_FORBID_REUSE' ),
+ array( 'CURLOPT_FRESH_CONNECT' ),
+ array( 'CURLOPT_FTPAPPEND' ),
+ array( 'CURLOPT_FTPLISTONLY' ),
+ array( 'CURLOPT_FTPPORT' ),
+ array( 'CURLOPT_FTPSSLAUTH' ),
+ array( 'CURLOPT_FTP_CREATE_MISSING_DIRS' ),
+ // array( 'CURLOPT_FTP_FILEMETHOD' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLOPT_FTP_SKIP_PASV_IP' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLOPT_FTP_SSL' ),
+ array( 'CURLOPT_FTP_USE_EPRT' ),
+ array( 'CURLOPT_FTP_USE_EPSV' ),
+ array( 'CURLOPT_HEADER' ),
+ array( 'CURLOPT_HEADERFUNCTION' ),
+ array( 'CURLOPT_HTTP200ALIASES' ),
+ array( 'CURLOPT_HTTPAUTH' ),
+ array( 'CURLOPT_HTTPGET' ),
+ array( 'CURLOPT_HTTPHEADER' ),
+ array( 'CURLOPT_HTTPPROXYTUNNEL' ),
+ array( 'CURLOPT_HTTP_VERSION' ),
+ array( 'CURLOPT_INFILE' ),
+ array( 'CURLOPT_INFILESIZE' ),
+ array( 'CURLOPT_INTERFACE' ),
+ array( 'CURLOPT_IPRESOLVE' ),
+ // array( 'CURLOPT_KEYPASSWD' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLOPT_KRB4LEVEL' ),
+ array( 'CURLOPT_LOW_SPEED_LIMIT' ),
+ array( 'CURLOPT_LOW_SPEED_TIME' ),
+ array( 'CURLOPT_MAXCONNECTS' ),
+ array( 'CURLOPT_MAXREDIRS' ),
+ // array( 'CURLOPT_MAX_RECV_SPEED_LARGE' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLOPT_MAX_SEND_SPEED_LARGE' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLOPT_NETRC' ),
+ array( 'CURLOPT_NOBODY' ),
+ array( 'CURLOPT_NOPROGRESS' ),
+ array( 'CURLOPT_NOSIGNAL' ),
+ array( 'CURLOPT_PORT' ),
+ array( 'CURLOPT_POST' ),
+ array( 'CURLOPT_POSTFIELDS' ),
+ array( 'CURLOPT_POSTQUOTE' ),
+ array( 'CURLOPT_POSTREDIR' ),
+ array( 'CURLOPT_PRIVATE' ),
+ array( 'CURLOPT_PROGRESSFUNCTION' ),
+ // array( 'CURLOPT_PROTOCOLS' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLOPT_PROXY' ),
+ array( 'CURLOPT_PROXYAUTH' ),
+ array( 'CURLOPT_PROXYPORT' ),
+ array( 'CURLOPT_PROXYTYPE' ),
+ array( 'CURLOPT_PROXYUSERPWD' ),
+ array( 'CURLOPT_PUT' ),
+ array( 'CURLOPT_QUOTE' ),
+ array( 'CURLOPT_RANDOM_FILE' ),
+ array( 'CURLOPT_RANGE' ),
+ array( 'CURLOPT_READDATA' ),
+ array( 'CURLOPT_READFUNCTION' ),
+ // array( 'CURLOPT_REDIR_PROTOCOLS' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLOPT_REFERER' ),
+ array( 'CURLOPT_RESUME_FROM' ),
+ array( 'CURLOPT_RETURNTRANSFER' ),
+ // array( 'CURLOPT_SSH_AUTH_TYPES' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLOPT_SSH_HOST_PUBLIC_KEY_MD5' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLOPT_SSH_PRIVATE_KEYFILE' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLOPT_SSH_PUBLIC_KEYFILE' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLOPT_SSLCERT' ),
+ array( 'CURLOPT_SSLCERTPASSWD' ),
+ array( 'CURLOPT_SSLCERTTYPE' ),
+ array( 'CURLOPT_SSLENGINE' ),
+ array( 'CURLOPT_SSLENGINE_DEFAULT' ),
+ array( 'CURLOPT_SSLKEY' ),
+ array( 'CURLOPT_SSLKEYPASSWD' ),
+ array( 'CURLOPT_SSLKEYTYPE' ),
+ array( 'CURLOPT_SSLVERSION' ),
+ array( 'CURLOPT_SSL_CIPHER_LIST' ),
+ array( 'CURLOPT_SSL_VERIFYHOST' ),
+ array( 'CURLOPT_SSL_VERIFYPEER' ),
+ array( 'CURLOPT_STDERR' ),
+ array( 'CURLOPT_TCP_NODELAY' ),
+ array( 'CURLOPT_TIMECONDITION' ),
+ array( 'CURLOPT_TIMEOUT' ),
+ array( 'CURLOPT_TIMEOUT_MS' ),
+ array( 'CURLOPT_TIMEVALUE' ),
+ array( 'CURLOPT_TRANSFERTEXT' ),
+ array( 'CURLOPT_UNRESTRICTED_AUTH' ),
+ array( 'CURLOPT_UPLOAD' ),
+ array( 'CURLOPT_URL' ),
+ array( 'CURLOPT_USERAGENT' ),
+ array( 'CURLOPT_USERPWD' ),
+ array( 'CURLOPT_VERBOSE' ),
+ array( 'CURLOPT_WRITEFUNCTION' ),
+ array( 'CURLOPT_WRITEHEADER' ),
+ // array( 'CURLPROTO_ALL' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_DICT' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_FILE' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_FTP' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_FTPS' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_HTTP' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_HTTPS' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_LDAP' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_LDAPS' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_SCP' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_SFTP' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_TELNET' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLPROTO_TFTP' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLPROXY_HTTP' ),
+ // array( 'CURLPROXY_SOCKS4' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLPROXY_SOCKS5' ),
+ // array( 'CURLSSH_AUTH_DEFAULT' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLSSH_AUTH_HOST' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLSSH_AUTH_KEYBOARD' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLSSH_AUTH_NONE' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLSSH_AUTH_PASSWORD' ), // not present in HHVM 3.3.0-dev
+ // array( 'CURLSSH_AUTH_PUBLICKEY' ), // not present in HHVM 3.3.0-dev
+ array( 'CURLVERSION_NOW' ),
+ array( 'CURL_HTTP_VERSION_1_0' ),
+ array( 'CURL_HTTP_VERSION_1_1' ),
+ array( 'CURL_HTTP_VERSION_NONE' ),
+ array( 'CURL_IPRESOLVE_V4' ),
+ array( 'CURL_IPRESOLVE_V6' ),
+ array( 'CURL_IPRESOLVE_WHATEVER' ),
+ array( 'CURL_NETRC_IGNORED' ),
+ array( 'CURL_NETRC_OPTIONAL' ),
+ array( 'CURL_NETRC_REQUIRED' ),
+ array( 'CURL_TIMECOND_IFMODSINCE' ),
+ array( 'CURL_TIMECOND_IFUNMODSINCE' ),
+ array( 'CURL_TIMECOND_LASTMOD' ),
+ array( 'CURL_VERSION_IPV6' ),
+ array( 'CURL_VERSION_KERBEROS4' ),
+ array( 'CURL_VERSION_LIBZ' ),
+ array( 'CURL_VERSION_SSL' ),
+ );
+ }
+
+ /**
+ * Added this test based on an issue experienced with HHVM 3.3.0-dev
+ * where it did not define a cURL constant.
+ *
+ * @bug 70570
+ * @dataProvider provideCurlConstants
+ */
+ public function testCurlConstants( $value ) {
+ $this->assertTrue( defined( $value ), $value . ' not defined' );
+ }
}
/**
@@ -179,7 +486,7 @@ class HttpTest extends MediaWikiTestCase {
class MWHttpRequestTester extends MWHttpRequest {
// function derived from the MWHttpRequest factory function but
// returns appropriate tester class here
- public static function factory( $url, $options = null ) {
+ public static function factory( $url, $options = null, $caller = __METHOD__ ) {
if ( !Http::$httpEngine ) {
Http::$httpEngine = function_exists( 'curl_init' ) ? 'curl' : 'php';
} elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) {
@@ -189,7 +496,7 @@ class MWHttpRequestTester extends MWHttpRequest {
switch ( Http::$httpEngine ) {
case 'curl':
- return new CurlHttpRequestTester( $url, $options );
+ return new CurlHttpRequestTester( $url, $options, $caller );
case 'php':
if ( !wfIniGetBool( 'allow_url_fopen' ) ) {
throw new MWException( __METHOD__ .
@@ -197,7 +504,7 @@ class MWHttpRequestTester extends MWHttpRequest {
. 'If possible, curl should be used instead. See http://php.net/curl.' );
}
- return new PhpHttpRequestTester( $url, $options );
+ return new PhpHttpRequestTester( $url, $options, $caller );
default:
}
}
diff --git a/tests/phpunit/includes/ImportTest.php b/tests/phpunit/includes/ImportTest.php
index 2fce6bfb..ea753e81 100644
--- a/tests/phpunit/includes/ImportTest.php
+++ b/tests/phpunit/includes/ImportTest.php
@@ -28,13 +28,14 @@ class ImportTest extends MediaWikiLangTestCase {
$source = $this->getInputStreamSource( $xml );
$redirect = null;
- $callback = function ( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) use ( &$redirect ) {
+ $callback = function ( Title $title, ForeignTitle $foreignTitle, $revCount,
+ $sRevCount, $pageInfo ) use ( &$redirect ) {
if ( array_key_exists( 'redirect', $pageInfo ) ) {
$redirect = $pageInfo['redirect'];
}
};
- $importer = new WikiImporter( $source );
+ $importer = new WikiImporter( $source, ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
$importer->setPageOutCallback( $callback );
$importer->doImport();
@@ -45,7 +46,7 @@ class ImportTest extends MediaWikiLangTestCase {
return array(
array(
<<< EOF
-<mediawiki>
+<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
<page>
<title>Test</title>
<ns>0</ns>
@@ -59,10 +60,10 @@ class ImportTest extends MediaWikiLangTestCase {
<id>10</id>
</contributor>
<comment>Admin moved page [[Test]] to [[Test22]]</comment>
- <text xml:space="preserve" bytes="20">#REDIRECT [[Test22]]</text>
- <sha1>tq456o9x3abm7r9ozi6km8yrbbc56o6</sha1>
<model>wikitext</model>
<format>text/x-wiki</format>
+ <text xml:space="preserve" bytes="20">#REDIRECT [[Test22]]</text>
+ <sha1>tq456o9x3abm7r9ozi6km8yrbbc56o6</sha1>
</revision>
</page>
</mediawiki>
@@ -72,7 +73,7 @@ EOF
),
array(
<<< EOF
-<mediawiki>
+<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.9/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.9/ http://www.mediawiki.org/xml/export-0.9.xsd" version="0.9" xml:lang="en">
<page>
<title>Test</title>
<ns>0</ns>
@@ -98,4 +99,59 @@ EOF
);
}
+ /**
+ * @covers WikiImporter::handleSiteInfo
+ * @dataProvider getSiteInfoXML
+ * @param string $xml
+ * @param array|null $namespaces
+ */
+ public function testSiteInfoContainsNamespaces( $xml, $namespaces ) {
+ $source = $this->getInputStreamSource( $xml );
+
+ $importNamespaces = null;
+ $callback = function ( array $siteinfo, $innerImporter ) use ( &$importNamespaces ) {
+ $importNamespaces = $siteinfo['_namespaces'];
+ };
+
+ $importer = new WikiImporter( $source, ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
+ $importer->setSiteInfoCallback( $callback );
+ $importer->doImport();
+
+ $this->assertEquals( $importNamespaces, $namespaces );
+ }
+
+ public function getSiteInfoXML() {
+ return array(
+ array(
+ <<< EOF
+<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
+ <siteinfo>
+ <namespaces>
+ <namespace key="-2" case="first-letter">Media</namespace>
+ <namespace key="-1" case="first-letter">Special</namespace>
+ <namespace key="0" case="first-letter" />
+ <namespace key="1" case="first-letter">Talk</namespace>
+ <namespace key="2" case="first-letter">User</namespace>
+ <namespace key="3" case="first-letter">User talk</namespace>
+ <namespace key="100" case="first-letter">Portal</namespace>
+ <namespace key="101" case="first-letter">Portal talk</namespace>
+ </namespaces>
+ </siteinfo>
+</mediawiki>
+EOF
+ ,
+ array(
+ '-2' => 'Media',
+ '-1' => 'Special',
+ '0' => '',
+ '1' => 'Talk',
+ '2' => 'User',
+ '3' => 'User talk',
+ '100' => 'Portal',
+ '101' => 'Portal talk',
+ )
+ ),
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/LanguageConverterTest.php b/tests/phpunit/includes/LanguageConverterTest.php
deleted file mode 100644
index d4ccca99..00000000
--- a/tests/phpunit/includes/LanguageConverterTest.php
+++ /dev/null
@@ -1,187 +0,0 @@
-<?php
-
-class LanguageConverterTest extends MediaWikiLangTestCase {
- /** @var LanguageToTest */
- protected $lang = null;
- /** @var TestConverter */
- protected $lc = null;
-
- protected function setUp() {
- parent::setUp();
-
- $this->setMwGlobals( array(
- 'wgContLang' => Language::factory( 'tg' ),
- 'wgLanguageCode' => 'tg',
- 'wgDefaultLanguageVariant' => false,
- 'wgMemc' => new EmptyBagOStuff,
- 'wgRequest' => new FauxRequest( array() ),
- 'wgUser' => new User,
- ) );
-
- $this->lang = new LanguageToTest();
- $this->lc = new TestConverter(
- $this->lang, 'tg',
- array( 'tg', 'tg-latn' )
- );
- }
-
- protected function tearDown() {
- unset( $this->lc );
- unset( $this->lang );
-
- parent::tearDown();
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- */
- public function testGetPreferredVariantDefaults() {
- $this->assertEquals( 'tg', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getHeaderVariant
- */
- public function testGetPreferredVariantHeaders() {
- global $wgRequest;
- $wgRequest->setHeader( 'Accept-Language', 'tg-latn' );
-
- $this->assertEquals( 'tg-latn', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getHeaderVariant
- */
- public function testGetPreferredVariantHeaderWeight() {
- global $wgRequest;
- $wgRequest->setHeader( 'Accept-Language', 'tg;q=1' );
-
- $this->assertEquals( 'tg', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getHeaderVariant
- */
- public function testGetPreferredVariantHeaderWeight2() {
- global $wgRequest;
- $wgRequest->setHeader( 'Accept-Language', 'tg-latn;q=1' );
-
- $this->assertEquals( 'tg-latn', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getHeaderVariant
- */
- public function testGetPreferredVariantHeaderMulti() {
- global $wgRequest;
- $wgRequest->setHeader( 'Accept-Language', 'en, tg-latn;q=1' );
-
- $this->assertEquals( 'tg-latn', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- */
- public function testGetPreferredVariantUserOption() {
- global $wgUser;
-
- $wgUser = new User;
- $wgUser->load(); // from 'defaults'
- $wgUser->mId = 1;
- $wgUser->mDataLoaded = true;
- $wgUser->mOptionsLoaded = true;
- $wgUser->setOption( 'variant', 'tg-latn' );
-
- $this->assertEquals( 'tg-latn', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getUserVariant
- */
- public function testGetPreferredVariantUserOptionForForeignLanguage() {
- global $wgContLang, $wgUser;
-
- $wgContLang = Language::factory( 'en' );
- $wgUser = new User;
- $wgUser->load(); // from 'defaults'
- $wgUser->mId = 1;
- $wgUser->mDataLoaded = true;
- $wgUser->mOptionsLoaded = true;
- $wgUser->setOption( 'variant-tg', 'tg-latn' );
-
- $this->assertEquals( 'tg-latn', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getUserVariant
- * @covers LanguageConverter::getURLVariant
- */
- public function testGetPreferredVariantHeaderUserVsUrl() {
- global $wgContLang, $wgRequest, $wgUser;
-
- $wgContLang = Language::factory( 'tg-latn' );
- $wgRequest->setVal( 'variant', 'tg' );
- $wgUser = User::newFromId( "admin" );
- $wgUser->setId( 1 );
- $wgUser->mFrom = 'defaults';
- $wgUser->mOptionsLoaded = true;
- // The user's data is ignored because the variant is set in the URL.
- $wgUser->setOption( 'variant', 'tg-latn' );
- $this->assertEquals( 'tg', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- */
- public function testGetPreferredVariantDefaultLanguageVariant() {
- global $wgDefaultLanguageVariant;
-
- $wgDefaultLanguageVariant = 'tg-latn';
- $this->assertEquals( 'tg-latn', $this->lc->getPreferredVariant() );
- }
-
- /**
- * @covers LanguageConverter::getPreferredVariant
- * @covers LanguageConverter::getURLVariant
- */
- public function testGetPreferredVariantDefaultLanguageVsUrlVariant() {
- global $wgDefaultLanguageVariant, $wgRequest, $wgContLang;
-
- $wgContLang = Language::factory( 'tg-latn' );
- $wgDefaultLanguageVariant = 'tg';
- $wgRequest->setVal( 'variant', null );
- $this->assertEquals( 'tg', $this->lc->getPreferredVariant() );
- }
-}
-
-/**
- * Test converter (from Tajiki to latin orthography)
- */
-class TestConverter extends LanguageConverter {
- private $table = array(
- 'б' => 'b',
- 'в' => 'v',
- 'г' => 'g',
- );
-
- function loadDefaultTables() {
- $this->mTables = array(
- 'tg-latn' => new ReplacementArray( $this->table ),
- 'tg' => new ReplacementArray()
- );
- }
-}
-
-class LanguageToTest extends Language {
- function __construct() {
- parent::__construct();
- $variants = array( 'tg', 'tg-latn' );
- $this->mConverter = new TestConverter( $this, 'tg', $variants );
- }
-}
diff --git a/tests/phpunit/includes/LinkerTest.php b/tests/phpunit/includes/LinkerTest.php
index 7b84107e..823c9330 100644
--- a/tests/phpunit/includes/LinkerTest.php
+++ b/tests/phpunit/includes/LinkerTest.php
@@ -149,10 +149,14 @@ class LinkerTest extends MediaWikiLangTestCase {
"pre /* autocomment */ post",
),
array(
- '/* autocomment */ multiple? <a href="/wiki/Special:BlankPage#autocomment2" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment2: </span> </span>',
+ '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment: </span> multiple? <a href="/wiki/Special:BlankPage#autocomment2" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment2: </span> </span></span>',
"/* autocomment */ multiple? /* autocomment2 */ ",
),
array(
+ '<a href="/wiki/Special:BlankPage#autocomment_containing_.2F.2A" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment containing /*: </span> T70361</span>',
+ "/* autocomment containing /* */ T70361"
+ ),
+ array(
'<a href="#autocomment">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
"/* autocomment */",
false, true
@@ -189,4 +193,54 @@ class LinkerTest extends MediaWikiLangTestCase {
),
);
}
+
+ /**
+ * @covers Linker::formatLinksInComment
+ * @dataProvider provideCasesForFormatLinksInComment
+ */
+ public function testFormatLinksInComment( $expected, $input, $wiki ) {
+
+ $conf = new SiteConfiguration();
+ $conf->settings = array(
+ 'wgServer' => array(
+ 'enwiki' => '//en.example.org'
+ ),
+ 'wgArticlePath' => array(
+ 'enwiki' => '/w/$1',
+ ),
+ );
+ $conf->suffixes = array( 'wiki' );
+ $this->setMwGlobals( array(
+ 'wgScript' => '/wiki/index.php',
+ 'wgArticlePath' => '/wiki/$1',
+ 'wgWellFormedXml' => true,
+ 'wgCapitalLinks' => true,
+ 'wgConf' => $conf,
+ ) );
+
+ $this->assertEquals(
+ $expected,
+ Linker::formatLinksInComment( $input, Title::newFromText( 'Special:BlankPage' ), false, $wiki )
+ );
+ }
+
+ public static function provideCasesForFormatLinksInComment() {
+ return array(
+ array(
+ 'foo bar <a href="/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a>',
+ 'foo bar [[Special:BlankPage]]',
+ null,
+ ),
+ array(
+ '<a class="external" rel="nofollow" href="//en.example.org/w/Foo%27bar">Foo\'bar</a>',
+ "[[Foo'bar]]",
+ 'enwiki',
+ ),
+ array(
+ 'foo bar <a class="external" rel="nofollow" href="//en.example.org/w/Special:BlankPage">Special:BlankPage</a>',
+ 'foo bar [[Special:BlankPage]]',
+ 'enwiki',
+ ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/MWTimestampTest.php b/tests/phpunit/includes/MWTimestampTest.php
index dcb98563..36562545 100644
--- a/tests/phpunit/includes/MWTimestampTest.php
+++ b/tests/phpunit/includes/MWTimestampTest.php
@@ -8,6 +8,9 @@ class MWTimestampTest extends MediaWikiLangTestCase {
protected function setUp() {
parent::setUp();
+ // Avoid 'GetHumanTimestamp' hook and others
+ $this->setMwGlobals( 'wgHooks', array() );
+
RequestContext::getMain()->setLanguage( Language::factory( 'en' ) );
}
@@ -79,6 +82,17 @@ class MWTimestampTest extends MediaWikiLangTestCase {
}
/**
+ * Test an out of range timestamp
+ * @dataProvider provideOutOfRangeTimestamps
+ * @expectedException TimestampException
+ * @covers MWTimestamp
+ */
+ public function testOutOfRangeTimestamps( $format, $input ) {
+ $timestamp = new MWTimestamp( $input );
+ $timestamp->getTimestamp( $format );
+ }
+
+ /**
* Test requesting an invalid output format.
* @expectedException TimestampException
* @covers MWTimestamp::getTimestamp
@@ -111,6 +125,18 @@ class MWTimestampTest extends MediaWikiLangTestCase {
}
/**
+ * Returns a list of out of range timestamps in the format:
+ * array( type, timestamp_of_type )
+ */
+ public static function provideOutOfRangeTimestamps() {
+ return array(
+ // Various formats
+ array( TS_MW, '-62167219201' ), // -0001-12-31T23:59:59Z
+ array( TS_MW, '253402300800' ), // 10000-01-01T00:00:00Z
+ );
+ }
+
+ /**
* @dataProvider provideHumanTimestampTests
* @covers MWTimestamp::getHumanTimestamp
*/
diff --git a/tests/phpunit/includes/MediaWikiVersionFetcherTest.php b/tests/phpunit/includes/MediaWikiVersionFetcherTest.php
index e548f817..fa59ef29 100644
--- a/tests/phpunit/includes/MediaWikiVersionFetcherTest.php
+++ b/tests/phpunit/includes/MediaWikiVersionFetcherTest.php
@@ -8,7 +8,6 @@
*
* @group ComposerHooks
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class MediaWikiVersionFetcherTest extends PHPUnit_Framework_TestCase {
diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php
index f3d2a84a..99ec2e42 100644
--- a/tests/phpunit/includes/MessageTest.php
+++ b/tests/phpunit/includes/MessageTest.php
@@ -16,22 +16,11 @@ class MessageTest extends MediaWikiLangTestCase {
* @dataProvider provideConstructor
*/
public function testConstructor( $expectedLang, $key, $params, $language ) {
- $reflection = new ReflectionClass( 'Message' );
-
- $keyProperty = $reflection->getProperty( 'key' );
- $keyProperty->setAccessible( true );
-
- $paramsProperty = $reflection->getProperty( 'parameters' );
- $paramsProperty->setAccessible( true );
-
- $langProperty = $reflection->getProperty( 'language' );
- $langProperty->setAccessible( true );
-
$message = new Message( $key, $params, $language );
- $this->assertEquals( $key, $keyProperty->getValue( $message ) );
- $this->assertEquals( $params, $paramsProperty->getValue( $message ) );
- $this->assertEquals( $expectedLang, $langProperty->getValue( $message ) );
+ $this->assertEquals( $key, $message->getKey() );
+ $this->assertEquals( $params, $message->getParams() );
+ $this->assertEquals( $expectedLang, $message->getLanguage() );
}
public static function provideConstructor() {
@@ -45,21 +34,62 @@ class MessageTest extends MediaWikiLangTestCase {
);
}
- public static function provideTestParams() {
+ public static function provideConstructorParams() {
return array(
- array( array() ),
- array( array( 'foo' ), 'foo' ),
- array( array( 'foo', 'bar' ), 'foo', 'bar' ),
- array( array( 'baz' ), array( 'baz' ) ),
- array( array( 'baz', 'foo' ), array( 'baz', 'foo' ) ),
- array( array( 'baz', 'foo' ), array( 'baz', 'foo' ), 'hhh' ),
- array( array( 'baz', 'foo' ), array( 'baz', 'foo' ), 'hhh', array( 'ahahahahha' ) ),
- array( array( 'baz', 'foo' ), array( 'baz', 'foo' ), array( 'ahahahahha' ) ),
- array( array( 'baz' ), array( 'baz' ), array( 'ahahahahha' ) ),
+ array(
+ array(),
+ array(),
+ ),
+ array(
+ array( 'foo' ),
+ array( 'foo' ),
+ ),
+ array(
+ array( 'foo', 'bar' ),
+ array( 'foo', 'bar' ),
+ ),
+ array(
+ array( 'baz' ),
+ array( array( 'baz' ) ),
+ ),
+ array(
+ array( 'baz', 'foo' ),
+ array( array( 'baz', 'foo' ) ),
+ ),
+ array(
+ array( 'baz', 'foo' ),
+ array( array( 'baz', 'foo' ), 'hhh' ),
+ ),
+ array(
+ array( 'baz', 'foo' ),
+ array( array( 'baz', 'foo' ), 'hhh', array( 'ahahahahha' ) ),
+ ),
+ array(
+ array( 'baz', 'foo' ),
+ array( array( 'baz', 'foo' ), array( 'ahahahahha' ) ),
+ ),
+ array(
+ array( 'baz' ),
+ array( array( 'baz' ), array( 'ahahahahha' ) ),
+ ),
);
}
- public function getLanguageProvider() {
+ /**
+ * @covers Message::__construct
+ * @covers Message::getParams
+ * @dataProvider provideConstructorParams
+ */
+ public function testConstructorParams( $expected, $args ) {
+ $msg = new Message( 'imasomething' );
+
+ $returned = call_user_func_array( array( $msg, 'params' ), $args );
+
+ $this->assertSame( $msg, $returned );
+ $this->assertEquals( $expected, $msg->getParams() );
+ }
+
+ public static function provideConstructorLanguage() {
return array(
array( 'foo', array( 'bar' ), 'en' ),
array( 'foo', array( 'bar' ), 'de' )
@@ -67,27 +97,98 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
+ * @covers Message::__construct
* @covers Message::getLanguage
- * @dataProvider getLanguageProvider
+ * @dataProvider provideConstructorLanguage
*/
- public function testGetLanguageCode( $key, $params, $languageCode ) {
+ public function testConstructorLanguage( $key, $params, $languageCode ) {
$language = Language::factory( $languageCode );
$message = new Message( $key, $params, $language );
$this->assertEquals( $language, $message->getLanguage() );
}
+ public static function provideKeys() {
+ return array(
+ 'string' => array(
+ 'key' => 'mainpage',
+ 'expected' => array( 'mainpage' ),
+ ),
+ 'single' => array(
+ 'key' => array( 'mainpage' ),
+ 'expected' => array( 'mainpage' ),
+ ),
+ 'multi' => array(
+ 'key' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ),
+ 'expected' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ),
+ ),
+ 'empty' => array(
+ 'key' => array(),
+ 'expected' => null,
+ 'exception' => 'InvalidArgumentException',
+ ),
+ 'null' => array(
+ 'key' => null,
+ 'expected' => null,
+ 'exception' => 'InvalidArgumentException',
+ ),
+ 'bad type' => array(
+ 'key' => 123,
+ 'expected' => null,
+ 'exception' => 'InvalidArgumentException',
+ ),
+ );
+ }
+
/**
- * @covers Message::params
- * @dataProvider provideTestParams
+ * @covers Message::__construct
+ * @covers Message::getKey
+ * @covers Message::isMultiKey
+ * @covers Message::getKeysToTry
+ * @dataProvider provideKeys
*/
- public function testParams( $expected ) {
- $msg = new Message( 'imasomething' );
+ public function testKeys( $key, $expected, $exception = null ) {
+ if ( $exception ) {
+ $this->setExpectedException( $exception );
+ }
+
+ $msg = new Message( $key );
+ $this->assertContains( $msg->getKey(), $expected );
+ $this->assertEquals( $expected, $msg->getKeysToTry() );
+ $this->assertEquals( count( $expected ) > 1, $msg->isMultiKey() );
+ }
- $returned = call_user_func_array( array( $msg, 'params' ), array_slice( func_get_args(), 1 ) );
+ /**
+ * @covers ::wfMessage
+ */
+ public function testWfMessage() {
+ $this->assertInstanceOf( 'Message', wfMessage( 'mainpage' ) );
+ $this->assertInstanceOf( 'Message', wfMessage( 'i-dont-exist-evar' ) );
+ }
- $this->assertSame( $msg, $returned );
- $this->assertEquals( $expected, $msg->getParams() );
+ /**
+ * @covers Message::newFromKey
+ */
+ public function testNewFromKey() {
+ $this->assertInstanceOf( 'Message', Message::newFromKey( 'mainpage' ) );
+ $this->assertInstanceOf( 'Message', Message::newFromKey( 'i-dont-exist-evar' ) );
+ }
+
+ /**
+ * @covers ::wfMessage
+ * @covers Message::__construct
+ */
+ public function testWfMessageParams() {
+ $this->assertEquals( 'Return to $1.', wfMessage( 'returnto' )->text() );
+ $this->assertEquals( 'Return to $1.', wfMessage( 'returnto', array() )->text() );
+ $this->assertEquals(
+ 'You have foo (bar).',
+ wfMessage( 'youhavenewmessages', 'foo', 'bar' )->text()
+ );
+ $this->assertEquals(
+ 'You have foo (bar).',
+ wfMessage( 'youhavenewmessages', array( 'foo', 'bar' ) )->text()
+ );
}
/**
@@ -104,14 +205,42 @@ class MessageTest extends MediaWikiLangTestCase {
/**
* @covers Message::__construct
+ * @covers Message::text
+ * @covers Message::plain
+ * @covers Message::escaped
+ * @covers Message::toString
*/
- public function testKey() {
- $this->assertInstanceOf( 'Message', wfMessage( 'mainpage' ) );
- $this->assertInstanceOf( 'Message', wfMessage( 'i-dont-exist-evar' ) );
+ public function testToStringKey() {
$this->assertEquals( 'Main Page', wfMessage( 'mainpage' )->text() );
- $this->assertEquals( '&lt;i-dont-exist-evar&gt;', wfMessage( 'i-dont-exist-evar' )->text() );
+ $this->assertEquals( '<i-dont-exist-evar>', wfMessage( 'i-dont-exist-evar' )->text() );
+ $this->assertEquals( '<i<dont>exist-evar>', wfMessage( 'i<dont>exist-evar' )->text() );
$this->assertEquals( '<i-dont-exist-evar>', wfMessage( 'i-dont-exist-evar' )->plain() );
+ $this->assertEquals( '<i<dont>exist-evar>', wfMessage( 'i<dont>exist-evar' )->plain() );
$this->assertEquals( '&lt;i-dont-exist-evar&gt;', wfMessage( 'i-dont-exist-evar' )->escaped() );
+ $this->assertEquals(
+ '&lt;i&lt;dont&gt;exist-evar&gt;',
+ wfMessage( 'i<dont>exist-evar' )->escaped()
+ );
+ }
+
+ public static function provideToString() {
+ return array(
+ array( 'mainpage', 'Main Page' ),
+ array( 'i-dont-exist-evar', '<i-dont-exist-evar>' ),
+ array( 'i-dont-exist-evar', '&lt;i-dont-exist-evar&gt;', 'escaped' ),
+ );
+ }
+
+ /**
+ * @covers Message::toString
+ * @covers Message::__toString
+ * @dataProvider provideToString
+ */
+ public function testToString( $key, $expect, $format = 'plain' ) {
+ $msg = new Message( $key );
+ $msg->$format();
+ $this->assertEquals( $expect, $msg->toString() );
+ $this->assertEquals( $expect, $msg->__toString() );
}
/**
@@ -132,26 +261,10 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
- * @covers Message::__construct
- */
- public function testMessageParams() {
- $this->assertEquals( 'Return to $1.', wfMessage( 'returnto' )->text() );
- $this->assertEquals( 'Return to $1.', wfMessage( 'returnto', array() )->text() );
- $this->assertEquals(
- 'You have foo (bar).',
- wfMessage( 'youhavenewmessages', 'foo', 'bar' )->text()
- );
- $this->assertEquals(
- 'You have foo (bar).',
- wfMessage( 'youhavenewmessages', array( 'foo', 'bar' ) )->text()
- );
- }
-
- /**
- * @covers Message::__construct
+ * @covers Message::rawParam
* @covers Message::rawParams
*/
- public function testMessageParamSubstitution() {
+ public function testRawParams() {
$this->assertEquals(
'(Заглавная страница)',
wfMessage( 'parentheses', 'Заглавная страница' )->plain()
@@ -171,10 +284,21 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
- * @covers Message::__construct
+ * @covers RawMessage::__construct
+ * @covers RawMessage::fetchMessage
+ */
+ public function testRawMessage() {
+ $msg = new RawMessage( 'example &' );
+ $this->assertEquals( 'example &', $msg->plain() );
+ $this->assertEquals( 'example &amp;', $msg->escaped() );
+ }
+
+ /**
* @covers Message::params
+ * @covers Message::toString
+ * @covers Message::replaceParameters
*/
- public function testDeliciouslyManyParams() {
+ public function testReplaceManyParams() {
$msg = new RawMessage( '$1$2$3$4$5$6$7$8$9$10$11$12' );
// One less than above has placeholders
$params = array( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k' );
@@ -183,12 +307,20 @@ class MessageTest extends MediaWikiLangTestCase {
$msg->params( $params )->plain(),
'Params > 9 are replaced correctly'
);
+
+ $msg = new RawMessage( 'Params$*' );
+ $params = array( 'ab', 'bc', 'cd' );
+ $this->assertEquals(
+ 'Params: ab, bc, cd',
+ $msg->params( $params )->text()
+ );
}
/**
+ * @covers Message::numParam
* @covers Message::numParams
*/
- public function testMessageNumParams() {
+ public function testNumParams() {
$lang = Language::factory( 'en' );
$msg = new RawMessage( '$1' );
@@ -200,9 +332,10 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
+ * @covers Message::durationParam
* @covers Message::durationParams
*/
- public function testMessageDurationParams() {
+ public function testDurationParams() {
$lang = Language::factory( 'en' );
$msg = new RawMessage( '$1' );
@@ -216,9 +349,10 @@ class MessageTest extends MediaWikiLangTestCase {
/**
* FIXME: This should not need database, but Language#formatExpiry does (bug 55912)
* @group Database
+ * @covers Message::expiryParam
* @covers Message::expiryParams
*/
- public function testMessageExpiryParams() {
+ public function testExpiryParams() {
$lang = Language::factory( 'en' );
$msg = new RawMessage( '$1' );
@@ -230,9 +364,10 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
+ * @covers Message::timeperiodParam
* @covers Message::timeperiodParams
*/
- public function testMessageTimeperiodParams() {
+ public function testTimeperiodParams() {
$lang = Language::factory( 'en' );
$msg = new RawMessage( '$1' );
@@ -244,9 +379,10 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
+ * @covers Message::sizeParam
* @covers Message::sizeParams
*/
- public function testMessageSizeParams() {
+ public function testSizeParams() {
$lang = Language::factory( 'en' );
$msg = new RawMessage( '$1' );
@@ -258,9 +394,10 @@ class MessageTest extends MediaWikiLangTestCase {
}
/**
+ * @covers Message::bitrateParam
* @covers Message::bitrateParams
*/
- public function testMessageBitrateParams() {
+ public function testBitrateParams() {
$lang = Language::factory( 'en' );
$msg = new RawMessage( '$1' );
@@ -271,6 +408,100 @@ class MessageTest extends MediaWikiLangTestCase {
);
}
+ public static function providePlaintextParams() {
+ return array(
+ array(
+ 'one $2 <div>foo</div> [[Bar]] {{Baz}} &lt;',
+ 'plain',
+ ),
+
+ array(
+ // expect
+ 'one $2 <div>foo</div> [[Bar]] {{Baz}} &lt;',
+ // format
+ 'text',
+ ),
+ array(
+ 'one $2 &lt;div&gt;foo&lt;/div&gt; [[Bar]] {{Baz}} &amp;lt;',
+ 'escaped',
+ ),
+
+ array(
+ 'one $2 &lt;div&gt;foo&lt;/div&gt; [[Bar]] {{Baz}} &amp;lt;',
+ 'parse',
+ ),
+
+ array(
+ "<p>one $2 &lt;div&gt;foo&lt;/div&gt; [[Bar]] {{Baz}} &amp;lt;\n</p>",
+ 'parseAsBlock',
+ ),
+ );
+ }
+
+ /**
+ * @covers Message::plaintextParam
+ * @covers Message::plaintextParams
+ * @covers Message::formatPlaintext
+ * @covers Message::toString
+ * @covers Message::parse
+ * @covers Message::parseAsBlock
+ * @dataProvider providePlaintextParams
+ */
+ public function testPlaintextParams( $expect, $format ) {
+ $lang = Language::factory( 'en' );
+
+ $msg = new RawMessage( '$1 $2' );
+ $params = array(
+ 'one $2',
+ '<div>foo</div> [[Bar]] {{Baz}} &lt;',
+ );
+ $this->assertEquals(
+ $expect,
+ $msg->inLanguage( $lang )->plaintextParams( $params )->$format(),
+ "Fail formatting for $format"
+ );
+ }
+
+ public static function provideParser() {
+ return array(
+ array(
+ "''&'' <x><!-- x -->",
+ 'plain',
+ ),
+
+ array(
+ "''&'' <x><!-- x -->",
+ 'text',
+ ),
+ array(
+ '<i>&amp;</i> &lt;x&gt;',
+ 'parse',
+ ),
+
+ array(
+ "<p><i>&amp;</i> &lt;x&gt;\n</p>",
+ 'parseAsBlock',
+ ),
+ );
+ }
+
+ /**
+ * @covers Message::text
+ * @covers Message::parse
+ * @covers Message::parseAsBlock
+ * @covers Message::toString
+ * @covers Message::transformText
+ * @covers Message::parseText
+ * @dataProvider provideParser
+ */
+ public function testParser( $expect, $format ) {
+ $msg = new RawMessage( "''&'' <x><!-- x -->" );
+ $this->assertEquals(
+ $expect,
+ $msg->inLanguage( 'en' )->$format()
+ );
+ }
+
/**
* @covers Message::inContentLanguage
*/
@@ -317,52 +548,4 @@ class MessageTest extends MediaWikiLangTestCase {
public function testInLanguageThrows() {
wfMessage( 'foo' )->inLanguage( 123 );
}
-
- public function keyProvider() {
- return array(
- 'string' => array(
- 'key' => 'mainpage',
- 'expected' => array( 'mainpage' ),
- ),
- 'single' => array(
- 'key' => array( 'mainpage' ),
- 'expected' => array( 'mainpage' ),
- ),
- 'multi' => array(
- 'key' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ),
- 'expected' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ),
- ),
- 'empty' => array(
- 'key' => array(),
- 'expected' => null,
- 'exception' => 'InvalidArgumentException',
- ),
- 'null' => array(
- 'key' => null,
- 'expected' => null,
- 'exception' => 'InvalidArgumentException',
- ),
- 'bad type' => array(
- 'key' => 17,
- 'expected' => null,
- 'exception' => 'InvalidArgumentException',
- ),
- );
- }
-
- /**
- * @dataProvider keyProvider()
- *
- * @covers Message::getKey
- */
- public function testGetKey( $key, $expected, $exception = null ) {
- if ( $exception ) {
- $this->setExpectedException( $exception );
- }
-
- $msg = new Message( $key );
- $this->assertEquals( $expected, $msg->getKeysToTry() );
- $this->assertEquals( count( $expected ) > 1, $msg->isMultiKey() );
- $this->assertContains( $msg->getKey(), $expected );
- }
}
diff --git a/tests/phpunit/includes/MovePageTest.php b/tests/phpunit/includes/MovePageTest.php
new file mode 100644
index 00000000..9501e452
--- /dev/null
+++ b/tests/phpunit/includes/MovePageTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @group Database
+ */
+class MovePageTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provideIsValidMove
+ * @covers MovePage::isValidMove
+ * @covers MovePage::isValidFileMove
+ */
+ public function testIsValidMove( $old, $new, $error ) {
+ $this->setMwGlobals( 'wgContentHandlerUseDB', false );
+ $mp = new MovePage(
+ Title::newFromText( $old ),
+ Title::newFromText( $new )
+ );
+ $status = $mp->isValidMove();
+ if ( $error === true ) {
+ $this->assertTrue( $status->isGood() );
+ } else {
+ $this->assertTrue( $status->hasMessage( $error ) );
+ }
+ }
+
+ /**
+ * This should be kept in sync with TitleTest::provideTestIsValidMoveOperation
+ */
+ public static function provideIsValidMove() {
+ return array(
+ // for MovePage::isValidMove
+ array( 'Test', 'Test', 'selfmove' ),
+ array( 'Special:FooBar', 'Test', 'immobile-source-namespace' ),
+ array( 'Test', 'Special:FooBar', 'immobile-target-namespace' ),
+ array( 'MediaWiki:Common.js', 'Help:Some wikitext page', 'bad-target-model' ),
+ array( 'Page', 'File:Test.jpg', 'nonfile-cannot-move-to-file' ),
+ // for MovePage::isValidFileMove
+ array( 'File:Test.jpg', 'Page', 'imagenocrossnamespace' ),
+ );
+ }
+
+ /**
+ * Integration test to catch regressions like T74870. Taken and modified
+ * from SemanticMediaWiki
+ */
+ public function testTitleMoveCompleteIntegrationTest() {
+ $oldTitle = Title::newFromText( 'Help:Some title' );
+ WikiPage::factory( $oldTitle )->doEditContent( new WikitextContent( 'foo' ), 'bar' );
+ $newTitle = Title::newFromText( 'Help:Some other title' );
+ $this->assertNull(
+ WikiPage::factory( $newTitle )->getRevision()
+ );
+
+ $this->assertTrue( $oldTitle->moveTo( $newTitle, false, 'test1', true ) );
+ $this->assertNotNull(
+ WikiPage::factory( $oldTitle )->getRevision()
+ );
+ $this->assertNotNull(
+ WikiPage::factory( $newTitle)->getRevision()
+ );
+ }
+}
diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php
index d7e8cd31..6c6d95ee 100644
--- a/tests/phpunit/includes/OutputPageTest.php
+++ b/tests/phpunit/includes/OutputPageTest.php
@@ -172,18 +172,18 @@ mw.test.baz({token:123});mw.loader.state({"test.quux":"ready"});
array(
array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ),
'<script>if(window.mw){
-mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n"]},{});
+mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n"]});
}</script>
'
),
- // Load module script with with ESI
+ // Load module script with ESI
array(
array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS, true ),
'<script><esi:include src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.foo&amp;only=scripts&amp;skin=fallback&amp;*" /></script>
'
),
- // Load module styles with with ESI
+ // Load module styles with ESI
array(
array( 'test.foo', ResourceLoaderModule::TYPE_STYLES, true ),
'<style><esi:include src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.foo&amp;only=styles&amp;skin=fallback&amp;*" /></style>
@@ -203,9 +203,13 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"
// Load two modules in separate groups
array(
array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ),
- '<script src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.group.bar&amp;skin=fallback&amp;*"></script>
-<script src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.group.foo&amp;skin=fallback&amp;*"></script>
-',
+ '<script>if(window.mw){
+document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\u0026amp;lang=en\u0026amp;modules=test.group.bar\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E");
+}</script>
+<script>if(window.mw){
+document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\u0026amp;lang=en\u0026amp;modules=test.group.foo\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E");
+}</script>
+'
),
);
}
@@ -213,6 +217,11 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"
/**
* @dataProvider provideMakeResourceLoaderLink
* @covers OutputPage::makeResourceLoaderLink
+ * @covers ResourceLoader::makeLoaderImplementScript
+ * @covers ResourceLoader::makeModuleResponse
+ * @covers ResourceLoader::makeInlineScript
+ * @covers ResourceLoader::makeLoaderStateScript
+ * @covers ResourceLoader::createLoaderURL
*/
public function testMakeResourceLoaderLink( $args, $expectedHtml ) {
$this->setMwGlobals( array(
@@ -230,6 +239,7 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"
$ctx->setLanguage( 'en' );
$out = new OutputPage( $ctx );
$rl = $out->getResourceLoader();
+ $rl->setMessageBlobStore( new NullMessageBlobStore() );
$rl->register( array(
'test.foo' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.foo( { a: true } );',
@@ -271,3 +281,26 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"
$this->assertEquals( $expectedHtml, $actualHtml );
}
}
+
+/**
+ * MessageBlobStore that doesn't do anything
+ */
+class NullMessageBlobStore extends MessageBlobStore {
+ public function get ( ResourceLoader $resourceLoader, $modules, $lang ) {
+ return array();
+ }
+
+ public function insertMessageBlob ( $name, ResourceLoaderModule $module, $lang ) {
+ return false;
+ }
+
+ public function updateModule ( $name, ResourceLoaderModule $module, $lang ) {
+ return;
+ }
+
+ public function updateMessage ( $key ) {
+ }
+ public function clear() {
+ }
+}
+
diff --git a/tests/phpunit/includes/PrefixSearchTest.php b/tests/phpunit/includes/PrefixSearchTest.php
new file mode 100644
index 00000000..d63541b7
--- /dev/null
+++ b/tests/phpunit/includes/PrefixSearchTest.php
@@ -0,0 +1,306 @@
+<?php
+/**
+ * @group Search
+ * @group Database
+ */
+class PrefixSearchTest extends MediaWikiLangTestCase {
+
+ public function addDBData() {
+ $this->insertPage( 'Sandbox' );
+ $this->insertPage( 'Bar' );
+ $this->insertPage( 'Example' );
+ $this->insertPage( 'Example Bar' );
+ $this->insertPage( 'Example Foo' );
+ $this->insertPage( 'Example Foo/Bar' );
+ $this->insertPage( 'Example/Baz' );
+ $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
+ $this->insertPage( 'Redirect Test' );
+ $this->insertPage( 'Redirect Test Worse Result' );
+ $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
+ $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
+ $this->insertPage( 'Redirect Test2' );
+ $this->insertPage( 'Redirect Test2 Worse Result' );
+
+ $this->insertPage( 'Talk:Sandbox' );
+ $this->insertPage( 'Talk:Example' );
+
+ $this->insertPage( 'User:Example' );
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ if ( !$this->isWikitextNS( NS_MAIN ) ) {
+ $this->markTestSkipped( 'Main namespace does not support wikitext.' );
+ }
+
+ // Avoid special pages from extensions interferring with the tests
+ $this->setMwGlobals( 'wgSpecialPages', array() );
+ }
+
+ protected function searchProvision( Array $results = null ) {
+ if ( $results === null ) {
+ $this->setMwGlobals( 'wgHooks', array() );
+ } else {
+ $this->setMwGlobals( 'wgHooks', array(
+ 'PrefixSearchBackend' => array(
+ function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) {
+ $srchres = $results;
+ return false;
+ }
+ ),
+ ) );
+ }
+ }
+
+ public static function provideSearch() {
+ return array(
+ array( array(
+ 'Empty string',
+ 'query' => '',
+ 'results' => array(),
+ ) ),
+ array( array(
+ 'Main namespace with title prefix',
+ 'query' => 'Ex',
+ 'results' => array(
+ 'Example',
+ 'Example/Baz',
+ 'Example Bar',
+ ),
+ // Third result when testing offset
+ 'offsetresult' => array(
+ 'Example Foo',
+ ),
+ ) ),
+ array( array(
+ 'Talk namespace prefix',
+ 'query' => 'Talk:',
+ 'results' => array(
+ 'Talk:Example',
+ 'Talk:Sandbox',
+ ),
+ ) ),
+ array( array(
+ 'User namespace prefix',
+ 'query' => 'User:',
+ 'results' => array(
+ 'User:Example',
+ ),
+ ) ),
+ array( array(
+ 'Special namespace prefix',
+ 'query' => 'Special:',
+ 'results' => array(
+ 'Special:ActiveUsers',
+ 'Special:AllMessages',
+ 'Special:AllMyFiles',
+ ),
+ // Third result when testing offset
+ 'offsetresult' => array(
+ 'Special:AllMyUploads',
+ ),
+ ) ),
+ array( array(
+ 'Special namespace with prefix',
+ 'query' => 'Special:Un',
+ 'results' => array(
+ 'Special:Unblock',
+ 'Special:UncategorizedCategories',
+ 'Special:UncategorizedFiles',
+ ),
+ // Third result when testing offset
+ 'offsetresult' => array(
+ 'Special:UncategorizedImages',
+ ),
+ ) ),
+ array( array(
+ 'Special page name',
+ 'query' => 'Special:EditWatchlist',
+ 'results' => array(
+ 'Special:EditWatchlist',
+ ),
+ ) ),
+ array( array(
+ 'Special page subpages',
+ 'query' => 'Special:EditWatchlist/',
+ 'results' => array(
+ 'Special:EditWatchlist/clear',
+ 'Special:EditWatchlist/raw',
+ ),
+ ) ),
+ array( array(
+ 'Special page subpages with prefix',
+ 'query' => 'Special:EditWatchlist/cl',
+ 'results' => array(
+ 'Special:EditWatchlist/clear',
+ ),
+ ) ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSearch
+ * @covers PrefixSearch::search
+ * @covers PrefixSearch::searchBackend
+ */
+ public function testSearch( Array $case ) {
+ $this->searchProvision( null );
+ $searcher = new StringPrefixSearch;
+ $results = $searcher->search( $case['query'], 3 );
+ $this->assertEquals(
+ $case['results'],
+ $results,
+ $case[0]
+ );
+ }
+
+ /**
+ * @dataProvider provideSearch
+ * @covers PrefixSearch::search
+ * @covers PrefixSearch::searchBackend
+ */
+ public function testSearchWithOffset( Array $case ) {
+ $this->searchProvision( null );
+ $searcher = new StringPrefixSearch;
+ $results = $searcher->search( $case['query'], 3, array(), 1 );
+
+ // We don't expect the first result when offsetting
+ array_shift( $case['results'] );
+ // And sometimes we expect a different last result
+ $expected = isset( $case['offsetresult'] ) ?
+ array_merge( $case['results'], $case['offsetresult'] ) :
+ $case['results'];
+
+ $this->assertEquals(
+ $expected,
+ $results,
+ $case[0]
+ );
+ }
+
+ public static function provideSearchBackend() {
+ return array(
+ array( array(
+ 'Simple case',
+ 'provision' => array(
+ 'Bar',
+ 'Barcelona',
+ 'Barbara',
+ ),
+ 'query' => 'Bar',
+ 'results' => array(
+ 'Bar',
+ 'Barcelona',
+ 'Barbara',
+ ),
+ ) ),
+ array( array(
+ 'Exact match not on top (bug 70958)',
+ 'provision' => array(
+ 'Barcelona',
+ 'Bar',
+ 'Barbara',
+ ),
+ 'query' => 'Bar',
+ 'results' => array(
+ 'Bar',
+ 'Barcelona',
+ 'Barbara',
+ ),
+ ) ),
+ array( array(
+ 'Exact match missing (bug 70958)',
+ 'provision' => array(
+ 'Barcelona',
+ 'Barbara',
+ 'Bart',
+ ),
+ 'query' => 'Bar',
+ 'results' => array(
+ 'Bar',
+ 'Barcelona',
+ 'Barbara',
+ ),
+ ) ),
+ array( array(
+ 'Exact match missing and not existing',
+ 'provision' => array(
+ 'Exile',
+ 'Exist',
+ 'External',
+ ),
+ 'query' => 'Ex',
+ 'results' => array(
+ 'Exile',
+ 'Exist',
+ 'External',
+ ),
+ ) ),
+ array( array(
+ "Exact match shouldn't override already found match if " .
+ "exact is redirect and found isn't",
+ 'provision' => array(
+ // Target of the exact match is low in the list
+ 'Redirect Test Worse Result',
+ 'Redirect Test',
+ ),
+ 'query' => 'redirect test',
+ 'results' => array(
+ // Redirect target is pulled up and exact match isn't added
+ 'Redirect Test',
+ 'Redirect Test Worse Result',
+ ),
+ ) ),
+ array( array(
+ "Exact match shouldn't override already found match if " .
+ "both exact match and found match are redirect",
+ 'provision' => array(
+ // Another redirect to the same target as the exact match
+ // is low in the list
+ 'Redirect Test2 Worse Result',
+ 'Redirect test2',
+ ),
+ 'query' => 'redirect TEST2',
+ 'results' => array(
+ // Found redirect is pulled to the top and exact match isn't
+ // added
+ 'Redirect test2',
+ 'Redirect Test2 Worse Result',
+ ),
+ ) ),
+ array( array(
+ "Exact match should override any already found matches that " .
+ "are redirects to it",
+ 'provision' => array(
+ // Another redirect to the same target as the exact match
+ // is low in the list
+ 'Redirect Test Worse Result',
+ 'Redirect test',
+ ),
+ 'query' => 'Redirect Test',
+ 'results' => array(
+ // Found redirect is pulled to the top and exact match isn't
+ // added
+ 'Redirect Test',
+ 'Redirect Test Worse Result',
+ ),
+ ) ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSearchBackend
+ * @covers PrefixSearch::searchBackend
+ */
+ public function testSearchBackend( Array $case ) {
+ $this->searchProvision( $case['provision'] );
+ $searcher = new StringPrefixSearch;
+ $results = $searcher->search( $case['query'], 3 );
+ $this->assertEquals(
+ $case['results'],
+ $results,
+ $case[0]
+ );
+ }
+}
diff --git a/tests/phpunit/includes/SampleTest.php b/tests/phpunit/includes/SampleTest.php
index 25858110..c5944d16 100644
--- a/tests/phpunit/includes/SampleTest.php
+++ b/tests/phpunit/includes/SampleTest.php
@@ -97,7 +97,7 @@ class TestSample extends MediaWikiLangTestCase {
// @codingStandardsIgnoreStart Ignore long line warning
/**
- * @expectedException MWException object
+ * @expectedException InvalidArgumentException
* See http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.expectedException
*/
// @codingStandardsIgnoreEnd
diff --git a/tests/phpunit/includes/SanitizerTest.php b/tests/phpunit/includes/SanitizerTest.php
index 50c1e509..c615c460 100644
--- a/tests/phpunit/includes/SanitizerTest.php
+++ b/tests/phpunit/includes/SanitizerTest.php
@@ -6,12 +6,6 @@
*/
class SanitizerTest extends MediaWikiTestCase {
- protected function setUp() {
- parent::setUp();
-
- AutoLoader::loadClass( 'Sanitizer' );
- }
-
/**
* @covers Sanitizer::decodeCharReferences
*/
@@ -85,7 +79,7 @@ class SanitizerTest extends MediaWikiTestCase {
*/
public function testInvalidNumberedEntities() {
$this->assertEquals(
- UTF8_REPLACEMENT,
+ UtfNormal\Constants::UTF8_REPLACEMENT,
Sanitizer::decodeCharReferences( "&#88888888888888;" ),
'Invalid numbered entity'
);
@@ -346,4 +340,25 @@ class SanitizerTest extends MediaWikiTestCase {
$message
);
}
+
+ /**
+ * @dataProvider provideEscapeHtmlAllowEntities
+ * @covers Sanitizer::escapeHtmlAllowEntities
+ */
+ public function testEscapeHtmlAllowEntities( $expected, $html ) {
+ $this->assertEquals(
+ $expected,
+ Sanitizer::escapeHtmlAllowEntities( $html )
+ );
+ }
+
+ public static function provideEscapeHtmlAllowEntities() {
+ return array(
+ array( 'foo', 'foo' ),
+ array( 'a¡b', 'a&#161;b' ),
+ array( 'foo&#039;bar', "foo'bar" ),
+ array( '&lt;script&gt;foo&lt;/script&gt;', '<script>foo</script>' ),
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/StatusTest.php b/tests/phpunit/includes/StatusTest.php
index 628c59b6..c013f4fc 100644
--- a/tests/phpunit/includes/StatusTest.php
+++ b/tests/phpunit/includes/StatusTest.php
@@ -57,6 +57,17 @@ class StatusTest extends MediaWikiLangTestCase {
}
/**
+ *
+ */
+ public function testOkAndErrors() {
+ $status = Status::newGood( 'foo' );
+ $this->assertTrue( $status->ok );
+ $status = Status::newFatal( 'foo', 1, 2 );
+ $this->assertFalse( $status->ok );
+ $this->assertArrayEquals( array( array( 'type' => 'error', 'message' => 'foo', 'params' => array( 1, 2 ) ) ), $status->errors );
+ }
+
+ /**
* @dataProvider provideSetResult
* @covers Status::setResult
*/
@@ -109,7 +120,9 @@ class StatusTest extends MediaWikiLangTestCase {
public function testIsGood( $ok, $errors, $expected ) {
$status = new Status();
$status->ok = $ok;
- $status->errors = $errors;
+ foreach ( $errors as $error ) {
+ $status->warning( $error );
+ }
$this->assertEquals( $expected, $status->isGood() );
}
diff --git a/tests/phpunit/includes/TemplateParserTest.php b/tests/phpunit/includes/TemplateParserTest.php
new file mode 100644
index 00000000..81854ff3
--- /dev/null
+++ b/tests/phpunit/includes/TemplateParserTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @group Templates
+ */
+class TemplateParserTest extends MediaWikiTestCase {
+
+ protected $templateDir;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgSecretKey' => 'foo',
+ 'wgMemc' => new EmptyBagOStuff(),
+ ) );
+
+ $this->templateDir = dirname( __DIR__ ) . '/data/templates/';
+ }
+
+ /**
+ * @dataProvider provideProcessTemplate
+ * @covers TemplateParser::processTemplate
+ * @covers TemplateParser::getTemplate
+ * @covers TemplateParser::getTemplateFilename
+ */
+ public function testProcessTemplate( $name, $args, $result, $exception = false ) {
+ if ( $exception ) {
+ $this->setExpectedException( $exception );
+ }
+ $tp = new TemplateParser( $this->templateDir );
+ $this->assertEquals( $result, $tp->processTemplate( $name, $args ) );
+ }
+
+ public static function provideProcessTemplate() {
+ return array(
+ array(
+ 'foobar',
+ array(),
+ "hello world!\n"
+ ),
+ array(
+ 'foobar_args',
+ array(
+ 'planet' => 'world',
+ ),
+ "hello world!\n",
+ ),
+ array(
+ '../foobar',
+ array(),
+ false,
+ 'UnexpectedValueException'
+ ),
+ array(
+ 'nonexistenttemplate',
+ array(),
+ false,
+ 'RuntimeException',
+ )
+ );
+ }
+}
diff --git a/tests/phpunit/includes/TestUser.php b/tests/phpunit/includes/TestUser.php
index 610a6acd..754568d0 100644
--- a/tests/phpunit/includes/TestUser.php
+++ b/tests/phpunit/includes/TestUser.php
@@ -5,24 +5,41 @@
* like password if we log in via the API.
*/
class TestUser {
+ /**
+ * @deprecated Since 1.25. Use TestUser::getUser()->getName()
+ * @private
+ * @var string
+ */
public $username;
+
+ /**
+ * @deprecated Since 1.25. Use TestUser::getPassword()
+ * @private
+ * @var string
+ */
public $password;
- public $email;
- public $groups;
+
+ /**
+ * @deprecated Since 1.25. Use TestUser::getUser()
+ * @private
+ * @var User
+ */
public $user;
+ private function assertNotReal() {
+ global $wgDBprefix;
+ if ( $wgDBprefix !== MediaWikiTestCase::DB_PREFIX && $wgDBprefix !== MediaWikiTestCase::ORA_DB_PREFIX ) {
+ throw new MWException( "Can't create user on real database" );
+ }
+ }
+
public function __construct( $username, $realname = 'Real Name',
$email = 'sample@example.com', $groups = array()
) {
- $this->username = $username;
- $this->realname = $realname;
- $this->email = $email;
- $this->groups = $groups;
+ $this->assertNotReal();
- // don't allow user to hardcode or select passwords -- people sometimes run tests
- // on live wikis. Sometimes we create sysop users in these tests. A sysop user with
- // a known password would be a Bad Thing.
- $this->password = User::randomPassword();
+ $this->username = $username;
+ $this->password = 'TestUser';
$this->user = User::newFromName( $this->username );
$this->user->load();
@@ -31,32 +48,99 @@ class TestUser {
// But for now, we just need to create or update the user with the desired properties.
// we particularly need the new password, since we just generated it randomly.
// In core MediaWiki, there is no functionality to delete users, so this is the best we can do.
- if ( !$this->user->getID() ) {
+ if ( !$this->user->isLoggedIn() ) {
// create the user
$this->user = User::createNew(
$this->username, array(
- "email" => $this->email,
- "real_name" => $this->realname
+ "email" => $email,
+ "real_name" => $realname
)
);
+
if ( !$this->user ) {
- throw new Exception( "error creating user" );
+ throw new MWException( "Error creating TestUser " . $username );
}
}
- // update the user to use the new random password and other details
- $this->user->setPassword( $this->password );
- $this->user->setEmail( $this->email );
- $this->user->setRealName( $this->realname );
+ // Update the user to use the password and other details
+ $change = $this->setPassword( $this->password ) ||
+ $this->setEmail( $email ) ||
+ $this->setRealName( $realname );
// Adjust groups by adding any missing ones and removing any extras
$currentGroups = $this->user->getGroups();
- foreach ( array_diff( $this->groups, $currentGroups ) as $group ) {
+ foreach ( array_diff( $groups, $currentGroups ) as $group ) {
$this->user->addGroup( $group );
}
- foreach ( array_diff( $currentGroups, $this->groups ) as $group ) {
+ foreach ( array_diff( $currentGroups, $groups ) as $group ) {
$this->user->removeGroup( $group );
}
- $this->user->saveSettings();
+ if ( $change ) {
+ $this->user->saveSettings();
+ }
+ }
+
+ /**
+ * @param string $realname
+ * @return bool
+ */
+ private function setRealName( $realname ) {
+ if ( $this->user->getRealName() !== $realname ) {
+ $this->user->setRealName( $realname );
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $email
+ * @return bool
+ */
+ private function setEmail( $email ) {
+ if ( $this->user->getEmail() !== $email ) {
+ $this->user->setEmail( $email );
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $password
+ * @return bool
+ */
+ private function setPassword( $password ) {
+ $passwordFactory = $this->user->getPasswordFactory();
+ $oldDefaultType = $passwordFactory->getDefaultType();
+
+ // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
+ $passwordFactory->setDefaultType( 'A' );
+ $newPassword = $passwordFactory->newFromPlaintext( $password, $this->user->getPassword() );
+
+ $change = false;
+ if ( !$this->user->getPassword()->equals( $newPassword ) ) {
+ // Password changed
+ $this->user->setPassword( $password );
+ $change = true;
+ }
+
+ $passwordFactory->setDefaultType( $oldDefaultType );
+
+ return $change;
+ }
+
+ /**
+ * @return User
+ */
+ public function getUser() {
+ return $this->user;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPassword() {
+ return $this->password;
}
}
diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php
new file mode 100644
index 00000000..84c0f9b5
--- /dev/null
+++ b/tests/phpunit/includes/TestingAccessWrapper.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Circumvent access restrictions on object internals
+ *
+ * This can be helpful for writing tests that can probe object internals,
+ * without having to modify the class under test to accomodate.
+ *
+ * Wrap an object with private methods as follows:
+ * $title = TestingAccessWrapper::newFromObject( Title::newFromDBkey( $key ) );
+ *
+ * You can access private and protected instance methods and variables:
+ * $formatter = $title->getTitleFormatter();
+ *
+ * TODO:
+ * - Provide access to static methods and properties.
+ * - Organize other helper classes in tests/testHelpers.inc into a directory.
+ */
+class TestingAccessWrapper {
+ public $object;
+
+ /**
+ * Return the same object, without access restrictions.
+ */
+ public static function newFromObject( $object ) {
+ $wrapper = new TestingAccessWrapper();
+ $wrapper->object = $object;
+ return $wrapper;
+ }
+
+ public function __call( $method, $args ) {
+ $classReflection = new ReflectionClass( $this->object );
+ $methodReflection = $classReflection->getMethod( $method );
+ $methodReflection->setAccessible( true );
+ return $methodReflection->invokeArgs( $this->object, $args );
+ }
+
+ public function __set( $name, $value ) {
+ $classReflection = new ReflectionClass( $this->object );
+ $propertyReflection = $classReflection->getProperty( $name );
+ $propertyReflection->setAccessible( true );
+ $propertyReflection->setValue( $this->object, $value );
+ }
+
+ public function __get( $name ) {
+ $classReflection = new ReflectionClass( $this->object );
+ $propertyReflection = $classReflection->getProperty( $name );
+ $propertyReflection->setAccessible( true );
+ return $propertyReflection->getValue( $this->object );
+ }
+}
diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php
new file mode 100644
index 00000000..7e5b91a1
--- /dev/null
+++ b/tests/phpunit/includes/TestingAccessWrapperTest.php
@@ -0,0 +1,34 @@
+<?php
+
+class TestingAccessWrapperTest extends MediaWikiTestCase {
+ protected $raw;
+ protected $wrapped;
+
+ function setUp() {
+ parent::setUp();
+
+ require_once __DIR__ . '/../data/helpers/WellProtectedClass.php';
+ $this->raw = new WellProtectedClass();
+ $this->wrapped = TestingAccessWrapper::newFromObject( $this->raw );
+ }
+
+ function testGetProperty() {
+ $this->assertSame( 1, $this->wrapped->property );
+ }
+
+ function testSetProperty() {
+ $this->wrapped->property = 10;
+ $this->assertSame( 10, $this->wrapped->property );
+ $this->assertSame( 10, $this->raw->getProperty() );
+ }
+
+ function testCallMethod() {
+ $this->wrapped->incrementPropertyValue();
+ $this->assertSame( 2, $this->wrapped->property );
+ $this->assertSame( 2, $this->raw->getProperty() );
+ }
+
+ function testCallMethodTwoArgs() {
+ $this->assertSame( 'two', $this->wrapped->whatSecondArg( 'one', 'two' ) );
+ }
+}
diff --git a/tests/phpunit/includes/TitleMethodsTest.php b/tests/phpunit/includes/TitleMethodsTest.php
index 5904facd..e186438b 100644
--- a/tests/phpunit/includes/TitleMethodsTest.php
+++ b/tests/phpunit/includes/TitleMethodsTest.php
@@ -7,7 +7,7 @@
* @note We don't make assumptions about the main namespace.
* But we do expect the Help namespace to contain Wikitext.
*/
-class TitleMethodsTest extends MediaWikiTestCase {
+class TitleMethodsTest extends MediaWikiLangTestCase {
protected function setUp() {
global $wgContLang;
@@ -297,4 +297,43 @@ class TitleMethodsTest extends MediaWikiTestCase {
$title = Title::newFromText( $title );
$this->assertEquals( $expectedBool, $title->isWikitextPage() );
}
+
+ public static function provideGetOtherPage() {
+ return array(
+ array( 'Main Page', 'Talk:Main Page' ),
+ array( 'Talk:Main Page', 'Main Page' ),
+ array( 'Help:Main Page', 'Help talk:Main Page' ),
+ array( 'Help talk:Main Page', 'Help:Main Page' ),
+ array( 'Special:FooBar', null ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetOtherpage
+ * @covers Title::getOtherPage
+ *
+ * @param string $text
+ * @param string|null $expected
+ */
+ public function testGetOtherPage( $text, $expected ) {
+ if ( $expected === null ) {
+ $this->setExpectedException( 'MWException' );
+ }
+
+ $title = Title::newFromText( $text );
+ $this->assertEquals( $expected, $title->getOtherPage()->getPrefixedText() );
+ }
+
+ public function testClearCaches() {
+ $linkCache = LinkCache::singleton();
+
+ $title1 = Title::newFromText( 'Foo' );
+ $linkCache->addGoodLinkObj( 23, $title1 );
+
+ Title::clearCaches();
+
+ $title2 = Title::newFromText( 'Foo' );
+ $this->assertNotSame( $title1, $title2, 'title cache should be empty' );
+ $this->assertEquals( 0, $linkCache->getGoodLinkID( 'Foo' ), 'link cache should be empty' );
+ }
}
diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php
index d2400b3f..022c7d53 100644
--- a/tests/phpunit/includes/TitlePermissionTest.php
+++ b/tests/phpunit/includes/TitlePermissionTest.php
@@ -326,6 +326,10 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->setUserPerm( null );
$this->assertEquals( $check[$action][0],
$this->title->getUserPermissionsErrors( $action, $this->user, true ) );
+ $this->assertEquals( $check[$action][0],
+ $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) );
+ $this->assertEquals( $check[$action][0],
+ $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) );
global $wgGroupPermissions;
$old = $wgGroupPermissions;
@@ -333,11 +337,19 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->assertEquals( $check[$action][1],
$this->title->getUserPermissionsErrors( $action, $this->user, true ) );
+ $this->assertEquals( $check[$action][1],
+ $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) );
+ $this->assertEquals( $check[$action][1],
+ $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) );
$wgGroupPermissions = $old;
$this->setUserPerm( $action );
$this->assertEquals( $check[$action][2],
$this->title->getUserPermissionsErrors( $action, $this->user, true ) );
+ $this->assertEquals( $check[$action][2],
+ $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) );
+ $this->assertEquals( $check[$action][2],
+ $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) );
$this->setUserPerm( $action );
$this->assertEquals( $check[$action][3],
@@ -403,7 +415,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->setTitle( NS_USER );
$this->setUserPerm( '' );
- $this->assertEquals( array( array( 'badaccess-group0' ), array( 'namespaceprotected', 'User', 'bogus' ) ),
+ $this->assertEquals( array( array( 'badaccess-group0' ),
+ array( 'namespaceprotected', 'User', 'bogus' ) ),
$this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
$this->setTitle( NS_MEDIAWIKI );
@@ -630,7 +643,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->assertEquals( false,
$this->title->userCan( 'bogus', $this->user ) );
- $this->assertEquals( array( array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ),
+ $this->assertEquals( array(
+ array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ),
array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ),
array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ) ),
$this->title->getUserPermissionsErrors( 'bogus', $this->user ) );
@@ -648,10 +662,10 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
public function testActionPermissions() {
$this->setUserPerm( array( "createpage" ) );
$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'] = wfGetDB( DB_SLAVE )->getInfinity();
- $this->title->mTitleProtection['pt_reason'] = 'test';
+ $this->title->mTitleProtection['permission'] = '';
+ $this->title->mTitleProtection['user'] = $this->user->getID();
+ $this->title->mTitleProtection['expiry'] = wfGetDB( DB_SLAVE )->getInfinity();
+ $this->title->mTitleProtection['reason'] = 'test';
$this->title->mCascadeRestriction = false;
$this->assertEquals( array( array( 'titleprotected', 'Useruser', 'test' ) ),
@@ -659,7 +673,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->assertEquals( false,
$this->title->userCan( 'create', $this->user ) );
- $this->title->mTitleProtection['pt_create_perm'] = 'sysop';
+ $this->title->mTitleProtection['permission'] = 'editprotected';
$this->setUserPerm( array( 'createpage', 'protect' ) );
$this->assertEquals( array( array( 'titleprotected', 'Useruser', 'test' ) ),
$this->title->getUserPermissionsErrors( 'create', $this->user ) );
diff --git a/tests/phpunit/includes/TitleTest.php b/tests/phpunit/includes/TitleTest.php
index fb58381f..d55f958b 100644
--- a/tests/phpunit/includes/TitleTest.php
+++ b/tests/phpunit/includes/TitleTest.php
@@ -14,6 +14,7 @@ class TitleTest extends MediaWikiTestCase {
'wgLang' => Language::factory( 'en' ),
'wgAllowUserJs' => false,
'wgDefaultLanguageVariant' => false,
+ 'wgMetaNamespace' => 'Project',
) );
}
@@ -324,36 +325,19 @@ class TitleTest extends MediaWikiTestCase {
$whitelistRegexp = array( $whitelistRegexp );
}
+ $this->setMwGlobals( array(
+ // So User::isEveryoneAllowed( 'read' ) === false
+ 'wgGroupPermissions' => array( '*' => array( 'read' => false ) ),
+ 'wgWhitelistRead' => array( 'some random non sense title' ),
+ 'wgWhitelistReadRegexp' => $whitelistRegexp,
+ ) );
+
$title = Title::newFromDBkey( $source );
- global $wgGroupPermissions;
- $oldPermissions = $wgGroupPermissions;
- // Disallow all so we can ensure our regex works
- $wgGroupPermissions = array();
- $wgGroupPermissions['*']['read'] = false;
-
- global $wgWhitelistRead;
- $oldWhitelist = $wgWhitelistRead;
- // Undo any LocalSettings explicite whitelists so they won't cause a
- // failing test to succeed. Set it to some random non sense just
- // to make sure we properly test Title::checkReadPermissions()
- $wgWhitelistRead = array( 'some random non sense title' );
-
- global $wgWhitelistReadRegexp;
- $oldWhitelistRegexp = $wgWhitelistReadRegexp;
- $wgWhitelistReadRegexp = $whitelistRegexp;
-
- // Just use $wgUser which in test is a user object for '127.0.0.1'
- global $wgUser;
- // Invalidate user rights cache to take in account $wgGroupPermissions
- // change above.
- $wgUser->clearInstanceCache();
- $errors = $title->userCan( $action, $wgUser );
-
- // Restore globals
- $wgGroupPermissions = $oldPermissions;
- $wgWhitelistRead = $oldWhitelist;
- $wgWhitelistReadRegexp = $oldWhitelistRegexp;
+ // New anonymous user with no rights
+ $user = new User;
+ $user->mRights = array();
+ $errors = $title->userCan( $action, $user );
if ( is_bool( $expected ) ) {
# Forge the assertion message depending on the assertion expectation
@@ -428,14 +412,14 @@ class TitleTest extends MediaWikiTestCase {
public function testGetPageViewLanguage( $expected, $titleText, $contLang,
$lang, $variant, $msg = ''
) {
- global $wgLanguageCode, $wgContLang, $wgLang, $wgDefaultLanguageVariant, $wgAllowUserJs;
-
// Setup environnement for this test
- $wgLanguageCode = $contLang;
- $wgContLang = Language::factory( $contLang );
- $wgLang = Language::factory( $lang );
- $wgDefaultLanguageVariant = $variant;
- $wgAllowUserJs = true;
+ $this->setMwGlobals( array(
+ 'wgLanguageCode' => $contLang,
+ 'wgContLang' => Language::factory( $contLang ),
+ 'wgLang' => Language::factory( $lang ),
+ 'wgDefaultLanguageVariant' => $variant,
+ 'wgAllowUserJs' => true,
+ ) );
$title = Title::newFromText( $titleText );
$this->assertInstanceOf( 'Title', $title,
diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php
index af95a721..b74a7ead 100644
--- a/tests/phpunit/includes/UserTest.php
+++ b/tests/phpunit/includes/UserTest.php
@@ -214,8 +214,10 @@ class UserTest extends MediaWikiTestCase {
*/
public function testEditCount() {
$user = User::newFromName( 'UnitTestUser' );
- $user->loadDefaults();
- $user->addToDatabase();
+
+ if ( !$user->getId() ) {
+ $user->addToDatabase();
+ }
// let the user have a few (3) edits
$page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
@@ -248,14 +250,17 @@ class UserTest extends MediaWikiTestCase {
*/
public function testOptions() {
$user = User::newFromName( 'UnitTestUser' );
- $user->addToDatabase();
- $user->setOption( 'someoption', 'test' );
+ if ( !$user->getId() ) {
+ $user->addToDatabase();
+ }
+
+ $user->setOption( 'userjs-someoption', 'test' );
$user->setOption( 'cols', 200 );
$user->saveSettings();
$user = User::newFromName( 'UnitTestUser' );
- $this->assertEquals( 'test', $user->getOption( 'someoption' ) );
+ $this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
$this->assertEquals( 200, $user->getOption( 'cols' ) );
}
@@ -266,9 +271,9 @@ class UserTest extends MediaWikiTestCase {
*/
public function testAnonOptions() {
global $wgDefaultUserOptions;
- $this->user->setOption( 'someoption', 'test' );
+ $this->user->setOption( 'userjs-someoption', 'test' );
$this->assertEquals( $wgDefaultUserOptions['cols'], $this->user->getOption( 'cols' ) );
- $this->assertEquals( 'test', $this->user->getOption( 'someoption' ) );
+ $this->assertEquals( 'test', $this->user->getOption( 'userjs-someoption' ) );
}
/**
@@ -276,12 +281,10 @@ class UserTest extends MediaWikiTestCase {
* @covers User::getPasswordExpired()
*/
public function testPasswordExpire() {
- global $wgPasswordExpireGrace;
- $wgTemp = $wgPasswordExpireGrace;
- $wgPasswordExpireGrace = 3600 * 24 * 7; // 7 days
+ $this->setMwGlobals( 'wgPasswordExpireGrace', 3600 * 24 * 7 ); // 7 days
$user = User::newFromName( 'UnitTestUser' );
- $user->loadDefaults();
+ $user->loadDefaults( 'UnitTestUser' );
$this->assertEquals( false, $user->getPasswordExpired() );
$ts = time() - ( 3600 * 24 * 1 ); // 1 day ago
@@ -291,8 +294,6 @@ class UserTest extends MediaWikiTestCase {
$ts = time() - ( 3600 * 24 * 10 ); // 10 days ago
$user->expirePassword( $ts );
$this->assertEquals( 'hard', $user->getPasswordExpired() );
-
- $wgPasswordExpireGrace = $wgTemp;
}
/**
@@ -343,8 +344,8 @@ class UserTest extends MediaWikiTestCase {
public function testGetCanonicalName( $name, $expectedArray, $msg ) {
foreach ( $expectedArray as $validate => $expected ) {
$this->assertEquals(
- User::getCanonicalName( $name, $validate === 'false' ? false : $validate ),
$expected,
+ User::getCanonicalName( $name, $validate === 'false' ? false : $validate ),
$msg . ' (' . $validate . ')'
);
}
@@ -352,8 +353,8 @@ class UserTest extends MediaWikiTestCase {
public static function provideGetCanonicalName() {
return array(
- array( ' trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ),
- // @todo FIXME: Maybe the createable name should be 'Talk:Username' or false to reject?
+ array( ' Trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ),
+ // @todo FIXME: Maybe the creatable name should be 'Talk:Username' or false to reject?
array( 'Talk:Username', array( 'creatable' => 'Username', 'usable' => 'Username',
'valid' => 'Username', 'false' => 'Talk:Username' ), 'Namespace prefix' ),
array( ' name with # hash', array( 'creatable' => false, 'usable' => false ), 'With hash' ),
@@ -366,4 +367,62 @@ class UserTest extends MediaWikiTestCase {
'false' => 'With / slash' ), 'With slash' ),
);
}
+
+ /**
+ * @covers User::equals
+ */
+ public function testEquals() {
+ $first = User::newFromName( 'EqualUser' );
+ $second = User::newFromName( 'EqualUser' );
+
+ $this->assertTrue( $first->equals( $first ) );
+ $this->assertTrue( $first->equals( $second ) );
+ $this->assertTrue( $second->equals( $first ) );
+
+ $third = User::newFromName( '0' );
+ $fourth = User::newFromName( '000' );
+
+ $this->assertFalse( $third->equals( $fourth ) );
+ $this->assertFalse( $fourth->equals( $third ) );
+
+ // Test users loaded from db with id
+ $user = User::newFromName( 'EqualUnitTestUser' );
+ if ( !$user->getId() ) {
+ $user->addToDatabase();
+ }
+
+ $id = $user->getId();
+
+ $fifth = User::newFromId( $id );
+ $sixth = User::newFromName( 'EqualUnitTestUser' );
+ $this->assertTrue( $fifth->equals( $sixth ) );
+ }
+
+ /**
+ * @covers User::getId
+ */
+ public function testGetId() {
+ $user = User::newFromName( 'UTSysop' );
+ $this->assertTrue( $user->getId() > 0 );
+
+ }
+
+ /**
+ * @covers User::isLoggedIn
+ * @covers User::isAnon
+ */
+ public function testLoggedIn() {
+ $user = User::newFromName( 'UTSysop' );
+ $this->assertTrue( $user->isLoggedIn() );
+ $this->assertFalse( $user->isAnon() );
+
+ // Non-existent users are perceived as anonymous
+ $user = User::newFromName( 'UTNonexistent' );
+ $this->assertFalse( $user->isLoggedIn() );
+ $this->assertTrue( $user->isAnon() );
+
+ $user = new User;
+ $this->assertFalse( $user->isLoggedIn() );
+ $this->assertTrue( $user->isAnon() );
+ }
}
diff --git a/tests/phpunit/includes/XmlSelectTest.php b/tests/phpunit/includes/XmlSelectTest.php
index 9f154bb7..0e03add4 100644
--- a/tests/phpunit/includes/XmlSelectTest.php
+++ b/tests/phpunit/includes/XmlSelectTest.php
@@ -166,7 +166,7 @@ class XmlSelectTest extends MediaWikiTestCase {
'razor'
);
- # inexistant keys should give us 'null'
+ # inexistent keys should give us 'null'
$this->assertEquals(
$this->select->getAttribute( 'I DO NOT EXIT' ),
null
diff --git a/tests/phpunit/includes/XmlTest.php b/tests/phpunit/includes/XmlTest.php
index e6558819..382e3d89 100644
--- a/tests/phpunit/includes/XmlTest.php
+++ b/tests/phpunit/includes/XmlTest.php
@@ -81,7 +81,7 @@ class XmlTest extends MediaWikiTestCase {
*/
public function testElementInputCanHaveAValueOfZero() {
$this->assertEquals(
- '<input name="name" value="0" class="mw-ui-input" />',
+ '<input name="name" value="0" />',
Xml::input( 'name', false, 0 ),
'Input with a value of 0 (bug 23797)'
);
@@ -152,7 +152,7 @@ class XmlTest extends MediaWikiTestCase {
$this->assertEquals(
'<label for="year">From year (and earlier):</label> ' .
- '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" class="mw-ui-input" /> ' .
+ '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" /> ' .
'<label for="month">From month (and earlier):</label> ' .
'<select id="month" name="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
@@ -173,7 +173,7 @@ class XmlTest extends MediaWikiTestCase {
);
$this->assertEquals(
'<label for="year">From year (and earlier):</label> ' .
- '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" class="mw-ui-input" /> ' .
+ '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" /> ' .
'<label for="month">From month (and earlier):</label> ' .
'<select id="month" name="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
@@ -207,7 +207,7 @@ class XmlTest extends MediaWikiTestCase {
$this->assertEquals(
'<label for="year">From year (and earlier):</label> ' .
- '<input id="year" maxlength="4" size="7" type="number" name="year" class="mw-ui-input" /> ' .
+ '<input id="year" maxlength="4" size="7" type="number" name="year" /> ' .
'<label for="month">From month (and earlier):</label> ' .
'<select id="month" name="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
@@ -233,7 +233,7 @@ class XmlTest extends MediaWikiTestCase {
*/
public function testTextareaNoContent() {
$this->assertEquals(
- '<textarea name="name" id="name" cols="40" rows="5" class="mw-ui-input"></textarea>',
+ '<textarea name="name" id="name" cols="40" rows="5"></textarea>',
Xml::textarea( 'name', '' ),
'textarea() with not content'
);
@@ -244,7 +244,7 @@ class XmlTest extends MediaWikiTestCase {
*/
public function testTextareaAttribs() {
$this->assertEquals(
- '<textarea name="name" id="name" cols="20" rows="10" class="mw-ui-input">&lt;txt&gt;</textarea>',
+ '<textarea name="name" id="name" cols="20" rows="10">&lt;txt&gt;</textarea>',
Xml::textarea( 'name', '<txt>', 20, 10 ),
'textarea() with custom attribs'
);
diff --git a/tests/phpunit/includes/actions/ActionTest.php b/tests/phpunit/includes/actions/ActionTest.php
index cc6fb11a..3babb97f 100644
--- a/tests/phpunit/includes/actions/ActionTest.php
+++ b/tests/phpunit/includes/actions/ActionTest.php
@@ -3,7 +3,6 @@
/**
* @covers Action
*
- * @licence GNU GPL v2+
* @author Thiemo Mättig
*
* @group Action
@@ -20,7 +19,7 @@ class ActionTest extends MediaWikiTestCase {
'disabled' => false,
'view' => true,
'edit' => true,
- 'revisiondelete' => true,
+ 'revisiondelete' => 'SpecialPageAction',
'dummy' => true,
'string' => 'NamedDummyAction',
'declared' => 'NonExistingClassName',
@@ -117,6 +116,15 @@ class ActionTest extends MediaWikiTestCase {
$this->assertEquals( 'revisiondelete', $actionName );
}
+ public function testGetActionName_whenCanNotUseWikiPage_defaultsToView() {
+ $request = new FauxRequest( array( 'action' => 'edit' ) );
+ $context = new DerivativeContext( RequestContext::getMain() );
+ $context->setRequest( $request );
+ $actionName = Action::getActionName( $context );
+
+ $this->assertEquals( 'view', $actionName );
+ }
+
/**
* @dataProvider actionProvider
* @param string $requestedAction
diff --git a/tests/phpunit/includes/api/ApiContinuationManagerTest.php b/tests/phpunit/includes/api/ApiContinuationManagerTest.php
new file mode 100644
index 00000000..2edf0c6f
--- /dev/null
+++ b/tests/phpunit/includes/api/ApiContinuationManagerTest.php
@@ -0,0 +1,195 @@
+<?php
+
+/**
+ * @covers ApiContinuationManager
+ * @group API
+ */
+class ApiContinuationManagerTest extends MediaWikiTestCase {
+
+ private static function getManager( $continue, $allModules, $generatedModules ) {
+ $context = new DerivativeContext( RequestContext::getMain() );
+ $context->setRequest( new FauxRequest( array( 'continue' => $continue ) ) );
+ $main = new ApiMain( $context );
+ return new ApiContinuationManager( $main, $allModules, $generatedModules );
+ }
+
+ public function testContinuation() {
+ $allModules = array(
+ new MockApiQueryBase( 'mock1' ),
+ new MockApiQueryBase( 'mock2' ),
+ new MockApiQueryBase( 'mocklist' ),
+ );
+ $generator = new MockApiQueryBase( 'generator' );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( 'ApiMain', $manager->getSource() );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $manager->addGeneratorContinueParam( $generator, 'gcontinue', 3 );
+ $this->assertSame( array( array(
+ 'mlcontinue' => 2,
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2',
+ ), false ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ 'generator' => array( 'gcontinue' => 3 ),
+ ), $manager->getRawContinuation() );
+
+ $result = new ApiResult( 0 );
+ $manager->setContinuationIntoResult( $result );
+ $this->assertSame( array(
+ 'mlcontinue' => 2,
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $manager->addGeneratorContinueParam( $generator, 'gcontinue', array( 3, 4 ) );
+ $this->assertSame( array( array(
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2|mocklist',
+ ), false ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ 'generator' => array( 'gcontinue' => '3|4' ),
+ ), $manager->getRawContinuation() );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $manager->addGeneratorContinueParam( $generator, 'gcontinue', 3 );
+ $this->assertSame( array( array(
+ 'mlcontinue' => 2,
+ 'gcontinue' => 3,
+ 'continue' => 'gcontinue||',
+ ), true ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ 'generator' => array( 'gcontinue' => 3 ),
+ ), $manager->getRawContinuation() );
+
+ $result = new ApiResult( 0 );
+ $manager->setContinuationIntoResult( $result );
+ $this->assertSame( array(
+ 'mlcontinue' => 2,
+ 'gcontinue' => 3,
+ 'continue' => 'gcontinue||',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addGeneratorContinueParam( $generator, 'gcontinue', 3 );
+ $this->assertSame( array( array(
+ 'gcontinue' => 3,
+ 'continue' => 'gcontinue||mocklist',
+ ), true ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'generator' => array( 'gcontinue' => 3 ),
+ ), $manager->getRawContinuation() );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $this->assertSame( array( array(
+ 'mlcontinue' => 2,
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2',
+ ), false ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ ), $manager->getRawContinuation() );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $this->assertSame( array( array(
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2|mocklist',
+ ), false ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ ), $manager->getRawContinuation() );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $this->assertSame( array( array(
+ 'mlcontinue' => 2,
+ 'continue' => '-||mock1|mock2',
+ ), true ), $manager->getContinuation() );
+ $this->assertSame( array(
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ ), $manager->getRawContinuation() );
+
+ $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame( $allModules, $manager->getRunModules() );
+ $this->assertSame( array( array(), true ), $manager->getContinuation() );
+ $this->assertSame( array(), $manager->getRawContinuation() );
+
+ $manager = self::getManager( '||mock2', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( false, $manager->isGeneratorDone() );
+ $this->assertSame(
+ array_values( array_diff_key( $allModules, array( 1 => 1 ) ) ),
+ $manager->getRunModules()
+ );
+
+ $manager = self::getManager( '-||', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( true, $manager->isGeneratorDone() );
+ $this->assertSame(
+ array_values( array_diff_key( $allModules, array( 0 => 0, 1 => 1 ) ) ),
+ $manager->getRunModules()
+ );
+
+ try {
+ self::getManager( 'foo', $allModules, array( 'mock1', 'mock2' ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UsageException $ex ) {
+ $this->assertSame(
+ 'Invalid continue param. You should pass the original value returned by the previous query',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $manager = self::getManager( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) );
+ try {
+ $manager->addContinueParam( $allModules[1], 'm2continue', 1 );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'Module \'mock2\' was not supposed to have been executed, but it was executed anyway',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $manager->addContinueParam( $allModules[2], 'mlcontinue', 1 );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ }
+
+}
diff --git a/tests/phpunit/includes/api/ApiErrorFormatterTest.php b/tests/phpunit/includes/api/ApiErrorFormatterTest.php
new file mode 100644
index 00000000..8ebdf60f
--- /dev/null
+++ b/tests/phpunit/includes/api/ApiErrorFormatterTest.php
@@ -0,0 +1,351 @@
+<?php
+
+/**
+ * @group API
+ */
+class ApiErrorFormatterTest extends MediaWikiTestCase {
+
+ /**
+ * @covers ApiErrorFormatter
+ * @dataProvider provideErrorFormatter
+ */
+ public function testErrorFormatter( $format, $lang, $useDB,
+ $expect1, $expect2, $expect3
+ ) {
+ $result = new ApiResult( 8388608 );
+ $formatter = new ApiErrorFormatter( $result, Language::factory( $lang ), $format, $useDB );
+
+ // Add default type
+ $expect1[ApiResult::META_TYPE] = 'assoc';
+ $expect2[ApiResult::META_TYPE] = 'assoc';
+ $expect3[ApiResult::META_TYPE] = 'assoc';
+
+ $formatter->addWarning( 'string', 'mainpage' );
+ $formatter->addError( 'err', 'mainpage' );
+ $this->assertSame( $expect1, $result->getResultData(), 'Simple test' );
+
+ $result->reset();
+ $formatter->addWarning( 'foo', 'mainpage' );
+ $formatter->addWarning( 'foo', 'mainpage' );
+ $formatter->addWarning( 'foo', array( 'parentheses', 'foobar' ) );
+ $msg1 = wfMessage( 'mainpage' );
+ $formatter->addWarning( 'message', $msg1 );
+ $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', array( 'overriddenData' => true ) );
+ $formatter->addWarning( 'messageWithData', $msg2 );
+ $formatter->addError( 'errWithData', $msg2 );
+ $this->assertSame( $expect2, $result->getResultData(), 'Complex test' );
+
+ $result->reset();
+ $status = Status::newGood();
+ $status->warning( 'mainpage' );
+ $status->warning( 'parentheses', 'foobar' );
+ $status->warning( $msg1 );
+ $status->warning( $msg2 );
+ $status->error( 'mainpage' );
+ $status->error( 'parentheses', 'foobar' );
+ $formatter->addMessagesFromStatus( 'status', $status );
+ $this->assertSame( $expect3, $result->getResultData(), 'Status test' );
+
+ $this->assertSame(
+ $expect3['errors']['status'],
+ $formatter->arrayFromStatus( $status, 'error' ),
+ 'arrayFromStatus test for error'
+ );
+ $this->assertSame(
+ $expect3['warnings']['status'],
+ $formatter->arrayFromStatus( $status, 'warning' ),
+ 'arrayFromStatus test for warning'
+ );
+ }
+
+ public static function provideErrorFormatter() {
+ $mainpagePlain = wfMessage( 'mainpage' )->useDatabase( false )->plain();
+ $parensPlain = wfMessage( 'parentheses', 'foobar' )->useDatabase( false )->plain();
+ $mainpageText = wfMessage( 'mainpage' )->inLanguage( 'de' )->text();
+ $parensText = wfMessage( 'parentheses', 'foobar' )->inLanguage( 'de' )->text();
+ $C = ApiResult::META_CONTENT;
+ $I = ApiResult::META_INDEXED_TAG_NAME;
+
+ return array(
+ array( 'wikitext', 'de', true,
+ array(
+ 'errors' => array(
+ 'err' => array(
+ array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'string' => array(
+ array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ array(
+ 'errors' => array(
+ 'errWithData' => array(
+ array( 'code' => 'overriddenCode', 'text' => $mainpageText,
+ 'overriddenData' => true, $C => 'text' ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'messageWithData' => array(
+ array( 'code' => 'overriddenCode', 'text' => $mainpageText,
+ 'overriddenData' => true, $C => 'text' ),
+ $I => 'warning',
+ ),
+ 'message' => array(
+ array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ),
+ $I => 'warning',
+ ),
+ 'foo' => array(
+ array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ),
+ array( 'code' => 'parentheses', 'text' => $parensText, $C => 'text' ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ array(
+ 'errors' => array(
+ 'status' => array(
+ array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ),
+ array( 'code' => 'parentheses', 'text' => $parensText, $C => 'text' ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'status' => array(
+ array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ),
+ array( 'code' => 'parentheses', 'text' => $parensText, $C => 'text' ),
+ array( 'code' => 'overriddenCode', 'text' => $mainpageText,
+ 'overriddenData' => true, $C => 'text' ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ ),
+ array( 'raw', 'fr', true,
+ array(
+ 'errors' => array(
+ 'err' => array(
+ array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'string' => array(
+ array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ array(
+ 'errors' => array(
+ 'errWithData' => array(
+ array( 'code' => 'overriddenCode', 'message' => 'mainpage', 'params' => array( $I => 'param' ),
+ 'overriddenData' => true ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'messageWithData' => array(
+ array( 'code' => 'overriddenCode', 'message' => 'mainpage', 'params' => array( $I => 'param' ),
+ 'overriddenData' => true ),
+ $I => 'warning',
+ ),
+ 'message' => array(
+ array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ $I => 'warning',
+ ),
+ 'foo' => array(
+ array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ array( 'code' => 'parentheses', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ array(
+ 'errors' => array(
+ 'status' => array(
+ array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ array( 'code' => 'parentheses', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'status' => array(
+ array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ array( 'code' => 'parentheses', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ),
+ array( 'code' => 'overriddenCode', 'message' => 'mainpage', 'params' => array( $I => 'param' ),
+ 'overriddenData' => true ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ ),
+ array( 'none', 'fr', true,
+ array(
+ 'errors' => array(
+ 'err' => array(
+ array( 'code' => 'mainpage' ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'string' => array(
+ array( 'code' => 'mainpage' ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ array(
+ 'errors' => array(
+ 'errWithData' => array(
+ array( 'code' => 'overriddenCode', 'overriddenData' => true ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'messageWithData' => array(
+ array( 'code' => 'overriddenCode', 'overriddenData' => true ),
+ $I => 'warning',
+ ),
+ 'message' => array(
+ array( 'code' => 'mainpage' ),
+ $I => 'warning',
+ ),
+ 'foo' => array(
+ array( 'code' => 'mainpage' ),
+ array( 'code' => 'parentheses' ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ array(
+ 'errors' => array(
+ 'status' => array(
+ array( 'code' => 'mainpage' ),
+ array( 'code' => 'parentheses' ),
+ $I => 'error',
+ ),
+ ),
+ 'warnings' => array(
+ 'status' => array(
+ array( 'code' => 'mainpage' ),
+ array( 'code' => 'parentheses' ),
+ array( 'code' => 'overriddenCode', 'overriddenData' => true ),
+ $I => 'warning',
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @covers ApiErrorFormatter_BackCompat
+ */
+ public function testErrorFormatterBC() {
+ $mainpagePlain = wfMessage( 'mainpage' )->useDatabase( false )->plain();
+ $parensPlain = wfMessage( 'parentheses', 'foobar' )->useDatabase( false )->plain();
+
+ $result = new ApiResult( 8388608 );
+ $formatter = new ApiErrorFormatter_BackCompat( $result );
+
+ $formatter->addWarning( 'string', 'mainpage' );
+ $formatter->addError( 'err', 'mainpage' );
+ $this->assertSame( array(
+ 'error' => array(
+ 'code' => 'mainpage',
+ 'info' => $mainpagePlain,
+ ),
+ 'warnings' => array(
+ 'string' => array(
+ 'warnings' => $mainpagePlain,
+ ApiResult::META_CONTENT => 'warnings',
+ ),
+ ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData(), 'Simple test' );
+
+ $result->reset();
+ $formatter->addWarning( 'foo', 'mainpage' );
+ $formatter->addWarning( 'foo', 'mainpage' );
+ $formatter->addWarning( 'foo', array( 'parentheses', 'foobar' ) );
+ $msg1 = wfMessage( 'mainpage' );
+ $formatter->addWarning( 'message', $msg1 );
+ $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', array( 'overriddenData' => true ) );
+ $formatter->addWarning( 'messageWithData', $msg2 );
+ $formatter->addError( 'errWithData', $msg2 );
+ $this->assertSame( array(
+ 'error' => array(
+ 'code' => 'overriddenCode',
+ 'info' => $mainpagePlain,
+ 'overriddenData' => true,
+ ),
+ 'warnings' => array(
+ 'messageWithData' => array(
+ 'warnings' => $mainpagePlain,
+ ApiResult::META_CONTENT => 'warnings',
+ ),
+ 'message' => array(
+ 'warnings' => $mainpagePlain,
+ ApiResult::META_CONTENT => 'warnings',
+ ),
+ 'foo' => array(
+ 'warnings' => "$mainpagePlain\n$parensPlain",
+ ApiResult::META_CONTENT => 'warnings',
+ ),
+ ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData(), 'Complex test' );
+
+ $result->reset();
+ $status = Status::newGood();
+ $status->warning( 'mainpage' );
+ $status->warning( 'parentheses', 'foobar' );
+ $status->warning( $msg1 );
+ $status->warning( $msg2 );
+ $status->error( 'mainpage' );
+ $status->error( 'parentheses', 'foobar' );
+ $formatter->addMessagesFromStatus( 'status', $status );
+ $this->assertSame( array(
+ 'error' => array(
+ 'code' => 'parentheses',
+ 'info' => $parensPlain,
+ ),
+ 'warnings' => array(
+ 'status' => array(
+ 'warnings' => "$mainpagePlain\n$parensPlain",
+ ApiResult::META_CONTENT => 'warnings',
+ ),
+ ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData(), 'Status test' );
+
+ $I = ApiResult::META_INDEXED_TAG_NAME;
+ $this->assertSame(
+ array(
+ array( 'type' => 'error', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ array( 'type' => 'error', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ),
+ $I => 'error',
+ ),
+ $formatter->arrayFromStatus( $status, 'error' ),
+ 'arrayFromStatus test for error'
+ );
+ $this->assertSame(
+ array(
+ array( 'type' => 'warning', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ),
+ array( 'type' => 'warning', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ),
+ array( 'message' => 'mainpage', 'params' => array( $I => 'param' ), 'type' => 'warning' ),
+ array( 'message' => 'mainpage', 'params' => array( $I => 'param' ), 'type' => 'warning' ),
+ $I => 'warning',
+ ),
+ $formatter->arrayFromStatus( $status, 'warning' ),
+ 'arrayFromStatus test for warning'
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/api/ApiLoginTest.php b/tests/phpunit/includes/api/ApiLoginTest.php
index 67a75f36..88a99e9b 100644
--- a/tests/phpunit/includes/api/ApiLoginTest.php
+++ b/tests/phpunit/includes/api/ApiLoginTest.php
@@ -123,7 +123,8 @@ class ApiLoginTest extends ApiTestCase {
"lgname" => $user->username,
"lgpassword" => $user->password
)
- )
+ ),
+ __METHOD__
);
$req->execute();
diff --git a/tests/phpunit/includes/api/ApiMainTest.php b/tests/phpunit/includes/api/ApiMainTest.php
index 780cf9ed..e8ef1804 100644
--- a/tests/phpunit/includes/api/ApiMainTest.php
+++ b/tests/phpunit/includes/api/ApiMainTest.php
@@ -2,7 +2,6 @@
/**
* @group API
- * @group Database
* @group medium
*
* @covers ApiMain
@@ -10,41 +9,25 @@
class ApiMainTest extends ApiTestCase {
/**
- * Test that the API will accept a FauxRequest and execute. The help action
- * (default) throws a UsageException. Just validate we're getting proper XML
- *
- * @expectedException UsageException
+ * Test that the API will accept a FauxRequest and execute.
*/
public function testApi() {
$api = new ApiMain(
- new FauxRequest( array( 'action' => 'help', 'format' => 'xml' ) )
+ new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
);
$api->execute();
- $api->getPrinter()->setBufferResult( true );
- $api->printResult( false );
- $resp = $api->getPrinter()->getBuffer();
-
- libxml_use_internal_errors( true );
- $sxe = simplexml_load_string( $resp );
- $this->assertNotInternalType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
+ $data = $api->getResult()->getResultData();
+ $this->assertInternalType( 'array', $data );
+ $this->assertArrayHasKey( 'query', $data );
}
public static function provideAssert() {
- $anon = new User();
- $bot = new User();
- $bot->setName( 'Bot' );
- $bot->addToDatabase();
- $bot->addGroup( 'bot' );
- $user = new User();
- $user->setName( 'User' );
- $user->addToDatabase();
return array(
- array( $anon, 'user', 'assertuserfailed' ),
- array( $user, 'user', false ),
- array( $user, 'bot', 'assertbotfailed' ),
- array( $bot, 'user', false ),
- array( $bot, 'bot', false ),
+ array( false, array(), 'user', 'assertuserfailed' ),
+ array( true, array(), 'user', false ),
+ array( true, array(), 'bot', 'assertbotfailed' ),
+ array( true, array( 'bot' ), 'user', false ),
+ array( true, array( 'bot' ), 'bot', false ),
);
}
@@ -53,11 +36,17 @@ class ApiMainTest extends ApiTestCase {
*
* @covers ApiMain::checkAsserts
* @dataProvider provideAssert
- * @param User $user
+ * @param bool $registered
+ * @param array $rights
* @param string $assert
* @param string|bool $error False if no error expected
*/
- public function testAssert( $user, $assert, $error ) {
+ public function testAssert( $registered, $rights, $assert, $error ) {
+ $user = new User();
+ if ( $registered ) {
+ $user->setId( 1 );
+ }
+ $user->mRights = $rights;
try {
$this->doApiRequest( array(
'action' => 'query',
@@ -69,4 +58,25 @@ class ApiMainTest extends ApiTestCase {
}
}
+ /**
+ * Test if all classes in the main module manager exists
+ */
+ public function testClassNamesInModuleManager() {
+ global $wgAutoloadLocalClasses, $wgAutoloadClasses;
+
+ // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php
+ $classes = $wgAutoloadLocalClasses + $wgAutoloadClasses;
+
+ $api = new ApiMain(
+ new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
+ );
+ $modules = $api->getModuleManager()->getNamesWithClasses();
+ foreach( $modules as $name => $class ) {
+ $this->assertArrayHasKey(
+ $class,
+ $classes,
+ 'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)'
+ );
+ }
+ }
}
diff --git a/tests/phpunit/includes/api/ApiMessageTest.php b/tests/phpunit/includes/api/ApiMessageTest.php
new file mode 100644
index 00000000..6c3ce60d
--- /dev/null
+++ b/tests/phpunit/includes/api/ApiMessageTest.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @group API
+ */
+class ApiMessageTest extends MediaWikiTestCase {
+
+ private function compareMessages( $msg, $msg2 ) {
+ $this->assertSame( $msg->getKey(), $msg2->getKey(), 'getKey' );
+ $this->assertSame( $msg->getKeysToTry(), $msg2->getKeysToTry(), 'getKeysToTry' );
+ $this->assertSame( $msg->getParams(), $msg2->getParams(), 'getParams' );
+ $this->assertSame( $msg->getFormat(), $msg2->getFormat(), 'getFormat' );
+ $this->assertSame( $msg->getLanguage(), $msg2->getLanguage(), 'getLanguage' );
+
+ $msg = TestingAccessWrapper::newFromObject( $msg );
+ $msg2 = TestingAccessWrapper::newFromObject( $msg2 );
+ foreach ( array( 'interface', 'useDatabase', 'title' ) as $key ) {
+ $this->assertSame( $msg->$key, $msg2->$key, $key );
+ }
+ }
+
+ /**
+ * @covers ApiMessage
+ */
+ public function testApiMessage() {
+ $msg = new Message( array( 'foo', 'bar' ), array( 'baz' ) );
+ $msg->inLanguage( 'de' )->title( Title::newMainPage() );
+ $msg2 = new ApiMessage( $msg, 'code', array( 'data' ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
+ $msg = new Message( array( 'foo', 'bar' ), array( 'baz' ) );
+ $msg2 = new ApiMessage( array( array( 'foo', 'bar' ), 'baz' ), 'code', array( 'data' ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
+ $msg = new Message( 'foo' );
+ $msg2 = new ApiMessage( 'foo' );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'foo', $msg2->getApiCode() );
+ $this->assertEquals( array(), $msg2->getApiData() );
+
+ $msg2->setApiCode( 'code', array( 'data' ) );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2->setApiCode( null );
+ $this->assertEquals( 'foo', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2->setApiData( array( 'data2' ) );
+ $this->assertEquals( array( 'data2' ), $msg2->getApiData() );
+ }
+
+ /**
+ * @covers ApiRawMessage
+ */
+ public function testApiRawMessage() {
+ $msg = new RawMessage( 'foo', array( 'baz' ) );
+ $msg->inLanguage( 'de' )->title( Title::newMainPage() );
+ $msg2 = new ApiRawMessage( $msg, 'code', array( 'data' ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
+ $msg = new RawMessage( 'foo', array( 'baz' ) );
+ $msg2 = new ApiRawMessage( array( 'foo', 'baz' ), 'code', array( 'data' ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
+ $msg = new RawMessage( 'foo' );
+ $msg2 = new ApiRawMessage( 'foo', 'code', array( 'data' ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
+ $msg2->setApiCode( 'code', array( 'data' ) );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2->setApiCode( null );
+ $this->assertEquals( 'foo', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2->setApiData( array( 'data2' ) );
+ $this->assertEquals( array( 'data2' ), $msg2->getApiData() );
+ }
+
+ /**
+ * @covers ApiMessage::create
+ */
+ public function testApiMessageCreate() {
+ $this->assertInstanceOf( 'ApiMessage', ApiMessage::create( new Message( 'mainpage' ) ) );
+ $this->assertInstanceOf( 'ApiRawMessage', ApiMessage::create( new RawMessage( 'mainpage' ) ) );
+ $this->assertInstanceOf( 'ApiMessage', ApiMessage::create( 'mainpage' ) );
+
+ $msg = new ApiMessage( 'mainpage' );
+ $this->assertSame( $msg, ApiMessage::create( $msg ) );
+
+ $msg = new ApiRawMessage( 'mainpage' );
+ $this->assertSame( $msg, ApiMessage::create( $msg ) );
+ }
+
+}
diff --git a/tests/phpunit/includes/api/ApiOptionsTest.php b/tests/phpunit/includes/api/ApiOptionsTest.php
index 5f955bbc..51154ae3 100644
--- a/tests/phpunit/includes/api/ApiOptionsTest.php
+++ b/tests/phpunit/includes/api/ApiOptionsTest.php
@@ -17,8 +17,6 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
/** @var DerivativeContext */
private $mContext;
- private $mOldGetPreferencesHooks;
-
private static $Success = array( 'options' => 'success' );
protected function setUp() {
@@ -50,21 +48,11 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
$this->mTested = new ApiOptions( $main, 'options' );
- global $wgHooks;
- if ( !isset( $wgHooks['GetPreferences'] ) ) {
- $wgHooks['GetPreferences'] = array();
- }
- $this->mOldGetPreferencesHooks = $wgHooks['GetPreferences'];
- $wgHooks['GetPreferences'][] = array( $this, 'hookGetPreferences' );
- }
-
- protected function tearDown() {
- global $wgHooks;
-
- $wgHooks['GetPreferences'] = $this->mOldGetPreferencesHooks;
- $this->mOldGetPreferencesHooks = false;
-
- parent::tearDown();
+ $this->mergeMwGlobalArrayValue( 'wgHooks', array(
+ 'GetPreferences' => array(
+ array( $this, 'hookGetPreferences' )
+ )
+ ) );
}
public function hookGetPreferences( $user, &$preferences ) {
@@ -150,7 +138,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
$this->mContext->setRequest( new FauxRequest( $request, true, $this->mSession ) );
$this->mTested->execute();
- return $this->mTested->getResult()->getData();
+ return $this->mTested->getResult()->getResultData( null, array( 'Strip' => 'all' ) );
}
/**
@@ -408,7 +396,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
'options' => 'success',
'warnings' => array(
'options' => array(
- '*' => "Validation error for 'special': cannot be set by this module"
+ 'warnings' => "Validation error for 'special': cannot be set by this module"
)
)
), $response );
@@ -431,7 +419,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
'options' => 'success',
'warnings' => array(
'options' => array(
- '*' => "Validation error for 'unknownOption': not a valid preference"
+ 'warnings' => "Validation error for 'unknownOption': not a valid preference"
)
)
), $response );
diff --git a/tests/phpunit/includes/api/ApiResultTest.php b/tests/phpunit/includes/api/ApiResultTest.php
new file mode 100644
index 00000000..f0d84552
--- /dev/null
+++ b/tests/phpunit/includes/api/ApiResultTest.php
@@ -0,0 +1,1563 @@
+<?php
+
+/**
+ * @covers ApiResult
+ * @group API
+ */
+class ApiResultTest extends MediaWikiTestCase {
+
+ /**
+ * @covers ApiResult
+ */
+ public function testStaticDataMethods() {
+ $arr = array();
+
+ ApiResult::setValue( $arr, 'setValue', '1' );
+
+ ApiResult::setValue( $arr, null, 'unnamed 1' );
+ ApiResult::setValue( $arr, null, 'unnamed 2' );
+
+ ApiResult::setValue( $arr, 'deleteValue', '2' );
+ ApiResult::unsetValue( $arr, 'deleteValue' );
+
+ ApiResult::setContentValue( $arr, 'setContentValue', '3' );
+
+ $this->assertSame( array(
+ 'setValue' => '1',
+ 'unnamed 1',
+ 'unnamed 2',
+ ApiResult::META_CONTENT => 'setContentValue',
+ 'setContentValue' => '3',
+ ), $arr );
+
+ try {
+ ApiResult::setValue( $arr, 'setValue', '99' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame(
+ 'Attempting to add element setValue=99, existing value is 1',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ try {
+ ApiResult::setContentValue( $arr, 'setContentValue2', '99' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame(
+ 'Attempting to set content element as setContentValue2 when setContentValue ' .
+ 'is already set as the content element',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ ApiResult::setValue( $arr, 'setValue', '99', ApiResult::OVERRIDE );
+ $this->assertSame( '99', $arr['setValue'] );
+
+ ApiResult::setContentValue( $arr, 'setContentValue2', '99', ApiResult::OVERRIDE );
+ $this->assertSame( 'setContentValue2', $arr[ApiResult::META_CONTENT] );
+
+ $arr = array( 'foo' => 1, 'bar' => 1 );
+ ApiResult::setValue( $arr, 'top', '2', ApiResult::ADD_ON_TOP );
+ ApiResult::setValue( $arr, null, '2', ApiResult::ADD_ON_TOP );
+ ApiResult::setValue( $arr, 'bottom', '2' );
+ ApiResult::setValue( $arr, 'foo', '2', ApiResult::OVERRIDE );
+ ApiResult::setValue( $arr, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
+ $this->assertSame( array( 0, 'top', 'foo', 'bar', 'bottom' ), array_keys( $arr ) );
+
+ $arr = array();
+ ApiResult::setValue( $arr, 'sub', array( 'foo' => 1 ) );
+ ApiResult::setValue( $arr, 'sub', array( 'bar' => 1 ) );
+ $this->assertSame( array( 'sub' => array( 'foo' => 1, 'bar' => 1 ) ), $arr );
+
+ try {
+ ApiResult::setValue( $arr, 'sub', array( 'foo' => 2, 'baz' => 2 ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame(
+ 'Conflicting keys (foo) when attempting to merge element sub',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $arr = array();
+ $title = Title::newFromText( "MediaWiki:Foobar" );
+ $obj = new stdClass;
+ $obj->foo = 1;
+ $obj->bar = 2;
+ ApiResult::setValue( $arr, 'title', $title );
+ ApiResult::setValue( $arr, 'obj', $obj );
+ $this->assertSame( array(
+ 'title' => (string)$title,
+ 'obj' => array( 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ),
+ ), $arr );
+
+ $fh = tmpfile();
+ try {
+ ApiResult::setValue( $arr, 'file', $fh );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ ApiResult::setValue( $arr, null, $fh );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $obj->file = $fh;
+ ApiResult::setValue( $arr, 'sub', $obj );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $obj->file = $fh;
+ ApiResult::setValue( $arr, null, $obj );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ fclose( $fh );
+
+ try {
+ ApiResult::setValue( $arr, 'inf', INF );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ ApiResult::setValue( $arr, null, INF );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ ApiResult::setValue( $arr, 'nan', NAN );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ ApiResult::setValue( $arr, null, NAN );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $arr = array();
+ $result2 = new ApiResult( 8388608 );
+ $result2->addValue( null, 'foo', 'bar' );
+ ApiResult::setValue( $arr, 'baz', $result2 );
+ $this->assertSame( array(
+ 'baz' => array(
+ ApiResult::META_TYPE => 'assoc',
+ 'foo' => 'bar',
+ )
+ ), $arr );
+
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', "foo\x80bar" );
+ ApiResult::setValue( $arr, 'bar', "a\xcc\x81" );
+ ApiResult::setValue( $arr, 'baz', 74 );
+ ApiResult::setValue( $arr, null, "foo\x80bar" );
+ ApiResult::setValue( $arr, null, "a\xcc\x81" );
+ $this->assertSame( array(
+ 'foo' => "foo\xef\xbf\xbdbar",
+ 'bar' => "\xc3\xa1",
+ 'baz' => 74,
+ 0 => "foo\xef\xbf\xbdbar",
+ 1 => "\xc3\xa1",
+ ), $arr );
+ }
+
+ /**
+ * @covers ApiResult
+ */
+ public function testInstanceDataMethods() {
+ $result = new ApiResult( 8388608 );
+
+ $result->addValue( null, 'setValue', '1' );
+
+ $result->addValue( null, null, 'unnamed 1' );
+ $result->addValue( null, null, 'unnamed 2' );
+
+ $result->addValue( null, 'deleteValue', '2' );
+ $result->removeValue( null, 'deleteValue' );
+
+ $result->addValue( array( 'a', 'b' ), 'deleteValue', '3' );
+ $result->removeValue( array( 'a', 'b', 'deleteValue' ), null, '3' );
+
+ $result->addContentValue( null, 'setContentValue', '3' );
+
+ $this->assertSame( array(
+ 'setValue' => '1',
+ 'unnamed 1',
+ 'unnamed 2',
+ 'a' => array( 'b' => array() ),
+ 'setContentValue' => '3',
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_CONTENT => 'setContentValue',
+ ), $result->getResultData() );
+ $this->assertSame( 20, $result->getSize() );
+
+ try {
+ $result->addValue( null, 'setValue', '99' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame(
+ 'Attempting to add element setValue=99, existing value is 1',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ try {
+ $result->addContentValue( null, 'setContentValue2', '99' );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame(
+ 'Attempting to set content element as setContentValue2 when setContentValue ' .
+ 'is already set as the content element',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $result->addValue( null, 'setValue', '99', ApiResult::OVERRIDE );
+ $this->assertSame( '99', $result->getResultData( array( 'setValue' ) ) );
+
+ $result->addContentValue( null, 'setContentValue2', '99', ApiResult::OVERRIDE );
+ $this->assertSame( 'setContentValue2',
+ $result->getResultData( array( ApiResult::META_CONTENT ) ) );
+
+ $result->reset();
+ $this->assertSame( array(
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+ $this->assertSame( 0, $result->getSize() );
+
+ $result->addValue( null, 'foo', 1 );
+ $result->addValue( null, 'bar', 1 );
+ $result->addValue( null, 'top', '2', ApiResult::ADD_ON_TOP );
+ $result->addValue( null, null, '2', ApiResult::ADD_ON_TOP );
+ $result->addValue( null, 'bottom', '2' );
+ $result->addValue( null, 'foo', '2', ApiResult::OVERRIDE );
+ $result->addValue( null, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
+ $this->assertSame( array( 0, 'top', 'foo', 'bar', 'bottom', ApiResult::META_TYPE ),
+ array_keys( $result->getResultData() ) );
+
+ $result->reset();
+ $result->addValue( null, 'foo', array( 'bar' => 1 ) );
+ $result->addValue( array( 'foo', 'top' ), 'x', 2, ApiResult::ADD_ON_TOP );
+ $result->addValue( array( 'foo', 'bottom' ), 'x', 2 );
+ $this->assertSame( array( 'top', 'bar', 'bottom' ),
+ array_keys( $result->getResultData( array( 'foo' ) ) ) );
+
+ $result->reset();
+ $result->addValue( null, 'sub', array( 'foo' => 1 ) );
+ $result->addValue( null, 'sub', array( 'bar' => 1 ) );
+ $this->assertSame( array(
+ 'sub' => array( 'foo' => 1, 'bar' => 1 ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+
+ try {
+ $result->addValue( null, 'sub', array( 'foo' => 2, 'baz' => 2 ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( RuntimeException $ex ) {
+ $this->assertSame(
+ 'Conflicting keys (foo) when attempting to merge element sub',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $result->reset();
+ $title = Title::newFromText( "MediaWiki:Foobar" );
+ $obj = new stdClass;
+ $obj->foo = 1;
+ $obj->bar = 2;
+ $result->addValue( null, 'title', $title );
+ $result->addValue( null, 'obj', $obj );
+ $this->assertSame( array(
+ 'title' => (string)$title,
+ 'obj' => array( 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+
+ $fh = tmpfile();
+ try {
+ $result->addValue( null, 'file', $fh );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $result->addValue( null, null, $fh );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $obj->file = $fh;
+ $result->addValue( null, 'sub', $obj );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $obj->file = $fh;
+ $result->addValue( null, null, $obj );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add resource(stream) to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ fclose( $fh );
+
+ try {
+ $result->addValue( null, 'inf', INF );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $result->addValue( null, null, INF );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $result->addValue( null, 'nan', NAN );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $result->addValue( null, null, NAN );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $result->reset();
+ $result->addParsedLimit( 'foo', 12 );
+ $this->assertSame( array(
+ 'limits' => array( 'foo' => 12 ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+ $result->addParsedLimit( 'foo', 13 );
+ $this->assertSame( array(
+ 'limits' => array( 'foo' => 13 ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+ $this->assertSame( null, $result->getResultData( array( 'foo', 'bar', 'baz' ) ) );
+ $this->assertSame( 13, $result->getResultData( array( 'limits', 'foo' ) ) );
+ try {
+ $result->getResultData( array( 'limits', 'foo', 'bar' ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Path limits.foo is not an array',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $result = new ApiResult( 10 );
+ $formatter = new ApiErrorFormatter( $result, Language::factory( 'en' ), 'none', false );
+ $result->setErrorFormatter( $formatter );
+ $this->assertFalse( $result->addValue( null, 'foo', '12345678901' ) );
+ $this->assertTrue( $result->addValue( null, 'foo', '12345678901', ApiResult::NO_SIZE_CHECK ) );
+ $this->assertSame( 0, $result->getSize() );
+ $result->reset();
+ $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
+ $this->assertFalse( $result->addValue( null, 'foo', '1' ) );
+ $result->removeValue( null, 'foo' );
+ $this->assertTrue( $result->addValue( null, 'foo', '1' ) );
+
+ $result = new ApiResult( 8388608 );
+ $result2 = new ApiResult( 8388608 );
+ $result2->addValue( null, 'foo', 'bar' );
+ $result->addValue( null, 'baz', $result2 );
+ $this->assertSame( array(
+ 'baz' => array(
+ 'foo' => 'bar',
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+
+ $result = new ApiResult( 8388608 );
+ $result->addValue( null, 'foo', "foo\x80bar" );
+ $result->addValue( null, 'bar', "a\xcc\x81" );
+ $result->addValue( null, 'baz', 74 );
+ $result->addValue( null, null, "foo\x80bar" );
+ $result->addValue( null, null, "a\xcc\x81" );
+ $this->assertSame( array(
+ 'foo' => "foo\xef\xbf\xbdbar",
+ 'bar' => "\xc3\xa1",
+ 'baz' => 74,
+ 0 => "foo\xef\xbf\xbdbar",
+ 1 => "\xc3\xa1",
+ ApiResult::META_TYPE => 'assoc',
+ ), $result->getResultData() );
+ }
+
+ /**
+ * @covers ApiResult
+ */
+ public function testMetadata() {
+ $arr = array( 'foo' => array( 'bar' => array() ) );
+ $result = new ApiResult( 8388608 );
+ $result->addValue( null, 'foo', array( 'bar' => array() ) );
+
+ $expect = array(
+ 'foo' => array(
+ 'bar' => array(
+ ApiResult::META_INDEXED_TAG_NAME => 'ritn',
+ ApiResult::META_TYPE => 'default',
+ ),
+ ApiResult::META_INDEXED_TAG_NAME => 'ritn',
+ ApiResult::META_TYPE => 'default',
+ ),
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar' ),
+ ApiResult::META_TYPE => 'array',
+ );
+
+ ApiResult::setSubelementsList( $arr, 'foo' );
+ ApiResult::setSubelementsList( $arr, array( 'bar', 'baz' ) );
+ ApiResult::unsetSubelementsList( $arr, 'baz' );
+ ApiResult::setIndexedTagNameRecursive( $arr, 'ritn' );
+ ApiResult::setIndexedTagName( $arr, 'itn' );
+ ApiResult::setPreserveKeysList( $arr, 'foo' );
+ ApiResult::setPreserveKeysList( $arr, array( 'bar', 'baz' ) );
+ ApiResult::unsetPreserveKeysList( $arr, 'baz' );
+ ApiResult::setArrayTypeRecursive( $arr, 'default' );
+ ApiResult::setArrayType( $arr, 'array' );
+ $this->assertSame( $expect, $arr );
+
+ $result->addSubelementsList( null, 'foo' );
+ $result->addSubelementsList( null, array( 'bar', 'baz' ) );
+ $result->removeSubelementsList( null, 'baz' );
+ $result->addIndexedTagNameRecursive( null, 'ritn' );
+ $result->addIndexedTagName( null, 'itn' );
+ $result->addPreserveKeysList( null, 'foo' );
+ $result->addPreserveKeysList( null, array( 'bar', 'baz' ) );
+ $result->removePreserveKeysList( null, 'baz' );
+ $result->addArrayTypeRecursive( null, 'default' );
+ $result->addArrayType( null, 'array' );
+ $this->assertEquals( $expect, $result->getResultData() );
+
+ $arr = array( 'foo' => array( 'bar' => array() ) );
+ $expect = array(
+ 'foo' => array(
+ 'bar' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ ApiResult::META_TYPE => 'BCkvp',
+ ApiResult::META_KVP_KEY_NAME => 'bc',
+ );
+ ApiResult::setArrayTypeRecursive( $arr, 'kvp', 'key' );
+ ApiResult::setArrayType( $arr, 'BCkvp', 'bc' );
+ $this->assertSame( $expect, $arr );
+ }
+
+ /**
+ * @covers ApiResult
+ */
+ public function testUtilityFunctions() {
+ $arr = array(
+ 'foo' => array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'bar2' => (object)array( '_dummy' => 'foobaz' ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ 'foo2' => (object)array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'bar2' => (object)array( '_dummy' => 'foobaz' ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
+ ApiResult::META_TYPE => 'array',
+ '_dummy' => 'foobaz',
+ '_dummy2' => 'foobaz!',
+ );
+ $this->assertEquals( array(
+ 'foo' => array(
+ 'bar' => array(),
+ 'bar2' => (object)array(),
+ 'x' => 'ok',
+ ),
+ 'foo2' => (object)array(
+ 'bar' => array(),
+ 'bar2' => (object)array(),
+ 'x' => 'ok',
+ ),
+ '_dummy2' => 'foobaz!',
+ ), ApiResult::stripMetadata( $arr ), 'ApiResult::stripMetadata' );
+
+ $metadata = array();
+ $data = ApiResult::stripMetadataNonRecursive( $arr, $metadata );
+ $this->assertEquals( array(
+ 'foo' => array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'bar2' => (object)array( '_dummy' => 'foobaz' ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ 'foo2' => (object)array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'bar2' => (object)array( '_dummy' => 'foobaz' ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ '_dummy2' => 'foobaz!',
+ ), $data, 'ApiResult::stripMetadataNonRecursive ($data)' );
+ $this->assertEquals( array(
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
+ ApiResult::META_TYPE => 'array',
+ '_dummy' => 'foobaz',
+ ), $metadata, 'ApiResult::stripMetadataNonRecursive ($metadata)' );
+
+ $metadata = null;
+ $data = ApiResult::stripMetadataNonRecursive( (object)$arr, $metadata );
+ $this->assertEquals( (object)array(
+ 'foo' => array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'bar2' => (object)array( '_dummy' => 'foobaz' ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ 'foo2' => (object)array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'bar2' => (object)array( '_dummy' => 'foobaz' ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ '_dummy2' => 'foobaz!',
+ ), $data, 'ApiResult::stripMetadataNonRecursive on object ($data)' );
+ $this->assertEquals( array(
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
+ ApiResult::META_TYPE => 'array',
+ '_dummy' => 'foobaz',
+ ), $metadata, 'ApiResult::stripMetadataNonRecursive on object ($metadata)' );
+ }
+
+ /**
+ * @covers ApiResult
+ * @dataProvider provideTransformations
+ * @param string $label
+ * @param array $input
+ * @param array $transforms
+ * @param array|Exception $expect
+ */
+ public function testTransformations( $label, $input, $transforms, $expect ) {
+ $result = new ApiResult( false );
+ $result->addValue( null, 'test', $input );
+
+ if ( $expect instanceof Exception ) {
+ try {
+ $output = $result->getResultData( 'test', $transforms );
+ $this->fail( 'Expected exception not thrown', $label );
+ } catch ( Exception $ex ) {
+ $this->assertEquals( $ex, $expect, $label );
+ }
+ } else {
+ $output = $result->getResultData( 'test', $transforms );
+ $this->assertEquals( $expect, $output, $label );
+ }
+ }
+
+ public function provideTransformations() {
+ $kvp = function ( $keyKey, $key, $valKey, $value ) {
+ return array(
+ $keyKey => $key,
+ $valKey => $value,
+ ApiResult::META_PRESERVE_KEYS => array( $keyKey ),
+ ApiResult::META_CONTENT => $valKey,
+ ApiResult::META_TYPE => 'assoc',
+ );
+ };
+ $typeArr = array(
+ 'defaultArray' => array( 2 => 'a', 0 => 'b', 1 => 'c' ),
+ 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c' ),
+ 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c' ),
+ 'array' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'array' ),
+ 'BCarray' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'BCarray' ),
+ 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'BCassoc' ),
+ 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'kvp' => array( 'x' => 'a', 'y' => 'b', 'z' => array( 'c' ), ApiResult::META_TYPE => 'kvp' ),
+ 'BCkvp' => array( 'x' => 'a', 'y' => 'b',
+ ApiResult::META_TYPE => 'BCkvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ 'emptyDefault' => array( '_dummy' => 1 ),
+ 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
+ '_dummy' => 1,
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
+ );
+ $stripArr = array(
+ 'foo' => array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'baz' => array(
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
+ ApiResult::META_TYPE => 'array',
+ ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
+ ApiResult::META_TYPE => 'array',
+ '_dummy' => 'foobaz',
+ '_dummy2' => 'foobaz!',
+ );
+
+ return array(
+ array(
+ 'BC: META_BC_BOOLS',
+ array(
+ 'BCtrue' => true,
+ 'BCfalse' => false,
+ 'true' => true,
+ 'false' => false,
+ ApiResult::META_BC_BOOLS => array( 0, 'true', 'false' ),
+ ),
+ array( 'BC' => array() ),
+ array(
+ 'BCtrue' => '',
+ 'true' => true,
+ 'false' => false,
+ ApiResult::META_BC_BOOLS => array( 0, 'true', 'false' ),
+ )
+ ),
+ array(
+ 'BC: META_BC_SUBELEMENTS',
+ array(
+ 'bc' => 'foo',
+ 'nobc' => 'bar',
+ ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
+ ),
+ array( 'BC' => array() ),
+ array(
+ 'bc' => array(
+ '*' => 'foo',
+ ApiResult::META_CONTENT => '*',
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ 'nobc' => 'bar',
+ ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
+ ),
+ ),
+ array(
+ 'BC: META_CONTENT',
+ array(
+ 'content' => '!!!',
+ ApiResult::META_CONTENT => 'content',
+ ),
+ array( 'BC' => array() ),
+ array(
+ '*' => '!!!',
+ ApiResult::META_CONTENT => '*',
+ ),
+ ),
+ array(
+ 'BC: BCkvp type',
+ array(
+ 'foo' => 'foo value',
+ 'bar' => 'bar value',
+ '_baz' => 'baz value',
+ ApiResult::META_TYPE => 'BCkvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
+ ),
+ array( 'BC' => array() ),
+ array(
+ $kvp( 'key', 'foo', '*', 'foo value' ),
+ $kvp( 'key', 'bar', '*', 'bar value' ),
+ $kvp( 'key', '_baz', '*', 'baz value' ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
+ ),
+ ),
+ array(
+ 'BC: BCarray type',
+ array(
+ ApiResult::META_TYPE => 'BCarray',
+ ),
+ array( 'BC' => array() ),
+ array(
+ ApiResult::META_TYPE => 'default',
+ ),
+ ),
+ array(
+ 'BC: BCassoc type',
+ array(
+ ApiResult::META_TYPE => 'BCassoc',
+ ),
+ array( 'BC' => array() ),
+ array(
+ ApiResult::META_TYPE => 'default',
+ ),
+ ),
+ array(
+ 'BC: BCkvp exception',
+ array(
+ ApiResult::META_TYPE => 'BCkvp',
+ ),
+ array( 'BC' => array() ),
+ new UnexpectedValueException(
+ 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
+ ),
+ ),
+ array(
+ 'BC: nobool, no*, nosub',
+ array(
+ 'true' => true,
+ 'false' => false,
+ 'content' => 'content',
+ ApiResult::META_CONTENT => 'content',
+ 'bc' => 'foo',
+ ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
+ 'BCarray' => array( ApiResult::META_TYPE => 'BCarray' ),
+ 'BCassoc' => array( ApiResult::META_TYPE => 'BCassoc' ),
+ 'BCkvp' => array(
+ 'foo' => 'foo value',
+ 'bar' => 'bar value',
+ '_baz' => 'baz value',
+ ApiResult::META_TYPE => 'BCkvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
+ ),
+ ),
+ array( 'BC' => array( 'nobool', 'no*', 'nosub' ) ),
+ array(
+ 'true' => true,
+ 'false' => false,
+ 'content' => 'content',
+ 'bc' => 'foo',
+ 'BCarray' => array( ApiResult::META_TYPE => 'default' ),
+ 'BCassoc' => array( ApiResult::META_TYPE => 'default' ),
+ 'BCkvp' => array(
+ $kvp( 'key', 'foo', '*', 'foo value' ),
+ $kvp( 'key', 'bar', '*', 'bar value' ),
+ $kvp( 'key', '_baz', '*', 'baz value' ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
+ ),
+ ApiResult::META_CONTENT => 'content',
+ ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
+ ),
+ ),
+
+ array(
+ 'Types: Normal transform',
+ $typeArr,
+ array( 'Types' => array() ),
+ array(
+ 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
+ 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'kvp' => array( 'x' => 'a', 'y' => 'b',
+ 'z' => array( 'c', ApiResult::META_TYPE => 'array' ),
+ ApiResult::META_TYPE => 'assoc'
+ ),
+ 'BCkvp' => array( 'x' => 'a', 'y' => 'b',
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
+ 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
+ '_dummy' => 1,
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ ),
+ array(
+ 'Types: AssocAsObject',
+ $typeArr,
+ array( 'Types' => array( 'AssocAsObject' => true ) ),
+ (object)array(
+ 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
+ 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'kvp' => (object)array( 'x' => 'a', 'y' => 'b',
+ 'z' => array( 'c', ApiResult::META_TYPE => 'array' ),
+ ApiResult::META_TYPE => 'assoc'
+ ),
+ 'BCkvp' => (object)array( 'x' => 'a', 'y' => 'b',
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
+ 'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
+ '_dummy' => 1,
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ ),
+ array(
+ 'Types: ArmorKVP',
+ $typeArr,
+ array( 'Types' => array( 'ArmorKVP' => 'name' ) ),
+ array(
+ 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
+ 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'kvp' => array(
+ $kvp( 'name', 'x', 'value', 'a' ),
+ $kvp( 'name', 'y', 'value', 'b' ),
+ $kvp( 'name', 'z', 'value', array( 'c', ApiResult::META_TYPE => 'array' ) ),
+ ApiResult::META_TYPE => 'array'
+ ),
+ 'BCkvp' => array(
+ $kvp( 'key', 'x', 'value', 'a' ),
+ $kvp( 'key', 'y', 'value', 'b' ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
+ 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
+ '_dummy' => 1,
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ ),
+ array(
+ 'Types: ArmorKVP + BC',
+ $typeArr,
+ array( 'BC' => array(), 'Types' => array( 'ArmorKVP' => 'name' ) ),
+ array(
+ 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
+ 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCarray' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'array' ),
+ 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'kvp' => array(
+ $kvp( 'name', 'x', '*', 'a' ),
+ $kvp( 'name', 'y', '*', 'b' ),
+ $kvp( 'name', 'z', '*', array( 'c', ApiResult::META_TYPE => 'array' ) ),
+ ApiResult::META_TYPE => 'array'
+ ),
+ 'BCkvp' => array(
+ $kvp( 'key', 'x', '*', 'a' ),
+ $kvp( 'key', 'y', '*', 'b' ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
+ 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
+ '_dummy' => 1,
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ ),
+ array(
+ 'Types: ArmorKVP + AssocAsObject',
+ $typeArr,
+ array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ) ),
+ (object)array(
+ 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
+ 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
+ 'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'kvp' => array(
+ (object)$kvp( 'name', 'x', 'value', 'a' ),
+ (object)$kvp( 'name', 'y', 'value', 'b' ),
+ (object)$kvp( 'name', 'z', 'value', array( 'c', ApiResult::META_TYPE => 'array' ) ),
+ ApiResult::META_TYPE => 'array'
+ ),
+ 'BCkvp' => array(
+ (object)$kvp( 'key', 'x', 'value', 'a' ),
+ (object)$kvp( 'key', 'y', 'value', 'b' ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ),
+ 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
+ 'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
+ '_dummy' => 1,
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
+ ApiResult::META_TYPE => 'assoc',
+ ),
+ ),
+ array(
+ 'Types: BCkvp exception',
+ array(
+ ApiResult::META_TYPE => 'BCkvp',
+ ),
+ array( 'Types' => array() ),
+ new UnexpectedValueException(
+ 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
+ ),
+ ),
+
+ array(
+ 'Strip: With ArmorKVP + AssocAsObject transforms',
+ $typeArr,
+ array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ), 'Strip' => 'all' ),
+ (object)array(
+ 'defaultArray' => array( 'b', 'c', 'a' ),
+ 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c' ),
+ 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c' ),
+ 'array' => array( 'a', 'c', 'b' ),
+ 'BCarray' => array( 'a', 'c', 'b' ),
+ 'BCassoc' => (object)array( 'a', 'b', 'c' ),
+ 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c' ),
+ 'kvp' => array(
+ (object)array( 'name' => 'x', 'value' => 'a' ),
+ (object)array( 'name' => 'y', 'value' => 'b' ),
+ (object)array( 'name' => 'z', 'value' => array( 'c' ) ),
+ ),
+ 'BCkvp' => array(
+ (object)array( 'key' => 'x', 'value' => 'a' ),
+ (object)array( 'key' => 'y', 'value' => 'b' ),
+ ),
+ 'emptyDefault' => array(),
+ 'emptyAssoc' => (object)array(),
+ '_dummy' => 1,
+ ),
+ ),
+
+ array(
+ 'Strip: all',
+ $stripArr,
+ array( 'Strip' => 'all' ),
+ array(
+ 'foo' => array(
+ 'bar' => array(),
+ 'baz' => array(),
+ 'x' => 'ok',
+ ),
+ '_dummy2' => 'foobaz!',
+ ),
+ ),
+ array(
+ 'Strip: base',
+ $stripArr,
+ array( 'Strip' => 'base' ),
+ array(
+ 'foo' => array(
+ 'bar' => array( '_dummy' => 'foobaz' ),
+ 'baz' => array(
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
+ ApiResult::META_TYPE => 'array',
+ ),
+ 'x' => 'ok',
+ '_dummy' => 'foobaz',
+ ),
+ '_dummy2' => 'foobaz!',
+ ),
+ ),
+ array(
+ 'Strip: bc',
+ $stripArr,
+ array( 'Strip' => 'bc' ),
+ array(
+ 'foo' => array(
+ 'bar' => array(),
+ 'baz' => array(
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ),
+ 'x' => 'ok',
+ ),
+ '_dummy2' => 'foobaz!',
+ ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'itn',
+ ),
+ ),
+
+ array(
+ 'Custom transform',
+ array(
+ 'foo' => '?',
+ 'bar' => '?',
+ '_dummy' => '?',
+ '_dummy2' => '?',
+ '_dummy3' => '?',
+ ApiResult::META_CONTENT => 'foo',
+ ApiResult::META_PRESERVE_KEYS => array( '_dummy2', '_dummy3' ),
+ ),
+ array(
+ 'Custom' => array( $this, 'customTransform' ),
+ 'BC' => array(),
+ 'Types' => array(),
+ 'Strip' => 'all'
+ ),
+ array(
+ '*' => 'FOO',
+ 'bar' => 'BAR',
+ 'baz' => array( 'a', 'b' ),
+ '_dummy2' => '_DUMMY2',
+ '_dummy3' => '_DUMMY3',
+ ApiResult::META_CONTENT => 'bar',
+ ),
+ ),
+ );
+
+ }
+
+ /**
+ * Custom transformer for testTransformations
+ * @param array &$data
+ * @param array &$metadata
+ */
+ public function customTransform( &$data, &$metadata ) {
+ // Prevent recursion
+ if ( isset( $metadata['_added'] ) ) {
+ $metadata[ApiResult::META_TYPE] = 'array';
+ return;
+ }
+
+ foreach ( $data as $k => $v ) {
+ $data[$k] = strtoupper( $k );
+ }
+ $data['baz'] = array( '_added' => 1, 'z' => 'b', 'y' => 'a' );
+ $metadata[ApiResult::META_PRESERVE_KEYS][0] = '_dummy';
+ $data[ApiResult::META_CONTENT] = 'bar';
+ }
+
+ /**
+ * @covers ApiResult
+ */
+ public function testDeprecatedFunctions() {
+ // Ignore ApiResult deprecation warnings during this test
+ set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
+ if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
+ return true;
+ }
+ if ( preg_match( '/Use of ApiMain to ApiResult::__construct was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
+ return true;
+ }
+ return false;
+ } );
+ $reset = new ScopedCallback( 'restore_error_handler' );
+
+ $context = new DerivativeContext( RequestContext::getMain() );
+ $context->setConfig( new HashConfig( array(
+ 'APIModules' => array(),
+ 'APIFormatModules' => array(),
+ 'APIMaxResultSize' => 42,
+ ) ) );
+ $main = new ApiMain( $context );
+ $result = TestingAccessWrapper::newFromObject( new ApiResult( $main ) );
+ $this->assertSame( 42, $result->maxSize );
+ $this->assertSame( $main->getErrorFormatter(), $result->errorFormatter );
+ $this->assertSame( $main, $result->mainForContinuation );
+
+ $result = new ApiResult( 8388608 );
+
+ $result->addContentValue( null, 'test', 'content' );
+ $result->addContentValue( array( 'foo', 'bar' ), 'test', 'content' );
+ $result->addIndexedTagName( null, 'itn' );
+ $result->addSubelementsList( null, array( 'sub' ) );
+ $this->assertSame( array(
+ 'foo' => array(
+ 'bar' => array(
+ '*' => 'content',
+ ),
+ ),
+ '*' => 'content',
+ ), $result->getData() );
+ $result->setRawMode();
+ $this->assertSame( array(
+ 'foo' => array(
+ 'bar' => array(
+ '*' => 'content',
+ ),
+ ),
+ '*' => 'content',
+ '_element' => 'itn',
+ '_subelements' => array( 'sub' ),
+ ), $result->getData() );
+
+ $arr = array();
+ ApiResult::setContent( $arr, 'value' );
+ ApiResult::setContent( $arr, 'value2', 'foobar' );
+ $this->assertSame( array(
+ ApiResult::META_CONTENT => 'content',
+ 'content' => 'value',
+ 'foobar' => array(
+ ApiResult::META_CONTENT => 'content',
+ 'content' => 'value2',
+ ),
+ ), $arr );
+
+ $result = new ApiResult( 3 );
+ $formatter = new ApiErrorFormatter_BackCompat( $result );
+ $result->setErrorFormatter( $formatter );
+ $result->disableSizeCheck();
+ $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
+ $result->enableSizeCheck();
+ $this->assertSame( 0, $result->getSize() );
+ $this->assertFalse( $result->addValue( null, 'foo', '1234567890' ) );
+
+ $arr = array( 'foo' => array( 'bar' => 1 ) );
+ $result->setIndexedTagName_recursive( $arr, 'itn' );
+ $this->assertSame( array(
+ 'foo' => array(
+ 'bar' => 1,
+ ApiResult::META_INDEXED_TAG_NAME => 'itn'
+ ),
+ ), $arr );
+
+ $status = Status::newGood();
+ $status->fatal( 'parentheses', '1' );
+ $status->fatal( 'parentheses', '2' );
+ $status->warning( 'parentheses', '3' );
+ $status->warning( 'parentheses', '4' );
+ $this->assertSame( array(
+ array(
+ 'type' => 'error',
+ 'message' => 'parentheses',
+ 'params' => array(
+ 0 => '1',
+ ApiResult::META_INDEXED_TAG_NAME => 'param',
+ ),
+ ),
+ array(
+ 'type' => 'error',
+ 'message' => 'parentheses',
+ 'params' => array(
+ 0 => '2',
+ ApiResult::META_INDEXED_TAG_NAME => 'param',
+ ),
+ ),
+ ApiResult::META_INDEXED_TAG_NAME => 'error',
+ ), $result->convertStatusToArray( $status, 'error' ) );
+ $this->assertSame( array(
+ array(
+ 'type' => 'warning',
+ 'message' => 'parentheses',
+ 'params' => array(
+ 0 => '3',
+ ApiResult::META_INDEXED_TAG_NAME => 'param',
+ ),
+ ),
+ array(
+ 'type' => 'warning',
+ 'message' => 'parentheses',
+ 'params' => array(
+ 0 => '4',
+ ApiResult::META_INDEXED_TAG_NAME => 'param',
+ ),
+ ),
+ ApiResult::META_INDEXED_TAG_NAME => 'warning',
+ ), $result->convertStatusToArray( $status, 'warning' ) );
+ }
+
+ /**
+ * @covers ApiResult
+ */
+ public function testDeprecatedContinuation() {
+ // Ignore ApiResult deprecation warnings during this test
+ set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
+ if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
+ return true;
+ }
+ return false;
+ } );
+
+ $reset = new ScopedCallback( 'restore_error_handler' );
+ $allModules = array(
+ new MockApiQueryBase( 'mock1' ),
+ new MockApiQueryBase( 'mock2' ),
+ new MockApiQueryBase( 'mocklist' ),
+ );
+ $generator = new MockApiQueryBase( 'generator' );
+
+ $main = new ApiMain( RequestContext::getMain() );
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'mlcontinue' => 2,
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ 'generator' => array( 'gcontinue' => 3 ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $result->setGeneratorContinueParam( $generator, 'gcontinue', array( 3, 4 ) );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2|mocklist',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ 'generator' => array( 'gcontinue' => '3|4' ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'mlcontinue' => 2,
+ 'gcontinue' => 3,
+ 'continue' => 'gcontinue||',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ 'generator' => array( 'gcontinue' => 3 ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'gcontinue' => 3,
+ 'continue' => 'gcontinue||mocklist',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'generator' => array( 'gcontinue' => 3 ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'mlcontinue' => 2,
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'm1continue' => '1|2',
+ 'continue' => '||mock2|mocklist',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'mock1' => array( 'm1continue' => '1|2' ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( array(
+ 'mlcontinue' => 2,
+ 'continue' => '-||mock1|mock2',
+ ), $result->getResultData( 'continue' ) );
+ $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( array(
+ 'mocklist' => array( 'mlcontinue' => 2 ),
+ ), $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame( array( false, $allModules ), $ret );
+ $result->endContinuation( 'raw' );
+ $result->endContinuation( 'standard' );
+ $this->assertSame( null, $result->getResultData( 'continue' ) );
+ $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
+ $this->assertSame( null, $result->getResultData( 'query-continue' ) );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( '||mock2', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame(
+ array( false, array_values( array_diff_key( $allModules, array( 1 => 1 ) ) ) ),
+ $ret
+ );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $ret = $result->beginContinuation( '-||', $allModules, array( 'mock1', 'mock2' ) );
+ $this->assertSame(
+ array( true, array_values( array_diff_key( $allModules, array( 0 => 0, 1 => 1 ) ) ) ),
+ $ret
+ );
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ try {
+ $result->beginContinuation( 'foo', $allModules, array( 'mock1', 'mock2' ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UsageException $ex ) {
+ $this->assertSame(
+ 'Invalid continue param. You should pass the original value returned by the previous query',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ $main->setContinuationManager( null );
+
+ $result = new ApiResult( 8388608 );
+ $result->setMainForContinuation( $main );
+ $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) );
+ try {
+ $result->setContinueParam( $allModules[1], 'm2continue', 1 );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'Module \'mock2\' was not supposed to have been executed, but it was executed anyway',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ try {
+ $result->setContinueParam( $allModules[2], 'mlcontinue', 1 );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ $main->setContinuationManager( null );
+
+ }
+
+ public function testObjectSerialization() {
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', (object)array( 'a' => 1, 'b' => 2 ) );
+ $this->assertSame( array(
+ 'a' => 1,
+ 'b' => 2,
+ ApiResult::META_TYPE => 'assoc',
+ ), $arr['foo'] );
+
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestStringifiableObject() );
+ $this->assertSame( 'Ok', $arr['foo'] );
+
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( 'Ok' ) );
+ $this->assertSame( 'Ok', $arr['foo'] );
+
+ try {
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
+ new ApiResultTestStringifiableObject()
+ ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'ApiResultTestSerializableObject::serializeForApiResult() returned an object of class ApiResultTestStringifiableObject',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ try {
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UnexpectedValueException $ex ) {
+ $this->assertSame(
+ 'ApiResultTestSerializableObject::serializeForApiResult() returned an invalid value: Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
+ $arr = array();
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
+ array(
+ 'one' => new ApiResultTestStringifiableObject( '1' ),
+ 'two' => new ApiResultTestSerializableObject( 2 ),
+ )
+ ) );
+ $this->assertSame( array(
+ 'one' => '1',
+ 'two' => 2,
+ ), $arr['foo'] );
+ }
+
+}
+
+class ApiResultTestStringifiableObject {
+ private $ret;
+
+ public function __construct( $ret = 'Ok' ) {
+ $this->ret = $ret;
+ }
+
+ public function __toString() {
+ return $this->ret;
+ }
+}
+
+class ApiResultTestSerializableObject {
+ private $ret;
+
+ public function __construct( $ret ) {
+ $this->ret = $ret;
+ }
+
+ public function __toString() {
+ return "Fail";
+ }
+
+ public function serializeForApiResult() {
+ return $this->ret;
+ }
+}
diff --git a/tests/phpunit/includes/api/ApiTestCase.php b/tests/phpunit/includes/api/ApiTestCase.php
index cd141947..da62bb0a 100644
--- a/tests/phpunit/includes/api/ApiTestCase.php
+++ b/tests/phpunit/includes/api/ApiTestCase.php
@@ -8,6 +8,11 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
*/
protected $apiContext;
+ /**
+ * @var array
+ */
+ protected $tablesUsed = array( 'user', 'user_groups', 'user_properties' );
+
protected function setUp() {
global $wgServer;
@@ -41,6 +46,17 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
$this->apiContext = new ApiTestContext();
}
+ protected function tearDown() {
+ // Avoid leaking session over tests
+ if ( session_id() != '' ) {
+ global $wgUser;
+ $wgUser->logout();
+ session_destroy();
+ }
+
+ parent::tearDown();
+ }
+
/**
* Edits or creates a page/revision
* @param string $pageName Page title
@@ -100,7 +116,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
// construct result
$results = array(
- $module->getResultData(),
+ $module->getResult()->getResultData( null, array( 'Strip' => 'all' ) ),
$context->getRequest(),
$context->getRequest()->getSessionArray()
);
@@ -134,10 +150,14 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
}
if ( isset( $session['wsToken'] ) && $session['wsToken'] ) {
+ // @todo Why does this directly mess with the session? Fix that.
// add edit token to fake session
$session['wsEditToken'] = $session['wsToken'];
// add token to request parameters
- $params['token'] = md5( $session['wsToken'] ) . User::EDIT_TOKEN_SUFFIX;
+ $timestamp = wfTimestamp();
+ $params['token'] = hash_hmac( 'md5', $timestamp, $session['wsToken'] ) .
+ dechex( $timestamp ) .
+ User::EDIT_TOKEN_SUFFIX;
return $this->doApiRequest( $params, $session, false, $user );
} else {
diff --git a/tests/phpunit/includes/api/ApiTestCaseUpload.php b/tests/phpunit/includes/api/ApiTestCaseUpload.php
index 7e513394..87f794c1 100644
--- a/tests/phpunit/includes/api/ApiTestCaseUpload.php
+++ b/tests/phpunit/includes/api/ApiTestCaseUpload.php
@@ -1,9 +1,8 @@
<?php
/**
- * * Abstract class to support upload tests
+ * Abstract class to support upload tests
*/
-
abstract class ApiTestCaseUpload extends ApiTestCase {
/**
* Fixture -- run before every test
@@ -21,12 +20,6 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
$this->clearFakeUploads();
}
- protected function tearDown() {
- $this->clearTempUpload();
-
- parent::tearDown();
- }
-
/**
* Helper function -- remove files and associated articles by Title
*
@@ -105,7 +98,7 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
* @return bool
*/
function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
- $tmpName = tempnam( wfTempDir(), "" );
+ $tmpName = $this->getNewTempFile();
if ( !file_exists( $filePath ) ) {
throw new Exception( "$filePath doesn't exist!" );
}
@@ -132,7 +125,7 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
}
function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ) {
- $tmpName = tempnam( wfTempDir(), "" );
+ $tmpName = $this->getNewTempFile();
// copy the chunk data to temp location:
if ( !file_put_contents( $tmpName, $chunkData ) ) {
throw new Exception( "couldn't copy chunk data to $tmpName" );
@@ -153,15 +146,6 @@ abstract class ApiTestCaseUpload extends ApiTestCase {
);
}
- 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/ApiUploadTest.php b/tests/phpunit/includes/api/ApiUploadTest.php
index 8ea761f8..f74fc354 100644
--- a/tests/phpunit/includes/api/ApiUploadTest.php
+++ b/tests/phpunit/includes/api/ApiUploadTest.php
@@ -1,31 +1,24 @@
<?php
/**
- * @group API
- * @group Database
- * @group medium
- */
-
-/**
* n.b. Ensure that you can write to the images/ directory as the
* user that will run tests.
- */
-
-// Note for reviewers: this intentionally duplicates functionality already in
-// "ApiSetup" and so on. This framework works better IMO and has less
-// strangeness (such as test cases inheriting from "ApiSetup"...) (and in the
-// case of the other Upload tests, this flat out just actually works... )
-
-// @todo Port the other Upload tests, and other API tests to this framework
-
-require_once 'ApiTestCaseUpload.php';
-
-/**
- * @group Database
- * @group Broken
- * Broken test, reports false errors from time to time.
+ *
+ * Note for reviewers: this intentionally duplicates functionality already in
+ * "ApiSetup" and so on. This framework works better IMO and has less
+ * strangeness (such as test cases inheriting from "ApiSetup"...) (and in the
+ * case of the other Upload tests, this flat out just actually works... )
+ *
+ * @todo Port the other Upload tests, and other API tests to this framework
+ *
+ * @todo Broken test, reports false errors from time to time.
* See https://bugzilla.wikimedia.org/26169
*
- * This is pretty sucky... needs to be prettified.
+ * @todo This is pretty sucky... needs to be prettified.
+ *
+ * @group API
+ * @group Database
+ * @group medium
+ * @group Broken
*/
class ApiUploadTest extends ApiTestCaseUpload {
/**
@@ -105,7 +98,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
try {
$randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
+ $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
} catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -145,7 +138,6 @@ class ApiUploadTest extends ApiTestCaseUpload {
// clean up
$this->deleteFileByFilename( $fileName );
- unlink( $filePath );
}
/**
@@ -154,7 +146,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
public function testUploadZeroLength( $session ) {
$mimeType = 'image/png';
- $filePath = tempnam( wfTempDir(), "" );
+ $filePath = $this->getNewTempFile();
$fileName = "apiTestUploadZeroLength.png";
$this->deleteFileByFileName( $fileName );
@@ -182,7 +174,6 @@ class ApiUploadTest extends ApiTestCaseUpload {
// clean up
$this->deleteFileByFilename( $fileName );
- unlink( $filePath );
}
/**
@@ -194,7 +185,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
try {
$randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() );
+ $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() );
} catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -253,8 +244,6 @@ class ApiUploadTest extends ApiTestCaseUpload {
// clean up
$this->deleteFileByFilename( $fileName );
- unlink( $filePaths[0] );
- unlink( $filePaths[1] );
}
/**
@@ -266,7 +255,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
try {
$randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
+ $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
} catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -335,7 +324,6 @@ class ApiUploadTest extends ApiTestCaseUpload {
// clean up
$this->deleteFileByFilename( $fileNames[0] );
$this->deleteFileByFilename( $fileNames[1] );
- unlink( $filePaths[0] );
}
/**
@@ -351,7 +339,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
try {
$randomImageGenerator = new RandomImageGenerator();
- $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
+ $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
} catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -419,7 +407,6 @@ class ApiUploadTest extends ApiTestCaseUpload {
// clean up
$this->deleteFileByFilename( $fileName );
- unlink( $filePath );
}
/**
@@ -433,16 +420,14 @@ class ApiUploadTest extends ApiTestCaseUpload {
$chunkSize = 1048576;
// Download a large image file
- // ( using RandomImageGenerator for large files is not stable )
+ // (using RandomImageGenerator for large files is not stable)
+ // @todo Don't download files from wikimedia.org
$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';
+ $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg';
try {
- // Only download if the file is not avaliable in the temp location:
- if ( !is_file( $filePath ) ) {
- copy( $url, $filePath );
- }
+ copy( $url, $filePath );
} catch ( Exception $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -566,7 +551,5 @@ class ApiUploadTest extends ApiTestCaseUpload {
// clean up
$this->deleteFileByFilename( $fileName );
- // don't remove downloaded temporary file for fast subquent tests.
- //unlink( $filePath );
}
}
diff --git a/tests/phpunit/includes/api/MockApi.php b/tests/phpunit/includes/api/MockApi.php
index d94aa2cd..516da0c8 100644
--- a/tests/phpunit/includes/api/MockApi.php
+++ b/tests/phpunit/includes/api/MockApi.php
@@ -4,9 +4,6 @@ class MockApi extends ApiBase {
public function execute() {
}
- public function getVersion() {
- }
-
public function __construct() {
}
diff --git a/tests/phpunit/includes/api/MockApiQueryBase.php b/tests/phpunit/includes/api/MockApiQueryBase.php
index 4bede519..f5b50e5a 100644
--- a/tests/phpunit/includes/api/MockApiQueryBase.php
+++ b/tests/phpunit/includes/api/MockApiQueryBase.php
@@ -1,11 +1,15 @@
<?php
class MockApiQueryBase extends ApiQueryBase {
+ private $name;
+
public function execute() {
}
- public function getVersion() {
+ public function __construct( $name = 'mock' ) {
+ $this->name = $name;
}
- public function __construct() {
+ public function getModuleName() {
+ return $this->name;
}
}
diff --git a/tests/phpunit/includes/api/PrefixUniquenessTest.php b/tests/phpunit/includes/api/PrefixUniquenessTest.php
index 13da33c7..d04766be 100644
--- a/tests/phpunit/includes/api/PrefixUniquenessTest.php
+++ b/tests/phpunit/includes/api/PrefixUniquenessTest.php
@@ -20,7 +20,7 @@ class PrefixUniquenessTest extends MediaWikiTestCase {
$class = get_class( $module );
$prefix = $module->getModulePrefix();
- if ( isset( $prefixes[$prefix] ) ) {
+ if ( $prefix !== '' && isset( $prefixes[$prefix] ) ) {
$this->fail( "Module prefix '{$prefix}' is shared between {$class} and {$prefixes[$prefix]}" );
}
$prefixes[$module->getModulePrefix()] = $class;
diff --git a/tests/phpunit/includes/api/format/ApiFormatDbgTest.php b/tests/phpunit/includes/api/format/ApiFormatDbgTest.php
new file mode 100644
index 00000000..3fcfc73f
--- /dev/null
+++ b/tests/phpunit/includes/api/format/ApiFormatDbgTest.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @group API
+ * @covers ApiFormatDbg
+ */
+class ApiFormatDbgTest extends ApiFormatTestBase {
+
+ protected $printerName = 'dbg';
+
+ public static function provideGeneralEncoding() {
+ $warning = "\n 'warnings' => \n array (\n 'dbg' => \n array (\n" .
+ " '*' => 'format=dbg has been deprecated. Please use format=json instead.',\n" .
+ " ),\n ),";
+
+ return array(
+ // Basic types
+ array( array( null ), "array ({$warning}\n 0 => NULL,\n)" ),
+ array( array( true ), "array ({$warning}\n 0 => '',\n)" ),
+ array( array( false ), "array ({$warning}\n)" ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "array ({$warning}\n 0 => true,\n)" ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "array ({$warning}\n 0 => false,\n)" ),
+ array( array( 42 ), "array ({$warning}\n 0 => 42,\n)" ),
+ array( array( 42.5 ), "array ({$warning}\n 0 => 42.5,\n)" ),
+ array( array( 1e42 ), "array ({$warning}\n 0 => 1.0E+42,\n)" ),
+ array( array( 'foo' ), "array ({$warning}\n 0 => 'foo',\n)" ),
+ array( array( 'fóo' ), "array ({$warning}\n 0 => 'fóo',\n)" ),
+
+ // Arrays and objects
+ array( array( array() ), "array ({$warning}\n 0 => \n array (\n ),\n)" ),
+ array( array( array( 1 ) ), "array ({$warning}\n 0 => \n array (\n 0 => 1,\n ),\n)" ),
+ array( array( array( 'x' => 1 ) ), "array ({$warning}\n 0 => \n array (\n 'x' => 1,\n ),\n)" ),
+ array( array( array( 2 => 1 ) ), "array ({$warning}\n 0 => \n array (\n 2 => 1,\n ),\n)" ),
+ array( array( (object)array() ), "array ({$warning}\n 0 => \n array (\n ),\n)" ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "array ({$warning}\n 0 => \n array (\n 0 => 1,\n ),\n)" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "array ({$warning}\n 0 => \n array (\n 0 => 1,\n ),\n)" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "array ({$warning}\n 0 => \n array (\n 'x' => 1,\n ),\n)" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ "array ({$warning}\n 0 => \n array (\n 0 => \n array (\n 'key' => 'x',\n '*' => 1,\n ),\n ),\n)" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "array ({$warning}\n 0 => \n array (\n 'x' => 1,\n ),\n)" ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "array ({$warning}\n 0 => \n array (\n 0 => 'a',\n 1 => 'b',\n ),\n)" ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ "array ({$warning}\n '*' => 'foo',\n)" ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ "array ({$warning}\n 'foo' => \n array (\n '*' => 'foo',\n ),\n)" ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/api/format/ApiFormatDumpTest.php b/tests/phpunit/includes/api/format/ApiFormatDumpTest.php
new file mode 100644
index 00000000..c0f67f8d
--- /dev/null
+++ b/tests/phpunit/includes/api/format/ApiFormatDumpTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @group API
+ * @covers ApiFormatDump
+ */
+class ApiFormatDumpTest extends ApiFormatTestBase {
+
+ protected $printerName = 'dump';
+
+ public static function provideGeneralEncoding() {
+ // Sigh. Docs claim it's a boolean, but can have values 0, 1, or 2.
+ // Fortunately wfIniGetBool does the right thing.
+ if ( wfIniGetBool( 'xdebug.overload_var_dump' ) ) {
+ return array(
+ array( array(), 'Cannot test ApiFormatDump when xDebug overloads var_dump', array( 'SKIP' => true ) ),
+ );
+ }
+
+ $warning = "\n [\"warnings\"]=>\n array(1) {\n [\"dump\"]=>\n array(1) {\n [\"*\"]=>\n" .
+ " string(64) \"format=dump has been deprecated. Please use format=json instead.\"\n" .
+ " }\n }";
+
+ return array(
+ // Basic types
+ array( array( null ), "array(2) {{$warning}\n [0]=>\n NULL\n}\n" ),
+ array( array( true ), "array(2) {{$warning}\n [0]=>\n string(0) \"\"\n}\n" ),
+ array( array( false ), "array(1) {{$warning}\n}\n" ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "array(2) {{$warning}\n [0]=>\n bool(true)\n}\n" ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "array(2) {{$warning}\n [0]=>\n bool(false)\n}\n" ),
+ array( array( 42 ), "array(2) {{$warning}\n [0]=>\n int(42)\n}\n" ),
+ array( array( 42.5 ), "array(2) {{$warning}\n [0]=>\n float(42.5)\n}\n" ),
+ array( array( 1e42 ), "array(2) {{$warning}\n [0]=>\n float(1.0E+42)\n}\n" ),
+ array( array( 'foo' ), "array(2) {{$warning}\n [0]=>\n string(3) \"foo\"\n}\n" ),
+ array( array( 'fóo' ), "array(2) {{$warning}\n [0]=>\n string(4) \"fóo\"\n}\n" ),
+
+ // Arrays
+ array( array( array() ), "array(2) {{$warning}\n [0]=>\n array(0) {\n }\n}\n" ),
+ array( array( array( 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ),
+ array( array( array( 'x' => 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ),
+ array( array( array( 2 => 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [2]=>\n int(1)\n }\n}\n" ),
+ array( array( (object)array() ), "array(2) {{$warning}\n [0]=>\n array(0) {\n }\n}\n" ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n array(2) {\n [\"key\"]=>\n string(1) \"x\"\n [\"*\"]=>\n int(1)\n }\n }\n}\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "array(2) {{$warning}\n [0]=>\n array(2) {\n [0]=>\n string(1) \"a\"\n [1]=>\n string(1) \"b\"\n }\n}\n" ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ "array(2) {{$warning}\n [\"*\"]=>\n string(3) \"foo\"\n}\n" ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ "array(2) {{$warning}\n [\"foo\"]=>\n array(1) {\n [\"*\"]=>\n string(3) \"foo\"\n }\n}\n" ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/api/format/ApiFormatJsonTest.php b/tests/phpunit/includes/api/format/ApiFormatJsonTest.php
index fc1f9021..3dfcaf0f 100644
--- a/tests/phpunit/includes/api/format/ApiFormatJsonTest.php
+++ b/tests/phpunit/includes/api/format/ApiFormatJsonTest.php
@@ -2,21 +2,109 @@
/**
* @group API
- * @group Database
- * @group medium
* @covers ApiFormatJson
*/
class ApiFormatJsonTest extends ApiFormatTestBase {
- public function testValidSyntax( ) {
- $data = $this->apiRequest( 'json', array( 'action' => 'query', 'meta' => 'siteinfo' ) );
+ protected $printerName = 'json';
- $this->assertInternalType( 'array', json_decode( $data, true ) );
- $this->assertGreaterThan( 0, count( (array)$data ) );
+ private static function addFormatVersion( $format, $arr ) {
+ foreach ( $arr as &$p ) {
+ if ( !isset( $p[2] ) ) {
+ $p[2] = array( 'formatversion' => $format );
+ } else {
+ $p[2]['formatversion'] = $format;
+ }
+ }
+ return $arr;
}
- public function testJsonpInjection( ) {
- $data = $this->apiRequest( 'json', array( 'action' => 'query', 'meta' => 'siteinfo', 'callback' => 'myCallback' ) );
- $this->assertEquals( '/**/myCallback(', substr( $data, 0, 15 ) );
+ public static function provideGeneralEncoding() {
+ return array_merge(
+ self::addFormatVersion( 1, array(
+ // Basic types
+ array( array( null ), '[null]' ),
+ array( array( true ), '[""]' ),
+ array( array( false ), '[]' ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), '[true]' ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), '[false]' ),
+ array( array( 42 ), '[42]' ),
+ array( array( 42.5 ), '[42.5]' ),
+ array( array( 1e42 ), '[1.0e+42]' ),
+ array( array( 'foo' ), '["foo"]' ),
+ array( array( 'fóo' ), '["f\u00f3o"]' ),
+ array( array( 'fóo' ), '["fóo"]', array( 'utf8' => 1 ) ),
+
+ // Arrays and objects
+ array( array( array() ), '[[]]' ),
+ array( array( array( 1 ) ), '[[1]]' ),
+ array( array( array( 'x' => 1 ) ), '[{"x":1}]' ),
+ array( array( array( 2 => 1 ) ), '[{"2":1}]' ),
+ array( array( (object)array() ), '[{}]' ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '[{"0":1}]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '[[1]]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), '[{"x":1}]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ '[[{"key":"x","*":1}]]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '[{"x":1}]' ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '[["a","b"]]' ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ '{"*":"foo"}' ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ '{"foo":{"*":"foo"}}' ),
+
+ // Callbacks
+ array( array( 1 ), '/**/myCallback([1])', array( 'callback' => 'myCallback' ) ),
+
+ // Cross-domain mangling
+ array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy \u003E"]' ),
+ ) ),
+ self::addFormatVersion( 2, array(
+ // Basic types
+ array( array( null ), '[null]' ),
+ array( array( true ), '[true]' ),
+ array( array( false ), '[false]' ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), '[true]' ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), '[false]' ),
+ array( array( 42 ), '[42]' ),
+ array( array( 42.5 ), '[42.5]' ),
+ array( array( 1e42 ), '[1.0e+42]' ),
+ array( array( 'foo' ), '["foo"]' ),
+ array( array( 'fóo' ), '["fóo"]' ),
+ array( array( 'fóo' ), '["f\u00f3o"]', array( 'ascii' => 1 ) ),
+
+ // Arrays and objects
+ array( array( array() ), '[[]]' ),
+ array( array( array( 'x' => 1 ) ), '[{"x":1}]' ),
+ array( array( array( 2 => 1 ) ), '[{"2":1}]' ),
+ array( array( (object)array() ), '[{}]' ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '[{"0":1}]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '[[1]]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), '[{"x":1}]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ '[{"x":1}]' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '[[1]]' ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '[{"0":"a","1":"b"}]' ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ '{"content":"foo"}' ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ '{"foo":"foo"}' ),
+
+ // Callbacks
+ array( array( 1 ), '/**/myCallback([1])', array( 'callback' => 'myCallback' ) ),
+
+ // Cross-domain mangling
+ array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy \u003E"]' ),
+ ) )
+ );
}
+
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatNoneTest.php b/tests/phpunit/includes/api/format/ApiFormatNoneTest.php
index cabd750b..8f81a411 100644
--- a/tests/phpunit/includes/api/format/ApiFormatNoneTest.php
+++ b/tests/phpunit/includes/api/format/ApiFormatNoneTest.php
@@ -2,15 +2,43 @@
/**
* @group API
- * @group Database
- * @group medium
* @covers ApiFormatNone
*/
class ApiFormatNoneTest extends ApiFormatTestBase {
- public function testValidSyntax( ) {
- $data = $this->apiRequest( 'none', array( 'action' => 'query', 'meta' => 'siteinfo' ) );
+ protected $printerName = 'none';
- $this->assertEquals( '', $data ); // No output!
+ public static function provideGeneralEncoding() {
+ return array(
+ // Basic types
+ array( array( null ), '' ),
+ array( array( true ), '' ),
+ array( array( false ), '' ),
+ array( array( 42 ), '' ),
+ array( array( 42.5 ), '' ),
+ array( array( 1e42 ), '' ),
+ array( array( 'foo' ), '' ),
+ array( array( 'fóo' ), '' ),
+
+ // Arrays and objects
+ array( array( array() ), '' ),
+ array( array( array( 1 ) ), '' ),
+ array( array( array( 'x' => 1 ) ), '' ),
+ array( array( array( 2 => 1 ) ), '' ),
+ array( array( (object)array() ), '' ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), '' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), '' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '' ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '' ),
+
+ // Content
+ array( array( '*' => 'foo' ), '' ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), '' ),
+ );
}
+
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatPhpTest.php b/tests/phpunit/includes/api/format/ApiFormatPhpTest.php
index 54f447a9..0cb44e92 100644
--- a/tests/phpunit/includes/api/format/ApiFormatPhpTest.php
+++ b/tests/phpunit/includes/api/format/ApiFormatPhpTest.php
@@ -2,16 +2,143 @@
/**
* @group API
- * @group Database
- * @group medium
* @covers ApiFormatPhp
*/
class ApiFormatPhpTest extends ApiFormatTestBase {
- public function testValidSyntax( ) {
- $data = $this->apiRequest( 'php', array( 'action' => 'query', 'meta' => 'siteinfo' ) );
+ protected $printerName = 'php';
- $this->assertInternalType( 'array', unserialize( $data ) );
- $this->assertGreaterThan( 0, count( (array)$data ) );
+ private static function addFormatVersion( $format, $arr ) {
+ foreach ( $arr as &$p ) {
+ if ( !isset( $p[2] ) ) {
+ $p[2] = array( 'formatversion' => $format );
+ } else {
+ $p[2]['formatversion'] = $format;
+ }
+ }
+ return $arr;
}
+
+ public static function provideGeneralEncoding() {
+ return array_merge(
+ self::addFormatVersion( 1, array(
+ // Basic types
+ array( array( null ), 'a:1:{i:0;N;}' ),
+ array( array( true ), 'a:1:{i:0;s:0:"";}' ),
+ array( array( false ), 'a:0:{}' ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ 'a:1:{i:0;b:1;}' ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ 'a:1:{i:0;b:0;}' ),
+ array( array( 42 ), 'a:1:{i:0;i:42;}' ),
+ array( array( 42.5 ), 'a:1:{i:0;d:42.5;}' ),
+ array( array( 1e42 ), 'a:1:{i:0;d:1.0E+42;}' ),
+ array( array( 'foo' ), 'a:1:{i:0;s:3:"foo";}' ),
+ array( array( 'fóo' ), 'a:1:{i:0;s:4:"fóo";}' ),
+
+ // Arrays and objects
+ array( array( array() ), 'a:1:{i:0;a:0:{}}' ),
+ array( array( array( 1 ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'x' => 1 ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
+ array( array( array( 2 => 1 ) ), 'a:1:{i:0;a:1:{i:2;i:1;}}' ),
+ array( array( (object)array() ), 'a:1:{i:0;a:0:{}}' ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ 'a:1:{i:0;a:1:{i:0;a:2:{s:3:"key";s:1:"x";s:1:"*";i:1;}}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ 'a:1:{s:1:"*";s:3:"foo";}' ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ 'a:1:{s:3:"foo";a:1:{s:1:"*";s:3:"foo";}}' ),
+ ) ),
+ self::addFormatVersion( 2, array(
+ // Basic types
+ array( array( null ), 'a:1:{i:0;N;}' ),
+ array( array( true ), 'a:1:{i:0;b:1;}' ),
+ array( array( false ), 'a:1:{i:0;b:0;}' ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ 'a:1:{i:0;b:1;}' ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ 'a:1:{i:0;b:0;}' ),
+ array( array( 42 ), 'a:1:{i:0;i:42;}' ),
+ array( array( 42.5 ), 'a:1:{i:0;d:42.5;}' ),
+ array( array( 1e42 ), 'a:1:{i:0;d:1.0E+42;}' ),
+ array( array( 'foo' ), 'a:1:{i:0;s:3:"foo";}' ),
+ array( array( 'fóo' ), 'a:1:{i:0;s:4:"fóo";}' ),
+
+ // Arrays and objects
+ array( array( array() ), 'a:1:{i:0;a:0:{}}' ),
+ array( array( array( 1 ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'x' => 1 ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
+ array( array( array( 2 => 1 ) ), 'a:1:{i:0;a:1:{i:2;i:1;}}' ),
+ array( array( (object)array() ), 'a:1:{i:0;a:0:{}}' ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ 'a:1:{s:7:"content";s:3:"foo";}' ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ 'a:1:{s:3:"foo";s:3:"foo";}' ),
+ ) )
+ );
+ }
+
+ public function testCrossDomainMangling() {
+ $config = new HashConfig( array( 'MangleFlashPolicy' => false ) );
+ $context = new RequestContext;
+ $context->setConfig( new MultiConfig( array(
+ $config,
+ $context->getConfig(),
+ ) ) );
+ $main = new ApiMain( $context );
+ $main->getResult()->addValue( null, null, '< Cross-Domain-Policy >' );
+
+ if ( !function_exists( 'wfOutputHandler' ) ) {
+ function wfOutputHandler( $s ) {
+ return $s;
+ }
+ }
+
+ $printer = $main->createPrinterByName( 'php' );
+ ob_start( 'wfOutputHandler' );
+ $printer->initPrinter();
+ $printer->execute();
+ $printer->closePrinter();
+ $ret = ob_get_clean();
+ $this->assertSame( 'a:1:{i:0;s:23:"< Cross-Domain-Policy >";}', $ret );
+
+ $config->set( 'MangleFlashPolicy', true );
+ $printer = $main->createPrinterByName( 'php' );
+ ob_start( 'wfOutputHandler' );
+ try {
+ $printer->initPrinter();
+ $printer->execute();
+ $printer->closePrinter();
+ ob_end_clean();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( UsageException $ex ) {
+ ob_end_clean();
+ $this->assertSame(
+ 'This response cannot be represented using format=php. See https://bugzilla.wikimedia.org/show_bug.cgi?id=66776',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+ }
+
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatTestBase.php b/tests/phpunit/includes/api/format/ApiFormatTestBase.php
index 5f6d53ce..cabf62b1 100644
--- a/tests/phpunit/includes/api/format/ApiFormatTestBase.php
+++ b/tests/phpunit/includes/api/format/ApiFormatTestBase.php
@@ -1,32 +1,64 @@
<?php
-abstract class ApiFormatTestBase extends ApiTestCase {
+abstract class ApiFormatTestBase extends MediaWikiTestCase {
/**
- * @param string $format
- * @param array $params
- * @param array $data
- *
- * @return string
+ * Name of the formatter being tested
+ * @var string
*/
- protected function apiRequest( $format, $params, $data = null ) {
- $data = parent::doApiRequest( $params, $data, true );
-
- /** @var ApiMain $module */
- $module = $data[3];
+ protected $printerName;
- $printer = $module->createPrinterByName( $format );
- $printer->setUnescapeAmps( false );
+ /**
+ * Return general data to be encoded for testing
+ * @return array See self::testGeneralEncoding
+ * @throws Exception
+ */
+ public static function provideGeneralEncoding() {
+ throw new Exception( 'Subclass must implement ' . __METHOD__ );
+ }
- $printer->initPrinter( false );
+ /**
+ * Get the formatter output for the given input data
+ * @param array $params Query parameters
+ * @param array $data Data to encode
+ * @param string $class Printer class to use instead of the normal one
+ * @return string
+ * @throws Exception
+ */
+ protected function encodeData( array $params, array $data, $class = null ) {
+ $context = new RequestContext;
+ $context->setRequest( new FauxRequest( $params, true ) );
+ $main = new ApiMain( $context );
+ if ( $class !== null ) {
+ $main->getModuleManager()->addModule( $this->printerName, 'format', $class );
+ }
+ $result = $main->getResult();
+ $result->addArrayType( null, 'default' );
+ foreach ( $data as $k => $v ) {
+ $result->addValue( null, $k, $v );
+ }
- ob_start();
+ $printer = $main->createPrinterByName( $this->printerName );
+ $printer->initPrinter();
$printer->execute();
- $out = ob_get_clean();
-
- $printer->closePrinter();
+ ob_start();
+ try {
+ $printer->closePrinter();
+ return ob_get_clean();
+ } catch ( Exception $ex ) {
+ ob_end_clean();
+ throw $ex;
+ }
+ }
- return $out;
+ /**
+ * @dataProvider provideGeneralEncoding
+ */
+ public function testGeneralEncoding( array $data, $expect, array $params = array() ) {
+ if ( isset( $params['SKIP'] ) ) {
+ $this->markTestSkipped( $expect );
+ }
+ $this->assertSame( $expect, $this->encodeData( $params, $data ) );
}
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatTxtTest.php b/tests/phpunit/includes/api/format/ApiFormatTxtTest.php
new file mode 100644
index 00000000..b0a2a960
--- /dev/null
+++ b/tests/phpunit/includes/api/format/ApiFormatTxtTest.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @group API
+ * @covers ApiFormatTxt
+ */
+class ApiFormatTxtTest extends ApiFormatTestBase {
+
+ protected $printerName = 'txt';
+
+ public static function provideGeneralEncoding() {
+ $warning = "\n [warnings] => Array\n (\n [txt] => Array\n (\n" .
+ " [*] => format=txt has been deprecated. Please use format=json instead.\n" .
+ " )\n\n )\n";
+
+ return array(
+ // Basic types
+ array( array( null ), "Array\n({$warning}\n [0] => \n)\n" ),
+ array( array( true ), "Array\n({$warning}\n [0] => \n)\n" ),
+ array( array( false ), "Array\n({$warning}\n)\n" ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "Array\n({$warning}\n [0] => 1\n)\n" ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "Array\n({$warning}\n [0] => \n)\n" ),
+ array( array( 42 ), "Array\n({$warning}\n [0] => 42\n)\n" ),
+ array( array( 42.5 ), "Array\n({$warning}\n [0] => 42.5\n)\n" ),
+ array( array( 1e42 ), "Array\n({$warning}\n [0] => 1.0E+42\n)\n" ),
+ array( array( 'foo' ), "Array\n({$warning}\n [0] => foo\n)\n" ),
+ array( array( 'fóo' ), "Array\n({$warning}\n [0] => fóo\n)\n" ),
+
+ // Arrays and objects
+ array( array( array() ), "Array\n({$warning}\n [0] => Array\n (\n )\n\n)\n" ),
+ array( array( array( 1 ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => 1\n )\n\n)\n" ),
+ array( array( array( 'x' => 1 ) ), "Array\n({$warning}\n [0] => Array\n (\n [x] => 1\n )\n\n)\n" ),
+ array( array( array( 2 => 1 ) ), "Array\n({$warning}\n [0] => Array\n (\n [2] => 1\n )\n\n)\n" ),
+ array( array( (object)array() ), "Array\n({$warning}\n [0] => Array\n (\n )\n\n)\n" ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => 1\n )\n\n)\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => 1\n )\n\n)\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "Array\n({$warning}\n [0] => Array\n (\n [x] => 1\n )\n\n)\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ "Array\n({$warning}\n [0] => Array\n (\n [0] => Array\n (\n [key] => x\n [*] => 1\n )\n\n )\n\n)\n" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "Array\n({$warning}\n [0] => Array\n (\n [x] => 1\n )\n\n)\n" ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => a\n [1] => b\n )\n\n)\n" ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ "Array\n({$warning}\n [*] => foo\n)\n" ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ "Array\n({$warning}\n [foo] => Array\n (\n [*] => foo\n )\n\n)\n" ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php b/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
index d075f547..07111300 100644
--- a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
+++ b/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
@@ -2,19 +2,79 @@
/**
* @group API
- * @group Database
- * @group medium
* @covers ApiFormatWddx
*/
class ApiFormatWddxTest extends ApiFormatTestBase {
+ protected $printerName = 'wddx';
+
+ public static function provideGeneralEncoding() {
+ if ( ApiFormatWddx::useSlowPrinter() ) {
+ return array(
+ array( array(), 'Fast Wddx printer is unavailable', array( 'SKIP' => true ) )
+ );
+ }
+ return self::provideEncoding();
+ }
+
+ public static function provideEncoding() {
+ $p = '<wddxPacket version=\'1.0\'><header/><data><struct><var name=\'warnings\'><struct><var name=\'wddx\'><struct><var name=\'*\'><string>format=wddx has been deprecated. Please use format=json instead.</string></var></struct></var></struct></var>';
+ $s = '</struct></data></wddxPacket>';
+
+ return array(
+ // Basic types
+ array( array( null ), "{$p}<var name='0'><null/></var>{$s}" ),
+ array( array( true ), "{$p}<var name='0'><string></string></var>{$s}" ),
+ array( array( false ), "{$p}{$s}" ),
+ array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "{$p}<var name='0'><boolean value='true'/></var>{$s}" ),
+ array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
+ "{$p}<var name='0'><boolean value='false'/></var>{$s}" ),
+ array( array( 42 ), "{$p}<var name='0'><number>42</number></var>{$s}" ),
+ array( array( 42.5 ), "{$p}<var name='0'><number>42.5</number></var>{$s}" ),
+ array( array( 1e42 ), "{$p}<var name='0'><number>1.0E+42</number></var>{$s}" ),
+ array( array( 'foo' ), "{$p}<var name='0'><string>foo</string></var>{$s}" ),
+ array( array( 'fóo' ), "{$p}<var name='0'><string>fóo</string></var>{$s}" ),
+
+ // Arrays and objects
+ array( array( array() ), "{$p}<var name='0'><array length='0'></array></var>{$s}" ),
+ array( array( array( 1 ) ), "{$p}<var name='0'><array length='1'><number>1</number></array></var>{$s}" ),
+ array( array( array( 'x' => 1 ) ), "{$p}<var name='0'><struct><var name='x'><number>1</number></var></struct></var>{$s}" ),
+ array( array( array( 2 => 1 ) ), "{$p}<var name='0'><struct><var name='2'><number>1</number></var></struct></var>{$s}" ),
+ array( array( (object)array() ), "{$p}<var name='0'><struct></struct></var>{$s}" ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "{$p}<var name='0'><struct><var name='0'><number>1</number></var></struct></var>{$s}" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "{$p}<var name='0'><array length='1'><number>1</number></array></var>{$s}" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "{$p}<var name='0'><struct><var name='x'><number>1</number></var></struct></var>{$s}" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ "{$p}<var name='0'><array length='1'><struct><var name='key'><string>x</string></var><var name='*'><number>1</number></var></struct></array></var>{$s}" ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "{$p}<var name='0'><struct><var name='x'><number>1</number></var></struct></var>{$s}" ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "{$p}<var name='0'><array length='2'><string>a</string><string>b</string></array></var>{$s}" ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ "{$p}<var name='*'><string>foo</string></var>{$s}" ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ "{$p}<var name='foo'><struct><var name='*'><string>foo</string></var></struct></var>{$s}" ),
+ );
+ }
+
/**
- * @requires function wddx_deserialize
+ * @dataProvider provideEncoding
*/
- public function testValidSyntax( ) {
- $data = $this->apiRequest( 'wddx', array( 'action' => 'query', 'meta' => 'siteinfo' ) );
+ public function testSlowEncoding( array $data, $expect, array $params = array() ) {
+ // Adjust expectation for differences between fast and slow printers.
+ $expect = str_replace( '\'', '"', $expect );
+ $expect = str_replace( '/>', ' />', $expect );
+ $expect = '<?xml version="1.0"?>' . $expect;
+
+ $this->assertSame( $expect, $this->encodeData( $params, $data, 'ApiFormatWddxTest_SlowWddx' ) );
+ }
+}
- $this->assertInternalType( 'array', wddx_deserialize( $data ) );
- $this->assertGreaterThan( 0, count( (array)$data ) );
+class ApiFormatWddxTest_SlowWddx extends ApiFormatWddx {
+ public static function useSlowPrinter() {
+ return true;
}
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatXmlTest.php b/tests/phpunit/includes/api/format/ApiFormatXmlTest.php
new file mode 100644
index 00000000..7babaedb
--- /dev/null
+++ b/tests/phpunit/includes/api/format/ApiFormatXmlTest.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @group API
+ * @group Database
+ * @covers ApiFormatXml
+ */
+class ApiFormatXmlTest extends ApiFormatTestBase {
+
+ protected $printerName = 'xml';
+
+ public static function setUpBeforeClass() {
+ parent::setUpBeforeClass();
+ $page = WikiPage::factory( Title::newFromText( 'MediaWiki:ApiFormatXmlTest.xsl' ) );
+ $page->doEditContent( new WikitextContent(
+ '<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />'
+ ), 'Summary' );
+ $page = WikiPage::factory( Title::newFromText( 'MediaWiki:ApiFormatXmlTest' ) );
+ $page->doEditContent( new WikitextContent( 'Bogus' ), 'Summary' );
+ $page = WikiPage::factory( Title::newFromText( 'ApiFormatXmlTest' ) );
+ $page->doEditContent( new WikitextContent( 'Bogus' ), 'Summary' );
+ }
+
+ public static function provideGeneralEncoding() {
+ return array(
+ // Basic types
+ array( array( null, 'a' => null ), '<?xml version="1.0"?><api><_v _idx="0" /></api>' ),
+ array( array( true, 'a' => true ), '<?xml version="1.0"?><api a=""><_v _idx="0">true</_v></api>' ),
+ array( array( false, 'a' => false ), '<?xml version="1.0"?><api><_v _idx="0">false</_v></api>' ),
+ array( array( true, 'a' => true, ApiResult::META_BC_BOOLS => array( 0, 'a' ) ),
+ '<?xml version="1.0"?><api a=""><_v _idx="0">1</_v></api>' ),
+ array( array( false, 'a' => false, ApiResult::META_BC_BOOLS => array( 0, 'a' ) ),
+ '<?xml version="1.0"?><api><_v _idx="0"></_v></api>' ),
+ array( array( 42, 'a' => 42 ), '<?xml version="1.0"?><api a="42"><_v _idx="0">42</_v></api>' ),
+ array( array( 42.5, 'a' => 42.5 ), '<?xml version="1.0"?><api a="42.5"><_v _idx="0">42.5</_v></api>' ),
+ array( array( 1e42, 'a' => 1e42 ), '<?xml version="1.0"?><api a="1.0E+42"><_v _idx="0">1.0E+42</_v></api>' ),
+ array( array( 'foo', 'a' => 'foo' ), '<?xml version="1.0"?><api a="foo"><_v _idx="0">foo</_v></api>' ),
+ array( array( 'fóo', 'a' => 'fóo' ), '<?xml version="1.0"?><api a="fóo"><_v _idx="0">fóo</_v></api>' ),
+
+ // Arrays and objects
+ array( array( array() ), '<?xml version="1.0"?><api><_v /></api>' ),
+ array( array( array( 'x' => 1 ) ), '<?xml version="1.0"?><api><_v x="1" /></api>' ),
+ array( array( array( 2 => 1 ) ), '<?xml version="1.0"?><api><_v><_v _idx="2">1</_v></_v></api>' ),
+ array( array( (object)array() ), '<?xml version="1.0"?><api><_v /></api>' ),
+ array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '<?xml version="1.0"?><api><_v><_v _idx="0">1</_v></_v></api>' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '<?xml version="1.0"?><api><_v><_v>1</_v></_v></api>' ),
+ array( array( array( 'x' => 1, 'y' => array( 'z' => 1 ), ApiResult::META_TYPE => 'kvp' ) ),
+ '<?xml version="1.0"?><api><_v><_v _name="x" xml:space="preserve">1</_v><_v _name="y"><z xml:space="preserve">1</z></_v></_v></api>' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp', ApiResult::META_INDEXED_TAG_NAME => 'i', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ '<?xml version="1.0"?><api><_v><i key="x" xml:space="preserve">1</i></_v></api>' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
+ '<?xml version="1.0"?><api><_v><_v key="x" xml:space="preserve">1</_v></_v></api>' ),
+ array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '<?xml version="1.0"?><api><_v x="1" /></api>' ),
+ array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '<?xml version="1.0"?><api><_v><_v _idx="0">a</_v><_v _idx="1">b</_v></_v></api>' ),
+
+ // Content
+ array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ '<?xml version="1.0"?><api xml:space="preserve">foo</api>' ),
+
+ // Specified element name
+ array( array( 'foo', 'bar', ApiResult::META_INDEXED_TAG_NAME => 'itn' ),
+ '<?xml version="1.0"?><api><itn>foo</itn><itn>bar</itn></api>' ),
+
+ // Subelements
+ array( array( 'a' => 1, 's' => 1, '_subelements' => array( 's' ) ),
+ '<?xml version="1.0"?><api a="1"><s xml:space="preserve">1</s></api>' ),
+
+ // Content and subelement
+ array( array( 'a' => 1, 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ '<?xml version="1.0"?><api a="1" xml:space="preserve">foo</api>' ),
+ array( array( 's' => array(), 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
+ '<?xml version="1.0"?><api><s /><content xml:space="preserve">foo</content></api>' ),
+ array(
+ array(
+ 's' => 1,
+ 'content' => 'foo',
+ ApiResult::META_CONTENT => 'content',
+ ApiResult::META_SUBELEMENTS => array( 's' )
+ ),
+ '<?xml version="1.0"?><api><s xml:space="preserve">1</s><content xml:space="preserve">foo</content></api>'
+ ),
+
+ // BC Subelements
+ array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
+ '<?xml version="1.0"?><api><foo xml:space="preserve">foo</foo></api>' ),
+
+ // Name mangling
+ array( array( 'foo.bar' => 1 ), '<?xml version="1.0"?><api foo.bar="1" />' ),
+ array( array( '' => 1 ), '<?xml version="1.0"?><api _="1" />' ),
+ array( array( 'foo bar' => 1 ), '<?xml version="1.0"?><api _foo.20.bar="1" />' ),
+ array( array( 'foo:bar' => 1 ), '<?xml version="1.0"?><api _foo.3A.bar="1" />' ),
+ array( array( 'foo%.bar' => 1 ), '<?xml version="1.0"?><api _foo.25..2E.bar="1" />' ),
+ array( array( '4foo' => 1, 'foo4' => 1 ), '<?xml version="1.0"?><api _4foo="1" foo4="1" />' ),
+ array( array( "foo\xe3\x80\x80bar" => 1 ), '<?xml version="1.0"?><api _foo.3000.bar="1" />' ),
+ array( array( 'foo:bar' => 1, ApiResult::META_PRESERVE_KEYS => array( 'foo:bar' ) ),
+ '<?xml version="1.0"?><api foo:bar="1" />' ),
+ array( array( 'a', 'b', ApiResult::META_INDEXED_TAG_NAME => 'foo bar' ),
+ '<?xml version="1.0"?><api><_foo.20.bar>a</_foo.20.bar><_foo.20.bar>b</_foo.20.bar></api>' ),
+
+ // includenamespace param
+ array( array( 'x' => 'foo' ), '<?xml version="1.0"?><api x="foo" xmlns="http://www.mediawiki.org/xml/api/" />',
+ array( 'includexmlnamespace' => 1 ) ),
+
+ // xslt param
+ array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Invalid or non-existent stylesheet specified</xml></warnings></api>',
+ array( 'xslt' => 'DoesNotExist' ) ),
+ array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should be in the MediaWiki namespace.</xml></warnings></api>',
+ array( 'xslt' => 'ApiFormatXmlTest' ) ),
+ array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should have .xsl extension.</xml></warnings></api>',
+ array( 'xslt' => 'MediaWiki:ApiFormatXmlTest' ) ),
+ array( array(),
+ '<?xml version="1.0"?><?xml-stylesheet href="' .
+ htmlspecialchars( Title::newFromText( 'MediaWiki:ApiFormatXmlTest.xsl' )->getLocalURL( 'action=raw' ) ) .
+ '" type="text/xsl" ?><api />',
+ array( 'xslt' => 'MediaWiki:ApiFormatXmlTest.xsl' ) ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/api/query/ApiQueryBasicTest.php b/tests/phpunit/includes/api/query/ApiQueryBasicTest.php
index e486c4f4..fa0e4cb5 100644
--- a/tests/phpunit/includes/api/query/ApiQueryBasicTest.php
+++ b/tests/phpunit/includes/api/query/ApiQueryBasicTest.php
@@ -23,8 +23,6 @@
* @file
*/
-require_once 'ApiQueryTestBase.php';
-
/**
* These tests validate basic functionality of the api query module
*
diff --git a/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php b/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php
index 347cd6f8..cd735223 100644
--- a/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php
+++ b/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php
@@ -18,8 +18,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-require_once 'ApiQueryContinueTestBase.php';
-
/**
* @group API
* @group Database
@@ -62,7 +60,8 @@ class ApiQueryContinue2Test extends ApiQueryContinueTestBase {
);
};
// generator + 1 prop + 1 list
- $data = $this->query( $mk( 99, 99, true ), 1, 'g1p', false );
+ $data = $this->query( $mk( 99, 99, true ), 1, 'g1p', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, 1, true ), 6, 'g1p-11t' );
$this->checkC( $data, $mk( 2, 2, true ), 3, 'g1p-22t' );
$this->checkC( $data, $mk( 1, 1, false ), 6, 'g1p-11f' );
diff --git a/tests/phpunit/includes/api/query/ApiQueryContinueTest.php b/tests/phpunit/includes/api/query/ApiQueryContinueTest.php
index 03797901..d441f4c4 100644
--- a/tests/phpunit/includes/api/query/ApiQueryContinueTest.php
+++ b/tests/phpunit/includes/api/query/ApiQueryContinueTest.php
@@ -18,8 +18,6 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-require_once 'ApiQueryContinueTestBase.php';
-
/**
* These tests validate the new continue functionality of the api query module by
* doing multiple requests with varying parameters, merging the results, and checking
@@ -68,7 +66,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
'aplimit' => "$l",
);
};
- $data = $this->query( $mk( 99 ), 1, '1L', false );
+ $data = $this->query( $mk( 99 ), 1, '1L', false ) +
+ array( 'batchcomplete' => true );
// 1 list
$this->checkC( $data, $mk( 1 ), 5, '1L-1' );
@@ -95,7 +94,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// 2 lists
- $data = $this->query( $mk( 99, 99 ), 1, '2L', false );
+ $data = $this->query( $mk( 99, 99 ), 1, '2L', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, 1 ), 5, '2L-11' );
$this->checkC( $data, $mk( 2, 2 ), 3, '2L-22' );
$this->checkC( $data, $mk( 3, 3 ), 2, '2L-33' );
@@ -119,7 +119,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// generator + 1 prop
- $data = $this->query( $mk( 99, 99 ), 1, 'G1P', false );
+ $data = $this->query( $mk( 99, 99 ), 1, 'G1P', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, 1 ), 11, 'G1P-11' );
$this->checkC( $data, $mk( 2, 2 ), 6, 'G1P-22' );
$this->checkC( $data, $mk( 3, 3 ), 4, 'G1P-33' );
@@ -144,7 +145,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// generator + 2 props
- $data = $this->query( $mk( 99, 99, 99 ), 1, 'G2P', false );
+ $data = $this->query( $mk( 99, 99, 99 ), 1, 'G2P', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, 1, 1 ), 16, 'G2P-111' );
$this->checkC( $data, $mk( 2, 2, 2 ), 9, 'G2P-222' );
$this->checkC( $data, $mk( 3, 3, 3 ), 6, 'G2P-333' );
@@ -177,7 +179,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// generator + 1 prop + 1 list
- $data = $this->query( $mk( 99, 99, 99 ), 1, 'G1P1L', false );
+ $data = $this->query( $mk( 99, 99, 99 ), 1, 'G1P1L', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, 1, 1 ), 11, 'G1P1L-111' );
$this->checkC( $data, $mk( 2, 2, 2 ), 6, 'G1P1L-222' );
$this->checkC( $data, $mk( 3, 3, 3 ), 4, 'G1P1L-333' );
@@ -214,7 +217,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// generator + 1 prop + 1 list
- $data = $this->query( $mk( 99, 99, 99, 99, 99 ), 1, 'G2P2L1M', false );
+ $data = $this->query( $mk( 99, 99, 99, 99, 99 ), 1, 'G2P2L1M', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, 1, 1, 1, 1 ), 16, 'G2P2L1M-11111' );
$this->checkC( $data, $mk( 2, 2, 2, 2, 2 ), 9, 'G2P2L1M-22222' );
$this->checkC( $data, $mk( 3, 3, 3, 3, 3 ), 6, 'G2P2L1M-33333' );
@@ -244,7 +248,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// generator + 1 prop
- $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=P', false );
+ $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=P', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, true, 1, true ), 4, 'G=P-1t1t' );
$this->checkC( $data, $mk( 2, true, 2, true ), 2, 'G=P-2t2t' );
@@ -290,7 +295,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase {
);
};
// generator + 1 list
- $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=L', false );
+ $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=L', false ) +
+ array( 'batchcomplete' => true );
$this->checkC( $data, $mk( 1, true, 1, true ), 5, 'G=L-1t1t' );
$this->checkC( $data, $mk( 2, true, 2, true ), 3, 'G=L-2t2t' );
diff --git a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
index bce62685..ce2f70de 100644
--- a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
+++ b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
@@ -21,9 +21,6 @@
*
* @file
*/
-
-require_once 'ApiQueryTestBase.php';
-
abstract class ApiQueryContinueTestBase extends ApiQueryTestBase {
/**
@@ -62,6 +59,8 @@ abstract class ApiQueryContinueTestBase extends ApiQueryTestBase {
}
if ( $useContinue && !isset( $params['continue'] ) ) {
$params['continue'] = '';
+ } else {
+ $params['rawcontinue'] = '1';
}
$count = 0;
$result = array();
diff --git a/tests/phpunit/includes/api/query/ApiQueryTest.php b/tests/phpunit/includes/api/query/ApiQueryTest.php
index bba22c77..5f061b50 100644
--- a/tests/phpunit/includes/api/query/ApiQueryTest.php
+++ b/tests/phpunit/includes/api/query/ApiQueryTest.php
@@ -7,32 +7,21 @@
* @covers ApiQuery
*/
class ApiQueryTest extends ApiTestCase {
- /**
- * @var array Storage for $wgHooks
- */
- protected $hooks;
-
protected function setUp() {
- global $wgHooks;
-
parent::setUp();
$this->doLogin();
- // Setup en: as interwiki prefix
- $this->hooks = $wgHooks;
- $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) {
- if ( $prefix == 'apiquerytestiw' ) {
- $data = array( 'iw_url' => 'wikipedia' );
- }
- return false;
- };
- }
-
- protected function tearDown() {
- global $wgHooks;
- $wgHooks = $this->hooks;
-
- parent::tearDown();
+ // Setup apiquerytestiw: as interwiki prefix
+ $this->setMwGlobals( 'wgHooks', array(
+ 'InterwikiLoadPrefix' => array(
+ function ( $prefix, &$data ) {
+ if ( $prefix == 'apiquerytestiw' ) {
+ $data = array( 'iw_url' => 'wikipedia' );
+ }
+ return false;
+ }
+ )
+ ) );
}
public function testTitlesGetNormalized() {
@@ -127,4 +116,27 @@ class ApiQueryTest extends ApiTestCase {
array( 'apiquerytestiw:foo', NS_MAIN, null, true ),
);
}
+
+ /**
+ * Test if all classes in the query module manager exists
+ */
+ public function testClassNamesInModuleManager() {
+ global $wgAutoloadLocalClasses, $wgAutoloadClasses;
+
+ // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php
+ $classes = $wgAutoloadLocalClasses + $wgAutoloadClasses;
+
+ $api = new ApiMain(
+ new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
+ );
+ $queryApi = new ApiQuery( $api, 'query' );
+ $modules = $queryApi->getModuleManager()->getNamesWithClasses();
+ foreach( $modules as $name => $class ) {
+ $this->assertArrayHasKey(
+ $class,
+ $classes,
+ 'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)'
+ );
+ }
+ }
}
diff --git a/tests/phpunit/includes/api/query/ApiQueryTestBase.php b/tests/phpunit/includes/api/query/ApiQueryTestBase.php
index 56c15b23..dabf72e0 100644
--- a/tests/phpunit/includes/api/query/ApiQueryTestBase.php
+++ b/tests/phpunit/includes/api/query/ApiQueryTestBase.php
@@ -88,19 +88,26 @@ STR;
/**
* Checks that the request's result matches the expected results.
* @param array $values Array is a two element array( request, expected_results )
- * @throws Exception
+ * @param array $session
+ * @param bool $appendModule
+ * @param User $user
*/
- protected function check( $values ) {
+ protected function check( $values, array $session = null,
+ $appendModule = false, User $user = null
+ ) {
list( $req, $exp ) = $this->validateRequestExpectedPair( $values );
if ( !array_key_exists( 'action', $req ) ) {
$req['action'] = 'query';
}
+ if ( !array_key_exists( 'continue', $req ) ) {
+ $req['rawcontinue'] = '1';
+ }
foreach ( $req as &$val ) {
if ( is_array( $val ) ) {
$val = implode( '|', array_unique( $val ) );
}
}
- $result = $this->doApiRequest( $req );
+ $result = $this->doApiRequest( $req, $session, $appendModule, $user );
$this->assertResult( array( 'query' => $exp ), $result[0], $req );
}
@@ -113,9 +120,16 @@ STR;
if ( is_array( $message ) ) {
$message = http_build_query( $message );
}
+
+ // FIXME: once we migrate to phpunit 4.1+, hardcode ComparisonFailure exception use
+ $compEx = 'SebastianBergmann\Comparator\ComparisonFailure';
+ if ( !class_exists( $compEx ) ) {
+ $compEx = 'PHPUnit_Framework_ComparisonFailure';
+ }
+
throw new PHPUnit_Framework_ExpectationFailedException(
$e->getMessage() . "\nRequest: $message",
- new PHPUnit_Framework_ComparisonFailure(
+ new $compEx(
$exp,
$result,
print_r( $exp, true ),
diff --git a/tests/phpunit/includes/cache/GenderCacheTest.php b/tests/phpunit/includes/cache/GenderCacheTest.php
index ce2db5d7..04fb00d9 100644
--- a/tests/phpunit/includes/cache/GenderCacheTest.php
+++ b/tests/phpunit/includes/cache/GenderCacheTest.php
@@ -6,14 +6,10 @@
*/
class GenderCacheTest extends MediaWikiLangTestCase {
- protected function setUp() {
- global $wgDefaultUserOptions;
- parent::setUp();
+ function addDBData() {
//ensure the correct default gender
- $wgDefaultUserOptions['gender'] = 'unknown';
- }
+ $this->mergeMwGlobalArrayValue( 'wgDefaultUserOptions', array( 'gender' => 'unknown' ) );
- function addDBData() {
$user = User::newFromName( 'UTMale' );
if ( $user->getID() == 0 ) {
$user->addToDatabase();
diff --git a/tests/phpunit/includes/cache/LocalisationCacheTest.php b/tests/phpunit/includes/cache/LocalisationCacheTest.php
index fc06a501..a0d308aa 100644
--- a/tests/phpunit/includes/cache/LocalisationCacheTest.php
+++ b/tests/phpunit/includes/cache/LocalisationCacheTest.php
@@ -7,18 +7,32 @@
*/
class LocalisationCacheTest extends MediaWikiTestCase {
protected function setUp() {
- global $IP;
-
parent::setUp();
$this->setMwGlobals( array(
- 'wgMessagesDirs' => array( "$IP/tests/phpunit/data/localisationcache" ),
'wgExtensionMessagesFiles' => array(),
'wgHooks' => array(),
) );
}
+ /**
+ * @return PHPUnit_Framework_MockObject_MockObject|LocalisationCache
+ */
+ protected function getMockLocalisationCache() {
+ global $IP;
+ $lc = $this->getMockBuilder( 'LocalisationCache' )
+ ->setConstructorArgs( array( array( 'store' => 'detect' ) ) )
+ ->setMethods( array( 'getMessagesDirs' ) )
+ ->getMock();
+ $lc->expects( $this->any() )->method( 'getMessagesDirs' )
+ ->will( $this->returnValue(
+ array( "$IP/tests/phpunit/data/localisationcache" )
+ ) );
+
+ return $lc;
+ }
+
public function testPuralRulesFallback() {
- $cache = new LocalisationCache( array( 'store' => 'detect' ) );
+ $cache = $this->getMockLocalisationCache();
$this->assertEquals(
$cache->getItem( 'ar', 'pluralRules' ),
@@ -46,7 +60,7 @@ class LocalisationCacheTest extends MediaWikiTestCase {
}
public function testRecacheFallbacks() {
- $lc = new LocalisationCache( array( 'store' => 'detect' ) );
+ $lc = $this->getMockLocalisationCache();
$lc->recache( 'uk' );
$this->assertEquals(
array(
@@ -60,23 +74,25 @@ class LocalisationCacheTest extends MediaWikiTestCase {
}
public function testRecacheFallbacksWithHooks() {
- global $wgHooks;
-
// Use hook to provide updates for messages. This is what the
// LocalisationUpdate extension does. See bug 68781.
- $wgHooks['LocalisationCacheRecacheFallback'][] = function (
- LocalisationCache $lc,
- $code,
- array &$cache
- ) {
- if ( $code === 'ru' ) {
- $cache['messages']['present-uk'] = 'ru-override';
- $cache['messages']['present-ru'] = 'ru-override';
- $cache['messages']['present-en'] = 'ru-override';
- }
- };
+ $this->mergeMwGlobalArrayValue( 'wgHooks', array(
+ 'LocalisationCacheRecacheFallback' => array(
+ function (
+ LocalisationCache $lc,
+ $code,
+ array &$cache
+ ) {
+ if ( $code === 'ru' ) {
+ $cache['messages']['present-uk'] = 'ru-override';
+ $cache['messages']['present-ru'] = 'ru-override';
+ $cache['messages']['present-en'] = 'ru-override';
+ }
+ }
+ )
+ ) );
- $lc = new LocalisationCache( array( 'store' => 'detect' ) );
+ $lc = $this->getMockLocalisationCache();
$lc->recache( 'uk' );
$this->assertEquals(
array(
diff --git a/tests/phpunit/includes/cache/RedisBloomCacheTest.php b/tests/phpunit/includes/cache/RedisBloomCacheTest.php
deleted file mode 100644
index 3d491e90..00000000
--- a/tests/phpunit/includes/cache/RedisBloomCacheTest.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-/**
- * Test for BloomCacheRedis class.
- *
- * @TODO: some generic base "redis test server conf" for all testing?
- *
- * @covers BloomCacheRedis
- * @group Cache
- */
-class BloomCacheRedisTest extends MediaWikiTestCase {
- private static $suffix;
-
- protected function setUp() {
- parent::setUp();
-
- self::$suffix = self::$suffix ? : mt_rand();
-
- $fcache = BloomCache::get( 'main' );
- if ( $fcache instanceof BloomCacheRedis ) {
- $fcache->delete( "unit-testing-" . self::$suffix );
- } else {
- $this->markTestSkipped( 'The main bloom cache is not redis.' );
- }
- }
-
- public function testBloomCache() {
- $key = "unit-testing-" . self::$suffix;
- $fcache = BloomCache::get( 'main' );
- $count = 1500;
-
- $this->assertTrue( $fcache->delete( $key ), "OK delete of filter '$key'." );
- $this->assertTrue( $fcache->init( $key, $count, .001 ), "OK init of filter '$key'." );
-
- $members = array();
- for ( $i = 0; $i < $count; ++$i ) {
- $members[] = "$i-value-$i";
- }
- $this->assertTrue( $fcache->add( $key, $members ), "Addition of members to '$key' OK." );
-
- for ( $i = 0; $i < $count; ++$i ) {
- $this->assertTrue( $fcache->isHit( $key, "$i-value-$i" ), "Hit on member '$i-value-$i'." );
- }
-
- $falsePositives = array();
- for ( $i = $count; $i < 2 * $count; ++$i ) {
- if ( $fcache->isHit( $key, "value$i" ) ) {
- $falsePositives[] = "value$i";
- }
- }
-
- $eFalsePositives = array(
- 'value1763',
- 'value2245',
- 'value2353',
- 'value2791',
- 'value2898',
- 'value2975'
- );
- $this->assertEquals( $eFalsePositives, $falsePositives, "Correct number of false positives found." );
- }
-
- protected function tearDown() {
- parent::tearDown();
-
- $fcache = BloomCache::get( 'main' );
- if ( $fcache instanceof BloomCacheRedis ) {
- $fcache->delete( "unit-testing-" . self::$suffix );
- }
- }
-}
diff --git a/tests/phpunit/includes/changes/EnhancedChangesListTest.php b/tests/phpunit/includes/changes/EnhancedChangesListTest.php
index 40a11d2d..a14a50d2 100644
--- a/tests/phpunit/includes/changes/EnhancedChangesListTest.php
+++ b/tests/phpunit/includes/changes/EnhancedChangesListTest.php
@@ -5,7 +5,6 @@
*
* @group Database
*
- * @licence GNU GPL v2+
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class EnhancedChangesListTest extends MediaWikiLangTestCase {
@@ -31,7 +30,7 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
'mediawiki.special.changeslist',
$styleModules,
'has mediawiki.special.changeslist'
- );
+ );
$this->assertContains(
'mediawiki.special.changeslist.enhanced',
@@ -75,10 +74,10 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
$this->assertEquals( '', $html );
}
- /**
- * @todo more tests for actual formatting, this is more of a smoke test
- */
- public function testEndRecentChangesList() {
+ /**
+ * @todo more tests for actual formatting, this is more of a smoke test
+ */
+ public function testEndRecentChangesList() {
$enhancedChangesList = $this->newEnhancedChangesList();
$enhancedChangesList->beginRecentChangesList();
@@ -92,7 +91,7 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase {
preg_match_all( '/td class="mw-enhanced-rc-nested"/', $html, $matches );
$this->assertCount( 2, $matches[0] );
- }
+ }
/**
* @return EnhancedChangesList
diff --git a/tests/phpunit/includes/changes/OldChangesListTest.php b/tests/phpunit/includes/changes/OldChangesListTest.php
index 2ea9f33e..311ad89c 100644
--- a/tests/phpunit/includes/changes/OldChangesListTest.php
+++ b/tests/phpunit/includes/changes/OldChangesListTest.php
@@ -9,7 +9,6 @@
*
* @group Database
*
- * @licence GNU GPL v2+
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class OldChangesListTest extends MediaWikiLangTestCase {
diff --git a/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php b/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php
index ee1a4d0e..0b877275 100644
--- a/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php
+++ b/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php
@@ -5,7 +5,6 @@
*
* @group Database
*
- * @licence GNU GPL v2+
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class RCCacheEntryFactoryTest extends MediaWikiLangTestCase {
diff --git a/tests/phpunit/includes/changes/RecentChangeTest.php b/tests/phpunit/includes/changes/RecentChangeTest.php
index 98903f1e..b3cb7b52 100644
--- a/tests/phpunit/includes/changes/RecentChangeTest.php
+++ b/tests/phpunit/includes/changes/RecentChangeTest.php
@@ -35,6 +35,7 @@ class RecentChangeTest extends MediaWikiTestCase {
* Should cover the following log actions (which are most commonly used by bots):
* - block/block
* - block/unblock
+ * - block/reblock
* - delete/delete
* - delete/restore
* - newusers/create
@@ -46,6 +47,9 @@ class RecentChangeTest extends MediaWikiTestCase {
* - protect/modifyprotect
* - protect/unprotect
* - upload/upload
+ * - merge/merge
+ * - import/upload
+ * - import/interwiki
*
* As well as the following Auto Edit Summaries:
* - blank
@@ -62,9 +66,13 @@ class RecentChangeTest extends MediaWikiTestCase {
# block/block
$this->assertIRCComment(
- $this->context->msg( 'blocklogentry', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
'block', 'block',
- array(),
+ array(
+ '5::duration' => 'duration',
+ '6::flags' => 'flags',
+ ),
$this->user_comment
);
# block/unblock
@@ -74,6 +82,17 @@ class RecentChangeTest extends MediaWikiTestCase {
array(),
$this->user_comment
);
+ # block/reblock
+ $this->assertIRCComment(
+ $this->context->msg( 'reblock-logentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
+ 'block', 'reblock',
+ array(
+ '5::duration' => 'duration',
+ '6::flags' => 'flags',
+ ),
+ $this->user_comment
+ );
}
/**
@@ -230,6 +249,48 @@ class RecentChangeTest extends MediaWikiTestCase {
}
/**
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeMerge() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # merge/merge
+ $this->assertIRCComment(
+ $this->context->msg( 'pagemerge-logentry', 'SomeTitle', 'Dest', 'timestamp' )->plain()
+ . $sep . $this->user_comment,
+ 'merge', 'merge',
+ array(
+ '4::dest' => 'Dest',
+ '5::mergepoint' => 'timestamp',
+ ),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeImport() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # import/upload
+ $this->assertIRCComment(
+ $this->context->msg( 'import-logentry-upload', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'import', 'upload',
+ array(),
+ $this->user_comment
+ );
+
+ # import/interwiki
+ $this->assertIRCComment(
+ $this->context->msg( 'import-logentry-interwiki', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'import', 'interwiki',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
* @todo Emulate these edits somehow and extract
* raw edit summary from RecentChange object
* --
diff --git a/tests/phpunit/includes/changes/TestRecentChangesHelper.php b/tests/phpunit/includes/changes/TestRecentChangesHelper.php
index ad643274..2506087b 100644
--- a/tests/phpunit/includes/changes/TestRecentChangesHelper.php
+++ b/tests/phpunit/includes/changes/TestRecentChangesHelper.php
@@ -3,7 +3,6 @@
/**
* Helper for generating test recent changes entries.
*
- * @licence GNU GPL v2+
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class TestRecentChangesHelper {
diff --git a/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php b/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php
index 3f887dc0..2fa11eaf 100644
--- a/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php
+++ b/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php
@@ -5,7 +5,6 @@
*
* @group ComposerHooks
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class ComposerVersionNormalizerTest extends PHPUnit_Framework_TestCase {
diff --git a/tests/phpunit/includes/config/GlobalVarConfigTest.php b/tests/phpunit/includes/config/GlobalVarConfigTest.php
index 70b9e684..28068d5e 100644
--- a/tests/phpunit/includes/config/GlobalVarConfigTest.php
+++ b/tests/phpunit/includes/config/GlobalVarConfigTest.php
@@ -87,34 +87,10 @@ class GlobalVarConfigTest extends MediaWikiTestCase {
$this->assertEquals( $config->get( $name ), $expected );
}
- public static function provideSet() {
- return array(
- array( 'Foo', 'wg', 'wgFoo' ),
- array( 'SomethingRandom', 'wg', 'wgSomethingRandom' ),
- array( 'FromAnExtension', 'eg', 'egFromAnExtension' ),
- array( 'NoPrefixHere', '', 'NoPrefixHere' ),
- );
- }
-
private function maybeStashGlobal( $var ) {
if ( array_key_exists( $var, $GLOBALS ) ) {
// Will be reset after this test is over
$this->stashMwGlobals( $var );
}
}
-
- /**
- * @dataProvider provideSet
- * @covers GlobalVarConfig::set
- * @covers GlobalVarConfig::setWithPrefix
- */
- public function testSet( $name, $prefix, $var ) {
- $this->hideDeprecated( 'GlobalVarConfig::set' );
- $this->maybeStashGlobal( $var );
- $config = new GlobalVarConfig( $prefix );
- $random = wfRandomString();
- $config->set( $name, $random );
- $this->assertArrayHasKey( $var, $GLOBALS );
- $this->assertEquals( $random, $GLOBALS[$var] );
- }
}
diff --git a/tests/phpunit/includes/config/HashConfigTest.php b/tests/phpunit/includes/config/HashConfigTest.php
index 3ad3bfbd..06973b09 100644
--- a/tests/phpunit/includes/config/HashConfigTest.php
+++ b/tests/phpunit/includes/config/HashConfigTest.php
@@ -60,4 +60,4 @@ class HashConfigTest extends MediaWikiTestCase {
$conf->set( 'one', '3' );
$this->assertEquals( '3', $conf->get( 'one' ) );
}
-} \ No newline at end of file
+}
diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php
index f7449734..988a59ee 100644
--- a/tests/phpunit/includes/content/ContentHandlerTest.php
+++ b/tests/phpunit/includes/content/ContentHandlerTest.php
@@ -2,11 +2,6 @@
/**
* @group ContentHandler
- * @group Database
- *
- * @note Declare that we are using the database, because otherwise we'll fail in
- * the "databaseless" test run. This is because the LinkHolderArray used by the
- * parser needs database access.
*/
class ContentHandlerTest extends MediaWikiTestCase {
@@ -36,6 +31,8 @@ class ContentHandlerTest extends MediaWikiTestCase {
// Reset namespace cache
MWNamespace::getCanonicalNamespaces( true );
$wgContLang->resetNamespaces();
+ // And LinkCache
+ LinkCache::destroySingleton();
}
protected function tearDown() {
@@ -44,6 +41,8 @@ class ContentHandlerTest extends MediaWikiTestCase {
// Reset namespace cache
MWNamespace::getCanonicalNamespaces( true );
$wgContLang->resetNamespaces();
+ // And LinkCache
+ LinkCache::destroySingleton();
parent::tearDown();
}
@@ -83,6 +82,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
*/
public function testGetForTitle( $title, $expectedContentModel ) {
$title = Title::newFromText( $title );
+ LinkCache::singleton()->addBadLinkObj( $title );
$handler = ContentHandler::getForTitle( $title );
$this->assertEquals( $expectedContentModel, $handler->getModelID() );
}
@@ -139,6 +139,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
public function testGetPageLanguage( $title, $expected ) {
if ( is_string( $title ) ) {
$title = Title::newFromText( $title );
+ LinkCache::singleton()->addBadLinkObj( $title );
}
$expected = wfGetLangObj( $expected );
@@ -292,7 +293,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
$expectedModelId, $expectedNativeData, $shouldFail
) {
$title = Title::newFromText( $title );
-
+ LinkCache::singleton()->addBadLinkObj( $title );
try {
$content = ContentHandler::makeContent( $data, $title, $modelId, $format );
@@ -317,6 +318,8 @@ class ContentHandlerTest extends MediaWikiTestCase {
* page.
*/
public function testGetAutosummary() {
+ $this->setMwGlobals( 'wgContLang', Language::factory( 'en' ) );
+
$content = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT );
$title = Title::newFromText( 'Help:Test' );
// Create a new content object with no content
diff --git a/tests/phpunit/includes/content/JsonContentTest.php b/tests/phpunit/includes/content/JsonContentTest.php
index 77b542f4..cccfe7b1 100644
--- a/tests/phpunit/includes/content/JsonContentTest.php
+++ b/tests/phpunit/includes/content/JsonContentTest.php
@@ -6,48 +6,85 @@
*/
class JsonContentTest extends MediaWikiLangTestCase {
- /**
- * @dataProvider provideValidConstruction
- */
- public function testValidConstruct( $text, $modelId, $isValid, $expected ) {
- $obj = new JsonContent( $text, $modelId );
- $this->assertEquals( $isValid, $obj->isValid() );
- $this->assertEquals( $expected, $obj->getJsonData() );
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( 'wgWellFormedXml', true );
}
public static function provideValidConstruction() {
return array(
- array( 'foo', CONTENT_MODEL_JSON, false, null ),
- array( FormatJson::encode( array() ), CONTENT_MODEL_JSON, true, array() ),
- array( FormatJson::encode( array( 'foo' ) ), CONTENT_MODEL_JSON, true, array( 'foo' ) ),
+ array( 'foo', false, null ),
+ array( '[]', true, array() ),
+ array( '{}', true, (object)array() ),
+ array( '""', true, '' ),
+ array( '"0"', true, '0' ),
+ array( '"bar"', true, 'bar' ),
+ array( '0', true, '0' ),
+ array( '{ "0": "bar" }', true, (object)array( 'bar' ) ),
);
}
/**
- * @dataProvider provideDataToEncode
+ * @dataProvider provideValidConstruction
*/
- public function testBeautifyUsesFormatJson( $data ) {
- $obj = new JsonContent( FormatJson::encode( $data ) );
- $this->assertEquals( FormatJson::encode( $data, true ), $obj->beautifyJSON() );
+ public function testIsValid( $text, $isValid, $expected ) {
+ $obj = new JsonContent( $text, CONTENT_MODEL_JSON );
+ $this->assertEquals( $isValid, $obj->isValid() );
+ $this->assertEquals( $expected, $obj->getData()->getValue() );
}
public static function provideDataToEncode() {
return array(
- array( array() ),
- array( array( 'foo' ) ),
- array( array( 'foo', 'bar' ) ),
- array( array( 'baz' => 'foo', 'bar' ) ),
- array( array( 'baz' => 1000, 'bar' ) ),
+ array(
+ // Round-trip empty array
+ '[]',
+ '[]',
+ ),
+ array(
+ // Round-trip empty object
+ '{}',
+ '{}',
+ ),
+ array(
+ // Round-trip empty array/object (nested)
+ '{ "foo": {}, "bar": [] }',
+ "{\n \"foo\": {},\n \"bar\": []\n}",
+ ),
+ array(
+ '{ "foo": "bar" }',
+ "{\n \"foo\": \"bar\"\n}",
+ ),
+ array(
+ '{ "foo": 1000 }',
+ "{\n \"foo\": 1000\n}",
+ ),
+ array(
+ '{ "foo": 1000, "0": "bar" }',
+ "{\n \"foo\": 1000,\n \"0\": \"bar\"\n}",
+ ),
);
}
/**
* @dataProvider provideDataToEncode
*/
- public function testPreSaveTransform( $data ) {
- $obj = new JsonContent( FormatJson::encode( $data ) );
- $newObj = $obj->preSaveTransform( $this->getMockTitle(), $this->getMockUser(), $this->getMockParserOptions() );
- $this->assertTrue( $newObj->equals( new JsonContent( FormatJson::encode( $data, true ) ) ) );
+ public function testBeautifyJson( $input, $beautified ) {
+ $obj = new JsonContent( $input );
+ $this->assertEquals( $beautified, $obj->beautifyJSON() );
+ }
+
+ /**
+ * @dataProvider provideDataToEncode
+ */
+ public function testPreSaveTransform( $input, $transformed ) {
+ $obj = new JsonContent( $input );
+ $newObj = $obj->preSaveTransform(
+ $this->getMockTitle(),
+ $this->getMockUser(),
+ $this->getMockParserOptions()
+ );
+ $this->assertTrue( $newObj->equals( new JsonContent( $transformed ) ) );
}
private function getMockTitle() {
@@ -67,48 +104,55 @@ class JsonContentTest extends MediaWikiLangTestCase {
->getMock();
}
- /**
- * @dataProvider provideDataAndParserText
- */
- public function testFillParserOutput( $data, $expected ) {
- $obj = new JsonContent( FormatJson::encode( $data ) );
- $parserOutput = $obj->getParserOutput( $this->getMockTitle(), null, null, true );
- $this->assertInstanceOf( 'ParserOutput', $parserOutput );
- $this->assertEquals( $expected, $parserOutput->getText() );
- }
-
public static function provideDataAndParserText() {
return array(
array(
array(),
- '<table class="mw-json"><tbody></tbody></table>'
+ '<table class="mw-json"><tbody><tr><td>' .
+ '<table class="mw-json"><tbody><tr><td class="mw-json-empty">Empty array</td></tr>'
+ . '</tbody></table></td></tr></tbody></table>'
),
array(
- array( 'foo' ),
- '<table class="mw-json"><tbody><tr><th>0</th><td class="value">&quot;foo&quot;</td></tr></tbody></table>'
+ (object)array(),
+ '<table class="mw-json"><tbody><tr><td class="mw-json-empty">Empty object</td></tr>' .
+ '</tbody></table>'
),
array(
- array( 'foo', 'bar' ),
- '<table class="mw-json"><tbody><tr><th>0</th><td class="value">&quot;foo&quot;</td></tr>' .
- "\n" .
- '<tr><th>1</th><td class="value">&quot;bar&quot;</td></tr></tbody></table>'
+ (object)array( 'foo' ),
+ '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' .
+ '</tbody></table>'
),
array(
- array( 'baz' => 'foo', 'bar' ),
- '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">&quot;foo&quot;</td></tr>' .
- "\n" .
- '<tr><th>0</th><td class="value">&quot;bar&quot;</td></tr></tbody></table>'
+ (object)array( 'foo', 'bar' ),
+ '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' .
+ '<tr><th>1</th><td class="value">"bar"</td></tr></tbody></table>'
),
array(
- array( 'baz' => 1000, 'bar' ),
+ (object)array( 'baz' => 'foo', 'bar' ),
+ '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">"foo"</td></tr>' .
+ '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>'
+ ),
+ array(
+ (object)array( 'baz' => 1000, 'bar' ),
'<table class="mw-json"><tbody><tr><th>baz</th><td class="value">1000</td></tr>' .
- "\n" .
- '<tr><th>0</th><td class="value">&quot;bar&quot;</td></tr></tbody></table>'
+ '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>'
),
array(
- array( '<script>alert("evil!")</script>'),
- '<table class="mw-json"><tbody><tr><th>0</th><td class="value">&quot;&lt;script&gt;alert(&quot;evil!&quot;)&lt;/script&gt;&quot;</td></tr></tbody></table>',
+ (object)array( '<script>alert("evil!")</script>'),
+ '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"' .
+ '&lt;script>alert("evil!")&lt;/script>"' .
+ '</td></tr></tbody></table>',
),
);
}
+
+ /**
+ * @dataProvider provideDataAndParserText
+ */
+ public function testFillParserOutput( $data, $expected ) {
+ $obj = new JsonContent( FormatJson::encode( $data ) );
+ $parserOutput = $obj->getParserOutput( $this->getMockTitle(), null, null, true );
+ $this->assertInstanceOf( 'ParserOutput', $parserOutput );
+ $this->assertEquals( $expected, $parserOutput->getText() );
+ }
}
diff --git a/tests/phpunit/includes/content/TextContentTest.php b/tests/phpunit/includes/content/TextContentTest.php
index 2f811094..dd61f85b 100644
--- a/tests/phpunit/includes/content/TextContentTest.php
+++ b/tests/phpunit/includes/content/TextContentTest.php
@@ -7,11 +7,8 @@
*/
class TextContentTest extends MediaWikiLangTestCase {
protected $context;
- protected $savedContentGetParserOutput;
protected function setUp() {
- global $wgHooks;
-
parent::setUp();
// Anon user
@@ -32,24 +29,8 @@ class TextContentTest extends MediaWikiLangTestCase {
'wgUseTidy' => false,
'wgAlwaysUseTidy' => false,
'wgCapitalLinks' => true,
+ 'wgHooks' => array(), // bypass hook ContentGetParserOutput that force custom rendering
) );
-
- // bypass hooks that force custom rendering
- if ( isset( $wgHooks['ContentGetParserOutput'] ) ) {
- $this->savedContentGetParserOutput = $wgHooks['ContentGetParserOutput'];
- unset( $wgHooks['ContentGetParserOutput'] );
- }
- }
-
- public function teardown() {
- global $wgHooks;
-
- // restore hooks that force custom rendering
- if ( $this->savedContentGetParserOutput !== null ) {
- $wgHooks['ContentGetParserOutput'] = $this->savedContentGetParserOutput;
- }
-
- parent::teardown();
}
public function newContent( $text ) {
diff --git a/tests/phpunit/includes/RequestContextTest.php b/tests/phpunit/includes/context/RequestContextTest.php
index cae0e52e..a9e5be24 100644
--- a/tests/phpunit/includes/RequestContextTest.php
+++ b/tests/phpunit/includes/context/RequestContextTest.php
@@ -88,9 +88,9 @@ class RequestContextTest extends MediaWikiTestCase {
unset( $sc ); // restore previous context
$info = $context->exportSession();
- $this->assertEquals( $oInfo['ip'], $info['ip'], "Correct initial IP address." );
- $this->assertEquals( $oInfo['headers'], $info['headers'], "Correct initial headers." );
- $this->assertEquals( $oInfo['sessionId'], $info['sessionId'], "Correct initial session ID." );
- $this->assertEquals( $oInfo['userId'], $info['userId'], "Correct initial user ID." );
+ $this->assertEquals( $oInfo['ip'], $info['ip'], "Correct restored IP address." );
+ $this->assertEquals( $oInfo['headers'], $info['headers'], "Correct restored headers." );
+ $this->assertEquals( $oInfo['sessionId'], $info['sessionId'], "Correct restored session ID." );
+ $this->assertEquals( $oInfo['userId'], $info['userId'], "Correct restored user ID." );
}
}
diff --git a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
index 55e48d13..b4292a60 100644
--- a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
+++ b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
@@ -2,7 +2,6 @@
/**
* Holds tests for DatabaseMysqlBase MediaWiki class.
*
- * @section LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/tests/phpunit/includes/db/DatabaseSQLTest.php b/tests/phpunit/includes/db/DatabaseSQLTest.php
index 5c2d4b70..b13751f3 100644
--- a/tests/phpunit/includes/db/DatabaseSQLTest.php
+++ b/tests/phpunit/includes/db/DatabaseSQLTest.php
@@ -722,4 +722,84 @@ class DatabaseSQLTest extends MediaWikiTestCase {
$this->database->dropTable( 'non_existing', __METHOD__ )
);
}
+
+ /**
+ * @dataProvider provideMakeList
+ * @covers DatabaseBase::makeList
+ */
+ public function testMakeList( $list, $mode, $sqlText ) {
+ $this->assertEquals( trim( $this->database->makeList(
+ $list, $mode
+ ) ), $sqlText );
+ }
+
+ public static function provideMakeList() {
+ return array(
+ array(
+ array( 'value', 'value2' ),
+ LIST_COMMA,
+ "'value','value2'"
+ ),
+ array(
+ array( 'field', 'field2' ),
+ LIST_NAMES,
+ "field,field2"
+ ),
+ array(
+ array( 'field' => 'value', 'field2' => 'value2' ),
+ LIST_AND,
+ "field = 'value' AND field2 = 'value2'"
+ ),
+ array(
+ array( 'field' => null, "field2 != 'value2'" ),
+ LIST_AND,
+ "field IS NULL AND (field2 != 'value2')"
+ ),
+ array(
+ array( 'field' => array( 'value', null, 'value2' ), 'field2' => 'value2' ),
+ LIST_AND,
+ "(field IN ('value','value2') OR field IS NULL) AND field2 = 'value2'"
+ ),
+ array(
+ array( 'field' => array( null ), 'field2' => null ),
+ LIST_AND,
+ "field IS NULL AND field2 IS NULL"
+ ),
+ array(
+ array( 'field' => 'value', 'field2' => 'value2' ),
+ LIST_OR,
+ "field = 'value' OR field2 = 'value2'"
+ ),
+ array(
+ array( 'field' => 'value', 'field2' => null ),
+ LIST_OR,
+ "field = 'value' OR field2 IS NULL"
+ ),
+ array(
+ array( 'field' => array( 'value', 'value2' ), 'field2' => array( 'value' ) ),
+ LIST_OR,
+ "field IN ('value','value2') OR field2 = 'value'"
+ ),
+ array(
+ array( 'field' => array( null, 'value', null, 'value2' ), "field2 != 'value2'" ),
+ LIST_OR,
+ "(field IN ('value','value2') OR field IS NULL) OR (field2 != 'value2')"
+ ),
+ array(
+ array( 'field' => 'value', 'field2' => 'value2' ),
+ LIST_SET,
+ "field = 'value',field2 = 'value2'"
+ ),
+ array(
+ array( 'field' => 'value', 'field2' => null ),
+ LIST_SET,
+ "field = 'value',field2 = NULL"
+ ),
+ array(
+ array( 'field' => 'value', "field2 != 'value2'" ),
+ LIST_SET,
+ "field = 'value',field2 != 'value2'"
+ ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php
index 98b4ca04..645baf1f 100644
--- a/tests/phpunit/includes/db/DatabaseSqliteTest.php
+++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php
@@ -1,10 +1,12 @@
<?php
-class MockDatabaseSqlite extends DatabaseSqliteStandalone {
+class MockDatabaseSqlite extends DatabaseSqlite {
private $lastQuery;
- function __construct() {
- parent::__construct( ':memory:' );
+ public static function newInstance( array $p = array() ) {
+ $p['dbFilePath'] = ':memory:';
+
+ return new self( $p );
}
function query( $sql, $fname = '', $tempIgnore = false ) {
@@ -36,7 +38,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
if ( !Sqlite::isPresent() ) {
$this->markTestSkipped( 'No SQLite support detected' );
}
- $this->db = new MockDatabaseSqlite();
+ $this->db = MockDatabaseSqlite::newInstance();
if ( version_compare( $this->db->getServerVersion(), '3.6.0', '<' ) ) {
$this->markTestSkipped( "SQLite at least 3.6 required, {$this->db->getServerVersion()} found" );
}
@@ -89,7 +91,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
*/
public function testAddQuotes( $value, $expected ) {
// check quoting
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$this->assertEquals( $expected, $db->addQuotes( $value ), 'string not quoted as expected' );
// ok, quoting works as expected, now try a round trip.
@@ -172,7 +174,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
*/
public function testTableName() {
// @todo Moar!
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$this->assertEquals( 'foo', $db->tableName( 'foo' ) );
$this->assertEquals( 'sqlite_master', $db->tableName( 'sqlite_master' ) );
$db->tablePrefix( 'foo' );
@@ -184,7 +186,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
* @covers DatabaseSqlite::duplicateTableStructure
*/
public function testDuplicateTableStructure() {
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$db->query( 'CREATE TABLE foo(foo, barfoo)' );
$db->duplicateTableStructure( 'foo', 'bar' );
@@ -208,7 +210,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
* @covers DatabaseSqlite::duplicateTableStructure
*/
public function testDuplicateTableStructureVirtual() {
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
if ( $db->getFulltextSearchModule() != 'FTS3' ) {
$this->markTestSkipped( 'FTS3 not supported, cannot create virtual tables' );
}
@@ -231,7 +233,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
* @covers DatabaseSqlite::deleteJoin
*/
public function testDeleteJoin() {
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$db->query( 'CREATE TABLE a (a_1)', __METHOD__ );
$db->query( 'CREATE TABLE b (b_1, b_2)', __METHOD__ );
$db->insert( 'a', array(
@@ -272,7 +274,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
* @todo Currently only checks list of tables
*/
public function testUpgrades() {
- global $IP, $wgVersion, $wgProfileToDatabase;
+ global $IP, $wgVersion, $wgProfiler;
// Versions tested
$versions = array(
@@ -289,9 +291,20 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
'user_newtalk.user_last_timestamp', // r84185
);
- $currentDB = new DatabaseSqliteStandalone( ':memory:' );
+ $currentDB = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$currentDB->sourceFile( "$IP/maintenance/tables.sql" );
- if ( $wgProfileToDatabase ) {
+
+ $profileToDb = false;
+ if ( isset( $wgProfiler['output'] ) ) {
+ $out = $wgProfiler['output'];
+ if ( $out === 'db' ) {
+ $profileToDb = true;
+ } elseif ( is_array( $out ) && in_array( 'db', $out ) ) {
+ $profileToDb = true;
+ }
+ }
+
+ if ( $profileToDb ) {
$currentDB->sourceFile( "$IP/maintenance/sqlite/archives/patch-profiling.sql" );
}
$currentTables = $this->getTables( $currentDB );
@@ -346,7 +359,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
* @covers DatabaseSqlite::insertId
*/
public function testInsertIdType() {
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$databaseCreation = $db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ );
$this->assertInstanceOf( 'ResultWrapper', $databaseCreation, "Database creation" );
@@ -366,7 +379,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
}
global $IP;
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$db->sourceFile( "$IP/tests/phpunit/data/db/sqlite/tables-$version.sql" );
$updater = DatabaseUpdater::newForDB( $db, false, $maint );
$updater->doUpdates( array( 'core' ) );
@@ -429,7 +442,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
public function testCaseInsensitiveLike() {
// TODO: Test this for all databases
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$res = $db->query( 'SELECT "a" LIKE "A" AS a' );
$row = $res->fetchRow();
$this->assertFalse( (bool)$row['a'] );
@@ -439,7 +452,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
* @covers DatabaseSqlite::numFields
*/
public function testNumFields() {
- $db = new DatabaseSqliteStandalone( ':memory:' );
+ $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$databaseCreation = $db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ );
$this->assertInstanceOf( 'ResultWrapper', $databaseCreation, "Failed to create table a" );
diff --git a/tests/phpunit/includes/db/LBFactoryTest.php b/tests/phpunit/includes/db/LBFactoryTest.php
index 4c59f474..81d6840b 100644
--- a/tests/phpunit/includes/db/LBFactoryTest.php
+++ b/tests/phpunit/includes/db/LBFactoryTest.php
@@ -2,7 +2,6 @@
/**
* Holds tests for LBFactory abstract MediaWiki class.
*
- * @section LICENSE
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
diff --git a/tests/phpunit/includes/db/ORMRowTest.php b/tests/phpunit/includes/db/ORMRowTest.php
index 447bf219..807bd14e 100644
--- a/tests/phpunit/includes/db/ORMRowTest.php
+++ b/tests/phpunit/includes/db/ORMRowTest.php
@@ -34,7 +34,6 @@
* that hold the first tests in a pending state awaiting access to the database.
* @group medium
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
abstract class ORMRowTest extends \MediaWikiTestCase {
diff --git a/tests/phpunit/includes/db/ORMTableTest.php b/tests/phpunit/includes/db/ORMTableTest.php
index 7171ee59..338d931f 100644
--- a/tests/phpunit/includes/db/ORMTableTest.php
+++ b/tests/phpunit/includes/db/ORMTableTest.php
@@ -25,14 +25,12 @@
* @group ORM
* @group Database
*
- * @licence GNU GPL v2+
+ * @covers PageORMTableForTesting
+ *
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
* @author Daniel Kinzler
*/
-/**
- * @covers PageORMTableForTesting
- */
class ORMTableTest extends MediaWikiTestCase {
/**
@@ -99,6 +97,10 @@ class ORMTableTest extends MediaWikiTestCase {
class PageORMTableForTesting extends ORMTable {
+ public function __construct() {
+ $this->fieldPrefix = 'page_';
+ }
+
/**
* @see ORMTable::getName
*
@@ -138,13 +140,4 @@ class PageORMTableForTesting extends ORMTable {
'title' => 'str',
);
}
-
- /**
- * @see ORMTable::getFieldPrefix
- *
- * @return string
- */
- protected function getFieldPrefix() {
- return 'page_';
- }
}
diff --git a/tests/phpunit/includes/db/TestORMRowTest.php b/tests/phpunit/includes/db/TestORMRowTest.php
index c9459c90..04bb9f38 100644
--- a/tests/phpunit/includes/db/TestORMRowTest.php
+++ b/tests/phpunit/includes/db/TestORMRowTest.php
@@ -20,27 +20,23 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @since 1.20
- *
* @ingroup Test
- *
- * @group ORM
- *
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+
+/**
* The database group has as a side effect that temporal database tables are created. This makes
* it possible to test without poisoning a production database.
- * @group Database
*
* Some of the tests takes more time, and needs therefor longer time before they can be aborted
* as non-functional. The reason why tests are aborted is assumed to be set up of temporal databases
* that hold the first tests in a pending state awaiting access to the database.
- * @group medium
*
- * @licence GNU GPL v2+
- * @author Jeroen De Dauw < jeroendedauw@gmail.com >
- */
-require_once __DIR__ . "/ORMRowTest.php";
-
-/**
+ * @since 1.20
+ *
+ * @group ORM
+ * @group Database
+ * @group medium
* @covers TestORMRow
*/
class TestORMRowTest extends ORMRowTest {
@@ -150,6 +146,10 @@ class TestORMRow extends ORMRow {
class TestORMTable extends ORMTable {
+ public function __construct() {
+ $this->fieldPrefix = 'test_';
+ }
+
/**
* Returns the name of the database table objects of this type are stored in.
*
@@ -204,15 +204,4 @@ class TestORMTable extends ORMTable {
'time' => 'str', // TS_MW
);
}
-
- /**
- * Gets the db field prefix.
- *
- * @since 1.20
- *
- * @return string
- */
- protected function getFieldPrefix() {
- return 'test_';
- }
}
diff --git a/tests/phpunit/includes/debug/MWDebugTest.php b/tests/phpunit/includes/debug/MWDebugTest.php
index 6e41de75..1abb47e7 100644
--- a/tests/phpunit/includes/debug/MWDebugTest.php
+++ b/tests/phpunit/includes/debug/MWDebugTest.php
@@ -96,16 +96,15 @@ class MWDebugTest extends MediaWikiTestCase {
$apiMain = new ApiMain( $context );
$result = new ApiResult( $apiMain );
- $result->setRawMode( true );
MWDebug::appendDebugInfoToApiResult( $context, $result );
$this->assertInstanceOf( 'ApiResult', $result );
- $data = $result->getData();
+ $data = $result->getResultData();
$expectedKeys = array( 'mwVersion', 'phpEngine', 'phpVersion', 'gitRevision', 'gitBranch',
'gitViewUrl', 'time', 'log', 'debugLog', 'queries', 'request', 'memory',
- 'memoryPeak', 'includes', 'profile', '_element' );
+ 'memoryPeak', 'includes', '_element' );
foreach ( $expectedKeys as $expectedKey ) {
$this->assertArrayHasKey( $expectedKey, $data['debuginfo'], "debuginfo has $expectedKey" );
diff --git a/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php b/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php
new file mode 100644
index 00000000..415fa045
--- /dev/null
+++ b/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Logger;
+
+use MediaWikiTestCase;
+use Psr\Log\LogLevel;
+
+class LegacyLoggerTest extends MediaWikiTestCase {
+
+ /**
+ * @covers LegacyLogger::interpolate
+ * @dataProvider provideInterpolate
+ */
+ public function testInterpolate( $message, $context, $expect ) {
+ $this->assertEquals(
+ $expect, LegacyLogger::interpolate( $message, $context ) );
+ }
+
+ public function provideInterpolate() {
+ return array(
+ array(
+ 'no-op',
+ array(),
+ 'no-op',
+ ),
+ array(
+ 'Hello {world}!',
+ array(
+ 'world' => 'World',
+ ),
+ 'Hello World!',
+ ),
+ array(
+ '{greeting} {user}',
+ array(
+ 'greeting' => 'Goodnight',
+ 'user' => 'Moon',
+ ),
+ 'Goodnight Moon',
+ ),
+ array(
+ 'Oops {key_not_set}',
+ array(),
+ 'Oops {key_not_set}',
+ ),
+ array(
+ '{ not interpolated }',
+ array(
+ 'not interpolated' => 'This should NOT show up in the message',
+ ),
+ '{ not interpolated }',
+ ),
+ );
+ }
+
+ /**
+ * @covers LegacyLogger::shouldEmit
+ * @dataProvider provideShouldEmit
+ */
+ public function testShouldEmit( $level, $config, $expected ) {
+ $this->setMwGlobals( 'wgDebugLogGroups', array( 'fakechannel' => $config ) );
+ $this->assertEquals(
+ $expected,
+ LegacyLogger::shouldEmit( 'fakechannel', 'some message', $level, array() )
+ );
+ }
+
+ public static function provideShouldEmit() {
+ $dest = array( 'destination' => 'foobar' );
+ $tests = array(
+ array(
+ LogLevel::DEBUG,
+ $dest,
+ true
+ ),
+ array(
+ LogLevel::WARNING,
+ $dest + array( 'level' => LogLevel::INFO ),
+ true,
+ ),
+ array(
+ LogLevel::INFO,
+ $dest + array( 'level' => LogLevel::CRITICAL ),
+ false,
+ ),
+ );
+
+ if ( class_exists( '\Monolog\Logger' ) ) {
+ $tests[] = array(
+ \Monolog\Logger::INFO,
+ $dest + array( 'level' => LogLevel::INFO ),
+ true,
+ );
+ $tests[] = array(
+ \Monolog\Logger::WARNING,
+ $dest + array( 'level' => LogLevel::EMERGENCY ),
+ false,
+ );
+ }
+
+ return $tests;
+ }
+
+}
diff --git a/tests/phpunit/includes/LinksUpdateTest.php b/tests/phpunit/includes/deferred/LinksUpdateTest.php
index 02f6b2ab..02f6b2ab 100644
--- a/tests/phpunit/includes/LinksUpdateTest.php
+++ b/tests/phpunit/includes/deferred/LinksUpdateTest.php
diff --git a/tests/phpunit/includes/search/SearchUpdateTest.php b/tests/phpunit/includes/deferred/SearchUpdateTest.php
index c6275371..90438a04 100644
--- a/tests/phpunit/includes/search/SearchUpdateTest.php
+++ b/tests/phpunit/includes/deferred/SearchUpdateTest.php
@@ -17,7 +17,6 @@ class MockSearch extends SearchEngine {
/**
* @group Search
- * @group Database
*/
class SearchUpdateTest extends MediaWikiTestCase {
@@ -67,9 +66,10 @@ EOT
/**
* @covers SearchUpdate::updateText
- * @todo give this test a real name explaining what is being tested here
+ * Test bug 32712
+ * Test if unicode quotes in article links make its search index empty
*/
- public function testBug32712() {
+ public function testUnicodeLinkSearchIndexError() {
$text = "text „http://example.com“ text";
$result = $this->updateText( $text );
$processed = preg_replace( '/Q/u', 'Q', $result );
diff --git a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
index 188ad3fd..3bea9b31 100644
--- a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
+++ b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
@@ -1,7 +1,6 @@
<?php
/**
- * @licence GNU GPL v2+
* @author Adam Shorland
*
* @group Diff
diff --git a/tests/phpunit/includes/diff/DiffOpTest.php b/tests/phpunit/includes/diff/DiffOpTest.php
index d89b89fe..cbe05732 100644
--- a/tests/phpunit/includes/diff/DiffOpTest.php
+++ b/tests/phpunit/includes/diff/DiffOpTest.php
@@ -1,10 +1,5 @@
<?php
-
-//Load our FakeDiffOp
-require_once __DIR__ . DIRECTORY_SEPARATOR . 'FakeDiffOp.php';
-
/**
- * @licence GNU GPL v2+
* @author Adam Shorland
*
* @group Diff
diff --git a/tests/phpunit/includes/diff/DiffTest.php b/tests/phpunit/includes/diff/DiffTest.php
index 1911c82a..e0d79157 100644
--- a/tests/phpunit/includes/diff/DiffTest.php
+++ b/tests/phpunit/includes/diff/DiffTest.php
@@ -1,7 +1,6 @@
<?php
/**
- * @licence GNU GPL v2+
* @author Adam Shorland
*
* @group Diff
diff --git a/tests/phpunit/includes/diff/DifferenceEngineTest.php b/tests/phpunit/includes/diff/DifferenceEngineTest.php
index 5474b963..0f599af1 100644
--- a/tests/phpunit/includes/diff/DifferenceEngineTest.php
+++ b/tests/phpunit/includes/diff/DifferenceEngineTest.php
@@ -8,7 +8,6 @@
* @group Database
* @group Diff
*
- * @licence GNU GPL v2+
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class DifferenceEngineTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/exception/BadTitleErrorTest.php b/tests/phpunit/includes/exception/BadTitleErrorTest.php
index 003efd27..500b7e48 100644
--- a/tests/phpunit/includes/exception/BadTitleErrorTest.php
+++ b/tests/phpunit/includes/exception/BadTitleErrorTest.php
@@ -5,23 +5,8 @@
*/
class BadTitleErrorTest extends MediaWikiTestCase {
- protected $wgOut;
-
- protected function setUp() {
- parent::setUp();
- global $wgOut;
- $this->wgOut = clone $wgOut;
- }
-
- protected function tearDown() {
- parent::tearDown();
- global $wgOut;
- $wgOut = $this->wgOut;
- }
-
public function testExceptionSetsStatusCode() {
- global $wgOut;
- $wgOut = $this->getMockWgOut();
+ $this->setMwGlobals( 'wgOut', $this->getMockWgOut() );
try {
throw new BadTitleError();
} catch ( BadTitleError $e ) {
diff --git a/tests/phpunit/includes/exception/ErrorPageErrorTest.php b/tests/phpunit/includes/exception/ErrorPageErrorTest.php
index 13dcf33b..9c4e4a0b 100644
--- a/tests/phpunit/includes/exception/ErrorPageErrorTest.php
+++ b/tests/phpunit/includes/exception/ErrorPageErrorTest.php
@@ -6,20 +6,6 @@
*/
class ErrorPageErrorTest extends MediaWikiTestCase {
- private $wgOut;
-
- protected function setUp() {
- parent::setUp();
- global $wgOut;
- $this->wgOut = clone $wgOut;
- }
-
- protected function tearDown() {
- global $wgOut;
- $wgOut = $this->wgOut;
- parent::tearDown();
- }
-
private function getMockMessage() {
$mockMessage = $this->getMockBuilder( 'Message' )
->disableOriginalConstructor()
@@ -48,20 +34,18 @@ class ErrorPageErrorTest extends MediaWikiTestCase {
$title = 'Foo';
$params = array( 'Baz' );
- global $wgOut;
- $wgOut = $this->getMockBuilder( 'OutputPage' )
+ $mock = $this->getMockBuilder( 'OutputPage' )
->disableOriginalConstructor()
->getMock();
- $wgOut->expects( $this->once() )
+ $mock->expects( $this->once() )
->method( 'showErrorPage' )
->with( $title, $mockMessage, $params );
- $wgOut->expects( $this->once() )
+ $mock->expects( $this->once() )
->method( 'output' );
+ $this->setMwGlobals( 'wgOut', $mock );
$e = new ErrorPageError( $title, $mockMessage, $params );
$e->report();
}
-
-
}
diff --git a/tests/phpunit/includes/exception/MWExceptionHandlerTest.php b/tests/phpunit/includes/exception/MWExceptionHandlerTest.php
index dc5dc6aa..d73f17d9 100644
--- a/tests/phpunit/includes/exception/MWExceptionHandlerTest.php
+++ b/tests/phpunit/includes/exception/MWExceptionHandlerTest.php
@@ -15,7 +15,7 @@ class MWExceptionHandlerTest extends MediaWikiTestCase {
$refvar = 'value';
try {
$array = array( 'a', 'b' );
- $object = new StdClass();
+ $object = new stdClass();
self::helperThrowAnException( $array, $object, $refvar );
} catch ( Exception $e ) {
}
diff --git a/tests/phpunit/includes/exception/ThrottledErrorTest.php b/tests/phpunit/includes/exception/ThrottledErrorTest.php
index bdb143fa..a1cf84bc 100644
--- a/tests/phpunit/includes/exception/ThrottledErrorTest.php
+++ b/tests/phpunit/includes/exception/ThrottledErrorTest.php
@@ -6,23 +6,8 @@
*/
class ThrottledErrorTest extends MediaWikiTestCase {
- protected $wgOut;
-
- protected function setUp() {
- parent::setUp();
- global $wgOut;
- $this->wgOut = clone $wgOut;
- }
-
- protected function tearDown() {
- parent::tearDown();
- global $wgOut;
- $wgOut = $this->wgOut;
- }
-
public function testExceptionSetsStatusCode() {
- global $wgOut;
- $wgOut = $this->getMockWgOut();
+ $this->setMwGlobals( 'wgOut', $this->getMockWgOut() );
try {
throw new ThrottledError();
} catch ( ThrottledError $e ) {
diff --git a/tests/phpunit/includes/ExternalStoreTest.php b/tests/phpunit/includes/externalstore/ExternalStoreTest.php
index 07c2957c..07c2957c 100644
--- a/tests/phpunit/includes/ExternalStoreTest.php
+++ b/tests/phpunit/includes/externalstore/ExternalStoreTest.php
diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php b/tests/phpunit/includes/filebackend/FileBackendTest.php
index 9558cc7d..bfca75ad 100644
--- a/tests/phpunit/includes/filebackend/FileBackendTest.php
+++ b/tests/phpunit/includes/filebackend/FileBackendTest.php
@@ -13,14 +13,13 @@ class FileBackendTest extends MediaWikiTestCase {
private $multiBackend;
/** @var FSFileBackend */
public $singleBackend;
- private $filesToPrune = array();
private static $backendToUse;
protected function setUp() {
global $wgFileBackends;
parent::setUp();
$uniqueId = time() . '-' . mt_rand();
- $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . $uniqueId;
+ $tmpDir = $this->getNewTempDirectory();
if ( $this->getCliArg( 'use-filebackend' ) ) {
if ( self::$backendToUse ) {
$this->singleBackend = self::$backendToUse;
@@ -51,8 +50,8 @@ class FileBackendTest extends MediaWikiTestCase {
'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
'wikiId' => wfWikiID(),
'containerPaths' => array(
- 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
- 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
+ 'unittest-cont1' => "{$tmpDir}/localtesting-cont1",
+ 'unittest-cont2' => "{$tmpDir}/localtesting-cont2" )
) );
}
$this->multiBackend = new FileBackendMultiWrite( array(
@@ -65,21 +64,20 @@ class FileBackendTest extends MediaWikiTestCase {
'name' => 'localmultitesting1',
'class' => 'FSFileBackend',
'containerPaths' => array(
- 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
- 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
+ 'unittest-cont1' => "{$tmpDir}/localtestingmulti1-cont1",
+ 'unittest-cont2' => "{$tmpDir}/localtestingmulti1-cont2" ),
'isMultiMaster' => false
),
array(
'name' => 'localmultitesting2',
'class' => 'FSFileBackend',
'containerPaths' => array(
- 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
- 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
+ 'unittest-cont1' => "{$tmpDir}/localtestingmulti2-cont1",
+ 'unittest-cont2' => "{$tmpDir}/localtestingmulti2-cont2" ),
'isMultiMaster' => true
)
)
) );
- $this->filesToPrune = array();
}
private static function baseStorePath() {
@@ -214,7 +212,7 @@ class FileBackendTest extends MediaWikiTestCase {
* @dataProvider provider_testStore
*/
public function testStore( $op ) {
- $this->filesToPrune[] = $op['src'];
+ $this->addTmpFiles( $op['src'] );
$this->backend = $this->singleBackend;
$this->tearDownFiles();
@@ -224,7 +222,6 @@ class FileBackendTest extends MediaWikiTestCase {
$this->backend = $this->multiBackend;
$this->tearDownFiles();
$this->doTestStore( $op );
- $this->filesToPrune[] = $op['src']; # avoid file leaking
$this->tearDownFiles();
}
@@ -275,27 +272,15 @@ class FileBackendTest extends MediaWikiTestCase {
$tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
$toPath = self::baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
$op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
- $cases[] = array(
- $op, // operation
- $tmpName, // source
- $toPath, // dest
- );
+ $cases[] = array( $op );
$op2 = $op;
$op2['overwrite'] = true;
- $cases[] = array(
- $op2, // operation
- $tmpName, // source
- $toPath, // dest
- );
+ $cases[] = array( $op2 );
- $op2 = $op;
- $op2['overwriteSame'] = true;
- $cases[] = array(
- $op2, // operation
- $tmpName, // source
- $toPath, // dest
- );
+ $op3 = $op;
+ $op3['overwriteSame'] = true;
+ $cases[] = array( $op3 );
return $cases;
}
@@ -948,18 +933,14 @@ class FileBackendTest extends MediaWikiTestCase {
* @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->filesToPrune[] = $op['dst']; # avoid file leaking
$this->tearDownFiles();
$this->backend = $this->multiBackend;
$this->tearDownFiles();
$this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
- $this->filesToPrune[] = $op['dst']; # avoid file leaking
$this->tearDownFiles();
}
@@ -983,7 +964,7 @@ class FileBackendTest extends MediaWikiTestCase {
$this->assertGoodStatus( $status,
"Creation of source files succeeded ($backendName)." );
- $dest = $params['dst'];
+ $dest = $params['dst'] = $this->getNewTempFile();
if ( $alreadyExists ) {
$ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
$this->assertEquals( true, $ok,
@@ -1029,8 +1010,6 @@ class FileBackendTest extends MediaWikiTestCase {
public static function provider_testConcatenate() {
$cases = array();
- $rand = mt_rand( 0, 2000000000 ) . time();
- $dest = wfTempDir() . "/randomfile!$rand.txt";
$srcs = array(
self::baseStorePath() . '/unittest-cont1/e/file1.txt',
self::baseStorePath() . '/unittest-cont1/e/file2.txt',
@@ -1055,7 +1034,7 @@ class FileBackendTest extends MediaWikiTestCase {
'lkaem;a',
'legma'
);
- $params = array( 'srcs' => $srcs, 'dst' => $dest );
+ $params = array( 'srcs' => $srcs );
$cases[] = array(
$params, // operation
@@ -1499,7 +1478,7 @@ class FileBackendTest extends MediaWikiTestCase {
$url = $this->backend->getFileHttpUrl( array( 'src' => $source ) );
if ( $url !== null ) { // supported
- $data = Http::request( "GET", $url );
+ $data = Http::request( "GET", $url, array(), __METHOD__ );
$this->assertEquals( $content, $data,
"HTTP GET of URL has right contents ($backendName)." );
}
@@ -1761,16 +1740,13 @@ class FileBackendTest extends MediaWikiTestCase {
$fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
$tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath();
- file_put_contents( $tmpNameA, $fileAContents );
$tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath();
- file_put_contents( $tmpNameB, $fileBContents );
$tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath();
+ $this->addTmpFiles( array( $tmpNameA, $tmpNameB, $tmpNameC ) );
+ file_put_contents( $tmpNameA, $fileAContents );
+ file_put_contents( $tmpNameB, $fileBContents );
file_put_contents( $tmpNameC, $fileCContents );
- $this->filesToPrune[] = $tmpNameA; # avoid file leaking
- $this->filesToPrune[] = $tmpNameB; # avoid file leaking
- $this->filesToPrune[] = $tmpNameC; # avoid file leaking
-
$fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
$fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
$fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
@@ -2434,16 +2410,10 @@ class FileBackendTest extends MediaWikiTestCase {
}
function tearDownFiles() {
- foreach ( $this->filesToPrune as $file ) {
- if ( is_file( $file ) ) {
- unlink( $file );
- }
- }
$containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont-bad' );
foreach ( $containers as $container ) {
$this->deleteFiles( $container );
}
- $this->filesToPrune = array();
}
private function deleteFiles( $container ) {
diff --git a/tests/phpunit/includes/filerepo/StoreBatchTest.php b/tests/phpunit/includes/filerepo/StoreBatchTest.php
index 9cc2efbf..86bfe123 100644
--- a/tests/phpunit/includes/filerepo/StoreBatchTest.php
+++ b/tests/phpunit/includes/filerepo/StoreBatchTest.php
@@ -16,7 +16,7 @@ class StoreBatchTest extends MediaWikiTestCase {
parent::setUp();
# Forge a FSRepo object to not have to rely on local wiki settings
- $tmpPrefix = wfTempDir() . '/storebatch-test-' . time() . '-' . mt_rand();
+ $tmpPrefix = $this->getNewTempDirectory();
if ( $this->getCliArg( 'use-filebackend' ) ) {
$name = $this->getCliArg( 'use-filebackend' );
$useConfig = array();
@@ -35,10 +35,10 @@ class StoreBatchTest extends MediaWikiTestCase {
'name' => 'local-testing',
'wikiId' => wfWikiID(),
'containerPaths' => array(
- 'unittests-public' => "{$tmpPrefix}-public",
- 'unittests-thumb' => "{$tmpPrefix}-thumb",
- 'unittests-temp' => "{$tmpPrefix}-temp",
- 'unittests-deleted' => "{$tmpPrefix}-deleted",
+ 'unittests-public' => "{$tmpPrefix}/public",
+ 'unittests-thumb' => "{$tmpPrefix}/thumb",
+ 'unittests-temp' => "{$tmpPrefix}/temp",
+ 'unittests-deleted' => "{$tmpPrefix}/deleted",
)
) );
}
@@ -52,13 +52,8 @@ class StoreBatchTest extends MediaWikiTestCase {
}
protected 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 ) );
- }
- }
+ // Delete files
+ $this->repo->cleanupBatch( $this->createdFiles );
parent::tearDown();
}
diff --git a/tests/phpunit/includes/LocalFileTest.php b/tests/phpunit/includes/filerepo/file/LocalFileTest.php
index 5c5052e4..3c5754bf 100644
--- a/tests/phpunit/includes/LocalFileTest.php
+++ b/tests/phpunit/includes/filerepo/file/LocalFileTest.php
@@ -2,7 +2,6 @@
/**
* These tests should work regardless of $wgCapitalLinks
- * @group Database
* @todo Split tests into providers and test methods
*/
diff --git a/tests/phpunit/includes/installer/DatabaseUpdaterTest.php b/tests/phpunit/includes/installer/DatabaseUpdaterTest.php
new file mode 100644
index 00000000..abff3e68
--- /dev/null
+++ b/tests/phpunit/includes/installer/DatabaseUpdaterTest.php
@@ -0,0 +1,279 @@
+<?php
+
+class DatabaseUpdaterTest extends MediaWikiTestCase {
+
+ public function testSetAppliedUpdates() {
+ $db = new FakeDatabase();
+ $dbu = new FakeDatabaseUpdater( $db );
+ $dbu->setAppliedUpdates( "test", array() );
+ $expected = "updatelist-test-" . time() . "0";
+ $actual = $db->lastInsertData['ul_key'];
+ $this->assertEquals( $expected, $actual, var_export( $db->lastInsertData, true ) );
+ $dbu->setAppliedUpdates( "test", array() );
+ $expected = "updatelist-test-" . time() . "1";
+ $actual = $db->lastInsertData['ul_key'];
+ $this->assertEquals( $expected, $actual, var_export( $db->lastInsertData, true ) );
+ }
+}
+
+class FakeDatabase extends DatabaseBase {
+ public $lastInsertTable;
+ public $lastInsertData;
+
+ function __construct() {
+ }
+
+ function clearFlag( $arg ) {
+ }
+
+ function setFlag( $arg ) {
+ }
+
+ public function insert( $table, $a, $fname = __METHOD__, $options = array() ) {
+ $this->lastInsertTable = $table;
+ $this->lastInsertData = $a;
+ }
+
+ /**
+ * Get the type of the DBMS, as it appears in $wgDBtype.
+ *
+ * @return string
+ */
+ function getType() {
+ // TODO: Implement getType() method.
+ }
+
+ /**
+ * Open a connection to the database. Usually aborts on failure
+ *
+ * @param string $server Database server host
+ * @param string $user Database user name
+ * @param string $password Database user password
+ * @param string $dbName Database name
+ * @return bool
+ * @throws DBConnectionError
+ */
+ function open( $server, $user, $password, $dbName ) {
+ // TODO: Implement open() method.
+ }
+
+ /**
+ * Fetch the next row from the given result object, in object form.
+ * Fields can be retrieved with $row->fieldname, with fields acting like
+ * member variables.
+ * If no more rows are available, false is returned.
+ *
+ * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc.
+ * @return stdClass|bool
+ * @throws DBUnexpectedError Thrown if the database returns an error
+ */
+ function fetchObject( $res ) {
+ // TODO: Implement fetchObject() method.
+ }
+
+ /**
+ * Fetch the next row from the given result object, in associative array
+ * form. Fields are retrieved with $row['fieldname'].
+ * If no more rows are available, false is returned.
+ *
+ * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc.
+ * @return array|bool
+ * @throws DBUnexpectedError Thrown if the database returns an error
+ */
+ function fetchRow( $res ) {
+ // TODO: Implement fetchRow() method.
+ }
+
+ /**
+ * Get the number of rows in a result object
+ *
+ * @param mixed $res A SQL result
+ * @return int
+ */
+ function numRows( $res ) {
+ // TODO: Implement numRows() method.
+ }
+
+ /**
+ * Get the number of fields in a result object
+ * @see http://www.php.net/mysql_num_fields
+ *
+ * @param mixed $res A SQL result
+ * @return int
+ */
+ function numFields( $res ) {
+ // TODO: Implement numFields() method.
+ }
+
+ /**
+ * Get a field name in a result object
+ * @see http://www.php.net/mysql_field_name
+ *
+ * @param mixed $res A SQL result
+ * @param int $n
+ * @return string
+ */
+ function fieldName( $res, $n ) {
+ // TODO: Implement fieldName() method.
+ }
+
+ /**
+ * Get the inserted value of an auto-increment row
+ *
+ * The value inserted should be fetched from nextSequenceValue()
+ *
+ * Example:
+ * $id = $dbw->nextSequenceValue( 'page_page_id_seq' );
+ * $dbw->insert( 'page', array( 'page_id' => $id ) );
+ * $id = $dbw->insertId();
+ *
+ * @return int
+ */
+ function insertId() {
+ // TODO: Implement insertId() method.
+ }
+
+ /**
+ * Change the position of the cursor in a result object
+ * @see http://www.php.net/mysql_data_seek
+ *
+ * @param mixed $res A SQL result
+ * @param int $row
+ */
+ function dataSeek( $res, $row ) {
+ // TODO: Implement dataSeek() method.
+ }
+
+ /**
+ * Get the last error number
+ * @see http://www.php.net/mysql_errno
+ *
+ * @return int
+ */
+ function lastErrno() {
+ // TODO: Implement lastErrno() method.
+ }
+
+ /**
+ * Get a description of the last error
+ * @see http://www.php.net/mysql_error
+ *
+ * @return string
+ */
+ function lastError() {
+ // TODO: Implement lastError() method.
+ }
+
+ /**
+ * mysql_fetch_field() wrapper
+ * Returns false if the field doesn't exist
+ *
+ * @param string $table Table name
+ * @param string $field Field name
+ *
+ * @return Field
+ */
+ function fieldInfo( $table, $field ) {
+ // TODO: Implement fieldInfo() method.
+ }
+
+ /**
+ * Get information about an index into an object
+ * @param string $table Table name
+ * @param string $index Index name
+ * @param string $fname Calling function name
+ * @return mixed Database-specific index description class or false if the index does not exist
+ */
+ function indexInfo( $table, $index, $fname = __METHOD__ ) {
+ // TODO: Implement indexInfo() method.
+ }
+
+ /**
+ * Get the number of rows affected by the last write query
+ * @see http://www.php.net/mysql_affected_rows
+ *
+ * @return int
+ */
+ function affectedRows() {
+ // TODO: Implement affectedRows() method.
+ }
+
+ /**
+ * Wrapper for addslashes()
+ *
+ * @param string $s String to be slashed.
+ * @return string Slashed string.
+ */
+ function strencode( $s ) {
+ // TODO: Implement strencode() method.
+ }
+
+ /**
+ * Returns a wikitext link to the DB's website, e.g.,
+ * return "[http://www.mysql.com/ MySQL]";
+ * Should at least contain plain text, if for some reason
+ * your database has no website.
+ *
+ * @return string Wikitext of a link to the server software's web site
+ */
+ function getSoftwareLink() {
+ // TODO: Implement getSoftwareLink() method.
+ }
+
+ /**
+ * A string describing the current software version, like from
+ * mysql_get_server_info().
+ *
+ * @return string Version information from the database server.
+ */
+ function getServerVersion() {
+ // TODO: Implement getServerVersion() method.
+ }
+
+ /**
+ * Closes underlying database connection
+ * @since 1.20
+ * @return bool Whether connection was closed successfully
+ */
+ protected function closeConnection() {
+ // TODO: Implement closeConnection() method.
+ }
+
+ /**
+ * The DBMS-dependent part of query()
+ *
+ * @param string $sql SQL query.
+ * @return ResultWrapper|bool Result object to feed to fetchObject,
+ * fetchRow, ...; or false on failure
+ */
+ protected function doQuery( $sql ) {
+ // TODO: Implement doQuery() method.
+ }
+}
+
+class FakeDatabaseUpdater extends DatabaseUpdater {
+ function __construct( $db ) {
+ $this->db = $db;
+ self::$updateCounter = 0;
+ }
+
+ /**
+ * Get an array of updates to perform on the database. Should return a
+ * multi-dimensional array. The main key is the MediaWiki version (1.12,
+ * 1.13...) with the values being arrays of updates, identical to how
+ * updaters.inc did it (for now)
+ *
+ * @return array
+ */
+ protected function getCoreUpdateList() {
+ return array();
+ }
+
+ public function canUseNewUpdatelog() {
+ return true;
+ }
+
+ public function setAppliedUpdates( $version, $updates = array() ) {
+ parent::setAppliedUpdates( $version, $updates );
+ }
+}
diff --git a/tests/phpunit/includes/installer/InstallDocFormatterTest.php b/tests/phpunit/includes/installer/InstallDocFormatterTest.php
index 064d5185..724f0c88 100644
--- a/tests/phpunit/includes/installer/InstallDocFormatterTest.php
+++ b/tests/phpunit/includes/installer/InstallDocFormatterTest.php
@@ -34,6 +34,21 @@ class InstallDocFormatterTest extends MediaWikiTestCase {
array( ':One indentation', "\tOne indentation", 'Replacing a single \t' ),
array( '::Two indentations', "\t\tTwo indentations", 'Replacing 2 x \t' ),
+ # Transform 'T123' links
+ array(
+ '<span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>',
+ 'T123', 'Testing T123 links' ),
+ array(
+ 'bug <span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>',
+ 'bug T123', 'Testing bug T123 links' ),
+ array(
+ '(<span class="config-plainlink">[https://phabricator.wikimedia.org/T987654 T987654]</span>)',
+ '(T987654)', 'Testing (T987654) links' ),
+
+ # "Tabc" shouldn't work
+ array( 'Tfoobar', 'Tfoobar', "Don't match T followed by non-digits" ),
+ array( 'T!!fakefake!!', 'T!!fakefake!!', "Don't match T followed by non-digits" ),
+
# Transform 'bug 123' links
array(
'<span class="config-plainlink">[https://bugzilla.wikimedia.org/123 bug 123]</span>',
diff --git a/tests/phpunit/includes/jobqueue/JobQueueTest.php b/tests/phpunit/includes/jobqueue/JobQueueTest.php
index 69e40068..ea1a4f63 100644
--- a/tests/phpunit/includes/jobqueue/JobQueueTest.php
+++ b/tests/phpunit/includes/jobqueue/JobQueueTest.php
@@ -247,8 +247,13 @@ class JobQueueTest extends MediaWikiTestCase {
$this->assertNull( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" );
}
$queue->deduplicateRootJob( $this->newJob( 0, $root1 ) );
- sleep( 1 ); // roo job timestamp will increase
- $root2 = Job::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
+
+ $root2 = $root1;
+ # Add a second to UNIX epoch and format back to TS_MW
+ $root2_ts = strtotime( $root2['rootJobTimestamp'] );
+ $root2_ts++;
+ $root2['rootJobTimestamp'] = wfTimestamp( TS_MW, $root2_ts );
+
$this->assertNotEquals( $root1['rootJobTimestamp'], $root2['rootJobTimestamp'],
"Root job signatures have different timestamps." );
for ( $i = 0; $i < 5; ++$i ) {
diff --git a/tests/phpunit/includes/jobqueue/JobTest.php b/tests/phpunit/includes/jobqueue/JobTest.php
new file mode 100644
index 00000000..93069d2e
--- /dev/null
+++ b/tests/phpunit/includes/jobqueue/JobTest.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @author Adam Shorland
+ */
+class JobTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provideTestToString
+ *
+ * @param Job $job
+ * @param string $expected
+ *
+ * @covers Job::toString
+ */
+ public function testToString( $job, $expected ) {
+ $this->assertEquals( $expected, $job->toString() );
+ }
+
+ public function provideTestToString() {
+ $mockToStringObj = $this->getMock( 'stdClass', array( '__toString' ) );
+ $mockToStringObj->expects( $this->any() )
+ ->method( '__toString' )
+ ->will( $this->returnValue( '{STRING_OBJ_VAL}' ) );
+
+ return array(
+ array(
+ $this->getMockJob( false ),
+ 'someCommand '
+ ),
+ array(
+ $this->getMockJob( array( 'key' => 'val' ) ),
+ 'someCommand key=val'
+ ),
+ array(
+ $this->getMockJob( array( 'key' => array( 'inkey' => 'inval' ) ) ),
+ 'someCommand key={"inkey":"inval"}'
+ ),
+ array(
+ $this->getMockJob( array( 'val1' ) ),
+ 'someCommand 0=val1'
+ ),
+ array(
+ $this->getMockJob( array( 'val1', 'val2' ) ),
+ 'someCommand 0=val1 1=val2'
+ ),
+ array(
+ $this->getMockJob( array( new stdClass() ) ),
+ 'someCommand 0=object(stdClass)'
+ ),
+ array(
+ $this->getMockJob( array( $mockToStringObj ) ),
+ 'someCommand 0={STRING_OBJ_VAL}'
+ ),
+ );
+ }
+
+ public function getMockJob( $params ) {
+ $mock = $this->getMockForAbstractClass(
+ 'Job',
+ array( 'someCommand', new Title(), $params ),
+ 'SomeJob'
+ );
+ return $mock;
+ }
+
+}
diff --git a/tests/phpunit/includes/json/FormatJsonTest.php b/tests/phpunit/includes/json/FormatJsonTest.php
index af68ab03..f0ac6acc 100644
--- a/tests/phpunit/includes/json/FormatJsonTest.php
+++ b/tests/phpunit/includes/json/FormatJsonTest.php
@@ -169,12 +169,30 @@ class FormatJsonTest extends MediaWikiTestCase {
$this->assertEquals( $value, $st->getValue() );
}
+ /**
+ * Test data for testParseTryFixing.
+ *
+ * Some PHP interpreters use json-c rather than the JSON.org cannonical
+ * parser to avoid being encumbered by the "shall be used for Good, not
+ * Evil" clause of the JSON.org parser's license. By default, json-c
+ * parses in a non-strict mode which allows trailing commas for array and
+ * object delarations among other things, so our JSON_ERROR_SYNTAX rescue
+ * block is not always triggered. It however isn't lenient in exactly the
+ * same ways as our TRY_FIXING mode, so the assertions in this test are
+ * a bit more complicated than they ideally would be:
+ *
+ * Optional third argument: true if json-c parses the value without
+ * intervention, false otherwise. Defaults to true.
+ *
+ * Optional fourth argument: expected cannonical JSON serialization of
+ * json-c parsed result. Defaults to the second argument's value.
+ */
public static function provideParseTryFixing() {
return array(
- array( "[,]", '[]' ),
- array( "[ , ]", '[]' ),
+ array( "[,]", '[]', false ),
+ array( "[ , ]", '[]', false ),
array( "[ , }", false ),
- array( '[1],', false ),
+ array( '[1],', false, true, '[1]' ),
array( "[1,]", '[1]' ),
array( "[1\n,]", '[1]' ),
array( "[1,\n]", '[1]' ),
@@ -182,24 +200,44 @@ class FormatJsonTest extends MediaWikiTestCase {
array( "[1\n,\n]\n", '[1]' ),
array( '["a,",]', '["a,"]' ),
array( "[[1,]\n,[2,\n],[3\n,]]", '[[1],[2],[3]]' ),
- array( '[[1,],[2,],[3,]]', false ), // I wish we could parse this, but would need quote parsing
- array( '[1,,]', false ),
+ // I wish we could parse this, but would need quote parsing
+ array( '[[1,],[2,],[3,]]', false, true, '[[1],[2],[3]]' ),
+ array( '[1,,]', false, false, '[1]' ),
);
}
/**
* @dataProvider provideParseTryFixing
* @param string $value
- * @param string|bool $expected
+ * @param string|bool $expected Expected result with strict parser
+ * @param bool $jsoncParses Will json-c parse this value without TRY_FIXING?
+ * @param string|bool $expectedJsonc Expected result with lenient parser
+ * if different from the strict expectation
*/
- public function testParseTryFixing( $value, $expected ) {
+ public function testParseTryFixing(
+ $value, $expected,
+ $jsoncParses = true, $expectedJsonc = null
+ ) {
+ // PHP5 results are always expected to have isGood() === false
+ $expectedGoodStatus = false;
+
+ // Check to see if json parser allows trailing commas
+ if ( json_decode( '[1,]' ) !== null ) {
+ // Use json-c specific expected result if provided
+ $expected = ( $expectedJsonc === null ) ? $expected : $expectedJsonc;
+ // If json-c parses the value natively, expect isGood() === true
+ $expectedGoodStatus = $jsoncParses;
+ }
+
$st = FormatJson::parse( $value, FormatJson::TRY_FIXING );
$this->assertType( 'Status', $st );
if ( $expected === false ) {
- $this->assertFalse( $st->isOK() );
+ $this->assertFalse( $st->isOK(), 'Expected isOK() == false' );
} else {
- $this->assertFalse( $st->isGood() );
- $this->assertTrue( $st->isOK() );
+ $this->assertSame( $expectedGoodStatus, $st->isGood(),
+ 'Expected isGood() == ' . ( $expectedGoodStatus ? 'true' : 'false' )
+ );
+ $this->assertTrue( $st->isOK(), 'Expected isOK == true' );
$val = FormatJson::encode( $st->getValue(), false, FormatJson::ALL_OK );
$this->assertEquals( $expected, $val );
}
@@ -222,6 +260,64 @@ class FormatJsonTest extends MediaWikiTestCase {
$this->assertFalse( $st->isOK() );
}
+ public function provideStripComments() {
+ return array(
+ array( '{"a":"b"}', '{"a":"b"}' ),
+ array( "{\"a\":\"b\"}\n", "{\"a\":\"b\"}\n" ),
+ array( '/*c*/{"c":"b"}', '{"c":"b"}' ),
+ array( '{"a":"c"}/*c*/', '{"a":"c"}' ),
+ array( '/*c//d*/{"c":"b"}', '{"c":"b"}' ),
+ array( '{/*c*/"c":"b"}', '{"c":"b"}' ),
+ array( "/*\nc\r\n*/{\"c\":\"b\"}", '{"c":"b"}' ),
+ array( "//c\n{\"c\":\"b\"}", '{"c":"b"}' ),
+ array( "//c\r\n{\"c\":\"b\"}", '{"c":"b"}' ),
+ array( '{"a":"c"}//c', '{"a":"c"}' ),
+ array( "{\"a-c\"://c\n\"b\"}", '{"a-c":"b"}' ),
+ array( '{"/*a":"b"}', '{"/*a":"b"}' ),
+ array( '{"a":"//b"}', '{"a":"//b"}' ),
+ array( '{"a":"b/*c*/"}', '{"a":"b/*c*/"}' ),
+ array( "{\"\\\"/*a\":\"b\"}", "{\"\\\"/*a\":\"b\"}" ),
+ array( '', '' ),
+ array( '/*c', '' ),
+ array( '//c', '' ),
+ array( '"http://example.com"', '"http://example.com"' ),
+ array( "\0", "\0" ),
+ array( '"Blåbærsyltetøy"', '"Blåbærsyltetøy"' ),
+ );
+ }
+
+ /**
+ * @covers FormatJson::stripComments
+ * @dataProvider provideStripComments
+ * @param string $json
+ * @param string $expect
+ */
+ public function testStripComments( $json, $expect ) {
+ $this->assertSame( $expect, FormatJson::stripComments( $json ) );
+ }
+
+ public function provideParseStripComments() {
+ return array(
+ array( '/* blah */true', true ),
+ array( "// blah \ntrue", true ),
+ array( '[ "a" , /* blah */ "b" ]', array( 'a', 'b' ) ),
+ );
+ }
+
+ /**
+ * @covers FormatJson::parse
+ * @covers FormatJson::stripComments
+ * @dataProvider provideParseStripComments
+ * @param string $json
+ * @param mixed $expect
+ */
+ public function testParseStripComments( $json, $expect ) {
+ $st = FormatJson::parse( $json, FormatJson::STRIP_COMMENTS );
+ $this->assertType( 'Status', $st );
+ $this->assertTrue( $st->isGood() );
+ $this->assertEquals( $expect, $st->getValue() );
+ }
+
/**
* Generate a set of test cases for a particular combination of encoder options.
*
diff --git a/tests/phpunit/includes/ArrayUtilsTest.php b/tests/phpunit/includes/libs/ArrayUtilsTest.php
index 7bdb1ca4..b5ea7b72 100644
--- a/tests/phpunit/includes/ArrayUtilsTest.php
+++ b/tests/phpunit/includes/libs/ArrayUtilsTest.php
@@ -5,7 +5,7 @@
* @group Database
*/
-class ArrayUtilsTest extends MediaWikiTestCase {
+class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
private $search;
/**
diff --git a/tests/phpunit/includes/libs/CSSMinTest.php b/tests/phpunit/includes/libs/CSSMinTest.php
index 43c50869..6142f967 100644
--- a/tests/phpunit/includes/libs/CSSMinTest.php
+++ b/tests/phpunit/includes/libs/CSSMinTest.php
@@ -141,15 +141,57 @@ class CSSMinTest extends MediaWikiTestCase {
);
}
+ public static function provideIsRemoteUrl() {
+ return array(
+ array( true, 'http://localhost/w/red.gif?123' ),
+ array( true, 'https://example.org/x.png' ),
+ array( true, '//example.org/x.y.z/image.png' ),
+ array( true, '//localhost/styles.css?query=yes' ),
+ array( true, 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=' ),
+ array( false, 'x.gif' ),
+ array( false, '/x.gif' ),
+ array( false, './x.gif' ),
+ array( false, '../x.gif' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideIsRemoteUrl
+ * @cover CSSMin::isRemoteUrl
+ */
+ public function testIsRemoteUrl( $expect, $url ) {
+ $this->assertEquals( CSSMin::isRemoteUrl( $url ), $expect );
+ }
+
+ public static function provideIsLocalUrls() {
+ return array(
+ array( false, 'x.gif' ),
+ array( true, '/x.gif' ),
+ array( false, './x.gif' ),
+ array( false, '../x.gif' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideIsLocalUrls
+ * @cover CSSMin::isLocalUrl
+ */
+ public function testIsLocalUrl( $expect, $url ) {
+ $this->assertEquals( CSSMin::isLocalUrl( $url ), $expect );
+ }
+
public static function provideRemapRemappingCases() {
// red.gif and green.gif are one-pixel 35-byte GIFs.
// large.png is a 35K PNG that should be non-embeddable.
// Full paths start with http://localhost/w/.
// Timestamps in output are replaced with 'timestamp'.
- // data: URIs for red.gif and green.gif
+ // data: URIs for red.gif, green.gif, circle.svg
$red = 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=';
$green = 'data:image/gif;base64,R0lGODlhAQABAIAAAACAADAAACwAAAAAAQABAAACAkQBADs=';
+ $svg = 'data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A'
+ . '%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%228%22%20height%3D'
+ . '%228%22%3E%0A%3Ccircle%20cx%3D%224%22%20cy%3D%224%22%20r%3D%222%22%2F%3E%0A%3C%2Fsvg%3E%0A';
return array(
array(
@@ -234,6 +276,11 @@ class CSSMinTest extends MediaWikiTestCase {
"foo { background: url(http://localhost/w/large.png?timestamp); }",
),
array(
+ 'SVG files are embedded without base64 encoding and unnecessary IE 6 and 7 fallback',
+ 'foo { /* @embed */ background: url(circle.svg); }',
+ "foo { background: url($svg); }",
+ ),
+ array(
'Two regular files in one rule',
'foo { background: url(red.gif), url(green.gif); }',
'foo { background: url(http://localhost/w/red.gif?timestamp), '
diff --git a/tests/phpunit/includes/libs/DeferredStringifierTest.php b/tests/phpunit/includes/libs/DeferredStringifierTest.php
new file mode 100644
index 00000000..8b7610ae
--- /dev/null
+++ b/tests/phpunit/includes/libs/DeferredStringifierTest.php
@@ -0,0 +1,50 @@
+<?php
+
+class DeferredStringifierTest extends PHPUnit_Framework_TestCase {
+
+ /**
+ * @covers DeferredStringifier
+ * @dataProvider provideToString
+ */
+ public function testToString( $params, $expected ) {
+ $class = new ReflectionClass( 'DeferredStringifier' );
+ $ds = $class->newInstanceArgs( $params );
+ $this->assertEquals( $expected, (string)$ds );
+ }
+
+ public static function provideToString() {
+ return array(
+ // No args
+ array(
+ array(
+ function() {
+ return 'foo';
+ }
+ ),
+ 'foo'
+ ),
+ // Has args
+ array(
+ array(
+ function( $i ) {
+ return $i;
+ },
+ 'bar'
+ ),
+ 'bar'
+ ),
+ );
+ }
+
+ /**
+ * Verify that the callback is not called if
+ * it is never converted to a string
+ */
+ public function testCallbackNotCalled() {
+ $ds = new DeferredStringifier( function() {
+ throw new Exception( 'This should not be reached!' );
+ } );
+ // No exception was thrown
+ $this->assertTrue( true );
+ }
+}
diff --git a/tests/phpunit/includes/libs/GenericArrayObjectTest.php b/tests/phpunit/includes/libs/GenericArrayObjectTest.php
index 4911f73a..315bc7ed 100644
--- a/tests/phpunit/includes/libs/GenericArrayObjectTest.php
+++ b/tests/phpunit/includes/libs/GenericArrayObjectTest.php
@@ -24,10 +24,9 @@
* @ingroup Test
* @group GenericArrayObject
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
-abstract class GenericArrayObjectTest extends MediaWikiTestCase {
+abstract class GenericArrayObjectTest extends PHPUnit_Framework_TestCase {
/**
* Returns objects that can serve as elements in the concrete
diff --git a/tests/phpunit/includes/libs/HashRingTest.php b/tests/phpunit/includes/libs/HashRingTest.php
index 68dfea1f..b51eb3f4 100644
--- a/tests/phpunit/includes/libs/HashRingTest.php
+++ b/tests/phpunit/includes/libs/HashRingTest.php
@@ -3,7 +3,7 @@
/**
* @group HashRing
*/
-class HashRingTest extends MediaWikiTestCase {
+class HashRingTest extends PHPUnit_Framework_TestCase {
/**
* @covers HashRing
*/
diff --git a/tests/phpunit/includes/libs/IEUrlExtensionTest.php b/tests/phpunit/includes/libs/IEUrlExtensionTest.php
index b7071230..e96953ee 100644
--- a/tests/phpunit/includes/libs/IEUrlExtensionTest.php
+++ b/tests/phpunit/includes/libs/IEUrlExtensionTest.php
@@ -5,7 +5,7 @@
* @todo tests below for findIE6Extension should be split into...
* ...a dataprovider and test method.
*/
-class IEUrlExtensionTest extends MediaWikiTestCase {
+class IEUrlExtensionTest extends PHPUnit_Framework_TestCase {
/**
* @covers IEUrlExtension::findIE6Extension
*/
diff --git a/tests/phpunit/includes/libs/IPSetTest.php b/tests/phpunit/includes/libs/IPSetTest.php
index d4e5214a..5bbacef4 100644
--- a/tests/phpunit/includes/libs/IPSetTest.php
+++ b/tests/phpunit/includes/libs/IPSetTest.php
@@ -3,7 +3,7 @@
/**
* @group IPSet
*/
-class IPSetTest extends MediaWikiTestCase {
+class IPSetTest extends PHPUnit_Framework_TestCase {
/**
* Provides test cases for IPSetTest::testIPSet
*
diff --git a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
index c8795b2e..149a28c1 100644
--- a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
+++ b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
@@ -1,6 +1,6 @@
<?php
-class JavaScriptMinifierTest extends MediaWikiTestCase {
+class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
public static function provideCases() {
return array(
@@ -164,7 +164,7 @@ class JavaScriptMinifierTest extends MediaWikiTestCase {
);
}
- public static function provideBug32548() {
+ public static function provideExponentLineBreaking() {
return array(
array(
// This one gets interpreted all together by the prior code;
@@ -183,14 +183,13 @@ class JavaScriptMinifierTest extends MediaWikiTestCase {
}
/**
- * @dataProvider provideBug32548
+ * @dataProvider provideExponentLineBreaking
* @covers JavaScriptMinifier::minify
- * @todo give this test a real name explaining what is being tested here
*/
- public function testBug32548Exponent( $num ) {
+ public function testExponentLineBreaking( $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.
+ // instead break at the start of the number. (T34548)
$prefix = 'var longVarName' . str_repeat( '_', 973 ) . '=';
$suffix = ',shortVarName=0;';
diff --git a/tests/phpunit/includes/libs/MWMessagePackTest.php b/tests/phpunit/includes/libs/MWMessagePackTest.php
index f80f78df..ec145836 100644
--- a/tests/phpunit/includes/libs/MWMessagePackTest.php
+++ b/tests/phpunit/includes/libs/MWMessagePackTest.php
@@ -3,7 +3,7 @@
* PHP Unit tests for MWMessagePack
* @covers MWMessagePack
*/
-class MWMessagePackTest extends MediaWikiTestCase {
+class MWMessagePackTest extends PHPUnit_Framework_TestCase {
/**
* Provides test cases for MWMessagePackTest::testMessagePack
diff --git a/tests/phpunit/includes/libs/ObjectFactoryTest.php b/tests/phpunit/includes/libs/ObjectFactoryTest.php
new file mode 100644
index 00000000..92207325
--- /dev/null
+++ b/tests/phpunit/includes/libs/ObjectFactoryTest.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
+
+ /**
+ * @covers ObjectFactory::getObjectFromSpec
+ */
+ public function testClosureExpansionDisabled() {
+ $obj = ObjectFactory::getObjectFromSpec( array(
+ 'class' => 'ObjectFactoryTest_Fixture',
+ 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'closure_expansion' => false,
+ ) );
+ $this->assertInstanceOf( 'Closure', $obj->args[0] );
+ $this->assertSame( 'unwrapped', $obj->args[0]() );
+ }
+
+ /**
+ * @covers ObjectFactory::getObjectFromSpec
+ */
+ public function testClosureExpansionEnabled() {
+ $obj = ObjectFactory::getObjectFromSpec( array(
+ 'class' => 'ObjectFactoryTest_Fixture',
+ 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'closure_expansion' => true,
+ ) );
+ $this->assertInternalType( 'string', $obj->args[0] );
+ $this->assertSame( 'unwrapped', $obj->args[0] );
+
+ $obj = ObjectFactory::getObjectFromSpec( array(
+ 'class' => 'ObjectFactoryTest_Fixture',
+ 'args' => array( function (){ return 'unwrapped'; }, ),
+ ) );
+ $this->assertInternalType( 'string', $obj->args[0] );
+ $this->assertSame( 'unwrapped', $obj->args[0] );
+ }
+}
+
+class ObjectFactoryTest_Fixture {
+ public $args;
+ public function __construct( /*...*/ ) { $this->args = func_get_args(); }
+}
diff --git a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
index 1a8a1e56..43001979 100644
--- a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
+++ b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
@@ -9,20 +9,20 @@
*
* @group Cache
*/
-class ProcessCacheLRUTest extends MediaWikiTestCase {
+class ProcessCacheLRUTest extends PHPUnit_Framework_TestCase {
/**
* Helper to verify emptiness of a cache object.
* Compare against an array so we get the cache content difference.
*/
- function assertCacheEmpty( $cache, $msg = 'Cache should be empty' ) {
+ protected function assertCacheEmpty( $cache, $msg = 'Cache should be empty' ) {
$this->assertAttributeEquals( array(), 'cache', $cache, $msg );
}
/**
* Helper to fill a cache object passed by reference
*/
- function fillCache( &$cache, $numEntries ) {
+ protected function fillCache( &$cache, $numEntries ) {
// Fill cache with three values
for ( $i = 1; $i <= $numEntries; $i++ ) {
$cache->set( "cache-key-$i", "prop-$i", "value-$i" );
@@ -33,17 +33,17 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
* Generates an array of what would be expected in cache for a given cache
* size and a number of entries filled in sequentially
*/
- function getExpectedCache( $cacheMaxEntries, $entryToFill ) {
+ protected function getExpectedCache( $cacheMaxEntries, $entryToFill ) {
$expected = array();
if ( $entryToFill === 0 ) {
- # The cache is empty!
+ // The cache is empty!
return array();
} elseif ( $entryToFill <= $cacheMaxEntries ) {
- # Cache is not fully filled
+ // Cache is not fully filled
$firstKey = 1;
} else {
- # Cache overflowed
+ // Cache overflowed
$firstKey = 1 + $entryToFill - $cacheMaxEntries;
}
@@ -62,13 +62,16 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
public function testPhpUnitArrayEquality() {
$one = array( 'A' => 1, 'B' => 2 );
$two = array( 'B' => 2, 'A' => 1 );
- $this->assertEquals( $one, $two ); // ==
- $this->assertNotSame( $one, $two ); // ===
+ // ==
+ $this->assertEquals( $one, $two );
+ // ===
+ $this->assertNotSame( $one, $two );
}
/**
* @dataProvider provideInvalidConstructorArg
* @expectedException UnexpectedValueException
+ * @covers ProcessCacheLRU::__construct
*/
public function testConstructorGivenInvalidValue( $maxSize ) {
new ProcessCacheLRUTestable( $maxSize );
@@ -88,6 +91,11 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
);
}
+ /**
+ * @covers ProcessCacheLRU::get
+ * @covers ProcessCacheLRU::set
+ * @covers ProcessCacheLRU::het
+ */
public function testAddAndGetAKey() {
$oneCache = new ProcessCacheLRUTestable( 1 );
$this->assertCacheEmpty( $oneCache );
@@ -99,6 +107,10 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
$this->assertEquals( 'value1', $oneCache->get( 'cache-key', 'prop1' ) );
}
+ /**
+ * @covers ProcessCacheLRU::set
+ * @covers ProcessCacheLRU::get
+ */
public function testDeleteOldKey() {
$oneCache = new ProcessCacheLRUTestable( 1 );
$this->assertCacheEmpty( $oneCache );
@@ -113,6 +125,7 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
* a sequence of always different cache-keys. Meant to verify we correclty
* delete the older key.
*
+ * @covers ProcessCacheLRU::set
* @dataProvider provideCacheFilling
* @param int $cacheMaxEntries Maximum entry the created cache will hold
* @param int $entryToFill Number of entries to insert in the created cache.
@@ -136,14 +149,18 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
return array(
array( 1, 0 ),
array( 1, 1 ),
- array( 1, 2 ), # overflow
- array( 5, 33 ), # overflow
+ // overflow
+ array( 1, 2 ),
+ // overflow
+ array( 5, 33 ),
);
}
/**
* Create a cache with only one remaining entry then update
* the first inserted entry. Should bump it to the top.
+ *
+ * @covers ProcessCacheLRU::set
*/
public function testReplaceExistingKeyShouldBumpEntryToTop() {
$maxEntries = 3;
@@ -164,6 +181,11 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
);
}
+ /**
+ * @covers ProcessCacheLRU::get
+ * @covers ProcessCacheLRU::set
+ * @covers ProcessCacheLRU::het
+ */
public function testRecentlyAccessedKeyStickIn() {
$cache = new ProcessCacheLRUTestable( 2 );
$cache->set( 'first', 'prop1', 'value1' );
@@ -182,6 +204,9 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
* filled entry.
* Given a cache having 1,2,3 as key, updating 2 should bump 2 to
* the top of the queue with the new value: 1,3,2* (* = updated).
+ *
+ * @covers ProcessCacheLRU::set
+ * @covers ProcessCacheLRU::get
*/
public function testReplaceExistingKeyInAFullCacheShouldBumpToTop() {
$maxEntries = 3;
@@ -204,6 +229,9 @@ class ProcessCacheLRUTest extends MediaWikiTestCase {
);
}
+ /**
+ * @covers ProcessCacheLRU::set
+ */
public function testBumpExistingKeyToTop() {
$cache = new ProcessCacheLRUTestable( 3 );
$this->fillCache( $cache, 3 );
diff --git a/tests/phpunit/includes/libs/RunningStatTest.php b/tests/phpunit/includes/libs/RunningStatTest.php
index dc5db82c..edfaf162 100644
--- a/tests/phpunit/includes/libs/RunningStatTest.php
+++ b/tests/phpunit/includes/libs/RunningStatTest.php
@@ -3,7 +3,7 @@
* PHP Unit tests for RunningStat class.
* @covers RunningStat
*/
-class RunningStatTest extends MediaWikiTestCase {
+class RunningStatTest extends PHPUnit_Framework_TestCase {
public $points = array(
49.7168, 74.3804, 7.0115, 96.5769, 34.9458,
diff --git a/tests/phpunit/includes/utils/StringUtilsTest.php b/tests/phpunit/includes/libs/StringUtilsTest.php
index 0fdb8e15..7c24fae6 100644
--- a/tests/phpunit/includes/utils/StringUtilsTest.php
+++ b/tests/phpunit/includes/libs/StringUtilsTest.php
@@ -1,6 +1,6 @@
<?php
-class StringUtilsTest extends MediaWikiTestCase {
+class StringUtilsTest extends PHPUnit_Framework_TestCase {
/**
* This tests StringUtils::isUtf8 whenever we have the mbstring extension
diff --git a/tests/phpunit/includes/libs/XhprofTest.php b/tests/phpunit/includes/libs/XhprofTest.php
new file mode 100644
index 00000000..2440fc08
--- /dev/null
+++ b/tests/phpunit/includes/libs/XhprofTest.php
@@ -0,0 +1,320 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @uses Xhprof
+ * @uses AutoLoader
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
+ * @since 1.25
+ */
+class XhprofTest extends PHPUnit_Framework_TestCase {
+
+ public function setUp() {
+ if ( !function_exists( 'xhprof_enable' ) ) {
+ $this->markTestSkipped( 'No xhprof support detected.' );
+ }
+ }
+
+ /**
+ * @covers Xhprof::splitKey
+ * @dataProvider provideSplitKey
+ */
+ public function testSplitKey( $key, $expect ) {
+ $this->assertSame( $expect, Xhprof::splitKey( $key ) );
+ }
+
+ public function provideSplitKey() {
+ return array(
+ array( 'main()', array( null, 'main()' ) ),
+ array( 'foo==>bar', array( 'foo', 'bar' ) ),
+ array( 'bar@1==>bar@2', array( 'bar@1', 'bar@2' ) ),
+ array( 'foo==>bar==>baz', array( 'foo', 'bar==>baz' ) ),
+ array( '==>bar', array( '', 'bar' ) ),
+ array( '', array( null, '' ) ),
+ );
+ }
+
+ /**
+ * @covers Xhprof::__construct
+ * @covers Xhprof::stop
+ * @covers Xhprof::getRawData
+ * @dataProvider provideRawData
+ */
+ public function testRawData( $flags, $keys ) {
+ $xhprof = new Xhprof( array( 'flags' => $flags ) );
+ $raw = $xhprof->getRawData();
+ $this->assertArrayHasKey( 'main()', $raw );
+ foreach ( $keys as $key ) {
+ $this->assertArrayHasKey( $key, $raw['main()'] );
+ }
+ }
+
+ public function provideRawData() {
+ $tests = array(
+ array( 0, array( 'ct', 'wt' ) ),
+ );
+
+ if ( defined( 'XHPROF_FLAGS_CPU' ) && defined( 'XHPROF_FLAGS_CPU' ) ) {
+ $tests[] = array( XHPROF_FLAGS_MEMORY, array(
+ 'ct', 'wt', 'mu', 'pmu',
+ ) );
+ $tests[] = array( XHPROF_FLAGS_CPU, array(
+ 'ct', 'wt', 'cpu',
+ ) );
+ $tests[] = array( XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU, array(
+ 'ct', 'wt', 'mu', 'pmu', 'cpu',
+ ) );
+ }
+
+ return $tests;
+ }
+
+ /**
+ * @covers Xhprof::pruneData
+ */
+ public function testInclude() {
+ $xhprof = $this->getXhprofFixture( array(
+ 'include' => array( 'main()' ),
+ ) );
+ $raw = $xhprof->getRawData();
+ $this->assertArrayHasKey( 'main()', $raw );
+ $this->assertArrayHasKey( 'main()==>foo', $raw );
+ $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
+ $this->assertSame( 3, count( $raw ) );
+ }
+
+ /**
+ * Validate the structure of data returned by
+ * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
+ * structural changes to the returned data in lieu of using a more heavy
+ * weight typed response object.
+ *
+ * @covers Xhprof::getInclusiveMetrics
+ */
+ public function testInclusiveMetricsStructure() {
+ $metricStruct = array(
+ 'ct' => 'int',
+ 'wt' => 'array',
+ 'cpu' => 'array',
+ 'mu' => 'array',
+ 'pmu' => 'array',
+ );
+ $statStruct = array(
+ 'total' => 'numeric',
+ 'min' => 'numeric',
+ 'mean' => 'numeric',
+ 'max' => 'numeric',
+ 'variance' => 'numeric',
+ 'percent' => 'numeric',
+ );
+
+ $xhprof = $this->getXhprofFixture();
+ $metrics = $xhprof->getInclusiveMetrics();
+
+ foreach ( $metrics as $name => $metric ) {
+ $this->assertArrayStructure( $metricStruct, $metric );
+
+ foreach ( $metricStruct as $key => $type ) {
+ if ( $type === 'array' ) {
+ $this->assertArrayStructure( $statStruct, $metric[$key] );
+ if ( $name === 'main()' ) {
+ $this->assertEquals( 100, $metric[$key]['percent'] );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Validate the structure of data returned by
+ * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
+ * structural changes to the returned data in lieu of using a more heavy
+ * weight typed response object.
+ *
+ * @covers Xhprof::getCompleteMetrics
+ */
+ public function testCompleteMetricsStructure() {
+ $metricStruct = array(
+ 'ct' => 'int',
+ 'wt' => 'array',
+ 'cpu' => 'array',
+ 'mu' => 'array',
+ 'pmu' => 'array',
+ 'calls' => 'array',
+ 'subcalls' => 'array',
+ );
+ $statsMetrics = array( 'wt', 'cpu', 'mu', 'pmu' );
+ $statStruct = array(
+ 'total' => 'numeric',
+ 'min' => 'numeric',
+ 'mean' => 'numeric',
+ 'max' => 'numeric',
+ 'variance' => 'numeric',
+ 'percent' => 'numeric',
+ 'exclusive' => 'numeric',
+ );
+
+ $xhprof = $this->getXhprofFixture();
+ $metrics = $xhprof->getCompleteMetrics();
+
+ foreach ( $metrics as $name => $metric ) {
+ $this->assertArrayStructure( $metricStruct, $metric, $name );
+
+ foreach ( $metricStruct as $key => $type ) {
+ if ( in_array( $key, $statsMetrics ) ) {
+ $this->assertArrayStructure(
+ $statStruct, $metric[$key], $key
+ );
+ $this->assertLessThanOrEqual(
+ $metric[$key]['total'], $metric[$key]['exclusive']
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * @covers Xhprof::getCallers
+ * @covers Xhprof::getCallees
+ * @uses Xhprof
+ */
+ public function testEdges() {
+ $xhprof = $this->getXhprofFixture();
+ $this->assertSame( array(), $xhprof->getCallers( 'main()' ) );
+ $this->assertSame( array( 'foo', 'xhprof_disable' ),
+ $xhprof->getCallees( 'main()' )
+ );
+ $this->assertSame( array( 'main()' ),
+ $xhprof->getCallers( 'foo' )
+ );
+ $this->assertSame( array(), $xhprof->getCallees( 'strlen' ) );
+ }
+
+ /**
+ * @covers Xhprof::getCriticalPath
+ * @uses Xhprof
+ */
+ public function testCriticalPath() {
+ $xhprof = $this->getXhprofFixture();
+ $path = $xhprof->getCriticalPath();
+
+ $last = null;
+ foreach ( $path as $key => $value ) {
+ list( $func, $call ) = Xhprof::splitKey( $key );
+ $this->assertSame( $last, $func );
+ $last = $call;
+ }
+ $this->assertSame( $last, 'bar@1' );
+ }
+
+ /**
+ * Get an Xhprof instance that has been primed with a set of known testing
+ * data. Tests for the Xhprof class should laregly be concerned with
+ * evaluating the manipulations of the data collected by xhprof rather
+ * than the data collection process itself.
+ *
+ * The returned Xhprof instance primed will be with a data set created by
+ * running this trivial program using the PECL xhprof implementation:
+ * @code
+ * function bar( $x ) {
+ * if ( $x > 0 ) {
+ * bar($x - 1);
+ * }
+ * }
+ * function foo() {
+ * for ( $idx = 0; $idx < 2; $idx++ ) {
+ * bar( $idx );
+ * $x = strlen( 'abc' );
+ * }
+ * }
+ * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
+ * foo();
+ * $x = xhprof_disable();
+ * var_export( $x );
+ * @endcode
+ *
+ * @return Xhprof
+ */
+ protected function getXhprofFixture( array $opts = array() ) {
+ $xhprof = new Xhprof( $opts );
+ $xhprof->loadRawData( array (
+ 'foo==>bar' => array (
+ 'ct' => 2,
+ 'wt' => 57,
+ 'cpu' => 92,
+ 'mu' => 1896,
+ 'pmu' => 0,
+ ),
+ 'foo==>strlen' => array (
+ 'ct' => 2,
+ 'wt' => 21,
+ 'cpu' => 141,
+ 'mu' => 752,
+ 'pmu' => 0,
+ ),
+ 'bar==>bar@1' => array (
+ 'ct' => 1,
+ 'wt' => 18,
+ 'cpu' => 19,
+ 'mu' => 752,
+ 'pmu' => 0,
+ ),
+ 'main()==>foo' => array (
+ 'ct' => 1,
+ 'wt' => 304,
+ 'cpu' => 307,
+ 'mu' => 4008,
+ 'pmu' => 0,
+ ),
+ 'main()==>xhprof_disable' => array (
+ 'ct' => 1,
+ 'wt' => 8,
+ 'cpu' => 10,
+ 'mu' => 768,
+ 'pmu' => 392,
+ ),
+ 'main()' => array (
+ 'ct' => 1,
+ 'wt' => 353,
+ 'cpu' => 351,
+ 'mu' => 6112,
+ 'pmu' => 1424,
+ ),
+ ) );
+ return $xhprof;
+ }
+
+ /**
+ * Assert that the given array has the described structure.
+ *
+ * @param array $struct Array of key => type mappings
+ * @param array $actual Array to check
+ * @param string $label
+ */
+ protected function assertArrayStructure( $struct, $actual, $label = null ) {
+ $this->assertInternalType( 'array', $actual, $label );
+ $this->assertCount( count($struct), $actual, $label );
+ foreach ( $struct as $key => $type ) {
+ $this->assertArrayHasKey( $key, $actual );
+ $this->assertInternalType( $type, $actual[$key] );
+ }
+ }
+}
diff --git a/tests/phpunit/includes/XmlTypeCheckTest.php b/tests/phpunit/includes/libs/XmlTypeCheckTest.php
index 6ad97fd4..f0ba934e 100644
--- a/tests/phpunit/includes/XmlTypeCheckTest.php
+++ b/tests/phpunit/includes/libs/XmlTypeCheckTest.php
@@ -5,7 +5,7 @@
* @group Xml
* @covers XMLTypeCheck
*/
-class XmlTypeCheckTest extends MediaWikiTestCase {
+class XmlTypeCheckTest extends PHPUnit_Framework_TestCase {
const WELL_FORMED_XML = "<root><child /></root>";
const MAL_FORMED_XML = "<root><child /></error>";
const XML_WITH_PIH = '<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="/w/index.php"?><svg><child /></svg>';
diff --git a/tests/phpunit/includes/libs/composer/ComposerJsonTest.php b/tests/phpunit/includes/libs/composer/ComposerJsonTest.php
new file mode 100644
index 00000000..0c58b65a
--- /dev/null
+++ b/tests/phpunit/includes/libs/composer/ComposerJsonTest.php
@@ -0,0 +1,57 @@
+<?php
+
+class ComposerJsonTest extends MediaWikiTestCase {
+
+ private $json, $json2;
+
+ public function setUp() {
+ parent::setUp();
+ global $IP;
+ $this->json = "$IP/tests/phpunit/data/composer/composer.json";
+ $this->json2 = "$IP/tests/phpunit/data/composer/new-composer.json";
+ }
+
+ public static function provideGetHash() {
+ return array(
+ array( 'json', 'cc6e7fc565b246cb30b0cac103a2b31e' ),
+ array( 'json2', '19921dd1fc457f1b00561da932432001' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetHash
+ * @covers ComposerJson::getHash
+ */
+ public function testIsHashUpToDate( $file, $expected ) {
+ $json = new ComposerJson( $this->$file );
+ $this->assertEquals( $expected, $json->getHash() );
+ }
+
+ /**
+ * @covers ComposerJson::getRequiredDependencies
+ */
+ public function testGetRequiredDependencies() {
+ $json = new ComposerJson( $this->json );
+ $this->assertArrayEquals( array(
+ 'cdb/cdb' => '1.0.0',
+ 'cssjanus/cssjanus' => '1.1.1',
+ 'leafo/lessphp' => '0.5.0',
+ 'psr/log' => '1.0.0',
+ ), $json->getRequiredDependencies(), false, true );
+ }
+
+ public static function provideNormalizeVersion() {
+ return array(
+ array( 'v1.0.0', '1.0.0' ),
+ array( '0.0.5', '0.0.5' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideNormalizeVersion
+ * @covers ComposerJson::normalizeVersion
+ */
+ public function testNormalizeVersion( $input, $expected ) {
+ $this->assertEquals( $expected, ComposerJson::normalizeVersion( $input ) );
+ }
+}
diff --git a/tests/phpunit/includes/libs/composer/ComposerLockTest.php b/tests/phpunit/includes/libs/composer/ComposerLockTest.php
new file mode 100644
index 00000000..b5fd5f6e
--- /dev/null
+++ b/tests/phpunit/includes/libs/composer/ComposerLockTest.php
@@ -0,0 +1,62 @@
+<?php
+
+class ComposerLockTest extends MediaWikiTestCase {
+
+ private $lock;
+
+ public function setUp() {
+ parent::setUp();
+ global $IP;
+ $this->lock = "$IP/tests/phpunit/data/composer/composer.lock";
+ }
+
+ /**
+ * @covers ComposerLock::getHash
+ */
+ public function testGetHash() {
+ $lock = new ComposerLock( $this->lock );
+ $this->assertEquals( 'a3bb80b0ac4c4a31e52574d48c032923', $lock->getHash() );
+ }
+
+ /**
+ * @covers ComposerLock::getInstalledDependencies
+ */
+ public function testGetInstalledDependencies() {
+ $lock = new ComposerLock( $this->lock );
+ $this->assertArrayEquals( array(
+ 'wikimedia/cdb' => array(
+ 'version' => '1.0.1',
+ 'type' => 'library',
+ ),
+ 'cssjanus/cssjanus' => array(
+ 'version' => '1.1.1',
+ 'type' => 'library',
+ ),
+ 'leafo/lessphp' => array(
+ 'version' => '0.5.0',
+ 'type' => 'library',
+ ),
+ 'psr/log' => array(
+ 'version' => '1.0.0',
+ 'type' => 'library',
+ ),
+ 'oojs/oojs-ui' => array(
+ 'version' => '0.6.0',
+ 'type' => 'library',
+ ),
+ 'composer/installers' => array(
+ 'version' => '1.0.19',
+ 'type' => 'composer-installer',
+ ),
+ 'mediawiki/translate' => array(
+ 'version' => '2014.12',
+ 'type' => 'mediawiki-extension',
+ ),
+ 'mediawiki/universal-language-selector' => array(
+ 'version' => '2014.12',
+ 'type' => 'mediawiki-extension',
+ ),
+ ), $lock->getInstalledDependencies(), false, true );
+ }
+
+}
diff --git a/tests/phpunit/includes/logging/LogFormatterTest.php b/tests/phpunit/includes/logging/LogFormatterTest.php
index 6210d098..515990e6 100644
--- a/tests/phpunit/includes/logging/LogFormatterTest.php
+++ b/tests/phpunit/includes/logging/LogFormatterTest.php
@@ -239,4 +239,57 @@ class LogFormatterTest extends MediaWikiLangTestCase {
$this->assertEquals( $comment, $formatter->getComment() );
}
+
+ /**
+ * @dataProvider provideApiParamFormatting
+ * @covers LogFormatter::formatParametersForApi
+ * @covers LogFormatter::formatParameterValueForApi
+ */
+ public function testApiParamFormatting( $key, $value, $expected ) {
+ $entry = $this->newLogEntry( 'param', array( $key => $value ) );
+ $formatter = LogFormatter::newFromEntry( $entry );
+ $formatter->setContext( $this->context );
+
+ ApiResult::setIndexedTagName( $expected, 'param' );
+ ApiResult::setArrayType( $expected, 'assoc' );
+
+ $this->assertEquals( $expected, $formatter->formatParametersForApi() );
+ }
+
+ public static function provideApiParamFormatting() {
+ return array(
+ array( 0, 'value', array( 'value' ) ),
+ array( 'named', 'value', array( 'named' => 'value' ) ),
+ array( '::key', 'value', array( 'key' => 'value' ) ),
+ array( '4::key', 'value', array( 'key' => 'value' ) ),
+ array( '4:raw:key', 'value', array( 'key' => 'value' ) ),
+ array( '4:plain:key', 'value', array( 'key' => 'value' ) ),
+ array( '4:bool:key', '1', array( 'key' => true ) ),
+ array( '4:bool:key', '0', array( 'key' => false ) ),
+ array( '4:number:key', '123', array( 'key' => 123 ) ),
+ array( '4:number:key', '123.5', array( 'key' => 123.5 ) ),
+ array( '4:array:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'array' ) ) ),
+ array( '4:assoc:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'assoc' ) ) ),
+ array( '4:kvp:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'kvp' ) ) ),
+ array( '4:timestamp:key', '20150102030405', array( 'key' => '2015-01-02T03:04:05Z' ) ),
+ array( '4:msg:key', 'parentheses', array(
+ 'key_key' => 'parentheses',
+ 'key_text' => wfMessage( 'parentheses' )->text(),
+ ) ),
+ array( '4:msg-content:key', 'parentheses', array(
+ 'key_key' => 'parentheses',
+ 'key_text' => wfMessage( 'parentheses' )->inContentLanguage()->text(),
+ ) ),
+ array( '4:title:key', 'project:foo', array(
+ 'key_ns' => NS_PROJECT,
+ 'key_title' => Title::newFromText( 'project:foo' )->getFullText(),
+ ) ),
+ array( '4:title-link:key', 'project:foo', array(
+ 'key_ns' => NS_PROJECT,
+ 'key_title' => Title::newFromText( 'project:foo' )->getFullText(),
+ ) ),
+ array( '4:user:key', 'foo', array( 'key' => 'Foo' ) ),
+ array( '4:user-link:key', 'foo', array( 'key' => 'Foo' ) ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/mail/MailAddressTest.php b/tests/phpunit/includes/mail/MailAddressTest.php
index 2d078120..18d2acdf 100644
--- a/tests/phpunit/includes/mail/MailAddressTest.php
+++ b/tests/phpunit/includes/mail/MailAddressTest.php
@@ -14,6 +14,9 @@ class MailAddressTest extends MediaWikiTestCase {
* @covers MailAddress::newFromUser
*/
public function testNewFromUser() {
+ if ( wfIsWindows() ) {
+ $this->markTestSkipped( 'This test only works on non-Windows platforms' );
+ }
$user = $this->getMock( 'User' );
$user->expects( $this->any() )->method( 'getName' )->will( $this->returnValue( 'UserName' ) );
$user->expects( $this->any() )->method( 'getEmail' )->will( $this->returnValue( 'foo@bar.baz' ) );
@@ -49,6 +52,7 @@ class MailAddressTest extends MediaWikiTestCase {
array( false, 'foo@bar.baz', 'AUserName', 'Some real name', 'AUserName <foo@bar.baz>' ),
array( false, 'foo@bar.baz', '', '', 'foo@bar.baz' ),
array( true, 'foo@bar.baz', '', '', 'foo@bar.baz' ),
+ array( true, '', '', '', '' ),
);
}
@@ -59,5 +63,4 @@ class MailAddressTest extends MediaWikiTestCase {
$ma = new MailAddress( 'some@email.com', 'UserName', 'A real name' );
$this->assertEquals( $ma->toString(), (string)$ma );
}
-
-} \ No newline at end of file
+}
diff --git a/tests/phpunit/includes/media/BitmapScalingTest.php b/tests/phpunit/includes/media/BitmapScalingTest.php
index 1972c969..e4415ece 100644
--- a/tests/phpunit/includes/media/BitmapScalingTest.php
+++ b/tests/phpunit/includes/media/BitmapScalingTest.php
@@ -113,7 +113,7 @@ class BitmapScalingTest extends MediaWikiTestCase {
$file = new FakeDimensionFile( array( 4000, 4000 ) );
$handler = new BitmapHandler;
$params = array( 'width' => '3700' ); // Still bigger than max size.
- $this->assertEquals( 'TransformParameterError',
+ $this->assertEquals( 'TransformTooBigImageAreaError',
get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) );
}
@@ -125,7 +125,7 @@ class BitmapScalingTest extends MediaWikiTestCase {
$file->mustRender = true;
$handler = new BitmapHandler;
$params = array( 'width' => '5000' ); // Still bigger than max size.
- $this->assertEquals( 'TransformParameterError',
+ $this->assertEquals( 'TransformTooBigImageAreaError',
get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) );
}
diff --git a/tests/phpunit/includes/media/FormatMetadataTest.php b/tests/phpunit/includes/media/FormatMetadataTest.php
index 002e2cb9..54758f94 100644
--- a/tests/phpunit/includes/media/FormatMetadataTest.php
+++ b/tests/phpunit/includes/media/FormatMetadataTest.php
@@ -68,4 +68,36 @@ class FormatMetadataTest extends MediaWikiMediaTestCase {
// TODO: more test cases
);
}
+
+ /**
+ * @param mixed $input
+ * @param mixed $output
+ * @dataProvider provideResolveMultivalueValue
+ * @covers FormatMetadata::resolveMultivalueValue
+ */
+ public function testResolveMultivalueValue( $input, $output ) {
+ $formatMetadata = new FormatMetadata();
+ $class = new ReflectionClass( 'FormatMetadata' );
+ $method = $class->getMethod( 'resolveMultivalueValue' );
+ $method->setAccessible( true );
+ $actualInput = $method->invoke( $formatMetadata, $input );
+ $this->assertEquals( $output, $actualInput );
+ }
+
+ public function provideResolveMultivalueValue() {
+ return array(
+ 'nonArray' => array( 'foo', 'foo' ),
+ 'multiValue' => array( array( 'first', 'second', 'third', '_type' => 'ol' ), 'first' ),
+ 'noType' => array( array( 'first', 'second', 'third' ), 'first' ),
+ 'typeFirst' => array( array( '_type' => 'ol', 'first', 'second', 'third' ), 'first' ),
+ 'multilang' => array(
+ array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
+ array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
+ ),
+ 'multilang-multivalue' => array(
+ array( 'en' => array( 'first', 'second' ), 'de' => array( 'Erste', 'Zweite' ), '_type' => 'lang' ),
+ array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
+ ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/media/MediaHandlerTest.php b/tests/phpunit/includes/media/MediaHandlerTest.php
index d8cfcc45..78ea9530 100644
--- a/tests/phpunit/includes/media/MediaHandlerTest.php
+++ b/tests/phpunit/includes/media/MediaHandlerTest.php
@@ -7,50 +7,62 @@ class MediaHandlerTest extends MediaWikiTestCase {
/**
* @covers MediaHandler::fitBoxWidth
- * @todo split into a dataprovider and test method
+ *
+ * @dataProvider provideTestFitBoxWidth
*/
- public function testFitBoxWidth() {
- $vals = array(
- array(
- 'width' => 50,
- 'height' => 50,
- 'tests' => array(
+ public function testFitBoxWidth( $width, $height, $max, $expected ) {
+ $y = round( $expected * $height / $width );
+ $result = MediaHandler::fitBoxWidth( $width, $height, $max );
+ $y2 = round( $result * $height / $width );
+ $this->assertEquals( $expected,
+ $result,
+ "($width, $height, $max) wanted: {$expected}x$y, got: {z$result}x$y2" );
+ }
+
+ public static function provideTestFitBoxWidth() {
+ return array_merge(
+ static::generateTestFitBoxWidthData( 50, 50, array(
50 => 50,
17 => 17,
- 18 => 18 ) ),
- array(
- 'width' => 366,
- 'height' => 300,
- 'tests' => array(
+ 18 => 18 )
+ ),
+ static::generateTestFitBoxWidthData( 366, 300, array(
50 => 61,
17 => 21,
- 18 => 22 ) ),
- array(
- 'width' => 300,
- 'height' => 366,
- 'tests' => array(
+ 18 => 22 )
+ ),
+ static::generateTestFitBoxWidthData( 300, 366, array(
50 => 41,
17 => 14,
- 18 => 15 ) ),
- array(
- 'width' => 100,
- 'height' => 400,
- 'tests' => array(
+ 18 => 15 )
+ ),
+ static::generateTestFitBoxWidthData( 100, 400, array(
50 => 12,
17 => 4,
- 18 => 4 ) ) );
- foreach ( $vals as $row ) {
- $tests = $row['tests'];
- $height = $row['height'];
- $width = $row['width'];
- foreach ( $tests as $max => $expected ) {
- $y = round( $expected * $height / $width );
- $result = MediaHandler::fitBoxWidth( $width, $height, $max );
- $y2 = round( $result * $height / $width );
- $this->assertEquals( $expected,
- $result,
- "($width, $height, $max) wanted: {$expected}x$y, got: {$result}x$y2" );
- }
+ 18 => 4 )
+ )
+ );
+ }
+
+ /**
+ * Generate single test cases by combining the dimensions and tests contents
+ *
+ * It creates:
+ * [$width, $height, $max, $expected],
+ * [$width, $height, $max2, $expected2], ...
+ * out of parameters:
+ * $width, $height, { $max => $expected, $max2 => $expected2, ... }
+ *
+ * @param $width int
+ * @param $height int
+ * @param $tests array associative array of $max => $expected values
+ * @return array
+ */
+ private static function generateTestFitBoxWidthData( $width, $height, $tests ) {
+ $result = array();
+ foreach ( $tests as $max => $expected ) {
+ $result[] = array( $width, $height, $max, $expected );
}
+ return $result;
}
}
diff --git a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php
index ab33d1c2..0241aec4 100644
--- a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php
+++ b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php
@@ -6,11 +6,6 @@
*/
class SVGMetadataExtractorTest extends MediaWikiTestCase {
- protected function setUp() {
- parent::setUp();
- AutoLoader::loadClass( 'SVGMetadataExtractorTest' );
- }
-
/**
* @dataProvider provideSvgFiles
*/
diff --git a/tests/phpunit/includes/normal/CleanUpTest.php b/tests/phpunit/includes/normal/CleanUpTest.php
deleted file mode 100644
index f4b469b8..00000000
--- a/tests/phpunit/includes/normal/CleanUpTest.php
+++ /dev/null
@@ -1,409 +0,0 @@
-<?php
-/**
- * Tests for UtfNormal::cleanUp() function.
- *
- * Copyright © 2004 Brion Vibber <brion@pobox.com>
- * https://www.mediawiki.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Additional tests for UtfNormal::cleanUp() function, inclusion
- * regression checks for known problems.
- * Requires PHPUnit.
- *
- * @ingroup UtfNormal
- * @group Large
- *
- * @todo covers tags, will be UtfNormal::cleanUp once the below is resolved
- * @todo split me into test methods and providers per the below comment
- *
- * We ignore code coverage for this test suite until they are rewritten
- * to use data providers (bug 46561).
- * @codeCoverageIgnore
- */
-class CleanUpTest extends MediaWikiTestCase {
- /** @todo document */
- public function testAscii() {
- $text = 'This is plain ASCII text.';
- $this->assertEquals( $text, UtfNormal::cleanUp( $text ) );
- }
-
- /** @todo document */
- public function testNull() {
- $text = "a \x00 null";
- $expect = "a \xef\xbf\xbd null";
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testLatin() {
- $text = "L'\xc3\xa9cole";
- $this->assertEquals( $text, UtfNormal::cleanUp( $text ) );
- }
-
- /** @todo document */
- public function testLatinNormal() {
- $text = "L'e\xcc\x81cole";
- $expect = "L'\xc3\xa9cole";
- $this->assertEquals( $expect, UtfNormal::cleanUp( $text ) );
- }
-
- /**
- * This test is *very* expensive!
- * @todo document
- */
- function XtestAllChars() {
- $rep = UTF8_REPLACEMENT;
- for ( $i = 0x0; $i < UNICODE_MAX; $i++ ) {
- $char = codepointToUtf8( $i );
- $clean = UtfNormal::cleanUp( $char );
- $x = sprintf( "%04X", $i );
-
- if ( $i % 0x1000 == 0 ) {
- echo "U+$x\n";
- }
-
- if ( $i == 0x0009 ||
- $i == 0x000a ||
- $i == 0x000d ||
- ( $i > 0x001f && $i < UNICODE_SURROGATE_FIRST ) ||
- ( $i > UNICODE_SURROGATE_LAST && $i < 0xfffe ) ||
- ( $i > 0xffff && $i <= UNICODE_MAX )
- ) {
- if ( isset( UtfNormal::$utfCanonicalComp[$char] )
- || isset( UtfNormal::$utfCanonicalDecomp[$char] )
- ) {
- $comp = UtfNormal::NFC( $char );
- $this->assertEquals(
- bin2hex( $comp ),
- bin2hex( $clean ),
- "U+$x should be decomposed" );
- } else {
- $this->assertEquals(
- bin2hex( $char ),
- bin2hex( $clean ),
- "U+$x should be intact" );
- }
- } else {
- $this->assertEquals( bin2hex( $rep ), bin2hex( $clean ), $x );
- }
- }
- }
-
- /** @todo document */
- public static function provideAllBytes() {
- return array(
- array( '', '' ),
- array( 'x', '' ),
- array( '', 'x' ),
- array( 'x', 'x' ),
- );
- }
-
- /**
- * @dataProvider provideAllBytes
- * @todo document
- */
- function testBytes( $head, $tail ) {
- for ( $i = 0x0; $i < 256; $i++ ) {
- $char = $head . chr( $i ) . $tail;
- $clean = UtfNormal::cleanUp( $char );
- $x = sprintf( "%02X", $i );
-
- if ( $i == 0x0009 ||
- $i == 0x000a ||
- $i == 0x000d ||
- ( $i > 0x001f && $i < 0x80 )
- ) {
- $this->assertEquals(
- bin2hex( $char ),
- bin2hex( $clean ),
- "ASCII byte $x should be intact" );
- if ( $char != $clean ) {
- return;
- }
- } else {
- $norm = $head . UTF8_REPLACEMENT . $tail;
- $this->assertEquals(
- bin2hex( $norm ),
- bin2hex( $clean ),
- "Forbidden byte $x should be rejected" );
- if ( $norm != $clean ) {
- return;
- }
- }
- }
- }
-
- /**
- * @dataProvider provideAllBytes
- * @todo document
- */
- function testDoubleBytes( $head, $tail ) {
- for ( $first = 0xc0; $first < 0x100; $first += 2 ) {
- for ( $second = 0x80; $second < 0x100; $second += 2 ) {
- $char = $head . chr( $first ) . chr( $second ) . $tail;
- $clean = UtfNormal::cleanUp( $char );
- $x = sprintf( "%02X,%02X", $first, $second );
- if ( $first > 0xc1 &&
- $first < 0xe0 &&
- $second < 0xc0
- ) {
- $norm = UtfNormal::NFC( $char );
- $this->assertEquals(
- bin2hex( $norm ),
- bin2hex( $clean ),
- "Pair $x should be intact" );
- if ( $norm != $clean ) {
- return;
- }
- } elseif ( $first > 0xfd || $second > 0xbf ) {
- # fe and ff are not legal head bytes -- expect two replacement chars
- $norm = $head . UTF8_REPLACEMENT . UTF8_REPLACEMENT . $tail;
- $this->assertEquals(
- bin2hex( $norm ),
- bin2hex( $clean ),
- "Forbidden pair $x should be rejected" );
- if ( $norm != $clean ) {
- return;
- }
- } else {
- $norm = $head . UTF8_REPLACEMENT . $tail;
- $this->assertEquals(
- bin2hex( $norm ),
- bin2hex( $clean ),
- "Forbidden pair $x should be rejected" );
- if ( $norm != $clean ) {
- return;
- }
- }
- }
- }
- }
-
- /**
- * @dataProvider provideAllBytes
- * @todo document
- */
- function testTripleBytes( $head, $tail ) {
- for ( $first = 0xc0; $first < 0x100; $first += 2 ) {
- for ( $second = 0x80; $second < 0x100; $second += 2 ) {
- #for( $third = 0x80; $third < 0x100; $third++ ) {
- for ( $third = 0x80; $third < 0x81; $third++ ) {
- $char = $head . chr( $first ) . chr( $second ) . chr( $third ) . $tail;
- $clean = UtfNormal::cleanUp( $char );
- $x = sprintf( "%02X,%02X,%02X", $first, $second, $third );
-
- if ( $first >= 0xe0 &&
- $first < 0xf0 &&
- $second < 0xc0 &&
- $third < 0xc0
- ) {
- if ( $first == 0xe0 && $second < 0xa0 ) {
- $this->assertEquals(
- bin2hex( $head . UTF8_REPLACEMENT . $tail ),
- bin2hex( $clean ),
- "Overlong triplet $x should be rejected" );
- } elseif ( $first == 0xed &&
- ( chr( $first ) . chr( $second ) . chr( $third ) ) >= UTF8_SURROGATE_FIRST
- ) {
- $this->assertEquals(
- bin2hex( $head . UTF8_REPLACEMENT . $tail ),
- bin2hex( $clean ),
- "Surrogate triplet $x should be rejected" );
- } else {
- $this->assertEquals(
- bin2hex( UtfNormal::NFC( $char ) ),
- bin2hex( $clean ),
- "Triplet $x should be intact" );
- }
- } elseif ( $first > 0xc1 && $first < 0xe0 && $second < 0xc0 ) {
- $this->assertEquals(
- bin2hex( UtfNormal::NFC( $head . chr( $first ) .
- chr( $second ) ) . UTF8_REPLACEMENT . $tail ),
- bin2hex( $clean ),
- "Valid 2-byte $x + broken tail" );
- } elseif ( $second > 0xc1 && $second < 0xe0 && $third < 0xc0 ) {
- $this->assertEquals(
- bin2hex( $head . UTF8_REPLACEMENT .
- UtfNormal::NFC( chr( $second ) . chr( $third ) . $tail ) ),
- bin2hex( $clean ),
- "Broken head + valid 2-byte $x" );
- } elseif ( ( $first > 0xfd || $second > 0xfd ) &&
- ( ( $second > 0xbf && $third > 0xbf ) ||
- ( $second < 0xc0 && $third < 0xc0 ) ||
- ( $second > 0xfd ) ||
- ( $third > 0xfd ) )
- ) {
- # fe and ff are not legal head bytes -- expect three replacement chars
- $this->assertEquals(
- bin2hex( $head . UTF8_REPLACEMENT . UTF8_REPLACEMENT . UTF8_REPLACEMENT . $tail ),
- bin2hex( $clean ),
- "Forbidden triplet $x should be rejected" );
- } elseif ( $first > 0xc2 && $second < 0xc0 && $third < 0xc0 ) {
- $this->assertEquals(
- bin2hex( $head . UTF8_REPLACEMENT . $tail ),
- bin2hex( $clean ),
- "Forbidden triplet $x should be rejected" );
- } else {
- $this->assertEquals(
- bin2hex( $head . UTF8_REPLACEMENT . UTF8_REPLACEMENT . $tail ),
- bin2hex( $clean ),
- "Forbidden triplet $x should be rejected" );
- }
- }
- }
- }
- }
-
- /** @todo document */
- public function testChunkRegression() {
- # Check for regression against a chunking bug
- $text = "\x46\x55\xb8" .
- "\xdc\x96" .
- "\xee" .
- "\xe7" .
- "\x44" .
- "\xaa" .
- "\x2f\x25";
- $expect = "\x46\x55\xef\xbf\xbd" .
- "\xdc\x96" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\x44" .
- "\xef\xbf\xbd" .
- "\x2f\x25";
-
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testInterposeRegression() {
- $text = "\x4e\x30" .
- "\xb1" . # bad tail
- "\x3a" .
- "\x92" . # bad tail
- "\x62\x3a" .
- "\x84" . # bad tail
- "\x43" .
- "\xc6" . # bad head
- "\x3f" .
- "\x92" . # bad tail
- "\xad" . # bad tail
- "\x7d" .
- "\xd9\x95";
-
- $expect = "\x4e\x30" .
- "\xef\xbf\xbd" .
- "\x3a" .
- "\xef\xbf\xbd" .
- "\x62\x3a" .
- "\xef\xbf\xbd" .
- "\x43" .
- "\xef\xbf\xbd" .
- "\x3f" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\x7d" .
- "\xd9\x95";
-
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testOverlongRegression() {
- $text = "\x67" .
- "\x1a" . # forbidden ascii
- "\xea" . # bad head
- "\xc1\xa6" . # overlong sequence
- "\xad" . # bad tail
- "\x1c" . # forbidden ascii
- "\xb0" . # bad tail
- "\x3c" .
- "\x9e"; # bad tail
- $expect = "\x67" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\x3c" .
- "\xef\xbf\xbd";
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testSurrogateRegression() {
- $text = "\xed\xb4\x96" . # surrogate 0xDD16
- "\x83" . # bad tail
- "\xb4" . # bad tail
- "\xac"; # bad head
- $expect = "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd";
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testBomRegression() {
- $text = "\xef\xbf\xbe" . # U+FFFE, illegal char
- "\xb2" . # bad tail
- "\xef" . # bad head
- "\x59";
- $expect = "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\xef\xbf\xbd" .
- "\x59";
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testForbiddenRegression() {
- $text = "\xef\xbf\xbf"; # U+FFFF, illegal char
- $expect = "\xef\xbf\xbd";
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-
- /** @todo document */
- public function testHangulRegression() {
- $text = "\xed\x9c\xaf" . # Hangul char
- "\xe1\x87\x81"; # followed by another final jamo
- $expect = $text; # Should *not* change.
- $this->assertEquals(
- bin2hex( $expect ),
- bin2hex( UtfNormal::cleanUp( $text ) ) );
- }
-}
diff --git a/tests/phpunit/includes/objectcache/BagOStuffTest.php b/tests/phpunit/includes/objectcache/BagOStuffTest.php
index 987b6e64..4516bb4e 100644
--- a/tests/phpunit/includes/objectcache/BagOStuffTest.php
+++ b/tests/phpunit/includes/objectcache/BagOStuffTest.php
@@ -1,8 +1,6 @@
<?php
/**
- * This class will test BagOStuff.
- *
- * @author Matthias Mullie <mmullie@wikimedia.org>
+ * @author Matthias Mullie <mmullie@wikimedia.org>
*/
class BagOStuffTest extends MediaWikiTestCase {
private $cache;
@@ -23,6 +21,10 @@ class BagOStuffTest extends MediaWikiTestCase {
$this->cache->delete( wfMemcKey( 'test' ) );
}
+ /**
+ * @covers BagOStuff::merge
+ * @covers BagOStuff::mergeViaLock
+ */
public function testMerge() {
$key = wfMemcKey( 'test' );
@@ -100,6 +102,9 @@ class BagOStuffTest extends MediaWikiTestCase {
}
}
+ /**
+ * @covers BagOStuff::add
+ */
public function testAdd() {
$key = wfMemcKey( 'test' );
$this->assertTrue( $this->cache->add( $key, 'test' ) );
@@ -125,6 +130,9 @@ class BagOStuffTest extends MediaWikiTestCase {
$this->assertEquals( $expectedValue, $actualValue, 'Value should be 1 after incrementing' );
}
+ /**
+ * @covers BagOStuff::getMulti
+ */
public function testGetMulti() {
$value1 = array( 'this' => 'is', 'a' => 'test' );
$value2 = array( 'this' => 'is', 'another' => 'test' );
diff --git a/tests/phpunit/includes/ArticleTablesTest.php b/tests/phpunit/includes/page/ArticleTablesTest.php
index 9f2b7a05..9f2b7a05 100644
--- a/tests/phpunit/includes/ArticleTablesTest.php
+++ b/tests/phpunit/includes/page/ArticleTablesTest.php
diff --git a/tests/phpunit/includes/ArticleTest.php b/tests/phpunit/includes/page/ArticleTest.php
index ae069eaf..ae069eaf 100644
--- a/tests/phpunit/includes/ArticleTest.php
+++ b/tests/phpunit/includes/page/ArticleTest.php
diff --git a/tests/phpunit/includes/ImagePage404Test.php b/tests/phpunit/includes/page/ImagePage404Test.php
index 197a2b32..197a2b32 100644
--- a/tests/phpunit/includes/ImagePage404Test.php
+++ b/tests/phpunit/includes/page/ImagePage404Test.php
diff --git a/tests/phpunit/includes/ImagePageTest.php b/tests/phpunit/includes/page/ImagePageTest.php
index 3c255b5f..3c255b5f 100644
--- a/tests/phpunit/includes/ImagePageTest.php
+++ b/tests/phpunit/includes/page/ImagePageTest.php
diff --git a/tests/phpunit/includes/WikiPageTest.php b/tests/phpunit/includes/page/WikiPageTest.php
index 7f7945b8..c011e9a9 100644
--- a/tests/phpunit/includes/WikiPageTest.php
+++ b/tests/phpunit/includes/page/WikiPageTest.php
@@ -55,8 +55,8 @@ class WikiPageTest extends MediaWikiLangTestCase {
}
/**
- * @param Title $title
- * @param string $model
+ * @param Title|string $title
+ * @param string|null $model
* @return WikiPage
*/
protected function newPage( $title, $model = null ) {
diff --git a/tests/phpunit/includes/WikiPageTestContentHandlerUseDB.php b/tests/phpunit/includes/page/WikiPageTestContentHandlerUseDB.php
index 3db76280..3db76280 100644
--- a/tests/phpunit/includes/WikiPageTestContentHandlerUseDB.php
+++ b/tests/phpunit/includes/page/WikiPageTestContentHandlerUseDB.php
diff --git a/tests/phpunit/includes/parser/NewParserTest.php b/tests/phpunit/includes/parser/NewParserTest.php
index 0df52f5e..91aad10c 100644
--- a/tests/phpunit/includes/parser/NewParserTest.php
+++ b/tests/phpunit/includes/parser/NewParserTest.php
@@ -124,7 +124,7 @@ class NewParserTest extends MediaWikiTestCase {
$tmpGlobals['wgFileExtensions'][] = 'svg';
$tmpGlobals['wgSVGConverter'] = 'rsvg';
$tmpGlobals['wgSVGConverters']['rsvg'] =
- '$path/rsvg-convert -w $width -h $height $input -o $output';
+ '$path/rsvg-convert -w $width -h $height -o $output $input';
if ( $GLOBALS['wgStyleDirectory'] === false ) {
$tmpGlobals['wgStyleDirectory'] = "$IP/skins";
@@ -160,9 +160,6 @@ class NewParserTest extends MediaWikiTestCase {
$this->djVuSupport = new DjVuSupport();
// Tidy support
$this->tidySupport = new TidySupport();
- // We always set 'wgUseTidy' to false when parsing, but certain
- // test-running modes still use tidy if available, so ensure
- // that the tidy-related options are all set to their defaults.
$tmpGlobals['wgUseTidy'] = false;
$tmpGlobals['wgAlwaysUseTidy'] = false;
$tmpGlobals['wgDebugTidy'] = false;
@@ -419,6 +416,7 @@ class NewParserTest extends MediaWikiTestCase {
'wgMathDirectory' => $uploadDir . '/math',
'wgDefaultLanguageVariant' => $variant,
'wgLinkHolderBatchSize' => $linkHolderBatchSize,
+ 'wgUseTidy' => isset( $opts['tidy'] ),
);
if ( $config ) {
@@ -434,7 +432,7 @@ class NewParserTest extends MediaWikiTestCase {
$this->savedGlobals = array();
/** @since 1.20 */
- wfRunHooks( 'ParserTestGlobals', array( &$settings ) );
+ Hooks::run( 'ParserTestGlobals', array( &$settings ) );
$langObj = Language::factory( $lang );
$settings['wgContLang'] = $langObj;
@@ -480,16 +478,16 @@ class NewParserTest extends MediaWikiTestCase {
*/
protected function getUploadDir() {
if ( $this->keepUploads ) {
+ // Don't use getNewTempDirectory() as this is meant to persist
$dir = wfTempDir() . '/mwParser-images';
if ( is_dir( $dir ) ) {
return $dir;
}
} else {
- $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images";
+ $dir = $this->getNewTempDirectory();
}
- // wfDebug( "Creating upload directory $dir\n" );
if ( file_exists( $dir ) ) {
wfDebug( "Already exists!\n" );
@@ -727,12 +725,21 @@ class NewParserTest extends MediaWikiTestCase {
. "Current configuration is:\n\$wgTexvc = '$wgTexvc'" );
}
}
+
if ( isset( $opts['djvu'] ) ) {
if ( !$this->djVuSupport->isEnabled() ) {
$this->markTestSkipped( "SKIPPED: djvu binaries do not exist or are not executable.\n" );
}
}
+ if ( isset( $opts['tidy'] ) ) {
+ if ( !$this->tidySupport->isEnabled() ) {
+ $this->markTestSkipped( "SKIPPED: tidy extension is not installed.\n" );
+ } else {
+ $options->setTidy( true );
+ }
+ }
+
if ( isset( $opts['pst'] ) ) {
$out = $parser->preSaveTransform( $input, $title, $user, $options );
} elseif ( isset( $opts['msg'] ) ) {
@@ -753,12 +760,7 @@ class NewParserTest extends MediaWikiTestCase {
$output->setTOCEnabled( !isset( $opts['notoc'] ) );
$out = $output->getText();
if ( isset( $opts['tidy'] ) ) {
- if ( !$this->tidySupport->isEnabled() ) {
- $this->markTestSkipped( "SKIPPED: tidy extension is not installed.\n" );
- } else {
- $out = MWTidy::tidy( $out );
- $out = preg_replace( '/\s+$/', '', $out );
- }
+ $out = preg_replace( '/\s+$/', '', $out );
}
if ( isset( $opts['showtitle'] ) ) {
@@ -769,6 +771,14 @@ class NewParserTest extends MediaWikiTestCase {
$out = "$title\n$out";
}
+ if ( isset( $opts['showindicators'] ) ) {
+ $indicators = '';
+ foreach ( $output->getIndicators() as $id => $content ) {
+ $indicators .= "$id=$content\n";
+ }
+ $out = $indicators . $out;
+ }
+
if ( isset( $opts['ill'] ) ) {
$out = implode( ' ', $output->getLanguageLinks() );
} elseif ( isset( $opts['cat'] ) ) {
@@ -939,7 +949,7 @@ class NewParserTest extends MediaWikiTestCase {
$class = $wgParserConf['class'];
$parser = new $class( array( 'preprocessorClass' => $preprocessor ) + $wgParserConf );
- wfRunHooks( 'ParserTestParser', array( &$parser ) );
+ Hooks::run( 'ParserTestParser', array( &$parser ) );
return $parser;
}
diff --git a/tests/phpunit/includes/parser/ParserOutputTest.php b/tests/phpunit/includes/parser/ParserOutputTest.php
index c024cee5..e660e096 100644
--- a/tests/phpunit/includes/parser/ParserOutputTest.php
+++ b/tests/phpunit/includes/parser/ParserOutputTest.php
@@ -1,5 +1,9 @@
<?php
+/**
+ * @group Database
+ * ^--- trigger DB shadowing because we are using Title magic
+ */
class ParserOutputTest extends MediaWikiTestCase {
public static function provideIsLinkInternal() {
@@ -84,4 +88,5 @@ class ParserOutputTest extends MediaWikiTestCase {
$this->assertEquals( $po->getProperty( 'foo' ), false );
$this->assertArrayNotHasKey( 'foo', $properties );
}
+
}
diff --git a/tests/phpunit/includes/parser/TagHooksTest.php b/tests/phpunit/includes/parser/TagHooksTest.php
index e3c4cc84..251da471 100644
--- a/tests/phpunit/includes/parser/TagHooksTest.php
+++ b/tests/phpunit/includes/parser/TagHooksTest.php
@@ -89,7 +89,7 @@ class TagHookTest extends MediaWikiTestCase {
global $wgParserConf, $wgContLang;
$parser = new Parser( $wgParserConf );
- $parser->setFunctionTagHook( $tag, array( $this, 'functionTagCallback' ), SFH_OBJECT_ARGS );
+ $parser->setFunctionTagHook( $tag, array( $this, 'functionTagCallback' ), Parser::SFH_OBJECT_ARGS );
$parser->parse(
"Foo<$tag>Bar</$tag>Baz",
Title::newFromText( 'Test' ),
diff --git a/tests/phpunit/includes/PasswordTest.php b/tests/phpunit/includes/password/PasswordTest.php
index ceb794b5..5ad8aca6 100644
--- a/tests/phpunit/includes/PasswordTest.php
+++ b/tests/phpunit/includes/password/PasswordTest.php
@@ -30,4 +30,10 @@ class PasswordTest extends MediaWikiTestCase {
$this->assertFalse( $invalid1->equals( $invalid2 ) );
}
+
+ public function testInvalidPlaintext() {
+ $invalid = User::getPasswordFactory()->newFromPlaintext( null );
+
+ $this->assertInstanceOf( 'InvalidPassword', $invalid );
+ }
}
diff --git a/tests/phpunit/includes/password/PasswordTestCase.php b/tests/phpunit/includes/password/PasswordTestCase.php
index ef16f1c4..9a142cbc 100644
--- a/tests/phpunit/includes/password/PasswordTestCase.php
+++ b/tests/phpunit/includes/password/PasswordTestCase.php
@@ -49,10 +49,13 @@ abstract class PasswordTestCase extends MediaWikiTestCase {
* An array of tests in the form of (bool, string, string), where the first
* element is whether the second parameter (a password hash) and the third
* parameter (a password) should match.
- *
* @return array
+ * @throws MWException
+ * @abstract
*/
- abstract public static function providePasswordTests();
+ public static function providePasswordTests() {
+ throw new MWException( "Not implemented" );
+ }
/**
* @dataProvider providePasswordTests
diff --git a/tests/phpunit/includes/registration/ExtensionProcessorTest.php b/tests/phpunit/includes/registration/ExtensionProcessorTest.php
new file mode 100644
index 00000000..8715711f
--- /dev/null
+++ b/tests/phpunit/includes/registration/ExtensionProcessorTest.php
@@ -0,0 +1,374 @@
+<?php
+
+class ExtensionProcessorTest extends MediaWikiTestCase {
+
+ private $dir;
+
+ public function setUp() {
+ parent::setUp();
+ $this->dir = __DIR__ . '/FooBar/extension.json';
+ }
+
+ /**
+ * 'name' is absolutely required
+ *
+ * @var array
+ */
+ static $default = array(
+ 'name' => 'FooBar',
+ );
+
+ /**
+ * @covers ExtensionProcessor::extractInfo
+ */
+ public function testExtractInfo() {
+ // Test that attributes that begin with @ are ignored
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, self::$default + array(
+ '@metadata' => array( 'foobarbaz' ),
+ 'AnAttribute' => array( 'omg' ),
+ 'AutoloadClasses' => array( 'FooBar' => 'includes/FooBar.php' ),
+ ) );
+
+ $extracted = $processor->getExtractedInfo();
+ $attributes = $extracted['attributes'];
+ $this->assertArrayHasKey( 'AnAttribute', $attributes );
+ $this->assertArrayNotHasKey( '@metadata', $attributes );
+ $this->assertArrayNotHasKey( 'AutoloadClasses', $attributes );
+ }
+
+ public static function provideRegisterHooks() {
+ return array(
+ // No hooks
+ array(
+ array(),
+ self::$default,
+ array(),
+ ),
+ // No current hooks, adding one for "FooBaz"
+ array(
+ array(),
+ array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default,
+ array( 'FooBaz' => array( 'FooBazCallback' ) ),
+ ),
+ // Hook for "FooBaz", adding another one
+ array(
+ array( 'FooBaz' => array( 'PriorCallback' ) ),
+ array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default,
+ array( 'FooBaz' => array( 'PriorCallback', 'FooBazCallback' ) ),
+ ),
+ // Hook for "BarBaz", adding one for "FooBaz"
+ array(
+ array( 'BarBaz' => array( 'BarBazCallback' ) ),
+ array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default,
+ array(
+ 'BarBaz' => array( 'BarBazCallback' ),
+ 'FooBaz' => array( 'FooBazCallback' ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @covers ExtensionProcessor::extractHooks
+ * @dataProvider provideRegisterHooks
+ */
+ public function testRegisterHooks( $pre, $info, $expected ) {
+ $processor = new MockExtensionProcessor( array( 'wgHooks' => $pre ) );
+ $processor->extractInfo( $this->dir, $info );
+ $extracted = $processor->getExtractedInfo();
+ $this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
+ }
+
+ /**
+ * @covers ExtensionProcessor::extractConfig
+ */
+ public function testExtractConfig() {
+ $processor = new ExtensionProcessor;
+ $info = array(
+ 'config' => array(
+ 'Bar' => 'somevalue',
+ 'Foo' => 10,
+ '@IGNORED' => 'yes',
+ ),
+ ) + self::$default;
+ $processor->extractInfo( $this->dir, $info );
+ $extracted = $processor->getExtractedInfo();
+ $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
+ $this->assertEquals( 10, $extracted['globals']['wgFoo'] );
+ $this->assertArrayNotHasKey( 'wg@IGNORED', $extracted['globals'] );
+ }
+
+ public static function provideExtracttExtensionMessagesFiles() {
+ $dir = __DIR__ . '/FooBar/';
+ return array(
+ array(
+ array( 'ExtensionMessagesFiles' => array( 'FooBarAlias' => 'FooBar.alias.php' ) ),
+ array( 'wgExtensionMessagesFiles' => array( 'FooBarAlias' => $dir . 'FooBar.alias.php' ) )
+ ),
+ array(
+ array(
+ 'ExtensionMessagesFiles' => array(
+ 'FooBarAlias' => 'FooBar.alias.php',
+ 'FooBarMagic' => 'FooBar.magic.i18n.php',
+ ),
+ ),
+ array(
+ 'wgExtensionMessagesFiles' => array(
+ 'FooBarAlias' => $dir . 'FooBar.alias.php',
+ 'FooBarMagic' => $dir . 'FooBar.magic.i18n.php',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @covers ExtensionProcessor::extracttExtensionMessagesFiles
+ * @dataProvider provideExtracttExtensionMessagesFiles
+ */
+ public function testExtracttExtensionMessagesFiles( $input, $expected ) {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, $input + self::$default );
+ $out = $processor->getExtractedInfo();
+ foreach ( $expected as $key => $value ) {
+ $this->assertEquals( $value, $out['globals'][$key] );
+ }
+ }
+
+
+ public static function provideExtractMessagesDirs() {
+ $dir = __DIR__ . '/FooBar/';
+ return array(
+ array(
+ array( 'MessagesDirs' => array( 'VisualEditor' => 'i18n' ) ),
+ array( 'wgMessagesDirs' => array( 'VisualEditor' => array( $dir . 'i18n' ) ) )
+ ),
+ array(
+ array( 'MessagesDirs' => array( 'VisualEditor' => array( 'i18n', 'foobar' ) ) ),
+ array( 'wgMessagesDirs' => array( 'VisualEditor' => array( $dir . 'i18n', $dir . 'foobar' ) ) )
+ ),
+ );
+ }
+
+ /**
+ * @covers ExtensionProcessor::extractMessagesDirs
+ * @dataProvider provideExtractMessagesDirs
+ */
+ public function testExtractMessagesDirs( $input, $expected ) {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, $input + self::$default );
+ $out = $processor->getExtractedInfo();
+ foreach ( $expected as $key => $value ) {
+ $this->assertEquals( $value, $out['globals'][$key] );
+ }
+ }
+
+ /**
+ * @covers ExtensionProcessor::extractResourceLoaderModules
+ * @dataProvider provideExtractResourceLoaderModules
+ */
+ public function testExtractResourceLoaderModules( $input, $expected ) {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo( $this->dir, $input + self::$default );
+ $out = $processor->getExtractedInfo();
+ foreach ( $expected as $key => $value ) {
+ $this->assertEquals( $value, $out['globals'][$key] );
+ }
+ }
+
+ public static function provideExtractResourceLoaderModules() {
+ $dir = __DIR__ . '/FooBar/';
+ return array(
+ // Generic module with localBasePath/remoteExtPath specified
+ array(
+ // Input
+ array(
+ 'ResourceModules' => array(
+ 'test.foo' => array(
+ 'styles' => 'foobar.js',
+ 'localBasePath' => '',
+ 'remoteExtPath' => 'FooBar',
+ ),
+ ),
+ ),
+ // Expected
+ array(
+ 'wgResourceModules' => array(
+ 'test.foo' => array(
+ 'styles' => 'foobar.js',
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'FooBar',
+ ),
+ ),
+ ),
+ ),
+ // ResourceFileModulePaths specified:
+ array(
+ // Input
+ array(
+ 'ResourceFileModulePaths' => array(
+ 'localBasePath' => '',
+ 'remoteExtPath' => 'FooBar',
+ ),
+ 'ResourceModules' => array(
+ // No paths
+ 'test.foo' => array(
+ 'styles' => 'foo.js',
+ ),
+ // Different paths set
+ 'test.bar' => array(
+ 'styles' => 'bar.js',
+ 'localBasePath' => 'subdir',
+ 'remoteExtPath' => 'FooBar/subdir',
+ ),
+ // Custom class with no paths set
+ 'test.class' => array(
+ 'class' => 'FooBarModule',
+ 'extra' => 'argument',
+ ),
+ // Custom class with a localBasePath
+ 'test.class.with.path' => array(
+ 'class' => 'FooBarPathModule',
+ 'extra' => 'argument',
+ 'localBasePath' => '',
+ )
+ ),
+ ),
+ // Expected
+ array(
+ 'wgResourceModules' => array(
+ 'test.foo' => array(
+ 'styles' => 'foo.js',
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'FooBar',
+ ),
+ 'test.bar' => array(
+ 'styles' => 'bar.js',
+ 'localBasePath' => $dir . 'subdir',
+ 'remoteExtPath' => 'FooBar/subdir',
+ ),
+ 'test.class' => array(
+ 'class' => 'FooBarModule',
+ 'extra' => 'argument',
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'FooBar',
+ ),
+ 'test.class.with.path' => array(
+ 'class' => 'FooBarPathModule',
+ 'extra' => 'argument',
+ 'localBasePath' => $dir,
+ 'remoteExtPath' => 'FooBar',
+ )
+ ),
+ ),
+ ),
+ // ResourceModuleSkinStyles with file module paths
+ array(
+ // Input
+ array(
+ 'ResourceFileModulePaths' => array(
+ 'localBasePath' => '',
+ 'remoteSkinPath' => 'FooBar',
+ ),
+ 'ResourceModuleSkinStyles' => array(
+ 'foobar' => array(
+ 'test.foo' => 'foo.css',
+ )
+ ),
+ ),
+ // Expected
+ array(
+ 'wgResourceModuleSkinStyles' => array(
+ 'foobar' => array(
+ 'test.foo' => 'foo.css',
+ 'localBasePath' => $dir,
+ 'remoteSkinPath' => 'FooBar',
+ ),
+ ),
+ ),
+ ),
+ // ResourceModuleSkinStyles with file module paths and an override
+ array(
+ // Input
+ array(
+ 'ResourceFileModulePaths' => array(
+ 'localBasePath' => '',
+ 'remoteSkinPath' => 'FooBar',
+ ),
+ 'ResourceModuleSkinStyles' => array(
+ 'foobar' => array(
+ 'test.foo' => 'foo.css',
+ 'remoteSkinPath' => 'BarFoo'
+ ),
+ ),
+ ),
+ // Expected
+ array(
+ 'wgResourceModuleSkinStyles' => array(
+ 'foobar' => array(
+ 'test.foo' => 'foo.css',
+ 'localBasePath' => $dir,
+ 'remoteSkinPath' => 'BarFoo',
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ public static function provideSetToGlobal() {
+ return array(
+ array(
+ array( 'wgAPIModules', 'wgAvailableRights' ),
+ array(),
+ array(
+ 'APIModules' => array( 'foobar' => 'ApiFooBar' ),
+ 'AvailableRights' => array( 'foobar', 'unfoobar' ),
+ ),
+ array(
+ 'wgAPIModules' => array( 'foobar' => 'ApiFooBar' ),
+ 'wgAvailableRights' => array( 'foobar', 'unfoobar' ),
+ ),
+ ),
+ array(
+ array( 'wgAPIModules', 'wgAvailableRights' ),
+ array(
+ 'wgAPIModules' => array( 'barbaz' => 'ApiBarBaz' ),
+ 'wgAvailableRights' => array( 'barbaz' )
+ ),
+ array(
+ 'APIModules' => array( 'foobar' => 'ApiFooBar' ),
+ 'AvailableRights' => array( 'foobar', 'unfoobar' ),
+ ),
+ array(
+ 'wgAPIModules' => array( 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ),
+ 'wgAvailableRights' => array( 'barbaz', 'foobar', 'unfoobar' ),
+ ),
+ ),
+ array(
+ array( 'wgGroupPermissions' ),
+ array(
+ 'wgGroupPermissions' => array( 'sysop' => array( 'delete' ) ),
+ ),
+ array(
+ 'GroupPermissions' => array( 'sysop' => array( 'undelete' ), 'user' => array( 'edit' ) ),
+ ),
+ array(
+ 'wgGroupPermissions' => array( 'sysop' => array( 'delete', 'undelete' ), 'user' => array( 'edit' ) ),
+ )
+ )
+ );
+ }
+}
+
+
+/**
+ * Allow overriding the default value of $this->globals
+ * so we can test merging
+ */
+class MockExtensionProcessor extends ExtensionProcessor {
+ public function __construct( $globals = array() ) {
+ $this->globals = $globals + $this->globals;
+ }
+}
diff --git a/tests/phpunit/includes/registration/ExtensionRegistryTest.php b/tests/phpunit/includes/registration/ExtensionRegistryTest.php
new file mode 100644
index 00000000..1b24628c
--- /dev/null
+++ b/tests/phpunit/includes/registration/ExtensionRegistryTest.php
@@ -0,0 +1,195 @@
+<?php
+
+class ExtensionRegistryTest extends MediaWikiTestCase {
+
+ /**
+ * @covers ExtensionRegistry::exportExtractedData
+ * @dataProvider provideExportExtractedDataGlobals
+ */
+ public function testExportExtractedDataGlobals( $desc, $before, $globals, $expected ) {
+ // Set globals for test
+ if ( $before ) {
+ foreach ( $before as $key => $value ) {
+ // mw prefixed globals does not exist normally
+ if ( substr( $key, 0, 2 ) == 'mw' ) {
+ $GLOBALS[$key] = $value;
+ } else {
+ $this->setMwGlobals( $key, $value );
+ }
+ }
+ }
+
+ $info = array(
+ 'globals' => $globals,
+ 'callbacks' => array(),
+ 'defines' => array(),
+ 'credits' => array(),
+ 'attributes' => array(),
+ );
+ $registry = new ExtensionRegistry();
+ $class = new ReflectionClass( 'ExtensionRegistry' );
+ $method = $class->getMethod( 'exportExtractedData' );
+ $method->setAccessible( true );
+ $method->invokeArgs( $registry, array( $info ) );
+ foreach ( $expected as $name => $value ) {
+ $this->assertArrayHasKey( $name, $GLOBALS, $desc );
+ $this->assertEquals( $value, $GLOBALS[$name], $desc );
+ }
+
+ // Remove mw prefixed globals
+ if ( $before ) {
+ foreach ( $before as $key => $value ) {
+ if ( substr( $key, 0, 2 ) == 'mw' ) {
+ unset( $GLOBALS[$key] );
+ }
+ }
+ }
+ }
+
+ public static function provideExportExtractedDataGlobals() {
+ // "mwtest" prefix used instead of "$wg" to avoid potential conflicts
+ return array(
+ array(
+ 'Simple non-array values',
+ array(
+ 'mwtestFooBarConfig' => true,
+ 'mwtestFooBarConfig2' => 'string',
+ ),
+ array(
+ 'mwtestFooBarDefault' => 1234,
+ 'mwtestFooBarConfig' => false,
+ ),
+ array(
+ 'mwtestFooBarConfig' => true,
+ 'mwtestFooBarConfig2' => 'string',
+ 'mwtestFooBarDefault' => 1234,
+ ),
+ ),
+ array(
+ 'No global already set, simple array',
+ null,
+ array(
+ 'mwtestDefaultOptions' => array(
+ 'foobar' => true,
+ )
+ ),
+ array(
+ 'mwtestDefaultOptions' => array(
+ 'foobar' => true,
+ )
+ ),
+ ),
+ array(
+ 'Global already set, simple array',
+ array(
+ 'mwtestDefaultOptions' => array(
+ 'foobar' => true,
+ 'foo' => 'string'
+ ),
+ ),
+ array(
+ 'mwtestDefaultOptions' => array(
+ 'barbaz' => 12345,
+ 'foobar' => false,
+ ),
+ ),
+ array(
+ 'mwtestDefaultOptions' => array(
+ 'barbaz' => 12345,
+ 'foo' => 'string',
+ 'foobar' => true,
+ ),
+ )
+ ),
+ array(
+ 'No global already set, $wgHooks',
+ array(
+ 'wgHooks' => array(),
+ ),
+ array(
+ 'wgHooks' => array(
+ 'FooBarEvent' => array(
+ 'FooBarClass::onFooBarEvent'
+ ),
+ ),
+ ),
+ array(
+ 'wgHooks' => array(
+ 'FooBarEvent' => array(
+ 'FooBarClass::onFooBarEvent'
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'Global already set, $wgHooks',
+ array(
+ 'wgHooks' => array(
+ 'FooBarEvent' => array(
+ 'FooBarClass::onFooBarEvent'
+ ),
+ 'BazBarEvent' => array(
+ 'FooBarClass::onBazBarEvent',
+ ),
+ ),
+ ),
+ array(
+ 'wgHooks' => array(
+ 'FooBarEvent' => array(
+ 'BazBarClass::onFooBarEvent',
+ ),
+ ),
+ ),
+ array(
+ 'wgHooks' => array(
+ 'FooBarEvent' => array(
+ 'FooBarClass::onFooBarEvent',
+ 'BazBarClass::onFooBarEvent',
+ ),
+ 'BazBarEvent' => array(
+ 'FooBarClass::onBazBarEvent',
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'Global already set, $wgGroupPermissions',
+ array(
+ 'wgGroupPermissions' => array(
+ 'sysop' => array(
+ 'something' => true,
+ ),
+ 'user' => array(
+ 'somethingtwo' => true,
+ )
+ ),
+ ),
+ array(
+ 'wgGroupPermissions' => array(
+ 'customgroup' => array(
+ 'right' => true,
+ ),
+ 'user' => array(
+ 'right' => true,
+ 'somethingtwo' => false,
+ )
+ ),
+ ),
+ array(
+ 'wgGroupPermissions' => array(
+ 'customgroup' => array(
+ 'right' => true,
+ ),
+ 'sysop' => array(
+ 'something' => true,
+ ),
+ 'user' => array(
+ 'somethingtwo' => true,
+ 'right' => true,
+ )
+ ),
+ ),
+ )
+ );
+ }
+}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
new file mode 100644
index 00000000..122995a5
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
@@ -0,0 +1,247 @@
+<?php
+
+/**
+ * @group ResourceLoader
+ */
+class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ // The return value of the closure shouldn't matter since this test should
+ // never call it
+ SkinFactory::getDefaultInstance()->register(
+ 'fakeskin',
+ 'FakeSkin',
+ function () {
+ }
+ );
+ }
+
+ private static function getModules() {
+ $base = array(
+ 'localBasePath' => realpath( dirname( __FILE__ ) ),
+ );
+
+ return array(
+ 'noTemplateModule' => array(),
+
+ 'htmlTemplateModule' => $base + array(
+ 'templates' => array(
+ 'templates/template.html',
+ 'templates/template2.html',
+ )
+ ),
+
+ 'aliasedHtmlTemplateModule' => $base + array(
+ 'templates' => array(
+ 'foo.html' => 'templates/template.html',
+ 'bar.html' => 'templates/template2.html',
+ )
+ ),
+
+ 'templateModuleHandlebars' => $base + array(
+ 'templates' => array(
+ 'templates/template_awesome.handlebars',
+ ),
+ ),
+
+ 'aliasFooFromBar' => $base + array(
+ 'templates' => array(
+ 'foo.foo' => 'templates/template.bar',
+ ),
+ ),
+ );
+ }
+
+ public static function providerTemplateDependencies() {
+ $modules = self::getModules();
+
+ return array(
+ array(
+ $modules['noTemplateModule'],
+ array(),
+ ),
+ array(
+ $modules['htmlTemplateModule'],
+ array(
+ 'mediawiki.template',
+ ),
+ ),
+ array(
+ $modules['templateModuleHandlebars'],
+ array(
+ 'mediawiki.template',
+ 'mediawiki.template.handlebars',
+ ),
+ ),
+ array(
+ $modules['aliasFooFromBar'],
+ array(
+ 'mediawiki.template',
+ 'mediawiki.template.foo',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providerTemplateDependencies
+ * @covers ResourceLoaderFileModule::__construct
+ * @covers ResourceLoaderFileModule::getDependencies
+ */
+ public function testTemplateDependencies( $module, $expected ) {
+ $rl = new ResourceLoaderFileModule( $module );
+ $this->assertEquals( $rl->getDependencies(), $expected );
+ }
+
+ /**
+ * @covers ResourceLoaderFileModule::getAllStyleFiles
+ * @covers ResourceLoaderFileModule::getAllSkinStyleFiles
+ * @covers ResourceLoaderFileModule::getSkinStyleFiles
+ */
+ public function testGetAllSkinStyleFiles() {
+ $baseParams = array(
+ 'scripts' => array(
+ 'foo.js',
+ 'bar.js',
+ ),
+ 'styles' => array(
+ 'foo.css',
+ 'bar.css' => array( 'media' => 'print' ),
+ 'screen.less' => array( 'media' => 'screen' ),
+ 'screen-query.css' => array( 'media' => 'screen and (min-width: 400px)' ),
+ ),
+ 'skinStyles' => array(
+ 'default' => 'quux-fallback.less',
+ 'fakeskin' => array(
+ 'baz-vector.css',
+ 'quux-vector.less',
+ ),
+ ),
+ 'messages' => array(
+ 'hello',
+ 'world',
+ ),
+ );
+
+ $module = new ResourceLoaderFileModule( $baseParams );
+
+ $this->assertEquals(
+ array(
+ 'foo.css',
+ 'baz-vector.css',
+ 'quux-vector.less',
+ 'quux-fallback.less',
+ 'bar.css',
+ 'screen.less',
+ 'screen-query.css',
+ ),
+ array_map( 'basename', $module->getAllStyleFiles() )
+ );
+ }
+
+ /**
+ * Strip @noflip annotations from CSS code.
+ * @param string $css
+ * @return string
+ */
+ private static function stripNoflip( $css ) {
+ return str_replace( '/*@noflip*/ ', '', $css );
+ }
+
+ /**
+ * What happens when you mix @embed and @noflip?
+ * This really is an integration test, but oh well.
+ *
+ * @covers ResourceLoaderFileModule::getStyles
+ * @covers ResourceLoaderFileModule::getStyleFiles
+ */
+ public function testMixedCssAnnotations( ) {
+ $basePath = __DIR__ . '/../../data/css';
+ $testModule = new ResourceLoaderFileModule( array(
+ 'localBasePath' => $basePath,
+ 'styles' => array( 'test.css' ),
+ ) );
+ $expectedModule = new ResourceLoaderFileModule( array(
+ 'localBasePath' => $basePath,
+ 'styles' => array( 'expected.css' ),
+ ) );
+
+ $contextLtr = $this->getResourceLoaderContext( 'en', 'ltr' );
+ $contextRtl = $this->getResourceLoaderContext( 'he', 'rtl' );
+
+ // Since we want to compare the effect of @noflip+@embed against the effect of just @embed, and
+ // the @noflip annotations are always preserved, we need to strip them first.
+ $this->assertEquals(
+ $expectedModule->getStyles( $contextLtr ),
+ self::stripNoflip( $testModule->getStyles( $contextLtr ) ),
+ "/*@noflip*/ with /*@embed*/ gives correct results in LTR mode"
+ );
+ $this->assertEquals(
+ $expectedModule->getStyles( $contextLtr ),
+ self::stripNoflip( $testModule->getStyles( $contextRtl ) ),
+ "/*@noflip*/ with /*@embed*/ gives correct results in RTL mode"
+ );
+ }
+
+ public static function providerGetTemplates() {
+ $modules = self::getModules();
+
+ return array(
+ array(
+ $modules['noTemplateModule'],
+ array(),
+ ),
+ array(
+ $modules['templateModuleHandlebars'],
+ array(
+ 'templates/template_awesome.handlebars' => "wow\n",
+ ),
+ ),
+ array(
+ $modules['htmlTemplateModule'],
+ array(
+ 'templates/template.html' => "<strong>hello</strong>\n",
+ 'templates/template2.html' => "<div>goodbye</div>\n",
+ ),
+ ),
+ array(
+ $modules['aliasedHtmlTemplateModule'],
+ array(
+ 'foo.html' => "<strong>hello</strong>\n",
+ 'bar.html' => "<div>goodbye</div>\n",
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providerGetTemplates
+ * @covers ResourceLoaderFileModule::getTemplates
+ */
+ public function testGetTemplates( $module, $expected ) {
+ $rl = new ResourceLoaderFileModule( $module );
+
+ $this->assertEquals( $rl->getTemplates(), $expected );
+ }
+
+ public static function providerGetModifiedTime() {
+ $modules = self::getModules();
+
+ return array(
+ // Check the default value when no templates present in module is 1
+ array( $modules['noTemplateModule'], 1 ),
+ );
+ }
+
+ /**
+ * @dataProvider providerGetModifiedTime
+ * @covers ResourceLoaderFileModule::getModifiedTime
+ */
+ public function testGetModifiedTime( $module, $expected ) {
+ $rl = new ResourceLoaderFileModule( $module );
+ $ts = $rl->getModifiedTime( $this->getResourceLoaderContext() );
+ $this->assertEquals( $ts, $expected );
+ }
+}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php
new file mode 100644
index 00000000..d0bc210b
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @group ResourceLoader
+ */
+class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase {
+
+ public static $commonImageData = array(
+ 'add' => 'add.gif',
+ 'remove' => array(
+ 'file' => 'remove.svg',
+ 'variants' => array( 'destructive' ),
+ ),
+ 'next' => array(
+ 'file' => array(
+ 'ltr' => 'next.svg',
+ 'rtl' => 'prev.svg'
+ ),
+ ),
+ 'help' => array(
+ 'file' => array(
+ 'ltr' => 'help-ltr.svg',
+ 'rtl' => 'help-rtl.svg',
+ 'lang' => array(
+ 'he' => 'help-ltr.svg',
+ )
+ ),
+ ),
+ 'bold' => array(
+ 'file' => array(
+ 'default' => 'bold-a.svg',
+ 'lang' => array(
+ 'en' => 'bold-b.svg',
+ 'ar,de' => 'bold-f.svg',
+ )
+ ),
+ )
+ );
+
+ public static $commonImageVariants = array(
+ 'invert' => array(
+ 'color' => '#FFFFFF',
+ 'global' => true,
+ ),
+ 'primary' => array(
+ 'color' => '#598AD1',
+ ),
+ 'constructive' => array(
+ 'color' => '#00C697',
+ ),
+ 'destructive' => array(
+ 'color' => '#E81915',
+ ),
+ );
+
+ public static function providerGetModules() {
+ return array(
+ array(
+ array(
+ 'class' => 'ResourceLoaderImageModule',
+ 'prefix' => 'oo-ui-icon',
+ 'variants' => self::$commonImageVariants,
+ 'images' => self::$commonImageData,
+ ),
+ '.oo-ui-icon-add {
+ ...
+}
+.oo-ui-icon-add-invert {
+ ...
+}
+.oo-ui-icon-remove {
+ ...
+}
+.oo-ui-icon-remove-invert {
+ ...
+}
+.oo-ui-icon-remove-destructive {
+ ...
+}
+.oo-ui-icon-next {
+ ...
+}
+.oo-ui-icon-next-invert {
+ ...
+}
+.oo-ui-icon-help {
+ ...
+}
+.oo-ui-icon-help-invert {
+ ...
+}
+.oo-ui-icon-bold {
+ ...
+}
+.oo-ui-icon-bold-invert {
+ ...
+}',
+ ),
+ array(
+ array(
+ 'class' => 'ResourceLoaderImageModule',
+ 'selectorWithoutVariant' => '.mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
+ 'selectorWithVariant' => '.mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before',
+ 'variants' => self::$commonImageVariants,
+ 'images' => self::$commonImageData,
+ ),
+ '.mw-ui-icon-add:after, .mw-ui-icon-add:before {
+ ...
+}
+.mw-ui-icon-add-invert:after, .mw-ui-icon-add-invert:before {
+ ...
+}
+.mw-ui-icon-remove:after, .mw-ui-icon-remove:before {
+ ...
+}
+.mw-ui-icon-remove-invert:after, .mw-ui-icon-remove-invert:before {
+ ...
+}
+.mw-ui-icon-remove-destructive:after, .mw-ui-icon-remove-destructive:before {
+ ...
+}
+.mw-ui-icon-next:after, .mw-ui-icon-next:before {
+ ...
+}
+.mw-ui-icon-next-invert:after, .mw-ui-icon-next-invert:before {
+ ...
+}
+.mw-ui-icon-help:after, .mw-ui-icon-help:before {
+ ...
+}
+.mw-ui-icon-help-invert:after, .mw-ui-icon-help-invert:before {
+ ...
+}
+.mw-ui-icon-bold:after, .mw-ui-icon-bold:before {
+ ...
+}
+.mw-ui-icon-bold-invert:after, .mw-ui-icon-bold-invert:before {
+ ...
+}',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providerGetModules
+ * @covers ResourceLoaderImageModule::getStyles
+ */
+ public function testGetStyles( $module, $expected ) {
+ $module = new ResourceLoaderImageModuleTestable( $module, __DIR__ . '/../../data/resourceloader' );
+ $styles = $module->getStyles( $this->getResourceLoaderContext() );
+ $this->assertEquals( $expected, $styles['all'] );
+ }
+}
+
+class ResourceLoaderImageModuleTestable extends ResourceLoaderImageModule {
+ /**
+ * Replace with a stub to make test cases easier to write.
+ */
+ protected function getCssDeclarations( $primary, $fallback ) {
+ return array( '...' );
+ }
+}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
new file mode 100644
index 00000000..758cfe19
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @group ResourceLoader
+ */
+class ResourceLoaderImageTest extends ResourceLoaderTestCase {
+
+ protected $imagesPath;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->imagesPath = __DIR__ . '/../../data/resourceloader';
+ }
+
+ protected function getTestImage( $name ) {
+ $options = ResourceLoaderImageModuleTest::$commonImageData[$name];
+ $fileDescriptor = is_string( $options ) ? $options : $options['file'];
+ $allowedVariants = is_array( $options ) && isset( $options['variants'] ) ? $options['variants'] : array();
+ $variants = array_fill_keys( $allowedVariants, array( 'color' => 'red' ) );
+ return new ResourceLoaderImageTestable( $name, 'test', $fileDescriptor, $this->imagesPath, $variants );
+ }
+
+ public static function provideGetPath() {
+ return array(
+ array( 'add', 'en', 'add.gif' ),
+ array( 'add', 'he', 'add.gif' ),
+ array( 'remove', 'en', 'remove.svg' ),
+ array( 'remove', 'he', 'remove.svg' ),
+ array( 'next', 'en', 'next.svg' ),
+ array( 'next', 'he', 'prev.svg' ),
+ array( 'help', 'en', 'help-ltr.svg' ),
+ array( 'help', 'ar', 'help-rtl.svg' ),
+ array( 'help', 'he', 'help-ltr.svg' ),
+ array( 'bold', 'en', 'bold-b.svg' ),
+ array( 'bold', 'de', 'bold-f.svg' ),
+ array( 'bold', 'ar', 'bold-f.svg' ),
+ array( 'bold', 'fr', 'bold-a.svg' ),
+ array( 'bold', 'he', 'bold-a.svg' ),
+ );
+ }
+
+ /**
+ * @covers ResourceLoaderImage::getPath
+ * @dataProvider provideGetPath
+ */
+ public function testGetPath( $imageName, $languageCode, $path ) {
+ static $dirMap = array(
+ 'en' => 'ltr',
+ 'de' => 'ltr',
+ 'fr' => 'ltr',
+ 'he' => 'rtl',
+ 'ar' => 'rtl',
+ );
+ static $contexts = array();
+
+ $image = $this->getTestImage( $imageName );
+ $context = $this->getResourceLoaderContext( $languageCode, $dirMap[$languageCode] );
+
+ $this->assertEquals( $image->getPath( $context ), $this->imagesPath . '/' . $path );
+ }
+
+ /**
+ * @covers ResourceLoaderImage::getExtension
+ * @covers ResourceLoaderImage::getMimeType
+ */
+ public function testGetExtension() {
+ $image = $this->getTestImage( 'remove' );
+ $this->assertEquals( $image->getExtension(), 'svg' );
+ $this->assertEquals( $image->getExtension( 'original' ), 'svg' );
+ $this->assertEquals( $image->getExtension( 'rasterized' ), 'png' );
+ $image = $this->getTestImage( 'add' );
+ $this->assertEquals( $image->getExtension(), 'gif' );
+ $this->assertEquals( $image->getExtension( 'original' ), 'gif' );
+ $this->assertEquals( $image->getExtension( 'rasterized' ), 'gif' );
+ }
+
+ /**
+ * @covers ResourceLoaderImage::getImageData
+ * @covers ResourceLoaderImage::variantize
+ * @covers ResourceLoaderImage::massageSvgPathdata
+ */
+ public function testGetImageData() {
+ $context = $this->getResourceLoaderContext( 'en', 'ltr' );
+
+ $image = $this->getTestImage( 'remove' );
+ $data = file_get_contents( $this->imagesPath . '/remove.svg' );
+ $dataConstructive = file_get_contents( $this->imagesPath . '/remove_variantize.svg' );
+ $this->assertEquals( $image->getImageData( $context, null, 'original' ), $data );
+ $this->assertEquals( $image->getImageData( $context, 'destructive', 'original' ), $dataConstructive );
+ // Stub, since we don't know if we even have a SVG handler, much less what exactly it'll output
+ $this->assertEquals( $image->getImageData( $context, null, 'rasterized' ), 'RASTERIZESTUB' );
+
+ $image = $this->getTestImage( 'add' );
+ $data = file_get_contents( $this->imagesPath . '/add.gif' );
+ $this->assertEquals( $image->getImageData( $context, null, 'original' ), $data );
+ $this->assertEquals( $image->getImageData( $context, null, 'rasterized' ), $data );
+ }
+
+ /**
+ * @covers ResourceLoaderImage::massageSvgPathdata
+ */
+ public function testMassageSvgPathdata() {
+ $image = $this->getTestImage( 'next' );
+ $data = file_get_contents( $this->imagesPath . '/next.svg' );
+ $dataMassaged = file_get_contents( $this->imagesPath . '/next_massage.svg' );
+ $this->assertEquals( $image->massageSvgPathdata( $data ), $dataMassaged );
+ }
+}
+
+class ResourceLoaderImageTestable extends ResourceLoaderImage {
+ // Make some protected methods public
+ public function getPath( ResourceLoaderContext $context ) {
+ return parent::getPath( $context );
+ }
+ public function massageSvgPathdata( $svg ) {
+ return parent::massageSvgPathdata( $svg );
+ }
+ // Stub, since we don't know if we even have a SVG handler, much less what exactly it'll output
+ public function rasterize( $svg ) {
+ return 'RASTERIZESTUB';
+ }
+}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
index b0edaaf7..6d1ed4e0 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
@@ -2,71 +2,12 @@
class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
- protected function setUp() {
- parent::setUp();
-
- // The return value of the closure shouldn't matter since this test should
- // never call it
- SkinFactory::getDefaultInstance()->register(
- 'fakeskin',
- 'FakeSkin',
- function () {
- }
- );
- }
-
- /**
- * @covers ResourceLoaderFileModule::getAllSkinStyleFiles
- */
- public function testGetAllSkinStyleFiles() {
- $context = self::getResourceLoaderContext();
-
- $baseParams = array(
- 'scripts' => array(
- 'foo.js',
- 'bar.js',
- ),
- 'styles' => array(
- 'foo.css',
- 'bar.css' => array( 'media' => 'print' ),
- 'screen.less' => array( 'media' => 'screen' ),
- 'screen-query.css' => array( 'media' => 'screen and (min-width: 400px)' ),
- ),
- 'skinStyles' => array(
- 'default' => 'quux-fallback.less',
- 'fakeskin' => array(
- 'baz-vector.css',
- 'quux-vector.less',
- ),
- ),
- 'messages' => array(
- 'hello',
- 'world',
- ),
- );
-
- $module = new ResourceLoaderFileModule( $baseParams );
-
- $this->assertEquals(
- array(
- 'foo.css',
- 'baz-vector.css',
- 'quux-vector.less',
- 'quux-fallback.less',
- 'bar.css',
- 'screen.less',
- 'screen-query.css',
- ),
- array_map( 'basename', $module->getAllStyleFiles() )
- );
- }
-
/**
* @covers ResourceLoaderModule::getDefinitionSummary
* @covers ResourceLoaderFileModule::getDefinitionSummary
*/
public function testDefinitionSummary() {
- $context = self::getResourceLoaderContext();
+ $context = $this->getResourceLoaderContext();
$baseParams = array(
'scripts' => array( 'foo.js', 'bar.js' ),
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderStartupModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
index a1893873..7f3506cc 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderStartupModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
@@ -1,6 +1,6 @@
<?php
-class ResourceLoaderStartupModuleTest extends ResourceLoaderTestCase {
+class ResourceLoaderStartUpModuleTest extends ResourceLoaderTestCase {
public static function provideGetModuleRegistrations() {
return array(
@@ -23,7 +23,7 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.blank",
- "1388534400"
+ 1388534400
]
] );',
) ),
@@ -40,17 +40,17 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.blank",
- "1388534400"
+ 1388534400
],
[
"test.group.foo",
- "1388534400",
+ 1388534400,
[],
"x-foo"
],
[
"test.group.bar",
- "1388534400",
+ 1388534400,
[],
"x-bar"
]
@@ -68,7 +68,7 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.blank",
- "1388534400"
+ 1388534400
]
] );'
) ),
@@ -90,7 +90,7 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.blank",
- "1388534400",
+ 1388534400,
[],
null,
"example"
@@ -115,8 +115,8 @@ mw.loader.addSource( {
'test.z.foo' => new ResourceLoaderTestModule( array(
'dependencies' => array(
'test.x.core',
- 'test.x.polyfil',
- 'test.y.polyfil',
+ 'test.x.polyfill',
+ 'test.y.polyfill',
),
) ),
),
@@ -126,31 +126,31 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.x.core",
- "1388534400"
+ 1388534400
],
[
"test.x.polyfill",
- "1388534400",
+ 1388534400,
[],
null,
- "local",
+ null,
"return true;"
],
[
"test.y.polyfill",
- "1388534400",
+ 1388534400,
[],
null,
- "local",
+ null,
"return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
],
[
"test.z.foo",
- "1388534400",
+ 1388534400,
[
- "test.x.core",
- "test.x.polyfil",
- "test.y.polyfil"
+ 0,
+ 1,
+ 2
]
]
] );',
@@ -222,63 +222,63 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.blank",
- "1388534400"
+ 1388534400
],
[
"test.x.core",
- "1388534400"
+ 1388534400
],
[
"test.x.util",
- "1388534400",
+ 1388534400,
[
- "test.x.core"
+ 1
]
],
[
"test.x.foo",
- "1388534400",
+ 1388534400,
[
- "test.x.core"
+ 1
]
],
[
"test.x.bar",
- "1388534400",
+ 1388534400,
[
- "test.x.util"
+ 2
]
],
[
"test.x.quux",
- "1388534400",
+ 1388534400,
[
- "test.x.foo",
- "test.x.bar",
+ 3,
+ 4,
"test.x.unknown"
]
],
[
"test.group.foo.1",
- "1388534400",
+ 1388534400,
[],
"x-foo"
],
[
"test.group.foo.2",
- "1388534400",
+ 1388534400,
[],
"x-foo"
],
[
"test.group.bar.1",
- "1388534400",
+ 1388534400,
[],
"x-bar"
],
[
"test.group.bar.2",
- "1388534400",
+ 1388534400,
[],
"x-bar",
"example"
@@ -290,7 +290,7 @@ mw.loader.addSource( {
/**
* @dataProvider provideGetModuleRegistrations
- * @covers ResourceLoaderStartupModule::optimizeDependencies
+ * @covers ResourceLoaderStartUpModule::compileUnresolvedDependencies
* @covers ResourceLoaderStartUpModule::getModuleRegistrations
* @covers ResourceLoader::makeLoaderSourcesScript
* @covers ResourceLoader::makeLoaderRegisterScript
@@ -300,7 +300,7 @@ mw.loader.addSource( {
$this->setMwGlobals( 'wgResourceLoaderSources', $case['sources'] );
}
- $context = self::getResourceLoaderContext();
+ $context = $this->getResourceLoaderContext();
$rl = $context->getResourceLoader();
$rl->register( $case['modules'] );
@@ -337,15 +337,15 @@ mw.loader.addSource( {
public function testRegistrationsMinified( $modules ) {
$this->setMwGlobals( 'wgResourceLoaderDebug', false );
- $context = self::getResourceLoaderContext();
+ $context = $this->getResourceLoaderContext();
$rl = $context->getResourceLoader();
$rl->register( $modules );
$module = new ResourceLoaderStartUpModule();
$this->assertEquals(
'mw.loader.addSource({"local":"/w/load.php"});'
. 'mw.loader.register(['
-. '["test.blank","1388534400"],'
-. '["test.min","1388534400",["test.blank"],null,"local",'
+. '["test.blank",1388534400],'
+. '["test.min",1388534400,[0],null,null,'
. '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"'
. ']]);',
$module->getModuleRegistrations( $context ),
@@ -357,7 +357,7 @@ mw.loader.addSource( {
* @dataProvider provideRegistrations
*/
public function testRegistrationsUnminified( $modules ) {
- $context = self::getResourceLoaderContext();
+ $context = $this->getResourceLoaderContext();
$rl = $context->getResourceLoader();
$rl->register( $modules );
$module = new ResourceLoaderStartUpModule();
@@ -367,16 +367,16 @@ mw.loader.addSource( {
} );mw.loader.register( [
[
"test.blank",
- "1388534400"
+ 1388534400
],
[
"test.min",
- "1388534400",
+ 1388534400,
[
- "test.blank"
+ 0
],
null,
- "local",
+ null,
"return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
]
] );',
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
index f19f6886..ca7307ec 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
@@ -2,13 +2,9 @@
class ResourceLoaderTest extends ResourceLoaderTestCase {
- protected static $resourceLoaderRegisterModulesHook;
-
protected function setUp() {
parent::setUp();
- // $wgResourceLoaderLESSFunctions, $wgResourceLoaderLESSImportPaths; $wgResourceLoaderLESSVars;
-
$this->setMwGlobals( array(
'wgResourceLoaderLESSFunctions' => array(
'test-sum' => function ( $frame, $less ) {
@@ -30,35 +26,33 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
) );
}
- /* Hook Methods */
-
- /**
- * ResourceLoaderRegisterModules hook
- */
- public static function resourceLoaderRegisterModules( &$resourceLoader ) {
- self::$resourceLoaderRegisterModulesHook = true;
-
- return true;
- }
-
- /* Provider Methods */
public static function provideValidModules() {
return array(
array( 'TEST.validModule1', new ResourceLoaderTestModule() ),
);
}
- /* Test Methods */
-
/**
* Ensures that the ResourceLoaderRegisterModules hook is called when a new
* ResourceLoader object is constructed.
* @covers ResourceLoader::__construct
*/
public function testCreatingNewResourceLoaderCallsRegistrationHook() {
- self::$resourceLoaderRegisterModulesHook = false;
+ $resourceLoaderRegisterModulesHook = false;
+
+ $this->setMwGlobals( 'wgHooks', array(
+ 'ResourceLoaderRegisterModules' => array(
+ function ( &$resourceLoader ) use ( &$resourceLoaderRegisterModulesHook ) {
+ $resourceLoaderRegisterModulesHook = true;
+ }
+ )
+ ) );
+
$resourceLoader = new ResourceLoader();
- $this->assertTrue( self::$resourceLoaderRegisterModulesHook );
+ $this->assertTrue(
+ $resourceLoaderRegisterModulesHook,
+ 'Hook ResourceLoaderRegisterModules called'
+ );
return $resourceLoader;
}
@@ -80,7 +74,7 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
* @covers ResourceLoaderFileModule::compileLessFile
*/
public function testLessFileCompilation() {
- $context = self::getResourceLoaderContext();
+ $context = $this->getResourceLoaderContext();
$basePath = __DIR__ . '/../../data/less/module';
$module = new ResourceLoaderFileModule( array(
'localBasePath' => $basePath,
@@ -96,43 +90,11 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
* @param string $css
* @return string
*/
- private function stripNoflip( $css ) {
+ private static function stripNoflip( $css ) {
return str_replace( '/*@noflip*/ ', '', $css );
}
/**
- * What happens when you mix @embed and @noflip?
- * This really is an integration test, but oh well.
- */
- public function testMixedCssAnnotations( ) {
- $basePath = __DIR__ . '/../../data/css';
- $testModule = new ResourceLoaderFileModule( array(
- 'localBasePath' => $basePath,
- 'styles' => array( 'test.css' ),
- ) );
- $expectedModule = new ResourceLoaderFileModule( array(
- 'localBasePath' => $basePath,
- 'styles' => array( 'expected.css' ),
- ) );
-
- $contextLtr = self::getResourceLoaderContext( 'en' );
- $contextRtl = self::getResourceLoaderContext( 'he' );
-
- // Since we want to compare the effect of @noflip+@embed against the effect of just @embed, and
- // the @noflip annotations are always preserved, we need to strip them first.
- $this->assertEquals(
- $expectedModule->getStyles( $contextLtr ),
- $this->stripNoflip( $testModule->getStyles( $contextLtr ) ),
- "/*@noflip*/ with /*@embed*/ gives correct results in LTR mode"
- );
- $this->assertEquals(
- $expectedModule->getStyles( $contextLtr ),
- $this->stripNoflip( $testModule->getStyles( $contextRtl ) ),
- "/*@noflip*/ with /*@embed*/ gives correct results in RTL mode"
- );
- }
-
- /**
* @dataProvider providePackedModules
* @covers ResourceLoader::makePackedModulesString
*/
@@ -193,6 +155,7 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
/**
* @dataProvider provideAddSource
* @covers ResourceLoader::addSource
+ * @covers ResourceLoader::getSources
*/
public function testAddSource( $name, $info, $expected ) {
$rl = new ResourceLoader;
@@ -223,6 +186,106 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
);
}
+ public static function provideLoaderImplement() {
+ return array(
+ array( array(
+ 'title' => 'Implement scripts, styles and messages',
+
+ 'name' => 'test.example',
+ 'scripts' => 'mw.example();',
+ 'styles' => array( 'css' => array( '.mw-example {}' ) ),
+ 'messages' => array( 'example' => '' ),
+ 'templates' => array(),
+
+ 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) {
+mw.example();
+}, {
+ "css": [
+ ".mw-example {}"
+ ]
+}, {
+ "example": ""
+} );',
+ ) ),
+ array( array(
+ 'title' => 'Implement scripts',
+
+ 'name' => 'test.example',
+ 'scripts' => 'mw.example();',
+ 'styles' => array(),
+ 'messages' => new XmlJsCode( '{}' ),
+ 'templates' => array(),
+ 'title' => 'scripts, styles and messags',
+
+ 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) {
+mw.example();
+} );',
+ ) ),
+ array( array(
+ 'title' => 'Implement styles',
+
+ 'name' => 'test.example',
+ 'scripts' => array(),
+ 'styles' => array( 'css' => array( '.mw-example {}' ) ),
+ 'messages' => new XmlJsCode( '{}' ),
+ 'templates' => array(),
+
+ 'expected' => 'mw.loader.implement( "test.example", [], {
+ "css": [
+ ".mw-example {}"
+ ]
+} );',
+ ) ),
+ array( array(
+ 'title' => 'Implement scripts and messages',
+
+ 'name' => 'test.example',
+ 'scripts' => 'mw.example();',
+ 'styles' => array(),
+ 'messages' => array( 'example' => '' ),
+ 'templates' => array(),
+
+ 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) {
+mw.example();
+}, {}, {
+ "example": ""
+} );',
+ ) ),
+ array( array(
+ 'title' => 'Implement scripts and templates',
+
+ 'name' => 'test.example',
+ 'scripts' => 'mw.example();',
+ 'styles' => array(),
+ 'messages' => new XmlJsCode( '{}' ),
+ 'templates' => array( 'example.html' => '' ),
+
+ 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) {
+mw.example();
+}, {}, {}, {
+ "example.html": ""
+} );',
+ ) ),
+ );
+ }
+
+ /**
+ * @dataProvider provideLoaderImplement
+ * @covers ResourceLoader::makeLoaderImplementScript
+ */
+ public function testMakeLoaderImplementScript( $case ) {
+ $this->assertEquals(
+ $case['expected'],
+ ResourceLoader::makeLoaderImplementScript(
+ $case['name'],
+ $case['scripts'],
+ $case['styles'],
+ $case['messages'],
+ $case['templates']
+ )
+ );
+ }
+
/**
* @covers ResourceLoader::getLoadScript
*/
@@ -242,8 +305,14 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
$this->assertTrue( true );
}
}
-}
-/* Hooks */
-global $wgHooks;
-$wgHooks['ResourceLoaderRegisterModules'][] = 'ResourceLoaderTest::resourceLoaderRegisterModules';
+ /**
+ * @covers ResourceLoader::isModuleRegistered
+ */
+ public function testIsModuleRegistered() {
+ $rl = new ResourceLoader();
+ $rl->register( 'test.module', new ResourceLoaderTestModule() );
+ $this->assertTrue( $rl->isModuleRegistered( 'test.module' ) );
+ $this->assertFalse( $rl->isModuleRegistered( 'test.modulenotregistered' ) );
+ }
+}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
index 9dc18050..93a3ebba 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
@@ -3,11 +3,93 @@
class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase {
/**
+ * @covers ResourceLoaderWikiModule::__construct
+ * @dataProvider provideConstructor
+ */
+ public function testConstructor( $params ) {
+ $module = new ResourceLoaderWikiModule( $params );
+ $this->assertInstanceOf( 'ResourceLoaderWikiModule', $module );
+ }
+
+ public static function provideConstructor() {
+ return array(
+ // Nothing
+ array( null ),
+ array( array() ),
+ // Unrecognized settings
+ array( array( 'foo' => 'baz' ) ),
+ // Real settings
+ array( array( 'scripts' => array( 'MediaWiki:Common.js' ) ) ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetPages
+ * @covers ResourceLoaderWikiModule::getPages
+ */
+ public function testGetPages( $params, Config $config, $expected ) {
+ $module = new ResourceLoaderWikiModule( $params );
+ $module->setConfig( $config );
+
+ // Use getDefinitionSummary because getPages is protected
+ $summary = $module->getDefinitionSummary( ResourceLoaderContext::newDummyContext() );
+ $this->assertEquals(
+ $expected,
+ $summary['pages']
+ );
+ }
+
+ public static function provideGetPages() {
+ $settings = array(
+ 'UseSiteJs' => true,
+ 'UseSiteCss' => true,
+ );
+
+ $params = array(
+ 'styles' => array( 'MediaWiki:Common.css' ),
+ 'scripts' => array( 'MediaWiki:Common.js' ),
+ );
+
+ return array(
+ array( array(), new HashConfig( $settings ), array() ),
+ array( $params, new HashConfig( $settings ), array(
+ 'MediaWiki:Common.js' => array( 'type' => 'script' ),
+ 'MediaWiki:Common.css' => array( 'type' => 'style' )
+ ) ),
+ array( $params, new HashConfig( array( 'UseSiteCss' => false ) + $settings ), array(
+ 'MediaWiki:Common.js' => array( 'type' => 'script' ),
+ ) ),
+ array( $params, new HashConfig( array( 'UseSiteJs' => false ) + $settings ), array(
+ 'MediaWiki:Common.css' => array( 'type' => 'style' ),
+ ) ),
+ array( $params, new HashConfig( array( 'UseSiteJs' => false, 'UseSiteCss' => false ) ), array() ),
+ );
+ }
+
+ /**
+ * @covers ResourceLoaderWikiModule::getGroup
+ * @dataProvider provideGetGroup
+ */
+ public function testGetGroup( $params, $expected ) {
+ $module = new ResourceLoaderWikiModule( $params );
+ $this->assertEquals( $expected, $module->getGroup() );
+ }
+
+ public static function provideGetGroup() {
+ return array(
+ // No group specified
+ array( array(), null ),
+ // A random group
+ array( array( 'group' => 'foobar' ), 'foobar' ),
+ );
+ }
+
+ /**
* @covers ResourceLoaderWikiModule::isKnownEmpty
* @dataProvider provideIsKnownEmpty
*/
public function testIsKnownEmpty( $titleInfo, $group, $expected ) {
- $module = $this->getMockBuilder( 'ResourceLoaderWikiModuleTestModule' )
+ $module = $this->getMockBuilder( 'ResourceLoaderWikiModule' )
->setMethods( array( 'getTitleInfo', 'getGroup' ) )
->getMock();
$module->expects( $this->any() )
diff --git a/tests/phpunit/includes/resourceloader/templates/template.html b/tests/phpunit/includes/resourceloader/templates/template.html
new file mode 100644
index 00000000..1f6a7d22
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/templates/template.html
@@ -0,0 +1 @@
+<strong>hello</strong>
diff --git a/tests/phpunit/includes/resourceloader/templates/template2.html b/tests/phpunit/includes/resourceloader/templates/template2.html
new file mode 100644
index 00000000..a322f67d
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/templates/template2.html
@@ -0,0 +1 @@
+<div>goodbye</div>
diff --git a/tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars b/tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars
new file mode 100644
index 00000000..5f5c07d5
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars
@@ -0,0 +1 @@
+wow
diff --git a/tests/phpunit/includes/search/SearchEngineTest.php b/tests/phpunit/includes/search/SearchEngineTest.php
index 3da13615..d0cbfa0a 100644
--- a/tests/phpunit/includes/search/SearchEngineTest.php
+++ b/tests/phpunit/includes/search/SearchEngineTest.php
@@ -14,8 +14,6 @@ class SearchEngineTest extends MediaWikiLangTestCase {
*/
protected $search;
- protected $pageList;
-
/**
* Checks for database type & version.
* Will skip current test if DB does not support search.
@@ -37,10 +35,6 @@ class SearchEngineTest extends MediaWikiLangTestCase {
'wgSearchType' => $searchType
) );
- if ( !isset( self::$pageList ) ) {
- $this->addPages();
- }
-
$this->search = new $searchType( $this->db );
}
@@ -50,33 +44,32 @@ class SearchEngineTest extends MediaWikiLangTestCase {
parent::tearDown();
}
- protected function addPages() {
+ public function addDBData() {
if ( !$this->isWikitextNS( NS_MAIN ) ) {
// @todo cover the case of non-wikitext content in the main namespace
return;
}
- $this->insertPage( "Not_Main_Page", "This is not a main page", 0 );
+ $this->insertPage( 'Not_Main_Page', 'This is not a main page' );
$this->insertPage(
'Talk:Not_Main_Page',
- 'This is not a talk page to the main page, see [[smithee]]',
- 1
+ 'This is not a talk page to the main page, see [[smithee]]'
);
- $this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]', 0 );
- $this->insertPage( 'Talk:Smithee', 'This article sucks.', 1 );
- $this->insertPage( 'Unrelated_page', 'Nothing in this page is about the S word.', 0 );
- $this->insertPage( 'Another_page', 'This page also is unrelated.', 0 );
- $this->insertPage( 'Help:Help', 'Help me!', 4 );
- $this->insertPage( 'Thppt', 'Blah blah', 0 );
- $this->insertPage( 'Alan_Smithee', 'yum', 0 );
- $this->insertPage( 'Pages', 'are\'food', 0 );
- $this->insertPage( 'HalfOneUp', 'AZ', 0 );
- $this->insertPage( 'FullOneUp', 'AZ', 0 );
- $this->insertPage( 'HalfTwoLow', 'az', 0 );
- $this->insertPage( 'FullTwoLow', 'az', 0 );
- $this->insertPage( 'HalfNumbers', '1234567890', 0 );
- $this->insertPage( 'FullNumbers', '1234567890', 0 );
- $this->insertPage( 'DomainName', 'example.com', 0 );
+ $this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]' );
+ $this->insertPage( 'Talk:Smithee', 'This article sucks.' );
+ $this->insertPage( 'Unrelated_page', 'Nothing in this page is about the S word.' );
+ $this->insertPage( 'Another_page', 'This page also is unrelated.' );
+ $this->insertPage( 'Help:Help', 'Help me!' );
+ $this->insertPage( 'Thppt', 'Blah blah' );
+ $this->insertPage( 'Alan_Smithee', 'yum' );
+ $this->insertPage( 'Pages', 'are\'food' );
+ $this->insertPage( 'HalfOneUp', 'AZ' );
+ $this->insertPage( 'FullOneUp', 'AZ' );
+ $this->insertPage( 'HalfTwoLow', 'az' );
+ $this->insertPage( 'FullTwoLow', 'az' );
+ $this->insertPage( 'HalfNumbers', '1234567890' );
+ $this->insertPage( 'FullNumbers', '1234567890' );
+ $this->insertPage( 'DomainName', 'example.com' );
}
protected function fetchIds( $results ) {
@@ -101,30 +94,6 @@ class SearchEngineTest extends MediaWikiLangTestCase {
return $matches;
}
- /**
- * Insert a new page
- *
- * @param string $pageName Page name
- * @param string $text Page's content
- * @param int $ns Unused
- */
- protected function insertPage( $pageName, $text, $ns ) {
- $title = Title::newFromText( $pageName, $ns );
-
- $user = User::newFromName( 'WikiSysop' );
- $comment = 'Search Test';
-
- // avoid memory leak...?
- LinkCache::singleton()->clear();
-
- $page = WikiPage::factory( $title );
- $page->doEditContent( ContentHandler::makeContent( $text, $title ), $comment, 0, false, $user );
-
- $this->pageList[] = array( $title, $page->getId() );
-
- return true;
- }
-
public function testFullWidth() {
$this->assertEquals(
array( 'FullOneUp', 'FullTwoLow', 'HalfOneUp', 'HalfTwoLow' ),
diff --git a/tests/phpunit/includes/site/CachingSiteStoreTest.php b/tests/phpunit/includes/site/CachingSiteStoreTest.php
new file mode 100644
index 00000000..d0a79803
--- /dev/null
+++ b/tests/phpunit/includes/site/CachingSiteStoreTest.php
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.25
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ * @group Database
+ *
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class CachingSiteStoreTest extends MediaWikiTestCase {
+
+ /**
+ * @covers CachingSiteStore::getSites
+ */
+ public function testGetSites() {
+ $testSites = TestSites::getSites();
+
+ $store = new CachingSiteStore(
+ $this->getHashSiteStore( $testSites ),
+ wfGetMainCache()
+ );
+
+ $sites = $store->getSites();
+
+ $this->assertInstanceOf( 'SiteList', $sites );
+
+ /**
+ * @var Site $site
+ */
+ foreach ( $sites as $site ) {
+ $this->assertInstanceOf( 'Site', $site );
+ }
+
+ foreach ( $testSites as $site ) {
+ if ( $site->getGlobalId() !== null ) {
+ $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) );
+ }
+ }
+ }
+
+ /**
+ * @covers CachingSiteStore::saveSites
+ */
+ public function testSaveSites() {
+ $store = new CachingSiteStore( new HashSiteStore(), wfGetMainCache() );
+
+ $sites = array();
+
+ $site = new Site();
+ $site->setGlobalId( 'ertrywuutr' );
+ $site->setLanguageCode( 'en' );
+ $sites[] = $site;
+
+ $site = new MediaWikiSite();
+ $site->setGlobalId( 'sdfhxujgkfpth' );
+ $site->setLanguageCode( 'nl' );
+ $sites[] = $site;
+
+ $this->assertTrue( $store->saveSites( $sites ) );
+
+ $site = $store->getSite( 'ertrywuutr' );
+ $this->assertInstanceOf( 'Site', $site );
+ $this->assertEquals( 'en', $site->getLanguageCode() );
+
+ $site = $store->getSite( 'sdfhxujgkfpth' );
+ $this->assertInstanceOf( 'Site', $site );
+ $this->assertEquals( 'nl', $site->getLanguageCode() );
+ }
+
+ /**
+ * @covers CachingSiteStore::reset
+ */
+ public function testReset() {
+ $dbSiteStore = $this->getMockBuilder( 'SiteStore' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ // php 5.3 compatibility!
+ $self = $this;
+
+ $dbSiteStore->expects( $this->any() )
+ ->method( 'getSite' )
+ ->will( $this->returnValue( $self->getTestSite() ) );
+
+ $dbSiteStore->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnCallback( function() use( $self ) {
+ $siteList = new SiteList();
+ $siteList->setSite( $self->getTestSite() );
+
+ return $siteList;
+ } ) );
+
+ $store = new CachingSiteStore( $dbSiteStore, wfGetMainCache() );
+
+ // initialize internal cache
+ $this->assertGreaterThan( 0, $store->getSites()->count(), 'count sites' );
+
+ $store->getSite( 'enwiki' )->setLanguageCode( 'en-ca' );
+
+ // sanity check: $store should have the new language code for 'enwiki'
+ $this->assertEquals( 'en-ca', $store->getSite( 'enwiki' )->getLanguageCode(), 'sanity check' );
+
+ // purge cache
+ $store->reset();
+
+ // the internal cache of $store should be updated, and now pulling
+ // the site from the 'fallback' DBSiteStore with the original language code.
+ $this->assertEquals( 'en', $store->getSite( 'enwiki' )->getLanguageCode(), 'reset' );
+ }
+
+ public function getTestSite() {
+ $enwiki = new MediaWikiSite();
+ $enwiki->setGlobalId( 'enwiki' );
+ $enwiki->setLanguageCode( 'en' );
+
+ return $enwiki;
+ }
+
+ /**
+ * @covers CachingSiteStore::clear
+ */
+ public function testClear() {
+ $store = new CachingSiteStore( new HashSiteStore(), wfGetMainCache() );
+ $this->assertTrue( $store->clear() );
+
+ $site = $store->getSite( 'enwiki' );
+ $this->assertNull( $site );
+
+ $sites = $store->getSites();
+ $this->assertEquals( 0, $sites->count() );
+ }
+
+ private function getHashSiteStore( array $sites ) {
+ $siteStore = new HashSiteStore();
+ $siteStore->saveSites( $sites );
+
+ return $siteStore;
+ }
+
+}
diff --git a/tests/phpunit/includes/site/DBSiteStoreTest.php b/tests/phpunit/includes/site/DBSiteStoreTest.php
new file mode 100644
index 00000000..673ba54d
--- /dev/null
+++ b/tests/phpunit/includes/site/DBSiteStoreTest.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * Tests for the DBSiteStore class.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.21
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ * @group Database
+ *
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+class DBSiteStoreTest extends MediaWikiTestCase {
+
+ /**
+ * @covers DBSiteStore::getSites
+ */
+ public function testGetSites() {
+ $expectedSites = TestSites::getSites();
+ TestSites::insertIntoDb();
+
+ $store = new DBSiteStore();
+
+ $sites = $store->getSites();
+
+ $this->assertInstanceOf( 'SiteList', $sites );
+
+ /**
+ * @var Site $site
+ */
+ foreach ( $sites as $site ) {
+ $this->assertInstanceOf( 'Site', $site );
+ }
+
+ foreach ( $expectedSites as $site ) {
+ if ( $site->getGlobalId() !== null ) {
+ $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) );
+ }
+ }
+ }
+
+ /**
+ * @covers DBSiteStore::saveSites
+ */
+ public function testSaveSites() {
+ $store = new DBSiteStore();
+
+ $sites = array();
+
+ $site = new Site();
+ $site->setGlobalId( 'ertrywuutr' );
+ $site->setLanguageCode( 'en' );
+ $sites[] = $site;
+
+ $site = new MediaWikiSite();
+ $site->setGlobalId( 'sdfhxujgkfpth' );
+ $site->setLanguageCode( 'nl' );
+ $sites[] = $site;
+
+ $this->assertTrue( $store->saveSites( $sites ) );
+
+ $site = $store->getSite( 'ertrywuutr' );
+ $this->assertInstanceOf( 'Site', $site );
+ $this->assertEquals( 'en', $site->getLanguageCode() );
+ $this->assertTrue( is_integer( $site->getInternalId() ) );
+ $this->assertTrue( $site->getInternalId() >= 0 );
+
+ $site = $store->getSite( 'sdfhxujgkfpth' );
+ $this->assertInstanceOf( 'Site', $site );
+ $this->assertEquals( 'nl', $site->getLanguageCode() );
+ $this->assertTrue( is_integer( $site->getInternalId() ) );
+ $this->assertTrue( $site->getInternalId() >= 0 );
+ }
+
+ /**
+ * @covers DBSiteStore::reset
+ */
+ public function testReset() {
+ $store1 = new DBSiteStore();
+ $store2 = new DBSiteStore();
+
+ // initialize internal cache
+ $this->assertGreaterThan( 0, $store1->getSites()->count() );
+ $this->assertGreaterThan( 0, $store2->getSites()->count() );
+
+ // Clear actual data. Will purge the external cache and reset the internal
+ // cache in $store1, but not the internal cache in store2.
+ $this->assertTrue( $store1->clear() );
+
+ // sanity check: $store2 should have a stale cache now
+ $this->assertNotNull( $store2->getSite( 'enwiki' ) );
+
+ // purge cache
+ $store2->reset();
+
+ // ...now the internal cache of $store2 should be updated and thus empty.
+ $site = $store2->getSite( 'enwiki' );
+ $this->assertNull( $site );
+ }
+
+ /**
+ * @covers DBSiteStore::clear
+ */
+ public function testClear() {
+ $store = new DBSiteStore();
+ $this->assertTrue( $store->clear() );
+
+ $site = $store->getSite( 'enwiki' );
+ $this->assertNull( $site );
+
+ $sites = $store->getSites();
+ $this->assertEquals( 0, $sites->count() );
+ }
+}
diff --git a/tests/phpunit/includes/site/FileBasedSiteLookupTest.php b/tests/phpunit/includes/site/FileBasedSiteLookupTest.php
new file mode 100644
index 00000000..90ebe5c4
--- /dev/null
+++ b/tests/phpunit/includes/site/FileBasedSiteLookupTest.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.25
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @covers FileBasedSiteLookup
+ * @group Site
+ *
+ * @author Katie Filbert < aude.wiki@gmail.com >
+ */
+class FileBasedSiteLookupTest extends PHPUnit_Framework_TestCase {
+
+ protected function setUp() {
+ $this->cacheFile = $this->getCacheFile();
+ }
+
+ protected function tearDown() {
+ unlink( $this->cacheFile );
+ }
+
+ public function testGetSites() {
+ $sites = $this->getSites();
+ $cacheBuilder = $this->newSitesCacheFileBuilder( $sites );
+ $cacheBuilder->build();
+
+ $cache = new FileBasedSiteLookup( $this->cacheFile );
+ $this->assertEquals( $sites, $cache->getSites() );
+ }
+
+ public function testGetSite() {
+ $sites = $this->getSites();
+ $cacheBuilder = $this->newSitesCacheFileBuilder( $sites );
+ $cacheBuilder->build();
+
+ $cache = new FileBasedSiteLookup( $this->cacheFile );
+
+ $this->assertEquals( $sites->getSite( 'enwiktionary' ), $cache->getSite( 'enwiktionary' ) );
+ }
+
+ private function newSitesCacheFileBuilder( SiteList $sites ) {
+ return new SitesCacheFileBuilder(
+ $this->getSiteLookup( $sites ),
+ $this->cacheFile
+ );
+ }
+
+ private function getSiteLookup( SiteList $sites ) {
+ $siteLookup = $this->getMockBuilder( 'SiteLookup' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $siteLookup->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( $sites ) );
+
+ return $siteLookup;
+ }
+
+ private function getSites() {
+ $sites = array();
+
+ $site = new Site();
+ $site->setGlobalId( 'foobar' );
+ $sites[] = $site;
+
+ $site = new MediaWikiSite();
+ $site->setGlobalId( 'enwiktionary' );
+ $site->setGroup( 'wiktionary' );
+ $site->setLanguageCode( 'en' );
+ $site->addNavigationId( 'enwiktionary' );
+ $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" );
+ $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" );
+ $sites[] = $site;
+
+ return new SiteList( $sites );
+ }
+
+ private function getCacheFile() {
+ return tempnam( sys_get_temp_dir(), 'mw-test-sitelist' );
+ }
+
+}
diff --git a/tests/phpunit/includes/site/HashSiteStoreTest.php b/tests/phpunit/includes/site/HashSiteStoreTest.php
new file mode 100644
index 00000000..49a96338
--- /dev/null
+++ b/tests/phpunit/includes/site/HashSiteStoreTest.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.25
+ *
+ * @ingroup Site
+ * @group Site
+ *
+ * @author Katie Filbert < aude.wiki@gmail.com >
+ */
+class HashSiteStoreTest extends MediaWikiTestCase {
+
+ /**
+ * @covers HashSiteStore::getSites
+ */
+ public function testGetSites() {
+ $expectedSites = array();
+
+ foreach( TestSites::getSites() as $testSite ) {
+ $siteId = $testSite->getGlobalId();
+ $expectedSites[$siteId] = $testSite;
+ }
+
+ $siteStore = new HashSiteStore( $expectedSites );
+
+ $this->assertEquals( new SiteList( $expectedSites ), $siteStore->getSites() );
+ }
+
+ /**
+ * @covers HashSiteStore::saveSite
+ * @covers HashSiteStore::getSite
+ */
+ public function testSaveSite() {
+ $store = new HashSiteStore();
+
+ $site = new Site();
+ $site->setGlobalId( 'dewiki' );
+
+ $this->assertCount( 0, $store->getSites(), '0 sites in store' );
+
+ $store->saveSite( $site );
+
+ $this->assertCount( 1, $store->getSites(), 'Store has 1 sites' );
+ $this->assertEquals( $site, $store->getSite( 'dewiki' ), 'Store has dewiki' );
+ }
+
+ /**
+ * @covers HashSiteStore::saveSites
+ */
+ public function testSaveSites() {
+ $store = new HashSiteStore();
+
+ $sites = array();
+
+ $site = new Site();
+ $site->setGlobalId( 'enwiki' );
+ $site->setLanguageCode( 'en' );
+ $sites[] = $site;
+
+ $site = new MediaWikiSite();
+ $site->setGlobalId( 'eswiki' );
+ $site->setLanguageCode( 'es' );
+ $sites[] = $site;
+
+ $this->assertCount( 0, $store->getSites(), '0 sites in store' );
+
+ $store->saveSites( $sites );
+
+ $this->assertCount( 2, $store->getSites(), 'Store has 2 sites' );
+ $this->assertTrue( $store->getSites()->hasSite( 'enwiki' ), 'Store has enwiki' );
+ $this->assertTrue( $store->getSites()->hasSite( 'eswiki' ), 'Store has eswiki' );
+ }
+
+ /**
+ * @covers HashSiteStore::clear
+ */
+ public function testClear() {
+ $store = new HashSiteStore();
+
+ $site = new Site();
+ $site->setGlobalId( 'arwiki' );
+ $store->saveSite( $site );
+
+ $this->assertCount( 1, $store->getSites(), '1 site in store' );
+
+ $store->clear();
+ $this->assertCount( 0, $store->getSites(), '0 sites in store' );
+ }
+}
diff --git a/tests/phpunit/includes/site/MediaWikiSiteTest.php b/tests/phpunit/includes/site/MediaWikiSiteTest.php
index c3fd1557..ef2ccca2 100644
--- a/tests/phpunit/includes/site/MediaWikiSiteTest.php
+++ b/tests/phpunit/includes/site/MediaWikiSiteTest.php
@@ -26,7 +26,6 @@
*
* @group Site
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class MediaWikiSiteTest extends SiteTest {
diff --git a/tests/phpunit/includes/site/SiteExporterTest.php b/tests/phpunit/includes/site/SiteExporterTest.php
new file mode 100644
index 00000000..19dd0aa1
--- /dev/null
+++ b/tests/phpunit/includes/site/SiteExporterTest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * Tests for the SiteExporter class.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @covers SiteExporter
+ *
+ * @author Daniel Kinzler
+ */
+class SiteExporterTest extends PHPUnit_Framework_TestCase {
+
+ public function testConstructor_InvalidArgument() {
+ $this->setExpectedException( 'InvalidArgumentException' );
+
+ new SiteExporter( 'Foo' );
+ }
+
+ public function testExportSites() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $tmp = tmpfile();
+ $exporter = new SiteExporter( $tmp );
+
+ $exporter->exportSites( array( $foo, $acme ) );
+
+ fseek( $tmp, 0 );
+ $xml = fread( $tmp, 16*1024 );
+
+ $this->assertContains( '<sites ', $xml );
+ $this->assertContains( '<site>', $xml );
+ $this->assertContains( '<globalid>Foo</globalid>', $xml );
+ $this->assertContains( '</site>', $xml );
+ $this->assertContains( '<globalid>acme.com</globalid>', $xml );
+ $this->assertContains( '<group>Test</group>', $xml );
+ $this->assertContains( '<localid type="interwiki">acme</localid>', $xml );
+ $this->assertContains( '<path type="link">http://acme.com/</path>', $xml );
+ $this->assertContains( '</sites>', $xml );
+
+ // NOTE: HHVM (at least on wmf Jenkins) doesn't like file URLs.
+ $xsdFile = __DIR__ . '/../../../../docs/sitelist-1.0.xsd';
+ $xsdData = file_get_contents( $xsdFile );
+
+ $document = new DOMDocument();
+ $document->loadXML( $xml, LIBXML_NONET );
+ $document->schemaValidateSource( $xsdData );
+ }
+
+ private function newSiteStore( SiteList $sites ) {
+ $store = $this->getMock( 'SiteStore' );
+
+ $store->expects( $this->once() )
+ ->method( 'saveSites' )
+ ->will( $this->returnCallback( function ( $moreSites ) use ( $sites ) {
+ foreach ( $moreSites as $site ) {
+ $sites->setSite( $site );
+ }
+ } ) );
+
+ $store->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( new SiteList() ) );
+
+ return $store;
+ }
+
+ public function provideRoundTrip() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
+ $dewiki->setGlobalId( 'dewiki' );
+ $dewiki->setGroup( 'wikipedia' );
+ $dewiki->setForward( true );
+ $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
+ $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
+ $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
+ $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
+ $dewiki->setSource( 'meta.wikimedia.org' );
+
+ return array(
+ 'empty' => array(
+ new SiteList()
+ ),
+
+ 'some' => array(
+ new SiteList( array( $foo, $acme, $dewiki ) ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRoundTrip()
+ */
+ public function testRoundTrip( SiteList $sites ) {
+ $tmp = tmpfile();
+ $exporter = new SiteExporter( $tmp );
+
+ $exporter->exportSites( $sites );
+
+ fseek( $tmp, 0 );
+ $xml = fread( $tmp, 16*1024 );
+
+ $actualSites = new SiteList();
+ $store = $this->newSiteStore( $actualSites );
+
+ $importer = new SiteImporter( $store );
+ $importer->importFromXML( $xml );
+
+ $this->assertEquals( $sites, $actualSites );
+ }
+
+}
diff --git a/tests/phpunit/includes/site/SiteImporterTest.php b/tests/phpunit/includes/site/SiteImporterTest.php
new file mode 100644
index 00000000..cb0316ab
--- /dev/null
+++ b/tests/phpunit/includes/site/SiteImporterTest.php
@@ -0,0 +1,200 @@
+<?php
+
+/**
+ * Tests for the SiteImporter class.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @group Site
+ *
+ * @covers SiteImporter
+ *
+ * @author Daniel Kinzler
+ */
+class SiteImporterTest extends PHPUnit_Framework_TestCase {
+
+ private function newSiteImporter( array $expectedSites, $errorCount ) {
+ $store = $this->getMock( 'SiteStore' );
+
+ $self = $this;
+ $store->expects( $this->once() )
+ ->method( 'saveSites' )
+ ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites, $self ) {
+ $self->assertSitesEqual( $expectedSites, $sites );
+ } ) );
+
+ $store->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( new SiteList() ) );
+
+ $errorHandler = $this->getMock( 'Psr\Log\LoggerInterface' );
+ $errorHandler->expects( $this->exactly( $errorCount ) )
+ ->method( 'error' );
+
+ $importer = new SiteImporter( $store );
+ $importer->setExceptionCallback( array( $errorHandler, 'error' ) );
+
+ return $importer;
+ }
+
+ public function assertSitesEqual( $expected, $actual, $message = '' ) {
+ $this->assertEquals(
+ $this->getSerializedSiteList( $expected ),
+ $this->getSerializedSiteList( $actual ),
+ $message
+ );
+ }
+
+ public function provideImportFromXML() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
+ $dewiki->setGlobalId( 'dewiki' );
+ $dewiki->setGroup( 'wikipedia' );
+ $dewiki->setForward( true );
+ $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
+ $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
+ $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
+ $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
+ $dewiki->setSource( 'meta.wikimedia.org' );
+
+ return array(
+ 'empty' => array(
+ '<sites></sites>',
+ array(),
+ ),
+ 'no sites' => array(
+ '<sites><Foo><globalid>Foo</globalid></Foo><Bar><quux>Bla</quux></Bar></sites>',
+ array(),
+ ),
+ 'minimal' => array(
+ '<sites>' .
+ '<site><globalid>Foo</globalid></site>' .
+ '</sites>',
+ array( $foo ),
+ ),
+ 'full' => array(
+ '<sites>' .
+ '<site><globalid>Foo</globalid></site>' .
+ '<site>' .
+ '<globalid>acme.com</globalid>' .
+ '<localid type="interwiki">acme</localid>' .
+ '<group>Test</group>' .
+ '<path type="link">http://acme.com/</path>' .
+ '</site>' .
+ '<site type="mediawiki">' .
+ '<source>meta.wikimedia.org</source>' .
+ '<globalid>dewiki</globalid>' .
+ '<localid type="interwiki">wikipedia</localid>' .
+ '<localid type="equivalent">de</localid>' .
+ '<group>wikipedia</group>' .
+ '<forward/>' .
+ '<path type="link">http://de.wikipedia.org/w/</path>' .
+ '<path type="page_path">http://de.wikipedia.org/wiki/</path>' .
+ '</site>' .
+ '</sites>',
+ array( $foo, $acme, $dewiki ),
+ ),
+ 'skip' => array(
+ '<sites>' .
+ '<site><globalid>Foo</globalid></site>' .
+ '<site><barf>Foo</barf></site>' .
+ '<site>' .
+ '<globalid>acme.com</globalid>' .
+ '<localid type="interwiki">acme</localid>' .
+ '<silly>boop!</silly>' .
+ '<group>Test</group>' .
+ '<path type="link">http://acme.com/</path>' .
+ '</site>' .
+ '</sites>',
+ array( $foo, $acme ),
+ 1
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideImportFromXML
+ */
+ public function testImportFromXML( $xml, array $expectedSites, $errorCount = 0 ) {
+ $importer = $this->newSiteImporter( $expectedSites, $errorCount );
+ $importer->importFromXML( $xml );
+ }
+
+ public function testImportFromXML_malformed() {
+ $this->setExpectedException( 'Exception' );
+
+ $store = $this->getMock( 'SiteStore' );
+ $importer = new SiteImporter( $store );
+ $importer->importFromXML( 'THIS IS NOT XML' );
+ }
+
+ public function testImportFromFile() {
+ $foo = Site::newForType( Site::TYPE_UNKNOWN );
+ $foo->setGlobalId( 'Foo' );
+
+ $acme = Site::newForType( Site::TYPE_UNKNOWN );
+ $acme->setGlobalId( 'acme.com' );
+ $acme->setGroup( 'Test' );
+ $acme->addLocalId( Site::ID_INTERWIKI, 'acme' );
+ $acme->setPath( Site::PATH_LINK, 'http://acme.com/' );
+
+ $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI );
+ $dewiki->setGlobalId( 'dewiki' );
+ $dewiki->setGroup( 'wikipedia' );
+ $dewiki->setForward( true );
+ $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' );
+ $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' );
+ $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' );
+ $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' );
+ $dewiki->setSource( 'meta.wikimedia.org' );
+
+ $importer = $this->newSiteImporter( array( $foo, $acme, $dewiki ), 0 );
+
+ $file = __DIR__ . '/SiteImporterTest.xml';
+ $importer->importFromFile( $file );
+ }
+
+ /**
+ * @param Site[] $sites
+ *
+ * @return array[]
+ */
+ private function getSerializedSiteList( $sites ) {
+ $serialized = array();
+
+ foreach ( $sites as $site ) {
+ $key = $site->getGlobalId();
+ $data = unserialize( $site->serialize() );
+
+ $serialized[$key] = $data;
+ }
+
+ return $serialized;
+ }
+}
diff --git a/tests/phpunit/includes/site/SiteImporterTest.xml b/tests/phpunit/includes/site/SiteImporterTest.xml
new file mode 100644
index 00000000..720b1faf
--- /dev/null
+++ b/tests/phpunit/includes/site/SiteImporterTest.xml
@@ -0,0 +1,19 @@
+<sites version="1.0" xmlns="http://www.mediawiki.org/xml/sitelist-1.0/">
+ <site><globalid>Foo</globalid></site>
+ <site>
+ <globalid>acme.com</globalid>
+ <localid type="interwiki">acme</localid>
+ <group>Test</group>
+ <path type="link">http://acme.com/</path>
+ </site>
+ <site type="mediawiki">
+ <source>meta.wikimedia.org</source>
+ <globalid>dewiki</globalid>
+ <localid type="interwiki">wikipedia</localid>
+ <localid type="equivalent">de</localid>
+ <group>wikipedia</group>
+ <forward/>
+ <path type="link">http://de.wikipedia.org/w/</path>
+ <path type="page_path">http://de.wikipedia.org/wiki/</path>
+ </site>
+</sites>
diff --git a/tests/phpunit/includes/site/SiteListTest.php b/tests/phpunit/includes/site/SiteListTest.php
index 534ed9c9..d6c58cf6 100644
--- a/tests/phpunit/includes/site/SiteListTest.php
+++ b/tests/phpunit/includes/site/SiteListTest.php
@@ -26,7 +26,6 @@
*
* @group Site
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class SiteListTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/site/SiteSQLStoreTest.php b/tests/phpunit/includes/site/SiteSQLStoreTest.php
index 6002c1a1..69088006 100644
--- a/tests/phpunit/includes/site/SiteSQLStoreTest.php
+++ b/tests/phpunit/includes/site/SiteSQLStoreTest.php
@@ -1,8 +1,6 @@
<?php
/**
- * Tests for the SiteSQLStore class.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -19,7 +17,7 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @since 1.21
+ * @since 1.25
*
* @ingroup Site
* @ingroup Test
@@ -27,108 +25,16 @@
* @group Site
* @group Database
*
- * @licence GNU GPL v2+
- * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Katie Filbert < aude.wiki@gmail.com >
*/
class SiteSQLStoreTest extends MediaWikiTestCase {
/**
- * @covers SiteSQLStore::getSites
- */
- public function testGetSites() {
- $expectedSites = TestSites::getSites();
- TestSites::insertIntoDb();
-
- $store = SiteSQLStore::newInstance();
-
- $sites = $store->getSites();
-
- $this->assertInstanceOf( 'SiteList', $sites );
-
- /**
- * @var Site $site
- */
- foreach ( $sites as $site ) {
- $this->assertInstanceOf( 'Site', $site );
- }
-
- foreach ( $expectedSites as $site ) {
- if ( $site->getGlobalId() !== null ) {
- $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) );
- }
- }
- }
-
- /**
- * @covers SiteSQLStore::saveSites
- */
- public function testSaveSites() {
- $store = SiteSQLStore::newInstance();
-
- $sites = array();
-
- $site = new Site();
- $site->setGlobalId( 'ertrywuutr' );
- $site->setLanguageCode( 'en' );
- $sites[] = $site;
-
- $site = new MediaWikiSite();
- $site->setGlobalId( 'sdfhxujgkfpth' );
- $site->setLanguageCode( 'nl' );
- $sites[] = $site;
-
- $this->assertTrue( $store->saveSites( $sites ) );
-
- $site = $store->getSite( 'ertrywuutr' );
- $this->assertInstanceOf( 'Site', $site );
- $this->assertEquals( 'en', $site->getLanguageCode() );
- $this->assertTrue( is_integer( $site->getInternalId() ) );
- $this->assertTrue( $site->getInternalId() >= 0 );
-
- $site = $store->getSite( 'sdfhxujgkfpth' );
- $this->assertInstanceOf( 'Site', $site );
- $this->assertEquals( 'nl', $site->getLanguageCode() );
- $this->assertTrue( is_integer( $site->getInternalId() ) );
- $this->assertTrue( $site->getInternalId() >= 0 );
- }
-
- /**
- * @covers SiteSQLStore::reset
+ * @covers SiteSQLStore::newInstance
*/
- public function testReset() {
- $store1 = SiteSQLStore::newInstance();
- $store2 = SiteSQLStore::newInstance();
-
- // initialize internal cache
- $this->assertGreaterThan( 0, $store1->getSites()->count() );
- $this->assertGreaterThan( 0, $store2->getSites()->count() );
-
- // Clear actual data. Will purge the external cache and reset the internal
- // cache in $store1, but not the internal cache in store2.
- $this->assertTrue( $store1->clear() );
-
- // sanity check: $store2 should have a stale cache now
- $this->assertNotNull( $store2->getSite( 'enwiki' ) );
-
- // purge cache
- $store2->reset();
-
- // ...now the internal cache of $store2 should be updated and thus empty.
- $site = $store2->getSite( 'enwiki' );
- $this->assertNull( $site );
+ public function testNewInstance() {
+ $siteStore = SiteSQLStore::newInstance();
+ $this->assertInstanceOf( 'SiteSQLStore', $siteStore );
}
- /**
- * @covers SiteSQLStore::clear
- */
- public function testClear() {
- $store = SiteSQLStore::newInstance();
- $this->assertTrue( $store->clear() );
-
- $site = $store->getSite( 'enwiki' );
- $this->assertNull( $site );
-
- $sites = $store->getSites();
- $this->assertEquals( 0, $sites->count() );
- }
}
diff --git a/tests/phpunit/includes/site/SiteTest.php b/tests/phpunit/includes/site/SiteTest.php
index 29c1ff33..63d90d2e 100644
--- a/tests/phpunit/includes/site/SiteTest.php
+++ b/tests/phpunit/includes/site/SiteTest.php
@@ -26,7 +26,6 @@
*
* @group Site
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class SiteTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/site/SitesCacheFileBuilderTest.php b/tests/phpunit/includes/site/SitesCacheFileBuilderTest.php
new file mode 100644
index 00000000..087341a0
--- /dev/null
+++ b/tests/phpunit/includes/site/SitesCacheFileBuilderTest.php
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.25
+ *
+ * @ingroup Site
+ * @ingroup Test
+ *
+ * @covers SitesCacheFileBuilder
+ * @group Site
+ *
+ * @author Katie Filbert < aude.wiki@gmail.com >
+ */
+class SitesCacheFileBuilderTest extends PHPUnit_Framework_TestCase {
+
+ protected function setUp() {
+ $this->cacheFile = $this->getCacheFile();
+ }
+
+ protected function tearDown() {
+ unlink( $this->cacheFile );
+ }
+
+ public function testBuild() {
+ $cacheBuilder = $this->newSitesCacheFileBuilder( $this->getSites() );
+ $cacheBuilder->build();
+
+ $contents = file_get_contents( $this->cacheFile );
+ $this->assertEquals( json_encode( $this->getExpectedData() ), $contents );
+ }
+
+ private function getExpectedData() {
+ return array(
+ 'sites' => array(
+ 'foobar' => array(
+ 'globalid' => 'foobar',
+ 'type' => 'unknown',
+ 'group' => 'none',
+ 'source' => 'local',
+ 'language' => null,
+ 'localids' => array(),
+ 'config' => array(),
+ 'data' => array(),
+ 'forward' => false,
+ 'internalid' => null,
+ 'identifiers' => array()
+ ),
+ 'enwiktionary' => array(
+ 'globalid' => 'enwiktionary',
+ 'type' => 'mediawiki',
+ 'group' => 'wiktionary',
+ 'source' => 'local',
+ 'language' => 'en',
+ 'localids' => array(
+ 'equivalent' => array( 'enwiktionary' )
+ ),
+ 'config' => array(),
+ 'data' => array(
+ 'paths' => array(
+ 'page_path' => 'https://en.wiktionary.org/wiki/$1',
+ 'file_path' => 'https://en.wiktionary.org/w/$1'
+ )
+ ),
+ 'forward' => false,
+ 'internalid' => null,
+ 'identifiers' => array(
+ array(
+ 'type' => 'equivalent',
+ 'key' => 'enwiktionary'
+ )
+ )
+ )
+ )
+ );
+ }
+
+ private function newSitesCacheFileBuilder( SiteList $sites ) {
+ return new SitesCacheFileBuilder(
+ $this->getSiteLookup( $sites ),
+ $this->cacheFile
+ );
+ }
+
+ private function getSiteLookup( SiteList $sites ) {
+ $siteLookup = $this->getMockBuilder( 'SiteLookup' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $siteLookup->expects( $this->any() )
+ ->method( 'getSites' )
+ ->will( $this->returnValue( $sites ) );
+
+ return $siteLookup;
+ }
+
+ private function getSites() {
+ $sites = array();
+
+ $site = new Site();
+ $site->setGlobalId( 'foobar' );
+ $sites[] = $site;
+
+ $site = new MediaWikiSite();
+ $site->setGlobalId( 'enwiktionary' );
+ $site->setGroup( 'wiktionary' );
+ $site->setLanguageCode( 'en' );
+ $site->addNavigationId( 'enwiktionary' );
+ $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" );
+ $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" );
+ $sites[] = $site;
+
+ return new SiteList( $sites );
+ }
+
+ private function getCacheFile() {
+ return tempnam( sys_get_temp_dir(), 'mw-test-sitelist' );
+ }
+
+}
diff --git a/tests/phpunit/includes/site/TestSites.php b/tests/phpunit/includes/site/TestSites.php
index af314ba2..4c402484 100644
--- a/tests/phpunit/includes/site/TestSites.php
+++ b/tests/phpunit/includes/site/TestSites.php
@@ -26,7 +26,6 @@
*
* @group Site
*
- * @licence GNU GPL v2+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
*/
class TestSites {
@@ -108,7 +107,7 @@ class TestSites {
* @since 0.1
*/
public static function insertIntoDb() {
- $sitesTable = SiteSQLStore::newInstance();
+ $sitesTable = new DBSiteStore();
$sitesTable->clear();
$sitesTable->saveSites( TestSites::getSites() );
}
diff --git a/tests/phpunit/includes/skins/SkinTemplateTest.php b/tests/phpunit/includes/skins/SkinTemplateTest.php
index baa995d4..8084a66f 100644
--- a/tests/phpunit/includes/skins/SkinTemplateTest.php
+++ b/tests/phpunit/includes/skins/SkinTemplateTest.php
@@ -5,7 +5,6 @@
*
* @group Output
*
- * @licence GNU GPL v2+
* @author Bene* < benestar.wikimedia@gmail.com >
*/
diff --git a/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php b/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php
index 779fa558..fd6911f6 100644
--- a/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php
+++ b/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php
@@ -28,21 +28,52 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
SpecialPageFactory::resetList();
}
+ public function testResetList() {
+ SpecialPageFactory::resetList();
+ $this->assertContains( 'Specialpages', SpecialPageFactory::getNames() );
+ }
+
+ public function testHookNotCalledTwice() {
+ $count = 0;
+ $this->mergeMwGlobalArrayValue( 'wgHooks', array(
+ 'SpecialPage_initList' => array(
+ function () use ( &$count ) {
+ $count++;
+ }
+ ) ) );
+ SpecialPageFactory::resetList();
+ SpecialPageFactory::getNames();
+ SpecialPageFactory::getNames();
+ $this->assertEquals( 1, $count );
+ }
+
public function newSpecialAllPages() {
return new SpecialAllPages();
}
public function specialPageProvider() {
+ $specialPageTestHelper = new SpecialPageTestHelper();
+
return array(
'class name' => array( 'SpecialAllPages', false ),
- 'closure' => array( function() {
+ 'closure' => array( function () {
return new SpecialAllPages();
}, false ),
- 'function' => array( array( $this, 'newSpecialAllPages' ), false ),
+ 'function' => array( array( $this, 'newSpecialAllPages' ), false ),
+ 'callback string' => array( 'SpecialPageTestHelper::newSpecialAllPages', false ),
+ 'callback with object' => array(
+ array( $specialPageTestHelper, 'newSpecialAllPages' ),
+ false
+ ),
+ 'callback array' => array(
+ array( 'SpecialPageTestHelper', 'newSpecialAllPages' ),
+ false
+ )
);
}
/**
+ * @covers SpecialPageFactory::getPage
* @dataProvider specialPageProvider
*/
public function testGetPage( $spec, $shouldReuseInstance ) {
@@ -56,6 +87,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
$this->assertEquals( $shouldReuseInstance, $page2 === $page, "Should re-use instance:" );
}
+ /**
+ * @covers SpecialPageFactory::getNames
+ */
public function testGetNames() {
$this->mergeMwGlobalArrayValue( 'wgSpecialPages', array( 'testdummy' => 'SpecialAllPages' ) );
SpecialPageFactory::resetList();
@@ -65,6 +99,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
$this->assertContains( 'testdummy', $names );
}
+ /**
+ * @covers SpecialPageFactory::resolveAlias
+ */
public function testResolveAlias() {
$this->setMwGlobals( 'wgContLang', Language::factory( 'de' ) );
SpecialPageFactory::resetList();
@@ -74,6 +111,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
$this->assertEquals( 'Foo', $param );
}
+ /**
+ * @covers SpecialPageFactory::getLocalNameFor
+ */
public function testGetLocalNameFor() {
$this->setMwGlobals( 'wgContLang', Language::factory( 'de' ) );
SpecialPageFactory::resetList();
@@ -82,6 +122,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
$this->assertEquals( 'Spezialseiten/Foo', $name );
}
+ /**
+ * @covers SpecialPageFactory::getTitleForAlias
+ */
public function testGetTitleForAlias() {
$this->setMwGlobals( 'wgContLang', Language::factory( 'de' ) );
SpecialPageFactory::resetList();
@@ -222,4 +265,19 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
);
}
+ public function testGetAliasListRecursion() {
+ $called = false;
+ $this->mergeMwGlobalArrayValue( 'wgHooks', array(
+ 'SpecialPage_initList' => array(
+ function () use ( &$called ) {
+ SpecialPageFactory::getLocalNameFor( 'Specialpages' );
+ $called = true;
+ }
+ ),
+ ) );
+ SpecialPageFactory::resetList();
+ SpecialPageFactory::getLocalNameFor( 'Specialpages' );
+ $this->assertTrue( $called, 'Recursive call succeeded' );
+ }
+
}
diff --git a/tests/phpunit/includes/SpecialPageTest.php b/tests/phpunit/includes/specialpage/SpecialPageTest.php
index 245cdffd..5a0aef97 100644
--- a/tests/phpunit/includes/SpecialPageTest.php
+++ b/tests/phpunit/includes/specialpage/SpecialPageTest.php
@@ -5,7 +5,6 @@
*
* @group Database
*
- * @licence GNU GPL v2+
* @author Katie Filbert < aude.wiki@gmail.com >
*/
class SpecialPageTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/specialpage/SpecialPageTestHelper.php b/tests/phpunit/includes/specialpage/SpecialPageTestHelper.php
new file mode 100644
index 00000000..37e29dcb
--- /dev/null
+++ b/tests/phpunit/includes/specialpage/SpecialPageTestHelper.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+class SpecialPageTestHelper {
+
+ public static function newSpecialAllPages() {
+ return new SpecialAllPages();
+ }
+
+}
diff --git a/tests/phpunit/includes/specials/SpecialBooksourcesTest.php b/tests/phpunit/includes/specials/SpecialBooksourcesTest.php
new file mode 100644
index 00000000..69485a03
--- /dev/null
+++ b/tests/phpunit/includes/specials/SpecialBooksourcesTest.php
@@ -0,0 +1,36 @@
+<?php
+class SpecialBooksourcesTest extends MediaWikiTestCase {
+ public static function provideISBNs() {
+ return array(
+ array( '978-0-300-14424-6', true ),
+ array( '0-14-020652-3', true ),
+ array( '020652-3', false ),
+ array( '9781234567897', true ),
+ array( '1-4133-0454-0', true ),
+ array( '978-1413304541', true ),
+ array( '0136091814', true ),
+ array( '0136091812', false ),
+ array( '9780136091813', true ),
+ array( '9780136091817', false ),
+ array( '123456789X', true ),
+
+ // Bug 67021
+ array( '1413304541', false ),
+ array( '141330454X', false ),
+ array( '1413304540', true ),
+ array( '14133X4540', false ),
+ array( '97814133X4541', false ),
+ array( '978035642615X', false ),
+ array( '9781413304541', true ),
+ array( '9780356426150', true ),
+ );
+ }
+
+ /**
+ * @covers SpecialBookSources::isValidISBN
+ * @dataProvider provideISBNs
+ */
+ public function testIsValidISBN( $isbn, $isValid ) {
+ $this->assertSame( $isValid, SpecialBookSources::isValidISBN( $isbn ) );
+ }
+}
diff --git a/tests/phpunit/includes/specials/SpecialMIMESearchTest.php b/tests/phpunit/includes/specials/SpecialMIMESearchTest.php
index 14d19685..fe1c9e83 100644
--- a/tests/phpunit/includes/specials/SpecialMIMESearchTest.php
+++ b/tests/phpunit/includes/specials/SpecialMIMESearchTest.php
@@ -5,11 +5,11 @@
class SpecialMIMESearchTest extends MediaWikiTestCase {
- /** @var MIMESearchPage */
+ /** @var MIMEsearchPage */
private $page;
function setUp() {
- $this->page = new MIMESearchPage;
+ $this->page = new MIMEsearchPage;
$context = new RequestContext();
$context->setTitle( Title::makeTitle( NS_SPECIAL, 'MIMESearch' ) );
$context->setRequest( new FauxRequest() );
diff --git a/tests/phpunit/includes/title/ForeignTitleTest.php b/tests/phpunit/includes/title/ForeignTitleTest.php
new file mode 100644
index 00000000..599d2a33
--- /dev/null
+++ b/tests/phpunit/includes/title/ForeignTitleTest.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author This, that and the other
+ */
+
+/**
+ * @covers ForeignTitle
+ *
+ * @group Title
+ */
+class ForeignTitleTest extends MediaWikiTestCase {
+
+ public function basicProvider() {
+ return array(
+ array(
+ new ForeignTitle( 20, 'Contributor', 'JohnDoe' ),
+ 20, 'Contributor', 'JohnDoe'
+ ),
+ array(
+ new ForeignTitle( '1', 'Discussion', 'Capital' ),
+ 1, 'Discussion', 'Capital'
+ ),
+ array(
+ new ForeignTitle( 0, '', 'MainNamespace' ),
+ 0, '', 'MainNamespace'
+ ),
+ array(
+ new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ),
+ 4, 'Some_ns', 'Article_title_with_spaces'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( ForeignTitle $title, $expectedId, $expectedName,
+ $expectedText ) {
+
+ $this->assertEquals( true, $title->isNamespaceIdKnown() );
+ $this->assertEquals( $expectedId, $title->getNamespaceId() );
+ $this->assertEquals( $expectedName, $title->getNamespaceName() );
+ $this->assertEquals( $expectedText, $title->getText() );
+ }
+
+ public function testUnknownNamespaceCheck( ) {
+ $title = new ForeignTitle( null, 'this', 'that' );
+
+ $this->assertEquals( false, $title->isNamespaceIdKnown() );
+ $this->assertEquals( 'this', $title->getNamespaceName() );
+ $this->assertEquals( 'that', $title->getText() );
+ }
+
+ public function testUnknownNamespaceError( ) {
+ $this->setExpectedException( 'MWException' );
+ $title = new ForeignTitle( null, 'this', 'that' );
+ $title->getNamespaceId();
+ }
+
+ public function fullTextProvider() {
+ return array(
+ array(
+ new ForeignTitle( 20, 'Contributor', 'JohnDoe' ),
+ 'Contributor:JohnDoe'
+ ),
+ array(
+ new ForeignTitle( '1', 'Discussion', 'Capital' ),
+ 'Discussion:Capital'
+ ),
+ array(
+ new ForeignTitle( 0, '', 'MainNamespace' ),
+ 'MainNamespace'
+ ),
+ array(
+ new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ),
+ 'Some_ns:Article_title_with_spaces'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider fullTextProvider
+ */
+ public function testFullText( ForeignTitle $title, $fullText ) {
+ $this->assertEquals( $fullText, $title->getFullText() );
+ }
+}
diff --git a/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php b/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
index 4171c10e..cd0d0b1c 100644
--- a/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
+++ b/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
@@ -16,7 +16,6 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @license GPL 2+
* @author Daniel Kinzler
*/
diff --git a/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php b/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php
index f95b3050..78d304c1 100644
--- a/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php
+++ b/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php
@@ -16,7 +16,6 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @license GPL 2+
* @author Daniel Kinzler
*/
@@ -39,6 +38,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
'wgLang' => Language::factory( 'en' ),
'wgAllowUserJs' => false,
'wgDefaultLanguageVariant' => false,
+ 'wgMetaNamespace' => 'Project',
'wgLocalInterwikis' => array( 'localtestiw' ),
'wgCapitalLinks' => true,
@@ -82,6 +82,8 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
protected function makeCodec( $lang ) {
$gender = $this->getGenderCache();
$lang = Language::factory( $lang );
+ // language object can came from cache, which does not respect test settings
+ $lang->resetNamespaces();
return new MediaWikiTitleCodec( $lang, $gender );
}
@@ -367,13 +369,6 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
/**
* @dataProvider provideGetNamespaceName
- *
- * @param int $namespace
- * @param string $text
- * @param string $lang
- * @param string $expected
- *
- * @internal param \TitleValue $title
*/
public function testGetNamespaceName( $namespace, $text, $lang, $expected ) {
$codec = $this->makeCodec( $lang );
diff --git a/tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php b/tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php
new file mode 100644
index 00000000..504e8712
--- /dev/null
+++ b/tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author This, that and the other
+ */
+
+/**
+ * @covers NaiveForeignTitleFactory
+ *
+ * @group Title
+ */
+class NaiveForeignTitleFactoryTest extends MediaWikiTestCase {
+
+ public function basicProvider() {
+ return array(
+ array(
+ 'MainNamespaceArticle', 0,
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ ),
+ array(
+ 'MainNamespaceArticle', null,
+ new ForeignTitle( null, '', 'MainNamespaceArticle' ),
+ ),
+ array(
+ 'Talk:Nice_talk', 1,
+ new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', 0,
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', 9000, // non-existent local namespace ID
+ new ForeignTitle( 9000, 'Bogus', 'Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', 4, // existing local namespace ID
+ new ForeignTitle( 4, 'Bogus', 'Nice_talk' ),
+ ),
+ array(
+ 'Talk:Extra:Nice_talk', 1,
+ new ForeignTitle( 1, 'Talk', 'Extra:Nice_talk' ),
+ ),
+ array(
+ 'Talk:Extra:Nice_talk', null,
+ new ForeignTitle( null, 'Talk', 'Extra:Nice_talk' ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( $title, $ns, ForeignTitle $foreignTitle ) {
+ $factory = new NaiveForeignTitleFactory();
+ $testTitle = $factory->createForeignTitle( $title, $ns );
+
+ $this->assertEquals( $testTitle->isNamespaceIdKnown(),
+ $foreignTitle->isNamespaceIdKnown() );
+
+ if (
+ $testTitle->isNamespaceIdKnown() &&
+ $foreignTitle->isNamespaceIdKnown()
+ ) {
+ $this->assertEquals( $testTitle->getNamespaceId(),
+ $foreignTitle->getNamespaceId() );
+ }
+
+ $this->assertEquals( $testTitle->getNamespaceName(),
+ $foreignTitle->getNamespaceName() );
+ $this->assertEquals( $testTitle->getText(), $foreignTitle->getText() );
+
+ $this->assertEquals( str_replace( ' ', '_', $title ),
+ $foreignTitle->getFullText() );
+ }
+}
diff --git a/tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php b/tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php
new file mode 100644
index 00000000..98b414e0
--- /dev/null
+++ b/tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author This, that and the other
+ */
+
+/**
+ * @covers NaiveImportTitleFactory
+ *
+ * @group Title
+ */
+class NaiveImportTitleFactoryTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgLanguageCode' => 'en',
+ 'wgContLang' => Language::factory( 'en' ),
+ 'wgExtraNamespaces' => array( 100 => 'Portal' ),
+ ) );
+ }
+
+ public function basicProvider() {
+ return array(
+ array(
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ Title::newFromText( 'MainNamespaceArticle' )
+ ),
+ array(
+ new ForeignTitle( null, '', 'MainNamespaceArticle' ),
+ Title::newFromText( 'MainNamespaceArticle' )
+ ),
+ array(
+ new ForeignTitle( 1, 'Discussion', 'Nice_talk' ),
+ Title::newFromText( 'Talk:Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ Title::newFromText( 'Bogus:Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 100, 'Bogus', 'Nice_talk' ),
+ Title::newFromText( 'Bogus:Nice_talk' ) // not Portal:Nice_talk
+ ),
+ array(
+ new ForeignTitle( 1, 'Bogus', 'Nice_talk' ),
+ Title::newFromText( 'Talk:Nice_talk' ) // not Bogus:Nice_talk
+ ),
+ array(
+ new ForeignTitle( 100, 'Portal', 'Nice_talk' ),
+ Title::newFromText( 'Portal:Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 724, 'Portal', 'Nice_talk' ),
+ Title::newFromText( 'Portal:Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 2, 'Portal', 'Nice_talk' ),
+ Title::newFromText( 'User:Nice_talk' )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( ForeignTitle $foreignTitle, Title $title ) {
+ $factory = new NaiveImportTitleFactory();
+ $testTitle = $factory->createTitleFromForeignTitle( $foreignTitle );
+
+ $this->assertTrue( $title->equals( $testTitle ) );
+ }
+}
diff --git a/tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php b/tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php
new file mode 100644
index 00000000..9cb195cc
--- /dev/null
+++ b/tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author This, that and the other
+ */
+
+/**
+ * @covers NamespaceAwareForeignTitleFactory
+ *
+ * @group Title
+ */
+class NamespaceAwareForeignTitleFactoryTest extends MediaWikiTestCase {
+
+ public function basicProvider() {
+ return array(
+ array(
+ 'MainNamespaceArticle', 0,
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ ),
+ array(
+ 'MainNamespaceArticle', null,
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ ),
+ array(
+ 'Talk:Nice_talk', 1,
+ new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', 0,
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', null,
+ new ForeignTitle( 9000, 'Bogus', 'Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', 4,
+ new ForeignTitle( 4, 'Bogus', 'Nice_talk' ),
+ ),
+ array(
+ 'Bogus:Nice_talk', 1,
+ new ForeignTitle( 1, 'Talk', 'Nice_talk' ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( $title, $ns, ForeignTitle $foreignTitle ) {
+
+ $foreignNamespaces = array(
+ 0 => '', 1 => 'Talk', 100 => 'Portal', 9000 => 'Bogus'
+ );
+
+ $factory = new NamespaceAwareForeignTitleFactory( $foreignNamespaces );
+ $testTitle = $factory->createForeignTitle( $title, $ns );
+
+ $this->assertEquals( $testTitle->isNamespaceIdKnown(),
+ $foreignTitle->isNamespaceIdKnown() );
+
+ if (
+ $testTitle->isNamespaceIdKnown() &&
+ $foreignTitle->isNamespaceIdKnown()
+ ) {
+ $this->assertEquals( $testTitle->getNamespaceId(),
+ $foreignTitle->getNamespaceId() );
+ }
+
+ $this->assertEquals( $testTitle->getNamespaceName(),
+ $foreignTitle->getNamespaceName() );
+ $this->assertEquals( $testTitle->getText(), $foreignTitle->getText() );
+ }
+}
diff --git a/tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php b/tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php
new file mode 100644
index 00000000..d6fe6848
--- /dev/null
+++ b/tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author This, that and the other
+ */
+
+/**
+ * @covers NamespaceImportTitleFactory
+ *
+ * @group Title
+ */
+class NamespaceImportTitleFactoryTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgLanguageCode' => 'en',
+ 'wgContLang' => Language::factory( 'en' ),
+ ) );
+ }
+
+ public function basicProvider() {
+ return array(
+ array(
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ 0,
+ Title::newFromText( 'MainNamespaceArticle' )
+ ),
+ array(
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ 2,
+ Title::newFromText( 'User:MainNamespaceArticle' )
+ ),
+ array(
+ new ForeignTitle( 1, 'Discussion', 'Nice_talk' ),
+ 0,
+ Title::newFromText( 'Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ 0,
+ Title::newFromText( 'Bogus:Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ 2,
+ Title::newFromText( 'User:Bogus:Nice_talk' )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( ForeignTitle $foreignTitle, $ns, Title $title ) {
+ $factory = new NamespaceImportTitleFactory( $ns );
+ $testTitle = $factory->createTitleFromForeignTitle( $foreignTitle );
+
+ $this->assertTrue( $title->equals( $testTitle ) );
+ }
+}
diff --git a/tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php b/tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php
new file mode 100644
index 00000000..d5c17f3e
--- /dev/null
+++ b/tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author This, that and the other
+ */
+
+/**
+ * @covers SubpageImportTitleFactory
+ *
+ * @group Title
+ */
+class SubpageImportTitleFactoryTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgLanguageCode' => 'en',
+ 'wgContLang' => Language::factory( 'en' ),
+ 'wgNamespacesWithSubpages' => array( 0 => false, 2 => true ),
+ ) );
+ }
+
+ public function basicProvider() {
+ return array(
+ array(
+ new ForeignTitle( 0, '', 'MainNamespaceArticle' ),
+ Title::newFromText( 'User:Graham' ),
+ Title::newFromText( 'User:Graham/MainNamespaceArticle' )
+ ),
+ array(
+ new ForeignTitle( 1, 'Discussion', 'Nice_talk' ),
+ Title::newFromText( 'User:Graham' ),
+ Title::newFromText( 'User:Graham/Discussion:Nice_talk' )
+ ),
+ array(
+ new ForeignTitle( 0, '', 'Bogus:Nice_talk' ),
+ Title::newFromText( 'User:Graham' ),
+ Title::newFromText( 'User:Graham/Bogus:Nice_talk' )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider basicProvider
+ */
+ public function testBasic( ForeignTitle $foreignTitle, Title $rootPage,
+ Title $title ) {
+
+ $factory = new SubpageImportTitleFactory( $rootPage );
+ $testTitle = $factory->createTitleFromForeignTitle( $foreignTitle );
+
+ $this->assertTrue( $testTitle->equals( $title ) );
+ }
+
+ public function failureProvider() {
+ return array(
+ array(
+ Title::newFromText( 'Graham' ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider failureProvider
+ */
+ public function testFailures( Title $rootPage ) {
+ $this->setExpectedException( 'MWException' );
+ new SubpageImportTitleFactory( $rootPage );
+ }
+}
diff --git a/tests/phpunit/includes/title/TitleValueTest.php b/tests/phpunit/includes/title/TitleValueTest.php
index 3ba008d6..184198d2 100644
--- a/tests/phpunit/includes/title/TitleValueTest.php
+++ b/tests/phpunit/includes/title/TitleValueTest.php
@@ -16,7 +16,6 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @license GPL 2+
* @author Daniel Kinzler
*/
diff --git a/tests/phpunit/includes/upload/UploadBaseTest.php b/tests/phpunit/includes/upload/UploadBaseTest.php
index 3d3b0068..9441b77f 100644
--- a/tests/phpunit/includes/upload/UploadBaseTest.php
+++ b/tests/phpunit/includes/upload/UploadBaseTest.php
@@ -9,21 +9,17 @@ class UploadBaseTest extends MediaWikiTestCase {
protected $upload;
protected function setUp() {
- global $wgHooks;
parent::setUp();
$this->upload = new UploadTestHandler;
- $this->hooks = $wgHooks;
- $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) {
- return false;
- };
- }
-
- protected function tearDown() {
- global $wgHooks;
- $wgHooks = $this->hooks;
- parent::tearDown();
+ $this->setMwGlobals( 'wgHooks', array(
+ 'InterwikiLoadPrefix' => array(
+ function ( $prefix, &$data ) {
+ return false;
+ }
+ ),
+ ) );
}
/**
@@ -97,7 +93,7 @@ class UploadBaseTest extends MediaWikiTestCase {
// Helper used to create an empty file of size $size.
private function createFileOfSize( $size ) {
- $filename = tempnam( wfTempDir(), "mwuploadtest" );
+ $filename = $this->getNewTempFile();
$fh = fopen( $filename, 'w' );
ftruncate( $fh, $size );
@@ -112,22 +108,21 @@ class UploadBaseTest extends MediaWikiTestCase {
* This method should be abstracted so we can test different settings.
*/
public function testMaxUploadSize() {
- global $wgMaxUploadSize;
- $savedGlobal = $wgMaxUploadSize; // save global
- global $wgFileExtensions;
- $wgFileExtensions[] = 'txt';
-
- $wgMaxUploadSize = 100;
+ $this->setMwGlobals( array(
+ 'wgMaxUploadSize' => 100,
+ 'wgFileExtensions' => array(
+ 'txt',
+ ),
+ ) );
- $filename = $this->createFileOfSize( $wgMaxUploadSize );
+ $filename = $this->createFileOfSize( 100 );
$this->upload->initializePathInfo( basename( $filename ) . '.txt', $filename, 100 );
$result = $this->upload->verifyUpload();
- unlink( $filename );
$this->assertEquals(
- array( 'status' => UploadBase::OK ), $result );
-
- $wgMaxUploadSize = $savedGlobal; // restore global
+ array( 'status' => UploadBase::OK ),
+ $result
+ );
}
diff --git a/tests/phpunit/includes/upload/UploadFromUrlTest.php b/tests/phpunit/includes/upload/UploadFromUrlTest.php
index ec56b63e..b7496629 100644
--- a/tests/phpunit/includes/upload/UploadFromUrlTest.php
+++ b/tests/phpunit/includes/upload/UploadFromUrlTest.php
@@ -35,7 +35,10 @@ class UploadFromUrlTest extends ApiTestCase {
wfSetupSession( $sessionId );
- return array( $module->getResultData(), $req );
+ return array(
+ $module->getResult()->getResultData( null, array( 'Strip' => 'all' ) ),
+ $req
+ );
}
/**
diff --git a/tests/phpunit/includes/utils/CdbTest.php b/tests/phpunit/includes/utils/CdbTest.php
deleted file mode 100644
index 487ee1fc..00000000
--- a/tests/phpunit/includes/utils/CdbTest.php
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-
-/**
- * Test the CDB reader/writer
- * @covers CdbWriterPHP
- * @covers CdbWriterDBA
- */
-class CdbTest extends MediaWikiTestCase {
-
- protected function setUp() {
- parent::setUp();
- if ( !CdbReader::haveExtension() ) {
- $this->markTestSkipped( 'Native CDB support is not available' );
- }
- }
-
- /**
- * @group medium
- */
- public function testCdb() {
- $dir = wfTempDir();
- if ( !is_writable( $dir ) ) {
- $this->markTestSkipped( "Temp dir isn't writable" );
- }
-
- $phpcdbfile = $this->getNewTempFile();
- $dbacdbfile = $this->getNewTempFile();
-
- $w1 = new CdbWriterPHP( $phpcdbfile );
- $w2 = new CdbWriterDBA( $dbacdbfile );
-
- $data = array();
- for ( $i = 0; $i < 1000; $i++ ) {
- $key = $this->randomString();
- $value = $this->randomString();
- $w1->set( $key, $value );
- $w2->set( $key, $value );
-
- if ( !isset( $data[$key] ) ) {
- $data[$key] = $value;
- }
- }
-
- $w1->close();
- $w2->close();
-
- $this->assertEquals(
- md5_file( $phpcdbfile ),
- md5_file( $dbacdbfile ),
- 'same hash'
- );
-
- $r1 = new CdbReaderPHP( $phpcdbfile );
- $r2 = new CdbReaderDBA( $dbacdbfile );
-
- foreach ( $data as $key => $value ) {
- if ( $key === '' ) {
- // Known bug
- continue;
- }
- $v1 = $r1->get( $key );
- $v2 = $r2->get( $key );
-
- $v1 = $v1 === false ? '(not found)' : $v1;
- $v2 = $v2 === false ? '(not found)' : $v2;
-
- # cdbAssert( 'Mismatch', $key, $v1, $v2 );
- $this->cdbAssert( "PHP error", $key, $v1, $value );
- $this->cdbAssert( "DBA error", $key, $v2, $value );
- }
- }
-
- private function randomString() {
- $len = mt_rand( 0, 10 );
- $s = '';
- for ( $j = 0; $j < $len; $j++ ) {
- $s .= chr( mt_rand( 0, 255 ) );
- }
-
- return $s;
- }
-
- private function cdbAssert( $msg, $key, $v1, $v2 ) {
- $this->assertEquals(
- $v2,
- $v1,
- $msg . ', k=' . bin2hex( $key )
- );
- }
-}
diff --git a/tests/phpunit/includes/utils/IPTest.php b/tests/phpunit/includes/utils/IPTest.php
index ebe347fd..09c1587d 100644
--- a/tests/phpunit/includes/utils/IPTest.php
+++ b/tests/phpunit/includes/utils/IPTest.php
@@ -9,7 +9,7 @@
* dataprovider.
*/
-class IPTest extends MediaWikiTestCase {
+class IPTest extends PHPUnit_Framework_TestCase {
/**
* not sure it should be tested with boolean false. hashar 20100924
* @covers IP::isIPAddress
diff --git a/tests/phpunit/includes/utils/MWCryptHKDFTest.php b/tests/phpunit/includes/utils/MWCryptHKDFTest.php
index 7e37534a..73e4c1a9 100644
--- a/tests/phpunit/includes/utils/MWCryptHKDFTest.php
+++ b/tests/phpunit/includes/utils/MWCryptHKDFTest.php
@@ -6,6 +6,12 @@
class MWCryptHKDFTest extends MediaWikiTestCase {
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( 'wgSecretKey', '5bf1945342e67799cb50704a7fa19ac6' );
+ }
+
/**
* Test basic usage works
*/
diff --git a/tests/phpunit/includes/MWFunctionTest.php b/tests/phpunit/includes/utils/MWFunctionTest.php
index f2a720e8..f4d17999 100644
--- a/tests/phpunit/includes/MWFunctionTest.php
+++ b/tests/phpunit/includes/utils/MWFunctionTest.php
@@ -13,6 +13,7 @@ class MWFunctionTest extends MediaWikiTestCase {
$args = array( $arg1, $arg2, $arg3, $arg4 );
$newObject = new MWBlankClass( $arg1, $arg2, $arg3, $arg4 );
+ $this->hideDeprecated( 'MWFunction::newObj' );
$this->assertEquals(
MWFunction::newObj( 'MWBlankClass', $args )->args,
$newObject->args
diff --git a/tests/phpunit/includes/utils/UIDGeneratorTest.php b/tests/phpunit/includes/utils/UIDGeneratorTest.php
index 50fa3849..0e11ccad 100644
--- a/tests/phpunit/includes/utils/UIDGeneratorTest.php
+++ b/tests/phpunit/includes/utils/UIDGeneratorTest.php
@@ -35,14 +35,14 @@ class UIDGeneratorTest extends MediaWikiTestCase {
$lastId_bin = wfBaseConvert( $lastId, 10, 2 );
$this->assertGreaterThanOrEqual(
- substr( $id_bin, 0, $tbits ),
substr( $lastId_bin, 0, $tbits ),
+ substr( $id_bin, 0, $tbits ),
"New ID timestamp ($id_bin) >= prior one ($lastId_bin)." );
if ( $hostbits ) {
$this->assertEquals(
- substr( $id_bin, 0, -$hostbits ),
- substr( $lastId_bin, 0, -$hostbits ),
+ substr( $id_bin, -$hostbits ),
+ substr( $lastId_bin, -$hostbits ),
"Host ID of ($id_bin) is same as prior one ($lastId_bin)." );
}
diff --git a/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php b/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php
index 34ffb535..05d07d45 100644
--- a/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php
+++ b/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php
@@ -4,7 +4,7 @@
* @covers ZipDirectoryReader
* NOTE: this test is more like an integration test than a unit test
*/
-class ZipDirectoryReaderTest extends MediaWikiTestCase {
+class ZipDirectoryReaderTest extends PHPUnit_Framework_TestCase {
protected $zipDir;
protected $entries;