3 * @author Antoine Musso
4 * @copyright Copyright © 2011, Antoine Musso
8 use MediaWiki\Config\ServiceOptions
;
9 use MediaWiki\Linker\LinkTarget
;
11 class NamespaceInfoTest
extends MediaWikiTestCase
{
12 use TestAllServiceOptionsUsed
;
14 /**********************************************************************************************
18 private $scopedCallback;
20 public function setUp() {
23 // Boo, there's still some global state in the class :(
26 unset( $hooks['CanonicalNamespaces'] );
27 $this->setMwGlobals( 'wgHooks', $hooks );
29 $this->scopedCallback
=
30 ExtensionRegistry
::getInstance()->setAttributeForTest( 'ExtensionNamespaces', [] );
33 public function tearDown() {
34 $this->scopedCallback
= null;
40 * TODO Make this a const once HHVM support is dropped (T192166)
42 private static $defaultOptions = [
43 'AllowImageMoving' => true,
44 'CanonicalNamespaceNames' => [
47 NS_USER_TALK
=> 'User_talk',
48 NS_SPECIAL
=> 'Special',
51 'CapitalLinkOverrides' => [],
52 'CapitalLinks' => true,
53 'ContentNamespaces' => [ NS_MAIN
],
54 'ExtraNamespaces' => [],
55 'ExtraSignatureNamespaces' => [],
56 'NamespaceContentModels' => [],
57 'NamespaceProtection' => [],
58 'NamespacesWithSubpages' => [
63 'NonincludableNamespaces' => [],
64 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
67 private function newObj( array $options = [] ) : NamespaceInfo
{
68 return new NamespaceInfo( new LoggedServiceOptions(
69 self
::$serviceOptionsAccessLog,
70 NamespaceInfo
::$constructorOptions,
71 $options, self
::$defaultOptions
77 /**********************************************************************************************
83 * @covers NamespaceInfo::__construct
84 * @dataProvider provideConstructor
85 * @param ServiceOptions $options
86 * @param string|null $expectedExceptionText
88 public function testConstructor( ServiceOptions
$options, $expectedExceptionText = null ) {
89 if ( $expectedExceptionText !== null ) {
90 $this->setExpectedException( \Wikimedia\Assert\PreconditionException
::class,
91 $expectedExceptionText );
93 new NamespaceInfo( $options );
94 $this->assertTrue( true );
97 public function provideConstructor() {
99 [ new ServiceOptions( NamespaceInfo
::$constructorOptions, self
::$defaultOptions ) ],
100 [ new ServiceOptions( [], [] ), 'Required options missing: ' ],
101 [ new ServiceOptions(
102 array_merge( NamespaceInfo
::$constructorOptions, [ 'invalid' ] ),
103 self
::$defaultOptions,
105 ), 'Unsupported options passed: invalid' ],
110 * @dataProvider provideIsMovable
111 * @covers NamespaceInfo::isMovable
113 * @param bool $expected
115 * @param bool $allowImageMoving
117 public function testIsMovable( $expected, $ns, $allowImageMoving = true ) {
118 $obj = $this->newObj( [ 'AllowImageMoving' => $allowImageMoving ] );
119 $this->assertSame( $expected, $obj->isMovable( $ns ) );
122 public function provideIsMovable() {
124 'Main' => [ true, NS_MAIN
],
125 'Talk' => [ true, NS_TALK
],
126 'Special' => [ false, NS_SPECIAL
],
127 'Nonexistent even namespace' => [ true, 1234 ],
128 'Nonexistent odd namespace' => [ true, 12345 ],
130 'Media with image moving' => [ false, NS_MEDIA
, true ],
131 'Media with no image moving' => [ false, NS_MEDIA
, false ],
132 'File with image moving' => [ true, NS_FILE
, true ],
133 'File with no image moving' => [ false, NS_FILE
, false ],
139 * @param bool $expected
140 * @dataProvider provideIsSubject
141 * @covers NamespaceInfo::isSubject
143 public function testIsSubject( $ns, $expected ) {
144 $this->assertSame( $expected, $this->newObj()->isSubject( $ns ) );
149 * @param bool $expected
150 * @dataProvider provideIsSubject
151 * @covers NamespaceInfo::isTalk
153 public function testIsTalk( $ns, $expected ) {
154 $this->assertSame( !$expected, $this->newObj()->isTalk( $ns ) );
157 public function provideIsSubject() {
159 // Special namespaces
161 [ NS_SPECIAL
, true ],
170 [ NS_USER_TALK
, false ],
176 * @covers NamespaceInfo::exists
177 * @dataProvider provideExists
179 * @param bool $expected
181 public function testExists( $ns, $expected ) {
182 $this->assertSame( $expected, $this->newObj()->exists( $ns ) );
185 public function provideExists() {
187 'Main' => [ NS_MAIN
, true ],
188 'Talk' => [ NS_TALK
, true ],
189 'Media' => [ NS_MEDIA
, true ],
190 'Special' => [ NS_SPECIAL
, true ],
191 'Nonexistent' => [ 12345, false ],
192 'Negative nonexistent' => [ -12345, false ],
197 * Note if we add a namespace registration system with keys like 'MAIN'
198 * we should add tests here for equivalence on things like 'MAIN' == 0
199 * and 'MAIN' == NS_MAIN.
200 * @covers NamespaceInfo::equals
202 public function testEquals() {
203 $obj = $this->newObj();
204 $this->assertTrue( $obj->equals( NS_MAIN
, NS_MAIN
) );
205 $this->assertTrue( $obj->equals( NS_MAIN
, 0 ) ); // In case we make NS_MAIN 'MAIN'
206 $this->assertTrue( $obj->equals( NS_USER
, NS_USER
) );
207 $this->assertTrue( $obj->equals( NS_USER
, 2 ) );
208 $this->assertTrue( $obj->equals( NS_USER_TALK
, NS_USER_TALK
) );
209 $this->assertTrue( $obj->equals( NS_SPECIAL
, NS_SPECIAL
) );
210 $this->assertFalse( $obj->equals( NS_MAIN
, NS_TALK
) );
211 $this->assertFalse( $obj->equals( NS_USER
, NS_USER_TALK
) );
212 $this->assertFalse( $obj->equals( NS_PROJECT
, NS_TEMPLATE
) );
218 * @param bool $expected
219 * @dataProvider provideSubjectEquals
220 * @covers NamespaceInfo::subjectEquals
222 public function testSubjectEquals( $ns1, $ns2, $expected ) {
223 $this->assertSame( $expected, $this->newObj()->subjectEquals( $ns1, $ns2 ) );
226 public function provideSubjectEquals() {
228 [ NS_MAIN
, NS_MAIN
, true ],
229 // In case we make NS_MAIN 'MAIN'
230 [ NS_MAIN
, 0, true ],
231 [ NS_USER
, NS_USER
, true ],
232 [ NS_USER
, 2, true ],
233 [ NS_USER_TALK
, NS_USER_TALK
, true ],
234 [ NS_SPECIAL
, NS_SPECIAL
, true ],
235 [ NS_MAIN
, NS_TALK
, true ],
236 [ NS_USER
, NS_USER_TALK
, true ],
238 [ NS_PROJECT
, NS_TEMPLATE
, false ],
239 [ NS_SPECIAL
, NS_MAIN
, false ],
240 [ NS_MEDIA
, NS_SPECIAL
, false ],
241 [ NS_SPECIAL
, NS_MEDIA
, false ],
246 * @dataProvider provideHasTalkNamespace
247 * @covers NamespaceInfo::hasTalkNamespace
250 * @param bool $expected
252 public function testHasTalkNamespace( $ns, $expected ) {
253 $this->assertSame( $expected, $this->newObj()->hasTalkNamespace( $ns ) );
256 public function provideHasTalkNamespace() {
259 [ NS_SPECIAL
, false ],
264 [ NS_USER_TALK
, true ],
273 * @param bool $expected
274 * @param array $contentNamespaces
275 * @covers NamespaceInfo::isContent
276 * @dataProvider provideIsContent
278 public function testIsContent( $ns, $expected, $contentNamespaces = [ NS_MAIN
] ) {
279 $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
280 $this->assertSame( $expected, $obj->isContent( $ns ) );
283 public function provideIsContent() {
287 [ NS_SPECIAL
, false ],
290 [ NS_CATEGORY
, false ],
292 [ 100, true, [ NS_MAIN
, 100, 252 ] ],
293 [ 252, true, [ NS_MAIN
, 100, 252 ] ],
294 [ NS_MAIN
, true, [ NS_MAIN
, 100, 252 ] ],
295 // NS_MAIN is always content
296 [ NS_MAIN
, true, [] ],
301 * @dataProvider provideWantSignatures
302 * @covers NamespaceInfo::wantSignatures
305 * @param bool $expected
307 public function testWantSignatures( $index, $expected ) {
308 $this->assertSame( $expected, $this->newObj()->wantSignatures( $index ) );
311 public function provideWantSignatures() {
313 'Main' => [ NS_MAIN
, false ],
314 'Talk' => [ NS_TALK
, true ],
315 'User' => [ NS_USER
, false ],
316 'User talk' => [ NS_USER_TALK
, true ],
317 'Special' => [ NS_SPECIAL
, false ],
318 'Media' => [ NS_MEDIA
, false ],
319 'Nonexistent talk' => [ 12345, true ],
320 'Nonexistent subject' => [ 123456, false ],
321 'Nonexistent negative odd' => [ -12345, false ],
326 * @dataProvider provideWantSignatures_ExtraSignatureNamespaces
327 * @covers NamespaceInfo::wantSignatures
330 * @param int $expected
332 public function testWantSignatures_ExtraSignatureNamespaces( $index, $expected ) {
333 $obj = $this->newObj( [ 'ExtraSignatureNamespaces' =>
334 [ NS_MAIN
, NS_USER
, NS_SPECIAL
, NS_MEDIA
, 123456, -12345 ] ] );
335 $this->assertSame( $expected, $obj->wantSignatures( $index ) );
338 public function provideWantSignatures_ExtraSignatureNamespaces() {
341 // We've added all these as extra signature namespaces, so expect true
342 return [ $arr[0], true ];
344 self
::provideWantSignatures()
347 // Add one more that's false
348 $ret['Another nonexistent subject'] = [ 12345678, false ];
354 * @param bool $expected
355 * @covers NamespaceInfo::isWatchable
356 * @dataProvider provideIsWatchable
358 public function testIsWatchable( $ns, $expected ) {
359 $this->assertSame( $expected, $this->newObj()->isWatchable( $ns ) );
362 public function provideIsWatchable() {
364 // Specials namespaces are not watchable
366 [ NS_SPECIAL
, false ],
368 // Core defined namespaces are watchables
372 // Additional, user defined namespaces are watchables
380 * @param int $expected
381 * @param array|null $namespacesWithSubpages To pass to constructor
382 * @covers NamespaceInfo::hasSubpages
383 * @dataProvider provideHasSubpages
385 public function testHasSubpages( $ns, $expected, array $namespacesWithSubpages = null ) {
386 $obj = $this->newObj( $namespacesWithSubpages
387 ?
[ 'NamespacesWithSubpages' => $namespacesWithSubpages ]
389 $this->assertSame( $expected, $obj->hasSubpages( $ns ) );
392 public function provideHasSubpages() {
394 // Special namespaces:
396 [ NS_SPECIAL
, false ],
398 // Namespaces without subpages
400 [ NS_MAIN
, true, [ NS_MAIN
=> true ] ],
401 [ NS_MAIN
, false, [ NS_MAIN
=> false ] ],
403 // Some namespaces with subpages
406 [ NS_USER_TALK
, true ],
411 * @param mixed $contentNamespaces To pass to constructor
412 * @param array $expected
413 * @dataProvider provideGetContentNamespaces
414 * @covers NamespaceInfo::getContentNamespaces
416 public function testGetContentNamespaces( $contentNamespaces, array $expected ) {
417 $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
418 $this->assertSame( $expected, $obj->getContentNamespaces() );
421 public function provideGetContentNamespaces() {
425 [ false, [ NS_MAIN
] ],
426 [ null, [ NS_MAIN
] ],
432 // NS_MAIN is forced to be content even if unwanted
433 [ [ NS_USER
, NS_CATEGORY
], [ NS_MAIN
, NS_USER
, NS_CATEGORY
] ],
435 // In other cases, return as-is
436 [ [ NS_MAIN
], [ NS_MAIN
] ],
437 [ [ NS_MAIN
, NS_USER
, NS_CATEGORY
], [ NS_MAIN
, NS_USER
, NS_CATEGORY
] ],
442 * @covers NamespaceInfo::getSubjectNamespaces
444 public function testGetSubjectNamespaces() {
445 $subjectsNS = $this->newObj()->getSubjectNamespaces();
446 $this->assertContains( NS_MAIN
, $subjectsNS,
447 "Talk namespaces should have NS_MAIN" );
448 $this->assertNotContains( NS_TALK
, $subjectsNS,
449 "Talk namespaces should have NS_TALK" );
451 $this->assertNotContains( NS_MEDIA
, $subjectsNS,
452 "Talk namespaces should not have NS_MEDIA" );
453 $this->assertNotContains( NS_SPECIAL
, $subjectsNS,
454 "Talk namespaces should not have NS_SPECIAL" );
458 * @covers NamespaceInfo::getTalkNamespaces
460 public function testGetTalkNamespaces() {
461 $talkNS = $this->newObj()->getTalkNamespaces();
462 $this->assertContains( NS_TALK
, $talkNS,
463 "Subject namespaces should have NS_TALK" );
464 $this->assertNotContains( NS_MAIN
, $talkNS,
465 "Subject namespaces should not have NS_MAIN" );
467 $this->assertNotContains( NS_MEDIA
, $talkNS,
468 "Subject namespaces should not have NS_MEDIA" );
469 $this->assertNotContains( NS_SPECIAL
, $talkNS,
470 "Subject namespaces should not have NS_SPECIAL" );
475 * @param bool $expected
476 * @param bool $capitalLinks To pass to constructor
477 * @param array $capitalLinkOverrides To pass to constructor
478 * @dataProvider provideIsCapitalized
479 * @covers NamespaceInfo::isCapitalized
481 public function testIsCapitalized(
482 $ns, $expected, $capitalLinks = true, array $capitalLinkOverrides = []
484 $obj = $this->newObj( [
485 'CapitalLinks' => $capitalLinks,
486 'CapitalLinkOverrides' => $capitalLinkOverrides,
488 $this->assertSame( $expected, $obj->isCapitalized( $ns ) );
491 public function provideIsCapitalized() {
493 // Test default settings
494 [ NS_PROJECT
, true ],
495 [ NS_PROJECT_TALK
, true ],
499 // Always capitalized no matter what
500 [ NS_SPECIAL
, true, false ],
501 [ NS_USER
, true, false ],
502 [ NS_MEDIAWIKI
, true, false ],
504 // Even with an override too
505 [ NS_SPECIAL
, true, false, [ NS_SPECIAL
=> false ] ],
506 [ NS_USER
, true, false, [ NS_USER
=> false ] ],
507 [ NS_MEDIAWIKI
, true, false, [ NS_MEDIAWIKI
=> false ] ],
509 // Overrides work for other namespaces
510 [ NS_PROJECT
, false, true, [ NS_PROJECT
=> false ] ],
511 [ NS_PROJECT
, true, false, [ NS_PROJECT
=> true ] ],
513 // NS_MEDIA is treated like NS_FILE, and ignores NS_MEDIA overrides
514 [ NS_MEDIA
, false, true, [ NS_FILE
=> false, NS_MEDIA
=> true ] ],
515 [ NS_MEDIA
, true, false, [ NS_FILE
=> true, NS_MEDIA
=> false ] ],
516 [ NS_FILE
, false, true, [ NS_FILE
=> false, NS_MEDIA
=> true ] ],
517 [ NS_FILE
, true, false, [ NS_FILE
=> true, NS_MEDIA
=> false ] ],
522 * @covers NamespaceInfo::hasGenderDistinction
524 public function testHasGenderDistinction() {
525 $obj = $this->newObj();
527 // Namespaces with gender distinctions
528 $this->assertTrue( $obj->hasGenderDistinction( NS_USER
) );
529 $this->assertTrue( $obj->hasGenderDistinction( NS_USER_TALK
) );
531 // Other ones, "genderless"
532 $this->assertFalse( $obj->hasGenderDistinction( NS_MEDIA
) );
533 $this->assertFalse( $obj->hasGenderDistinction( NS_SPECIAL
) );
534 $this->assertFalse( $obj->hasGenderDistinction( NS_MAIN
) );
535 $this->assertFalse( $obj->hasGenderDistinction( NS_TALK
) );
539 * @covers NamespaceInfo::isNonincludable
541 public function testIsNonincludable() {
542 $obj = $this->newObj( [ 'NonincludableNamespaces' => [ NS_USER
] ] );
543 $this->assertTrue( $obj->isNonincludable( NS_USER
) );
544 $this->assertFalse( $obj->isNonincludable( NS_TEMPLATE
) );
548 * @dataProvider provideGetNamespaceContentModel
549 * @covers NamespaceInfo::getNamespaceContentModel
552 * @param string $expected
554 public function testGetNamespaceContentModel( $ns, $expected ) {
555 $obj = $this->newObj( [ 'NamespaceContentModels' =>
556 [ NS_USER
=> CONTENT_MODEL_WIKITEXT
, 123 => CONTENT_MODEL_JSON
, 1234 => 'abcdef' ],
558 $this->assertSame( $expected, $obj->getNamespaceContentModel( $ns ) );
561 public function provideGetNamespaceContentModel() {
565 [ NS_USER
, CONTENT_MODEL_WIKITEXT
],
566 [ NS_USER_TALK
, null ],
567 [ NS_SPECIAL
, null ],
569 [ 123, CONTENT_MODEL_JSON
],
576 * @dataProvider provideGetCategoryLinkType
577 * @covers NamespaceInfo::getCategoryLinkType
580 * @param string $expected
582 public function testGetCategoryLinkType( $ns, $expected ) {
583 $this->assertSame( $expected, $this->newObj()->getCategoryLinkType( $ns ) );
586 public function provideGetCategoryLinkType() {
591 [ NS_USER_TALK
, 'page' ],
594 [ NS_FILE_TALK
, 'page' ],
596 [ NS_CATEGORY
, 'subcat' ],
597 [ NS_CATEGORY_TALK
, 'page' ],
604 // %} End basic methods
606 /**********************************************************************************************
607 * getSubject/Talk/Associated
612 * @dataProvider provideSubjectTalk
613 * @covers NamespaceInfo::getSubject
614 * @covers NamespaceInfo::getSubjectPage
615 * @covers NamespaceInfo::isMethodValidFor
616 * @covers Title::getSubjectPage
618 * @param int $subject
621 public function testGetSubject( $subject, $talk ) {
622 $obj = $this->newObj();
623 $this->assertSame( $subject, $obj->getSubject( $subject ) );
624 $this->assertSame( $subject, $obj->getSubject( $talk ) );
626 $subjectTitleVal = new TitleValue( $subject, 'A' );
627 $talkTitleVal = new TitleValue( $talk, 'A' );
628 // Object will be the same one passed in if it's a subject, different but equal object if
630 $this->assertSame( $subjectTitleVal, $obj->getSubjectPage( $subjectTitleVal ) );
631 $this->assertEquals( $subjectTitleVal, $obj->getSubjectPage( $talkTitleVal ) );
633 $subjectTitle = Title
::makeTitle( $subject, 'A' );
634 $talkTitle = Title
::makeTitle( $talk, 'A' );
635 $this->assertSame( $subjectTitle, $subjectTitle->getSubjectPage() );
636 $this->assertEquals( $subjectTitle, $talkTitle->getSubjectPage() );
640 * @dataProvider provideSpecialNamespaces
641 * @covers NamespaceInfo::getSubject
642 * @covers NamespaceInfo::getSubjectPage
646 public function testGetSubject_special( $ns ) {
647 $obj = $this->newObj();
648 $this->assertSame( $ns, $obj->getSubject( $ns ) );
650 $title = new TitleValue( $ns, 'A' );
651 $this->assertSame( $title, $obj->getSubjectPage( $title ) );
655 * @dataProvider provideSubjectTalk
656 * @covers NamespaceInfo::getTalk
657 * @covers NamespaceInfo::getTalkPage
658 * @covers NamespaceInfo::isMethodValidFor
659 * @covers Title::getTalkPage
661 * @param int $subject
664 public function testGetTalk( $subject, $talk ) {
665 $obj = $this->newObj();
666 $this->assertSame( $talk, $obj->getTalk( $subject ) );
667 $this->assertSame( $talk, $obj->getTalk( $talk ) );
669 $subjectTitleVal = new TitleValue( $subject, 'A' );
670 $talkTitleVal = new TitleValue( $talk, 'A' );
671 // Object will be the same one passed in if it's a talk, different but equal object if it's
673 $this->assertEquals( $talkTitleVal, $obj->getTalkPage( $subjectTitleVal ) );
674 $this->assertSame( $talkTitleVal, $obj->getTalkPage( $talkTitleVal ) );
676 $subjectTitle = Title
::makeTitle( $subject, 'A' );
677 $talkTitle = Title
::makeTitle( $talk, 'A' );
678 $this->assertEquals( $talkTitle, $subjectTitle->getTalkPage() );
679 $this->assertSame( $talkTitle, $talkTitle->getTalkPage() );
683 * @dataProvider provideSpecialNamespaces
684 * @covers NamespaceInfo::getTalk
685 * @covers NamespaceInfo::isMethodValidFor
689 public function testGetTalk_special( $ns ) {
690 $this->setExpectedException( MWException
::class,
691 "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
692 $this->newObj()->getTalk( $ns );
696 * @dataProvider provideSpecialNamespaces
697 * @covers NamespaceInfo::getAssociated
698 * @covers NamespaceInfo::isMethodValidFor
702 public function testGetAssociated_special( $ns ) {
703 $this->setExpectedException(
705 "NamespaceInfo::getAssociated does not make any sense for given namespace $ns"
707 $this->newObj()->getAssociated( $ns );
710 public static function provideCanHaveTalkPage() {
712 [ new TitleValue( NS_MAIN
, 'Test' ), true ],
713 [ new TitleValue( NS_TALK
, 'Test' ), true ],
714 [ new TitleValue( NS_USER
, 'Test' ), true ],
715 [ new TitleValue( NS_SPECIAL
, 'Test' ), false ],
716 [ new TitleValue( NS_MEDIA
, 'Test' ), false ],
717 [ new TitleValue( NS_MAIN
, '', 'Kittens' ), false ],
718 [ new TitleValue( NS_MAIN
, 'Kittens', '', 'acme' ), false ],
723 * @dataProvider provideCanHaveTalkPage
724 * @covers NamespaceInfo::canHaveTalkPage
726 public function testCanHaveTalkPage( LinkTarget
$t, $expected ) {
727 $actual = $this->newObj()->canHaveTalkPage( $t );
728 $this->assertEquals( $expected, $actual, $t->getDBkey() );
731 public static function provideGetTalkPage_good() {
733 [ new TitleValue( NS_MAIN
, 'Test' ), new TitleValue( NS_TALK
, 'Test' ) ],
734 [ new TitleValue( NS_TALK
, 'Test' ), new TitleValue( NS_TALK
, 'Test' ) ],
735 [ new TitleValue( NS_USER
, 'Test' ), new TitleValue( NS_USER_TALK
, 'Test' ) ],
740 * @dataProvider provideGetTalkPage_good
741 * @covers NamespaceInfo::getTalk
742 * @covers NamespaceInfo::getTalkPage
743 * @covers NamespaceInfo::isMethodValidFor
745 public function testGetTalkPage_good( LinkTarget
$t, LinkTarget
$expected ) {
746 $actual = $this->newObj()->getTalkPage( $t );
747 $this->assertEquals( $expected, $actual, $t->getDBkey() );
750 public static function provideGetTalkPage_bad() {
752 [ new TitleValue( NS_SPECIAL
, 'Test' ) ],
753 [ new TitleValue( NS_MEDIA
, 'Test' ) ],
754 [ new TitleValue( NS_MAIN
, '', 'Kittens' ) ],
755 [ new TitleValue( NS_MAIN
, 'Kittens', '', 'acme' ) ],
760 * @dataProvider provideGetTalkPage_bad
761 * @covers NamespaceInfo::getTalk
762 * @covers NamespaceInfo::getTalkPage
763 * @covers NamespaceInfo::isMethodValidFor
765 public function testGetTalkPage_bad( LinkTarget
$t ) {
766 $this->setExpectedException( MWException
::class );
767 $this->newObj()->getTalkPage( $t );
771 * @dataProvider provideGetTalkPage_bad
772 * @covers NamespaceInfo::getAssociated
773 * @covers NamespaceInfo::getAssociatedPage
774 * @covers NamespaceInfo::isMethodValidFor
776 public function testGetAssociatedPage_bad( LinkTarget
$t ) {
777 $this->setExpectedException( MWException
::class );
778 $this->newObj()->getAssociatedPage( $t );
782 * @dataProvider provideSubjectTalk
783 * @covers NamespaceInfo::getAssociated
784 * @covers NamespaceInfo::getAssociatedPage
785 * @covers Title::getOtherPage
787 * @param int $subject
790 public function testGetAssociated( $subject, $talk ) {
791 $obj = $this->newObj();
792 $this->assertSame( $talk, $obj->getAssociated( $subject ) );
793 $this->assertSame( $subject, $obj->getAssociated( $talk ) );
795 $subjectTitle = new TitleValue( $subject, 'A' );
796 $talkTitle = new TitleValue( $talk, 'A' );
797 // Object will not be the same
798 $this->assertEquals( $talkTitle, $obj->getAssociatedPage( $subjectTitle ) );
799 $this->assertEquals( $subjectTitle, $obj->getAssociatedPage( $talkTitle ) );
801 $subjectTitle = Title
::makeTitle( $subject, 'A' );
802 $talkTitle = Title
::makeTitle( $talk, 'A' );
803 $this->assertEquals( $talkTitle, $subjectTitle->getOtherPage() );
804 $this->assertEquals( $subjectTitle, $talkTitle->getOtherPage() );
807 public static function provideSubjectTalk() {
809 // Format: [ subject, talk ]
810 'Main/talk' => [ NS_MAIN
, NS_TALK
],
811 'User/user talk' => [ NS_USER
, NS_USER_TALK
],
812 'Unknown namespaces also supported' => [ 106, 107 ],
816 public static function provideSpecialNamespaces() {
818 'Special' => [ NS_SPECIAL
],
819 'Media' => [ NS_MEDIA
],
820 'Unknown negative index' => [ -613 ],
824 // %} End getSubject/Talk/Associated
826 /**********************************************************************************************
827 * Canonical namespaces
831 // Default canonical namespaces
833 private function getDefaultNamespaces() {
834 return [ NS_MAIN
=> '' ] + self
::$defaultOptions['CanonicalNamespaceNames'];
838 * @covers NamespaceInfo::getCanonicalNamespaces
840 public function testGetCanonicalNamespaces() {
842 $this->getDefaultNamespaces(),
843 $this->newObj()->getCanonicalNamespaces()
848 * @dataProvider provideGetCanonicalName
849 * @covers NamespaceInfo::getCanonicalName
852 * @param string|bool $expected
854 public function testGetCanonicalName( $index, $expected ) {
855 $this->assertSame( $expected, $this->newObj()->getCanonicalName( $index ) );
858 public function provideGetCanonicalName() {
860 'Main' => [ NS_MAIN
, '' ],
861 'Talk' => [ NS_TALK
, 'Talk' ],
862 'With underscore not space' => [ NS_USER_TALK
, 'User_talk' ],
863 'Special' => [ NS_SPECIAL
, 'Special' ],
864 'Nonexistent' => [ 12345, false ],
865 'Nonexistent negative' => [ -12345, false ],
870 * @dataProvider provideGetCanonicalIndex
871 * @covers NamespaceInfo::getCanonicalIndex
873 * @param string $name
874 * @param int|null $expected
876 public function testGetCanonicalIndex( $name, $expected ) {
877 $this->assertSame( $expected, $this->newObj()->getCanonicalIndex( $name ) );
880 public function provideGetCanonicalIndex() {
882 'Main' => [ '', NS_MAIN
],
883 'Talk' => [ 'talk', NS_TALK
],
884 'Not lowercase' => [ 'Talk', null ],
885 'With underscore' => [ 'user_talk', NS_USER_TALK
],
886 'Space is not recognized for underscore' => [ 'user talk', null ],
887 '0' => [ '0', null ],
892 * @covers NamespaceInfo::getValidNamespaces
894 public function testGetValidNamespaces() {
896 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
],
897 $this->newObj()->getValidNamespaces()
901 // %} End default canonical namespaces
903 // No canonical namespace names
907 * @covers NamespaceInfo::getCanonicalNamespaces
909 public function testGetCanonicalNamespaces_NoCanonicalNamespaceNames() {
910 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
912 $this->assertSame( [ NS_MAIN
=> '' ], $obj->getCanonicalNamespaces() );
916 * @covers NamespaceInfo::getCanonicalName
918 public function testGetCanonicalName_NoCanonicalNamespaceNames() {
919 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
921 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
922 $this->assertFalse( $obj->getCanonicalName( NS_TALK
) );
926 * @covers NamespaceInfo::getCanonicalIndex
928 public function testGetCanonicalIndex_NoCanonicalNamespaceNames() {
929 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
931 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( '' ) );
932 $this->assertNull( $obj->getCanonicalIndex( 'talk' ) );
936 * @covers NamespaceInfo::getValidNamespaces
938 public function testGetValidNamespaces_NoCanonicalNamespaceNames() {
939 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
941 $this->assertSame( [ NS_MAIN
], $obj->getValidNamespaces() );
944 // %} End no canonical namespace names
946 // Test extension namespaces
948 private function setupExtensionNamespaces() {
949 $this->scopedCallback
= null;
950 $this->scopedCallback
= ExtensionRegistry
::getInstance()->setAttributeForTest(
951 'ExtensionNamespaces',
952 [ NS_MAIN
=> 'No effect', NS_TALK
=> 'No effect', 12345 => 'Extended' ]
957 * @covers NamespaceInfo::getCanonicalNamespaces
959 public function testGetCanonicalNamespaces_ExtensionNamespaces() {
960 $this->setupExtensionNamespaces();
963 $this->getDefaultNamespaces() +
[ 12345 => 'Extended' ],
964 $this->newObj()->getCanonicalNamespaces()
969 * @covers NamespaceInfo::getCanonicalName
971 public function testGetCanonicalName_ExtensionNamespaces() {
972 $this->setupExtensionNamespaces();
973 $obj = $this->newObj();
975 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
976 $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK
) );
977 $this->assertSame( 'Extended', $obj->getCanonicalName( 12345 ) );
981 * @covers NamespaceInfo::getCanonicalIndex
983 public function testGetCanonicalIndex_ExtensionNamespaces() {
984 $this->setupExtensionNamespaces();
985 $obj = $this->newObj();
987 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( '' ) );
988 $this->assertSame( NS_TALK
, $obj->getCanonicalIndex( 'talk' ) );
989 $this->assertSame( 12345, $obj->getCanonicalIndex( 'extended' ) );
993 * @covers NamespaceInfo::getValidNamespaces
995 public function testGetValidNamespaces_ExtensionNamespaces() {
996 $this->setupExtensionNamespaces();
999 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
, 12345 ],
1000 $this->newObj()->getValidNamespaces()
1004 // %} End extension namespaces
1010 * @return array Expected canonical namespaces
1012 private function setupHookNamespaces() {
1014 function ( &$canonicalNamespaces ) {
1015 $canonicalNamespaces[NS_MAIN
] = 'Main';
1016 unset( $canonicalNamespaces[NS_MEDIA
] );
1017 $canonicalNamespaces[123456] = 'Hooked';
1019 $this->setTemporaryHook( 'CanonicalNamespaces', $callback );
1020 $expected = $this->getDefaultNamespaces();
1021 ( $callback )( $expected );
1026 * @covers NamespaceInfo::getCanonicalNamespaces
1028 public function testGetCanonicalNamespaces_HookNamespaces() {
1029 $expected = $this->setupHookNamespaces();
1031 $this->assertSame( $expected, $this->newObj()->getCanonicalNamespaces() );
1035 * @covers NamespaceInfo::getCanonicalName
1037 public function testGetCanonicalName_HookNamespaces() {
1038 $this->setupHookNamespaces();
1039 $obj = $this->newObj();
1041 $this->assertSame( 'Main', $obj->getCanonicalName( NS_MAIN
) );
1042 $this->assertFalse( $obj->getCanonicalName( NS_MEDIA
) );
1043 $this->assertSame( 'Hooked', $obj->getCanonicalName( 123456 ) );
1047 * @covers NamespaceInfo::getCanonicalIndex
1049 public function testGetCanonicalIndex_HookNamespaces() {
1050 $this->setupHookNamespaces();
1051 $obj = $this->newObj();
1053 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( 'main' ) );
1054 $this->assertNull( $obj->getCanonicalIndex( 'media' ) );
1055 $this->assertSame( 123456, $obj->getCanonicalIndex( 'hooked' ) );
1059 * @covers NamespaceInfo::getValidNamespaces
1061 public function testGetValidNamespaces_HookNamespaces() {
1062 $this->setupHookNamespaces();
1065 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
, 123456 ],
1066 $this->newObj()->getValidNamespaces()
1070 // %} End hook namespaces
1076 * @return NamespaceInfo
1078 private function setupExtraNamespaces() {
1079 return $this->newObj( [ 'ExtraNamespaces' =>
1080 [ NS_MAIN
=> 'No effect', NS_TALK
=> 'No effect', 1234567 => 'Extra' ]
1085 * @covers NamespaceInfo::getCanonicalNamespaces
1087 public function testGetCanonicalNamespaces_ExtraNamespaces() {
1089 $this->getDefaultNamespaces() +
[ 1234567 => 'Extra' ],
1090 $this->setupExtraNamespaces()->getCanonicalNamespaces()
1095 * @covers NamespaceInfo::getCanonicalName
1097 public function testGetCanonicalName_ExtraNamespaces() {
1098 $obj = $this->setupExtraNamespaces();
1100 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
1101 $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK
) );
1102 $this->assertSame( 'Extra', $obj->getCanonicalName( 1234567 ) );
1106 * @covers NamespaceInfo::getCanonicalIndex
1108 public function testGetCanonicalIndex_ExtraNamespaces() {
1109 $obj = $this->setupExtraNamespaces();
1111 $this->assertNull( $obj->getCanonicalIndex( 'no effect' ) );
1112 $this->assertNull( $obj->getCanonicalIndex( 'no_effect' ) );
1113 $this->assertSame( 1234567, $obj->getCanonicalIndex( 'extra' ) );
1117 * @covers NamespaceInfo::getValidNamespaces
1119 public function testGetValidNamespaces_ExtraNamespaces() {
1121 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
, 1234567 ],
1122 $this->setupExtraNamespaces()->getValidNamespaces()
1126 // %} End extra namespaces
1128 // Canonical namespace caching
1132 * @covers NamespaceInfo::getCanonicalNamespaces
1134 public function testGetCanonicalNamespaces_caching() {
1135 $obj = $this->newObj();
1137 // This should cache the values
1138 $obj->getCanonicalNamespaces();
1140 // Now try to alter them through nefarious means
1141 $this->setupExtensionNamespaces();
1142 $this->setupHookNamespaces();
1144 // Should have no effect
1145 $this->assertSame( $this->getDefaultNamespaces(), $obj->getCanonicalNamespaces() );
1149 * @covers NamespaceInfo::getCanonicalName
1151 public function testGetCanonicalName_caching() {
1152 $obj = $this->newObj();
1154 // This should cache the values
1155 $obj->getCanonicalName( NS_MAIN
);
1157 // Now try to alter them through nefarious means
1158 $this->setupExtensionNamespaces();
1159 $this->setupHookNamespaces();
1161 // Should have no effect
1162 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
1163 $this->assertSame( 'Media', $obj->getCanonicalName( NS_MEDIA
) );
1164 $this->assertFalse( $obj->getCanonicalName( 12345 ) );
1165 $this->assertFalse( $obj->getCanonicalName( 123456 ) );
1169 * @covers NamespaceInfo::getCanonicalIndex
1171 public function testGetCanonicalIndex_caching() {
1172 $obj = $this->newObj();
1174 // This should cache the values
1175 $obj->getCanonicalIndex( '' );
1177 // Now try to alter them through nefarious means
1178 $this->setupExtensionNamespaces();
1179 $this->setupHookNamespaces();
1181 // Should have no effect
1182 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( '' ) );
1183 $this->assertSame( NS_MEDIA
, $obj->getCanonicalIndex( 'media' ) );
1184 $this->assertNull( $obj->getCanonicalIndex( 'extended' ) );
1185 $this->assertNull( $obj->getCanonicalIndex( 'hooked' ) );
1189 * @covers NamespaceInfo::getValidNamespaces
1191 public function testGetValidNamespaces_caching() {
1192 $obj = $this->newObj();
1194 // This should cache the values
1195 $obj->getValidNamespaces();
1197 // Now try to alter through nefarious means
1198 $this->setupExtensionNamespaces();
1199 $this->setupHookNamespaces();
1201 // Should have no effect
1203 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
],
1204 $obj->getValidNamespaces()
1208 // %} End canonical namespace caching
1214 * @dataProvider provideGetValidNamespaces_misc
1215 * @covers NamespaceInfo::getValidNamespaces
1217 * @param array $namespaces List of namespace indices to return from getCanonicalNamespaces()
1218 * (list is overwritten by a hook, so NS_MAIN doesn't have to be present)
1219 * @param array $expected
1221 public function testGetValidNamespaces_misc( array $namespaces, array $expected ) {
1222 // Each namespace's name is just its index
1223 $this->setTemporaryHook( 'CanonicalNamespaces',
1224 function ( &$canonicalNamespaces ) use ( $namespaces ) {
1225 $canonicalNamespaces = array_combine( $namespaces, $namespaces );
1228 $this->assertSame( $expected, $this->newObj()->getValidNamespaces() );
1231 public function provideGetValidNamespaces_misc() {
1233 'Out of order (T109137)' => [ [ 1, 0 ], [ 0, 1 ] ],
1234 'Alphabetical order' => [ [ 10, 2 ], [ 2, 10 ] ],
1235 'Negative' => [ [ -1000, -500, -2, 0 ], [ 0 ] ],
1239 // %} End miscellaneous
1240 // %} End canonical namespaces
1242 /**********************************************************************************************
1243 * Restriction levels
1248 * This mock user can only have isAllowed() called on it.
1250 * @param array $groups Groups for the mock user to have
1253 private function getMockUser( array $groups = [] ) : User
{
1256 $mock = $this->createMock( User
::class );
1257 $mock->method( 'isAllowed' )->will( $this->returnCallback(
1258 function ( $action ) use ( $groups ) {
1259 global $wgGroupPermissions, $wgRevokePermissions;
1260 if ( $action == '' ) {
1263 foreach ( $wgRevokePermissions as $group => $rights ) {
1264 if ( !in_array( $group, $groups ) ) {
1267 if ( isset( $rights[$action] ) && $rights[$action] ) {
1271 foreach ( $wgGroupPermissions as $group => $rights ) {
1272 if ( !in_array( $group, $groups ) ) {
1275 if ( isset( $rights[$action] ) && $rights[$action] ) {
1282 $mock->expects( $this->never() )->method( $this->anythingBut( 'isAllowed' ) );
1287 * @dataProvider provideGetRestrictionLevels
1288 * @covers NamespaceInfo::getRestrictionLevels
1290 * @param array $expected
1292 * @param User|null $user
1294 public function testGetRestrictionLevels( array $expected, $ns, User
$user = null ) {
1295 $this->setMwGlobals( [
1296 'wgGroupPermissions' => [
1297 '*' => [ 'edit' => true ],
1298 'autoconfirmed' => [ 'editsemiprotected' => true ],
1300 'editsemiprotected' => true,
1301 'editprotected' => true,
1303 'privileged' => [ 'privileged' => true ],
1305 'wgRevokePermissions' => [
1306 'noeditsemiprotected' => [ 'editsemiprotected' => true ],
1309 $obj = $this->newObj( [
1310 'NamespaceProtection' => [
1311 NS_MAIN
=> 'autoconfirmed',
1313 101 => [ 'editsemiprotected', 'privileged' ],
1316 $this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
1319 public function provideGetRestrictionLevels() {
1321 'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK
],
1322 'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN
],
1323 'Restricted to sysop' => [ [ '' ], NS_USER
],
1324 'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
1325 'No special permissions' => [ [ '' ], NS_TALK
, $this->getMockUser() ],
1326 'autoconfirmed' => [
1327 [ '', 'autoconfirmed' ],
1329 $this->getMockUser( [ 'autoconfirmed' ] )
1331 'autoconfirmed revoked' => [
1334 $this->getMockUser( [ 'autoconfirmed', 'noeditsemiprotected' ] )
1337 [ '', 'autoconfirmed', 'sysop' ],
1339 $this->getMockUser( [ 'sysop' ] )
1341 'sysop with autoconfirmed revoked (a bit silly)' => [
1344 $this->getMockUser( [ 'sysop', 'noeditsemiprotected' ] )
1349 // %} End restriction levels
1354 public function testAllServiceOptionsUsed() {
1355 $this->assertAllServiceOptionsUsed();
1360 * For really cool vim folding this needs to be at the end:
1361 * vim: foldmarker=%{,%} foldmethod=marker