diff options
Diffstat (limited to 'tests/phpunit/includes')
89 files changed, 5199 insertions, 3675 deletions
diff --git a/tests/phpunit/includes/ArticleTablesTest.php b/tests/phpunit/includes/ArticleTablesTest.php index 01776c95..02571b55 100644 --- a/tests/phpunit/includes/ArticleTablesTest.php +++ b/tests/phpunit/includes/ArticleTablesTest.php @@ -6,29 +6,28 @@ class ArticleTablesTest extends MediaWikiLangTestCase { function testbug14404() { - global $wgUser, $wgContLang, $wgLanguageCode, $wgLang; - - $title = Title::newFromText("Bug 14404"); - $article = new Article( $title ); - $wgUser = new User(); - $wgUser->mRights = array( 'createpage', 'edit', 'purge' ); + global $wgContLang, $wgLanguageCode, $wgLang; + + $title = Title::newFromText( 'Bug 14404' ); + $page = WikiPage::factory( $title ); + $user = new User(); + $user->mRights = array( 'createpage', 'edit', 'purge' ); $wgLanguageCode = 'es'; $wgContLang = Language::factory( 'es' ); - + $wgLang = Language::factory( 'fr' ); - $status = $article->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', 0 ); - $templates1 = $article->getUsedTemplates(); + $status = $page->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', 0, false, $user ); + $templates1 = $page->getUsedTemplates(); $wgLang = Language::factory( 'de' ); - $article->mParserOptions = null; // Let it pick the new user language - $article->mPreparedEdit = false; // In order to force the rerendering of the same wikitext - + $page->mPreparedEdit = false; // In order to force the rerendering of the same wikitext + // We need an edit, a purge is not enough to regenerate the tables - $status = $article->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', EDIT_UPDATE ); - $templates2 = $article->getUsedTemplates(); - + $status = $page->doEdit( '{{:{{int:history}}}}', 'Test code for bug 14404', EDIT_UPDATE, false, $user ); + $templates2 = $page->getUsedTemplates(); + $this->assertEquals( $templates1, $templates2 ); $this->assertEquals( $templates1[0]->getFullText(), 'Historial' ); } - + } diff --git a/tests/phpunit/includes/ArticleTest.php b/tests/phpunit/includes/ArticleTest.php index 285efee9..846d2b86 100644 --- a/tests/phpunit/includes/ArticleTest.php +++ b/tests/phpunit/includes/ArticleTest.php @@ -19,25 +19,25 @@ class ArticleTest extends MediaWikiTestCase { } - function testImplementsGetMagic() { - $this->assertEquals( -1, $this->article->mCounter, "Article __get magic" ); + function testImplementsGetMagic() { + $this->assertEquals( false, $this->article->mLatest, "Article __get magic" ); } /** * @depends testImplementsGetMagic */ function testImplementsSetMagic() { - - $this->article->mCounter = 2; - $this->assertEquals( 2, $this->article->mCounter, "Article __set magic" ); + $this->article->mLatest = 2; + $this->assertEquals( 2, $this->article->mLatest, "Article __set magic" ); } /** * @depends testImplementsSetMagic */ function testImplementsCallMagic() { - $this->article->mCounter = 33; - $this->assertEquals( 33, $this->article->getCount(), "Article __call magic" ); + $this->article->mLatest = 33; + $this->article->mDataLoaded = true; + $this->assertEquals( 33, $this->article->getLatest(), "Article __call magic" ); } function testGetOrSetOnNewProperty() { diff --git a/tests/phpunit/includes/BlockTest.php b/tests/phpunit/includes/BlockTest.php index 2f224ba8..749f40b4 100644 --- a/tests/phpunit/includes/BlockTest.php +++ b/tests/phpunit/includes/BlockTest.php @@ -2,11 +2,10 @@ /** * @group Database + * @group Blocking */ class BlockTest extends MediaWikiLangTestCase { - const REASON = "Some reason"; - private $block, $madeAt; /* variable used to save up the blockID we insert in this test suite */ @@ -36,8 +35,8 @@ class BlockTest extends MediaWikiLangTestCase { $oldBlock->delete(); } - $this->block = new Block( 'UTBlockee', 1, 0, - self::REASON + $this->block = new Block( 'UTBlockee', $user->getID(), 0, + 'Parce que', 0, false, time() + 100500 ); $this->madeAt = wfTimestamp( TS_MW ); @@ -68,7 +67,7 @@ class BlockTest extends MediaWikiLangTestCase { // $this->dumpBlocks(); $this->assertTrue( $this->block->equals( Block::newFromTarget('UTBlockee') ), "newFromTarget() returns the same block as the one that was made"); - + $this->assertTrue( $this->block->equals( Block::newFromID( $this->blockId ) ), "newFromID() returns the same block as the one that was made"); } @@ -77,8 +76,9 @@ class BlockTest extends MediaWikiLangTestCase { * per bug 26425 */ function testBug26425BlockTimestampDefaultsToTime() { - - $this->assertEquals( $this->madeAt, $this->block->mTimestamp, "If no timestamp is specified, the block is recorded as time()"); + // delta to stop one-off errors when things happen to go over a second mark. + $delta = abs( $this->madeAt - $this->block->mTimestamp ); + $this->assertLessThan( 2, $delta, "If no timestamp is specified, the block is recorded as time()"); } @@ -91,6 +91,8 @@ class BlockTest extends MediaWikiLangTestCase { * @dataProvider dataBug29116 */ function testBug29116LoadWithEmptyIp( $vagueTarget ) { + $this->hideDeprecated( 'Block::load' ); + $uid = User::idFromName( 'UTBlockee' ); $this->assertTrue( ($uid > 0), 'Must be able to look up the target user during tests' ); @@ -121,4 +123,3 @@ class BlockTest extends MediaWikiLangTestCase { ); } } - diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php new file mode 100644 index 00000000..e98e9707 --- /dev/null +++ b/tests/phpunit/includes/EditPageTest.php @@ -0,0 +1,33 @@ +<?php + +class EditPageTest extends MediaWikiTestCase { + + /** + * @dataProvider dataExtractSectionTitle + */ + function testExtractSectionTitle( $section, $title ) { + $extracted = EditPage::extractSectionTitle( $section ); + $this->assertEquals( $title, $extracted ); + } + + function dataExtractSectionTitle() { + return array( + array( + "== Test ==\n\nJust a test section.", + "Test" + ), + array( + "An initial section, no header.", + false + ), + array( + "An initial section with a fake heder (bug 32617)\n\n== Test == ??\nwtf", + false + ), + array( + "== Section ==\nfollowed by a fake == Non-section == ??\nnoooo", + "Section" + ) + ); + } +} diff --git a/tests/phpunit/includes/ExtraParserTest.php b/tests/phpunit/includes/ExtraParserTest.php index 5b0aa98b..a9088cb2 100644 --- a/tests/phpunit/includes/ExtraParserTest.php +++ b/tests/phpunit/includes/ExtraParserTest.php @@ -10,11 +10,13 @@ class ExtraParserTest extends MediaWikiTestCase { global $wgContLang; global $wgShowDBErrorBacktrace; global $wgLanguageCode; + global $wgAlwaysUseTidy; $wgShowDBErrorBacktrace = true; $wgLanguageCode = 'en'; $wgContLang = new Language( 'en' ); $wgMemc = new EmptyBagOStuff; + $wgAlwaysUseTidy = false; $this->options = new ParserOptions; $this->options->setTemplateCallback( array( __CLASS__, 'statelessFetchTemplate' ) ); @@ -61,20 +63,48 @@ class ExtraParserTest extends MediaWikiTestCase { * cleanSig() makes all templates substs and removes tildes */ function testCleanSig() { + global $wgCleanSignatures; + $oldCleanSignature = $wgCleanSignatures; + $wgCleanSignatures = true; + $title = Title::newFromText( __FUNCTION__ ); $outputText = $this->parser->cleanSig( "{{Foo}} ~~~~" ); + + $wgCleanSignatures = $oldCleanSignature; $this->assertEquals( "{{SUBST:Foo}} ", $outputText ); } - + /** - * cleanSigInSig() just removes tildes + * cleanSig() should do nothing if disabled */ - function testCleanSigInSig() { + function testCleanSigDisabled() { + global $wgCleanSignatures; + $oldCleanSignature = $wgCleanSignatures; + $wgCleanSignatures = false; + $title = Title::newFromText( __FUNCTION__ ); - $outputText = $this->parser->cleanSigInSig( "{{Foo}} ~~~~" ); + $outputText = $this->parser->cleanSig( "{{Foo}} ~~~~" ); + + $wgCleanSignatures = $oldCleanSignature; - $this->assertEquals( "{{Foo}} ", $outputText ); + $this->assertEquals( "{{Foo}} ~~~~", $outputText ); + } + + /** + * cleanSigInSig() just removes tildes + * @dataProvider provideStringsForCleanSigInSig + */ + function testCleanSigInSig( $in, $out ) { + $this->assertEquals( Parser::cleanSigInSig( $in), $out ); + } + + function provideStringsForCleanSigInSig() { + return array( + array( "{{Foo}} ~~~~", "{{Foo}} " ), + array( "~~~", "" ), + array( "~~~~~", "" ), + ); } function testGetSection() { @@ -110,4 +140,28 @@ class ExtraParserTest extends MediaWikiTestCase { 'finalTitle' => $title, 'deps' => $deps ); } + + /** + * @group Database + */ + function testTrackingCategory() { + $title = Title::newFromText( __FUNCTION__ ); + $catName = wfMsgForContent( 'broken-file-category' ); + $cat = Title::makeTitleSafe( NS_CATEGORY, $catName ); + $expected = array( $cat->getDBkey() ); + $parserOutput = $this->parser->parse( "[[file:nonexistent]]" , $title, $this->options ); + $result = $parserOutput->getCategoryLinks(); + $this->assertEquals( $expected, $result ); + } + + /** + * @group Database + */ + function testTrackingCategorySpecial() { + // Special pages shouldn't have tracking cats. + $title = SpecialPage::getTitleFor( 'Contributions' ); + $parserOutput = $this->parser->parse( "[[file:nonexistent]]" , $title, $this->options ); + $result = $parserOutput->getCategoryLinks(); + $this->assertEmpty( $result ); + } } diff --git a/tests/phpunit/includes/FormOptionsInitializationTest.php b/tests/phpunit/includes/FormOptionsInitializationTest.php index 85d76271..d86c95d7 100644 --- a/tests/phpunit/includes/FormOptionsInitializationTest.php +++ b/tests/phpunit/includes/FormOptionsInitializationTest.php @@ -25,9 +25,9 @@ class FormOptionsExposed extends FormOptions { * * Generated by PHPUnit on 2011-02-28 at 20:46:27. * - * Copyright © 2011, Ashar Voultoiz + * Copyright © 2011, Antoine Musso * - * @author Ashar Voultoiz + * @author Antoine Musso */ class FormOptionsInitializationTest extends MediaWikiTestCase { /** diff --git a/tests/phpunit/includes/FormOptionsTest.php b/tests/phpunit/includes/FormOptionsTest.php index 86618d93..749343ec 100644 --- a/tests/phpunit/includes/FormOptionsTest.php +++ b/tests/phpunit/includes/FormOptionsTest.php @@ -12,9 +12,9 @@ * Test class for FormOptions methods. * Generated by PHPUnit on 2011-02-28 at 20:46:27. * - * Copyright © 2011, Ashar Voultoiz + * Copyright © 2011, Antoine Musso * - * @author Ashar Voultoiz + * @author Antoine Musso */ class FormOptionsTest extends MediaWikiTestCase { /** diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php index 3d157d0a..3cb42f12 100644 --- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php +++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php @@ -94,24 +94,80 @@ class GlobalTest extends MediaWikiTestCase { $this->assertTrue( $end > $start, "Time is running backwards!" ); } - function testArrayToCGI() { + function dataArrayToCGI() { + return array( + array( array(), '' ), // empty + array( array( 'foo' => 'bar' ), 'foo=bar' ), // string test + array( array( 'foo' => '' ), 'foo=' ), // empty string test + array( array( 'foo' => 1 ), 'foo=1' ), // number test + array( array( 'foo' => true ), 'foo=1' ), // true test + array( array( 'foo' => false ), '' ), // false test + array( array( 'foo' => null ), '' ), // null test + array( array( 'foo' => 'A&B=5+6@!"\'' ), 'foo=A%26B%3D5%2B6%40%21%22%27' ), // urlencoding test + array( array( 'foo' => 'bar', 'baz' => 'is', 'asdf' => 'qwerty' ), 'foo=bar&baz=is&asdf=qwerty' ), // multi-item test + array( array( 'foo' => array( 'bar' => 'baz' ) ), 'foo%5Bbar%5D=baz' ), + array( array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ), 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf' ), + array( array( 'foo' => array( 'bar', 'baz' ) ), 'foo%5B0%5D=bar&foo%5B1%5D=baz' ), + array( array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ), 'foo%5Bbar%5D%5Bbar%5D=baz' ), + ); + } + + /** + * @dataProvider dataArrayToCGI + */ + function testArrayToCGI( $array, $result ) { + $this->assertEquals( $result, wfArrayToCGI( $array ) ); + } + + + function testArrayToCGI2() { $this->assertEquals( - "baz=AT%26T&foo=bar", + "baz=bar&foo=bar", wfArrayToCGI( - array( 'baz' => 'AT&T', 'ignore' => '' ), + array( 'baz' => 'bar' ), array( 'foo' => 'bar', 'baz' => 'overridden value' ) ) ); - $this->assertEquals( - "path%5B0%5D=wiki&path%5B1%5D=test&cfg%5Bservers%5D%5Bhttp%5D=localhost", - wfArrayToCGI( array( - 'path' => array( 'wiki', 'test' ), - 'cfg' => array( 'servers' => array( 'http' => 'localhost' ) ) ) ) ); } - function testCgiToArray() { - $this->assertEquals( - array( 'path' => array( 'wiki', 'test' ), - 'cfg' => array( 'servers' => array( 'http' => 'localhost' ) ) ), - wfCgiToArray( 'path%5B0%5D=wiki&path%5B1%5D=test&cfg%5Bservers%5D%5Bhttp%5D=localhost' ) ); + function dataCgiToArray() { + return array( + array( '', array() ), // empty + array( 'foo=bar', array( 'foo' => 'bar' ) ), // string + array( 'foo=', array( 'foo' => '' ) ), // empty string + array( 'foo', array( 'foo' => '' ) ), // missing = + array( 'foo=bar&qwerty=asdf', array( 'foo' => 'bar', 'qwerty' => 'asdf' ) ), // multiple value + array( 'foo=A%26B%3D5%2B6%40%21%22%27', array( 'foo' => 'A&B=5+6@!"\'' ) ), // urldecoding test + array( 'foo%5Bbar%5D=baz', array( 'foo' => array( 'bar' => 'baz' ) ) ), + array( 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf', array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ) ), + array( 'foo%5B0%5D=bar&foo%5B1%5D=baz', array( 'foo' => array( 0 => 'bar', 1 => 'baz' ) ) ), + array( 'foo%5Bbar%5D%5Bbar%5D=baz', array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ) ), + ); + } + + /** + * @dataProvider dataCgiToArray + */ + function testCgiToArray( $cgi, $result ) { + $this->assertEquals( $result, wfCgiToArray( $cgi ) ); + } + + function dataCgiRoundTrip() { + return array( + array( '' ), + array( 'foo=bar' ), + array( 'foo=' ), + array( 'foo=bar&baz=biz' ), + array( 'foo=A%26B%3D5%2B6%40%21%22%27' ), + array( 'foo%5Bbar%5D=baz' ), + array( 'foo%5B0%5D=bar&foo%5B1%5D=baz' ), + array( 'foo%5Bbar%5D%5Bbar%5D=baz' ), + ); + } + + /** + * @dataProvider dataCgiRoundTrip + */ + function testCgiRoundTrip( $cgi ) { + $this->assertEquals( $cgi, wfArrayToCGI( wfCgiToArray( $cgi ) ) ); } function testMimeTypeMatch() { @@ -176,263 +232,6 @@ class GlobalTest extends MediaWikiTestCase { array( 'text/*' => 1.0 ), array( 'application/xhtml+xml' => 1.0 ) ) ); } - - function testTimestamp() { - $t = gmmktime( 12, 34, 56, 1, 15, 2001 ); - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, $t ), - 'TS_UNIX to TS_MW' ); - $this->assertEquals( - '19690115123456', - wfTimestamp( TS_MW, -30281104 ), - 'Negative TS_UNIX to TS_MW' ); - $this->assertEquals( - 979562096, - wfTimestamp( TS_UNIX, $t ), - 'TS_UNIX to TS_UNIX' ); - $this->assertEquals( - '2001-01-15 12:34:56', - wfTimestamp( TS_DB, $t ), - 'TS_UNIX to TS_DB' ); - $this->assertEquals( - '20010115T123456Z', - wfTimestamp( TS_ISO_8601_BASIC, $t ), - 'TS_ISO_8601_BASIC to TS_DB' ); - - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, '20010115123456' ), - 'TS_MW to TS_MW' ); - $this->assertEquals( - 979562096, - wfTimestamp( TS_UNIX, '20010115123456' ), - 'TS_MW to TS_UNIX' ); - $this->assertEquals( - '2001-01-15 12:34:56', - wfTimestamp( TS_DB, '20010115123456' ), - 'TS_MW to TS_DB' ); - $this->assertEquals( - '20010115T123456Z', - wfTimestamp( TS_ISO_8601_BASIC, '20010115123456' ), - 'TS_MW to TS_ISO_8601_BASIC' ); - - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, '2001-01-15 12:34:56' ), - 'TS_DB to TS_MW' ); - $this->assertEquals( - 979562096, - wfTimestamp( TS_UNIX, '2001-01-15 12:34:56' ), - 'TS_DB to TS_UNIX' ); - $this->assertEquals( - '2001-01-15 12:34:56', - wfTimestamp( TS_DB, '2001-01-15 12:34:56' ), - 'TS_DB to TS_DB' ); - $this->assertEquals( - '20010115T123456Z', - wfTimestamp( TS_ISO_8601_BASIC, '2001-01-15 12:34:56' ), - 'TS_DB to TS_ISO_8601_BASIC' ); - - # rfc2822 section 3.3 - - $this->assertEquals( - 'Mon, 15 Jan 2001 12:34:56 GMT', - wfTimestamp( TS_RFC2822, '20010115123456' ), - 'TS_MW to TS_RFC2822' ); - - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, 'Mon, 15 Jan 2001 12:34:56 GMT' ), - 'TS_RFC2822 to TS_MW' ); - - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, ' Mon, 15 Jan 2001 12:34:56 GMT' ), - 'TS_RFC2822 with leading space to TS_MW' ); - - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, '15 Jan 2001 12:34:56 GMT' ), - 'TS_RFC2822 without optional day-of-week to TS_MW' ); - - # FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space - # obs-FWS = 1*WSP *(CRLF 1*WSP) ; Section 4.2 - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, 'Mon, 15 Jan 2001 12:34:56 GMT' ), - 'TS_RFC2822 to TS_MW' ); - - # WSP = SP / HTAB ; rfc2234 - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, "Mon, 15 Jan\x092001 12:34:56 GMT" ), - 'TS_RFC2822 with HTAB to TS_MW' ); - - $this->assertEquals( - '20010115123456', - wfTimestamp( TS_MW, "Mon, 15 Jan\x09 \x09 2001 12:34:56 GMT" ), - 'TS_RFC2822 with HTAB and SP to TS_MW' ); - - $this->assertEquals( - '19941106084937', - wfTimestamp( TS_MW, "Sun, 6 Nov 94 08:49:37 GMT" ), - 'TS_RFC2822 with obsolete year to TS_MW' ); - } - - /** - * This test checks wfTimestamp() with values outside. - * It needs PHP 64 bits or PHP > 5.1. - * See r74778 and bug 25451 - */ - function testOldTimestamps() { - $this->assertEquals( 'Fri, 13 Dec 1901 20:45:54 GMT', - wfTimestamp( TS_RFC2822, '19011213204554' ), - 'Earliest time according to php documentation' ); - - $this->assertEquals( 'Tue, 19 Jan 2038 03:14:07 GMT', - wfTimestamp( TS_RFC2822, '20380119031407' ), - 'Latest 32 bit time' ); - - $this->assertEquals( '-2147483648', - wfTimestamp( TS_UNIX, '19011213204552' ), - 'Earliest 32 bit unix time' ); - - $this->assertEquals( '2147483647', - wfTimestamp( TS_UNIX, '20380119031407' ), - 'Latest 32 bit unix time' ); - - $this->assertEquals( 'Fri, 13 Dec 1901 20:45:52 GMT', - wfTimestamp( TS_RFC2822, '19011213204552' ), - 'Earliest 32 bit time' ); - - $this->assertEquals( 'Fri, 13 Dec 1901 20:45:51 GMT', - wfTimestamp( TS_RFC2822, '19011213204551' ), - 'Earliest 32 bit time - 1' ); - - $this->assertEquals( 'Tue, 19 Jan 2038 03:14:08 GMT', - wfTimestamp( TS_RFC2822, '20380119031408' ), - 'Latest 32 bit time + 1' ); - - $this->assertEquals( '19011212000000', - wfTimestamp(TS_MW, '19011212000000'), - 'Convert to itself r74778#c10645' ); - - $this->assertEquals( '-2147483649', - wfTimestamp( TS_UNIX, '19011213204551' ), - 'Earliest 32 bit unix time - 1' ); - - $this->assertEquals( '2147483648', - wfTimestamp( TS_UNIX, '20380119031408' ), - 'Latest 32 bit unix time + 1' ); - - $this->assertEquals( '19011213204551', - wfTimestamp( TS_MW, '-2147483649' ), - '1901 negative unix time to MediaWiki' ); - - $this->assertEquals( '18010115123456', - wfTimestamp( TS_MW, '-5331871504' ), - '1801 negative unix time to MediaWiki' ); - - $this->assertEquals( 'Tue, 09 Aug 0117 12:34:56 GMT', - wfTimestamp( TS_RFC2822, '0117-08-09 12:34:56'), - 'Death of Roman Emperor [[Trajan]]'); - - /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */ - - $this->assertEquals( 'Sun, 01 Jan 0101 00:00:00 GMT', - wfTimestamp( TS_RFC2822, '-58979923200'), - '1/1/101'); - - $this->assertEquals( 'Mon, 01 Jan 0001 00:00:00 GMT', - wfTimestamp( TS_RFC2822, '-62135596800'), - 'Year 1'); - - /* It is not clear if we should generate a year 0 or not - * We are completely off RFC2822 requirement of year being - * 1900 or later. - */ - $this->assertEquals( 'Wed, 18 Oct 0000 00:00:00 GMT', - wfTimestamp( TS_RFC2822, '-62142076800'), - 'ISO 8601:2004 [[year 0]], also called [[1 BC]]'); - } - - function testHttpDate() { - # The Resource Loader uses wfTimestamp() to convert timestamps - # from If-Modified-Since header. - # Thus it must be able to parse all rfc2616 date formats - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 - - $this->assertEquals( - '19941106084937', - wfTimestamp( TS_MW, 'Sun, 06 Nov 1994 08:49:37 GMT' ), - 'RFC 822 date' ); - - $this->assertEquals( - '19941106084937', - wfTimestamp( TS_MW, 'Sunday, 06-Nov-94 08:49:37 GMT' ), - 'RFC 850 date' ); - - $this->assertEquals( - '19941106084937', - wfTimestamp( TS_MW, 'Sun Nov 6 08:49:37 1994' ), - "ANSI C's asctime() format" ); - - // See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html and r77171 - $this->assertEquals( - '20101122141242', - wfTimestamp( TS_MW, 'Mon, 22 Nov 2010 14:12:42 GMT; length=52626' ), - "Netscape extension to HTTP/1.0" ); - - } - - function testTimestampParameter() { - // There are a number of assumptions in our codebase where wfTimestamp() should give - // the current date but it is not given a 0 there. See r71751 CR - - $now = wfTimestamp( TS_UNIX ); - // We check that wfTimestamp doesn't return false (error) and use a LessThan assert - // for the cases where the test is run in a second boundary. - - $zero = wfTimestamp( TS_UNIX, 0 ); - $this->assertNotEquals( false, $zero ); - $this->assertLessThan( 5, $zero - $now ); - - $empty = wfTimestamp( TS_UNIX, '' ); - $this->assertNotEquals( false, $empty ); - $this->assertLessThan( 5, $empty - $now ); - - $null = wfTimestamp( TS_UNIX, null ); - $this->assertNotEquals( false, $null ); - $this->assertLessThan( 5, $null - $now ); - } - - function testBasename() { - $sets = array( - '' => '', - '/' => '', - '\\' => '', - '//' => '', - '\\\\' => '', - 'a' => 'a', - 'aaaa' => 'aaaa', - '/a' => 'a', - '\\a' => 'a', - '/aaaa' => 'aaaa', - '\\aaaa' => 'aaaa', - '/aaaa/' => 'aaaa', - '\\aaaa\\' => 'aaaa', - '\\aaaa\\' => 'aaaa', - '/mnt/upload3/wikipedia/en/thumb/8/8b/Zork_Grand_Inquisitor_box_cover.jpg/93px-Zork_Grand_Inquisitor_box_cover.jpg' => '93px-Zork_Grand_Inquisitor_box_cover.jpg', - 'C:\\Progra~1\\Wikime~1\\Wikipe~1\\VIEWER.EXE' => 'VIEWER.EXE', - 'Östergötland_coat_of_arms.png' => 'Östergötland_coat_of_arms.png', - ); - foreach ( $sets as $from => $to ) { - $this->assertEquals( $to, wfBaseName( $from ), - "wfBaseName('$from') => '$to'" ); - } - } - function testFallbackMbstringFunctions() { @@ -701,135 +500,6 @@ class GlobalTest extends MediaWikiTestCase { ); } - - /** - * test @see wfBCP47(). - * Please note the BCP explicitly state that language codes are case - * insensitive, there are some exceptions to the rule :) - * This test is used to verify our formatting against all lower and - * all upper cases language code. - * - * @see http://tools.ietf.org/html/bcp47 - * @dataProvider provideLanguageCodes() - */ - function testBCP47( $code, $expected ) { - $code = strtolower( $code ); - $this->assertEquals( $expected, wfBCP47($code), - "Applying BCP47 standard to lower case '$code'" - ); - - $code = strtoupper( $code ); - $this->assertEquals( $expected, wfBCP47($code), - "Applying BCP47 standard to upper case '$code'" - ); - } - - /** - * Array format is ($code, $expected) - */ - function provideLanguageCodes() { - return array( - // Extracted from BCP47 (list not exhaustive) - # 2.1.1 - array( 'en-ca-x-ca' , 'en-CA-x-ca' ), - array( 'sgn-be-fr' , 'sgn-BE-FR' ), - array( 'az-latn-x-latn', 'az-Latn-x-latn' ), - # 2.2 - array( 'sr-Latn-RS', 'sr-Latn-RS' ), - array( 'az-arab-ir', 'az-Arab-IR' ), - - # 2.2.5 - array( 'sl-nedis' , 'sl-nedis' ), - array( 'de-ch-1996', 'de-CH-1996' ), - - # 2.2.6 - array( - 'en-latn-gb-boont-r-extended-sequence-x-private', - 'en-Latn-GB-boont-r-extended-sequence-x-private' - ), - - // Examples from BCP47 Appendix A - # Simple language subtag: - array( 'DE', 'de' ), - array( 'fR', 'fr' ), - array( 'ja', 'ja' ), - - # Language subtag plus script subtag: - array( 'zh-hans', 'zh-Hans'), - array( 'sr-cyrl', 'sr-Cyrl'), - array( 'sr-latn', 'sr-Latn'), - - # Extended language subtags and their primary language subtag - # counterparts: - array( 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ), - array( 'cmn-hans-cn' , 'cmn-Hans-CN' ), - array( 'zh-yue-hk' , 'zh-yue-HK' ), - array( 'yue-hk' , 'yue-HK' ), - - # Language-Script-Region: - array( 'zh-hans-cn', 'zh-Hans-CN' ), - array( 'sr-latn-RS', 'sr-Latn-RS' ), - - # Language-Variant: - array( 'sl-rozaj' , 'sl-rozaj' ), - array( 'sl-rozaj-biske', 'sl-rozaj-biske' ), - array( 'sl-nedis' , 'sl-nedis' ), - - # Language-Region-Variant: - array( 'de-ch-1901' , 'de-CH-1901' ), - array( 'sl-it-nedis' , 'sl-IT-nedis' ), - - # Language-Script-Region-Variant: - array( 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ), - - # Language-Region: - array( 'de-de' , 'de-DE' ), - array( 'en-us' , 'en-US' ), - array( 'es-419', 'es-419'), - - # Private use subtags: - array( 'de-ch-x-phonebk' , 'de-CH-x-phonebk' ), - array( 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ), - /** - * Previous test does not reflect the BCP which states: - * az-Arab-x-AZE-derbend - * AZE being private, it should be lower case, hence the test above - * should probably be: - #array( 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ), - */ - - # Private use registry values: - array( 'x-whatever', 'x-whatever' ), - array( 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ), - array( 'de-qaaa' , 'de-Qaaa' ), - array( 'sr-latn-qm', 'sr-Latn-QM' ), - array( 'sr-qaaa-rs', 'sr-Qaaa-RS' ), - - # Tags that use extensions - array( 'en-us-u-islamcal', 'en-US-u-islamcal' ), - array( 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ), - array( 'en-a-myext-b-another', 'en-a-myext-b-another' ), - - # Invalid: - // de-419-DE - // a-DE - // ar-a-aaa-b-bbb-a-ccc - - /* - // ISO 15924 : - array( 'sr-Cyrl', 'sr-Cyrl' ), - # @todo FIXME: Fix our function? - array( 'SR-lATN', 'sr-Latn' ), - array( 'fr-latn', 'fr-Latn' ), - // Use lowercase for single segment - // ISO 3166-1-alpha-2 code - array( 'US', 'us' ), # USA - array( 'uS', 'us' ), # USA - array( 'Fr', 'fr' ), # France - array( 'va', 'va' ), # Holy See (Vatican City State) - */); - } - /** * @dataProvider provideMakeUrlIndexes() */ @@ -886,7 +556,63 @@ class GlobalTest extends MediaWikiTestCase { ), ); } + + /** + * @dataProvider provideWfMatchesDomainList + */ + function testWfMatchesDomainList( $url, $domains, $expected, $description ) { + $actual = wfMatchesDomainList( $url, $domains ); + $this->assertEquals( $expected, $actual, $description ); + } + + function provideWfMatchesDomainList() { + $a = array(); + $protocols = array( 'HTTP' => 'http:', 'HTTPS' => 'https:', 'protocol-relative' => '' ); + foreach ( $protocols as $pDesc => $p ) { + $a = array_merge( $a, array( + array( "$p//www.example.com", array(), false, "No matches for empty domains array, $pDesc URL" ), + array( "$p//www.example.com", array( 'www.example.com' ), true, "Exact match in domains array, $pDesc URL" ), + array( "$p//www.example.com", array( 'example.com' ), true, "Match without subdomain in domains array, $pDesc URL" ), + array( "$p//www.example2.com", array( 'www.example.com', 'www.example2.com', 'www.example3.com' ), true, "Exact match with other domains in array, $pDesc URL" ), + array( "$p//www.example2.com", array( 'example.com', 'example2.com', 'example3,com' ), true, "Match without subdomain with other domains in array, $pDesc URL" ), + array( "$p//www.example4.com", array( 'example.com', 'example2.com', 'example3,com' ), false, "Domain not in array, $pDesc URL" ), + + // FIXME: This is a bug in wfMatchesDomainList(). If and when this is fixed, update this test case + array( "$p//nds-nl.wikipedia.org", array( 'nl.wikipedia.org' ), true, "Substrings of domains match while they shouldn't, $pDesc URL" ), + ) ); + } + return $a; + } + /** + * @dataProvider provideWfShellMaintenanceCmdList + */ + function testWfShellMaintenanceCmd( $script, $parameters, $options, $expected, $description ) { + if( wfIsWindows() ) { + // Approximation that's good enough for our purposes just now + $expected = str_replace( "'", '"', $expected ); + } + $actual = wfShellMaintenanceCmd( $script, $parameters, $options ); + $this->assertEquals( $expected, $actual, $description ); + } + + function provideWfShellMaintenanceCmdList() { + global $wgPhpCli; + return array( + array( 'eval.php', array( '--help', '--test' ), array(), + "'$wgPhpCli' 'eval.php' '--help' '--test'", + "Called eval.php --help --test" ), + array( 'eval.php', array( '--help', '--test space' ), array('php' => 'php5'), + "'php5' 'eval.php' '--help' '--test space'", + "Called eval.php --help --test with php option" ), + array( 'eval.php', array( '--help', '--test', 'X' ), array('wrapper' => 'MWScript.php'), + "'$wgPhpCli' 'MWScript.php' 'eval.php' '--help' '--test' 'X'", + "Called eval.php --help --test with wrapper option" ), + array( 'eval.php', array( '--help', '--test', 'y' ), array('php' => 'php5', 'wrapper' => 'MWScript.php'), + "'php5' 'MWScript.php' 'eval.php' '--help' '--test' 'y'", + "Called eval.php --help --test with wrapper and php option" ), + ); + } /* TODO: many more! */ } diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php new file mode 100644 index 00000000..4879a38d --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php @@ -0,0 +1,29 @@ +<?php + +/** + * @group Database + */ +class GlobalWithDBTest extends MediaWikiTestCase { + /** + * @dataProvider provideWfIsBadImageList + */ + function testWfIsBadImage( $name, $title, $blacklist, $expected, $desc ) { + $this->assertEquals( $expected, wfIsBadImage( $name, $title, $blacklist ), $desc ); + } + + function provideWfIsBadImageList() { + $blacklist = '* [[File:Bad.jpg]] except [[Nasty page]]'; + return array( + array( 'Bad.jpg', false, $blacklist, true, + 'Called on a bad image' ), + array( 'Bad.jpg', Title::makeTitle( NS_MAIN, 'A page' ), $blacklist, true, + 'Called on a bad image' ), + array( 'NotBad.jpg', false, $blacklist, false, + 'Called on a non-bad image' ), + array( 'Bad.jpg', Title::makeTitle( NS_MAIN, 'Nasty page' ), $blacklist, false, + 'Called on a bad image but is on a whitelisted page' ), + array( 'File:Bad.jpg', false, $blacklist, false, + 'Called on a bad image with File:' ), + ); + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php b/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php new file mode 100644 index 00000000..be6c99e7 --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php @@ -0,0 +1,111 @@ +<?php +/** + * Unit tests for wfAssembleUrl() + */ + +class wfAssembleUrl extends MediaWikiTestCase { + /** @dataProvider provideURLParts */ + public function testWfAssembleUrl( $parts, $output ) { + $partsDump = print_r( $parts, true ); + $this->assertEquals( + $output, + wfAssembleUrl( $parts ), + "Testing $partsDump assembles to $output" + ); + } + + /** + * Provider of URL parts for testing wfAssembleUrl() + * + * @return array + */ + public function provideURLParts() { + $schemes = array( + '' => array(), + '//' => array( + 'delimiter' => '//', + ), + 'http://' => array( + 'scheme' => 'http', + 'delimiter' => '://', + ), + ); + + $hosts = array( + '' => array(), + 'example.com' => array( + 'host' => 'example.com', + ), + 'example.com:123' => array( + 'host' => 'example.com', + 'port' => 123, + ), + 'id@example.com' => array( + 'user' => 'id', + 'host' => 'example.com', + ), + 'id@example.com:123' => array( + 'user' => 'id', + 'host' => 'example.com', + 'port' => 123, + ), + 'id:key@example.com' => array( + 'user' => 'id', + 'pass' => 'key', + 'host' => 'example.com', + ), + 'id:key@example.com:123' => array( + 'user' => 'id', + 'pass' => 'key', + 'host' => 'example.com', + 'port' => 123, + ), + ); + + $cases = array(); + foreach ( $schemes as $scheme => $schemeParts ) { + foreach ( $hosts as $host => $hostParts ) { + foreach ( array( '', '/path' ) as $path ) { + foreach ( array( '', 'query' ) as $query ) { + foreach ( array( '', 'fragment' ) as $fragment ) { + $parts = array_merge( + $schemeParts, + $hostParts + ); + $url = $scheme . + $host . + $path; + + if ( $path ) { + $parts['path'] = $path; + } + if ( $query ) { + $parts['query'] = $query; + $url .= '?' . $query; + } + if( $fragment ) { + $parts['fragment'] = $fragment; + $url .= '#' . $fragment; + } + + + $cases[] = array( + $parts, + $url, + ); + } + } + } + } + } + + $complexURL = 'http://id:key@example.org:321' . + '/over/there?name=ferret&foo=bar#nose'; + $cases[] = array( + wfParseUrl( $complexURL ), + $complexURL, + ); + + return $cases; + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php b/tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php new file mode 100644 index 00000000..f4ec7a5f --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php @@ -0,0 +1,133 @@ +<?php +/** + * Unit tests for wfBCP47() + */ +class wfBCP47 extends MediaWikiTestCase { + /** + * test @see wfBCP47(). + * Please note the BCP explicitly state that language codes are case + * insensitive, there are some exceptions to the rule :) + * This test is used to verify our formatting against all lower and + * all upper cases language code. + * + * @see http://tools.ietf.org/html/bcp47 + * @dataProvider provideLanguageCodes() + */ + function testBCP47( $code, $expected ) { + $code = strtolower( $code ); + $this->assertEquals( $expected, wfBCP47($code), + "Applying BCP47 standard to lower case '$code'" + ); + + $code = strtoupper( $code ); + $this->assertEquals( $expected, wfBCP47($code), + "Applying BCP47 standard to upper case '$code'" + ); + } + + /** + * Array format is ($code, $expected) + */ + function provideLanguageCodes() { + return array( + // Extracted from BCP47 (list not exhaustive) + # 2.1.1 + array( 'en-ca-x-ca' , 'en-CA-x-ca' ), + array( 'sgn-be-fr' , 'sgn-BE-FR' ), + array( 'az-latn-x-latn', 'az-Latn-x-latn' ), + # 2.2 + array( 'sr-Latn-RS', 'sr-Latn-RS' ), + array( 'az-arab-ir', 'az-Arab-IR' ), + + # 2.2.5 + array( 'sl-nedis' , 'sl-nedis' ), + array( 'de-ch-1996', 'de-CH-1996' ), + + # 2.2.6 + array( + 'en-latn-gb-boont-r-extended-sequence-x-private', + 'en-Latn-GB-boont-r-extended-sequence-x-private' + ), + + // Examples from BCP47 Appendix A + # Simple language subtag: + array( 'DE', 'de' ), + array( 'fR', 'fr' ), + array( 'ja', 'ja' ), + + # Language subtag plus script subtag: + array( 'zh-hans', 'zh-Hans'), + array( 'sr-cyrl', 'sr-Cyrl'), + array( 'sr-latn', 'sr-Latn'), + + # Extended language subtags and their primary language subtag + # counterparts: + array( 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ), + array( 'cmn-hans-cn' , 'cmn-Hans-CN' ), + array( 'zh-yue-hk' , 'zh-yue-HK' ), + array( 'yue-hk' , 'yue-HK' ), + + # Language-Script-Region: + array( 'zh-hans-cn', 'zh-Hans-CN' ), + array( 'sr-latn-RS', 'sr-Latn-RS' ), + + # Language-Variant: + array( 'sl-rozaj' , 'sl-rozaj' ), + array( 'sl-rozaj-biske', 'sl-rozaj-biske' ), + array( 'sl-nedis' , 'sl-nedis' ), + + # Language-Region-Variant: + array( 'de-ch-1901' , 'de-CH-1901' ), + array( 'sl-it-nedis' , 'sl-IT-nedis' ), + + # Language-Script-Region-Variant: + array( 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ), + + # Language-Region: + array( 'de-de' , 'de-DE' ), + array( 'en-us' , 'en-US' ), + array( 'es-419', 'es-419'), + + # Private use subtags: + array( 'de-ch-x-phonebk' , 'de-CH-x-phonebk' ), + array( 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ), + /** + * Previous test does not reflect the BCP which states: + * az-Arab-x-AZE-derbend + * AZE being private, it should be lower case, hence the test above + * should probably be: + #array( 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ), + */ + + # Private use registry values: + array( 'x-whatever', 'x-whatever' ), + array( 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ), + array( 'de-qaaa' , 'de-Qaaa' ), + array( 'sr-latn-qm', 'sr-Latn-QM' ), + array( 'sr-qaaa-rs', 'sr-Qaaa-RS' ), + + # Tags that use extensions + array( 'en-us-u-islamcal', 'en-US-u-islamcal' ), + array( 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ), + array( 'en-a-myext-b-another', 'en-a-myext-b-another' ), + + # Invalid: + // de-419-DE + // a-DE + // ar-a-aaa-b-bbb-a-ccc + + /* + // ISO 15924 : + array( 'sr-Cyrl', 'sr-Cyrl' ), + # @todo FIXME: Fix our function? + array( 'SR-lATN', 'sr-Latn' ), + array( 'fr-latn', 'fr-Latn' ), + // Use lowercase for single segment + // ISO 3166-1-alpha-2 code + array( 'US', 'us' ), # USA + array( 'uS', 'us' ), # USA + array( 'Fr', 'fr' ), # France + array( 'va', 'va' ), # Holy See (Vatican City State) + */); + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php b/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php new file mode 100644 index 00000000..59954b23 --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php @@ -0,0 +1,36 @@ +<?php +/** + * Tests for wfBaseName() + */ +class wfBaseName extends MediaWikiTestCase { + /** + * @dataProvider providePaths + */ + function testBaseName( $fullpath, $basename ) { + $this->assertEquals( $basename, wfBaseName( $fullpath ), + "wfBaseName('$fullpath') => '$basename'" ); + } + + function providePaths() { + return array( + array( '', '' ), + array( '/', '' ), + array( '\\', '' ), + array( '//', '' ), + array( '\\\\', '' ), + array( 'a', 'a' ), + array( 'aaaa', 'aaaa' ), + array( '/a', 'a' ), + array( '\\a', 'a' ), + array( '/aaaa', 'aaaa' ), + array( '\\aaaa', 'aaaa' ), + array( '/aaaa/', 'aaaa' ), + array( '\\aaaa\\', 'aaaa' ), + array( '\\aaaa\\', 'aaaa' ), + array( '/mnt/upload3/wikipedia/en/thumb/8/8b/Zork_Grand_Inquisitor_box_cover.jpg/93px-Zork_Grand_Inquisitor_box_cover.jpg', + '93px-Zork_Grand_Inquisitor_box_cover.jpg' ), + array( 'C:\\Progra~1\\Wikime~1\\Wikipe~1\\VIEWER.EXE', 'VIEWER.EXE' ), + array( 'Östergötland_coat_of_arms.png', 'Östergötland_coat_of_arms.png' ), + ); + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfExpandUrl.php b/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php index b388b266..192689f8 100644 --- a/tests/phpunit/includes/GlobalFunctions/wfExpandUrl.php +++ b/tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php @@ -1,5 +1,5 @@ <?php -/* +/** * Unit tests for wfExpandUrl() */ @@ -12,16 +12,16 @@ class wfExpandUrl extends MediaWikiTestCase { $oldCanServer = $wgCanonicalServer; $wgServer = $server; $wgCanonicalServer = $canServer; - + // Fake $_SERVER['HTTPS'] if needed if ( $httpsMode ) { $_SERVER['HTTPS'] = 'on'; } else { unset( $_SERVER['HTTPS'] ); } - + $this->assertEquals( $fullUrl, wfExpandUrl( $shortUrl, $defaultProto ), $message ); - + // Restore $wgServer and $wgCanonicalServer $wgServer = $oldServer; $wgCanonicalServer = $oldCanServer; @@ -29,12 +29,14 @@ class wfExpandUrl extends MediaWikiTestCase { /** * Provider of URL examples for testing wfExpandUrl() + * + * @return array */ public function provideExpandableUrls() { $modes = array( 'http', 'https' ); $servers = array( 'http' => 'http://example.com', 'https' => 'https://example.com', 'protocol-relative' => '//example.com' ); $defaultProtos = array( 'http' => PROTO_HTTP, 'https' => PROTO_HTTPS, 'protocol-relative' => PROTO_RELATIVE, 'current' => PROTO_CURRENT, 'canonical' => PROTO_CANONICAL ); - + $retval = array(); foreach ( $modes as $mode ) { $httpsMode = $mode == 'https'; @@ -46,14 +48,14 @@ class wfExpandUrl extends MediaWikiTestCase { $retval[] = array( 'https://example.com', 'https://example.com', $defaultProto, $server, $canServer, $httpsMode, "Testing fully qualified https URLs (no need to expand) (defaultProto: $protoDesc , wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" ); # Would be nice to support this, see fixme on wfExpandUrl() $retval[] = array( "wiki/FooBar", 'wiki/FooBar', $defaultProto, $server, $canServer, $httpsMode, "Test non-expandable relative URLs (defaultProto: $protoDesc , wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" ); - + // Determine expected protocol $p = $protoDesc . ':'; // default case if ( $protoDesc == 'protocol-relative' ) { $p = ''; - } else if ( $protoDesc == 'current' ) { + } elseif ( $protoDesc == 'current' ) { $p = "$mode:"; - } else if ( $protoDesc == 'canonical' ) { + } elseif ( $protoDesc == 'canonical' ) { $p = "$canServerMode:"; } else { $p = $protoDesc . ':'; @@ -61,12 +63,12 @@ class wfExpandUrl extends MediaWikiTestCase { // Determine expected server name if ( $protoDesc == 'canonical' ) { $srv = $canServer; - } else if ( $serverDesc == 'protocol-relative' ) { + } elseif ( $serverDesc == 'protocol-relative' ) { $srv = $p . $server; } else { $srv = $server; } - + $retval[] = array( "$p//wikipedia.org", '//wikipedia.org', $defaultProto, $server, $canServer, $httpsMode, "Test protocol-relative URL (defaultProto: $protoDesc, wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" ); $retval[] = array( "$srv/wiki/FooBar", '/wiki/FooBar', $defaultProto, $server, $canServer, $httpsMode, "Testing expanding URL beginning with / (defaultProto: $protoDesc , wgServer: $server, wgCanonicalServer: $canServer, current request protocol: $mode )" ); } diff --git a/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php b/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php new file mode 100644 index 00000000..1cf0e0fb --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php @@ -0,0 +1,90 @@ +<?php +/** + * Unit tests for wfRemoveDotSegments() + */ + +class wfRemoveDotSegments extends MediaWikiTestCase { + /** @dataProvider providePaths */ + public function testWfRemoveDotSegments( $inputPath, $outputPath ) { + $this->assertEquals( + $outputPath, + wfRemoveDotSegments( $inputPath ), + "Testing $inputPath expands to $outputPath" + ); + } + + /** + * Provider of URL paths for testing wfRemoveDotSegments() + * + * @return array + */ + public function providePaths() { + return array( + array( '/a/b/c/./../../g', '/a/g' ), + array( 'mid/content=5/../6', 'mid/6' ), + array( '/a//../b', '/a/b' ), + array( '/.../a', '/.../a' ), + array( '.../a', '.../a' ), + array( '', '' ), + array( '/', '/' ), + array( '//', '//' ), + array( '.', '' ), + array( '..', '' ), + array( '...', '...' ), + array( '/.', '/' ), + array( '/..', '/' ), + array( './', '' ), + array( '../', '' ), + array( './a', 'a' ), + array( '../a', 'a' ), + array( '../../a', 'a' ), + array( '.././a', 'a' ), + array( './../a', 'a' ), + array( '././a', 'a' ), + array( '../../', '' ), + array( '.././', '' ), + array( './../', '' ), + array( '././', '' ), + array( '../..', '' ), + array( '../.', '' ), + array( './..', '' ), + array( './.', '' ), + array( '/../../a', '/a' ), + array( '/.././a', '/a' ), + array( '/./../a', '/a' ), + array( '/././a', '/a' ), + array( '/../../', '/' ), + array( '/.././', '/' ), + array( '/./../', '/' ), + array( '/././', '/' ), + array( '/../..', '/' ), + array( '/../.', '/' ), + array( '/./..', '/' ), + array( '/./.', '/' ), + array( 'b/../../a', '/a' ), + array( 'b/.././a', '/a' ), + array( 'b/./../a', '/a' ), + array( 'b/././a', 'b/a' ), + array( 'b/../../', '/' ), + array( 'b/.././', '/' ), + array( 'b/./../', '/' ), + array( 'b/././', 'b/' ), + array( 'b/../..', '/' ), + array( 'b/../.', '/' ), + array( 'b/./..', '/' ), + array( 'b/./.', 'b/' ), + array( '/b/../../a', '/a' ), + array( '/b/.././a', '/a' ), + array( '/b/./../a', '/a' ), + array( '/b/././a', '/b/a' ), + array( '/b/../../', '/' ), + array( '/b/.././', '/' ), + array( '/b/./../', '/' ), + array( '/b/././', '/b/' ), + array( '/b/../..', '/' ), + array( '/b/../.', '/' ), + array( '/b/./..', '/' ), + array( '/b/./.', '/b/' ), + ); + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php b/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php new file mode 100644 index 00000000..1df26d2c --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php @@ -0,0 +1,28 @@ +<?php + +class wfShorthandToIntegerTest extends MediaWikiTestCase { + /** + * @dataProvider provideABunchOfShorthands + */ + function testWfShorthandToInteger( $input, $output, $description ) { + $this->assertEquals( + wfShorthandToInteger( $input ), + $output, + $description + ); + } + + function provideABunchOfShorthands() { + return array( + array( '', -1, 'Empty string' ), + array( ' ', -1, 'String of spaces' ), + array( '1G', 1024 * 1024 * 1024, 'One gig uppercased' ), + array( '1g', 1024 * 1024 * 1024, 'One gig lowercased' ), + array( '1M', 1024 * 1024, 'One meg uppercased' ), + array( '1m', 1024 * 1024, 'One meg lowercased' ), + array( '1K', 1024, 'One kb uppercased' ), + array( '1k', 1024, 'One kb lowercased' ), + ); + } + +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php new file mode 100644 index 00000000..505c28c7 --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php @@ -0,0 +1,134 @@ +<?php + +/* + * Tests for wfTimestamp() + */ +class wfTimestamp extends MediaWikiTestCase { + /** + * @dataProvider provideNormalTimestamps + */ + function testNormalTimestamps( $input, $format, $output, $desc ) { + $this->assertEquals( $output, wfTimestamp( $format, $input ), $desc ); + } + + function provideNormalTimestamps() { + $t = gmmktime( 12, 34, 56, 1, 15, 2001 ); + return array ( + // TS_UNIX + array( $t, TS_MW, '20010115123456', 'TS_UNIX to TS_MW' ), + array( -30281104, TS_MW, '19690115123456', 'Negative TS_UNIX to TS_MW' ), + array( $t, TS_UNIX, 979562096, 'TS_UNIX to TS_UNIX' ), + array( $t, TS_DB, '2001-01-15 12:34:56', 'TS_UNIX to TS_DB' ), + + array( $t, TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_ISO_8601_BASIC to TS_DB' ), + + // TS_MW + array( '20010115123456', TS_MW, '20010115123456', 'TS_MW to TS_MW' ), + array( '20010115123456', TS_UNIX, 979562096, 'TS_MW to TS_UNIX' ), + array( '20010115123456', TS_DB, '2001-01-15 12:34:56', 'TS_MW to TS_DB' ), + array( '20010115123456', TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_MW to TS_ISO_8601_BASIC' ), + + // TS_DB + array( '2001-01-15 12:34:56', TS_MW, '20010115123456', 'TS_DB to TS_MW' ), + array( '2001-01-15 12:34:56', TS_UNIX, 979562096, 'TS_DB to TS_UNIX' ), + array( '2001-01-15 12:34:56', TS_DB, '2001-01-15 12:34:56', 'TS_DB to TS_DB' ), + array( '2001-01-15 12:34:56', TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_DB to TS_ISO_8601_BASIC' ), + + # rfc2822 section 3.3 + array( '20010115123456', TS_RFC2822, 'Mon, 15 Jan 2001 12:34:56 GMT', 'TS_MW to TS_RFC2822' ), + array( 'Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 to TS_MW' ), + array( ' Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 with leading space to TS_MW' ), + array( '15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 without optional day-of-week to TS_MW' ), + + # FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space + # obs-FWS = 1*WSP *(CRLF 1*WSP) ; Section 4.2 + array( 'Mon, 15 Jan 2001 12:34:56 GMT', TS_MW, '20010115123456', 'TS_RFC2822 to TS_MW' ), + + # WSP = SP / HTAB ; rfc2234 + array( "Mon, 15 Jan\x092001 12:34:56 GMT", TS_MW, '20010115123456', 'TS_RFC2822 with HTAB to TS_MW' ), + array( "Mon, 15 Jan\x09 \x09 2001 12:34:56 GMT", TS_MW, '20010115123456', 'TS_RFC2822 with HTAB and SP to TS_MW' ), + array( 'Sun, 6 Nov 94 08:49:37 GMT', TS_MW, '19941106084937', 'TS_RFC2822 with obsolete year to TS_MW' ), + ); + } + + /** + * This test checks wfTimestamp() with values outside. + * It needs PHP 64 bits or PHP > 5.1. + * See r74778 and bug 25451 + * @dataProvider provideOldTimestamps + */ + function testOldTimestamps( $input, $format, $output, $desc ) { + $this->assertEquals( $output, wfTimestamp( $format, $input ), $desc ); + } + + function provideOldTimestamps() { + return array ( + array( '19011213204554', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:54 GMT', 'Earliest time according to php documentation' ), + array( '20380119031407', TS_RFC2822, 'Tue, 19 Jan 2038 03:14:07 GMT', 'Latest 32 bit time' ), + array( '19011213204552', TS_UNIX, '-2147483648', 'Earliest 32 bit unix time' ), + array( '20380119031407', TS_UNIX, '2147483647', 'Latest 32 bit unix time' ), + array( '19011213204552', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:52 GMT', 'Earliest 32 bit time' ), + array( '19011213204551', TS_RFC2822, 'Fri, 13 Dec 1901 20:45:51 GMT', 'Earliest 32 bit time - 1' ), + array( '20380119031408', TS_RFC2822, 'Tue, 19 Jan 2038 03:14:08 GMT', 'Latest 32 bit time + 1' ), + array( '19011212000000', TS_MW, '19011212000000', 'Convert to itself r74778#c10645' ), + array( '19011213204551', TS_UNIX, '-2147483649', 'Earliest 32 bit unix time - 1' ), + array( '20380119031408', TS_UNIX, '2147483648', 'Latest 32 bit unix time + 1' ), + array( '-2147483649', TS_MW, '19011213204551', '1901 negative unix time to MediaWiki' ), + array( '-5331871504', TS_MW, '18010115123456', '1801 negative unix time to MediaWiki' ), + array( '0117-08-09 12:34:56', TS_RFC2822, 'Tue, 09 Aug 0117 12:34:56 GMT', 'Death of Roman Emperor [[Trajan]]' ), + + /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */ + array( '-58979923200', TS_RFC2822, 'Sun, 01 Jan 0101 00:00:00 GMT', '1/1/101' ), + array( '-62135596800', TS_RFC2822, 'Mon, 01 Jan 0001 00:00:00 GMT', 'Year 1' ), + + /* It is not clear if we should generate a year 0 or not + * We are completely off RFC2822 requirement of year being + * 1900 or later. + */ + array( '-62142076800', TS_RFC2822, 'Wed, 18 Oct 0000 00:00:00 GMT', 'ISO 8601:2004 [[year 0]], also called [[1 BC]]' ), + ); + } + + /** + * The Resource Loader uses wfTimestamp() to convert timestamps + * from If-Modified-Since header. Thus it must be able to parse all + * rfc2616 date formats + * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + * @dataProvider provideHttpDates + */ + function testHttpDate( $input, $output, $desc ) { + $this->assertEquals( $output, wfTimestamp( TS_MW, $input ), $desc ); + } + + function provideHttpDates() { + return array( + array( 'Sun, 06 Nov 1994 08:49:37 GMT', '19941106084937', 'RFC 822 date' ), + array( 'Sunday, 06-Nov-94 08:49:37 GMT', '19941106084937', 'RFC 850 date' ), + array( 'Sun Nov 6 08:49:37 1994', '19941106084937', "ANSI C's asctime() format" ), + // See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html and r77171 + array( 'Mon, 22 Nov 2010 14:12:42 GMT; length=52626', '20101122141242', 'Netscape extension to HTTP/1.0' ), + ); + } + + /** + * There are a number of assumptions in our codebase where wfTimestamp() + * should give the current date but it is not given a 0 there. See r71751 CR + */ + function testTimestampParameter() { + $now = wfTimestamp( TS_UNIX ); + // We check that wfTimestamp doesn't return false (error) and use a LessThan assert + // for the cases where the test is run in a second boundary. + + $zero = wfTimestamp( TS_UNIX, 0 ); + $this->assertNotEquals( false, $zero ); + $this->assertLessThan( 5, $zero - $now ); + + $empty = wfTimestamp( TS_UNIX, '' ); + $this->assertNotEquals( false, $empty ); + $this->assertLessThan( 5, $empty - $now ); + + $null = wfTimestamp( TS_UNIX, null ); + $this->assertNotEquals( false, $null ); + $this->assertLessThan( 5, $null - $now ); + } +} diff --git a/tests/phpunit/includes/HtmlTest.php b/tests/phpunit/includes/HtmlTest.php index 96bb1803..67b60d32 100644 --- a/tests/phpunit/includes/HtmlTest.php +++ b/tests/phpunit/includes/HtmlTest.php @@ -3,58 +3,90 @@ class HtmlTest extends MediaWikiTestCase { private static $oldLang; + private static $oldContLang; + private static $oldLanguageCode; + private static $oldNamespaces; public function setUp() { - global $wgLang, $wgLanguageCode; + global $wgLang, $wgContLang, $wgLanguageCode; self::$oldLang = $wgLang; + self::$oldContLang = $wgContLang; + self::$oldNamespaces = $wgContLang->getNamespaces(); + self::$oldLanguageCode = $wgLanguageCode; + $wgLanguageCode = 'en'; - $wgLang = Language::factory( $wgLanguageCode ); + $wgContLang = $wgLang = Language::factory( $wgLanguageCode ); + + // Hardcode namespaces during test runs, + // so that html output based on existing namespaces + // can be properly evaluated. + $wgContLang->setNamespaces( array( + -2 => 'Media', + -1 => 'Special', + 0 => '', + 1 => 'Talk', + 2 => 'User', + 3 => 'User_talk', + 4 => 'MyWiki', + 5 => 'MyWiki_Talk', + 6 => 'File', + 7 => 'File_talk', + 8 => 'MediaWiki', + 9 => 'MediaWiki_talk', + 10 => 'Template', + 11 => 'Template_talk', + 100 => 'Custom', + 101 => 'Custom_talk', + ) ); } public function tearDown() { - global $wgLang, $wgLanguageCode; + global $wgLang, $wgContLang, $wgLanguageCode; + + $wgContLang->setNamespaces( self::$oldNamespaces ); $wgLang = self::$oldLang; - $wgLanguageCode = $wgLang->getCode(); + $wgContLang = self::$oldContLang; + $wgLanguageCode = self::$oldLanguageCode; } public function testExpandAttributesSkipsNullAndFalse() { ### EMPTY ######## $this->AssertEmpty( - Html::expandAttributes( array( 'foo'=>null) ), + Html::expandAttributes( array( 'foo' => null ) ), 'skip keys with null value' ); $this->AssertEmpty( - Html::expandAttributes( array( 'foo'=>false) ), + Html::expandAttributes( array( 'foo' => false ) ), 'skip keys with false value' ); $this->AssertNotEmpty( - Html::expandAttributes( array( 'foo'=>'') ), + Html::expandAttributes( array( 'foo' => '' ) ), 'keep keys with an empty string' ); } public function testExpandAttributesForBooleans() { + global $wgHtml5; $this->AssertEquals( '', - Html::expandAttributes( array( 'selected'=>false) ), + Html::expandAttributes( array( 'selected' => false ) ), 'Boolean attributes do not generates output when value is false' ); $this->AssertEquals( '', - Html::expandAttributes( array( 'selected'=>null) ), + Html::expandAttributes( array( 'selected' => null ) ), 'Boolean attributes do not generates output when value is null' ); - ### FIXME: maybe they should just output 'selected' $this->AssertEquals( - ' selected=""', - Html::expandAttributes( array( 'selected'=>true ) ), + $wgHtml5 ? ' selected=""' : ' selected="selected"', + Html::expandAttributes( array( 'selected' => true ) ), 'Boolean attributes skip value output' ); $this->AssertEquals( - ' selected=""', + $wgHtml5 ? ' selected=""' : ' selected="selected"', Html::expandAttributes( array( 'selected' ) ), 'Boolean attributes (ex: selected) do not need a value' ); @@ -68,23 +100,234 @@ class HtmlTest extends MediaWikiTestCase { ### NOT EMPTY #### $this->AssertEquals( ' empty_string=""', - Html::expandAttributes( array( 'empty_string'=>'') ), + Html::expandAttributes( array( 'empty_string' => '' ) ), 'Value with an empty string' ); $this->AssertEquals( ' key="value"', - Html::expandAttributes( array( 'key'=>'value') ), + Html::expandAttributes( array( 'key' => 'value' ) ), 'Value is a string' ); $this->AssertEquals( ' one="1"', - Html::expandAttributes( array( 'one'=>1) ), + Html::expandAttributes( array( 'one' => 1 ) ), 'Value is a numeric one' ); $this->AssertEquals( ' zero="0"', - Html::expandAttributes( array( 'zero'=>0) ), + Html::expandAttributes( array( 'zero' => 0 ) ), 'Value is a numeric zero' ); } + + /** + * Html::expandAttributes has special features for HTML + * attributes that use space separated lists and also + * allows arrays to be used as values. + */ + public function testExpandAttributesListValueAttributes() { + ### STRING VALUES + $this->AssertEquals( + ' class="redundant spaces here"', + Html::expandAttributes( array( 'class' => ' redundant spaces here ' ) ), + 'Normalization should strip redundant spaces' + ); + $this->AssertEquals( + ' class="foo bar"', + Html::expandAttributes( array( 'class' => 'foo bar foo bar bar' ) ), + 'Normalization should remove duplicates in string-lists' + ); + ### "EMPTY" ARRAY VALUES + $this->AssertEquals( + ' class=""', + Html::expandAttributes( array( 'class' => array() ) ), + 'Value with an empty array' + ); + $this->AssertEquals( + ' class=""', + Html::expandAttributes( array( 'class' => array( null, '', ' ', ' ' ) ) ), + 'Array with null, empty string and spaces' + ); + ### NON-EMPTY ARRAY VALUES + $this->AssertEquals( + ' class="foo bar"', + Html::expandAttributes( array( 'class' => array( + 'foo', + 'bar', + 'foo', + 'bar', + 'bar', + ) ) ), + 'Normalization should remove duplicates in the array' + ); + $this->AssertEquals( + ' class="foo bar"', + Html::expandAttributes( array( 'class' => array( + 'foo bar', + 'bar foo', + 'foo', + 'bar bar', + ) ) ), + 'Normalization should remove duplicates in string-lists in the array' + ); + } + + /** + * Test feature added by r96188, let pass attributes values as + * a PHP array. Restricted to class,rel, accesskey. + */ + function testExpandAttributesSpaceSeparatedAttributesWithBoolean() { + $this->assertEquals( + ' class="booltrue one"', + Html::expandAttributes( array( 'class' => array( + 'booltrue' => true, + 'one' => 1, + + # Method use isset() internally, make sure we do discard + # attributes values which have been assigned well known values + 'emptystring' => '', + 'boolfalse' => false, + 'zero' => 0, + 'null' => null, + ))) + ); + } + + /** + * How do we handle duplicate keys in HTML attributes expansion? + * We could pass a "class" the values: 'GREEN' and array( 'GREEN' => false ) + * The later will take precedence. + * + * Feature added by r96188 + */ + function testValueIsAuthoritativeInSpaceSeparatedAttributesArrays() { + $this->assertEquals( + ' class=""', + Html::expandAttributes( array( 'class' => array( + 'GREEN', + 'GREEN' => false, + 'GREEN', + ))) + ); + } + + function testNamespaceSelector() { + $this->assertEquals( + '<select id="namespace" name="namespace">' . "\n" . +'<option value="0">(Main)</option>' . "\n" . +'<option value="1">Talk</option>' . "\n" . +'<option value="2">User</option>' . "\n" . +'<option value="3">User talk</option>' . "\n" . +'<option value="4">MyWiki</option>' . "\n" . +'<option value="5">MyWiki Talk</option>' . "\n" . +'<option value="6">File</option>' . "\n" . +'<option value="7">File talk</option>' . "\n" . +'<option value="8">MediaWiki</option>' . "\n" . +'<option value="9">MediaWiki talk</option>' . "\n" . +'<option value="10">Template</option>' . "\n" . +'<option value="11">Template talk</option>' . "\n" . +'<option value="100">Custom</option>' . "\n" . +'<option value="101">Custom talk</option>' . "\n" . +'</select>', + Html::namespaceSelector(), + 'Basic namespace selector without custom options' + ); + $this->assertEquals( + '<label for="mw-test-namespace">Select a namespace:</label> ' . +'<select id="mw-test-namespace" name="wpNamespace">' . "\n" . +'<option value="all">all</option>' . "\n" . +'<option value="0">(Main)</option>' . "\n" . +'<option value="1">Talk</option>' . "\n" . +'<option value="2" selected="">User</option>' . "\n" . +'<option value="3">User talk</option>' . "\n" . +'<option value="4">MyWiki</option>' . "\n" . +'<option value="5">MyWiki Talk</option>' . "\n" . +'<option value="6">File</option>' . "\n" . +'<option value="7">File talk</option>' . "\n" . +'<option value="8">MediaWiki</option>' . "\n" . +'<option value="9">MediaWiki talk</option>' . "\n" . +'<option value="10">Template</option>' . "\n" . +'<option value="11">Template talk</option>' . "\n" . +'<option value="100">Custom</option>' . "\n" . +'<option value="101">Custom talk</option>' . "\n" . +'</select>', + Html::namespaceSelector( + array( 'selected' => '2', 'all' => 'all', 'label' => 'Select a namespace:' ), + array( 'name' => 'wpNamespace', 'id' => 'mw-test-namespace' ) + ), + 'Basic namespace selector with custom values' + ); + } + + function testNamespaceSelectorIdAndNameDefaultsAttributes() { + + $this->assertNsSelectorIdAndName( + 'namespace', 'namespace', + Html::namespaceSelector( array(), array( + # neither 'id' nor 'name' key given + )), + "Neither 'id' nor 'name' key given" + ); + + $this->assertNsSelectorIdAndName( + 'namespace', 'select_name', + Html::namespaceSelector( array(), array( + 'name' => 'select_name', + # no 'id' key given + )), + "No 'id' key given, 'name' given" + ); + + $this->assertNsSelectorIdAndName( + 'select_id', 'namespace', + Html::namespaceSelector( array(), array( + 'id' => 'select_id', + # no 'name' key given + )), + "'id' given, no 'name' key given" + ); + + $this->assertNsSelectorIdAndName( + 'select_id', 'select_name', + Html::namespaceSelector( array(), array( + 'id' => 'select_id', + 'name' => 'select_name', + )), + "Both 'id' and 'name' given" + ); + } + + /** + * Helper to verify <select> attributes generated by Html::namespaceSelector() + * This helper expect the Html method to use 'namespace' as a default value for + * both 'id' and 'name' attributes. + * + * @param String $expectedId <select> id attribute value + * @param String $expectedName <select> name attribute value + * @param String $html Output of a call to Html::namespaceSelector() + * @param String $msg Optional message (default: '') + */ + function assertNsSelectorIdAndName( $expectedId, $expectedName, $html, $msg = '' ) { + $actualId = 'namespace'; + if( 1 === preg_match( '/id="(.+?)"/', $html, $m ) ) { + $actualId = $m[1]; + } + + $actualName = 'namespace'; + if( 1 === preg_match( '/name="(.+?)"/', $html, $m ) ) { + $actualName = $m[1]; + } + $this->assertEquals( + array( #expected + 'id' => $expectedId, + 'name' => $expectedName, + ), + array( #actual + 'id' => $actualId, + 'name' => $actualName, + ), + 'Html::namespaceSelector() got wrong id and/or name attribute(s). ' . $msg + ); + } + } diff --git a/tests/phpunit/includes/HttpTest.php b/tests/phpunit/includes/HttpTest.php index 1a99af7d..263383f1 100644 --- a/tests/phpunit/includes/HttpTest.php +++ b/tests/phpunit/includes/HttpTest.php @@ -1,325 +1,12 @@ <?php - -class MockCookie extends Cookie { - public function canServeDomain( $arg ) { return parent::canServeDomain( $arg ); } - public function canServePath( $arg ) { return parent::canServePath( $arg ); } - public function isUnExpired() { return parent::isUnExpired(); } -} - /** * @group Broken */ class HttpTest extends MediaWikiTestCase { - static $content; - static $headers; - static $has_curl; - static $has_fopen; - static $has_proxy = false; - static $proxy = "http://hulk:8080/"; - var $test_geturl = array( - "http://en.wikipedia.org/robots.txt", - "https://secure.wikimedia.org/", - "http://pecl.php.net/feeds/pkg_apc.rss", - "http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw", - "http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&format=php", - ); - var $test_requesturl = array( "http://en.wikipedia.org/wiki/Special:Export/User:MarkAHershberger" ); - - var $test_posturl = array( "http://www.comp.leeds.ac.uk/cgi-bin/Perl/environment-example" => "review=test" ); - - function setUp() { - putenv( "http_proxy" ); /* Remove any proxy env var, so curl doesn't get confused */ - if ( is_array( self::$content ) ) { - return; - } - self::$has_curl = function_exists( 'curl_init' ); - self::$has_fopen = wfIniGetBool( 'allow_url_fopen' ); - - if ( !file_exists( "/usr/bin/curl" ) ) { - $this->markTestIncomplete( "This test requires the curl binary at /usr/bin/curl. If you have curl, please file a bug on this test, or, better yet, provide a patch." ); - } - - $content = tempnam( wfTempDir(), "" ); - $headers = tempnam( wfTempDir(), "" ); - if ( !$content && !$headers ) { - die( "Couldn't create temp file!" ); - } - - // This probably isn't the best test for a proxy, but it works on my system! - system( "curl -0 -o $content -s " . self::$proxy ); - $out = file_get_contents( $content ); - if ( $out ) { - self::$has_proxy = true; - } - - /* Maybe use wget instead of curl here ... just to use a different codebase? */ - foreach ( $this->test_geturl as $u ) { - system( "curl -0 -s -D $headers '$u' -o $content" ); - self::$content["GET $u"] = file_get_contents( $content ); - self::$headers["GET $u"] = file_get_contents( $headers ); - } - foreach ( $this->test_requesturl as $u ) { - system( "curl -0 -s -X POST -H 'Content-Length: 0' -D $headers '$u' -o $content" ); - self::$content["POST $u"] = file_get_contents( $content ); - self::$headers["POST $u"] = file_get_contents( $headers ); - } - foreach ( $this->test_posturl as $u => $postData ) { - system( "curl -0 -s -X POST -d '$postData' -D $headers '$u' -o $content" ); - self::$content["POST $u => $postData"] = file_get_contents( $content ); - self::$headers["POST $u => $postData"] = file_get_contents( $headers ); - } - unlink( $content ); - unlink( $headers ); - } - - - function testInstantiation() { - Http::$httpEngine = false; - - $r = MWHttpRequest::factory( "http://www.example.com/" ); - if ( self::$has_curl ) { - $this->assertThat( $r, $this->isInstanceOf( 'CurlHttpRequest' ) ); - } else { - $this->assertThat( $r, $this->isInstanceOf( 'PhpHttpRequest' ) ); - } - unset( $r ); - - if ( !self::$has_fopen ) { - $this->setExpectedException( 'MWException' ); - } - Http::$httpEngine = 'php'; - $r = MWHttpRequest::factory( "http://www.example.com/" ); - $this->assertThat( $r, $this->isInstanceOf( 'PhpHttpRequest' ) ); - unset( $r ); - - if ( !self::$has_curl ) { - $this->setExpectedException( 'MWException' ); - } - Http::$httpEngine = 'curl'; - $r = MWHttpRequest::factory( "http://www.example.com/" ); - if ( self::$has_curl ) { - $this->assertThat( $r, $this->isInstanceOf( 'CurlHttpRequest' ) ); - } - } - - function runHTTPFailureChecks() { - // Each of the following requests should result in a failure. - - $timeout = 1; - $start_time = time(); - $r = Http::get( "http://www.example.com:1/", $timeout ); - $end_time = time(); - $this->assertLessThan( $timeout + 2, $end_time - $start_time, - "Request took less than {$timeout}s via " . Http::$httpEngine ); - $this->assertEquals( $r, false, "false -- what we get on error from Http::get()" ); - - $r = Http::get( "http://www.mediawiki.org/xml/made-up-url", $timeout ); - $this->assertFalse( $r, "False on 404s" ); - - - $r = MWHttpRequest::factory( "http://www.mediawiki.org/xml/made-up-url" ); - $er = $r->execute(); - if ( $r instanceof PhpHttpRequest && version_compare( '5.2.10', phpversion(), '>' ) ) { - $this->assertRegexp( "/HTTP request failed/", $er->getWikiText() ); - } else { - $this->assertRegexp( "/404 Not Found/", $er->getWikiText() ); - } - } - - function testFailureDefault() { - Http::$httpEngine = false; - $this->runHTTPFailureChecks(); - } - - function testFailurePhp() { - if ( !self::$has_fopen ) { - $this->markTestIncomplete( "This test requires allow_url_fopen=true." ); - } - - Http::$httpEngine = "php"; - $this->runHTTPFailureChecks(); - } - - function testFailureCurl() { - if ( !self::$has_curl ) { - $this->markTestIncomplete( "This test requires curl." ); - } - - Http::$httpEngine = "curl"; - $this->runHTTPFailureChecks(); - } - - /* ./phase3/includes/Import.php:1108: $data = Http::request( $method, $url ); */ - /* ./includes/Import.php:1124: $link = Title::newFromText( "$interwiki:Special:Export/$page" ); */ - /* ./includes/Import.php:1134: return ImportStreamSource::newFromURL( $url, "POST" ); */ - function runHTTPRequests( $proxy = null ) { - $opt = array(); - - if ( $proxy ) { - $opt['proxy'] = $proxy; - } elseif ( $proxy === false ) { - $opt['noProxy'] = true; - } - - /* no postData here because the only request I could find in code so far didn't have any */ - foreach ( $this->test_requesturl as $u ) { - $r = Http::request( "POST", $u, $opt ); - $this->assertEquals( self::$content["POST $u"], "$r", "POST $u with " . Http::$httpEngine ); - } - } - - function testRequestDefault() { - Http::$httpEngine = false; - $this->runHTTPRequests(); - } - - function testRequestPhp() { - if ( !self::$has_fopen ) { - $this->markTestIncomplete( "This test requires allow_url_fopen=true." ); - } - - Http::$httpEngine = "php"; - $this->runHTTPRequests(); - } - - function testRequestCurl() { - if ( !self::$has_curl ) { - $this->markTestIncomplete( "This test requires curl." ); - } - - Http::$httpEngine = "curl"; - $this->runHTTPRequests(); - } - - function runHTTPGets( $proxy = null ) { - $opt = array(); - - if ( $proxy ) { - $opt['proxy'] = $proxy; - } elseif ( $proxy === false ) { - $opt['noProxy'] = true; - } - - foreach ( $this->test_geturl as $u ) { - $r = Http::get( $u, 30, $opt ); /* timeout of 30s */ - $this->assertEquals( self::$content["GET $u"], "$r", "Get $u with " . Http::$httpEngine ); - } - } - - function testGetDefault() { - Http::$httpEngine = false; - $this->runHTTPGets(); - } - - function testGetPhp() { - if ( !self::$has_fopen ) { - $this->markTestIncomplete( "This test requires allow_url_fopen=true." ); - } - - Http::$httpEngine = "php"; - $this->runHTTPGets(); - } - - function testGetCurl() { - if ( !self::$has_curl ) { - $this->markTestIncomplete( "This test requires curl." ); - } - - Http::$httpEngine = "curl"; - $this->runHTTPGets(); - } - - function runHTTPPosts( $proxy = null ) { - $opt = array(); - - if ( $proxy ) { - $opt['proxy'] = $proxy; - } elseif ( $proxy === false ) { - $opt['noProxy'] = true; - } - - foreach ( $this->test_posturl as $u => $postData ) { - $opt['postData'] = $postData; - $r = Http::post( $u, $opt ); - $this->assertEquals( self::$content["POST $u => $postData"], "$r", - "POST $u (postData=$postData) with " . Http::$httpEngine ); - } - } - - function testPostDefault() { - Http::$httpEngine = false; - $this->runHTTPPosts(); - } - - function testPostPhp() { - if ( !self::$has_fopen ) { - $this->markTestIncomplete( "This test requires allow_url_fopen=true." ); - } - - Http::$httpEngine = "php"; - $this->runHTTPPosts(); - } - - function testPostCurl() { - if ( !self::$has_curl ) { - $this->markTestIncomplete( "This test requires curl." ); - } - - Http::$httpEngine = "curl"; - $this->runHTTPPosts(); - } - - function runProxyRequests() { - if ( !self::$has_proxy ) { - $this->markTestIncomplete( "This test requires a proxy." ); - } - $this->runHTTPGets( self::$proxy ); - $this->runHTTPPosts( self::$proxy ); - $this->runHTTPRequests( self::$proxy ); - - // Set false here to do noProxy - $this->runHTTPGets( false ); - $this->runHTTPPosts( false ); - $this->runHTTPRequests( false ); - } - - function testProxyDefault() { - Http::$httpEngine = false; - $this->runProxyRequests(); - } - - function testProxyPhp() { - if ( !self::$has_fopen ) { - $this->markTestIncomplete( "This test requires allow_url_fopen=true." ); - } - - Http::$httpEngine = 'php'; - $this->runProxyRequests(); - } - - function testProxyCurl() { - if ( !self::$has_curl ) { - $this->markTestIncomplete( "This test requires curl." ); - } - - Http::$httpEngine = 'curl'; - $this->runProxyRequests(); - } - - function testIsLocalUrl() { - } - - /* ./extensions/DonationInterface/payflowpro_gateway/payflowpro_gateway.body.php:559: $user_agent = Http::userAgent(); */ - function testUserAgent() { - } - - function testIsValidUrl() { - } - /** * @dataProvider cookieDomains */ - function testValidateCookieDomain( $expected, $domain, $origin=null ) { + function testValidateCookieDomain( $expected, $domain, $origin = null ) { if ( $origin ) { $ok = Cookie::validateCookieDomain( $domain, $origin ); $msg = "$domain against origin $origin"; @@ -329,7 +16,7 @@ class HttpTest extends MediaWikiTestCase { } $this->assertEquals( $expected, $ok, $msg ); } - + function cookieDomains() { return array( array( false, "org"), @@ -359,189 +46,11 @@ class HttpTest extends MediaWikiTestCase { ); } - function testSetCooke() { - $c = new MockCookie( "name", "value", - array( - "domain" => "ac.th", - "path" => "/path/", - ) ); - $this->assertFalse( $c->canServeDomain( "ac.th" ) ); - - $c = new MockCookie( "name", "value", - array( - "domain" => "example.com", - "path" => "/path/", - ) ); - - $this->assertTrue( $c->canServeDomain( "example.com" ) ); - $this->assertFalse( $c->canServeDomain( "www.example.com" ) ); - - $c = new MockCookie( "name", "value", - array( - "domain" => ".example.com", - "path" => "/path/", - ) ); - - $this->assertFalse( $c->canServeDomain( "www.example.net" ) ); - $this->assertFalse( $c->canServeDomain( "example.com" ) ); - $this->assertTrue( $c->canServeDomain( "www.example.com" ) ); - - $this->assertFalse( $c->canServePath( "/" ) ); - $this->assertFalse( $c->canServePath( "/bogus/path/" ) ); - $this->assertFalse( $c->canServePath( "/path" ) ); - $this->assertTrue( $c->canServePath( "/path/" ) ); - - $this->assertTrue( $c->isUnExpired() ); - - $this->assertEquals( "", $c->serializeToHttpRequest( "/path/", "www.example.net" ) ); - $this->assertEquals( "", $c->serializeToHttpRequest( "/", "www.example.com" ) ); - $this->assertEquals( "name=value", $c->serializeToHttpRequest( "/path/", "www.example.com" ) ); - - $c = new MockCookie( "name", "value", - array( - "domain" => "www.example.com", - "path" => "/path/", - ) ); - $this->assertFalse( $c->canServeDomain( "example.com" ) ); - $this->assertFalse( $c->canServeDomain( "www.example.net" ) ); - $this->assertTrue( $c->canServeDomain( "www.example.com" ) ); - - $c = new MockCookie( "name", "value", - array( - "domain" => ".example.com", - "path" => "/path/", - "expires" => "-1 day", - ) ); - $this->assertFalse( $c->isUnExpired() ); - $this->assertEquals( "", $c->serializeToHttpRequest( "/path/", "www.example.com" ) ); - - $c = new MockCookie( "name", "value", - array( - "domain" => ".example.com", - "path" => "/path/", - "expires" => "+1 day", - ) ); - $this->assertTrue( $c->isUnExpired() ); - $this->assertEquals( "name=value", $c->serializeToHttpRequest( "/path/", "www.example.com" ) ); - } - - function testCookieJarSetCookie() { - $cj = new CookieJar; - $cj->setCookie( "name", "value", - array( - "domain" => ".example.com", - "path" => "/path/", - ) ); - $cj->setCookie( "name2", "value", - array( - "domain" => ".example.com", - "path" => "/path/sub", - ) ); - $cj->setCookie( "name3", "value", - array( - "domain" => ".example.com", - "path" => "/", - ) ); - $cj->setCookie( "name4", "value", - array( - "domain" => ".example.net", - "path" => "/path/", - ) ); - $cj->setCookie( "name5", "value", - array( - "domain" => ".example.net", - "path" => "/path/", - "expires" => "-1 day", - ) ); - - $this->assertEquals( "name4=value", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) ); - $this->assertEquals( "name3=value", $cj->serializeToHttpRequest( "/", "www.example.com" ) ); - $this->assertEquals( "name=value; name3=value", $cj->serializeToHttpRequest( "/path/", "www.example.com" ) ); - - $cj->setCookie( "name5", "value", - array( - "domain" => ".example.net", - "path" => "/path/", - "expires" => "+1 day", - ) ); - $this->assertEquals( "name4=value; name5=value", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) ); - - $cj->setCookie( "name4", "value", - array( - "domain" => ".example.net", - "path" => "/path/", - "expires" => "-1 day", - ) ); - $this->assertEquals( "name5=value", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) ); - } - - function testParseResponseHeader() { - $cj = new CookieJar; - - $h[] = "Set-Cookie: name4=value; domain=.example.com; path=/; expires=Mon, 09-Dec-2029 13:46:00 GMT"; - $cj->parseCookieResponseHeader( $h[0], "www.example.com" ); - $this->assertEquals( "name4=value", $cj->serializeToHttpRequest( "/", "www.example.com" ) ); - - $h[] = "name4=value2; domain=.example.com; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT"; - $cj->parseCookieResponseHeader( $h[1], "www.example.com" ); - $this->assertEquals( "", $cj->serializeToHttpRequest( "/", "www.example.com" ) ); - $this->assertEquals( "name4=value2", $cj->serializeToHttpRequest( "/path/", "www.example.com" ) ); - - $h[] = "name5=value3; domain=.example.com; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT"; - $cj->parseCookieResponseHeader( $h[2], "www.example.com" ); - $this->assertEquals( "name4=value2; name5=value3", $cj->serializeToHttpRequest( "/path/", "www.example.com" ) ); - - $h[] = "name6=value3; domain=.example.net; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT"; - $cj->parseCookieResponseHeader( $h[3], "www.example.com" ); - $this->assertEquals( "", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) ); - - $h[] = "name6=value0; domain=.example.net; path=/path/; expires=Mon, 09-Dec-1999 13:46:00 GMT"; - $cj->parseCookieResponseHeader( $h[4], "www.example.net" ); - $this->assertEquals( "", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) ); - - $h[] = "name6=value4; domain=.example.net; path=/path/; expires=Mon, 09-Dec-2029 13:46:00 GMT"; - $cj->parseCookieResponseHeader( $h[5], "www.example.net" ); - $this->assertEquals( "name6=value4", $cj->serializeToHttpRequest( "/path/", "www.example.net" ) ); - } - - function runCookieRequests() { - $r = MWHttpRequest::factory( "http://www.php.net/manual", array( 'followRedirects' => true ) ); - $r->execute(); - - $jar = $r->getCookieJar(); - $this->assertThat( $jar, $this->isInstanceOf( 'CookieJar' ) ); - - $serialized = $jar->serializeToHttpRequest( "/search?q=test", "www.php.net" ); - $this->assertRegExp( '/\bCOUNTRY=[^=;]+/', $serialized ); - $this->assertRegExp( '/\bLAST_LANG=[^=;]+/', $serialized ); - $this->assertEquals( '', $jar->serializeToHttpRequest( "/search?q=test", "www.php.com" ) ); - } - - function testCookieRequestDefault() { - Http::$httpEngine = false; - $this->runCookieRequests(); - } - function testCookieRequestPhp() { - if ( !self::$has_fopen ) { - $this->markTestIncomplete( "This test requires allow_url_fopen=true." ); - } - - Http::$httpEngine = 'php'; - $this->runCookieRequests(); - } - function testCookieRequestCurl() { - if ( !self::$has_curl ) { - $this->markTestIncomplete( "This test requires curl." ); - } - - Http::$httpEngine = 'curl'; - $this->runCookieRequests(); - } - /** * Test Http::isValidURI() - * @bug 27854 : Http::isValidURI is to lax - *@dataProvider provideURI */ + * @bug 27854 : Http::isValidURI is too lax + * @dataProvider provideURI + */ function testIsValidUri( $expect, $URI, $message = '' ) { $this->assertEquals( $expect, @@ -567,7 +76,7 @@ class HttpTest extends MediaWikiTestCase { array( false, '\\host\directory', 'CIFS share' ), array( false, 'gopher://host/dir', 'Reject gopher scheme' ), array( false, 'telnet://host', 'Reject telnet scheme' ), - + # :\/\/ - double slashes array( false, 'http//example.org', 'Reject missing colon in protocol' ), array( false, 'http:/example.org', 'Reject missing slash in protocol' ), @@ -615,4 +124,57 @@ class HttpTest extends MediaWikiTestCase { ); } + /** + * Warning: + * + * These tests are for code that makes use of an artifact of how CURL + * handles header reporting on redirect pages, and will need to be + * rewritten when bug 29232 is taken care of (high-level handling of + * HTTP redirects). + */ + function testRelativeRedirections() { + $h = new MWHttpRequestTester( 'http://oldsite/file.ext' ); + # Forge a Location header + $h->setRespHeaders( 'location', array( + 'http://newsite/file.ext', + '/newfile.ext', + ) + ); + # Verify we correctly fix the Location + $this->assertEquals( + 'http://newsite/newfile.ext', + $h->getFinalUrl(), + "Relative file path Location: interpreted as full URL" + ); + + $h->setRespHeaders( 'location', array( + 'https://oldsite/file.ext' + ) + ); + $this->assertEquals( + 'https://oldsite/file.ext', + $h->getFinalUrl(), + "Location to the HTTPS version of the site" + ); + + $h->setRespHeaders( 'location', array( + '/anotherfile.ext', + 'http://anotherfile/hoster.ext', + 'https://anotherfile/hoster.ext' + ) + ); + $this->assertEquals( + 'https://anotherfile/hoster.ext', + $h->getFinalUrl( "Relative file path Location: should keep the latest host and scheme!") + ); + } +} + +/** + * Class to let us overwrite MWHttpREquest respHeaders variable + */ +class MWHttpRequestTester extends MWHttpRequest { + function setRespHeaders( $name, $value ) { + $this->respHeaders[$name] = $value ; + } } diff --git a/tests/phpunit/includes/IPTest.php b/tests/phpunit/includes/IPTest.php index c77dd852..4397b879 100644 --- a/tests/phpunit/includes/IPTest.php +++ b/tests/phpunit/includes/IPTest.php @@ -1,5 +1,5 @@ <?php -/* +/** * Tests for IP validity functions. Ported from /t/inc/IP.t by avar. */ @@ -43,20 +43,20 @@ class IPTest extends MediaWikiTestCase { $this->assertFalse( IP::isIPv6( 'fc:100:::' ), 'IPv6 ending with a ":::"' ); $this->assertFalse( IP::isIPv6( 'fc:300' ), 'IPv6 with only 2 words' ); $this->assertFalse( IP::isIPv6( 'fc:100:300' ), 'IPv6 with only 3 words' ); - + $this->assertTrue( IP::isIPv6( 'fc:100::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac::' ) ); - + $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' ); $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' ); $this->assertFalse( IP::isIPv6( ':::' ) ); $this->assertFalse( IP::isIPv6( '::0:' ), 'IPv6 ending in a lone ":"' ); - + $this->assertTrue( IP::isIPv6( '::' ), 'IPv6 zero address' ); $this->assertTrue( IP::isIPv6( '::0' ) ); $this->assertTrue( IP::isIPv6( '::fc' ) ); @@ -66,14 +66,14 @@ class IPTest extends MediaWikiTestCase { $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1' ) ); $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e' ) ); $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e:ac' ) ); - + $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' ); $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' ); $this->assertFalse( IP::isIPv6( ':fc::100' ), 'IPv6 starting with lone ":"' ); $this->assertFalse( IP::isIPv6( 'fc::100:' ), 'IPv6 ending with lone ":"' ); $this->assertFalse( IP::isIPv6( 'fc:::100' ), 'IPv6 with ":::" in the middle' ); - + $this->assertTrue( IP::isIPv6( 'fc::100' ), 'IPv6 with "::" and 2 words' ); $this->assertTrue( IP::isIPv6( 'fc::100:a' ), 'IPv6 with "::" and 3 words' ); $this->assertTrue( IP::isIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ) ); @@ -83,7 +83,7 @@ class IPTest extends MediaWikiTestCase { $this->assertTrue( IP::isIPv6( '2001::df'), 'IPv6 with "::" and 2 words' ); $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df'), 'IPv6 with "::" and 5 words' ); $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df:2'), 'IPv6 with "::" and 6 words' ); - + $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' ); $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' ); @@ -135,11 +135,11 @@ class IPTest extends MediaWikiTestCase { $this->assertFalse( IP::isValid( 'fc:100:::' ), 'IPv6 ending with a ":::"' ); $this->assertFalse( IP::isValid( 'fc:300' ), 'IPv6 with only 2 words' ); $this->assertFalse( IP::isValid( 'fc:100:300' ), 'IPv6 with only 3 words' ); - + $this->assertTrue( IP::isValid( 'fc:100::' ) ); $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e::' ) ); $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e:ac::' ) ); - + $this->assertTrue( IP::isValid( 'fc::100' ), 'IPv6 with "::" and 2 words' ); $this->assertTrue( IP::isValid( 'fc::100:a' ), 'IPv6 with "::" and 3 words' ); $this->assertTrue( IP::isValid( '2001::df'), 'IPv6 with "::" and 2 words' ); @@ -147,7 +147,7 @@ class IPTest extends MediaWikiTestCase { $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df:2'), 'IPv6 with "::" and 6 words' ); $this->assertTrue( IP::isValid( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' ); $this->assertTrue( IP::isValid( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' ); - + $this->assertFalse( IP::isValid( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' ); $this->assertFalse( IP::isValid( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' ); } @@ -276,7 +276,7 @@ class IPTest extends MediaWikiTestCase { foreach ( $private as $p ) { $this->assertFalse( IP::isPublic( $p ), "$p is not a public IP address" ); } - $public = array( '2001:5c0:1000:a::133', 'fc::3' ); + $public = array( '2001:5c0:1000:a::133', 'fc::3', '00FC::' ); foreach ( $public as $p ) { $this->assertTrue( IP::isPublic( $p ), "$p is a public IP address" ); } @@ -332,7 +332,7 @@ class IPTest extends MediaWikiTestCase { $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF', IP::hexToOctet( 'FCCFFAFF' ) ); } - /* + /** * IP::parseCIDR() returns an array containing a signed IP address * representing the network mask and the bit mask. * @covers IP::parseCIDR @@ -391,7 +391,7 @@ class IPTest extends MediaWikiTestCase { } /** - * Issues there are most probably from IP::toHex() or IP::parseRange() + * Issues there are most probably from IP::toHex() or IP::parseRange() * @covers IP::isInRange * @dataProvider provideIPsAndRanges */ @@ -464,9 +464,9 @@ class IPTest extends MediaWikiTestCase { */ function testCombineHostAndPort( $expected, $input, $description ) { list( $host, $port, $defaultPort ) = $input; - $this->assertEquals( - $expected, - IP::combineHostAndPort( $host, $port, $defaultPort ), + $this->assertEquals( + $expected, + IP::combineHostAndPort( $host, $port, $defaultPort ), $description ); } diff --git a/tests/phpunit/includes/LocalFileTest.php b/tests/phpunit/includes/LocalFileTest.php index e08d4d7e..5b26b89c 100644 --- a/tests/phpunit/includes/LocalFileTest.php +++ b/tests/phpunit/includes/LocalFileTest.php @@ -10,12 +10,21 @@ class LocalFileTest extends MediaWikiTestCase { global $wgCapitalLinks; $wgCapitalLinks = true; + $info = array( - 'name' => 'test', - 'directory' => '/testdir', - 'url' => '/testurl', - 'hashLevels' => 2, + 'name' => 'test', + 'directory' => '/testdir', + 'url' => '/testurl', + 'hashLevels' => 2, 'transformVia404' => false, + 'backend' => new FSFileBackend( array( + 'name' => 'local-backend', + 'lockManager' => 'fsLockManager', + 'containerPaths' => array( + 'cont1' => "/testdir/local-backend/tempimages/cont1", + 'cont2' => "/testdir/local-backend/tempimages/cont2" + ) + ) ) ); $this->repo_hl0 = new LocalRepo( array( 'hashLevels' => 0 ) + $info ); $this->repo_hl2 = new LocalRepo( array( 'hashLevels' => 2 ) + $info ); @@ -44,17 +53,17 @@ class LocalFileTest extends MediaWikiTestCase { } function testGetArchivePath() { - $this->assertEquals( '/testdir/archive', $this->file_hl0->getArchivePath() ); - $this->assertEquals( '/testdir/archive/a/a2', $this->file_hl2->getArchivePath() ); - $this->assertEquals( '/testdir/archive/!', $this->file_hl0->getArchivePath( '!' ) ); - $this->assertEquals( '/testdir/archive/a/a2/!', $this->file_hl2->getArchivePath( '!' ) ); + $this->assertEquals( 'mwstore://local-backend/test-public/archive', $this->file_hl0->getArchivePath() ); + $this->assertEquals( 'mwstore://local-backend/test-public/archive/a/a2', $this->file_hl2->getArchivePath() ); + $this->assertEquals( 'mwstore://local-backend/test-public/archive/!', $this->file_hl0->getArchivePath( '!' ) ); + $this->assertEquals( 'mwstore://local-backend/test-public/archive/a/a2/!', $this->file_hl2->getArchivePath( '!' ) ); } function testGetThumbPath() { - $this->assertEquals( '/testdir/thumb/Test!', $this->file_hl0->getThumbPath() ); - $this->assertEquals( '/testdir/thumb/a/a2/Test!', $this->file_hl2->getThumbPath() ); - $this->assertEquals( '/testdir/thumb/Test!/x', $this->file_hl0->getThumbPath( 'x' ) ); - $this->assertEquals( '/testdir/thumb/a/a2/Test!/x', $this->file_hl2->getThumbPath( 'x' ) ); + $this->assertEquals( 'mwstore://local-backend/test-thumb/Test!', $this->file_hl0->getThumbPath() ); + $this->assertEquals( 'mwstore://local-backend/test-thumb/a/a2/Test!', $this->file_hl2->getThumbPath() ); + $this->assertEquals( 'mwstore://local-backend/test-thumb/Test!/x', $this->file_hl0->getThumbPath( 'x' ) ); + $this->assertEquals( 'mwstore://local-backend/test-thumb/a/a2/Test!/x', $this->file_hl2->getThumbPath( 'x' ) ); } function testGetArchiveUrl() { diff --git a/tests/phpunit/includes/MWNamespaceTest.php b/tests/phpunit/includes/MWNamespaceTest.php index 462afc24..6b231fc5 100644 --- a/tests/phpunit/includes/MWNamespaceTest.php +++ b/tests/phpunit/includes/MWNamespaceTest.php @@ -1,7 +1,7 @@ <?php /** - * @author Ashar Voultoiz - * @copyright Copyright © 2011, Ashar Voultoiz + * @author Antoine Musso + * @copyright Copyright © 2011, Antoine Musso * @file */ @@ -39,40 +39,55 @@ class MWNamespaceTest extends MediaWikiTestCase { /** * Please make sure to change testIsTalk() if you change the assertions below */ - public function testIsMain() { + public function testIsSubject() { // Special namespaces - $this->assertTrue( MWNamespace::isMain( NS_MEDIA ) ); - $this->assertTrue( MWNamespace::isMain( NS_SPECIAL ) ); + $this->assertIsSubject( NS_MEDIA ); + $this->assertIsSubject( NS_SPECIAL ); // Subject pages - $this->assertTrue( MWNamespace::isMain( NS_MAIN ) ); - $this->assertTrue( MWNamespace::isMain( NS_USER ) ); - $this->assertTrue( MWNamespace::isMain( 100 ) ); # user defined + $this->assertIsSubject( NS_MAIN ); + $this->assertIsSubject( NS_USER ); + $this->assertIsSubject( 100 ); # user defined // Talk pages - $this->assertFalse( MWNamespace::isMain( NS_TALK ) ); - $this->assertFalse( MWNamespace::isMain( NS_USER_TALK ) ); - $this->assertFalse( MWNamespace::isMain( 101 ) ); # user defined + $this->assertIsNotSubject( NS_TALK ); + $this->assertIsNotSubject( NS_USER_TALK ); + $this->assertIsNotSubject( 101 ); # user defined + + // Back compat + $this->assertTrue( MWNamespace::isMain( NS_MAIN ) == MWNamespace::isSubject( NS_MAIN ) ); + $this->assertTrue( MWNamespace::isMain( NS_USER_TALK ) == MWNamespace::isSubject( NS_USER_TALK ) ); } /** - * Reverse of testIsMain(). - * Please update testIsMain() if you change assertions below + * Reverse of testIsSubject(). + * Please update testIsSubject() if you change assertions below */ public function testIsTalk() { // Special namespaces - $this->assertFalse( MWNamespace::isTalk( NS_MEDIA ) ); - $this->assertFalse( MWNamespace::isTalk( NS_SPECIAL ) ); + $this->assertIsNotTalk( NS_MEDIA ); + $this->assertIsNotTalk( NS_SPECIAL ); // Subject pages - $this->assertFalse( MWNamespace::isTalk( NS_MAIN ) ); - $this->assertFalse( MWNamespace::isTalk( NS_USER ) ); - $this->assertFalse( MWNamespace::isTalk( 100 ) ); # user defined + $this->assertIsNotTalk( NS_MAIN ); + $this->assertIsNotTalk( NS_USER ); + $this->assertIsNotTalk( 100 ); # user defined // Talk pages - $this->assertTrue( MWNamespace::isTalk( NS_TALK ) ); - $this->assertTrue( MWNamespace::isTalk( NS_USER_TALK ) ); - $this->assertTrue( MWNamespace::isTalk( 101 ) ); # user defined + $this->assertIsTalk( NS_TALK ); + $this->assertIsTalk( NS_USER_TALK ); + $this->assertIsTalk( 101 ); # user defined + } + + /** + */ + public function testGetSubject() { + // Special namespaces are their own subjects + $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) ); + $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) ); + + $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) ); + $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) ); } /** @@ -82,6 +97,9 @@ class MWNamespaceTest extends MediaWikiTestCase { */ public function testGetTalk() { $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_MAIN ) ); + $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_TALK ) ); + $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER ) ); + $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER_TALK ) ); } /** @@ -93,7 +111,7 @@ class MWNamespaceTest extends MediaWikiTestCase { $this->assertNull( MWNamespace::getTalk( NS_MEDIA ) ); } - /** + /** * Exceptions with getTalk() * NS_SPECIAL does not have talk pages. MediaWiki raise an exception for them. * @expectedException MWException @@ -108,7 +126,7 @@ class MWNamespaceTest extends MediaWikiTestCase { * the function testGetAssociatedExceptions() */ public function testGetAssociated() { - $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) ); + $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) ); $this->assertEquals( NS_MAIN, MWNamespace::getAssociated( NS_TALK ) ); } @@ -131,80 +149,122 @@ class MWNamespaceTest extends MediaWikiTestCase { } /** - */ - public function testGetSubject() { - // Special namespaces are their own subjects - $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) ); - $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) ); - - $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) ); - $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) ); - } - - /** * @todo Implement testExists(). */ +/* public function testExists() { // Remove the following lines when you implement this test. $this->markTestIncomplete( 'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.' ); } +*/ + + /** + * Test MWNamespace::equals + * Note if we add a namespace registration system with keys like 'MAIN' + * we should add tests here for equivilance on things like 'MAIN' == 0 + * and 'MAIN' == NS_MAIN. + */ + public function testEquals() { + $this->assertTrue( MWNamespace::equals( NS_MAIN, NS_MAIN ) ); + $this->assertTrue( MWNamespace::equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN' + $this->assertTrue( MWNamespace::equals( NS_USER, NS_USER ) ); + $this->assertTrue( MWNamespace::equals( NS_USER, 2 ) ); + $this->assertTrue( MWNamespace::equals( NS_USER_TALK, NS_USER_TALK ) ); + $this->assertTrue( MWNamespace::equals( NS_SPECIAL, NS_SPECIAL ) ); + $this->assertFalse( MWNamespace::equals( NS_MAIN, NS_TALK ) ); + $this->assertFalse( MWNamespace::equals( NS_USER, NS_USER_TALK ) ); + $this->assertFalse( MWNamespace::equals( NS_PROJECT, NS_TEMPLATE ) ); + } + + /** + * Test MWNamespace::subjectEquals + */ + public function testSubjectEquals() { + $this->assertSameSubject( NS_MAIN, NS_MAIN ); + $this->assertSameSubject( NS_MAIN, 0 ); // In case we make NS_MAIN 'MAIN' + $this->assertSameSubject( NS_USER, NS_USER ); + $this->assertSameSubject( NS_USER, 2 ); + $this->assertSameSubject( NS_USER_TALK, NS_USER_TALK ); + $this->assertSameSubject( NS_SPECIAL, NS_SPECIAL ); + $this->assertSameSubject( NS_MAIN, NS_TALK ); + $this->assertSameSubject( NS_USER, NS_USER_TALK ); + + $this->assertDifferentSubject( NS_PROJECT, NS_TEMPLATE ); + $this->assertDifferentSubject( NS_SPECIAL, NS_MAIN ); + } + + public function testSpecialAndMediaAreDifferentSubjects() { + $this->assertDifferentSubject( + NS_MEDIA, NS_SPECIAL, + "NS_MEDIA and NS_SPECIAL are different subject namespaces" + ); + $this->assertDifferentSubject( + NS_SPECIAL, NS_MEDIA, + "NS_SPECIAL and NS_MEDIA are different subject namespaces" + ); + + } /** * @todo Implement testGetCanonicalNamespaces(). */ +/* public function testGetCanonicalNamespaces() { // Remove the following lines when you implement this test. $this->markTestIncomplete( 'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.' ); } - +*/ /** * @todo Implement testGetCanonicalName(). */ +/* public function testGetCanonicalName() { // Remove the following lines when you implement this test. $this->markTestIncomplete( 'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.' ); } - +*/ /** * @todo Implement testGetCanonicalIndex(). */ +/* public function testGetCanonicalIndex() { // Remove the following lines when you implement this test. $this->markTestIncomplete( 'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.' ); } - +*/ /** * @todo Implement testGetValidNamespaces(). */ +/* public function testGetValidNamespaces() { // Remove the following lines when you implement this test. $this->markTestIncomplete( 'This test has not been implemented yet. Rely on $wgCanonicalNamespaces.' ); } - +*/ /** */ public function testCanTalk() { - $this->assertFalse( MWNamespace::canTalk( NS_MEDIA ) ); - $this->assertFalse( MWNamespace::canTalk( NS_SPECIAL ) ); + $this->assertCanNotTalk( NS_MEDIA ); + $this->assertCanNotTalk( NS_SPECIAL ); - $this->assertTrue( MWNamespace::canTalk( NS_MAIN ) ); - $this->assertTrue( MWNamespace::canTalk( NS_TALK ) ); - $this->assertTrue( MWNamespace::canTalk( NS_USER ) ); - $this->assertTrue( MWNamespace::canTalk( NS_USER_TALK ) ); + $this->assertCanTalk( NS_MAIN ); + $this->assertCanTalk( NS_TALK ); + $this->assertCanTalk( NS_USER ); + $this->assertCanTalk( NS_USER_TALK ); // User defined namespaces - $this->assertTrue( MWNamespace::canTalk( 100 ) ); - $this->assertTrue( MWNamespace::canTalk( 101 ) ); + $this->assertCanTalk( 100 ); + $this->assertCanTalk( 101 ); } /** @@ -212,16 +272,47 @@ class MWNamespaceTest extends MediaWikiTestCase { public function testIsContent() { // NS_MAIN is a content namespace per DefaultSettings.php // and per function definition. - $this->assertTrue( MWNamespace::isContent( NS_MAIN ) ); + $this->assertIsContent( NS_MAIN ); + + global $wgContentNamespaces; + + $saved = $wgContentNamespaces; + + $wgContentNamespaces[] = NS_MAIN; + $this->assertIsContent( NS_MAIN ); // Other namespaces which are not expected to be content - $this->assertFalse( MWNamespace::isContent( NS_MEDIA ) ); - $this->assertFalse( MWNamespace::isContent( NS_SPECIAL ) ); - $this->assertFalse( MWNamespace::isContent( NS_TALK ) ); - $this->assertFalse( MWNamespace::isContent( NS_USER ) ); - $this->assertFalse( MWNamespace::isContent( NS_CATEGORY ) ); - // User defined namespace: - $this->assertFalse( MWNamespace::isContent( 100 ) ); + if ( isset( $wgContentNamespaces[NS_MEDIA] ) ) { + unset( $wgContentNamespaces[NS_MEDIA] ); + } + $this->assertIsNotContent( NS_MEDIA ); + + if ( isset( $wgContentNamespaces[NS_SPECIAL] ) ) { + unset( $wgContentNamespaces[NS_SPECIAL] ); + } + $this->assertIsNotContent( NS_SPECIAL ); + + if ( isset( $wgContentNamespaces[NS_TALK] ) ) { + unset( $wgContentNamespaces[NS_TALK] ); + } + $this->assertIsNotContent( NS_TALK ); + + if ( isset( $wgContentNamespaces[NS_USER] ) ) { + unset( $wgContentNamespaces[NS_USER] ); + } + $this->assertIsNotContent( NS_USER ); + + if ( isset( $wgContentNamespaces[NS_CATEGORY] ) ) { + unset( $wgContentNamespaces[NS_CATEGORY] ); + } + $this->assertIsNotContent( NS_CATEGORY ); + + if ( isset( $wgContentNamespaces[100] ) ) { + unset( $wgContentNamespaces[100] ); + } + $this->assertIsNotContent( 100 ); + + $wgContentNamespaces = $saved; } /** @@ -231,47 +322,47 @@ class MWNamespaceTest extends MediaWikiTestCase { public function testIsContentWithAdditionsInWgContentNamespaces() { // NS_MAIN is a content namespace per DefaultSettings.php // and per function definition. - $this->assertTrue( MWNamespace::isContent( NS_MAIN ) ); + $this->assertIsContent( NS_MAIN ); // Tests that user defined namespace #252 is not content: - $this->assertFalse( MWNamespace::isContent( 252 ) ); + $this->assertIsNotContent( 252 ); # @todo FIXME: Is global saving really required for PHPUnit? // Bless namespace # 252 as a content namespace global $wgContentNamespaces; $savedGlobal = $wgContentNamespaces; $wgContentNamespaces[] = 252; - $this->assertTrue( MWNamespace::isContent( 252 ) ); + $this->assertIsContent( 252 ); // Makes sure NS_MAIN was not impacted - $this->assertTrue( MWNamespace::isContent( NS_MAIN ) ); + $this->assertIsContent( NS_MAIN ); // Restore global $wgContentNamespaces = $savedGlobal; // Verify namespaces after global restauration - $this->assertTrue( MWNamespace::isContent( NS_MAIN ) ); - $this->assertFalse( MWNamespace::isContent( 252 ) ); + $this->assertIsContent( NS_MAIN ); + $this->assertIsNotContent( 252 ); } public function testIsWatchable() { // Specials namespaces are not watchable - $this->assertFalse( MWNamespace::isWatchable( NS_MEDIA ) ); - $this->assertFalse( MWNamespace::isWatchable( NS_SPECIAL ) ); + $this->assertIsNotWatchable( NS_MEDIA ); + $this->assertIsNotWatchable( NS_SPECIAL ); // Core defined namespaces are watchables - $this->assertTrue( MWNamespace::isWatchable( NS_MAIN ) ); - $this->assertTrue( MWNamespace::isWatchable( NS_TALK ) ); + $this->assertIsWatchable( NS_MAIN ); + $this->assertIsWatchable( NS_TALK ); // Additional, user defined namespaces are watchables - $this->assertTrue( MWNamespace::isWatchable( 100 ) ); - $this->assertTrue( MWNamespace::isWatchable( 101 ) ); + $this->assertIsWatchable( 100 ); + $this->assertIsWatchable( 101 ); } public function testHasSubpages() { // Special namespaces: - $this->assertFalse( MWNamespace::hasSubpages( NS_MEDIA ) ); - $this->assertFalse( MWNamespace::hasSubpages( NS_SPECIAL ) ); + $this->assertHasNotSubpages( NS_MEDIA ); + $this->assertHasNotSubpages( NS_SPECIAL ); // namespaces without subpages # save up global @@ -282,12 +373,12 @@ class MWNamespaceTest extends MediaWikiTestCase { unset( $wgNamespacesWithSubpages[NS_MAIN] ); } - $this->assertFalse( MWNamespace::hasSubpages( NS_MAIN ) ); + $this->assertHasNotSubpages( NS_MAIN ); $wgNamespacesWithSubpages[NS_MAIN] = true; - $this->assertTrue( MWNamespace::hasSubpages( NS_MAIN ) ); + $this->assertHasSubpages( NS_MAIN ); $wgNamespacesWithSubpages[NS_MAIN] = false; - $this->assertFalse( MWNamespace::hasSubpages( NS_MAIN ) ); + $this->assertHasNotSubpages( NS_MAIN ); # restore global if( $saved !== null ) { @@ -295,9 +386,9 @@ class MWNamespaceTest extends MediaWikiTestCase { } // Some namespaces with subpages - $this->assertTrue( MWNamespace::hasSubpages( NS_TALK ) ); - $this->assertTrue( MWNamespace::hasSubpages( NS_USER ) ); - $this->assertTrue( MWNamespace::hasSubpages( NS_USER_TALK ) ); + $this->assertHasSubpages( NS_TALK ); + $this->assertHasSubpages( NS_USER ); + $this->assertHasSubpages( NS_USER_TALK ); } /** @@ -311,6 +402,7 @@ class MWNamespaceTest extends MediaWikiTestCase { global $wgContentNamespaces; + $saved = $wgContentNamespaces; # test !is_array( $wgcontentNamespaces ) $wgContentNamespaces = ''; $this->assertEquals( NS_MAIN, MWNamespace::getcontentNamespaces() ); @@ -330,7 +422,7 @@ class MWNamespaceTest extends MediaWikiTestCase { $this->assertEquals( array( NS_MAIN, NS_USER, NS_CATEGORY ), MWNamespace::getcontentNamespaces(), - 'NS_MAIN is forced in wgContentNamespaces even if unwanted' + 'NS_MAIN is forced in $wgContentNamespaces even if unwanted' ); # test other cases, return $wgcontentNamespaces as is @@ -346,6 +438,7 @@ class MWNamespaceTest extends MediaWikiTestCase { MWNamespace::getcontentNamespaces() ); + $wgContentNamespaces = $saved; } /** @@ -361,14 +454,14 @@ class MWNamespaceTest extends MediaWikiTestCase { ); // Boths are capitalized by default - $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIA ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_FILE ) ); + $this->assertIsCapitalized( NS_MEDIA ); + $this->assertIsCapitalized( NS_FILE ); // Always capitalized namespaces // @see MWNamespace::$alwaysCapitalizedNamespaces - $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) ); + $this->assertIsCapitalized( NS_SPECIAL ); + $this->assertIsCapitalized( NS_USER ); + $this->assertIsCapitalized( NS_MEDIAWIKI ); } /** @@ -389,17 +482,17 @@ class MWNamespaceTest extends MediaWikiTestCase { $savedGlobal = $wgCapitalLinks; $wgCapitalLinks = true; - $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT_TALK ) ); + $this->assertIsCapitalized( NS_PROJECT ); + $this->assertIsCapitalized( NS_PROJECT_TALK ); $wgCapitalLinks = false; // hardcoded namespaces (see above function) are still capitalized: - $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) ); + $this->assertIsCapitalized( NS_SPECIAL ); + $this->assertIsCapitalized( NS_USER ); + $this->assertIsCapitalized( NS_MEDIAWIKI ); // setting is correctly applied - $this->assertFalse( MWNamespace::isCapitalized( NS_PROJECT ) ); - $this->assertFalse( MWNamespace::isCapitalized( NS_PROJECT_TALK ) ); + $this->assertIsNotCapitalized( NS_PROJECT ); + $this->assertIsNotCapitalized( NS_PROJECT_TALK ); // reset global state: $wgCapitalLinks = $savedGlobal; @@ -417,28 +510,28 @@ class MWNamespaceTest extends MediaWikiTestCase { $savedGlobal = $wgCapitalLinkOverrides; // Test default settings - $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT_TALK ) ); + $this->assertIsCapitalized( NS_PROJECT ); + $this->assertIsCapitalized( NS_PROJECT_TALK ); // hardcoded namespaces (see above function) are capitalized: - $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) ); + $this->assertIsCapitalized( NS_SPECIAL ); + $this->assertIsCapitalized( NS_USER ); + $this->assertIsCapitalized( NS_MEDIAWIKI ); // Hardcoded namespaces remains capitalized $wgCapitalLinkOverrides[NS_SPECIAL] = false; $wgCapitalLinkOverrides[NS_USER] = false; $wgCapitalLinkOverrides[NS_MEDIAWIKI] = false; - $this->assertTrue( MWNamespace::isCapitalized( NS_SPECIAL ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_USER ) ); - $this->assertTrue( MWNamespace::isCapitalized( NS_MEDIAWIKI ) ); + $this->assertIsCapitalized( NS_SPECIAL ); + $this->assertIsCapitalized( NS_USER ); + $this->assertIsCapitalized( NS_MEDIAWIKI ); $wgCapitalLinkOverrides = $savedGlobal; $wgCapitalLinkOverrides[NS_PROJECT] = false; - $this->assertFalse( MWNamespace::isCapitalized( NS_PROJECT ) ); + $this->assertIsNotCapitalized( NS_PROJECT ); $wgCapitalLinkOverrides[NS_PROJECT] = true ; - $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) ); + $this->assertIsCapitalized( NS_PROJECT ); unset( $wgCapitalLinkOverrides[NS_PROJECT] ); - $this->assertTrue( MWNamespace::isCapitalized( NS_PROJECT ) ); + $this->assertIsCapitalized( NS_PROJECT ); // reset global state: $wgCapitalLinkOverrides = $savedGlobal; @@ -456,5 +549,45 @@ class MWNamespaceTest extends MediaWikiTestCase { $this->assertFalse( MWNamespace::hasGenderDistinction( NS_TALK ) ); } + + ####### HELPERS ########################################################### + function __call( $method, $args ) { + // Call the real method if it exists + if( method_exists($this, $method ) ) { + return $this->$method( $args ); + } + + if( preg_match( '/^assert(Has|Is|Can)(Not|)(Subject|Talk|Watchable|Content|Subpages|Capitalized)$/', $method, $m ) ) { + # Interprets arguments: + $ns = $args[0]; + $msg = isset($args[1]) ? $args[1] : " dummy message"; + + # Forge the namespace constant name: + if( $ns === 0 ) { + $ns_name = "NS_MAIN"; + } else { + $ns_name = "NS_" . strtoupper( MWNamespace::getCanonicalName( $ns ) ); + } + # ... and the MWNamespace method name + $nsMethod = strtolower( $m[1] ) . $m[3]; + + $expect = ($m[2] === ''); + $expect_name = $expect ? 'TRUE' : 'FALSE'; + + return $this->assertEquals( $expect, + MWNamespace::$nsMethod( $ns, $msg ), + "MWNamespace::$nsMethod( $ns_name ) should returns $expect_name" + ); + } + + throw new Exception( __METHOD__ . " could not find a method named $method\n" ); + } + + function assertSameSubject( $ns1, $ns2, $msg = '' ) { + $this->assertTrue( MWNamespace::subjectEquals( $ns1, $ns2, $msg ) ); + } + function assertDifferentSubject( $ns1, $ns2, $msg = '' ) { + $this->assertFalse( MWNamespace::subjectEquals( $ns1, $ns2, $msg ) ); + } } diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php index 45c02bbe..295b6d74 100644 --- a/tests/phpunit/includes/MessageTest.php +++ b/tests/phpunit/includes/MessageTest.php @@ -47,7 +47,7 @@ class MessageTest extends MediaWikiLangTestCase { $this->assertEquals( 'Main Page', wfMessage( 'mainpage' )->inContentLanguage()->plain(), 'ForceUIMsg disabled' ); $wgForceUIMsgAsContentMsg['testInContentLanguage'] = 'mainpage'; $this->assertEquals( 'Accueil', wfMessage( 'mainpage' )->inContentLanguage()->plain(), 'ForceUIMsg enabled' ); - + /* Restore globals */ $wgLang = $oldLang; unset( $wgForceUIMsgAsContentMsg['testInContentLanguage'] ); diff --git a/tests/phpunit/includes/ParserOptionsTest.php b/tests/phpunit/includes/ParserOptionsTest.php index 58c89146..59c955fe 100644 --- a/tests/phpunit/includes/ParserOptionsTest.php +++ b/tests/phpunit/includes/ParserOptionsTest.php @@ -6,10 +6,9 @@ class ParserOptionsTest extends MediaWikiTestCase { private $pcache; function setUp() { - ParserTest::setUp(); //reuse setup from parser tests global $wgContLang, $wgUser, $wgLanguageCode; $wgContLang = Language::factory( $wgLanguageCode ); - $this->popts = new ParserOptions( $wgUser ); + $this->popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang ); $this->pcache = ParserCache::singleton(); } @@ -26,11 +25,11 @@ class ParserOptionsTest extends MediaWikiTestCase { $wgUseDynamicDates = true; $title = Title::newFromText( "Some test article" ); - $article = new Article( $title ); + $page = WikiPage::factory( $title ); - $pcacheKeyBefore = $this->pcache->getKey( $article, $this->popts ); + $pcacheKeyBefore = $this->pcache->getKey( $page, $this->popts ); $this->assertNotNull( $this->popts->getDateFormat() ); - $pcacheKeyAfter = $this->pcache->getKey( $article, $this->popts ); + $pcacheKeyAfter = $this->pcache->getKey( $page, $this->popts ); $this->assertEquals( $pcacheKeyBefore, $pcacheKeyAfter ); } } diff --git a/tests/phpunit/includes/PathRouterTest.php b/tests/phpunit/includes/PathRouterTest.php new file mode 100644 index 00000000..f6274584 --- /dev/null +++ b/tests/phpunit/includes/PathRouterTest.php @@ -0,0 +1,254 @@ +<?php +/** + * Tests for the PathRouter parsing + */ + +class PathRouterTest extends MediaWikiTestCase { + + public function setUp() { + $router = new PathRouter; + $router->add("/wiki/$1"); + $this->basicRouter = $router; + } + + /** + * Test basic path parsing + */ + public function testBasic() { + $matches = $this->basicRouter->parse( "/wiki/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo" ) ); + } + + /** + * Test loose path auto-$1 + */ + public function testLoose() { + $router = new PathRouter; + $router->add("/"); # Should be the same as "/$1" + $matches = $router->parse( "/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo" ) ); + + $router = new PathRouter; + $router->add("/wiki"); # Should be the same as /wiki/$1 + $matches = $router->parse( "/wiki/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo" ) ); + + $router = new PathRouter; + $router->add("/wiki/"); # Should be the same as /wiki/$1 + $matches = $router->parse( "/wiki/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo" ) ); + } + + /** + * Test to ensure that path is based on specifity, not order + */ + public function testOrder() { + $router = new PathRouter; + $router->add("/$1"); + $router->add("/a/$1"); + $router->add("/b/$1"); + $matches = $router->parse( "/a/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo" ) ); + + $router = new PathRouter; + $router->add("/b/$1"); + $router->add("/a/$1"); + $router->add("/$1"); + $matches = $router->parse( "/a/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo" ) ); + } + + /** + * Test the handling of key based arrays with a url parameter + */ + public function testKeyParameter() { + $router = new PathRouter; + $router->add( array( 'edit' => "/edit/$1" ), array( 'action' => '$key' ) ); + $matches = $router->parse( "/edit/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo", 'action' => 'edit' ) ); + } + + /** + * Test the handling of $2 inside paths + */ + public function testAdditionalParameter() { + // Basic $2 + $router = new PathRouter; + $router->add( '/$2/$1', array( 'test' => '$2' ) ); + $matches = $router->parse( "/asdf/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo", 'test' => 'asdf' ) ); + } + + /** + * Test additional restricted value parameter + */ + public function testRestrictedValue() { + $router = new PathRouter; + $router->add( '/$2/$1', + array( 'test' => '$2' ), + array( '$2' => array( 'a', 'b' ) ) + ); + $router->add( '/$2/$1', + array( 'test2' => '$2' ), + array( '$2' => 'c' ) + ); + $router->add( '/$1' ); + + $matches = $router->parse( "/asdf/Foo" ); + $this->assertEquals( $matches, array( 'title' => "asdf/Foo" ) ); + + $matches = $router->parse( "/a/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo", 'test' => 'a' ) ); + + $matches = $router->parse( "/c/Foo" ); + $this->assertEquals( $matches, array( 'title' => "Foo", 'test2' => 'c' ) ); + } + + public function callbackForTest( &$matches, $data ) { + $matches['x'] = $data['$1']; + $matches['foo'] = $data['foo']; + } + + public function testCallback() { + $router = new PathRouter; + $router->add( "/$1", + array( 'a' => 'b', 'data:foo' => 'bar' ), + array( 'callback' => array( $this, 'callbackForTest' ) ) + ); + $matches = $router->parse( '/Foo' ); + $this->assertEquals( $matches, array( + 'title' => "Foo", + 'x' => 'Foo', + 'a' => 'b', + 'foo' => 'bar' + ) ); + } + + /** + * Test to ensure that matches are not made if a parameter expects nonexistent input + */ + public function testFail() { + $router = new PathRouter; + $router->add( "/wiki/$1", array( 'title' => "$1$2" ) ); + $matches = $router->parse( "/wiki/A" ); + $this->assertEquals( array(), $matches ); + } + + /** + * Test to ensure weight of paths is handled correctly + */ + public function testWeight() { + $router = new PathRouter; + $router->addStrict( "/Bar", array( 'ping' => 'pong' ) ); + $router->add( "/asdf-$1", array( 'title' => 'qwerty-$1' ) ); + $router->add( "/$1" ); + $router->add( "/qwerty-$1", array( 'title' => 'asdf-$1' ) ); + $router->addStrict( "/Baz", array( 'marco' => 'polo' ) ); + $router->add( "/a/$1" ); + $router->add( "/asdf/$1" ); + $router->add( "/$2/$1", array( 'unrestricted' => '$2' ) ); + $router->add( array( 'qwerty' => "/qwerty/$1" ), array( 'qwerty' => '$key' ) ); + $router->add( "/$2/$1", array( 'restricted-to-y' => '$2' ), array( '$2' => 'y' ) ); + + foreach( array( + "/Foo" => array( 'title' => "Foo" ), + "/Bar" => array( 'ping' => 'pong' ), + "/Baz" => array( 'marco' => 'polo' ), + "/asdf-foo" => array( 'title' => "qwerty-foo" ), + "/qwerty-bar" => array( 'title' => "asdf-bar" ), + "/a/Foo" => array( 'title' => "Foo" ), + "/asdf/Foo" => array( 'title' => "Foo" ), + "/qwerty/Foo" => array( 'title' => "Foo", 'qwerty' => 'qwerty' ), + "/baz/Foo" => array( 'title' => "Foo", 'unrestricted' => 'baz' ), + "/y/Foo" => array( 'title' => "Foo", 'restricted-to-y' => 'y' ), + ) as $path => $result ) { + $this->assertEquals( $router->parse( $path ), $result ); + } + } + + /** + * Make sure the router handles titles like Special:Recentchanges correctly + */ + public function testSpecial() { + $matches = $this->basicRouter->parse( "/wiki/Special:Recentchanges" ); + $this->assertEquals( $matches, array( 'title' => "Special:Recentchanges" ) ); + } + + /** + * Make sure the router decodes urlencoding properly + */ + public function testUrlencoding() { + $matches = $this->basicRouter->parse( "/wiki/Title_With%20Space" ); + $this->assertEquals( $matches, array( 'title' => "Title_With Space" ) ); + } + + public function dataRegexpChars() { + return array( + array( "$" ), + array( "$1" ), + array( "\\" ), + array( "\\$1" ), + ); + } + + /** + * Make sure the router doesn't break on special characters like $ used in regexp replacements + * @dataProvider dataRegexpChars + */ + public function testRegexpChars( $char ) { + $matches = $this->basicRouter->parse( "/wiki/$char" ); + $this->assertEquals( $matches, array( 'title' => "$char" ) ); + } + + /** + * Make sure the router handles characters like +&() properly + */ + public function testCharacters() { + $matches = $this->basicRouter->parse( "/wiki/Plus+And&Dollar\\Stuff();[]{}*" ); + $this->assertEquals( $matches, array( 'title' => "Plus+And&Dollar\\Stuff();[]{}*" ) ); + } + + /** + * Make sure the router handles unicode characters correctly + * @depends testSpecial + * @depends testUrlencoding + * @depends testCharacters + */ + public function testUnicode() { + $matches = $this->basicRouter->parse( "/wiki/Spécial:Modifications_récentes" ); + $this->assertEquals( $matches, array( 'title' => "Spécial:Modifications_récentes" ) ); + + $matches = $this->basicRouter->parse( "/wiki/Sp%C3%A9cial:Modifications_r%C3%A9centes" ); + $this->assertEquals( $matches, array( 'title' => "Spécial:Modifications_récentes" ) ); + } + + /** + * Ensure the router doesn't choke on long paths. + */ + public function testLength() { + $matches = $this->basicRouter->parse( "/wiki/Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." ); + $this->assertEquals( $matches, array( 'title' => "Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." ) ); + } + + + /** + * Ensure that the php passed site of parameter values are not urldecoded + */ + public function testPatternUrlencoding() { + $router = new PathRouter; + $router->add( "/wiki/$1", array( 'title' => '%20:$1' ) ); + $matches = $router->parse( "/wiki/Foo" ); + $this->assertEquals( $matches, array( 'title' => '%20:Foo' ) ); + } + + /** + * Ensure that raw parameter values do not have any variable replacements or urldecoding + */ + public function testRawParamValue() { + $router = new PathRouter; + $router->add( "/wiki/$1", array( 'title' => array( 'value' => 'bar%20$1' ) ) ); + $matches = $router->parse( "/wiki/Foo" ); + $this->assertEquals( $matches, array( 'title' => 'bar%20$1' ) ); + } + +} diff --git a/tests/phpunit/includes/Providers.php b/tests/phpunit/includes/Providers.php index 02898673..f451f8a0 100644 --- a/tests/phpunit/includes/Providers.php +++ b/tests/phpunit/includes/Providers.php @@ -2,8 +2,8 @@ /** * Generic providers for the MediaWiki PHPUnit test suite * - * @author Ashar Voultoiz - * @copyright Copyright © 2011, Ashar Voultoiz + * @author Antoine Musso + * @copyright Copyright © 2011, Antoine Musso * @file */ diff --git a/tests/phpunit/includes/ResourceLoaderTest.php b/tests/phpunit/includes/ResourceLoaderTest.php index 30a69c5e..ab704839 100644 --- a/tests/phpunit/includes/ResourceLoaderTest.php +++ b/tests/phpunit/includes/ResourceLoaderTest.php @@ -1,6 +1,6 @@ <?php -class ResourceLoaderTest extends PHPUnit_Framework_TestCase { +class ResourceLoaderTest extends MediaWikiTestCase { protected static $resourceLoaderRegisterModulesHook; diff --git a/tests/phpunit/includes/SanitizerTest.php b/tests/phpunit/includes/SanitizerTest.php index 40d6cf77..b76aa5c7 100644 --- a/tests/phpunit/includes/SanitizerTest.php +++ b/tests/phpunit/includes/SanitizerTest.php @@ -109,5 +109,48 @@ class SanitizerTest extends MediaWikiTestCase { $this->assertEquals( Sanitizer::decodeTagAttributes( 'foo=&"' ), array( 'foo' => '&"' ), 'Special chars can be provided as entities' ); $this->assertEquals( Sanitizer::decodeTagAttributes( 'foo=&foobar;' ), array( 'foo' => '&foobar;' ), 'Entity-like items are accepted' ); } + + function testDeprecatedAttributes() { + $GLOBALS['wgCleanupPresentationalAttributes'] = true; + $this->assertEquals( Sanitizer::fixTagAttributes( 'clear="left"', 'br' ), ' style="clear: left;"', 'Deprecated attributes are converted to styles when enabled.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'clear="all"', 'br' ), ' style="clear: both;"', 'clear=all is converted to clear: both; not clear: all;' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'CLEAR="ALL"', 'br' ), ' style="clear: both;"', 'clear=ALL is not treated differently from clear=all' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'width="100"', 'td' ), ' style="width: 100px;"', 'Numeric sizes use pixels instead of numbers.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'width="100%"', 'td' ), ' style="width: 100%;"', 'Units are allowed in sizes.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'WIDTH="100%"', 'td' ), ' style="width: 100%;"', 'Uppercase WIDTH is treated as lowercase width.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'WiDTh="100%"', 'td' ), ' style="width: 100%;"', 'Mixed case does not break WiDTh.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'nowrap="true"', 'td' ), ' style="white-space: nowrap;"', 'nowrap attribute is output as white-space: nowrap; not something else.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'nowrap=""', 'td' ), ' style="white-space: nowrap;"', 'nowrap="" is considered true, not false' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'NOWRAP="true"', 'td' ), ' style="white-space: nowrap;"', 'nowrap attribute works when uppercase.' ); + $this->assertEquals( Sanitizer::fixTagAttributes( 'NoWrAp="true"', 'td' ), ' style="white-space: nowrap;"', 'nowrap attribute works when mixed-case.' ); + $GLOBALS['wgCleanupPresentationalAttributes'] = false; + $this->assertEquals( Sanitizer::fixTagAttributes( 'clear="left"', 'br' ), ' clear="left"', 'Deprecated attributes are not converted to styles when enabled.' ); + } + + /** + * @dataProvider provideCssCommentsFixtures + */ + function testCssCommentsChecking( $expected, $css, $message = '' ) { + $this->assertEquals( + $expected, + Sanitizer::checkCss( $css ), + $message + ); + } + + function provideCssCommentsFixtures() { + /** array( <expected>, <css>, [message] ) */ + return array( + array( ' ', '/**/' ), + array( ' ', '/****/' ), + array( ' ', '/* comment */' ), + array( ' ', "\\2f\\2a foo \\2a\\2f", + 'Backslash-escaped comments must be stripped (bug 28450)' ), + array( '', '/* unfinished comment structure', + 'Remove anything after a comment-start token' ), + array( '', "\\2f\\2a unifinished comment'", + 'Remove anything after a backslash-escaped comment-start token' ), + ); + } } diff --git a/tests/phpunit/includes/UserIsValidEmailAddrTest.php b/tests/phpunit/includes/SanitizerValidateEmailTest.php index 99bf718e..14d799cf 100644 --- a/tests/phpunit/includes/UserIsValidEmailAddrTest.php +++ b/tests/phpunit/includes/SanitizerValidateEmailTest.php @@ -1,12 +1,12 @@ <?php -class UserIsValidEmailAddrTest extends MediaWikiTestCase { +class SanitizerValidateEmailTest extends MediaWikiTestCase { private function checkEmail( $addr, $expected = true, $msg = '') { if( $msg == '' ) { $msg = "Testing $addr"; } $this->assertEquals( $expected, - User::isValidEmailAddr( $addr ), + Sanitizer::validateEmail( $addr ), $msg ); } diff --git a/tests/phpunit/includes/SeleniumConfigurationTest.php b/tests/phpunit/includes/SeleniumConfigurationTest.php index 750524eb..8589c188 100644 --- a/tests/phpunit/includes/SeleniumConfigurationTest.php +++ b/tests/phpunit/includes/SeleniumConfigurationTest.php @@ -2,13 +2,13 @@ class SeleniumConfigurationTest extends MediaWikiTestCase { - /* + /** * The file where the test temporarity stores the selenium config. * This should be cleaned up as part of teardown. */ private $tempFileName; - /* + /** * String containing the a sample selenium settings */ private $testConfig0 = @@ -32,14 +32,14 @@ runAgainstGrid = false testSuite[SimpleSeleniumTestSuite] = "tests/selenium/SimpleSeleniumTestSuite.php" testSuite[TestSuiteName] = "testSuitePath" '; - /* + /** * Array of expected browsers from $testConfig0 */ private $testBrowsers0 = array( 'firefox' => '*firefox', 'iexplorer' => '*iexploreproxy', 'chrome' => '*chrome' ); - /* + /** * Array of expected selenium settings from $testConfig0 */ private $testSettings0 = array( @@ -55,7 +55,7 @@ testSuite[TestSuiteName] = "testSuitePath" 'jUnitLogFile' => null, 'runAgainstGrid' => null ); - /* + /** * Array of expected testSuites from $testConfig0 */ private $testSuites0 = array( @@ -64,7 +64,7 @@ testSuite[TestSuiteName] = "testSuitePath" ); - /* + /** * Another sample selenium settings file contents */ private $testConfig1 = @@ -73,11 +73,11 @@ testSuite[TestSuiteName] = "testSuitePath" host = "localhost" testBrowser = "firefox" '; - /* + /** * Expected browsers from $testConfig1 */ private $testBrowsers1 = null; - /* + /** * Expected selenium settings from $testConfig1 */ private $testSettings1 = array( @@ -93,7 +93,7 @@ testBrowser = "firefox" 'jUnitLogFile' => null, 'runAgainstGrid' => null ); - /* + /** * Expected test suites from $testConfig1 */ private $testSuites1 = null; @@ -105,7 +105,7 @@ testBrowser = "firefox" } } - /* + /** * Clean up the temporary file used to store the selenium settings. */ public function tearDown() { @@ -199,7 +199,7 @@ testBrowser = "firefox" } - /* + /** * create a temp file and write text to it. * @param $testToWrite the text to write to the temp file */ @@ -210,7 +210,7 @@ testBrowser = "firefox" fclose($tempFile); } - /* + /** * Returns an array containing: * The contents of the selenium cingiguration ini file * The expected selenium configuration array that getSeleniumSettings should return diff --git a/tests/phpunit/includes/TemplateCategoriesTest.php b/tests/phpunit/includes/TemplateCategoriesTest.php new file mode 100644 index 00000000..de9d6dc6 --- /dev/null +++ b/tests/phpunit/includes/TemplateCategoriesTest.php @@ -0,0 +1,38 @@ +<?php + +/** + * @group Database + */ +require dirname( __FILE__ ) . "/../../../maintenance/runJobs.php"; + +class TemplateCategoriesTest extends MediaWikiLangTestCase { + + function testTemplateCategories() { + global $wgUser; + + $title = Title::newFromText( "Categorized from template" ); + $article = new Article( $title ); + $wgUser = new User(); + $wgUser->mRights['*'] = array( 'createpage', 'edit', 'purge' ); + + $status = $article->doEdit( '{{Categorising template}}', 'Create a page with a template', 0 ); + $this->assertEquals( + array() + , $title->getParentCategories() + ); + + $template = new Article( Title::newFromText( 'Template:Categorising template' ) ); + $status = $template->doEdit( '[[Category:Solved bugs]]', 'Add a category through a template', 0 ); + + // Run the job queue + $jobs = new RunJobs; + $jobs->loadParamsAndArgs( null, array( 'quiet' => true ), null ); + $jobs->execute(); + + $this->assertEquals( + array( 'Category:Solved_bugs' => $title->getPrefixedText() ) + , $title->getParentCategories() + ); + } + +} diff --git a/tests/phpunit/includes/TitleMethodsTest.php b/tests/phpunit/includes/TitleMethodsTest.php new file mode 100644 index 00000000..2f1103e8 --- /dev/null +++ b/tests/phpunit/includes/TitleMethodsTest.php @@ -0,0 +1,78 @@ +<?php + +class TitleMethodsTest extends MediaWikiTestCase { + + public function dataEquals() { + return array( + array( 'Main Page', 'Main Page', true ), + array( 'Main Page', 'Not The Main Page', false ), + array( 'Main Page', 'Project:Main Page', false ), + array( 'File:Example.png', 'Image:Example.png', true ), + array( 'Special:Version', 'Special:Version', true ), + array( 'Special:Version', 'Special:Recentchanges', false ), + array( 'Special:Version', 'Main Page', false ), + ); + } + + /** + * @dataProvider dataEquals + */ + public function testEquals( $titleA, $titleB, $expectedBool ) { + $titleA = Title::newFromText( $titleA ); + $titleB = Title::newFromText( $titleB ); + + $this->assertEquals( $titleA->equals( $titleB ), $expectedBool ); + $this->assertEquals( $titleB->equals( $titleA ), $expectedBool ); + } + + public function dataInNamespace() { + return array( + array( 'Main Page', NS_MAIN, true ), + array( 'Main Page', NS_TALK, false ), + array( 'Main Page', NS_USER, false ), + array( 'User:Foo', NS_USER, true ), + array( 'User:Foo', NS_USER_TALK, false ), + array( 'User:Foo', NS_TEMPLATE, false ), + array( 'User_talk:Foo', NS_USER_TALK, true ), + array( 'User_talk:Foo', NS_USER, false ), + ); + } + + /** + * @dataProvider dataInNamespace + */ + public function testInNamespace( $title, $ns, $expectedBool ) { + $title = Title::newFromText( $title ); + $this->assertEquals( $title->inNamespace( $ns ), $expectedBool ); + } + + public function testInNamespaces() { + $mainpage = Title::newFromText( 'Main Page' ); + $this->assertTrue( $mainpage->inNamespaces( NS_MAIN, NS_USER ) ); + $this->assertTrue( $mainpage->inNamespaces( array( NS_MAIN, NS_USER ) ) ); + $this->assertTrue( $mainpage->inNamespaces( array( NS_USER, NS_MAIN ) ) ); + $this->assertFalse( $mainpage->inNamespaces( array( NS_PROJECT, NS_TEMPLATE ) ) ); + } + + public function dataHasSubjectNamespace() { + return array( + array( 'Main Page', NS_MAIN, true ), + array( 'Main Page', NS_TALK, true ), + array( 'Main Page', NS_USER, false ), + array( 'User:Foo', NS_USER, true ), + array( 'User:Foo', NS_USER_TALK, true ), + array( 'User:Foo', NS_TEMPLATE, false ), + array( 'User_talk:Foo', NS_USER_TALK, true ), + array( 'User_talk:Foo', NS_USER, true ), + ); + } + + /** + * @dataProvider dataHasSubjectNamespace + */ + public function testHasSubjectNamespace( $title, $ns, $expectedBool ) { + $title = Title::newFromText( $title ); + $this->assertEquals( $title->hasSubjectNamespace( $ns ), $expectedBool ); + } + +} diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php index 1b179686..f62ac5dd 100644 --- a/tests/phpunit/includes/TitlePermissionTest.php +++ b/tests/phpunit/includes/TitlePermissionTest.php @@ -5,12 +5,16 @@ */ class TitlePermissionTest extends MediaWikiLangTestCase { protected $title; - protected $user; - protected $anonUser; - protected $userUser; - protected $altUser; - protected $userName; - protected $altUserName; + + /** + * @var User + */ + protected $user, $anonUser, $userUser, $altUser; + + /** + * @var string + */ + protected $userName, $altUserName; function setUp() { global $wgLocaltimezone, $wgLocalTZoffset, $wgMemc, $wgContLang, $wgLang; @@ -56,6 +60,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase { } function setUserPerm( $perm ) { + // Setting member variables is evil!!! + if ( is_array( $perm ) ) { $this->user->mRights = $perm; } else { @@ -299,7 +305,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->assertEquals( $check[$action][3], $this->title->userCan( $action, true ) ); $this->assertEquals( $check[$action][3], - $this->title->quickUserCan( $action, false ) ); + $this->title->quickUserCan( $action ) ); # count( User::getGroupsWithPermissions( $action ) ) < 1 } @@ -451,7 +457,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->user ) ); $this->assertEquals( true, - $this->title->quickUserCan( 'edit', false ) ); + $this->title->quickUserCan( 'edit' ) ); $this->title->mRestrictions = array( "edit" => array( 'bogus', "sysop", "protect", "" ), "bogus" => array( 'bogus', "sysop", "protect", "" ) ); @@ -491,9 +497,9 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->user ) ); $this->title->mCascadeRestriction = true; $this->assertEquals( false, - $this->title->quickUserCan( 'bogus', false ) ); + $this->title->quickUserCan( 'bogus' ) ); $this->assertEquals( false, - $this->title->quickUserCan( 'edit', false ) ); + $this->title->quickUserCan( 'edit' ) ); $this->assertEquals( array( array( 'badaccess-group0' ), array( 'protectedpagetext', 'bogus' ), array( 'protectedpagetext', 'protect' ), @@ -537,7 +543,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->setTitle( NS_MAIN, "test page" ); $this->title->mTitleProtection['pt_create_perm'] = ''; $this->title->mTitleProtection['pt_user'] = $this->user->getID(); - $this->title->mTitleProtection['pt_expiry'] = Block::infinity(); + $this->title->mTitleProtection['pt_expiry'] = wfGetDB( DB_SLAVE )->getInfinity(); $this->title->mTitleProtection['pt_reason'] = 'test'; $this->title->mCascadeRestriction = false; @@ -574,7 +580,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->title->userCan( 'move' ) ); $this->title->mInterwiki = "no"; - $this->assertEquals( array( array( 'immobile-page' ) ), + $this->assertEquals( array( array( 'immobile-source-page' ) ), $this->title->getUserPermissionsErrors( 'move', $this->user ) ); $this->assertEquals( false, $this->title->userCan( 'move' ) ); @@ -623,7 +629,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $prev = time(); $now = time() + 120; $this->user->mBlockedby = $this->user->getId(); - $this->user->mBlock = new Block( '127.0.8.1', $this->user->getId(), $this->user->getId(), + $this->user->mBlock = new Block( '127.0.8.1', 0, $this->user->getId(), 'no reason given', $prev + 3600, 1, 0 ); $this->user->mBlock->mTimestamp = 0; $this->assertEquals( array( array( 'autoblockedtext', @@ -640,7 +646,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { global $wgLocalTZoffset; $wgLocalTZoffset = -60; $this->user->mBlockedby = $this->user->getName(); - $this->user->mBlock = new Block( '127.0.8.1', 2, 1, 'no reason given', $now, 0, 10 ); + $this->user->mBlock = new Block( '127.0.8.1', 0, 1, 'no reason given', $now, 0, 10 ); $this->assertEquals( array( array( 'blockedtext', '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1', 'Useruser', null, '23:00, 31 December 1969', '127.0.8.1', diff --git a/tests/phpunit/includes/TitleTest.php b/tests/phpunit/includes/TitleTest.php index e7bb98ac..1c8be5f9 100644 --- a/tests/phpunit/includes/TitleTest.php +++ b/tests/phpunit/includes/TitleTest.php @@ -41,10 +41,10 @@ class TitleTest extends MediaWikiTestCase { /** * Auth-less test of Title::isValidMoveOperation * + * @group Database * @param string $source * @param string $target - * @param array|string|true $requiredErrors - * @group Database + * @param array|string|true $expected Required error * @dataProvider dataTestIsValidMoveOperation */ function testIsValidMoveOperation( $source, $target, $expected ) { diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php index df91aca8..ef03e835 100644 --- a/tests/phpunit/includes/UserTest.php +++ b/tests/phpunit/includes/UserTest.php @@ -1,47 +1,67 @@ <?php +define( 'NS_UNITTEST', 5600 ); +define( 'NS_UNITTEST_TALK', 5601 ); + +/** + * @group Database + */ class UserTest extends MediaWikiTestCase { protected $savedGroupPermissions, $savedRevokedPermissions; - + + /** + * @var User + */ + protected $user; + public function setUp() { parent::setUp(); - + $this->savedGroupPermissions = $GLOBALS['wgGroupPermissions']; $this->savedRevokedPermissions = $GLOBALS['wgRevokePermissions']; - + $this->setUpPermissionGlobals(); + $this->setUpUser(); } private function setUpPermissionGlobals() { global $wgGroupPermissions, $wgRevokePermissions; - + + # Data for regular $wgGroupPermissions test $wgGroupPermissions['unittesters'] = array( + 'test' => true, 'runtest' => true, 'writetest' => false, 'nukeworld' => false, ); $wgGroupPermissions['testwriters'] = array( + 'test' => true, 'writetest' => true, 'modifytest' => true, ); - + # Data for regular $wgRevokePermissions test $wgRevokePermissions['formertesters'] = array( 'runtest' => true, ); } + private function setUpUser() { + $this->user = new User; + $this->user->addGroup( 'unittesters' ); + } + public function tearDown() { parent::tearDown(); - + $GLOBALS['wgGroupPermissions'] = $this->savedGroupPermissions; $GLOBALS['wgRevokePermissions'] = $this->savedRevokedPermissions; } - + public function testGroupPermissions() { $rights = User::getGroupPermissions( array( 'unittesters' ) ); $this->assertContains( 'runtest', $rights ); $this->assertNotContains( 'writetest', $rights ); $this->assertNotContains( 'modifytest', $rights ); $this->assertNotContains( 'nukeworld', $rights ); - + $rights = User::getGroupPermissions( array( 'unittesters', 'testwriters' ) ); $this->assertContains( 'runtest', $rights ); $this->assertContains( 'writetest', $rights ); @@ -53,6 +73,71 @@ class UserTest extends MediaWikiTestCase { $this->assertNotContains( 'runtest', $rights ); $this->assertNotContains( 'writetest', $rights ); $this->assertNotContains( 'modifytest', $rights ); - $this->assertNotContains( 'nukeworld', $rights ); + $this->assertNotContains( 'nukeworld', $rights ); + } + + public function testUserPermissions() { + $rights = $this->user->getRights(); + $this->assertContains( 'runtest', $rights ); + $this->assertNotContains( 'writetest', $rights ); + $this->assertNotContains( 'modifytest', $rights ); + $this->assertNotContains( 'nukeworld', $rights ); + } + + /** + * @dataProvider provideGetGroupsWithPermission + */ + public function testGetGroupsWithPermission( $expected, $right ) { + $result = User::getGroupsWithPermission( $right ); + sort( $result ); + sort( $expected ); + + $this->assertEquals( $expected, $result, "Groups with permission $right" ); + } + + public function provideGetGroupsWithPermission() { + return array( + array( + array( 'unittesters', 'testwriters' ), + 'test' + ), + array( + array( 'unittesters' ), + 'runtest' + ), + array( + array( 'testwriters' ), + 'writetest' + ), + array( + array( 'testwriters' ), + 'modifytest' + ), + ); + } + + /** + * @dataProvider provideUserNames + */ + public function testIsValidUserName( $username, $result, $message ) { + $this->assertEquals( $this->user->isValidUserName( $username ), $result, $message ); + } + + public function provideUserNames() { + return array( + array( '', false, 'Empty string' ), + array( ' ', false, 'Blank space' ), + array( 'abcd', false, 'Starts with small letter' ), + array( 'Ab/cd', false, 'Contains slash' ), + array( 'Ab cd' , true, 'Whitespace' ), + array( '192.168.1.1', false, 'IP' ), + array( 'User:Abcd', false, 'Reserved Namespace' ), + array( '12abcd232' , true , 'Starts with Numbers' ), + array( '?abcd' , true, 'Start with ? mark' ), + array( '#abcd', false, 'Start with #' ), + array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ), + array( 'ജോസ്തോമസ്', false, 'ZWNJ- Format control character' ), + array( 'Ab cd', false, ' Ideographic space' ), + ); } -}
\ No newline at end of file +} diff --git a/tests/phpunit/includes/WebRequestTest.php b/tests/phpunit/includes/WebRequestTest.php index 1cfbd3fc..e72408f6 100644 --- a/tests/phpunit/includes/WebRequestTest.php +++ b/tests/phpunit/includes/WebRequestTest.php @@ -85,4 +85,101 @@ class WebRequestTest extends MediaWikiTestCase { ), ); } + + /** + * @dataProvider provideGetIP + */ + function testGetIP( $expected, $input, $squid, $private, $description ) { + global $wgSquidServersNoPurge, $wgUsePrivateIPs; + $oldServer = $_SERVER; + $_SERVER = $input; + $wgSquidServersNoPurge = $squid; + $wgUsePrivateIPs = $private; + $request = new WebRequest(); + $result = $request->getIP(); + $_SERVER = $oldServer; + $this->assertEquals( $expected, $result, $description ); + } + + function provideGetIP() { + return array( + array( + '127.0.0.1', + array( + 'REMOTE_ADDR' => '127.0.0.1' + ), + array(), + false, + 'Simple IPv4' + ), + array( + '::1', + array( + 'REMOTE_ADDR' => '::1' + ), + array(), + false, + 'Simple IPv6' + ), + array( + '12.0.0.3', + array( + 'REMOTE_ADDR' => '12.0.0.1', + 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2' + ), + array( '12.0.0.1', '12.0.0.2' ), + false, + 'With X-Forwaded-For' + ), + array( + '12.0.0.1', + array( + 'REMOTE_ADDR' => '12.0.0.1', + 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2' + ), + array(), + false, + 'With X-Forwaded-For and disallowed server' + ), + array( + '12.0.0.2', + array( + 'REMOTE_ADDR' => '12.0.0.1', + 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2' + ), + array( '12.0.0.1' ), + false, + 'With multiple X-Forwaded-For and only one allowed server' + ), + array( + '12.0.0.2', + array( + 'REMOTE_ADDR' => '12.0.0.2', + 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2' + ), + array( '12.0.0.1', '12.0.0.2' ), + false, + 'With X-Forwaded-For and private IP' + ), + array( + '10.0.0.3', + array( + 'REMOTE_ADDR' => '12.0.0.2', + 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2' + ), + array( '12.0.0.1', '12.0.0.2' ), + true, + 'With X-Forwaded-For and private IP (allowed)' + ), + ); + } + + /** + * @expectedException MWException + */ + function testGetIpLackOfRemoteAddrThrowAnException() { + $request = new WebRequest(); + # Next call throw an exception about lacking an IP + $request->getIP(); + } } diff --git a/tests/phpunit/includes/XmlSelectTest.php b/tests/phpunit/includes/XmlSelectTest.php index bf761e3d..2407c151 100644 --- a/tests/phpunit/includes/XmlSelectTest.php +++ b/tests/phpunit/includes/XmlSelectTest.php @@ -80,7 +80,7 @@ class XmlSelectTest extends MediaWikiTestCase { $this->select->addOption( 'foo2' ); $this->assertEquals( '<select><option value="foo1">foo1</option>' . "\n" . -'<option value="bar1" selected="selected">bar1</option>' . "\n" . +'<option value="bar1" selected="">bar1</option>' . "\n" . '<option value="foo2">foo2</option></select>', $this->select->getHTML() ); } @@ -96,7 +96,7 @@ class XmlSelectTest extends MediaWikiTestCase { $this->select->setDefault( 'bar1' ); # setting default after adding options $this->assertEquals( '<select><option value="foo1">foo1</option>' . "\n" . -'<option value="bar1" selected="selected">bar1</option>' . "\n" . +'<option value="bar1" selected="">bar1</option>' . "\n" . '<option value="foo2">foo2</option></select>', $this->select->getHTML() ); } diff --git a/tests/phpunit/includes/XmlTest.php b/tests/phpunit/includes/XmlTest.php index a6058ef6..1d9361f2 100644 --- a/tests/phpunit/includes/XmlTest.php +++ b/tests/phpunit/includes/XmlTest.php @@ -2,19 +2,43 @@ class XmlTest extends MediaWikiTestCase { private static $oldLang; + private static $oldNamespaces; public function setUp() { - global $wgLang, $wgLanguageCode; - + global $wgLang, $wgContLang; + self::$oldLang = $wgLang; - $wgLanguageCode = 'en'; - $wgLang = Language::factory( $wgLanguageCode ); + $wgLang = Language::factory( 'en' ); + + // Hardcode namespaces during test runs, + // so that html output based on existing namespaces + // can be properly evaluated. + self::$oldNamespaces = $wgContLang->getNamespaces(); + $wgContLang->setNamespaces( array( + -2 => 'Media', + -1 => 'Special', + 0 => '', + 1 => 'Talk', + 2 => 'User', + 3 => 'User_talk', + 4 => 'MyWiki', + 5 => 'MyWiki_Talk', + 6 => 'File', + 7 => 'File_talk', + 8 => 'MediaWiki', + 9 => 'MediaWiki_talk', + 10 => 'Template', + 11 => 'Template_talk', + 100 => 'Custom', + 101 => 'Custom_talk', + ) ); } - + public function tearDown() { - global $wgLang, $wgLanguageCode; + global $wgLang, $wgContLang; $wgLang = self::$oldLang; - $wgLanguageCode = $wgLang->getCode(); + + $wgContLang->setNamespaces( self::$oldNamespaces ); } public function testExpandAttributes() { @@ -88,6 +112,9 @@ class XmlTest extends MediaWikiTestCase { $this->assertEquals( '</element>', Xml::closeElement( 'element' ), 'closeElement() shortcut' ); } + /** + * @group Broken + */ public function testDateMenu( ) { $curYear = intval(gmdate('Y')); $prevYear = $curYear - 1; @@ -98,11 +125,10 @@ class XmlTest extends MediaWikiTestCase { $nextMonth = $curMonth + 1; if( $nextMonth == 13 ) { $nextMonth = 1; } - $this->assertEquals( '<label for="year">From year (and earlier):</label> <input name="year" size="4" value="2011" id="year" maxlength="4" /> <label for="month">From month (and earlier):</label> <select id="month" name="month" class="mw-month-selector"><option value="-1">all</option>' . "\n" . '<option value="1">January</option>' . "\n" . -'<option value="2" selected="selected">February</option>' . "\n" . +'<option value="2" selected="">February</option>' . "\n" . '<option value="3">March</option>' . "\n" . '<option value="4">April</option>' . "\n" . '<option value="5">May</option>' . "\n" . @@ -139,7 +165,6 @@ class XmlTest extends MediaWikiTestCase { "Date menu year is the current one when not specified" ); - $this->markTestIncomplete( "Broken" ); // @todo FIXME: next month can be in the next year // test failing because it is now december $this->assertEquals( @@ -163,11 +188,57 @@ class XmlTest extends MediaWikiTestCase { '<option value="10">October</option>' . "\n" . '<option value="11">November</option>' . "\n" . '<option value="12">December</option></select>', - Xml::dateMenu( '', ''), + Xml::dateMenu( '', '' ), "Date menu with neither year or month" ); } + function testNamespaceSelector() { + $this->assertEquals( + '<select class="namespaceselector" id="namespace" name="namespace">' . "\n" . +'<option value="0">(Main)</option>' . "\n" . +'<option value="1">Talk</option>' . "\n" . +'<option value="2">User</option>' . "\n" . +'<option value="3">User talk</option>' . "\n" . +'<option value="4">MyWiki</option>' . "\n" . +'<option value="5">MyWiki Talk</option>' . "\n" . +'<option value="6">File</option>' . "\n" . +'<option value="7">File talk</option>' . "\n" . +'<option value="8">MediaWiki</option>' . "\n" . +'<option value="9">MediaWiki talk</option>' . "\n" . +'<option value="10">Template</option>' . "\n" . +'<option value="11">Template talk</option>' . "\n" . +'<option value="100">Custom</option>' . "\n" . +'<option value="101">Custom talk</option>' . "\n" . +'</select>', + Xml::namespaceSelector(), + 'Basic namespace selector without custom options' + ); + $this->assertEquals( + '<label for="namespace">Select a namespace:</label>' . +' <select class="namespaceselector" id="namespace" name="myname">' . "\n" . +'<option value="all">all</option>' . "\n" . +'<option value="0">(Main)</option>' . "\n" . +'<option value="1">Talk</option>' . "\n" . +'<option value="2" selected="">User</option>' . "\n" . +'<option value="3">User talk</option>' . "\n" . +'<option value="4">MyWiki</option>' . "\n" . +'<option value="5">MyWiki Talk</option>' . "\n" . +'<option value="6">File</option>' . "\n" . +'<option value="7">File talk</option>' . "\n" . +'<option value="8">MediaWiki</option>' . "\n" . +'<option value="9">MediaWiki talk</option>' . "\n" . +'<option value="10">Template</option>' . "\n" . +'<option value="11">Template talk</option>' . "\n" . +'<option value="100">Custom</option>' . "\n" . +'<option value="101">Custom talk</option>' . "\n" . +'</select>', + Xml::namespaceSelector( $selected = '2', $all = 'all', $element_name = 'myname', $label = 'Select a namespace:' ), + 'Basic namespace selector with custom values' + ); + } + + # # textarea # @@ -255,12 +326,12 @@ class XmlTest extends MediaWikiTestCase { function testEncodeJsVarArray() { $this->assertEquals( - '["a", 1]', + '["a",1]', Xml::encodeJsVar( array( 'a', 1 ) ), 'encodeJsVar() with array' ); $this->assertEquals( - '{"a": "a", "b": 1}', + '{"a":"a","b":1}', Xml::encodeJsVar( array( 'a' => 'a', 'b' => 1 ) ), 'encodeJsVar() with associative array' ); @@ -268,7 +339,7 @@ class XmlTest extends MediaWikiTestCase { function testEncodeJsVarObject() { $this->assertEquals( - '{"a": "a", "b": 1}', + '{"a":"a","b":1}', Xml::encodeJsVar( (object)array( 'a' => 'a', 'b' => 1 ) ), 'encodeJsVar() with object' ); diff --git a/tests/phpunit/includes/api/ApiBlockTest.php b/tests/phpunit/includes/api/ApiBlockTest.php index 227555eb..b95d8214 100644 --- a/tests/phpunit/includes/api/ApiBlockTest.php +++ b/tests/phpunit/includes/api/ApiBlockTest.php @@ -15,24 +15,34 @@ class ApiBlockTest extends ApiTestCase { } function addDBData() { - $user = User::newFromName( 'UTBlockee' ); + $user = User::newFromName( 'UTApiBlockee' ); if ( $user->getId() == 0 ) { $user->addToDatabase(); - $user->setPassword( 'UTBlockeePassword' ); + $user->setPassword( 'UTApiBlockeePassword' ); $user->saveSettings(); } } + /** + * This test has probably always been broken and use an invalid token + * Bug tracking brokenness is https://bugzilla.wikimedia.org/35646 + * + * Root cause is https://gerrit.wikimedia.org/r/3434 + * Which made the Block/Unblock API to actually verify the token + * previously always considered valid (bug 34212). + * + * @group Broken + */ function testMakeNormalBlock() { $data = $this->getTokens(); - $user = User::newFromName( 'UTBlockee' ); + $user = User::newFromName( 'UTApiBlockee' ); if ( !$user->getId() ) { - $this->markTestIncomplete( "The user UTBlockee does not exist" ); + $this->markTestIncomplete( "The user UTApiBlockee does not exist" ); } if( !isset( $data[0]['query']['pages'] ) ) { @@ -45,15 +55,15 @@ class ApiBlockTest extends ApiTestCase { $data = $this->doApiRequest( array( 'action' => 'block', - 'user' => 'UTBlockee', - 'reason' => BlockTest::REASON, - 'token' => $pageinfo['blocktoken'] ), $data ); + 'user' => 'UTApiBlockee', + 'reason' => 'Some reason', + 'token' => $pageinfo['blocktoken'] ), $data, false, self::$users['sysop']->user ); - $block = Block::newFromTarget('UTBlockee'); + $block = Block::newFromTarget('UTApiBlockee'); $this->assertTrue( !is_null( $block ), 'Block is valid' ); - $this->assertEquals( 'UTBlockee', (string)$block->getTarget() ); + $this->assertEquals( 'UTApiBlockee', (string)$block->getTarget() ); $this->assertEquals( 'Some reason', $block->mReason ); $this->assertEquals( 'infinity', $block->mExpiry ); diff --git a/tests/phpunit/includes/api/ApiPurgeTest.php b/tests/phpunit/includes/api/ApiPurgeTest.php index db1563e9..70c20746 100644 --- a/tests/phpunit/includes/api/ApiPurgeTest.php +++ b/tests/phpunit/includes/api/ApiPurgeTest.php @@ -9,33 +9,31 @@ class ApiPurgeTest extends ApiTestCase { parent::setUp(); $this->doLogin(); } - + + /** + * @group Broken + */ function testPurgeMainPage() { - if ( !Title::newFromText( 'UTPage' )->exists() ) { $this->markTestIncomplete( "The article [[UTPage]] does not exist" ); } - + $somePage = mt_rand(); $data = $this->doApiRequest( array( 'action' => 'purge', 'titles' => 'UTPage|' . $somePage . '|%5D' ) ); - - $this->assertArrayHasKey( 'purge', $data[0] ); - - $this->assertArrayHasKey( 0, $data[0]['purge'] ); - $this->assertArrayHasKey( 'purged', $data[0]['purge'][0] ); - $this->assertEquals( 'UTPage', $data[0]['purge'][0]['title'] ); - - $this->assertArrayHasKey( 1, $data[0]['purge'] ); - $this->assertArrayHasKey( 'missing', $data[0]['purge'][1] ); - $this->assertEquals( $somePage, $data[0]['purge'][1]['title'] ); - - $this->assertArrayHasKey( 2, $data[0]['purge'] ); - $this->assertArrayHasKey( 'invalid', $data[0]['purge'][2] ); - $this->assertEquals( '%5D', $data[0]['purge'][2]['title'] ); - + + $this->assertArrayHasKey( 'purge', $data[0], + "Must receive a 'purge' result from API" ); + + $this->assertEquals( 3, count( $data[0]['purge'] ), + "Purge request for three articles should give back three results received: " . var_export( $data[0]['purge'], true ) ); + + $pages = array( 'UTPage' => 'purged', $somePage => 'missing', '%5D' => 'invalid' ); + foreach( $data[0]['purge'] as $v ) { + $this->assertArrayHasKey( $pages[$v['title']], $v ); + } } } diff --git a/tests/phpunit/includes/api/ApiQueryTest.php b/tests/phpunit/includes/api/ApiQueryTest.php index 114eadf3..ae05a30a 100644 --- a/tests/phpunit/includes/api/ApiQueryTest.php +++ b/tests/phpunit/includes/api/ApiQueryTest.php @@ -22,10 +22,13 @@ class ApiQueryTest extends ApiTestCase { $this->assertArrayHasKey( 'query', $data[0] ); $this->assertArrayHasKey( 'normalized', $data[0]['query'] ); + // Forge a normalized title + $to = Title::newFromText( $wgMetaNamespace.':ArticleA' ); + $this->assertEquals( array( 'from' => 'Project:articleA', - 'to' => $wgMetaNamespace . ':ArticleA' + 'to' => $to->getPrefixedText(), ), $data[0]['query']['normalized'][0] ); @@ -50,7 +53,6 @@ class ApiQueryTest extends ApiTestCase { 'action' => 'query', 'titles' => $title . '|Talk:' ) ); - $this->assertArrayHasKey( 'query', $data[0] ); $this->assertArrayHasKey( 'pages', $data[0]['query'] ); $this->assertEquals( 2, count( $data[0]['query']['pages'] ) ); @@ -60,8 +62,6 @@ class ApiQueryTest extends ApiTestCase { $this->assertArrayHasKey( 'missing', $data[0]['query']['pages'][-2] ); $this->assertArrayHasKey( 'invalid', $data[0]['query']['pages'][-1] ); - - } } diff --git a/tests/phpunit/includes/api/ApiTest.php b/tests/phpunit/includes/api/ApiTest.php index a587e6b1..1d9c3238 100644 --- a/tests/phpunit/includes/api/ApiTest.php +++ b/tests/phpunit/includes/api/ApiTest.php @@ -96,7 +96,7 @@ class ApiTest extends ApiTestCase { "lgtoken" => $token, "lgname" => $user->username, "lgpassword" => "badnowayinhell", - ) + ), $ret[2] ); $result = $ret[0]; @@ -137,7 +137,7 @@ class ApiTest extends ApiTestCase { "lgtoken" => $token, "lgname" => $user->username, "lgpassword" => $user->password, - ) + ), $ret[2] ); $result = $ret[0]; @@ -148,6 +148,9 @@ class ApiTest extends ApiTestCase { $this->assertEquals( "Success", $a ); } + /** + * @group Broken + */ function testApiGotCookie() { $this->markTestIncomplete( "The server can't do external HTTP requests, and the internal one won't give cookies" ); @@ -192,24 +195,23 @@ class ApiTest extends ApiTestCase { } /** - * @depends testApiGotCookie + * @todo Finish filling me out...what are we trying to test here? */ - function testApiListPages( CookieJar $cj ) { - $this->markTestIncomplete( "Not done with this yet" ); + function testApiListPages() { global $wgServer; - - if ( $wgServer == "http://localhost" ) { + if ( !isset( $wgServer ) ) { $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' ); } - $req = MWHttpRequest::factory( self::$apiUrl . "?action=query&format=xml&prop=revisions&" . - "titles=Main%20Page&rvprop=timestamp|user|comment|content" ); - $req->setCookieJar( $cj ); - $req->execute(); - libxml_use_internal_errors( true ); - $sxe = simplexml_load_string( $req->getContent() ); - $this->assertNotInternalType( "bool", $sxe ); - $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) ); - $a = $sxe->query[0]->pages[0]->page[0]->attributes(); + + $ret = $this->doApiRequest( array( + 'action' => 'query', + 'prop' => 'revisions', + 'titles' => 'Main Page', + 'rvprop' => 'timestamp|user|comment|content', + ) ); + + $result = $ret[0]['query']['pages']; + $this->markTestIncomplete( "Somebody needs to finish loving me" ); } function testRunLogin() { @@ -228,7 +230,7 @@ class ApiTest extends ApiTestCase { 'action' => 'login', "lgtoken" => $token, "lgname" => $sysopUser->username, - "lgpassword" => $sysopUser->password ), $data ); + "lgpassword" => $sysopUser->password ), $data[2] ); $this->assertArrayHasKey( "login", $data[0] ); $this->assertArrayHasKey( "result", $data[0]['login'] ); diff --git a/tests/phpunit/includes/api/ApiTestCase.php b/tests/phpunit/includes/api/ApiTestCase.php index 2917c880..8801391f 100644 --- a/tests/phpunit/includes/api/ApiTestCase.php +++ b/tests/phpunit/includes/api/ApiTestCase.php @@ -7,6 +7,11 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { public static $users; protected static $apiUrl; + /** + * @var ApiTestContext + */ + protected $apiContext; + function setUp() { global $wgContLang, $wgAuth, $wgMemc, $wgRequest, $wgUser, $wgServer; @@ -21,31 +26,37 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { 'sysop' => new ApiTestUser( 'Apitestsysop', 'Api Test Sysop', - 'api_test_sysop@sample.com', + 'api_test_sysop@example.com', array( 'sysop' ) ), 'uploader' => new ApiTestUser( 'Apitestuser', 'Api Test User', - 'api_test_user@sample.com', + 'api_test_user@example.com', array() ) ); $wgUser = self::$users['sysop']->user; + $this->apiContext = new ApiTestContext(); + } - protected function doApiRequest( $params, $session = null, $appendModule = false ) { + protected function doApiRequest( $params, $session = null, $appendModule = false, $user = null ) { if ( is_null( $session ) ) { $session = array(); } - $request = new FauxRequest( $params, true, $session ); - $module = new ApiMain( $request, true ); + $context = $this->apiContext->newTestContext( $params, $session, $user ); + $module = new ApiMain( $context, true ); $module->execute(); - $results = array( $module->getResultData(), $request, $request->getSessionArray() ); + $results = array( + $module->getResultData(), + $context->getRequest(), + $context->getRequest()->getSessionArray() + ); if( $appendModule ) { $results[] = $module; } @@ -59,14 +70,15 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { * request, without actually requesting a "real" edit token * @param $params: key-value API params * @param $session: session array + * @param $user String|null A User object for the context */ - protected function doApiRequestWithToken( $params, $session ) { + protected function doApiRequestWithToken( $params, $session, $user = null ) { if ( $session['wsToken'] ) { // add edit token to fake session $session['wsEditToken'] = $session['wsToken']; // add token to request parameters $params['token'] = md5( $session['wsToken'] ) . User::EDIT_TOKEN_SUFFIX; - return $this->doApiRequest( $params, $session ); + return $this->doApiRequest( $params, $session, false, $user ); } else { throw new Exception( "request data not in right format" ); } @@ -91,12 +103,11 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { } protected function getTokenList( $user ) { - $GLOBALS['wgUser'] = $user->user; $data = $this->doApiRequest( array( 'action' => 'query', 'titles' => 'Main Page', 'intoken' => 'edit|delete|protect|move|block|unblock', - 'prop' => 'info' ) ); + 'prop' => 'info' ), false, $user->user ); return $data; } } @@ -137,3 +148,23 @@ class MockApi extends ApiBase { ); } } + +class ApiTestContext extends RequestContext { + + /** + * Returns a DerivativeContext with the request variables in place + * + * @param $params Array key-value API params + * @param $session Array session data + * @param $user User or null + * @return DerivativeContext + */ + public function newTestContext( $params, $session, $user = null ) { + $context = new DerivativeContext( $this ); + $context->setRequest( new FauxRequest( $params, true, $session ) ); + if ( $user !== null ) { + $context->setUser( $user ); + } + return $context; + } +} diff --git a/tests/phpunit/includes/api/ApiTestCaseUpload.php b/tests/phpunit/includes/api/ApiTestCaseUpload.php index e51e7214..39c79547 100644 --- a/tests/phpunit/includes/api/ApiTestCaseUpload.php +++ b/tests/phpunit/includes/api/ApiTestCaseUpload.php @@ -19,6 +19,10 @@ abstract class ApiTestCaseUpload extends ApiTestCase { $this->clearFakeUploads(); } + public function tearDown() { + $this->clearTempUpload(); + } + /** * Helper function -- remove files and associated articles by Title * @param $title Title: title to be removed @@ -33,8 +37,8 @@ abstract class ApiTestCaseUpload extends ApiTestCase { if ( !$status->isGood() ) { return false; } - $article = new Article( $title ); - $article->doDeleteArticle( "removing for test" ); + $page = WikiPage::factory( $title ); + $page->doDeleteArticle( "removing for test" ); // see if it now doesn't exist; reload $title = Title::newFromText( $title->getText(), NS_FILE ); @@ -56,7 +60,7 @@ abstract class ApiTestCaseUpload extends ApiTestCase { * @param $filePath String: path to file on the filesystem */ public function deleteFileByContent( $filePath ) { - $hash = File::sha1Base36( $filePath ); + $hash = FSFile::getSha1Base36FromPath( $filePath ); $dupes = RepoGroup::singleton()->findBySha1( $hash ); $success = true; foreach ( $dupes as $dupe ) { @@ -100,6 +104,36 @@ abstract class ApiTestCaseUpload extends ApiTestCase { return true; } + function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ){ + $tmpName = tempnam( wfTempDir(), "" ); + // copy the chunk data to temp location: + if ( !file_put_contents( $tmpName, $chunkData ) ) { + throw new Exception( "couldn't copy chunk data to $tmpName" ); + } + + clearstatcache(); + $size = filesize( $tmpName ); + if ( $size === false ) { + throw new Exception( "couldn't stat $tmpName" ); + } + + $_FILES[ $fieldName ] = array( + 'name' => $fileName, + 'type' => $type, + 'tmp_name' => $tmpName, + 'size' => $size, + 'error' => null + ); + } + + function clearTempUpload() { + if( isset( $_FILES['file']['tmp_name'] ) ) { + $tmp = $_FILES['file']['tmp_name']; + if( file_exists( $tmp ) ) { + unlink( $tmp ); + } + } + } /** * Remove traces of previous fake uploads diff --git a/tests/phpunit/includes/api/ApiTestUser.php b/tests/phpunit/includes/api/ApiTestUser.php index df60682f..8d5f61a7 100644 --- a/tests/phpunit/includes/api/ApiTestUser.php +++ b/tests/phpunit/includes/api/ApiTestUser.php @@ -8,7 +8,7 @@ class ApiTestUser { public $groups; public $user; - function __construct( $username, $realname = 'Real Name', $email = 'sample@sample.com', $groups = array() ) { + function __construct( $username, $realname = 'Real Name', $email = 'sample@example.com', $groups = array() ) { $this->username = $username; $this->realname = $realname; $this->email = $email; diff --git a/tests/phpunit/includes/api/ApiUploadTest.php b/tests/phpunit/includes/api/ApiUploadTest.php index 5c929784..7a700326 100644 --- a/tests/phpunit/includes/api/ApiUploadTest.php +++ b/tests/phpunit/includes/api/ApiUploadTest.php @@ -19,6 +19,9 @@ require_once( 'ApiTestCaseUpload.php' ); /** * @group Database + * @group Broken + * Broken test, reports false errors from time to time. + * See https://bugzilla.wikimedia.org/26169 * * This is pretty sucky... needs to be prettified. */ @@ -54,6 +57,7 @@ class ApiUploadTest extends ApiTestCaseUpload { $this->assertEquals( "Success", $result['login']['result'] ); $this->assertArrayHasKey( 'lgtoken', $result['login'] ); + $this->assertNotEmpty( $session, 'API Login must return a session' ); return $session; } @@ -78,14 +82,11 @@ class ApiUploadTest extends ApiTestCaseUpload { * @depends testLogin */ public function testUploadMissingParams( $session ) { - global $wgUser; - $wgUser = self::$users['uploader']->user; - $exception = false; try { $this->doApiRequestWithToken( array( 'action' => 'upload', - ), $session ); + ), $session, self::$users['uploader']->user ); } catch ( UsageException $e ) { $exception = true; $this->assertEquals( "One of the parameters filekey, file, url, statuskey is required", @@ -99,20 +100,17 @@ class ApiUploadTest extends ApiTestCaseUpload { * @depends testLogin */ public function testUpload( $session ) { - global $wgUser; - $wgUser = self::$users['uploader']->user; - $extension = 'png'; $mimeType = 'image/png'; try { $randomImageGenerator = new RandomImageGenerator(); + $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } - $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); $filePath = $filePaths[0]; $fileSize = filesize( $filePath ); $fileName = basename( $filePath ); @@ -135,7 +133,8 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - list( $result, , ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, , ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); } catch ( UsageException $e ) { $exception = true; } @@ -155,9 +154,6 @@ class ApiUploadTest extends ApiTestCaseUpload { * @depends testLogin */ public function testUploadZeroLength( $session ) { - global $wgUser; - $wgUser = self::$users['uploader']->user; - $mimeType = 'image/png'; $filePath = tempnam( wfTempDir(), "" ); @@ -179,7 +175,7 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - $this->doApiRequestWithToken( $params, $session ); + $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user ); } catch ( UsageException $e ) { $this->assertContains( 'The file you submitted was empty', $e->getMessage() ); $exception = true; @@ -196,20 +192,17 @@ class ApiUploadTest extends ApiTestCaseUpload { * @depends testLogin */ public function testUploadSameFileName( $session ) { - global $wgUser; - $wgUser = self::$users['uploader']->user; - $extension = 'png'; $mimeType = 'image/png'; try { $randomImageGenerator = new RandomImageGenerator(); + $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } - $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() ); // we'll reuse this filename $fileName = basename( $filePaths[0] ); @@ -233,7 +226,8 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); } catch ( UsageException $e ) { $exception = true; } @@ -249,7 +243,8 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - list( $result, , ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, , ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); // FIXME: leaks a temporary file } catch ( UsageException $e ) { $exception = true; } @@ -270,19 +265,17 @@ class ApiUploadTest extends ApiTestCaseUpload { * @depends testLogin */ public function testUploadSameContent( $session ) { - global $wgUser; - $wgUser = self::$users['uploader']->user; - $extension = 'png'; $mimeType = 'image/png'; try { $randomImageGenerator = new RandomImageGenerator(); + $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } - $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); + $fileNames[0] = basename( $filePaths[0] ); $fileNames[1] = "SameContentAs" . $fileNames[0]; @@ -307,7 +300,8 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); } catch ( UsageException $e ) { $exception = true; } @@ -332,7 +326,8 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); // FIXME: leaks a temporary file } catch ( UsageException $e ) { $exception = true; } @@ -354,19 +349,19 @@ class ApiUploadTest extends ApiTestCaseUpload { */ public function testUploadStash( $session ) { global $wgUser; - $wgUser = self::$users['uploader']->user; + $wgUser = self::$users['uploader']->user; // @todo FIXME: still used somewhere $extension = 'png'; $mimeType = 'image/png'; try { $randomImageGenerator = new RandomImageGenerator(); + $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } - $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); $filePath = $filePaths[0]; $fileSize = filesize( $filePath ); $fileName = basename( $filePath ); @@ -389,7 +384,8 @@ class ApiUploadTest extends ApiTestCaseUpload { $exception = false; try { - list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); // FIXME: leaks a temporary file } catch ( UsageException $e ) { $exception = true; } @@ -417,17 +413,156 @@ class ApiUploadTest extends ApiTestCaseUpload { $this->clearFakeUploads(); $exception = false; try { - list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session ); + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); } catch ( UsageException $e ) { $exception = true; } $this->assertTrue( isset( $result['upload'] ) ); $this->assertEquals( 'Success', $result['upload']['result'] ); - $this->assertFalse( $exception ); + $this->assertFalse( $exception, "No UsageException exception." ); // clean up $this->deleteFileByFilename( $fileName ); unlink( $filePath ); } -} + + + /** + * @depends testLogin + */ + public function testUploadChunks( $session ) { + global $wgUser; + $wgUser = self::$users['uploader']->user; // @todo FIXME: still used somewhere + + $chunkSize = 1048576; + // Download a large image file + // ( using RandomImageGenerator for large files is not stable ) + $mimeType = 'image/jpeg'; + $url = 'http://upload.wikimedia.org/wikipedia/commons/e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG'; + $filePath = wfTempDir() . '/Oberaargletscher_from_Oberaar.jpg'; + try { + // Only download if the file is not avaliable in the temp location: + if( !is_file( $filePath ) ){ + copy($url, $filePath); + } + } + catch ( Exception $e ) { + $this->markTestIncomplete( $e->getMessage() ); + } + $fileSize = filesize( $filePath ); + $fileName = basename( $filePath ); + + $this->deleteFileByFileName( $fileName ); + $this->deleteFileByContent( $filePath ); + + // Base upload params: + $params = array( + 'action' => 'upload', + 'stash' => 1, + 'filename' => $fileName, + 'filesize' => $fileSize, + 'offset' => 0, + ); + + // Upload chunks + $chunkSessionKey = false; + $resultOffset = 0; + // Open the file: + $handle = @fopen ($filePath, "r"); + if( $handle === false ){ + $this->markTestIncomplete( "could not open file: $filePath" ); + } + while (!feof ($handle)) { + // Get the current chunk + $chunkData = @fread( $handle, $chunkSize ); + + // Upload the current chunk into the $_FILE object: + $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData ); + + // Check for chunkSessionKey + if( !$chunkSessionKey ){ + // Upload fist chunk ( and get the session key ) + try { + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); + } catch ( UsageException $e ) { + $this->markTestIncomplete( $e->getMessage() ); + } + // Make sure we got a valid chunk continue: + $this->assertTrue( isset( $result['upload'] ) ); + $this->assertTrue( isset( $result['upload']['filekey'] ) ); + // If we don't get a session key mark test incomplete. + if( ! isset( $result['upload']['filekey'] ) ){ + $this->markTestIncomplete( "no filekey provided" ); + } + $chunkSessionKey = $result['upload']['filekey']; + $this->assertEquals( 'Continue', $result['upload']['result'] ); + // First chunk should have chunkSize == offset + $this->assertEquals( $chunkSize, $result['upload']['offset'] ); + $resultOffset = $result['upload']['offset']; + continue; + } + // Filekey set to chunk session + $params['filekey'] = $chunkSessionKey; + // Update the offset ( always add chunkSize for subquent chunks should be in-sync with $result['upload']['offset'] ) + $params['offset'] += $chunkSize; + // Make sure param offset is insync with resultOffset: + $this->assertEquals( $resultOffset, $params['offset'] ); + // Upload current chunk + try { + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); + } catch ( UsageException $e ) { + $this->markTestIncomplete( $e->getMessage() ); + } + // Make sure we got a valid chunk continue: + $this->assertTrue( isset( $result['upload'] ) ); + $this->assertTrue( isset( $result['upload']['filekey'] ) ); + + // Check if we were on the last chunk: + if( $params['offset'] + $chunkSize >= $fileSize ){ + $this->assertEquals( 'Success', $result['upload']['result'] ); + break; + } else { + $this->assertEquals( 'Continue', $result['upload']['result'] ); + // update $resultOffset + $resultOffset = $result['upload']['offset']; + } + } + fclose ($handle); + + // Check that we got a valid file result: + wfDebug( __METHOD__ . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n"); + $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] ); + $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] ); + $this->assertTrue( isset( $result['upload']['filekey'] ) ); + $filekey = $result['upload']['filekey']; + + // Now we should try to release the file from stash + $params = array( + 'action' => 'upload', + 'filekey' => $filekey, + 'filename' => $fileName, + 'comment' => 'dummy comment', + 'text' => "This is the page text for $fileName, altered", + ); + $this->clearFakeUploads(); + $exception = false; + try { + list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session, + self::$users['uploader']->user ); + } catch ( UsageException $e ) { + $exception = true; + } + $this->assertTrue( isset( $result['upload'] ) ); + $this->assertEquals( 'Success', $result['upload']['result'] ); + $this->assertFalse( $exception ); + + // clean up + $this->deleteFileByFilename( $fileName ); + // don't remove downloaded temporary file for fast subquent tests. + //unlink( $filePath ); + } +} diff --git a/tests/phpunit/includes/api/ApiWatchTest.php b/tests/phpunit/includes/api/ApiWatchTest.php index 3c7ff304..b7803746 100644 --- a/tests/phpunit/includes/api/ApiWatchTest.php +++ b/tests/phpunit/includes/api/ApiWatchTest.php @@ -41,6 +41,7 @@ class ApiWatchTest extends ApiTestCase { /** * @depends testWatchEdit + * @group Broken */ function testWatchClear() { @@ -92,7 +93,9 @@ class ApiWatchTest extends ApiTestCase { $this->assertArrayHasKey( 'edit', $data[0]['protect']['protections'][0] ); } - + /** + * @group Broken + */ function testGetRollbackToken() { $data = $this->getTokens(); diff --git a/tests/phpunit/includes/api/RandomImageGenerator.php b/tests/phpunit/includes/api/RandomImageGenerator.php index ae349978..86c0a828 100644 --- a/tests/phpunit/includes/api/RandomImageGenerator.php +++ b/tests/phpunit/includes/api/RandomImageGenerator.php @@ -1,6 +1,6 @@ <?php -/* +/** * RandomImageGenerator -- does what it says on the tin. * Requires Imagick, the ImageMagick library for PHP, or the command line equivalent (usually 'convert'). * @@ -27,12 +27,11 @@ class RandomImageGenerator { private $dictionaryFile; - private $minWidth = 400; - private $maxWidth = 800; - private $minHeight = 400; - private $maxHeight = 800; - private $shapesToDraw = 5; - private $imageWriteMethod; + private $minWidth = 400 ; + private $maxWidth = 800 ; + private $minHeight = 400 ; + private $maxHeight = 800 ; + private $shapesToDraw = 5 ; /** * Orientations: 0th row, 0th column, EXIF orientation code, rotation 2x2 matrix that is opposite of orientation @@ -41,35 +40,35 @@ class RandomImageGenerator { * (we also would need a non-symmetric shape for the images to test those, like a letter F) */ private static $orientations = array( - array( - '0thRow' => 'top', - '0thCol' => 'left', - 'exifCode' => 1, - 'counterRotation' => array( array( 1, 0 ), array( 0, 1 ) ) + array( + '0thRow' => 'top', + '0thCol' => 'left', + 'exifCode' => 1, + 'counterRotation' => array( array( 1, 0 ), array( 0, 1 ) ) ), - array( + array( '0thRow' => 'bottom', - '0thCol' => 'right', - 'exifCode' => 3, - 'counterRotation' => array( array( -1, 0 ), array( 0, -1 ) ) + '0thCol' => 'right', + 'exifCode' => 3, + 'counterRotation' => array( array( -1, 0 ), array( 0, -1 ) ) ), - array( - '0thRow' => 'right', - '0thCol' => 'top', - 'exifCode' => 6, - 'counterRotation' => array( array( 0, 1 ), array( 1, 0 ) ) + array( + '0thRow' => 'right', + '0thCol' => 'top', + 'exifCode' => 6, + 'counterRotation' => array( array( 0, 1 ), array( 1, 0 ) ) ), - array( - '0thRow' => 'left', - '0thCol' => 'bottom', - 'exifCode' => 8, - 'counterRotation' => array( array( 0, -1 ), array( -1, 0 ) ) + array( + '0thRow' => 'left', + '0thCol' => 'bottom', + 'exifCode' => 8, + 'counterRotation' => array( array( 0, -1 ), array( -1, 0 ) ) ) ); public function __construct( $options = array() ) { - foreach ( array( 'dictionaryFile', 'minWidth', 'minHeight', 'maxHeight', 'shapesToDraw' ) as $property ) { + foreach ( array( 'dictionaryFile', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight', 'shapesToDraw' ) as $property ) { if ( isset( $options[$property] ) ) { $this->$property = $options[$property]; } @@ -77,10 +76,10 @@ class RandomImageGenerator { // find the dictionary file, to generate random names if ( !isset( $this->dictionaryFile ) ) { - foreach ( array( - '/usr/share/dict/words', - '/usr/dict/words', - dirname( __FILE__ ) . '/words.txt' ) + foreach ( array( + '/usr/share/dict/words', + '/usr/dict/words', + dirname( __FILE__ ) . '/words.txt' ) as $dictionaryFile ) { if ( is_file( $dictionaryFile ) and is_readable( $dictionaryFile ) ) { $this->dictionaryFile = $dictionaryFile; @@ -91,14 +90,6 @@ class RandomImageGenerator { if ( !isset( $this->dictionaryFile ) ) { throw new Exception( "RandomImageGenerator: dictionary file not found or not specified properly" ); } - - if ( !class_exists( 'Imagick' ) ) { - throw new Exception( 'No Imagick extension' ); - } - global $wgExiv2Command; - if ( !$wgExiv2Command || !is_executable( $wgExiv2Command ) ) { - throw new Exception( 'exiv2 not executable or $wgExiv2Command not set' ); - } } /** @@ -125,15 +116,16 @@ class RandomImageGenerator { */ function getImageWriteMethod( $format ) { global $wgUseImageMagick, $wgImageMagickConvertCommand; - if ( $format === 'svg' ) { + if ( $format === 'svg' ) { return 'writeSvg'; } else { // figure out how to write images - if ( class_exists( 'Imagick' ) ) { + global $wgExiv2Command; + if ( class_exists( 'Imagick' ) && $wgExiv2Command && is_executable( $wgExiv2Command ) ) { return 'writeImageWithApi'; } elseif ( $wgUseImageMagick && $wgImageMagickConvertCommand && is_executable( $wgImageMagickConvertCommand ) ) { return 'writeImageWithCommandLine'; - } + } } throw new Exception( "RandomImageGenerator: could not find a suitable method to write images in '$format' format" ); } @@ -219,7 +211,7 @@ class RandomImageGenerator { */ static function shapePointsToString( $shape ) { $points = array(); - foreach ( $shape as $point ) { + foreach ( $shape as $point ) { $points[] = $point['x'] . ',' . $point['y']; } return join( " ", $points ); @@ -232,16 +224,16 @@ class RandomImageGenerator { * @param $format: file format to write (which is obviously always svg here) * @param $filename: filename to write to */ - public function writeSvg( $spec, $format, $filename ) { + public function writeSvg( $spec, $format, $filename ) { $svg = new SimpleXmlElement( '<svg/>' ); $svg->addAttribute( 'xmlns', 'http://www.w3.org/2000/svg' ); - $svg->addAttribute( 'version', '1.1' ); - $svg->addAttribute( 'width', $spec['width'] ); - $svg->addAttribute( 'height', $spec['height'] ); + $svg->addAttribute( 'version', '1.1' ); + $svg->addAttribute( 'width', $spec['width'] ); + $svg->addAttribute( 'height', $spec['height'] ); $g = $svg->addChild( 'g' ); foreach ( $spec['draws'] as $drawSpec ) { $shape = $g->addChild( 'polygon' ); - $shape->addAttribute( 'fill', $drawSpec['fill'] ); + $shape->addAttribute( 'fill', $drawSpec['fill'] ); $shape->addAttribute( 'points', self::shapePointsToString( $drawSpec['shape'] ) ); }; if ( ! $fh = fopen( $filename, 'w' ) ) { @@ -260,20 +252,20 @@ class RandomImageGenerator { * @param $filename: filename to write to */ public function writeImageWithApi( $spec, $format, $filename ) { - // this is a hack because I can't get setImageOrientation() to work. See below. + // this is a hack because I can't get setImageOrientation() to work. See below. global $wgExiv2Command; $image = new Imagick(); /** - * If the format is 'jpg', will also add a random orientation -- the image will be drawn rotated with triangle points + * If the format is 'jpg', will also add a random orientation -- the image will be drawn rotated with triangle points * facing in some direction (0, 90, 180 or 270 degrees) and a countering rotation should turn the triangle points upward again */ $orientation = self::$orientations[0]; // default is normal orientation if ( $format == 'jpg' ) { $orientation = self::$orientations[ array_rand( self::$orientations ) ]; - $spec = self::rotateImageSpec( $spec, $orientation['counterRotation'] ); + $spec = self::rotateImageSpec( $spec, $orientation['counterRotation'] ); } - + $image->newImage( $spec['width'], $spec['height'], new ImagickPixel( $spec['fill'] ) ); foreach ( $spec['draws'] as $drawSpec ) { @@ -296,7 +288,7 @@ class RandomImageGenerator { $cmd = wfEscapeShellArg( $wgExiv2Command ) . " -M " . wfEscapeShellArg( "set Exif.Image.Orientation " . $orientation['exifCode'] ) - . " " + . " " . wfEscapeShellArg( $filename ); $retval = 0; @@ -304,15 +296,13 @@ class RandomImageGenerator { if ( $retval !== 0 ) { print "Error with $cmd: $retval, $err\n"; } - } - - + } } /** * Given an image specification, produce rotated version * This is used when simulating a rotated image capture with EXIF orientation - * @param $spec Object returned by getImageSpec + * @param $spec Object returned by getImageSpec * @param $matrix 2x2 transformation matrix * @return transformed Spec */ @@ -323,8 +313,8 @@ class RandomImageGenerator { $correctionY = 0; if ( $dims['x'] < 0 ) { $correctionX = abs( $dims['x'] ); - } - if ( $dims['y'] < 0 ) { + } + if ( $dims['y'] < 0 ) { $correctionY = abs( $dims['y'] ); } $tSpec['width'] = abs( $dims['x'] ); @@ -332,7 +322,7 @@ class RandomImageGenerator { $tSpec['fill'] = $spec['fill']; $tSpec['draws'] = array(); foreach( $spec['draws'] as $draw ) { - $tDraw = array( + $tDraw = array( 'fill' => $draw['fill'], 'shape' => array() ); @@ -349,13 +339,13 @@ class RandomImageGenerator { /** * Given a matrix and a pair of images, return new position - * @param $matrix: 2x2 rotation matrix + * @param $matrix: 2x2 rotation matrix * @param $x: x-coordinate number * @param $y: y-coordinate number - * @return Array transformed with properties x, y + * @return Array transformed with properties x, y */ private static function matrixMultiply2x2( $matrix, $x, $y ) { - return array( + return array( 'x' => $x * $matrix[0][0] + $y * $matrix[0][1], 'y' => $x * $matrix[1][0] + $y * $matrix[1][1] ); @@ -366,10 +356,10 @@ class RandomImageGenerator { * Based on an image specification, write such an image to disk, using the command line ImageMagick program ('convert'). * * Sample command line: - * $ convert -size 100x60 xc:rgb(90,87,45) \ - * -draw 'fill rgb(12,34,56) polygon 41,39 44,57 50,57 41,39' \ - * -draw 'fill rgb(99,123,231) circle 59,39 56,57' \ - * -draw 'fill rgb(240,12,32) circle 50,21 50,3' filename.png + * $ convert -size 100x60 xc:rgb(90,87,45) \ + * -draw 'fill rgb(12,34,56) polygon 41,39 44,57 50,57 41,39' \ + * -draw 'fill rgb(99,123,231) circle 59,39 56,57' \ + * -draw 'fill rgb(240,12,32) circle 50,21 50,3' filename.png * * @param $spec: spec describing background and shapes to draw * @param $format: file format to write (unused by this method but kept so it has the same signature as writeImageWithApi) diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php index 914ab27c..067c731a 100644 --- a/tests/phpunit/includes/db/DatabaseSqliteTest.php +++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php @@ -19,6 +19,7 @@ class MockDatabaseSqlite extends DatabaseSqliteStandalone { /** * @group sqlite + * @group Database */ class DatabaseSqliteTest extends MediaWikiTestCase { var $db; @@ -98,7 +99,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { $this->assertEquals( 'sqlite_master', $db->tableName( 'sqlite_master' ) ); $this->assertEquals( 'foobar', $db->tableName( 'bar' ) ); } - + public function testDuplicateTableStructure() { $db = new DatabaseSqliteStandalone( ':memory:' ); $db->query( 'CREATE TABLE foo(foo, barfoo)' ); @@ -119,7 +120,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { 'Create a temporary duplicate only' ); } - + public function testDuplicateTableStructureVirtual() { $db = new DatabaseSqliteStandalone( ':memory:' ); if ( $db->getFulltextSearchModule() != 'FTS3' ) { @@ -191,13 +192,14 @@ class DatabaseSqliteTest extends MediaWikiTestCase { '1.15', '1.16', '1.17', + '1.18', ); // Mismatches for these columns we can safely ignore $ignoredColumns = array( 'user_newtalk.user_last_timestamp', // r84185 ); - + $currentDB = new DatabaseSqliteStandalone( ':memory:' ); $currentDB->sourceFile( "$IP/maintenance/tables.sql" ); $currentTables = $this->getTables( $currentDB ); @@ -254,9 +256,10 @@ class DatabaseSqliteTest extends MediaWikiTestCase { $maint = new FakeMaintenance(); $maint->loadParamsAndArgs( null, array( 'quiet' => 1 ) ); } - + + global $IP; $db = new DatabaseSqliteStandalone( ':memory:' ); - $db->sourceFile( dirname( __FILE__ ) . "/sqlite/tables-$version.sql" ); + $db->sourceFile( "$IP/tests/phpunit/data/db/sqlite/tables-$version.sql" ); $updater = DatabaseUpdater::newForDB( $db, false, $maint ); $updater->doUpdates( array( 'core' ) ); return $db; @@ -266,6 +269,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { $list = array_flip( $db->listTables() ); $excluded = array( 'math', // moved out of core in 1.18 + 'trackbacks', // removed from core in 1.19 'searchindex', 'searchindex_content', 'searchindex_segments', diff --git a/tests/phpunit/includes/db/DatabaseTest.php b/tests/phpunit/includes/db/DatabaseTest.php index d480ac6e..672e6645 100644 --- a/tests/phpunit/includes/db/DatabaseTest.php +++ b/tests/phpunit/includes/db/DatabaseTest.php @@ -2,12 +2,20 @@ /** * @group Database + * @group DatabaseBase */ class DatabaseTest extends MediaWikiTestCase { - var $db; + var $db, $functionTest = false; function setUp() { - $this->db = wfGetDB( DB_SLAVE ); + $this->db = wfGetDB( DB_MASTER ); + } + + function tearDown() { + if ( $this->functionTest ) { + $this->dropFunctions(); + $this->functionTest = false; + } } function testAddQuotesNull() { @@ -90,6 +98,26 @@ class DatabaseTest extends MediaWikiTestCase { $sql ); } + /** + * @group Broken + */ + function testStoredFunctions() { + if ( !in_array( wfGetDB( DB_MASTER )->getType(), array( 'mysql', 'postgres' ) ) ) { + $this->markTestSkipped( 'MySQL or Postgres required' ); + } + global $IP; + $this->dropFunctions(); + $this->functionTest = true; + $this->assertTrue( $this->db->sourceFile( "$IP/tests/phpunit/data/db/{$this->db->getType()}/functions.sql" ) ); + $res = $this->db->query( 'SELECT mw_test_function() AS test', __METHOD__ ); + $this->assertEquals( 42, $res->fetchObject()->test ); + } + + private function dropFunctions() { + $this->db->query( 'DROP FUNCTION IF EXISTS mw_test_function' + . ( $this->db->getType() == 'postgres' ? '()' : '' ) + ); + } } diff --git a/tests/phpunit/includes/db/sqlite/tables-1.13.sql b/tests/phpunit/includes/db/sqlite/tables-1.13.sql deleted file mode 100644 index a0dcb553..00000000 --- a/tests/phpunit/includes/db/sqlite/tables-1.13.sql +++ /dev/null @@ -1,342 +0,0 @@ --- This is a copy of SQLite schema from MediaWiki 1.13 used for updater testing - -CREATE TABLE /*$wgDBprefix*/user ( - user_id INTEGER PRIMARY KEY AUTOINCREMENT, - user_name varchar(255) default '', - user_real_name varchar(255) default '', - user_password tinyblob , - user_newpassword tinyblob , - user_newpass_time BLOB, - user_email tinytext , - user_options blob , - user_touched BLOB default '', - user_token BLOB default '', - user_email_authenticated BLOB, - user_email_token BLOB, - user_email_token_expires BLOB, - user_registration BLOB, - user_editcount int) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/user_groups ( - ug_user INTEGER default '0', - ug_group varBLOB default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/user_newtalk ( - user_id INTEGER default '0', - user_ip varBLOB default '', - user_last_timestamp BLOB default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/page ( - page_id INTEGER PRIMARY KEY AUTOINCREMENT, - page_namespace INTEGER , - page_title varchar(255) , - page_restrictions tinyblob , - page_counter bigint default '0', - page_is_redirect tinyint default '0', - page_is_new tinyint default '0', - page_random real , - page_touched BLOB default '', - page_latest INTEGER , - page_len INTEGER ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/revision ( - rev_id INTEGER PRIMARY KEY AUTOINCREMENT, - rev_page INTEGER , - rev_text_id INTEGER , - rev_comment tinyblob , - rev_user INTEGER default '0', - rev_user_text varchar(255) default '', - rev_timestamp BLOB default '', - rev_minor_edit tinyint default '0', - rev_deleted tinyint default '0', - rev_len int, - rev_parent_id INTEGER default NULL) /*$wgDBTableOptions*/ ; - -CREATE TABLE /*$wgDBprefix*/text ( - old_id INTEGER PRIMARY KEY AUTOINCREMENT, - old_text mediumblob , - old_flags tinyblob ) /*$wgDBTableOptions*/ ; - -CREATE TABLE /*$wgDBprefix*/archive ( - ar_namespace INTEGER default '0', - ar_title varchar(255) default '', - ar_text mediumblob , - ar_comment tinyblob , - ar_user INTEGER default '0', - ar_user_text varchar(255) , - ar_timestamp BLOB default '', - ar_minor_edit tinyint default '0', - ar_flags tinyblob , - ar_rev_id int, - ar_text_id int, - ar_deleted tinyint default '0', - ar_len int, - ar_page_id int, - ar_parent_id INTEGER default NULL) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/pagelinks ( - pl_from INTEGER default '0', - pl_namespace INTEGER default '0', - pl_title varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/templatelinks ( - tl_from INTEGER default '0', - tl_namespace INTEGER default '0', - tl_title varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/imagelinks ( - il_from INTEGER default '0', - il_to varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/categorylinks ( - cl_from INTEGER default '0', - cl_to varchar(255) default '', - cl_sortkey varchar(70) default '', - cl_timestamp timestamp ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/category ( - cat_id INTEGER PRIMARY KEY AUTOINCREMENT, - cat_title varchar(255) , - cat_pages INTEGER signed default 0, - cat_subcats INTEGER signed default 0, - cat_files INTEGER signed default 0, - cat_hidden tinyint default 0) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/externallinks ( - el_from INTEGER default '0', - el_to blob , - el_index blob ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/langlinks ( - ll_from INTEGER default '0', - ll_lang varBLOB default '', - ll_title varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/site_stats ( - ss_row_id INTEGER , - ss_total_views bigint default '0', - ss_total_edits bigint default '0', - ss_good_articles bigint default '0', - ss_total_pages bigint default '-1', - ss_users bigint default '-1', - ss_admins INTEGER default '-1', - ss_images INTEGER default '0') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/hitcounter ( - hc_id INTEGER -) ; - -CREATE TABLE /*$wgDBprefix*/ipblocks ( - ipb_id INTEGER PRIMARY KEY AUTOINCREMENT, - ipb_address tinyblob , - ipb_user INTEGER default '0', - ipb_by INTEGER default '0', - ipb_by_text varchar(255) default '', - ipb_reason tinyblob , - ipb_timestamp BLOB default '', - ipb_auto bool default 0, - ipb_anon_only bool default 0, - ipb_create_account bool default 1, - ipb_enable_autoblock bool default '1', - ipb_expiry varBLOB default '', - ipb_range_start tinyblob , - ipb_range_end tinyblob , - ipb_deleted bool default 0, - ipb_block_email bool default 0) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/image ( - img_name varchar(255) default '', - img_size INTEGER default '0', - img_width INTEGER default '0', - img_height INTEGER default '0', - img_metadata mediumblob , - img_bits INTEGER default '0', - img_media_type TEXT default NULL, - img_major_mime TEXT default "unknown", - img_minor_mime varBLOB default "unknown", - img_description tinyblob , - img_user INTEGER default '0', - img_user_text varchar(255) , - img_timestamp varBLOB default '', - img_sha1 varBLOB default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/oldimage ( - oi_name varchar(255) default '', - oi_archive_name varchar(255) default '', - oi_size INTEGER default 0, - oi_width INTEGER default 0, - oi_height INTEGER default 0, - oi_bits INTEGER default 0, - oi_description tinyblob , - oi_user INTEGER default '0', - oi_user_text varchar(255) , - oi_timestamp BLOB default '', - oi_metadata mediumblob , - oi_media_type TEXT default NULL, - oi_major_mime TEXT default "unknown", - oi_minor_mime varBLOB default "unknown", - oi_deleted tinyint default '0', - oi_sha1 varBLOB default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/filearchive ( - fa_id INTEGER PRIMARY KEY AUTOINCREMENT, - fa_name varchar(255) default '', - fa_archive_name varchar(255) default '', - fa_storage_group varBLOB, - fa_storage_key varBLOB default '', - fa_deleted_user int, - fa_deleted_timestamp BLOB default '', - fa_deleted_reason text, - fa_size INTEGER default '0', - fa_width INTEGER default '0', - fa_height INTEGER default '0', - fa_metadata mediumblob, - fa_bits INTEGER default '0', - fa_media_type TEXT default NULL, - fa_major_mime TEXT default "unknown", - fa_minor_mime varBLOB default "unknown", - fa_description tinyblob, - fa_user INTEGER default '0', - fa_user_text varchar(255) , - fa_timestamp BLOB default '', - fa_deleted tinyint default '0') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/recentchanges ( - rc_id INTEGER PRIMARY KEY AUTOINCREMENT, - rc_timestamp varBLOB default '', - rc_cur_time varBLOB default '', - rc_user INTEGER default '0', - rc_user_text varchar(255) , - rc_namespace INTEGER default '0', - rc_title varchar(255) default '', - rc_comment varchar(255) default '', - rc_minor tinyint default '0', - rc_bot tinyint default '0', - rc_new tinyint default '0', - rc_cur_id INTEGER default '0', - rc_this_oldid INTEGER default '0', - rc_last_oldid INTEGER default '0', - rc_type tinyint default '0', - rc_moved_to_ns tinyint default '0', - rc_moved_to_title varchar(255) default '', - rc_patrolled tinyint default '0', - rc_ip varBLOB default '', - rc_old_len int, - rc_new_len int, - rc_deleted tinyint default '0', - rc_logid INTEGER default '0', - rc_log_type varBLOB NULL default NULL, - rc_log_action varBLOB NULL default NULL, - rc_params blob NULL) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/watchlist ( - wl_user INTEGER , - wl_namespace INTEGER default '0', - wl_title varchar(255) default '', - wl_notificationtimestamp varBLOB) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/math ( - math_inputhash varBLOB , - math_outputhash varBLOB , - math_html_conservativeness tinyint , - math_html text, - math_mathml text) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/searchindex ( - si_page INTEGER , - si_title varchar(255) default '', - si_text mediumtext ) ; - -CREATE TABLE /*$wgDBprefix*/interwiki ( - iw_prefix varchar(32) , - iw_url blob , - iw_local bool , - iw_trans tinyint default 0) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/querycache ( - qc_type varBLOB , - qc_value INTEGER default '0', - qc_namespace INTEGER default '0', - qc_title varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/objectcache ( - keyname varBLOB default '', - value mediumblob, - exptime datetime) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/transcache ( - tc_url varBLOB , - tc_contents text, - tc_time INTEGER ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/logging ( - log_id INTEGER PRIMARY KEY AUTOINCREMENT, - log_type varBLOB default '', - log_action varBLOB default '', - log_timestamp BLOB default '19700101000000', - log_user INTEGER default 0, - log_namespace INTEGER default 0, - log_title varchar(255) default '', - log_comment varchar(255) default '', - log_params blob , - log_deleted tinyint default '0') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/trackbacks ( - tb_id INTEGER PRIMARY KEY AUTOINCREMENT, - tb_page INTEGER REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE, - tb_title varchar(255) , - tb_url blob , - tb_ex text, - tb_name varchar(255)) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/job ( - job_id INTEGER PRIMARY KEY AUTOINCREMENT, - job_cmd varBLOB default '', - job_namespace INTEGER , - job_title varchar(255) , - job_params blob ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/querycache_info ( - qci_type varBLOB default '', - qci_timestamp BLOB default '19700101000000') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/redirect ( - rd_from INTEGER default '0', - rd_namespace INTEGER default '0', - rd_title varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/querycachetwo ( - qcc_type varBLOB , - qcc_value INTEGER default '0', - qcc_namespace INTEGER default '0', - qcc_title varchar(255) default '', - qcc_namespacetwo INTEGER default '0', - qcc_titletwo varchar(255) default '') /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/page_restrictions ( - pr_page INTEGER , - pr_type varBLOB , - pr_level varBLOB , - pr_cascade tinyint , - pr_user INTEGER NULL, - pr_expiry varBLOB NULL, - pr_id INTEGER PRIMARY KEY AUTOINCREMENT) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/protected_titles ( - pt_namespace INTEGER , - pt_title varchar(255) , - pt_user INTEGER , - pt_reason tinyblob, - pt_timestamp BLOB , - pt_expiry varBLOB default '', - pt_create_perm varBLOB ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/page_props ( - pp_page INTEGER , - pp_propname varBLOB , - pp_value blob ) /*$wgDBTableOptions*/; - -CREATE TABLE /*$wgDBprefix*/updatelog ( - ul_key varchar(255) ) /*$wgDBTableOptions*/; - - diff --git a/tests/phpunit/includes/db/sqlite/tables-1.15.sql b/tests/phpunit/includes/db/sqlite/tables-1.15.sql deleted file mode 100644 index 901bac52..00000000 --- a/tests/phpunit/includes/db/sqlite/tables-1.15.sql +++ /dev/null @@ -1,454 +0,0 @@ --- This is a copy of MediaWiki 1.15 schema shared by MySQL and SQLite. --- It is used for updater testing. Comments are stripped to decrease --- file size, as we don't need to maintain it. - -CREATE TABLE /*_*/user ( - user_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - user_name varchar(255) binary NOT NULL default '', - user_real_name varchar(255) binary NOT NULL default '', - user_password tinyblob NOT NULL, - user_newpassword tinyblob NOT NULL, - user_newpass_time binary(14), - user_email tinytext NOT NULL, - user_options blob NOT NULL, - user_touched binary(14) NOT NULL default '', - user_token binary(32) NOT NULL default '', - user_email_authenticated binary(14), - user_email_token binary(32), - user_email_token_expires binary(14), - user_registration binary(14), - user_editcount int -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/user_name ON /*_*/user (user_name); -CREATE INDEX /*i*/user_email_token ON /*_*/user (user_email_token); -CREATE TABLE /*_*/user_groups ( - ug_user int unsigned NOT NULL default 0, - ug_group varbinary(16) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group); -CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group); -CREATE TABLE /*_*/user_newtalk ( - user_id int NOT NULL default 0, - user_ip varbinary(40) NOT NULL default '', - user_last_timestamp binary(14) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/un_user_id ON /*_*/user_newtalk (user_id); -CREATE INDEX /*i*/un_user_ip ON /*_*/user_newtalk (user_ip); -CREATE TABLE /*_*/page ( - page_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - page_namespace int NOT NULL, - page_title varchar(255) binary NOT NULL, - page_restrictions tinyblob NOT NULL, - page_counter bigint unsigned NOT NULL default 0, - page_is_redirect tinyint unsigned NOT NULL default 0, - page_is_new tinyint unsigned NOT NULL default 0, - page_random real unsigned NOT NULL, - page_touched binary(14) NOT NULL default '', - page_latest int unsigned NOT NULL, - page_len int unsigned NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title); -CREATE INDEX /*i*/page_random ON /*_*/page (page_random); -CREATE INDEX /*i*/page_len ON /*_*/page (page_len); -CREATE TABLE /*_*/revision ( - rev_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - rev_page int unsigned NOT NULL, - rev_text_id int unsigned NOT NULL, - rev_comment tinyblob NOT NULL, - rev_user int unsigned NOT NULL default 0, - rev_user_text varchar(255) binary NOT NULL default '', - rev_timestamp binary(14) NOT NULL default '', - rev_minor_edit tinyint unsigned NOT NULL default 0, - rev_deleted tinyint unsigned NOT NULL default 0, - rev_len int unsigned, - rev_parent_id int unsigned default NULL -) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; -CREATE UNIQUE INDEX /*i*/rev_page_id ON /*_*/revision (rev_page, rev_id); -CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp); -CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp); -CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp); -CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp); -CREATE TABLE /*_*/text ( - old_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - old_text mediumblob NOT NULL, - old_flags tinyblob NOT NULL -) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=10240; -CREATE TABLE /*_*/archive ( - ar_namespace int NOT NULL default 0, - ar_title varchar(255) binary NOT NULL default '', - ar_text mediumblob NOT NULL, - ar_comment tinyblob NOT NULL, - ar_user int unsigned NOT NULL default 0, - ar_user_text varchar(255) binary NOT NULL, - ar_timestamp binary(14) NOT NULL default '', - ar_minor_edit tinyint NOT NULL default 0, - ar_flags tinyblob NOT NULL, - ar_rev_id int unsigned, - ar_text_id int unsigned, - ar_deleted tinyint unsigned NOT NULL default 0, - ar_len int unsigned, - ar_page_id int unsigned, - ar_parent_id int unsigned default NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp); -CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp); -CREATE TABLE /*_*/pagelinks ( - pl_from int unsigned NOT NULL default 0, - pl_namespace int NOT NULL default 0, - pl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title); -CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from); -CREATE TABLE /*_*/templatelinks ( - tl_from int unsigned NOT NULL default 0, - tl_namespace int NOT NULL default 0, - tl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title); -CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from); -CREATE TABLE /*_*/imagelinks ( - il_from int unsigned NOT NULL default 0, - il_to varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to); -CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from); -CREATE TABLE /*_*/categorylinks ( - cl_from int unsigned NOT NULL default 0, - cl_to varchar(255) binary NOT NULL default '', - cl_sortkey varchar(70) binary NOT NULL default '', - cl_timestamp timestamp NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to); -CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_sortkey,cl_from); -CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp); -CREATE TABLE /*_*/category ( - cat_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - cat_title varchar(255) binary NOT NULL, - cat_pages int signed NOT NULL default 0, - cat_subcats int signed NOT NULL default 0, - cat_files int signed NOT NULL default 0, - cat_hidden tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title); -CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages); -CREATE TABLE /*_*/externallinks ( - el_from int unsigned NOT NULL default 0, - el_to blob NOT NULL, - el_index blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40)); -CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from); -CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60)); -CREATE TABLE /*_*/langlinks ( - ll_from int unsigned NOT NULL default 0, - - ll_lang varbinary(20) NOT NULL default '', - ll_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ll_from ON /*_*/langlinks (ll_from, ll_lang); -CREATE INDEX /*i*/ll_lang ON /*_*/langlinks (ll_lang, ll_title); -CREATE TABLE /*_*/site_stats ( - ss_row_id int unsigned NOT NULL, - ss_total_views bigint unsigned default 0, - ss_total_edits bigint unsigned default 0, - ss_good_articles bigint unsigned default 0, - ss_total_pages bigint default '-1', - ss_users bigint default '-1', - ss_active_users bigint default '-1', - ss_admins int default '-1', - ss_images int default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id); -CREATE TABLE /*_*/hitcounter ( - hc_id int unsigned NOT NULL -) ENGINE=HEAP MAX_ROWS=25000; -CREATE TABLE /*_*/ipblocks ( - ipb_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - ipb_address tinyblob NOT NULL, - ipb_user int unsigned NOT NULL default 0, - ipb_by int unsigned NOT NULL default 0, - ipb_by_text varchar(255) binary NOT NULL default '', - ipb_reason tinyblob NOT NULL, - ipb_timestamp binary(14) NOT NULL default '', - ipb_auto bool NOT NULL default 0, - ipb_anon_only bool NOT NULL default 0, - ipb_create_account bool NOT NULL default 1, - ipb_enable_autoblock bool NOT NULL default '1', - ipb_expiry varbinary(14) NOT NULL default '', - ipb_range_start tinyblob NOT NULL, - ipb_range_end tinyblob NOT NULL, - ipb_deleted bool NOT NULL default 0, - ipb_block_email bool NOT NULL default 0, - ipb_allow_usertalk bool NOT NULL default 0 -) /*$wgDBTableOptions*/; - -CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only); -CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user); -CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8)); -CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp); -CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry); -CREATE TABLE /*_*/image ( - img_name varchar(255) binary NOT NULL default '' PRIMARY KEY, - img_size int unsigned NOT NULL default 0, - img_width int NOT NULL default 0, - img_height int NOT NULL default 0, - img_metadata mediumblob NOT NULL, - img_bits int NOT NULL default 0, - img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - img_minor_mime varbinary(32) NOT NULL default "unknown", - img_description tinyblob NOT NULL, - img_user int unsigned NOT NULL default 0, - img_user_text varchar(255) binary NOT NULL, - img_timestamp varbinary(14) NOT NULL default '', - img_sha1 varbinary(32) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp); -CREATE INDEX /*i*/img_size ON /*_*/image (img_size); -CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp); -CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1); -CREATE TABLE /*_*/oldimage ( - oi_name varchar(255) binary NOT NULL default '', - oi_archive_name varchar(255) binary NOT NULL default '', - oi_size int unsigned NOT NULL default 0, - oi_width int NOT NULL default 0, - oi_height int NOT NULL default 0, - oi_bits int NOT NULL default 0, - oi_description tinyblob NOT NULL, - oi_user int unsigned NOT NULL default 0, - oi_user_text varchar(255) binary NOT NULL, - oi_timestamp binary(14) NOT NULL default '', - oi_metadata mediumblob NOT NULL, - oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - oi_minor_mime varbinary(32) NOT NULL default "unknown", - oi_deleted tinyint unsigned NOT NULL default 0, - oi_sha1 varbinary(32) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp); -CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp); -CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14)); -CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1); -CREATE TABLE /*_*/filearchive ( - fa_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - fa_name varchar(255) binary NOT NULL default '', - fa_archive_name varchar(255) binary default '', - fa_storage_group varbinary(16), - fa_storage_key varbinary(64) default '', - fa_deleted_user int, - fa_deleted_timestamp binary(14) default '', - fa_deleted_reason text, - fa_size int unsigned default 0, - fa_width int default 0, - fa_height int default 0, - fa_metadata mediumblob, - fa_bits int default 0, - fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") default "unknown", - fa_minor_mime varbinary(32) default "unknown", - fa_description tinyblob, - fa_user int unsigned default 0, - fa_user_text varchar(255) binary, - fa_timestamp binary(14) default '', - fa_deleted tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp); -CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key); -CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp); -CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp); -CREATE TABLE /*_*/recentchanges ( - rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - rc_timestamp varbinary(14) NOT NULL default '', - rc_cur_time varbinary(14) NOT NULL default '', - rc_user int unsigned NOT NULL default 0, - rc_user_text varchar(255) binary NOT NULL, - rc_namespace int NOT NULL default 0, - rc_title varchar(255) binary NOT NULL default '', - rc_comment varchar(255) binary NOT NULL default '', - rc_minor tinyint unsigned NOT NULL default 0, - rc_bot tinyint unsigned NOT NULL default 0, - rc_new tinyint unsigned NOT NULL default 0, - rc_cur_id int unsigned NOT NULL default 0, - rc_this_oldid int unsigned NOT NULL default 0, - rc_last_oldid int unsigned NOT NULL default 0, - rc_type tinyint unsigned NOT NULL default 0, - rc_moved_to_ns tinyint unsigned NOT NULL default 0, - rc_moved_to_title varchar(255) binary NOT NULL default '', - rc_patrolled tinyint unsigned NOT NULL default 0, - rc_ip varbinary(40) NOT NULL default '', - rc_old_len int, - rc_new_len int, - rc_deleted tinyint unsigned NOT NULL default 0, - rc_logid int unsigned NOT NULL default 0, - rc_log_type varbinary(255) NULL default NULL, - rc_log_action varbinary(255) NULL default NULL, - rc_params blob NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp); -CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title); -CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id); -CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp); -CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip); -CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text); -CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp); -CREATE TABLE /*_*/watchlist ( - wl_user int unsigned NOT NULL, - wl_namespace int NOT NULL default 0, - wl_title varchar(255) binary NOT NULL default '', - wl_notificationtimestamp varbinary(14) -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/wl_user ON /*_*/watchlist (wl_user, wl_namespace, wl_title); -CREATE INDEX /*i*/namespace_title ON /*_*/watchlist (wl_namespace, wl_title); -CREATE TABLE /*_*/math ( - math_inputhash varbinary(16) NOT NULL, - math_outputhash varbinary(16) NOT NULL, - math_html_conservativeness tinyint NOT NULL, - math_html text, - math_mathml text -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/math_inputhash ON /*_*/math (math_inputhash); -CREATE TABLE /*_*/searchindex ( - si_page int unsigned NOT NULL, - si_title varchar(255) NOT NULL default '', - si_text mediumtext NOT NULL -) ENGINE=MyISAM; -CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page); -CREATE FULLTEXT INDEX /*i*/si_title ON /*_*/searchindex (si_title); -CREATE FULLTEXT INDEX /*i*/si_text ON /*_*/searchindex (si_text); -CREATE TABLE /*_*/interwiki ( - iw_prefix varchar(32) NOT NULL, - iw_url blob NOT NULL, - iw_local bool NOT NULL, - iw_trans tinyint NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/iw_prefix ON /*_*/interwiki (iw_prefix); -CREATE TABLE /*_*/querycache ( - qc_type varbinary(32) NOT NULL, - qc_value int unsigned NOT NULL default 0, - qc_namespace int NOT NULL default 0, - qc_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/qc_type ON /*_*/querycache (qc_type,qc_value); -CREATE TABLE /*_*/objectcache ( - keyname varbinary(255) NOT NULL default '' PRIMARY KEY, - value mediumblob, - exptime datetime -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime); -CREATE TABLE /*_*/transcache ( - tc_url varbinary(255) NOT NULL, - tc_contents text, - tc_time int NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url); -CREATE TABLE /*_*/logging ( - log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - log_type varbinary(10) NOT NULL default '', - log_action varbinary(10) NOT NULL default '', - log_timestamp binary(14) NOT NULL default '19700101000000', - log_user int unsigned NOT NULL default 0, - log_namespace int NOT NULL default 0, - log_title varchar(255) binary NOT NULL default '', - log_comment varchar(255) NOT NULL default '', - log_params blob NOT NULL, - log_deleted tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp); -CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp); -CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp); -CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp); -CREATE TABLE /*_*/trackbacks ( - tb_id int PRIMARY KEY AUTO_INCREMENT, - tb_page int REFERENCES /*_*/page(page_id) ON DELETE CASCADE, - tb_title varchar(255) NOT NULL, - tb_url blob NOT NULL, - tb_ex text, - tb_name varchar(255) -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/tb_page ON /*_*/trackbacks (tb_page); -CREATE TABLE /*_*/job ( - job_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - job_cmd varbinary(60) NOT NULL default '', - job_namespace int NOT NULL, - job_title varchar(255) binary NOT NULL, - job_params blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title); -CREATE TABLE /*_*/querycache_info ( - qci_type varbinary(32) NOT NULL default '', - qci_timestamp binary(14) NOT NULL default '19700101000000' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/qci_type ON /*_*/querycache_info (qci_type); -CREATE TABLE /*_*/redirect ( - rd_from int unsigned NOT NULL default 0 PRIMARY KEY, - rd_namespace int NOT NULL default 0, - rd_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/rd_ns_title ON /*_*/redirect (rd_namespace,rd_title,rd_from); -CREATE TABLE /*_*/querycachetwo ( - qcc_type varbinary(32) NOT NULL, - qcc_value int unsigned NOT NULL default 0, - qcc_namespace int NOT NULL default 0, - qcc_title varchar(255) binary NOT NULL default '', - qcc_namespacetwo int NOT NULL default 0, - qcc_titletwo varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/qcc_type ON /*_*/querycachetwo (qcc_type,qcc_value); -CREATE INDEX /*i*/qcc_title ON /*_*/querycachetwo (qcc_type,qcc_namespace,qcc_title); -CREATE INDEX /*i*/qcc_titletwo ON /*_*/querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); -CREATE TABLE /*_*/page_restrictions ( - pr_page int NOT NULL, - pr_type varbinary(60) NOT NULL, - pr_level varbinary(60) NOT NULL, - pr_cascade tinyint NOT NULL, - pr_user int NULL, - pr_expiry varbinary(14) NULL, - pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions (pr_page,pr_type); -CREATE INDEX /*i*/pr_typelevel ON /*_*/page_restrictions (pr_type,pr_level); -CREATE INDEX /*i*/pr_level ON /*_*/page_restrictions (pr_level); -CREATE INDEX /*i*/pr_cascade ON /*_*/page_restrictions (pr_cascade); -CREATE TABLE /*_*/protected_titles ( - pt_namespace int NOT NULL, - pt_title varchar(255) binary NOT NULL, - pt_user int unsigned NOT NULL, - pt_reason tinyblob, - pt_timestamp binary(14) NOT NULL, - pt_expiry varbinary(14) NOT NULL default '', - pt_create_perm varbinary(60) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pt_namespace_title ON /*_*/protected_titles (pt_namespace,pt_title); -CREATE INDEX /*i*/pt_timestamp ON /*_*/protected_titles (pt_timestamp); -CREATE TABLE /*_*/page_props ( - pp_page int NOT NULL, - pp_propname varbinary(60) NOT NULL, - pp_value blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname); -CREATE TABLE /*_*/updatelog ( - ul_key varchar(255) NOT NULL PRIMARY KEY -) /*$wgDBTableOptions*/; -CREATE TABLE /*_*/change_tag ( - ct_rc_id int NULL, - ct_log_id int NULL, - ct_rev_id int NULL, - ct_tag varchar(255) NOT NULL, - ct_params blob NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag); -CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag); -CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag); -CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id); -CREATE TABLE /*_*/tag_summary ( - ts_rc_id int NULL, - ts_log_id int NULL, - ts_rev_id int NULL, - ts_tags blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id); -CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id); -CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id); -CREATE TABLE /*_*/valid_tag ( - vt_tag varchar(255) NOT NULL PRIMARY KEY -) /*$wgDBTableOptions*/; diff --git a/tests/phpunit/includes/db/sqlite/tables-1.16.sql b/tests/phpunit/includes/db/sqlite/tables-1.16.sql deleted file mode 100644 index 6e56add2..00000000 --- a/tests/phpunit/includes/db/sqlite/tables-1.16.sql +++ /dev/null @@ -1,483 +0,0 @@ --- This is a copy of MediaWiki 1.16 schema shared by MySQL and SQLite. --- It is used for updater testing. Comments are stripped to decrease --- file size, as we don't need to maintain it. - -CREATE TABLE /*_*/user ( - user_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - user_name varchar(255) binary NOT NULL default '', - user_real_name varchar(255) binary NOT NULL default '', - user_password tinyblob NOT NULL, - user_newpassword tinyblob NOT NULL, - user_newpass_time binary(14), - user_email tinytext NOT NULL, - user_options blob NOT NULL, - user_touched binary(14) NOT NULL default '', - user_token binary(32) NOT NULL default '', - user_email_authenticated binary(14), - user_email_token binary(32), - user_email_token_expires binary(14), - user_registration binary(14), - user_editcount int -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/user_name ON /*_*/user (user_name); -CREATE INDEX /*i*/user_email_token ON /*_*/user (user_email_token); -CREATE TABLE /*_*/user_groups ( - ug_user int unsigned NOT NULL default 0, - ug_group varbinary(16) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group); -CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group); -CREATE TABLE /*_*/user_newtalk ( - user_id int NOT NULL default 0, - user_ip varbinary(40) NOT NULL default '', - user_last_timestamp binary(14) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/un_user_id ON /*_*/user_newtalk (user_id); -CREATE INDEX /*i*/un_user_ip ON /*_*/user_newtalk (user_ip); -CREATE TABLE /*_*/user_properties ( - up_user int NOT NULL, - up_property varbinary(32) NOT NULL, - up_value blob -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/user_properties_user_property ON /*_*/user_properties (up_user,up_property); -CREATE INDEX /*i*/user_properties_property ON /*_*/user_properties (up_property); -CREATE TABLE /*_*/page ( - page_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - page_namespace int NOT NULL, - page_title varchar(255) binary NOT NULL, - page_restrictions tinyblob NOT NULL, - page_counter bigint unsigned NOT NULL default 0, - page_is_redirect tinyint unsigned NOT NULL default 0, - page_is_new tinyint unsigned NOT NULL default 0, - page_random real unsigned NOT NULL, - page_touched binary(14) NOT NULL default '', - page_latest int unsigned NOT NULL, - page_len int unsigned NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title); -CREATE INDEX /*i*/page_random ON /*_*/page (page_random); -CREATE INDEX /*i*/page_len ON /*_*/page (page_len); -CREATE TABLE /*_*/revision ( - rev_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - rev_page int unsigned NOT NULL, - rev_text_id int unsigned NOT NULL, - rev_comment tinyblob NOT NULL, - rev_user int unsigned NOT NULL default 0, - rev_user_text varchar(255) binary NOT NULL default '', - rev_timestamp binary(14) NOT NULL default '', - rev_minor_edit tinyint unsigned NOT NULL default 0, - rev_deleted tinyint unsigned NOT NULL default 0, - rev_len int unsigned, - rev_parent_id int unsigned default NULL -) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; -CREATE UNIQUE INDEX /*i*/rev_page_id ON /*_*/revision (rev_page, rev_id); -CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp); -CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp); -CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp); -CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp); -CREATE TABLE /*_*/text ( - old_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - old_text mediumblob NOT NULL, - old_flags tinyblob NOT NULL -) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=10240; -CREATE TABLE /*_*/archive ( - ar_namespace int NOT NULL default 0, - ar_title varchar(255) binary NOT NULL default '', - ar_text mediumblob NOT NULL, - ar_comment tinyblob NOT NULL, - ar_user int unsigned NOT NULL default 0, - ar_user_text varchar(255) binary NOT NULL, - ar_timestamp binary(14) NOT NULL default '', - ar_minor_edit tinyint NOT NULL default 0, - ar_flags tinyblob NOT NULL, - ar_rev_id int unsigned, - ar_text_id int unsigned, - ar_deleted tinyint unsigned NOT NULL default 0, - ar_len int unsigned, - ar_page_id int unsigned, - ar_parent_id int unsigned default NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp); -CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp); -CREATE TABLE /*_*/pagelinks ( - pl_from int unsigned NOT NULL default 0, - pl_namespace int NOT NULL default 0, - pl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title); -CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from); -CREATE TABLE /*_*/templatelinks ( - tl_from int unsigned NOT NULL default 0, - tl_namespace int NOT NULL default 0, - tl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title); -CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from); -CREATE TABLE /*_*/imagelinks ( - il_from int unsigned NOT NULL default 0, - il_to varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to); -CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from); -CREATE TABLE /*_*/categorylinks ( - cl_from int unsigned NOT NULL default 0, - cl_to varchar(255) binary NOT NULL default '', - cl_sortkey varchar(70) binary NOT NULL default '', - cl_timestamp timestamp NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to); -CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_sortkey,cl_from); -CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp); -CREATE TABLE /*_*/category ( - cat_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - cat_title varchar(255) binary NOT NULL, - cat_pages int signed NOT NULL default 0, - cat_subcats int signed NOT NULL default 0, - cat_files int signed NOT NULL default 0, - cat_hidden tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title); -CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages); -CREATE TABLE /*_*/externallinks ( - el_from int unsigned NOT NULL default 0, - el_to blob NOT NULL, - el_index blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40)); -CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from); -CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60)); -CREATE TABLE /*_*/external_user ( - eu_local_id int unsigned NOT NULL PRIMARY KEY, - eu_external_id varchar(255) binary NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id); -CREATE TABLE /*_*/langlinks ( - ll_from int unsigned NOT NULL default 0, - ll_lang varbinary(20) NOT NULL default '', - ll_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ll_from ON /*_*/langlinks (ll_from, ll_lang); -CREATE INDEX /*i*/ll_lang ON /*_*/langlinks (ll_lang, ll_title); -CREATE TABLE /*_*/site_stats ( - ss_row_id int unsigned NOT NULL, - ss_total_views bigint unsigned default 0, - ss_total_edits bigint unsigned default 0, - ss_good_articles bigint unsigned default 0, - ss_total_pages bigint default '-1', - ss_users bigint default '-1', - ss_active_users bigint default '-1', - ss_admins int default '-1', - ss_images int default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id); -CREATE TABLE /*_*/hitcounter ( - hc_id int unsigned NOT NULL -) ENGINE=HEAP MAX_ROWS=25000; -CREATE TABLE /*_*/ipblocks ( - ipb_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - ipb_address tinyblob NOT NULL, - ipb_user int unsigned NOT NULL default 0, - ipb_by int unsigned NOT NULL default 0, - ipb_by_text varchar(255) binary NOT NULL default '', - ipb_reason tinyblob NOT NULL, - ipb_timestamp binary(14) NOT NULL default '', - ipb_auto bool NOT NULL default 0, - ipb_anon_only bool NOT NULL default 0, - ipb_create_account bool NOT NULL default 1, - ipb_enable_autoblock bool NOT NULL default '1', - ipb_expiry varbinary(14) NOT NULL default '', - ipb_range_start tinyblob NOT NULL, - ipb_range_end tinyblob NOT NULL, - ipb_deleted bool NOT NULL default 0, - ipb_block_email bool NOT NULL default 0, - ipb_allow_usertalk bool NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only); -CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user); -CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8)); -CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp); -CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry); -CREATE TABLE /*_*/image ( - img_name varchar(255) binary NOT NULL default '' PRIMARY KEY, - img_size int unsigned NOT NULL default 0, - img_width int NOT NULL default 0, - img_height int NOT NULL default 0, - img_metadata mediumblob NOT NULL, - img_bits int NOT NULL default 0, - img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - img_minor_mime varbinary(100) NOT NULL default "unknown", - img_description tinyblob NOT NULL, - img_user int unsigned NOT NULL default 0, - img_user_text varchar(255) binary NOT NULL, - img_timestamp varbinary(14) NOT NULL default '', - img_sha1 varbinary(32) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp); -CREATE INDEX /*i*/img_size ON /*_*/image (img_size); -CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp); -CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1); -CREATE TABLE /*_*/oldimage ( - oi_name varchar(255) binary NOT NULL default '', - oi_archive_name varchar(255) binary NOT NULL default '', - oi_size int unsigned NOT NULL default 0, - oi_width int NOT NULL default 0, - oi_height int NOT NULL default 0, - oi_bits int NOT NULL default 0, - oi_description tinyblob NOT NULL, - oi_user int unsigned NOT NULL default 0, - oi_user_text varchar(255) binary NOT NULL, - oi_timestamp binary(14) NOT NULL default '', - oi_metadata mediumblob NOT NULL, - oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - oi_minor_mime varbinary(100) NOT NULL default "unknown", - oi_deleted tinyint unsigned NOT NULL default 0, - oi_sha1 varbinary(32) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp); -CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp); -CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14)); -CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1); -CREATE TABLE /*_*/filearchive ( - fa_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - fa_name varchar(255) binary NOT NULL default '', - fa_archive_name varchar(255) binary default '', - fa_storage_group varbinary(16), - fa_storage_key varbinary(64) default '', - fa_deleted_user int, - fa_deleted_timestamp binary(14) default '', - fa_deleted_reason text, - fa_size int unsigned default 0, - fa_width int default 0, - fa_height int default 0, - fa_metadata mediumblob, - fa_bits int default 0, - fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") default "unknown", - fa_minor_mime varbinary(100) default "unknown", - fa_description tinyblob, - fa_user int unsigned default 0, - fa_user_text varchar(255) binary, - fa_timestamp binary(14) default '', - fa_deleted tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp); -CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key); -CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp); -CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp); -CREATE TABLE /*_*/recentchanges ( - rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - rc_timestamp varbinary(14) NOT NULL default '', - rc_cur_time varbinary(14) NOT NULL default '', - rc_user int unsigned NOT NULL default 0, - rc_user_text varchar(255) binary NOT NULL, - rc_namespace int NOT NULL default 0, - rc_title varchar(255) binary NOT NULL default '', - rc_comment varchar(255) binary NOT NULL default '', - rc_minor tinyint unsigned NOT NULL default 0, - rc_bot tinyint unsigned NOT NULL default 0, - rc_new tinyint unsigned NOT NULL default 0, - rc_cur_id int unsigned NOT NULL default 0, - rc_this_oldid int unsigned NOT NULL default 0, - rc_last_oldid int unsigned NOT NULL default 0, - rc_type tinyint unsigned NOT NULL default 0, - rc_moved_to_ns tinyint unsigned NOT NULL default 0, - rc_moved_to_title varchar(255) binary NOT NULL default '', - rc_patrolled tinyint unsigned NOT NULL default 0, - rc_ip varbinary(40) NOT NULL default '', - rc_old_len int, - rc_new_len int, - rc_deleted tinyint unsigned NOT NULL default 0, - rc_logid int unsigned NOT NULL default 0, - rc_log_type varbinary(255) NULL default NULL, - rc_log_action varbinary(255) NULL default NULL, - rc_params blob NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp); -CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title); -CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id); -CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp); -CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip); -CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text); -CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp); -CREATE TABLE /*_*/watchlist ( - wl_user int unsigned NOT NULL, - wl_namespace int NOT NULL default 0, - wl_title varchar(255) binary NOT NULL default '', - wl_notificationtimestamp varbinary(14) -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/wl_user ON /*_*/watchlist (wl_user, wl_namespace, wl_title); -CREATE INDEX /*i*/namespace_title ON /*_*/watchlist (wl_namespace, wl_title); -CREATE TABLE /*_*/math ( - math_inputhash varbinary(16) NOT NULL, - math_outputhash varbinary(16) NOT NULL, - math_html_conservativeness tinyint NOT NULL, - math_html text, - math_mathml text -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/math_inputhash ON /*_*/math (math_inputhash); -CREATE TABLE /*_*/searchindex ( - si_page int unsigned NOT NULL, - si_title varchar(255) NOT NULL default '', - si_text mediumtext NOT NULL -) ENGINE=MyISAM; -CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page); -CREATE FULLTEXT INDEX /*i*/si_title ON /*_*/searchindex (si_title); -CREATE FULLTEXT INDEX /*i*/si_text ON /*_*/searchindex (si_text); -CREATE TABLE /*_*/interwiki ( - iw_prefix varchar(32) NOT NULL, - iw_url blob NOT NULL, - iw_local bool NOT NULL, - iw_trans tinyint NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/iw_prefix ON /*_*/interwiki (iw_prefix); -CREATE TABLE /*_*/querycache ( - qc_type varbinary(32) NOT NULL, - qc_value int unsigned NOT NULL default 0, - qc_namespace int NOT NULL default 0, - qc_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/qc_type ON /*_*/querycache (qc_type,qc_value); -CREATE TABLE /*_*/objectcache ( - keyname varbinary(255) NOT NULL default '' PRIMARY KEY, - value mediumblob, - exptime datetime -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime); -CREATE TABLE /*_*/transcache ( - tc_url varbinary(255) NOT NULL, - tc_contents text, - tc_time binary(14) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url); -CREATE TABLE /*_*/logging ( - log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - log_type varbinary(32) NOT NULL default '', - log_action varbinary(32) NOT NULL default '', - log_timestamp binary(14) NOT NULL default '19700101000000', - log_user int unsigned NOT NULL default 0, - log_user_text varchar(255) binary NOT NULL default '', - log_namespace int NOT NULL default 0, - log_title varchar(255) binary NOT NULL default '', - log_page int unsigned NULL, - log_comment varchar(255) NOT NULL default '', - log_params blob NOT NULL, - log_deleted tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp); -CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp); -CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp); -CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp); -CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp); -CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp); -CREATE TABLE /*_*/log_search ( - ls_field varbinary(32) NOT NULL, - ls_value varchar(255) NOT NULL, - ls_log_id int unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ls_field_val ON /*_*/log_search (ls_field,ls_value,ls_log_id); -CREATE INDEX /*i*/ls_log_id ON /*_*/log_search (ls_log_id); -CREATE TABLE /*_*/trackbacks ( - tb_id int PRIMARY KEY AUTO_INCREMENT, - tb_page int REFERENCES /*_*/page(page_id) ON DELETE CASCADE, - tb_title varchar(255) NOT NULL, - tb_url blob NOT NULL, - tb_ex text, - tb_name varchar(255) -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/tb_page ON /*_*/trackbacks (tb_page); -CREATE TABLE /*_*/job ( - job_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - job_cmd varbinary(60) NOT NULL default '', - job_namespace int NOT NULL, - job_title varchar(255) binary NOT NULL, - job_params blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title, job_params(128)); -CREATE TABLE /*_*/querycache_info ( - qci_type varbinary(32) NOT NULL default '', - qci_timestamp binary(14) NOT NULL default '19700101000000' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/qci_type ON /*_*/querycache_info (qci_type); -CREATE TABLE /*_*/redirect ( - rd_from int unsigned NOT NULL default 0 PRIMARY KEY, - rd_namespace int NOT NULL default 0, - rd_title varchar(255) binary NOT NULL default '', - rd_interwiki varchar(32) default NULL, - rd_fragment varchar(255) binary default NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/rd_ns_title ON /*_*/redirect (rd_namespace,rd_title,rd_from); -CREATE TABLE /*_*/querycachetwo ( - qcc_type varbinary(32) NOT NULL, - qcc_value int unsigned NOT NULL default 0, - qcc_namespace int NOT NULL default 0, - qcc_title varchar(255) binary NOT NULL default '', - qcc_namespacetwo int NOT NULL default 0, - qcc_titletwo varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/qcc_type ON /*_*/querycachetwo (qcc_type,qcc_value); -CREATE INDEX /*i*/qcc_title ON /*_*/querycachetwo (qcc_type,qcc_namespace,qcc_title); -CREATE INDEX /*i*/qcc_titletwo ON /*_*/querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); -CREATE TABLE /*_*/page_restrictions ( - pr_page int NOT NULL, - pr_type varbinary(60) NOT NULL, - pr_level varbinary(60) NOT NULL, - pr_cascade tinyint NOT NULL, - pr_user int NULL, - pr_expiry varbinary(14) NULL, - pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions (pr_page,pr_type); -CREATE INDEX /*i*/pr_typelevel ON /*_*/page_restrictions (pr_type,pr_level); -CREATE INDEX /*i*/pr_level ON /*_*/page_restrictions (pr_level); -CREATE INDEX /*i*/pr_cascade ON /*_*/page_restrictions (pr_cascade); -CREATE TABLE /*_*/protected_titles ( - pt_namespace int NOT NULL, - pt_title varchar(255) binary NOT NULL, - pt_user int unsigned NOT NULL, - pt_reason tinyblob, - pt_timestamp binary(14) NOT NULL, - pt_expiry varbinary(14) NOT NULL default '', - pt_create_perm varbinary(60) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pt_namespace_title ON /*_*/protected_titles (pt_namespace,pt_title); -CREATE INDEX /*i*/pt_timestamp ON /*_*/protected_titles (pt_timestamp); -CREATE TABLE /*_*/page_props ( - pp_page int NOT NULL, - pp_propname varbinary(60) NOT NULL, - pp_value blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname); -CREATE TABLE /*_*/updatelog ( - ul_key varchar(255) NOT NULL PRIMARY KEY -) /*$wgDBTableOptions*/; -CREATE TABLE /*_*/change_tag ( - ct_rc_id int NULL, - ct_log_id int NULL, - ct_rev_id int NULL, - ct_tag varchar(255) NOT NULL, - ct_params blob NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag); -CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag); -CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag); -CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id); -CREATE TABLE /*_*/tag_summary ( - ts_rc_id int NULL, - ts_log_id int NULL, - ts_rev_id int NULL, - ts_tags blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id); -CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id); -CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id); -CREATE TABLE /*_*/valid_tag ( - vt_tag varchar(255) NOT NULL PRIMARY KEY -) /*$wgDBTableOptions*/; -CREATE TABLE /*_*/l10n_cache ( - lc_lang varbinary(32) NOT NULL, - lc_key varchar(255) NOT NULL, - lc_value mediumblob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/lc_lang_key ON /*_*/l10n_cache (lc_lang, lc_key); diff --git a/tests/phpunit/includes/db/sqlite/tables-1.17.sql b/tests/phpunit/includes/db/sqlite/tables-1.17.sql deleted file mode 100644 index 69ae3764..00000000 --- a/tests/phpunit/includes/db/sqlite/tables-1.17.sql +++ /dev/null @@ -1,516 +0,0 @@ --- This is a copy of MediaWiki 1.17 schema shared by MySQL and SQLite. --- It is used for updater testing. Comments are stripped to decrease --- file size, as we don't need to maintain it. - -CREATE TABLE /*_*/user ( - user_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - user_name varchar(255) binary NOT NULL default '', - user_real_name varchar(255) binary NOT NULL default '', - user_password tinyblob NOT NULL, - user_newpassword tinyblob NOT NULL, - user_newpass_time binary(14), - user_email tinytext NOT NULL, - user_options blob NOT NULL, - user_touched binary(14) NOT NULL default '', - user_token binary(32) NOT NULL default '', - user_email_authenticated binary(14), - user_email_token binary(32), - user_email_token_expires binary(14), - user_registration binary(14), - user_editcount int -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/user_name ON /*_*/user (user_name); -CREATE INDEX /*i*/user_email_token ON /*_*/user (user_email_token); -CREATE TABLE /*_*/user_groups ( - ug_user int unsigned NOT NULL default 0, - ug_group varbinary(16) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group); -CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group); -CREATE TABLE /*_*/user_newtalk ( - user_id int NOT NULL default 0, - user_ip varbinary(40) NOT NULL default '', - user_last_timestamp binary(14) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/un_user_id ON /*_*/user_newtalk (user_id); -CREATE INDEX /*i*/un_user_ip ON /*_*/user_newtalk (user_ip); -CREATE TABLE /*_*/user_properties ( - up_user int NOT NULL, - up_property varbinary(32) NOT NULL, - up_value blob -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/user_properties_user_property ON /*_*/user_properties (up_user,up_property); -CREATE INDEX /*i*/user_properties_property ON /*_*/user_properties (up_property); -CREATE TABLE /*_*/page ( - page_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - page_namespace int NOT NULL, - page_title varchar(255) binary NOT NULL, - page_restrictions tinyblob NOT NULL, - page_counter bigint unsigned NOT NULL default 0, - page_is_redirect tinyint unsigned NOT NULL default 0, - page_is_new tinyint unsigned NOT NULL default 0, - page_random real unsigned NOT NULL, - page_touched binary(14) NOT NULL default '', - page_latest int unsigned NOT NULL, - page_len int unsigned NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title); -CREATE INDEX /*i*/page_random ON /*_*/page (page_random); -CREATE INDEX /*i*/page_len ON /*_*/page (page_len); -CREATE TABLE /*_*/revision ( - rev_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - rev_page int unsigned NOT NULL, - rev_text_id int unsigned NOT NULL, - rev_comment tinyblob NOT NULL, - rev_user int unsigned NOT NULL default 0, - rev_user_text varchar(255) binary NOT NULL default '', - rev_timestamp binary(14) NOT NULL default '', - rev_minor_edit tinyint unsigned NOT NULL default 0, - rev_deleted tinyint unsigned NOT NULL default 0, - rev_len int unsigned, - rev_parent_id int unsigned default NULL -) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; -CREATE UNIQUE INDEX /*i*/rev_page_id ON /*_*/revision (rev_page, rev_id); -CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp); -CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp); -CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp); -CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp); -CREATE TABLE /*_*/text ( - old_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - old_text mediumblob NOT NULL, - old_flags tinyblob NOT NULL -) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=10240; -CREATE TABLE /*_*/archive ( - ar_namespace int NOT NULL default 0, - ar_title varchar(255) binary NOT NULL default '', - ar_text mediumblob NOT NULL, - ar_comment tinyblob NOT NULL, - ar_user int unsigned NOT NULL default 0, - ar_user_text varchar(255) binary NOT NULL, - ar_timestamp binary(14) NOT NULL default '', - ar_minor_edit tinyint NOT NULL default 0, - ar_flags tinyblob NOT NULL, - ar_rev_id int unsigned, - ar_text_id int unsigned, - ar_deleted tinyint unsigned NOT NULL default 0, - ar_len int unsigned, - ar_page_id int unsigned, - ar_parent_id int unsigned default NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp); -CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp); -CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id); -CREATE TABLE /*_*/pagelinks ( - pl_from int unsigned NOT NULL default 0, - pl_namespace int NOT NULL default 0, - pl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title); -CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from); -CREATE TABLE /*_*/templatelinks ( - tl_from int unsigned NOT NULL default 0, - tl_namespace int NOT NULL default 0, - tl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title); -CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from); -CREATE TABLE /*_*/imagelinks ( - il_from int unsigned NOT NULL default 0, - il_to varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to); -CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from); -CREATE TABLE /*_*/categorylinks ( - cl_from int unsigned NOT NULL default 0, - cl_to varchar(255) binary NOT NULL default '', - cl_sortkey varbinary(230) NOT NULL default '', - cl_sortkey_prefix varchar(255) binary NOT NULL default '', - cl_timestamp timestamp NOT NULL, - cl_collation varbinary(32) NOT NULL default '', - cl_type ENUM('page', 'subcat', 'file') NOT NULL default 'page' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to); -CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_sortkey,cl_from); -CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp); -CREATE INDEX /*i*/cl_collation ON /*_*/categorylinks (cl_collation); -CREATE TABLE /*_*/category ( - cat_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - cat_title varchar(255) binary NOT NULL, - cat_pages int signed NOT NULL default 0, - cat_subcats int signed NOT NULL default 0, - cat_files int signed NOT NULL default 0, - cat_hidden tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title); -CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages); -CREATE TABLE /*_*/externallinks ( - el_from int unsigned NOT NULL default 0, - el_to blob NOT NULL, - el_index blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40)); -CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from); -CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60)); -CREATE TABLE /*_*/external_user ( - eu_local_id int unsigned NOT NULL PRIMARY KEY, - eu_external_id varchar(255) binary NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id); -CREATE TABLE /*_*/langlinks ( - ll_from int unsigned NOT NULL default 0, - ll_lang varbinary(20) NOT NULL default '', - ll_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ll_from ON /*_*/langlinks (ll_from, ll_lang); -CREATE INDEX /*i*/ll_lang ON /*_*/langlinks (ll_lang, ll_title); -CREATE TABLE /*_*/iwlinks ( - iwl_from int unsigned NOT NULL default 0, - iwl_prefix varbinary(20) NOT NULL default '', - iwl_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/iwl_from ON /*_*/iwlinks (iwl_from, iwl_prefix, iwl_title); -CREATE UNIQUE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from); -CREATE TABLE /*_*/site_stats ( - ss_row_id int unsigned NOT NULL, - ss_total_views bigint unsigned default 0, - ss_total_edits bigint unsigned default 0, - ss_good_articles bigint unsigned default 0, - ss_total_pages bigint default '-1', - ss_users bigint default '-1', - ss_active_users bigint default '-1', - ss_admins int default '-1', - ss_images int default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id); -CREATE TABLE /*_*/hitcounter ( - hc_id int unsigned NOT NULL -) ENGINE=HEAP MAX_ROWS=25000; -CREATE TABLE /*_*/ipblocks ( - ipb_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - ipb_address tinyblob NOT NULL, - ipb_user int unsigned NOT NULL default 0, - ipb_by int unsigned NOT NULL default 0, - ipb_by_text varchar(255) binary NOT NULL default '', - ipb_reason tinyblob NOT NULL, - ipb_timestamp binary(14) NOT NULL default '', - ipb_auto bool NOT NULL default 0, - ipb_anon_only bool NOT NULL default 0, - ipb_create_account bool NOT NULL default 1, - ipb_enable_autoblock bool NOT NULL default '1', - ipb_expiry varbinary(14) NOT NULL default '', - ipb_range_start tinyblob NOT NULL, - ipb_range_end tinyblob NOT NULL, - ipb_deleted bool NOT NULL default 0, - ipb_block_email bool NOT NULL default 0, - ipb_allow_usertalk bool NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only); -CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user); -CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8)); -CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp); -CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry); -CREATE TABLE /*_*/image ( - img_name varchar(255) binary NOT NULL default '' PRIMARY KEY, - img_size int unsigned NOT NULL default 0, - img_width int NOT NULL default 0, - img_height int NOT NULL default 0, - img_metadata mediumblob NOT NULL, - img_bits int NOT NULL default 0, - img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - img_minor_mime varbinary(100) NOT NULL default "unknown", - img_description tinyblob NOT NULL, - img_user int unsigned NOT NULL default 0, - img_user_text varchar(255) binary NOT NULL, - img_timestamp varbinary(14) NOT NULL default '', - img_sha1 varbinary(32) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp); -CREATE INDEX /*i*/img_size ON /*_*/image (img_size); -CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp); -CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1); -CREATE TABLE /*_*/oldimage ( - oi_name varchar(255) binary NOT NULL default '', - oi_archive_name varchar(255) binary NOT NULL default '', - oi_size int unsigned NOT NULL default 0, - oi_width int NOT NULL default 0, - oi_height int NOT NULL default 0, - oi_bits int NOT NULL default 0, - oi_description tinyblob NOT NULL, - oi_user int unsigned NOT NULL default 0, - oi_user_text varchar(255) binary NOT NULL, - oi_timestamp binary(14) NOT NULL default '', - oi_metadata mediumblob NOT NULL, - oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - oi_minor_mime varbinary(100) NOT NULL default "unknown", - oi_deleted tinyint unsigned NOT NULL default 0, - oi_sha1 varbinary(32) NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp); -CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp); -CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name(14)); -CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1); -CREATE TABLE /*_*/filearchive ( - fa_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - fa_name varchar(255) binary NOT NULL default '', - fa_archive_name varchar(255) binary default '', - fa_storage_group varbinary(16), - fa_storage_key varbinary(64) default '', - fa_deleted_user int, - fa_deleted_timestamp binary(14) default '', - fa_deleted_reason text, - fa_size int unsigned default 0, - fa_width int default 0, - fa_height int default 0, - fa_metadata mediumblob, - fa_bits int default 0, - fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") default "unknown", - fa_minor_mime varbinary(100) default "unknown", - fa_description tinyblob, - fa_user int unsigned default 0, - fa_user_text varchar(255) binary, - fa_timestamp binary(14) default '', - fa_deleted tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp); -CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key); -CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp); -CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp); -CREATE TABLE /*_*/recentchanges ( - rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, - rc_timestamp varbinary(14) NOT NULL default '', - rc_cur_time varbinary(14) NOT NULL default '', - rc_user int unsigned NOT NULL default 0, - rc_user_text varchar(255) binary NOT NULL, - rc_namespace int NOT NULL default 0, - rc_title varchar(255) binary NOT NULL default '', - rc_comment varchar(255) binary NOT NULL default '', - rc_minor tinyint unsigned NOT NULL default 0, - rc_bot tinyint unsigned NOT NULL default 0, - rc_new tinyint unsigned NOT NULL default 0, - rc_cur_id int unsigned NOT NULL default 0, - rc_this_oldid int unsigned NOT NULL default 0, - rc_last_oldid int unsigned NOT NULL default 0, - rc_type tinyint unsigned NOT NULL default 0, - rc_moved_to_ns tinyint unsigned NOT NULL default 0, - rc_moved_to_title varchar(255) binary NOT NULL default '', - rc_patrolled tinyint unsigned NOT NULL default 0, - rc_ip varbinary(40) NOT NULL default '', - rc_old_len int, - rc_new_len int, - rc_deleted tinyint unsigned NOT NULL default 0, - rc_logid int unsigned NOT NULL default 0, - rc_log_type varbinary(255) NULL default NULL, - rc_log_action varbinary(255) NULL default NULL, - rc_params blob NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp); -CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title); -CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id); -CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp); -CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip); -CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text); -CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp); -CREATE TABLE /*_*/watchlist ( - wl_user int unsigned NOT NULL, - wl_namespace int NOT NULL default 0, - wl_title varchar(255) binary NOT NULL default '', - wl_notificationtimestamp varbinary(14) -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/wl_user ON /*_*/watchlist (wl_user, wl_namespace, wl_title); -CREATE INDEX /*i*/namespace_title ON /*_*/watchlist (wl_namespace, wl_title); -CREATE TABLE /*_*/math ( - math_inputhash varbinary(16) NOT NULL, - math_outputhash varbinary(16) NOT NULL, - math_html_conservativeness tinyint NOT NULL, - math_html text, - math_mathml text -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/math_inputhash ON /*_*/math (math_inputhash); -CREATE TABLE /*_*/searchindex ( - si_page int unsigned NOT NULL, - si_title varchar(255) NOT NULL default '', - si_text mediumtext NOT NULL -) ENGINE=MyISAM; -CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page); -CREATE FULLTEXT INDEX /*i*/si_title ON /*_*/searchindex (si_title); -CREATE FULLTEXT INDEX /*i*/si_text ON /*_*/searchindex (si_text); -CREATE TABLE /*_*/interwiki ( - iw_prefix varchar(32) NOT NULL, - iw_url blob NOT NULL, - iw_api blob NOT NULL, - iw_wikiid varchar(64) NOT NULL, - iw_local bool NOT NULL, - iw_trans tinyint NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/iw_prefix ON /*_*/interwiki (iw_prefix); -CREATE TABLE /*_*/querycache ( - qc_type varbinary(32) NOT NULL, - qc_value int unsigned NOT NULL default 0, - qc_namespace int NOT NULL default 0, - qc_title varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/qc_type ON /*_*/querycache (qc_type,qc_value); -CREATE TABLE /*_*/objectcache ( - keyname varbinary(255) NOT NULL default '' PRIMARY KEY, - value mediumblob, - exptime datetime -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime); -CREATE TABLE /*_*/transcache ( - tc_url varbinary(255) NOT NULL, - tc_contents text, - tc_time binary(14) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url); -CREATE TABLE /*_*/logging ( - log_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - log_type varbinary(32) NOT NULL default '', - log_action varbinary(32) NOT NULL default '', - log_timestamp binary(14) NOT NULL default '19700101000000', - log_user int unsigned NOT NULL default 0, - log_user_text varchar(255) binary NOT NULL default '', - log_namespace int NOT NULL default 0, - log_title varchar(255) binary NOT NULL default '', - log_page int unsigned NULL, - log_comment varchar(255) NOT NULL default '', - log_params blob NOT NULL, - log_deleted tinyint unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp); -CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp); -CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp); -CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp); -CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp); -CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp); -CREATE TABLE /*_*/log_search ( - ls_field varbinary(32) NOT NULL, - ls_value varchar(255) NOT NULL, - ls_log_id int unsigned NOT NULL default 0 -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/ls_field_val ON /*_*/log_search (ls_field,ls_value,ls_log_id); -CREATE INDEX /*i*/ls_log_id ON /*_*/log_search (ls_log_id); -CREATE TABLE /*_*/trackbacks ( - tb_id int PRIMARY KEY AUTO_INCREMENT, - tb_page int REFERENCES /*_*/page(page_id) ON DELETE CASCADE, - tb_title varchar(255) NOT NULL, - tb_url blob NOT NULL, - tb_ex text, - tb_name varchar(255) -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/tb_page ON /*_*/trackbacks (tb_page); -CREATE TABLE /*_*/job ( - job_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - job_cmd varbinary(60) NOT NULL default '', - job_namespace int NOT NULL, - job_title varchar(255) binary NOT NULL, - job_params blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title, job_params(128)); -CREATE TABLE /*_*/querycache_info ( - qci_type varbinary(32) NOT NULL default '', - qci_timestamp binary(14) NOT NULL default '19700101000000' -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/qci_type ON /*_*/querycache_info (qci_type); -CREATE TABLE /*_*/redirect ( - rd_from int unsigned NOT NULL default 0 PRIMARY KEY, - rd_namespace int NOT NULL default 0, - rd_title varchar(255) binary NOT NULL default '', - rd_interwiki varchar(32) default NULL, - rd_fragment varchar(255) binary default NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/rd_ns_title ON /*_*/redirect (rd_namespace,rd_title,rd_from); -CREATE TABLE /*_*/querycachetwo ( - qcc_type varbinary(32) NOT NULL, - qcc_value int unsigned NOT NULL default 0, - qcc_namespace int NOT NULL default 0, - qcc_title varchar(255) binary NOT NULL default '', - qcc_namespacetwo int NOT NULL default 0, - qcc_titletwo varchar(255) binary NOT NULL default '' -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/qcc_type ON /*_*/querycachetwo (qcc_type,qcc_value); -CREATE INDEX /*i*/qcc_title ON /*_*/querycachetwo (qcc_type,qcc_namespace,qcc_title); -CREATE INDEX /*i*/qcc_titletwo ON /*_*/querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); -CREATE TABLE /*_*/page_restrictions ( - pr_page int NOT NULL, - pr_type varbinary(60) NOT NULL, - pr_level varbinary(60) NOT NULL, - pr_cascade tinyint NOT NULL, - pr_user int NULL, - pr_expiry varbinary(14) NULL, - pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions (pr_page,pr_type); -CREATE INDEX /*i*/pr_typelevel ON /*_*/page_restrictions (pr_type,pr_level); -CREATE INDEX /*i*/pr_level ON /*_*/page_restrictions (pr_level); -CREATE INDEX /*i*/pr_cascade ON /*_*/page_restrictions (pr_cascade); -CREATE TABLE /*_*/protected_titles ( - pt_namespace int NOT NULL, - pt_title varchar(255) binary NOT NULL, - pt_user int unsigned NOT NULL, - pt_reason tinyblob, - pt_timestamp binary(14) NOT NULL, - pt_expiry varbinary(14) NOT NULL default '', - pt_create_perm varbinary(60) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pt_namespace_title ON /*_*/protected_titles (pt_namespace,pt_title); -CREATE INDEX /*i*/pt_timestamp ON /*_*/protected_titles (pt_timestamp); -CREATE TABLE /*_*/page_props ( - pp_page int NOT NULL, - pp_propname varbinary(60) NOT NULL, - pp_value blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname); -CREATE TABLE /*_*/updatelog ( - ul_key varchar(255) NOT NULL PRIMARY KEY, - ul_value blob -) /*$wgDBTableOptions*/; -CREATE TABLE /*_*/change_tag ( - ct_rc_id int NULL, - ct_log_id int NULL, - ct_rev_id int NULL, - ct_tag varchar(255) NOT NULL, - ct_params blob NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag); -CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag); -CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag); -CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id); -CREATE TABLE /*_*/tag_summary ( - ts_rc_id int NULL, - ts_log_id int NULL, - ts_rev_id int NULL, - ts_tags blob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id); -CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id); -CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id); -CREATE TABLE /*_*/valid_tag ( - vt_tag varchar(255) NOT NULL PRIMARY KEY -) /*$wgDBTableOptions*/; -CREATE TABLE /*_*/l10n_cache ( - lc_lang varbinary(32) NOT NULL, - lc_key varchar(255) NOT NULL, - lc_value mediumblob NOT NULL -) /*$wgDBTableOptions*/; -CREATE INDEX /*i*/lc_lang_key ON /*_*/l10n_cache (lc_lang, lc_key); -CREATE TABLE /*_*/msg_resource ( - mr_resource varbinary(255) NOT NULL, - mr_lang varbinary(32) NOT NULL, - mr_blob mediumblob NOT NULL, - mr_timestamp binary(14) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/mr_resource_lang ON /*_*/msg_resource (mr_resource, mr_lang); -CREATE TABLE /*_*/msg_resource_links ( - mrl_resource varbinary(255) NOT NULL, - mrl_message varbinary(255) NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/mrl_message_resource ON /*_*/msg_resource_links (mrl_message, mrl_resource); -CREATE TABLE /*_*/module_deps ( - md_module varbinary(255) NOT NULL, - md_skin varbinary(32) NOT NULL, - md_deps mediumblob NOT NULL -) /*$wgDBTableOptions*/; -CREATE UNIQUE INDEX /*i*/md_module_skin ON /*_*/module_deps (md_module, md_skin); diff --git a/tests/phpunit/includes/debug/MWDebugTest.php b/tests/phpunit/includes/debug/MWDebugTest.php new file mode 100644 index 00000000..5a4e66d4 --- /dev/null +++ b/tests/phpunit/includes/debug/MWDebugTest.php @@ -0,0 +1,63 @@ +<?php + +class MWDebugTest extends MediaWikiTestCase { + + + function setUp() { + // Make sure MWDebug class is enabled + static $MWDebugEnabled = false; + if( !$MWDebugEnabled ) { + MWDebug::init(); + $MWDebugEnabled = true; + } + /** Clear log before each test */ + MWDebug::clearLog(); + } + + function testAddLog() { + MWDebug::log( 'logging a string' ); + $this->assertEquals( array( array( + 'msg' => 'logging a string', + 'type' => 'log', + 'caller' => __METHOD__ , + ) ), + MWDebug::getLog() + ); + } + + function testAddWarning() { + MWDebug::warning( 'Warning message' ); + $this->assertEquals( array( array( + 'msg' => 'Warning message', + 'type' => 'warn', + 'caller' => 'MWDebug::warning', + ) ), + MWDebug::getLog() + ); + } + + function testAvoidDuplicateDeprecations() { + MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' ); + MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' ); + + // assertCount() not available on WMF integration server + $this->assertEquals( 1, + count( MWDebug::getLog() ), + "Only one deprecated warning per function should be kept" + ); + } + + function testAvoidNonConsecutivesDuplicateDeprecations() { + MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' ); + MWDebug::warning( 'some warning' ); + MWDebug::log( 'we could have logged something too' ); + // Another deprecation + MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' ); + + // assertCount() not available on WMF integration server + $this->assertEquals( 3, + count( MWDebug::getLog() ), + "Only one deprecated warning per function should be kept" + ); + } +} diff --git a/tests/phpunit/includes/filerepo/FileBackendTest.php b/tests/phpunit/includes/filerepo/FileBackendTest.php new file mode 100644 index 00000000..da44797a --- /dev/null +++ b/tests/phpunit/includes/filerepo/FileBackendTest.php @@ -0,0 +1,1358 @@ +<?php + +/** + * @group FileRepo + * @group FileBackend + */ +class FileBackendTest extends MediaWikiTestCase { + private $backend, $multiBackend; + private $filesToPrune = array(); + private $dirsToPrune = array(); + private static $backendToUse; + + function setUp() { + global $wgFileBackends; + parent::setUp(); + $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . time() . '-' . mt_rand(); + if ( $this->getCliArg( 'use-filebackend=' ) ) { + if ( self::$backendToUse ) { + $this->singleBackend = self::$backendToUse; + } else { + $name = $this->getCliArg( 'use-filebackend=' ); + $useConfig = array(); + foreach ( $wgFileBackends as $conf ) { + if ( $conf['name'] == $name ) { + $useConfig = $conf; + } + } + $useConfig['name'] = 'localtesting'; // swap name + $class = $conf['class']; + self::$backendToUse = new $class( $useConfig ); + $this->singleBackend = self::$backendToUse; + } + } else { + $this->singleBackend = new FSFileBackend( array( + 'name' => 'localtesting', + 'lockManager' => 'fsLockManager', + 'containerPaths' => array( + 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1", + 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" ) + ) ); + } + $this->multiBackend = new FileBackendMultiWrite( array( + 'name' => 'localtesting', + 'lockManager' => 'fsLockManager', + 'backends' => array( + array( + 'name' => 'localmutlitesting1', + 'class' => 'FSFileBackend', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( + 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1", + 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ), + 'isMultiMaster' => false + ), + array( + 'name' => 'localmutlitesting2', + 'class' => 'FSFileBackend', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( + 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1", + 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ), + 'isMultiMaster' => true + ) + ) + ) ); + $this->filesToPrune = array(); + } + + private function baseStorePath() { + return 'mwstore://localtesting'; + } + + private function backendClass() { + return get_class( $this->backend ); + } + + /** + * @dataProvider provider_testIsStoragePath + */ + public function testIsStoragePath( $path, $isStorePath ) { + $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ), + "FileBackend::isStoragePath on path '$path'" ); + } + + function provider_testIsStoragePath() { + return array( + array( 'mwstore://', true ), + array( 'mwstore://backend', true ), + array( 'mwstore://backend/container', true ), + array( 'mwstore://backend/container/', true ), + array( 'mwstore://backend/container/path', true ), + array( 'mwstore://backend//container/', true ), + array( 'mwstore://backend//container//', true ), + array( 'mwstore://backend//container//path', true ), + array( 'mwstore:///', true ), + array( 'mwstore:/', false ), + array( 'mwstore:', false ), + ); + } + + /** + * @dataProvider provider_testSplitStoragePath + */ + public function testSplitStoragePath( $path, $res ) { + $this->assertEquals( $res, FileBackend::splitStoragePath( $path ), + "FileBackend::splitStoragePath on path '$path'" ); + } + + function provider_testSplitStoragePath() { + return array( + array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ), + array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ), + array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ), + array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ), + array( 'mwstore://backend//container/path', array( null, null, null ) ), + array( 'mwstore://backend//container//path', array( null, null, null ) ), + array( 'mwstore://', array( null, null, null ) ), + array( 'mwstore://backend', array( null, null, null ) ), + array( 'mwstore:///', array( null, null, null ) ), + array( 'mwstore:/', array( null, null, null ) ), + array( 'mwstore:', array( null, null, null ) ) + ); + } + + /** + * @dataProvider provider_normalizeStoragePath + */ + public function testNormalizeStoragePath( $path, $res ) { + $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ), + "FileBackend::normalizeStoragePath on path '$path'" ); + } + + function provider_normalizeStoragePath() { + return array( + array( 'mwstore://backend/container', 'mwstore://backend/container' ), + array( 'mwstore://backend/container/', 'mwstore://backend/container' ), + array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ), + array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ), + array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ), + array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj', + array( 'mwstore://', null ), + array( 'mwstore://backend', null ), + array( 'mwstore://backend//container/path', null ), + array( 'mwstore://backend//container//path', null ), + array( 'mwstore:///', null ), + array( 'mwstore:/', null ), + array( 'mwstore:', null ), ) + ); + } + + /** + * @dataProvider provider_testParentStoragePath + */ + public function testParentStoragePath( $path, $res ) { + $this->assertEquals( $res, FileBackend::parentStoragePath( $path ), + "FileBackend::parentStoragePath on path '$path'" ); + } + + function provider_testParentStoragePath() { + return array( + array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ), + array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ), + array( 'mwstore://backend/container/path', 'mwstore://backend/container' ), + array( 'mwstore://backend/container', null ), + array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ), + array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ), + array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ), + array( 'mwstore://backend/container/', null ), + ); + } + + /** + * @dataProvider provider_testExtensionFromPath + */ + public function testExtensionFromPath( $path, $res ) { + $this->assertEquals( $res, FileBackend::extensionFromPath( $path ), + "FileBackend::extensionFromPath on path '$path'" ); + } + + function provider_testExtensionFromPath() { + return array( + array( 'mwstore://backend/container/path.txt', 'txt' ), + array( 'mwstore://backend/container/path.svg.png', 'png' ), + array( 'mwstore://backend/container/path', '' ), + array( 'mwstore://backend/container/path.', '' ), + ); + } + + /** + * @dataProvider provider_testStore + */ + public function testStore( $op ) { + $this->filesToPrune[] = $op['src']; + + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestStore( $op ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestStore( $op ); + $this->filesToPrune[] = $op['src']; # avoid file leaking + $this->tearDownFiles(); + } + + function doTestStore( $op ) { + $backendName = $this->backendClass(); + + $source = $op['src']; + $dest = $op['dst']; + $this->prepare( array( 'dir' => dirname( $dest ) ) ); + + file_put_contents( $source, "Unit test file" ); + + if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) { + $this->backend->store( $op ); + } + + $status = $this->backend->doOperation( $op ); + + $this->assertEquals( array(), $status->errors, + "Store from $source to $dest succeeded without warnings ($backendName)." ); + $this->assertEquals( array(), $status->errors, + "Store from $source to $dest succeeded ($backendName)." ); + $this->assertEquals( array( 0 => true ), $status->success, + "Store from $source to $dest has proper 'success' field in Status ($backendName)." ); + $this->assertEquals( true, file_exists( $source ), + "Source file $source still exists ($backendName)." ); + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), + "Destination file $dest exists ($backendName)." ); + + $this->assertEquals( filesize( $source ), + $this->backend->getFileSize( array( 'src' => $dest ) ), + "Destination file $dest has correct size ($backendName)." ); + + $props1 = FSFile::getPropsFromPath( $source ); + $props2 = $this->backend->getFileProps( array( 'src' => $dest ) ); + $this->assertEquals( $props1, $props2, + "Source and destination have the same props ($backendName)." ); + } + + public function provider_testStore() { + $cases = array(); + + $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath(); + $toPath = $this->baseStorePath() . '/unittest-cont1/fun/obj1.txt'; + $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath ); + $cases[] = array( + $op, // operation + $tmpName, // source + $toPath, // dest + ); + + $op2 = $op; + $op2['overwrite'] = true; + $cases[] = array( + $op2, // operation + $tmpName, // source + $toPath, // dest + ); + + $op2 = $op; + $op2['overwriteSame'] = true; + $cases[] = array( + $op2, // operation + $tmpName, // source + $toPath, // dest + ); + + return $cases; + } + + /** + * @dataProvider provider_testCopy + */ + public function testCopy( $op ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestCopy( $op ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestCopy( $op ); + $this->tearDownFiles(); + } + + function doTestCopy( $op ) { + $backendName = $this->backendClass(); + + $source = $op['src']; + $dest = $op['dst']; + $this->prepare( array( 'dir' => dirname( $source ) ) ); + $this->prepare( array( 'dir' => dirname( $dest ) ) ); + + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $source succeeded ($backendName)." ); + + if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) { + $this->backend->copy( $op ); + } + + $status = $this->backend->doOperation( $op ); + + $this->assertEquals( array(), $status->errors, + "Copy from $source to $dest succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Copy from $source to $dest succeeded ($backendName)." ); + $this->assertEquals( array( 0 => true ), $status->success, + "Copy from $source to $dest has proper 'success' field in Status ($backendName)." ); + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ), + "Source file $source still exists ($backendName)." ); + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), + "Destination file $dest exists after copy ($backendName)." ); + + $this->assertEquals( + $this->backend->getFileSize( array( 'src' => $source ) ), + $this->backend->getFileSize( array( 'src' => $dest ) ), + "Destination file $dest has correct size ($backendName)." ); + + $props1 = $this->backend->getFileProps( array( 'src' => $source ) ); + $props2 = $this->backend->getFileProps( array( 'src' => $dest ) ); + $this->assertEquals( $props1, $props2, + "Source and destination have the same props ($backendName)." ); + } + + public function provider_testCopy() { + $cases = array(); + + $source = $this->baseStorePath() . '/unittest-cont1/file.txt'; + $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt'; + + $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest ); + $cases[] = array( + $op, // operation + $source, // source + $dest, // dest + ); + + $op2 = $op; + $op2['overwrite'] = true; + $cases[] = array( + $op2, // operation + $source, // source + $dest, // dest + ); + + $op2 = $op; + $op2['overwriteSame'] = true; + $cases[] = array( + $op2, // operation + $source, // source + $dest, // dest + ); + + return $cases; + } + + /** + * @dataProvider provider_testMove + */ + public function testMove( $op ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestMove( $op ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestMove( $op ); + $this->tearDownFiles(); + } + + private function doTestMove( $op ) { + $backendName = $this->backendClass(); + + $source = $op['src']; + $dest = $op['dst']; + $this->prepare( array( 'dir' => dirname( $source ) ) ); + $this->prepare( array( 'dir' => dirname( $dest ) ) ); + + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $source succeeded ($backendName)." ); + + if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) { + $this->backend->copy( $op ); + } + + $status = $this->backend->doOperation( $op ); + $this->assertEquals( array(), $status->errors, + "Move from $source to $dest succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Move from $source to $dest succeeded ($backendName)." ); + $this->assertEquals( array( 0 => true ), $status->success, + "Move from $source to $dest has proper 'success' field in Status ($backendName)." ); + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ), + "Source file $source does not still exists ($backendName)." ); + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), + "Destination file $dest exists after move ($backendName)." ); + + $this->assertNotEquals( + $this->backend->getFileSize( array( 'src' => $source ) ), + $this->backend->getFileSize( array( 'src' => $dest ) ), + "Destination file $dest has correct size ($backendName)." ); + + $props1 = $this->backend->getFileProps( array( 'src' => $source ) ); + $props2 = $this->backend->getFileProps( array( 'src' => $dest ) ); + $this->assertEquals( false, $props1['fileExists'], + "Source file does not exist accourding to props ($backendName)." ); + $this->assertEquals( true, $props2['fileExists'], + "Destination file exists accourding to props ($backendName)." ); + } + + public function provider_testMove() { + $cases = array(); + + $source = $this->baseStorePath() . '/unittest-cont1/file.txt'; + $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt'; + + $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest ); + $cases[] = array( + $op, // operation + $source, // source + $dest, // dest + ); + + $op2 = $op; + $op2['overwrite'] = true; + $cases[] = array( + $op2, // operation + $source, // source + $dest, // dest + ); + + $op2 = $op; + $op2['overwriteSame'] = true; + $cases[] = array( + $op2, // operation + $source, // source + $dest, // dest + ); + + return $cases; + } + + /** + * @dataProvider provider_testDelete + */ + public function testDelete( $op, $withSource, $okStatus ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestDelete( $op, $withSource, $okStatus ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestDelete( $op, $withSource, $okStatus ); + $this->tearDownFiles(); + } + + private function doTestDelete( $op, $withSource, $okStatus ) { + $backendName = $this->backendClass(); + + $source = $op['src']; + $this->prepare( array( 'dir' => dirname( $source ) ) ); + + if ( $withSource ) { + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $source succeeded ($backendName)." ); + } + + $status = $this->backend->doOperation( $op ); + if ( $okStatus ) { + $this->assertEquals( array(), $status->errors, + "Deletion of file at $source succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Deletion of file at $source succeeded ($backendName)." ); + $this->assertEquals( array( 0 => true ), $status->success, + "Deletion of file at $source has proper 'success' field in Status ($backendName)." ); + } else { + $this->assertEquals( false, $status->isOK(), + "Deletion of file at $source failed ($backendName)." ); + } + + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ), + "Source file $source does not exist after move ($backendName)." ); + + $this->assertFalse( + $this->backend->getFileSize( array( 'src' => $source ) ), + "Source file $source has correct size (false) ($backendName)." ); + + $props1 = $this->backend->getFileProps( array( 'src' => $source ) ); + $this->assertFalse( $props1['fileExists'], + "Source file $source does not exist according to props ($backendName)." ); + } + + public function provider_testDelete() { + $cases = array(); + + $source = $this->baseStorePath() . '/unittest-cont1/myfacefile.txt'; + + $op = array( 'op' => 'delete', 'src' => $source ); + $cases[] = array( + $op, // operation + true, // with source + true // succeeds + ); + + $cases[] = array( + $op, // operation + false, // without source + false // fails + ); + + $op['ignoreMissingSource'] = true; + $cases[] = array( + $op, // operation + false, // without source + true // succeeds + ); + + return $cases; + } + + /** + * @dataProvider provider_testCreate + */ + public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize ); + $this->tearDownFiles(); + } + + private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) { + $backendName = $this->backendClass(); + + $dest = $op['dst']; + $this->prepare( array( 'dir' => dirname( $dest ) ) ); + + $oldText = 'blah...blah...waahwaah'; + if ( $alreadyExists ) { + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $dest succeeded ($backendName)." ); + } + + $status = $this->backend->doOperation( $op ); + if ( $okStatus ) { + $this->assertEquals( array(), $status->errors, + "Creation of file at $dest succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Creation of file at $dest succeeded ($backendName)." ); + $this->assertEquals( array( 0 => true ), $status->success, + "Creation of file at $dest has proper 'success' field in Status ($backendName)." ); + } else { + $this->assertEquals( false, $status->isOK(), + "Creation of file at $dest failed ($backendName)." ); + } + + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), + "Destination file $dest exists after creation ($backendName)." ); + + $props1 = $this->backend->getFileProps( array( 'src' => $dest ) ); + $this->assertEquals( true, $props1['fileExists'], + "Destination file $dest exists according to props ($backendName)." ); + if ( $okStatus ) { // file content is what we saved + $this->assertEquals( $newSize, $props1['size'], + "Destination file $dest has expected size according to props ($backendName)." ); + $this->assertEquals( $newSize, + $this->backend->getFileSize( array( 'src' => $dest ) ), + "Destination file $dest has correct size ($backendName)." ); + } else { // file content is some other previous text + $this->assertEquals( strlen( $oldText ), $props1['size'], + "Destination file $dest has original size according to props ($backendName)." ); + $this->assertEquals( strlen( $oldText ), + $this->backend->getFileSize( array( 'src' => $dest ) ), + "Destination file $dest has original size according to props ($backendName)." ); + } + } + + /** + * @dataProvider provider_testCreate + */ + public function provider_testCreate() { + $cases = array(); + + $dest = $this->baseStorePath() . '/unittest-cont2/myspacefile.txt'; + + $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest ); + $cases[] = array( + $op, // operation + false, // no dest already exists + true, // succeeds + strlen( $op['content'] ) + ); + + $op2 = $op; + $op2['content'] = "\n"; + $cases[] = array( + $op2, // operation + false, // no dest already exists + true, // succeeds + strlen( $op2['content'] ) + ); + + $op2 = $op; + $op2['content'] = "fsf\n waf 3kt"; + $cases[] = array( + $op2, // operation + true, // dest already exists + false, // fails + strlen( $op2['content'] ) + ); + + $op2 = $op; + $op2['content'] = "egm'g gkpe gpqg eqwgwqg"; + $op2['overwrite'] = true; + $cases[] = array( + $op2, // operation + true, // dest already exists + true, // succeeds + strlen( $op2['content'] ) + ); + + $op2 = $op; + $op2['content'] = "39qjmg3-qg"; + $op2['overwriteSame'] = true; + $cases[] = array( + $op2, // operation + true, // dest already exists + false, // succeeds + strlen( $op2['content'] ) + ); + + return $cases; + } + + /** + * @dataProvider provider_testConcatenate + */ + public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) { + $this->filesToPrune[] = $op['dst']; + + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ); + $this->filesToPrune[] = $op['dst']; # avoid file leaking + $this->tearDownFiles(); + } + + public function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) { + $backendName = $this->backendClass(); + + $expContent = ''; + // Create sources + $ops = array(); + foreach ( $srcs as $i => $source ) { + $this->prepare( array( 'dir' => dirname( $source ) ) ); + $ops[] = array( + 'op' => 'create', // operation + 'dst' => $source, // source + 'content' => $srcsContent[$i] + ); + $expContent .= $srcsContent[$i]; + } + $status = $this->backend->doOperations( $ops ); + + $this->assertEquals( array(), $status->errors, + "Creation of source files succeeded ($backendName)." ); + + $dest = $params['dst']; + if ( $alreadyExists ) { + $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false; + $this->assertEquals( true, $ok, + "Creation of file at $dest succeeded ($backendName)." ); + } else { + $ok = file_put_contents( $dest, '' ) !== false; + $this->assertEquals( true, $ok, + "Creation of 0-byte file at $dest succeeded ($backendName)." ); + } + + // Combine the files into one + $status = $this->backend->concatenate( $params ); + if ( $okStatus ) { + $this->assertEquals( array(), $status->errors, + "Creation of concat file at $dest succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Creation of concat file at $dest succeeded ($backendName)." ); + } else { + $this->assertEquals( false, $status->isOK(), + "Creation of concat file at $dest failed ($backendName)." ); + } + + if ( $okStatus ) { + $this->assertEquals( true, is_file( $dest ), + "Dest concat file $dest exists after creation ($backendName)." ); + } else { + $this->assertEquals( true, is_file( $dest ), + "Dest concat file $dest exists after failed creation ($backendName)." ); + } + + $contents = file_get_contents( $dest ); + $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." ); + + if ( $okStatus ) { + $this->assertEquals( $expContent, $contents, + "Concat file at $dest has correct contents ($backendName)." ); + } else { + $this->assertNotEquals( $expContent, $contents, + "Concat file at $dest has correct contents ($backendName)." ); + } + } + + function provider_testConcatenate() { + $cases = array(); + + $rand = mt_rand( 0, 2000000000 ) . time(); + $dest = wfTempDir() . "/randomfile!$rand.txt"; + $srcs = array( + $this->baseStorePath() . '/unittest-cont1/file1.txt', + $this->baseStorePath() . '/unittest-cont1/file2.txt', + $this->baseStorePath() . '/unittest-cont1/file3.txt', + $this->baseStorePath() . '/unittest-cont1/file4.txt', + $this->baseStorePath() . '/unittest-cont1/file5.txt', + $this->baseStorePath() . '/unittest-cont1/file6.txt', + $this->baseStorePath() . '/unittest-cont1/file7.txt', + $this->baseStorePath() . '/unittest-cont1/file8.txt', + $this->baseStorePath() . '/unittest-cont1/file9.txt', + $this->baseStorePath() . '/unittest-cont1/file10.txt' + ); + $content = array( + 'egfage', + 'ageageag', + 'rhokohlr', + 'shgmslkg', + 'kenga', + 'owagmal', + 'kgmae', + 'g eak;g', + 'lkaem;a', + 'legma' + ); + $params = array( 'srcs' => $srcs, 'dst' => $dest ); + + $cases[] = array( + $params, // operation + $srcs, // sources + $content, // content for each source + false, // no dest already exists + true, // succeeds + ); + + $cases[] = array( + $params, // operation + $srcs, // sources + $content, // content for each source + true, // dest already exists + false, // succeeds + ); + + return $cases; + } + + /** + * @dataProvider provider_testGetFileStat + */ + public function testGetFileStat( $path, $content, $alreadyExists ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestGetFileStat( $path, $content, $alreadyExists ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestGetFileStat( $path, $content, $alreadyExists ); + $this->tearDownFiles(); + } + + private function doTestGetFileStat( $path, $content, $alreadyExists ) { + $backendName = $this->backendClass(); + + if ( $alreadyExists ) { + $this->prepare( array( 'dir' => dirname( $path ) ) ); + $status = $this->backend->create( array( 'dst' => $path, 'content' => $content ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $path succeeded ($backendName)." ); + + $size = $this->backend->getFileSize( array( 'src' => $path ) ); + $time = $this->backend->getFileTimestamp( array( 'src' => $path ) ); + $stat = $this->backend->getFileStat( array( 'src' => $path ) ); + + $this->assertEquals( strlen( $content ), $size, + "Correct file size of '$path'" ); + $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 5, + "Correct file timestamp of '$path'" ); + + $size = $stat['size']; + $time = $stat['mtime']; + $this->assertEquals( strlen( $content ), $size, + "Correct file size of '$path'" ); + $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 5, + "Correct file timestamp of '$path'" ); + } else { + $size = $this->backend->getFileSize( array( 'src' => $path ) ); + $time = $this->backend->getFileTimestamp( array( 'src' => $path ) ); + $stat = $this->backend->getFileStat( array( 'src' => $path ) ); + + $this->assertFalse( $size, "Correct file size of '$path'" ); + $this->assertFalse( $time, "Correct file timestamp of '$path'" ); + $this->assertFalse( $stat, "Correct file stat of '$path'" ); + } + } + + function provider_testGetFileStat() { + $cases = array(); + + $base = $this->baseStorePath(); + $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents", true ); + $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "", true ); + $cases[] = array( "$base/unittest-cont1/b/some-diff_file.txt", null, false ); + + return $cases; + } + + /** + * @dataProvider provider_testGetFileContents + */ + public function testGetFileContents( $source, $content ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestGetFileContents( $source, $content ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestGetFileContents( $source, $content ); + $this->tearDownFiles(); + } + + public function doTestGetFileContents( $source, $content ) { + $backendName = $this->backendClass(); + + $this->prepare( array( 'dir' => dirname( $source ) ) ); + + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $source succeeded ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Creation of file at $source succeeded with OK status ($backendName)." ); + + $newContents = $this->backend->getFileContents( array( 'src' => $source, 'latest' => 1 ) ); + $this->assertNotEquals( false, $newContents, + "Read of file at $source succeeded ($backendName)." ); + + $this->assertEquals( $content, $newContents, + "Contents read match data at $source ($backendName)." ); + } + + function provider_testGetFileContents() { + $cases = array(); + + $base = $this->baseStorePath(); + $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents" ); + $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "more file contents" ); + + return $cases; + } + + /** + * @dataProvider provider_testGetLocalCopy + */ + public function testGetLocalCopy( $source, $content ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestGetLocalCopy( $source, $content ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestGetLocalCopy( $source, $content ); + $this->tearDownFiles(); + } + + public function doTestGetLocalCopy( $source, $content ) { + $backendName = $this->backendClass(); + + $this->prepare( array( 'dir' => dirname( $source ) ) ); + + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $source succeeded ($backendName)." ); + + $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) ); + $this->assertNotNull( $tmpFile, + "Creation of local copy of $source succeeded ($backendName)." ); + + $contents = file_get_contents( $tmpFile->getPath() ); + $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." ); + } + + function provider_testGetLocalCopy() { + $cases = array(); + + $base = $this->baseStorePath(); + $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" ); + $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" ); + + return $cases; + } + + /** + * @dataProvider provider_testGetLocalReference + */ + public function testGetLocalReference( $source, $content ) { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestGetLocalReference( $source, $content ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestGetLocalReference( $source, $content ); + $this->tearDownFiles(); + } + + private function doTestGetLocalReference( $source, $content ) { + $backendName = $this->backendClass(); + + $this->prepare( array( 'dir' => dirname( $source ) ) ); + + $status = $this->backend->doOperation( + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); + $this->assertEquals( array(), $status->errors, + "Creation of file at $source succeeded ($backendName)." ); + + $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) ); + $this->assertNotNull( $tmpFile, + "Creation of local copy of $source succeeded ($backendName)." ); + + $contents = file_get_contents( $tmpFile->getPath() ); + $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." ); + } + + function provider_testGetLocalReference() { + $cases = array(); + + $base = $this->baseStorePath(); + $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" ); + $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" ); + + return $cases; + } + + /** + * @dataProvider provider_testPrepareAndClean + */ + public function testPrepareAndClean( $path, $isOK ) { + $this->backend = $this->singleBackend; + $this->doTestPrepareAndClean( $path, $isOK ); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->doTestPrepareAndClean( $path, $isOK ); + $this->tearDownFiles(); + } + + function provider_testPrepareAndClean() { + $base = $this->baseStorePath(); + return array( + array( "$base/unittest-cont1/a/z/some_file1.txt", true ), + array( "$base/unittest-cont2/a/z/some_file2.txt", true ), + # Specific to FS backend with no basePath field set + #array( "$base/unittest-cont3/a/z/some_file3.txt", false ), + ); + } + + function doTestPrepareAndClean( $path, $isOK ) { + $backendName = $this->backendClass(); + + $status = $this->prepare( array( 'dir' => dirname( $path ) ) ); + if ( $isOK ) { + $this->assertEquals( array(), $status->errors, + "Preparing dir $path succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Preparing dir $path succeeded ($backendName)." ); + } else { + $this->assertEquals( false, $status->isOK(), + "Preparing dir $path failed ($backendName)." ); + } + + $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) ); + if ( $isOK ) { + $this->assertEquals( array(), $status->errors, + "Cleaning dir $path succeeded without warnings ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Cleaning dir $path succeeded ($backendName)." ); + } else { + $this->assertEquals( false, $status->isOK(), + "Cleaning dir $path failed ($backendName)." ); + } + } + + // @TODO: testSecure + + public function testDoOperations() { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestDoOperations(); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestDoOperations(); + $this->tearDownFiles(); + + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestDoOperationsFailing(); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestDoOperationsFailing(); + $this->tearDownFiles(); + + // @TODO: test some cases where the ops should fail + } + + function doTestDoOperations() { + $base = $this->baseStorePath(); + + $fileA = "$base/unittest-cont1/a/b/fileA.txt"; + $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq'; + $fileB = "$base/unittest-cont1/a/b/fileB.txt"; + $fileBContents = 'g-jmq3gpqgt3qtg q3GT '; + $fileC = "$base/unittest-cont1/a/b/fileC.txt"; + $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag'; + $fileD = "$base/unittest-cont1/a/b/fileD.txt"; + + $this->prepare( array( 'dir' => dirname( $fileA ) ) ); + $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) ); + $this->prepare( array( 'dir' => dirname( $fileB ) ) ); + $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) ); + $this->prepare( array( 'dir' => dirname( $fileC ) ) ); + $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) ); + + $status = $this->backend->doOperations( array( + array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ), + // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>) + array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ), + // Now: A:<A>, B:<B>, C:<A>, D:<empty> + array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ), + // Now: A:<A>, B:<B>, C:<empty>, D:<A> + array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ), + // Now: A:<A>, B:<empty>, C:<B>, D:<A> + array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ), + // Now: A:<A>, B:<empty>, C:<B>, D:<empty> + array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ), + // Now: A:<B>, B:<empty>, C:<empty>, D:<empty> + array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ), + // Now: A:<B>, B:<empty>, C:<B>, D:<empty> + array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ), + // Now: A:<empty>, B:<empty>, C:<B>, D:<empty> + array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ), + // Does nothing + array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ), + // Does nothing + array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ), + // Does nothing + array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ), + // Does nothing + array( 'op' => 'null' ), + // Does nothing + ) ); + + $this->assertEquals( array(), $status->errors, "Operation batch succeeded" ); + $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" ); + $this->assertEquals( 13, count( $status->success ), + "Operation batch has correct success array" ); + + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ), + "File does not exist at $fileA" ); + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ), + "File does not exist at $fileB" ); + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ), + "File does not exist at $fileD" ); + + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ), + "File exists at $fileC" ); + $this->assertEquals( $fileBContents, + $this->backend->getFileContents( array( 'src' => $fileC ) ), + "Correct file contents of $fileC" ); + $this->assertEquals( strlen( $fileBContents ), + $this->backend->getFileSize( array( 'src' => $fileC ) ), + "Correct file size of $fileC" ); + $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ), + $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ), + "Correct file SHA-1 of $fileC" ); + } + + function doTestDoOperationsFailing() { + $base = $this->baseStorePath(); + + $fileA = "$base/unittest-cont2/a/b/fileA.txt"; + $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq'; + $fileB = "$base/unittest-cont2/a/b/fileB.txt"; + $fileBContents = 'g-jmq3gpqgt3qtg q3GT '; + $fileC = "$base/unittest-cont2/a/b/fileC.txt"; + $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag'; + $fileD = "$base/unittest-cont2/a/b/fileD.txt"; + + $this->prepare( array( 'dir' => dirname( $fileA ) ) ); + $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) ); + $this->prepare( array( 'dir' => dirname( $fileB ) ) ); + $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) ); + $this->prepare( array( 'dir' => dirname( $fileC ) ) ); + $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) ); + + $status = $this->backend->doOperations( array( + array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ), + // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>) + array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ), + // Now: A:<A>, B:<B>, C:<A>, D:<empty> + array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ), + // Now: A:<A>, B:<B>, C:<A>, D:<B> + array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ), + // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed) + array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ), + // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed) + array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ), + // Now: A:<B>, B:<empty>, C:<A>, D:<empty> + array( 'op' => 'delete', 'src' => $fileD ), + // Now: A:<B>, B:<empty>, C:<A>, D:<empty> + array( 'op' => 'null' ), + // Does nothing + ), array( 'force' => 1 ) ); + + $this->assertNotEquals( array(), $status->errors, "Operation had warnings" ); + $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" ); + $this->assertEquals( 8, count( $status->success ), + "Operation batch has correct success array" ); + + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ), + "File does not exist at $fileB" ); + $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ), + "File does not exist at $fileD" ); + + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ), + "File does not exist at $fileA" ); + $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ), + "File exists at $fileC" ); + $this->assertEquals( $fileBContents, + $this->backend->getFileContents( array( 'src' => $fileA ) ), + "Correct file contents of $fileA" ); + $this->assertEquals( strlen( $fileBContents ), + $this->backend->getFileSize( array( 'src' => $fileA ) ), + "Correct file size of $fileA" ); + $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ), + $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ), + "Correct file SHA-1 of $fileA" ); + } + + public function testGetFileList() { + $this->backend = $this->singleBackend; + $this->tearDownFiles(); + $this->doTestGetFileList(); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->tearDownFiles(); + $this->doTestGetFileList(); + $this->tearDownFiles(); + } + + private function doTestGetFileList() { + $backendName = $this->backendClass(); + + $base = $this->baseStorePath(); + $files = array( + "$base/unittest-cont1/test1.txt", + "$base/unittest-cont1/test2.txt", + "$base/unittest-cont1/test3.txt", + "$base/unittest-cont1/subdir1/test1.txt", + "$base/unittest-cont1/subdir1/test2.txt", + "$base/unittest-cont1/subdir2/test3.txt", + "$base/unittest-cont1/subdir2/test4.txt", + "$base/unittest-cont1/subdir2/subdir/test1.txt", + "$base/unittest-cont1/subdir2/subdir/test2.txt", + "$base/unittest-cont1/subdir2/subdir/test3.txt", + "$base/unittest-cont1/subdir2/subdir/test4.txt", + "$base/unittest-cont1/subdir2/subdir/test5.txt", + "$base/unittest-cont1/subdir2/subdir/sub/test0.txt", + "$base/unittest-cont1/subdir2/subdir/sub/120-px-file.txt", + ); + + // Add the files + $ops = array(); + foreach ( $files as $file ) { + $this->prepare( array( 'dir' => dirname( $file ) ) ); + $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file ); + } + $status = $this->backend->doOperations( $ops ); + $this->assertEquals( array(), $status->errors, + "Creation of files succeeded ($backendName)." ); + $this->assertEquals( true, $status->isOK(), + "Creation of files succeeded with OK status ($backendName)." ); + + // Expected listing + $expected = array( + "test1.txt", + "test2.txt", + "test3.txt", + "subdir1/test1.txt", + "subdir1/test2.txt", + "subdir2/test3.txt", + "subdir2/test4.txt", + "subdir2/subdir/test1.txt", + "subdir2/subdir/test2.txt", + "subdir2/subdir/test3.txt", + "subdir2/subdir/test4.txt", + "subdir2/subdir/test5.txt", + "subdir2/subdir/sub/test0.txt", + "subdir2/subdir/sub/120-px-file.txt", + ); + sort( $expected ); + + // Actual listing (no trailing slash) + $list = array(); + $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) ); + foreach ( $iter as $file ) { + $list[] = $file; + } + sort( $list ); + + $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); + + // Actual listing (with trailing slash) + $list = array(); + $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) ); + foreach ( $iter as $file ) { + $list[] = $file; + } + sort( $list ); + + $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); + + // Expected listing + $expected = array( + "test1.txt", + "test2.txt", + "test3.txt", + "test4.txt", + "test5.txt", + "sub/test0.txt", + "sub/120-px-file.txt", + ); + sort( $expected ); + + // Actual listing (no trailing slash) + $list = array(); + $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) ); + foreach ( $iter as $file ) { + $list[] = $file; + } + sort( $list ); + + $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); + + // Actual listing (with trailing slash) + $list = array(); + $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir/" ) ); + foreach ( $iter as $file ) { + $list[] = $file; + } + sort( $list ); + + $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); + + // Actual listing (using iterator second time) + $list = array(); + foreach ( $iter as $file ) { + $list[] = $file; + } + sort( $list ); + + $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." ); + + foreach ( $files as $file ) { // clean up + $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) ); + } + + $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) ); + foreach ( $iter as $iter ) {} // no errors + } + + // test helper wrapper for backend prepare() function + private function prepare( array $params ) { + $this->dirsToPrune[] = $params['dir']; + return $this->backend->prepare( $params ); + } + + function tearDownFiles() { + foreach ( $this->filesToPrune as $file ) { + @unlink( $file ); + } + $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' ); + foreach ( $containers as $container ) { + $this->deleteFiles( $container ); + } + foreach ( $this->dirsToPrune as $dir ) { + $this->recursiveClean( $dir ); + } + $this->filesToPrune = $this->dirsToPrune = array(); + } + + private function deleteFiles( $container ) { + $base = $this->baseStorePath(); + $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) ); + if ( $iter ) { + foreach ( $iter as $file ) { + $this->backend->delete( array( 'src' => "$base/$container/$file" ), array( 'force' => 1 ) ); + } + } + } + + private function recursiveClean( $dir ) { + do { + if ( !$this->backend->clean( array( 'dir' => $dir ) )->isOK() ) { + break; + } + } while ( $dir = FileBackend::parentStoragePath( $dir ) ); + } + + function tearDown() { + parent::tearDown(); + } +} diff --git a/tests/phpunit/includes/filerepo/FileRepoTest.php b/tests/phpunit/includes/filerepo/FileRepoTest.php new file mode 100644 index 00000000..0f023138 --- /dev/null +++ b/tests/phpunit/includes/filerepo/FileRepoTest.php @@ -0,0 +1,41 @@ +<?php + +class FileRepoTest extends MediaWikiTestCase { + + /** + * @expectedException MWException + */ + function testFileRepoConstructionOptionCanNotBeNull() { + $f = new FileRepo(); + } + /** + * @expectedException MWException + */ + function testFileRepoConstructionOptionCanNotBeAnEmptyArray() { + $f = new FileRepo( array() ); + } + /** + * @expectedException MWException + */ + function testFileRepoConstructionOptionNeedNameKey() { + $f = new FileRepo( array( + 'backend' => 'foobar' + ) ); + } + /** + * @expectedException MWException + */ + function testFileRepoConstructionOptionNeedBackendKey() { + $f = new FileRepo( array( + 'name' => 'foobar' + ) ); + } + + function testFileRepoConstructionWithRequiredOptions() { + $f = new FileRepo( array( + 'name' => 'FileRepoTestRepository', + 'backend' => 'local-backend', + )); + $this->assertInstanceOf( 'FileRepo', $f ); + } +} diff --git a/tests/phpunit/includes/filerepo/StoreBatchTest.php b/tests/phpunit/includes/filerepo/StoreBatchTest.php new file mode 100644 index 00000000..6abceeb3 --- /dev/null +++ b/tests/phpunit/includes/filerepo/StoreBatchTest.php @@ -0,0 +1,122 @@ +<?php +/** + * @group FileRepo + */ +class StoreBatchTest extends MediaWikiTestCase { + + public function setUp() { + global $wgFileBackends; + parent::setUp(); + + # Forge a FSRepo object to not have to rely on local wiki settings + $tmpPrefix = wfTempDir() . '/storebatch-test-' . time() . '-' . mt_rand(); + if ( $this->getCliArg( 'use-filebackend=' ) ) { + $name = $this->getCliArg( 'use-filebackend=' ); + $useConfig = array(); + foreach ( $wgFileBackends as $conf ) { + if ( $conf['name'] == $name ) { + $useConfig = $conf; + } + } + $useConfig['name'] = 'local-testing'; // swap name + $class = $useConfig['class']; + $backend = new $class( $useConfig ); + } else { + $backend = new FSFileBackend( array( + 'name' => 'local-testing', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( + 'unittests-public' => "{$tmpPrefix}-public", + 'unittests-thumb' => "{$tmpPrefix}-thumb", + 'unittests-temp' => "{$tmpPrefix}-temp", + 'unittests-deleted' => "{$tmpPrefix}-deleted", + ) + ) ); + } + $this->repo = new FileRepo( array( + 'name' => 'unittests', + 'backend' => $backend + ) ); + + $this->date = gmdate( "YmdHis" ); + $this->createdFiles = array(); + } + + /** + * Store a file or virtual URL source into a media file name. + * + * @param $originalName string The title of the image + * @param $srcPath string The filepath or virtual URL + * @param $flags integer Flags to pass into repo::store(). + */ + private function storeit($originalName, $srcPath, $flags) { + $hashPath = $this->repo->getHashPath( $originalName ); + $dstRel = "$hashPath{$this->date}!$originalName"; + $dstUrlRel = $hashPath . $this->date . '!' . rawurlencode( $originalName ); + + $result = $this->repo->store( $srcPath, 'temp', $dstRel, $flags ); + $result->value = $this->repo->getVirtualUrl( 'temp' ) . '/' . $dstUrlRel; + $this->createdFiles[] = $result->value; + return $result; + } + + /** + * Test storing a file using different flags. + * + * @param $fn string The title of the image + * @param $infn string The name of the file (in the filesystem) + * @param $otherfn string The name of the different file (in the filesystem) + * @param $fromrepo logical 'true' if we want to copy from a virtual URL out of the Repo. + */ + private function storecohort($fn, $infn, $otherfn, $fromrepo) { + $f = $this->storeit( $fn, $infn, 0 ); + $this->assertTrue( $f->isOK(), 'failed to store a new file' ); + $this->assertEquals( $f->failCount, 0, "counts wrong {$f->successCount} {$f->failCount}" ); + $this->assertEquals( $f->successCount, 1 , "counts wrong {$f->successCount} {$f->failCount}" ); + if ( $fromrepo ) { + $f = $this->storeit( "Other-$fn", $infn, FileRepo::OVERWRITE); + $infn = $f->value; + } + // This should work because we're allowed to overwrite + $f = $this->storeit( $fn, $infn, FileRepo::OVERWRITE ); + $this->assertTrue( $f->isOK(), 'We should be allowed to overwrite' ); + $this->assertEquals( $f->failCount, 0, "counts wrong {$f->successCount} {$f->failCount}" ); + $this->assertEquals( $f->successCount, 1 , "counts wrong {$f->successCount} {$f->failCount}" ); + // This should fail because we're overwriting. + $f = $this->storeit( $fn, $infn, 0 ); + $this->assertFalse( $f->isOK(), 'We should not be allowed to overwrite' ); + $this->assertEquals( $f->failCount, 1, "counts wrong {$f->successCount} {$f->failCount}" ); + $this->assertEquals( $f->successCount, 0 , "counts wrong {$f->successCount} {$f->failCount}" ); + // This should succeed because we're overwriting the same content. + $f = $this->storeit( $fn, $infn, FileRepo::OVERWRITE_SAME ); + $this->assertTrue( $f->isOK(), 'We should be able to overwrite the same content' ); + $this->assertEquals( $f->failCount, 0, "counts wrong {$f->successCount} {$f->failCount}" ); + $this->assertEquals( $f->successCount, 1 , "counts wrong {$f->successCount} {$f->failCount}" ); + // This should fail because we're overwriting different content. + if ( $fromrepo ) { + $f = $this->storeit( "Other-$fn", $otherfn, FileRepo::OVERWRITE); + $otherfn = $f->value; + } + $f = $this->storeit( $fn, $otherfn, FileRepo::OVERWRITE_SAME ); + $this->assertFalse( $f->isOK(), 'We should not be allowed to overwrite different content' ); + $this->assertEquals( $f->failCount, 1, "counts wrong {$f->successCount} {$f->failCount}" ); + $this->assertEquals( $f->successCount, 0 , "counts wrong {$f->successCount} {$f->failCount}" ); + } + + public function teststore() { + global $IP; + $this->storecohort( "Test1.png", "$IP/skins/monobook/wiki.png", "$IP/skins/monobook/video.png", false ); + $this->storecohort( "Test2.png", "$IP/skins/monobook/wiki.png", "$IP/skins/monobook/video.png", true ); + } + + public function tearDown() { + $this->repo->cleanupBatch( $this->createdFiles ); // delete files + foreach ( $this->createdFiles as $tmp ) { // delete dirs + $tmp = $this->repo->resolveVirtualUrl( $tmp ); + while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) { + $this->repo->getBackend()->clean( array( 'dir' => $tmp ) ); + } + } + parent::tearDown(); + } +} diff --git a/tests/phpunit/includes/json/ServicesJsonTest.php b/tests/phpunit/includes/json/ServicesJsonTest.php new file mode 100644 index 00000000..8f2421a2 --- /dev/null +++ b/tests/phpunit/includes/json/ServicesJsonTest.php @@ -0,0 +1,93 @@ +<?php +/* + * Test cases for our Services_Json library. Requires PHP json support as well, + * so we can compare output + */ +class ServicesJsonTest extends MediaWikiTestCase { + /** + * Test to make sure core json_encode() and our Services_Json()->encode() + * produce the same output + * + * @dataProvider provideValuesToEncode + */ + public function testJsonEncode( $input, $desc ) { + if ( !function_exists( 'json_encode' ) ) { + $this->markTestIncomplete( 'No PHP json support, unable to test' ); + return; + } elseif( strtolower( json_encode( "\xf0\xa0\x80\x80" ) ) != '"\ud840\udc00"' ) { + $this->markTestIncomplete( 'Have buggy PHP json support, unable to test' ); + return; + } else { + $jsonObj = new Services_JSON(); + $this->assertEquals( + $jsonObj->encode( $input ), + json_encode( $input ), + $desc + ); + } + } + + /** + * Test to make sure core json_decode() and our Services_Json()->decode() + * produce the same output + * + * @dataProvider provideValuesToDecode + */ + public function testJsonDecode( $input, $desc ) { + if ( !function_exists( 'json_decode' ) ) { + $this->markTestIncomplete( 'No PHP json support, unable to test' ); + return; + } else { + $jsonObj = new Services_JSON(); + $this->assertEquals( + $jsonObj->decode( $input ), + json_decode( $input ), + $desc + ); + } + } + + function provideValuesToEncode() { + $obj = new stdClass(); + $obj->property = 'value'; + $obj->property2 = null; + $obj->property3 = 1.234; + return array( + array( 1, 'basic integer' ), + array( -1, 'negative integer' ), + array( 1.1, 'basic float' ), + array( true, 'basic bool true' ), + array( false, 'basic bool false' ), + array( 'some string', 'basic string test' ), + array( "some string\nwith newline", 'newline string test' ), + array( '♥ü', 'unicode string test' ), + array( array( 'some', 'string', 'values' ), 'basic array of strings' ), + array( array( 'key1' => 'val1', 'key2' => 'val2' ), 'array with string keys' ), + array( array( 1 => 'val1', 3 => 'val2', '2' => 'val3' ), 'out of order numbered array test' ), + array( array(), 'empty array test' ), + array( $obj, 'basic object test' ), + array( new stdClass, 'empty object test' ), + array( null, 'null test' ), + ); + } + + function provideValuesToDecode() { + return array( + array( '1', 'basic integer' ), + array( '-1', 'negative integer' ), + array( '1.1', 'basic float' ), + array( '1.1e1', 'scientific float' ), + array( 'true', 'basic bool true' ), + array( 'false', 'basic bool false' ), + array( '"some string"', 'basic string test' ), + array( '"some string\nwith newline"', 'newline string test' ), + array( '"♥ü"', 'unicode character string test' ), + array( '"\u2665"', 'unicode \\u string test' ), + array( '["some","string","values"]', 'basic array of strings' ), + array( '[]', 'empty array test' ), + array( '{"key":"value"}', 'Basic key => value test' ), + array( '{}', 'empty object test' ), + array( 'null', 'null test' ), + ); + } +} diff --git a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php index aa05500e..d2bfeedf 100644 --- a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php +++ b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php @@ -84,6 +84,13 @@ class JavaScriptMinifierTest extends MediaWikiTestCase { // And also per spec unicode char escape values should work in identifiers, // as long as it's a valid char. In future it might get normalized. array( "var Ka\\u015dSkatolVal = {}", 'var Ka\\u015dSkatolVal={}'), + + /* Some structures that might look invalid at first sight */ + array( "var a = 5.;", "var a=5.;" ), + array( "5.0.toString();", "5.0.toString();" ), + array( "5..toString();", "5..toString();" ), + array( "5...toString();", false ), + array( "5.\n.toString();", '5..toString();' ), ); } @@ -102,4 +109,40 @@ class JavaScriptMinifierTest extends MediaWikiTestCase { $this->assertEquals( $expectedOutput, $minified, "Minified output should be in the form expected." ); } + + /** + * @dataProvider provideBug32548 + */ + function testBug32548Exponent($num) { + // Long line breaking was being incorrectly done between the base and + // exponent part of a number, causing a syntax error. The line should + // instead break at the start of the number. + $prefix = 'var longVarName' . str_repeat('_', 973) . '='; + $suffix = ',shortVarName=0;'; + + $input = $prefix . $num . $suffix; + $expected = $prefix . "\n" . $num . $suffix; + + $minified = JavaScriptMinifier::minify( $input ); + + $this->assertEquals( $expected, $minified, "Line breaks must not occur in middle of exponent"); + } + + function provideBug32548() { + return array( + array( + // This one gets interpreted all together by the prior code; + // no break at the 'E' happens. + '1.23456789E55', + ), + array( + // This one breaks under the bad code; splits between 'E' and '+' + '1.23456789E+5', + ), + array( + // This one breaks under the bad code; splits between 'E' and '-' + '1.23456789E-5', + ), + ); + } } diff --git a/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php b/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php index a0d5cd86..f4f52dd8 100644 --- a/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php +++ b/tests/phpunit/includes/media/BitmapMetadataHandlerTest.php @@ -14,10 +14,15 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase { * translation (to en) where XMP should win. */ public function testMultilingualCascade() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); + if ( !wfDl( 'exif' ) ) { + $this->markTestSkipped( "This test needs the exif extension." ); + } + if ( !wfDl( 'xml' ) ) { + $this->markTestSkipped( "This test needs the xml extension." ); } + global $wgShowEXIF; + $oldExif = $wgShowEXIF; + $wgShowEXIF = true; $meta = BitmapMetadataHandler::Jpeg( $this->filePath . '/Xmp-exif-multilingual_test.jpg' ); @@ -32,6 +37,8 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase { 'Did not extract any ImageDescription info?!' ); $this->assertEquals( $expected, $meta['ImageDescription'] ); + + $wgShowEXIF = $oldExif; } /** @@ -49,6 +56,16 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase { $meta['JPEGFileComment'][0] ); } + /** + * Make sure a bad iptc block doesn't stop the other metadata + * from being extracted. + */ + public function testBadIPTC() { + $meta = BitmapMetadataHandler::Jpeg( $this->filePath . + 'iptc-invalid-psir.jpg' ); + $this->assertEquals( 'Created with GIMP', $meta['JPEGFileComment'][0] ); + } + public function testIPTCDates() { $meta = BitmapMetadataHandler::Jpeg( $this->filePath . 'iptc-timetest.jpg' ); @@ -95,6 +112,9 @@ class BitmapMetadataHandlerTest extends MediaWikiTestCase { } public function testPNGXMP() { + if ( !wfDl( 'xml' ) ) { + $this->markTestSkipped( "This test needs the xml extension." ); + } $handler = new BitmapMetadataHandler(); $result = $handler->png( $this->filePath . 'xmp.png' ); $expected = array ( diff --git a/tests/phpunit/includes/media/BitmapScalingTest.php b/tests/phpunit/includes/media/BitmapScalingTest.php index 5bcd3232..11d9dc47 100644 --- a/tests/phpunit/includes/media/BitmapScalingTest.php +++ b/tests/phpunit/includes/media/BitmapScalingTest.php @@ -3,13 +3,16 @@ class BitmapScalingTest extends MediaWikiTestCase { function setUp() { - global $wgMaxImageArea; + global $wgMaxImageArea, $wgCustomConvertCommand; $this->oldMaxImageArea = $wgMaxImageArea; + $this->oldCustomConvertCommand = $wgCustomConvertCommand; $wgMaxImageArea = 1.25e7; // 3500x3500 + $wgCustomConvertCommand = 'dummy'; // Set so that we don't get client side rendering } function tearDown() { - global $wgMaxImageArea; + global $wgMaxImageArea, $wgCustomConvertCommand; $wgMaxImageArea = $this->oldMaxImageArea; + $wgCustomConvertCommand = $this->oldCustomConvertCommand; } /** * @dataProvider provideNormaliseParams @@ -105,14 +108,22 @@ class BitmapScalingTest extends MediaWikiTestCase { $file = new FakeDimensionFile( array( 4000, 4000 ) ); $handler = new BitmapHandler; $params = array( 'width' => '3700' ); // Still bigger than max size. - $this->assertFalse( $handler->normaliseParams( $file, $params ) ); + $this->assertEquals( 'TransformParameterError', + get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); } function testTooBigMustRenderImage() { $file = new FakeDimensionFile( array( 4000, 4000 ) ); $file->mustRender = true; $handler = new BitmapHandler; $params = array( 'width' => '5000' ); // Still bigger than max size. - $this->assertFalse( $handler->normaliseParams( $file, $params ) ); + $this->assertEquals( 'TransformParameterError', + get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); + } + + function testImageArea() { + $file = new FakeDimensionFile( array( 7, 9 ) ); + $handler = new BitmapHandler; + $this->assertEquals( 63, $handler->getImageArea( $file ) ); } } @@ -120,7 +131,8 @@ class FakeDimensionFile extends File { public $mustRender = false; public function __construct( $dimensions ) { - parent::__construct( Title::makeTitle( NS_FILE, 'Test' ), null ); + parent::__construct( Title::makeTitle( NS_FILE, 'Test' ), + new NullRepo( null ) ); $this->dimensions = $dimensions; } @@ -133,4 +145,7 @@ class FakeDimensionFile extends File { public function mustRender() { return $this->mustRender; } + public function getPath() { + return ''; + } } diff --git a/tests/phpunit/includes/media/ExifBitmapTest.php b/tests/phpunit/includes/media/ExifBitmapTest.php index 4282d3c8..b2f6b7ba 100644 --- a/tests/phpunit/includes/media/ExifBitmapTest.php +++ b/tests/phpunit/includes/media/ExifBitmapTest.php @@ -1,4 +1,5 @@ <?php + class ExifBitmapTest extends MediaWikiTestCase { public function setUp() { @@ -17,42 +18,23 @@ class ExifBitmapTest extends MediaWikiTestCase { } public function testIsOldBroken() { - if ( !wfDl( 'exif' ) ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $res = $this->handler->isMetadataValid( null, ExifBitmapHandler::OLD_BROKEN_FILE ); $this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res ); } public function testIsBrokenFile() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $res = $this->handler->isMetadataValid( null, ExifBitmapHandler::BROKEN_FILE ); $this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res ); } public function testIsInvalid() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $res = $this->handler->isMetadataValid( null, 'Something Invalid Here.' ); $this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res ); } public function testGoodMetadata() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}'; $res = $this->handler->isMetadataValid( null, $meta ); $this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res ); } public function testIsOldGood() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}'; $res = $this->handler->isMetadataValid( null, $meta ); $this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res ); @@ -60,10 +42,6 @@ class ExifBitmapTest extends MediaWikiTestCase { // Handle metadata from paged tiff handler (gotten via instant commons) // gracefully. public function testPagedTiffHandledGracefully() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $meta = 'a:6:{s:9:"page_data";a:1:{i:1;a:5:{s:5:"width";i:643;s:6:"height";i:448;s:5:"alpha";s:4:"true";s:4:"page";i:1;s:6:"pixels";i:288064;}}s:10:"page_count";i:1;s:10:"first_page";i:1;s:9:"last_page";i:1;s:4:"exif";a:9:{s:10:"ImageWidth";i:643;s:11:"ImageLength";i:448;s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:4;s:12:"RowsPerStrip";i:50;s:19:"PlanarConfiguration";i:1;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}s:21:"TIFF_METADATA_VERSION";s:3:"1.4";}'; $res = $this->handler->isMetadataValid( null, $meta ); $this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res ); diff --git a/tests/phpunit/includes/media/ExifRotationTest.php b/tests/phpunit/includes/media/ExifRotationTest.php index 639091d0..25149a05 100644 --- a/tests/phpunit/includes/media/ExifRotationTest.php +++ b/tests/phpunit/includes/media/ExifRotationTest.php @@ -5,15 +5,26 @@ */ class ExifRotationTest extends MediaWikiTestCase { + /** track directories creations. Content will be deleted. */ + private $createdDirs = array(); + function setUp() { parent::setUp(); - $this->filePath = dirname( __FILE__ ) . '/../../data/media/'; $this->handler = new BitmapHandler(); - $this->repo = new FSRepo(array( - 'name' => 'temp', - 'directory' => wfTempDir() . '/exif-test-' . time() . '-' . mt_rand(), - 'url' => 'http://localhost/thumbtest' - )); + $filePath = dirname( __FILE__ ) . '/../../data/media'; + + $tmpDir = wfTempDir() . '/exif-test-' . time() . '-' . mt_rand(); + $this->createdDirs[] = $tmpDir; + + $this->repo = new FSRepo( array( + 'name' => 'temp', + 'url' => 'http://localhost/thumbtest', + 'backend' => new FSFileBackend( array( + 'name' => 'localtesting', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( 'temp-thumb' => $tmpDir, 'data' => $filePath ) + ) ) + ) ); if ( !wfDl( 'exif' ) ) { $this->markTestSkipped( "This test needs the exif extension." ); } @@ -25,10 +36,23 @@ class ExifRotationTest extends MediaWikiTestCase { $this->oldAuto = $wgEnableAutoRotation; $wgEnableAutoRotation = true; } + public function tearDown() { global $wgShowEXIF, $wgEnableAutoRotation; $wgShowEXIF = $this->show; $wgEnableAutoRotation = $this->oldAuto; + + $this->tearDownFiles(); + } + + private function tearDownFiles() { + foreach( $this->createdDirs as $dir ) { + wfRecursiveRemoveDir( $dir ); + } + } + + function __destruct() { + $this->tearDownFiles(); } /** @@ -39,7 +63,7 @@ class ExifRotationTest extends MediaWikiTestCase { if ( !BitmapHandler::canRotate() ) { $this->markTestSkipped( "This test needs a rasterizer that can auto-rotate." ); } - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $name, $type ); + $file = $this->dataFile( $name, $type ); $this->assertEquals( $info['width'], $file->getWidth(), "$name: width check" ); $this->assertEquals( $info['height'], $file->getHeight(), "$name: height check" ); } @@ -66,13 +90,13 @@ class ExifRotationTest extends MediaWikiTestCase { throw new MWException('bogus test data format ' . $size); } - $file = $this->localFile( $name, $type ); - $thumb = $file->transform( $params, File::RENDER_NOW ); + $file = $this->dataFile( $name, $type ); + $thumb = $file->transform( $params, File::RENDER_NOW | File::RENDER_FORCE ); $this->assertEquals( $out[0], $thumb->getWidth(), "$name: thumb reported width check for $size" ); $this->assertEquals( $out[1], $thumb->getHeight(), "$name: thumb reported height check for $size" ); - $gis = getimagesize( $thumb->getPath() ); + $gis = getimagesize( $thumb->getLocalCopyPath() ); if ($out[0] > $info['width']) { // Physical image won't be scaled bigger than the original. $this->assertEquals( $info['width'], $gis[0], "$name: thumb actual width check for $size"); @@ -84,8 +108,9 @@ class ExifRotationTest extends MediaWikiTestCase { } } - private function localFile( $name, $type ) { - return new UnregisteredLocalFile( false, $this->repo, $this->filePath . $name, $type ); + private function dataFile( $name, $type ) { + return new UnregisteredLocalFile( false, $this->repo, + "mwstore://localtesting/data/$name", $type ); } function providerFiles() { @@ -129,7 +154,7 @@ class ExifRotationTest extends MediaWikiTestCase { global $wgEnableAutoRotation; $wgEnableAutoRotation = false; - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $name, $type ); + $file = $this->dataFile( $name, $type ); $this->assertEquals( $info['width'], $file->getWidth(), "$name: width check" ); $this->assertEquals( $info['height'], $file->getHeight(), "$name: height check" ); @@ -158,13 +183,13 @@ class ExifRotationTest extends MediaWikiTestCase { throw new MWException('bogus test data format ' . $size); } - $file = $this->localFile( $name, $type ); - $thumb = $file->transform( $params, File::RENDER_NOW ); + $file = $this->dataFile( $name, $type ); + $thumb = $file->transform( $params, File::RENDER_NOW | File::RENDER_FORCE ); $this->assertEquals( $out[0], $thumb->getWidth(), "$name: thumb reported width check for $size" ); $this->assertEquals( $out[1], $thumb->getHeight(), "$name: thumb reported height check for $size" ); - $gis = getimagesize( $thumb->getPath() ); + $gis = getimagesize( $thumb->getLocalCopyPath() ); if ($out[0] > $info['width']) { // Physical image won't be scaled bigger than the original. $this->assertEquals( $info['width'], $gis[0], "$name: thumb actual width check for $size"); @@ -242,7 +267,7 @@ class ExifRotationTest extends MediaWikiTestCase { array( 270, array( self::TEST_HEIGHT, self::TEST_WIDTH ) - ), + ), ); } } diff --git a/tests/phpunit/includes/media/ExifTest.php b/tests/phpunit/includes/media/ExifTest.php index 9b490e92..b39c15e4 100644 --- a/tests/phpunit/includes/media/ExifTest.php +++ b/tests/phpunit/includes/media/ExifTest.php @@ -4,6 +4,9 @@ class ExifTest extends MediaWikiTestCase { public function setUp() { $this->mediaPath = dirname( __FILE__ ) . '/../../data/media/'; + if ( !wfDl( 'exif' ) ) { + $this->markTestSkipped( "This test needs the exif extension." ); + } global $wgShowEXIF; $this->showExif = $wgShowEXIF; $wgShowEXIF = true; @@ -14,9 +17,6 @@ class ExifTest extends MediaWikiTestCase { } public function testGPSExtraction() { - if ( !wfDl( 'exif' ) ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $filename = $this->mediaPath . 'exif-gps.jpg'; $seg = JpegMetadataExtractor::segmentSplitter( $filename ); @@ -32,9 +32,6 @@ class ExifTest extends MediaWikiTestCase { $this->assertEquals( $expected, $data, '', 0.0000000001 ); } public function testUnicodeUserComment() { - if ( !wfDl( 'exif' ) ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $filename = $this->mediaPath . 'exif-user-comment.jpg'; $seg = JpegMetadataExtractor::segmentSplitter( $filename ); diff --git a/tests/phpunit/includes/media/FormatMetadataTest.php b/tests/phpunit/includes/media/FormatMetadataTest.php index db36dea3..8a632f52 100644 --- a/tests/phpunit/includes/media/FormatMetadataTest.php +++ b/tests/phpunit/includes/media/FormatMetadataTest.php @@ -1,13 +1,31 @@ <?php class FormatMetadataTest extends MediaWikiTestCase { - public function testInvalidDate() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); + public function setUp() { + if ( !wfDl( 'exif' ) ) { + $this->markTestSkipped( "This test needs the exif extension." ); } - - $file = UnregisteredLocalFile::newFromPath( dirname( __FILE__ ) . - '/../../data/media/broken_exif_date.jpg', 'image/jpeg' ); + $filePath = dirname( __FILE__ ) . '/../../data/media'; + $this->backend = new FSFileBackend( array( + 'name' => 'localtesting', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( 'data' => $filePath ) + ) ); + $this->repo = new FSRepo( array( + 'name' => 'temp', + 'url' => 'http://localhost/thumbtest', + 'backend' => $this->backend + ) ); + global $wgShowEXIF; + $this->show = $wgShowEXIF; + $wgShowEXIF = true; + } + public function tearDown() { + global $wgShowEXIF; + $wgShowEXIF = $this->show; + } + + public function testInvalidDate() { + $file = $this->dataFile( 'broken_exif_date.jpg', 'image/jpeg' ); // Throws an error if bug hit $meta = $file->formatMetadata(); @@ -26,4 +44,9 @@ class FormatMetadataTest extends MediaWikiTestCase { $meta['visible'][$dateIndex]['value'], 'File with invalid date metadata (bug 29471)' ); } -}
\ No newline at end of file + + private function dataFile( $name, $type ) { + return new UnregisteredLocalFile( false, $this->repo, + "mwstore://localtesting/data/$name", $type ); + } +} diff --git a/tests/phpunit/includes/media/GIFMetadataExtractorTest.php b/tests/phpunit/includes/media/GIFMetadataExtractorTest.php index 59b30441..47fc368b 100644 --- a/tests/phpunit/includes/media/GIFMetadataExtractorTest.php +++ b/tests/phpunit/includes/media/GIFMetadataExtractorTest.php @@ -63,6 +63,7 @@ class GIFMetadataExtractorTest extends MediaWikiTestCase { <?xpacket end='w'?> EOF; + $xmpNugget = str_replace( "\r", '', $xmpNugget ); // Windows compat return array( array( 'nonanimated.gif', array( diff --git a/tests/phpunit/includes/media/GIFTest.php b/tests/phpunit/includes/media/GIFTest.php index 42c25ca5..36658358 100644 --- a/tests/phpunit/includes/media/GIFTest.php +++ b/tests/phpunit/includes/media/GIFTest.php @@ -2,12 +2,22 @@ class GIFHandlerTest extends MediaWikiTestCase { public function setUp() { - $this->filePath = dirname( __FILE__ ) . '/../../data/media/'; + $this->filePath = dirname( __FILE__ ) . '/../../data/media'; + $this->backend = new FSFileBackend( array( + 'name' => 'localtesting', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( 'data' => $this->filePath ) + ) ); + $this->repo = new FSRepo( array( + 'name' => 'temp', + 'url' => 'http://localhost/thumbtest', + 'backend' => $this->backend + ) ); $this->handler = new GIFHandler(); } public function testInvalidFile() { - $res = $this->handler->getMetadata( null, $this->filePath . 'README' ); + $res = $this->handler->getMetadata( null, $this->filePath . '/README' ); $this->assertEquals( GIFHandler::BROKEN_FILE, $res ); } /** @@ -16,8 +26,7 @@ class GIFHandlerTest extends MediaWikiTestCase { * @dataProvider dataIsAnimated */ public function testIsAnimanted( $filename, $expected ) { - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename, - 'image/gif' ); + $file = $this->dataFile( $filename, 'image/gif' ); $actual = $this->handler->isAnimatedImage( $file ); $this->assertEquals( $expected, $actual ); } @@ -34,8 +43,7 @@ class GIFHandlerTest extends MediaWikiTestCase { * @dataProvider dataGetImageArea */ public function testGetImageArea( $filename, $expected ) { - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename, - 'image/gif' ); + $file = $this->dataFile( $filename, 'image/gif' ); $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() ); $this->assertEquals( $expected, $actual ); } @@ -71,15 +79,20 @@ class GIFHandlerTest extends MediaWikiTestCase { * @dataProvider dataGetMetadata */ public function testGetMetadata( $filename, $expected ) { - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename, - 'image/gif' ); - $actual = $this->handler->getMetadata( $file, $this->filePath . $filename ); + $file = $this->dataFile( $filename, 'image/gif' ); + $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" ); $this->assertEquals( unserialize( $expected ), unserialize( $actual ) ); } + public function dataGetMetadata() { return array( array( 'nonanimated.gif', 'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}' ), array( 'animated-xmp.gif', 'a:4:{s:10:"frameCount";i:4;s:6:"looped";b:1;s:8:"duration";d:2.399999999999999911182158029987476766109466552734375;s:8:"metadata";a:5:{s:6:"Artist";s:7:"Bawolff";s:16:"ImageDescription";a:2:{s:9:"x-default";s:18:"A file to test GIF";s:5:"_type";s:4:"lang";}s:15:"SublocationDest";s:13:"The interwebs";s:14:"GIFFileComment";a:1:{i:0;s:16:"GIƒ·test·file";}s:15:"_MW_GIF_VERSION";i:1;}}' ), ); } + + private function dataFile( $name, $type ) { + return new UnregisteredLocalFile( false, $this->repo, + "mwstore://localtesting/data/$name", $type ); + } } diff --git a/tests/phpunit/includes/media/JpegMetadataExtractorTest.php b/tests/phpunit/includes/media/JpegMetadataExtractorTest.php index 61fc9c81..f48382a4 100644 --- a/tests/phpunit/includes/media/JpegMetadataExtractorTest.php +++ b/tests/phpunit/includes/media/JpegMetadataExtractorTest.php @@ -1,5 +1,5 @@ <?php -/* +/** * @todo Could use a test of extended XMP segments. Hard to find programs that * create example files, and creating my own in vim propbably wouldn't * serve as a very good "test". (Adobe photoshop probably creates such files @@ -59,7 +59,7 @@ class JpegMetadataExtractorTest extends MediaWikiTestCase { public function testPSIRExtraction() { $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' ); $expected = '50686f746f73686f7020332e30003842494d04040000000000181c02190004746573741c02190003666f6f1c020000020004'; - $this->assertEquals( $expected, bin2hex( $res['PSIR'] ) ); + $this->assertEquals( $expected, bin2hex( $res['PSIR'][0] ) ); } public function testXMPExtractionAltAppId() { $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' ); @@ -70,19 +70,19 @@ class JpegMetadataExtractorTest extends MediaWikiTestCase { public function testIPTCHashComparisionNoHash() { $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' ); - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); $this->assertEquals( 'iptc-no-hash', $res ); } public function testIPTCHashComparisionBadHash() { $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' ); - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); $this->assertEquals( 'iptc-bad-hash', $res ); } public function testIPTCHashComparisionGoodHash() { $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' ); - $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] ); + $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'][0] ); $this->assertEquals( 'iptc-good-hash', $res ); } diff --git a/tests/phpunit/includes/media/JpegTest.php b/tests/phpunit/includes/media/JpegTest.php index 713a3410..ddabf5b8 100644 --- a/tests/phpunit/includes/media/JpegTest.php +++ b/tests/phpunit/includes/media/JpegTest.php @@ -3,22 +3,24 @@ class JpegTest extends MediaWikiTestCase { public function setUp() { $this->filePath = dirname( __FILE__ ) . '/../../data/media/'; + if ( !wfDl( 'exif' ) ) { + $this->markTestSkipped( "This test needs the exif extension." ); + } + global $wgShowEXIF; + $this->show = $wgShowEXIF; + $wgShowEXIF = true; + } + public function tearDown() { + global $wgShowEXIF; + $wgShowEXIF = $this->show; } public function testInvalidFile() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $jpeg = new JpegHandler; $res = $jpeg->getMetadata( null, $this->filePath . 'README' ); $this->assertEquals( ExifBitmapHandler::BROKEN_FILE, $res ); } public function testJpegMetadataExtraction() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { - $this->markTestIncomplete( "This test needs the exif extension." ); - } $h = new JpegHandler; $res = $h->getMetadata( null, $this->filePath . 'test.jpg' ); $expected = 'a:7:{s:16:"ImageDescription";s:9:"Test file";s:11:"XResolution";s:4:"72/1";s:11:"YResolution";s:4:"72/1";s:14:"ResolutionUnit";i:2;s:16:"YCbCrPositioning";i:1;s:15:"JPEGFileComment";a:1:{i:0;s:17:"Created with GIMP";}s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}'; diff --git a/tests/phpunit/includes/ImageFunctionsTest.php b/tests/phpunit/includes/media/MediaHandlerTest.php index cb7e67f3..99df4f80 100644 --- a/tests/phpunit/includes/ImageFunctionsTest.php +++ b/tests/phpunit/includes/media/MediaHandlerTest.php @@ -1,6 +1,6 @@ <?php -class ImageFunctionsTest extends MediaWikiTestCase { +class MediaHandlerTest extends MediaWikiTestCase { function testFitBoxWidth() { $vals = array( array( @@ -32,10 +32,12 @@ class ImageFunctionsTest extends MediaWikiTestCase { 17 => 4, 18 => 4 ) ) ); foreach ( $vals as $row ) { - extract( $row ); + $tests = $row['tests']; + $height = $row['height']; + $width = $row['width']; foreach ( $tests as $max => $expected ) { $y = round( $expected * $height / $width ); - $result = wfFitBoxWidth( $width, $height, $max ); + $result = MediaHandler::fitBoxWidth( $width, $height, $max ); $y2 = round( $result * $height / $width ); $this->assertEquals( $expected, $result, diff --git a/tests/phpunit/includes/media/PNGTest.php b/tests/phpunit/includes/media/PNGTest.php index b782918c..b6f911fd 100644 --- a/tests/phpunit/includes/media/PNGTest.php +++ b/tests/phpunit/includes/media/PNGTest.php @@ -2,12 +2,22 @@ class PNGHandlerTest extends MediaWikiTestCase { public function setUp() { - $this->filePath = dirname( __FILE__ ) . '/../../data/media/'; + $this->filePath = dirname( __FILE__ ) . '/../../data/media'; + $this->backend = new FSFileBackend( array( + 'name' => 'localtesting', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( 'data' => $this->filePath ) + ) ); + $this->repo = new FSRepo( array( + 'name' => 'temp', + 'url' => 'http://localhost/thumbtest', + 'backend' => $this->backend + ) ); $this->handler = new PNGHandler(); } public function testInvalidFile() { - $res = $this->handler->getMetadata( null, $this->filePath . 'README' ); + $res = $this->handler->getMetadata( null, $this->filePath . '/README' ); $this->assertEquals( PNGHandler::BROKEN_FILE, $res ); } /** @@ -16,8 +26,7 @@ class PNGHandlerTest extends MediaWikiTestCase { * @dataProvider dataIsAnimated */ public function testIsAnimanted( $filename, $expected ) { - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename, - 'image/png' ); + $file = $this->dataFile( $filename, 'image/png' ); $actual = $this->handler->isAnimatedImage( $file ); $this->assertEquals( $expected, $actual ); } @@ -34,8 +43,7 @@ class PNGHandlerTest extends MediaWikiTestCase { * @dataProvider dataGetImageArea */ public function testGetImageArea( $filename, $expected ) { - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename, - 'image/png' ); + $file = $this->dataFile($filename, 'image/png' ); $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() ); $this->assertEquals( $expected, $actual ); } @@ -73,9 +81,8 @@ class PNGHandlerTest extends MediaWikiTestCase { * @dataProvider dataGetMetadata */ public function testGetMetadata( $filename, $expected ) { - $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename, - 'image/png' ); - $actual = $this->handler->getMetadata( $file, $this->filePath . $filename ); + $file = $this->dataFile( $filename, 'image/png' ); + $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" ); // $this->assertEquals( unserialize( $expected ), unserialize( $actual ) ); $this->assertEquals( ( $expected ), ( $actual ) ); } @@ -85,4 +92,9 @@ class PNGHandlerTest extends MediaWikiTestCase { array( 'xmp.png', 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:1;s:9:"colorType";s:14:"index-coloured";s:8:"metadata";a:2:{s:12:"SerialNumber";s:9:"123456789";s:15:"_MW_PNG_VERSION";i:1;}}' ), ); } + + private function dataFile( $name, $type ) { + return new UnregisteredLocalFile( false, $this->repo, + "mwstore://localtesting/data/$name", $type ); + } } diff --git a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php index c2c81b98..526beae8 100644 --- a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php +++ b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php @@ -62,23 +62,33 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase { 'height' => 60 ) ), + array( + "$base/Toll_Texas_1.svg", + // This file triggered bug 31719, needs entity expansion in the xmlns checks + array( + 'width' => 385, + 'height' => 385 + ) + ) ); } function providerSvgFilesWithXMLMetadata() { $base = dirname( __FILE__ ) . '/../../data/media'; - return array( - array( - "$base/US_states_by_total_state_tax_revenue.svg", - array( - 'height' => 593, - 'metadata' => + $metadata = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <ns4:Work xmlns:ns4="http://creativecommons.org/ns#" rdf:about=""> <ns5:format xmlns:ns5="http://purl.org/dc/elements/1.1/">image/svg+xml</ns5:format> <ns5:type xmlns:ns5="http://purl.org/dc/elements/1.1/" rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> </ns4:Work> - </rdf:RDF>', + </rdf:RDF>'; + $metadata = str_replace( "\r", '', $metadata ); // Windows compat + return array( + array( + "$base/US_states_by_total_state_tax_revenue.svg", + array( + 'height' => 593, + 'metadata' => $metadata, 'width' => 959 ) ), diff --git a/tests/phpunit/includes/media/TiffTest.php b/tests/phpunit/includes/media/TiffTest.php index 0a7e8e8c..d4cf503b 100644 --- a/tests/phpunit/includes/media/TiffTest.php +++ b/tests/phpunit/includes/media/TiffTest.php @@ -15,16 +15,15 @@ class TiffTest extends MediaWikiTestCase { } public function testInvalidFile() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { + if ( !wfDl( 'exif' ) ) { $this->markTestIncomplete( "This test needs the exif extension." ); } $res = $this->handler->getMetadata( null, $this->filePath . 'README' ); $this->assertEquals( ExifBitmapHandler::BROKEN_FILE, $res ); } + public function testTiffMetadataExtraction() { - global $wgShowEXIF; - if ( !$wgShowEXIF ) { + if ( !wfDl( 'exif' ) ) { $this->markTestIncomplete( "This test needs the exif extension." ); } $res = $this->handler->getMetadata( null, $this->filePath . 'test.tiff' ); diff --git a/tests/phpunit/includes/media/XMPTest.php b/tests/phpunit/includes/media/XMPTest.php index d1ec4767..c952b23c 100644 --- a/tests/phpunit/includes/media/XMPTest.php +++ b/tests/phpunit/includes/media/XMPTest.php @@ -1,6 +1,12 @@ <?php class XMPTest extends MediaWikiTestCase { + function setUp() { + if ( !wfDl( 'xml' ) ) { + $this->markTestSkipped( 'Requires libxml to do XMP parsing' ); + } + } + /** * Put XMP in, compare what comes out... * @@ -11,9 +17,6 @@ class XMPTest extends MediaWikiTestCase { * @dataProvider dataXMPParse */ public function testXMPParse( $xmp, $expected, $info ) { - if ( !function_exists( 'xml_parser_create_ns' ) ) { - $this->markIncomplete( 'Requires libxml to do XMP parsing' ); - } if ( !is_string( $xmp ) || !is_array( $expected ) ) { throw new Exception( "Invalid data provided to " . __METHOD__ ); } diff --git a/tests/phpunit/includes/media/XMPValidateTest.php b/tests/phpunit/includes/media/XMPValidateTest.php new file mode 100644 index 00000000..e2bb8d8d --- /dev/null +++ b/tests/phpunit/includes/media/XMPValidateTest.php @@ -0,0 +1,47 @@ +<?php +class XMPValidateTest extends MediaWikiTestCase { + + /** + * @dataProvider providerDate + */ + function testValidateDate( $value, $expected ) { + // The method should modify $value. + XMPValidate::validateDate( array(), $value, true ); + $this->assertEquals( $expected, $value ); + } + + function providerDate() { + /* For reference valid date formats are: + * YYYY + * YYYY-MM + * YYYY-MM-DD + * YYYY-MM-DDThh:mmTZD + * YYYY-MM-DDThh:mm:ssTZD + * YYYY-MM-DDThh:mm:ss.sTZD + * (Time zone is optional) + */ + return array( + array( '1992', '1992' ), + array( '1992-04', '1992:04' ), + array( '1992-02-01', '1992:02:01' ), + array( '2011-09-29', '2011:09:29' ), + array( '1982-12-15T20:12', '1982:12:15 20:12' ), + array( '1982-12-15T20:12Z', '1982:12:15 20:12' ), + array( '1982-12-15T20:12+02:30', '1982:12:15 22:42' ), + array( '1982-12-15T01:12-02:30', '1982:12:14 22:42' ), + array( '1982-12-15T20:12:11', '1982:12:15 20:12:11' ), + array( '1982-12-15T20:12:11Z', '1982:12:15 20:12:11' ), + array( '1982-12-15T20:12:11+01:10', '1982:12:15 21:22:11' ), + array( '2045-12-15T20:12:11', '2045:12:15 20:12:11' ), + array( '1867-06-01T15:00:00', '1867:06:01 15:00:00' ), + /* some invalid ones */ + array( '2001--12', null ), + array( '2001-5-12', null ), + array( '2001-5-12TZ', null ), + array( '2001-05-12T15', null ), + array( '2001-12T15:13', null ), + ); + + } + +} diff --git a/tests/phpunit/includes/parser/MagicVariableTest.php b/tests/phpunit/includes/parser/MagicVariableTest.php index a47653e3..31645313 100644 --- a/tests/phpunit/includes/parser/MagicVariableTest.php +++ b/tests/phpunit/includes/parser/MagicVariableTest.php @@ -6,8 +6,8 @@ * As of february 2011, it only tests some revisions and date related * magic variables. * - * @author Ashar Voultoiz - * @copyright Copyright © 2011, Ashar Voultoiz + * @author Antoine Musso + * @copyright Copyright © 2011, Antoine Musso * @file */ @@ -38,6 +38,12 @@ class MagicVariableTest extends MediaWikiTestCase { # initialize parser output $this->testParser->clearState(); + + # Needs a title to do magic word stuff + $title = Title::newFromText( 'Tests' ); + $title->mRedirect = false; # Else it needs a db connection just to check if it's a redirect (when deciding the page language) + + $this->testParser->setTitle( $title ); } /** destroy parser (TODO: is it really neded?)*/ diff --git a/tests/phpunit/includes/parser/MediaWikiParserTest.php b/tests/phpunit/includes/parser/MediaWikiParserTest.php index 18510d9a..816c017a 100644 --- a/tests/phpunit/includes/parser/MediaWikiParserTest.php +++ b/tests/phpunit/includes/parser/MediaWikiParserTest.php @@ -1,10 +1,8 @@ <?php - -require_once( dirname( __FILE__ ) . '/ParserHelpers.php' ); require_once( dirname( __FILE__ ) . '/NewParserTest.php' ); /** - * The UnitTest must be either a class that inherits from PHPUnit_Framework_TestCase + * The UnitTest must be either a class that inherits from MediaWikiTestCase * or a class that provides a public static suite() method which returns * an PHPUnit_Framework_Test object * @@ -20,9 +18,13 @@ class MediaWikiParserTest { foreach ( $wgParserTestFiles as $filename ) { $testsName = basename( $filename, '.txt' ); - $className = /*ucfirst( basename( dirname( $filename ) ) ) .*/ ucfirst( basename( $filename, '.txt' ) ); + /* This used to be ucfirst( basename( dirname( $filename ) ) ) + * and then was ucfirst( basename( $filename, '.txt' ) + * but that didn't work with names like foo.tests.txt + */ + $className = str_replace( '.', '_', ucfirst( basename( $filename, '.txt' ) ) ); - eval( "/** @group Database\n@group Parser\n*/ class $className extends NewParserTest { protected \$file = \"" . addslashes( $filename ) . "\"; } " ); + eval( "/** @group Database\n@group Parser\n*/ class $className extends NewParserTest { protected \$file = '" . strtr( $filename, array( "'" => "\\'", '\\' => '\\\\' ) ) . "'; } " ); $parserTester = new $className( $testsName ); $suite->addTestSuite( new ReflectionClass ( $parserTester ) ); diff --git a/tests/phpunit/includes/parser/NewParserTest.php b/tests/phpunit/includes/parser/NewParserTest.php index f4d5f757..d1221ca8 100644 --- a/tests/phpunit/includes/parser/NewParserTest.php +++ b/tests/phpunit/includes/parser/NewParserTest.php @@ -8,13 +8,12 @@ * @group Stub */ class NewParserTest extends MediaWikiTestCase { - static protected $articles = array(); // Array of test articles defined by the tests /* The dataProvider is run on a different instance than the test, so it must be static * When running tests from several files, all tests will see all articles. */ - - public $uploadDir; + static protected $backendToUse; + public $keepUploads = false; public $runDisabled = false; public $regex = ''; @@ -31,16 +30,12 @@ class NewParserTest extends MediaWikiTestCase { public $memoryLimit = 50; protected $file = false; - - /*function __construct($a = null,$b = array(),$c = null ) { - parent::__construct($a,$b,$c); - }*/ - + function setUp() { global $wgContLang, $wgNamespaceProtection, $wgNamespaceAliases; global $wgHooks, $IP; $wgContLang = Language::factory( 'en' ); - + //Setup CLI arguments if ( $this->getCliArg( 'regex=' ) ) { $this->regex = $this->getCliArg( 'regex=' ); @@ -48,11 +43,11 @@ class NewParserTest extends MediaWikiTestCase { # Matches anything $this->regex = ''; } - + $this->keepUploads = $this->getCliArg( 'keep-uploads' ); - + $tmpGlobals = array(); - + $tmpGlobals['wgScript'] = '/index.php'; $tmpGlobals['wgScriptPath'] = '/'; $tmpGlobals['wgArticlePath'] = '/wiki/$1'; @@ -60,15 +55,14 @@ class NewParserTest extends MediaWikiTestCase { $tmpGlobals['wgStylePath'] = '/skins'; $tmpGlobals['wgThumbnailScriptPath'] = false; $tmpGlobals['wgLocalFileRepo'] = array( - 'class' => 'LocalRepo', - 'name' => 'local', - 'directory' => wfTempDir() . '/test-repo', - 'url' => 'http://example.com/images', - 'deletedDir' => wfTempDir() . '/test-repo/delete', - 'hashLevels' => 2, + 'class' => 'LocalRepo', + 'name' => 'local', + 'url' => 'http://example.com/images', + 'hashLevels' => 2, 'transformVia404' => false, + 'backend' => 'local-backend' ); - + $tmpGlobals['wgForeignFileRepos'] = array(); $tmpGlobals['wgEnableParserCache'] = false; $tmpGlobals['wgHooks'] = $wgHooks; $tmpGlobals['wgDeferredUpdateList'] = array(); @@ -79,16 +73,16 @@ class NewParserTest extends MediaWikiTestCase { // $tmpGlobals['wgContLang'] = new StubContLang; $tmpGlobals['wgUser'] = new User; $context = new RequestContext(); - $tmpGlobals['wgLang'] = $context->getLang(); + $tmpGlobals['wgLang'] = $context->getLanguage(); $tmpGlobals['wgOut'] = $context->getOutput(); $tmpGlobals['wgParser'] = new StubObject( 'wgParser', $GLOBALS['wgParserConf']['class'], array( $GLOBALS['wgParserConf'] ) ); - $tmpGlobals['wgRequest'] = new WebRequest; + $tmpGlobals['wgRequest'] = $context->getRequest(); if ( $GLOBALS['wgStyleDirectory'] === false ) { $tmpGlobals['wgStyleDirectory'] = "$IP/skins"; } - - + + foreach ( $tmpGlobals as $var => $val ) { if ( array_key_exists( $var, $GLOBALS ) ) { $this->savedInitialGlobals[$var] = $GLOBALS[$var]; @@ -96,31 +90,38 @@ class NewParserTest extends MediaWikiTestCase { $GLOBALS[$var] = $val; } - + $this->savedWeirdGlobals['mw_namespace_protection'] = $wgNamespaceProtection[NS_MEDIAWIKI]; $this->savedWeirdGlobals['image_alias'] = $wgNamespaceAliases['Image']; $this->savedWeirdGlobals['image_talk_alias'] = $wgNamespaceAliases['Image_talk']; - + $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface'; $wgNamespaceAliases['Image'] = NS_FILE; $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK; - } - + public function tearDown() { - foreach ( $this->savedInitialGlobals as $var => $val ) { $GLOBALS[$var] = $val; } - + global $wgNamespaceProtection, $wgNamespaceAliases; - + $wgNamespaceProtection[NS_MEDIAWIKI] = $this->savedWeirdGlobals['mw_namespace_protection']; $wgNamespaceAliases['Image'] = $this->savedWeirdGlobals['image_alias']; $wgNamespaceAliases['Image_talk'] = $this->savedWeirdGlobals['image_talk_alias']; + + // Restore backends + RepoGroup::destroySingleton(); + FileBackendGroup::destroySingleton(); } - + function addDBData() { + $this->tablesUsed[] = 'site_stats'; + $this->tablesUsed[] = 'interwiki'; + # disabled for performance + #$this->tablesUsed[] = 'image'; + # Hack: insert a few Wikipedia in-project interwiki prefixes, # for testing inter-language links $this->db->insert( 'interwiki', array( @@ -158,17 +159,14 @@ class NewParserTest extends MediaWikiTestCase { * @todo Fixme! Why are we inserting duplicate data here? Shouldn't * need this IGNORE or shouldn't need the insert at all. */ - ), __METHOD__, array( 'IGNORE' ) ); + ), __METHOD__, array( 'IGNORE' ) + ); # Update certain things in site_stats - $this->db->insert( 'site_stats', + $this->db->insert( 'site_stats', array( 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ), - __METHOD__, - /** - * @todo Fixme! Same as above! - */ - array( 'IGNORE' ) + __METHOD__ ); # Reinitialise the LocalisationCache to match the database state @@ -177,50 +175,66 @@ class NewParserTest extends MediaWikiTestCase { # Clear the message cache MessageCache::singleton()->clear(); - $this->uploadDir = $this->setupUploadDir(); - $user = User::newFromId( 0 ); LinkCache::singleton()->clear(); # Avoids the odd failure at creating the nullRevision - + + # Upload DB table entries for files. + # We will upload the actual files later. Note that if anything causes LocalFile::load() + # to be triggered before then, it will break via maybeUpgrade() setting the fileExists + # member to false and storing it in cache. $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.jpg' ) ); - $image->recordUpload2( '', 'Upload of some lame file', 'Some lame file', array( - 'size' => 12345, - 'width' => 1941, - 'height' => 220, - 'bits' => 24, - 'media_type' => MEDIATYPE_BITMAP, - 'mime' => 'image/jpeg', - 'metadata' => serialize( array() ), - 'sha1' => wfBaseConvert( '', 16, 36, 31 ), - 'fileExists' => true - ), $this->db->timestamp( '20010115123500' ), $user ); + if ( !$this->db->selectField( 'image', '1', array( 'img_name' => $image->getName() ) ) ) { + $image->recordUpload2( + '', // archive name + 'Upload of some lame file', + 'Some lame file', + array( + 'size' => 12345, + 'width' => 1941, + 'height' => 220, + 'bits' => 24, + 'media_type' => MEDIATYPE_BITMAP, + 'mime' => 'image/jpeg', + 'metadata' => serialize( array() ), + 'sha1' => wfBaseConvert( '', 16, 36, 31 ), + 'fileExists' => true ), + $this->db->timestamp( '20010115123500' ), $user + ); + } # This image will be blacklisted in [[MediaWiki:Bad image list]] $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Bad.jpg' ) ); - $image->recordUpload2( '', 'zomgnotcensored', 'Borderline image', array( - 'size' => 12345, - 'width' => 320, - 'height' => 240, - 'bits' => 24, - 'media_type' => MEDIATYPE_BITMAP, - 'mime' => 'image/jpeg', - 'metadata' => serialize( array() ), - 'sha1' => wfBaseConvert( '', 16, 36, 31 ), - 'fileExists' => true - ), $this->db->timestamp( '20010115123500' ), $user ); - + if ( !$this->db->selectField( 'image', '1', array( 'img_name' => $image->getName() ) ) ) { + $image->recordUpload2( + '', // archive name + 'zomgnotcensored', + 'Borderline image', + array( + 'size' => 12345, + 'width' => 320, + 'height' => 240, + 'bits' => 24, + 'media_type' => MEDIATYPE_BITMAP, + 'mime' => 'image/jpeg', + 'metadata' => serialize( array() ), + 'sha1' => wfBaseConvert( '', 16, 36, 31 ), + 'fileExists' => true ), + $this->db->timestamp( '20010115123500' ), $user + ); + } } - - - - + + + + //ParserTest setup/teardown functions - + /** * Set up the global variables for a consistent environment for each test. * Ideally this should replace the global configuration entirely. */ protected function setupGlobals( $opts = '', $config = '' ) { + global $wgFileBackends; # Find out values for some special options. $lang = self::getOptionValue( 'language', $opts, 'en' ); @@ -231,19 +245,48 @@ class NewParserTest extends MediaWikiTestCase { $linkHolderBatchSize = self::getOptionValue( 'wgLinkHolderBatchSize', $opts, 1000 ); + $uploadDir = $this->getUploadDir(); + if ( $this->getCliArg( 'use-filebackend=' ) ) { + if ( self::$backendToUse ) { + $backend = self::$backendToUse; + } else { + $name = $this->getCliArg( 'use-filebackend=' ); + $useConfig = array(); + foreach ( $wgFileBackends as $conf ) { + if ( $conf['name'] == $name ) { + $useConfig = $conf; + } + } + $useConfig['name'] = 'local-backend'; // swap name + $class = $conf['class']; + self::$backendToUse = new $class( $useConfig ); + $backend = self::$backendToUse; + } + } else { + $backend = new FSFileBackend( array( + 'name' => 'local-backend', + 'lockManager' => 'nullLockManager', + 'containerPaths' => array( + 'local-public' => "$uploadDir", + 'local-thumb' => "$uploadDir/thumb", + ) + ) ); + } + $settings = array( 'wgServer' => 'http://Britney-Spears', 'wgScript' => '/index.php', 'wgScriptPath' => '/', 'wgArticlePath' => '/wiki/$1', + 'wgExtensionAssetsPath' => '/extensions', 'wgActionPaths' => array(), 'wgLocalFileRepo' => array( - 'class' => 'LocalRepo', - 'name' => 'local', - 'directory' => $this->uploadDir, - 'url' => 'http://example.com/images', - 'hashLevels' => 2, + 'class' => 'LocalRepo', + 'name' => 'local', + 'url' => 'http://example.com/images', + 'hashLevels' => 2, 'transformVia404' => false, + 'backend' => $backend ), 'wgEnableUploads' => self::getOptionValue( 'wgEnableUploads', $opts, true ), 'wgStylePath' => '/skins', @@ -262,7 +305,7 @@ class NewParserTest extends MediaWikiTestCase { 'wgThumbnailScriptPath' => false, 'wgUseImageResize' => false, 'wgUseTeX' => isset( $opts['math'] ), - 'wgMathDirectory' => $this->uploadDir . '/math', + 'wgMathDirectory' => $uploadDir . '/math', 'wgLocaltimezone' => 'UTC', 'wgAllowExternalImages' => true, 'wgUseTidy' => false, @@ -283,6 +326,7 @@ class NewParserTest extends MediaWikiTestCase { 'wgExternalLinkTarget' => false, 'wgAlwaysUseTidy' => false, 'wgHtml5' => true, + 'wgCleanupPresentationalAttributes' => true, 'wgWellFormedXml' => true, 'wgAllowMicrodataAttributes' => true, 'wgAdaptiveMessageCache' => true, @@ -312,39 +356,41 @@ class NewParserTest extends MediaWikiTestCase { $langObj = Language::factory( $lang ); $GLOBALS['wgContLang'] = $langObj; $context = new RequestContext(); - $GLOBALS['wgLang'] = $context->getLang(); + $GLOBALS['wgLang'] = $context->getLanguage(); $GLOBALS['wgMemc'] = new EmptyBagOStuff; $GLOBALS['wgOut'] = $context->getOutput(); + $GLOBALS['wgUser'] = $context->getUser(); global $wgHooks; $wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup'; - $wgHooks['ParserTestParser'][] = 'ParserTestStaticParserHook::setup'; $wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp'; MagicWord::clearCache(); + RepoGroup::destroySingleton(); + FileBackendGroup::destroySingleton(); + + # Create dummy files in storage + $this->setupUploads(); # Publish the articles after we have the final language set $this->publishTestArticles(); # The entries saved into RepoGroup cache with previous globals will be wrong. RepoGroup::destroySingleton(); + FileBackendGroup::destroySingleton(); MessageCache::singleton()->destroyInstance(); - - global $wgUser; - $wgUser = new User(); + + return $context; } /** - * Create a dummy uploads directory which will contain a couple - * of files in order to pass existence tests. + * Get an FS upload directory (only applies to FSFileBackend) * * @return String: the directory */ - protected function setupUploadDir() { - global $IP; - + protected function getUploadDir() { if ( $this->keepUploads ) { $dir = wfTempDir() . '/mwParser-images'; @@ -361,70 +407,67 @@ class NewParserTest extends MediaWikiTestCase { return $dir; } - wfMkdirParents( $dir . '/3/3a' ); - copy( "$IP/skins/monobook/headbg.jpg", "$dir/3/3a/Foobar.jpg" ); - wfMkdirParents( $dir . '/0/09' ); - copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" ); - return $dir; } - + + /** + * Create a dummy uploads directory which will contain a couple + * of files in order to pass existence tests. + * + * @return String: the directory + */ + protected function setupUploads() { + global $IP; + + $base = $this->getBaseDir(); + $backend = RepoGroup::singleton()->getLocalRepo()->getBackend(); + $backend->prepare( array( 'dir' => "$base/local-public/3/3a" ) ); + $backend->store( array( + 'src' => "$IP/skins/monobook/headbg.jpg", 'dst' => "$base/local-public/3/3a/Foobar.jpg" + ) ); + $backend->prepare( array( 'dir' => "$base/local-public/0/09" ) ); + $backend->store( array( + 'src' => "$IP/skins/monobook/headbg.jpg", 'dst' => "$base/local-public/0/09/Bad.jpg" + ) ); + } + /** * Restore default values and perform any necessary clean-up * after each test runs. */ protected function teardownGlobals() { - RepoGroup::destroySingleton(); - LinkCache::singleton()->clear(); + $this->teardownUploads(); foreach ( $this->savedGlobals as $var => $val ) { $GLOBALS[$var] = $val; } - - $this->teardownUploadDir( $this->uploadDir ); + + RepoGroup::destroySingleton(); + LinkCache::singleton()->clear(); } /** * Remove the dummy uploads directory */ - private function teardownUploadDir( $dir ) { + private function teardownUploads() { if ( $this->keepUploads ) { return; } + $base = $this->getBaseDir(); // delete the files first, then the dirs. self::deleteFiles( array ( - "$dir/3/3a/Foobar.jpg", - "$dir/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg", - "$dir/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg", - "$dir/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg", - "$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg", - - "$dir/0/09/Bad.jpg", + "$base/local-public/3/3a/Foobar.jpg", + "$base/local-thumb/3/3a/Foobar.jpg/180px-Foobar.jpg", + "$base/local-thumb/3/3a/Foobar.jpg/200px-Foobar.jpg", + "$base/local-thumb/3/3a/Foobar.jpg/640px-Foobar.jpg", + "$base/local-thumb/3/3a/Foobar.jpg/120px-Foobar.jpg", - "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png", - ) - ); + "$base/local-public/0/09/Bad.jpg", + "$base/local-thumb/0/09/Bad.jpg", - self::deleteDirs( - array ( - "$dir/3/3a", - "$dir/3", - "$dir/thumb/6/65", - "$dir/thumb/6", - "$dir/thumb/3/3a/Foobar.jpg", - "$dir/thumb/3/3a", - "$dir/thumb/3", - - "$dir/0/09/", - "$dir/0/", - "$dir/thumb", - "$dir/math/f/a/5", - "$dir/math/f/a", - "$dir/math/f", - "$dir/math", - "$dir", + "$base/local-public/math/f/a/5/fa50b8b616463173474302ca3e63586b.png", ) ); } @@ -434,25 +477,24 @@ class NewParserTest extends MediaWikiTestCase { * @param $files Array: full paths to files to delete. */ private static function deleteFiles( $files ) { + $backend = RepoGroup::singleton()->getLocalRepo()->getBackend(); foreach ( $files as $file ) { - if ( file_exists( $file ) ) { - unlink( $file ); + $backend->delete( array( 'src' => $file ), array( 'force' => 1 ) ); + } + foreach ( $files as $file ) { + $tmp = $file; + while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) { + if ( !$backend->clean( array( 'dir' => $tmp ) )->isOK() ) { + break; + } } } } - /** - * Delete the specified directories, if they exist. Must be empty. - * @param $dirs Array: full paths to directories to delete. - */ - private static function deleteDirs( $dirs ) { - foreach ( $dirs as $dir ) { - if ( is_dir( $dir ) ) { - rmdir( $dir ); - } - } + protected function getBaseDir() { + return 'mwstore://local-backend'; } - + public function parserTestProvider() { if ( $this->file === false ) { global $wgParserTestFiles; @@ -460,25 +502,29 @@ class NewParserTest extends MediaWikiTestCase { } return new TestFileIterator( $this->file, $this ); } - + /** * Set the file from whose tests will be run by this instance */ public function setParserTestFile( $filename ) { $this->file = $filename; } - + /** @dataProvider parserTestProvider */ public function testParserTest( $desc, $input, $result, $opts, $config ) { - if ( !preg_match( '/' . $this->regex . '/', $desc ) ) return; //$this->markTestSkipped( 'Filtered out by the user' ); + if ( $this->regex != '' && !preg_match( '/' . $this->regex . '/', $desc ) ) { + $this->assertTrue( true ); // XXX: don't flood output with "test made no assertions" + //$this->markTestSkipped( 'Filtered out by the user' ); + return; + } wfDebug( "Running parser test: $desc\n" ); $opts = $this->parseOptions( $opts ); - $this->setupGlobals( $opts, $config ); + $context = $this->setupGlobals( $opts, $config ); - $user = new User(); - $options = ParserOptions::newFromUser( $user ); + $user = $context->getUser(); + $options = ParserOptions::newFromContext( $context ); if ( isset( $opts['title'] ) ) { $titleText = $opts['title']; @@ -490,7 +536,7 @@ class NewParserTest extends MediaWikiTestCase { $local = isset( $opts['local'] ); $preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null; $parser = $this->getParser( $preprocessor ); - + $title = Title::newFromText( $titleText ); if ( isset( $opts['pst'] ) ) { @@ -505,8 +551,7 @@ class NewParserTest extends MediaWikiTestCase { $replace = $opts['replace'][1]; $out = $parser->replaceSection( $input, $section, $replace ); } elseif ( isset( $opts['comment'] ) ) { - $linker = $user->getSkin(); - $out = $linker->formatComment( $input, $title, $local ); + $out = Linker::formatComment( $input, $title, $local ); } elseif ( isset( $opts['preload'] ) ) { $out = $parser->getpreloadText( $input, $title, $options ); } else { @@ -524,10 +569,9 @@ class NewParserTest extends MediaWikiTestCase { if ( isset( $opts['ill'] ) ) { $out = $this->tidy( implode( ' ', $output->getLanguageLinks() ) ); } elseif ( isset( $opts['cat'] ) ) { - global $wgOut; - - $wgOut->addCategoryLinks( $output->getCategories() ); - $cats = $wgOut->getCategoryLinks(); + $outputPage = $context->getOutput(); + $outputPage->addCategoryLinks( $output->getCategories() ); + $cats = $outputPage->getCategoryLinks(); if ( isset( $cats['normal'] ) ) { $out = $this->tidy( implode( ' ', $cats['normal'] ) ); @@ -541,38 +585,41 @@ class NewParserTest extends MediaWikiTestCase { } $this->teardownGlobals(); - + $this->assertEquals( $result, $out, $desc ); } - + /** * Run a fuzz test series * Draw input from a set of test files + * + * @todo @fixme Needs some work to not eat memory until the world explodes + * + * @group ParserFuzz */ function testFuzzTests() { - - $this->markTestIncomplete( "Somebody is serializing PDO objects, that's a no-no" ); - global $wgParserTestFiles; - + $files = $wgParserTestFiles; - + if( $this->getCliArg( 'file=' ) ) { $files = array( $this->getCliArg( 'file=' ) ); } - + $dict = $this->getFuzzInput( $files ); $dictSize = strlen( $dict ); $logMaxLength = log( $this->maxFuzzTestLength ); + ini_set( 'memory_limit', $this->memoryLimit * 1048576 ); + $user = new User; $opts = ParserOptions::newFromUser( $user ); $title = Title::makeTitle( NS_MAIN, 'Parser_test' ); $id = 1; - + while ( true ) { - + // Generate test input mt_srand( ++$this->fuzzSeed ); $totalLength = mt_rand( 1, $this->maxFuzzTestLength ); @@ -594,7 +641,7 @@ class NewParserTest extends MediaWikiTestCase { $this->assertTrue( true, "Test $id, fuzz seed {$this->fuzzSeed}" ); } catch ( Exception $exception ) { $input_dump = sprintf( "string(%d) \"%s\"\n", strlen( $input ), $input ); - + $this->assertTrue( false, "Test $id, fuzz seed {$this->fuzzSeed}. \n\nInput: $input_dump\n\nError: {$exception->getMessage()}\n\nBacktrace: {$exception->getTraceAsString()}" ); } @@ -611,18 +658,18 @@ class NewParserTest extends MediaWikiTestCase { foreach ( $memStats as $name => $usage ) { $ret .= "$name: $usage\n"; } - + throw new MWException( $ret ); } } - + $id++; - + } } //Various getter functions - + /** * Get an input dictionary from a set of parser test files */ @@ -640,7 +687,7 @@ class NewParserTest extends MediaWikiTestCase { return $dict; } - + /** * Get a memory usage breakdown */ @@ -675,7 +722,7 @@ class NewParserTest extends MediaWikiTestCase { return $memStats; } - + /** * Get a Parser object */ @@ -693,23 +740,20 @@ class NewParserTest extends MediaWikiTestCase { //Various action functions public function addArticle( $name, $text, $line ) { - self::$articles[$name] = $text; - } - + self::$articles[$name] = array( $text, $line ); + } + public function publishTestArticles() { if ( empty( self::$articles ) ) { return; } - foreach ( self::$articles as $name => $text ) { - $title = Title::newFromText( $name ); - - if ( $title->getArticleID( Title::GAID_FOR_UPDATE ) == 0 ) { - ParserTest::addArticle( $name, $text ); - } + foreach ( self::$articles as $name => $info ) { + list( $text, $line ) = $info; + ParserTest::addArticle( $name, $text, $line, 'ignoreduplicate' ); } } - + /** * Steal a callback function from the primary parser, save it for * application to our scary parser. If the hook is not installed, @@ -730,8 +774,8 @@ class NewParserTest extends MediaWikiTestCase { return isset( $wgParser->mFunctionHooks[$name] ); } //Various "cleanup" functions - - /* + + /** * Run the "tidy" command on text if the $wgUseTidy * global is true * @@ -747,7 +791,7 @@ class NewParserTest extends MediaWikiTestCase { return $text; } - + /** * Remove last character if it is a newline */ @@ -760,12 +804,8 @@ class NewParserTest extends MediaWikiTestCase { } } - public function showRunFile( $file ) { - /* NOP */ - } - //Test options parser functions - + protected function parseOptions( $instring ) { $opts = array(); // foo @@ -820,7 +860,7 @@ class NewParserTest extends MediaWikiTestCase { } return $opts; } - + protected function cleanupOption( $opt ) { if ( substr( $opt, 0, 1 ) == '"' ) { return substr( $opt, 1, -1 ); @@ -831,7 +871,7 @@ class NewParserTest extends MediaWikiTestCase { } return $opt; } - + /** * Use a regex to find out the value of an option * @param $key String: name of option val to retrieve diff --git a/tests/phpunit/includes/parser/ParserHelpers.php b/tests/phpunit/includes/parser/ParserHelpers.php deleted file mode 100644 index 4a6ce7c4..00000000 --- a/tests/phpunit/includes/parser/ParserHelpers.php +++ /dev/null @@ -1,136 +0,0 @@ -<?php - -class PHPUnitParserTest extends ParserTest { - function showTesting( $desc ) { - /* Do nothing since we don't want to show info during PHPUnit testing. */ - } - - public function showSuccess( $desc ) { - PHPUnit_Framework_Assert::assertTrue( true, $desc ); - return true; - } - - public function showFailure( $desc, $expected, $got ) { - PHPUnit_Framework_Assert::assertEquals( $expected, $got, $desc ); - return false; - } - - public function setupRecorder( $options ) { - $this->recorder = new PHPUnitTestRecorder( $this ); - } -} - -class ParserUnitTest extends MediaWikiTestCase { - private $test = ""; - - public function __construct( $suite, $test = null ) { - parent::__construct(); - $this->test = $test; - $this->suite = $suite; - } - - function count() { return 1; } - - public function run( PHPUnit_Framework_TestResult $result = null ) { - PHPUnit_Framework_Assert::resetCount(); - if ( $result === NULL ) { - $result = new PHPUnit_Framework_TestResult; - } - - $this->suite->publishTestArticles(); // Add articles needed by the tests. - $backend = new ParserTestSuiteBackend; - $result->startTest( $this ); - - // Support the transition to PHPUnit 3.5 where PHPUnit_Util_Timer is replaced with PHP_Timer - if ( class_exists( 'PHP_Timer' ) ) { - PHP_Timer::start(); - } else { - PHPUnit_Util_Timer::start(); - } - - $r = false; - try { - # Run the test. - # On failure, the subclassed backend will throw an exception with - # the details. - $pt = new PHPUnitParserTest; - $r = $pt->runTest( $this->test['test'], $this->test['input'], - $this->test['result'], $this->test['options'], $this->test['config'] - ); - } - catch ( PHPUnit_Framework_AssertionFailedError $e ) { - - // PHPUnit_Util_Timer -> PHP_Timer support (see above) - if ( class_exists( 'PHP_Timer' ) ) { - $result->addFailure( $this, $e, PHP_Timer::stop() ); - } else { - $result->addFailure( $this, $e, PHPUnit_Util_Timer::stop() ); - } - } - catch ( Exception $e ) { - // PHPUnit_Util_Timer -> PHP_Timer support (see above) - if ( class_exists( 'PHP_Timer' ) ) { - $result->addFailure( $this, $e, PHP_Timer::stop() ); - } else { - $result->addFailure( $this, $e, PHPUnit_Util_Timer::stop() ); - } - } - - // PHPUnit_Util_Timer -> PHP_Timer support (see above) - if ( class_exists( 'PHP_Timer' ) ) { - $result->endTest( $this, PHP_Timer::stop() ); - } else { - $result->endTest( $this, PHPUnit_Util_Timer::stop() ); - } - - $backend->recorder->record( $this->test['test'], $r ); - $this->addToAssertionCount( PHPUnit_Framework_Assert::getCount() ); - - return $result; - } - - public function toString() { - return $this->test['test']; - } - -} - -class ParserTestSuiteBackend extends PHPUnit_FrameWork_TestSuite { - public $recorder; - public $term; - static $usePHPUnit = false; - - function __construct() { - parent::__construct(); - $this->setupRecorder(null); - self::$usePHPUnit = method_exists('PHPUnit_Framework_Assert', 'assertEquals'); - } - - function showTesting( $desc ) { - } - - function showRunFile( $path ) { - } - - function showTestResult( $desc, $result, $out ) { - if ( $result === $out ) { - return self::showSuccess( $desc, $result, $out ); - } else { - return self::showFailure( $desc, $result, $out ); - } - } - - public function setupRecorder( $options ) { - $this->recorder = new PHPUnitTestRecorder( $this ); - } -} - -class PHPUnitTestRecorder extends TestRecorder { - function record( $test, $result ) { - $this->total++; - $this->success += $result; - - } - - function reportPercentage( $success, $total ) { } -} diff --git a/tests/phpunit/includes/parser/ParserPreloadTest.php b/tests/phpunit/includes/parser/ParserPreloadTest.php new file mode 100644 index 00000000..0e8ef530 --- /dev/null +++ b/tests/phpunit/includes/parser/ParserPreloadTest.php @@ -0,0 +1,67 @@ +<?php +/** + * Basic tests for Parser::getPreloadText + * @author Antoine Musso + */ +class ParserPreloadTest extends MediaWikiTestCase { + private $testParser; + private $testParserOptions; + private $title; + + function setUp() { + $this->testParserOptions = new ParserOptions(); + + $this->testParser = new Parser(); + $this->testParser->Options( $this->testParserOptions ); + $this->testParser->clearState(); + + $this->title = Title::newFromText( 'Preload Test' ); + } + + function tearDown() { + unset( $this->testParser ); + unset( $this->title ); + } + + /** + * @covers Parser::getPreloadText + */ + function testPreloadSimpleText() { + $this->assertPreloaded( 'simple', 'simple' ); + } + + /** + * @covers Parser::getPreloadText + */ + function testPreloadedPreIsUnstripped() { + $this->assertPreloaded( + '<pre>monospaced</pre>', + '<pre>monospaced</pre>', + '<pre> in preloaded text must be unstripped (bug 27467)' + ); + } + + /** + * @covers Parser::getPreloadText + */ + function testPreloadedNowikiIsUnstripped() { + $this->assertPreloaded( + '<nowiki>[[Dummy title]]</nowiki>', + '<nowiki>[[Dummy title]]</nowiki>', + '<nowiki> in preloaded text must be unstripped (bug 27467)' + ); + } + + function assertPreloaded( $expected, $text, $msg='') { + $this->assertEquals( + $expected, + $this->testParser->getPreloadText( + $text, + $this->title, + $this->testParserOptions + ), + $msg + ); + } + +} diff --git a/tests/phpunit/includes/parser/PreprocessorTest.php b/tests/phpunit/includes/parser/PreprocessorTest.php index 7a5948d4..9d3499a0 100644 --- a/tests/phpunit/includes/parser/PreprocessorTest.php +++ b/tests/phpunit/includes/parser/PreprocessorTest.php @@ -49,43 +49,45 @@ class PreprocessorTest extends MediaWikiTestCase { array( "== Foo ==\n== Bar == \n", "<root><h level=\"2\" i=\"1\">== Foo ==</h>\n<h level=\"2\" i=\"2\">== Bar == </h>\n</root>" ), array( "===========", "<root><h level=\"5\" i=\"1\">===========</h></root>" ), array( "Foo\n=\n==\n=\n", "<root>Foo\n=\n==\n=\n</root>" ), - array( "{{Foo}}", "<root><template lineStart=\"1\"><title>Foo</title></template></root>" ), + array( "{{Foo}}", "<root><template><title>Foo</title></template></root>" ), array( "\n{{Foo}}", "<root>\n<template lineStart=\"1\"><title>Foo</title></template></root>" ), - array( "{{Foo|bar}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template></root>" ), - array( "{{Foo|bar}}a", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template>a</root>" ), - array( "{{Foo|bar|baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></template></root>" ), - array( "{{Foo|1=bar}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>1</name>=<value>bar</value></part></template></root>" ), - array( "{{Foo|=bar}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name></name>=<value>bar</value></part></template></root>" ), - array( "{{Foo|bar=baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>bar</name>=<value>baz</value></part></template></root>" ), - array( "{{Foo|1=bar|baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name index=\"1\" /><value>baz</value></part></template></root>" ), - array( "{{Foo|1=bar|2=baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name>2</name>=<value>baz</value></part></template></root>" ), - array( "{{Foo|bar|foo=baz}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name>foo</name>=<value>baz</value></part></template></root>" ), - array( "{{{1}}}", "<root><tplarg lineStart=\"1\"><title>1</title></tplarg></root>" ), - array( "{{{1|}}}", "<root><tplarg lineStart=\"1\"><title>1</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ), - array( "{{{Foo}}}", "<root><tplarg lineStart=\"1\"><title>Foo</title></tplarg></root>" ), - array( "{{{Foo|}}}", "<root><tplarg lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ), - array( "{{{Foo|bar|baz}}}", "<root><tplarg lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></tplarg></root>" ), + array( "{{Foo|bar}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template></root>" ), + array( "{{Foo|bar}}a", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template>a</root>" ), + array( "{{Foo|bar|baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></template></root>" ), + array( "{{Foo|1=bar}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part></template></root>" ), + array( "{{Foo|=bar}}", "<root><template><title>Foo</title><part><name></name>=<value>bar</value></part></template></root>" ), + array( "{{Foo|bar=baz}}", "<root><template><title>Foo</title><part><name>bar</name>=<value>baz</value></part></template></root>" ), + array( "{{Foo|{{bar}}=baz}}", "<root><template><title>Foo</title><part><name><template><title>bar</title></template></name>=<value>baz</value></part></template></root>" ), + array( "{{Foo|1=bar|baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name index=\"1\" /><value>baz</value></part></template></root>" ), + array( "{{Foo|1=bar|2=baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name>2</name>=<value>baz</value></part></template></root>" ), + array( "{{Foo|bar|foo=baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name>foo</name>=<value>baz</value></part></template></root>" ), + array( "{{{1}}}", "<root><tplarg><title>1</title></tplarg></root>" ), + array( "{{{1|}}}", "<root><tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ), + array( "{{{Foo}}}", "<root><tplarg><title>Foo</title></tplarg></root>" ), + array( "{{{Foo|}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ), + array( "{{{Foo|bar|baz}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></tplarg></root>" ), array( "{<!-- -->{Foo}}", "<root>{<comment><!-- --></comment>{Foo}}</root>" ), array( "{{{{Foobar}}}}", "<root>{<tplarg><title>Foobar</title></tplarg>}</root>" ), - array( "{{{ {{Foo}} }}}", "<root><tplarg lineStart=\"1\"><title> <template><title>Foo</title></template> </title></tplarg></root>" ), - array( "{{ {{{Foo}}} }}", "<root><template lineStart=\"1\"><title> <tplarg><title>Foo</title></tplarg> </title></template></root>" ), - array( "{{{{{Foo}}}}}", "<root><template lineStart=\"1\"><title><tplarg><title>Foo</title></tplarg></title></template></root>" ), - array( "{{{{{Foo}} }}}", "<root><tplarg lineStart=\"1\"><title><template><title>Foo</title></template> </title></tplarg></root>" ), - array( "{{{{{{Foo}}}}}}", "<root><tplarg lineStart=\"1\"><title><tplarg><title>Foo</title></tplarg></title></tplarg></root>" ), + array( "{{{ {{Foo}} }}}", "<root><tplarg><title> <template><title>Foo</title></template> </title></tplarg></root>" ), + array( "{{ {{{Foo}}} }}", "<root><template><title> <tplarg><title>Foo</title></tplarg> </title></template></root>" ), + array( "{{{{{Foo}}}}}", "<root><template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ), + array( "{{{{{Foo}} }}}", "<root><tplarg><title><template><title>Foo</title></template> </title></tplarg></root>" ), + array( "{{{{{{Foo}}}}}}", "<root><tplarg><title><tplarg><title>Foo</title></tplarg></title></tplarg></root>" ), array( "{{{{{{Foo}}}}}", "<root>{<template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ), array( "[[[Foo]]", "<root>[[[Foo]]</root>" ), - array( "{{Foo|[[[[bar]]|baz]]}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name index=\"1\" /><value>[[[[bar]]|baz]]</value></part></template></root>" ), // This test is important, since it means the difference between having the [[ rule stacked or not + array( "{{Foo|[[[[bar]]|baz]]}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>[[[[bar]]|baz]]</value></part></template></root>" ), // This test is important, since it means the difference between having the [[ rule stacked or not array( "{{Foo|[[[[bar]|baz]]}}", "<root>{{Foo|[[[[bar]|baz]]}}</root>" ), array( "{{Foo|Foo [[[[bar]|baz]]}}", "<root>{{Foo|Foo [[[[bar]|baz]]}}</root>" ), array( "Foo <display map>Bar</display map >Baz", "<root>Foo <ext><name>display map</name><attr></attr><inner>Bar</inner><close></display map ></close></ext>Baz</root>" ), array( "Foo <display map foo>Bar</display map >Baz", "<root>Foo <ext><name>display map</name><attr> foo</attr><inner>Bar</inner><close></display map ></close></ext>Baz</root>" ), array( "Foo <gallery bar=\"baz\" />", "<root>Foo <ext><name>gallery</name><attr> bar="baz" </attr></ext></root>" ), + array( "Foo <gallery bar=\"1\" baz=2 />", "<root>Foo <ext><name>gallery</name><attr> bar="1" baz=2 </attr></ext></root>" ), array( "</foo>Foo<//foo>", "<root><ext><name>/foo</name><attr></attr><inner>Foo</inner><close><//foo></close></ext></root>" ), # Worth blacklisting IMHO - array( "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "<root><template lineStart=\"1\"><title>#ifexpr: (<tplarg><title>1</title><part><name index=\"1\" /><value>1</value></part></tplarg> = 2) </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"), - array( "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> <template><title>Bar</title></template> </value></part></template></root>"), - array( "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> [[Bar]] </value></part></template></root>"), - array( "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> [[Foo]] </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"), - array( "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "<root><template lineStart=\"1\"><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 1 </value></part><part><name index=\"2\" /><value> <template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 2 </value></part><part><name index=\"2\" /><value> 3 </value></part></template> </value></part></template></root>"), + array( "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "<root><template><title>#ifexpr: (<tplarg><title>1</title><part><name index=\"1\" /><value>1</value></part></tplarg> = 2) </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"), + array( "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> <template><title>Bar</title></template> </value></part></template></root>"), + array( "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> [[Bar]] </value></part></template></root>"), + array( "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> [[Foo]] </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>"), + array( "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 1 </value></part><part><name index=\"2\" /><value> <template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 2 </value></part><part><name index=\"2\" /><value> 3 </value></part></template> </value></part></template></root>"), array( "{{ {{Foo}}", "<root>{{ <template><title>Foo</title></template></root>"), array( "{{Foobar {{Foo}} {{Bar}} {{Baz}} ", "<root>{{Foobar <template><title>Foo</title></template> <template><title>Bar</title></template> <template><title>Baz</title></template> </root>"), array( "[[Foo]] |", "<root>[[Foo]] |</root>"), @@ -97,19 +99,54 @@ class PreprocessorTest extends MediaWikiTestCase { array( "{{Foo|bar=[[baz]}}", "<root>{{Foo|bar=[[baz]}}</root>"), array( "{{foo|", "<root>{{foo|</root>"), array( "{{foo|}", "<root>{{foo|}</root>"), - array( "{{foo|} }}", "<root><template lineStart=\"1\"><title>foo</title><part><name index=\"1\" /><value>} </value></part></template></root>"), + array( "{{foo|} }}", "<root><template><title>foo</title><part><name index=\"1\" /><value>} </value></part></template></root>"), array( "{{foo|bar=|}", "<root>{{foo|bar=|}</root>"), array( "{{Foo|} Bar=", "<root>{{Foo|} Bar=</root>"), - array( "{{Foo|} Bar=}}", "<root><template lineStart=\"1\"><title>Foo</title><part><name>} Bar</name>=<value></value></part></template></root>"), + array( "{{Foo|} Bar=}}", "<root><template><title>Foo</title><part><name>} Bar</name>=<value></value></part></template></root>"), /* array( file_get_contents( dirname( __FILE__ ) . '/QuoteQuran.txt' ), file_get_contents( dirname( __FILE__ ) . '/QuoteQuranExpanded.txt' ) ), */ ); } /** + * Get XML preprocessor tree from the preprocessor (which may not be the + * native XML-based one). + * + * @param string $wikiText + * @return string + */ + function preprocessToXml( $wikiText ) { + if ( method_exists( $this->mPreprocessor, 'preprocessToXml' ) ) { + return $this->normalizeXml( $this->mPreprocessor->preprocessToXml( $wikiText ) ); + } + + $dom = $this->mPreprocessor->preprocessToObj( $wikiText ); + if ( is_callable( array( $dom, 'saveXML' ) ) ) { + return $dom->saveXML(); + } else { + return $this->normalizeXml( $dom->__toString() ); + } + } + + /** + * Normalize XML string to the form that a DOMDocument saves out. + * + * @param string $xml + * @return string + */ + function normalizeXml( $xml ) { + return preg_replace( '!<([a-z]+)/>!', '<$1></$1>', str_replace( ' />', '/>', $xml ) ); + + $dom = new DOMDocument(); + // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2 don't barf when the XML is >256 levels deep + $dom->loadXML( $xml, 1 << 19 ); + return $dom->saveXML(); + } + + /** * @dataProvider provideCases */ function testPreprocessorOutput( $wikiText, $expectedXml ) { - $this->assertEquals( $expectedXml, $this->mPreprocessor->preprocessToXml( $wikiText ) ); + $this->assertEquals( $this->normalizeXml( $expectedXml ), $this->preprocessToXml( $wikiText ) ); } /** @@ -130,11 +167,12 @@ class PreprocessorTest extends MediaWikiTestCase { function testPreprocessorOutputFiles( $filename ) { $folder = dirname( __FILE__ ) . "/../../../parser/preprocess"; $wikiText = file_get_contents( "$folder/$filename.txt" ); - $output = $this->mPreprocessor->preprocessToXml( $wikiText ); + $output = $this->preprocessToXml( $wikiText ); $expectedFilename = "$folder/$filename.expected"; if ( file_exists( $expectedFilename ) ) { - $this->assertStringEqualsFile( $expectedFilename, $output ); + $expectedXml = $this->normalizeXml( file_get_contents( $expectedFilename ) ); + $this->assertEquals( $expectedXml, $output ); } else { $tempFilename = tempnam( $folder, "$filename." ); file_put_contents( $tempFilename, $output ); @@ -189,7 +227,7 @@ class PreprocessorTest extends MediaWikiTestCase { * @dataProvider provideHeadings */ function testHeadings( $wikiText, $expectedXml ) { - $this->assertEquals( $expectedXml, $this->mPreprocessor->preprocessToXml( $wikiText ) ); + $this->assertEquals( $this->normalizeXml( $expectedXml ), $this->preprocessToXml( $wikiText ) ); } } diff --git a/tests/phpunit/includes/parser/TagHooks.php b/tests/phpunit/includes/parser/TagHooksTest.php index 713ce846..713ce846 100644 --- a/tests/phpunit/includes/parser/TagHooks.php +++ b/tests/phpunit/includes/parser/TagHooksTest.php diff --git a/tests/phpunit/includes/search/SearchEngineTest.php b/tests/phpunit/includes/search/SearchEngineTest.php index 1a0fcd31..957907c7 100644 --- a/tests/phpunit/includes/search/SearchEngineTest.php +++ b/tests/phpunit/includes/search/SearchEngineTest.php @@ -12,7 +12,7 @@ class SearchEngineTest extends MediaWikiTestCase { unset( $this->search ); } - /* + /** * Checks for database type & version. * Will skip current test if DB does not support search. */ @@ -64,8 +64,10 @@ class SearchEngineTest extends MediaWikiTestCase { $this->assertTrue( is_object( $results ) ); $matches = array(); - while ( $row = $results->next() ) { + $row = $results->next(); + while ( $row ) { $matches[] = $row->getTitle()->getPrefixedText(); + $row = $results->next(); } $results->free(); # Search is not guaranteed to return results in a certain order; @@ -83,20 +85,18 @@ class SearchEngineTest extends MediaWikiTestCase { * @param $n Integer: unused */ function insertPage( $pageName, $text, $ns ) { - $dbw = $this->db; $title = Title::newFromText( $pageName ); $user = User::newFromName( 'WikiSysop' ); $comment = 'Search Test'; // avoid memory leak...? - $linkCache = LinkCache::singleton(); - $linkCache->clear(); + LinkCache::singleton()->clear(); - $article = new Article( $title ); - $article->doEdit( $text, $comment, 0, false, $user ); + $page = WikiPage::factory( $title ); + $page->doEdit( $text, $comment, 0, false, $user ); - $this->pageList[] = array( $title, $article->getId() ); + $this->pageList[] = array( $title, $page->getId() ); return true; } diff --git a/tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php b/tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php new file mode 100644 index 00000000..a33c7b68 --- /dev/null +++ b/tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Test class to run the query of most of all our special pages + * + * Copyright © 2011, Antoine Musso + * + * @author Antoine Musso + * @group Database + */ + +if ( !defined( 'MEDIAWIKI' ) ) { + die( 1 ); +} + +global $IP; +require_once "$IP/includes/QueryPage.php"; // Needed to populate $wgQueryPages + +class QueryAllSpecialPagesTest extends MediaWikiTestCase { + + /** List query pages that can not be tested automatically */ + protected $manualTest = array( + 'LinkSearchPage' + ); + + /** + * Pages whose query use the same DB table more than once. + * This is used to skip testing those pages when run against a MySQL backend + * which does not support reopening a temporary table. See upstream bug: + * http://bugs.mysql.com/bug.php?id=10327 + */ + protected $reopensTempTable = array( + 'BrokenRedirects', + ); + + /** + * Initialize all query page objects + */ + function __construct() { + parent::__construct(); + + global $wgQueryPages; + foreach( $wgQueryPages as $page ) { + $class = $page[0]; + if( ! in_array( $class, $this->manualTest ) ) { + $this->queryPages[$class] = new $class; + } + } + } + + /** + * Test SQL for each of our QueryPages objects + * @group Database + */ + function testQuerypageSqlQuery() { + global $wgDBtype; + + foreach( $this->queryPages as $page ) { + + // With MySQL, skips special pages reopening a temporary table + // See http://bugs.mysql.com/bug.php?id=10327 + if( + $wgDBtype === 'mysql' + && in_array( $page->getName(), $this->reopensTempTable ) + ) { + $this->markTestSkipped( "SQL query for page {$page->getName()} can not be tested on MySQL backend (it reopens a temporary table)" ); + continue; + } + + $msg = "SQL query for page {$page->getName()} should give a result wrapper object" ; + + $result = $page->reallyDoQuery( 50 ); + if( $result instanceof ResultWrapper ) { + $this->assertTrue( true, $msg ); + } else { + $this->assertFalse( false, $msg ); + } + } + } +} diff --git a/tests/phpunit/includes/specials/SpecialRecentchanges.php b/tests/phpunit/includes/specials/SpecialRecentchangesTest.php index a98e7c1a..2e4f4b09 100644 --- a/tests/phpunit/includes/specials/SpecialRecentchanges.php +++ b/tests/phpunit/includes/specials/SpecialRecentchangesTest.php @@ -2,9 +2,10 @@ /** * Test class for SpecialRecentchanges class * - * Copyright © 2011, Ashar Voultoiz + * Copyright © 2011, Antoine Musso * - * @author Ashar Voultoiz + * @author Antoine Musso + * @group Database */ class SpecialRecentchangesTest extends MediaWikiTestCase { @@ -18,13 +19,12 @@ class SpecialRecentchangesTest extends MediaWikiTestCase { /** helper to test SpecialRecentchanges::buildMainQueryConds() */ private function assertConditions( $expected, $requestOptions = null, $message = '' ) { - global $wgRequest; - $savedGlobal = $wgRequest; + $context = new RequestContext; + $context->setRequest( new FauxRequest( $requestOptions ) ); - # Initialize a WebRequest object ... - $wgRequest = new FauxRequest( $requestOptions ); - # ... then setup the rc object (which use wgRequest internally) + # setup the rc object $this->rc = new SpecialRecentChanges(); + $this->rc->setContext( $context ); $formOptions = $this->rc->setup( null ); # Filter out rc_timestamp conditions which depends on the test runtime @@ -40,8 +40,6 @@ class SpecialRecentchangesTest extends MediaWikiTestCase { $queryConditions, $message ); - - $wgRequest = $savedGlobal; } /** return false if condition begin with 'rc_timestamp ' */ diff --git a/tests/phpunit/includes/specials/SpecialSearchTest.php b/tests/phpunit/includes/specials/SpecialSearchTest.php new file mode 100644 index 00000000..ea9d5533 --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialSearchTest.php @@ -0,0 +1,108 @@ +<?php +/** + * Test class for SpecialSearch class + * Copyright © 2012, Antoine Musso + * + * @author Antoine Musso + * @group Database + */ + +class SpecialSearchTest extends MediaWikiTestCase { + private $search; + + function setUp() { } + function tearDown() { } + + /** + * @covers SpecialSearch::load + * @dataProvider provideSearchOptionsTests + * @param $requested Array Request parameters. For example array( 'ns5' => true, 'ns6' => true). NULL to use default options. + * @param $userOptions Array User options to test with. For example array('searchNs5' => 1 );. NULL to use default options. + * @param $expectedProfile An expected search profile name + * @param $expectedNs Array Expected namespaces + */ + function testProfileAndNamespaceLoading( + $requested, $userOptions, $expectedProfile, $expectedNS, + $message = 'Profile name and namespaces mismatches!' + ) { + $context = new RequestContext; + $context->setUser( + $this->newUserWithSearchNS( $userOptions ) + ); + /* + $context->setRequest( new FauxRequest( array( + 'ns5'=>true, + 'ns6'=>true, + ) )); + */ + $context->setRequest( new FauxRequest( $requested )); + $search = new SpecialSearch(); + $search->setContext( $context ); + $search->load(); + + /** + * Verify profile name and namespace in the same assertion to make + * sure we will be able to fully compare the above code. PHPUnit stop + * after an assertion fail. + */ + $this->assertEquals( + array( /** Expected: */ + 'ProfileName' => $expectedProfile, + 'Namespaces' => $expectedNS, + ) + , array( /** Actual: */ + 'ProfileName' => $search->getProfile(), + 'Namespaces' => $search->getNamespaces(), + ) + , $message + ); + + } + + function provideSearchOptionsTests() { + $defaultNS = SearchEngine::defaultNamespaces(); + $EMPTY_REQUEST = array(); + $NO_USER_PREF = null; + + return array( + /** + * Parameters: + * <Web Request>, <User options> + * Followed by expected values: + * <ProfileName>, <NSList> + * Then an optional message. + */ + array( + $EMPTY_REQUEST, $NO_USER_PREF, + 'default', $defaultNS, + 'Bug 33270: No request nor user preferences should give default profile' + ), + array( + array( 'ns5' => 1 ), $NO_USER_PREF, + 'advanced', array( 5), + 'Web request with specific NS should override user preference' + ), + array( + $EMPTY_REQUEST, array( 'searchNs2' => 1, 'searchNs14' => 1 ), + 'advanced', array( 2, 14 ), + 'Bug 33583: search with no option should honor User search preferences' + ), + ); + } + + /** + * Helper to create a new User object with given options + * User remains anonymous though + */ + function newUserWithSearchNS( $opt = null ) { + $u = User::newFromId(0); + if( $opt === null ) { + return $u; + } + foreach($opt as $name => $value) { + $u->setOption( $name, $value ); + } + return $u; + } +} + diff --git a/tests/phpunit/includes/upload/UploadFromUrlTest.php b/tests/phpunit/includes/upload/UploadFromUrlTest.php index 4722d408..d56cce31 100644 --- a/tests/phpunit/includes/upload/UploadFromUrlTest.php +++ b/tests/phpunit/includes/upload/UploadFromUrlTest.php @@ -20,7 +20,7 @@ class UploadFromUrlTest extends ApiTestCase { } } - protected function doApiRequest( $params, $unused = null, $appendModule = false ) { + protected function doApiRequest( $params, $unused = null, $appendModule = false, $user = null ) { $sessionId = session_id(); session_write_close(); @@ -36,7 +36,10 @@ class UploadFromUrlTest extends ApiTestCase { * Ensure that the job queue is empty before continuing */ public function testClearQueue() { - while ( $job = Job::pop() ) { } + $job = Job::pop(); + while ( $job ) { + $job = Job::pop(); + } $this->assertFalse( $job ); } @@ -73,7 +76,7 @@ class UploadFromUrlTest extends ApiTestCase { * @depends testClearQueue */ public function testSetupUrlDownload( $data ) { - $token = $this->user->editToken(); + $token = $this->user->getEditToken(); $exception = false; try { @@ -147,7 +150,7 @@ class UploadFromUrlTest extends ApiTestCase { * @depends testClearQueue */ public function testAsyncUpload( $data ) { - $token = $this->user->editToken(); + $token = $this->user->getEditToken(); $this->user->addGroup( 'users' ); @@ -166,7 +169,7 @@ class UploadFromUrlTest extends ApiTestCase { * @depends testClearQueue */ public function testAsyncUploadWarning( $data ) { - $token = $this->user->editToken(); + $token = $this->user->getEditToken(); $this->user->addGroup( 'users' ); @@ -197,7 +200,7 @@ class UploadFromUrlTest extends ApiTestCase { * @depends testClearQueue */ public function testSyncDownload( $data ) { - $token = $this->user->editToken(); + $token = $this->user->getEditToken(); $job = Job::pop(); $this->assertFalse( $job, 'Starting with an empty jobqueue' ); @@ -221,7 +224,7 @@ class UploadFromUrlTest extends ApiTestCase { } public function testLeaveMessage() { - $token = $this->user->user->editToken(); + $token = $this->user->user->getEditToken(); $talk = $this->user->user->getTalkPage(); if ( $talk->exists() ) { @@ -274,7 +277,7 @@ class UploadFromUrlTest extends ApiTestCase { return; - /** + /* // Broken until using leavemessage with ignorewarnings is supported $job->run(); diff --git a/tests/phpunit/includes/upload/UploadStashTest.php b/tests/phpunit/includes/upload/UploadStashTest.php index e644a259..c9dbb138 100644 --- a/tests/phpunit/includes/upload/UploadStashTest.php +++ b/tests/phpunit/includes/upload/UploadStashTest.php @@ -1,5 +1,7 @@ <?php - +/** + * @group Database + */ class UploadStashTest extends MediaWikiTestCase { /** * @var Array of UploadStashTestUser @@ -8,49 +10,68 @@ class UploadStashTest extends MediaWikiTestCase { public function setUp() { parent::setUp(); - + // Setup a file for bug 29408 $this->bug29408File = dirname( __FILE__ ) . '/bug29408'; - file_put_contents( $this->bug29408File, "\x00" ); - + file_put_contents( $this->bug29408File, "\x00" ); + self::$users = array( 'sysop' => new ApiTestUser( 'Uploadstashtestsysop', 'Upload Stash Test Sysop', - 'upload_stash_test_sysop@sample.com', + 'upload_stash_test_sysop@example.com', array( 'sysop' ) ), 'uploader' => new ApiTestUser( 'Uploadstashtestuser', 'Upload Stash Test User', - 'upload_stash_test_user@sample.com', + 'upload_stash_test_user@example.com', array() ) ); } - /** - * @group Database - */ public function testBug29408() { global $wgUser; $wgUser = self::$users['uploader']->user; - + $repo = RepoGroup::singleton()->getLocalRepo(); $stash = new UploadStash( $repo ); - + // Throws exception caught by PHPUnit on failure $file = $stash->stashFile( $this->bug29408File ); // We'll never reach this point if we hit bug 29408 $this->assertTrue( true, 'Unrecognized file without extension' ); - + $stash->removeFile( $file->getFileKey() ); } - + + public function testValidRequest() { + $request = new FauxRequest( array( 'wpFileKey' => 'foo') ); + $this->assertFalse( UploadFromStash::isValidRequest($request), 'Check failure on bad wpFileKey' ); + + $request = new FauxRequest( array( 'wpSessionKey' => 'foo') ); + $this->assertFalse( UploadFromStash::isValidRequest($request), 'Check failure on bad wpSessionKey' ); + + $request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test') ); + $this->assertTrue( UploadFromStash::isValidRequest($request), 'Check good wpFileKey' ); + + $request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test') ); + $this->assertTrue( UploadFromStash::isValidRequest($request), 'Check good wpSessionKey' ); + + $request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test', 'wpSessionKey' => 'foo') ); + $this->assertTrue( UploadFromStash::isValidRequest($request), 'Check key precedence' ); + } + public function tearDown() { parent::tearDown(); - - unlink( $this->bug29408File . "." ); - + + if( file_exists( $this->bug29408File . "." ) ) { + unlink( $this->bug29408File . "." ); + } + + if( file_exists( $this->bug29408File ) ) { + unlink( $this->bug29408File ); + } } } diff --git a/tests/phpunit/includes/upload/UploadTest.php b/tests/phpunit/includes/upload/UploadTest.php index 69c29032..4293d23b 100644 --- a/tests/phpunit/includes/upload/UploadTest.php +++ b/tests/phpunit/includes/upload/UploadTest.php @@ -20,53 +20,14 @@ class UploadTest extends MediaWikiTestCase { $wgHooks = $this->hooks; } - /** - * Test various forms of valid and invalid titles that can be supplied. - */ - public function testTitleValidation() { - - - /* Test a valid title */ - $this->assertUploadTitleAndCode( 'ValidTitle.jpg', - 'ValidTitle.jpg', UploadBase::OK, - 'upload valid title' ); - - /* A title with a slash */ - $this->assertUploadTitleAndCode( 'A/B.jpg', - 'B.jpg', UploadBase::OK, - 'upload title with slash' ); - - /* A title with illegal char */ - $this->assertUploadTitleAndCode( 'A:B.jpg', - 'A-B.jpg', UploadBase::OK, - 'upload title with colon' ); - - /* Stripping leading File: prefix */ - $this->assertUploadTitleAndCode( 'File:C.jpg', - 'C.jpg', UploadBase::OK, - 'upload title with File prefix' ); - /* Test illegal suggested title (r94601) */ - $this->assertUploadTitleAndCode( '%281%29.JPG', - null, UploadBase::ILLEGAL_FILENAME, - 'illegal title for upload' ); - - /* A title without extension */ - $this->assertUploadTitleAndCode( 'A', - null, UploadBase::FILETYPE_MISSING, - 'upload title without extension' ); - - /* A title with no basename */ - $this->assertUploadTitleAndCode( '.jpg', - null, UploadBase::MIN_LENGTH_PARTNAME, - 'upload title without basename' ); - - } /** - * Helper function for testTitleValidation. First checks the return code - * of UploadBase::getTitle() and then the actual returned titl + * First checks the return code + * of UploadBase::getTitle() and then the actual returned title + * + * @dataProvider dataTestTitleValidation */ - private function assertUploadTitleAndCode( $srcFilename, $dstFilename, $code, $msg ) { + public function testTitleValidation( $srcFilename, $dstFilename, $code, $msg ) { /* Check the result code */ $this->assertEquals( $code, $this->upload->testTitleValidation( $srcFilename ), @@ -79,6 +40,41 @@ class UploadTest extends MediaWikiTestCase { "$msg text" ); } } + + /** + * Test various forms of valid and invalid titles that can be supplied. + */ + public function dataTestTitleValidation() { + return array( + /* Test a valid title */ + array( 'ValidTitle.jpg', 'ValidTitle.jpg', UploadBase::OK, + 'upload valid title' ), + /* A title with a slash */ + array( 'A/B.jpg', 'B.jpg', UploadBase::OK, + 'upload title with slash' ), + /* A title with illegal char */ + array( 'A:B.jpg', 'A-B.jpg', UploadBase::OK, + 'upload title with colon' ), + /* Stripping leading File: prefix */ + array( 'File:C.jpg', 'C.jpg', UploadBase::OK, + 'upload title with File prefix' ), + /* Test illegal suggested title (r94601) */ + array( '%281%29.JPG', null, UploadBase::ILLEGAL_FILENAME, + 'illegal title for upload' ), + /* A title without extension */ + array( 'A', null, UploadBase::FILETYPE_MISSING, + 'upload title without extension' ), + /* A title with no basename */ + array( '.jpg', null, UploadBase::MIN_LENGTH_PARTNAME, + 'upload title without basename' ), + /* A title that is longer than 255 bytes */ + array( str_repeat( 'a', 255 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG, + 'upload title longer than 255 bytes' ), + /* A title that is longer than 240 bytes */ + array( str_repeat( 'a', 240 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG, + 'upload title longer than 240 bytes' ), + ); + } /** * Test the upload verification functions @@ -104,7 +100,7 @@ class UploadTest extends MediaWikiTestCase { } /** - * test uploading a 100 bytes file with wgMaxUploadSize = 100 + * test uploading a 100 bytes file with $wgMaxUploadSize = 100 * * This method should be abstracted so we can test different settings. */ @@ -134,6 +130,7 @@ class UploadTestHandler extends UploadBase { public function testTitleValidation( $name ) { $this->mTitle = false; $this->mDesiredDestName = $name; + $this->mTitleError = UploadBase::OK; $this->getTitle(); return $this->mTitleError; } |