MediaWiki
REL1_24
|
00001 <?php 00030 class MediaWikiTitleCodecTest extends MediaWikiTestCase { 00031 00032 public function setUp() { 00033 parent::setUp(); 00034 00035 $this->setMwGlobals( array( 00036 'wgLanguageCode' => 'en', 00037 'wgContLang' => Language::factory( 'en' ), 00038 // User language 00039 'wgLang' => Language::factory( 'en' ), 00040 'wgAllowUserJs' => false, 00041 'wgDefaultLanguageVariant' => false, 00042 'wgLocalInterwikis' => array( 'localtestiw' ), 00043 'wgCapitalLinks' => true, 00044 00045 // NOTE: this is why global state is evil. 00046 // TODO: refactor access to the interwiki codes so it can be injected. 00047 'wgHooks' => array( 00048 'InterwikiLoadPrefix' => array( 00049 function ( $prefix, &$data ) { 00050 if ( $prefix === 'localtestiw' ) { 00051 $data = array( 'iw_url' => 'localtestiw' ); 00052 } elseif ( $prefix === 'remotetestiw' ) { 00053 $data = array( 'iw_url' => 'remotetestiw' ); 00054 } 00055 return false; 00056 } 00057 ) 00058 ) 00059 ) ); 00060 } 00061 00068 private function getGenderCache() { 00069 $genderCache = $this->getMockBuilder( 'GenderCache' ) 00070 ->disableOriginalConstructor() 00071 ->getMock(); 00072 00073 $genderCache->expects( $this->any() ) 00074 ->method( 'getGenderOf' ) 00075 ->will( $this->returnCallback( function ( $userName ) { 00076 return preg_match( '/^[^- _]+a( |_|$)/u', $userName ) ? 'female' : 'male'; 00077 } ) ); 00078 00079 return $genderCache; 00080 } 00081 00082 protected function makeCodec( $lang ) { 00083 $gender = $this->getGenderCache(); 00084 $lang = Language::factory( $lang ); 00085 return new MediaWikiTitleCodec( $lang, $gender ); 00086 } 00087 00088 public static function provideFormat() { 00089 return array( 00090 array( NS_MAIN, 'Foo_Bar', '', 'en', 'Foo Bar' ), 00091 array( NS_USER, 'Hansi_Maier', 'stuff_and_so_on', 'en', 'User:Hansi Maier#stuff and so on' ), 00092 array( false, 'Hansi_Maier', '', 'en', 'Hansi Maier' ), 00093 array( 00094 NS_USER_TALK, 00095 'hansi__maier', 00096 '', 00097 'en', 00098 'User talk:hansi maier', 00099 'User talk:Hansi maier' 00100 ), 00101 00102 // getGenderCache() provides a mock that considers first 00103 // names ending in "a" to be female. 00104 array( NS_USER, 'Lisa_Müller', '', 'de', 'Benutzerin:Lisa Müller' ), 00105 ); 00106 } 00107 00111 public function testFormat( $namespace, $text, $fragment, $lang, $expected, $normalized = null ) { 00112 if ( $normalized === null ) { 00113 $normalized = $expected; 00114 } 00115 00116 $codec = $this->makeCodec( $lang ); 00117 $actual = $codec->formatTitle( $namespace, $text, $fragment ); 00118 00119 $this->assertEquals( $expected, $actual, 'formatted' ); 00120 00121 // test round trip 00122 $parsed = $codec->parseTitle( $actual, NS_MAIN ); 00123 $actual2 = $codec->formatTitle( 00124 $parsed->getNamespace(), 00125 $parsed->getText(), 00126 $parsed->getFragment() 00127 ); 00128 00129 $this->assertEquals( $normalized, $actual2, 'normalized after round trip' ); 00130 } 00131 00132 public static function provideGetText() { 00133 return array( 00134 array( NS_MAIN, 'Foo_Bar', '', 'en', 'Foo Bar' ), 00135 array( NS_USER, 'Hansi_Maier', 'stuff_and_so_on', 'en', 'Hansi Maier' ), 00136 ); 00137 } 00138 00142 public function testGetText( $namespace, $dbkey, $fragment, $lang, $expected ) { 00143 $codec = $this->makeCodec( $lang ); 00144 $title = new TitleValue( $namespace, $dbkey, $fragment ); 00145 00146 $actual = $codec->getText( $title ); 00147 00148 $this->assertEquals( $expected, $actual ); 00149 } 00150 00151 public static function provideGetPrefixedText() { 00152 return array( 00153 array( NS_MAIN, 'Foo_Bar', '', 'en', 'Foo Bar' ), 00154 array( NS_USER, 'Hansi_Maier', 'stuff_and_so_on', 'en', 'User:Hansi Maier' ), 00155 00156 // No capitalization or normalization is applied while formatting! 00157 array( NS_USER_TALK, 'hansi__maier', '', 'en', 'User talk:hansi maier' ), 00158 00159 // getGenderCache() provides a mock that considers first 00160 // names ending in "a" to be female. 00161 array( NS_USER, 'Lisa_Müller', '', 'de', 'Benutzerin:Lisa Müller' ), 00162 ); 00163 } 00164 00168 public function testGetPrefixedText( $namespace, $dbkey, $fragment, $lang, $expected ) { 00169 $codec = $this->makeCodec( $lang ); 00170 $title = new TitleValue( $namespace, $dbkey, $fragment ); 00171 00172 $actual = $codec->getPrefixedText( $title ); 00173 00174 $this->assertEquals( $expected, $actual ); 00175 } 00176 00177 public static function provideGetFullText() { 00178 return array( 00179 array( NS_MAIN, 'Foo_Bar', '', 'en', 'Foo Bar' ), 00180 array( NS_USER, 'Hansi_Maier', 'stuff_and_so_on', 'en', 'User:Hansi Maier#stuff and so on' ), 00181 00182 // No capitalization or normalization is applied while formatting! 00183 array( NS_USER_TALK, 'hansi__maier', '', 'en', 'User talk:hansi maier' ), 00184 ); 00185 } 00186 00190 public function testGetFullText( $namespace, $dbkey, $fragment, $lang, $expected ) { 00191 $codec = $this->makeCodec( $lang ); 00192 $title = new TitleValue( $namespace, $dbkey, $fragment ); 00193 00194 $actual = $codec->getFullText( $title ); 00195 00196 $this->assertEquals( $expected, $actual ); 00197 } 00198 00199 public static function provideParseTitle() { 00200 //TODO: test capitalization and trimming 00201 //TODO: test unicode normalization 00202 00203 return array( 00204 array( ' : Hansi_Maier _ ', NS_MAIN, 'en', 00205 new TitleValue( NS_MAIN, 'Hansi_Maier', '' ) ), 00206 array( 'User:::1', NS_MAIN, 'de', 00207 new TitleValue( NS_USER, '0:0:0:0:0:0:0:1', '' ) ), 00208 array( ' lisa Müller', NS_USER, 'de', 00209 new TitleValue( NS_USER, 'Lisa_Müller', '' ) ), 00210 array( 'benutzerin:lisa Müller#stuff', NS_MAIN, 'de', 00211 new TitleValue( NS_USER, 'Lisa_Müller', 'stuff' ) ), 00212 00213 array( ':Category:Quux', NS_MAIN, 'en', 00214 new TitleValue( NS_CATEGORY, 'Quux', '' ) ), 00215 array( 'Category:Quux', NS_MAIN, 'en', 00216 new TitleValue( NS_CATEGORY, 'Quux', '' ) ), 00217 array( 'Category:Quux', NS_CATEGORY, 'en', 00218 new TitleValue( NS_CATEGORY, 'Quux', '' ) ), 00219 array( 'Quux', NS_CATEGORY, 'en', 00220 new TitleValue( NS_CATEGORY, 'Quux', '' ) ), 00221 array( ':Quux', NS_CATEGORY, 'en', 00222 new TitleValue( NS_MAIN, 'Quux', '' ) ), 00223 00224 // getGenderCache() provides a mock that considers first 00225 // names ending in "a" to be female. 00226 00227 array( 'a b c', NS_MAIN, 'en', 00228 new TitleValue( NS_MAIN, 'A_b_c' ) ), 00229 array( ' a b c ', NS_MAIN, 'en', 00230 new TitleValue( NS_MAIN, 'A_b_c' ) ), 00231 array( ' _ Foo __ Bar_ _', NS_MAIN, 'en', 00232 new TitleValue( NS_MAIN, 'Foo_Bar' ) ), 00233 00234 //NOTE: cases copied from TitleTest::testSecureAndSplit. Keep in sync. 00235 array( 'Sandbox', NS_MAIN, 'en', ), 00236 array( 'A "B"', NS_MAIN, 'en', ), 00237 array( 'A \'B\'', NS_MAIN, 'en', ), 00238 array( '.com', NS_MAIN, 'en', ), 00239 array( '~', NS_MAIN, 'en', ), 00240 array( '"', NS_MAIN, 'en', ), 00241 array( '\'', NS_MAIN, 'en', ), 00242 00243 array( 'Talk:Sandbox', NS_MAIN, 'en', 00244 new TitleValue( NS_TALK, 'Sandbox' ) ), 00245 array( 'Talk:Foo:Sandbox', NS_MAIN, 'en', 00246 new TitleValue( NS_TALK, 'Foo:Sandbox' ) ), 00247 array( 'File:Example.svg', NS_MAIN, 'en', 00248 new TitleValue( NS_FILE, 'Example.svg' ) ), 00249 array( 'File_talk:Example.svg', NS_MAIN, 'en', 00250 new TitleValue( NS_FILE_TALK, 'Example.svg' ) ), 00251 array( 'Foo/.../Sandbox', NS_MAIN, 'en', 00252 'Foo/.../Sandbox' ), 00253 array( 'Sandbox/...', NS_MAIN, 'en', 00254 'Sandbox/...' ), 00255 array( 'A~~', NS_MAIN, 'en', 00256 'A~~' ), 00257 // Length is 256 total, but only title part matters 00258 array( 'Category:' . str_repeat( 'x', 248 ), NS_MAIN, 'en', 00259 new TitleValue( NS_CATEGORY, 00260 'X' . str_repeat( 'x', 247 ) ) ), 00261 array( str_repeat( 'x', 252 ), NS_MAIN, 'en', 00262 'X' . str_repeat( 'x', 251 ) ) 00263 ); 00264 } 00265 00269 public function testParseTitle( $text, $ns, $lang, $title = null ) { 00270 if ( $title === null ) { 00271 $title = str_replace( ' ', '_', trim( $text ) ); 00272 } 00273 00274 if ( is_string( $title ) ) { 00275 $title = new TitleValue( NS_MAIN, $title, '' ); 00276 } 00277 00278 $codec = $this->makeCodec( $lang ); 00279 $actual = $codec->parseTitle( $text, $ns ); 00280 00281 $this->assertEquals( $title, $actual ); 00282 } 00283 00284 public static function provideParseTitle_invalid() { 00285 //TODO: test unicode errors 00286 00287 return array( 00288 array( '#' ), 00289 array( '::' ), 00290 array( '::xx' ), 00291 array( '::##' ), 00292 array( ' :: x' ), 00293 00294 array( 'Talk:File:Foo.jpg' ), 00295 array( 'Talk:localtestiw:Foo' ), 00296 array( 'remotetestiw:Foo' ), 00297 array( '::1' ), // only valid in user namespace 00298 array( 'User::x' ), // leading ":" in a user name is only valid of IPv6 addresses 00299 00300 //NOTE: cases copied from TitleTest::testSecureAndSplit. Keep in sync. 00301 array( '' ), 00302 array( ':' ), 00303 array( '__ __' ), 00304 array( ' __ ' ), 00305 // Bad characters forbidden regardless of wgLegalTitleChars 00306 array( 'A [ B' ), 00307 array( 'A ] B' ), 00308 array( 'A { B' ), 00309 array( 'A } B' ), 00310 array( 'A < B' ), 00311 array( 'A > B' ), 00312 array( 'A | B' ), 00313 // URL encoding 00314 array( 'A%20B' ), 00315 array( 'A%23B' ), 00316 array( 'A%2523B' ), 00317 // XML/HTML character entity references 00318 // Note: Commented out because they are not marked invalid by the PHP test as 00319 // Title::newFromText runs Sanitizer::decodeCharReferencesAndNormalize first. 00320 //array( 'A é B' ), 00321 //array( 'A é B' ), 00322 //array( 'A é B' ), 00323 // Subject of NS_TALK does not roundtrip to NS_MAIN 00324 array( 'Talk:File:Example.svg' ), 00325 // Directory navigation 00326 array( '.' ), 00327 array( '..' ), 00328 array( './Sandbox' ), 00329 array( '../Sandbox' ), 00330 array( 'Foo/./Sandbox' ), 00331 array( 'Foo/../Sandbox' ), 00332 array( 'Sandbox/.' ), 00333 array( 'Sandbox/..' ), 00334 // Tilde 00335 array( 'A ~~~ Name' ), 00336 array( 'A ~~~~ Signature' ), 00337 array( 'A ~~~~~ Timestamp' ), 00338 array( str_repeat( 'x', 256 ) ), 00339 // Namespace prefix without actual title 00340 array( 'Talk:' ), 00341 array( 'Category: ' ), 00342 array( 'Category: #bar' ) 00343 ); 00344 } 00345 00349 public function testParseTitle_invalid( $text ) { 00350 $this->setExpectedException( 'MalformedTitleException' ); 00351 00352 $codec = $this->makeCodec( 'en' ); 00353 $codec->parseTitle( $text, NS_MAIN ); 00354 } 00355 00356 public static function provideGetNamespaceName() { 00357 return array( 00358 array( NS_MAIN, 'Foo', 'en', '' ), 00359 array( NS_USER, 'Foo', 'en', 'User' ), 00360 array( NS_USER, 'Hansi Maier', 'de', 'Benutzer' ), 00361 00362 // getGenderCache() provides a mock that considers first 00363 // names ending in "a" to be female. 00364 array( NS_USER, 'Lisa Müller', 'de', 'Benutzerin' ), 00365 ); 00366 } 00367 00378 public function testGetNamespaceName( $namespace, $text, $lang, $expected ) { 00379 $codec = $this->makeCodec( $lang ); 00380 $name = $codec->getNamespaceName( $namespace, $text ); 00381 00382 $this->assertEquals( $expected, $name ); 00383 } 00384 }