From 9db190c7e736ec8d063187d4241b59feaf7dc2d1 Mon Sep 17 00:00:00 2001
From: Pierre Schmitz
Date: Wed, 22 Jun 2011 11:28:20 +0200
Subject: update to MediaWiki 1.17.0
---
maintenance/tests/ApiSetup.php | 39 -
maintenance/tests/ApiTest.php | 164 -
maintenance/tests/CdbTest.php | 79 -
maintenance/tests/DatabaseSqliteTest.php | 57 -
maintenance/tests/DatabaseTest.php | 92 -
maintenance/tests/GlobalTest.php | 212 -
maintenance/tests/HttpTest.php | 567 --
maintenance/tests/IPTest.php | 52 -
maintenance/tests/ImageFunctionsTest.php | 48 -
maintenance/tests/LanguageConverterTest.php | 148 -
maintenance/tests/LicensesTest.php | 17 -
maintenance/tests/LocalFileTest.php | 97 -
maintenance/tests/Makefile | 23 -
maintenance/tests/MediaWikiParserTest.php | 283 -
maintenance/tests/MediaWiki_Setup.php | 28 -
maintenance/tests/README | 24 -
maintenance/tests/RevisionTest.php | 114 -
maintenance/tests/RunSeleniumTests.php | 220 +
maintenance/tests/SanitizerTest.php | 73 -
maintenance/tests/SearchEngineTest.php | 138 -
maintenance/tests/SearchMySQLTest.php | 26 -
maintenance/tests/SearchUpdateTest.php | 103 -
maintenance/tests/SiteConfigurationTest.php | 311 -
maintenance/tests/TimeAdjustTest.php | 40 -
maintenance/tests/TitleTest.php | 17 -
maintenance/tests/XmlTest.php | 115 -
maintenance/tests/bootstrap.php | 15 -
maintenance/tests/parser/ExtraParserTests.txt | Bin 0 -> 1261 bytes
maintenance/tests/parser/parserTest.inc | 1305 +++
maintenance/tests/parser/parserTests.txt | 8315 ++++++++++++++++++++
maintenance/tests/parser/parserTestsParserHook.php | 46 +
.../tests/parser/parserTestsStaticParserHook.php | 58 +
maintenance/tests/parserTests.php | 92 +
maintenance/tests/phpunit.xml | 17 -
maintenance/tests/selenium/Selenium.php | 190 +
maintenance/tests/selenium/SeleniumConfig.php | 88 +
maintenance/tests/selenium/SeleniumLoader.php | 9 +
.../tests/selenium/SeleniumServerManager.php | 239 +
maintenance/tests/selenium/SeleniumTestCase.php | 103 +
.../tests/selenium/SeleniumTestConsoleLogger.php | 25 +
.../tests/selenium/SeleniumTestHTMLLogger.php | 36 +
.../tests/selenium/SeleniumTestListener.php | 68 +
maintenance/tests/selenium/SeleniumTestSuite.php | 46 +
.../tests/selenium/data/Wikipedia-logo-v2-de.png | Bin 0 -> 21479 bytes
.../selenium/selenium_settings.ini.php52.sample | 23 +
.../tests/selenium/selenium_settings.ini.sample | 32 +
.../selenium/selenium_settings_grid.ini.sample | 14 +
.../suites/AddContentToNewPageTestCase.php | 182 +
.../tests/selenium/suites/AddNewPageTestCase.php | 65 +
.../selenium/suites/CreateAccountTestCase.php | 114 +
.../selenium/suites/DeletePageAdminTestCase.php | 89 +
.../selenium/suites/EmailPasswordTestCase.php | 81 +
.../selenium/suites/MediaWikExtraTestSuite.php | 20 +
.../selenium/suites/MediaWikiEditorConfig.php | 47 +
.../selenium/suites/MediaWikiEditorTestSuite.php | 18 +
.../selenium/suites/MediawikiCoreSmokeTestCase.php | 69 +
.../suites/MediawikiCoreSmokeTestSuite.php | 19 +
.../tests/selenium/suites/MovePageTestCase.php | 117 +
.../selenium/suites/MyContributionsTestCase.php | 76 +
.../tests/selenium/suites/MyWatchListTestCase.php | 73 +
.../tests/selenium/suites/PageDeleteTestSuite.php | 16 +
.../tests/selenium/suites/PageSearchTestCase.php | 105 +
.../tests/selenium/suites/PreviewPageTestCase.php | 53 +
.../tests/selenium/suites/SavePageTestCase.php | 58 +
.../tests/selenium/suites/SimpleSeleniumConfig.php | 15 +
.../selenium/suites/SimpleSeleniumTestCase.php | 30 +
.../selenium/suites/SimpleSeleniumTestSuite.php | 26 +
.../selenium/suites/UserPreferencesTestCase.php | 179 +
maintenance/tests/test-prefetch-current.xml | 75 -
maintenance/tests/test-prefetch-previous.xml | 57 -
maintenance/tests/test-prefetch-stub.xml | 75 -
maintenance/tests/testHelpers.inc | 652 ++
72 files changed, 13013 insertions(+), 3106 deletions(-)
delete mode 100644 maintenance/tests/ApiSetup.php
delete mode 100644 maintenance/tests/ApiTest.php
delete mode 100644 maintenance/tests/CdbTest.php
delete mode 100644 maintenance/tests/DatabaseSqliteTest.php
delete mode 100644 maintenance/tests/DatabaseTest.php
delete mode 100644 maintenance/tests/GlobalTest.php
delete mode 100644 maintenance/tests/HttpTest.php
delete mode 100644 maintenance/tests/IPTest.php
delete mode 100644 maintenance/tests/ImageFunctionsTest.php
delete mode 100644 maintenance/tests/LanguageConverterTest.php
delete mode 100644 maintenance/tests/LicensesTest.php
delete mode 100644 maintenance/tests/LocalFileTest.php
delete mode 100644 maintenance/tests/Makefile
delete mode 100644 maintenance/tests/MediaWikiParserTest.php
delete mode 100644 maintenance/tests/MediaWiki_Setup.php
delete mode 100644 maintenance/tests/README
delete mode 100644 maintenance/tests/RevisionTest.php
create mode 100644 maintenance/tests/RunSeleniumTests.php
delete mode 100644 maintenance/tests/SanitizerTest.php
delete mode 100644 maintenance/tests/SearchEngineTest.php
delete mode 100644 maintenance/tests/SearchMySQLTest.php
delete mode 100644 maintenance/tests/SearchUpdateTest.php
delete mode 100644 maintenance/tests/SiteConfigurationTest.php
delete mode 100644 maintenance/tests/TimeAdjustTest.php
delete mode 100644 maintenance/tests/TitleTest.php
delete mode 100644 maintenance/tests/XmlTest.php
delete mode 100644 maintenance/tests/bootstrap.php
create mode 100644 maintenance/tests/parser/ExtraParserTests.txt
create mode 100644 maintenance/tests/parser/parserTest.inc
create mode 100644 maintenance/tests/parser/parserTests.txt
create mode 100644 maintenance/tests/parser/parserTestsParserHook.php
create mode 100644 maintenance/tests/parser/parserTestsStaticParserHook.php
create mode 100644 maintenance/tests/parserTests.php
delete mode 100644 maintenance/tests/phpunit.xml
create mode 100644 maintenance/tests/selenium/Selenium.php
create mode 100644 maintenance/tests/selenium/SeleniumConfig.php
create mode 100644 maintenance/tests/selenium/SeleniumLoader.php
create mode 100644 maintenance/tests/selenium/SeleniumServerManager.php
create mode 100644 maintenance/tests/selenium/SeleniumTestCase.php
create mode 100644 maintenance/tests/selenium/SeleniumTestConsoleLogger.php
create mode 100644 maintenance/tests/selenium/SeleniumTestHTMLLogger.php
create mode 100644 maintenance/tests/selenium/SeleniumTestListener.php
create mode 100644 maintenance/tests/selenium/SeleniumTestSuite.php
create mode 100644 maintenance/tests/selenium/data/Wikipedia-logo-v2-de.png
create mode 100644 maintenance/tests/selenium/selenium_settings.ini.php52.sample
create mode 100644 maintenance/tests/selenium/selenium_settings.ini.sample
create mode 100644 maintenance/tests/selenium/selenium_settings_grid.ini.sample
create mode 100644 maintenance/tests/selenium/suites/AddContentToNewPageTestCase.php
create mode 100644 maintenance/tests/selenium/suites/AddNewPageTestCase.php
create mode 100644 maintenance/tests/selenium/suites/CreateAccountTestCase.php
create mode 100644 maintenance/tests/selenium/suites/DeletePageAdminTestCase.php
create mode 100644 maintenance/tests/selenium/suites/EmailPasswordTestCase.php
create mode 100644 maintenance/tests/selenium/suites/MediaWikExtraTestSuite.php
create mode 100644 maintenance/tests/selenium/suites/MediaWikiEditorConfig.php
create mode 100644 maintenance/tests/selenium/suites/MediaWikiEditorTestSuite.php
create mode 100644 maintenance/tests/selenium/suites/MediawikiCoreSmokeTestCase.php
create mode 100644 maintenance/tests/selenium/suites/MediawikiCoreSmokeTestSuite.php
create mode 100644 maintenance/tests/selenium/suites/MovePageTestCase.php
create mode 100644 maintenance/tests/selenium/suites/MyContributionsTestCase.php
create mode 100644 maintenance/tests/selenium/suites/MyWatchListTestCase.php
create mode 100644 maintenance/tests/selenium/suites/PageDeleteTestSuite.php
create mode 100644 maintenance/tests/selenium/suites/PageSearchTestCase.php
create mode 100644 maintenance/tests/selenium/suites/PreviewPageTestCase.php
create mode 100644 maintenance/tests/selenium/suites/SavePageTestCase.php
create mode 100644 maintenance/tests/selenium/suites/SimpleSeleniumConfig.php
create mode 100644 maintenance/tests/selenium/suites/SimpleSeleniumTestCase.php
create mode 100644 maintenance/tests/selenium/suites/SimpleSeleniumTestSuite.php
create mode 100644 maintenance/tests/selenium/suites/UserPreferencesTestCase.php
delete mode 100644 maintenance/tests/test-prefetch-current.xml
delete mode 100644 maintenance/tests/test-prefetch-previous.xml
delete mode 100644 maintenance/tests/test-prefetch-stub.xml
create mode 100644 maintenance/tests/testHelpers.inc
(limited to 'maintenance/tests')
diff --git a/maintenance/tests/ApiSetup.php b/maintenance/tests/ApiSetup.php
deleted file mode 100644
index 549d8aef..00000000
--- a/maintenance/tests/ApiSetup.php
+++ /dev/null
@@ -1,39 +0,0 @@
-getID() ) {
- self::$user = User::createNew(self::$userName, array(
- "password" => self::$passWord,
- "email" => "test@example.com",
- "real_name" => "Test User"));
- } else {
- self::$user->setPassword(self::$passWord);
- }
- self::$user->saveSettings();
- }
- }
-}
diff --git a/maintenance/tests/ApiTest.php b/maintenance/tests/ApiTest.php
deleted file mode 100644
index d098b1a2..00000000
--- a/maintenance/tests/ApiTest.php
+++ /dev/null
@@ -1,164 +0,0 @@
- null,
- 'enablechunks' => false,
- 'sessionkey' => null,
- );
- }
-
-
-}
-
-
-class ApiTest extends ApiSetup {
-
- function setup() {
- parent::setup();
- }
-
- function testRequireOnlyOneParameterDefault() {
- $mock = new MockApi();
-
- $this->assertEquals(
- null, $mock->requireOnlyOneParameter(array("filename" => "foo.txt",
- "enablechunks" => false), "filename", "enablechunks"));
- }
-
- /**
- * @expectedException UsageException
- */
- function testRequireOnlyOneParameterZero() {
- $mock = new MockApi();
-
- $this->assertEquals(
- null, $mock->requireOnlyOneParameter(array("filename" => "foo.txt",
- "enablechunks" => 0), "filename", "enablechunks"));
- }
-
- /**
- * @expectedException UsageException
- */
- function testRequireOnlyOneParameterTrue() {
- $mock = new MockApi();
-
- $this->assertEquals(
- null, $mock->requireOnlyOneParameter(array("filename" => "foo.txt",
- "enablechunks" => true), "filename", "enablechunks"));
- }
-
- function testApi() {
- if(!isset($wgServername) || !isset($wgServer)) {
- $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '.
- 'be set in LocalSettings.php');
- }
- /* Haven't thought about test ordering yet -- but this depends on HttpTest.php */
- $resp = Http::get( self::$apiUrl . "?format=xml" );
-
- libxml_use_internal_errors( true );
- $sxe = simplexml_load_string( $resp );
- $this->assertNotType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
- }
-
- function testApiLoginNoName() {
- if(!isset($wgServername) || !isset($wgServer)) {
- $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '.
- 'be set in LocalSettings.php');
- }
- $resp = Http::post( self::$apiUrl . "?action=login&format=xml",
- array( "postData" => array(
- "lgname" => "",
- "lgpassword" => self::$passWord ) ) );
- libxml_use_internal_errors( true );
- $sxe = simplexml_load_string( $resp );
- $this->assertNotType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
- $a = $sxe->login[0]->attributes()->result;
- $this->assertEquals( ' result="NoName"', $a->asXML() );
- }
-
- function testApiLoginBadPass() {
- if(!isset($wgServername) || !isset($wgServer)) {
- $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '.
- 'be set in LocalSettings.php');
- }
- $resp = Http::post( self::$apiUrl . "?action=login&format=xml",
- array( "postData" => array(
- "lgname" => self::$userName,
- "lgpassword" => "bad" ) ) );
- libxml_use_internal_errors( true );
- $sxe = simplexml_load_string( $resp );
- $this->assertNotType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
- $a = $sxe->login[0]->attributes()->result;
- $this->assertEquals( ' result="WrongPass"', $a->asXML() );
- }
-
- function testApiLoginGoodPass() {
- if(!isset($wgServername) || !isset($wgServer)) {
- $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '.
- 'be set in LocalSettings.php');
- }
- $resp = Http::post( self::$apiUrl . "?action=login&format=xml",
- array( "postData" => array(
- "lgname" => self::$userName,
- "lgpassword" => self::$passWord ) ) );
- libxml_use_internal_errors( true );
- $sxe = simplexml_load_string( $resp );
- $this->assertNotType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
- $a = $sxe->login[0]->attributes()->result;
- $this->assertEquals( ' result="Success"', $a->asXML() );
- }
-
- function testApiGotCookie() {
- global $wgScriptPath, $wgServerName;
-
- if(!isset($wgServername) || !isset($wgServer)) {
- $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '.
- 'be set in LocalSettings.php');
- }
- $req = HttpRequest::factory( self::$apiUrl . "?action=login&format=xml",
- array( "method" => "POST",
- "postData" => array( "lgname" => self::$userName,
- "lgpassword" => self::$passWord ) ) );
- $req->execute();
- $cj = $req->getCookieJar();
- $this->assertRegexp( '/_session=[^;]*; .*UserID=[0-9]*; .*UserName=' . self::$userName . '; .*Token=/',
- $cj->serializeToHttpRequest( $wgScriptPath, $wgServerName ) );
-
-
- return $cj;
- }
-
- /**
- * @depends testApiGotCookie
- */
- function testApiListPages(CookieJar $cj) {
- $this->markTestIncomplete("Not done with this yet");
-
- if($wgServerName == "localhost" || $wgServer == "http://localhost") {
- $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '.
- 'be set in LocalSettings.php');
- }
- $req = HttpRequest::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->assertNotType( "bool", $sxe );
- $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
- $a = $sxe->query[0]->pages[0]->page[0]->attributes();
- }
-}
diff --git a/maintenance/tests/CdbTest.php b/maintenance/tests/CdbTest.php
deleted file mode 100644
index 444229e7..00000000
--- a/maintenance/tests/CdbTest.php
+++ /dev/null
@@ -1,79 +0,0 @@
-markTestIncomplete( 'This test requires native CDB support to be present.' );
- }
- }
-
- public function testCdb() {
- $w1 = new CdbWriter_PHP( 'php.cdb' );
- $w2 = new CdbWriter_DBA( 'dba.cdb' );
-
- $data = array();
- for ( $i = 0; $i < 1000; $i++ ) {
- $key = $this->randomString();
- $value = $this->randomString();
- $w1->set( $key, $value );
- $w2->set( $key, $value );
-
- if ( !isset( $data[$key] ) ) {
- $data[$key] = $value;
- }
- }
-
- $w1->close();
- $w2->close();
-
- $this->assertEquals(
- md5_file( 'dba.cdb' ),
- md5_file( 'php.cdb' ),
- 'same hash'
- );
-
- $r1 = new CdbReader_PHP( 'php.cdb' );
- $r2 = new CdbReader_DBA( 'dba.cdb' );
-
- foreach ( $data as $key => $value ) {
- if ( $key === '' ) {
- // Known bug
- continue;
- }
- $v1 = $r1->get( $key );
- $v2 = $r2->get( $key );
-
- $v1 = $v1 === false ? '(not found)' : $v1;
- $v2 = $v2 === false ? '(not found)' : $v2;
-
- #cdbAssert( 'Mismatch', $key, $v1, $v2 );
- $this->cdbAssert( "PHP error", $key, $v1, $value );
- $this->cdbAssert( "DBA error", $key, $v2, $value );
- }
-
- unlink( 'dba.cdb' );
- unlink( 'php.cdb' );
- }
-
- private function randomString() {
- $len = mt_rand( 0, 10 );
- $s = '';
- for ( $j = 0; $j < $len; $j++ ) {
- $s .= chr( mt_rand( 0, 255 ) );
- }
- return $s;
- }
-
- private function cdbAssert( $msg, $key, $v1, $v2 ) {
- $this->assertEquals(
- $v2,
- $v1,
- $msg . ', k=' . bin2hex( $key )
- );
- }
-}
diff --git a/maintenance/tests/DatabaseSqliteTest.php b/maintenance/tests/DatabaseSqliteTest.php
deleted file mode 100644
index 011ef798..00000000
--- a/maintenance/tests/DatabaseSqliteTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-lastQuery = $sql;
- return true;
- }
-
- function replaceVars( $s ) {
- return parent::replaceVars( $s );
- }
-}
-
-class DatabaseSqliteTest extends PHPUnit_Framework_TestCase {
- var $db;
-
- function setup() {
- if ( !extension_loaded( 'pdo_sqlite' ) ) {
- $this->markTestIncomplete( 'No SQLite support detected' );
- }
- $this->db = new MockDatabaseSqlite();
- }
-
- function replaceVars( $sql ) {
- // normalize spacing to hide implementation details
- return preg_replace( '/\s+/', ' ', $this->db->replaceVars( $sql ) );
- }
-
- function testReplaceVars() {
- $this->assertEquals( 'foo', $this->replaceVars( 'foo' ), "Don't break anything accidentally" );
-
- $this->assertEquals( "CREATE TABLE /**/foo (foo_key INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
- . "foo_name TEXT NOT NULL DEFAULT '', foo_int INTEGER, foo_int2 INTEGER );",
- $this->replaceVars( "CREATE TABLE /**/foo (foo_key int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
- foo_name varchar(255) binary NOT NULL DEFAULT '', foo_int tinyint( 8 ), foo_int2 int(16) ) ENGINE=MyISAM;" )
- );
-
- $this->assertEquals( "CREATE TABLE foo ( foo_binary1 BLOB, foo_binary2 BLOB );",
- $this->replaceVars( "CREATE TABLE foo ( foo_binary1 binary(16), foo_binary2 varbinary(32) );" )
- );
-
- $this->assertEquals( "CREATE TABLE text ( text_foo TEXT );",
- $this->replaceVars( "CREATE TABLE text ( text_foo tinytext );" ),
- 'Table name changed'
- );
-
- $this->assertEquals( "ALTER TABLE foo ADD COLUMN foo_bar INTEGER DEFAULT 42",
- $this->replaceVars( "ALTER TABLE foo\nADD COLUMN foo_bar int(10) unsigned DEFAULT 42")
- );
- }
-}
\ No newline at end of file
diff --git a/maintenance/tests/DatabaseTest.php b/maintenance/tests/DatabaseTest.php
deleted file mode 100644
index aa50de2e..00000000
--- a/maintenance/tests/DatabaseTest.php
+++ /dev/null
@@ -1,92 +0,0 @@
-db = wfGetDB( DB_SLAVE );
- }
-
- function testAddQuotesNull() {
- $check = "NULL";
- if ( $this->db->getType() === 'sqlite' ) {
- $check = "''";
- }
- $this->assertEquals( $check, $this->db->addQuotes( null ) );
- }
-
- function testAddQuotesInt() {
- # returning just "1234" should be ok too, though...
- # maybe
- $this->assertEquals(
- "'1234'",
- $this->db->addQuotes( 1234 ) );
- }
-
- function testAddQuotesFloat() {
- # returning just "1234.5678" would be ok too, though
- $this->assertEquals(
- "'1234.5678'",
- $this->db->addQuotes( 1234.5678 ) );
- }
-
- function testAddQuotesString() {
- $this->assertEquals(
- "'string'",
- $this->db->addQuotes( 'string' ) );
- }
-
- function testAddQuotesStringQuote() {
- $check = "'string''s cause trouble'";
- if ( $this->db->getType() === 'mysql' ) {
- $check = "'string\'s cause trouble'";
- }
- $this->assertEquals(
- $check,
- $this->db->addQuotes( "string's cause trouble" ) );
- }
-
- function testFillPreparedEmpty() {
- $sql = $this->db->fillPrepared(
- 'SELECT * FROM interwiki', array() );
- $this->assertEquals(
- "SELECT * FROM interwiki",
- $sql);
- }
-
- function testFillPreparedQuestion() {
- $sql = $this->db->fillPrepared(
- 'SELECT * FROM cur WHERE cur_namespace=? AND cur_title=?',
- array( 4, "Snicker's_paradox" ) );
-
- $check = "SELECT * FROM cur WHERE cur_namespace='4' AND cur_title='Snicker''s_paradox'";
- if ( $this->db->getType() === 'mysql' ) {
- $check = "SELECT * FROM cur WHERE cur_namespace='4' AND cur_title='Snicker\'s_paradox'";
- }
- $this->assertEquals( $check, $sql );
- }
-
- function testFillPreparedBang() {
- $sql = $this->db->fillPrepared(
- 'SELECT user_id FROM ! WHERE user_name=?',
- array( '"user"', "Slash's Dot" ) );
-
- $check = "SELECT user_id FROM \"user\" WHERE user_name='Slash''s Dot'";
- if ( $this->db->getType() === 'mysql' ) {
- $check = "SELECT user_id FROM \"user\" WHERE user_name='Slash\'s Dot'";
- }
- $this->assertEquals( $check, $sql );
- }
-
- function testFillPreparedRaw() {
- $sql = $this->db->fillPrepared(
- "SELECT * FROM cur WHERE cur_title='This_\\&_that,_WTF\\?\\!'",
- array( '"user"', "Slash's Dot" ) );
- $this->assertEquals(
- "SELECT * FROM cur WHERE cur_title='This_&_that,_WTF?!'",
- $sql);
- }
-
-}
-
-
diff --git a/maintenance/tests/GlobalTest.php b/maintenance/tests/GlobalTest.php
deleted file mode 100644
index ec694241..00000000
--- a/maintenance/tests/GlobalTest.php
+++ /dev/null
@@ -1,212 +0,0 @@
-originals['wgReadOnlyFile'] = $wgReadOnlyFile;
- $wgReadOnlyFile = tempnam(wfTempDir(), "mwtest_readonly");
- unlink( $wgReadOnlyFile );
- }
-
- function tearDown() {
- global $wgReadOnlyFile;
- if( file_exists( $wgReadOnlyFile ) ) {
- unlink( $wgReadOnlyFile );
- }
- $wgReadOnlyFile = $this->originals['wgReadOnlyFile'];
- }
-
- function testRandom() {
- # This could hypothetically fail, but it shouldn't ;)
- $this->assertFalse(
- wfRandom() == wfRandom() );
- }
-
- function testUrlencode() {
- $this->assertEquals(
- "%E7%89%B9%E5%88%A5:Contributions/Foobar",
- wfUrlencode( "\xE7\x89\xB9\xE5\x88\xA5:Contributions/Foobar" ) );
- }
-
- function testReadOnlyEmpty() {
- global $wgReadOnly;
- $wgReadOnly = null;
-
- $this->assertFalse( wfReadOnly() );
- $this->assertFalse( wfReadOnly() );
- }
-
- function testReadOnlySet() {
- global $wgReadOnly, $wgReadOnlyFile;
-
- $f = fopen( $wgReadOnlyFile, "wt" );
- fwrite( $f, 'Message' );
- fclose( $f );
- $wgReadOnly = null;
-
- $this->assertTrue( wfReadOnly() );
- $this->assertTrue( wfReadOnly() );
-
- unlink( $wgReadOnlyFile );
- $wgReadOnly = null;
-
- $this->assertFalse( wfReadOnly() );
- $this->assertFalse( wfReadOnly() );
- }
-
- function testQuotedPrintable() {
- $this->assertEquals(
- "=?UTF-8?Q?=C4=88u=20legebla=3F?=",
- wfQuotedPrintable( "\xc4\x88u legebla?", "UTF-8" ) );
- }
-
- function testTime() {
- $start = wfTime();
- $this->assertType( 'float', $start );
- $end = wfTime();
- $this->assertTrue( $end > $start, "Time is running backwards!" );
- }
-
- function testArrayToCGI() {
- $this->assertEquals(
- "baz=AT%26T&foo=bar",
- wfArrayToCGI(
- array( 'baz' => 'AT&T', 'ignore' => '' ),
- array( 'foo' => 'bar', 'baz' => 'overridden value' ) ) );
- }
-
- function testMimeTypeMatch() {
- $this->assertEquals(
- 'text/html',
- mimeTypeMatch( 'text/html',
- array( 'application/xhtml+xml' => 1.0,
- 'text/html' => 0.7,
- 'text/plain' => 0.3 ) ) );
- $this->assertEquals(
- 'text/*',
- mimeTypeMatch( 'text/html',
- array( 'image/*' => 1.0,
- 'text/*' => 0.5 ) ) );
- $this->assertEquals(
- '*/*',
- mimeTypeMatch( 'text/html',
- array( '*/*' => 1.0 ) ) );
- $this->assertNull(
- mimeTypeMatch( 'text/html',
- array( 'image/png' => 1.0,
- 'image/svg+xml' => 0.5 ) ) );
- }
-
- function testNegotiateType() {
- $this->assertEquals(
- 'text/html',
- wfNegotiateType(
- array( 'application/xhtml+xml' => 1.0,
- 'text/html' => 0.7,
- 'text/plain' => 0.5,
- 'text/*' => 0.2 ),
- array( 'text/html' => 1.0 ) ) );
- $this->assertEquals(
- 'application/xhtml+xml',
- wfNegotiateType(
- array( 'application/xhtml+xml' => 1.0,
- 'text/html' => 0.7,
- 'text/plain' => 0.5,
- 'text/*' => 0.2 ),
- array( 'application/xhtml+xml' => 1.0,
- 'text/html' => 0.5 ) ) );
- $this->assertEquals(
- 'text/html',
- wfNegotiateType(
- array( 'text/html' => 1.0,
- 'text/plain' => 0.5,
- 'text/*' => 0.5,
- 'application/xhtml+xml' => 0.2 ),
- array( 'application/xhtml+xml' => 1.0,
- 'text/html' => 0.5 ) ) );
- $this->assertEquals(
- 'text/html',
- wfNegotiateType(
- array( 'text/*' => 1.0,
- 'image/*' => 0.7,
- '*/*' => 0.3 ),
- array( 'application/xhtml+xml' => 1.0,
- 'text/html' => 0.5 ) ) );
- $this->assertNull(
- wfNegotiateType(
- 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(
- 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(
- '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(
- '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' );
- }
-
- 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'");
- }
- }
-
- /* TODO: many more! */
-}
-
-
diff --git a/maintenance/tests/HttpTest.php b/maintenance/tests/HttpTest.php
deleted file mode 100644
index 83734910..00000000
--- a/maintenance/tests/HttpTest.php
+++ /dev/null
@@ -1,567 +0,0 @@
- "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 = HttpRequest::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 = HttpRequest::factory("http://www.example.com/");
- $this->assertThat($r, $this->isInstanceOf( 'PhpHttpRequest' ));
- unset($r);
-
- if( !self::$has_curl ) {
- $this->setExpectedException( 'MWException' );
- }
- Http::$httpEngine = 'curl';
- $r = HttpRequest::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.example.com/this-file-does-not-exist", $timeout);
- $this->assertFalse($r, "False on 404s");
-
-
- $r = HttpRequest::factory( "http://www.example.com/this-file-does-not-exist" );
- $er = $r->execute();
- if ( is_a($r, '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;
- self::runHTTPFailureChecks();
- }
-
- function testFailurePhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- self::runHTTPFailureChecks();
- }
-
- function testFailureCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- self::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;
- self::runHTTPRequests();
- }
-
- function testRequestPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- self::runHTTPRequests();
- }
-
- function testRequestCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- self::runHTTPRequests();
- }
-
- /* ./extensions/SpamBlacklist/SpamBlacklist_body.php:164: $httpText = Http::get( $fileName ); */
- /* ./extensions/ApiSVGProxy/ApiSVGProxy.body.php:44: $contents = Http::get( $file->getFullUrl() ); */
- /* ./extensions/BookInformation/drivers/IsbnDb.php:24: if( ( $xml = Http::get( $uri ) ) !== false ) { */
- /* ./extensions/BookInformation/drivers/Amazon.php:23: if( ( $xml = Http::get( $uri ) ) !== false ) { */
- /* ./extensions/TitleBlacklist/TitleBlacklist.list.php:217: $result = Http::get( $url ); */
- /* ./extensions/TSPoll/TSPoll.php:68: $get_server = Http::get( 'http://toolserver.org/~jan/poll/dev/main.php?page=wiki_output&id='.$id ); */
- /* ./extensions/TSPoll/TSPoll.php:70: $get_server = Http::get( 'http://toolserver.org/~jan/poll/main.php?page=wiki_output&id='.$id ); */
- /* ./extensions/DoubleWiki/DoubleWiki.php:56: $translation = Http::get( $url.$sep.'action=render' ); */
- /* ./extensions/ExternalPages/ExternalPages_body.php:177: $serializedText = Http::get( $this->mPageURL ); */
- /* ./extensions/Translate/utils/TranslationHelpers.php:143: $suggestions = Http::get( $url, $timeout ); */
- /* ./extensions/Translate/SpecialImportTranslations.php:169: $filedata = Http::get( $url ); ; */
- /* ./extensions/Translate/TranslateEditAddons.php:338: $suggestions = Http::get( $url, $timeout ); */
- /* ./extensions/SecurePoll/includes/user/Auth.php:283: $value = Http::get( $url, 20, $curlParams ); */
- /* ./extensions/DumpHTML/dumpHTML.inc:778: $contents = Http::get( $url ); */
- /* ./extensions/DumpHTML/dumpHTML.inc:1298: $contents = Http::get( $sourceUrl ); */
- /* ./extensions/DumpHTML/dumpHTML.inc:1373: $contents = Http::get( $sourceUrl ); */
- /* ./phase3/maintenance/rebuildInterwiki.inc:101: $intermap = Http::get( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); */
- /* ./phase3/maintenance/findhooks.php:98: $allhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php' ); */
- /* ./phase3/maintenance/findhooks.php:109: $oldhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Removed_hooks&cmlimit=500&format=php' ); */
- /* ./phase3/maintenance/dumpInterwiki.inc:95: $intermap = Http::get( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); */
- /* ./phase3/includes/parser/Parser.php:3204: $text = Http::get($url); */
- /* ./phase3/includes/filerepo/ForeignAPIRepo.php:131: $data = Http::get( $url ); */
- /* ./phase3/includes/filerepo/ForeignAPIRepo.php:205: $thumb = Http::get( $foreignUrl ); */
- /* ./phase3/includes/filerepo/File.php:1105: $res = Http::get( $renderUrl ); */
- /* ./phase3/includes/GlobalFunctions.php:2760: * @deprecated Use Http::get() instead */
- /* ./phase3/includes/GlobalFunctions.php:2764: return Http::get( $url ); */
- /* ./phase3/includes/ExternalStoreHttp.php:18: $ret = Http::get( $url ); */
- /* ./phase3/includes/Import.php:357: $data = Http::get( $src ); */
- /* ./extensions/ExternalData/ED_Utils.php:291: return Http::get( $url, 'default', array(CURLOPT_SSL_VERIFYPEER => false) ); */
- /* ./extensions/ExternalData/ED_Utils.php:293: return Http::get( $url ); */
- /* ./extensions/ExternalData/ED_Utils.php:306: $page = Http::get( $url, 'default', array(CURLOPT_SSL_VERIFYPEER => false) ); */
- /* ./extensions/ExternalData/ED_Utils.php:308: $page = Http::get( $url ); */
- /* ./extensions/CodeReview/backend/Subversion.php:320: $blob = Http::get( $target, $this->mTimeout ); */
- /* ./extensions/AmazonPlus/AmazonPlus.php:214: $this->response = Http::get( $urlstr ); */
- /* ./extensions/StaticWiki/StaticWiki.php:24: $text = Http::get( $url ) ; */
- /* ./extensions/StaticWiki/StaticWiki.php:64: $history = Http::get ( $wgStaticWikiExternalSite . "index.php?title=" . urlencode ( $url_title ) . "&action=history" ) ; */
- /* ./extensions/Configure/scripts/findSettings.php:126: $cont = Http::get( "http://www.mediawiki.org/w/index.php?title={$page}&action=raw" ); */
- /* ./extensions/TorBlock/TorBlock.class.php:148: $data = Http::get( $url ); */
- /* ./extensions/HoneypotIntegration/HoneypotIntegration.class.php:60: $data = Http::get( $wgHoneypotURLSource, 'default', */
- /* ./extensions/SemanticForms/includes/SF_Utils.inc:378: $page_contents = Http::get($url); */
- /* ./extensions/LocalisationUpdate/LocalisationUpdate.class.php:172: $basefilecontents = Http::get( $basefile ); */
- /* ./extensions/APC/SpecialAPC.php:245: $rss = Http::get( 'http://pecl.php.net/feeds/pkg_apc.rss' ); */
- /* ./extensions/Interlanguage/Interlanguage.php:56: $a = Http::get( $url ); */
- /* ./extensions/MWSearch/MWSearch_body.php:492: $data = Http::get( $searchUrl, $wgLuceneSearchTimeout, $httpOpts); */
- 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;
- self::runHTTPGets();
- }
-
- function testGetPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- self::runHTTPGets();
- }
-
- function testGetCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- self::runHTTPGets();
- }
-
- /* ./phase3/maintenance/parserTests.inc:1618: return Http::post( $url, array( 'postData' => wfArrayToCGI( $data ) ) ); */
- 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;
- self::runHTTPPosts();
- }
-
- function testPostPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = "php";
- self::runHTTPPosts();
- }
-
- function testPostCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = "curl";
- self::runHTTPPosts();
- }
-
- function runProxyRequests() {
- if(!self::$has_proxy) {
- $this->markTestIncomplete( "This test requires a proxy." );
- }
- self::runHTTPGets(self::$proxy);
- self::runHTTPPosts(self::$proxy);
- self::runHTTPRequests(self::$proxy);
-
- // Set false here to do noProxy
- self::runHTTPGets(false);
- self::runHTTPPosts(false);
- self::runHTTPRequests(false);
- }
-
- function testProxyDefault() {
- Http::$httpEngine = false;
- self::runProxyRequests();
- }
-
- function testProxyPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = 'php';
- self::runProxyRequests();
- }
-
- function testProxyCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = 'curl';
- self::runProxyRequests();
- }
-
- function testIsLocalUrl() {
- }
-
- /* ./extensions/DonationInterface/payflowpro_gateway/payflowpro_gateway.body.php:559: $user_agent = Http::userAgent(); */
- function testUserAgent() {
- }
-
- function testIsValidUrl() {
- }
-
- function testValidateCookieDomain() {
- $this->assertFalse( Cookie::validateCookieDomain( "co.uk" ) );
- $this->assertFalse( Cookie::validateCookieDomain( ".co.uk" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "gov.uk" ) );
- $this->assertFalse( Cookie::validateCookieDomain( ".gov.uk" ) );
- $this->assertTrue( Cookie::validateCookieDomain( "supermarket.uk" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "uk" ) );
- $this->assertFalse( Cookie::validateCookieDomain( ".uk" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "127.0.0." ) );
- $this->assertFalse( Cookie::validateCookieDomain( "127." ) );
- $this->assertFalse( Cookie::validateCookieDomain( "127.0.0.1." ) );
- $this->assertTrue( Cookie::validateCookieDomain( "127.0.0.1" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "333.0.0.1" ) );
- $this->assertTrue( Cookie::validateCookieDomain( "example.com" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "example.com." ) );
- $this->assertTrue( Cookie::validateCookieDomain( ".example.com" ) );
-
- $this->assertTrue( Cookie::validateCookieDomain( ".example.com", "www.example.com" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "example.com", "www.example.com" ) );
- $this->assertTrue( Cookie::validateCookieDomain( "127.0.0.1", "127.0.0.1" ) );
- $this->assertFalse( Cookie::validateCookieDomain( "127.0.0.1", "localhost" ) );
-
-
- }
-
- 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 = HttpRequest::factory( "http://www.php.net/manual" );
- $r->execute();
-
- $jar = $r->getCookieJar();
- $this->assertThat( $jar, $this->isInstanceOf( 'CookieJar' ) );
-
- if ( is_a($r, 'PhpHttpRequest') && version_compare( '5.1.7', phpversion(), '>' ) ) {
- $this->markTestSkipped( 'Redirection fails or crashes PHP on 5.1.6 and prior' );
- }
- $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;
- self::runCookieRequests();
- }
- function testCookieRequestPhp() {
- if ( !self::$has_fopen ) {
- $this->markTestIncomplete( "This test requires allow_url_fopen=true." );
- }
-
- Http::$httpEngine = 'php';
- self::runCookieRequests();
- }
- function testCookieRequestCurl() {
- if ( !self::$has_curl ) {
- $this->markTestIncomplete( "This test requires curl." );
- }
-
- Http::$httpEngine = 'curl';
- self::runCookieRequests();
- }
-}
\ No newline at end of file
diff --git a/maintenance/tests/IPTest.php b/maintenance/tests/IPTest.php
deleted file mode 100644
index 9db77f72..00000000
--- a/maintenance/tests/IPTest.php
+++ /dev/null
@@ -1,52 +0,0 @@
-assertTrue( IP::isValid( $ip ) , "$ip is a valid IPv4 address" );
- }
- }
- }
-
- public function testInvalidIPs() {
- foreach ( range( 256, 999 ) as $i ) {
- $a = sprintf( "%03d", $i );
- $b = sprintf( "%02d", $i );
- $c = sprintf( "%01d", $i );
- foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
- $ip = "$f.$f.$f.$f";
- $this->assertFalse( IP::isValid( $ip ), "$ip is not a valid IPv4 address" );
- }
- }
- }
-
- public function testBogusIPs() {
- $invalid = array(
- 'www.xn--var-xla.net',
- '216.17.184.G',
- '216.17.184.1.',
- '216.17.184',
- '216.17.184.',
- '256.17.184.1'
- );
- foreach ( $invalid as $i ) {
- $this->assertFalse( IP::isValid( $i ), "$i is an invalid IPv4 address" );
- }
- }
-
- public function testPrivateIPs() {
- $private = array( '10.0.0.1', '172.16.0.1', '192.168.0.1' );
- foreach ( $private as $p ) {
- $this->assertFalse( IP::isPublic( $p ), "$p is not a public IP address" );
- }
- }
-}
diff --git a/maintenance/tests/ImageFunctionsTest.php b/maintenance/tests/ImageFunctionsTest.php
deleted file mode 100644
index 9794a2a2..00000000
--- a/maintenance/tests/ImageFunctionsTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
- 50,
- 'height' => 50,
- 'tests' => array(
- 50 => 50,
- 17 => 17,
- 18 => 18 ) ),
- array(
- 'width' => 366,
- 'height' => 300,
- 'tests' => array(
- 50 => 61,
- 17 => 21,
- 18 => 22 ) ),
- array(
- 'width' => 300,
- 'height' => 366,
- 'tests' => array(
- 50 => 41,
- 17 => 14,
- 18 => 15 ) ),
- array(
- 'width' => 100,
- 'height' => 400,
- 'tests' => array(
- 50 => 12,
- 17 => 4,
- 18 => 4 ) ) );
- foreach( $vals as $row ) {
- extract( $row );
- foreach( $tests as $max => $expected ) {
- $y = round( $expected * $height / $width );
- $result = wfFitBoxWidth( $width, $height, $max );
- $y2 = round( $result * $height / $width );
- $this->assertEquals( $expected,
- $result,
- "($width, $height, $max) wanted: {$expected}x$y, got: {$result}x$y2" );
- }
- }
- }
-}
-
-
diff --git a/maintenance/tests/LanguageConverterTest.php b/maintenance/tests/LanguageConverterTest.php
deleted file mode 100644
index 22b396e7..00000000
--- a/maintenance/tests/LanguageConverterTest.php
+++ /dev/null
@@ -1,148 +0,0 @@
-lang = new LanguageTest();
- $this->lc = new TestConverter( $this->lang, 'tg',
- array( 'tg', 'tg-latn' ) );
- }
-
- function tearDown() {
- global $wgMemc;
- unset($wgMemc);
- unset($this->lc);
- unset($this->lang);
- }
-
- function testGetPreferredVariantDefaults() {
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantHeaders() {
- global $wgRequest;
- $wgRequest->setHeader('Accept-Language', 'tg-latn');
-
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantHeaderWeight() {
- global $wgRequest;
- $wgRequest->setHeader('Accept-Language', 'tg;q=1');
-
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantHeaderWeight2() {
- global $wgRequest;
- $wgRequest->setHeader('Accept-Language', 'tg-latn;q=1');
-
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantHeaderMulti() {
- global $wgRequest;
- $wgRequest->setHeader('Accept-Language', 'en, tg-latn;q=1');
-
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantUserOption() {
- global $wgUser;
-
- $wgUser = new User;
- $wgUser->setId(1);
- $wgUser->setOption('variant', 'tg-latn');
-
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantHeaderUserVsUrl() {
- global $wgRequest, $wgUser, $wgContLang;
-
- $wgContLang = Language::factory( 'tg-latn' );
- $wgRequest->setVal('variant', 'tg');
- $wgUser = User::newFromId("admin");
- $wgUser->setId(1);
- $wgUser->setOption('variant', 'tg-latn'); // The user's data is ignored
- // because the variant is set in the URL.
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(true, true));
- }
-
-
- function testGetPreferredVariantDefaultLanguageVariant() {
- global $wgDefaultLanguageVariant;
-
- $wgDefaultLanguageVariant = 'tg-latn';
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
- }
-
- function testGetPreferredVariantDefaultLanguageVsUrlVariant() {
- global $wgDefaultLanguageVariant, $wgRequest, $wgContLang;
-
- $wgContLang = Language::factory( 'tg-latn' );
- $wgDefaultLanguageVariant = 'tg';
- $wgRequest->setVal('variant', null);
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, false));
- $this->assertEquals('tg', $this->lc->getPreferredVariant(false, true));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, false));
- $this->assertEquals('tg-latn', $this->lc->getPreferredVariant(true, true));
- }
-}
-
-/**
- * Test converter (from Tajiki to latin orthography)
- */
-class TestConverter extends LanguageConverter {
- private $table = array(
- 'б' => 'b',
- 'в' => 'v',
- 'г' => 'g',
- );
-
- function loadDefaultTables() {
- $this->mTables = array(
- 'tg-latn' => new ReplacementArray( $this->table ),
- 'tg' => new ReplacementArray()
- );
- }
-
-}
-
-class LanguageTest extends Language {
- function __construct() {
- parent::__construct();
- $variants = array( 'tg', 'tg-latn' );
- $this->mConverter = new TestConverter( $this, 'tg', $variants );
- }
-}
diff --git a/maintenance/tests/LicensesTest.php b/maintenance/tests/LicensesTest.php
deleted file mode 100644
index c5357f89..00000000
--- a/maintenance/tests/LicensesTest.php
+++ /dev/null
@@ -1,17 +0,0 @@
-assertTrue( is_a( $lc, 'Licenses' ), 'Correct class' );
- }
-}
\ No newline at end of file
diff --git a/maintenance/tests/LocalFileTest.php b/maintenance/tests/LocalFileTest.php
deleted file mode 100644
index e57798be..00000000
--- a/maintenance/tests/LocalFileTest.php
+++ /dev/null
@@ -1,97 +0,0 @@
- 'test',
- 'directory' => '/testdir',
- 'url' => '/testurl',
- 'hashLevels' => 2,
- 'transformVia404' => false,
- );
- $this->repo_hl0 = new LocalRepo( array( 'hashLevels' => 0 ) + $info );
- $this->repo_hl2 = new LocalRepo( array( 'hashLevels' => 2 ) + $info );
- $this->repo_lc = new LocalRepo( array( 'initialCapital' => false ) + $info );
- $this->file_hl0 = $this->repo_hl0->newFile( 'test!' );
- $this->file_hl2 = $this->repo_hl2->newFile( 'test!' );
- $this->file_lc = $this->repo_lc->newFile( 'test!' );
- }
-
- function tearDown() {
- global $wgContLang;
- unset($wgContLang);
- }
-
- function testGetHashPath() {
- $this->assertEquals( '', $this->file_hl0->getHashPath() );
- $this->assertEquals( 'a/a2/', $this->file_hl2->getHashPath() );
- $this->assertEquals( 'c/c4/', $this->file_lc->getHashPath() );
- }
-
- function testGetRel() {
- $this->assertEquals( 'Test!', $this->file_hl0->getRel() );
- $this->assertEquals( 'a/a2/Test!', $this->file_hl2->getRel() );
- $this->assertEquals( 'c/c4/test!', $this->file_lc->getRel() );
- }
-
- function testGetUrlRel() {
- $this->assertEquals( 'Test%21', $this->file_hl0->getUrlRel() );
- $this->assertEquals( 'a/a2/Test%21', $this->file_hl2->getUrlRel() );
- $this->assertEquals( 'c/c4/test%21', $this->file_lc->getUrlRel() );
- }
-
- 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( '!' ) );
- }
-
- 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' ) );
- }
-
- function testGetArchiveUrl() {
- $this->assertEquals( '/testurl/archive', $this->file_hl0->getArchiveUrl() );
- $this->assertEquals( '/testurl/archive/a/a2', $this->file_hl2->getArchiveUrl() );
- $this->assertEquals( '/testurl/archive/%21', $this->file_hl0->getArchiveUrl( '!' ) );
- $this->assertEquals( '/testurl/archive/a/a2/%21', $this->file_hl2->getArchiveUrl( '!' ) );
- }
-
- function testGetThumbUrl() {
- $this->assertEquals( '/testurl/thumb/Test%21', $this->file_hl0->getThumbUrl() );
- $this->assertEquals( '/testurl/thumb/a/a2/Test%21', $this->file_hl2->getThumbUrl() );
- $this->assertEquals( '/testurl/thumb/Test%21/x', $this->file_hl0->getThumbUrl( 'x' ) );
- $this->assertEquals( '/testurl/thumb/a/a2/Test%21/x', $this->file_hl2->getThumbUrl( 'x' ) );
- }
-
- function testGetArchiveVirtualUrl() {
- $this->assertEquals( 'mwrepo://test/public/archive', $this->file_hl0->getArchiveVirtualUrl() );
- $this->assertEquals( 'mwrepo://test/public/archive/a/a2', $this->file_hl2->getArchiveVirtualUrl() );
- $this->assertEquals( 'mwrepo://test/public/archive/%21', $this->file_hl0->getArchiveVirtualUrl( '!' ) );
- $this->assertEquals( 'mwrepo://test/public/archive/a/a2/%21', $this->file_hl2->getArchiveVirtualUrl( '!' ) );
- }
-
- function testGetThumbVirtualUrl() {
- $this->assertEquals( 'mwrepo://test/thumb/Test%21', $this->file_hl0->getThumbVirtualUrl() );
- $this->assertEquals( 'mwrepo://test/thumb/a/a2/Test%21', $this->file_hl2->getThumbVirtualUrl() );
- $this->assertEquals( 'mwrepo://test/thumb/Test%21/%21', $this->file_hl0->getThumbVirtualUrl( '!' ) );
- $this->assertEquals( 'mwrepo://test/thumb/a/a2/Test%21/%21', $this->file_hl2->getThumbVirtualUrl( '!' ) );
- }
-
- function testGetUrl() {
- $this->assertEquals( '/testurl/Test%21', $this->file_hl0->getUrl() );
- $this->assertEquals( '/testurl/a/a2/Test%21', $this->file_hl2->getUrl() );
- }
-}
-
-
diff --git a/maintenance/tests/Makefile b/maintenance/tests/Makefile
deleted file mode 100644
index b2c0fb71..00000000
--- a/maintenance/tests/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# See
-# http://lists.wikimedia.org/pipermail/wikitech-l/2010-February/046657.html
-# for why prove(1) is the default target and not phpunit(1)
-
-.PHONY: help test
-all test: tap
-
-tap:
- prove -e 'phpunit --tap' *Test*.php
-
-phpunit:
- phpunit
-
-install:
- pear channel-discover pear.phpunit.de
- pear install phpunit/PHPUnit
-
-help:
- # Options:
- # test (default) Run the tests individually through Test::Harness's prove(1)
- # phpunit Run all the tests with phpunit
- # install Install PHPUnit from phpunit.de
- # help You're looking at it!
diff --git a/maintenance/tests/MediaWikiParserTest.php b/maintenance/tests/MediaWikiParserTest.php
deleted file mode 100644
index a545b3bb..00000000
--- a/maintenance/tests/MediaWikiParserTest.php
+++ /dev/null
@@ -1,283 +0,0 @@
-total++;
- $this->success += $result;
-
- }
-
- function reportPercentage( $success, $total ) {}
-}
-
-class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite {
-#implements PHPUnit_Framework_SelfDescribing {
- static private $count;
- static public $parser;
- static public $iter;
-
- public static function suite() {
- $suite = new PHPUnit_Framework_TestSuite();
-
- self::$iter = new TestFileIterator( PARSER_TESTS );
-
- foreach(self::$iter as $i => $test) {
- $suite->addTest(new ParserUnitTest($i, $test['test']));
- self::$count++;
- }
- unset($tests);
-
- self::$parser = new PTShell;
- self::$iter->setParser(self::$parser);
- self::$parser->recorder->start();
- self::$parser->setupDatabase();
- self::$iter->rewind();
- /* } */
- /* function setUp() { */
- global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
- $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
- $wgMessageCache, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $parserMemc,
- $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
- $wgNamespacesWithSubpages, $wgThumbnailScriptPath, $wgScriptPath,
- $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath;
-
- $wgScript = '/index.php';
- $wgScriptPath = '/';
- $wgArticlePath = '/wiki/$1';
- $wgStyleSheetPath = '/skins';
- $wgStylePath = '/skins';
- $wgThumbnailScriptPath = false;
- $wgLocalFileRepo = array(
- 'class' => 'LocalRepo',
- 'name' => 'local',
- 'directory' => '',
- 'url' => 'http://example.com/images',
- 'hashLevels' => 2,
- 'transformVia404' => false,
- );
- $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
- $wgNamespaceAliases['Image'] = NS_FILE;
- $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
-
-
- $wgEnableParserCache = false;
- $wgDeferredUpdateList = array();
- $wgMemc =& wfGetMainCache();
- $messageMemc =& wfGetMessageCacheStorage();
- $parserMemc =& wfGetParserCacheStorage();
-
- $wgContLang = new StubContLang;
- $wgUser = new StubUser;
- $wgLang = new StubUserLang;
- $wgOut = new StubObject( 'wgOut', 'OutputPage' );
- $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
- $wgRequest = new WebRequest;
-
- $wgMessageCache = new StubObject( 'wgMessageCache', 'MessageCache',
- array( $messageMemc, $wgUseDatabaseMessages,
- $wgMsgCacheExpiry, wfWikiID() ) );
- if( $wgStyleDirectory === false) $wgStyleDirectory = "$IP/skins";
-
- return $suite;
- }
-
- public function tearDown() {
- $this->teardownDatabase();
- $this->recorder->report();
- $this->recorder->end();
- $this->teardownUploadDir($this->uploadDir);
- }
-
- public function count() {return self::$count;}
-
- public function toString() {
- return "MediaWiki Parser Tests";
- }
-
-
- private $db;
- private $uploadDir;
- private $keepUploads;
- /**
- * Remove the dummy uploads directory
- */
- private function teardownUploadDir( $dir ) {
- if ( $this->keepUploads ) {
- return;
- }
-
- // 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",
- )
- );
-
- 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",
- )
- );
- }
-
- /**
- * Delete the specified files, if they exist.
- * @param array $files full paths to files to delete.
- */
- private static function deleteFiles( $files ) {
- foreach( $files as $file ) {
- if( file_exists( $file ) ) {
- unlink( $file );
- }
- }
- }
- /**
- * Delete the specified directories, if they exist. Must be empty.
- * @param array $dirs full paths to directories to delete.
- */
- private static function deleteDirs( $dirs ) {
- foreach( $dirs as $dir ) {
- if( is_dir( $dir ) ) {
- rmdir( $dir );
- }
- }
- }
-
- /**
- * Create a dummy uploads directory which will contain a couple
- * of files in order to pass existence tests.
- * @return string The directory
- */
- private function setupUploadDir() {
- global $IP;
- if ( $this->keepUploads ) {
- $dir = wfTempDir() . '/mwParser-images';
- if ( is_dir( $dir ) ) {
- return $dir;
- }
- } else {
- $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images";
- }
-
- wfDebug( "Creating upload directory $dir\n" );
- if ( file_exists( $dir ) ) {
- wfDebug( "Already exists!\n" );
- 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;
- }
-}
-
-class ParserUnitTest extends PHPUnit_Framework_TestCase {
- private $number = 0;
- private $test = "";
-
- public function __construct($number, $test) {
- $this->number = $number;
- $this->test = $test;
- }
-
- function count() {return 1;}
-
- public function run(PHPUnit_Framework_TestResult $result = NULL) {
- PHPUnit_Framework_Assert::resetCount();
- if ($result === NULL) {
- $result = new PHPUnit_Framework_TestResult;
- }
-
- $t = MediaWikiParserTestSuite::$iter->current();
- $k = MediaWikiParserTestSuite::$iter->key();
-
- if(!MediaWikiParserTestSuite::$iter->valid()) {
- return;
- }
-
- // The only way this should happen is if the parserTest.txt
- // file were modified while the script is running.
- if($k != $this->number) {
- $i = $this->number;
- wfDie("I got confused!\n");
- }
-
- $result->startTest($this);
- PHPUnit_Util_Timer::start();
-
- $r = false;
- try {
- $r = MediaWikiParserTestSuite::$parser->runTest(
- $t['test'], $t['input'], $t['result'], $t['options'], $t['config']
- );
- PHPUnit_Framework_Assert::assertTrue(true, $t['test']);
- }
- catch (PHPUnit_Framework_AssertionFailedError $e) {
- $result->addFailure($this, $e, PHPUnit_Util_Timer::stop());
- }
- catch (Exception $e) {
- $result->addError($this, $e, PHPUnit_Util_Timer::stop());
- }
- PHPUnit_Framework_Assert::assertTrue(true, $t['test']);
-
- $result->endTest($this, PHPUnit_Util_Timer::stop());
-
- MediaWikiParserTestSuite::$parser->recorder->record($t['test'], $r);
- MediaWikiParserTestSuite::$iter->next();
- $this->addToAssertionCount(PHPUnit_Framework_Assert::getCount());
-
- return $result;
- }
-
-}
-
-class PTShell extends ParserTest {
- function showTesting( $desc ) {
- }
-
- function showRunFile( $path ) {
- }
-
- function showSuccess( $desc ) {
- PHPUnit_Framework_Assert::assertTrue(true, $desc);
- return true;
- }
-
- function showFailure( $desc, $expected, $got ) {
- PHPUnit_Framework_Assert::assertEquals($expected, $got, $desc);
- }
-
-}
-
-
diff --git a/maintenance/tests/MediaWiki_Setup.php b/maintenance/tests/MediaWiki_Setup.php
deleted file mode 100644
index e7acc338..00000000
--- a/maintenance/tests/MediaWiki_Setup.php
+++ /dev/null
@@ -1,28 +0,0 @@
-tableName( $table );
- $db->tablePrefix( 'parsertest_' );
-
- if( $db->isOpen() ) {
- foreach ( $tables as $tbl ) {
- $newTableName = $db->tableName( $tbl );
- $tableName = $oldTableNames[$tbl];
- $db->query( "DROP TABLE IF EXISTS $newTableName", __METHOD__ );
- $db->duplicateTableStructure( $tableName, $newTableName, __METHOD__ );
- }
- return $db;
- } else {
- // Something amiss
- return null;
- }
- }
-}
-
diff --git a/maintenance/tests/README b/maintenance/tests/README
deleted file mode 100644
index b52e790e..00000000
--- a/maintenance/tests/README
+++ /dev/null
@@ -1,24 +0,0 @@
-Some quickie unit tests done with the PHPUnit testing framework. To run the
-test suite, run 'make test' in this dir. This directly invokes 'phpunit.'
-
-PHPUnit is no longer maintained by PEAR. To get the current version of
-PHPUnit, first uninstall any old version of PHPUnit or PHPUnit2 from PEAR,
-then install the current version from phpunit.de like this:
-
-# pear channel-discover pear.phpunit.de
-# pear install phpunit/PHPUnit
-
-You also may wish to install this via your normal package mechanism:
-
-# aptitude install phpunit
- - or -
-# yum install phpunit
-
-Notes:
-- Label currently broken tests in the group Broken and they will not
- be run by phpunit. You can add them to the group by putting the
- following comment at the top of the file:
- /**
- * @group Broken
- */
-- Need to fix some broken tests
diff --git a/maintenance/tests/RevisionTest.php b/maintenance/tests/RevisionTest.php
deleted file mode 100644
index 78fcc7c3..00000000
--- a/maintenance/tests/RevisionTest.php
+++ /dev/null
@@ -1,114 +0,0 @@
- false,
- 'wgCompressRevisions' => false,
- 'wgInputEncoding' => 'utf-8',
- 'wgOutputEncoding' => 'utf-8' );
- foreach( $globalSet as $var => $data ) {
- $this->saveGlobals[$var] = $GLOBALS[$var];
- $GLOBALS[$var] = $data;
- }
- }
-
- function tearDown() {
- foreach( $this->saveGlobals as $var => $data ) {
- $GLOBALS[$var] = $data;
- }
- }
-
- function testGetRevisionText() {
- $row = new stdClass;
- $row->old_flags = '';
- $row->old_text = 'This is a bunch of revision text.';
- $this->assertEquals(
- 'This is a bunch of revision text.',
- Revision::getRevisionText( $row ) );
- }
-
- function testGetRevisionTextGzip() {
- $row = new stdClass;
- $row->old_flags = 'gzip';
- $row->old_text = gzdeflate( 'This is a bunch of revision text.' );
- $this->assertEquals(
- 'This is a bunch of revision text.',
- Revision::getRevisionText( $row ) );
- }
-
- function testGetRevisionTextUtf8Native() {
- $row = new stdClass;
- $row->old_flags = 'utf-8';
- $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
- $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
- $this->assertEquals(
- "Wiki est l'\xc3\xa9cole superieur !",
- Revision::getRevisionText( $row ) );
- }
-
- function testGetRevisionTextUtf8Legacy() {
- $row = new stdClass;
- $row->old_flags = '';
- $row->old_text = "Wiki est l'\xe9cole superieur !";
- $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
- $this->assertEquals(
- "Wiki est l'\xc3\xa9cole superieur !",
- Revision::getRevisionText( $row ) );
- }
-
- function testGetRevisionTextUtf8NativeGzip() {
- $row = new stdClass;
- $row->old_flags = 'gzip,utf-8';
- $row->old_text = gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" );
- $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
- $this->assertEquals(
- "Wiki est l'\xc3\xa9cole superieur !",
- Revision::getRevisionText( $row ) );
- }
-
- function testGetRevisionTextUtf8LegacyGzip() {
- $row = new stdClass;
- $row->old_flags = 'gzip';
- $row->old_text = gzdeflate( "Wiki est l'\xe9cole superieur !" );
- $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
- $this->assertEquals(
- "Wiki est l'\xc3\xa9cole superieur !",
- Revision::getRevisionText( $row ) );
- }
-
- function testCompressRevisionTextUtf8() {
- $row = new stdClass;
- $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
- $row->old_flags = Revision::compressRevisionText( $row->old_text );
- $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
- "Flags should contain 'utf-8'" );
- $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ),
- "Flags should not contain 'gzip'" );
- $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
- $row->old_text, "Direct check" );
- $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
- Revision::getRevisionText( $row ), "getRevisionText" );
- }
-
- function testCompressRevisionTextUtf8Gzip() {
- $GLOBALS['wgCompressRevisions'] = true;
- $row = new stdClass;
- $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
- $row->old_flags = Revision::compressRevisionText( $row->old_text );
- $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
- "Flags should contain 'utf-8'" );
- $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ),
- "Flags should contain 'gzip'" );
- $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
- gzinflate( $row->old_text ), "Direct check" );
- $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
- Revision::getRevisionText( $row ), "getRevisionText" );
- }
-}
-
-
diff --git a/maintenance/tests/RunSeleniumTests.php b/maintenance/tests/RunSeleniumTests.php
new file mode 100644
index 00000000..2574f4b2
--- /dev/null
+++ b/maintenance/tests/RunSeleniumTests.php
@@ -0,0 +1,220 @@
+#!/usr/bin/php
+mDescription = "Selenium Test Runner. For documentation, visit http://www.mediawiki.org/wiki/SeleniumFramework";
+ $this->addOption( 'port', 'Port used by selenium server. Default: 4444', false, true );
+ $this->addOption( 'host', 'Host selenium server. Default: $wgServer . $wgScriptPath', false, true );
+ $this->addOption( 'testBrowser', 'The browser used during testing. Default: firefox', false, true );
+ $this->addOption( 'wikiUrl', 'The Mediawiki installation to point to. Default: http://localhost', false, true );
+ $this->addOption( 'username', 'The login username for sunning tests. Default: empty', false, true );
+ $this->addOption( 'userPassword', 'The login password for running tests. Default: empty', false, true );
+ $this->addOption( 'seleniumConfig', 'Location of the selenium config file. Default: empty', false, true );
+ $this->addOption( 'list-browsers', 'List the available browsers.' );
+ $this->addOption( 'verbose', 'Be noisier.' );
+ $this->addOption( 'startserver', 'Start Selenium Server (on localhost) before the run.' );
+ $this->addOption( 'stopserver', 'Stop Selenium Server (on localhost) after the run.' );
+ $this->addOption( 'jUnitLogFile', 'Log results in a specified JUnit log file. Default: empty', false, true );
+ $this->addOption( 'runAgainstGrid', 'The test will be run against a Selenium Grid. Default: false.', false, true );
+ $this->deleteOption( 'dbpass' );
+ $this->deleteOption( 'dbuser' );
+ $this->deleteOption( 'globals' );
+ $this->deleteOption( 'wiki' );
+ }
+
+ public function listBrowsers() {
+ $desc = "Available browsers:\n";
+
+ foreach ($this->selenium->getAvailableBrowsers() as $k => $v) {
+ $desc .= " $k => $v\n";
+ }
+
+ echo $desc;
+ }
+
+ protected function startServer() {
+ if ( $this->seleniumServerExecPath == '' ) {
+ die ( "The selenium server exec path is not set in " .
+ "selenium_settings.ini. Cannot start server \n" .
+ "as requested - terminating RunSeleniumTests\n" );
+ }
+ $this->serverManager = new SeleniumServerManager( 'true',
+ $this->selenium->getPort(),
+ $this->seleniumServerExecPath );
+ switch ( $this->serverManager->start() ) {
+ case 'started':
+ break;
+ case 'failed':
+ die ( "Unable to start the Selenium Server - " .
+ "terminating RunSeleniumTests\n" );
+ case 'running':
+ echo ( "Warning: The Selenium Server is " .
+ "already running\n" );
+ break;
+ }
+
+ return;
+ }
+
+ protected function stopServer() {
+ if ( !isset ( $this->serverManager ) ) {
+ echo ( "Warning: Request to stop Selenium Server, but it was " .
+ "not stared by RunSeleniumTests\n" .
+ "RunSeleniumTests cannot stop a Selenium Server it " .
+ "did not start\n" );
+ } else {
+ switch ( $this->serverManager->stop() ) {
+ case 'stopped':
+ break;
+ case 'failed':
+ echo ( "unable to stop the Selenium Server\n" );
+ }
+ }
+ return;
+ }
+
+ protected function runTests( $seleniumTestSuites = array() ) {
+ $result = new PHPUnit_Framework_TestResult;
+ $result->addListener( new SeleniumTestListener( $this->selenium->getLogger() ) );
+ if ( $this->selenium->getJUnitLogFile() ) {
+ $jUnitListener = new PHPUnit_Util_Log_JUnit( $this->selenium->getJUnitLogFile(), true );
+ $result->addListener( $jUnitListener );
+ }
+
+ foreach ( $seleniumTestSuites as $testSuiteName => $testSuiteFile ) {
+ require( $testSuiteFile );
+ $suite = new $testSuiteName();
+ $suite->setName( $testSuiteName );
+ $suite->addTests();
+
+ try {
+ $suite->run( $result );
+ } catch ( Testing_Selenium_Exception $e ) {
+ $suite->tearDown();
+ throw new MWException( $e->getMessage() );
+ }
+ }
+
+ if ( $this->selenium->getJUnitLogFile() ) {
+ $jUnitListener->flush();
+ }
+ }
+
+ public function execute() {
+ global $wgServer, $wgScriptPath, $wgHooks;
+
+ $seleniumSettings = array();
+ $seleniumBrowsers = array();
+ $seleniumTestSuites = array();
+
+ $configFile = $this->getOption( 'seleniumConfig', '' );
+ if ( strlen( $configFile ) > 0 ) {
+ $this->output("Using Selenium Configuration file: " . $configFile . "\n");
+ SeleniumConfig::getSeleniumSettings( $seleniumSettings,
+ $seleniumBrowsers,
+ $seleniumTestSuites,
+ $configFile );
+ } else if ( !isset( $wgHooks['SeleniumSettings'] ) ) {
+ $this->output("No command line configuration file or configuration hook found.\n");
+ SeleniumConfig::getSeleniumSettings( $seleniumSettings,
+ $seleniumBrowsers,
+ $seleniumTestSuites
+ );
+ } else {
+ $this->output("Using 'SeleniumSettings' hook for configuration.\n");
+ wfRunHooks('SeleniumSettings', array( $seleniumSettings,
+ $seleniumBrowsers,
+ $seleniumTestSuites ) );
+ }
+
+ // State for starting/stopping the Selenium server has nothing to do with the Selenium
+ // class. Keep this state local to SeleniumTester class. Using getOption() is clumsy, but
+ // the Maintenance class does not have a setOption()
+ if ( isset( $seleniumSettings['startserver'] ) ) $this->getOption( 'startserver', true );
+ if ( isset( $seleniumSettings['stopserver'] ) ) $this->getOption( 'stopserver', true );
+ if ( !isset( $seleniumSettings['seleniumserverexecpath'] ) ) $seleniumSettings['seleniumserverexecpath'] = '';
+ $this->seleniumServerExecPath = $seleniumSettings['seleniumserverexecpath'];
+
+ //set reasonable defaults if we did not find the settings
+ if ( !isset( $seleniumBrowsers ) ) $seleniumBrowsers = array ('firefox' => '*firefox');
+ if ( !isset( $seleniumSettings['host'] ) ) $seleniumSettings['host'] = $wgServer . $wgScriptPath;
+ if ( !isset( $seleniumSettings['port'] ) ) $seleniumSettings['port'] = '4444';
+ if ( !isset( $seleniumSettings['wikiUrl'] ) ) $seleniumSettings['wikiUrl'] = 'http://localhost';
+ if ( !isset( $seleniumSettings['username'] ) ) $seleniumSettings['username'] = '';
+ if ( !isset( $seleniumSettings['userPassword'] ) ) $seleniumSettings['userPassword'] = '';
+ if ( !isset( $seleniumSettings['testBrowser'] ) ) $seleniumSettings['testBrowser'] = 'firefox';
+ if ( !isset( $seleniumSettings['jUnitLogFile'] ) ) $seleniumSettings['jUnitLogFile'] = false;
+ if ( !isset( $seleniumSettings['runAgainstGrid'] ) ) $seleniumSettings['runAgainstGrid'] = false;
+
+ // Setup Selenium class
+ $this->selenium = new Selenium( );
+ $this->selenium->setAvailableBrowsers( $seleniumBrowsers );
+ $this->selenium->setRunAgainstGrid( $this->getOption( 'runAgainstGrid', $seleniumSettings['runAgainstGrid'] ) );
+ $this->selenium->setUrl( $this->getOption( 'wikiUrl', $seleniumSettings['wikiUrl'] ) );
+ $this->selenium->setBrowser( $this->getOption( 'testBrowser', $seleniumSettings['testBrowser'] ) );
+ $this->selenium->setPort( $this->getOption( 'port', $seleniumSettings['port'] ) );
+ $this->selenium->setHost( $this->getOption( 'host', $seleniumSettings['host'] ) );
+ $this->selenium->setUser( $this->getOption( 'username', $seleniumSettings['username'] ) );
+ $this->selenium->setPass( $this->getOption( 'userPassword', $seleniumSettings['userPassword'] ) );
+ $this->selenium->setVerbose( $this->hasOption( 'verbose' ) );
+ $this->selenium->setJUnitLogFile( $this->getOption( 'jUnitLogFile', $seleniumSettings['jUnitLogFile'] ) );
+
+ if( $this->hasOption( 'list-browsers' ) ) {
+ $this->listBrowsers();
+ exit(0);
+ }
+ if ( $this->hasOption( 'startserver' ) ) {
+ $this->startServer();
+ }
+
+ $logger = new SeleniumTestConsoleLogger;
+ $this->selenium->setLogger( $logger );
+
+ $this->runTests( $seleniumTestSuites );
+
+ if ( $this->hasOption( 'stopserver' ) ) {
+ $this->stopServer();
+ }
+ }
+}
+
+$maintClass = "SeleniumTester";
+
+require_once( DO_MAINTENANCE );
diff --git a/maintenance/tests/SanitizerTest.php b/maintenance/tests/SanitizerTest.php
deleted file mode 100644
index 8a2287d5..00000000
--- a/maintenance/tests/SanitizerTest.php
+++ /dev/null
@@ -1,73 +0,0 @@
-assertEquals(
- "\xc3\xa9cole",
- Sanitizer::decodeCharReferences( 'école' ),
- 'decode named entities'
- );
- }
-
- function testDecodeNumericEntities() {
- $this->assertEquals(
- "\xc4\x88io bonas dans l'\xc3\xa9cole!",
- Sanitizer::decodeCharReferences( "Ĉio bonas dans l'école!" ),
- 'decode numeric entities'
- );
- }
-
- function testDecodeMixedEntities() {
- $this->assertEquals(
- "\xc4\x88io bonas dans l'\xc3\xa9cole!",
- Sanitizer::decodeCharReferences( "Ĉio bonas dans l'école!" ),
- 'decode mixed numeric/named entities'
- );
- }
-
- function testDecodeMixedComplexEntities() {
- $this->assertEquals(
- "\xc4\x88io bonas dans l'\xc3\xa9cole! (mais pas Ĉio dans l'école)",
- Sanitizer::decodeCharReferences(
- "Ĉio bonas dans l'école! (mais pas Ĉio dans l'école)"
- ),
- 'decode mixed complex entities'
- );
- }
-
- function testInvalidAmpersand() {
- $this->assertEquals(
- 'a & b',
- Sanitizer::decodeCharReferences( 'a & b' ),
- 'Invalid ampersand'
- );
- }
-
- function testInvalidEntities() {
- $this->assertEquals(
- '&foo;',
- Sanitizer::decodeCharReferences( '&foo;' ),
- 'Invalid named entity'
- );
- }
-
- function testInvalidNumberedEntities() {
- $this->assertEquals( UTF8_REPLACEMENT, Sanitizer::decodeCharReferences( "" ), 'Invalid numbered entity' );
- }
-
- function testSelfClosingTag() {
- $GLOBALS['wgUseTidy'] = false;
- $this->assertEquals(
- 'Hello world
',
- Sanitizer::removeHTMLtags( 'Hello world
' ),
- 'Self-closing closing div'
- );
- }
-}
-
diff --git a/maintenance/tests/SearchEngineTest.php b/maintenance/tests/SearchEngineTest.php
deleted file mode 100644
index 0cae2d42..00000000
--- a/maintenance/tests/SearchEngineTest.php
+++ /dev/null
@@ -1,138 +0,0 @@
-db->safeQuery( <<db->tableName( 'page' ) );
- $this->db->safeQuery( <<db->tableName( 'revision' ) );
- $this->db->safeQuery( <<db->tableName( 'text' ) );
- $this->db->safeQuery( <<db->tableName( 'searchindex' ) );
- }
-
- function fetchIds( $results ) {
- $matches = array();
- while( $row = $results->next() ) {
- $matches[] = $row->getTitle()->getPrefixedText();
- }
- $results->free();
- # Search is not guaranteed to return results in a certain order;
- # sort them numerically so we will compare simply that we received
- # the expected matches.
- sort( $matches );
- return $matches;
- }
-
- function testTextSearch() {
- if( is_null( $this->db ) ) {
- $this->markTestIncomplete( "Can't find a database to test with." );
- }
- $this->assertEquals(
- array( 'Smithee' ),
- $this->fetchIds( $this->search->searchText( 'smithee' ) ),
- "Plain search failed" );
- }
-
- function testTextPowerSearch() {
- if( is_null( $this->db ) ) {
- $this->markTestIncomplete( "Can't find a database to test with." );
- }
- $this->search->setNamespaces( array( 0, 1, 4 ) );
- $this->assertEquals(
- array(
- 'Smithee',
- 'Talk:Main Page',
- ),
- $this->fetchIds( $this->search->searchText( 'smithee' ) ),
- "Power search failed" );
- }
-
- function testTitleSearch() {
- if( is_null( $this->db ) ) {
- $this->markTestIncomplete( "Can't find a database to test with." );
- }
- $this->assertEquals(
- array(
- 'Alan Smithee',
- 'Smithee',
- ),
- $this->fetchIds( $this->search->searchTitle( 'smithee' ) ),
- "Title search failed" );
- }
-
- function testTextTitlePowerSearch() {
- if( is_null( $this->db ) ) {
- $this->markTestIncomplete( "Can't find a database to test with." );
- }
- $this->search->setNamespaces( array( 0, 1, 4 ) );
- $this->assertEquals(
- array(
- 'Alan Smithee',
- 'Smithee',
- 'Talk:Smithee',
- ),
- $this->fetchIds( $this->search->searchTitle( 'smithee' ) ),
- "Title power search failed" );
- }
-
-}
-
-
-
diff --git a/maintenance/tests/SearchMySQLTest.php b/maintenance/tests/SearchMySQLTest.php
deleted file mode 100644
index 526f6216..00000000
--- a/maintenance/tests/SearchMySQLTest.php
+++ /dev/null
@@ -1,26 +0,0 @@
-db = $this->buildTestDatabase(
- array( 'page', 'revision', 'text', 'searchindex', 'user' ) );
- if( $this->db ) {
- $this->insertSearchData();
- }
- $this->search = new SearchMySQL( $this->db );
- }
-
- function tearDown() {
- if( !is_null( $this->db ) ) {
- wfGetLB()->closeConnecton( $this->db );
- }
- unset( $this->db );
- unset( $this->search );
- }
-}
-
-
diff --git a/maintenance/tests/SearchUpdateTest.php b/maintenance/tests/SearchUpdateTest.php
deleted file mode 100644
index d21319a4..00000000
--- a/maintenance/tests/SearchUpdateTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
-mConn = true;
- $this->mOpened = true;
- }
-
- function open( $server, $user, $password, $dbName ) { return true; }
- function doQuery( $sql ) {}
- function fetchObject( $res ) {}
- function fetchRow( $res ) {}
- function numRows( $res ) {}
- function numFields( $res ) {}
- function fieldName( $res, $n ) {}
- function insertId() {}
- function dataSeek( $res, $row ) {}
- function lastErrno() { return 0; }
- function lastError() { return ''; }
- function affectedRows() {}
- function fieldInfo( $table, $field ) {}
- function strencode( $s ) {}
- function getSoftwareLink() {}
- function getServerVersion() {}
- function getType() {}
-}
-
-class MockSearch extends SearchEngine {
- public static $id;
- public static $title;
- public static $text;
-
- public function __construct( $db ) {
- }
-
- public function update( $id, $title, $text ) {
- self::$id = $id;
- self::$title = $title;
- self::$text = $text;
- }
-}
-
-class SearchUpdateTest extends PHPUnit_Framework_TestCase {
-
- function update( $text, $title = 'Test', $id = 1 ) {
- $u = new SearchUpdate( $id, $title, $text );
- $u->doUpdate();
- return array( MockSearch::$title, MockSearch::$text );
- }
-
- function updateText( $text ) {
- list( $title, $resultText ) = $this->update( $text );
- $resultText = trim( $resultText ); // abstract from some implementation details
- return $resultText;
- }
-
- function setUp() {
- global $wgSearchType, $wgDBtype, $wgLBFactoryConf, $wgDBservers;
- $wgSearchType = 'MockSearch';
- $wgDBtype = 'mock';
- $wgLBFactoryConf['class'] = 'LBFactory_Simple';
- $wgDBservers = null;
- LBFactory::destroyInstance();
- }
-
- function tearDown() {
- LBFactory::destroyInstance();
- }
-
- function testUpdateText() {
- $this->assertEquals(
- 'test',
- $this->updateText( 'TeSt
' ),
- 'HTML stripped, text lowercased'
- );
-
- $this->assertEquals(
- 'foo bar boz quux',
- $this->updateText( <<
- foo |
bar
- boz |
quux
-
-EOT
- ), 'Stripping HTML tables' );
-
- $this->assertEquals(
- 'a b',
- $this->updateText( 'a > b' ),
- 'Handle unclosed tags'
- );
-
- $text = str_pad( "foo assertNotEquals(
- '',
- $this->updateText( $text ),
- 'Bug 18609'
- );
- }
-}
diff --git a/maintenance/tests/SiteConfigurationTest.php b/maintenance/tests/SiteConfigurationTest.php
deleted file mode 100644
index 791b6fe5..00000000
--- a/maintenance/tests/SiteConfigurationTest.php
+++ /dev/null
@@ -1,311 +0,0 @@
-suffixes as $suffix ) {
- if ( substr( $wiki, -strlen( $suffix ) ) == $suffix ) {
- $site = $suffix;
- $lang = substr( $wiki, 0, -strlen( $suffix ) );
- break;
- }
- }
- return array(
- 'suffix' => $site,
- 'lang' => $lang,
- 'params' => array(
- 'lang' => $lang,
- 'site' => $site,
- 'wiki' => $wiki,
- ),
- 'tags' => array( 'tag' ),
- );
-}
-
-class SiteConfigurationTest extends PHPUnit_Framework_TestCase {
- var $mConf;
-
- function setUp() {
- $this->mConf = new SiteConfiguration;
-
- $this->mConf->suffixes = array( 'wiki' );
- $this->mConf->wikis = array( 'enwiki', 'dewiki', 'frwiki' );
- $this->mConf->settings = array(
- 'simple' => array(
- 'wiki' => 'wiki',
- 'tag' => 'tag',
- 'enwiki' => 'enwiki',
- 'dewiki' => 'dewiki',
- 'frwiki' => 'frwiki',
- ),
-
- 'fallback' => array(
- 'default' => 'default',
- 'wiki' => 'wiki',
- 'tag' => 'tag',
- ),
-
- 'params' => array(
- 'default' => '$lang $site $wiki',
- ),
-
- '+global' => array(
- 'wiki' => array(
- 'wiki' => 'wiki',
- ),
- 'tag' => array(
- 'tag' => 'tag',
- ),
- 'enwiki' => array(
- 'enwiki' => 'enwiki',
- ),
- 'dewiki' => array(
- 'dewiki' => 'dewiki',
- ),
- 'frwiki' => array(
- 'frwiki' => 'frwiki',
- ),
- ),
-
- 'merge' => array(
- '+wiki' => array(
- 'wiki' => 'wiki',
- ),
- '+tag' => array(
- 'tag' => 'tag',
- ),
- 'default' => array(
- 'default' => 'default',
- ),
- '+enwiki' => array(
- 'enwiki' => 'enwiki',
- ),
- '+dewiki' => array(
- 'dewiki' => 'dewiki',
- ),
- '+frwiki' => array(
- 'frwiki' => 'frwiki',
- ),
- ),
- );
-
- $GLOBALS['global'] = array( 'global' => 'global' );
- }
-
-
- function testSiteFromDB() {
- $this->assertEquals(
- array( 'wikipedia', 'en' ),
- $this->mConf->siteFromDB( 'enwiki' ),
- 'siteFromDB()'
- );
- $this->assertEquals(
- array( 'wikipedia', '' ),
- $this->mConf->siteFromDB( 'wiki' ),
- 'siteFromDB() on a suffix'
- );
- $this->assertEquals(
- array( null, null ),
- $this->mConf->siteFromDB( 'wikien' ),
- 'siteFromDB() on a non-existing wiki'
- );
-
- $this->mConf->suffixes = array( 'wiki', '' );
- $this->assertEquals(
- array( '', 'wikien' ),
- $this->mConf->siteFromDB( 'wikien' ),
- 'siteFromDB() on a non-existing wiki (2)'
- );
- }
-
- function testGetLocalDatabases() {
- $this->assertEquals(
- array( 'enwiki', 'dewiki', 'frwiki' ),
- $this->mConf->getLocalDatabases(),
- 'getLocalDatabases()'
- );
- }
-
- function testGet() {
- $this->assertEquals(
- 'enwiki',
- $this->mConf->get( 'simple', 'enwiki', 'wiki' ),
- 'get(): simple setting on an existing wiki'
- );
- $this->assertEquals(
- 'dewiki',
- $this->mConf->get( 'simple', 'dewiki', 'wiki' ),
- 'get(): simple setting on an existing wiki (2)'
- );
- $this->assertEquals(
- 'frwiki',
- $this->mConf->get( 'simple', 'frwiki', 'wiki' ),
- 'get(): simple setting on an existing wiki (3)'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'simple', 'wiki', 'wiki' ),
- 'get(): simple setting on an suffix'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'simple', 'eswiki', 'wiki' ),
- 'get(): simple setting on an non-existing wiki'
- );
-
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'fallback', 'enwiki', 'wiki' ),
- 'get(): fallback setting on an existing wiki'
- );
- $this->assertEquals(
- 'tag',
- $this->mConf->get( 'fallback', 'dewiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): fallback setting on an existing wiki (with wiki tag)'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'fallback', 'wiki', 'wiki' ),
- 'get(): fallback setting on an suffix'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'fallback', 'wiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): fallback setting on an suffix (with wiki tag)'
- );
- $this->assertEquals(
- 'wiki',
- $this->mConf->get( 'fallback', 'eswiki', 'wiki' ),
- 'get(): fallback setting on an non-existing wiki'
- );
- $this->assertEquals(
- 'tag',
- $this->mConf->get( 'fallback', 'eswiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): fallback setting on an non-existing wiki (with wiki tag)'
- );
-
- $common = array( 'wiki' => 'wiki', 'default' => 'default' );
- $commonTag = array( 'tag' => 'tag', 'wiki' => 'wiki', 'default' => 'default' );
- $this->assertEquals(
- array( 'enwiki' => 'enwiki' ) + $common,
- $this->mConf->get( 'merge', 'enwiki', 'wiki' ),
- 'get(): merging setting on an existing wiki'
- );
- $this->assertEquals(
- array( 'enwiki' => 'enwiki' ) + $commonTag,
- $this->mConf->get( 'merge', 'enwiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): merging setting on an existing wiki (with tag)'
- );
- $this->assertEquals(
- array( 'dewiki' => 'dewiki' ) + $common,
- $this->mConf->get( 'merge', 'dewiki', 'wiki' ),
- 'get(): merging setting on an existing wiki (2)'
- );
- $this->assertEquals(
- array( 'dewiki' => 'dewiki' ) + $commonTag,
- $this->mConf->get( 'merge', 'dewiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): merging setting on an existing wiki (2) (with tag)'
- );
- $this->assertEquals(
- array( 'frwiki' => 'frwiki' ) + $common,
- $this->mConf->get( 'merge', 'frwiki', 'wiki' ),
- 'get(): merging setting on an existing wiki (3)'
- );
- $this->assertEquals(
- array( 'frwiki' => 'frwiki' ) + $commonTag,
- $this->mConf->get( 'merge', 'frwiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): merging setting on an existing wiki (3) (with tag)'
- );
- $this->assertEquals(
- array( 'wiki' => 'wiki' ) + $common,
- $this->mConf->get( 'merge', 'wiki', 'wiki' ),
- 'get(): merging setting on an suffix'
- );
- $this->assertEquals(
- array( 'wiki' => 'wiki' ) + $commonTag,
- $this->mConf->get( 'merge', 'wiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): merging setting on an suffix (with tag)'
- );
- $this->assertEquals(
- $common,
- $this->mConf->get( 'merge', 'eswiki', 'wiki' ),
- 'get(): merging setting on an non-existing wiki'
- );
- $this->assertEquals(
- $commonTag,
- $this->mConf->get( 'merge', 'eswiki', 'wiki', array(), array( 'tag' ) ),
- 'get(): merging setting on an non-existing wiki (with tag)'
- );
- }
-
- function testSiteFromDBWithCallback() {
- $this->mConf->siteParamsCallback = 'getSiteParams';
-
- $this->assertEquals(
- array( 'wiki', 'en' ),
- $this->mConf->siteFromDB( 'enwiki' ),
- 'siteFromDB() with callback'
- );
- $this->assertEquals(
- array( 'wiki', '' ),
- $this->mConf->siteFromDB( 'wiki' ),
- 'siteFromDB() with callback on a suffix'
- );
- $this->assertEquals(
- array( null, null ),
- $this->mConf->siteFromDB( 'wikien' ),
- 'siteFromDB() with callback on a non-existing wiki'
- );
- }
-
- function testParamReplacement() {
- $this->mConf->siteParamsCallback = 'getSiteParams';
-
- $this->assertEquals(
- 'en wiki enwiki',
- $this->mConf->get( 'params', 'enwiki', 'wiki' ),
- 'get(): parameter replacement on an existing wiki'
- );
- $this->assertEquals(
- 'de wiki dewiki',
- $this->mConf->get( 'params', 'dewiki', 'wiki' ),
- 'get(): parameter replacement on an existing wiki (2)'
- );
- $this->assertEquals(
- 'fr wiki frwiki',
- $this->mConf->get( 'params', 'frwiki', 'wiki' ),
- 'get(): parameter replacement on an existing wiki (3)'
- );
- $this->assertEquals(
- ' wiki wiki',
- $this->mConf->get( 'params', 'wiki', 'wiki' ),
- 'get(): parameter replacement on an suffix'
- );
- $this->assertEquals(
- 'es wiki eswiki',
- $this->mConf->get( 'params', 'eswiki', 'wiki' ),
- 'get(): parameter replacement on an non-existing wiki'
- );
- }
-
- function testGetAll() {
- $this->mConf->siteParamsCallback = 'getSiteParams';
-
- $getall = array(
- 'simple' => 'enwiki',
- 'fallback' => 'tag',
- 'params' => 'en wiki enwiki',
- 'global' => array( 'enwiki' => 'enwiki' ) + $GLOBALS['global'],
- 'merge' => array( 'enwiki' => 'enwiki', 'tag' => 'tag', 'wiki' => 'wiki', 'default' => 'default' ),
- );
- $this->assertEquals( $getall, $this->mConf->getAll( 'enwiki' ), 'getAll()' );
-
- $this->mConf->extractAllGlobals( 'enwiki', 'wiki' );
-
- $this->assertEquals( $getall['simple'], $GLOBALS['simple'], 'extractAllGlobals(): simple setting' );
- $this->assertEquals( $getall['fallback'], $GLOBALS['fallback'], 'extractAllGlobals(): fallback setting' );
- $this->assertEquals( $getall['params'], $GLOBALS['params'], 'extractAllGlobals(): parameter replacement' );
- $this->assertEquals( $getall['global'], $GLOBALS['global'], 'extractAllGlobals(): merging with global' );
- $this->assertEquals( $getall['merge'], $GLOBALS['merge'], 'extractAllGlobals(): merging setting' );
- }
-}
diff --git a/maintenance/tests/TimeAdjustTest.php b/maintenance/tests/TimeAdjustTest.php
deleted file mode 100644
index bbd697bf..00000000
--- a/maintenance/tests/TimeAdjustTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-iniSet( 'precision', 15 );
- }
-
- # Test offset usage for a given language::userAdjust
- function testUserAdjust() {
- global $wgLocalTZoffset, $wgContLang, $wgUser;
-
- $wgContLang = $en = Language::factory( 'en' );
-
- # Collection of parameters for Language_t_Offset.
- # Format: date to be formatted, localTZoffset value, expected date
- $userAdjust_tests = array(
- array( 20061231235959, 0, 20061231235959 ),
- array( 20061231235959, 5, 20070101000459 ),
- array( 20061231235959, 15, 20070101001459 ),
- array( 20061231235959, 60, 20070101005959 ),
- array( 20061231235959, 90, 20070101012959 ),
- array( 20061231235959, 120, 20070101015959 ),
- array( 20061231235959, 540, 20070101085959 ),
- array( 20061231235959, -5, 20061231235459 ),
- array( 20061231235959, -30, 20061231232959 ),
- array( 20061231235959, -60, 20061231225959 ),
- );
-
- foreach( $userAdjust_tests as $data ) {
- $wgLocalTZoffset = $data[1];
-
- $this->assertEquals(
- strval( $data[2] ),
- strval( $en->userAdjust( $data[0], '' ) ),
- "User adjust {$data[0]} by {$data[1]} minutes should give {$data[2]}"
- );
- }
- }
-}
diff --git a/maintenance/tests/TitleTest.php b/maintenance/tests/TitleTest.php
deleted file mode 100644
index 5b42c1c5..00000000
--- a/maintenance/tests/TitleTest.php
+++ /dev/null
@@ -1,17 +0,0 @@
-|", $chr ) !== false || preg_match( "/[\\x00-\\x1f\\x7f]/", $chr ) ) {
- $this->assertFalse( (bool)preg_match( "/[$titlechars]/", $chr ), "chr($num) = $chr is not a valid titlechar" );
- } else {
- $this->assertTrue( (bool)preg_match( "/[$titlechars]/", $chr ), "chr($num) = $chr is a valid titlechar" );
- }
- }
- }
-}
diff --git a/maintenance/tests/XmlTest.php b/maintenance/tests/XmlTest.php
deleted file mode 100644
index 330e60c6..00000000
--- a/maintenance/tests/XmlTest.php
+++ /dev/null
@@ -1,115 +0,0 @@
-assertEquals(
- '',
- Xml::element( 'element', null, null ),
- 'Opening element with no attributes'
- );
- }
-
- function testElementEmpty() {
- $this->assertEquals(
- '',
- Xml::element( 'element', null, '' ),
- 'Terminated empty element'
- );
- }
-
- function testElementEscaping() {
- $this->assertEquals(
- 'hello <there> you & you',
- Xml::element( 'element', null, 'hello you & you' ),
- 'Element with no attributes and content that needs escaping'
- );
- }
-
- function testElementAttributes() {
- $this->assertEquals(
- '="<>">',
- Xml::element( 'element', array( 'key' => 'value', '<>' => '<>' ), null ),
- 'Element attributes, keys are not escaped'
- );
- }
-
- function testOpenElement() {
- $this->assertEquals(
- '',
- Xml::openElement( 'element', array( 'k' => 'v' ) ),
- 'openElement() shortcut'
- );
- }
-
- function testCloseElement() {
- $this->assertEquals( '', Xml::closeElement( 'element' ), 'closeElement() shortcut' );
- }
-
- #
- # textarea
- #
- function testTextareaNoContent() {
- $this->assertEquals(
- '',
- Xml::textarea( 'name', '' ),
- 'textarea() with not content'
- );
- }
-
- function testTextareaAttribs() {
- $this->assertEquals(
- '',
- Xml::textarea( 'name', '', 20, 10 ),
- 'textarea() with custom attribs'
- );
- }
-
- #
- # JS
- #
- function testEscapeJsStringSpecialChars() {
- $this->assertEquals(
- '\\\\\r\n',
- Xml::escapeJsString( "\\\r\n" ),
- 'escapeJsString() with special characters'
- );
- }
-
- function testEncodeJsVarBoolean() {
- $this->assertEquals(
- 'true',
- Xml::encodeJsVar( true ),
- 'encodeJsVar() with boolean'
- );
- }
-
- function testEncodeJsVarNull() {
- $this->assertEquals(
- 'null',
- Xml::encodeJsVar( null ),
- 'encodeJsVar() with null'
- );
- }
-
- function testEncodeJsVarArray() {
- $this->assertEquals(
- '["a", 1]',
- Xml::encodeJsVar( array( 'a', 1 ) ),
- 'encodeJsVar() with array'
- );
- $this->assertEquals(
- '{"a": "a", "b": 1}',
- Xml::encodeJsVar( array( 'a' => 'a', 'b' => 1 ) ),
- 'encodeJsVar() with associative array'
- );
- }
-
- function testEncodeJsVarObject() {
- $this->assertEquals(
- '{"a": "a", "b": 1}',
- Xml::encodeJsVar( (object)array( 'a' => 'a', 'b' => 1 ) ),
- 'encodeJsVar() with object'
- );
- }
-}
diff --git a/maintenance/tests/bootstrap.php b/maintenance/tests/bootstrap.php
deleted file mode 100644
index 019bee07..00000000
--- a/maintenance/tests/bootstrap.php
+++ /dev/null
@@ -1,15 +0,0 @@
-
+# http://www.mediawiki.org/
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# http://www.gnu.org/copyleft/gpl.html
+
+/**
+ * @todo Make this more independent of the configuration (and if possible the database)
+ * @todo document
+ * @file
+ * @ingroup Maintenance
+ */
+
+/**
+ * @ingroup Maintenance
+ */
+class ParserTest {
+ /**
+ * boolean $color whereas output should be colorized
+ */
+ private $color;
+
+ /**
+ * boolean $showOutput Show test output
+ */
+ private $showOutput;
+
+ /**
+ * boolean $useTemporaryTables Use temporary tables for the temporary database
+ */
+ private $useTemporaryTables = true;
+
+ /**
+ * boolean $databaseSetupDone True if the database has been set up
+ */
+ private $databaseSetupDone = false;
+
+ /**
+ * string $oldTablePrefix Original table prefix
+ */
+ private $oldTablePrefix;
+
+ private $maxFuzzTestLength = 300;
+ private $fuzzSeed = 0;
+ private $memoryLimit = 50;
+ private $uploadDir = null;
+
+ public $regex = "";
+ private $savedGlobals = array();
+ /**
+ * Sets terminal colorization and diff/quick modes depending on OS and
+ * command-line options (--color and --quick).
+ */
+ public function ParserTest( $options = array() ) {
+ # Only colorize output if stdout is a terminal.
+ $this->color = !wfIsWindows() && posix_isatty( 1 );
+
+ if ( isset( $options['color'] ) ) {
+ switch( $options['color'] ) {
+ case 'no':
+ $this->color = false;
+ break;
+ case 'yes':
+ default:
+ $this->color = true;
+ break;
+ }
+ }
+
+ $this->term = $this->color
+ ? new AnsiTermColorer()
+ : new DummyTermColorer();
+
+ $this->showDiffs = !isset( $options['quick'] );
+ $this->showProgress = !isset( $options['quiet'] );
+ $this->showFailure = !(
+ isset( $options['quiet'] )
+ && ( isset( $options['record'] )
+ || isset( $options['compare'] ) ) ); // redundant output
+
+ $this->showOutput = isset( $options['show-output'] );
+
+
+ if ( isset( $options['regex'] ) ) {
+ if ( isset( $options['record'] ) ) {
+ echo "Warning: --record cannot be used with --regex, disabling --record\n";
+ unset( $options['record'] );
+ }
+ $this->regex = $options['regex'];
+ } else {
+ # Matches anything
+ $this->regex = '';
+ }
+
+ $this->setupRecorder( $options );
+ $this->keepUploads = isset( $options['keep-uploads'] );
+
+ if ( isset( $options['seed'] ) ) {
+ $this->fuzzSeed = intval( $options['seed'] ) - 1;
+ }
+
+ $this->runDisabled = isset( $options['run-disabled'] );
+
+ $this->hooks = array();
+ $this->functionHooks = array();
+ self::setUp();
+ }
+
+ static function setUp() {
+ global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
+ $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
+ $wgMessageCache, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $parserMemc,
+ $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
+ $wgThumbnailScriptPath, $wgScriptPath,
+ $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath;
+
+ $wgScript = '/index.php';
+ $wgScriptPath = '/';
+ $wgArticlePath = '/wiki/$1';
+ $wgStyleSheetPath = '/skins';
+ $wgStylePath = '/skins';
+ $wgThumbnailScriptPath = false;
+ $wgLocalFileRepo = array(
+ 'class' => 'LocalRepo',
+ 'name' => 'local',
+ 'directory' => wfTempDir() . '/test-repo',
+ 'url' => 'http://example.com/images',
+ 'deletedDir' => wfTempDir() . '/test-repo/delete',
+ 'hashLevels' => 2,
+ 'transformVia404' => false,
+ );
+ $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
+ $wgNamespaceAliases['Image'] = NS_FILE;
+ $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
+
+
+ $wgEnableParserCache = false;
+ $wgDeferredUpdateList = array();
+ $wgMemc = &wfGetMainCache();
+ $messageMemc = &wfGetMessageCacheStorage();
+ $parserMemc = &wfGetParserCacheStorage();
+
+ // $wgContLang = new StubContLang;
+ $wgUser = new User;
+ $wgLang = new StubUserLang;
+ $wgOut = new StubObject( 'wgOut', 'OutputPage' );
+ $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
+ $wgRequest = new WebRequest;
+
+ $wgMessageCache = new StubObject( 'wgMessageCache', 'MessageCache',
+ array( $messageMemc, $wgUseDatabaseMessages,
+ $wgMsgCacheExpiry ) );
+ if ( $wgStyleDirectory === false ) {
+ $wgStyleDirectory = "$IP/skins";
+ }
+
+ }
+
+ public function setupRecorder ( $options ) {
+ if ( isset( $options['record'] ) ) {
+ $this->recorder = new DbTestRecorder( $this );
+ $this->recorder->version = isset( $options['setversion'] ) ?
+ $options['setversion'] : SpecialVersion::getVersion();
+ } elseif ( isset( $options['compare'] ) ) {
+ $this->recorder = new DbTestPreviewer( $this );
+ } elseif ( isset( $options['upload'] ) ) {
+ $this->recorder = new RemoteTestRecorder( $this );
+ } else {
+ $this->recorder = new TestRecorder( $this );
+ }
+ }
+
+ /**
+ * Remove last character if it is a newline
+ * @group utility
+ */
+ static public function chomp( $s ) {
+ if ( substr( $s, -1 ) === "\n" ) {
+ return substr( $s, 0, -1 );
+ }
+ else {
+ return $s;
+ }
+ }
+
+ /**
+ * Run a fuzz test series
+ * Draw input from a set of test files
+ */
+ function fuzzTest( $filenames ) {
+ $GLOBALS['wgContLang'] = Language::factory( 'en' );
+ $dict = $this->getFuzzInput( $filenames );
+ $dictSize = strlen( $dict );
+ $logMaxLength = log( $this->maxFuzzTestLength );
+ $this->setupDatabase();
+ ini_set( 'memory_limit', $this->memoryLimit * 1048576 );
+
+ $numTotal = 0;
+ $numSuccess = 0;
+ $user = new User;
+ $opts = ParserOptions::newFromUser( $user );
+ $title = Title::makeTitle( NS_MAIN, 'Parser_test' );
+
+ while ( true ) {
+ // Generate test input
+ mt_srand( ++$this->fuzzSeed );
+ $totalLength = mt_rand( 1, $this->maxFuzzTestLength );
+ $input = '';
+
+ while ( strlen( $input ) < $totalLength ) {
+ $logHairLength = mt_rand( 0, 1000000 ) / 1000000 * $logMaxLength;
+ $hairLength = min( intval( exp( $logHairLength ) ), $dictSize );
+ $offset = mt_rand( 0, $dictSize - $hairLength );
+ $input .= substr( $dict, $offset, $hairLength );
+ }
+
+ $this->setupGlobals();
+ $parser = $this->getParser();
+
+ // Run the test
+ try {
+ $parser->parse( $input, $title, $opts );
+ $fail = false;
+ } catch ( Exception $exception ) {
+ $fail = true;
+ }
+
+ if ( $fail ) {
+ echo "Test failed with seed {$this->fuzzSeed}\n";
+ echo "Input:\n";
+ var_dump( $input );
+ echo "\n\n";
+ echo "$exception\n";
+ } else {
+ $numSuccess++;
+ }
+
+ $numTotal++;
+ $this->teardownGlobals();
+ $parser->__destruct();
+
+ if ( $numTotal % 100 == 0 ) {
+ $usage = intval( memory_get_usage( true ) / $this->memoryLimit / 1048576 * 100 );
+ echo "{$this->fuzzSeed}: $numSuccess/$numTotal (mem: $usage%)\n";
+ if ( $usage > 90 ) {
+ echo "Out of memory:\n";
+ $memStats = $this->getMemoryBreakdown();
+
+ foreach ( $memStats as $name => $usage ) {
+ echo "$name: $usage\n";
+ }
+ $this->abort();
+ }
+ }
+ }
+ }
+
+ /**
+ * Get an input dictionary from a set of parser test files
+ */
+ function getFuzzInput( $filenames ) {
+ $dict = '';
+
+ foreach ( $filenames as $filename ) {
+ $contents = file_get_contents( $filename );
+ preg_match_all( '/!!\s*input\n(.*?)\n!!\s*result/s', $contents, $matches );
+
+ foreach ( $matches[1] as $match ) {
+ $dict .= $match . "\n";
+ }
+ }
+
+ return $dict;
+ }
+
+ /**
+ * Get a memory usage breakdown
+ */
+ function getMemoryBreakdown() {
+ $memStats = array();
+
+ foreach ( $GLOBALS as $name => $value ) {
+ $memStats['$' . $name] = strlen( serialize( $value ) );
+ }
+
+ $classes = get_declared_classes();
+
+ foreach ( $classes as $class ) {
+ $rc = new ReflectionClass( $class );
+ $props = $rc->getStaticProperties();
+ $memStats[$class] = strlen( serialize( $props ) );
+ $methods = $rc->getMethods();
+
+ foreach ( $methods as $method ) {
+ $memStats[$class] += strlen( serialize( $method->getStaticVariables() ) );
+ }
+ }
+
+ $functions = get_defined_functions();
+
+ foreach ( $functions['user'] as $function ) {
+ $rf = new ReflectionFunction( $function );
+ $memStats["$function()"] = strlen( serialize( $rf->getStaticVariables() ) );
+ }
+
+ asort( $memStats );
+
+ return $memStats;
+ }
+
+ function abort() {
+ $this->abort();
+ }
+
+ /**
+ * Run a series of tests listed in the given text files.
+ * Each test consists of a brief description, wikitext input,
+ * and the expected HTML output.
+ *
+ * Prints status updates on stdout and counts up the total
+ * number and percentage of passed tests.
+ *
+ * @param $filenames Array of strings
+ * @return Boolean: true if passed all tests, false if any tests failed.
+ */
+ public function runTestsFromFiles( $filenames ) {
+ $ok = false;
+ $GLOBALS['wgContLang'] = Language::factory( 'en' );
+ $this->recorder->start();
+ try {
+ $this->setupDatabase();
+ $ok = true;
+
+ foreach ( $filenames as $filename ) {
+ $tests = new TestFileIterator( $filename, $this );
+ $ok = $this->runTests( $tests ) && $ok;
+ }
+
+ $this->teardownDatabase();
+ $this->recorder->report();
+ } catch (DBError $e) {
+ echo $e->getMessage();
+ }
+ $this->recorder->end();
+
+ return $ok;
+ }
+
+ function runTests( $tests ) {
+ $ok = true;
+
+ foreach ( $tests as $t ) {
+ $result =
+ $this->runTest( $t['test'], $t['input'], $t['result'], $t['options'], $t['config'] );
+ $ok = $ok && $result;
+ $this->recorder->record( $t['test'], $result );
+ }
+
+ if ( $this->showProgress ) {
+ print "\n";
+ }
+
+ return $ok;
+ }
+
+ /**
+ * Get a Parser object
+ */
+ function getParser( $preprocessor = null ) {
+ global $wgParserConf;
+
+ $class = $wgParserConf['class'];
+ $parser = new $class( array( 'preprocessorClass' => $preprocessor ) + $wgParserConf );
+
+ foreach ( $this->hooks as $tag => $callback ) {
+ $parser->setHook( $tag, $callback );
+ }
+
+ foreach ( $this->functionHooks as $tag => $bits ) {
+ list( $callback, $flags ) = $bits;
+ $parser->setFunctionHook( $tag, $callback, $flags );
+ }
+
+ wfRunHooks( 'ParserTestParser', array( &$parser ) );
+
+ return $parser;
+ }
+
+ /**
+ * Run a given wikitext input through a freshly-constructed wiki parser,
+ * and compare the output against the expected results.
+ * Prints status and explanatory messages to stdout.
+ *
+ * @param $desc String: test's description
+ * @param $input String: wikitext to try rendering
+ * @param $result String: result to output
+ * @param $opts Array: test's options
+ * @param $config String: overrides for global variables, one per line
+ * @return Boolean
+ */
+ public function runTest( $desc, $input, $result, $opts, $config ) {
+ if ( $this->showProgress ) {
+ $this->showTesting( $desc );
+ }
+
+ $opts = $this->parseOptions( $opts );
+ $this->setupGlobals( $opts, $config );
+
+ $user = new User();
+ $options = ParserOptions::newFromUser( $user );
+
+ if ( isset( $opts['title'] ) ) {
+ $titleText = $opts['title'];
+ }
+ else {
+ $titleText = 'Parser test';
+ }
+
+ $local = isset( $opts['local'] );
+ $preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null;
+ $parser = $this->getParser( $preprocessor );
+ $title = Title::newFromText( $titleText );
+
+ if ( isset( $opts['pst'] ) ) {
+ $out = $parser->preSaveTransform( $input, $title, $user, $options );
+ } elseif ( isset( $opts['msg'] ) ) {
+ $out = $parser->transformMsg( $input, $options );
+ } elseif ( isset( $opts['section'] ) ) {
+ $section = $opts['section'];
+ $out = $parser->getSection( $input, $section );
+ } elseif ( isset( $opts['replace'] ) ) {
+ $section = $opts['replace'][0];
+ $replace = $opts['replace'][1];
+ $out = $parser->replaceSection( $input, $section, $replace );
+ } elseif ( isset( $opts['comment'] ) ) {
+ $linker = $user->getSkin();
+ $out = $linker->formatComment( $input, $title, $local );
+ } elseif ( isset( $opts['preload'] ) ) {
+ $out = $parser->getpreloadText( $input, $title, $options );
+ } else {
+ $output = $parser->parse( $input, $title, $options, true, true, 1337 );
+ $out = $output->getText();
+
+ if ( isset( $opts['showtitle'] ) ) {
+ if ( $output->getTitleText() ) {
+ $title = $output->getTitleText();
+ }
+
+ $out = "$title\n$out";
+ }
+
+ if ( isset( $opts['ill'] ) ) {
+ $out = $this->tidy( implode( ' ', $output->getLanguageLinks() ) );
+ } elseif ( isset( $opts['cat'] ) ) {
+ global $wgOut;
+
+ $wgOut->addCategoryLinks( $output->getCategories() );
+ $cats = $wgOut->getCategoryLinks();
+
+ if ( isset( $cats['normal'] ) ) {
+ $out = $this->tidy( implode( ' ', $cats['normal'] ) );
+ } else {
+ $out = '';
+ }
+ }
+
+ $result = $this->tidy( $result );
+ }
+
+ $this->teardownGlobals();
+ return $this->showTestResult( $desc, $result, $out );
+ }
+
+ /**
+ *
+ */
+ function showTestResult( $desc, $result, $out ) {
+ if ( $result === $out ) {
+ $this->showSuccess( $desc );
+ return true;
+ } else {
+ $this->showFailure( $desc, $result, $out );
+ return false;
+ }
+ }
+
+ /**
+ * Use a regex to find out the value of an option
+ * @param $key String: name of option val to retrieve
+ * @param $opts Options array to look in
+ * @param $default Mixed: default value returned if not found
+ */
+ private static function getOptionValue( $key, $opts, $default ) {
+ $key = strtolower( $key );
+
+ if ( isset( $opts[$key] ) ) {
+ return $opts[$key];
+ } else {
+ return $default;
+ }
+ }
+
+ private function parseOptions( $instring ) {
+ $opts = array();
+ // foo
+ // foo=bar
+ // foo="bar baz"
+ // foo=[[bar baz]]
+ // foo=bar,"baz quux"
+ $regex = '/\b
+ ([\w-]+) # Key
+ \b
+ (?:\s*
+ = # First sub-value
+ \s*
+ (
+ "
+ [^"]* # Quoted val
+ "
+ |
+ \[\[
+ [^]]* # Link target
+ \]\]
+ |
+ [\w-]+ # Plain word
+ )
+ (?:\s*
+ , # Sub-vals 1..N
+ \s*
+ (
+ "[^"]*" # Quoted val
+ |
+ \[\[[^]]*\]\] # Link target
+ |
+ [\w-]+ # Plain word
+ )
+ )*
+ )?
+ /x';
+
+ if ( preg_match_all( $regex, $instring, $matches, PREG_SET_ORDER ) ) {
+ foreach ( $matches as $bits ) {
+ array_shift( $bits );
+ $key = strtolower( array_shift( $bits ) );
+ if ( count( $bits ) == 0 ) {
+ $opts[$key] = true;
+ } elseif ( count( $bits ) == 1 ) {
+ $opts[$key] = $this->cleanupOption( array_shift( $bits ) );
+ } else {
+ // Array!
+ $opts[$key] = array_map( array( $this, 'cleanupOption' ), $bits );
+ }
+ }
+ }
+ return $opts;
+ }
+
+ private function cleanupOption( $opt ) {
+ if ( substr( $opt, 0, 1 ) == '"' ) {
+ return substr( $opt, 1, -1 );
+ }
+
+ if ( substr( $opt, 0, 2 ) == '[[' ) {
+ return substr( $opt, 2, -2 );
+ }
+ return $opt;
+ }
+
+ /**
+ * Set up the global variables for a consistent environment for each test.
+ * Ideally this should replace the global configuration entirely.
+ */
+ private function setupGlobals( $opts = '', $config = '' ) {
+ global $wgDBtype;
+
+ # Find out values for some special options.
+ $lang =
+ self::getOptionValue( 'language', $opts, 'en' );
+ $variant =
+ self::getOptionValue( 'variant', $opts, false );
+ $maxtoclevel =
+ self::getOptionValue( 'wgMaxTocLevel', $opts, 999 );
+ $linkHolderBatchSize =
+ self::getOptionValue( 'wgLinkHolderBatchSize', $opts, 1000 );
+
+ $settings = array(
+ 'wgServer' => 'http://Britney-Spears',
+ 'wgScript' => '/index.php',
+ 'wgScriptPath' => '/',
+ 'wgArticlePath' => '/wiki/$1',
+ 'wgActionPaths' => array(),
+ 'wgLocalFileRepo' => array(
+ 'class' => 'LocalRepo',
+ 'name' => 'local',
+ 'directory' => $this->uploadDir,
+ 'url' => 'http://example.com/images',
+ 'hashLevels' => 2,
+ 'transformVia404' => false,
+ ),
+ 'wgEnableUploads' => self::getOptionValue( 'wgEnableUploads', $opts, true ),
+ 'wgStylePath' => '/skins',
+ 'wgStyleSheetPath' => '/skins',
+ 'wgSitename' => 'MediaWiki',
+ 'wgLanguageCode' => $lang,
+ 'wgDBprefix' => $wgDBtype != 'oracle' ? 'parsertest_' : 'pt_',
+ 'wgRawHtml' => isset( $opts['rawhtml'] ),
+ 'wgLang' => null,
+ 'wgContLang' => null,
+ 'wgNamespacesWithSubpages' => array( 0 => isset( $opts['subpage'] ) ),
+ 'wgMaxTocLevel' => $maxtoclevel,
+ 'wgCapitalLinks' => true,
+ 'wgNoFollowLinks' => true,
+ 'wgNoFollowDomainExceptions' => array(),
+ 'wgThumbnailScriptPath' => false,
+ 'wgUseImageResize' => false,
+ 'wgUseTeX' => isset( $opts['math'] ),
+ 'wgMathDirectory' => $this->uploadDir . '/math',
+ 'wgLocaltimezone' => 'UTC',
+ 'wgAllowExternalImages' => true,
+ 'wgUseTidy' => false,
+ 'wgDefaultLanguageVariant' => $variant,
+ 'wgVariantArticlePath' => false,
+ 'wgGroupPermissions' => array( '*' => array(
+ 'createaccount' => true,
+ 'read' => true,
+ 'edit' => true,
+ 'createpage' => true,
+ 'createtalk' => true,
+ ) ),
+ 'wgNamespaceProtection' => array( NS_MEDIAWIKI => 'editinterface' ),
+ 'wgDefaultExternalStore' => array(),
+ 'wgForeignFileRepos' => array(),
+ 'wgLinkHolderBatchSize' => $linkHolderBatchSize,
+ 'wgExperimentalHtmlIds' => false,
+ 'wgExternalLinkTarget' => false,
+ 'wgAlwaysUseTidy' => false,
+ 'wgHtml5' => true,
+ 'wgWellFormedXml' => true,
+ 'wgAllowMicrodataAttributes' => true,
+ );
+
+ if ( $config ) {
+ $configLines = explode( "\n", $config );
+
+ foreach ( $configLines as $line ) {
+ list( $var, $value ) = explode( '=', $line, 2 );
+
+ $settings[$var] = eval( "return $value;" );
+ }
+ }
+
+ $this->savedGlobals = array();
+
+ foreach ( $settings as $var => $val ) {
+ if ( array_key_exists( $var, $GLOBALS ) ) {
+ $this->savedGlobals[$var] = $GLOBALS[$var];
+ }
+
+ $GLOBALS[$var] = $val;
+ }
+
+ $langObj = Language::factory( $lang );
+ $GLOBALS['wgLang'] = $langObj;
+ $GLOBALS['wgContLang'] = $langObj;
+ $GLOBALS['wgMemc'] = new FakeMemCachedClient;
+ $GLOBALS['wgOut'] = new OutputPage;
+
+ global $wgHooks;
+
+ $wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
+ $wgHooks['ParserTestParser'][] = 'ParserTestStaticParserHook::setup';
+ $wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
+
+ MagicWord::clearCache();
+
+ global $wgUser;
+ $wgUser = new User();
+ }
+
+ /**
+ * List of temporary tables to create, without prefix.
+ * Some of these probably aren't necessary.
+ */
+ private function listTables() {
+ global $wgDBtype;
+
+ $tables = array( 'user', 'user_properties', 'page', 'page_restrictions',
+ 'protected_titles', 'revision', 'text', 'pagelinks', 'imagelinks',
+ 'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'iwlinks',
+ 'site_stats', 'hitcounter', 'ipblocks', 'image', 'oldimage',
+ 'recentchanges', 'watchlist', 'math', 'interwiki', 'logging',
+ 'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo',
+ 'archive', 'user_groups', 'page_props', 'category', 'msg_resource', 'msg_resource_links'
+ );
+
+ if ( in_array( $wgDBtype, array( 'mysql', 'sqlite', 'oracle' ) ) )
+ array_push( $tables, 'searchindex' );
+
+ // Allow extensions to add to the list of tables to duplicate;
+ // may be necessary if they hook into page save or other code
+ // which will require them while running tests.
+ wfRunHooks( 'ParserTestTables', array( &$tables ) );
+
+ return $tables;
+ }
+
+ /**
+ * Set up a temporary set of wiki tables to work with for the tests.
+ * Currently this will only be done once per run, and any changes to
+ * the db will be visible to later tests in the run.
+ */
+ public function setupDatabase() {
+ global $wgDBprefix, $wgDBtype;
+
+ if ( $this->databaseSetupDone ) {
+ return;
+ }
+
+ if ( $wgDBprefix === 'parsertest_' || ( $wgDBtype == 'oracle' && $wgDBprefix === 'pt_' ) ) {
+ throw new MWException( 'setupDatabase should be called before setupGlobals' );
+ }
+
+ $this->databaseSetupDone = true;
+ $this->oldTablePrefix = $wgDBprefix;
+
+ # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892).
+ # It seems to have been fixed since (r55079?).
+ # If it fails, $wgCaches[CACHE_DB] = new HashBagOStuff(); should work around it.
+
+ # CREATE TEMPORARY TABLE breaks if there is more than one server
+ if ( wfGetLB()->getServerCount() != 1 ) {
+ $this->useTemporaryTables = false;
+ }
+
+ $temporary = $this->useTemporaryTables || $wgDBtype == 'postgres';
+
+ $db = wfGetDB( DB_MASTER );
+ $tables = $this->listTables();
+
+ foreach ( $tables as $tbl ) {
+ # Clean up from previous aborted run. So that table escaping
+ # works correctly across DB engines, we need to change the pre-
+ # fix back and forth so tableName() works right.
+ $this->changePrefix( $this->oldTablePrefix );
+ $oldTableName = $db->tableName( $tbl );
+ $this->changePrefix( $wgDBtype != 'oracle' ? 'parsertest_' : 'pt_' );
+ $newTableName = $db->tableName( $tbl );
+
+ if ( $wgDBtype == 'mysql' ) {
+ $db->query( "DROP TABLE IF EXISTS $newTableName" );
+ } elseif ( in_array( $wgDBtype, array( 'postgres', 'oracle' ) ) ) {
+ /* DROPs wouldn't work due to Foreign Key Constraints (bug 14990, r58669)
+ * Use "DROP TABLE IF EXISTS $newTableName CASCADE" for postgres? That
+ * syntax would also work for mysql.
+ */
+ } elseif ( $db->tableExists( $tbl ) ) {
+ $db->query( "DROP TABLE $newTableName" );
+ }
+
+ # Create new table
+ $db->duplicateTableStructure( $oldTableName, $newTableName, $temporary );
+ }
+
+ if ( $wgDBtype == 'oracle' )
+ $db->query( 'BEGIN FILL_WIKI_INFO; END;' );
+
+ $this->changePrefix( $wgDBtype != 'oracle' ? 'parsertest_' : 'pt_' );
+
+ if ( $wgDBtype == 'oracle' ) {
+ # Insert 0 user to prevent FK violations
+
+ # Anonymous user
+ $db->insert( 'user', array(
+ 'user_id' => 0,
+ 'user_name' => 'Anonymous' ) );
+ }
+
+ # Hack: insert a few Wikipedia in-project interwiki prefixes,
+ # for testing inter-language links
+ $db->insert( 'interwiki', array(
+ array( 'iw_prefix' => 'wikipedia',
+ 'iw_url' => 'http://en.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 0 ),
+ array( 'iw_prefix' => 'meatball',
+ 'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 0 ),
+ array( 'iw_prefix' => 'zh',
+ 'iw_url' => 'http://zh.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ array( 'iw_prefix' => 'es',
+ 'iw_url' => 'http://es.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ array( 'iw_prefix' => 'fr',
+ 'iw_url' => 'http://fr.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ array( 'iw_prefix' => 'ru',
+ 'iw_url' => 'http://ru.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ ) );
+
+
+ # Update certain things in site_stats
+ $db->insert( 'site_stats', array( 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ) );
+
+ # Reinitialise the LocalisationCache to match the database state
+ Language::getLocalisationCache()->unloadAll();
+
+ # Make a new message cache
+ global $wgMessageCache, $wgMemc;
+ $wgMessageCache = new MessageCache( $wgMemc, true, 3600 );
+
+ $this->uploadDir = $this->setupUploadDir();
+ $user = User::createNew( 'WikiSysop' );
+ $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
+ ), $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
+ ), $db->timestamp( '20010115123500' ), $user );
+ }
+
+ /**
+ * Change the table prefix on all open DB connections/
+ */
+ protected function changePrefix( $prefix ) {
+ global $wgDBprefix;
+ wfGetLBFactory()->forEachLB( array( $this, 'changeLBPrefix' ), array( $prefix ) );
+ $wgDBprefix = $prefix;
+ }
+
+ public function changeLBPrefix( $lb, $prefix ) {
+ $lb->forEachOpenConnection( array( $this, 'changeDBPrefix' ), array( $prefix ) );
+ }
+
+ public function changeDBPrefix( $db, $prefix ) {
+ $db->tablePrefix( $prefix );
+ }
+
+ public function teardownDatabase() {
+ global $wgDBtype;
+
+ if ( !$this->databaseSetupDone ) {
+ $this->teardownGlobals();
+ return;
+ }
+ $this->teardownUploadDir( $this->uploadDir );
+
+ $this->changePrefix( $this->oldTablePrefix );
+ $this->databaseSetupDone = false;
+
+ if ( $this->useTemporaryTables ) {
+ # Don't need to do anything
+ $this->teardownGlobals();
+ return;
+ }
+
+ $tables = $this->listTables();
+ $db = wfGetDB( DB_MASTER );
+
+ foreach ( $tables as $table ) {
+ $sql = $wgDBtype == 'oracle' ? "DROP TABLE pt_$table DROP CONSTRAINTS" : "DROP TABLE `parsertest_$table`";
+ $db->query( $sql );
+ }
+
+ if ( $wgDBtype == 'oracle' )
+ $db->query( 'BEGIN FILL_WIKI_INFO; END;' );
+
+ $this->teardownGlobals();
+ }
+
+ /**
+ * Create a dummy uploads directory which will contain a couple
+ * of files in order to pass existence tests.
+ *
+ * @return String: the directory
+ */
+ private function setupUploadDir() {
+ global $IP;
+
+ if ( $this->keepUploads ) {
+ $dir = wfTempDir() . '/mwParser-images';
+
+ if ( is_dir( $dir ) ) {
+ return $dir;
+ }
+ } else {
+ $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images";
+ }
+
+ // wfDebug( "Creating upload directory $dir\n" );
+ if ( file_exists( $dir ) ) {
+ wfDebug( "Already exists!\n" );
+ 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;
+ }
+
+ /**
+ * Restore default values and perform any necessary clean-up
+ * after each test runs.
+ */
+ private function teardownGlobals() {
+ RepoGroup::destroySingleton();
+ LinkCache::singleton()->clear();
+
+ foreach ( $this->savedGlobals as $var => $val ) {
+ $GLOBALS[$var] = $val;
+ }
+ }
+
+ /**
+ * Remove the dummy uploads directory
+ */
+ private function teardownUploadDir( $dir ) {
+ if ( $this->keepUploads ) {
+ return;
+ }
+
+ // 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",
+
+ "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png",
+ )
+ );
+
+ 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",
+ )
+ );
+ }
+
+ /**
+ * Delete the specified files, if they exist.
+ * @param $files Array: full paths to files to delete.
+ */
+ private static function deleteFiles( $files ) {
+ foreach ( $files as $file ) {
+ if ( file_exists( $file ) ) {
+ unlink( $file );
+ }
+ }
+ }
+
+ /**
+ * 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 );
+ }
+ }
+ }
+
+ /**
+ * "Running test $desc..."
+ */
+ protected function showTesting( $desc ) {
+ print "Running test $desc... ";
+ }
+
+ /**
+ * Print a happy success message.
+ *
+ * @param $desc String: the test name
+ * @return Boolean
+ */
+ protected function showSuccess( $desc ) {
+ if ( $this->showProgress ) {
+ print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n";
+ }
+
+ return true;
+ }
+
+ /**
+ * Print a failure message and provide some explanatory output
+ * about what went wrong if so configured.
+ *
+ * @param $desc String: the test name
+ * @param $result String: expected HTML output
+ * @param $html String: actual HTML output
+ * @return Boolean
+ */
+ protected function showFailure( $desc, $result, $html ) {
+ if ( $this->showFailure ) {
+ if ( !$this->showProgress ) {
+ # In quiet mode we didn't show the 'Testing' message before the
+ # test, in case it succeeded. Show it now:
+ $this->showTesting( $desc );
+ }
+
+ print $this->term->color( '31' ) . 'FAILED!' . $this->term->reset() . "\n";
+
+ if ( $this->showOutput ) {
+ print "--- Expected ---\n$result\n--- Actual ---\n$html\n";
+ }
+
+ if ( $this->showDiffs ) {
+ print $this->quickDiff( $result, $html );
+ if ( !$this->wellFormed( $html ) ) {
+ print "XML error: $this->mXmlError\n";
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Run given strings through a diff and return the (colorized) output.
+ * Requires writable /tmp directory and a 'diff' command in the PATH.
+ *
+ * @param $input String
+ * @param $output String
+ * @param $inFileTail String: tailing for the input file name
+ * @param $outFileTail String: tailing for the output file name
+ * @return String
+ */
+ protected function quickDiff( $input, $output, $inFileTail = 'expected', $outFileTail = 'actual' ) {
+ $prefix = wfTempDir() . "/mwParser-" . mt_rand();
+
+ $infile = "$prefix-$inFileTail";
+ $this->dumpToFile( $input, $infile );
+
+ $outfile = "$prefix-$outFileTail";
+ $this->dumpToFile( $output, $outfile );
+
+ $diff = `diff -au $infile $outfile`;
+ unlink( $infile );
+ unlink( $outfile );
+
+ return $this->colorDiff( $diff );
+ }
+
+ /**
+ * Write the given string to a file, adding a final newline.
+ *
+ * @param $data String
+ * @param $filename String
+ */
+ private function dumpToFile( $data, $filename ) {
+ $file = fopen( $filename, "wt" );
+ fwrite( $file, $data . "\n" );
+ fclose( $file );
+ }
+
+ /**
+ * Colorize unified diff output if set for ANSI color output.
+ * Subtractions are colored blue, additions red.
+ *
+ * @param $text String
+ * @return String
+ */
+ protected function colorDiff( $text ) {
+ return preg_replace(
+ array( '/^(-.*)$/m', '/^(\+.*)$/m' ),
+ array( $this->term->color( 34 ) . '$1' . $this->term->reset(),
+ $this->term->color( 31 ) . '$1' . $this->term->reset() ),
+ $text );
+ }
+
+ /**
+ * Show "Reading tests from ..."
+ *
+ * @param $path String
+ */
+ public function showRunFile( $path ) {
+ print $this->term->color( 1 ) .
+ "Reading tests from \"$path\"..." .
+ $this->term->reset() .
+ "\n";
+ }
+
+ /**
+ * Insert a temporary test article
+ * @param $name String: the title, including any prefix
+ * @param $text String: the article text
+ * @param $line Integer: the input line number, for reporting errors
+ */
+ static public function addArticle( $name, $text, $line = 'unknown' ) {
+ global $wgCapitalLinks;
+
+ $text = self::chomp($text);
+
+ $oldCapitalLinks = $wgCapitalLinks;
+ $wgCapitalLinks = true; // We only need this from SetupGlobals() See r70917#c8637
+
+ $name = self::chomp( $name );
+ $title = Title::newFromText( $name );
+
+ if ( is_null( $title ) ) {
+ wfDie( "invalid title ('$name' => '$title') at line $line\n" );
+ }
+
+ $aid = $title->getArticleID( Title::GAID_FOR_UPDATE );
+
+ if ( $aid != 0 ) {
+ debug_print_backtrace();
+ wfDie( "duplicate article '$name' at line $line\n" );
+ }
+
+ $art = new Article( $title );
+ $art->insertNewArticle( $text, '', false, false );
+
+ $wgCapitalLinks = $oldCapitalLinks;
+ }
+
+ /**
+ * Steal a callback function from the primary parser, save it for
+ * application to our scary parser. If the hook is not installed,
+ * abort processing of this file.
+ *
+ * @param $name String
+ * @return Bool true if tag hook is present
+ */
+ public function requireHook( $name ) {
+ global $wgParser;
+
+ $wgParser->firstCallInit( ); // make sure hooks are loaded.
+
+ if ( isset( $wgParser->mTagHooks[$name] ) ) {
+ $this->hooks[$name] = $wgParser->mTagHooks[$name];
+ } else {
+ echo " This test suite requires the '$name' hook extension, skipping.\n";
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Steal a callback function from the primary parser, save it for
+ * application to our scary parser. If the hook is not installed,
+ * abort processing of this file.
+ *
+ * @param $name String
+ * @return Bool true if function hook is present
+ */
+ public function requireFunctionHook( $name ) {
+ global $wgParser;
+
+ $wgParser->firstCallInit( ); // make sure hooks are loaded.
+
+ if ( isset( $wgParser->mFunctionHooks[$name] ) ) {
+ $this->functionHooks[$name] = $wgParser->mFunctionHooks[$name];
+ } else {
+ echo " This test suite requires the '$name' function hook extension, skipping.\n";
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ * Run the "tidy" command on text if the $wgUseTidy
+ * global is true
+ *
+ * @param $text String: the text to tidy
+ * @return String
+ * @static
+ */
+ private function tidy( $text ) {
+ global $wgUseTidy;
+
+ if ( $wgUseTidy ) {
+ $text = MWTidy::tidy( $text );
+ }
+
+ return $text;
+ }
+
+ private function wellFormed( $text ) {
+ $html =
+ Sanitizer::hackDocType() .
+ '' .
+ $text .
+ '';
+
+ $parser = xml_parser_create( "UTF-8" );
+
+ # case folding violates XML standard, turn it off
+ xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
+
+ if ( !xml_parse( $parser, $html, true ) ) {
+ $err = xml_error_string( xml_get_error_code( $parser ) );
+ $position = xml_get_current_byte_index( $parser );
+ $fragment = $this->extractFragment( $html, $position );
+ $this->mXmlError = "$err at byte $position:\n$fragment";
+ xml_parser_free( $parser );
+
+ return false;
+ }
+
+ xml_parser_free( $parser );
+
+ return true;
+ }
+
+ private function extractFragment( $text, $position ) {
+ $start = max( 0, $position - 10 );
+ $before = $position - $start;
+ $fragment = '...' .
+ $this->term->color( 34 ) .
+ substr( $text, $start, $before ) .
+ $this->term->color( 0 ) .
+ $this->term->color( 31 ) .
+ $this->term->color( 1 ) .
+ substr( $text, $position, 1 ) .
+ $this->term->color( 0 ) .
+ $this->term->color( 34 ) .
+ substr( $text, $position + 1, 9 ) .
+ $this->term->color( 0 ) .
+ '...';
+ $display = str_replace( "\n", ' ', $fragment );
+ $caret = ' ' .
+ str_repeat( ' ', $before ) .
+ $this->term->color( 31 ) .
+ '^' .
+ $this->term->color( 0 );
+
+ return "$display\n$caret";
+ }
+
+ static function getFakeTimestamp( &$parser, &$ts ) {
+ $ts = 123;
+ return true;
+ }
+}
diff --git a/maintenance/tests/parser/parserTests.txt b/maintenance/tests/parser/parserTests.txt
new file mode 100644
index 00000000..b3fa560c
--- /dev/null
+++ b/maintenance/tests/parser/parserTests.txt
@@ -0,0 +1,8315 @@
+# MediaWiki Parser test cases
+# Some taken from http://meta.wikimedia.org/wiki/Parser_testing
+# All (C) their respective authors and released under the GPL
+#
+# The syntax should be fairly self-explanatory.
+#
+# Currently supported test options:
+# One of the following three:
+#
+# (default) generate HTML output
+# pst apply pre-save transform
+# msg apply message transform
+#
+# Plus any combination of these:
+#
+# cat add category links
+# ill add inter-language links
+# subpage enable subpages (disabled by default)
+# noxml don't check for XML well formdness
+# title=[[XXX]] run test using article title XXX
+# language=XXX set content language to XXX for this test
+# variant=XXX set the variant of language for this test (eg zh-tw)
+# disabled do not run test
+# showtitle make the first line the title
+# comment run through Linker::formatComment() instead of main parser
+# local format section links in edit comment text as local links
+#
+# For testing purposes, temporary articles can created:
+# !!article / NAMESPACE:TITLE / !!text / ARTICLE TEXT / !!endarticle
+# where '/' denotes a newline.
+
+# This is the standard article assumed to exist.
+!! article
+Main Page
+!! text
+blah blah
+!! endarticle
+
+!!article
+Template:Foo
+!!text
+FOO
+!!endarticle
+
+!! article
+Template:Blank
+!! text
+!! endarticle
+
+!! article
+Template:!
+!! text
+|
+!! endarticle
+
+!!article
+MediaWiki:bad image list
+!!text
+* [[File:Bad.jpg]] except [[Nasty page]]
+!!endarticle
+
+###
+### Basic tests
+###
+!! test
+Blank input
+!! input
+!! result
+!! end
+
+
+!! test
+Simple paragraph
+!! input
+This is a simple paragraph.
+!! result
+This is a simple paragraph.
+
+!! end
+
+!! test
+Simple list
+!! input
+* Item 1
+* Item 2
+!! result
+
+
+!! end
+
+!! test
+Italics and bold
+!! input
+* plain
+* plain''italic''plain
+* plain''italic''plain''italic''plain
+* plain'''bold'''plain
+* plain'''bold'''plain'''bold'''plain
+* plain''italic''plain'''bold'''plain
+* plain'''bold'''plain''italic''plain
+* plain''italic'''bold-italic'''italic''plain
+* plain'''bold''bold-italic''bold'''plain
+* plain'''''bold-italic'''italic''plain
+* plain'''''bold-italic''bold'''plain
+* plain''italic'''bold-italic'''''plain
+* plain'''bold''bold-italic'''''plain
+* plain l'''italic''plain
+* plain l''''bold''' plain
+!! result
+- plain
+
- plainitalicplain
+
- plainitalicplainitalicplain
+
- plainboldplain
+
- plainboldplainboldplain
+
- plainitalicplainboldplain
+
- plainboldplainitalicplain
+
- plainitalicbold-italicitalicplain
+
- plainboldbold-italicboldplain
+
- plainbold-italicitalicplain
+
- plainbold-italicboldplain
+
- plainitalicbold-italicplain
+
- plainboldbold-italicplain
+
- plain l'italicplain
+
- plain l'bold plain
+
+
+!! end
+
+###
+### test cases
+###
+
+!! test
+ unordered list
+!! input
+* This is not an unordered list item.
+!! result
+* This is not an unordered list item.
+
+!! end
+
+!! test
+ spacing
+!! input
+Lorem ipsum dolor
+
+sed abit.
+ sed nullum.
+
+:and a colon
+
+!! result
+Lorem ipsum dolor
+
+sed abit.
+ sed nullum.
+
+:and a colon
+
+
+!! end
+
+!! test
+nowiki 3
+!! input
+:There is not nowiki.
+:There is nowiki.
+
+#There is not nowiki.
+#There is nowiki.
+
+*There is not nowiki.
+*There is nowiki.
+!! result
+- There is not nowiki.
+
- There is nowiki.
+
+- There is not nowiki.
+
- There is nowiki.
+
+- There is not nowiki.
+
- There is nowiki.
+
+
+!! end
+
+
+###
+### Comments
+###
+!! test
+Comment test 1
+!! input
+ asdf
+
+!! result
+asdf
+
+
+!! end
+
+!! test
+Comment test 2
+!! input
+asdf
+
+jkl
+!! result
+asdf
+jkl
+
+!! end
+
+!! test
+Comment test 3
+!! input
+asdf
+
+
+jkl
+!! result
+asdf
+jkl
+
+!! end
+
+!! test
+Comment test 4
+!! input
+asdfjkl
+!! result
+asdfjkl
+
+!! end
+
+!! test
+Comment spacing
+!! input
+a
+ b
+c
+!! result
+a
+
+ b
+
+c
+
+!! end
+
+!! test
+Comment whitespace
+!! input
+
+!! result
+
+!! end
+
+!! test
+Comment semantics and delimiters
+!! input
+
+!! result
+
+!! end
+
+!! test
+Comment semantics and delimiters, redux
+!! input
+
+!! result
+
+!! end
+
+!! test
+Comment semantics and delimiters: directors cut
+!! input
+-->
+!! result
+-->
+
+!! end
+
+!! test
+Comment semantics: nesting
+!! input
+-->
+!! result
+-->
+
+!! end
+
+!! test
+Comment semantics: unclosed comment at end
+!! input
+oo}}
+!! result
+FOO
+
+!! end
+
+!! test
+Comment on its own line post-expand
+!! input
+a
+{{blank}}
+b
+!! result
+a
+
b
+
+!! end
+
+###
+### Preformatted text
+###
+!! test
+Preformatted text
+!! input
+ This is some
+ Preformatted text
+ With ''italic''
+ And '''bold'''
+ And a [[Main Page|link]]
+!! result
+This is some
+Preformatted text
+With italic
+And bold
+And a link
+
+!! end
+
+!! test
+ with inside (compatibility with 1.6 and earlier)
+!! input
+
+
+
+
+
+!! result
+
+<b>
+<cite>
+<em>
+
+
+!! end
+
+!! test
+Regression with preformatted in
+!! input
+
+ Blah
+
+!! result
+
+Blah
+
+
+
+!! end
+
+# Expected output in the following test is not really expected (there should be
+# in the output) -- it's only testing for well-formedness.
+!! test
+Bug 6200: Preformatted in
+!! input
+
+ Blah
+
+!! result
+
+ Blah
+
+
+!! end
+
+!! test
+ with attributes (bug 3202)
+!! input
+Bluescreen of WikiDeath
+!! result
+Bluescreen of WikiDeath
+
+!! end
+
+!! test
+ with width attribute (bug 3202)
+!! input
+Narrow screen goodies
+!! result
+Narrow screen goodies
+
+!! end
+
+!! test
+ with forbidden attribute (bug 3202)
+!! input
+Narrow screen goodies
+!! result
+Narrow screen goodies
+
+!! end
+
+!! test
+ with forbidden attribute values (bug 3202)
+!! input
+Narrow screen goodies
+!! result
+Narrow screen goodies
+
+!! end
+
+!! test
+ inside (bug 13238)
+!! input
+
+
+
+
+
+
+Foo
+!! result
+
+<nowiki>
+
+
+
+
+<nowiki>Foo</nowiki>
+
+!! end
+
+!! test
+ and preference (first one wins)
+!! input
+
+
+
+
+
+
+
+
+
+
+
+
+
+!! result
+
+<nowiki>
+
+</nowiki>
+</pre>
+
+<pre>
+<nowiki>
+</pre>
+
+</pre>
+
+!! end
+
+
+###
+### Definition lists
+###
+!! test
+Simple definition
+!! input
+; name : Definition
+!! result
+
- name
- Definition
+
+
+!! end
+
+!! test
+Definition list for indentation only
+!! input
+: Indented text
+!! result
+- Indented text
+
+
+!! end
+
+!! test
+Definition list with no space
+!! input
+;name:Definition
+!! result
+- name
- Definition
+
+
+!!end
+
+!! test
+Definition list with URL link
+!! input
+; http://example.com/ : definition
+!! result
+- http://example.com/
- definition
+
+
+!! end
+
+!! test
+Definition list with bracketed URL link
+!! input
+;[http://www.example.com/ Example]:Something about it
+!! result
+- Example
- Something about it
+
+
+!! end
+
+!! test
+Definition list with wikilink containing colon
+!! input
+; [[Help:FAQ]]: The least-read page on Wikipedia
+!! result
+- Help:FAQ
- The least-read page on Wikipedia
+
+
+!! end
+
+# At Brion's and JeLuF's insistence... :)
+!! test
+Definition list with news link containing colon
+!! input
+; news:alt.wikipedia.rox: This isn't even a real newsgroup!
+!! result
+- news:alt.wikipedia.rox
- This isn't even a real newsgroup!
+
+
+!! end
+
+!! test
+Malformed definition list with colon
+!! input
+; news:alt.wikipedia.rox -- don't crash or enter an infinite loop
+!! result
+- news:alt.wikipedia.rox -- don't crash or enter an infinite loop
+
+
+!! end
+
+!! test
+Definition lists: colon in external link text
+!! input
+; [http://www.wikipedia2.org/ Wikipedia : The Next Generation]: OK, I made that up
+!! result
+- Wikipedia : The Next Generation
- OK, I made that up
+
+
+!! end
+
+!! test
+Definition lists: colon in HTML attribute
+!! input
+;bold
+!! result
+- bold
+
+
+!! end
+
+
+!! test
+Definition lists: self-closed tag
+!! input
+;one
two : two-line fun
+!! result
+- one
two - two-line fun
+
+
+!! end
+
+
+###
+### External links
+###
+!! test
+External links: non-bracketed
+!! input
+Non-bracketed: http://example.com
+!! result
+Non-bracketed: http://example.com
+
+!! end
+
+!! test
+External links: numbered
+!! input
+Numbered: [http://example.com]
+Numbered: [http://example.net]
+Numbered: [http://example.com]
+!! result
+Numbered: [1]
+Numbered: [2]
+Numbered: [3]
+
+!!end
+
+!! test
+External links: specified text
+!! input
+Specified text: [http://example.com link]
+!! result
+Specified text: link
+
+!!end
+
+!! test
+External links: trail
+!! input
+Linktrails should not work for external links: [http://example.com link]s
+!! result
+Linktrails should not work for external links: links
+
+!! end
+
+!! test
+External links: dollar sign in URL
+!! input
+http://example.com/1$2345
+!! result
+http://example.com/1$2345
+
+!! end
+
+!! test
+External links: dollar sign in URL (named)
+!! input
+[http://example.com/1$2345]
+!! result
+[1]
+
+!!end
+
+!! test
+External links: open square bracket forbidden in URL (bug 4377)
+!! input
+http://example.com/1[2345
+!! result
+http://example.com/1[2345
+
+!! end
+
+!! test
+External links: open square bracket forbidden in URL (named) (bug 4377)
+!! input
+[http://example.com/1[2345]
+!! result
+[2345
+
+!!end
+
+!! test
+External links: nowiki in URL link text (bug 6230)
+!!input
+[http://example.com/ ''example site'']
+!! result
+''example site''
+
+!! end
+
+!! test
+External links: newline forbidden in text (bug 6230 regression check)
+!! input
+[http://example.com/ first
+second]
+!! result
+[http://example.com/ first
+second]
+
+!!end
+
+!! test
+External image
+!! input
+External image: http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png
+!! result
+External image:
+
+!! end
+
+!! test
+External image from https
+!! input
+External image from https: https://meta.wikimedia.org/upload/f/f1/Ncwikicol.png
+!! result
+External image from https:
+
+!! end
+
+!! test
+Link to non-http image, no img tag
+!! input
+Link to non-http image, no img tag: ftp://example.com/test.jpg
+!! result
+Link to non-http image, no img tag: ftp://example.com/test.jpg
+
+!! end
+
+!! test
+External links: terminating separator
+!! input
+Terminating separator: http://example.com/thing,
+!! result
+Terminating separator: http://example.com/thing,
+
+!! end
+
+!! test
+External links: intervening separator
+!! input
+Intervening separator: http://example.com/1,2,3
+!! result
+Intervening separator: http://example.com/1,2,3
+
+!! end
+
+!! test
+External links: old bug with URL in query
+!! input
+Old bug with URL in query: [http://example.com/thing?url=http://example.com link]
+!! result
+Old bug with URL in query: link
+
+!! end
+
+!! test
+External links: old URL-in-URL bug, mixed protocols
+!! input
+And again with mixed protocols: [ftp://example.com?url=http://example.com link]
+!! result
+And again with mixed protocols: link
+
+!!end
+
+!! test
+External links: URL in text
+!! input
+URL in text: [http://example.com http://example.com]
+!! result
+URL in text: http://example.com
+
+!! end
+
+!! test
+External links: Clickable images
+!! input
+ja-style clickable images: [http://example.com http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png]
+!! result
+ja-style clickable images:
+
+!!end
+
+!! test
+External links: raw ampersand
+!! input
+Old & use: http://x&y
+!! result
+Old & use: http://x&y
+
+!! end
+
+!! test
+External links: encoded ampersand
+!! input
+Old & use: http://x&y
+!! result
+Old & use: http://x&y
+
+!! end
+
+!! test
+External links: encoded equals (bug 6102)
+!! input
+http://example.com/?foo=bar
+!! result
+http://example.com/?foo=bar
+
+!! end
+
+!! test
+External links: [raw ampersand]
+!! input
+Old & use: [http://x&y]
+!! result
+Old & use: [1]
+
+!! end
+
+!! test
+External links: [encoded ampersand]
+!! input
+Old & use: [http://x&y]
+!! result
+Old & use: [1]
+
+!! end
+
+!! test
+External links: [encoded equals] (bug 6102)
+!! input
+[http://example.com/?foo=bar]
+!! result
+[1]
+
+!! end
+
+!! test
+External links: [IDN ignored character reference in hostname; strip it right off]
+!! input
+[http://example.com/]
+!! result
+[1]
+
+!! end
+
+!! test
+External links: IDN ignored character reference in hostname; strip it right off
+!! input
+http://example.com/
+!! result
+http://example.com/
+
+!! end
+
+!! test
+External links: www.jpeg.org (bug 554)
+!! input
+http://www.jpeg.org
+!!result
+http://www.jpeg.org
+
+!! end
+
+!! test
+External links: URL within URL (original bug 2)
+!! input
+[http://www.unausa.org/newindex.asp?place=http://www.unausa.org/programs/mun.asp]
+!! result
+[1]
+
+!! end
+
+!! test
+BUG 361: URL inside bracketed URL
+!! input
+[http://www.example.com/foo http://www.example.com/bar]
+!! result
+http://www.example.com/bar
+
+!! end
+
+!! test
+BUG 361: URL within URL, not bracketed
+!! input
+http://www.example.com/foo?=http://www.example.com/bar
+!! result
+http://www.example.com/foo?=http://www.example.com/bar
+
+!! end
+
+!! test
+BUG 289: ">"-token in URL-tail
+!! input
+http://www.example.com/
+!! result
+http://www.example.com/<hello>
+
+!!end
+
+!! test
+BUG 289: literal ">"-token in URL-tail
+!! input
+http://www.example.com/html
+!! result
+http://www.example.com/html
+
+!!end
+
+!! test
+BUG 289: ">"-token in bracketed URL
+!! input
+[http://www.example.com/ stuff]
+!! result
+<hello> stuff
+
+!!end
+
+!! test
+BUG 289: literal ">"-token in bracketed URL
+!! input
+[http://www.example.com/html stuff]
+!! result
+html stuff
+
+!!end
+
+!! test
+BUG 289: literal double quote at end of URL
+!! input
+http://www.example.com/"hello"
+!! result
+http://www.example.com/"hello"
+
+!!end
+
+!! test
+BUG 289: literal double quote in bracketed URL
+!! input
+[http://www.example.com/"hello" stuff]
+!! result
+"hello" stuff
+
+!!end
+
+!! test
+External links: multiple legal whitespace is fine, Magnus. Don't break it please. (bug 5081)
+!! input
+[http://www.example.com test]
+!! result
+test
+
+!! end
+
+!! test
+External links: wiki links within external link (Bug 3695)
+!! input
+[http://example.com [[wikilink]] embedded in ext link]
+!! result
+wikilink embedded in ext link
+
+!! end
+
+!! test
+BUG 787: Links with one slash after the url protocol are invalid
+!! input
+http:/example.com
+
+[http:/example.com title]
+!! result
+http:/example.com
+
[http:/example.com title]
+
+!! end
+
+!! test
+Bug 2702: Mismatched , and tags are invalid
+!! input
+''[http://example.com text'']
+[http://example.com '''text]'''
+''Something [http://example.com in italic'']
+''Something [http://example.com mixed''''', even bold]'''
+'''''Now [http://example.com both''''']
+!! result
+text
+text
+Something in italic
+Something mixed, even bold
+Now both
+
+!! end
+
+
+!! test
+Bug 4781: %26 in URL
+!! input
+http://www.example.com/?title=AT%26T
+!! result
+http://www.example.com/?title=AT%26T
+
+!! end
+
+!! test
+Bug 4781, 5267: %26 in URL
+!! input
+http://www.example.com/?title=100%25_Bran
+!! result
+http://www.example.com/?title=100%25_Bran
+
+!! end
+
+!! test
+Bug 4781, 5267: %28, %29 in URL
+!! input
+http://www.example.com/?title=Ben-Hur_%281959_film%29
+!! result
+http://www.example.com/?title=Ben-Hur_%281959_film%29
+
+!! end
+
+
+!! test
+Bug 4781: %26 in autonumber URL
+!! input
+[http://www.example.com/?title=AT%26T]
+!! result
+[1]
+
+!! end
+
+!! test
+Bug 4781, 5267: %26 in autonumber URL
+!! input
+[http://www.example.com/?title=100%25_Bran]
+!! result
+[1]
+
+!! end
+
+!! test
+Bug 4781, 5267: %28, %29 in autonumber URL
+!! input
+[http://www.example.com/?title=Ben-Hur_%281959_film%29]
+!! result
+[1]
+
+!! end
+
+
+!! test
+Bug 4781: %26 in bracketed URL
+!! input
+[http://www.example.com/?title=AT%26T link]
+!! result
+link
+
+!! end
+
+!! test
+Bug 4781, 5267: %26 in bracketed URL
+!! input
+[http://www.example.com/?title=100%25_Bran link]
+!! result
+link
+
+!! end
+
+!! test
+Bug 4781, 5267: %28, %29 in bracketed URL
+!! input
+[http://www.example.com/?title=Ben-Hur_%281959_film%29 link]
+!! result
+link
+
+!! end
+
+!! test
+External link containing double-single-quotes in text '' (bug 4598 sanity check)
+!! input
+Some [http://example.com/ pretty ''italics'' and stuff]!
+!! result
+Some pretty italics and stuff!
+
+!! end
+
+!! test
+External link containing double-single-quotes in text embedded in italics (bug 4598 sanity check)
+!! input
+''Some [http://example.com/ pretty ''italics'' and stuff]!''
+!! result
+Some pretty italics and stuff!
+
+!! end
+
+!! test
+External link containing double-single-quotes with no space separating the url from text in italics
+!! input
+[http://www.musee-picasso.fr/pages/page_id18528_u1l2.htm''La muerte de Casagemas'' (1901) en el sitio de [[Museo Picasso (París)|Museo Picasso]].]
+!! result
+La muerte de Casagemas (1901) en el sitio de Museo Picasso.
+
+!! end
+
+!! test
+URL-encoding in URL functions (single parameter)
+!! input
+{{localurl:Some page|amp=&}}
+!! result
+/index.php?title=Some_page&=&
+
+!! end
+
+!! test
+URL-encoding in URL functions (multiple parameters)
+!! input
+{{localurl:Some page|q=?&=&}}
+!! result
+/index.php?title=Some_page&q=?&=&
+
+!! end
+
+###
+### Quotes
+###
+
+!! test
+Quotes
+!! input
+Normal text. '''Bold text.''' Normal text. ''Italic text.''
+
+Normal text. '''''Bold italic text.''''' Normal text.
+!!result
+Normal text. Bold text. Normal text. Italic text.
+
Normal text. Bold italic text. Normal text.
+
+!! end
+
+
+!! test
+Unclosed and unmatched quotes
+!! input
+'''''Bold italic text '''with bold deactivated''' in between.'''''
+
+'''''Bold italic text ''with italic deactivated'' in between.'''''
+
+'''Bold text..
+
+..spanning two paragraphs (should not work).'''
+
+'''Bold tag left open
+
+''Italic tag left open
+
+Normal text.
+
+
+'''This year''''s election ''should'' beat '''last year''''s.
+
+''Tom'''s car is bigger than ''Susan'''s.
+!! result
+Bold italic text with bold deactivated in between.
+
Bold italic text with italic deactivated in between.
+
Bold text..
+
..spanning two paragraphs (should not work).
+
Bold tag left open
+
Italic tag left open
+
Normal text.
+
This year's election should beat last year's.
+
Toms car is bigger than Susans.
+
+!! end
+
+###
+### Tables
+###
+### some content taken from http://meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide:_Using_tables
+###
+
+# This should not produce as
+# is the bare minimun required by the spec, see:
+# http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html#a_module_Basic_Tables
+!! test
+A table with no data.
+!! input
+{||}
+!! result
+!! end
+
+# A table with nothing but a caption is invalid XHTML, we might want to render
+# this as caption
+!! test
+A table with nothing but a caption
+!! input
+{|
+|+ caption
+|}
+!! result
+
+
+!! end
+
+!! test
+Simple table
+!! input
+{|
+| 1 || 2
+|-
+| 3 || 4
+|}
+!! result
+
+
+!! end
+
+!! test
+Multiplication table
+!! input
+{| border="1" cellpadding="2"
+|+Multiplication table
+|-
+! × !! 1 !! 2 !! 3
+|-
+! 1
+| 1 || 2 || 3
+|-
+! 2
+| 2 || 4 || 6
+|-
+! 3
+| 3 || 6 || 9
+|-
+! 4
+| 4 || 8 || 12
+|-
+! 5
+| 5 || 10 || 15
+|}
+!! result
+
+Multiplication table
+
+
+ × |
+ 1 |
+ 2 |
+ 3
+ |
+
+ 1
+ |
+ 1 |
+ 2 |
+ 3
+ |
+
+ 2
+ |
+ 2 |
+ 4 |
+ 6
+ |
+
+ 3
+ |
+ 3 |
+ 6 |
+ 9
+ |
+
+ 4
+ |
+ 4 |
+ 8 |
+ 12
+ |
+
+ 5
+ |
+ 5 |
+ 10 |
+ 15
+ |
+
+!! end
+
+!! test
+Table rowspan
+!! input
+{| align=right border=1
+| Cell 1, row 1
+|rowspan=2| Cell 2, row 1 (and 2)
+| Cell 3, row 1
+|-
+| Cell 1, row 2
+| Cell 3, row 2
+|}
+!! result
+
+
+ Cell 1, row 1
+ |
+ Cell 2, row 1 (and 2)
+ |
+ Cell 3, row 1
+ |
+
+ Cell 1, row 2
+ |
+ Cell 3, row 2
+ |
+
+!! end
+
+!! test
+Nested table
+!! input
+{| border=1
+| α
+|
+{| bgcolor=#ABCDEF border=2
+|nested
+|-
+|table
+|}
+|the original table again
+|}
+!! result
+
+
+ α
+ |
+
+
+ |
+the original table again
+ |
+
+!! end
+
+!! test
+Invalid attributes in table cell (bug 1830)
+!! input
+{|
+|Cell:|broken
+|}
+!! result
+
+
+!! end
+
+
+!! test
+Table security: embedded pipes (http://lists.wikimedia.org/mailman/htdig/wikitech-l/2006-April/022293.html)
+!! input
+{|
+| |[ftp://|x||]" onmouseover="alert(document.cookie)">test
+!! result
+
+
+[ftp://%7Cx |
+]" onmouseover="alert(document.cookie)">test
+ |
+
+
+
+!! end
+
+
+###
+### Internal links
+###
+!! test
+Plain link, capitalized
+!! input
+[[Main Page]]
+!! result
+Main Page
+
+!! end
+
+!! test
+Plain link, uncapitalized
+!! input
+[[main Page]]
+!! result
+main Page
+
+!! end
+
+!! test
+Piped link
+!! input
+[[Main Page|The Main Page]]
+!! result
+The Main Page
+
+!! end
+
+!! test
+Broken link
+!! input
+[[Zigzagzogzagzig]]
+!! result
+Zigzagzogzagzig
+
+!! end
+
+!! test
+Broken link with fragment
+!! input
+[[Zigzagzogzagzig#zug]]
+!! result
+Zigzagzogzagzig#zug
+
+!! end
+
+!! test
+Special page link with fragment
+!! input
+[[Special:Version#anchor]]
+!! result
+Special:Version#anchor
+
+!! end
+
+!! test
+Nonexistent special page link with fragment
+!! input
+[[Special:ThisNameWillHopefullyNeverBeUsed#anchor]]
+!! result
+Special:ThisNameWillHopefullyNeverBeUsed#anchor
+
+!! end
+
+!! test
+Link with prefix
+!! input
+xxx[[main Page]], xxx[[Main Page]], Xxx[[main Page]] XXX[[main Page]], XXX[[Main Page]]
+!! result
+xxxmain Page, xxxMain Page, Xxxmain Page XXXmain Page, XXXMain Page
+
+!! end
+
+!! test
+Link with suffix
+!! input
+[[Main Page]]xxx, [[Main Page]]XXX, [[Main Page]]!!!
+!! result
+Main Pagexxx, Main PageXXX, Main Page!!!
+
+!! end
+
+!! test
+Link with 3 brackets
+!! input
+[[[main page]]]
+!! result
+[[[main page]]]
+
+!! end
+
+!! test
+Piped link with 3 brackets
+!! input
+[[[main page|the main page]]]
+!! result
+[[[main page|the main page]]]
+
+!! end
+
+!! test
+Link with multiple pipes
+!! input
+[[Main Page|The|Main|Page]]
+!! result
+The|Main|Page
+
+!! end
+
+!! test
+Link to namespaces
+!! input
+[[Talk:Parser testing]], [[Meta:Disclaimers]]
+!! result
+Talk:Parser testing, Meta:Disclaimers
+
+!! end
+
+!! test
+Piped link to namespace
+!! input
+[[Meta:Disclaimers|The disclaimers]]
+!! result
+The disclaimers
+
+!! end
+
+!! test
+Link containing }
+!! input
+[[Usually caused by a typo (oops}]]
+!! result
+[[Usually caused by a typo (oops}]]
+
+!! end
+
+!! test
+Link containing % (not as a hex sequence)
+!! input
+[[7% Solution]]
+!! result
+7% Solution
+
+!! end
+
+!! test
+Link containing % as a single hex sequence interpreted to char
+!! input
+[[7%25 Solution]]
+!! result
+7% Solution
+
+!!end
+
+!! test
+Link containing % as a double hex sequence interpreted to hex sequence
+!! input
+[[7%2525 Solution]]
+!! result
+[[7%2525 Solution]]
+
+!!end
+
+!! test
+Link containing "#<" and "#>" % as a hex sequences- these are valid section anchors
+Example for such a section: == < ==
+!! input
+[[%23%3c]][[%23%3e]]
+!! result
+#<#>
+
+!! end
+
+!! test
+Link containing "<#" and ">#" as a hex sequences
+!! input
+[[%3c%23]][[%3e%23]]
+!! result
+[[%3c%23]][[%3e%23]]
+
+!! end
+
+!! test
+Link containing double-single-quotes '' (bug 4598)
+!! input
+[[Lista d''e paise d''o munno]]
+!! result
+Lista d''e paise d''o munno
+
+!! end
+
+!! test
+Link containing double-single-quotes '' in text (bug 4598 sanity check)
+!! input
+Some [[Link|pretty ''italics'' and stuff]]!
+!! result
+Some pretty italics and stuff!
+
+!! end
+
+!! test
+Link containing double-single-quotes '' in text embedded in italics (bug 4598 sanity check)
+!! input
+''Some [[Link|pretty ''italics'' and stuff]]!
+!! result
+Some pretty italics and stuff!
+
+!! end
+
+!! test
+Link with double quotes in title part (literal) and alternate part (interpreted)
+!! input
+[[File:Denys Savchenko ''Pentecoste''.jpg]]
+
+[[''Pentecoste'']]
+
+[[''Pentecoste''|Pentecoste]]
+
+[[''Pentecoste''|''Pentecoste'']]
+!! result
+File:Denys Savchenko Pentecoste.jpg
+
''Pentecoste''
+
Pentecoste
+
Pentecoste
+
+!! end
+
+!! test
+Plain link to URL
+!! input
+[[http://www.example.com]]
+!! result
+[[1]]
+
+!! end
+
+# I'm fairly sure the expected result here is wrong.
+# We want these to be URL links, not pseudo-pages with URLs for titles....
+# However the current output is also pretty screwy.
+#
+# ----
+# I'm changing it to match the current output--it arguably makes more
+# sense in the light of the test above. Old expected result was:
+#Piped link to URL: an example URL
+#
+# But I think this test is bordering on "garbage in, garbage out" anyway.
+# -- wtm
+!! test
+Piped link to URL
+!! input
+Piped link to URL: [[http://www.example.com|an example URL]]
+!! result
+Piped link to URL: [example URL]
+
+!! end
+
+!! test
+BUG 2: [[page|http://url/]] should link to page, not http://url/
+!! input
+[[Main Page|http://url/]]
+!! result
+http://url/
+
+!! end
+
+!! test
+BUG 337: Escaped self-links should be bold
+!! options
+title=[[Bug462]]
+!! input
+[[Bug462]] [[Bug462]]
+!! result
+Bug462 Bug462
+
+!! end
+
+!! test
+Self-link to section should not be bold
+!! options
+title=[[Main Page]]
+!! input
+[[Main Page#section]]
+!! result
+Main Page#section
+
+!! end
+
+!! article
+00
+!! text
+This is 00.
+!! endarticle
+
+!!test
+Self-link to numeric title
+!!options
+title=[[0]]
+!!input
+[[0]]
+!!result
+0
+
+!!end
+
+!!test
+Link to numeric-equivalent title
+!!options
+title=[[0]]
+!!input
+[[00]]
+!!result
+00
+
+!!end
+
+!! test
+ inside a link
+!! input
+[[Main Page]] [[Main Page|the main page [it's not very good]]]
+!! result
+[[Main Page]] the main page [it's not very good]
+
+!! end
+
+!! test
+Non-breaking spaces in title
+!! input
+[[ Main Page ]]
+!! result
+ Main Page
+
+!!end
+
+
+###
+### Interwiki links (see maintenance/interwiki.sql)
+###
+
+!! test
+Inline interwiki link
+!! input
+[[MeatBall:SoftSecurity]]
+!! result
+MeatBall:SoftSecurity
+
+!! end
+
+!! test
+Inline interwiki link with empty title (bug 2372)
+!! input
+[[MeatBall:]]
+!! result
+MeatBall:
+
+!! end
+
+!! test
+Interwiki link encoding conversion (bug 1636)
+!! input
+*[[Wikipedia:ro:Olteniţa]]
+*[[Wikipedia:ro:Olteniţa]]
+!! result
+
+
+!! end
+
+!! test
+Interwiki link with fragment (bug 2130)
+!! input
+[[MeatBall:SoftSecurity#foo]]
+!! result
+MeatBall:SoftSecurity#foo
+
+!! end
+
+!! test
+Interlanguage link
+!! input
+Blah blah blah
+[[zh:Chinese]]
+!!result
+Blah blah blah
+
+!! end
+
+!! test
+Double interlanguage link
+!! input
+Blah blah blah
+[[es:Spanish]]
+[[zh:Chinese]]
+!!result
+Blah blah blah
+
+!! end
+
+!! test
+Interlanguage link, with prefix links
+!! options
+language=ln
+!! input
+Blah blah blah
+[[zh:Chinese]]
+!!result
+Blah blah blah
+
+!! end
+
+!! test
+Double interlanguage link, with prefix links (bug 8897)
+!! options
+language=ln
+!! input
+Blah blah blah
+[[es:Spanish]]
+[[zh:Chinese]]
+!!result
+Blah blah blah
+
+!! end
+
+
+##
+## XHTML tidiness
+###
+
+!! test
+
to
+!! input
+1
2
3
+!! result
+1
2
3
+
+!! end
+
+!! test
+Incorrecly removing closing slashes from correctly formed XHTML
+!! input
+
+!! result
+
+
+!! end
+
+!! test
+Failing to transform badly formed HTML into correct XHTML
+!! input
+
+
+
+!! result
+
+
+
+
+!!end
+
+!! test
+Horizontal ruler (should it add that extra space?)
+!! input
+
+
+foo
bar
+!! result
+
+
+foo
bar
+
+!! end
+
+###
+### Block-level elements
+###
+!! test
+Common list
+!! input
+*Common list
+* item 2
+*item 3
+!! result
+- Common list
+
- item 2
+
- item 3
+
+
+!! end
+
+!! test
+Numbered list
+!! input
+#Numbered list
+#item 2
+# item 3
+!! result
+- Numbered list
+
- item 2
+
- item 3
+
+
+!! end
+
+!! test
+Mixed list
+!! input
+*Mixed list
+*# with numbers
+** and bullets
+*# and numbers
+*bullets again
+**bullet level 2
+***bullet level 3
+***#Number on level 4
+**bullet level 2
+**#Number on level 3
+**#Number on level 3
+*#number level 2
+*Level 1
+!! result
+- Mixed list
+
- with numbers
+
+
+- and numbers
+
+ - bullets again
+
- bullet level 2
+
- bullet level 3
+
- Number on level 4
+
+
+ - bullet level 2
+
- Number on level 3
+
- Number on level 3
+
+
+- number level 2
+
+ - Level 1
+
+
+!! end
+
+!! test
+List items are not parsed correctly following a block (bug 785)
+!! input
+* foo
+* bar
+* zar
+!! result
+
+
+!! end
+
+###
+### Magic Words
+###
+
+!! test
+Magic Word: {{CURRENTDAY}}
+!! input
+{{CURRENTDAY}}
+!! result
+1
+
+!! end
+
+!! test
+Magic Word: {{CURRENTDAY2}}
+!! input
+{{CURRENTDAY2}}
+!! result
+01
+
+!! end
+
+!! test
+Magic Word: {{CURRENTDAYNAME}}
+!! input
+{{CURRENTDAYNAME}}
+!! result
+Thursday
+
+!! end
+
+!! test
+Magic Word: {{CURRENTDOW}}
+!! input
+{{CURRENTDOW}}
+!! result
+4
+
+!! end
+
+!! test
+Magic Word: {{CURRENTMONTH}}
+!! input
+{{CURRENTMONTH}}
+!! result
+01
+
+!! end
+
+!! test
+Magic Word: {{CURRENTMONTHABBREV}}
+!! input
+{{CURRENTMONTHABBREV}}
+!! result
+Jan
+
+!! end
+
+!! test
+Magic Word: {{CURRENTMONTHNAME}}
+!! input
+{{CURRENTMONTHNAME}}
+!! result
+January
+
+!! end
+
+!! test
+Magic Word: {{CURRENTMONTHNAMEGEN}}
+!! input
+{{CURRENTMONTHNAMEGEN}}
+!! result
+January
+
+!! end
+
+!! test
+Magic Word: {{CURRENTTIME}}
+!! input
+{{CURRENTTIME}}
+!! result
+00:02
+
+!! end
+
+!! test
+Magic Word: {{CURRENTWEEK}} (@bug 4594)
+!! input
+{{CURRENTWEEK}}
+!! result
+1
+
+!! end
+
+!! test
+Magic Word: {{CURRENTYEAR}}
+!! input
+{{CURRENTYEAR}}
+!! result
+1970
+
+!! end
+
+!! test
+Magic Word: {{FULLPAGENAME}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{FULLPAGENAME}}
+!! result
+User:Ævar Arnfjörð Bjarmason
+
+!! end
+
+!! test
+Magic Word: {{FULLPAGENAMEE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{FULLPAGENAMEE}}
+!! result
+User:%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason
+
+!! end
+
+!! test
+Magic Word: {{NAMESPACE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{NAMESPACE}}
+!! result
+User
+
+!! end
+
+!! test
+Magic Word: {{NAMESPACEE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{NAMESPACEE}}
+!! result
+User
+
+!! end
+
+!! test
+Magic Word: {{NUMBEROFFILES}}
+!! input
+{{NUMBEROFFILES}}
+!! result
+2
+
+!! end
+
+!! test
+Magic Word: {{PAGENAME}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{PAGENAME}}
+!! result
+Ævar Arnfjörð Bjarmason
+
+!! end
+
+!! test
+Magic Word: {{PAGENAMEE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{PAGENAMEE}}
+!! result
+%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason
+
+!! end
+
+!! test
+Magic Word: {{REVISIONID}}
+!! input
+{{REVISIONID}}
+!! result
+1337
+
+!! end
+
+!! test
+Magic Word: {{SCRIPTPATH}}
+!! input
+{{SCRIPTPATH}}
+!! result
+/
+
+!! end
+
+!! test
+Magic Word: {{SERVER}}
+!! input
+{{SERVER}}
+!! result
+http://Britney-Spears
+
+!! end
+
+!! test
+Magic Word: {{SERVERNAME}}
+!! input
+{{SERVERNAME}}
+!! result
+Britney-Spears
+
+!! end
+
+!! test
+Magic Word: {{SITENAME}}
+!! input
+{{SITENAME}}
+!! result
+MediaWiki
+
+!! end
+
+!! test
+Namespace 1 {{ns:1}}
+!! input
+{{ns:1}}
+!! result
+Talk
+
+!! end
+
+!! test
+Namespace 1 {{ns:01}}
+!! input
+{{ns:01}}
+!! result
+Talk
+
+!! end
+
+!! test
+Namespace 0 {{ns:0}} (bug 4783)
+!! input
+{{ns:0}}
+!! result
+
+!! end
+
+!! test
+Namespace 0 {{ns:00}} (bug 4783)
+!! input
+{{ns:00}}
+!! result
+
+!! end
+
+!! test
+Namespace -1 {{ns:-1}}
+!! input
+{{ns:-1}}
+!! result
+Special
+
+!! end
+
+!! test
+Namespace User {{ns:User}}
+!! input
+{{ns:User}}
+!! result
+User
+
+!! end
+
+!! test
+Namespace User talk {{ns:User_talk}}
+!! input
+{{ns:User_talk}}
+!! result
+User talk
+
+!! end
+
+!! test
+Namespace User talk {{ns:uSeR tAlK}}
+!! input
+{{ns:uSeR tAlK}}
+!! result
+User talk
+
+!! end
+
+!! test
+Namespace File {{ns:File}}
+!! input
+{{ns:File}}
+!! result
+File
+
+!! end
+
+!! test
+Namespace File {{ns:Image}}
+!! input
+{{ns:Image}}
+!! result
+File
+
+!! end
+
+!! test
+Namespace (lang=de) Benutzer {{ns:User}}
+!! options
+language=de
+!! input
+{{ns:User}}
+!! result
+Benutzer
+
+!! end
+
+!! test
+Namespace (lang=de) Benutzer Diskussion {{ns:3}}
+!! options
+language=de
+!! input
+{{ns:3}}
+!! result
+Benutzer Diskussion
+
+!! end
+
+
+!! test
+Urlencode
+!! input
+{{urlencode:hi world?!}}
+{{urlencode:hi world?!|WIKI}}
+{{urlencode:hi world?!|PATH}}
+{{urlencode:hi world?!|QUERY}}
+!! result
+hi+world%3F%21
+hi_world%3F!
+hi%20world%3F%21
+hi+world%3F%21
+
+!! end
+
+###
+### Magic links
+###
+!! test
+Magic links: internal link to RFC (bug 479)
+!! input
+[[RFC 123]]
+!! result
+RFC 123
+
+!! end
+
+!! test
+Magic links: RFC (bug 479)
+!! input
+RFC 822
+!! result
+RFC 822
+
+!! end
+
+!! test
+Magic links: ISBN (bug 1937)
+!! input
+ISBN 0-306-40615-2
+!! result
+ISBN 0-306-40615-2
+
+!! end
+
+!! test
+Magic links: PMID incorrectly converts space to underscore
+!! input
+PMID 1234
+!! result
+PMID 1234
+
+!! end
+
+###
+### Templates
+####
+
+!! test
+Nonexistent template
+!! input
+{{thistemplatedoesnotexist}}
+!! result
+Template:Thistemplatedoesnotexist
+
+!! end
+
+!! article
+Template:test
+!! text
+This is a test template
+!! endarticle
+
+!! test
+Simple template
+!! input
+{{test}}
+!! result
+This is a test template
+
+!! end
+
+!! test
+Template with explicit namespace
+!! input
+{{Template:test}}
+!! result
+This is a test template
+
+!! end
+
+
+!! article
+Template:paramtest
+!! text
+This is a test template with parameter {{{param}}}
+!! endarticle
+
+!! test
+Template parameter
+!! input
+{{paramtest|param=foo}}
+!! result
+This is a test template with parameter foo
+
+!! end
+
+!! article
+Template:paramtestnum
+!! text
+[[{{{1}}}|{{{2}}}]]
+!! endarticle
+
+!! test
+Template unnamed parameter
+!! input
+{{paramtestnum|Main Page|the main page}}
+!! result
+the main page
+
+!! end
+
+!! article
+Template:templatesimple
+!! text
+(test)
+!! endarticle
+
+!! article
+Template:templateredirect
+!! text
+#redirect [[Template:templatesimple]]
+!! endarticle
+
+!! article
+Template:templateasargtestnum
+!! text
+{{{{{1}}}}}
+!! endarticle
+
+!! article
+Template:templateasargtest
+!! text
+{{template{{{templ}}}}}
+!! endarticle
+
+!! article
+Template:templateasargtest2
+!! text
+{{{{{templ}}}}}
+!! endarticle
+
+!! test
+Template with template name as unnamed argument
+!! input
+{{templateasargtestnum|templatesimple}}
+!! result
+(test)
+
+!! end
+
+!! test
+Template with template name as argument
+!! input
+{{templateasargtest|templ=simple}}
+!! result
+(test)
+
+!! end
+
+!! test
+Template with template name as argument (2)
+!! input
+{{templateasargtest2|templ=templatesimple}}
+!! result
+(test)
+
+!! end
+
+!! article
+Template:templateasargtestdefault
+!! text
+{{{{{templ|templatesimple}}}}}
+!! endarticle
+
+!! article
+Template:templa
+!! text
+'''templ'''
+!! endarticle
+
+!! test
+Template with default value
+!! input
+{{templateasargtestdefault}}
+!! result
+(test)
+
+!! end
+
+!! test
+Template with default value (value set)
+!! input
+{{templateasargtestdefault|templ=templa}}
+!! result
+templ
+
+!! end
+
+!! test
+Template redirect
+!! input
+{{templateredirect}}
+!! result
+(test)
+
+!! end
+
+!! test
+Template with argument in separate line
+!! input
+{{ templateasargtest |
+ templ = simple }}
+!! result
+(test)
+
+!! end
+
+!! test
+Template with complex template as argument
+!! input
+{{paramtest|
+ param ={{ templateasargtest |
+ templ = simple }}}}
+!! result
+This is a test template with parameter (test)
+
+!! end
+
+!! test
+Template with thumb image (with link in description)
+!! input
+{{paramtest|
+ param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}}
+!! result
+This is a test template with parameter
+
+!! end
+
+!! article
+Template:complextemplate
+!! text
+{{{1}}} {{paramtest|
+ param ={{{param}}}}}
+!! endarticle
+
+!! test
+Template with complex arguments
+!! input
+{{complextemplate|
+ param ={{ templateasargtest |
+ templ = simple }}|[[Template:complextemplate|link]]}}
+!! result
+link This is a test template with parameter (test)
+
+!! end
+
+!! test
+BUG 553: link with two variables in a piped link
+!! input
+{|
+|[[{{{1}}}|{{{2}}}]]
+|}
+!! result
+
+
+!! end
+
+!! test
+Magic variable as template parameter
+!! input
+{{paramtest|param={{SITENAME}}}}
+!! result
+This is a test template with parameter MediaWiki
+
+!! end
+
+!! article
+Template:linktest
+!! text
+[[{{{param}}}|link]]
+!! endarticle
+
+!! test
+Template parameter as link source
+!! input
+{{linktest|param=Main Page}}
+!! result
+link
+
+!! end
+
+
+!!article
+Template:paramtest2
+!! text
+including another template, {{paramtest|param={{{arg}}}}}
+!! endarticle
+
+!! test
+Template passing argument to another template
+!! input
+{{paramtest2|arg='hmm'}}
+!! result
+including another template, This is a test template with parameter 'hmm'
+
+!! end
+
+!! article
+Template:Linktest2
+!! text
+Main Page
+!! endarticle
+
+!! test
+Template as link source
+!! input
+[[{{linktest2}}]]
+!! result
+Main Page
+
+!! end
+
+
+!! article
+Template:loop1
+!! text
+{{loop2}}
+!! endarticle
+
+!! article
+Template:loop2
+!! text
+{{loop1}}
+!! endarticle
+
+!! test
+Template infinite loop
+!! input
+{{loop1}}
+!! result
+Template loop detected: Template:Loop1
+
+!! end
+
+!! test
+Template from main namespace
+!! input
+{{:Main Page}}
+!! result
+blah blah
+
+!! end
+
+!! article
+Template:table
+!! text
+{|
+| 1 || 2
+|-
+| 3 || 4
+|}
+!! endarticle
+
+!! test
+BUG 529: Template with table, not included at beginning of line
+!! input
+foo {{table}}
+!! result
+foo
+
+
+
+!! end
+
+!! test
+BUG 523: Template shouldn't eat newline (or add an extra one before table)
+!! input
+foo
+{{table}}
+!! result
+foo
+
+
+
+!! end
+
+!! test
+BUG 41: Template parameters shown as broken links
+!! input
+{{{parameter}}}
+!! result
+{{{parameter}}}
+
+!! end
+
+
+!! article
+Template:MSGNW test
+!! text
+''None'' of '''this''' should be
+* interpreted
+ but rather passed unmodified
+{{test}}
+!! endarticle
+
+# hmm, fix this or just deprecate msgnw and document its behavior?
+!! test
+msgnw keyword
+!! options
+disabled
+!! input
+{{msgnw:MSGNW test}}
+!! result
+''None'' of '''this''' should be
+* interpreted
+ but rather passed unmodified
+{{test}}
+
+!! end
+
+!! test
+int keyword
+!! input
+{{int:youhavenewmessages|lots of money|not!}}
+!! result
+You have lots of money (not!).
+
+!! end
+
+!! article
+Template:Includes
+!! text
+Foozarbar
+!! endarticle
+
+!! test
+ and being included
+!! input
+{{Includes}}
+!! result
+Foobar
+
+!! end
+
+!! article
+Template:Includes2
+!! text
+Foobar
+!! endarticle
+
+!! test
+ being included
+!! input
+{{Includes2}}
+!! result
+Foo
+
+!! end
+
+
+!! article
+Template:Includes3
+!! text
+Foobarzar
+!! endarticle
+
+!! test
+ and being included
+!! input
+{{Includes3}}
+!! result
+Foo
+
+!! end
+
+!! test
+ and on a page
+!! input
+Foozarbar
+!! result
+Foozar
+
+!! end
+
+!! test
+ on a page
+!! input
+Foobar
+!! result
+Foobar
+
+!! end
+
+!! article
+Template:Includeonly section
+!! text
+
+==Includeonly section==
+
+==Section T-1==
+!!endarticle
+
+!! test
+Bug 6563: Edit link generation for section shown by
+!! input
+{{includeonly section}}
+!! result
+[edit] Includeonly section
+[edit] Section T-1
+
+!! end
+
+# Uses same input as the contents of [[Template:Includeonly section]]
+!! test
+Bug 6563: Section extraction for section shown by
+!! options
+section=T-2
+!! input
+
+==Includeonly section==
+
+==Section T-2==
+!! result
+==Section T-2==
+!! end
+
+!! test
+Bug 6563: Edit link generation for section suppressed by
+!! input
+
+==Includeonly section==
+
+==Section 1==
+!! result
+[edit] Section 1
+
+!! end
+
+!! test
+Bug 6563: Section extraction for section suppressed by
+!! options
+section=1
+!! input
+
+==Includeonly section==
+
+==Section 1==
+!! result
+==Section 1==
+!! end
+
+###
+### Pre-save transform tests
+###
+!! test
+pre-save transform: subst:
+!! options
+PST
+!! input
+{{subst:test}}
+!! result
+This is a test template
+!! end
+
+!! test
+pre-save transform: normal template
+!! options
+PST
+!! input
+{{test}}
+!! result
+{{test}}
+!! end
+
+!! test
+pre-save transform: nonexistent template
+!! options
+PST
+!! input
+{{thistemplatedoesnotexist}}
+!! result
+{{thistemplatedoesnotexist}}
+!! end
+
+
+!! test
+pre-save transform: subst magic variables
+!! options
+PST
+!! input
+{{subst:SITENAME}}
+!! result
+MediaWiki
+!! end
+
+# This is bug 89, which I fixed. -- wtm
+!! test
+pre-save transform: subst: templates with parameters
+!! options
+pst
+!! input
+{{subst:paramtest|param="something else"}}
+!! result
+This is a test template with parameter "something else"
+!! end
+
+!! article
+Template:nowikitest
+!! text
+'''not wiki'''
+!! endarticle
+
+!! test
+pre-save transform: nowiki in subst (bug 1188)
+!! options
+pst
+!! input
+{{subst:nowikitest}}
+!! result
+'''not wiki'''
+!! end
+
+
+!! article
+Template:commenttest
+!! text
+This template has in it.
+!! endarticle
+
+!! test
+pre-save transform: comment in subst (bug 1936)
+!! options
+pst
+!! input
+{{subst:commenttest}}
+!! result
+This template has in it.
+!! end
+
+!! test
+pre-save transform: unclosed tag
+!! options
+pst noxml
+!! input
+'''not wiki'''
+!! result
+'''not wiki'''
+!! end
+
+!! test
+pre-save transform: mixed tag case
+!! options
+pst noxml
+!! input
+'''not wiki'''
+!! result
+'''not wiki'''
+!! end
+
+!! test
+pre-save transform: unclosed comment in
+!! options
+pst noxml
+!! input
+wikinowiki
+!!result
+
+!!end
+
+!! test
+pre-save transform: comment containing extension
+!! options
+pst
+!! input
+
+!!result
+
+!!end
+
+!! test
+pre-save transform: comment containing nowiki
+!! options
+pst
+!! input
+
+!!result
+
+!!end
+
+!! test
+pre-save transform: comment containing math
+!! options
+pst
+!! input
+
+!!result
+
+!!end
+
+!! test
+pre-save transform: in subst (bug 3298)
+!! options
+pst
+!! input
+{{subst:Includes}}
+!! result
+Foobar
+!! end
+
+!! test
+pre-save transform: in subst (bug 3298)
+!! options
+pst
+!! input
+{{subst:Includes2}}
+!! result
+Foo
+!! end
+
+!! article
+Template:SubstTest
+!!text
+{{subst:Includes}}
+!! endarticle
+
+!! article
+Template:SafeSubstTest
+!! text
+{{safesubst:Includes}}
+!! endarticle
+
+!! test
+bug 22297: safesubst: works during PST
+!! options
+pst
+!! input
+{{subst:SafeSubstTest}}{{safesubst:SubstTest}}
+!! result
+FoobarFoobar
+!! end
+
+!! test
+bug 22297: safesubst: works during normal parse
+!! input
+{{SafeSubstTest}}
+!! result
+Foobar
+
+!! end
+
+!! test:
+subst: does not work during normal parse
+!! input
+{{SubstTest}}
+!! result
+{{subst:Includes}}
+
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick")
+!! options
+pst
+!! input
+[[Article (context)|]]
+[[Bar:Article|]]
+[[:Bar:Article|]]
+[[Bar:Article (context)|]]
+[[:Bar:Article (context)|]]
+[[|Article]]
+[[|Article (context)]]
+[[Bar:X (Y) Z|]]
+[[:Bar:X (Y) Z|]]
+!! result
+[[Article (context)|Article]]
+[[Bar:Article|Article]]
+[[:Bar:Article|Article]]
+[[Bar:Article (context)|Article]]
+[[:Bar:Article (context)|Article]]
+[[Article]]
+[[Article (context)]]
+[[Bar:X (Y) Z|X (Y) Z]]
+[[:Bar:X (Y) Z|X (Y) Z]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with interwiki prefix
+!! options
+pst
+!! input
+[[interwiki:Article|]]
+[[:interwiki:Article|]]
+[[interwiki:Bar:Article|]]
+[[:interwiki:Bar:Article|]]
+!! result
+[[interwiki:Article|Article]]
+[[:interwiki:Article|Article]]
+[[interwiki:Bar:Article|Bar:Article]]
+[[:interwiki:Bar:Article|Bar:Article]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with parens in title
+!! options
+pst title=[[Somearticle (context)]]
+!! input
+[[|Article]]
+!! result
+[[Article (context)|Article]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with comma in title
+!! options
+pst title=[[Someplace, Somewhere]]
+!! input
+[[|Otherplace]]
+[[Otherplace, Elsewhere|]]
+[[Otherplace, Elsewhere, Anywhere|]]
+!! result
+[[Otherplace, Somewhere|Otherplace]]
+[[Otherplace, Elsewhere|Otherplace]]
+[[Otherplace, Elsewhere, Anywhere|Otherplace]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with parens and comma
+!! options
+pst title=[[Someplace (IGNORED), Somewhere]]
+!! input
+[[|Otherplace]]
+[[Otherplace (place), Elsewhere|]]
+!! result
+[[Otherplace, Somewhere|Otherplace]]
+[[Otherplace (place), Elsewhere|Otherplace]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with comma and parens
+!! options
+pst title=[[Who, me? (context)]]
+!! input
+[[|Yes, you.]]
+[[Me, Myself, and I (1937 song)|]]
+!! result
+[[Yes, you. (context)|Yes, you.]]
+[[Me, Myself, and I (1937 song)|Me, Myself, and I]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with namespace
+!! options
+pst title=[[Ns:Somearticle]]
+!! input
+[[|Article]]
+!! result
+[[Ns:Article|Article]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with namespace and parens
+!! options
+pst title=[[Ns:Somearticle (context)]]
+!! input
+[[|Article]]
+!! result
+[[Ns:Article (context)|Article]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with namespace and comma
+!! options
+pst title=[[Ns:Somearticle, Context, Whatever]]
+!! input
+[[|Article]]
+!! result
+[[Ns:Article, Context, Whatever|Article]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with namespace, comma and parens
+!! options
+pst title=[[Ns:Somearticle, Context (context)]]
+!! input
+[[|Article]]
+!! result
+[[Ns:Article (context)|Article]]
+!! end
+
+!! test
+pre-save transform: context links ("pipe trick") with namespace, parens and comma
+!! options
+pst title=[[Ns:Somearticle (IGNORED), Context]]
+!! input
+[[|Article]]
+!! result
+[[Ns:Article, Context|Article]]
+!! end
+
+
+###
+### Message transform tests
+###
+!! test
+message transform: magic variables
+!! options
+msg
+!! input
+{{SITENAME}}
+!! result
+MediaWiki
+!! end
+
+!! test
+message transform: should not transform wiki markup
+!! options
+msg
+!! input
+''test''
+!! result
+''test''
+!! end
+
+!! test
+message transform: in transcluded template (bug 4926)
+!! options
+msg
+!! input
+{{Includes}}
+!! result
+Foobar
+!! end
+
+!! test
+message transform: in transcluded template (bug 4926)
+!! options
+msg
+!! input
+{{Includes2}}
+!! result
+Foo
+!! end
+
+!! test
+{{#special:}} page name, known
+!! options
+msg
+!! input
+{{#special:Recentchanges}}
+!! result
+Special:RecentChanges
+!! end
+
+!! test
+{{#special:}} page name with subpage, known
+!! options
+msg
+!! input
+{{#special:Recentchanges/param}}
+!! result
+Special:RecentChanges/param
+!! end
+
+!! test
+{{#special:}} page name, unknown
+!! options
+msg
+!! input
+{{#special:foobarnonexistent}}
+!! result
+No such special page
+!! end
+
+###
+### Images
+###
+!! test
+Simple image
+!! input
+[[Image:foobar.jpg]]
+!! result
+
+
+!! end
+
+!! test
+Right-aligned image
+!! input
+[[Image:foobar.jpg|right]]
+!! result
+
+
+!! end
+
+!! test
+Simple image (using File: namespace, now canonical)
+!! input
+[[File:foobar.jpg]]
+!! result
+
+
+!! end
+
+!! test
+Image with caption
+!! input
+[[Image:foobar.jpg|right|Caption text]]
+!! result
+
+
+!! end
+
+!! test
+Image with link parameter, wiki target
+!! input
+[[Image:foobar.jpg|link=Target page]]
+!! result
+
+
+!! end
+
+!! test
+Image with link parameter, URL target
+!! input
+[[Image:foobar.jpg|link=http://example.com/]]
+!! result
+
+
+!! end
+
+!! test
+Image with empty link parameter
+!! input
+[[Image:foobar.jpg|link=]]
+!! result
+
+
+!! end
+
+!! test
+Image with link parameter (wiki target) and unnamed parameter
+!! input
+[[Image:foobar.jpg|link=Target page|Title]]
+!! result
+
+
+!! end
+
+!! test
+Image with link parameter (URL target) and unnamed parameter
+!! input
+[[Image:foobar.jpg|link=http://example.com/|Title]]
+!! result
+
+
+!! end
+
+!! test
+Thumbnail image with link parameter
+!! input
+[[Image:foobar.jpg|thumb|link=http://example.com/|Title]]
+!! result
+
+
+!! end
+
+!! test
+Image with frame and link
+!! input
+[[Image:Foobar.jpg|frame|left|This is a test image [[Main Page]]]]
+!! result
+
+
+!! end
+
+!! test
+Image with frame and link and explicit alt
+!! input
+[[Image:Foobar.jpg|frame|left|This is a test image [[Main Page]]|alt=Altitude]]
+!! result
+
+
+!! end
+
+!! test
+Image with wiki markup in implicit alt
+!! input
+[[Image:Foobar.jpg|testing '''bold''' in alt]]
+!! result
+
+
+!! end
+
+!! test
+Image with wiki markup in explicit alt
+!! input
+[[Image:Foobar.jpg|alt=testing '''bold''' in alt]]
+!! result
+
+
+!! end
+
+!! test
+Link to image page- image page normally doesn't exists, hence edit link
+Add test with existing image page
+#Image:test
+!! input
+[[:Image:test]]
+!! result
+
Image:test
+
+!! end
+
+!! test
+bug 18784 Link to non-existent image page with caption should use caption as link text
+!! input
+[[:Image:test|caption]]
+!! result
+caption
+
+!! end
+
+!! test
+Frameless image caption with a free URL
+!! input
+[[Image:foobar.jpg|http://example.com]]
+!! result
+
+
+!! end
+
+!! test
+Thumbnail image caption with a free URL
+!! input
+[[Image:foobar.jpg|thumb|http://example.com]]
+!! result
+
+
+!! end
+
+!! test
+Thumbnail image caption with a free URL and explicit alt
+!! input
+[[Image:foobar.jpg|thumb|http://example.com|alt=Alteration]]
+!! result
+
+
+!! end
+
+!! test
+BUG 1887: A ISBN with a thumbnail
+!! input
+[[Image:foobar.jpg|thumb|ISBN 1235467890]]
+!! result
+
+
+!! end
+
+!! test
+BUG 1887: A RFC with a thumbnail
+!! input
+[[Image:foobar.jpg|thumb|This is RFC 12354]]
+!! result
+
+
+!! end
+
+!! test
+BUG 1887: A mailto link with a thumbnail
+!! input
+[[Image:foobar.jpg|thumb|Please mailto:nobody@example.com]]
+!! result
+
+
+!! end
+
+!! test
+BUG 1887: A