summaryrefslogtreecommitdiff
path: root/tests/phpunit/includes
diff options
context:
space:
mode:
Diffstat (limited to 'tests/phpunit/includes')
-rw-r--r--tests/phpunit/includes/BlockTest.php114
-rw-r--r--tests/phpunit/includes/ConsecutiveParametersMatcher.php123
-rw-r--r--tests/phpunit/includes/EditPageTest.php55
-rw-r--r--tests/phpunit/includes/ExtraParserTest.php3
-rw-r--r--tests/phpunit/includes/FauxRequestTest.php43
-rw-r--r--tests/phpunit/includes/FauxResponseTest.php7
-rw-r--r--tests/phpunit/includes/GlobalFunctions/GlobalTest.php103
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php94
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php1
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php2
-rw-r--r--tests/phpunit/includes/ImportLinkCacheIntegrationTest.php112
-rw-r--r--tests/phpunit/includes/LinkFilterTest.php12
-rw-r--r--tests/phpunit/includes/LinkerTest.php66
-rw-r--r--tests/phpunit/includes/MediaWikiTest.php10
-rw-r--r--tests/phpunit/includes/MessageTest.php33
-rw-r--r--tests/phpunit/includes/MimeMagicTest.php2
-rw-r--r--tests/phpunit/includes/MovePageTest.php2
-rw-r--r--tests/phpunit/includes/OutputPageTest.php168
-rw-r--r--tests/phpunit/includes/PrefixSearchTest.php5
-rw-r--r--tests/phpunit/includes/SanitizerTest.php12
-rw-r--r--tests/phpunit/includes/SanitizerValidateEmailTest.php2
-rw-r--r--tests/phpunit/includes/StatusTest.php4
-rw-r--r--tests/phpunit/includes/TemplateParserTest.php15
-rw-r--r--tests/phpunit/includes/TestingAccessWrapper.php34
-rw-r--r--tests/phpunit/includes/TestingAccessWrapperTest.php18
-rw-r--r--tests/phpunit/includes/TitleArrayFromResultTest.php2
-rw-r--r--tests/phpunit/includes/TitlePermissionTest.php22
-rw-r--r--tests/phpunit/includes/TitleTest.php101
-rw-r--r--tests/phpunit/includes/UserTest.php130
-rw-r--r--tests/phpunit/includes/WikiMapTest.php108
-rw-r--r--tests/phpunit/includes/WikiReferenceTest.php80
-rw-r--r--tests/phpunit/includes/XmlJsTest.php2
-rw-r--r--tests/phpunit/includes/XmlTest.php6
-rw-r--r--tests/phpunit/includes/api/ApiBlockTest.php6
-rw-r--r--tests/phpunit/includes/api/ApiEditPageTest.php113
-rw-r--r--tests/phpunit/includes/api/ApiLoginTest.php4
-rw-r--r--tests/phpunit/includes/api/ApiMainTest.php171
-rw-r--r--tests/phpunit/includes/api/ApiMessageTest.php20
-rw-r--r--tests/phpunit/includes/api/ApiQueryAllPagesTest.php6
-rw-r--r--tests/phpunit/includes/api/ApiResultTest.php194
-rw-r--r--tests/phpunit/includes/api/ApiRevisionDeleteTest.php4
-rw-r--r--tests/phpunit/includes/api/ApiTestCase.php1
-rw-r--r--tests/phpunit/includes/api/ApiUnblockTest.php4
-rw-r--r--tests/phpunit/includes/api/ApiUploadTest.php36
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatDumpTest.php63
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatWddxTest.php80
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php5
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryTest.php2
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryTestBase.php14
-rw-r--r--tests/phpunit/includes/cache/MessageCacheTest.php29
-rw-r--r--tests/phpunit/includes/changes/RecentChangeTest.php327
-rw-r--r--tests/phpunit/includes/config/HashConfigTest.php2
-rw-r--r--tests/phpunit/includes/content/ContentHandlerTest.php179
-rw-r--r--tests/phpunit/includes/content/CssContentHandlerTest.php30
-rw-r--r--tests/phpunit/includes/content/CssContentTest.php45
-rw-r--r--tests/phpunit/includes/content/JavaScriptContentHandlerTest.php30
-rw-r--r--tests/phpunit/includes/content/JavaScriptContentTest.php53
-rw-r--r--tests/phpunit/includes/content/JsonContentTest.php2
-rw-r--r--tests/phpunit/includes/content/TextContentHandlerTest.php12
-rw-r--r--tests/phpunit/includes/content/TextContentTest.php8
-rw-r--r--tests/phpunit/includes/content/WikitextContentHandlerTest.php5
-rw-r--r--tests/phpunit/includes/db/DatabaseMysqlBaseTest.php2
-rw-r--r--tests/phpunit/includes/db/DatabaseSqliteTest.php25
-rw-r--r--tests/phpunit/includes/db/ORMTableTest.php19
-rw-r--r--tests/phpunit/includes/debug/MWDebugTest.php4
-rw-r--r--tests/phpunit/includes/debug/logger/LegacyLoggerTest.php (renamed from tests/phpunit/includes/debug/logging/LegacyLoggerTest.php)53
-rw-r--r--tests/phpunit/includes/debug/logger/MonologSpiTest.php136
-rw-r--r--tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php64
-rw-r--r--tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php207
-rw-r--r--tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php75
-rw-r--r--tests/phpunit/includes/deferred/DeferredUpdatesTest.php37
-rw-r--r--tests/phpunit/includes/diff/ArrayDiffFormatterTest.php4
-rw-r--r--tests/phpunit/includes/exception/HttpErrorTest.php65
-rw-r--r--tests/phpunit/includes/exception/MWExceptionTest.php2
-rw-r--r--tests/phpunit/includes/filebackend/FileBackendTest.php52
-rw-r--r--tests/phpunit/includes/filebackend/SwiftFileBackendTest.php148
-rw-r--r--tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php138
-rw-r--r--tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php114
-rw-r--r--tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php2
-rw-r--r--tests/phpunit/includes/json/FormatJsonTest.php10
-rw-r--r--tests/phpunit/includes/libs/ArrayUtilsTest.php12
-rw-r--r--tests/phpunit/includes/libs/CSSMinTest.php57
-rw-r--r--tests/phpunit/includes/libs/IEUrlExtensionTest.php33
-rw-r--r--tests/phpunit/includes/libs/IPSetTest.php252
-rw-r--r--tests/phpunit/includes/libs/JavaScriptMinifierTest.php19
-rw-r--r--tests/phpunit/includes/libs/ObjectFactoryTest.php41
-rw-r--r--tests/phpunit/includes/libs/ProcessCacheLRUTest.php2
-rw-r--r--tests/phpunit/includes/libs/SamplingStatsdClientTest.php43
-rw-r--r--tests/phpunit/includes/libs/XhprofTest.php16
-rw-r--r--tests/phpunit/includes/libs/composer/ComposerLockTest.php61
-rw-r--r--tests/phpunit/includes/logging/BlockLogFormatterTest.php372
-rw-r--r--tests/phpunit/includes/logging/DeleteLogFormatterTest.php527
-rw-r--r--tests/phpunit/includes/logging/LogFormatterTest.php321
-rw-r--r--tests/phpunit/includes/logging/LogFormatterTestCase.php65
-rw-r--r--tests/phpunit/includes/logging/MergeLogFormatterTest.php67
-rw-r--r--tests/phpunit/includes/logging/MoveLogFormatterTest.php270
-rw-r--r--tests/phpunit/includes/logging/NewUsersLogFormatterTest.php207
-rw-r--r--tests/phpunit/includes/logging/PageLangLogFormatterTest.php53
-rw-r--r--tests/phpunit/includes/logging/PatrolLogFormatterTest.php118
-rw-r--r--tests/phpunit/includes/logging/ProtectLogFormatterTest.php63
-rw-r--r--tests/phpunit/includes/logging/RightsLogFormatterTest.php157
-rw-r--r--tests/phpunit/includes/logging/UploadLogFormatterTest.php166
-rw-r--r--tests/phpunit/includes/media/ExifBitmapTest.php39
-rw-r--r--tests/phpunit/includes/media/FormatMetadataTest.php33
-rw-r--r--tests/phpunit/includes/media/WebPTest.php127
-rw-r--r--tests/phpunit/includes/media/XMPValidateTest.php5
-rw-r--r--tests/phpunit/includes/objectcache/BagOStuffTest.php34
-rw-r--r--tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php55
-rw-r--r--tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php62
-rw-r--r--tests/phpunit/includes/objectcache/WANObjectCacheTest.php292
-rw-r--r--tests/phpunit/includes/parser/MagicVariableTest.php2
-rw-r--r--tests/phpunit/includes/parser/MediaWikiParserTest.php2
-rw-r--r--tests/phpunit/includes/parser/NewParserTest.php10
-rw-r--r--tests/phpunit/includes/parser/ParserMethodsTest.php4
-rw-r--r--tests/phpunit/includes/parser/TagHooksTest.php7
-rw-r--r--tests/phpunit/includes/parser/TidyTest.php3
-rw-r--r--tests/phpunit/includes/password/PasswordPolicyChecksTest.php136
-rw-r--r--tests/phpunit/includes/password/UserPasswordPolicyTest.php234
-rw-r--r--tests/phpunit/includes/registration/CoreVersionCheckerTest.php38
-rw-r--r--tests/phpunit/includes/registration/ExtensionProcessorTest.php16
-rw-r--r--tests/phpunit/includes/registration/ExtensionRegistryTest.php2
-rw-r--r--tests/phpunit/includes/resourceloader/DerivativeResourceLoaderContextTest.php78
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php22
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php3
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php58
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php74
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderTest.php11
-rw-r--r--tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php49
-rw-r--r--tests/phpunit/includes/site/CachingSiteStoreTest.php8
-rw-r--r--tests/phpunit/includes/site/DBSiteStoreTest.php24
-rw-r--r--tests/phpunit/includes/site/HashSiteStoreTest.php2
-rw-r--r--tests/phpunit/includes/site/SiteExporterTest.php4
-rw-r--r--tests/phpunit/includes/site/SiteImporterTest.php12
-rw-r--r--tests/phpunit/includes/specials/SpecialBlankPageTest.php25
-rw-r--r--tests/phpunit/includes/specials/SpecialPageTestBase.php165
-rw-r--r--tests/phpunit/includes/specials/SpecialPreferencesTest.php3
-rw-r--r--tests/phpunit/includes/specials/SpecialSearchTest.php106
-rw-r--r--tests/phpunit/includes/title/ForeignTitleTest.php4
-rw-r--r--tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php2
-rw-r--r--tests/phpunit/includes/upload/UploadStashTest.php2
-rw-r--r--tests/phpunit/includes/utils/AvroValidatorTest.php96
-rw-r--r--tests/phpunit/includes/utils/BatchRowUpdateTest.php243
-rw-r--r--tests/phpunit/includes/utils/IPTest.php273
-rw-r--r--tests/phpunit/includes/utils/MWFunctionTest.php34
-rw-r--r--tests/phpunit/includes/utils/UIDGeneratorTest.php10
145 files changed, 7889 insertions, 1535 deletions
diff --git a/tests/phpunit/includes/BlockTest.php b/tests/phpunit/includes/BlockTest.php
index 19741621..7b0de866 100644
--- a/tests/phpunit/includes/BlockTest.php
+++ b/tests/phpunit/includes/BlockTest.php
@@ -38,9 +38,13 @@ class BlockTest extends MediaWikiLangTestCase {
$oldBlock->delete();
}
- $this->block = new Block( 'UTBlockee', $user->getID(), 0,
- 'Parce que', 0, false, time() + 100500
+ $blockOptions = array(
+ 'address' => 'UTBlockee',
+ 'user' => $user->getID(),
+ 'reason' => 'Parce que',
+ 'expiry' => time() + 100500,
);
+ $this->block = new Block( $blockOptions );
$this->madeAt = wfTimestamp( TS_MW );
$this->block->insert();
@@ -151,22 +155,19 @@ class BlockTest extends MediaWikiLangTestCase {
);
// Foreign perspective (blockee not on current wiki)...
- $block = new Block(
- /* $address */ $username,
- /* $user */ 14146,
- /* $by */ 0,
- /* $reason */ 'crosswiki block...',
- /* $timestamp */ wfTimestampNow(),
- /* $auto */ false,
- /* $expiry */ $this->db->getInfinity(),
- /* anonOnly */ false,
- /* $createAccount */ true,
- /* $enableAutoblock */ true,
- /* $hideName (ipb_deleted) */ true,
- /* $blockEmail */ true,
- /* $allowUsertalk */ false,
- /* $byName */ 'MetaWikiUser'
+ $blockOptions = array(
+ 'address' => $username,
+ 'user' => 14146,
+ 'reason' => 'crosswiki block...',
+ 'timestamp' => wfTimestampNow(),
+ 'expiry' => $this->db->getInfinity(),
+ 'createAccount' => true,
+ 'enableAutoblock' => true,
+ 'hideName' => true,
+ 'blockEmail' => true,
+ 'byText' => 'MetaWikiUser',
);
+ $block = new Block( $blockOptions );
$block->insert();
// Reload block from DB
@@ -208,22 +209,19 @@ class BlockTest extends MediaWikiLangTestCase {
$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',
- /* $user */ 14146,
- /* $by */ 0,
- /* $reason */ 'crosswiki block...',
- /* $timestamp */ wfTimestampNow(),
- /* $auto */ false,
- /* $expiry */ $this->db->getInfinity(),
- /* anonOnly */ false,
- /* $createAccount */ true,
- /* $enableAutoblock */ true,
- /* $hideName (ipb_deleted) */ true,
- /* $blockEmail */ true,
- /* $allowUsertalk */ false,
- /* $byName */ 'MetaWikiUser'
+ $blockOptions = array(
+ 'address' => 'UserOnForeignWiki',
+ 'user' => 14146,
+ 'reason' => 'crosswiki block...',
+ 'timestamp' => wfTimestampNow(),
+ 'expiry' => $this->db->getInfinity(),
+ 'createAccount' => true,
+ 'enableAutoblock' => true,
+ 'hideName' => true,
+ 'blockEmail' => true,
+ 'byText' => 'MetaWikiUser',
);
+ $block = new Block( $blockOptions );
$res = $block->insert( $this->db );
$this->assertTrue( (bool)$res['id'], 'Block succeeded' );
@@ -367,4 +365,56 @@ class BlockTest extends MediaWikiLangTestCase {
$block = Block::chooseBlock( $xffblocks, $list );
$this->assertEquals( $exResult, $block->mReason, 'Correct block type for XFF header ' . $xff );
}
+
+ public function testDeprecatedConstructor() {
+ $this->hideDeprecated( 'Block::__construct with multiple arguments' );
+ $username = 'UnthinkablySecretRandomUsername';
+ $reason = 'being irrational';
+
+ # Set up the target
+ $u = User::newFromName( $username );
+ if ( $u->getID() == 0 ) {
+ $u->setPassword( 'TotallyObvious' );
+ $u->addToDatabase();
+ }
+ unset( $u );
+
+ # Make sure the user isn't blocked
+ $this->assertNull(
+ Block::newFromTarget( $username ),
+ "$username should not be blocked"
+ );
+
+ # Perform the block
+ $block = new Block(
+ /* address */ $username,
+ /* user */ 0,
+ /* by */ 0,
+ /* reason */ $reason,
+ /* timestamp */ 0,
+ /* auto */ false,
+ /* expiry */ 0
+ );
+ $block->insert();
+
+ # Check target
+ $this->assertEquals(
+ $block->getTarget()->getName(),
+ $username,
+ "Target should be set properly"
+ );
+
+ # Check supplied parameter
+ $this->assertEquals(
+ $block->mReason,
+ $reason,
+ "Reason should be non-default"
+ );
+
+ # Check default parameter
+ $this->assertFalse(
+ (bool)$block->prevents( 'createaccount' ),
+ "Account creation should not be blocked by default"
+ );
+ }
}
diff --git a/tests/phpunit/includes/ConsecutiveParametersMatcher.php b/tests/phpunit/includes/ConsecutiveParametersMatcher.php
new file mode 100644
index 00000000..adf74bb4
--- /dev/null
+++ b/tests/phpunit/includes/ConsecutiveParametersMatcher.php
@@ -0,0 +1,123 @@
+<?php
+/*
+ * This file is part of the PHPUnit_MockObject package.
+ *
+ * (c) Sebastian Bergmann <sebastian@phpunit.de>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Invocation matcher which looks for sets of specific parameters in the invocations.
+ *
+ * Checks the parameters of the incoming invocations, the parameter list is
+ * checked against the defined constraints in $parameters. If the constraint
+ * is met it will return true in matches().
+ *
+ * It takes a list of match groups and and increases a call index after each invocation.
+ * So the first invocation uses the first group of constraints, the second the next and so on.
+ */
+class PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
+{
+ /**
+ * @var array
+ */
+ private $_parameterGroups = array();
+
+ /**
+ * @var array
+ */
+ private $_invocations = array();
+
+ /**
+ * @param array $parameterGroups
+ */
+ public function __construct(array $parameterGroups)
+ {
+ foreach ($parameterGroups as $index => $parameters) {
+ foreach ($parameters as $parameter) {
+ if (!($parameter instanceof \PHPUnit_Framework_Constraint)) {
+ $parameter = new \PHPUnit_Framework_Constraint_IsEqual($parameter);
+ }
+ $this->_parameterGroups[$index][] = $parameter;
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function toString()
+ {
+ $text = 'with consecutive parameters';
+
+ return $text;
+ }
+
+ /**
+ * @param PHPUnit_Framework_MockObject_Invocation $invocation
+ * @return bool
+ */
+ public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
+ {
+ $this->_invocations[] = $invocation;
+ $callIndex = count($this->_invocations) - 1;
+ $this->verifyInvocation($invocation, $callIndex);
+
+ return false;
+ }
+
+ public function verify()
+ {
+ foreach ($this->_invocations as $callIndex => $invocation) {
+ $this->verifyInvocation($invocation, $callIndex);
+ }
+ }
+
+ /**
+ * Verify a single invocation
+ *
+ * @param PHPUnit_Framework_MockObject_Invocation $invocation
+ * @param int $callIndex
+ * @throws PHPUnit_Framework_ExpectationFailedException
+ */
+ private function verifyInvocation(PHPUnit_Framework_MockObject_Invocation $invocation, $callIndex)
+ {
+
+ if (isset($this->_parameterGroups[$callIndex])) {
+ $parameters = $this->_parameterGroups[$callIndex];
+ } else {
+ // no parameter assertion for this call index
+ return;
+ }
+
+ if ($invocation === null) {
+ throw new PHPUnit_Framework_ExpectationFailedException(
+ 'Mocked method does not exist.'
+ );
+ }
+
+ if (count($invocation->parameters) < count($parameters)) {
+ throw new PHPUnit_Framework_ExpectationFailedException(
+ sprintf(
+ 'Parameter count for invocation %s is too low.',
+ $invocation->toString()
+ )
+ );
+ }
+
+ foreach ($parameters as $i => $parameter) {
+ $parameter->evaluate(
+ $invocation->parameters[$i],
+ sprintf(
+ 'Parameter %s for invocation #%d %s does not match expected ' .
+ 'value.',
+ $i,
+ $callIndex,
+ $invocation->toString()
+ )
+ );
+ }
+ }
+}
diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php
index 15778e40..27959b1d 100644
--- a/tests/phpunit/includes/EditPageTest.php
+++ b/tests/phpunit/includes/EditPageTest.php
@@ -11,6 +11,28 @@
*/
class EditPageTest extends MediaWikiLangTestCase {
+ protected function setUp() {
+ global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
+
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgExtraNamespaces' => $wgExtraNamespaces,
+ 'wgNamespaceContentModels' => $wgNamespaceContentModels,
+ 'wgContentHandlers' => $wgContentHandlers,
+ 'wgContLang' => $wgContLang,
+ ) );
+
+ $wgExtraNamespaces[12312] = 'Dummy';
+ $wgExtraNamespaces[12313] = 'Dummy_talk';
+
+ $wgNamespaceContentModels[12312] = "testing";
+ $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
+
+ MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
+ $wgContLang->resetNamespaces(); # reset namespace cache
+ }
+
/**
* @dataProvider provideExtractSectionTitle
* @covers EditPage::extractSectionTitle
@@ -499,4 +521,37 @@ hello
$this->assertEdit( 'EditPageTest_testAutoMerge', null, 'Berta', $bertasEdit,
$expectedCode, $expectedText, $message );
}
+
+ /**
+ * @depends testAutoMerge
+ */
+ public function testCheckDirectEditingDisallowed_forNonTextContent() {
+ $title = Title::newFromText( 'Dummy:NonTextPageForEditPage' );
+ $page = WikiPage::factory( $title );
+
+ $article = new Article( $title );
+ $article->getContext()->setTitle( $title );
+ $ep = new EditPage( $article );
+ $ep->setContextTitle( $title );
+
+ $user = $GLOBALS['wgUser'];
+
+ $edit = array(
+ 'wpTextbox1' => serialize( 'non-text content' ),
+ 'wpEditToken' => $user->getEditToken(),
+ 'wpEdittime' => '',
+ 'wpStarttime' => wfTimestampNow()
+ );
+
+ $req = new FauxRequest( $edit, true );
+ $ep->importFormData( $req );
+
+ $this->setExpectedException(
+ 'MWException',
+ 'This content model is not supported: testing'
+ );
+
+ $ep->internalAttemptSave( $result, false );
+ }
+
}
diff --git a/tests/phpunit/includes/ExtraParserTest.php b/tests/phpunit/includes/ExtraParserTest.php
index 4a4130e0..7b60fb3f 100644
--- a/tests/phpunit/includes/ExtraParserTest.php
+++ b/tests/phpunit/includes/ExtraParserTest.php
@@ -2,6 +2,8 @@
/**
* Parser-related tests that don't suit for parserTests.txt
+ *
+ * @group Database
*/
class ExtraParserTest extends MediaWikiTestCase {
@@ -20,7 +22,6 @@ class ExtraParserTest extends MediaWikiTestCase {
'wgContLang' => $contLang,
'wgLang' => Language::factory( 'en' ),
'wgMemc' => new EmptyBagOStuff,
- 'wgAlwaysUseTidy' => false,
'wgCleanSignatures' => true,
) );
diff --git a/tests/phpunit/includes/FauxRequestTest.php b/tests/phpunit/includes/FauxRequestTest.php
index 745a5b42..07214b21 100644
--- a/tests/phpunit/includes/FauxRequestTest.php
+++ b/tests/phpunit/includes/FauxRequestTest.php
@@ -6,13 +6,46 @@ class FauxRequestTest extends MediaWikiTestCase {
* @covers FauxRequest::getHeader
*/
public function testGetSetHeader() {
- $value = 'test/test';
+ $value = 'text/plain, text/html';
$request = new FauxRequest();
- $request->setHeader( 'Content-Type', $value );
+ $request->setHeader( 'Accept', $value );
- $this->assertEquals( $request->getHeader( 'Content-Type' ), $value );
- $this->assertEquals( $request->getHeader( 'CONTENT-TYPE' ), $value );
- $this->assertEquals( $request->getHeader( 'content-type' ), $value );
+ $this->assertEquals( $request->getHeader( 'Nonexistent' ), false );
+ $this->assertEquals( $request->getHeader( 'Accept' ), $value );
+ $this->assertEquals( $request->getHeader( 'ACCEPT' ), $value );
+ $this->assertEquals( $request->getHeader( 'accept' ), $value );
+ $this->assertEquals(
+ $request->getHeader( 'Accept', WebRequest::GETHEADER_LIST ),
+ array( 'text/plain', 'text/html' )
+ );
+ }
+
+ /**
+ * @covers FauxRequest::getAllHeaders
+ */
+ public function testGetAllHeaders() {
+ $_SERVER['HTTP_TEST'] = 'Example';
+
+ $request = new FauxRequest();
+
+ $this->assertEquals(
+ array(),
+ $request->getAllHeaders()
+ );
+ }
+
+ /**
+ * @covers FauxRequest::getHeader
+ */
+ public function testGetHeader() {
+ $_SERVER['HTTP_TEST'] = 'Example';
+
+ $request = new FauxRequest();
+
+ $this->assertEquals(
+ false,
+ $request->getHeader( 'test' )
+ );
}
}
diff --git a/tests/phpunit/includes/FauxResponseTest.php b/tests/phpunit/includes/FauxResponseTest.php
index 4a974ba2..39a0effa 100644
--- a/tests/phpunit/includes/FauxResponseTest.php
+++ b/tests/phpunit/includes/FauxResponseTest.php
@@ -108,6 +108,13 @@ class FauxResponseTest extends MediaWikiTestCase {
'Third parameter overrides the HTTP/... header'
);
+ $this->response->statusHeader( 210 );
+ $this->assertEquals(
+ 210,
+ $this->response->getStatusCode(),
+ 'Handle statusHeader method'
+ );
+
$this->response->header( 'Location: http://localhost/', false, 206 );
$this->assertEquals(
206,
diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
index 1e30273e..e89e36f6 100644
--- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
@@ -666,9 +666,9 @@ class GlobalTest extends MediaWikiTestCase {
public function testWfMkdirParents() {
// Should not return true if file exists instead of directory
$fname = $this->getNewTempFile();
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = wfMkdirParents( $fname );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$this->assertFalse( $ok );
}
@@ -687,6 +687,105 @@ class GlobalTest extends MediaWikiTestCase {
$this->assertEquals( $expected, $actual, $description );
}
+ public function wfWikiID() {
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ) );
+ $this->assertEquals(
+ wfWikiID(),
+ 'example'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfWikiID(),
+ 'example-mw_'
+ );
+ }
+
+ public function testWfMemcKey() {
+ // Just assert the exact output so we can catch unintentional changes to key
+ // construction, which would effectively invalidate all existing cache.
+
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => false,
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ) );
+ $this->assertEquals(
+ wfMemcKey( 'foo', '123', 'bar' ),
+ 'example:foo:123:bar'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => false,
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfMemcKey( 'foo', '123', 'bar' ),
+ 'example-mw_:foo:123:bar'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => 'custom',
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfMemcKey( 'foo', '123', 'bar' ),
+ 'custom:foo:123:bar'
+ );
+ }
+
+ public function testWfForeignMemcKey() {
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => false,
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ) );
+ $local = wfMemcKey( 'foo', 'bar' );
+
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'other',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfForeignMemcKey( 'example', '', 'foo', 'bar' ),
+ $local,
+ 'Match output of wfMemcKey from local wiki'
+ );
+ }
+
+ public function testWfGlobalCacheKey() {
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => 'ignored',
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => ''
+ ) );
+ $one = wfGlobalCacheKey( 'some', 'thing' );
+ $this->assertEquals(
+ $one,
+ 'global:some:thing'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'other',
+ 'wgDBprefix' => 'mw_'
+ ) );
+ $two = wfGlobalCacheKey( 'some', 'thing' );
+
+ $this->assertEquals(
+ $one,
+ $two,
+ 'Not fragmented by wiki id'
+ );
+ }
+
public static function provideWfShellWikiCmdList() {
global $wgPhpCli;
diff --git a/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php b/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php
new file mode 100644
index 00000000..88875bb0
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * @group GlobalFunctions
+ * @covers ::wfArrayPlus2d
+ */
+class WfArrayPlus2dTest extends MediaWikiTestCase {
+ /**
+ * @dataProvider provideArrays
+ */
+ public function testWfArrayPlus2d( $baseArray, $newValues, $expected, $testName ) {
+ $this->assertEquals(
+ $expected,
+ wfArrayPlus2d( $baseArray, $newValues ),
+ $testName
+ );
+ }
+
+ /**
+ * Provider for testing wfArrayPlus2d
+ *
+ * @return array
+ */
+ public static function provideArrays() {
+ return array(
+ // target array, new values array, expected result
+ array(
+ array( 0 => '1dArray' ),
+ array( 1 => '1dArray' ),
+ array( 0 => '1dArray', 1 => '1dArray' ),
+ "Test simple union of two arrays with different keys",
+ ),
+ array(
+ array(
+ 0 => array( 0 => '2dArray' ),
+ ),
+ array(
+ 0 => array( 1 => '2dArray' ),
+ ),
+ array(
+ 0 => array( 0 => '2dArray', 1 => '2dArray' ),
+ ),
+ "Test union of 2d arrays with different keys in the value array",
+ ),
+ array(
+ array(
+ 0 => array( 0 => '2dArray' ),
+ ),
+ array(
+ 0 => array( 0 => '1dArray' ),
+ ),
+ array(
+ 0 => array( 0 => '2dArray' ),
+ ),
+ "Test union of 2d arrays with same keys in the value array",
+ ),
+ array(
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 1 => '2dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ "Test union of 3d array with different keys",
+ ),
+ array(
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ array(
+ 0 => array( 1 => array( 0 => '2dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ), 1 => array( 0 => '2dArray' ) ),
+ ),
+ "Test union of 3d array with different keys in the value array",
+ ),
+ array(
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '2dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ "Test union of 3d array with same keys in the value array",
+ ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
index bea496c4..4ce51c6a 100644
--- a/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
@@ -21,6 +21,7 @@ class WfTimestampTest extends MediaWikiTestCase {
array( -30281104, TS_MW, '19690115123456', 'Negative TS_UNIX to TS_MW' ),
array( $t, TS_UNIX, 979562096, 'TS_UNIX to TS_UNIX' ),
array( $t, TS_DB, '2001-01-15 12:34:56', 'TS_UNIX to TS_DB' ),
+ array( $t + .01, TS_MW, '20010115123456', 'TS_UNIX float to TS_MW' ),
array( $t, TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_ISO_8601_BASIC to TS_DB' ),
diff --git a/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php b/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
index d11668b7..d4df7b00 100644
--- a/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
@@ -112,6 +112,8 @@ class WfUrlencodeTest extends MediaWikiTestCase {
### Other tests
// slash remain unchanged. %2F seems to break things
array( '/', '/' ),
+ // T105265
+ array( '~', '~' ),
// Other 'funnies' chars
array( '[]', '%5B%5D' ),
diff --git a/tests/phpunit/includes/ImportLinkCacheIntegrationTest.php b/tests/phpunit/includes/ImportLinkCacheIntegrationTest.php
new file mode 100644
index 00000000..1433b898
--- /dev/null
+++ b/tests/phpunit/includes/ImportLinkCacheIntegrationTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Integration test that checks import success and
+ * LinkCache integration.
+ *
+ * @group medium
+ * @group Database
+ *
+ * @author mwjames
+ */
+class ImportLinkCacheIntegrationTest extends MediaWikiTestCase {
+
+ private $importStreamSource;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $file = dirname( __DIR__ ) . '/data/import/ImportLinkCacheIntegrationTest.xml';
+
+ $this->importStreamSource = ImportStreamSource::newFromFile( $file );
+
+ if ( !$this->importStreamSource->isGood() ) {
+ throw new Exception( "Import source for {$file} failed" );
+ }
+ }
+
+ public function testImportForImportSource() {
+
+ $this->doImport( $this->importStreamSource );
+
+ // Imported title
+ $loremIpsum = Title::newFromText( 'Lorem ipsum' );
+
+ $this->assertSame(
+ $loremIpsum->getArticleID(),
+ $loremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+
+ $categoryLoremIpsum = Title::newFromText( 'Category:Lorem ipsum' );
+
+ $this->assertSame(
+ $categoryLoremIpsum->getArticleID(),
+ $categoryLoremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+
+ $page = new WikiPage( $loremIpsum );
+ $page->doDeleteArticle( 'import test: delete page' );
+
+ $page = new WikiPage( $categoryLoremIpsum );
+ $page->doDeleteArticle( 'import test: delete page' );
+ }
+
+ /**
+ * @depends testImportForImportSource
+ */
+ public function testReImportForImportSource() {
+
+ $this->doImport( $this->importStreamSource );
+
+ // ReImported title
+ $loremIpsum = Title::newFromText( 'Lorem ipsum' );
+
+ $this->assertSame(
+ $loremIpsum->getArticleID(),
+ $loremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+
+ $categoryLoremIpsum = Title::newFromText( 'Category:Lorem ipsum' );
+
+ $this->assertSame(
+ $categoryLoremIpsum->getArticleID(),
+ $categoryLoremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+ }
+
+ private function doImport( $importStreamSource ) {
+
+ $importer = new WikiImporter(
+ $importStreamSource->value,
+ ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ );
+ $importer->setDebug( true );
+
+ $reporter = new ImportReporter(
+ $importer,
+ false,
+ '',
+ false
+ );
+
+ $reporter->setContext( new RequestContext() );
+ $reporter->open();
+ $exception = false;
+
+ try {
+ $importer->doImport();
+ } catch ( Exception $e ) {
+ $exception = $e;
+ }
+
+ $result = $reporter->close();
+
+ $this->assertFalse(
+ $exception
+ );
+
+ $this->assertTrue(
+ $result->isGood()
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/LinkFilterTest.php b/tests/phpunit/includes/LinkFilterTest.php
index f2c9cb43..68081059 100644
--- a/tests/phpunit/includes/LinkFilterTest.php
+++ b/tests/phpunit/includes/LinkFilterTest.php
@@ -76,7 +76,7 @@ class LinkFilterTest extends MediaWikiLangTestCase {
array( 'https://', '*.com', 'https://name:pass@secure.com/index.html' ),
array( 'http://', 'name:pass@test.com', 'http://test.com' ),
array( 'http://', 'test.com', 'http://name:pass@test.com' ),
- array( 'http://', '*.test.com', 'http://a.b.c.test.com/dir/dir/file?a=6'),
+ array( 'http://', '*.test.com', 'http://a.b.c.test.com/dir/dir/file?a=6' ),
array( null, 'http://*.test.com', 'http://www.test.com' ),
array( 'mailto:', 'name@mail.test123.com', 'mailto:name@mail.test123.com' ),
array( '',
@@ -122,8 +122,8 @@ class LinkFilterTest extends MediaWikiLangTestCase {
array( '', 'git://github.com/prwef/abc-def.git', 'git://github.com/prwef/abc-def.git' ),
array( 'git://', 'github.com/', 'git://github.com/prwef/abc-def.git' ),
array( 'git://', '*.github.com/', 'git://a.b.c.d.e.f.github.com/prwef/abc-def.git' ),
- array( '', 'gopher://*.test.com/', 'gopher://gopher.test.com/0/v2/vstat'),
- array( 'telnet://', '*.test.com', 'telnet://shell.test.com/~home/'),
+ array( '', 'gopher://*.test.com/', 'gopher://gopher.test.com/0/v2/vstat' ),
+ array( 'telnet://', '*.test.com', 'telnet://shell.test.com/~home/' ),
//
// The following only work in PHP >= 5.3.7, due to a bug in parse_url which eats
@@ -243,10 +243,10 @@ class LinkFilterTest extends MediaWikiLangTestCase {
array( 'http://*.test.*' ),
array( 'http://*test.com' ),
array( 'https://*' ),
- array( '*://test.com'),
+ array( '*://test.com' ),
array( 'mailto:name:pass@t*est.com' ),
- array( 'http://*:888/'),
- array( '*http://'),
+ array( 'http://*:888/' ),
+ array( '*http://' ),
array( 'test.com/*/index' ),
array( 'test.com/dir/index?arg=*' ),
);
diff --git a/tests/phpunit/includes/LinkerTest.php b/tests/phpunit/includes/LinkerTest.php
index 823c9330..a3efbb8d 100644
--- a/tests/phpunit/includes/LinkerTest.php
+++ b/tests/phpunit/includes/LinkerTest.php
@@ -93,12 +93,26 @@ class LinkerTest extends MediaWikiLangTestCase {
* @covers Linker::formatAutocomments
* @covers Linker::formatLinksInComment
*/
- public function testFormatComment( $expected, $comment, $title = false, $local = false ) {
+ public function testFormatComment( $expected, $comment, $title = false, $local = false, $wikiId = null ) {
+ $conf = new SiteConfiguration();
+ $conf->settings = array(
+ 'wgServer' => array(
+ 'enwiki' => '//en.example.org',
+ 'dewiki' => '//de.example.org',
+ ),
+ 'wgArticlePath' => array(
+ 'enwiki' => '/w/$1',
+ 'dewiki' => '/w/$1',
+ ),
+ );
+ $conf->suffixes = array( 'wiki' );
+
$this->setMwGlobals( array(
'wgScript' => '/wiki/index.php',
'wgArticlePath' => '/wiki/$1',
'wgWellFormedXml' => true,
'wgCapitalLinks' => true,
+ 'wgConf' => $conf,
) );
if ( $title === false ) {
@@ -108,11 +122,13 @@ class LinkerTest extends MediaWikiLangTestCase {
$this->assertEquals(
$expected,
- Linker::formatComment( $comment, $title, $local )
+ Linker::formatComment( $comment, $title, $local, $wikiId )
);
}
- public static function provideCasesForFormatComment() {
+ public function provideCasesForFormatComment() {
+ $wikiId = 'enwiki'; // $wgConf has a fake entry for this
+
return array(
// Linker::formatComment
array(
@@ -127,6 +143,10 @@ class LinkerTest extends MediaWikiLangTestCase {
"&#039;&#039;&#039;not bolded&#039;&#039;&#039;",
"'''not bolded'''",
),
+ array(
+ "try &lt;script&gt;evil&lt;/scipt&gt; things",
+ "try <script>evil</scipt> things",
+ ),
// Linker::formatAutocomments
array(
'<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
@@ -157,6 +177,14 @@ class LinkerTest extends MediaWikiLangTestCase {
"/* autocomment containing /* */ T70361"
),
array(
+ '<a href="/wiki/Special:BlankPage#autocomment_containing_.22quotes.22" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment containing &quot;quotes&quot;</span></span>',
+ "/* autocomment containing \"quotes\" */"
+ ),
+ array(
+ '<a href="/wiki/Special:BlankPage#autocomment_containing_.3Cscript.3Etags.3C.2Fscript.3E" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment containing &lt;script&gt;tags&lt;/script&gt;</span></span>',
+ "/* autocomment containing <script>tags</script> */"
+ ),
+ array(
'<a href="#autocomment">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
"/* autocomment */",
false, true
@@ -166,6 +194,16 @@ class LinkerTest extends MediaWikiLangTestCase {
"/* autocomment */",
null
),
+ array(
+ '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
+ "/* autocomment */",
+ false, false
+ ),
+ array(
+ '<a class="external" rel="nofollow" href="//en.example.org/w/Special:BlankPage#autocomment">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
+ "/* autocomment */",
+ false, false, $wikiId
+ ),
// Linker::formatLinksInComment
array(
'abc <a href="/wiki/index.php?title=Link&amp;action=edit&amp;redlink=1" class="new" title="Link (page does not exist)">link</a> def',
@@ -191,6 +229,28 @@ class LinkerTest extends MediaWikiLangTestCase {
'abc <a href="/wiki/index.php?title=/subpage&amp;action=edit&amp;redlink=1" class="new" title="/subpage (page does not exist)">/subpage</a> def',
"abc [[/subpage]] def",
),
+ array(
+ 'abc <a href="/wiki/index.php?title=%22evil!%22&amp;action=edit&amp;redlink=1" class="new" title="&quot;evil!&quot; (page does not exist)">&quot;evil!&quot;</a> def',
+ "abc [[\"evil!\"]] def",
+ ),
+ array(
+ 'abc [[&lt;script&gt;very evil&lt;/script&gt;]] def',
+ "abc [[<script>very evil</script>]] def",
+ ),
+ array(
+ 'abc [[|]] def',
+ "abc [[|]] def",
+ ),
+ array(
+ 'abc <a href="/wiki/index.php?title=Link&amp;action=edit&amp;redlink=1" class="new" title="Link (page does not exist)">link</a> def',
+ "abc [[link]] def",
+ false, false
+ ),
+ array(
+ 'abc <a class="external" rel="nofollow" href="//en.example.org/w/Link">link</a> def',
+ "abc [[link]] def",
+ false, false, $wikiId
+ )
);
}
diff --git a/tests/phpunit/includes/MediaWikiTest.php b/tests/phpunit/includes/MediaWikiTest.php
index df94d3e3..e1962436 100644
--- a/tests/phpunit/includes/MediaWikiTest.php
+++ b/tests/phpunit/includes/MediaWikiTest.php
@@ -34,7 +34,7 @@ class MediaWikiTest extends MediaWikiTestCase {
'url' => 'http://example.org/w/index.php?title=Foo_Bar',
'query' => array( 'title' => 'Foo_Bar' ),
'title' => 'Foo_Bar',
- 'redirect' => false,
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
),
array(
// View: Script path with implicit title from page id
@@ -76,21 +76,21 @@ class MediaWikiTest extends MediaWikiTestCase {
'url' => 'http://example.org/w/?title=Foo_Bar',
'query' => array( 'title' => 'Foo_Bar' ),
'title' => 'Foo_Bar',
- 'redirect' => false,
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
),
array(
// View: Root path with escaped title
'url' => 'http://example.org/?title=Foo_Bar',
'query' => array( 'title' => 'Foo_Bar' ),
'title' => 'Foo_Bar',
- 'redirect' => false,
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
),
array(
// View: Canonical with redundant query
'url' => 'http://example.org/wiki/Foo_Bar?action=view',
'query' => array( 'action' => 'view' ),
'title' => 'Foo_Bar',
- 'redirect' => false,
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
),
array(
// Edit: Canonical view url with action query
@@ -104,7 +104,7 @@ class MediaWikiTest extends MediaWikiTestCase {
'url' => 'http://example.org/w/index.php?title=Foo_Bar&action=view',
'query' => array( 'title' => 'Foo_Bar', 'action' => 'view' ),
'title' => 'Foo_Bar',
- 'redirect' => false,
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
),
array(
// Edit: Index with action query
diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php
index 99ec2e42..9c953a6d 100644
--- a/tests/phpunit/includes/MessageTest.php
+++ b/tests/phpunit/includes/MessageTest.php
@@ -21,6 +21,17 @@ class MessageTest extends MediaWikiLangTestCase {
$this->assertEquals( $key, $message->getKey() );
$this->assertEquals( $params, $message->getParams() );
$this->assertEquals( $expectedLang, $message->getLanguage() );
+
+ $messageSpecifier = $this->getMockForAbstractClass( 'MessageSpecifier' );
+ $messageSpecifier->expects( $this->any() )
+ ->method( 'getKey' )->will( $this->returnValue( $key ) );
+ $messageSpecifier->expects( $this->any() )
+ ->method( 'getParams' )->will( $this->returnValue( $params ) );
+ $message = new Message( $messageSpecifier, array(), $language );
+
+ $this->assertEquals( $key, $message->getKey() );
+ $this->assertEquals( $params, $message->getParams() );
+ $this->assertEquals( $expectedLang, $message->getLanguage() );
}
public static function provideConstructor() {
@@ -548,4 +559,26 @@ class MessageTest extends MediaWikiLangTestCase {
public function testInLanguageThrows() {
wfMessage( 'foo' )->inLanguage( 123 );
}
+
+ /**
+ * @covers Message::serialize
+ * @covers Message::unserialize
+ */
+ public function testSerialization() {
+ $msg = new Message( 'parentheses' );
+ $msg->rawParams( '<a>foo</a>' );
+ $msg->title( Title::newFromText( 'Testing' ) );
+ $this->assertEquals( '(<a>foo</a>)', $msg->parse(), 'Sanity check' );
+ $msg = unserialize( serialize( $msg ) );
+ $this->assertEquals( '(<a>foo</a>)', $msg->parse() );
+ $title = TestingAccessWrapper::newFromObject( $msg )->title;
+ $this->assertInstanceOf( 'Title', $title );
+ $this->assertEquals( 'Testing', $title->getFullText() );
+
+ $msg = new Message( 'mainpage' );
+ $msg->inLanguage( 'de' );
+ $this->assertEquals( 'Hauptseite', $msg->plain(), 'Sanity check' );
+ $msg = unserialize( serialize( $msg ) );
+ $this->assertEquals( 'Hauptseite', $msg->plain() );
+ }
}
diff --git a/tests/phpunit/includes/MimeMagicTest.php b/tests/phpunit/includes/MimeMagicTest.php
index 742d3827..3c45f305 100644
--- a/tests/phpunit/includes/MimeMagicTest.php
+++ b/tests/phpunit/includes/MimeMagicTest.php
@@ -1,5 +1,5 @@
<?php
-class MimeMagicTest extends MediaWikiTestCase {
+class MimeMagicTest extends PHPUnit_Framework_TestCase {
/** @var MimeMagic */
private $mimeMagic;
diff --git a/tests/phpunit/includes/MovePageTest.php b/tests/phpunit/includes/MovePageTest.php
index 9501e452..0ef2fa63 100644
--- a/tests/phpunit/includes/MovePageTest.php
+++ b/tests/phpunit/includes/MovePageTest.php
@@ -57,7 +57,7 @@ class MovePageTest extends MediaWikiTestCase {
WikiPage::factory( $oldTitle )->getRevision()
);
$this->assertNotNull(
- WikiPage::factory( $newTitle)->getRevision()
+ WikiPage::factory( $newTitle )->getRevision()
);
}
}
diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php
index 6c6d95ee..f0d905e5 100644
--- a/tests/phpunit/includes/OutputPageTest.php
+++ b/tests/phpunit/includes/OutputPageTest.php
@@ -141,53 +141,36 @@ class OutputPageTest extends MediaWikiTestCase {
// Load module script only
array(
array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ),
- '<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.foo\u0026amp;only=scripts\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E");
-}</script>
-'
+ "<script>window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n"
+ . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback");'
+ . "\n} );</script>"
),
array(
// Don't condition wrap raw modules (like the startup module)
array( 'test.raw', ResourceLoaderModule::TYPE_SCRIPTS ),
- '<script src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.raw&amp;only=scripts&amp;skin=fallback&amp;*"></script>
-'
+ '<script async src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.raw&amp;only=scripts&amp;skin=fallback"></script>'
),
// Load module styles only
// This also tests the order the modules are put into the url
array(
array( array( 'test.baz', 'test.foo', 'test.bar' ), ResourceLoaderModule::TYPE_STYLES ),
- '<link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.bar%2Cbaz%2Cfoo&amp;only=styles&amp;skin=fallback&amp;*">
-'
+
+ '<link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.bar%2Cbaz%2Cfoo&amp;only=styles&amp;skin=fallback">'
),
// Load private module (only=scripts)
array(
array( 'test.quux', ResourceLoaderModule::TYPE_SCRIPTS ),
- '<script>if(window.mw){
-mw.test.baz({token:123});mw.loader.state({"test.quux":"ready"});
-
-}</script>
-'
+ "<script>window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n"
+ . "mw.test.baz({token:123});mw.loader.state({\"test.quux\":\"ready\"});\n"
+ . "} );</script>"
),
// Load private module (combined)
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"]});
-
-}</script>
-'
- ),
- // 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 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>
-',
+ "<script>window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n"
+ . "mw.loader.implement(\"test.quux\",function($,jQuery){"
+ . "mw.test.baz({token:123});},{\"css\":[\".mw-icon{transition:none}"
+ . "\"]});\n} );</script>"
),
// Load no modules
array(
@@ -197,19 +180,17 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"
// noscript group
array(
array( 'test.noscript', ResourceLoaderModule::TYPE_STYLES ),
- '<noscript><link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.noscript&amp;only=styles&amp;skin=fallback&amp;*"></noscript>
-'
+ '<noscript><link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.noscript&amp;only=styles&amp;skin=fallback"></noscript>'
),
// Load two modules in separate groups
array(
array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ),
- '<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>
-'
+ "<script>window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n"
+ . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.bar\u0026skin=fallback");'
+ . "\n} );</script>\n"
+ . "<script>window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n"
+ . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.foo\u0026skin=fallback");'
+ . "\n} );</script>"
),
);
}
@@ -226,7 +207,6 @@ document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\
public function testMakeResourceLoaderLink( $args, $expectedHtml ) {
$this->setMwGlobals( array(
'wgResourceLoaderDebug' => false,
- 'wgResourceLoaderUseESI' => true,
'wgLoadScript' => 'http://127.0.0.1:8080/w/load.php',
// Affects whether CDATA is inserted
'wgWellFormedXml' => false,
@@ -244,63 +224,141 @@ document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\
'test.foo' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.foo( { a: true } );',
'styles' => '.mw-test-foo { content: "style"; }',
- )),
+ ) ),
'test.bar' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.bar( { a: true } );',
'styles' => '.mw-test-bar { content: "style"; }',
- )),
+ ) ),
'test.baz' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.baz( { a: true } );',
'styles' => '.mw-test-baz { content: "style"; }',
- )),
+ ) ),
'test.quux' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.baz( { token: 123 } );',
'styles' => '/* pref-animate=off */ .mw-icon { transition: none; }',
'group' => 'private',
- )),
+ ) ),
'test.raw' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.baz( { token: 123 } );',
'isRaw' => true,
- )),
+ ) ),
'test.noscript' => new ResourceLoaderTestModule( array(
'styles' => '.mw-test-noscript { content: "style"; }',
'group' => 'noscript',
- )),
+ ) ),
'test.group.bar' => new ResourceLoaderTestModule( array(
'styles' => '.mw-group-bar { content: "style"; }',
'group' => 'bar',
- )),
+ ) ),
'test.group.foo' => new ResourceLoaderTestModule( array(
'styles' => '.mw-group-foo { content: "style"; }',
'group' => 'foo',
- )),
+ ) ),
) );
$links = $method->invokeArgs( $out, $args );
- // Strip comments to avoid variation due to wgDBname in WikiID and cache key
- $actualHtml = preg_replace( '#/\*[^*]+\*/#', '', $links['html'] );
+ $actualHtml = implode( "\n", $links['html'] );
$this->assertEquals( $expectedHtml, $actualHtml );
}
+
+ /**
+ * @dataProvider provideVaryHeaders
+ * @covers OutputPage::addVaryHeader
+ * @covers OutputPage::getVaryHeader
+ * @covers OutputPage::getXVO
+ */
+ public function testVaryHeaders( $calls, $vary, $xvo ) {
+ // get rid of default Vary fields
+ $outputPage = $this->getMockBuilder( 'OutputPage' )
+ ->setConstructorArgs( array( new RequestContext() ) )
+ ->setMethods( array( 'getCacheVaryCookies' ) )
+ ->getMock();
+ $outputPage->expects( $this->any() )
+ ->method( 'getCacheVaryCookies' )
+ ->will( $this->returnValue( array() ) );
+ TestingAccessWrapper::newFromObject( $outputPage )->mVaryHeader = array();
+
+ foreach ( $calls as $call ) {
+ call_user_func_array( array( $outputPage, 'addVaryHeader' ), $call );
+ }
+ $this->assertEquals( $vary, $outputPage->getVaryHeader(), 'Vary:' );
+ $this->assertEquals( $xvo, $outputPage->getXVO(), 'X-Vary-Options:' );
+ }
+
+ public function provideVaryHeaders() {
+ // note: getXVO() automatically adds Vary: Cookie
+ return array(
+ array( // single header
+ array(
+ array( 'Cookie' ),
+ ),
+ 'Vary: Cookie',
+ 'X-Vary-Options: Cookie',
+ ),
+ array( // non-unique headers
+ array(
+ array( 'Cookie' ),
+ array( 'Accept-Language' ),
+ array( 'Cookie' ),
+ ),
+ 'Vary: Cookie, Accept-Language',
+ 'X-Vary-Options: Cookie,Accept-Language',
+ ),
+ array( // two headers with single options
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Accept-Language', array( 'string-contains=en' ) ),
+ ),
+ 'Vary: Cookie, Accept-Language',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
+ ),
+ array( // one header with multiple options
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid', 'string-contains=userId' ) ),
+ ),
+ 'Vary: Cookie',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid;string-contains=userId',
+ ),
+ array( // Duplicate option
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Accept-Language', array( 'string-contains=en', 'string-contains=en' ) ),
+
+
+ ),
+ 'Vary: Cookie, Accept-Language',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
+ ),
+ array( // Same header, different options
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Cookie', array( 'string-contains=userId' ) ),
+ ),
+ 'Vary: Cookie',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid;string-contains=userId',
+ ),
+ );
+ }
}
/**
* MessageBlobStore that doesn't do anything
*/
class NullMessageBlobStore extends MessageBlobStore {
- public function get ( ResourceLoader $resourceLoader, $modules, $lang ) {
+ public function get( ResourceLoader $resourceLoader, $modules, $lang ) {
return array();
}
- public function insertMessageBlob ( $name, ResourceLoaderModule $module, $lang ) {
+ public function insertMessageBlob( $name, ResourceLoaderModule $module, $lang ) {
return false;
}
- public function updateModule ( $name, ResourceLoaderModule $module, $lang ) {
+ public function updateModule( $name, ResourceLoaderModule $module, $lang ) {
return;
}
- public function updateMessage ( $key ) {
+ public function updateMessage( $key ) {
}
public function clear() {
}
}
-
diff --git a/tests/phpunit/includes/PrefixSearchTest.php b/tests/phpunit/includes/PrefixSearchTest.php
index d63541b7..afd10e9a 100644
--- a/tests/phpunit/includes/PrefixSearchTest.php
+++ b/tests/phpunit/includes/PrefixSearchTest.php
@@ -6,6 +6,11 @@
class PrefixSearchTest extends MediaWikiLangTestCase {
public function addDBData() {
+ if ( !$this->isWikitextNS( NS_MAIN ) ) {
+ // tests are skipped if NS_MAIN is not wikitext
+ return;
+ }
+
$this->insertPage( 'Sandbox' );
$this->insertPage( 'Bar' );
$this->insertPage( 'Example' );
diff --git a/tests/phpunit/includes/SanitizerTest.php b/tests/phpunit/includes/SanitizerTest.php
index c615c460..d3dc512b 100644
--- a/tests/phpunit/includes/SanitizerTest.php
+++ b/tests/phpunit/includes/SanitizerTest.php
@@ -6,6 +6,11 @@
*/
class SanitizerTest extends MediaWikiTestCase {
+ protected function tearDown() {
+ MWTidy::destroySingleton();
+ parent::tearDown();
+ }
+
/**
* @covers Sanitizer::decodeCharReferences
*/
@@ -93,9 +98,7 @@ class SanitizerTest extends MediaWikiTestCase {
* @param bool $escaped Whether sanitizer let the tag in or escape it (ie: '&lt;video&gt;')
*/
public function testRemovehtmltagsOnHtml5Tags( $tag, $escaped ) {
- $this->setMwGlobals( array(
- 'wgUseTidy' => false
- ) );
+ MWTidy::setInstance( false );
if ( $escaped ) {
$this->assertEquals( "&lt;$tag&gt;",
@@ -157,7 +160,7 @@ class SanitizerTest extends MediaWikiTestCase {
* @covers Sanitizer::removeHTMLtags
*/
public function testRemoveHTMLtags( $input, $output, $msg = null ) {
- $GLOBALS['wgUseTidy'] = false;
+ MWTidy::setInstance( false );
$this->assertEquals( $output, Sanitizer::removeHTMLtags( $input ), $msg );
}
@@ -360,5 +363,4 @@ class SanitizerTest extends MediaWikiTestCase {
array( '&lt;script&gt;foo&lt;/script&gt;', '<script>foo</script>' ),
);
}
-
}
diff --git a/tests/phpunit/includes/SanitizerValidateEmailTest.php b/tests/phpunit/includes/SanitizerValidateEmailTest.php
index 14911f04..f47e74e2 100644
--- a/tests/phpunit/includes/SanitizerValidateEmailTest.php
+++ b/tests/phpunit/includes/SanitizerValidateEmailTest.php
@@ -5,7 +5,7 @@
* @todo all test methods in this class should be refactored and...
* use a single test method and a single data provider...
*/
-class SanitizerValidateEmailTest extends MediaWikiTestCase {
+class SanitizerValidateEmailTest extends PHPUnit_Framework_TestCase {
private function checkEmail( $addr, $expected = true, $msg = '' ) {
if ( $msg == '' ) {
diff --git a/tests/phpunit/includes/StatusTest.php b/tests/phpunit/includes/StatusTest.php
index c013f4fc..291ed315 100644
--- a/tests/phpunit/includes/StatusTest.php
+++ b/tests/phpunit/includes/StatusTest.php
@@ -372,7 +372,7 @@ class StatusTest extends MediaWikiLangTestCase {
);
$status = new Status();
- $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
+ $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
$testCases['1MessageWarning'] = array(
$status,
"<fooBar!>",
@@ -449,7 +449,7 @@ class StatusTest extends MediaWikiLangTestCase {
// );
$status = new Status();
- $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
+ $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
$testCases['1MessageWarning'] = array(
$status,
array( 'foo', 'bar' ),
diff --git a/tests/phpunit/includes/TemplateParserTest.php b/tests/phpunit/includes/TemplateParserTest.php
index 81854ff3..3b37f4a4 100644
--- a/tests/phpunit/includes/TemplateParserTest.php
+++ b/tests/phpunit/includes/TemplateParserTest.php
@@ -57,7 +57,20 @@ class TemplateParserTest extends MediaWikiTestCase {
array(),
false,
'RuntimeException',
- )
+ ),
+ array(
+ 'has_partial',
+ array(
+ 'planet' => 'world',
+ ),
+ "Partial hello world!\n in here\n",
+ ),
+ array(
+ 'bad_partial',
+ array(),
+ false,
+ 'Exception',
+ ),
);
}
}
diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php
index 84c0f9b5..63d89719 100644
--- a/tests/phpunit/includes/TestingAccessWrapper.php
+++ b/tests/phpunit/includes/TestingAccessWrapper.php
@@ -34,16 +34,42 @@ class TestingAccessWrapper {
return $methodReflection->invokeArgs( $this->object, $args );
}
- public function __set( $name, $value ) {
+ /**
+ * ReflectionClass::getProperty() fails if the private property is defined
+ * in a parent class. This works more like ReflectionClass::getMethod().
+ */
+ private function getProperty( $name ) {
$classReflection = new ReflectionClass( $this->object );
- $propertyReflection = $classReflection->getProperty( $name );
+ try {
+ return $classReflection->getProperty( $name );
+ } catch ( ReflectionException $ex ) {
+ while ( true ) {
+ $classReflection = $classReflection->getParentClass();
+ if ( !$classReflection ) {
+ throw $ex;
+ }
+ try {
+ $propertyReflection = $classReflection->getProperty( $name );
+ } catch ( ReflectionException $ex2 ) {
+ continue;
+ }
+ if ( $propertyReflection->isPrivate() ) {
+ return $propertyReflection;
+ } else {
+ throw $ex;
+ }
+ }
+ }
+ }
+
+ public function __set( $name, $value ) {
+ $propertyReflection = $this->getProperty( $name );
$propertyReflection->setAccessible( true );
$propertyReflection->setValue( $this->object, $value );
}
public function __get( $name ) {
- $classReflection = new ReflectionClass( $this->object );
- $propertyReflection = $classReflection->getProperty( $name );
+ $propertyReflection = $this->getProperty( $name );
$propertyReflection->setAccessible( true );
return $propertyReflection->getValue( $this->object );
}
diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php
index 7e5b91a1..fc54afae 100644
--- a/tests/phpunit/includes/TestingAccessWrapperTest.php
+++ b/tests/phpunit/includes/TestingAccessWrapperTest.php
@@ -14,18 +14,36 @@ class TestingAccessWrapperTest extends MediaWikiTestCase {
function testGetProperty() {
$this->assertSame( 1, $this->wrapped->property );
+ $this->assertSame( 42, $this->wrapped->privateProperty );
+ $this->assertSame( 9000, $this->wrapped->privateParentProperty );
}
function testSetProperty() {
$this->wrapped->property = 10;
$this->assertSame( 10, $this->wrapped->property );
$this->assertSame( 10, $this->raw->getProperty() );
+
+ $this->wrapped->privateProperty = 11;
+ $this->assertSame( 11, $this->wrapped->privateProperty );
+ $this->assertSame( 11, $this->raw->getPrivateProperty() );
+
+ $this->wrapped->privateParentProperty = 12;
+ $this->assertSame( 12, $this->wrapped->privateParentProperty );
+ $this->assertSame( 12, $this->raw->getPrivateParentProperty() );
}
function testCallMethod() {
$this->wrapped->incrementPropertyValue();
$this->assertSame( 2, $this->wrapped->property );
$this->assertSame( 2, $this->raw->getProperty() );
+
+ $this->wrapped->incrementPrivatePropertyValue();
+ $this->assertSame( 43, $this->wrapped->privateProperty );
+ $this->assertSame( 43, $this->raw->getPrivateProperty() );
+
+ $this->wrapped->incrementPrivateParentPropertyValue();
+ $this->assertSame( 9001, $this->wrapped->privateParentProperty );
+ $this->assertSame( 9001, $this->raw->getPrivateParentProperty() );
}
function testCallMethodTwoArgs() {
diff --git a/tests/phpunit/includes/TitleArrayFromResultTest.php b/tests/phpunit/includes/TitleArrayFromResultTest.php
index 0f7069ae..6654a5b6 100644
--- a/tests/phpunit/includes/TitleArrayFromResultTest.php
+++ b/tests/phpunit/includes/TitleArrayFromResultTest.php
@@ -4,7 +4,7 @@
* @author Adam Shorland
* @covers TitleArrayFromResult
*/
-class TitleArrayFromResultTest extends MediaWikiTestCase {
+class TitleArrayFromResultTest extends PHPUnit_Framework_TestCase {
private function getMockResultWrapper( $row = null, $numRows = 1 ) {
$resultWrapper = $this->getMockBuilder( 'ResultWrapper' )
diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php
index 022c7d53..f588ed63 100644
--- a/tests/phpunit/includes/TitlePermissionTest.php
+++ b/tests/phpunit/includes/TitlePermissionTest.php
@@ -664,7 +664,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->setTitle( NS_MAIN, "test page" );
$this->title->mTitleProtection['permission'] = '';
$this->title->mTitleProtection['user'] = $this->user->getID();
- $this->title->mTitleProtection['expiry'] = wfGetDB( DB_SLAVE )->getInfinity();
+ $this->title->mTitleProtection['expiry'] = 'infinity';
$this->title->mTitleProtection['reason'] = 'test';
$this->title->mCascadeRestriction = false;
@@ -753,8 +753,14 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$prev = time();
$now = time() + 120;
$this->user->mBlockedby = $this->user->getId();
- $this->user->mBlock = new Block( '127.0.8.1', 0, $this->user->getId(),
- 'no reason given', $prev + 3600, 1, 0 );
+ $this->user->mBlock = new Block( array(
+ 'address' => '127.0.8.1',
+ 'by' => $this->user->getId(),
+ 'reason' => 'no reason given',
+ 'timestamp' => $prev + 3600,
+ 'auto' => true,
+ 'expiry' => 0
+ ) );
$this->user->mBlock->mTimestamp = 0;
$this->assertEquals( array( array( 'autoblockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
@@ -770,8 +776,14 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
global $wgLocalTZoffset;
$wgLocalTZoffset = -60;
$this->user->mBlockedby = $this->user->getName();
- $this->user->mBlock = new Block( '127.0.8.1', 0, $this->user->getId(),
- 'no reason given', $now, 0, 10 );
+ $this->user->mBlock = new Block( array(
+ 'address' => '127.0.8.1',
+ 'by' => $this->user->getId(),
+ 'reason' => 'no reason given',
+ 'timestamp' => $now,
+ 'auto' => false,
+ 'expiry' => 10,
+ ) );
$this->assertEquals( array( array( 'blockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
diff --git a/tests/phpunit/includes/TitleTest.php b/tests/phpunit/includes/TitleTest.php
index d55f958b..a2c6f23d 100644
--- a/tests/phpunit/includes/TitleTest.php
+++ b/tests/phpunit/includes/TitleTest.php
@@ -1,6 +1,7 @@
<?php
/**
+ * @group Database
* @group Title
*/
class TitleTest extends MediaWikiTestCase {
@@ -79,22 +80,22 @@ class TitleTest extends MediaWikiTestCase {
public static function provideInvalidSecureAndSplit() {
return array(
- array( '' ),
- array( ':' ),
- array( '__ __' ),
- array( ' __ ' ),
+ array( '', 'title-invalid-empty' ),
+ array( ':', 'title-invalid-empty' ),
+ array( '__ __', 'title-invalid-empty' ),
+ array( ' __ ', 'title-invalid-empty' ),
// Bad characters forbidden regardless of wgLegalTitleChars
- array( 'A [ B' ),
- array( 'A ] B' ),
- array( 'A { B' ),
- array( 'A } B' ),
- array( 'A < B' ),
- array( 'A > B' ),
- array( 'A | B' ),
+ array( 'A [ B', 'title-invalid-characters' ),
+ array( 'A ] B', 'title-invalid-characters' ),
+ array( 'A { B', 'title-invalid-characters' ),
+ array( 'A } B', 'title-invalid-characters' ),
+ array( 'A < B', 'title-invalid-characters' ),
+ array( 'A > B', 'title-invalid-characters' ),
+ array( 'A | B', 'title-invalid-characters' ),
// URL encoding
- array( 'A%20B' ),
- array( 'A%23B' ),
- array( 'A%2523B' ),
+ array( 'A%20B', 'title-invalid-characters' ),
+ array( 'A%23B', 'title-invalid-characters' ),
+ array( 'A%2523B', 'title-invalid-characters' ),
// XML/HTML character entity references
// Note: Commented out because they are not marked invalid by the PHP test as
// Title::newFromText runs Sanitizer::decodeCharReferencesAndNormalize first.
@@ -102,29 +103,30 @@ class TitleTest extends MediaWikiTestCase {
//'A &#233; B',
//'A &#x00E9; B',
// Subject of NS_TALK does not roundtrip to NS_MAIN
- array( 'Talk:File:Example.svg' ),
+ array( 'Talk:File:Example.svg', 'title-invalid-talk-namespace' ),
// Directory navigation
- array( '.' ),
- array( '..' ),
- array( './Sandbox' ),
- array( '../Sandbox' ),
- array( 'Foo/./Sandbox' ),
- array( 'Foo/../Sandbox' ),
- array( 'Sandbox/.' ),
- array( 'Sandbox/..' ),
+ array( '.', 'title-invalid-relative' ),
+ array( '..', 'title-invalid-relative' ),
+ array( './Sandbox', 'title-invalid-relative' ),
+ array( '../Sandbox', 'title-invalid-relative' ),
+ array( 'Foo/./Sandbox', 'title-invalid-relative' ),
+ array( 'Foo/../Sandbox', 'title-invalid-relative' ),
+ array( 'Sandbox/.', 'title-invalid-relative' ),
+ array( 'Sandbox/..', 'title-invalid-relative' ),
// Tilde
- array( 'A ~~~ Name' ),
- array( 'A ~~~~ Signature' ),
- array( 'A ~~~~~ Timestamp' ),
- array( str_repeat( 'x', 256 ) ),
+ array( 'A ~~~ Name', 'title-invalid-magic-tilde' ),
+ array( 'A ~~~~ Signature', 'title-invalid-magic-tilde' ),
+ array( 'A ~~~~~ Timestamp', 'title-invalid-magic-tilde' ),
+ // Length
+ array( str_repeat( 'x', 256 ), 'title-invalid-too-long' ),
// Namespace prefix without actual title
- array( 'Talk:' ),
- array( 'Talk:#' ),
- array( 'Category: ' ),
- array( 'Category: #bar' ),
+ array( 'Talk:', 'title-invalid-empty' ),
+ array( 'Talk:#', 'title-invalid-empty' ),
+ array( 'Category: ', 'title-invalid-empty' ),
+ array( 'Category: #bar', 'title-invalid-empty' ),
// interwiki prefix
- array( 'localtestiw: Talk: # anchor' ),
- array( 'localtestiw: Talk:' )
+ array( 'localtestiw: Talk: # anchor', 'title-invalid-empty' ),
+ array( 'localtestiw: Talk:', 'title-invalid-empty' )
);
}
@@ -143,7 +145,7 @@ class TitleTest extends MediaWikiTestCase {
}
)
)
- ));
+ ) );
}
/**
@@ -163,9 +165,14 @@ class TitleTest extends MediaWikiTestCase {
* @dataProvider provideInvalidSecureAndSplit
* @note This mainly tests MediaWikiTitleCodec::parseTitle().
*/
- public function testSecureAndSplitInvalid( $text ) {
+ public function testSecureAndSplitInvalid( $text, $expectedErrorMessage ) {
$this->secureAndSplitGlobals();
- $this->assertNull( Title::newFromText( $text ), "Invalid: $text" );
+ try {
+ Title::newFromTextThrow( $text ); // should throw
+ $this->assertTrue( false, "Invalid: $text" );
+ } catch ( MalformedTitleException $ex ) {
+ $this->assertEquals( $expectedErrorMessage, $ex->getErrorMessage(), "Invalid: $text" );
+ }
}
public static function provideConvertByteClassToUnicodeClass() {
@@ -631,4 +638,26 @@ class TitleTest extends MediaWikiTestCase {
$title = Title::makeTitle( NS_MAIN, 'Interwiki link', '', 'externalwiki' );
$this->assertTrue( $title->isAlwaysKnown() );
}
+
+ /**
+ * @covers Title::exists
+ */
+ public function testExists() {
+ $title = Title::makeTitle( NS_PROJECT, 'New page' );
+ $linkCache = LinkCache::singleton();
+
+ $article = new Article( $title );
+ $page = $article->getPage();
+ $page->doEditContent( new WikitextContent( 'Some [[link]]' ), 'summary' );
+
+ // Tell Title it doesn't know whether it exists
+ $title->mArticleID = -1;
+
+ // Tell the link cache it doesn't exists when it really does
+ $linkCache->clearLink( $title );
+ $linkCache->addBadLinkObj( $title );
+
+ $this->assertEquals( false, $title->exists(), 'exists() should rely on link cache unless GAID_FOR_UPDATE is used' );
+ $this->assertEquals( true, $title->exists( Title::GAID_FOR_UPDATE ), 'exists() should re-query database when GAID_FOR_UPDATE is used' );
+ }
}
diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php
index b74a7ead..77132bbb 100644
--- a/tests/phpunit/includes/UserTest.php
+++ b/tests/phpunit/includes/UserTest.php
@@ -307,9 +307,30 @@ class UserTest extends MediaWikiTestCase {
*/
public function testCheckPasswordValidity() {
$this->setMwGlobals( array(
- 'wgMinimalPasswordLength' => 6,
- 'wgMaximalPasswordLength' => 30,
+ 'wgPasswordPolicy' => array(
+ 'policies' => array(
+ 'sysop' => array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => 1,
+ ),
+ 'default' => array(
+ 'MinimalPasswordLength' => 6,
+ 'PasswordCannotMatchUsername' => true,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 30,
+ ),
+ ),
+ 'checks' => array(
+ 'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
+ 'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
+ 'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
+ 'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
+ 'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
+ ),
+ ),
) );
+
$user = User::newFromName( 'Useruser' );
// Sanity
$this->assertTrue( $user->isValidPassword( 'Password1234' ) );
@@ -425,4 +446,109 @@ class UserTest extends MediaWikiTestCase {
$this->assertFalse( $user->isLoggedIn() );
$this->assertTrue( $user->isAnon() );
}
+
+ /**
+ * @covers User::checkAndSetTouched
+ */
+ public function testCheckAndSetTouched() {
+ $user = TestingAccessWrapper::newFromObject( User::newFromName( 'UTSysop' ) );
+ $this->assertTrue( $user->isLoggedIn() );
+
+ $touched = $user->getDBTouched();
+ $this->assertTrue(
+ $user->checkAndSetTouched(), "checkAndSetTouched() succeded" );
+ $this->assertGreaterThan(
+ $touched, $user->getDBTouched(), "user_touched increased with casOnTouched()" );
+
+ $touched = $user->getDBTouched();
+ $this->assertTrue(
+ $user->checkAndSetTouched(), "checkAndSetTouched() succeded #2" );
+ $this->assertGreaterThan(
+ $touched, $user->getDBTouched(), "user_touched increased with casOnTouched() #2" );
+ }
+
+ public static function setExtendedLoginCookieDataProvider() {
+ $data = array();
+ $now = time();
+
+ $secondsInDay = 86400;
+
+ // Arbitrary durations, in units of days, to ensure it chooses the
+ // right one. There is a 5-minute grace period (see testSetExtendedLoginCookie)
+ // to work around slow tests, since we're not currently mocking time() for PHP.
+
+ $durationOne = $secondsInDay * 5;
+ $durationTwo = $secondsInDay * 29;
+ $durationThree = $secondsInDay * 17;
+
+ // If $wgExtendedLoginCookieExpiration is null, then the expiry passed to
+ // set cookie is time() + $wgCookieExpiration
+ $data[] = array(
+ null,
+ $durationOne,
+ $now + $durationOne,
+ );
+
+ // If $wgExtendedLoginCookieExpiration isn't null, then the expiry passed to
+ // set cookie is $now + $wgExtendedLoginCookieExpiration
+ $data[] = array(
+ $durationTwo,
+ $durationThree,
+ $now + $durationTwo,
+ );
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider setExtendedLoginCookieDataProvider
+ * @covers User::getRequest
+ * @covers User::setCookie
+ * @backupGlobals enabled
+ */
+ public function testSetExtendedLoginCookie(
+ $extendedLoginCookieExpiration,
+ $cookieExpiration,
+ $expectedExpiry
+ ) {
+ $this->setMwGlobals( array(
+ 'wgExtendedLoginCookieExpiration' => $extendedLoginCookieExpiration,
+ 'wgCookieExpiration' => $cookieExpiration,
+ ) );
+
+ $response = $this->getMock( 'WebResponse' );
+ $setcookieSpy = $this->any();
+ $response->expects( $setcookieSpy )
+ ->method( 'setcookie' );
+
+ $request = new MockWebRequest( $response );
+ $user = new UserProxy( User::newFromSession( $request ) );
+ $user->setExtendedLoginCookie( 'name', 'value', true );
+
+ $setcookieInvocations = $setcookieSpy->getInvocations();
+ $setcookieInvocation = end( $setcookieInvocations );
+ $actualExpiry = $setcookieInvocation->parameters[ 2 ];
+
+ // TODO: ± 300 seconds compensates for
+ // slow-running tests. However, the dependency on the time
+ // function should be removed. This requires some way
+ // to mock/isolate User->setExtendedLoginCookie's call to time()
+ $this->assertEquals( $expectedExpiry, $actualExpiry, '', 300 );
+ }
+}
+
+class UserProxy extends User {
+
+ /**
+ * @var User
+ */
+ protected $user;
+
+ public function __construct( User $user ) {
+ $this->user = $user;
+ }
+
+ public function setExtendedLoginCookie( $name, $value, $secure ) {
+ $this->user->setExtendedLoginCookie( $name, $value, $secure );
+ }
}
diff --git a/tests/phpunit/includes/WikiMapTest.php b/tests/phpunit/includes/WikiMapTest.php
new file mode 100644
index 00000000..9233416c
--- /dev/null
+++ b/tests/phpunit/includes/WikiMapTest.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @covers WikiMap
+ */
+
+class WikiMapTest extends MediaWikiLangTestCase {
+
+ public function setUp() {
+ parent::setUp();
+
+ $conf = new SiteConfiguration();
+ $conf->settings = array(
+ 'wgServer' => array(
+ 'enwiki' => 'http://en.example.org',
+ 'ruwiki' => '//ru.example.org',
+ ),
+ 'wgArticlePath' => array(
+ 'enwiki' => '/w/$1',
+ 'ruwiki' => '/wiki/$1',
+ ),
+ );
+ $conf->suffixes = array( 'wiki' );
+ $this->setMwGlobals( array(
+ 'wgConf' => $conf,
+ ) );
+ }
+
+ public function provideGetWiki() {
+ $enwiki = new WikiReference( 'wiki', 'en', 'http://en.example.org', '/w/$1' );
+ $ruwiki = new WikiReference( 'wiki', 'ru', '//ru.example.org', '/wiki/$1' );
+
+ return array(
+ 'unknown' => array( false, 'xyzzy' ),
+ 'enwiki' => array( $enwiki, 'enwiki' ),
+ 'ruwiki' => array( $ruwiki, 'ruwiki' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetWiki
+ */
+ public function testGetWiki( $expected, $wikiId ) {
+ $this->assertEquals( $expected, WikiMap::getWiki( $wikiId ) );
+ }
+
+ public function provideGetWikiName() {
+ return array(
+ 'unknown' => array( 'xyzzy', 'xyzzy' ),
+ 'enwiki' => array( 'en.example.org', 'enwiki' ),
+ 'ruwiki' => array( 'ru.example.org', 'ruwiki' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetWikiName
+ */
+ public function testGetWikiName( $expected, $wikiId ) {
+ $this->assertEquals( $expected, WikiMap::getWikiName( $wikiId ) );
+ }
+
+ public function provideMakeForeignLink() {
+ return array(
+ 'unknown' => array( false, 'xyzzy', 'Foo' ),
+ 'enwiki' => array( '<a class="external" rel="nofollow" href="http://en.example.org/w/Foo">Foo</a>', 'enwiki', 'Foo', ),
+ 'ruwiki' => array( '<a class="external" rel="nofollow" href="//ru.example.org/wiki/%D0%A4%D1%83">вар</a>', 'ruwiki', 'Фу', 'вар' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMakeForeignLink
+ */
+ public function testMakeForeignLink( $expected, $wikiId, $page, $text = null ) {
+ $this->assertEquals( $expected, WikiMap::makeForeignLink( $wikiId, $page, $text ) );
+ }
+
+ public function provideForeignUserLink() {
+ return array(
+ 'unknown' => array( false, 'xyzzy', 'Foo' ),
+ 'enwiki' => array( '<a class="external" rel="nofollow" href="http://en.example.org/w/User:Foo">User:Foo</a>', 'enwiki', 'Foo', ),
+ 'ruwiki' => array( '<a class="external" rel="nofollow" href="//ru.example.org/wiki/User:%D0%A4%D1%83">вар</a>', 'ruwiki', 'Фу', 'вар' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideForeignUserLink
+ */
+ public function testForeignUserLink( $expected, $wikiId, $user, $text = null ) {
+ $this->assertEquals( $expected, WikiMap::foreignUserLink( $wikiId, $user, $text ) );
+ }
+
+ public function provideGetForeignURL() {
+ return array(
+ 'unknown' => array( false, 'xyzzy', 'Foo' ),
+ 'enwiki' => array( 'http://en.example.org/w/Foo', 'enwiki', 'Foo', ),
+ 'ruwiki with fragement' => array( '//ru.example.org/wiki/%D0%A4%D1%83#%D0%B2%D0%B0%D1%80', 'ruwiki', 'Фу', 'вар' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetForeignURL
+ */
+ public function testGetForeignURL( $expected, $wikiId, $page, $fragment = null ) {
+ $this->assertEquals( $expected, WikiMap::getForeignURL( $wikiId, $page, $fragment ) );
+ }
+
+}
+
diff --git a/tests/phpunit/includes/WikiReferenceTest.php b/tests/phpunit/includes/WikiReferenceTest.php
new file mode 100644
index 00000000..4fe2e855
--- /dev/null
+++ b/tests/phpunit/includes/WikiReferenceTest.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @covers WikiReference
+ */
+
+class WikiReferenceTest extends PHPUnit_Framework_TestCase {
+
+ public function provideGetDisplayName() {
+ return array(
+ 'http' => array( 'foo.bar', 'http://foo.bar' ),
+ 'https' => array( 'foo.bar', 'http://foo.bar' ),
+
+ // apparently, this is the expected behavior
+ 'invalid' => array( 'purple kittens', 'purple kittens' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetDisplayName
+ */
+ public function testGetDisplayName( $expected, $canonicalServer ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, '/wiki/$1' );
+ $this->assertEquals( $expected, $reference->getDisplayName() );
+ }
+
+ public function testGetCanonicalServer() {
+ $reference = new WikiReference( 'wiki', 'xx', 'https://acme.com', '/wiki/$1', '//acme.com' );
+ $this->assertEquals( 'https://acme.com', $reference->getCanonicalServer() );
+ }
+
+ public function provideGetCanonicalUrl() {
+ return array(
+ 'no fragement' => array( 'https://acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', null ),
+ 'empty fragement' => array( 'https://acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', '' ),
+ 'fragment' => array( 'https://acme.com/wiki/Foo#Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar' ),
+ 'double fragment' => array( 'https://acme.com/wiki/Foo#Bar%23Xus', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar#Xus' ),
+ 'escaped fragement' => array( 'https://acme.com/wiki/Foo%23Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo#Bar', null ),
+ 'empty path' => array( 'https://acme.com/Foo', 'https://acme.com', '//acme.com', '/$1', 'Foo', null ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetCanonicalUrl
+ */
+ public function testGetCanonicalUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getCanonicalUrl( $page, $fragmentId ) );
+ }
+
+ /**
+ * @dataProvider provideGetCanonicalUrl
+ * @note getUrl is an alias for getCanonicalUrl
+ */
+ public function testGetUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getUrl( $page, $fragmentId ) );
+ }
+
+ public function provideGetFullUrl() {
+ return array(
+ 'no fragement' => array( '//acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', null ),
+ 'empty fragement' => array( '//acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', '' ),
+ 'fragment' => array( '//acme.com/wiki/Foo#Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar' ),
+ 'double fragment' => array( '//acme.com/wiki/Foo#Bar%23Xus', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar#Xus' ),
+ 'escaped fragement' => array( '//acme.com/wiki/Foo%23Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo#Bar', null ),
+ 'empty path' => array( '//acme.com/Foo', 'https://acme.com', '//acme.com', '/$1', 'Foo', null ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetFullUrl
+ */
+ public function testGetFullUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getFullUrl( $page, $fragmentId ) );
+ }
+
+}
+
diff --git a/tests/phpunit/includes/XmlJsTest.php b/tests/phpunit/includes/XmlJsTest.php
index 0dbb0109..21819b7e 100644
--- a/tests/phpunit/includes/XmlJsTest.php
+++ b/tests/phpunit/includes/XmlJsTest.php
@@ -3,7 +3,7 @@
/**
* @group Xml
*/
-class XmlJs extends MediaWikiTestCase {
+class XmlJs extends PHPUnit_Framework_TestCase {
/**
* @covers XmlJsCode::__construct
diff --git a/tests/phpunit/includes/XmlTest.php b/tests/phpunit/includes/XmlTest.php
index 382e3d89..bea338de 100644
--- a/tests/phpunit/includes/XmlTest.php
+++ b/tests/phpunit/includes/XmlTest.php
@@ -154,7 +154,7 @@ class XmlTest extends MediaWikiTestCase {
'<label for="year">From year (and earlier):</label> ' .
'<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">' .
+ '<select name="month" id="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
'<option value="1">January</option>' . "\n" .
'<option value="2" selected="">February</option>' . "\n" .
@@ -175,7 +175,7 @@ class XmlTest extends MediaWikiTestCase {
'<label for="year">From year (and earlier):</label> ' .
'<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">' .
+ '<select name="month" id="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
'<option value="1">January</option>' . "\n" .
'<option value="2">February</option>' . "\n" .
@@ -209,7 +209,7 @@ class XmlTest extends MediaWikiTestCase {
'<label for="year">From year (and earlier):</label> ' .
'<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">' .
+ '<select name="month" id="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
'<option value="1">January</option>' . "\n" .
'<option value="2">February</option>' . "\n" .
diff --git a/tests/phpunit/includes/api/ApiBlockTest.php b/tests/phpunit/includes/api/ApiBlockTest.php
index d98eec6a..575efd6d 100644
--- a/tests/phpunit/includes/api/ApiBlockTest.php
+++ b/tests/phpunit/includes/api/ApiBlockTest.php
@@ -53,7 +53,7 @@ class ApiBlockTest extends ApiTestCase {
'action' => 'block',
'user' => 'UTApiBlockee',
'reason' => 'Some reason',
- 'token' => $tokens['blocktoken'] ), null, false, self::$users['sysop']->user );
+ 'token' => $tokens['blocktoken'] ), null, false, self::$users['sysop']->getUser() );
$block = Block::newFromTarget( 'UTApiBlockee' );
@@ -68,7 +68,7 @@ class ApiBlockTest extends ApiTestCase {
* @expectedException UsageException
* @expectedExceptionMessage The token parameter must be set
*/
- public function testBlockingActionWithNoToken( ) {
+ public function testBlockingActionWithNoToken() {
$this->doApiRequest(
array(
'action' => 'block',
@@ -77,7 +77,7 @@ class ApiBlockTest extends ApiTestCase {
),
null,
false,
- self::$users['sysop']->user
+ self::$users['sysop']->getUser()
);
}
}
diff --git a/tests/phpunit/includes/api/ApiEditPageTest.php b/tests/phpunit/includes/api/ApiEditPageTest.php
index 3179a452..61a8ad11 100644
--- a/tests/phpunit/includes/api/ApiEditPageTest.php
+++ b/tests/phpunit/includes/api/ApiEditPageTest.php
@@ -27,9 +27,14 @@ class ApiEditPageTest extends ApiTestCase {
$wgExtraNamespaces[12312] = 'Dummy';
$wgExtraNamespaces[12313] = 'Dummy_talk';
+ $wgExtraNamespaces[12314] = 'DummyNonText';
+ $wgExtraNamespaces[12315] = 'DummyNonText_talk';
$wgNamespaceContentModels[12312] = "testing";
+ $wgNamespaceContentModels[12314] = "testing-nontext";
+
$wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
+ $wgContentHandlers["testing-nontext"] = 'DummyNonTextContentHandler';
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
@@ -96,33 +101,6 @@ class ApiEditPageTest extends ApiTestCase {
);
}
- public function testNonTextEdit() {
- $name = 'Dummy:ApiEditPageTest_testNonTextEdit';
- $data = serialize( 'some bla bla text' );
-
- // -- test new page --------------------------------------------
- $apiResult = $this->doApiRequestWithToken( array(
- 'action' => 'edit',
- 'title' => $name,
- 'text' => $data, ) );
- $apiResult = $apiResult[0];
-
- // Validate API result data
- $this->assertArrayHasKey( 'edit', $apiResult );
- $this->assertArrayHasKey( 'result', $apiResult['edit'] );
- $this->assertEquals( 'Success', $apiResult['edit']['result'] );
-
- $this->assertArrayHasKey( 'new', $apiResult['edit'] );
- $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
-
- $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
-
- // validate resulting revision
- $page = WikiPage::factory( Title::newFromText( $name ) );
- $this->assertEquals( "testing", $page->getContentModel() );
- $this->assertEquals( $data, $page->getContent()->serialize() );
- }
-
/**
* @return array
*/
@@ -240,7 +218,7 @@ class ApiEditPageTest extends ApiTestCase {
'section' => 'new',
'text' => 'test',
'summary' => 'header',
- ));
+ ) );
$this->assertEquals( 'Success', $re['edit']['result'] );
// Check the page text is correct
@@ -257,7 +235,7 @@ class ApiEditPageTest extends ApiTestCase {
'section' => 'new',
'text' => 'test',
'summary' => 'header',
- ));
+ ) );
$this->assertEquals( 'Success', $re2['edit']['result'] );
$text = WikiPage::factory( Title::newFromText( $name ) )
@@ -284,18 +262,18 @@ class ApiEditPageTest extends ApiTestCase {
// base edit for content
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// base edit for redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $rpage, '20120101000000' );
// conflicting edit to redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $rpage, '20120101020202' );
// try to save edit, following the redirect
@@ -306,7 +284,7 @@ class ApiEditPageTest extends ApiTestCase {
'basetimestamp' => $baseTime,
'section' => 'new',
'redirect' => true,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->assertEquals( 'Success', $re['edit']['result'],
"no problems expected when following redirect" );
@@ -330,18 +308,18 @@ class ApiEditPageTest extends ApiTestCase {
// base edit for content
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// base edit for redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $rpage, '20120101000000' );
// conflicting edit to redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $rpage, '20120101020202' );
// try to save edit, following the redirect but without creating a section
@@ -352,7 +330,7 @@ class ApiEditPageTest extends ApiTestCase {
'text' => 'nix bar!',
'basetimestamp' => $baseTime,
'redirect' => true,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->fail( 'redirect-appendonly error expected' );
} catch ( UsageException $ex ) {
@@ -372,13 +350,13 @@ class ApiEditPageTest extends ApiTestCase {
// base edit
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// conflicting edit
$page->doEditContent( new WikitextContent( "Foo bar" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $page, '20120101020202' );
// try to save edit, expect conflict
@@ -388,7 +366,7 @@ class ApiEditPageTest extends ApiTestCase {
'title' => $name,
'text' => 'nix bar!',
'basetimestamp' => $baseTime,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->fail( 'edit conflict expected' );
} catch ( UsageException $ex ) {
@@ -411,13 +389,13 @@ class ApiEditPageTest extends ApiTestCase {
// base edit
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// conflicting edit
$page->doEditContent( new WikitextContent( "Foo bar" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $page, '20120101020202' );
// try to save edit, expect no conflict
@@ -427,7 +405,7 @@ class ApiEditPageTest extends ApiTestCase {
'text' => 'nix bar!',
'basetimestamp' => $baseTime,
'section' => 'new',
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->assertEquals( 'Success', $re['edit']['result'],
"no edit conflict expected here" );
@@ -454,17 +432,17 @@ class ApiEditPageTest extends ApiTestCase {
// base edit for content
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
// base edit for redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $rpage, '20120101000000' );
// new edit to content
$page->doEditContent( new WikitextContent( "Foo bar" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $rpage, '20120101020202' );
// try to save edit; should work, following the redirect.
@@ -474,7 +452,7 @@ class ApiEditPageTest extends ApiTestCase {
'text' => 'nix bar!',
'section' => 'new',
'redirect' => true,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->assertEquals( 'Success', $re['edit']['result'],
"no edit conflict expected here" );
@@ -493,4 +471,45 @@ class ApiEditPageTest extends ApiTestCase {
$page->clear();
}
+
+ public function testCheckDirectApiEditingDisallowed_forNonTextContent() {
+ $this->setExpectedException(
+ 'UsageException',
+ 'Direct editing via API is not supported for content model testing used by Dummy:ApiEditPageTest_nonTextPageEdit'
+ );
+
+ $this->doApiRequestWithToken( array(
+ 'action' => 'edit',
+ 'title' => 'Dummy:ApiEditPageTest_nonTextPageEdit',
+ 'text' => '{"animals":["kittens!"]}'
+ ) );
+ }
+
+ public function testSupportsDirectApiEditing_withContentHandlerOverride() {
+ $name = 'DummyNonText:ApiEditPageTest_testNonTextEdit';
+ $data = serialize( 'some bla bla text' );
+
+ $result = $this->doApiRequestWithToken( array(
+ 'action' => 'edit',
+ 'title' => $name,
+ 'text' => $data,
+ ) );
+
+ $apiResult = $result[0];
+
+ // Validate API result data
+ $this->assertArrayHasKey( 'edit', $apiResult );
+ $this->assertArrayHasKey( 'result', $apiResult['edit'] );
+ $this->assertEquals( 'Success', $apiResult['edit']['result'] );
+
+ $this->assertArrayHasKey( 'new', $apiResult['edit'] );
+ $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
+
+ $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
+
+ // validate resulting revision
+ $page = WikiPage::factory( Title::newFromText( $name ) );
+ $this->assertEquals( "testing-nontext", $page->getContentModel() );
+ $this->assertEquals( $data, $page->getContent()->serialize() );
+ }
}
diff --git a/tests/phpunit/includes/api/ApiLoginTest.php b/tests/phpunit/includes/api/ApiLoginTest.php
index 88a99e9b..7dfd14f3 100644
--- a/tests/phpunit/includes/api/ApiLoginTest.php
+++ b/tests/phpunit/includes/api/ApiLoginTest.php
@@ -23,7 +23,7 @@ class ApiLoginTest extends ApiTestCase {
global $wgServer;
$user = self::$users['sysop'];
- $user->user->logOut();
+ $user->getUser()->logOut();
if ( !isset( $wgServer ) ) {
$this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
@@ -68,7 +68,7 @@ class ApiLoginTest extends ApiTestCase {
}
$user = self::$users['sysop'];
- $user->user->logOut();
+ $user->getUser()->logOut();
$ret = $this->doApiRequest( array(
"action" => "login",
diff --git a/tests/phpunit/includes/api/ApiMainTest.php b/tests/phpunit/includes/api/ApiMainTest.php
index e8ef1804..94b741dc 100644
--- a/tests/phpunit/includes/api/ApiMainTest.php
+++ b/tests/phpunit/includes/api/ApiMainTest.php
@@ -71,7 +71,7 @@ class ApiMainTest extends ApiTestCase {
new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
);
$modules = $api->getModuleManager()->getNamesWithClasses();
- foreach( $modules as $name => $class ) {
+ foreach ( $modules as $name => $class ) {
$this->assertArrayHasKey(
$class,
$classes,
@@ -79,4 +79,173 @@ class ApiMainTest extends ApiTestCase {
);
}
}
+
+ /**
+ * Test HTTP precondition headers
+ *
+ * @covers ApiMain::checkConditionalRequestHeaders
+ * @dataProvider provideCheckConditionalRequestHeaders
+ * @param array $headers HTTP headers
+ * @param array $conditions Return data for ApiBase::getConditionalRequestData
+ * @param int $status Expected response status
+ * @param bool $post Request is a POST
+ */
+ public function testCheckConditionalRequestHeaders( $headers, $conditions, $status, $post = false ) {
+ $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
+ $request->setHeaders( $headers );
+ $request->response()->statusHeader( 200 ); // Why doesn't it default?
+
+ $api = new ApiMain( $request );
+ $priv = TestingAccessWrapper::newFromObject( $api );
+ $priv->mInternalMode = false;
+
+ $module = $this->getMockBuilder( 'ApiBase' )
+ ->setConstructorArgs( array( $api, 'mock' ) )
+ ->setMethods( array( 'getConditionalRequestData' ) )
+ ->getMockForAbstractClass();
+ $module->expects( $this->any() )
+ ->method( 'getConditionalRequestData' )
+ ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
+ return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
+ } ) );
+
+ $ret = $priv->checkConditionalRequestHeaders( $module );
+
+ $this->assertSame( $status, $request->response()->getStatusCode() );
+ $this->assertSame( $status === 200, $ret );
+ }
+
+ public static function provideCheckConditionalRequestHeaders() {
+ $now = time();
+
+ return array(
+ // Non-existing from module is ignored
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array(), 200 ),
+ array( array( 'If-Modified-Since' => 'Tue, 18 Aug 2015 00:00:00 GMT' ), array(), 200 ),
+
+ // No headers
+ array(
+ array(),
+ array(
+ 'etag' => '""',
+ 'last-modified' => '20150815000000',
+ ),
+ 200
+ ),
+
+ // Basic If-None-Match
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 304 ),
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"baz"' ), 200 ),
+ array( array( 'If-None-Match' => '"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
+ array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => '"foo"' ), 304 ),
+ array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
+
+ // Pointless, but supported
+ array( array( 'If-None-Match' => '*' ), array(), 304 ),
+
+ // Basic If-Modified-Since
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now ) ), 304 ),
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now + 1 ) ), 200 ),
+
+ // If-Modified-Since ignored when If-None-Match is given too
+ array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'etag' => '"x"', 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
+ array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+
+ // Ignored for POST
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 200, true ),
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200, true ),
+
+ // Other date formats allowed by the RFC
+ array( array( 'If-Modified-Since' => gmdate( 'l, d-M-y H:i:s', $now ) . ' GMT' ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+ array( array( 'If-Modified-Since' => gmdate( 'D M j H:i:s Y', $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+
+ // Old browser extension to HTTP/1.0
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) . '; length=123' ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+
+ // Invalid date formats should be ignored
+ array( array( 'If-Modified-Since' => gmdate( 'Y-m-d H:i:s', $now ) . ' GMT' ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
+ );
+ }
+
+ /**
+ * Test conditional headers output
+ * @dataProvider provideConditionalRequestHeadersOutput
+ * @param array $conditions Return data for ApiBase::getConditionalRequestData
+ * @param array $headers Expected output headers
+ * @param bool $isError $isError flag
+ * @param bool $post Request is a POST
+ */
+ public function testConditionalRequestHeadersOutput( $conditions, $headers, $isError = false, $post = false ) {
+ $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
+ $response = $request->response();
+
+ $api = new ApiMain( $request );
+ $priv = TestingAccessWrapper::newFromObject( $api );
+ $priv->mInternalMode = false;
+
+ $module = $this->getMockBuilder( 'ApiBase' )
+ ->setConstructorArgs( array( $api, 'mock' ) )
+ ->setMethods( array( 'getConditionalRequestData' ) )
+ ->getMockForAbstractClass();
+ $module->expects( $this->any() )
+ ->method( 'getConditionalRequestData' )
+ ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
+ return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
+ } ) );
+ $priv->mModule = $module;
+
+ $priv->sendCacheHeaders( $isError );
+
+ foreach ( array( 'Last-Modified', 'ETag' ) as $header ) {
+ $this->assertEquals(
+ isset( $headers[$header] ) ? $headers[$header] : null,
+ $response->getHeader( $header ),
+ $header
+ );
+ }
+ }
+
+ public static function provideConditionalRequestHeadersOutput() {
+ return array(
+ array(
+ array(),
+ array()
+ ),
+ array(
+ array( 'etag' => '"foo"' ),
+ array( 'ETag' => '"foo"' )
+ ),
+ array(
+ array( 'last-modified' => '20150818000102' ),
+ array( 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
+ ),
+ array(
+ array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
+ array( 'ETag' => '"foo"', 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
+ ),
+ array(
+ array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
+ array(),
+ true,
+ ),
+ array(
+ array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
+ array(),
+ false,
+ true,
+ ),
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/api/ApiMessageTest.php b/tests/phpunit/includes/api/ApiMessageTest.php
index 6c3ce60d..08a984eb 100644
--- a/tests/phpunit/includes/api/ApiMessageTest.php
+++ b/tests/phpunit/includes/api/ApiMessageTest.php
@@ -14,9 +14,13 @@ class ApiMessageTest extends MediaWikiTestCase {
$msg = TestingAccessWrapper::newFromObject( $msg );
$msg2 = TestingAccessWrapper::newFromObject( $msg2 );
- foreach ( array( 'interface', 'useDatabase', 'title' ) as $key ) {
- $this->assertSame( $msg->$key, $msg2->$key, $key );
- }
+ $this->assertSame( $msg->interface, $msg2->interface, 'interface' );
+ $this->assertSame( $msg->useDatabase, $msg2->useDatabase, 'useDatabase' );
+ $this->assertSame(
+ $msg->title ? $msg->title->getFullText() : null,
+ $msg2->title ? $msg2->title->getFullText() : null,
+ 'title'
+ );
}
/**
@@ -30,6 +34,11 @@ class ApiMessageTest extends MediaWikiTestCase {
$this->assertEquals( 'code', $msg2->getApiCode() );
$this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2 = unserialize( serialize( $msg2 ) );
+ $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 );
@@ -63,6 +72,11 @@ class ApiMessageTest extends MediaWikiTestCase {
$this->assertEquals( 'code', $msg2->getApiCode() );
$this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2 = unserialize( serialize( $msg2 ) );
+ $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 );
diff --git a/tests/phpunit/includes/api/ApiQueryAllPagesTest.php b/tests/phpunit/includes/api/ApiQueryAllPagesTest.php
index 124988f3..0ac00eea 100644
--- a/tests/phpunit/includes/api/ApiQueryAllPagesTest.php
+++ b/tests/phpunit/includes/api/ApiQueryAllPagesTest.php
@@ -13,9 +13,11 @@ class ApiQueryAllPagesTest extends ApiTestCase {
}
/**
- * @todo give this test a real name explaining what is being tested here
+ *Test bug 25702
+ *Prefixes of API search requests are not handled with case sensitivity and may result
+ *in wrong search results
*/
- public function testBug25702() {
+ public function testPrefixNormalizationSearchBug() {
$title = Title::newFromText( 'Category:Template:xyz' );
$page = WikiPage::factory( $title );
$page->doEdit( 'Some text', 'inserting content' );
diff --git a/tests/phpunit/includes/api/ApiResultTest.php b/tests/phpunit/includes/api/ApiResultTest.php
index f0d84552..2f31677e 100644
--- a/tests/phpunit/includes/api/ApiResultTest.php
+++ b/tests/phpunit/includes/api/ApiResultTest.php
@@ -181,6 +181,19 @@ class ApiResultTest extends MediaWikiTestCase {
);
}
+ ApiResult::setValue( $arr, null, NAN, ApiResult::NO_VALIDATE );
+
+ try {
+ ApiResult::setValue( $arr, null, NAN, ApiResult::NO_SIZE_CHECK );
+ $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' );
@@ -408,6 +421,19 @@ class ApiResultTest extends MediaWikiTestCase {
);
}
+ $result->addValue( null, null, NAN, ApiResult::NO_VALIDATE );
+
+ try {
+ $result->addValue( null, null, NAN, ApiResult::NO_SIZE_CHECK );
+ $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(
@@ -444,6 +470,12 @@ class ApiResultTest extends MediaWikiTestCase {
$result->removeValue( null, 'foo' );
$this->assertTrue( $result->addValue( null, 'foo', '1' ) );
+ $result = new ApiResult( 10 );
+ $obj = new ApiResultTestSerializableObject( 'ok' );
+ $obj->foobar = 'foobaz';
+ $this->assertTrue( $result->addValue( null, 'foo', $obj ) );
+ $this->assertSame( 2, $result->getSize() );
+
$result = new ApiResult( 8388608 );
$result2 = new ApiResult( 8388608 );
$result2->addValue( null, 'foo', 'bar' );
@@ -674,6 +706,10 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'BCkvp',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array( 'x' => 'a', 'y' => array( 'b' ), 'z' => array( 'c' => 'd' ),
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1 ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -858,6 +894,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'assoc',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ 'x' => 'a',
+ 'y' => array( 'b', ApiResult::META_TYPE => 'array' ),
+ 'z' => array( 'c' => 'd', ApiResult::META_TYPE => 'assoc' ),
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -871,8 +914,12 @@ class ApiResultTest extends MediaWikiTestCase {
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' ),
+ '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' ),
@@ -885,6 +932,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'assoc',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => (object)array(
+ 'x' => 'a',
+ 'y' => array( 'b', ApiResult::META_TYPE => 'array' ),
+ 'z' => (object)array( 'c' => 'd', ApiResult::META_TYPE => 'assoc' ),
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -916,6 +970,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'array',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ $kvp( 'name', 'x', 'value', 'a' ),
+ $kvp( 'name', 'y', 'value', array( 'b', ApiResult::META_TYPE => 'array' ) ),
+ array( 'name' => 'z', 'c' => 'd', ApiResult::META_TYPE => 'assoc', ApiResult::META_PRESERVE_KEYS => array( 'name' ) ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -947,6 +1008,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'array',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ $kvp( 'name', 'x', '*', 'a' ),
+ $kvp( 'name', 'y', '*', array( 'b', ApiResult::META_TYPE => 'array' ) ),
+ array( 'name' => 'z', 'c' => 'd', ApiResult::META_TYPE => 'assoc', ApiResult::META_PRESERVE_KEYS => array( 'name' ) ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -960,8 +1028,12 @@ class ApiResultTest extends MediaWikiTestCase {
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' ),
+ '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' ),
@@ -978,6 +1050,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'array',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ (object)$kvp( 'name', 'x', 'value', 'a' ),
+ (object)$kvp( 'name', 'y', 'value', array( 'b', ApiResult::META_TYPE => 'array' ) ),
+ (object)array( 'name' => 'z', 'c' => 'd', ApiResult::META_TYPE => 'assoc', ApiResult::META_PRESERVE_KEYS => array( 'name' ) ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -1017,6 +1096,11 @@ class ApiResultTest extends MediaWikiTestCase {
(object)array( 'key' => 'x', 'value' => 'a' ),
(object)array( 'key' => 'y', 'value' => 'b' ),
),
+ 'kvpmerge' => array(
+ (object)array( 'name' => 'x', 'value' => 'a' ),
+ (object)array( 'name' => 'y', 'value' => array( 'b' ) ),
+ (object)array( 'name' => 'z', 'c' => 'd' ),
+ ),
'emptyDefault' => array(),
'emptyAssoc' => (object)array(),
'_dummy' => 1,
@@ -1127,13 +1211,84 @@ class ApiResultTest extends MediaWikiTestCase {
/**
* @covers ApiResult
*/
+ public function testAddMetadataToResultVars() {
+ $arr = array(
+ 'a' => "foo",
+ 'b' => false,
+ 'c' => 10,
+ 'sequential_numeric_keys' => array( 'a', 'b', 'c' ),
+ 'non_sequential_numeric_keys' => array( 'a', 'b', 4 => 'c' ),
+ 'string_keys' => array(
+ 'one' => 1,
+ 'two' => 2
+ ),
+ 'object_sequential_keys' => (object)array( 'a', 'b', 'c' ),
+ '_type' => "should be overwritten in result",
+ );
+ $this->assertSame( array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array(
+ 'a', 'b', 'c',
+ 'sequential_numeric_keys', 'non_sequential_numeric_keys',
+ 'string_keys', 'object_sequential_keys'
+ ),
+ ApiResult::META_BC_BOOLS => array( 'b' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 'a' => "foo",
+ 'b' => false,
+ 'c' => 10,
+ 'sequential_numeric_keys' => array(
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'value',
+ 0 => 'a',
+ 1 => 'b',
+ 2 => 'c',
+ ),
+ 'non_sequential_numeric_keys' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( 0, 1, 4 ),
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 0 => 'a',
+ 1 => 'b',
+ 4 => 'c',
+ ),
+ 'string_keys' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( 'one', 'two' ),
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 'one' => 1,
+ 'two' => 2,
+ ),
+ 'object_sequential_keys' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( 0, 1, 2 ),
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 0 => 'a',
+ 1 => 'b',
+ 2 => 'c',
+ ),
+ ), ApiResult::addMetadataToResultVars( $arr ) );
+ }
+
+ /**
+ * @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 ) ) {
+ if ( preg_match( '/Use of ApiMain to ApiResult::__construct ' .
+ 'was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
return true;
}
return false;
@@ -1166,17 +1321,6 @@ class ApiResultTest extends MediaWikiTestCase {
),
'*' => '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' );
@@ -1451,7 +1595,8 @@ class ApiResultTest extends MediaWikiTestCase {
$result = new ApiResult( 8388608 );
$result->setMainForContinuation( $main );
- $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) );
+ $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ),
+ array( 'mock1', 'mock2' ) );
try {
$result->setContinueParam( $allModules[1], 'm2continue', 1 );
$this->fail( 'Expected exception not thrown' );
@@ -1467,7 +1612,8 @@ class ApiResultTest extends MediaWikiTestCase {
$this->fail( 'Expected exception not thrown' );
} catch ( UnexpectedValueException $ex ) {
$this->assertSame(
- 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct',
+ 'Module \'mocklist\' called ApiContinuationManager::addContinueParam ' .
+ 'but was not passed to ApiContinuationManager::__construct',
$ex->getMessage(),
'Expected exception'
);
@@ -1495,13 +1641,14 @@ class ApiResultTest extends MediaWikiTestCase {
try {
$arr = array();
- ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
+ 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',
+ 'ApiResultTestSerializableObject::serializeForApiResult() ' .
+ 'returned an object of class ApiResultTestStringifiableObject',
$ex->getMessage(),
'Expected exception'
);
@@ -1509,18 +1656,19 @@ class ApiResultTest extends MediaWikiTestCase {
try {
$arr = array();
- ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) );
+ 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',
+ '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(
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
array(
'one' => new ApiResultTestStringifiableObject( '1' ),
'two' => new ApiResultTestSerializableObject( 2 ),
diff --git a/tests/phpunit/includes/api/ApiRevisionDeleteTest.php b/tests/phpunit/includes/api/ApiRevisionDeleteTest.php
index b03836eb..362d647f 100644
--- a/tests/phpunit/includes/api/ApiRevisionDeleteTest.php
+++ b/tests/phpunit/includes/api/ApiRevisionDeleteTest.php
@@ -25,7 +25,7 @@ class ApiRevisionDeleteTest extends ApiTestCase {
}
public function testHidingRevisions() {
- $user = self::$users['sysop']->user;
+ $user = self::$users['sysop']->getUser();
$revid = array_shift( $this->revs );
$out = $this->doApiRequest( array(
'action' => 'revisiondelete',
@@ -80,7 +80,7 @@ class ApiRevisionDeleteTest extends ApiTestCase {
}
public function testUnhidingOutput() {
- $user = self::$users['sysop']->user;
+ $user = self::$users['sysop']->getUser();
$revid = array_shift( $this->revs );
// Hide revisions
$this->doApiRequest( array(
diff --git a/tests/phpunit/includes/api/ApiTestCase.php b/tests/phpunit/includes/api/ApiTestCase.php
index da62bb0a..21345ac1 100644
--- a/tests/phpunit/includes/api/ApiTestCase.php
+++ b/tests/phpunit/includes/api/ApiTestCase.php
@@ -105,6 +105,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
$wgRequest = new FauxRequest( $params, true, $session );
RequestContext::getMain()->setRequest( $wgRequest );
+ RequestContext::getMain()->setUser( $wgUser );
// set up local environment
$context = $this->apiContext->newTestContext( $wgRequest, $wgUser );
diff --git a/tests/phpunit/includes/api/ApiUnblockTest.php b/tests/phpunit/includes/api/ApiUnblockTest.php
index 2c2370a8..a374f094 100644
--- a/tests/phpunit/includes/api/ApiUnblockTest.php
+++ b/tests/phpunit/includes/api/ApiUnblockTest.php
@@ -16,7 +16,7 @@ class ApiUnblockTest extends ApiTestCase {
/**
* @expectedException UsageException
*/
- public function testWithNoToken( ) {
+ public function testWithNoToken() {
$this->doApiRequest(
array(
'action' => 'unblock',
@@ -25,7 +25,7 @@ class ApiUnblockTest extends ApiTestCase {
),
null,
false,
- self::$users['sysop']->user
+ self::$users['sysop']->getUser()
);
}
}
diff --git a/tests/phpunit/includes/api/ApiUploadTest.php b/tests/phpunit/includes/api/ApiUploadTest.php
index f74fc354..c852d72b 100644
--- a/tests/phpunit/includes/api/ApiUploadTest.php
+++ b/tests/phpunit/includes/api/ApiUploadTest.php
@@ -80,7 +80,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
try {
$this->doApiRequestWithToken( array(
'action' => 'upload',
- ), $session, self::$users['uploader']->user );
+ ), $session, self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
$this->assertEquals( "One of the parameters filekey, file, url, statuskey is required",
@@ -126,7 +126,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -165,7 +165,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user );
+ $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$this->assertContains( 'The file you submitted was empty', $e->getMessage() );
$exception = true;
@@ -215,7 +215,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -232,7 +232,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user ); // FIXME: leaks a temporary file
+ self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -286,7 +286,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -311,7 +311,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user ); // FIXME: leaks a temporary file
+ self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -331,7 +331,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
*/
public function testUploadStash( $session ) {
$this->setMwGlobals( array(
- 'wgUser' => self::$users['uploader']->user, // @todo FIXME: still used somewhere
+ 'wgUser' => self::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
) );
$extension = 'png';
@@ -368,7 +368,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user ); // FIXME: leaks a temporary file
+ self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -397,7 +397,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -415,7 +415,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
public function testUploadChunks( $session ) {
$this->setMwGlobals( array(
// @todo FIXME: still used somewhere
- 'wgUser' => self::$users['uploader']->user,
+ 'wgUser' => self::$users['uploader']->getUser(),
) );
$chunkSize = 1048576;
@@ -451,9 +451,9 @@ class ApiUploadTest extends ApiTestCaseUpload {
$chunkSessionKey = false;
$resultOffset = 0;
// Open the file:
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$handle = fopen( $filePath, "r" );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $handle === false ) {
$this->markTestIncomplete( "could not open file: $filePath" );
@@ -461,9 +461,9 @@ class ApiUploadTest extends ApiTestCaseUpload {
while ( !feof( $handle ) ) {
// Get the current chunk
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$chunkData = fread( $handle, $chunkSize );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
// Upload the current chunk into the $_FILE object:
$this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
@@ -473,7 +473,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
// Upload fist chunk ( and get the session key )
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -501,7 +501,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
// Upload current chunk
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -541,7 +541,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatDumpTest.php b/tests/phpunit/includes/api/format/ApiFormatDumpTest.php
deleted file mode 100644
index c0f67f8d..00000000
--- a/tests/phpunit/includes/api/format/ApiFormatDumpTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?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/ApiFormatWddxTest.php b/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
deleted file mode 100644
index 07111300..00000000
--- a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-/**
- * @group API
- * @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}" ),
- );
- }
-
- /**
- * @dataProvider provideEncoding
- */
- 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' ) );
- }
-}
-
-class ApiFormatWddxTest_SlowWddx extends ApiFormatWddx {
- public static function useSlowPrinter() {
- return true;
- }
-}
diff --git a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
index ce2f70de..db61bc80 100644
--- a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
+++ b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
@@ -57,10 +57,9 @@ abstract class ApiQueryContinueTestBase extends ApiQueryTestBase {
} else {
$params['action'] = 'query';
}
- if ( $useContinue && !isset( $params['continue'] ) ) {
+ // Silence warning
+ if ( !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 5f061b50..61b992ba 100644
--- a/tests/phpunit/includes/api/query/ApiQueryTest.php
+++ b/tests/phpunit/includes/api/query/ApiQueryTest.php
@@ -131,7 +131,7 @@ class ApiQueryTest extends ApiTestCase {
);
$queryApi = new ApiQuery( $api, 'query' );
$modules = $queryApi->getModuleManager()->getNamesWithClasses();
- foreach( $modules as $name => $class ) {
+ foreach ( $modules as $name => $class ) {
$this->assertArrayHasKey(
$class,
$classes,
diff --git a/tests/phpunit/includes/api/query/ApiQueryTestBase.php b/tests/phpunit/includes/api/query/ApiQueryTestBase.php
index dabf72e0..d5fa4542 100644
--- a/tests/phpunit/includes/api/query/ApiQueryTestBase.php
+++ b/tests/phpunit/includes/api/query/ApiQueryTestBase.php
@@ -56,12 +56,12 @@ STR;
* @return array
*/
private function validateRequestExpectedPair( $v ) {
- $this->assertType( 'array', $v, self::PARAM_ASSERT );
+ $this->assertInternalType( 'array', $v, self::PARAM_ASSERT );
$this->assertEquals( 2, count( $v ), self::PARAM_ASSERT );
$this->assertArrayHasKey( 0, $v, self::PARAM_ASSERT );
$this->assertArrayHasKey( 1, $v, self::PARAM_ASSERT );
- $this->assertType( 'array', $v[0], self::PARAM_ASSERT );
- $this->assertType( 'array', $v[1], self::PARAM_ASSERT );
+ $this->assertInternalType( 'array', $v[0], self::PARAM_ASSERT );
+ $this->assertInternalType( 'array', $v[1], self::PARAM_ASSERT );
return $v;
}
@@ -87,6 +87,7 @@ STR;
/**
* Checks that the request's result matches the expected results.
+ * Assumes no rawcontinue and a complete batch.
* @param array $values Array is a two element array( request, expected_results )
* @param array $session
* @param bool $appendModule
@@ -99,8 +100,9 @@ STR;
if ( !array_key_exists( 'action', $req ) ) {
$req['action'] = 'query';
}
- if ( !array_key_exists( 'continue', $req ) ) {
- $req['rawcontinue'] = '1';
+ // Silence warning
+ if ( !isset( $params['continue'] ) ) {
+ $params['continue'] = '';
}
foreach ( $req as &$val ) {
if ( is_array( $val ) ) {
@@ -108,7 +110,7 @@ STR;
}
}
$result = $this->doApiRequest( $req, $session, $appendModule, $user );
- $this->assertResult( array( 'query' => $exp ), $result[0], $req );
+ $this->assertResult( array( 'batchcomplete' => true, 'query' => $exp ), $result[0], $req );
}
protected function assertResult( $exp, $result, $message = '' ) {
diff --git a/tests/phpunit/includes/cache/MessageCacheTest.php b/tests/phpunit/includes/cache/MessageCacheTest.php
index 442e9f9f..5302b363 100644
--- a/tests/phpunit/includes/cache/MessageCacheTest.php
+++ b/tests/phpunit/includes/cache/MessageCacheTest.php
@@ -52,7 +52,7 @@ class MessageCacheTest extends MediaWikiLangTestCase {
$this->makePage( 'MessageCacheTest-FullKeyTest', 'ru' );
// In content language -- get base if no derivative
- $this->makePage( 'FallbackLanguageTest-NoDervContLang', 'de', 'de/none', false );
+ $this->makePage( 'FallbackLanguageTest-NoDervContLang', 'de', 'de/none' );
}
/**
@@ -61,15 +61,14 @@ class MessageCacheTest extends MediaWikiLangTestCase {
* @param string $title Title of page to be created
* @param string $lang Language and content of the created page
* @param string|null $content Content of the created page, or null for a generic string
- * @param bool $createSubPage Set to false if a root page should be created
*/
- protected function makePage( $title, $lang, $content = null, $createSubPage = true ) {
+ protected function makePage( $title, $lang, $content = null ) {
global $wgContLang;
if ( $content === null ) {
$content = $lang;
}
- if ( $lang !== $wgContLang->getCode() || $createSubPage ) {
+ if ( $lang !== $wgContLang->getCode() ) {
$title = "$title/$lang";
}
@@ -125,4 +124,26 @@ class MessageCacheTest extends MediaWikiLangTestCase {
);
}
+ /**
+ * @dataProvider provideNormalizeKey
+ */
+ public function testNormalizeKey( $key, $expected ) {
+ $actual = MessageCache::normalizeKey( $key );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function provideNormalizeKey() {
+ return array(
+ array( 'Foo', 'foo' ),
+ array( 'foo', 'foo' ),
+ array( 'fOo', 'fOo' ),
+ array( 'FOO', 'fOO' ),
+ array( 'Foo bar', 'foo_bar' ),
+ array( 'Ćab', 'ćab' ),
+ array( 'Ćab_e 3', 'ćab_e_3' ),
+ array( 'ĆAB', 'ćAB' ),
+ array( 'ćab', 'ćab' ),
+ array( 'ćaB', 'ćaB' ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/changes/RecentChangeTest.php b/tests/phpunit/includes/changes/RecentChangeTest.php
index b3cb7b52..4d1a936e 100644
--- a/tests/phpunit/includes/changes/RecentChangeTest.php
+++ b/tests/phpunit/includes/changes/RecentChangeTest.php
@@ -10,8 +10,8 @@ class RecentChangeTest extends MediaWikiTestCase {
protected $user_comment;
protected $context;
- public function __construct() {
- parent::__construct();
+ public function setUp() {
+ parent::setUp();
$this->title = Title::newFromText( 'SomeTitle' );
$this->target = Title::newFromText( 'TestTarget' );
@@ -22,6 +22,26 @@ class RecentChangeTest extends MediaWikiTestCase {
}
/**
+ * @covers RecentChange::newFromRow
+ * @covers RecentChange::loadFromRow
+ */
+ public function testNewFromRow() {
+ $row = new stdClass();
+ $row->rc_foo = 'AAA';
+ $row->rc_timestamp = '20150921134808';
+ $row->rc_deleted = 'bar';
+
+ $rc = RecentChange::newFromRow( $row );
+
+ $expected = array(
+ 'rc_foo' => 'AAA',
+ 'rc_timestamp' => '20150921134808',
+ 'rc_deleted' => 'bar',
+ );
+ $this->assertEquals( $expected, $rc->getAttributes() );
+ }
+
+ /**
* The testIrcMsgForAction* tests are supposed to cover the hacky
* LogFormatter::getIRCActionText / bug 34508
*
@@ -46,6 +66,7 @@ class RecentChangeTest extends MediaWikiTestCase {
* - protect/protect
* - protect/modifyprotect
* - protect/unprotect
+ * - protect/move_prot
* - upload/upload
* - merge/merge
* - import/upload
@@ -59,289 +80,95 @@ class RecentChangeTest extends MediaWikiTestCase {
*/
/**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeBlock() {
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # block/block
- $this->assertIRCComment(
- $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
- . $sep . $this->user_comment,
- 'block', 'block',
- array(
- '5::duration' => 'duration',
- '6::flags' => 'flags',
- ),
- $this->user_comment
- );
- # block/unblock
- $this->assertIRCComment(
- $this->context->msg( 'unblocklogentry', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'block', 'unblock',
- 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
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeDelete() {
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # delete/delete
- $this->assertIRCComment(
- $this->context->msg( 'deletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'delete', 'delete',
- array(),
- $this->user_comment
- );
-
- # delete/restore
- $this->assertIRCComment(
- $this->context->msg( 'undeletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'delete', 'restore',
- array(),
- $this->user_comment
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeNewusers() {
- $this->assertIRCComment(
- 'New user account',
- 'newusers', 'newusers',
- array()
- );
- $this->assertIRCComment(
- 'New user account',
- 'newusers', 'create',
- array()
- );
- $this->assertIRCComment(
- 'created new account SomeTitle',
- 'newusers', 'create2',
- array()
- );
- $this->assertIRCComment(
- 'Account created automatically',
- 'newusers', 'autocreate',
- array()
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeMove() {
- $move_params = array(
- '4::target' => $this->target->getPrefixedText(),
- '5::noredir' => 0,
- );
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # move/move
- $this->assertIRCComment(
- $this->context->msg( '1movedto2', 'SomeTitle', 'TestTarget' )
- ->plain() . $sep . $this->user_comment,
- 'move', 'move',
- $move_params,
- $this->user_comment
- );
-
- # move/move_redir
- $this->assertIRCComment(
- $this->context->msg( '1movedto2_redir', 'SomeTitle', 'TestTarget' )
- ->plain() . $sep . $this->user_comment,
- 'move', 'move_redir',
- $move_params,
- $this->user_comment
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
+ * @covers RecentChange::parseParams
*/
- public function testIrcMsgForLogTypePatrol() {
- # patrol/patrol
- $this->assertIRCComment(
- $this->context->msg( 'patrol-log-line', 'revision 777', '[[SomeTitle]]', '' )->plain(),
- 'patrol', 'patrol',
- array(
- '4::curid' => '777',
- '5::previd' => '666',
- '6::auto' => 0,
+ public function testParseParams() {
+ $params = array(
+ 'root' => array(
+ 'A' => 1,
+ 'B' => 'two'
)
);
- }
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeProtect() {
- $protectParams = array(
- '[edit=sysop] (indefinite) ‎[move=sysop] (indefinite)'
+ $this->assertParseParams(
+ $params,
+ 'a:1:{s:4:"root";a:2:{s:1:"A";i:1;s:1:"B";s:3:"two";}}'
);
- $sep = $this->context->msg( 'colon-separator' )->text();
- # protect/protect
- $this->assertIRCComment(
- $this->context->msg( 'protectedarticle', 'SomeTitle ' . $protectParams[0] )
- ->plain() . $sep . $this->user_comment,
- 'protect', 'protect',
- $protectParams,
- $this->user_comment
+ $this->assertParseParams(
+ null,
+ null
);
- # protect/unprotect
- $this->assertIRCComment(
- $this->context->msg( 'unprotectedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'protect', 'unprotect',
- array(),
- $this->user_comment
+ $this->assertParseParams(
+ null,
+ serialize( false )
);
- # protect/modify
- $this->assertIRCComment(
- $this->context->msg( 'modifiedarticleprotection', 'SomeTitle ' . $protectParams[0] )
- ->plain() . $sep . $this->user_comment,
- 'protect', 'modify',
- $protectParams,
- $this->user_comment
+ $this->assertParseParams(
+ null,
+ 'not-an-array'
);
}
/**
- * @covers LogFormatter::getIRCActionText
+ * @param array $expectedParseParams
+ * @param string|null $rawRcParams
*/
- public function testIrcMsgForLogTypeUpload() {
- $sep = $this->context->msg( 'colon-separator' )->text();
+ protected function assertParseParams( $expectedParseParams, $rawRcParams ) {
+ $rc = new RecentChange;
+ $rc->setAttribs( array( 'rc_params' => $rawRcParams ) );
- # upload/upload
- $this->assertIRCComment(
- $this->context->msg( 'uploadedimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'upload', 'upload',
- array(),
- $this->user_comment
- );
+ $actualParseParams = $rc->parseParams();
- # upload/overwrite
- $this->assertIRCComment(
- $this->context->msg( 'overwroteimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'upload', 'overwrite',
- array(),
- $this->user_comment
- );
+ $this->assertEquals( $expectedParseParams, $actualParseParams );
}
/**
- * @covers LogFormatter::getIRCActionText
+ * 50 mins and 100 mins are used here as the tests never take that long!
+ * @return array
*/
- 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
+ public function provideIsInRCLifespan() {
+ return array(
+ array( 6000, time() - 3000, 0, true ),
+ array( 3000, time() - 6000, 0, false ),
+ array( 6000, time() - 3000, 6000, true ),
+ array( 3000, time() - 6000, 6000, true ),
);
}
/**
- * @covers LogFormatter::getIRCActionText
+ * @covers RecentChange::isInRCLifespan
+ * @dataProvider provideIsInRCLifespan
*/
- 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
- );
+ public function testIsInRCLifespan( $maxAge, $timestamp, $tolerance, $expected ) {
+ $this->setMwGlobals( 'wgRCMaxAge', $maxAge );
+ $this->assertEquals( $expected, RecentChange::isInRCLifespan( $timestamp, $tolerance ) );
+ }
- # import/interwiki
- $this->assertIRCComment(
- $this->context->msg( 'import-logentry-interwiki', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'import', 'interwiki',
- array(),
- $this->user_comment
+ public function provideRCTypes() {
+ return array(
+ array( RC_EDIT, 'edit' ),
+ array( RC_NEW, 'new' ),
+ array( RC_LOG, 'log' ),
+ array( RC_EXTERNAL, 'external' ),
);
}
/**
- * @todo Emulate these edits somehow and extract
- * raw edit summary from RecentChange object
- * --
+ * @dataProvider provideRCTypes
+ * @covers RecentChange::parseFromRCType
*/
- /*
- public function testIrcMsgForBlankingAES() {
- // $this->context->msg( 'autosumm-blank', .. );
- }
-
- public function testIrcMsgForReplaceAES() {
- // $this->context->msg( 'autosumm-replace', .. );
- }
-
- public function testIrcMsgForRollbackAES() {
- // $this->context->msg( 'revertpage', .. );
+ public function testParseFromRCType( $rcType, $type ) {
+ $this->assertEquals( $type, RecentChange::parseFromRCType( $rcType ) );
}
- public function testIrcMsgForUndoAES() {
- // $this->context->msg( 'undo-summary', .. );
- }
- */
-
/**
- * @param string $expected Expected IRC text without colors codes
- * @param string $type Log type (move, delete, suppress, patrol ...)
- * @param string $action A log type action
- * @param array $params
- * @param string $comment (optional) A comment for the log action
- * @param string $msg (optional) A message for PHPUnit :-)
+ * @dataProvider provideRCTypes
+ * @covers RecentChange::parseToRCType
*/
- protected function assertIRCComment( $expected, $type, $action, $params,
- $comment = null, $msg = ''
- ) {
- $logEntry = new ManualLogEntry( $type, $action );
- $logEntry->setPerformer( $this->user );
- $logEntry->setTarget( $this->title );
- if ( $comment !== null ) {
- $logEntry->setComment( $comment );
- }
- $logEntry->setParameters( $params );
-
- $formatter = LogFormatter::newFromEntry( $logEntry );
- $formatter->setContext( $this->context );
-
- // Apply the same transformation as done in IRCColourfulRCFeedFormatter::getLine for rc_comment
- $ircRcComment = IRCColourfulRCFeedFormatter::cleanupForIRC( $formatter->getIRCActionComment() );
-
- $this->assertEquals(
- $expected,
- $ircRcComment,
- $msg
- );
+ public function testParseToRCType( $rcType, $type ) {
+ $this->assertEquals( $rcType, RecentChange::parseToRCType( $type ) );
}
+
}
diff --git a/tests/phpunit/includes/config/HashConfigTest.php b/tests/phpunit/includes/config/HashConfigTest.php
index 06973b09..4aa3e30c 100644
--- a/tests/phpunit/includes/config/HashConfigTest.php
+++ b/tests/phpunit/includes/config/HashConfigTest.php
@@ -30,7 +30,7 @@ class HashConfigTest extends MediaWikiTestCase {
public function testGet() {
$conf = new HashConfig( array(
'one' => '1',
- ));
+ ) );
$this->assertEquals( '1', $conf->get( 'one' ) );
$this->setExpectedException( 'ConfigException', 'HashConfig::get: undefined option' );
$conf->get( 'two' );
diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php
index 988a59ee..8178c12e 100644
--- a/tests/phpunit/includes/content/ContentHandlerTest.php
+++ b/tests/phpunit/includes/content/ContentHandlerTest.php
@@ -22,6 +22,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
'wgContentHandlers' => array(
CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler',
CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler',
+ CONTENT_MODEL_JSON => 'JsonContentHandler',
CONTENT_MODEL_CSS => 'CssContentHandler',
CONTENT_MODEL_TEXT => 'TextContentHandler',
'testing' => 'DummyContentHandlerForTesting',
@@ -51,19 +52,27 @@ class ContentHandlerTest extends MediaWikiTestCase {
return array(
array( 'Help:Foo', CONTENT_MODEL_WIKITEXT ),
array( 'Help:Foo.js', CONTENT_MODEL_WIKITEXT ),
+ array( 'Help:Foo.css', CONTENT_MODEL_WIKITEXT ),
+ array( 'Help:Foo.json', CONTENT_MODEL_WIKITEXT ),
array( 'Help:Foo/bar.js', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo.js', CONTENT_MODEL_WIKITEXT ),
+ array( 'User:Foo.css', CONTENT_MODEL_WIKITEXT ),
+ array( 'User:Foo.json', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo/bar.js', CONTENT_MODEL_JAVASCRIPT ),
array( 'User:Foo/bar.css', CONTENT_MODEL_CSS ),
+ array( 'User:Foo/bar.json', CONTENT_MODEL_JSON ),
+ array( 'User:Foo/bar.json.nope', CONTENT_MODEL_WIKITEXT ),
array( 'User talk:Foo/bar.css', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo/bar.js.xxx', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo/bar.xxx', CONTENT_MODEL_WIKITEXT ),
array( 'MediaWiki:Foo.js', CONTENT_MODEL_JAVASCRIPT ),
- array( 'MediaWiki:Foo.css', CONTENT_MODEL_CSS ),
array( 'MediaWiki:Foo.JS', CONTENT_MODEL_WIKITEXT ),
- array( 'MediaWiki:Foo.CSS', CONTENT_MODEL_WIKITEXT ),
+ array( 'MediaWiki:Foo.css', CONTENT_MODEL_CSS ),
array( 'MediaWiki:Foo.css.xxx', CONTENT_MODEL_WIKITEXT ),
+ array( 'MediaWiki:Foo.CSS', CONTENT_MODEL_WIKITEXT ),
+ array( 'MediaWiki:Foo.json', CONTENT_MODEL_JSON ),
+ array( 'MediaWiki:Foo.JSON', CONTENT_MODEL_WIKITEXT ),
);
}
@@ -338,6 +347,11 @@ class ContentHandlerTest extends MediaWikiTestCase {
}
*/
+ public function testSupportsDirectEditing() {
+ $handler = new DummyContentHandlerForTesting( CONTENT_MODEL_JSON );
+ $this->assertFalse( $handler->supportsDirectEditing(), 'direct editing is not supported' );
+ }
+
/**
* @covers ContentHandler::runLegacyHooks
*/
@@ -365,164 +379,3 @@ class ContentHandlerTest extends MediaWikiTestCase {
return true;
}
}
-
-class DummyContentHandlerForTesting extends ContentHandler {
-
- public function __construct( $dataModel ) {
- parent::__construct( $dataModel, array( "testing" ) );
- }
-
- /**
- * @see ContentHandler::serializeContent
- *
- * @param Content $content
- * @param string $format
- *
- * @return string
- */
- public function serializeContent( Content $content, $format = null ) {
- return $content->serialize();
- }
-
- /**
- * @see ContentHandler::unserializeContent
- *
- * @param string $blob
- * @param string $format Unused.
- *
- * @return Content
- */
- public function unserializeContent( $blob, $format = null ) {
- $d = unserialize( $blob );
-
- return new DummyContentForTesting( $d );
- }
-
- /**
- * Creates an empty Content object of the type supported by this ContentHandler.
- *
- */
- public function makeEmptyContent() {
- return new DummyContentForTesting( '' );
- }
-}
-
-class DummyContentForTesting extends AbstractContent {
-
- public function __construct( $data ) {
- parent::__construct( "testing" );
-
- $this->data = $data;
- }
-
- public function serialize( $format = null ) {
- return serialize( $this->data );
- }
-
- /**
- * @return string A string representing the content in a way useful for
- * building a full text search index. If no useful representation exists,
- * this method returns an empty string.
- */
- public function getTextForSearchIndex() {
- return '';
- }
-
- /**
- * @return string|bool The wikitext to include when another page includes this content,
- * or false if the content is not includable in a wikitext page.
- */
- public function getWikitextForTransclusion() {
- return false;
- }
-
- /**
- * Returns a textual representation of the content suitable for use in edit
- * summaries and log messages.
- *
- * @param int $maxlength Maximum length of the summary text.
- * @return string The summary text.
- */
- public function getTextForSummary( $maxlength = 250 ) {
- return '';
- }
-
- /**
- * Returns native represenation of the data. Interpretation depends on the data model used,
- * as given by getDataModel().
- *
- * @return mixed The native representation of the content. Could be a string, a nested array
- * structure, an object, a binary blob... anything, really.
- */
- public function getNativeData() {
- return $this->data;
- }
-
- /**
- * returns the content's nominal size in bogo-bytes.
- *
- * @return int
- */
- public function getSize() {
- return strlen( $this->data );
- }
-
- /**
- * Return a copy of this Content object. The following must be true for the object returned
- * if $copy = $original->copy()
- *
- * * get_class($original) === get_class($copy)
- * * $original->getModel() === $copy->getModel()
- * * $original->equals( $copy )
- *
- * If and only if the Content object is imutable, the copy() method can and should
- * return $this. That is, $copy === $original may be true, but only for imutable content
- * objects.
- *
- * @return Content A copy of this object
- */
- public function copy() {
- return $this;
- }
-
- /**
- * Returns true if this content is countable as a "real" wiki page, provided
- * that it's also in a countable location (e.g. a current revision in the main namespace).
- *
- * @param bool $hasLinks If it is known whether this content contains links,
- * provide this information here, to avoid redundant parsing to find out.
- * @return bool
- */
- public function isCountable( $hasLinks = null ) {
- return false;
- }
-
- /**
- * @param Title $title
- * @param int $revId Unused.
- * @param null|ParserOptions $options
- * @param bool $generateHtml Whether to generate Html (default: true). If false, the result
- * of calling getText() on the ParserOutput object returned by this method is undefined.
- *
- * @return ParserOutput
- */
- public function getParserOutput( Title $title, $revId = null,
- ParserOptions $options = null, $generateHtml = true
- ) {
- return new ParserOutput( $this->getNativeData() );
- }
-
- /**
- * @see AbstractContent::fillParserOutput()
- *
- * @param Title $title Context title for parsing
- * @param int|null $revId Revision ID (for {{REVISIONID}})
- * @param ParserOptions $options Parser options
- * @param bool $generateHtml Whether or not to generate HTML
- * @param ParserOutput &$output The output object to fill (reference).
- */
- protected function fillParserOutput( Title $title, $revId,
- ParserOptions $options, $generateHtml, ParserOutput &$output ) {
- $output = new ParserOutput( $this->getNativeData() );
- }
-}
diff --git a/tests/phpunit/includes/content/CssContentHandlerTest.php b/tests/phpunit/includes/content/CssContentHandlerTest.php
new file mode 100644
index 00000000..e1785a96
--- /dev/null
+++ b/tests/phpunit/includes/content/CssContentHandlerTest.php
@@ -0,0 +1,30 @@
+<?php
+
+class CssContentHandlerTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provideMakeRedirectContent
+ * @covers CssContentHandler::makeRedirectContent
+ */
+ public function testMakeRedirectContent( $title, $expected ) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScript' => '/w/index.php',
+ ) );
+ $ch = new CssContentHandler();
+ $content = $ch->makeRedirectContent( Title::newFromText( $title ) );
+ $this->assertInstanceOf( 'CssContent', $content );
+ $this->assertEquals( $expected, $content->serialize( CONTENT_FORMAT_CSS ) );
+ }
+
+ /**
+ * Keep this in sync with CssContentTest::provideGetRedirectTarget()
+ */
+ public static function provideMakeRedirectContent() {
+ return array(
+ array( 'MediaWiki:MonoBook.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=MediaWiki:MonoBook.css&action=raw&ctype=text/css);" ),
+ array( 'User:FooBar/common.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=User:FooBar/common.css&action=raw&ctype=text/css);" ),
+ array( 'Gadget:FooBaz.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/content/CssContentTest.php b/tests/phpunit/includes/content/CssContentTest.php
index 40484d3a..c4d87c24 100644
--- a/tests/phpunit/includes/content/CssContentTest.php
+++ b/tests/phpunit/includes/content/CssContentTest.php
@@ -4,6 +4,8 @@
* @group ContentHandler
* @group Database
* ^--- needed, because we do need the database to test link updates
+ *
+ * @FIXME this should not extend JavaScriptContentTest.
*/
class CssContentTest extends JavaScriptContentTest {
@@ -68,7 +70,48 @@ class CssContentTest extends JavaScriptContentTest {
$this->assertEquals( CONTENT_MODEL_CSS, $content->getContentHandler()->getModelID() );
}
- public static function dataEquals() {
+ /**
+ * Redirects aren't supported
+ */
+ public static function provideUpdateRedirect() {
+ return array(
+ array(
+ '#REDIRECT [[Someplace]]',
+ '#REDIRECT [[Someplace]]',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetRedirectTarget
+ */
+ public function testGetRedirectTarget( $title, $text ) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScriptPath' => '/w',
+ 'wgScript' => '/w/index.php',
+ ) );
+ $content = new CssContent( $text );
+ $target = $content->getRedirectTarget();
+ $this->assertEquals( $title, $target ? $target->getPrefixedText() : null );
+ }
+
+ /**
+ * Keep this in sync with CssContentHandlerTest::provideMakeRedirectContent()
+ */
+ public static function provideGetRedirectTarget() {
+ return array(
+ array( 'MediaWiki:MonoBook.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=MediaWiki:MonoBook.css&action=raw&ctype=text/css);" ),
+ array( 'User:FooBar/common.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=User:FooBar/common.css&action=raw&ctype=text/css);" ),
+ array( 'Gadget:FooBaz.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ # No #REDIRECT comment
+ array( null, "@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ # Wrong domain
+ array( null, "/* #REDIRECT */@import url(//example.com/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ );
+ }
+
+ public static function dataEquals() {
return array(
array( new CssContent( 'hallo' ), null, false ),
array( new CssContent( 'hallo' ), new CssContent( 'hallo' ), true ),
diff --git a/tests/phpunit/includes/content/JavaScriptContentHandlerTest.php b/tests/phpunit/includes/content/JavaScriptContentHandlerTest.php
new file mode 100644
index 00000000..0f41020f
--- /dev/null
+++ b/tests/phpunit/includes/content/JavaScriptContentHandlerTest.php
@@ -0,0 +1,30 @@
+<?php
+
+class JavaScriptContentHandlerTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provideMakeRedirectContent
+ * @covers JavaScriptContentHandler::makeRedirectContent
+ */
+ public function testMakeRedirectContent( $title, $expected ) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScript' => '/w/index.php',
+ ) );
+ $ch = new JavaScriptContentHandler();
+ $content = $ch->makeRedirectContent( Title::newFromText( $title ) );
+ $this->assertInstanceOf( 'JavaScriptContent', $content );
+ $this->assertEquals( $expected, $content->serialize( CONTENT_FORMAT_JAVASCRIPT ) );
+ }
+
+ /**
+ * Keep this in sync with JavaScriptContentTest::provideGetRedirectTarget()
+ */
+ public static function provideMakeRedirectContent() {
+ return array(
+ array( 'MediaWiki:MonoBook.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'User:FooBar/common.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'Gadget:FooBaz.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/content/JavaScriptContentTest.php b/tests/phpunit/includes/content/JavaScriptContentTest.php
index 7193ec9f..0ee27129 100644
--- a/tests/phpunit/includes/content/JavaScriptContentTest.php
+++ b/tests/phpunit/includes/content/JavaScriptContentTest.php
@@ -251,16 +251,31 @@ class JavaScriptContentTest extends TextContentTest {
/**
* @covers JavaScriptContent::updateRedirect
+ * @dataProvider provideUpdateRedirect
*/
- public function testUpdateRedirect() {
+ public function testUpdateRedirect( $oldText, $expectedText) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScriptPath' => '/w/index.php',
+ ) );
$target = Title::newFromText( "testUpdateRedirect_target" );
- $content = $this->newContent( "#REDIRECT [[Someplace]]" );
+ $content = new JavaScriptContent( $oldText );
$newContent = $content->updateRedirect( $target );
- $this->assertTrue(
- $content->equals( $newContent ),
- "content should be unchanged since it's not wikitext"
+ $this->assertEquals( $expectedText, $newContent->getNativeData() );
+ }
+
+ public static function provideUpdateRedirect() {
+ return array(
+ array(
+ '#REDIRECT [[Someplace]]',
+ '#REDIRECT [[Someplace]]',
+ ),
+ array(
+ '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");',
+ '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=TestUpdateRedirect_target\u0026action=raw\u0026ctype=text/javascript");'
+ )
);
}
@@ -290,4 +305,32 @@ class JavaScriptContentTest extends TextContentTest {
array( new JavaScriptContent( "hallo" ), new JavaScriptContent( "HALLO" ), false ),
);
}
+
+ /**
+ * @dataProvider provideGetRedirectTarget
+ */
+ public function testGetRedirectTarget( $title, $text ) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScriptPath' => '/w/index.php',
+ ) );
+ $content = new JavaScriptContent( $text );
+ $target = $content->getRedirectTarget();
+ $this->assertEquals( $title, $target ? $target->getPrefixedText() : null );
+ }
+
+ /**
+ * Keep this in sync with JavaScriptContentHandlerTest::provideMakeRedirectContent()
+ */
+ public static function provideGetRedirectTarget() {
+ return array(
+ array( 'MediaWiki:MonoBook.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'User:FooBar/common.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'Gadget:FooBaz.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ // No #REDIRECT comment
+ array( null, 'mw.loader.load("//example.org/w/index.php?title=MediaWiki:NoRedirect.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ // Different domain
+ array( null, '/* #REDIRECT */mw.loader.load("//example.com/w/index.php?title=MediaWiki:OtherWiki.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/content/JsonContentTest.php b/tests/phpunit/includes/content/JsonContentTest.php
index cccfe7b1..8a9d2ab0 100644
--- a/tests/phpunit/includes/content/JsonContentTest.php
+++ b/tests/phpunit/includes/content/JsonContentTest.php
@@ -138,7 +138,7 @@ class JsonContentTest extends MediaWikiLangTestCase {
'<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>'
),
array(
- (object)array( '<script>alert("evil!")</script>'),
+ (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>',
diff --git a/tests/phpunit/includes/content/TextContentHandlerTest.php b/tests/phpunit/includes/content/TextContentHandlerTest.php
new file mode 100644
index 00000000..492fec6b
--- /dev/null
+++ b/tests/phpunit/includes/content/TextContentHandlerTest.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @group ContentHandler
+ */
+class TextContentHandlerTest extends MediaWikiLangTestCase {
+ public function testSupportsDirectEditing() {
+ $handler = new TextContentHandler();
+ $this->assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' );
+ }
+
+}
diff --git a/tests/phpunit/includes/content/TextContentTest.php b/tests/phpunit/includes/content/TextContentTest.php
index dd61f85b..fe263756 100644
--- a/tests/phpunit/includes/content/TextContentTest.php
+++ b/tests/phpunit/includes/content/TextContentTest.php
@@ -27,10 +27,16 @@ class TextContentTest extends MediaWikiLangTestCase {
CONTENT_MODEL_JAVASCRIPT,
),
'wgUseTidy' => false,
- 'wgAlwaysUseTidy' => false,
'wgCapitalLinks' => true,
'wgHooks' => array(), // bypass hook ContentGetParserOutput that force custom rendering
) );
+
+ MWTidy::destroySingleton();
+ }
+
+ protected function tearDown() {
+ MWTidy::destroySingleton();
+ parent::tearDown();
}
public function newContent( $text ) {
diff --git a/tests/phpunit/includes/content/WikitextContentHandlerTest.php b/tests/phpunit/includes/content/WikitextContentHandlerTest.php
index 38fb5733..361238b7 100644
--- a/tests/phpunit/includes/content/WikitextContentHandlerTest.php
+++ b/tests/phpunit/includes/content/WikitextContentHandlerTest.php
@@ -115,6 +115,11 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase {
$this->assertEquals( $supported, $this->handler->isSupportedFormat( $format ) );
}
+ public function testSupportsDirectEditing() {
+ $handler = new WikiTextContentHandler();
+ $this->assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' );
+ }
+
public static function dataMerge3() {
return array(
array(
diff --git a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
index b4292a60..42ea58e5 100644
--- a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
+++ b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
@@ -181,7 +181,7 @@ class DatabaseMysqlBaseTest extends MediaWikiTestCase {
array( 'Tables_in_' => 'view2' ),
array( 'Tables_in_' => 'myview' ),
false # no more rows
- ));
+ ) );
return $db;
}
/**
diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php
index 645baf1f..3db9172a 100644
--- a/tests/phpunit/includes/db/DatabaseSqliteTest.php
+++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php
@@ -1,12 +1,13 @@
<?php
-class MockDatabaseSqlite extends DatabaseSqlite {
+class DatabaseSqliteMock extends DatabaseSqlite {
private $lastQuery;
public static function newInstance( array $p = array() ) {
$p['dbFilePath'] = ':memory:';
+ $p['schema'] = false;
- return new self( $p );
+ return DatabaseBase::factory( 'SqliteMock', $p );
}
function query( $sql, $fname = '', $tempIgnore = false ) {
@@ -29,7 +30,7 @@ class MockDatabaseSqlite extends DatabaseSqlite {
* @group medium
*/
class DatabaseSqliteTest extends MediaWikiTestCase {
- /** @var MockDatabaseSqlite */
+ /** @var DatabaseSqliteMock */
protected $db;
protected function setUp() {
@@ -38,7 +39,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
if ( !Sqlite::isPresent() ) {
$this->markTestSkipped( 'No SQLite support detected' );
}
- $this->db = MockDatabaseSqlite::newInstance();
+ $this->db = DatabaseSqliteMock::newInstance();
if ( version_compare( $this->db->getServerVersion(), '3.6.0', '<' ) ) {
$this->markTestSkipped( "SQLite at least 3.6 required, {$this->db->getServerVersion()} found" );
}
@@ -188,18 +189,34 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
public function testDuplicateTableStructure() {
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$db->query( 'CREATE TABLE foo(foo, barfoo)' );
+ $db->query( 'CREATE INDEX index1 ON foo(foo)' );
+ $db->query( 'CREATE UNIQUE INDEX index2 ON foo(barfoo)' );
$db->duplicateTableStructure( 'foo', 'bar' );
$this->assertEquals( 'CREATE TABLE "bar"(foo, barfoo)',
$db->selectField( 'sqlite_master', 'sql', array( 'name' => 'bar' ) ),
'Normal table duplication'
);
+ $indexList = $db->query( 'PRAGMA INDEX_LIST("bar")' );
+ $index = $indexList->next();
+ $this->assertEquals( 'bar_index1', $index->name );
+ $this->assertEquals( '0', $index->unique );
+ $index = $indexList->next();
+ $this->assertEquals( 'bar_index2', $index->name );
+ $this->assertEquals( '1', $index->unique );
$db->duplicateTableStructure( 'foo', 'baz', true );
$this->assertEquals( 'CREATE TABLE "baz"(foo, barfoo)',
$db->selectField( 'sqlite_temp_master', 'sql', array( 'name' => 'baz' ) ),
'Creation of temporary duplicate'
);
+ $indexList = $db->query( 'PRAGMA INDEX_LIST("baz")' );
+ $index = $indexList->next();
+ $this->assertEquals( 'baz_index1', $index->name );
+ $this->assertEquals( '0', $index->unique );
+ $index = $indexList->next();
+ $this->assertEquals( 'baz_index2', $index->name );
+ $this->assertEquals( '1', $index->unique );
$this->assertEquals( 0,
$db->selectField( 'sqlite_master', 'COUNT(*)', array( 'name' => 'baz' ) ),
'Create a temporary duplicate only'
diff --git a/tests/phpunit/includes/db/ORMTableTest.php b/tests/phpunit/includes/db/ORMTableTest.php
index 338d931f..764560d5 100644
--- a/tests/phpunit/includes/db/ORMTableTest.php
+++ b/tests/phpunit/includes/db/ORMTableTest.php
@@ -68,25 +68,6 @@ class ORMTableTest extends MediaWikiTestCase {
$this->assertInstanceOf( $class, $class::singleton() );
$this->assertTrue( $class::singleton() === $class::singleton() );
}
-
- /**
- * @since 1.21
- */
- public function testIgnoreErrorsOverride() {
- $table = $this->getTable();
-
- $db = $table->getReadDbConnection();
- $db->ignoreErrors( true );
-
- try {
- $table->rawSelect( "this is invalid" );
- $this->fail( "An invalid query should trigger a DBQueryError even if ignoreErrors is enabled." );
- } catch ( DBQueryError $ex ) {
- $this->assertTrue( true, "just making phpunit happy" );
- }
-
- $db->ignoreErrors( false );
- }
}
/**
diff --git a/tests/phpunit/includes/debug/MWDebugTest.php b/tests/phpunit/includes/debug/MWDebugTest.php
index 1abb47e7..7280a97b 100644
--- a/tests/phpunit/includes/debug/MWDebugTest.php
+++ b/tests/phpunit/includes/debug/MWDebugTest.php
@@ -12,11 +12,11 @@ class MWDebugTest extends MediaWikiTestCase {
}
/** Clear log before each test */
MWDebug::clearLog();
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
}
protected function tearDown() {
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
parent::tearDown();
}
diff --git a/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php b/tests/phpunit/includes/debug/logger/LegacyLoggerTest.php
index 415fa045..1b3ce2ca 100644
--- a/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php
+++ b/tests/phpunit/includes/debug/logger/LegacyLoggerTest.php
@@ -35,6 +35,8 @@ class LegacyLoggerTest extends MediaWikiTestCase {
}
public function provideInterpolate() {
+ $e = new \Exception( 'boom!' );
+ $d = new \DateTime();
return array(
array(
'no-op',
@@ -68,6 +70,57 @@ class LegacyLoggerTest extends MediaWikiTestCase {
),
'{ not interpolated }',
),
+ array(
+ '{null}',
+ array(
+ 'null' => null,
+ ),
+ '[Null]',
+ ),
+ array(
+ '{bool}',
+ array(
+ 'bool' => true,
+ ),
+ 'true',
+ ),
+ array(
+ '{float}',
+ array(
+ 'float' => 1.23,
+ ),
+ '1.23',
+ ),
+ array(
+ '{array}',
+ array(
+ 'array' => array( 1, 2, 3 ),
+ ),
+ '[Array(3)]',
+ ),
+ array(
+ '{exception}',
+ array(
+ 'exception' => $e,
+ ),
+ '[Exception ' . get_class( $e ) . '( ' .
+ $e->getFile() . ':' . $e->getLine() . ') ' .
+ $e->getMessage() . ']',
+ ),
+ array(
+ '{datetime}',
+ array(
+ 'datetime' => $d,
+ ),
+ $d->format( 'c' ),
+ ),
+ array(
+ '{object}',
+ array(
+ 'object' => new \stdClass,
+ ),
+ '[Object stdClass]',
+ ),
);
}
diff --git a/tests/phpunit/includes/debug/logger/MonologSpiTest.php b/tests/phpunit/includes/debug/logger/MonologSpiTest.php
new file mode 100644
index 00000000..aa0a54ff
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/MonologSpiTest.php
@@ -0,0 +1,136 @@
+<?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 TestingAccessWrapper;
+
+class MonologSpiTest extends MediaWikiTestCase {
+
+ /**
+ * @covers MonologSpi::mergeConfig
+ */
+ public function testMergeConfig() {
+ $base = array(
+ 'loggers' => array(
+ '@default' => array(
+ 'processors' => array( 'constructor' ),
+ 'handlers' => array( 'constructor' ),
+ ),
+ ),
+ 'processors' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ ),
+ 'handlers' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ 'formatter' => 'constructor',
+ ),
+ ),
+ 'formatters' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ ),
+ );
+
+ $fixture = new MonologSpi( $base );
+ $this->assertSame(
+ $base,
+ TestingAccessWrapper::newFromObject( $fixture )->config
+ );
+
+ $fixture->mergeConfig( array(
+ 'loggers' => array(
+ 'merged' => array(
+ 'processors' => array( 'merged' ),
+ 'handlers' => array( 'merged' ),
+ ),
+ ),
+ 'processors' => array(
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ 'magic' => array(
+ 'idkfa' => array( 'xyzzy' ),
+ ),
+ 'handlers' => array(
+ 'merged' => array(
+ 'class' => 'merged',
+ 'formatter' => 'merged',
+ ),
+ ),
+ 'formatters' => array(
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ ) );
+ $this->assertSame(
+ array(
+ 'loggers' => array(
+ '@default' => array(
+ 'processors' => array( 'constructor' ),
+ 'handlers' => array( 'constructor' ),
+ ),
+ 'merged' => array(
+ 'processors' => array( 'merged' ),
+ 'handlers' => array( 'merged' ),
+ ),
+ ),
+ 'processors' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ 'handlers' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ 'formatter' => 'constructor',
+ ),
+ 'merged' => array(
+ 'class' => 'merged',
+ 'formatter' => 'merged',
+ ),
+ ),
+ 'formatters' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ 'magic' => array(
+ 'idkfa' => array( 'xyzzy' ),
+ ),
+ ),
+ TestingAccessWrapper::newFromObject( $fixture )->config
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php b/tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php
new file mode 100644
index 00000000..44242ed2
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php
@@ -0,0 +1,64 @@
+<?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\Monolog;
+
+use MediaWikiTestCase;
+use PHPUnit_Framework_Error_Notice;
+
+class AvroFormatterTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ if ( !class_exists( 'AvroStringIO' ) ) {
+ $this->markTestSkipped( 'Avro is required for the AvroFormatterTest' );
+ }
+ parent::setUp();
+ }
+
+ public function testSchemaNotAvailable() {
+ $formatter = new AvroFormatter( array() );
+ $this->setExpectedException( 'PHPUnit_Framework_Error_Notice', "The schema for channel 'marty' is not available" );
+ $formatter->format( array( 'channel' => 'marty' ) );
+ }
+
+ public function testSchemaNotAvailableReturnValue() {
+ $formatter = new AvroFormatter( array() );
+ $noticeEnabled = PHPUnit_Framework_Error_Notice::$enabled;
+ // disable conversion of notices
+ PHPUnit_Framework_Error_Notice::$enabled = false;
+ // have to keep the user notice from being output
+ wfSuppressWarnings();
+ $res = $formatter->format( array( 'channel' => 'marty' ) );
+ wfRestoreWarnings();
+ PHPUnit_Framework_Error_Notice::$enabled = $noticeEnabled;
+ $this->assertNull( $res );
+ }
+
+ public function testDoesSomethingWhenSchemaAvailable() {
+ $formatter = new AvroFormatter( array( 'string' => array( 'type' => 'string' ) ) );
+ $res = $formatter->format( array(
+ 'channel' => 'string',
+ 'context' => 'better to be',
+ ) );
+ $this->assertNotNull( $res );
+ // basically just tell us if avro changes its string encoding
+ $this->assertEquals( base64_decode( 'GGJldHRlciB0byBiZQ==' ), $res );
+ }
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php b/tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php
new file mode 100644
index 00000000..090f439e
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php
@@ -0,0 +1,207 @@
+<?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\Monolog;
+
+use MediaWikiTestCase;
+use Monolog\Logger;
+
+// not available in the version of phpunit mw uses, so copied into repo
+require_once __DIR__ . '/../../../ConsecutiveParametersMatcher.php';
+
+class KafkaHandlerTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ if ( !class_exists( 'Monolog\Handler\AbstractProcessingHandler' )
+ || !class_exists( 'Kafka\Produce' )
+ ) {
+ $this->markTestSkipped( 'Monolog and Kafka are required for the KafkaHandlerTest' );
+ }
+
+ parent::setUp();
+ }
+
+ public function topicNamingProvider() {
+ return array(
+ array( array(), 'monolog_foo' ),
+ array( array( 'alias' => array( 'foo' => 'bar' ) ), 'bar' )
+ );
+ }
+
+ /**
+ * @dataProvider topicNamingProvider
+ */
+ public function testTopicNaming( $options, $expect ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects($this->any())
+ ->method('getAvailablePartitions')
+ ->will($this->returnValue( array( 'A' ) ) );
+ $produce->expects($this->once())
+ ->method( 'setMessages' )
+ ->with( $expect, $this->anything(), $this->anything() );
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+ }
+
+ public function swallowsExceptionsWhenRequested() {
+ return array(
+ // defaults to false
+ array( array(), true ),
+ // also try false explicitly
+ array( array( 'swallowExceptions' => false ), true ),
+ // turn it on
+ array( array( 'swallowExceptions' => true ), false ),
+ );
+ }
+
+ /**
+ * @dataProvider swallowsExceptionsWhenRequested
+ */
+ public function testGetAvailablePartitionsException( $options, $expectException ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->throwException( new \Kafka\Exception ) );
+
+ if ( $expectException ) {
+ $this->setExpectedException( 'Kafka\Exception' );
+ }
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+
+ if ( !$expectException ) {
+ $this->assertTrue( true, 'no exception was thrown' );
+ }
+ }
+
+ /**
+ * @dataProvider swallowsExceptionsWhenRequested
+ */
+ public function testSendException( $options, $expectException ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( array( 'A' ) ) );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->throwException( new \Kafka\Exception ) );
+
+ if ( $expectException ) {
+ $this->setExpectedException( 'Kafka\Exception' );
+ }
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+
+ if ( !$expectException ) {
+ $this->assertTrue( true, 'no exception was thrown' );
+ }
+ }
+
+ public function testHandlesNullFormatterResult() {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( array( 'A' ) ) );
+ $mockMethod = $produce->expects( $this->exactly( 2 ) )
+ ->method( 'setMessages' );
+ // evil hax
+ \TestingAccessWrapper::newFromObject( $mockMethod )->matcher->parametersMatcher =
+ new \PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters( array(
+ array( $this->anything(), $this->anything(), array( 'words' ) ),
+ array( $this->anything(), $this->anything(), array( 'lines' ) )
+ ) );
+
+ $formatter = $this->getMock( 'Monolog\Formatter\FormatterInterface' );
+ $formatter->expects( $this->any() )
+ ->method( 'format' )
+ ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
+
+ $handler = new KafkaHandler( $produce, array() );
+ $handler->setFormatter( $formatter );
+ for ( $i = 0; $i < 3; ++$i ) {
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+ }
+ }
+
+
+ public function testBatchHandlesNullFormatterResult() {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( array( 'A' ) ) );
+ $produce->expects( $this->once() )
+ ->method( 'setMessages' )
+ ->with( $this->anything(), $this->anything(), array( 'words', 'lines' ) );
+
+ $formatter = $this->getMock( 'Monolog\Formatter\FormatterInterface' );
+ $formatter->expects( $this->any() )
+ ->method( 'format' )
+ ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
+
+ $handler = new KafkaHandler( $produce, array() );
+ $handler->setFormatter( $formatter );
+ $handler->handleBatch( array(
+ array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ),
+ array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ),
+ array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ),
+ ) );
+ }
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php b/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php
new file mode 100644
index 00000000..be23c4a2
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php
@@ -0,0 +1,75 @@
+<?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\Monolog;
+
+use InvalidArgumentException;
+use LengthException;
+use LogicException;
+use MediaWikiTestCase;
+use TestingAccessWrapper;
+
+class LineFormatterTest extends MediaWikiTestCase {
+
+ protected function setUp() {
+ if ( !class_exists( 'Monolog\Formatter\LineFormatter' ) ) {
+ $this->markTestSkipped( 'This test requires monolog to be installed' );
+ }
+ parent::setUp();
+ }
+
+ /**
+ * @covers LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionNoTrace() {
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( false );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new LogicException( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
+ $this->assertNotContains( "\n #0", $out );
+ }
+
+ /**
+ * @covers LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionTrace() {
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( true );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new LogicException( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
+ $this->assertContains( "\n #0", $out );
+ }
+}
diff --git a/tests/phpunit/includes/deferred/DeferredUpdatesTest.php b/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
index 5348c854..df4213ab 100644
--- a/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
+++ b/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
@@ -1,8 +1,9 @@
<?php
class DeferredUpdatesTest extends MediaWikiTestCase {
+ public function testDoUpdatesWeb() {
+ $this->setMwGlobals( 'wgCommandLineMode', false );
- public function testDoUpdates() {
$updates = array(
'1' => 'deferred update 1',
'2' => 'deferred update 2',
@@ -35,4 +36,38 @@ class DeferredUpdatesTest extends MediaWikiTestCase {
DeferredUpdates::doUpdates();
}
+ public function testDoUpdatesCLI() {
+ $this->setMwGlobals( 'wgCommandLineMode', true );
+
+ $updates = array(
+ '1' => 'deferred update 1',
+ '2' => 'deferred update 2',
+ '2-1' => 'deferred update 1 within deferred update 2',
+ '3' => 'deferred update 3',
+ );
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates['1'];
+ }
+ );
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates['2'];
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates['2-1'];
+ }
+ );
+ }
+ );
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates[3];
+ }
+ );
+
+ $this->expectOutputString( implode( '', $updates ) );
+
+ DeferredUpdates::doUpdates();
+ }
}
diff --git a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
index 3bea9b31..a546bec1 100644
--- a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
+++ b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
@@ -69,11 +69,11 @@ class ArrayDiffFormatterTest extends MediaWikiTestCase {
$otherTestCases = array();
$otherTestCases[] = array(
- $this->getMockDiff( array( $this->getMockDiffOp( 'add', array( ), array( 'a1' ) ) ) ),
+ $this->getMockDiff( array( $this->getMockDiffOp( 'add', array(), array( 'a1' ) ) ) ),
array( array( 'action' => 'add', 'new' => 'a1', 'newline' => 1 ) ),
);
$otherTestCases[] = array(
- $this->getMockDiff( array( $this->getMockDiffOp( 'add', array( ), array( 'a1', 'a2' ) ) ) ),
+ $this->getMockDiff( array( $this->getMockDiffOp( 'add', array(), array( 'a1', 'a2' ) ) ) ),
array(
array( 'action' => 'add', 'new' => 'a1', 'newline' => 1 ),
array( 'action' => 'add', 'new' => 'a2', 'newline' => 2 ),
diff --git a/tests/phpunit/includes/exception/HttpErrorTest.php b/tests/phpunit/includes/exception/HttpErrorTest.php
new file mode 100644
index 00000000..66fe90c9
--- /dev/null
+++ b/tests/phpunit/includes/exception/HttpErrorTest.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @todo tests for HttpError::report
+ *
+ * @covers HttpError
+ */
+class HttpErrorTest extends MediaWikiTestCase {
+
+ public function testIsLoggable() {
+ $httpError = new HttpError( 500, 'server error!' );
+ $this->assertFalse( $httpError->isLoggable(), 'http error is not loggable' );
+ }
+
+ public function testGetStatusCode() {
+ $httpError = new HttpError( 500, 'server error!' );
+ $this->assertEquals( 500, $httpError->getStatusCode() );
+ }
+
+ /**
+ * @dataProvider getHtmlProvider
+ */
+ public function testGetHtml( array $expected, $content, $header ) {
+ $httpError = new HttpError( 500, $content, $header );
+ $errorHtml = $httpError->getHtml();
+
+ foreach ( $expected as $key => $html ) {
+ $this->assertContains( $html, $errorHtml, $key );
+ }
+ }
+
+ public function getHtmlProvider() {
+ return array(
+ array(
+ array(
+ 'head html' => '<head><title>Server Error 123</title></head>',
+ 'body html' => '<body><h1>Server Error 123</h1>'
+ . '<p>a server error!</p></body>'
+ ),
+ 'a server error!',
+ 'Server Error 123'
+ ),
+ array(
+ array(
+ 'head html' => '<head><title>loginerror</title></head>',
+ 'body html' => '<body><h1>loginerror</h1>'
+ . '<p>suspicious-userlogout</p></body>'
+ ),
+ new RawMessage( 'suspicious-userlogout' ),
+ new RawMessage( 'loginerror' )
+ ),
+ array(
+ array(
+ 'head html' => '<html><head><title>Internal Server Error</title></head>',
+ 'body html' => '<body><h1>Internal Server Error</h1>'
+ . '<p>a server error!</p></body></html>'
+ ),
+ 'a server error!',
+ null
+ )
+ );
+ }
+
+
+}
diff --git a/tests/phpunit/includes/exception/MWExceptionTest.php b/tests/phpunit/includes/exception/MWExceptionTest.php
index ef0f2a9e..f11fda32 100644
--- a/tests/phpunit/includes/exception/MWExceptionTest.php
+++ b/tests/phpunit/includes/exception/MWExceptionTest.php
@@ -178,7 +178,7 @@ class MWExceptionTest extends MediaWikiTestCase {
$this->setMwGlobals( array( 'wgLogExceptionBacktrace' => true ) );
$json = json_decode(
- MWExceptionHandler::jsonSerializeException( new $exClass())
+ MWExceptionHandler::jsonSerializeException( new $exClass() )
);
$this->assertObjectHasAttribute( $key, $json,
"JSON serialized exception is missing key '$key'"
diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php b/tests/phpunit/includes/filebackend/FileBackendTest.php
index bfca75ad..2e4942f0 100644
--- a/tests/phpunit/includes/filebackend/FileBackendTest.php
+++ b/tests/phpunit/includes/filebackend/FileBackendTest.php
@@ -2376,7 +2376,7 @@ class FileBackendTest extends MediaWikiTestCase {
$status = Status::newGood();
$sl = $this->backend->getScopedFileLocks( $paths, LockManager::LOCK_EX, $status );
- $this->assertType( 'ScopedLock', $sl,
+ $this->assertInstanceOf( 'ScopedLock', $sl,
"Scoped locking of files succeeded ($backendName)." );
$this->assertEquals( array(), $status->errors,
"Scoped locking of files succeeded ($backendName)." );
@@ -2392,6 +2392,56 @@ class FileBackendTest extends MediaWikiTestCase {
"Scoped unlocking of files succeeded with OK status ($backendName)." );
}
+ public function testReadAffinity() {
+ $be = TestingAccessWrapper::newFromObject(
+ new FileBackendMultiWrite( array(
+ 'name' => 'localtesting',
+ 'wikiId' => wfWikiId() . mt_rand(),
+ 'backends' => array(
+ array( // backend 0
+ 'name' => 'multitesting0',
+ 'class' => 'MemoryFileBackend',
+ 'isMultiMaster' => false,
+ 'readAffinity' => true
+ ),
+ array( // backend 1
+ 'name' => 'multitesting1',
+ 'class' => 'MemoryFileBackend',
+ 'isMultiMaster' => true
+ )
+ )
+ ) )
+ );
+
+ $this->assertEquals(
+ 1,
+ $be->getReadIndexFromParams( array( 'latest' => 1 ) ),
+ 'Reads with "latest" flag use backend 1'
+ );
+ $this->assertEquals(
+ 0,
+ $be->getReadIndexFromParams( array( 'latest' => 0 ) ),
+ 'Reads without "latest" flag use backend 0'
+ );
+
+ $p = 'container/test-cont/file.txt';
+ $be->backends[0]->quickCreate( array(
+ 'dst' => "mwstore://multitesting0/$p", 'content' => 'cattitude' ) );
+ $be->backends[1]->quickCreate( array(
+ 'dst' => "mwstore://multitesting1/$p", 'content' => 'princess of power' ) );
+
+ $this->assertEquals(
+ 'cattitude',
+ $be->getFileContents( array( 'src' => "mwstore://localtesting/$p" ) ),
+ "Non-latest read came from backend 0"
+ );
+ $this->assertEquals(
+ 'princess of power',
+ $be->getFileContents( array( 'src' => "mwstore://localtesting/$p", 'latest' => 1 ) ),
+ "Latest read came from backend1"
+ );
+ }
+
// helper function
private function listToArray( $iter ) {
return is_array( $iter ) ? $iter : iterator_to_array( $iter );
diff --git a/tests/phpunit/includes/filebackend/SwiftFileBackendTest.php b/tests/phpunit/includes/filebackend/SwiftFileBackendTest.php
new file mode 100644
index 00000000..a618889c
--- /dev/null
+++ b/tests/phpunit/includes/filebackend/SwiftFileBackendTest.php
@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * @group FileRepo
+ * @group FileBackend
+ * @group medium
+ */
+class SwiftFileBackendTest extends MediaWikiTestCase {
+ /** @var TestingAccessWrapper Proxy to SwiftFileBackend */
+ private $backend;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->backend = TestingAccessWrapper::newFromObject(
+ new SwiftFileBackend( array(
+ 'name' => 'local-swift-testing',
+ 'class' => 'SwiftFileBackend',
+ 'wikiId' => 'unit-testing',
+ 'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
+ 'swiftAuthUrl' => 'http://127.0.0.1:8080/auth', // unused
+ 'swiftUser' => 'test:tester',
+ 'swiftKey' => 'testing',
+ 'swiftTempUrlKey' => 'b3968d0207b54ece87cccc06515a89d4' // unused
+ ) )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testSanitzeHdrs
+ * @covers SwiftFileBackend::sanitzeHdrs
+ * @covers SwiftFileBackend::getCustomHeaders
+ */
+ public function testSanitzeHdrs( $raw, $sanitized ) {
+ $hdrs = $this->backend->sanitizeHdrs( array( 'headers' => $raw ) );
+
+ $this->assertEquals( $hdrs, $sanitized, 'sanitizeHdrs() has expected result' );
+ }
+
+ public static function provider_testSanitzeHdrs() {
+ return array(
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-type' => 'image+bitmap/jpeg',
+ 'content-disposition' => 'inline',
+ 'content-duration' => 35.6363,
+ 'content-Custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ ),
+ array(
+ 'content-disposition' => 'inline',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ )
+ ),
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-type' => 'image+bitmap/jpeg',
+ 'content-Disposition' => 'inline; filename=xxx; ' . str_repeat( 'o', 1024 ),
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ ),
+ array(
+ 'content-disposition' => 'inline;filename=xxx',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ )
+ ),
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-type' => 'image+bitmap/jpeg',
+ 'content-disposition' => 'filename='. str_repeat( 'o', 1024 ) . ';inline',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ ),
+ array(
+ 'content-disposition' => '',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testGetMetadataHeaders
+ * @covers SwiftFileBackend::getMetadataHeaders
+ */
+ public function testGetMetadataHeaders( $raw, $sanitized ) {
+ $hdrs = $this->backend->getMetadataHeaders( $raw );
+
+ $this->assertEquals( $hdrs, $sanitized, 'getMetadataHeaders() has expected result' );
+ }
+
+ public static function provider_testGetMetadataHeaders() {
+ return array(
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello',
+ 'x-object-meta-custom' => 5,
+ 'x-object-meta-sha1Base36' => 'a3deadfg...',
+ ),
+ array(
+ 'x-object-meta-custom' => 5,
+ 'x-object-meta-sha1base36' => 'a3deadfg...',
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testGetMetadata
+ * @covers SwiftFileBackend::getMetadata
+ */
+ public function testGetMetadata( $raw, $sanitized ) {
+ $hdrs = $this->backend->getMetadata( $raw );
+
+ $this->assertEquals( $hdrs, $sanitized, 'getMetadata() has expected result' );
+ }
+
+ public static function provider_testGetMetadata() {
+ return array(
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello',
+ 'x-object-meta-custom' => 5,
+ 'x-object-meta-sha1Base36' => 'a3deadfg...',
+ ),
+ array(
+ 'custom' => 5,
+ 'sha1base36' => 'a3deadfg...',
+ )
+ )
+ );
+ }
+} \ No newline at end of file
diff --git a/tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php b/tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php
new file mode 100644
index 00000000..681e3681
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php
@@ -0,0 +1,138 @@
+<?php
+
+class FileBackendDBRepoWrapperTest extends MediaWikiTestCase {
+ protected $backendName = 'foo-backend';
+ protected $repoName = 'pureTestRepo';
+
+ /**
+ * @dataProvider getBackendPathsProvider
+ * @covers FileBackendDBRepoWrapper::getBackendPaths
+ */
+ public function testGetBackendPaths(
+ $mocks,
+ $latest,
+ $dbReadsExpected,
+ $dbReturnValue,
+ $originalPath,
+ $expectedBackendPath,
+ $message ) {
+ list( $dbMock, $backendMock, $wrapperMock ) = $mocks;
+
+ $dbMock->expects( $dbReadsExpected )
+ ->method( 'selectField' )
+ ->will( $this->returnValue( $dbReturnValue ) );
+
+ $newPaths = $wrapperMock->getBackendPaths( array( $originalPath ), $latest );
+
+ $this->assertEquals(
+ $expectedBackendPath,
+ $newPaths[0],
+ $message );
+ }
+
+ public function getBackendPathsProvider() {
+ $prefix = 'mwstore://' . $this->backendName . '/' . $this->repoName;
+ $mocksForCaching = $this->getMocks();
+
+ return array(
+ array(
+ $mocksForCaching,
+ false,
+ $this->once(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'Public path translated correctly',
+ ),
+ array(
+ $mocksForCaching,
+ false,
+ $this->never(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'LRU cache leveraged',
+ ),
+ array(
+ $this->getMocks(),
+ true,
+ $this->once(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'Latest obtained',
+ ),
+ array(
+ $this->getMocks(),
+ true,
+ $this->never(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-deleted/f/o/foobar.jpg',
+ $prefix . '-original/f/o/o/foobar',
+ 'Deleted path translated correctly',
+ ),
+ array(
+ $this->getMocks(),
+ true,
+ $this->once(),
+ null,
+ $prefix . '-public/b/a/baz.jpg',
+ $prefix . '-public/b/a/baz.jpg',
+ 'Path left untouched if no sha1 can be found',
+ ),
+ );
+ }
+
+ /**
+ * @covers FileBackendDBRepoWrapper::getFileContentsMulti
+ */
+ public function testGetFileContentsMulti() {
+ list( $dbMock, $backendMock, $wrapperMock ) = $this->getMocks();
+
+ $sha1Path = 'mwstore://' . $this->backendName . '/' . $this->repoName
+ . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9';
+ $filenamePath = 'mwstore://' . $this->backendName . '/' . $this->repoName
+ . '-public/f/o/foobar.jpg';
+
+ $dbMock->expects( $this->once() )
+ ->method( 'selectField' )
+ ->will( $this->returnValue( '96246614d75ba1703bdfd5d7660bb57407aaf5d9' ) );
+
+ $backendMock->expects( $this->once() )
+ ->method( 'getFileContentsMulti')
+ ->will( $this->returnValue( array( $sha1Path => 'foo' ) ) );
+
+ $result = $wrapperMock->getFileContentsMulti( array( 'srcs' => array( $filenamePath ) ) );
+
+ $this->assertEquals(
+ array( $filenamePath => 'foo' ),
+ $result,
+ 'File contents paths translated properly'
+ );
+ }
+
+ protected function getMocks() {
+ $dbMock = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $backendMock = $this->getMock( 'FSFileBackend',
+ array(),
+ array( array(
+ 'name' => $this->backendName,
+ 'wikiId' => wfWikiId()
+ ) ) );
+
+ $wrapperMock = $this->getMock( 'FileBackendDBRepoWrapper',
+ array( 'getDB' ),
+ array( array(
+ 'backend' => $backendMock,
+ 'repoName' => $this->repoName,
+ 'dbHandleFactory' => null
+ ) ) );
+
+ $wrapperMock->expects( $this->any() )->method( 'getDB' )->will( $this->returnValue( $dbMock ) );
+
+ return array( $dbMock, $backendMock, $wrapperMock );
+ }
+}
diff --git a/tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php b/tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
new file mode 100644
index 00000000..551d3a76
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
@@ -0,0 +1,114 @@
+<?php
+
+class MigrateFileRepoLayoutTest extends MediaWikiTestCase {
+ protected $tmpPrefix;
+ protected $migratorMock;
+ protected $tmpFilepath;
+ protected $text = 'testing';
+
+ protected function setUp() {
+ parent::setUp();
+
+ $filename = 'Foo.png';
+
+ $this->tmpPrefix = wfTempDir() . '/migratefilelayout-test-' . time() . '-' . mt_rand();
+
+ $backend = new FSFileBackend( array(
+ 'name' => 'local-migratefilerepolayouttest',
+ 'wikiId' => wfWikiID(),
+ 'containerPaths' => array(
+ 'migratefilerepolayouttest-original' => "{$this->tmpPrefix}-original",
+ 'migratefilerepolayouttest-public' => "{$this->tmpPrefix}-public",
+ 'migratefilerepolayouttest-thumb' => "{$this->tmpPrefix}-thumb",
+ 'migratefilerepolayouttest-temp' => "{$this->tmpPrefix}-temp",
+ 'migratefilerepolayouttest-deleted' => "{$this->tmpPrefix}-deleted",
+ )
+ ) );
+
+ $dbMock = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $imageRow = new stdClass;
+ $imageRow->img_name = $filename;
+ $imageRow->img_sha1 = sha1( $this->text );
+
+ $dbMock->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->onConsecutiveCalls(
+ new FakeResultWrapper( array( $imageRow ) ), // image
+ new FakeResultWrapper( array() ), // image
+ new FakeResultWrapper( array() ) // filearchive
+ ) );
+
+ $repoMock = $this->getMock( 'LocalRepo',
+ array( 'getMasterDB' ),
+ array( array(
+ 'name' => 'migratefilerepolayouttest',
+ 'backend' => $backend
+ ) ) );
+
+ $repoMock->expects( $this->any() )->method( 'getMasterDB' )->will( $this->returnValue( $dbMock ) );
+
+ $this->migratorMock = $this->getMock( 'MigrateFileRepoLayout', array( 'getRepo' ) );
+ $this->migratorMock->expects( $this->any() )->method( 'getRepo' )->will( $this->returnValue( $repoMock ) );
+
+ $this->tmpFilepath = TempFSFile::factory( 'migratefilelayout-test-', 'png' )->getPath();
+
+ file_put_contents( $this->tmpFilepath, $this->text );
+
+ $hashPath = $repoMock->getHashPath( $filename );
+
+ $status = $repoMock->store( $this->tmpFilepath, 'public', $hashPath . $filename, FileRepo::OVERWRITE );
+ }
+
+ protected function deleteFilesRecursively( $directory ) {
+ foreach ( glob( $directory . '/*' ) as $file ) {
+ if ( is_dir( $file ) ) {
+ $this->deleteFilesRecursively( $file );
+ } else {
+ unlink( $file );
+ }
+ }
+
+ rmdir( $directory );
+ }
+
+ protected function tearDown() {
+ foreach ( glob( $this->tmpPrefix . '*' ) as $directory ) {
+ $this->deleteFilesRecursively( $directory );
+ }
+
+ unlink( $this->tmpFilepath );
+
+ parent::tearDown();
+ }
+
+ public function testMigration() {
+ $this->migratorMock->loadParamsAndArgs( null, array( 'oldlayout' => 'name', 'newlayout' => 'sha1' ) );
+
+ ob_start();
+
+ $this->migratorMock->execute();
+
+ ob_end_clean();
+
+ $sha1 = sha1( $this->text );
+
+ $expectedOriginalFilepath = $this->tmpPrefix
+ . '-original/'
+ . substr( $sha1, 0, 1 )
+ . '/'
+ . substr( $sha1, 1, 1 )
+ . '/'
+ . substr( $sha1, 2, 1 )
+ . '/'
+ . $sha1 ;
+
+ $this->assertEquals( file_get_contents( $expectedOriginalFilepath ), $this->text, 'New sha1 file should be exist and have the right contents' );
+
+ $expectedPublicFilepath = $this->tmpPrefix . '-public/f/f8/Foo.png';
+
+ $this->assertEquals( file_get_contents( $expectedPublicFilepath ), $this->text, 'Existing name file should still and have the right contents' );
+ }
+}
diff --git a/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php b/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php
index 2c7f50c9..3b5347cd 100644
--- a/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php
+++ b/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php
@@ -6,7 +6,7 @@
*/
class HtmlAutoCompleteSelectFieldTest extends MediaWikiTestCase {
- var $options = array(
+ public $options = array(
'Bulgaria' => 'BGR',
'Burkina Faso' => 'BFA',
'Burundi' => 'BDI',
diff --git a/tests/phpunit/includes/json/FormatJsonTest.php b/tests/phpunit/includes/json/FormatJsonTest.php
index f0ac6acc..8bca3331 100644
--- a/tests/phpunit/includes/json/FormatJsonTest.php
+++ b/tests/phpunit/includes/json/FormatJsonTest.php
@@ -159,12 +159,12 @@ class FormatJsonTest extends MediaWikiTestCase {
$this->assertJson( $json );
$st = FormatJson::parse( $json );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertTrue( $st->isGood() );
$this->assertEquals( $expected, $st->getValue() );
$st = FormatJson::parse( $json, FormatJson::FORCE_ASSOC );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertTrue( $st->isGood() );
$this->assertEquals( $value, $st->getValue() );
}
@@ -230,7 +230,7 @@ class FormatJsonTest extends MediaWikiTestCase {
}
$st = FormatJson::parse( $value, FormatJson::TRY_FIXING );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
if ( $expected === false ) {
$this->assertFalse( $st->isOK(), 'Expected isOK() == false' );
} else {
@@ -256,7 +256,7 @@ class FormatJsonTest extends MediaWikiTestCase {
*/
public function testParseErrors( $value ) {
$st = FormatJson::parse( $value );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertFalse( $st->isOK() );
}
@@ -313,7 +313,7 @@ class FormatJsonTest extends MediaWikiTestCase {
*/
public function testParseStripComments( $json, $expect ) {
$st = FormatJson::parse( $json, FormatJson::STRIP_COMMENTS );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertTrue( $st->isGood() );
$this->assertEquals( $expect, $st->getValue() );
}
diff --git a/tests/phpunit/includes/libs/ArrayUtilsTest.php b/tests/phpunit/includes/libs/ArrayUtilsTest.php
index b5ea7b72..32b150c7 100644
--- a/tests/phpunit/includes/libs/ArrayUtilsTest.php
+++ b/tests/phpunit/includes/libs/ArrayUtilsTest.php
@@ -23,11 +23,11 @@ class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
}
function provideFindLowerBound() {
- $self = $this;
- $indexValueCallback = function ( $size ) use ( $self ) {
- return function ( $val ) use ( $self, $size ) {
- $self->assertTrue( $val >= 0 );
- $self->assertTrue( $val < $size );
+ $that = $this;
+ $indexValueCallback = function ( $size ) use ( $that ) {
+ return function ( $val ) use ( $that, $size ) {
+ $that->assertTrue( $val >= 0 );
+ $that->assertTrue( $val < $size );
return $val;
};
};
@@ -212,7 +212,7 @@ class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
array(),
array( 1 => 1 ),
array( 1 ),
- array( 1 => 1),
+ array( 1 => 1 ),
),
array(
array(),
diff --git a/tests/phpunit/includes/libs/CSSMinTest.php b/tests/phpunit/includes/libs/CSSMinTest.php
index 6142f967..7841f30f 100644
--- a/tests/phpunit/includes/libs/CSSMinTest.php
+++ b/tests/phpunit/includes/libs/CSSMinTest.php
@@ -102,12 +102,12 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Without trailing slash',
array( 'foo { prop: url(../bar.png); }', false, 'http://example.org/quux', false ),
- 'foo { prop: url(http://example.org/quux/../bar.png); }',
+ 'foo { prop: url(http://example.org/bar.png); }',
),
array(
'With trailing slash on remote (bug 27052)',
array( 'foo { prop: url(../bar.png); }', false, 'http://example.org/quux/', false ),
- 'foo { prop: url(http://example.org/quux/../bar.png); }',
+ 'foo { prop: url(http://example.org/bar.png); }',
),
array(
'Guard against stripping double slashes from query',
@@ -133,12 +133,7 @@ class CSSMinTest extends MediaWikiTestCase {
$remotePath = 'http://localhost/w/';
$realOutput = CSSMin::remap( $input, $localPath, $remotePath );
-
- $this->assertEquals(
- $expectedOutput,
- preg_replace( '/\d+-\d+-\d+T\d+:\d+:\d+Z/', 'timestamp', $realOutput ),
- "CSSMin::remap: $message"
- );
+ $this->assertEquals( $expectedOutput, $realOutput, "CSSMin::remap: $message" );
}
public static function provideIsRemoteUrl() {
@@ -197,7 +192,7 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Regular file',
'foo { background: url(red.gif); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6); }',
),
array(
'Regular file (missing)',
@@ -242,12 +237,12 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Embedded file',
'foo { /* @embed */ background: url(red.gif); }',
- "foo { background: url($red); background: url(http://localhost/w/red.gif?timestamp)!ie; }",
+ "foo { background: url($red); background: url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Embedded file, other comments before the rule',
"foo { /* Bar. */ /* @embed */ background: url(red.gif); }",
- "foo { /* Bar. */ background: url($red); /* Bar. */ background: url(http://localhost/w/red.gif?timestamp)!ie; }",
+ "foo { /* Bar. */ background: url($red); /* Bar. */ background: url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Can not re-embed data: URIs',
@@ -268,12 +263,12 @@ class CSSMinTest extends MediaWikiTestCase {
'Embedded file (inline @embed)',
'foo { background: /* @embed */ url(red.gif); }',
"foo { background: url($red); "
- . "background: url(http://localhost/w/red.gif?timestamp)!ie; }",
+ . "background: url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Can not embed large files',
'foo { /* @embed */ background: url(large.png); }',
- "foo { background: url(http://localhost/w/large.png?timestamp); }",
+ "foo { background: url(http://localhost/w/large.png?e3d1f); }",
),
array(
'SVG files are embedded without base64 encoding and unnecessary IE 6 and 7 fallback',
@@ -283,55 +278,55 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Two regular files in one rule',
'foo { background: url(red.gif), url(green.gif); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp), '
- . 'url(http://localhost/w/green.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6), '
+ . 'url(http://localhost/w/green.gif?13651); }',
),
array(
'Two embedded files in one rule',
'foo { /* @embed */ background: url(red.gif), url(green.gif); }',
"foo { background: url($red), url($green); "
- . "background: url(http://localhost/w/red.gif?timestamp), "
- . "url(http://localhost/w/green.gif?timestamp)!ie; }",
+ . "background: url(http://localhost/w/red.gif?34ac6), "
+ . "url(http://localhost/w/green.gif?13651)!ie; }",
),
array(
'Two embedded files in one rule (inline @embed)',
'foo { background: /* @embed */ url(red.gif), /* @embed */ url(green.gif); }',
"foo { background: url($red), url($green); "
- . "background: url(http://localhost/w/red.gif?timestamp), "
- . "url(http://localhost/w/green.gif?timestamp)!ie; }",
+ . "background: url(http://localhost/w/red.gif?34ac6), "
+ . "url(http://localhost/w/green.gif?13651)!ie; }",
),
array(
'Two embedded files in one rule (inline @embed), one too large',
'foo { background: /* @embed */ url(red.gif), /* @embed */ url(large.png); }',
- "foo { background: url($red), url(http://localhost/w/large.png?timestamp); "
- . "background: url(http://localhost/w/red.gif?timestamp), "
- . "url(http://localhost/w/large.png?timestamp)!ie; }",
+ "foo { background: url($red), url(http://localhost/w/large.png?e3d1f); "
+ . "background: url(http://localhost/w/red.gif?34ac6), "
+ . "url(http://localhost/w/large.png?e3d1f)!ie; }",
),
array(
'Practical example with some noise',
'foo { /* @embed */ background: #f9f9f9 url(red.gif) 0 0 no-repeat; }',
"foo { background: #f9f9f9 url($red) 0 0 no-repeat; "
- . "background: #f9f9f9 url(http://localhost/w/red.gif?timestamp) 0 0 no-repeat!ie; }",
+ . "background: #f9f9f9 url(http://localhost/w/red.gif?34ac6) 0 0 no-repeat!ie; }",
),
array(
'Does not mess with other properties',
'foo { color: red; background: url(red.gif); font-size: small; }',
- 'foo { color: red; background: url(http://localhost/w/red.gif?timestamp); font-size: small; }',
+ 'foo { color: red; background: url(http://localhost/w/red.gif?34ac6); font-size: small; }',
),
array(
'Spacing and miscellanea not changed (1)',
'foo { background: url(red.gif); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6); }',
),
array(
'Spacing and miscellanea not changed (2)',
'foo {background:url(red.gif)}',
- 'foo {background:url(http://localhost/w/red.gif?timestamp)}',
+ 'foo {background:url(http://localhost/w/red.gif?34ac6)}',
),
array(
'Spaces within url() parentheses are ignored',
'foo { background: url( red.gif ); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6); }',
),
array(
'@import rule to local file (should we remap this?)',
@@ -351,22 +346,22 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Simple case with comments after url',
'foo { prop: url(red.gif)/* some {funny;} comment */ ; }',
- 'foo { prop: url(http://localhost/w/red.gif?timestamp)/* some {funny;} comment */ ; }',
+ 'foo { prop: url(http://localhost/w/red.gif?34ac6)/* some {funny;} comment */ ; }',
),
array(
'Embedded file with comment before url',
'foo { /* @embed */ background: /* some {funny;} comment */ url(red.gif); }',
- "foo { background: /* some {funny;} comment */ url($red); background: /* some {funny;} comment */ url(http://localhost/w/red.gif?timestamp)!ie; }",
+ "foo { background: /* some {funny;} comment */ url($red); background: /* some {funny;} comment */ url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Embedded file with comments inside and outside the rule',
'foo { /* @embed */ background: url(red.gif) /* some {foo;} comment */; /* some {bar;} comment */ }',
- "foo { background: url($red) /* some {foo;} comment */; background: url(http://localhost/w/red.gif?timestamp) /* some {foo;} comment */!ie; /* some {bar;} comment */ }",
+ "foo { background: url($red) /* some {foo;} comment */; background: url(http://localhost/w/red.gif?34ac6) /* some {foo;} comment */!ie; /* some {bar;} comment */ }",
),
array(
'Embedded file with comment outside the rule',
'foo { /* @embed */ background: url(red.gif); /* some {funny;} comment */ }',
- "foo { background: url($red); background: url(http://localhost/w/red.gif?timestamp)!ie; /* some {funny;} comment */ }",
+ "foo { background: url($red); background: url(http://localhost/w/red.gif?34ac6)!ie; /* some {funny;} comment */ }",
),
array(
'Rule with two urls, each with comments',
diff --git a/tests/phpunit/includes/libs/IEUrlExtensionTest.php b/tests/phpunit/includes/libs/IEUrlExtensionTest.php
index e96953ee..57668e50 100644
--- a/tests/phpunit/includes/libs/IEUrlExtensionTest.php
+++ b/tests/phpunit/includes/libs/IEUrlExtensionTest.php
@@ -170,4 +170,37 @@ class IEUrlExtensionTest extends PHPUnit_Framework_TestCase {
'Two dots'
);
}
+
+ /**
+ * @covers IEUrlExtension::findIE6Extension
+ */
+ public function testScriptQuery() {
+ $this->assertEquals(
+ 'php',
+ IEUrlExtension::findIE6Extension( 'example.php?foo=a&bar=b' ),
+ 'Script with query'
+ );
+ }
+
+ /**
+ * @covers IEUrlExtension::findIE6Extension
+ */
+ public function testEscapedScriptQuery() {
+ $this->assertEquals(
+ '',
+ IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a&bar=b' ),
+ 'Script with urlencoded dot and query'
+ );
+ }
+
+ /**
+ * @covers IEUrlExtension::findIE6Extension
+ */
+ public function testEscapedScriptQueryDot() {
+ $this->assertEquals(
+ 'y',
+ IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a.x&bar=b.y' ),
+ 'Script with urlencoded dot and query with dot'
+ );
+ }
}
diff --git a/tests/phpunit/includes/libs/IPSetTest.php b/tests/phpunit/includes/libs/IPSetTest.php
deleted file mode 100644
index 5bbacef4..00000000
--- a/tests/phpunit/includes/libs/IPSetTest.php
+++ /dev/null
@@ -1,252 +0,0 @@
-<?php
-
-/**
- * @group IPSet
- */
-class IPSetTest extends PHPUnit_Framework_TestCase {
- /**
- * Provides test cases for IPSetTest::testIPSet
- *
- * Returns an array of test cases. Each case is an array of (description,
- * config, tests). Description is just text output for failure messages,
- * config is an array constructor argument for IPSet, and the tests are
- * an array of IP => expected (boolean) result against the config dataset.
- */
- public static function provideIPSets() {
- return array(
- array(
- 'old_list_subset',
- array(
- '208.80.152.162',
- '10.64.0.123',
- '10.64.0.124',
- '10.64.0.125',
- '10.64.0.126',
- '10.64.0.127',
- '10.64.0.128',
- '10.64.0.129',
- '10.64.32.104',
- '10.64.32.105',
- '10.64.32.106',
- '10.64.32.107',
- '91.198.174.45',
- '91.198.174.46',
- '91.198.174.47',
- '91.198.174.57',
- '2620:0:862:1:A6BA:DBFF:FE30:CFB3',
- '91.198.174.58',
- '2620:0:862:1:A6BA:DBFF:FE38:FFDA',
- '208.80.152.16',
- '208.80.152.17',
- '208.80.152.18',
- '208.80.152.19',
- '91.198.174.102',
- '91.198.174.103',
- '91.198.174.104',
- '91.198.174.105',
- '91.198.174.106',
- '91.198.174.107',
- '91.198.174.81',
- '2620:0:862:1:26B6:FDFF:FEF5:B2D4',
- '91.198.174.82',
- '2620:0:862:1:26B6:FDFF:FEF5:ABB4',
- '10.20.0.113',
- '2620:0:862:102:26B6:FDFF:FEF5:AD9C',
- '10.20.0.114',
- '2620:0:862:102:26B6:FDFF:FEF5:7C38',
- ),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '10.64.0.122' => false,
- '10.64.0.123' => true,
- '10.64.0.124' => true,
- '10.64.0.129' => true,
- '10.64.0.130' => false,
- '91.198.174.81' => true,
- '91.198.174.80' => false,
- '0::0' => false,
- 'ffff:ffff:ffff:ffff:FFFF:FFFF:FFFF:FFFF' => false,
- '2001:db8::1234' => false,
- '2620:0:862:1:26b6:fdff:fef5:abb3' => false,
- '2620:0:862:1:26b6:fdff:fef5:abb4' => true,
- '2620:0:862:1:26b6:fdff:fef5:abb5' => false,
- ),
- ),
- array(
- 'new_cidr_set',
- array(
- '208.80.154.0/26',
- '2620:0:861:1::/64',
- '208.80.154.128/26',
- '2620:0:861:2::/64',
- '208.80.154.64/26',
- '2620:0:861:3::/64',
- '208.80.155.96/27',
- '2620:0:861:4::/64',
- '10.64.0.0/22',
- '2620:0:861:101::/64',
- '10.64.16.0/22',
- '2620:0:861:102::/64',
- '10.64.32.0/22',
- '2620:0:861:103::/64',
- '10.64.48.0/22',
- '2620:0:861:107::/64',
- '91.198.174.0/25',
- '2620:0:862:1::/64',
- '10.20.0.0/24',
- '2620:0:862:102::/64',
- '10.128.0.0/24',
- '2620:0:863:101::/64',
- '10.2.4.26',
- ),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '10.2.4.25' => false,
- '10.2.4.26' => true,
- '10.2.4.27' => false,
- '10.20.0.255' => true,
- '10.128.0.0' => true,
- '10.64.17.55' => true,
- '10.64.20.0' => false,
- '10.64.27.207' => false,
- '10.64.31.255' => false,
- '0::0' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => false,
- '2001:DB8::1' => false,
- '2620:0:861:106::45' => false,
- '2620:0:862:103::' => false,
- '2620:0:862:102:10:20:0:113' => true,
- ),
- ),
- array(
- 'empty_set',
- array(),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '10.2.4.25' => false,
- '10.2.4.26' => false,
- '10.2.4.27' => false,
- '10.20.0.255' => false,
- '10.128.0.0' => false,
- '10.64.17.55' => false,
- '10.64.20.0' => false,
- '10.64.27.207' => false,
- '10.64.31.255' => false,
- '0::0' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => false,
- '2001:DB8::1' => false,
- '2620:0:861:106::45' => false,
- '2620:0:862:103::' => false,
- '2620:0:862:102:10:20:0:113' => false,
- ),
- ),
- array(
- 'edge_cases',
- array(
- '0.0.0.0',
- '255.255.255.255',
- '::',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
- '10.10.10.10/25', // host bits intentional
- ),
- array(
- '0.0.0.0' => true,
- '255.255.255.255' => true,
- '10.2.4.25' => false,
- '10.2.4.26' => false,
- '10.2.4.27' => false,
- '10.20.0.255' => false,
- '10.128.0.0' => false,
- '10.64.17.55' => false,
- '10.64.20.0' => false,
- '10.64.27.207' => false,
- '10.64.31.255' => false,
- '0::0' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => true,
- '2001:DB8::1' => false,
- '2620:0:861:106::45' => false,
- '2620:0:862:103::' => false,
- '2620:0:862:102:10:20:0:113' => false,
- '10.10.9.255' => false,
- '10.10.10.0' => true,
- '10.10.10.1' => true,
- '10.10.10.10' => true,
- '10.10.10.126' => true,
- '10.10.10.127' => true,
- '10.10.10.128' => false,
- '10.10.10.177' => false,
- '10.10.10.255' => false,
- '10.10.11.0' => false,
- ),
- ),
- array(
- 'exercise_optimizer',
- array(
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffd:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffb:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffa:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff9:8000/113',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff9:0/113',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff7:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff6:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff5:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff4:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff3:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff2:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff1:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffef:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffee:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffec:0/111',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffeb:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffea:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe9:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe8:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe7:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe6:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe5:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe4:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe3:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe2:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe1:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/110',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/107',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffa0:0/107',
- ),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '::' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ff9f:ffff' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffa0:0' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffc0:1234' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffed:ffff' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff4:4444' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff9:8080' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => true,
- ),
- ),
- );
- }
-
- /**
- * Validates IPSet loading and matching code
- *
- * @covers IPSet
- * @dataProvider provideIPSets
- */
- public function testIPSet( $desc, array $cfg, array $tests ) {
- $ipset = new IPSet( $cfg );
- foreach ( $tests as $ip => $expected ) {
- $result = $ipset->match( $ip );
- $this->assertEquals( $expected, $result, "Incorrect match() result for $ip in dataset $desc" );
- }
- }
-}
diff --git a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
index 149a28c1..d23534ed 100644
--- a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
+++ b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
@@ -140,6 +140,13 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
array( "5..toString();", "5..toString();" ),
array( "5...toString();", false ),
array( "5.\n.toString();", '5..toString();' ),
+
+ // Boolean minification (!0 / !1)
+ array( "var a = { b: true };", "var a={b:!0};" ),
+ array( "var a = { true: 12 };", "var a={true:12};", false ),
+ array( "a.true = 12;", "a.true=12;", false ),
+ array( "a.foo = true;", "a.foo=!0;" ),
+ array( "a.foo = false;", "a.foo=!1;" ),
);
}
@@ -147,15 +154,17 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
* @dataProvider provideCases
* @covers JavaScriptMinifier::minify
*/
- public function testJavaScriptMinifierOutput( $code, $expectedOutput ) {
+ public function testJavaScriptMinifierOutput( $code, $expectedOutput, $expectedValid = true ) {
$minified = JavaScriptMinifier::minify( $code );
// JSMin+'s parser will throw an exception if output is not valid JS.
// suppression of warnings needed for stupid crap
- wfSuppressWarnings();
- $parser = new JSParser();
- wfRestoreWarnings();
- $parser->parse( $minified, 'minify-test.js', 1 );
+ if ( $expectedValid ) {
+ MediaWiki\suppressWarnings();
+ $parser = new JSParser();
+ MediaWiki\restoreWarnings();
+ $parser->parse( $minified, 'minify-test.js', 1 );
+ }
$this->assertEquals(
$expectedOutput,
diff --git a/tests/phpunit/includes/libs/ObjectFactoryTest.php b/tests/phpunit/includes/libs/ObjectFactoryTest.php
index 92207325..aea037e0 100644
--- a/tests/phpunit/includes/libs/ObjectFactoryTest.php
+++ b/tests/phpunit/includes/libs/ObjectFactoryTest.php
@@ -26,11 +26,20 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
public function testClosureExpansionDisabled() {
$obj = ObjectFactory::getObjectFromSpec( array(
'class' => 'ObjectFactoryTest_Fixture',
- 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'args' => array( function() {
+ return 'unwrapped';
+ }, ),
+ 'calls' => array(
+ 'setter' => array( function() {
+ return 'unwrapped';
+ }, ),
+ ),
'closure_expansion' => false,
) );
$this->assertInstanceOf( 'Closure', $obj->args[0] );
$this->assertSame( 'unwrapped', $obj->args[0]() );
+ $this->assertInstanceOf( 'Closure', $obj->setterArgs[0] );
+ $this->assertSame( 'unwrapped', $obj->setterArgs[0]() );
}
/**
@@ -39,22 +48,46 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
public function testClosureExpansionEnabled() {
$obj = ObjectFactory::getObjectFromSpec( array(
'class' => 'ObjectFactoryTest_Fixture',
- 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'args' => array( function() {
+ return 'unwrapped';
+ }, ),
+ 'calls' => array(
+ 'setter' => array( function() {
+ return 'unwrapped';
+ }, ),
+ ),
'closure_expansion' => true,
) );
$this->assertInternalType( 'string', $obj->args[0] );
$this->assertSame( 'unwrapped', $obj->args[0] );
+ $this->assertInternalType( 'string', $obj->setterArgs[0] );
+ $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
$obj = ObjectFactory::getObjectFromSpec( array(
'class' => 'ObjectFactoryTest_Fixture',
- 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'args' => array( function() {
+ return 'unwrapped';
+ }, ),
+ 'calls' => array(
+ 'setter' => array( function() {
+ return 'unwrapped';
+ }, ),
+ ),
) );
$this->assertInternalType( 'string', $obj->args[0] );
$this->assertSame( 'unwrapped', $obj->args[0] );
+ $this->assertInternalType( 'string', $obj->setterArgs[0] );
+ $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
}
}
class ObjectFactoryTest_Fixture {
public $args;
- public function __construct( /*...*/ ) { $this->args = func_get_args(); }
+ public $setterArgs;
+ public function __construct( /*...*/ ) {
+ $this->args = func_get_args();
+ }
+ public function setter( /*...*/ ) {
+ $this->setterArgs = func_get_args();
+ }
}
diff --git a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
index 43001979..cec662a9 100644
--- a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
+++ b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
@@ -70,7 +70,7 @@ class ProcessCacheLRUTest extends PHPUnit_Framework_TestCase {
/**
* @dataProvider provideInvalidConstructorArg
- * @expectedException UnexpectedValueException
+ * @expectedException Wikimedia\Assert\ParameterAssertionException
* @covers ProcessCacheLRU::__construct
*/
public function testConstructorGivenInvalidValue( $maxSize ) {
diff --git a/tests/phpunit/includes/libs/SamplingStatsdClientTest.php b/tests/phpunit/includes/libs/SamplingStatsdClientTest.php
new file mode 100644
index 00000000..be6732d5
--- /dev/null
+++ b/tests/phpunit/includes/libs/SamplingStatsdClientTest.php
@@ -0,0 +1,43 @@
+<?php
+
+use Liuggio\StatsdClient\Entity\StatsdData;
+
+class SamplingStatsdClientTest extends PHPUnit_Framework_TestCase {
+ /**
+ * @dataProvider samplingDataProvider
+ */
+ public function testSampling( $data, $sampleRate, $seed, $expectWrite ) {
+ $sender = $this->getMock( 'Liuggio\StatsdClient\Sender\SenderInterface' );
+ $sender->expects( $this->any() )->method( 'open' )->will( $this->returnValue( true ) );
+ if ( $expectWrite ) {
+ $sender->expects( $this->once() )->method( 'write' )
+ ->with( $this->anything(), $this->equalTo( $data ) );
+ } else {
+ $sender->expects( $this->never() )->method( 'write' );
+ }
+ mt_srand( $seed );
+ $client = new SamplingStatsdClient( $sender );
+ $client->send( $data, $sampleRate );
+ }
+
+ public function samplingDataProvider() {
+ $unsampled = new StatsdData();
+ $unsampled->setKey( 'foo' );
+ $unsampled->setValue( 1 );
+
+ $sampled = new StatsdData();
+ $sampled->setKey( 'foo' );
+ $sampled->setValue( 1 );
+ $sampled->setSampleRate( '0.1' );
+
+ return array(
+ // $data, $sampleRate, $seed, $expectWrite
+ array( $unsampled, 1, 0 /*0.44*/, $unsampled ),
+ array( $sampled, 1, 0 /*0.44*/, null ),
+ array( $sampled, 1, 4 /*0.03*/, $sampled ),
+ array( $unsampled, 0.1, 4 /*0.03*/, $sampled ),
+ array( $sampled, 0.5, 0 /*0.44*/, null ),
+ array( $sampled, 0.5, 4 /*0.03*/, $sampled ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/libs/XhprofTest.php b/tests/phpunit/includes/libs/XhprofTest.php
index 2440fc08..77b188cf 100644
--- a/tests/phpunit/includes/libs/XhprofTest.php
+++ b/tests/phpunit/includes/libs/XhprofTest.php
@@ -255,43 +255,43 @@ class XhprofTest extends PHPUnit_Framework_TestCase {
*/
protected function getXhprofFixture( array $opts = array() ) {
$xhprof = new Xhprof( $opts );
- $xhprof->loadRawData( array (
- 'foo==>bar' => array (
+ $xhprof->loadRawData( array(
+ 'foo==>bar' => array(
'ct' => 2,
'wt' => 57,
'cpu' => 92,
'mu' => 1896,
'pmu' => 0,
),
- 'foo==>strlen' => array (
+ 'foo==>strlen' => array(
'ct' => 2,
'wt' => 21,
'cpu' => 141,
'mu' => 752,
'pmu' => 0,
),
- 'bar==>bar@1' => array (
+ 'bar==>bar@1' => array(
'ct' => 1,
'wt' => 18,
'cpu' => 19,
'mu' => 752,
'pmu' => 0,
),
- 'main()==>foo' => array (
+ 'main()==>foo' => array(
'ct' => 1,
'wt' => 304,
'cpu' => 307,
'mu' => 4008,
'pmu' => 0,
),
- 'main()==>xhprof_disable' => array (
+ 'main()==>xhprof_disable' => array(
'ct' => 1,
'wt' => 8,
'cpu' => 10,
'mu' => 768,
'pmu' => 392,
),
- 'main()' => array (
+ 'main()' => array(
'ct' => 1,
'wt' => 353,
'cpu' => 351,
@@ -311,7 +311,7 @@ class XhprofTest extends PHPUnit_Framework_TestCase {
*/
protected function assertArrayStructure( $struct, $actual, $label = null ) {
$this->assertInternalType( 'array', $actual, $label );
- $this->assertCount( count($struct), $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/libs/composer/ComposerLockTest.php b/tests/phpunit/includes/libs/composer/ComposerLockTest.php
index b5fd5f6e..cac3b101 100644
--- a/tests/phpunit/includes/libs/composer/ComposerLockTest.php
+++ b/tests/phpunit/includes/libs/composer/ComposerLockTest.php
@@ -27,34 +27,95 @@ class ComposerLockTest extends MediaWikiTestCase {
'wikimedia/cdb' => array(
'version' => '1.0.1',
'type' => 'library',
+ 'licenses' => array( 'GPL-2.0' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Tim Starling',
+ 'email' => 'tstarling@wikimedia.org',
+ ),
+ array(
+ 'name' => 'Chad Horohoe',
+ 'email' => 'chad@wikimedia.org',
+ ),
+ ),
+ 'description' => 'Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.',
),
'cssjanus/cssjanus' => array(
'version' => '1.1.1',
'type' => 'library',
+ 'licenses' => array( 'Apache-2.0' ),
+ 'authors' => array(),
+ 'description' => 'Convert CSS stylesheets between left-to-right and right-to-left.',
),
'leafo/lessphp' => array(
'version' => '0.5.0',
'type' => 'library',
+ 'licenses' => array( 'MIT', 'GPL-3.0' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Leaf Corcoran',
+ 'email' => 'leafot@gmail.com',
+ 'homepage' => 'http://leafo.net',
+ ),
+ ),
+ 'description' => 'lessphp is a compiler for LESS written in PHP.',
),
'psr/log' => array(
'version' => '1.0.0',
'type' => 'library',
+ 'licenses' => array( 'MIT' ),
+ 'authors' => array(
+ array(
+ 'name' => 'PHP-FIG',
+ 'homepage' => 'http://www.php-fig.org/',
+ ),
+ ),
+ 'description' => 'Common interface for logging libraries',
),
'oojs/oojs-ui' => array(
'version' => '0.6.0',
'type' => 'library',
+ 'licenses' => array( 'MIT' ),
+ 'authors' => array(),
+ 'description' => '',
),
'composer/installers' => array(
'version' => '1.0.19',
'type' => 'composer-installer',
+ 'licenses' => array( 'MIT' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Kyle Robinson Young',
+ 'email' => 'kyle@dontkry.com',
+ 'homepage' => 'https://github.com/shama',
+ ),
+ ),
+ 'description' => 'A multi-framework Composer library installer',
),
'mediawiki/translate' => array(
'version' => '2014.12',
'type' => 'mediawiki-extension',
+ 'licenses' => array( 'GPL-2.0+' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Niklas Laxström',
+ 'email' => 'niklas.laxstrom@gmail.com',
+ 'role' => 'Lead nitpicker',
+ ),
+ array(
+ 'name' => 'Siebrand Mazeland',
+ 'email' => 's.mazeland@xs4all.nl',
+ 'role' => 'Developer',
+ ),
+ ),
+ 'description' => 'The only standard solution to translate any kind of text with an avant-garde web interface within MediaWiki, including your documentation and software',
),
'mediawiki/universal-language-selector' => array(
'version' => '2014.12',
'type' => 'mediawiki-extension',
+ 'licenses' => array( 'GPL-2.0+', 'MIT' ),
+ 'authors' => array(),
+ 'description' => 'The primary aim is to allow users to select a language and configure its support in an easy way. Main features are language selection, input methods and web fonts.',
),
), $lock->getInstalledDependencies(), false, true );
}
diff --git a/tests/phpunit/includes/logging/BlockLogFormatterTest.php b/tests/phpunit/includes/logging/BlockLogFormatterTest.php
new file mode 100644
index 00000000..c7dc641d
--- /dev/null
+++ b/tests/phpunit/includes/logging/BlockLogFormatterTest.php
@@ -0,0 +1,372 @@
+<?php
+
+class BlockLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideBlockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Old legacy log
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Old legacy log without flag
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array(),
+ ),
+ ),
+ ),
+
+ // Very old legacy log without duration
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array(),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideBlockLogDatabaseRows
+ */
+ public function testBlockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideReblockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Old log
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Older log without flag
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ )
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of indefinite',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array(),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideReblockLogDatabaseRows
+ */
+ public function testReblockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideUnblockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'unblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'Sysop unblocked Logtestuser',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideUnblockLogDatabaseRows
+ */
+ public function testUnblockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressBlockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // legacy log
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressBlockLogDatabaseRows
+ */
+ public function testSuppressBlockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressReblockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressReblockLogDatabaseRows
+ */
+ public function testSuppressReblockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/DeleteLogFormatterTest.php b/tests/phpunit/includes/logging/DeleteLogFormatterTest.php
new file mode 100644
index 00000000..28e7efaf
--- /dev/null
+++ b/tests/phpunit/includes/logging/DeleteLogFormatterTest.php
@@ -0,0 +1,527 @@
+<?php
+
+class DeleteLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideDeleteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User deleted page Page',
+ 'api' => array(),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User deleted page Page',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideDeleteLogDatabaseRows
+ */
+ public function testDeleteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRestoreLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'restore',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User restored page Page',
+ 'api' => array(),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'restore',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User restored page Page',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRestoreLogDatabaseRows
+ */
+ public function testRestoreLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRevisionLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'revision',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::type' => 'archive',
+ '5::ids' => array( '1', '3', '4' ),
+ '6::ofield' => '1',
+ '7::nfield' => '2',
+ ),
+ ),
+ array(
+ 'text' => 'User changed visibility of 3 revisions on page Page: edit summary '
+ . 'hidden and content unhidden',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'revision',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ 'archive',
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=2',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User changed visibility of 3 revisions on page Page: edit summary '
+ . 'hidden and content unhidden',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRevisionLogDatabaseRows
+ */
+ public function testRevisionLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideEventLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'event',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::ids' => array( '1', '3', '4' ),
+ '5::ofield' => '1',
+ '6::nfield' => '2',
+ ),
+ ),
+ array(
+ 'text' => 'User changed visibility of 3 log events on Page: edit summary hidden '
+ . 'and content unhidden',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'event',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=2',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User changed visibility of 3 log events on Page: edit summary hidden '
+ . 'and content unhidden',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideEventLogDatabaseRows
+ */
+ public function testEventLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressRevisionLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'revision',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::type' => 'archive',
+ '5::ids' => array( '1', '3', '4' ),
+ '6::ofield' => '1',
+ '7::nfield' => '10',
+ ),
+ ),
+ array(
+ 'text' => 'User secretly changed visibility of 3 revisions on page Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'revision',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ 'archive',
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=10',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User secretly changed visibility of 3 revisions on page Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressRevisionLogDatabaseRows
+ */
+ public function testSuppressRevisionLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressEventLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'event',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::ids' => array( '1', '3', '4' ),
+ '5::ofield' => '1',
+ '6::nfield' => '10',
+ ),
+ ),
+ array(
+ 'text' => 'User secretly changed visibility of 3 log events on Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'event',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=10',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User secretly changed visibility of 3 log events on Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressEventLogDatabaseRows
+ */
+ public function testSuppressEventLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressDeleteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User suppressed page Page',
+ 'api' => array(),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User suppressed page Page',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressDeleteLogDatabaseRows
+ */
+ public function testSuppressDeleteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/LogFormatterTest.php b/tests/phpunit/includes/logging/LogFormatterTest.php
index 515990e6..844c9afb 100644
--- a/tests/phpunit/includes/logging/LogFormatterTest.php
+++ b/tests/phpunit/includes/logging/LogFormatterTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* @group Database
*/
@@ -19,6 +20,16 @@ class LogFormatterTest extends MediaWikiLangTestCase {
*/
protected $context;
+ /**
+ * @var Title
+ */
+ protected $target;
+
+ /**
+ * @var string
+ */
+ protected $user_comment;
+
protected function setUp() {
parent::setUp();
@@ -35,12 +46,15 @@ class LogFormatterTest extends MediaWikiLangTestCase {
Language::getLocalisationCache()->recache( $wgLang->getCode() );
$this->user = User::newFromName( 'Testuser' );
- $this->title = Title::newMainPage();
+ $this->title = Title::newFromText( 'SomeTitle' );
+ $this->target = Title::newFromText( 'TestTarget' );
$this->context = new RequestContext();
$this->context->setUser( $this->user );
$this->context->setTitle( $this->title );
$this->context->setLanguage( $wgLang );
+
+ $this->user_comment = '<User comment about action>';
}
protected function tearDown() {
@@ -292,4 +306,309 @@ class LogFormatterTest extends MediaWikiLangTestCase {
array( '4:user-link:key', 'foo', array( 'key' => 'Foo' ) ),
);
}
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeBlock() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # block/block
+ $this->assertIRCComment(
+ $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
+ 'block', 'block',
+ array(
+ '5::duration' => 'duration',
+ '6::flags' => 'flags',
+ ),
+ $this->user_comment
+ );
+ # block/block - legacy
+ $this->assertIRCComment(
+ $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
+ 'block', 'block',
+ array(
+ 'duration',
+ 'flags',
+ ),
+ $this->user_comment,
+ '',
+ true
+ );
+ # block/unblock
+ $this->assertIRCComment(
+ $this->context->msg( 'unblocklogentry', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'block', 'unblock',
+ 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
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeDelete() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # delete/delete
+ $this->assertIRCComment(
+ $this->context->msg( 'deletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'delete', 'delete',
+ array(),
+ $this->user_comment
+ );
+
+ # delete/restore
+ $this->assertIRCComment(
+ $this->context->msg( 'undeletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'delete', 'restore',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeNewusers() {
+ $this->assertIRCComment(
+ 'New user account',
+ 'newusers', 'newusers',
+ array()
+ );
+ $this->assertIRCComment(
+ 'New user account',
+ 'newusers', 'create',
+ array()
+ );
+ $this->assertIRCComment(
+ 'created new account SomeTitle',
+ 'newusers', 'create2',
+ array()
+ );
+ $this->assertIRCComment(
+ 'Account created automatically',
+ 'newusers', 'autocreate',
+ array()
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeMove() {
+ $move_params = array(
+ '4::target' => $this->target->getPrefixedText(),
+ '5::noredir' => 0,
+ );
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # move/move
+ $this->assertIRCComment(
+ $this->context->msg( '1movedto2', 'SomeTitle', 'TestTarget' )
+ ->plain() . $sep . $this->user_comment,
+ 'move', 'move',
+ $move_params,
+ $this->user_comment
+ );
+
+ # move/move_redir
+ $this->assertIRCComment(
+ $this->context->msg( '1movedto2_redir', 'SomeTitle', 'TestTarget' )
+ ->plain() . $sep . $this->user_comment,
+ 'move', 'move_redir',
+ $move_params,
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypePatrol() {
+ # patrol/patrol
+ $this->assertIRCComment(
+ $this->context->msg( 'patrol-log-line', 'revision 777', '[[SomeTitle]]', '' )->plain(),
+ 'patrol', 'patrol',
+ array(
+ '4::curid' => '777',
+ '5::previd' => '666',
+ '6::auto' => 0,
+ )
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeProtect() {
+ $protectParams = array(
+ '[edit=sysop] (indefinite) ‎[move=sysop] (indefinite)'
+ );
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # protect/protect
+ $this->assertIRCComment(
+ $this->context->msg( 'protectedarticle', 'SomeTitle ' . $protectParams[0] )
+ ->plain() . $sep . $this->user_comment,
+ 'protect', 'protect',
+ $protectParams,
+ $this->user_comment
+ );
+
+ # protect/unprotect
+ $this->assertIRCComment(
+ $this->context->msg( 'unprotectedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'protect', 'unprotect',
+ array(),
+ $this->user_comment
+ );
+
+ # protect/modify
+ $this->assertIRCComment(
+ $this->context->msg( 'modifiedarticleprotection', 'SomeTitle ' . $protectParams[0] )
+ ->plain() . $sep . $this->user_comment,
+ 'protect', 'modify',
+ $protectParams,
+ $this->user_comment
+ );
+
+ # protect/move_prot
+ $this->assertIRCComment(
+ $this->context->msg( 'movedarticleprotection', 'SomeTitle', 'OldTitle' )
+ ->plain() . $sep . $this->user_comment,
+ 'protect', 'move_prot',
+ array(
+ '4::oldtitle' => 'OldTitle'
+ ),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeUpload() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # upload/upload
+ $this->assertIRCComment(
+ $this->context->msg( 'uploadedimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'upload', 'upload',
+ array(),
+ $this->user_comment
+ );
+
+ # upload/overwrite
+ $this->assertIRCComment(
+ $this->context->msg( 'overwroteimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'upload', 'overwrite',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @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::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeImport() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # import/upload
+ $msg = $this->context->msg( 'import-logentry-upload', 'SomeTitle' )->plain() .
+ $sep .
+ $this->user_comment;
+ $this->assertIRCComment(
+ $msg,
+ 'import', 'upload',
+ array(),
+ $this->user_comment
+ );
+
+ # import/interwiki
+ $msg = $this->context->msg( 'import-logentry-interwiki', 'SomeTitle' )->plain() .
+ $sep .
+ $this->user_comment;
+ $this->assertIRCComment(
+ $msg,
+ 'import', 'interwiki',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @param string $expected Expected IRC text without colors codes
+ * @param string $type Log type (move, delete, suppress, patrol ...)
+ * @param string $action A log type action
+ * @param array $params
+ * @param string $comment (optional) A comment for the log action
+ * @param string $msg (optional) A message for PHPUnit :-)
+ */
+ protected function assertIRCComment( $expected, $type, $action, $params,
+ $comment = null, $msg = '', $legacy = false
+ ) {
+ $logEntry = new ManualLogEntry( $type, $action );
+ $logEntry->setPerformer( $this->user );
+ $logEntry->setTarget( $this->title );
+ if ( $comment !== null ) {
+ $logEntry->setComment( $comment );
+ }
+ $logEntry->setParameters( $params );
+ $logEntry->setLegacy( $legacy );
+
+ $formatter = LogFormatter::newFromEntry( $logEntry );
+ $formatter->setContext( $this->context );
+
+ // Apply the same transformation as done in IRCColourfulRCFeedFormatter::getLine for rc_comment
+ $ircRcComment = IRCColourfulRCFeedFormatter::cleanupForIRC( $formatter->getIRCActionComment() );
+
+ $this->assertEquals(
+ $expected,
+ $ircRcComment,
+ $msg
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/logging/LogFormatterTestCase.php b/tests/phpunit/includes/logging/LogFormatterTestCase.php
new file mode 100644
index 00000000..e88452b7
--- /dev/null
+++ b/tests/phpunit/includes/logging/LogFormatterTestCase.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @since 1.26
+ */
+abstract class LogFormatterTestCase extends MediaWikiLangTestCase {
+
+ public function doTestLogFormatter( $row, $extra ) {
+ RequestContext::resetMain();
+ $row = $this->expandDatabaseRow( $row, $this->isLegacy( $extra ) );
+
+ $formatter = LogFormatter::newFromRow( $row );
+
+ $this->assertEquals(
+ $extra['text'],
+ self::removeSomeHtml( $formatter->getActionText() ),
+ 'Action text is equal to expected text'
+ );
+
+ $this->assertSame( // ensure types and array key order
+ $extra['api'],
+ self::removeApiMetaData( $formatter->formatParametersForApi() ),
+ 'Api log params is equal to expected array'
+ );
+ }
+
+ protected function isLegacy( $extra ) {
+ return isset( $extra['legacy'] ) && $extra['legacy'];
+ }
+
+ protected function expandDatabaseRow( $data, $legacy ) {
+ return array(
+ // no log_id because no insert in database
+ 'log_type' => $data['type'],
+ 'log_action' => $data['action'],
+ 'log_timestamp' => isset( $data['timestamp'] ) ? $data['timestamp'] : wfTimestampNow(),
+ 'log_user' => isset( $data['user'] ) ? $data['user'] : 0,
+ 'log_user_text' => isset( $data['user_text'] ) ? $data['user_text'] : 'User',
+ 'log_namespace' => isset( $data['namespace'] ) ? $data['namespace'] : NS_MAIN,
+ 'log_title' => isset( $data['title'] ) ? $data['title'] : 'Main_Page',
+ 'log_page' => isset( $data['page'] ) ? $data['page'] : 0,
+ 'log_comment' => isset( $data['comment'] ) ? $data['comment'] : '',
+ 'log_params' => $legacy
+ ? LogPage::makeParamBlob( $data['params'] )
+ : LogEntryBase::makeParamBlob( $data['params'] ),
+ 'log_deleted' => isset( $data['deleted'] ) ? $data['deleted'] : 0,
+ );
+ }
+
+ private static function removeSomeHtml( $html ) {
+ $html = str_replace( '&quot;', '"', $html );
+ return trim( preg_replace( '/<(a|span)[^>]*>([^<]*)<\/\1>/', '$2', $html ) );
+ }
+
+ private static function removeApiMetaData( $val ) {
+ if ( is_array( $val ) ) {
+ unset( $val['_element'] );
+ unset( $val['_type'] );
+ foreach ( $val as $key => $value ) {
+ $val[$key] = self::removeApiMetaData( $value );
+ }
+ }
+ return $val;
+ }
+}
diff --git a/tests/phpunit/includes/logging/MergeLogFormatterTest.php b/tests/phpunit/includes/logging/MergeLogFormatterTest.php
new file mode 100644
index 00000000..2ff0ddf5
--- /dev/null
+++ b/tests/phpunit/includes/logging/MergeLogFormatterTest.php
@@ -0,0 +1,67 @@
+<?php
+
+class MergeLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideMergeLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'merge',
+ 'action' => 'merge',
+ 'comment' => 'Merge comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::dest' => 'NewPage',
+ '5::mergepoint' => '20140804160710',
+ ),
+ ),
+ array(
+ 'text' => 'User merged OldPage into NewPage (revisions up to 16:07, 4 August 2014)',
+ 'api' => array(
+ 'dest_ns' => 0,
+ 'dest_title' => 'NewPage',
+ 'mergepoint' => '2014-08-04T16:07:10Z',
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'merge',
+ 'action' => 'merge',
+ 'comment' => 'merge comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '20140804160710',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User merged OldPage into NewPage (revisions up to 16:07, 4 August 2014)',
+ 'api' => array(
+ 'dest_ns' => 0,
+ 'dest_title' => 'NewPage',
+ 'mergepoint' => '2014-08-04T16:07:10Z',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMergeLogDatabaseRows
+ */
+ public function testMergeLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/MoveLogFormatterTest.php b/tests/phpunit/includes/logging/MoveLogFormatterTest.php
new file mode 100644
index 00000000..fdc4b7e1
--- /dev/null
+++ b/tests/phpunit/includes/logging/MoveLogFormatterTest.php
@@ -0,0 +1,270 @@
+<?php
+
+class MoveLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideMoveLogDatabaseRows() {
+ return array(
+ // Current format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment with redirect',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '0',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // Current format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '1',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // legacy format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // legacy format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '1',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // old format without flag for redirect suppression
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMoveLogDatabaseRows
+ */
+ public function testMoveLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideMoveRedirLogDatabaseRows() {
+ return array(
+ // Current format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment with redirect',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '0',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage over redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // Current format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '1',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage over a redirect without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // legacy format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage over redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // legacy format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '1',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage over a redirect without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // old format without flag for redirect suppression
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage over redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMoveRedirLogDatabaseRows
+ */
+ public function testMoveRedirLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/NewUsersLogFormatterTest.php b/tests/phpunit/includes/logging/NewUsersLogFormatterTest.php
new file mode 100644
index 00000000..5b03370d
--- /dev/null
+++ b/tests/phpunit/includes/logging/NewUsersLogFormatterTest.php
@@ -0,0 +1,207 @@
+<?php
+
+/**
+ * @group Database
+ */
+class NewUsersLogFormatterTest extends LogFormatterTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ // Register LogHandler, see $wgNewUserLog in Setup.php
+ $this->mergeMwGlobalArrayValue( 'wgLogActionsHandlers', array(
+ 'newusers/newusers' => 'NewUsersLogFormatter',
+ 'newusers/create' => 'NewUsersLogFormatter',
+ 'newusers/create2' => 'NewUsersLogFormatter',
+ 'newusers/byemail' => 'NewUsersLogFormatter',
+ 'newusers/autocreate' => 'NewUsersLogFormatter',
+ ) );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideNewUsersLogDatabaseRows() {
+ return array(
+ // Only old logs
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'newusers',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'New user',
+ 'namespace' => NS_USER,
+ 'title' => 'New user',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User account New user was created',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideNewUsersLogDatabaseRows
+ */
+ public function testNewUsersLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideCreateLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'create',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'New user',
+ 'namespace' => NS_USER,
+ 'title' => 'New user',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account New user was created',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideCreateLogDatabaseRows
+ */
+ public function testCreateLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideCreate2LogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'create2',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'User',
+ 'namespace' => NS_USER,
+ 'title' => 'UTSysop',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account UTSysop was created by User',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideCreate2LogDatabaseRows
+ */
+ public function testCreate2LogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideByemailLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'byemail',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'UTSysop',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account UTSysop was created by Sysop and password was sent by email',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideByemailLogDatabaseRows
+ */
+ public function testByemailLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideAutocreateLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'autocreate',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'New user',
+ 'namespace' => NS_USER,
+ 'title' => 'New user',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account New user was created automatically',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideAutocreateLogDatabaseRows
+ */
+ public function testAutocreateLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/PageLangLogFormatterTest.php b/tests/phpunit/includes/logging/PageLangLogFormatterTest.php
new file mode 100644
index 00000000..226e492b
--- /dev/null
+++ b/tests/phpunit/includes/logging/PageLangLogFormatterTest.php
@@ -0,0 +1,53 @@
+<?php
+
+class PageLangLogFormatterTest extends LogFormatterTestCase {
+
+ protected function setUp() {
+ parent::setUp();
+
+ // Disable cldr extension
+ $this->setMwGlobals( 'wgHooks', array() );
+ // Register LogHandler, see $wgPageLanguageUseDB in Setup.php
+ $this->mergeMwGlobalArrayValue( 'wgLogActionsHandlers', array(
+ 'pagelang/pagelang' => 'PageLangLogFormatter',
+ ) );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function providePageLangLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'pagelang',
+ 'action' => 'pagelang',
+ 'comment' => 'page lang comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::oldlanguage' => 'en',
+ '5::newlanguage' => 'de[def]',
+ ),
+ ),
+ array(
+ 'text' => 'User changed page language for Page from English (en) to Deutsch (de) [default].',
+ 'api' => array(
+ 'oldlanguage' => 'en',
+ 'newlanguage' => 'de[def]'
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providePageLangLogDatabaseRows
+ */
+ public function testPageLangLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/PatrolLogFormatterTest.php b/tests/phpunit/includes/logging/PatrolLogFormatterTest.php
new file mode 100644
index 00000000..6e1c5efc
--- /dev/null
+++ b/tests/phpunit/includes/logging/PatrolLogFormatterTest.php
@@ -0,0 +1,118 @@
+<?php
+
+class PatrolLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function providePatrolLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::curid' => 2,
+ '5::previd' => 1,
+ '6::auto' => 0,
+ ),
+ ),
+ array(
+ 'text' => 'User marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => false,
+ ),
+ ),
+ ),
+
+ // Current format - autopatrol
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::curid' => 2,
+ '5::previd' => 1,
+ '6::auto' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User automatically marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => true,
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '2',
+ '1',
+ '0',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => false,
+ ),
+ ),
+ ),
+
+ // Legacy format - autopatrol
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '2',
+ '1',
+ '1',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User automatically marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => true,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providePatrolLogDatabaseRows
+ */
+ public function testPatrolLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/ProtectLogFormatterTest.php b/tests/phpunit/includes/logging/ProtectLogFormatterTest.php
new file mode 100644
index 00000000..611b2dfc
--- /dev/null
+++ b/tests/phpunit/includes/logging/ProtectLogFormatterTest.php
@@ -0,0 +1,63 @@
+<?php
+
+class ProtectLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideMoveProtLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'protect',
+ 'action' => 'move_prot',
+ 'comment' => 'Move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'NewPage',
+ 'params' => array(
+ '4::oldtitle' => 'OldPage',
+ ),
+ ),
+ array(
+ 'text' => 'User moved protection settings from OldPage to NewPage',
+ 'api' => array(
+ 'oldtitle_ns' => 0,
+ 'oldtitle_title' => 'OldPage',
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'protect',
+ 'action' => 'move_prot',
+ 'comment' => 'Move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'NewPage',
+ 'params' => array(
+ 'OldPage',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved protection settings from OldPage to NewPage',
+ 'api' => array(
+ 'oldtitle_ns' => 0,
+ 'oldtitle_title' => 'OldPage',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMoveProtLogDatabaseRows
+ */
+ public function testMoveProtLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/RightsLogFormatterTest.php b/tests/phpunit/includes/logging/RightsLogFormatterTest.php
new file mode 100644
index 00000000..e9577f11
--- /dev/null
+++ b/tests/phpunit/includes/logging/RightsLogFormatterTest.php
@@ -0,0 +1,157 @@
+<?php
+
+class RightsLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRightsLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'rights',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'User',
+ 'params' => array(
+ '4::oldgroups' => array(),
+ '5::newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ array(
+ 'text' => 'Sysop changed group membership for User:User from (none) to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array(),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'rights',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'User',
+ 'params' => array(
+ '',
+ 'sysop, bureaucrat',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed group membership for User:User from (none) to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array(),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+
+ // Really old entry
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'rights',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'User',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed group membership for User:User',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRightsLogDatabaseRows
+ */
+ public function testRightsLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideAutopromoteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'autopromote',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Sysop',
+ 'params' => array(
+ '4::oldgroups' => array( 'sysop' ),
+ '5::newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ array(
+ 'text' => 'Sysop was automatically promoted from administrator to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array( 'sysop' ),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'autopromote',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Sysop',
+ 'params' => array(
+ 'sysop',
+ 'sysop, bureaucrat',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop was automatically promoted from administrator to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array( 'sysop' ),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideAutopromoteLogDatabaseRows
+ */
+ public function testAutopromoteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/UploadLogFormatterTest.php b/tests/phpunit/includes/logging/UploadLogFormatterTest.php
new file mode 100644
index 00000000..12f51613
--- /dev/null
+++ b/tests/phpunit/includes/logging/UploadLogFormatterTest.php
@@ -0,0 +1,166 @@
+<?php
+
+class UploadLogFormatterTest extends LogFormatterTestCase {
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideUploadLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'upload',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '20150101000000',
+ ),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '2015-01-01T00:00:00Z',
+ ),
+ ),
+ ),
+
+ // Old format without params
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'upload',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideUploadLogDatabaseRows
+ */
+ public function testUploadLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideOverwriteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'overwrite',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '20150101000000',
+ ),
+ ),
+ array(
+ 'text' => 'User uploaded a new version of File:File.png',
+ 'api' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '2015-01-01T00:00:00Z',
+ ),
+ ),
+ ),
+
+ // Old format without params
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'overwrite',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User uploaded a new version of File:File.png',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideOverwriteLogDatabaseRows
+ */
+ public function testOverwriteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRevertLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'revert',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '20150101000000',
+ ),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '2015-01-01T00:00:00Z',
+ ),
+ ),
+ ),
+
+ // Old format without params
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'revert',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRevertLogDatabaseRows
+ */
+ public function testRevertLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/media/ExifBitmapTest.php b/tests/phpunit/includes/media/ExifBitmapTest.php
index 41330f41..adbc9775 100644
--- a/tests/phpunit/includes/media/ExifBitmapTest.php
+++ b/tests/phpunit/includes/media/ExifBitmapTest.php
@@ -3,7 +3,7 @@
/**
* @group Media
*/
-class ExifBitmapTest extends MediaWikiTestCase {
+class ExifBitmapTest extends MediaWikiMediaTestCase {
/**
* @var ExifBitmapHandler
@@ -143,4 +143,41 @@ class ExifBitmapTest extends MediaWikiTestCase {
$res = $this->handler->convertMetadataVersion( $metadata, 1 );
$this->assertEquals( $expected, $res );
}
+
+ /**
+ * @dataProvider provideSwappingICCProfile
+ * @covers BitmapHandler::swapICCProfile
+ */
+ public function testSwappingICCProfile( $sourceFilename, $controlFilename, $newProfileFilename, $oldProfileName ) {
+ global $wgExiftool;
+
+ if ( !$wgExiftool || !is_file( $wgExiftool ) ) {
+ $this->markTestSkipped( "Exiftool not installed, cannot test ICC profile swapping" );
+ }
+
+ $this->setMwGlobals( 'wgUseTinyRGBForJPGThumbnails', true );
+
+ $sourceFilepath = $this->filePath . $sourceFilename;
+ $controlFilepath = $this->filePath . $controlFilename;
+ $profileFilepath = $this->filePath . $newProfileFilename;
+ $filepath = $this->getNewTempFile();
+
+ copy( $sourceFilepath, $filepath );
+
+ $file = $this->dataFile( $sourceFilename, 'image/jpeg' );
+ $this->handler->swapICCProfile( $filepath, $oldProfileName, $profileFilepath );
+
+ $this->assertEquals( sha1( file_get_contents( $filepath ) ), sha1( file_get_contents( $controlFilepath ) ) );
+ }
+
+ public function provideSwappingICCProfile() {
+ return array(
+ // File with sRGB should end up with TinyRGB
+ array( 'srgb.jpg', 'tinyrgb.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ),
+ // File with TinyRGB should be left unchanged
+ array( 'tinyrgb.jpg', 'tinyrgb.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ),
+ // File with no profile should be left unchanged
+ array( 'test.jpg', 'test.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' )
+ );
+ }
}
diff --git a/tests/phpunit/includes/media/FormatMetadataTest.php b/tests/phpunit/includes/media/FormatMetadataTest.php
index 54758f94..b666c83c 100644
--- a/tests/phpunit/includes/media/FormatMetadataTest.php
+++ b/tests/phpunit/includes/media/FormatMetadataTest.php
@@ -37,39 +37,6 @@ class FormatMetadataTest extends MediaWikiMediaTestCase {
}
/**
- * @param string $filename
- * @param int $expected Total image area
- * @dataProvider provideFlattenArray
- * @covers FormatMetadata::flattenArray
- */
- public function testFlattenArray( $vals, $type, $noHtml, $ctx, $expected ) {
- $actual = FormatMetadata::flattenArray( $vals, $type, $noHtml, $ctx );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideFlattenArray() {
- return array(
- array(
- array( 1, 2, 3 ), 'ul', false, false,
- "<ul><li>1</li>\n<li>2</li>\n<li>3</li></ul>",
- ),
- array(
- array( 1, 2, 3 ), 'ol', false, false,
- "<ol><li>1</li>\n<li>2</li>\n<li>3</li></ol>",
- ),
- array(
- array( 1, 2, 3 ), 'ul', true, false,
- "\n*1\n*2\n*3",
- ),
- array(
- array( 1, 2, 3 ), 'ol', true, false,
- "\n#1\n#2\n#3",
- ),
- // TODO: more test cases
- );
- }
-
- /**
* @param mixed $input
* @param mixed $output
* @dataProvider provideResolveMultivalueValue
diff --git a/tests/phpunit/includes/media/WebPTest.php b/tests/phpunit/includes/media/WebPTest.php
new file mode 100644
index 00000000..d36710a3
--- /dev/null
+++ b/tests/phpunit/includes/media/WebPTest.php
@@ -0,0 +1,127 @@
+<?php
+class WebPHandlerTest extends MediaWikiTestCase {
+ public function setUp() {
+ parent::setUp();
+ // Allocated file for testing
+ $this->tempFileName = tempnam( wfTempDir(), 'WEBP' );
+ }
+ public function tearDown() {
+ parent::tearDown();
+ unlink( $this->tempFileName );
+ }
+ /**
+ * @dataProvider provideTestExtractMetaData
+ */
+ public function testExtractMetaData( $header, $expectedResult ) {
+ // Put header into file
+ file_put_contents( $this->tempFileName, $header );
+
+ $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $this->tempFileName ) );
+ }
+ public function provideTestExtractMetaData() {
+ return array(
+ // Files from https://developers.google.com/speed/webp/gallery2
+ array( "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
+ array( 'compression' => 'lossless', 'width' => 400, 'height' => 301 ) ),
+ array( "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301) ),
+ array( "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
+ array( 'compression' => 'lossless', 'width' => 386, 'height' => 395 ) ),
+ array( "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ) ),
+ array( "\x52\x49\x46\x46\x70\x61\x02\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x63\x61\x02\x00\x2F\x1F\xC3\x95\x10\x8D\xC8\x72\xDB\xC8\x92\x24\xD8\x91\xD9\x91",
+ array( 'compression' => 'lossless', 'width' => 800, 'height' => 600 ) ),
+ array( "\x52\x49\x46\x46\x1C\x1D\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x1F\x03\x00\x57\x02\x00\x41\x4C\x50\x48\x25\x8B",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 800, 'height' => 600 ) ),
+ array( "\x52\x49\x46\x46\xFA\xC5\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xEE\xC5\x00\x00\x2F\xA4\x81\x28\x10\x8D\x40\x68\x24\xC9\x91\xA4\xAE\xF3\x97\x75",
+ array( 'compression' => 'lossless', 'width' => 421, 'height' => 163 ) ),
+ array( "\x52\x49\x46\x46\xF6\x5D\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\xA4\x01\x00\xA2\x00\x00\x41\x4C\x50\x48\x38\x1A",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 421, 'height' => 163 ) ),
+ array( "\x52\x49\x46\x46\xC4\x96\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xB8\x96\x01\x00\x2F\x2B\xC1\x4A\x10\x11\x87\x6D\xDB\x48\x12\xFC\x60\xB0\x83\x24",
+ array( 'compression' => 'lossless', 'width' => 300, 'height' => 300 ) ),
+ array( "\x52\x49\x46\x46\x0A\x11\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x2B\x01\x00\x2B\x01\x00\x41\x4C\x50\x48\x67\x6E",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 300, 'height' => 300 ) ),
+
+ // Lossy files from https://developers.google.com/speed/webp/gallery1
+ array( "\x52\x49\x46\x46\x68\x76\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\x5C\x76\x00\x00\xD2\xBE\x01\x9D\x01\x2A\x26\x02\x70\x01\x3E\xD5\x4E\x97\x43\xA2",
+ array( 'compression' => 'lossy', 'width' => 550, 'height' => 368 ) ),
+ array( "\x52\x49\x46\x46\xB0\xEC\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\xA4\xEC\x00\x00\xB2\x4B\x02\x9D\x01\x2A\x26\x02\x94\x01\x3E\xD1\x50\x96\x46\x26",
+ array( 'compression' => 'lossy', 'width' => 550, 'height' => 404 ) ),
+ array( "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
+ array( 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ) ),
+ array( "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
+ array( 'compression' => 'lossy', 'width' => 1024, 'height' => 772) ),
+ array( "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
+ array( 'compression' => 'lossy', 'width' => 1024, 'height' => 752) ),
+
+ // Animated file from https://groups.google.com/a/chromium.org/d/topic/blink-dev/Y8tRC4mdQz8/discussion
+ array( "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
+ array( 'compression' => 'unknown', 'animated' => true, 'transparency' => true, 'width' => 320, 'height' => 320 ) ),
+
+ // Error cases
+ array( '', false ),
+ array( ' ', false ),
+ array( 'RIFF ', false ),
+ array( 'RIFF1234WEBP ', false ),
+ array( 'RIFF1234WEBPVP8 ', false ),
+ array( 'RIFF1234WEBPVP8L ', false ),
+ );
+ }
+
+ /**
+ * @dataProvider provideTestWithFileExtractMetaData
+ */
+ public function testWithFileExtractMetaData( $filename, $expectedResult ) {
+ $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $filename ) );
+ }
+ public function provideTestWithFileExtractMetaData() {
+ return array(
+ array( __DIR__ . '/../../data/media/2_webp_ll.webp',
+ array( 'compression' => 'lossless', 'width' => 386, 'height' => 395 ) ),
+ array( __DIR__ . '/../../data/media/2_webp_a.webp',
+ array( 'compression' => 'lossy', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ) ),
+ );
+ }
+
+ /**
+ * @dataProvider provideTestGetImageSize
+ */
+ public function testGetImageSize( $path, $expectedResult ) {
+ $handler = new WebPHandler();
+ $this->assertEquals( $expectedResult, $handler->getImageSize( null, $path ) );
+ }
+ public function provideTestGetImageSize() {
+ return array(
+ // Public domain files from https://developers.google.com/speed/webp/gallery2
+ array( __DIR__ . '/../../data/media/2_webp_a.webp', array( 386, 395 ) ),
+ array( __DIR__ . '/../../data/media/2_webp_ll.webp', array( 386, 395 ) ),
+ array( __DIR__ . '/../../data/media/webp_animated.webp', array( 300, 225 ) ),
+
+ // Error cases
+ array( __FILE__, false ),
+ );
+ }
+
+ /**
+ * Tests the WebP MIME detection. This should really be a separate test, but sticking it
+ * here for now.
+ *
+ * @dataProvider provideTestGetMimeType
+ */
+ public function testGuessMimeType( $path ) {
+ $mime = MimeMagic::singleton();
+ $this->assertEquals( 'image/webp', $mime->guessMimeType( $path, false ) );
+ }
+ public function provideTestGetMimeType() {
+ return array(
+ // Public domain files from https://developers.google.com/speed/webp/gallery2
+ array( __DIR__ . '/../../data/media/2_webp_a.webp' ),
+ array( __DIR__ . '/../../data/media/2_webp_ll.webp' ),
+ array( __DIR__ . '/../../data/media/webp_animated.webp' ),
+ );
+ }
+}
+
+/* Python code to extract a header and convert to PHP format:
+ * print '"%s"' % ''.join( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
+ */
diff --git a/tests/phpunit/includes/media/XMPValidateTest.php b/tests/phpunit/includes/media/XMPValidateTest.php
index ebec8f6c..53671d42 100644
--- a/tests/phpunit/includes/media/XMPValidateTest.php
+++ b/tests/phpunit/includes/media/XMPValidateTest.php
@@ -1,5 +1,7 @@
<?php
+use Psr\Log\NullLogger;
+
/**
* @group Media
*/
@@ -11,7 +13,8 @@ class XMPValidateTest extends MediaWikiTestCase {
*/
public function testValidateDate( $value, $expected ) {
// The method should modify $value.
- XMPValidate::validateDate( array(), $value, true );
+ $validate = new XMPValidate( new NullLogger() );
+ $validate->validateDate( array(), $value, true );
$this->assertEquals( $expected, $value );
}
diff --git a/tests/phpunit/includes/objectcache/BagOStuffTest.php b/tests/phpunit/includes/objectcache/BagOStuffTest.php
index 4516bb4e..b6840062 100644
--- a/tests/phpunit/includes/objectcache/BagOStuffTest.php
+++ b/tests/phpunit/includes/objectcache/BagOStuffTest.php
@@ -1,8 +1,10 @@
<?php
/**
* @author Matthias Mullie <mmullie@wikimedia.org>
+ * @group BagOStuff
*/
class BagOStuffTest extends MediaWikiTestCase {
+ /** @var BagOStuff */
private $cache;
protected function setUp() {
@@ -136,20 +138,48 @@ class BagOStuffTest extends MediaWikiTestCase {
public function testGetMulti() {
$value1 = array( 'this' => 'is', 'a' => 'test' );
$value2 = array( 'this' => 'is', 'another' => 'test' );
+ $value3 = array( 'testing a key that may be encoded when sent to cache backend' );
$key1 = wfMemcKey( 'test1' );
$key2 = wfMemcKey( 'test2' );
+ $key3 = wfMemcKey( 'will-%-encode' ); // internally, MemcachedBagOStuffs will encode to will-%25-encode
$this->cache->add( $key1, $value1 );
$this->cache->add( $key2, $value2 );
+ $this->cache->add( $key3, $value3 );
$this->assertEquals(
- $this->cache->getMulti( array( $key1, $key2 ) ),
- array( $key1 => $value1, $key2 => $value2 )
+ array( $key1 => $value1, $key2 => $value2, $key3 => $value3 ),
+ $this->cache->getMulti( array( $key1, $key2, $key3 ) )
);
// cleanup
$this->cache->delete( $key1 );
$this->cache->delete( $key2 );
+ $this->cache->delete( $key3 );
+ }
+
+ /**
+ * @covers BagOStuff::getScopedLock
+ */
+ public function testGetScopedLock() {
+ $key = wfMemcKey( 'test' );
+ $value1 = $this->cache->getScopedLock( $key, 0 );
+ $value2 = $this->cache->getScopedLock( $key, 0 );
+
+ $this->assertType( 'ScopedCallback', $value1, 'First call returned lock' );
+ $this->assertNull( $value2, 'Duplicate call returned no lock' );
+
+ unset( $value1 );
+
+ $value3 = $this->cache->getScopedLock( $key, 0 );
+ $this->assertType( 'ScopedCallback', $value3, 'Lock returned callback after release' );
+ unset( $value3 );
+
+ $value1 = $this->cache->getScopedLock( $key, 0, 5, 'reentry' );
+ $value2 = $this->cache->getScopedLock( $key, 0, 5, 'reentry' );
+
+ $this->assertType( 'ScopedCallback', $value1, 'First reentrant call returned lock' );
+ $this->assertType( 'ScopedCallback', $value1, 'Second reentrant call returned lock' );
}
}
diff --git a/tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php b/tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php
new file mode 100644
index 00000000..2b66181c
--- /dev/null
+++ b/tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @group Database
+ */
+class MultiWriteBagOStuffTest extends MediaWikiTestCase {
+ /** @var HashBagOStuff */
+ private $cache1;
+ /** @var HashBagOStuff */
+ private $cache2;
+ /** @var MultiWriteBagOStuff */
+ private $cache;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->cache1 = new HashBagOStuff();
+ $this->cache2 = new HashBagOStuff();
+ $this->cache = new MultiWriteBagOStuff( array(
+ 'caches' => array( $this->cache1, $this->cache2 ),
+ 'replication' => 'async'
+ ) );
+ }
+
+ public function testSetImmediate() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->cache->set( $key, $value );
+
+ // Set in tier 1
+ $this->assertEquals( $value, $this->cache1->get( $key ), 'Written to tier 1' );
+ // Set in tier 2
+ $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
+ }
+
+ public function testSetDelayed() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+
+ // XXX: DeferredUpdates bound to transactions in CLI mode
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->begin();
+ $this->cache->set( $key, $value );
+
+ // Set in tier 1
+ $this->assertEquals( $value, $this->cache1->get( $key ), 'Written to tier 1' );
+ // Not yet set in tier 2
+ $this->assertEquals( false, $this->cache2->get( $key ), 'Not written to tier 2' );
+
+ $dbw->commit();
+
+ // Set in tier 2
+ $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
+ }
+}
diff --git a/tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php b/tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php
new file mode 100644
index 00000000..a419f5b6
--- /dev/null
+++ b/tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php
@@ -0,0 +1,62 @@
+<?php
+
+class ReplicatedBagOStuffTest extends MediaWikiTestCase {
+ /** @var HashBagOStuff */
+ private $writeCache;
+ /** @var HashBagOStuff */
+ private $readCache;
+ /** @var ReplicatedBagOStuff */
+ private $cache;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->writeCache = new HashBagOStuff();
+ $this->readCache = new HashBagOStuff();
+ $this->cache = new ReplicatedBagOStuff( array(
+ 'writeFactory' => $this->writeCache,
+ 'readFactory' => $this->readCache,
+ ) );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::set
+ */
+ public function testSet() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->cache->set( $key, $value );
+
+ // Write to master.
+ $this->assertEquals( $this->writeCache->get( $key ), $value );
+ // Don't write to slave. Replication is deferred to backend.
+ $this->assertEquals( $this->readCache->get( $key ), false );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::get
+ */
+ public function testGet() {
+ $key = wfRandomString();
+
+ $write = wfRandomString();
+ $this->writeCache->set( $key, $write );
+ $read = wfRandomString();
+ $this->readCache->set( $key, $read );
+
+ // Read from slave.
+ $this->assertEquals( $this->cache->get( $key ), $read );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::get
+ */
+ public function testGetAbsent() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->writeCache->set( $key, $value );
+
+ // Don't read from master. No failover if value is absent.
+ $this->assertEquals( $this->cache->get( $key ), false );
+ }
+}
diff --git a/tests/phpunit/includes/objectcache/WANObjectCacheTest.php b/tests/phpunit/includes/objectcache/WANObjectCacheTest.php
new file mode 100644
index 00000000..40ae4613
--- /dev/null
+++ b/tests/phpunit/includes/objectcache/WANObjectCacheTest.php
@@ -0,0 +1,292 @@
+<?php
+
+class WANObjectCacheTest extends MediaWikiTestCase {
+ /** @var WANObjectCache */
+ private $cache;
+
+ protected function setUp() {
+ parent::setUp();
+
+ if ( $this->getCliArg( 'use-wanobjectcache' ) ) {
+ $name = $this->getCliArg( 'use-wanobjectcache' );
+
+ $this->cache = ObjectCache::getWANInstance( $name );
+ } else {
+ $this->cache = new WANObjectCache( array(
+ 'cache' => new HashBagOStuff(),
+ 'pool' => 'testcache-hash',
+ 'relayer' => new EventRelayerNull( array() )
+ ) );
+ }
+
+ $wanCache = TestingAccessWrapper::newFromObject( $this->cache );
+ $this->internalCache = $wanCache->cache;
+ }
+
+ /**
+ * @dataProvider provider_testSetAndGet
+ * @covers WANObjectCache::set()
+ * @covers WANObjectCache::get()
+ * @param mixed $value
+ * @param integer $ttl
+ */
+ public function testSetAndGet( $value, $ttl ) {
+ $key = wfRandomString();
+ $this->cache->set( $key, $value, $ttl );
+
+ $curTTL = null;
+ $this->assertEquals( $value, $this->cache->get( $key, $curTTL ) );
+ if ( is_infinite( $ttl ) || $ttl == 0 ) {
+ $this->assertTrue( is_infinite( $curTTL ), "Current TTL is infinite" );
+ } else {
+ $this->assertGreaterThan( 0, $curTTL, "Current TTL > 0" );
+ $this->assertLessThanOrEqual( $ttl, $curTTL, "Current TTL < nominal TTL" );
+ }
+ }
+
+ public static function provider_testSetAndGet() {
+ return array(
+ array( 14141, 3 ),
+ array( 3535.666, 3 ),
+ array( array(), 3 ),
+ array( null, 3 ),
+ array( '0', 3 ),
+ array( (object)array( 'meow' ), 3 ),
+ array( INF, 3 ),
+ array( '', 3 ),
+ array( 'pizzacat', INF ),
+ );
+ }
+
+ public function testGetNotExists() {
+ $key = wfRandomString();
+ $curTTL = null;
+ $value = $this->cache->get( $key, $curTTL );
+
+ $this->assertFalse( $value, "Non-existing key has false value" );
+ $this->assertNull( $curTTL, "Non-existing key has null current TTL" );
+ }
+
+ public function testSetOver() {
+ $key = wfRandomString();
+ for ( $i = 0; $i < 3; ++$i ) {
+ $value = wfRandomString();
+ $this->cache->set( $key, $value, 3 );
+
+ $this->assertEquals( $this->cache->get( $key ), $value );
+ }
+ }
+
+ /**
+ * @covers WANObjectCache::getWithSetCallback()
+ */
+ public function testGetWithSetCallback() {
+ $cache = $this->cache;
+
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $cKey1 = wfRandomString();
+ $cKey2 = wfRandomString();
+
+ $wasSet = 0;
+ $func = function( $old, &$ttl ) use ( &$wasSet, $value ) {
+ ++$wasSet;
+ $ttl = 20; // override with another value
+ return $value;
+ };
+
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 1, $wasSet, "Value regenerated" );
+
+ $curTTL = null;
+ $v = $cache->get( $key, $curTTL );
+ $this->assertLessThanOrEqual( 20, $curTTL, 'Current TTL between 19-20 (overriden)' );
+ $this->assertGreaterThanOrEqual( 19, $curTTL, 'Current TTL between 19-20 (overriden)' );
+
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 0, $wasSet, "Value not regenerated" );
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array( $cKey1, $cKey2 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 1, $wasSet, "Value regenerated due to check keys" );
+ $t1 = $cache->getCheckKeyTime( $cKey1 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check keys generated on miss' );
+ $t2 = $cache->getCheckKeyTime( $cKey2 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check keys generated on miss' );
+
+ $priorTime = microtime( true );
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array( $cKey1, $cKey2 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 1, $wasSet, "Value regenerated due to still-recent check keys" );
+ $t1 = $cache->getCheckKeyTime( $cKey1 );
+ $this->assertLessThanOrEqual( $priorTime, $t1, 'Check keys did not change again' );
+ $t2 = $cache->getCheckKeyTime( $cKey2 );
+ $this->assertLessThanOrEqual( $priorTime, $t2, 'Check keys did not change again' );
+
+ $curTTL = null;
+ $v = $cache->get( $key, $curTTL, array( $cKey1, $cKey2 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertLessThanOrEqual( 0, $curTTL, "Value has current TTL < 0 due to check keys" );
+ }
+
+ /**
+ * @covers WANObjectCache::getWithSetCallback()
+ */
+ public function testLockTSE() {
+ $cache = $this->cache;
+ $key = wfRandomString();
+ $value = wfRandomString();
+
+ $calls = 0;
+ $func = function() use ( &$calls, $value ) {
+ ++$calls;
+ return $value;
+ };
+
+ $cache->delete( $key );
+ $ret = $cache->getWithSetCallback( $key, 30, $func, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $value, $ret );
+ $this->assertEquals( 1, $calls, 'Value was populated' );
+
+ // Acquire a lock to verify that getWithSetCallback uses lockTSE properly
+ $this->internalCache->lock( $key, 0 );
+ $ret = $cache->getWithSetCallback( $key, 30, $func, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $value, $ret );
+ $this->assertEquals( 1, $calls, 'Callback was not used' );
+ }
+
+ /**
+ * @covers WANObjectCache::getMulti()
+ */
+ public function testGetMulti() {
+ $cache = $this->cache;
+
+ $value1 = array( 'this' => 'is', 'a' => 'test' );
+ $value2 = array( 'this' => 'is', 'another' => 'test' );
+
+ $key1 = wfRandomString();
+ $key2 = wfRandomString();
+ $key3 = wfRandomString();
+
+ $cache->set( $key1, $value1, 5 );
+ $cache->set( $key2, $value2, 10 );
+
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs )
+ );
+
+ $this->assertEquals( 2, count( $curTTLs ), "Two current TTLs in array" );
+ $this->assertGreaterThan( 0, $curTTLs[$key1], "Key 1 has current TTL > 0" );
+ $this->assertGreaterThan( 0, $curTTLs[$key2], "Key 2 has current TTL > 0" );
+
+ $cKey1 = wfRandomString();
+ $cKey2 = wfRandomString();
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs ),
+ 'Result array populated'
+ );
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs, array( $cKey1, $cKey2 ) ),
+ "Result array populated even with new check keys"
+ );
+ $t1 = $cache->getCheckKeyTime( $cKey1 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check key 1 generated on miss' );
+ $t2 = $cache->getCheckKeyTime( $cKey2 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check key 2 generated on miss' );
+ $this->assertEquals( 2, count( $curTTLs ), "Current TTLs array set" );
+ $this->assertLessThanOrEqual( 0, $curTTLs[$key1], 'Key 1 has current TTL <= 0' );
+ $this->assertLessThanOrEqual( 0, $curTTLs[$key2], 'Key 2 has current TTL <= 0' );
+
+ usleep( 1 );
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs, array( $cKey1, $cKey2 ) ),
+ "Result array still populated even with new check keys"
+ );
+ $this->assertEquals( 2, count( $curTTLs ), "Current TTLs still array set" );
+ $this->assertLessThan( 0, $curTTLs[$key1], 'Key 1 has negative current TTL' );
+ $this->assertLessThan( 0, $curTTLs[$key2], 'Key 2 has negative current TTL' );
+ }
+
+ /**
+ * @covers WANObjectCache::delete()
+ */
+ public function testDelete() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->cache->set( $key, $value );
+
+ $curTTL = null;
+ $v = $this->cache->get( $key, $curTTL );
+ $this->assertEquals( $value, $v, "Key was created with value" );
+ $this->assertGreaterThan( 0, $curTTL, "Existing key has current TTL > 0" );
+
+ $this->cache->delete( $key );
+
+ $curTTL = null;
+ $v = $this->cache->get( $key, $curTTL );
+ $this->assertFalse( $v, "Deleted key has false value" );
+ $this->assertLessThan( 0, $curTTL, "Deleted key has current TTL < 0" );
+
+ $this->cache->set( $key, $value . 'more' );
+ $this->assertFalse( $v, "Deleted key is tombstoned and has false value" );
+ $this->assertLessThan( 0, $curTTL, "Deleted key is tombstoned and has current TTL < 0" );
+ }
+
+ /**
+ * @covers WANObjectCache::touchCheckKey()
+ * @covers WANObjectCache::resetCheckKey()
+ * @covers WANObjectCache::getCheckKeyTime()
+ */
+ public function testTouchKeys() {
+ $key = wfRandomString();
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $t0 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThanOrEqual( $priorTime, $t0, 'Check key auto-created' );
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $this->cache->touchCheckKey( $key );
+ $t1 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check key created' );
+
+ $t2 = $this->cache->getCheckKeyTime( $key );
+ $this->assertEquals( $t1, $t2, 'Check key time did not change' );
+
+ usleep( 1 );
+ $this->cache->touchCheckKey( $key );
+ $t3 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThan( $t2, $t3, 'Check key time increased' );
+
+ $t4 = $this->cache->getCheckKeyTime( $key );
+ $this->assertEquals( $t3, $t4, 'Check key time did not change' );
+
+ usleep( 1 );
+ $this->cache->resetCheckKey( $key );
+ $t5 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThan( $t4, $t5, 'Check key time increased' );
+
+ $t6 = $this->cache->getCheckKeyTime( $key );
+ $this->assertEquals( $t5, $t6, 'Check key time did not change' );
+ }
+}
diff --git a/tests/phpunit/includes/parser/MagicVariableTest.php b/tests/phpunit/includes/parser/MagicVariableTest.php
index 17226113..cd54a9e3 100644
--- a/tests/phpunit/includes/parser/MagicVariableTest.php
+++ b/tests/phpunit/includes/parser/MagicVariableTest.php
@@ -10,6 +10,8 @@
* @copyright Copyright © 2011, Antoine Musso
* @file
* @todo covers tags
+ *
+ * @group Database
*/
class MagicVariableTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/parser/MediaWikiParserTest.php b/tests/phpunit/includes/parser/MediaWikiParserTest.php
index e6dbfc30..210c17c5 100644
--- a/tests/phpunit/includes/parser/MediaWikiParserTest.php
+++ b/tests/phpunit/includes/parser/MediaWikiParserTest.php
@@ -92,7 +92,7 @@ class MediaWikiParserTest {
// enough to cause there to be separate names for different
// things, which is good enough for our purposes.
$extensionName = basename( dirname( $fileName ) );
- $testsName = $extensionName . '⁄' . basename( $fileName, '.txt' );
+ $testsName = $extensionName . '__' . basename( $fileName, '.txt' );
$escapedFileName = strtr( $fileName, array( "'" => "\\'", '\\' => '\\\\' ) );
$parserTestClassName = ucfirst( $testsName );
// Official spec for class names: http://php.net/manual/en/language.oop5.basic.php
diff --git a/tests/phpunit/includes/parser/NewParserTest.php b/tests/phpunit/includes/parser/NewParserTest.php
index 7d21c4f7..d95e9225 100644
--- a/tests/phpunit/includes/parser/NewParserTest.php
+++ b/tests/phpunit/includes/parser/NewParserTest.php
@@ -91,7 +91,7 @@ class NewParserTest extends MediaWikiTestCase {
);
$tmpGlobals['wgForeignFileRepos'] = array();
$tmpGlobals['wgDefaultExternalStore'] = array();
- $tmpGlobals['wgEnableParserCache'] = false;
+ $tmpGlobals['wgParserCacheType'] = CACHE_NONE;
$tmpGlobals['wgCapitalLinks'] = true;
$tmpGlobals['wgNoFollowLinks'] = true;
$tmpGlobals['wgNoFollowDomainExceptions'] = array();
@@ -106,7 +106,6 @@ class NewParserTest extends MediaWikiTestCase {
$tmpGlobals['wgAdaptiveMessageCache'] = true;
$tmpGlobals['wgUseDatabaseMessages'] = true;
$tmpGlobals['wgLocaltimezone'] = 'UTC';
- $tmpGlobals['wgDeferredUpdateList'] = array();
$tmpGlobals['wgGroupPermissions'] = array(
'*' => array(
'createaccount' => true,
@@ -160,10 +159,10 @@ class NewParserTest extends MediaWikiTestCase {
$this->djVuSupport = new DjVuSupport();
// Tidy support
$this->tidySupport = new TidySupport();
+ $tmpGlobals['wgTidyConfig'] = null;
$tmpGlobals['wgUseTidy'] = false;
- $tmpGlobals['wgAlwaysUseTidy'] = false;
$tmpGlobals['wgDebugTidy'] = false;
- $tmpGlobals['wgTidyConf'] = $IP . '/includes/tidy.conf';
+ $tmpGlobals['wgTidyConf'] = $IP . '/includes/tidy/tidy.conf';
$tmpGlobals['wgTidyOpts'] = '';
$tmpGlobals['wgTidyInternal'] = $this->tidySupport->isInternal();
@@ -185,6 +184,8 @@ class NewParserTest extends MediaWikiTestCase {
$wgNamespaceAliases['Image'] = $this->savedWeirdGlobals['image_alias'];
$wgNamespaceAliases['Image_talk'] = $this->savedWeirdGlobals['image_talk_alias'];
+ MWTidy::destroySingleton();
+
// Restore backends
RepoGroup::destroySingleton();
FileBackendGroup::destroySingleton();
@@ -454,6 +455,7 @@ class NewParserTest extends MediaWikiTestCase {
$GLOBALS[$var] = $val;
}
+ MWTidy::destroySingleton();
MagicWord::clearCache();
# The entries saved into RepoGroup cache with previous globals will be wrong.
diff --git a/tests/phpunit/includes/parser/ParserMethodsTest.php b/tests/phpunit/includes/parser/ParserMethodsTest.php
index 1790086a..af143caa 100644
--- a/tests/phpunit/includes/parser/ParserMethodsTest.php
+++ b/tests/phpunit/includes/parser/ParserMethodsTest.php
@@ -1,5 +1,9 @@
<?php
+/**
+ * @group Database
+ */
+
class ParserMethodsTest extends MediaWikiLangTestCase {
public static function providePreSaveTransform() {
diff --git a/tests/phpunit/includes/parser/TagHooksTest.php b/tests/phpunit/includes/parser/TagHooksTest.php
index 251da471..4af38985 100644
--- a/tests/phpunit/includes/parser/TagHooksTest.php
+++ b/tests/phpunit/includes/parser/TagHooksTest.php
@@ -1,6 +1,7 @@
<?php
/**
+ * @group Database
* @group Parser
*/
class TagHookTest extends MediaWikiTestCase {
@@ -18,12 +19,6 @@ class TagHookTest extends MediaWikiTestCase {
return array( array( "foo<bar" ), array( "foo>bar" ), array( "foo\nbar" ), array( "foo\rbar" ) );
}
- protected function setUp() {
- parent::setUp();
-
- $this->setMwGlobals( 'wgAlwaysUseTidy', false );
- }
-
/**
* @dataProvider provideValidNames
* @covers Parser::setHook
diff --git a/tests/phpunit/includes/parser/TidyTest.php b/tests/phpunit/includes/parser/TidyTest.php
index f656a74d..5db29080 100644
--- a/tests/phpunit/includes/parser/TidyTest.php
+++ b/tests/phpunit/includes/parser/TidyTest.php
@@ -7,8 +7,7 @@ class TidyTest extends MediaWikiTestCase {
protected function setUp() {
parent::setUp();
- $check = MWTidy::tidy( '' );
- if ( strpos( $check, '<!--' ) !== false ) {
+ if ( !MWTidy::isEnabled() ) {
$this->markTestSkipped( 'Tidy not found' );
}
}
diff --git a/tests/phpunit/includes/password/PasswordPolicyChecksTest.php b/tests/phpunit/includes/password/PasswordPolicyChecksTest.php
new file mode 100644
index 00000000..af34282f
--- /dev/null
+++ b/tests/phpunit/includes/password/PasswordPolicyChecksTest.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Testing password-policy check functions
+ *
+ * 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 PasswordPolicyChecksTest extends MediaWikiTestCase {
+
+ /**
+ * @covers PasswordPolicyChecks::checkMinimalPasswordLength
+ */
+ public function testCheckMinimalPasswordLength() {
+ $statusOK = PasswordPolicyChecks::checkMinimalPasswordLength(
+ 3, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertTrue( $statusOK->isGood(), 'Password is longer than minimal policy' );
+ $statusShort = PasswordPolicyChecks::checkMinimalPasswordLength(
+ 10, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertFalse(
+ $statusShort->isGood(),
+ 'Password is shorter than minimal policy'
+ );
+ $this->assertTrue(
+ $statusShort->isOk(),
+ 'Password is shorter than minimal policy, not fatal'
+ );
+ }
+
+ /**
+ * @covers PasswordPolicyChecks::checkMinimumPasswordLengthToLogin
+ */
+ public function testCheckMinimumPasswordLengthToLogin() {
+ $statusOK = PasswordPolicyChecks::checkMinimumPasswordLengthToLogin(
+ 3, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertTrue( $statusOK->isGood(), 'Password is longer than minimal policy' );
+ $statusShort = PasswordPolicyChecks::checkMinimumPasswordLengthToLogin(
+ 10, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertFalse(
+ $statusShort->isGood(),
+ 'Password is shorter than minimum login policy'
+ );
+ $this->assertFalse(
+ $statusShort->isOk(),
+ 'Password is shorter than minimum login policy, fatal'
+ );
+ }
+
+ /**
+ * @covers PasswordPolicyChecks::checkMaximalPasswordLength
+ */
+ public function testCheckMaximalPasswordLength() {
+ $statusOK = PasswordPolicyChecks::checkMaximalPasswordLength(
+ 100, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertTrue( $statusOK->isGood(), 'Password is shorter than maximal policy' );
+ $statusLong = PasswordPolicyChecks::checkMaximalPasswordLength(
+ 4, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertFalse( $statusLong->isGood(),
+ 'Password is longer than maximal policy'
+ );
+ $this->assertFalse( $statusLong->isOk(),
+ 'Password is longer than maximal policy, fatal'
+ );
+ }
+
+ /**
+ * @covers PasswordPolicyChecks::checkPasswordCannotMatchUsername
+ */
+ public function testCheckPasswordCannotMatchUsername() {
+ $statusOK = PasswordPolicyChecks::checkPasswordCannotMatchUsername(
+ 1, // policy value
+ User::newFromName( 'user' ), // User
+ 'password' // password
+ );
+ $this->assertTrue( $statusOK->isGood(), 'Password does not match username' );
+ $statusLong = PasswordPolicyChecks::checkPasswordCannotMatchUsername(
+ 1, // policy value
+ User::newFromName( 'user' ), // User
+ 'user' // password
+ );
+ $this->assertFalse( $statusLong->isGood(), 'Password matches username' );
+ $this->assertTrue( $statusLong->isOk(), 'Password matches username, not fatal' );
+ }
+
+ /**
+ * @covers PasswordPolicyChecks::checkPasswordCannotMatchBlacklist
+ */
+ public function testCheckPasswordCannotMatchBlacklist() {
+ $statusOK = PasswordPolicyChecks::checkPasswordCannotMatchBlacklist(
+ true, // policy value
+ User::newFromName( 'Username' ), // User
+ 'AUniquePassword' // password
+ );
+ $this->assertTrue( $statusOK->isGood(), 'Password is not on blacklist' );
+ $statusLong = PasswordPolicyChecks::checkPasswordCannotMatchBlacklist(
+ true, // policy value
+ User::newFromName( 'Useruser1' ), // User
+ 'Passpass1' // password
+ );
+ $this->assertFalse( $statusLong->isGood(), 'Password matches blacklist' );
+ $this->assertTrue( $statusLong->isOk(), 'Password matches blacklist, not fatal' );
+ }
+
+}
diff --git a/tests/phpunit/includes/password/UserPasswordPolicyTest.php b/tests/phpunit/includes/password/UserPasswordPolicyTest.php
new file mode 100644
index 00000000..ce4e30ab
--- /dev/null
+++ b/tests/phpunit/includes/password/UserPasswordPolicyTest.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ * Testing for password-policy enforcement, based on a user's groups.
+ *
+ * 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 UserPasswordPolicyTest extends MediaWikiTestCase {
+
+ protected $policies = array(
+ 'checkuser' => array(
+ 'MinimalPasswordLength' => 10,
+ 'MinimumPasswordLengthToLogin' => 6,
+ 'PasswordCannotMatchUsername' => true,
+ ),
+ 'sysop' => array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => true,
+ ),
+ 'default' => array(
+ 'MinimalPasswordLength' => 4,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 4096,
+ ),
+ );
+
+ protected $checks = array(
+ 'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
+ 'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
+ 'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
+ 'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
+ 'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
+ );
+
+ private function getUserPasswordPolicy() {
+ return new UserPasswordPolicy( $this->policies, $this->checks );
+ }
+
+ /**
+ * @covers UserPasswordPolicy::getPoliciesForUser
+ */
+ public function testGetPoliciesForUser() {
+
+ $upp = $this->getUserPasswordPolicy();
+
+ $user = User::newFromName( 'TestUserPolicy' );
+ $user->addGroup( 'sysop' );
+
+ $this->assertArrayEquals(
+ array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => 1,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 4096,
+ ),
+ $upp->getPoliciesForUser( $user )
+ );
+ }
+
+ /**
+ * @covers UserPasswordPolicy::getPoliciesForGroups
+ */
+ public function testGetPoliciesForGroups() {
+ $effective = UserPasswordPolicy::getPoliciesForGroups(
+ $this->policies,
+ array( 'user', 'checkuser' ),
+ $this->policies['default']
+ );
+
+ $this->assertArrayEquals(
+ array(
+ 'MinimalPasswordLength' => 10,
+ 'MinimumPasswordLengthToLogin' => 6,
+ 'PasswordCannotMatchUsername' => true,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 4096,
+ ),
+ $effective
+ );
+ }
+
+ /**
+ * @dataProvider provideCheckUserPassword
+ * @covers UserPasswordPolicy::checkUserPassword
+ */
+ public function testCheckUserPassword( $username, $groups, $password, $valid, $ok, $msg ) {
+
+ $upp = $this->getUserPasswordPolicy();
+
+ $user = User::newFromName( $username );
+ foreach ( $groups as $group ) {
+ $user->addGroup( $group );
+ }
+
+ $status = $upp->checkUserPassword( $user, $password );
+ $this->assertSame( $valid, $status->isGood(), $msg . ' - password valid' );
+ $this->assertSame( $ok, $status->isOk(), $msg . ' - can login' );
+ }
+
+ public function provideCheckUserPassword() {
+ return array(
+ array(
+ 'PassPolicyUser',
+ array(),
+ '',
+ false,
+ false,
+ 'No groups, default policy, password too short to login'
+ ),
+ array(
+ 'PassPolicyUser',
+ array( 'user' ),
+ 'aaa',
+ false,
+ true,
+ 'Default policy, short password'
+ ),
+ array(
+ 'PassPolicyUser',
+ array( 'sysop' ),
+ 'abcdabcdabcd',
+ true,
+ true,
+ 'Sysop with good password'
+ ),
+ array(
+ 'PassPolicyUser',
+ array( 'sysop' ),
+ 'abcd',
+ false,
+ true,
+ 'Sysop with short password'
+ ),
+ array(
+ 'PassPolicyUser',
+ array( 'sysop', 'checkuser' ),
+ 'abcdabcd',
+ false,
+ true,
+ 'Checkuser with short password'
+ ),
+ array(
+ 'PassPolicyUser',
+ array( 'sysop', 'checkuser' ),
+ 'abcd',
+ false,
+ false,
+ 'Checkuser with too short password to login'
+ ),
+ array(
+ 'Useruser',
+ array( 'user' ),
+ 'Passpass',
+ false,
+ true,
+ 'Username & password on blacklist'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMaxOfPolicies
+ * @covers UserPasswordPolicy::maxOfPolicies
+ */
+ public function testMaxOfPolicies( $p1, $p2, $max, $msg ) {
+ $this->assertArrayEquals(
+ $max,
+ UserPasswordPolicy::maxOfPolicies( $p1, $p2 ),
+ $msg
+ );
+ }
+
+ public function provideMaxOfPolicies() {
+ return array(
+ array(
+ array( 'MinimalPasswordLength' => 8 ), //p1
+ array( 'MinimalPasswordLength' => 2 ), //p2
+ array( 'MinimalPasswordLength' => 8 ), //max
+ 'Basic max in p1'
+ ),
+ array(
+ array( 'MinimalPasswordLength' => 2 ), //p1
+ array( 'MinimalPasswordLength' => 8 ), //p2
+ array( 'MinimalPasswordLength' => 8 ), //max
+ 'Basic max in p2'
+ ),
+ array(
+ array( 'MinimalPasswordLength' => 8 ), //p1
+ array(
+ 'MinimalPasswordLength' => 2,
+ 'PasswordCannotMatchUsername' => 1,
+ ), //p2
+ array(
+ 'MinimalPasswordLength' => 8,
+ 'PasswordCannotMatchUsername' => 1,
+ ), //max
+ 'Missing items in p1'
+ ),
+ array(
+ array(
+ 'MinimalPasswordLength' => 8,
+ 'PasswordCannotMatchUsername' => 1,
+ ), //p1
+ array(
+ 'MinimalPasswordLength' => 2,
+ ), //p2
+ array(
+ 'MinimalPasswordLength' => 8,
+ 'PasswordCannotMatchUsername' => 1,
+ ), //max
+ 'Missing items in p2'
+ ),
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/registration/CoreVersionCheckerTest.php b/tests/phpunit/includes/registration/CoreVersionCheckerTest.php
new file mode 100644
index 00000000..bc154b37
--- /dev/null
+++ b/tests/phpunit/includes/registration/CoreVersionCheckerTest.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @covers CoreVersionChecker
+ */
+class CoreVersionCheckerTest extends PHPUnit_Framework_TestCase {
+ /**
+ * @dataProvider provideCheck
+ */
+ public function testCheck( $coreVersion, $constraint, $expected ) {
+ $checker = new CoreVersionChecker( $coreVersion );
+ $this->assertEquals( $expected, $checker->check( $constraint ) );
+ }
+
+ public static function provideCheck() {
+ return array(
+ // array( $wgVersion, constraint, expected )
+ array( '1.25alpha', '>= 1.26', false ),
+ array( '1.25.0', '>= 1.26', false ),
+ array( '1.26alpha', '>= 1.26', true ),
+ array( '1.26alpha', '>= 1.26.0', true ),
+ array( '1.26alpha', '>= 1.26.0-stable', false ),
+ array( '1.26.0', '>= 1.26.0-stable', true ),
+ array( '1.26.1', '>= 1.26.0-stable', true ),
+ array( '1.27.1', '>= 1.26.0-stable', true ),
+ array( '1.26alpha', '>= 1.26.1', false ),
+ array( '1.26alpha', '>= 1.26alpha', true ),
+ array( '1.26alpha', '>= 1.25', true ),
+ array( '1.26.0-alpha.14', '>= 1.26.0-alpha.15', false ),
+ array( '1.26.0-alpha.14', '>= 1.26.0-alpha.10', true ),
+ array( '1.26.1', '>= 1.26.2, <=1.26.0', false ),
+ array( '1.26.1', '^1.26.2', false ),
+ // Accept anything for un-parsable version strings
+ array( '1.26mwf14', '== 1.25alpha', true ),
+ array( 'totallyinvalid', '== 1.0', true ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/registration/ExtensionProcessorTest.php b/tests/phpunit/includes/registration/ExtensionProcessorTest.php
index ff6be6c2..1cb8a5d9 100644
--- a/tests/phpunit/includes/registration/ExtensionProcessorTest.php
+++ b/tests/phpunit/includes/registration/ExtensionProcessorTest.php
@@ -14,7 +14,7 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
*
* @var array
*/
- static $default = array(
+ public static $default = array(
'name' => 'FooBar',
);
@@ -28,7 +28,7 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
'@metadata' => array( 'foobarbaz' ),
'AnAttribute' => array( 'omg' ),
'AutoloadClasses' => array( 'FooBar' => 'includes/FooBar.php' ),
- ) );
+ ), 1 );
$extracted = $processor->getExtractedInfo();
$attributes = $extracted['attributes'];
@@ -96,7 +96,7 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
*/
public function testRegisterHooks( $pre, $info, $expected ) {
$processor = new MockExtensionProcessor( array( 'wgHooks' => $pre ) );
- $processor->extractInfo( $this->dir, $info );
+ $processor->extractInfo( $this->dir, $info, 1 );
$extracted = $processor->getExtractedInfo();
$this->assertEquals( $expected, $extracted['globals']['wgHooks'] );
}
@@ -119,8 +119,8 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
'Bar' => 'somevalue'
),
) + self::$default;
- $processor->extractInfo( $this->dir, $info );
- $processor->extractInfo( $this->dir, $info2 );
+ $processor->extractInfo( $this->dir, $info, 1 );
+ $processor->extractInfo( $this->dir, $info2, 1 );
$extracted = $processor->getExtractedInfo();
$this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] );
$this->assertEquals( 10, $extracted['globals']['wgFoo'] );
@@ -159,7 +159,7 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
*/
public function testExtracttExtensionMessagesFiles( $input, $expected ) {
$processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default );
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
$out = $processor->getExtractedInfo();
foreach ( $expected as $key => $value ) {
$this->assertEquals( $value, $out['globals'][$key] );
@@ -187,7 +187,7 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
*/
public function testExtractMessagesDirs( $input, $expected ) {
$processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default );
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
$out = $processor->getExtractedInfo();
foreach ( $expected as $key => $value ) {
$this->assertEquals( $value, $out['globals'][$key] );
@@ -200,7 +200,7 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
*/
public function testExtractResourceLoaderModules( $input, $expected ) {
$processor = new ExtensionProcessor();
- $processor->extractInfo( $this->dir, $input + self::$default );
+ $processor->extractInfo( $this->dir, $input + self::$default, 1 );
$out = $processor->getExtractedInfo();
foreach ( $expected as $key => $value ) {
$this->assertEquals( $value, $out['globals'][$key] );
diff --git a/tests/phpunit/includes/registration/ExtensionRegistryTest.php b/tests/phpunit/includes/registration/ExtensionRegistryTest.php
index c3a0c8d4..201cbfcd 100644
--- a/tests/phpunit/includes/registration/ExtensionRegistryTest.php
+++ b/tests/phpunit/includes/registration/ExtensionRegistryTest.php
@@ -218,6 +218,7 @@ class ExtensionRegistryTest extends MediaWikiTestCase {
'user' => array(
'right' => true,
'somethingtwo' => false,
+ 'nonduplicated' => true,
),
ExtensionRegistry::MERGE_STRATEGY => 'array_plus_2d',
),
@@ -233,6 +234,7 @@ class ExtensionRegistryTest extends MediaWikiTestCase {
'user' => array(
'somethingtwo' => true,
'right' => true,
+ 'nonduplicated' => true,
)
),
),
diff --git a/tests/phpunit/includes/resourceloader/DerivativeResourceLoaderContextTest.php b/tests/phpunit/includes/resourceloader/DerivativeResourceLoaderContextTest.php
new file mode 100644
index 00000000..0d11f621
--- /dev/null
+++ b/tests/phpunit/includes/resourceloader/DerivativeResourceLoaderContextTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @group ResourceLoader
+ */
+class DerivativeResourceLoaderContextTest extends PHPUnit_Framework_TestCase {
+
+ protected static function getResourceLoaderContext() {
+ $resourceLoader = new ResourceLoader();
+ $request = new FauxRequest( array(
+ 'lang' => 'zh',
+ 'modules' => 'test.context',
+ 'only' => 'scripts',
+ 'skin' => 'fallback',
+ 'target' => 'test',
+ ) );
+ return new ResourceLoaderContext( $resourceLoader, $request );
+ }
+
+ public function testGet() {
+ $context = self::getResourceLoaderContext();
+ $derived = new DerivativeResourceLoaderContext( $context );
+
+ $this->assertEquals( $derived->getLanguage(), 'zh' );
+ $this->assertEquals( $derived->getModules(), array( 'test.context' ) );
+ $this->assertEquals( $derived->getOnly(), 'scripts' );
+ $this->assertEquals( $derived->getSkin(), 'fallback' );
+ $this->assertEquals( $derived->getHash(), 'zh|ltr|fallback||||||scripts|' );
+ }
+
+ public function testSetLanguage() {
+ $context = self::getResourceLoaderContext();
+ $derived = new DerivativeResourceLoaderContext( $context );
+
+ $derived->setLanguage( 'nl' );
+ $this->assertEquals( $derived->getLanguage(), 'nl' );
+
+ $derived->setLanguage( 'he' );
+ $this->assertEquals( $derived->getDirection(), 'rtl' );
+ }
+
+ public function testSetModules() {
+ $context = self::getResourceLoaderContext();
+ $derived = new DerivativeResourceLoaderContext( $context );
+
+ $derived->setModules( array( 'test.override' ) );
+ $this->assertEquals( $derived->getModules(), array( 'test.override' ) );
+ }
+
+ public function testSetOnly() {
+ $context = self::getResourceLoaderContext();
+ $derived = new DerivativeResourceLoaderContext( $context );
+
+ $derived->setOnly( 'styles' );
+ $this->assertEquals( $derived->getOnly(), 'styles' );
+
+ $derived->setOnly( null );
+ $this->assertEquals( $derived->getOnly(), null );
+ }
+
+ public function testSetSkin() {
+ $context = self::getResourceLoaderContext();
+ $derived = new DerivativeResourceLoaderContext( $context );
+
+ $derived->setSkin( 'override' );
+ $this->assertEquals( $derived->getSkin(), 'override' );
+ }
+
+ public function testGetHash() {
+ $context = self::getResourceLoaderContext();
+ $derived = new DerivativeResourceLoaderContext( $context );
+
+ $derived->setLanguage( 'nl' );
+ // Assert that subclass is able to clear parent class "hash" member
+ $this->assertEquals( $derived->getHash(), 'nl|ltr|fallback||||||scripts|' );
+ }
+
+}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
index 122995a5..9d97b282 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
@@ -1,6 +1,7 @@
<?php
/**
+ * @group Database
* @group ResourceLoader
*/
class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
@@ -157,7 +158,7 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
* @covers ResourceLoaderFileModule::getStyles
* @covers ResourceLoaderFileModule::getStyleFiles
*/
- public function testMixedCssAnnotations( ) {
+ public function testMixedCssAnnotations() {
$basePath = __DIR__ . '/../../data/css';
$testModule = new ResourceLoaderFileModule( array(
'localBasePath' => $basePath,
@@ -225,23 +226,4 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
$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/ResourceLoaderImageTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
index 758cfe19..cc121ba3 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php
@@ -109,9 +109,6 @@ class ResourceLoaderImageTest extends ResourceLoaderTestCase {
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 );
}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
index 6d1ed4e0..41653fb0 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php
@@ -3,10 +3,9 @@
class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
/**
- * @covers ResourceLoaderModule::getDefinitionSummary
- * @covers ResourceLoaderFileModule::getDefinitionSummary
+ * @covers ResourceLoaderModule::getVersionHash
*/
- public function testDefinitionSummary() {
+ public function testGetVersionHash() {
$context = $this->getResourceLoaderContext();
$baseParams = array(
@@ -16,15 +15,13 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
);
$module = new ResourceLoaderFileModule( $baseParams );
-
- $jsonSummary = json_encode( $module->getDefinitionSummary( $context ) );
+ $version = json_encode( $module->getVersionHash( $context ) );
// Exactly the same
$module = new ResourceLoaderFileModule( $baseParams );
-
$this->assertEquals(
- $jsonSummary,
- json_encode( $module->getDefinitionSummary( $context ) ),
+ $version,
+ json_encode( $module->getVersionHash( $context ) ),
'Instance is insignificant'
);
@@ -32,10 +29,9 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
$module = new ResourceLoaderFileModule( array(
'dependencies' => array( 'mediawiki', 'jquery' ),
) + $baseParams );
-
$this->assertEquals(
- $jsonSummary,
- json_encode( $module->getDefinitionSummary( $context ) ),
+ $version,
+ json_encode( $module->getVersionHash( $context ) ),
'Order of dependencies is insignificant'
);
@@ -43,10 +39,9 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
$module = new ResourceLoaderFileModule( array(
'messages' => array( 'world', 'hello' ),
) + $baseParams );
-
$this->assertEquals(
- $jsonSummary,
- json_encode( $module->getDefinitionSummary( $context ) ),
+ $version,
+ json_encode( $module->getVersionHash( $context ) ),
'Order of messages is insignificant'
);
@@ -54,20 +49,43 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase {
$module = new ResourceLoaderFileModule( array(
'scripts' => array( 'bar.js', 'foo.js' ),
) + $baseParams );
-
$this->assertNotEquals(
- $jsonSummary,
- json_encode( $module->getDefinitionSummary( $context ) ),
+ $version,
+ json_encode( $module->getVersionHash( $context ) ),
'Order of scripts is significant'
);
// Subclass
$module = new ResourceLoaderFileModuleTestModule( $baseParams );
-
$this->assertNotEquals(
- $jsonSummary,
- json_encode( $module->getDefinitionSummary( $context ) ),
+ $version,
+ json_encode( $module->getVersionHash( $context ) ),
'Class is significant'
);
}
+
+ /**
+ * @covers ResourceLoaderModule::validateScriptFile
+ */
+ public function testValidateScriptFile() {
+ $context = $this->getResourceLoaderContext();
+
+ $module = new ResourceLoaderTestModule( array(
+ 'script' => "var a = 'this is';\n {\ninvalid"
+ ) );
+ $this->assertEquals(
+ $module->getScript( $context ),
+ 'mw.log.error("JavaScript parse error: Parse error: Unexpected token; token } expected in file \'input\' on line 3");',
+ 'Replace invalid syntax with error logging'
+ );
+
+ $module = new ResourceLoaderTestModule( array(
+ 'script' => "\n'valid';"
+ ) );
+ $this->assertEquals(
+ $module->getScript( $context ),
+ "\n'valid';",
+ 'Leave valid scripts as-is'
+ );
+ }
}
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
index 7f3506cc..cb916142 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
@@ -10,7 +10,8 @@ class ResourceLoaderStartUpModuleTest extends ResourceLoaderTestCase {
'out' => '
mw.loader.addSource( {
"local": "/w/load.php"
-} );mw.loader.register( [] );'
+} );
+mw.loader.register( [] );'
) ),
array( array(
'msg' => 'Basic registry',
@@ -20,10 +21,11 @@ mw.loader.addSource( {
'out' => '
mw.loader.addSource( {
"local": "/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.blank",
- 1388534400
+ "wvTifjse"
]
] );',
) ),
@@ -37,20 +39,21 @@ mw.loader.addSource( {
'out' => '
mw.loader.addSource( {
"local": "/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.blank",
- 1388534400
+ "wvTifjse"
],
[
"test.group.foo",
- 1388534400,
+ "wvTifjse",
[],
"x-foo"
],
[
"test.group.bar",
- 1388534400,
+ "wvTifjse",
[],
"x-bar"
]
@@ -65,10 +68,11 @@ mw.loader.addSource( {
'out' => '
mw.loader.addSource( {
"local": "/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.blank",
- 1388534400
+ "wvTifjse"
]
] );'
) ),
@@ -87,10 +91,11 @@ mw.loader.addSource( {
mw.loader.addSource( {
"local": "/w/load.php",
"example": "http://example.org/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.blank",
- 1388534400,
+ "wvTifjse",
[],
null,
"example"
@@ -123,14 +128,15 @@ mw.loader.addSource( {
'out' => '
mw.loader.addSource( {
"local": "/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.x.core",
- 1388534400
+ "wvTifjse"
],
[
"test.x.polyfill",
- 1388534400,
+ "wvTifjse",
[],
null,
null,
@@ -138,7 +144,7 @@ mw.loader.addSource( {
],
[
"test.y.polyfill",
- 1388534400,
+ "wvTifjse",
[],
null,
null,
@@ -146,7 +152,7 @@ mw.loader.addSource( {
],
[
"test.z.foo",
- 1388534400,
+ "wvTifjse",
[
0,
1,
@@ -219,39 +225,40 @@ mw.loader.addSource( {
mw.loader.addSource( {
"local": "/w/load.php",
"example": "http://example.org/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.blank",
- 1388534400
+ "wvTifjse"
],
[
"test.x.core",
- 1388534400
+ "wvTifjse"
],
[
"test.x.util",
- 1388534400,
+ "wvTifjse",
[
1
]
],
[
"test.x.foo",
- 1388534400,
+ "wvTifjse",
[
1
]
],
[
"test.x.bar",
- 1388534400,
+ "wvTifjse",
[
2
]
],
[
"test.x.quux",
- 1388534400,
+ "wvTifjse",
[
3,
4,
@@ -260,25 +267,25 @@ mw.loader.addSource( {
],
[
"test.group.foo.1",
- 1388534400,
+ "wvTifjse",
[],
"x-foo"
],
[
"test.group.foo.2",
- 1388534400,
+ "wvTifjse",
[],
"x-foo"
],
[
"test.group.bar.1",
- 1388534400,
+ "wvTifjse",
[],
"x-bar"
],
[
"test.group.bar.2",
- 1388534400,
+ "wvTifjse",
[],
"x-bar",
"example"
@@ -342,10 +349,10 @@ mw.loader.addSource( {
$rl->register( $modules );
$module = new ResourceLoaderStartUpModule();
$this->assertEquals(
-'mw.loader.addSource({"local":"/w/load.php"});'
+'mw.loader.addSource({"local":"/w/load.php"});' . "\n"
. 'mw.loader.register(['
-. '["test.blank",1388534400],'
-. '["test.min",1388534400,[0],null,null,'
+. '["test.blank","wvTifjse"],'
+. '["test.min","wvTifjse",[0],null,null,'
. '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"'
. ']]);',
$module->getModuleRegistrations( $context ),
@@ -364,14 +371,15 @@ mw.loader.addSource( {
$this->assertEquals(
'mw.loader.addSource( {
"local": "/w/load.php"
-} );mw.loader.register( [
+} );
+mw.loader.register( [
[
"test.blank",
- 1388534400
+ "wvTifjse"
],
[
"test.min",
- 1388534400,
+ "wvTifjse",
[
0
],
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
index ca7307ec..b6838859 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
@@ -6,17 +6,8 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
parent::setUp();
$this->setMwGlobals( array(
- 'wgResourceLoaderLESSFunctions' => array(
- 'test-sum' => function ( $frame, $less ) {
- $sum = 0;
- foreach ( $frame[2] as $arg ) {
- $sum += (int)$arg[1];
- }
- return $sum;
- },
- ),
'wgResourceLoaderLESSImportPaths' => array(
- dirname( dirname( __DIR__ ) ) . '/data/less/common',
+ dirname( dirname( __DIR__ ) ) . '/data/less/common',
),
'wgResourceLoaderLESSVars' => array(
'foo' => '2px',
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
index 93a3ebba..8cefec75 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php
@@ -31,16 +31,15 @@ class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase {
$module = new ResourceLoaderWikiModule( $params );
$module->setConfig( $config );
- // Use getDefinitionSummary because getPages is protected
- $summary = $module->getDefinitionSummary( ResourceLoaderContext::newDummyContext() );
- $this->assertEquals(
- $expected,
- $summary['pages']
- );
+ // Because getPages is protected..
+ $getPages = new ReflectionMethod( $module, 'getPages' );
+ $getPages->setAccessible( true );
+ $out = $getPages->invoke( $module, ResourceLoaderContext::newDummyContext() );
+ $this->assertEquals( $expected, $out );
}
public static function provideGetPages() {
- $settings = array(
+ $settings = self::getSettings() + array(
'UseSiteJs' => true,
'UseSiteCss' => true,
);
@@ -110,39 +109,27 @@ class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase {
array( array(), 'test1', true ),
// 'site' module with a non-empty page
array(
- array(
- 'MediaWiki:Common.js' => array(
- 'timestamp' => 123456789,
- 'length' => 1234
- )
- ), 'site', false,
+ array( 'MediaWiki:Common.js' => array( 'rev_sha1' => 'dmh6qn', 'rev_len' => 1234 ) ),
+ 'site',
+ false,
),
// 'site' module with an empty page
array(
- array(
- 'MediaWiki:Monobook.js' => array(
- 'timestamp' => 987654321,
- 'length' => 0,
- ),
- ), 'site', false,
+ array( 'MediaWiki:Foo.js' => array( 'rev_sha1' => 'phoi', 'rev_len' => 0 ) ),
+ 'site',
+ false,
),
// 'user' module with a non-empty page
array(
- array(
- 'User:FooBar/common.js' => array(
- 'timestamp' => 246813579,
- 'length' => 25,
- ),
- ), 'user', false,
+ array( 'User:Example/common.js' => array( 'rev_sha1' => 'j7ssba', 'rev_len' => 25 ) ),
+ 'user',
+ false,
),
// 'user' module with an empty page
array(
- array(
- 'User:FooBar/monobook.js' => array(
- 'timestamp' => 1357924680,
- 'length' => 0,
- ),
- ), 'user', true,
+ array( 'User:Example/foo.js' => array( 'rev_sha1' => 'phoi', 'rev_len' => 0 ) ),
+ 'user',
+ true,
),
);
}
diff --git a/tests/phpunit/includes/site/CachingSiteStoreTest.php b/tests/phpunit/includes/site/CachingSiteStoreTest.php
index d0a79803..4305ceb9 100644
--- a/tests/phpunit/includes/site/CachingSiteStoreTest.php
+++ b/tests/phpunit/includes/site/CachingSiteStoreTest.php
@@ -96,17 +96,17 @@ class CachingSiteStoreTest extends MediaWikiTestCase {
->getMock();
// php 5.3 compatibility!
- $self = $this;
+ $that = $this;
$dbSiteStore->expects( $this->any() )
->method( 'getSite' )
- ->will( $this->returnValue( $self->getTestSite() ) );
+ ->will( $this->returnValue( $that->getTestSite() ) );
$dbSiteStore->expects( $this->any() )
->method( 'getSites' )
- ->will( $this->returnCallback( function() use( $self ) {
+ ->will( $this->returnCallback( function() use ( $that ) {
$siteList = new SiteList();
- $siteList->setSite( $self->getTestSite() );
+ $siteList->setSite( $that->getTestSite() );
return $siteList;
} ) );
diff --git a/tests/phpunit/includes/site/DBSiteStoreTest.php b/tests/phpunit/includes/site/DBSiteStoreTest.php
index 673ba54d..48ef5243 100644
--- a/tests/phpunit/includes/site/DBSiteStoreTest.php
+++ b/tests/phpunit/includes/site/DBSiteStoreTest.php
@@ -130,4 +130,28 @@ class DBSiteStoreTest extends MediaWikiTestCase {
$sites = $store->getSites();
$this->assertEquals( 0, $sites->count() );
}
+
+ /**
+ * @covers DBSiteStore::getSites
+ */
+ public function testGetSitesDefaultOrder() {
+ $store = new DBSiteStore();
+ $siteB = new Site();
+ $siteB->setGlobalId( 'B' );
+ $siteA = new Site();
+ $siteA->setGlobalId( 'A' );
+ $store->saveSites( array( $siteB, $siteA ) );
+
+ $sites = $store->getSites();
+ $siteIdentifiers = array();
+ /** @var Site $site */
+ foreach ( $sites as $site ) {
+ $siteIdentifiers[] = $site->getGlobalId();
+ }
+ $this->assertSame( array( 'A', 'B' ), $siteIdentifiers );
+
+ // Note: SiteList::getGlobalIdentifiers uses an other internal state. Iteration must be
+ // tested separately.
+ $this->assertSame( array( 'A', 'B' ), $sites->getGlobalIdentifiers() );
+ }
}
diff --git a/tests/phpunit/includes/site/HashSiteStoreTest.php b/tests/phpunit/includes/site/HashSiteStoreTest.php
index 49a96338..bebc0936 100644
--- a/tests/phpunit/includes/site/HashSiteStoreTest.php
+++ b/tests/phpunit/includes/site/HashSiteStoreTest.php
@@ -32,7 +32,7 @@ class HashSiteStoreTest extends MediaWikiTestCase {
public function testGetSites() {
$expectedSites = array();
- foreach( TestSites::getSites() as $testSite ) {
+ foreach ( TestSites::getSites() as $testSite ) {
$siteId = $testSite->getGlobalId();
$expectedSites[$siteId] = $testSite;
}
diff --git a/tests/phpunit/includes/site/SiteExporterTest.php b/tests/phpunit/includes/site/SiteExporterTest.php
index 19dd0aa1..7be19ef9 100644
--- a/tests/phpunit/includes/site/SiteExporterTest.php
+++ b/tests/phpunit/includes/site/SiteExporterTest.php
@@ -53,7 +53,7 @@ class SiteExporterTest extends PHPUnit_Framework_TestCase {
$exporter->exportSites( array( $foo, $acme ) );
fseek( $tmp, 0 );
- $xml = fread( $tmp, 16*1024 );
+ $xml = fread( $tmp, 16 * 1024 );
$this->assertContains( '<sites ', $xml );
$this->assertContains( '<site>', $xml );
@@ -133,7 +133,7 @@ class SiteExporterTest extends PHPUnit_Framework_TestCase {
$exporter->exportSites( $sites );
fseek( $tmp, 0 );
- $xml = fread( $tmp, 16*1024 );
+ $xml = fread( $tmp, 16 * 1024 );
$actualSites = new SiteList();
$store = $this->newSiteStore( $actualSites );
diff --git a/tests/phpunit/includes/site/SiteImporterTest.php b/tests/phpunit/includes/site/SiteImporterTest.php
index cb0316ab..b11b1a9f 100644
--- a/tests/phpunit/includes/site/SiteImporterTest.php
+++ b/tests/phpunit/includes/site/SiteImporterTest.php
@@ -34,11 +34,11 @@ class SiteImporterTest extends PHPUnit_Framework_TestCase {
private function newSiteImporter( array $expectedSites, $errorCount ) {
$store = $this->getMock( 'SiteStore' );
- $self = $this;
+ $that = $this;
$store->expects( $this->once() )
->method( 'saveSites' )
- ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites, $self ) {
- $self->assertSitesEqual( $expectedSites, $sites );
+ ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites, $that ) {
+ $that->assertSitesEqual( $expectedSites, $sites );
} ) );
$store->expects( $this->any() )
@@ -141,12 +141,12 @@ class SiteImporterTest extends PHPUnit_Framework_TestCase {
/**
* @dataProvider provideImportFromXML
*/
- public function testImportFromXML( $xml, array $expectedSites, $errorCount = 0 ) {
+ public function testImportFromXML( $xml, array $expectedSites, $errorCount = 0 ) {
$importer = $this->newSiteImporter( $expectedSites, $errorCount );
$importer->importFromXML( $xml );
}
- public function testImportFromXML_malformed() {
+ public function testImportFromXML_malformed() {
$this->setExpectedException( 'Exception' );
$store = $this->getMock( 'SiteStore' );
@@ -154,7 +154,7 @@ class SiteImporterTest extends PHPUnit_Framework_TestCase {
$importer->importFromXML( 'THIS IS NOT XML' );
}
- public function testImportFromFile() {
+ public function testImportFromFile() {
$foo = Site::newForType( Site::TYPE_UNKNOWN );
$foo->setGlobalId( 'Foo' );
diff --git a/tests/phpunit/includes/specials/SpecialBlankPageTest.php b/tests/phpunit/includes/specials/SpecialBlankPageTest.php
new file mode 100644
index 00000000..1d4f5e51
--- /dev/null
+++ b/tests/phpunit/includes/specials/SpecialBlankPageTest.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @licence GNU GPL v2+
+ * @author Adam Shorland
+ *
+ * @covers SpecialBlankpage
+ */
+class SpecialBlankPageTest extends SpecialPageTestBase {
+
+ /**
+ * Returns a new instance of the special page under test.
+ *
+ * @return SpecialPage
+ */
+ protected function newSpecialPage() {
+ return new SpecialBlankpage();
+ }
+
+ public function testHasWikiMsg() {
+ list( $html, ) = $this->executeSpecialPage();
+ $this->assertContains( wfMessage( 'intentionallyblankpage' )->text(), $html );
+ }
+
+}
diff --git a/tests/phpunit/includes/specials/SpecialPageTestBase.php b/tests/phpunit/includes/specials/SpecialPageTestBase.php
new file mode 100644
index 00000000..9c7b0f00
--- /dev/null
+++ b/tests/phpunit/includes/specials/SpecialPageTestBase.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * Base class for testing special pages.
+ *
+ * @since 1.26
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ * @author Daniel Kinzler
+ * @author Adam Shorland
+ * @author Thiemo Mättig
+ */
+abstract class SpecialPageTestBase extends MediaWikiTestCase {
+
+ private $obLevel;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->obLevel = ob_get_level();
+ }
+
+ protected function tearDown() {
+ $obLevel = ob_get_level();
+
+ while ( ob_get_level() > $this->obLevel ) {
+ ob_end_clean();
+ }
+
+ if ( $obLevel !== $this->obLevel ) {
+ $this->fail(
+ "Test changed output buffer level: was {$this->obLevel} before test, but $obLevel after test."
+ );
+ }
+
+ parent::tearDown();
+ }
+
+ /**
+ * Returns a new instance of the special page under test.
+ *
+ * @return SpecialPage
+ */
+ abstract protected function newSpecialPage();
+
+ /**
+ * @param string $subPage The subpage parameter to call the page with
+ * @param WebRequest|null $request Web request that may contain URL parameters, etc
+ * @param Language|string|null $language The language which should be used in the context
+ * @param User|null $user The user which should be used in the context of this special page
+ *
+ * @throws Exception
+ * @return array( string, WebResponse ) A two-elements array containing the HTML output
+ * generated by the special page as well as the response object.
+ */
+ protected function executeSpecialPage(
+ $subPage = '',
+ WebRequest $request = null,
+ $language = null,
+ User $user = null
+ ) {
+ $context = $this->newContext( $request, $language, $user );
+
+ $output = new OutputPage( $context );
+ $context->setOutput( $output );
+
+ $page = $this->newSpecialPage();
+ $page->setContext( $context );
+ $output->setTitle( $page->getPageTitle() );
+
+ $html = $this->getHTMLFromSpecialPage( $page, $subPage );
+ $response = $context->getRequest()->response();
+
+ if ( $response instanceof FauxResponse ) {
+ $code = $response->getStatusCode();
+
+ if ( $code > 0 ) {
+ $response->header( 'Status: ' . $code . ' ' . HttpStatus::getMessage( $code ) );
+ }
+ }
+
+ return array( $html, $response );
+ }
+
+ /**
+ * @param WebRequest|null $request
+ * @param Language|string|null $language
+ * @param User|null $user
+ *
+ * @return DerivativeContext
+ */
+ private function newContext(
+ WebRequest $request = null,
+ $language = null,
+ User $user = null
+ ) {
+ $context = new DerivativeContext( RequestContext::getMain() );
+
+ $context->setRequest( $request ?: new FauxRequest() );
+
+ if ( $language !== null ) {
+ $context->setLanguage( $language );
+ }
+
+ if ( $user !== null ) {
+ $context->setUser( $user );
+ }
+
+ $this->setEditTokenFromUser( $context );
+
+ return $context;
+ }
+
+ /**
+ * If we are trying to edit and no token is set, supply one.
+ *
+ * @param DerivativeContext $context
+ */
+ private function setEditTokenFromUser( DerivativeContext $context ) {
+ $request = $context->getRequest();
+
+ // Edits via GET are a security issue and should not succeed. On the other hand, not all
+ // POST requests are edits, but should ignore unused parameters.
+ if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) {
+ $request->setVal( 'wpEditToken', $context->getUser()->getEditToken() );
+ }
+ }
+
+ /**
+ * @param SpecialPage $page
+ * @param string $subPage
+ *
+ * @throws Exception
+ * @return string HTML
+ */
+ private function getHTMLFromSpecialPage( SpecialPage $page, $subPage ) {
+ ob_start();
+
+ try {
+ $page->execute( $subPage );
+
+ $output = $page->getOutput();
+
+ if ( $output->getRedirect() !== '' ) {
+ $output->output();
+ $html = ob_get_contents();
+ } elseif ( $output->isDisabled() ) {
+ $html = ob_get_contents();
+ } else {
+ $html = $output->getHTML();
+ }
+ } catch ( Exception $ex ) {
+ ob_end_clean();
+
+ // Re-throw exception after "finally" handling because PHP 5.3 doesn't have "finally".
+ throw $ex;
+ }
+
+ ob_end_clean();
+
+ return $html;
+ }
+
+}
diff --git a/tests/phpunit/includes/specials/SpecialPreferencesTest.php b/tests/phpunit/includes/specials/SpecialPreferencesTest.php
index 4f6c4116..1545d7ec 100644
--- a/tests/phpunit/includes/specials/SpecialPreferencesTest.php
+++ b/tests/phpunit/includes/specials/SpecialPreferencesTest.php
@@ -4,10 +4,11 @@
*
* Copyright © 2013, Antoine Musso
* Copyright © 2013, Wikimedia Foundation Inc.
- *
*/
/**
+ * @group Database
+ *
* @covers SpecialPreferences
*/
class SpecialPreferencesTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/specials/SpecialSearchTest.php b/tests/phpunit/includes/specials/SpecialSearchTest.php
index 83489c65..13c28381 100644
--- a/tests/phpunit/includes/specials/SpecialSearchTest.php
+++ b/tests/phpunit/includes/specials/SpecialSearchTest.php
@@ -136,9 +136,113 @@ class SpecialSearchTest extends MediaWikiTestCase {
# Compare :-]
$this->assertRegExp(
- '/' . preg_quote( $term ) . '/',
+ '/' . preg_quote( $term, '/' ) . '/',
$pageTitle,
"Search term '{$term}' should not be expanded in Special:Search <title>"
);
}
+
+ public function provideRewriteQueryWithSuggestion() {
+ return array(
+ array(
+ 'With suggestion and no rewritten query shows did you mean',
+ '/Did you mean: <a[^>]+>first suggestion/',
+ new SpecialSearchTestMockResultSet( 'first suggestion', null, array(
+ SearchResult::newFromTitle( Title::newMainPage() ),
+ ) ),
+ ),
+
+ array(
+ 'With rewritten query informs user of change',
+ '/Showing results for <a[^>]+>first suggestion/',
+ new SpecialSearchTestMockResultSet( 'asdf', 'first suggestion', array(
+ SearchResult::newFromTitle( Title::newMainPage() ),
+ ) ),
+ ),
+
+ array(
+ 'When both queries have no results user gets no results',
+ '/There were no results matching the query/',
+ new SpecialSearchTestMockResultSet( 'first suggestion', 'first suggestion', array() ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRewriteQueryWithSuggestion
+ */
+ public function testRewriteQueryWithSuggestion( $message, $expectRegex, $results ) {
+ $mockSearchEngine = $this->mockSearchEngine( $results );
+ $search = $this->getMockBuilder( 'SpecialSearch' )
+ ->setMethods( array( 'getSearchEngine' ) )
+ ->getMock();
+ $search->expects( $this->any() )
+ ->method( 'getSearchEngine' )
+ ->will( $this->returnValue( $mockSearchEngine ) );
+
+ $search->getContext()->setTitle( Title::makeTitle( NS_SPECIAL, 'Search' ) );
+ $search->load();
+ $search->showResults( 'this is a fake search' );
+
+ $html = $search->getContext()->getOutput()->getHTML();
+ foreach ( (array)$expectRegex as $regex ) {
+ $this->assertRegExp( $regex, $html, $message );
+ }
+ }
+
+ protected function mockSearchEngine( $results ) {
+ $mock = $this->getMockBuilder( 'SearchEngine' )
+ ->setMethods( array( 'searchText', 'searchTitle' ) )
+ ->getMock();
+
+ $mock->expects( $this->any() )
+ ->method( 'searchText' )
+ ->will( $this->returnValue( $results ) );
+
+ return $mock;
+ }
+}
+
+class SpecialSearchTestMockResultSet extends SearchResultSet {
+ protected $results;
+ protected $suggestion;
+
+ public function __construct( $suggestion = null, $rewrittenQuery = null, array $results = array(), $containedSyntax = false) {
+ $this->suggestion = $suggestion;
+ $this->rewrittenQuery = $rewrittenQuery;
+ $this->results = $results;
+ $this->containedSyntax = $containedSyntax;
+ }
+
+ public function numRows() {
+ return count( $this->results );
+ }
+
+ public function getTotalHits() {
+ return $this->numRows();
+ }
+
+ public function hasSuggestion() {
+ return $this->suggestion !== null;
+ }
+
+ public function getSuggestionQuery() {
+ return $this->suggestion;
+ }
+
+ public function getSuggestionSnippet() {
+ return $this->suggestion;
+ }
+
+ public function hasRewrittenQuery() {
+ return $this->rewrittenQuery !== null;
+ }
+
+ public function getQueryAfterRewrite() {
+ return $this->rewrittenQuery;
+ }
+
+ public function getQueryAfterRewriteSnippet() {
+ return htmlspecialchars( $this->rewrittenQuery );
+ }
}
diff --git a/tests/phpunit/includes/title/ForeignTitleTest.php b/tests/phpunit/includes/title/ForeignTitleTest.php
index 599d2a33..10b7e28f 100644
--- a/tests/phpunit/includes/title/ForeignTitleTest.php
+++ b/tests/phpunit/includes/title/ForeignTitleTest.php
@@ -59,7 +59,7 @@ class ForeignTitleTest extends MediaWikiTestCase {
$this->assertEquals( $expectedText, $title->getText() );
}
- public function testUnknownNamespaceCheck( ) {
+ public function testUnknownNamespaceCheck() {
$title = new ForeignTitle( null, 'this', 'that' );
$this->assertEquals( false, $title->isNamespaceIdKnown() );
@@ -67,7 +67,7 @@ class ForeignTitleTest extends MediaWikiTestCase {
$this->assertEquals( 'that', $title->getText() );
}
- public function testUnknownNamespaceError( ) {
+ public function testUnknownNamespaceError() {
$this->setExpectedException( 'MWException' );
$title = new ForeignTitle( null, 'this', 'that' );
$title->getNamespaceId();
diff --git a/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php b/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
index cd0d0b1c..1e5f9d01 100644
--- a/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
+++ b/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
@@ -158,7 +158,7 @@ class MediaWikiPageLinkRendererTest extends MediaWikiTestCase {
function ( TitleValue $title ) {
return str_replace( '_', ' ', "$title" );
}
- ));
+ ) );
$renderer = new MediaWikiPageLinkRenderer( $formatter, '/' );
$actual = $renderer->renderWikitextLink( $title, $text );
diff --git a/tests/phpunit/includes/upload/UploadStashTest.php b/tests/phpunit/includes/upload/UploadStashTest.php
index d5d1188e..8f9eabe9 100644
--- a/tests/phpunit/includes/upload/UploadStashTest.php
+++ b/tests/phpunit/includes/upload/UploadStashTest.php
@@ -20,7 +20,7 @@ class UploadStashTest extends MediaWikiTestCase {
parent::setUp();
// Setup a file for bug 29408
- $this->bug29408File = __DIR__ . '/bug29408';
+ $this->bug29408File = wfTempDir() . '/bug29408';
file_put_contents( $this->bug29408File, "\x00" );
self::$users = array(
diff --git a/tests/phpunit/includes/utils/AvroValidatorTest.php b/tests/phpunit/includes/utils/AvroValidatorTest.php
new file mode 100644
index 00000000..52c242c1
--- /dev/null
+++ b/tests/phpunit/includes/utils/AvroValidatorTest.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Tests for IP validity functions.
+ *
+ * Ported from /t/inc/IP.t by avar.
+ *
+ * @group IP
+ * @todo Test methods in this call should be split into a method and a
+ * dataprovider.
+ */
+
+class AvroValidatorTest extends PHPUnit_Framework_TestCase {
+ public function setUp() {
+ if ( !class_exists( 'AvroSchema' ) ) {
+ $this->markTestSkipped( 'Avro is required to run the AvroValidatorTest' );
+ }
+ parent::setUp();
+ }
+
+ public function getErrorsProvider() {
+ $stringSchema = AvroSchema::parse( json_encode( array( 'type' => 'string' ) ) );
+ $recordSchema = AvroSchema::parse( json_encode( array(
+ 'type' => 'record',
+ 'name' => 'ut',
+ 'fields' => array(
+ array( 'name' => 'id', 'type' => 'int', 'required' => true ),
+ ),
+ ) ) );
+ $enumSchema = AvroSchema::parse( json_encode( array(
+ 'type' => 'record',
+ 'name' => 'ut',
+ 'fields' => array(
+ array( 'name' => 'count', 'type' => array( 'int', 'null' ) ),
+ ),
+ ) ) );
+
+ return array(
+ array(
+ 'No errors with a simple string serialization',
+ $stringSchema, 'foobar', array(),
+ ),
+
+ array(
+ 'Cannot serialize integer into string',
+ $stringSchema, 5, 'Expected string, but recieved integer',
+ ),
+
+ array(
+ 'Cannot serialize array into string',
+ $stringSchema, array(), 'Expected string, but recieved array',
+ ),
+
+ array(
+ 'allows and ignores extra fields',
+ $recordSchema, array( 'id' => 4, 'foo' => 'bar' ), array(),
+ ),
+
+ array(
+ 'detects missing fields',
+ $recordSchema, array(), array( 'id' => 'Missing expected field' ),
+ ),
+
+ array(
+ 'handles first element in enum',
+ $enumSchema, array( 'count' => 4 ), array(),
+ ),
+
+ array(
+ 'handles second element in enum',
+ $enumSchema, array( 'count' => null ), array(),
+ ),
+
+ array(
+ 'rejects element not in union',
+ $enumSchema, array( 'count' => 'invalid' ), array( 'count' => array(
+ 'Expected any one of these to be true',
+ array(
+ 'Expected integer, but recieved string',
+ 'Expected null, but recieved string',
+ )
+ ) )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getErrorsProvider
+ */
+ public function testGetErrors( $message, $schema, $datum, $expected ) {
+ $this->assertEquals(
+ $expected,
+ AvroValidator::getErrors( $schema, $datum ),
+ $message
+ );
+ }
+}
diff --git a/tests/phpunit/includes/utils/BatchRowUpdateTest.php b/tests/phpunit/includes/utils/BatchRowUpdateTest.php
new file mode 100644
index 00000000..a2b35f39
--- /dev/null
+++ b/tests/phpunit/includes/utils/BatchRowUpdateTest.php
@@ -0,0 +1,243 @@
+<?php
+
+/**
+ * Tests for BatchRowUpdate and its components
+ *
+ * @group db
+ */
+class BatchRowUpdateTest extends MediaWikiTestCase {
+
+ public function testWriterBasicFunctionality() {
+ $db = $this->mockDb();
+ $writer = new BatchRowWriter( $db, 'echo_event' );
+
+ $updates = array(
+ self::mockUpdate( array( 'something' => 'changed' ) ),
+ self::mockUpdate( array( 'otherthing' => 'changed' ) ),
+ self::mockUpdate( array( 'and' => 'something', 'else' => 'changed' ) ),
+ );
+
+ $db->expects( $this->exactly( count( $updates ) ) )
+ ->method( 'update' );
+
+ $writer->write( $updates );
+ }
+
+ static protected function mockUpdate( array $changes ) {
+ static $i = 0;
+ return array(
+ 'primaryKey' => array( 'event_id' => $i++ ),
+ 'changes' => $changes,
+ );
+ }
+
+ public function testReaderBasicIterate() {
+ $db = $this->mockDb();
+ $batchSize = 2;
+ $reader = new BatchRowIterator( $db, 'some_table', 'id_field', $batchSize );
+
+ $response = $this->genSelectResult( $batchSize, /*numRows*/ 5, function() {
+ static $i = 0;
+ return array( 'id_field' => ++$i );
+ } );
+ $db->expects( $this->exactly( count( $response ) ) )
+ ->method( 'select' )
+ ->will( $this->consecutivelyReturnFromSelect( $response ) );
+
+ $pos = 0;
+ foreach ( $reader as $rows ) {
+ $this->assertEquals( $response[$pos], $rows, "Testing row in position $pos" );
+ $pos++;
+ }
+ // -1 is because the final array() marks the end and isnt included
+ $this->assertEquals( count( $response ) - 1, $pos );
+ }
+
+ static public function provider_readerGetPrimaryKey() {
+ $row = array(
+ 'id_field' => 42,
+ 'some_col' => 'dvorak',
+ 'other_col' => 'samurai',
+ );
+ return array(
+
+ array(
+ 'Must return single column pk when requested',
+ array( 'id_field' => 42 ),
+ $row
+ ),
+
+ array(
+ 'Must return multiple column pks when requested',
+ array( 'id_field' => 42, 'other_col' => 'samurai' ),
+ $row
+ ),
+
+ );
+ }
+
+ /**
+ * @dataProvider provider_readerGetPrimaryKey
+ */
+ public function testReaderGetPrimaryKey( $message, array $expected, array $row ) {
+ $reader = new BatchRowIterator( $this->mockDb(), 'some_table', array_keys( $expected ), 8675309 );
+ $this->assertEquals( $expected, $reader->extractPrimaryKeys( (object) $row ), $message );
+ }
+
+ static public function provider_readerSetFetchColumns() {
+ return array(
+
+ array(
+ 'Must merge primary keys into select conditions',
+ // Expected column select
+ array( 'foo', 'bar' ),
+ // primary keys
+ array( 'foo' ),
+ // setFetchColumn
+ array( 'bar' )
+ ),
+
+ array(
+ 'Must not merge primary keys into the all columns selector',
+ // Expected column select
+ array( '*' ),
+ // primary keys
+ array( 'foo' ),
+ // setFetchColumn
+ array( '*' ),
+ ),
+
+ array(
+ 'Must not duplicate primary keys into column selector',
+ // Expected column select.
+ // TODO: figure out how to only assert the array_values portion and not the keys
+ array( 0 => 'foo', 1 => 'bar', 3 => 'baz' ),
+ // primary keys
+ array( 'foo', 'bar', ),
+ // setFetchColumn
+ array( 'bar', 'baz' ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_readerSetFetchColumns
+ */
+ public function testReaderSetFetchColumns( $message, array $columns, array $primaryKeys, array $fetchColumns ) {
+ $db = $this->mockDb();
+ $db->expects( $this->once() )
+ ->method( 'select' )
+ ->with( 'some_table', $columns ) // only testing second parameter of DatabaseBase::select
+ ->will( $this->returnValue( new ArrayIterator( array() ) ) );
+
+ $reader = new BatchRowIterator( $db, 'some_table', $primaryKeys, 22 );
+ $reader->setFetchColumns( $fetchColumns );
+ // triggers first database select
+ $reader->rewind();
+ }
+
+ static public function provider_readerSelectConditions() {
+ return array(
+
+ array(
+ "With single primary key must generate id > 'value'",
+ // Expected second iteration
+ array( "( id_field > '3' )" ),
+ // Primary key(s)
+ 'id_field',
+ ),
+
+ array(
+ 'With multiple primary keys the first conditions must use >= and the final condition must use >',
+ // Expected second iteration
+ array( "( id_field = '3' AND foo > '103' ) OR ( id_field > '3' )" ),
+ // Primary key(s)
+ array( 'id_field', 'foo' ),
+ ),
+
+ );
+ }
+
+ /**
+ * Slightly hackish to use reflection, but asserting different parameters
+ * to consecutive calls of DatabaseBase::select in phpunit is error prone
+ *
+ * @dataProvider provider_readerSelectConditions
+ */
+ public function testReaderSelectConditionsMultiplePrimaryKeys( $message, $expectedSecondIteration, $primaryKeys, $batchSize = 3 ) {
+ $results = $this->genSelectResult( $batchSize, $batchSize * 3, function() {
+ static $i = 0, $j = 100, $k = 1000;
+ return array( 'id_field' => ++$i, 'foo' => ++$j, 'bar' => ++$k );
+ } );
+ $db = $this->mockDbConsecutiveSelect( $results );
+
+ $conditions = array( 'bar' => 42, 'baz' => 'hai' );
+ $reader = new BatchRowIterator( $db, 'some_table', $primaryKeys, $batchSize );
+ $reader->addConditions( $conditions );
+
+ $buildConditions = new ReflectionMethod( $reader, 'buildConditions' );
+ $buildConditions->setAccessible( true );
+
+ // On first iteration only the passed conditions must be used
+ $this->assertEquals( $conditions, $buildConditions->invoke( $reader ),
+ 'First iteration must return only the conditions passed in addConditions' );
+ $reader->rewind();
+
+ // Second iteration must use the maximum primary key of last set
+ $this->assertEquals(
+ $conditions + $expectedSecondIteration,
+ $buildConditions->invoke( $reader ),
+ $message
+ );
+ }
+
+ protected function mockDbConsecutiveSelect( array $retvals ) {
+ $db = $this->mockDb();
+ $db->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->consecutivelyReturnFromSelect( $retvals ) );
+ $db->expects( $this->any() )
+ ->method( 'addQuotes' )
+ ->will( $this->returnCallback( function( $value ) {
+ return "'$value'"; // not real quoting: doesn't matter in test
+ } ) );
+
+ return $db;
+ }
+
+ protected function consecutivelyReturnFromSelect( array $results ) {
+ $retvals = array();
+ foreach ( $results as $rows ) {
+ // The DatabaseBase::select method returns iterators, so we do too.
+ $retvals[] = $this->returnValue( new ArrayIterator( $rows ) );
+ }
+
+ return call_user_func_array( array( $this, 'onConsecutiveCalls' ), $retvals );
+ }
+
+
+ protected function genSelectResult( $batchSize, $numRows, $rowGenerator ) {
+ $res = array();
+ for ( $i = 0; $i < $numRows; $i += $batchSize ) {
+ $rows = array();
+ for ( $j = 0; $j < $batchSize && $i + $j < $numRows; $j++ ) {
+ $rows [] = (object) call_user_func( $rowGenerator );
+ }
+ $res[] = $rows;
+ }
+ $res[] = array(); // termination condition requires empty result for last row
+ return $res;
+ }
+
+ protected function mockDb() {
+ // Cant mock from DatabaseType or DatabaseBase, they dont
+ // have the full gamut of methods
+ $databaseMysql = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $databaseMysql->expects( $this->any() )
+ ->method( 'isOpen' )
+ ->will( $this->returnValue( true ) );
+ return $databaseMysql;
+ }
+}
diff --git a/tests/phpunit/includes/utils/IPTest.php b/tests/phpunit/includes/utils/IPTest.php
index 886ee908..34aff796 100644
--- a/tests/phpunit/includes/utils/IPTest.php
+++ b/tests/phpunit/includes/utils/IPTest.php
@@ -11,29 +11,37 @@
class IPTest extends PHPUnit_Framework_TestCase {
/**
- * not sure it should be tested with boolean false. hashar 20100924
* @covers IP::isIPAddress
+ * @dataProvider provideInvalidIPs
*/
- public function testisIPAddress() {
- $this->assertFalse( IP::isIPAddress( false ), 'Boolean false is not an IP' );
- $this->assertFalse( IP::isIPAddress( true ), 'Boolean true is not an IP' );
- $this->assertFalse( IP::isIPAddress( "" ), 'Empty string is not an IP' );
- $this->assertFalse( IP::isIPAddress( 'abc' ), 'Garbage IP string' );
- $this->assertFalse( IP::isIPAddress( ':' ), 'Single ":" is not an IP' );
- $this->assertFalse( IP::isIPAddress( '2001:0DB8::A:1::1' ), 'IPv6 with a double :: occurrence' );
- $this->assertFalse(
- IP::isIPAddress( '2001:0DB8::A:1::' ),
- 'IPv6 with a double :: occurrence, last at end'
- );
- $this->assertFalse(
- IP::isIPAddress( '::2001:0DB8::5:1' ),
- 'IPv6 with a double :: occurrence, firt at beginning'
+ public function isNotIPAddress( $val, $desc ) {
+ $this->assertFalse( IP::isIPAddress( $val ), $desc );
+ }
+
+ /**
+ * Provide a list of things that aren't IP addresses
+ */
+ public function provideInvalidIPs() {
+ return array(
+ array( false, 'Boolean false is not an IP' ),
+ array( true, 'Boolean true is not an IP' ),
+ array( '', 'Empty string is not an IP' ),
+ array( 'abc', 'Garbage IP string' ),
+ array( ':', 'Single ":" is not an IP' ),
+ array( '2001:0DB8::A:1::1', 'IPv6 with a double :: occurrence' ),
+ array( '2001:0DB8::A:1::', 'IPv6 with a double :: occurrence, last at end' ),
+ array( '::2001:0DB8::5:1', 'IPv6 with a double :: occurrence, firt at beginning' ),
+ array( '124.24.52', 'IPv4 not enough quads' ),
+ array( '24.324.52.13', 'IPv4 out of range' ),
+ array( '.24.52.13', 'IPv4 starts with period' ),
+ array( 'fc:100:300', 'IPv6 with only 3 words' ),
);
- $this->assertFalse( IP::isIPAddress( '124.24.52' ), 'IPv4 not enough quads' );
- $this->assertFalse( IP::isIPAddress( '24.324.52.13' ), 'IPv4 out of range' );
- $this->assertFalse( IP::isIPAddress( '.24.52.13' ), 'IPv4 starts with period' );
- $this->assertFalse( IP::isIPAddress( 'fc:100:300' ), 'IPv6 with only 3 words' );
+ }
+ /**
+ * @covers IP::isIPAddress
+ */
+ public function testisIPAddress() {
$this->assertTrue( IP::isIPAddress( '::' ), 'RFC 4291 IPv6 Unspecified Address' );
$this->assertTrue( IP::isIPAddress( '::1' ), 'RFC 4291 IPv6 Loopback Address' );
$this->assertTrue( IP::isIPAddress( '74.24.52.13/20', 'IPv4 range' ) );
@@ -107,20 +115,42 @@ class IPTest extends PHPUnit_Framework_TestCase {
/**
* @covers IP::isIPv4
+ * @dataProvider provideInvalidIPv4Addresses
+ */
+ public function testisNotIPv4( $bogusIP, $desc ) {
+ $this->assertFalse( IP::isIPv4( $bogusIP ), $desc );
+ }
+
+ public function provideInvalidIPv4Addresses() {
+ return array(
+ array( false, 'Boolean false is not an IP' ),
+ array( true, 'Boolean true is not an IP' ),
+ array( '', 'Empty string is not an IP' ),
+ array( 'abc', 'Letters are not an IP' ),
+ array( ':', 'A colon is not an IP' ),
+ array( '124.24.52', 'IPv4 not enough quads' ),
+ array( '24.324.52.13', 'IPv4 out of range' ),
+ array( '.24.52.13', 'IPv4 starts with period' ),
+ );
+ }
+
+ /**
+ * @covers IP::isIPv4
+ * @dataProvider provideValidIPv4Address
*/
- public function testisIPv4() {
- $this->assertFalse( IP::isIPv4( false ), 'Boolean false is not an IP' );
- $this->assertFalse( IP::isIPv4( true ), 'Boolean true is not an IP' );
- $this->assertFalse( IP::isIPv4( "" ), 'Empty string is not an IP' );
- $this->assertFalse( IP::isIPv4( 'abc' ) );
- $this->assertFalse( IP::isIPv4( ':' ) );
- $this->assertFalse( IP::isIPv4( '124.24.52' ), 'IPv4 not enough quads' );
- $this->assertFalse( IP::isIPv4( '24.324.52.13' ), 'IPv4 out of range' );
- $this->assertFalse( IP::isIPv4( '.24.52.13' ), 'IPv4 starts with period' );
+ public function testIsIPv4( $ip, $desc ) {
+ $this->assertTrue( IP::isIPv4( $ip ), $desc );
+ }
- $this->assertTrue( IP::isIPv4( '124.24.52.13' ) );
- $this->assertTrue( IP::isIPv4( '1.24.52.13' ) );
- $this->assertTrue( IP::isIPv4( '74.24.52.13/20', 'IPv4 range' ) );
+ /**
+ * Provide some IPv4 addresses and ranges
+ */
+ public function provideValidIPv4Address() {
+ return array(
+ array( '124.24.52.13', 'Valid IPv4 address' ),
+ array( '1.24.52.13', 'Another valid IPv4 address' ),
+ array( '74.24.52.13/20', 'An IPv4 range' ),
+ );
}
/**
@@ -224,49 +254,56 @@ class IPTest extends PHPUnit_Framework_TestCase {
}
/**
- * @covers IP::isValidBlock
+ * Provide some valid IP blocks
*/
- public function testValidBlocks() {
- $valid = array(
- '116.17.184.5/32',
- '0.17.184.5/30',
- '16.17.184.1/24',
- '30.242.52.14/1',
- '10.232.52.13/8',
- '30.242.52.14/0',
- '::e:f:2001/96',
- '::c:f:2001/128',
- '::10:f:2001/70',
- '::fe:f:2001/1',
- '::6d:f:2001/8',
- '::fe:f:2001/0',
+ public function provideValidBlocks() {
+ return array(
+ array( '116.17.184.5/32' ),
+ array( '0.17.184.5/30' ),
+ array( '16.17.184.1/24' ),
+ array( '30.242.52.14/1' ),
+ array( '10.232.52.13/8' ),
+ array( '30.242.52.14/0' ),
+ array( '::e:f:2001/96' ),
+ array( '::c:f:2001/128' ),
+ array( '::10:f:2001/70' ),
+ array( '::fe:f:2001/1' ),
+ array( '::6d:f:2001/8' ),
+ array( '::fe:f:2001/0' ),
);
- foreach ( $valid as $i ) {
- $this->assertTrue( IP::isValidBlock( $i ), "$i is a valid IP block" );
- }
}
/**
* @covers IP::isValidBlock
+ * @dataProvider provideValidBlocks
*/
- public function testInvalidBlocks() {
- $invalid = array(
- '116.17.184.5/33',
- '0.17.184.5/130',
- '16.17.184.1/-1',
- '10.232.52.13/*',
- '7.232.52.13/ab',
- '11.232.52.13/',
- '::e:f:2001/129',
- '::c:f:2001/228',
- '::10:f:2001/-1',
- '::6d:f:2001/*',
- '::86:f:2001/ab',
- '::23:f:2001/',
+ public function testValidBlocks( $block ) {
+ $this->assertTrue( IP::isValidBlock( $block ), "$block is a valid IP block" );
+ }
+
+ /**
+ * @covers IP::isValidBlock
+ * @dataProvider provideInvalidBlocks
+ */
+ public function testInvalidBlocks( $invalid ) {
+ $this->assertFalse( IP::isValidBlock( $invalid ), "$invalid is not a valid IP block" );
+ }
+
+ public function provideInvalidBlocks() {
+ return array(
+ array( '116.17.184.5/33' ),
+ array( '0.17.184.5/130' ),
+ array( '16.17.184.1/-1' ),
+ array( '10.232.52.13/*' ),
+ array( '7.232.52.13/ab' ),
+ array( '11.232.52.13/' ),
+ array( '::e:f:2001/129' ),
+ array( '::c:f:2001/228' ),
+ array( '::10:f:2001/-1' ),
+ array( '::6d:f:2001/*' ),
+ array( '::86:f:2001/ab' ),
+ array( '::23:f:2001/' ),
);
- foreach ( $invalid as $i ) {
- $this->assertFalse( IP::isValidBlock( $i ), "$i is not a valid IP block" );
- }
}
/**
@@ -333,16 +370,31 @@ class IPTest extends PHPUnit_Framework_TestCase {
/**
* @covers IP::isPublic
+ * @dataProvider provideIsPublic
*/
- public function testPrivateIPs() {
- $private = array( 'fc00::3', 'fc00::ff', '::1', '10.0.0.1', '172.16.0.1', '192.168.0.1' );
- foreach ( $private as $p ) {
- $this->assertFalse( IP::isPublic( $p ), "$p is not a public IP address" );
- }
- $public = array( '2001:5c0:1000:a::133', 'fc::3', '00FC::' );
- foreach ( $public as $p ) {
- $this->assertTrue( IP::isPublic( $p ), "$p is a public IP address" );
- }
+ public function testIsPublic( $expected, $input ) {
+ $result = IP::isPublic( $input );
+ $this->assertEquals( $expected, $result );
+ }
+
+ /**
+ * Provider for IP::testIsPublic()
+ */
+ public static function provideIsPublic() {
+ return array(
+ array( false, 'fc00::3' ), # RFC 4193 (local)
+ array( false, 'fc00::ff' ), # RFC 4193 (local)
+ array( false, '127.1.2.3' ), # loopback
+ array( false, '::1' ), # loopback
+ array( false, 'fe80::1' ), # link-local
+ array( false, '169.254.1.1' ), # link-local
+ array( false, '10.0.0.1' ), # RFC 1918 (private)
+ array( false, '172.16.0.1' ), # RFC 1918 (private)
+ array( false, '192.168.0.1' ), # RFC 1918 (private)
+ array( true, '2001:5c0:1000:a::133' ), # public
+ array( true, 'fc::3' ), # public
+ array( true, '00FC::' ) # public
+ );
}
// Private wrapper used to test CIDR Parsing.
@@ -359,40 +411,55 @@ class IPTest extends PHPUnit_Framework_TestCase {
/**
* @covers IP::hexToQuad
+ * @dataProvider provideIPsAndHexes
*/
- public function testHexToQuad() {
- $this->assertEquals( '0.0.0.1', IP::hexToQuad( '00000001' ) );
- $this->assertEquals( '255.0.0.0', IP::hexToQuad( 'FF000000' ) );
- $this->assertEquals( '255.255.255.255', IP::hexToQuad( 'FFFFFFFF' ) );
- $this->assertEquals( '10.188.222.255', IP::hexToQuad( '0ABCDEFF' ) );
- // hex not left-padded...
- $this->assertEquals( '0.0.0.0', IP::hexToQuad( '0' ) );
- $this->assertEquals( '0.0.0.1', IP::hexToQuad( '1' ) );
- $this->assertEquals( '0.0.0.255', IP::hexToQuad( 'FF' ) );
- $this->assertEquals( '0.0.255.0', IP::hexToQuad( 'FF00' ) );
+ public function testHexToQuad( $ip, $hex ) {
+ $this->assertEquals( $ip, IP::hexToQuad( $hex ) );
+ }
+
+ /**
+ * Provide some IP addresses and their equivalent hex representations
+ */
+ public function provideIPsandHexes() {
+ return array(
+ array( '0.0.0.1', '00000001' ),
+ array( '255.0.0.0', 'FF000000' ),
+ array( '255.255.255.255', 'FFFFFFFF' ),
+ array( '10.188.222.255', '0ABCDEFF' ),
+ // hex not left-padded...
+ array( '0.0.0.0', '0' ),
+ array( '0.0.0.1', '1' ),
+ array( '0.0.0.255', 'FF' ),
+ array( '0.0.255.0', 'FF00' ),
+ );
}
/**
* @covers IP::hexToOctet
+ * @dataProvider provideOctetsAndHexes
*/
- public function testHexToOctet() {
- $this->assertEquals( '0:0:0:0:0:0:0:1',
- IP::hexToOctet( '00000000000000000000000000000001' ) );
- $this->assertEquals( '0:0:0:0:0:0:FF:3',
- IP::hexToOctet( '00000000000000000000000000FF0003' ) );
- $this->assertEquals( '0:0:0:0:0:0:FF00:6',
- IP::hexToOctet( '000000000000000000000000FF000006' ) );
- $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF',
- IP::hexToOctet( '000000000000000000000000FCCFFAFF' ) );
- $this->assertEquals( 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',
- IP::hexToOctet( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' ) );
- // hex not left-padded...
- $this->assertEquals( '0:0:0:0:0:0:0:0', IP::hexToOctet( '0' ) );
- $this->assertEquals( '0:0:0:0:0:0:0:1', IP::hexToOctet( '1' ) );
- $this->assertEquals( '0:0:0:0:0:0:0:FF', IP::hexToOctet( 'FF' ) );
- $this->assertEquals( '0:0:0:0:0:0:0:FFD0', IP::hexToOctet( 'FFD0' ) );
- $this->assertEquals( '0:0:0:0:0:0:FA00:0', IP::hexToOctet( 'FA000000' ) );
- $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF', IP::hexToOctet( 'FCCFFAFF' ) );
+ public function testHexToOctet( $octet, $hex ) {
+ $this->assertEquals( $octet, IP::hexToOctet( $hex ) );
+ }
+
+ /**
+ * Provide some hex and octet representations of the same IPs
+ */
+ public function provideOctetsAndHexes() {
+ return array(
+ array( '0:0:0:0:0:0:0:1', '00000000000000000000000000000001' ),
+ array( '0:0:0:0:0:0:FF:3', '00000000000000000000000000FF0003' ),
+ array( '0:0:0:0:0:0:FF00:6', '000000000000000000000000FF000006' ),
+ array( '0:0:0:0:0:0:FCCF:FAFF', '000000000000000000000000FCCFFAFF' ),
+ array( 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF', 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' ),
+ // hex not left-padded...
+ array( '0:0:0:0:0:0:0:0', '0' ),
+ array( '0:0:0:0:0:0:0:1', '1' ),
+ array( '0:0:0:0:0:0:0:FF', 'FF' ),
+ array( '0:0:0:0:0:0:0:FFD0', 'FFD0' ),
+ array( '0:0:0:0:0:0:FA00:0', 'FA000000' ),
+ array( '0:0:0:0:0:0:FCCF:FAFF', 'FCCFFAFF' ),
+ );
}
/**
diff --git a/tests/phpunit/includes/utils/MWFunctionTest.php b/tests/phpunit/includes/utils/MWFunctionTest.php
deleted file mode 100644
index f4d17999..00000000
--- a/tests/phpunit/includes/utils/MWFunctionTest.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/**
- * @covers MWFunction
- */
-class MWFunctionTest extends MediaWikiTestCase {
- public function testNewObjFunction() {
- $arg1 = 'Foo';
- $arg2 = 'Bar';
- $arg3 = array( 'Baz' );
- $arg4 = new ExampleObject;
-
- $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
- );
- }
-}
-
-class MWBlankClass {
-
- public $args = array();
-
- function __construct( $arg1, $arg2, $arg3, $arg4 ) {
- $this->args = array( $arg1, $arg2, $arg3, $arg4 );
- }
-}
-
-class ExampleObject {
-}
diff --git a/tests/phpunit/includes/utils/UIDGeneratorTest.php b/tests/phpunit/includes/utils/UIDGeneratorTest.php
index 0e11ccad..fedcc762 100644
--- a/tests/phpunit/includes/utils/UIDGeneratorTest.php
+++ b/tests/phpunit/includes/utils/UIDGeneratorTest.php
@@ -1,6 +1,6 @@
<?php
-class UIDGeneratorTest extends MediaWikiTestCase {
+class UIDGeneratorTest extends PHPUnit_Framework_TestCase {
protected function tearDown() {
// Bug: 44850
@@ -28,7 +28,7 @@ class UIDGeneratorTest extends MediaWikiTestCase {
$lastId = array_shift( $ids );
- $this->assertArrayEquals( array_unique( $ids ), $ids, "All generated IDs are unique." );
+ $this->assertSame( array_unique( $ids ), $ids, "All generated IDs are unique." );
foreach ( $ids as $id ) {
$id_bin = wfBaseConvert( $id, 10, 2 );
@@ -105,8 +105,8 @@ class UIDGeneratorTest extends MediaWikiTestCase {
$id1 = UIDGenerator::newSequentialPerNodeID( 'test', 32 );
$id2 = UIDGenerator::newSequentialPerNodeID( 'test', 32 );
- $this->assertType( 'float', $id1, "ID returned as float" );
- $this->assertType( 'float', $id2, "ID returned as float" );
+ $this->assertInternalType( 'float', $id1, "ID returned as float" );
+ $this->assertInternalType( 'float', $id2, "ID returned as float" );
$this->assertGreaterThan( 0, $id1, "ID greater than 1" );
$this->assertGreaterThan( $id1, $id2, "IDs increasing in value" );
}
@@ -118,7 +118,7 @@ class UIDGeneratorTest extends MediaWikiTestCase {
$ids = UIDGenerator::newSequentialPerNodeIDs( 'test', 32, 5 );
$lastId = null;
foreach ( $ids as $id ) {
- $this->assertType( 'float', $id, "ID returned as float" );
+ $this->assertInternalType( 'float', $id, "ID returned as float" );
$this->assertGreaterThan( 0, $id, "ID greater than 1" );
if ( $lastId ) {
$this->assertGreaterThan( $lastId, $id, "IDs increasing in value" );