Prepare for REL1_33 cut, labelling master as 1.34-alpha
[lhc/web/wiklou.git] / tests / phpunit / includes / MWNamespaceTest.php
1 <?php
2 /**
3 * @author Antoine Musso
4 * @copyright Copyright © 2011, Antoine Musso
5 * @file
6 */
7
8 class MWNamespaceTest extends MediaWikiTestCase {
9
10 protected function setUp() {
11 parent::setUp();
12
13 $this->setMwGlobals( [
14 'wgContentNamespaces' => [ NS_MAIN ],
15 'wgNamespacesWithSubpages' => [
16 NS_TALK => true,
17 NS_USER => true,
18 NS_USER_TALK => true,
19 ],
20 'wgCapitalLinks' => true,
21 'wgCapitalLinkOverrides' => [],
22 'wgNonincludableNamespaces' => [],
23 ] );
24 }
25
26 /**
27 * @todo Write more texts, handle $wgAllowImageMoving setting
28 * @covers MWNamespace::isMovable
29 */
30 public function testIsMovable() {
31 $this->assertFalse( MWNamespace::isMovable( NS_SPECIAL ) );
32 }
33
34 private function assertIsSubject( $ns ) {
35 $this->assertTrue( MWNamespace::isSubject( $ns ) );
36 }
37
38 private function assertIsNotSubject( $ns ) {
39 $this->assertFalse( MWNamespace::isSubject( $ns ) );
40 }
41
42 /**
43 * Please make sure to change testIsTalk() if you change the assertions below
44 * @covers MWNamespace::isSubject
45 */
46 public function testIsSubject() {
47 // Special namespaces
48 $this->assertIsSubject( NS_MEDIA );
49 $this->assertIsSubject( NS_SPECIAL );
50
51 // Subject pages
52 $this->assertIsSubject( NS_MAIN );
53 $this->assertIsSubject( NS_USER );
54 $this->assertIsSubject( 100 ); # user defined
55
56 // Talk pages
57 $this->assertIsNotSubject( NS_TALK );
58 $this->assertIsNotSubject( NS_USER_TALK );
59 $this->assertIsNotSubject( 101 ); # user defined
60 }
61
62 private function assertIsTalk( $ns ) {
63 $this->assertTrue( MWNamespace::isTalk( $ns ) );
64 }
65
66 private function assertIsNotTalk( $ns ) {
67 $this->assertFalse( MWNamespace::isTalk( $ns ) );
68 }
69
70 /**
71 * Reverse of testIsSubject().
72 * Please update testIsSubject() if you change assertions below
73 * @covers MWNamespace::isTalk
74 */
75 public function testIsTalk() {
76 // Special namespaces
77 $this->assertIsNotTalk( NS_MEDIA );
78 $this->assertIsNotTalk( NS_SPECIAL );
79
80 // Subject pages
81 $this->assertIsNotTalk( NS_MAIN );
82 $this->assertIsNotTalk( NS_USER );
83 $this->assertIsNotTalk( 100 ); # user defined
84
85 // Talk pages
86 $this->assertIsTalk( NS_TALK );
87 $this->assertIsTalk( NS_USER_TALK );
88 $this->assertIsTalk( 101 ); # user defined
89 }
90
91 /**
92 * @covers MWNamespace::getSubject
93 */
94 public function testGetSubject() {
95 // Special namespaces are their own subjects
96 $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) );
97 $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) );
98
99 $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) );
100 $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) );
101 }
102
103 /**
104 * Regular getTalk() calls
105 * Namespaces without a talk page (NS_MEDIA, NS_SPECIAL) are tested in
106 * the function testGetTalkExceptions()
107 * @covers MWNamespace::getTalk
108 */
109 public function testGetTalk() {
110 $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_MAIN ) );
111 $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_TALK ) );
112 $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER ) );
113 $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER_TALK ) );
114 }
115
116 /**
117 * Exceptions with getTalk()
118 * NS_MEDIA does not have talk pages. MediaWiki raise an exception for them.
119 * @expectedException MWException
120 * @covers MWNamespace::getTalk
121 */
122 public function testGetTalkExceptionsForNsMedia() {
123 $this->assertNull( MWNamespace::getTalk( NS_MEDIA ) );
124 }
125
126 /**
127 * Exceptions with getTalk()
128 * NS_SPECIAL does not have talk pages. MediaWiki raise an exception for them.
129 * @expectedException MWException
130 * @covers MWNamespace::getTalk
131 */
132 public function testGetTalkExceptionsForNsSpecial() {
133 $this->assertNull( MWNamespace::getTalk( NS_SPECIAL ) );
134 }
135
136 /**
137 * Regular getAssociated() calls
138 * Namespaces without an associated page (NS_MEDIA, NS_SPECIAL) are tested in
139 * the function testGetAssociatedExceptions()
140 * @covers MWNamespace::getAssociated
141 */
142 public function testGetAssociated() {
143 $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) );
144 $this->assertEquals( NS_MAIN, MWNamespace::getAssociated( NS_TALK ) );
145 }
146
147 # ## Exceptions with getAssociated()
148 # ## NS_MEDIA and NS_SPECIAL do not have talk pages. MediaWiki raises
149 # ## an exception for them.
150 /**
151 * @expectedException MWException
152 * @covers MWNamespace::getAssociated
153 */
154 public function testGetAssociatedExceptionsForNsMedia() {
155 $this->assertNull( MWNamespace::getAssociated( NS_MEDIA ) );
156 }
157
158 /**
159 * @expectedException MWException
160 * @covers MWNamespace::getAssociated
161 */
162 public function testGetAssociatedExceptionsForNsSpecial() {
163 $this->assertNull( MWNamespace::getAssociated( NS_SPECIAL ) );
164 }
165
166 /**
167 * Test MWNamespace::equals
168 * Note if we add a namespace registration system with keys like 'MAIN'
169 * we should add tests here for equivilance on things like 'MAIN' == 0
170 * and 'MAIN' == NS_MAIN.
171 * @covers MWNamespace::equals
172 */
173 public function testEquals() {
174 $this->assertTrue( MWNamespace::equals( NS_MAIN, NS_MAIN ) );
175 $this->assertTrue( MWNamespace::equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN'
176 $this->assertTrue( MWNamespace::equals( NS_USER, NS_USER ) );
177 $this->assertTrue( MWNamespace::equals( NS_USER, 2 ) );
178 $this->assertTrue( MWNamespace::equals( NS_USER_TALK, NS_USER_TALK ) );
179 $this->assertTrue( MWNamespace::equals( NS_SPECIAL, NS_SPECIAL ) );
180 $this->assertFalse( MWNamespace::equals( NS_MAIN, NS_TALK ) );
181 $this->assertFalse( MWNamespace::equals( NS_USER, NS_USER_TALK ) );
182 $this->assertFalse( MWNamespace::equals( NS_PROJECT, NS_TEMPLATE ) );
183 }
184
185 /**
186 * @covers MWNamespace::subjectEquals
187 */
188 public function testSubjectEquals() {
189 $this->assertSameSubject( NS_MAIN, NS_MAIN );
190 $this->assertSameSubject( NS_MAIN, 0 ); // In case we make NS_MAIN 'MAIN'
191 $this->assertSameSubject( NS_USER, NS_USER );
192 $this->assertSameSubject( NS_USER, 2 );
193 $this->assertSameSubject( NS_USER_TALK, NS_USER_TALK );
194 $this->assertSameSubject( NS_SPECIAL, NS_SPECIAL );
195 $this->assertSameSubject( NS_MAIN, NS_TALK );
196 $this->assertSameSubject( NS_USER, NS_USER_TALK );
197
198 $this->assertDifferentSubject( NS_PROJECT, NS_TEMPLATE );
199 $this->assertDifferentSubject( NS_SPECIAL, NS_MAIN );
200 }
201
202 /**
203 * @covers MWNamespace::subjectEquals
204 */
205 public function testSpecialAndMediaAreDifferentSubjects() {
206 $this->assertDifferentSubject(
207 NS_MEDIA, NS_SPECIAL,
208 "NS_MEDIA and NS_SPECIAL are different subject namespaces"
209 );
210 $this->assertDifferentSubject(
211 NS_SPECIAL, NS_MEDIA,
212 "NS_SPECIAL and NS_MEDIA are different subject namespaces"
213 );
214 }
215
216 public function provideHasTalkNamespace() {
217 return [
218 [ NS_MEDIA, false ],
219 [ NS_SPECIAL, false ],
220
221 [ NS_MAIN, true ],
222 [ NS_TALK, true ],
223 [ NS_USER, true ],
224 [ NS_USER_TALK, true ],
225
226 [ 100, true ],
227 [ 101, true ],
228 ];
229 }
230
231 /**
232 * @dataProvider provideHasTalkNamespace
233 * @covers MWNamespace::hasTalkNamespace
234 *
235 * @param int $index
236 * @param bool $expected
237 */
238 public function testHasTalkNamespace( $index, $expected ) {
239 $actual = MWNamespace::hasTalkNamespace( $index );
240 $this->assertSame( $actual, $expected, "NS $index" );
241 }
242
243 /**
244 * @dataProvider provideHasTalkNamespace
245 * @covers MWNamespace::canTalk
246 *
247 * @param int $index
248 * @param bool $expected
249 */
250 public function testCanTalk( $index, $expected ) {
251 $this->hideDeprecated( 'MWNamespace::canTalk' );
252 $actual = MWNamespace::canTalk( $index );
253 $this->assertSame( $actual, $expected, "NS $index" );
254 }
255
256 private function assertIsContent( $ns ) {
257 $this->assertTrue( MWNamespace::isContent( $ns ) );
258 }
259
260 private function assertIsNotContent( $ns ) {
261 $this->assertFalse( MWNamespace::isContent( $ns ) );
262 }
263
264 /**
265 * @covers MWNamespace::isContent
266 */
267 public function testIsContent() {
268 // NS_MAIN is a content namespace per DefaultSettings.php
269 // and per function definition.
270
271 $this->assertIsContent( NS_MAIN );
272
273 // Other namespaces which are not expected to be content
274
275 $this->assertIsNotContent( NS_MEDIA );
276 $this->assertIsNotContent( NS_SPECIAL );
277 $this->assertIsNotContent( NS_TALK );
278 $this->assertIsNotContent( NS_USER );
279 $this->assertIsNotContent( NS_CATEGORY );
280 $this->assertIsNotContent( 100 );
281 }
282
283 /**
284 * Similar to testIsContent() but alters the $wgContentNamespaces
285 * global variable.
286 * @covers MWNamespace::isContent
287 */
288 public function testIsContentAdvanced() {
289 global $wgContentNamespaces;
290
291 // Test that user defined namespace #252 is not content
292 $this->assertIsNotContent( 252 );
293
294 // Bless namespace # 252 as a content namespace
295 $wgContentNamespaces[] = 252;
296
297 $this->assertIsContent( 252 );
298
299 // Makes sure NS_MAIN was not impacted
300 $this->assertIsContent( NS_MAIN );
301 }
302
303 private function assertIsWatchable( $ns ) {
304 $this->assertTrue( MWNamespace::isWatchable( $ns ) );
305 }
306
307 private function assertIsNotWatchable( $ns ) {
308 $this->assertFalse( MWNamespace::isWatchable( $ns ) );
309 }
310
311 /**
312 * @covers MWNamespace::isWatchable
313 */
314 public function testIsWatchable() {
315 // Specials namespaces are not watchable
316 $this->assertIsNotWatchable( NS_MEDIA );
317 $this->assertIsNotWatchable( NS_SPECIAL );
318
319 // Core defined namespaces are watchables
320 $this->assertIsWatchable( NS_MAIN );
321 $this->assertIsWatchable( NS_TALK );
322
323 // Additional, user defined namespaces are watchables
324 $this->assertIsWatchable( 100 );
325 $this->assertIsWatchable( 101 );
326 }
327
328 private function assertHasSubpages( $ns ) {
329 $this->assertTrue( MWNamespace::hasSubpages( $ns ) );
330 }
331
332 private function assertHasNotSubpages( $ns ) {
333 $this->assertFalse( MWNamespace::hasSubpages( $ns ) );
334 }
335
336 /**
337 * @covers MWNamespace::hasSubpages
338 */
339 public function testHasSubpages() {
340 global $wgNamespacesWithSubpages;
341
342 // Special namespaces:
343 $this->assertHasNotSubpages( NS_MEDIA );
344 $this->assertHasNotSubpages( NS_SPECIAL );
345
346 // Namespaces without subpages
347 $this->assertHasNotSubpages( NS_MAIN );
348
349 $wgNamespacesWithSubpages[NS_MAIN] = true;
350 $this->assertHasSubpages( NS_MAIN );
351
352 $wgNamespacesWithSubpages[NS_MAIN] = false;
353 $this->assertHasNotSubpages( NS_MAIN );
354
355 // Some namespaces with subpages
356 $this->assertHasSubpages( NS_TALK );
357 $this->assertHasSubpages( NS_USER );
358 $this->assertHasSubpages( NS_USER_TALK );
359 }
360
361 /**
362 * @covers MWNamespace::getContentNamespaces
363 */
364 public function testGetContentNamespaces() {
365 global $wgContentNamespaces;
366
367 $this->assertEquals(
368 [ NS_MAIN ],
369 MWNamespace::getContentNamespaces(),
370 '$wgContentNamespaces is an array with only NS_MAIN by default'
371 );
372
373 # test !is_array( $wgcontentNamespaces )
374 $wgContentNamespaces = '';
375 $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
376
377 $wgContentNamespaces = false;
378 $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
379
380 $wgContentNamespaces = null;
381 $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
382
383 $wgContentNamespaces = 5;
384 $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
385
386 # test $wgContentNamespaces === []
387 $wgContentNamespaces = [];
388 $this->assertEquals( [ NS_MAIN ], MWNamespace::getContentNamespaces() );
389
390 # test !in_array( NS_MAIN, $wgContentNamespaces )
391 $wgContentNamespaces = [ NS_USER, NS_CATEGORY ];
392 $this->assertEquals(
393 [ NS_MAIN, NS_USER, NS_CATEGORY ],
394 MWNamespace::getContentNamespaces(),
395 'NS_MAIN is forced in $wgContentNamespaces even if unwanted'
396 );
397
398 # test other cases, return $wgcontentNamespaces as is
399 $wgContentNamespaces = [ NS_MAIN ];
400 $this->assertEquals(
401 [ NS_MAIN ],
402 MWNamespace::getContentNamespaces()
403 );
404
405 $wgContentNamespaces = [ NS_MAIN, NS_USER, NS_CATEGORY ];
406 $this->assertEquals(
407 [ NS_MAIN, NS_USER, NS_CATEGORY ],
408 MWNamespace::getContentNamespaces()
409 );
410 }
411
412 /**
413 * @covers MWNamespace::getSubjectNamespaces
414 */
415 public function testGetSubjectNamespaces() {
416 $subjectsNS = MWNamespace::getSubjectNamespaces();
417 $this->assertContains( NS_MAIN, $subjectsNS,
418 "Talk namespaces should have NS_MAIN" );
419 $this->assertNotContains( NS_TALK, $subjectsNS,
420 "Talk namespaces should have NS_TALK" );
421
422 $this->assertNotContains( NS_MEDIA, $subjectsNS,
423 "Talk namespaces should not have NS_MEDIA" );
424 $this->assertNotContains( NS_SPECIAL, $subjectsNS,
425 "Talk namespaces should not have NS_SPECIAL" );
426 }
427
428 /**
429 * @covers MWNamespace::getTalkNamespaces
430 */
431 public function testGetTalkNamespaces() {
432 $talkNS = MWNamespace::getTalkNamespaces();
433 $this->assertContains( NS_TALK, $talkNS,
434 "Subject namespaces should have NS_TALK" );
435 $this->assertNotContains( NS_MAIN, $talkNS,
436 "Subject namespaces should not have NS_MAIN" );
437
438 $this->assertNotContains( NS_MEDIA, $talkNS,
439 "Subject namespaces should not have NS_MEDIA" );
440 $this->assertNotContains( NS_SPECIAL, $talkNS,
441 "Subject namespaces should not have NS_SPECIAL" );
442 }
443
444 private function assertIsCapitalized( $ns ) {
445 $this->assertTrue( MWNamespace::isCapitalized( $ns ) );
446 }
447
448 private function assertIsNotCapitalized( $ns ) {
449 $this->assertFalse( MWNamespace::isCapitalized( $ns ) );
450 }
451
452 /**
453 * Some namespaces are always capitalized per code definition
454 * in MWNamespace::$alwaysCapitalizedNamespaces
455 * @covers MWNamespace::isCapitalized
456 */
457 public function testIsCapitalizedHardcodedAssertions() {
458 // NS_MEDIA and NS_FILE are treated the same
459 $this->assertEquals(
460 MWNamespace::isCapitalized( NS_MEDIA ),
461 MWNamespace::isCapitalized( NS_FILE ),
462 'NS_MEDIA and NS_FILE have same capitalization rendering'
463 );
464
465 // Boths are capitalized by default
466 $this->assertIsCapitalized( NS_MEDIA );
467 $this->assertIsCapitalized( NS_FILE );
468
469 // Always capitalized namespaces
470 // @see MWNamespace::$alwaysCapitalizedNamespaces
471 $this->assertIsCapitalized( NS_SPECIAL );
472 $this->assertIsCapitalized( NS_USER );
473 $this->assertIsCapitalized( NS_MEDIAWIKI );
474 }
475
476 /**
477 * Follows up for testIsCapitalizedHardcodedAssertions() but alter the
478 * global $wgCapitalLink setting to have extended coverage.
479 *
480 * MWNamespace::isCapitalized() rely on two global settings:
481 * $wgCapitalLinkOverrides = []; by default
482 * $wgCapitalLinks = true; by default
483 * This function test $wgCapitalLinks
484 *
485 * Global setting correctness is tested against the NS_PROJECT and
486 * NS_PROJECT_TALK namespaces since they are not hardcoded nor specials
487 * @covers MWNamespace::isCapitalized
488 */
489 public function testIsCapitalizedWithWgCapitalLinks() {
490 global $wgCapitalLinks;
491
492 $this->assertIsCapitalized( NS_PROJECT );
493 $this->assertIsCapitalized( NS_PROJECT_TALK );
494
495 $wgCapitalLinks = false;
496
497 // hardcoded namespaces (see above function) are still capitalized:
498 $this->assertIsCapitalized( NS_SPECIAL );
499 $this->assertIsCapitalized( NS_USER );
500 $this->assertIsCapitalized( NS_MEDIAWIKI );
501
502 // setting is correctly applied
503 $this->assertIsNotCapitalized( NS_PROJECT );
504 $this->assertIsNotCapitalized( NS_PROJECT_TALK );
505 }
506
507 /**
508 * Counter part for MWNamespace::testIsCapitalizedWithWgCapitalLinks() now
509 * testing the $wgCapitalLinkOverrides global.
510 *
511 * @todo split groups of assertions in autonomous testing functions
512 * @covers MWNamespace::isCapitalized
513 */
514 public function testIsCapitalizedWithWgCapitalLinkOverrides() {
515 global $wgCapitalLinkOverrides;
516
517 // Test default settings
518 $this->assertIsCapitalized( NS_PROJECT );
519 $this->assertIsCapitalized( NS_PROJECT_TALK );
520
521 // hardcoded namespaces (see above function) are capitalized:
522 $this->assertIsCapitalized( NS_SPECIAL );
523 $this->assertIsCapitalized( NS_USER );
524 $this->assertIsCapitalized( NS_MEDIAWIKI );
525
526 // Hardcoded namespaces remains capitalized
527 $wgCapitalLinkOverrides[NS_SPECIAL] = false;
528 $wgCapitalLinkOverrides[NS_USER] = false;
529 $wgCapitalLinkOverrides[NS_MEDIAWIKI] = false;
530
531 $this->assertIsCapitalized( NS_SPECIAL );
532 $this->assertIsCapitalized( NS_USER );
533 $this->assertIsCapitalized( NS_MEDIAWIKI );
534
535 $wgCapitalLinkOverrides[NS_PROJECT] = false;
536 $this->assertIsNotCapitalized( NS_PROJECT );
537
538 $wgCapitalLinkOverrides[NS_PROJECT] = true;
539 $this->assertIsCapitalized( NS_PROJECT );
540
541 unset( $wgCapitalLinkOverrides[NS_PROJECT] );
542 $this->assertIsCapitalized( NS_PROJECT );
543 }
544
545 /**
546 * @covers MWNamespace::hasGenderDistinction
547 */
548 public function testHasGenderDistinction() {
549 // Namespaces with gender distinctions
550 $this->assertTrue( MWNamespace::hasGenderDistinction( NS_USER ) );
551 $this->assertTrue( MWNamespace::hasGenderDistinction( NS_USER_TALK ) );
552
553 // Other ones, "genderless"
554 $this->assertFalse( MWNamespace::hasGenderDistinction( NS_MEDIA ) );
555 $this->assertFalse( MWNamespace::hasGenderDistinction( NS_SPECIAL ) );
556 $this->assertFalse( MWNamespace::hasGenderDistinction( NS_MAIN ) );
557 $this->assertFalse( MWNamespace::hasGenderDistinction( NS_TALK ) );
558 }
559
560 /**
561 * @covers MWNamespace::isNonincludable
562 */
563 public function testIsNonincludable() {
564 global $wgNonincludableNamespaces;
565
566 $wgNonincludableNamespaces = [ NS_USER ];
567
568 $this->assertTrue( MWNamespace::isNonincludable( NS_USER ) );
569 $this->assertFalse( MWNamespace::isNonincludable( NS_TEMPLATE ) );
570 }
571
572 private function assertSameSubject( $ns1, $ns2, $msg = '' ) {
573 $this->assertTrue( MWNamespace::subjectEquals( $ns1, $ns2 ), $msg );
574 }
575
576 private function assertDifferentSubject( $ns1, $ns2, $msg = '' ) {
577 $this->assertFalse( MWNamespace::subjectEquals( $ns1, $ns2 ), $msg );
578 }
579
580 public function provideGetCategoryLinkType() {
581 return [
582 [ NS_MAIN, 'page' ],
583 [ NS_TALK, 'page' ],
584 [ NS_USER, 'page' ],
585 [ NS_USER_TALK, 'page' ],
586
587 [ NS_FILE, 'file' ],
588 [ NS_FILE_TALK, 'page' ],
589
590 [ NS_CATEGORY, 'subcat' ],
591 [ NS_CATEGORY_TALK, 'page' ],
592
593 [ 100, 'page' ],
594 [ 101, 'page' ],
595 ];
596 }
597
598 /**
599 * @dataProvider provideGetCategoryLinkType
600 * @covers MWNamespace::getCategoryLinkType
601 *
602 * @param int $index
603 * @param string $expected
604 */
605 public function testGetCategoryLinkType( $index, $expected ) {
606 $actual = MWNamespace::getCategoryLinkType( $index );
607 $this->assertSame( $expected, $actual, "NS $index" );
608 }
609 }