From 222b01f5169f1c7e69762e0e8904c24f78f71882 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Wed, 28 Jul 2010 11:52:48 +0200 Subject: update to MediaWiki 1.16.0 --- maintenance/tests/.svnignore | 6 + 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/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/phpunit.xml | 17 + maintenance/tests/test-prefetch-current.xml | 75 ++++ maintenance/tests/test-prefetch-previous.xml | 57 +++ maintenance/tests/test-prefetch-stub.xml | 75 ++++ 31 files changed, 3112 insertions(+) create mode 100644 maintenance/tests/.svnignore create mode 100644 maintenance/tests/ApiSetup.php create mode 100644 maintenance/tests/ApiTest.php create mode 100644 maintenance/tests/CdbTest.php create mode 100644 maintenance/tests/DatabaseSqliteTest.php create mode 100644 maintenance/tests/DatabaseTest.php create mode 100644 maintenance/tests/GlobalTest.php create mode 100644 maintenance/tests/HttpTest.php create mode 100644 maintenance/tests/IPTest.php create mode 100644 maintenance/tests/ImageFunctionsTest.php create mode 100644 maintenance/tests/LanguageConverterTest.php create mode 100644 maintenance/tests/LicensesTest.php create mode 100644 maintenance/tests/LocalFileTest.php create mode 100644 maintenance/tests/Makefile create mode 100644 maintenance/tests/MediaWikiParserTest.php create mode 100644 maintenance/tests/MediaWiki_Setup.php create mode 100644 maintenance/tests/README create mode 100644 maintenance/tests/RevisionTest.php create mode 100644 maintenance/tests/SanitizerTest.php create mode 100644 maintenance/tests/SearchEngineTest.php create mode 100644 maintenance/tests/SearchMySQLTest.php create mode 100644 maintenance/tests/SearchUpdateTest.php create mode 100644 maintenance/tests/SiteConfigurationTest.php create mode 100644 maintenance/tests/TimeAdjustTest.php create mode 100644 maintenance/tests/TitleTest.php create mode 100644 maintenance/tests/XmlTest.php create mode 100644 maintenance/tests/bootstrap.php create mode 100644 maintenance/tests/phpunit.xml create mode 100644 maintenance/tests/test-prefetch-current.xml create mode 100644 maintenance/tests/test-prefetch-previous.xml create mode 100644 maintenance/tests/test-prefetch-stub.xml (limited to 'maintenance/tests') diff --git a/maintenance/tests/.svnignore b/maintenance/tests/.svnignore new file mode 100644 index 00000000..20cb61e9 --- /dev/null +++ b/maintenance/tests/.svnignore @@ -0,0 +1,6 @@ +LocalTestSettings.php +*~ +bin +.classpath +.project +project.index diff --git a/maintenance/tests/ApiSetup.php b/maintenance/tests/ApiSetup.php new file mode 100644 index 00000000..549d8aef --- /dev/null +++ b/maintenance/tests/ApiSetup.php @@ -0,0 +1,39 @@ +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 new file mode 100644 index 00000000..d098b1a2 --- /dev/null +++ b/maintenance/tests/ApiTest.php @@ -0,0 +1,164 @@ + 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 new file mode 100644 index 00000000..444229e7 --- /dev/null +++ b/maintenance/tests/CdbTest.php @@ -0,0 +1,79 @@ +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 new file mode 100644 index 00000000..011ef798 --- /dev/null +++ b/maintenance/tests/DatabaseSqliteTest.php @@ -0,0 +1,57 @@ +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 new file mode 100644 index 00000000..aa50de2e --- /dev/null +++ b/maintenance/tests/DatabaseTest.php @@ -0,0 +1,92 @@ +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 new file mode 100644 index 00000000..ec694241 --- /dev/null +++ b/maintenance/tests/GlobalTest.php @@ -0,0 +1,212 @@ +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 new file mode 100644 index 00000000..83734910 --- /dev/null +++ b/maintenance/tests/HttpTest.php @@ -0,0 +1,567 @@ + "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 new file mode 100644 index 00000000..9db77f72 --- /dev/null +++ b/maintenance/tests/IPTest.php @@ -0,0 +1,52 @@ +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 new file mode 100644 index 00000000..9794a2a2 --- /dev/null +++ b/maintenance/tests/ImageFunctionsTest.php @@ -0,0 +1,48 @@ + 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 new file mode 100644 index 00000000..22b396e7 --- /dev/null +++ b/maintenance/tests/LanguageConverterTest.php @@ -0,0 +1,148 @@ +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 new file mode 100644 index 00000000..c5357f89 --- /dev/null +++ b/maintenance/tests/LicensesTest.php @@ -0,0 +1,17 @@ +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 new file mode 100644 index 00000000..e57798be --- /dev/null +++ b/maintenance/tests/LocalFileTest.php @@ -0,0 +1,97 @@ + '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 new file mode 100644 index 00000000..b2c0fb71 --- /dev/null +++ b/maintenance/tests/Makefile @@ -0,0 +1,23 @@ +# 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 new file mode 100644 index 00000000..a545b3bb --- /dev/null +++ b/maintenance/tests/MediaWikiParserTest.php @@ -0,0 +1,283 @@ +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 new file mode 100644 index 00000000..e7acc338 --- /dev/null +++ b/maintenance/tests/MediaWiki_Setup.php @@ -0,0 +1,28 @@ +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 new file mode 100644 index 00000000..b52e790e --- /dev/null +++ b/maintenance/tests/README @@ -0,0 +1,24 @@ +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 new file mode 100644 index 00000000..78fcc7c3 --- /dev/null +++ b/maintenance/tests/RevisionTest.php @@ -0,0 +1,114 @@ + 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/SanitizerTest.php b/maintenance/tests/SanitizerTest.php new file mode 100644 index 00000000..8a2287d5 --- /dev/null +++ b/maintenance/tests/SanitizerTest.php @@ -0,0 +1,73 @@ +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 &#x108;io dans l'&eacute;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 new file mode 100644 index 00000000..0cae2d42 --- /dev/null +++ b/maintenance/tests/SearchEngineTest.php @@ -0,0 +1,138 @@ +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 new file mode 100644 index 00000000..526f6216 --- /dev/null +++ b/maintenance/tests/SearchMySQLTest.php @@ -0,0 +1,26 @@ +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 new file mode 100644 index 00000000..d21319a4 --- /dev/null +++ b/maintenance/tests/SearchUpdateTest.php @@ -0,0 +1,103 @@ +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 + bozquux + +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 new file mode 100644 index 00000000..791b6fe5 --- /dev/null +++ b/maintenance/tests/SiteConfigurationTest.php @@ -0,0 +1,311 @@ +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 new file mode 100644 index 00000000..bbd697bf --- /dev/null +++ b/maintenance/tests/TimeAdjustTest.php @@ -0,0 +1,40 @@ +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 new file mode 100644 index 00000000..5b42c1c5 --- /dev/null +++ b/maintenance/tests/TitleTest.php @@ -0,0 +1,17 @@ +|", $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 new file mode 100644 index 00000000..330e60c6 --- /dev/null +++ b/maintenance/tests/XmlTest.php @@ -0,0 +1,115 @@ +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 new file mode 100644 index 00000000..019bee07 --- /dev/null +++ b/maintenance/tests/bootstrap.php @@ -0,0 +1,15 @@ + + + + + + + . + + + + Broken + Stub + + + \ No newline at end of file diff --git a/maintenance/tests/test-prefetch-current.xml b/maintenance/tests/test-prefetch-current.xml new file mode 100644 index 00000000..a4c8bda3 --- /dev/null +++ b/maintenance/tests/test-prefetch-current.xml @@ -0,0 +1,75 @@ + + + DemoWiki + http://example.com/wiki/Main_Page + MediaWiki 1.5.0 + first-letter + + Media + Special + + Talk + User + User talk + DemoWiki + DemoWIki talk + Image + Image talk + MediaWiki + MediaWiki talk + Template + Template talk + Help + Help talk + Category + Category talk + + + + First page + 1 + + 1 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 1 + page 1, rev 1 + + + 2 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 2 + page 1, rev 2 + + + 4 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 4 + page 1, rev 4 + + + + Second page + 2 + + 3 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 2, rev 3 + page 2, rev 3 + + + + Third page + 3 + + 5 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 3, rev 5 + page 3, rev 5 + + + diff --git a/maintenance/tests/test-prefetch-previous.xml b/maintenance/tests/test-prefetch-previous.xml new file mode 100644 index 00000000..95eb82dd --- /dev/null +++ b/maintenance/tests/test-prefetch-previous.xml @@ -0,0 +1,57 @@ + + + DemoWiki + http://example.com/wiki/Main_Page + MediaWiki 1.5.0 + first-letter + + Media + Special + + Talk + User + User talk + DemoWiki + DemoWIki talk + Image + Image talk + MediaWiki + MediaWiki talk + Template + Template talk + Help + Help talk + Category + Category talk + + + + First page + 1 + + 1 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 1 + page 1, rev 1 + + + 2 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 2 + page 1, rev 2 + + + + Second page + 2 + + 3 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 2, rev 3 + page 2, rev 3 + + + diff --git a/maintenance/tests/test-prefetch-stub.xml b/maintenance/tests/test-prefetch-stub.xml new file mode 100644 index 00000000..59d43d2f --- /dev/null +++ b/maintenance/tests/test-prefetch-stub.xml @@ -0,0 +1,75 @@ + + + DemoWiki + http://example.com/wiki/Main_Page + MediaWiki 1.5.0 + first-letter + + Media + Special + + Talk + User + User talk + DemoWiki + DemoWIki talk + Image + Image talk + MediaWiki + MediaWiki talk + Template + Template talk + Help + Help talk + Category + Category talk + + + + First page + 1 + + 1 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 1 + + + + 2 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 2 + + + + 4 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 1, rev 4 + + + + + Second page + 2 + + 3 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 2, rev 3 + + + + + Third page + 3 + + 5 + 2001-01-15T12:00:00Z + 10.0.0.1 + page 3, rev 5 + + + + -- cgit v1.2.3-54-g00ecf