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 'NamespacesWithSubpages' => [
62 'NonincludableNamespaces' => [],
65 private function newObj( array $options = [] ) : NamespaceInfo
{
66 return new NamespaceInfo( new LoggedServiceOptions(
67 self
::$serviceOptionsAccessLog,
68 NamespaceInfo
::$constructorOptions,
69 $options, self
::$defaultOptions
75 /**********************************************************************************************
81 * @covers NamespaceInfo::__construct
82 * @dataProvider provideConstructor
83 * @param ServiceOptions $options
84 * @param string|null $expectedExceptionText
86 public function testConstructor( ServiceOptions
$options, $expectedExceptionText = null ) {
87 if ( $expectedExceptionText !== null ) {
88 $this->setExpectedException( \Wikimedia\Assert\PreconditionException
::class,
89 $expectedExceptionText );
91 new NamespaceInfo( $options );
92 $this->assertTrue( true );
95 public function provideConstructor() {
97 [ new ServiceOptions( NamespaceInfo
::$constructorOptions, self
::$defaultOptions ) ],
98 [ new ServiceOptions( [], [] ), 'Required options missing: ' ],
100 array_merge( NamespaceInfo
::$constructorOptions, [ 'invalid' ] ),
101 self
::$defaultOptions,
103 ), 'Unsupported options passed: invalid' ],
108 * @dataProvider provideIsMovable
109 * @covers NamespaceInfo::isMovable
111 * @param bool $expected
113 * @param bool $allowImageMoving
115 public function testIsMovable( $expected, $ns, $allowImageMoving = true ) {
116 $obj = $this->newObj( [ 'AllowImageMoving' => $allowImageMoving ] );
117 $this->assertSame( $expected, $obj->isMovable( $ns ) );
120 public function provideIsMovable() {
122 'Main' => [ true, NS_MAIN
],
123 'Talk' => [ true, NS_TALK
],
124 'Special' => [ false, NS_SPECIAL
],
125 'Nonexistent even namespace' => [ true, 1234 ],
126 'Nonexistent odd namespace' => [ true, 12345 ],
128 'Media with image moving' => [ false, NS_MEDIA
, true ],
129 'Media with no image moving' => [ false, NS_MEDIA
, false ],
130 'File with image moving' => [ true, NS_FILE
, true ],
131 'File with no image moving' => [ false, NS_FILE
, false ],
137 * @param bool $expected
138 * @dataProvider provideIsSubject
139 * @covers NamespaceInfo::isSubject
141 public function testIsSubject( $ns, $expected ) {
142 $this->assertSame( $expected, $this->newObj()->isSubject( $ns ) );
147 * @param bool $expected
148 * @dataProvider provideIsSubject
149 * @covers NamespaceInfo::isTalk
151 public function testIsTalk( $ns, $expected ) {
152 $this->assertSame( !$expected, $this->newObj()->isTalk( $ns ) );
155 public function provideIsSubject() {
157 // Special namespaces
159 [ NS_SPECIAL
, true ],
168 [ NS_USER_TALK
, false ],
174 * @covers NamespaceInfo::exists
175 * @dataProvider provideExists
177 * @param bool $expected
179 public function testExists( $ns, $expected ) {
180 $this->assertSame( $expected, $this->newObj()->exists( $ns ) );
183 public function provideExists() {
185 'Main' => [ NS_MAIN
, true ],
186 'Talk' => [ NS_TALK
, true ],
187 'Media' => [ NS_MEDIA
, true ],
188 'Special' => [ NS_SPECIAL
, true ],
189 'Nonexistent' => [ 12345, false ],
190 'Negative nonexistent' => [ -12345, false ],
195 * Note if we add a namespace registration system with keys like 'MAIN'
196 * we should add tests here for equivalence on things like 'MAIN' == 0
197 * and 'MAIN' == NS_MAIN.
198 * @covers NamespaceInfo::equals
200 public function testEquals() {
201 $obj = $this->newObj();
202 $this->assertTrue( $obj->equals( NS_MAIN
, NS_MAIN
) );
203 $this->assertTrue( $obj->equals( NS_MAIN
, 0 ) ); // In case we make NS_MAIN 'MAIN'
204 $this->assertTrue( $obj->equals( NS_USER
, NS_USER
) );
205 $this->assertTrue( $obj->equals( NS_USER
, 2 ) );
206 $this->assertTrue( $obj->equals( NS_USER_TALK
, NS_USER_TALK
) );
207 $this->assertTrue( $obj->equals( NS_SPECIAL
, NS_SPECIAL
) );
208 $this->assertFalse( $obj->equals( NS_MAIN
, NS_TALK
) );
209 $this->assertFalse( $obj->equals( NS_USER
, NS_USER_TALK
) );
210 $this->assertFalse( $obj->equals( NS_PROJECT
, NS_TEMPLATE
) );
216 * @param bool $expected
217 * @dataProvider provideSubjectEquals
218 * @covers NamespaceInfo::subjectEquals
220 public function testSubjectEquals( $ns1, $ns2, $expected ) {
221 $this->assertSame( $expected, $this->newObj()->subjectEquals( $ns1, $ns2 ) );
224 public function provideSubjectEquals() {
226 [ NS_MAIN
, NS_MAIN
, true ],
227 // In case we make NS_MAIN 'MAIN'
228 [ NS_MAIN
, 0, true ],
229 [ NS_USER
, NS_USER
, true ],
230 [ NS_USER
, 2, true ],
231 [ NS_USER_TALK
, NS_USER_TALK
, true ],
232 [ NS_SPECIAL
, NS_SPECIAL
, true ],
233 [ NS_MAIN
, NS_TALK
, true ],
234 [ NS_USER
, NS_USER_TALK
, true ],
236 [ NS_PROJECT
, NS_TEMPLATE
, false ],
237 [ NS_SPECIAL
, NS_MAIN
, false ],
238 [ NS_MEDIA
, NS_SPECIAL
, false ],
239 [ NS_SPECIAL
, NS_MEDIA
, false ],
244 * @dataProvider provideHasTalkNamespace
245 * @covers NamespaceInfo::hasTalkNamespace
248 * @param bool $expected
250 public function testHasTalkNamespace( $ns, $expected ) {
251 $this->assertSame( $expected, $this->newObj()->hasTalkNamespace( $ns ) );
254 public function provideHasTalkNamespace() {
257 [ NS_SPECIAL
, false ],
262 [ NS_USER_TALK
, true ],
271 * @param bool $expected
272 * @param array $contentNamespaces
273 * @covers NamespaceInfo::isContent
274 * @dataProvider provideIsContent
276 public function testIsContent( $ns, $expected, $contentNamespaces = [ NS_MAIN
] ) {
277 $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
278 $this->assertSame( $expected, $obj->isContent( $ns ) );
281 public function provideIsContent() {
285 [ NS_SPECIAL
, false ],
288 [ NS_CATEGORY
, false ],
290 [ 100, true, [ NS_MAIN
, 100, 252 ] ],
291 [ 252, true, [ NS_MAIN
, 100, 252 ] ],
292 [ NS_MAIN
, true, [ NS_MAIN
, 100, 252 ] ],
293 // NS_MAIN is always content
294 [ NS_MAIN
, true, [] ],
299 * @dataProvider provideWantSignatures
300 * @covers NamespaceInfo::wantSignatures
303 * @param bool $expected
305 public function testWantSignatures( $index, $expected ) {
306 $this->assertSame( $expected, $this->newObj()->wantSignatures( $index ) );
309 public function provideWantSignatures() {
311 'Main' => [ NS_MAIN
, false ],
312 'Talk' => [ NS_TALK
, true ],
313 'User' => [ NS_USER
, false ],
314 'User talk' => [ NS_USER_TALK
, true ],
315 'Special' => [ NS_SPECIAL
, false ],
316 'Media' => [ NS_MEDIA
, false ],
317 'Nonexistent talk' => [ 12345, true ],
318 'Nonexistent subject' => [ 123456, false ],
319 'Nonexistent negative odd' => [ -12345, false ],
324 * @dataProvider provideWantSignatures_ExtraSignatureNamespaces
325 * @covers NamespaceInfo::wantSignatures
328 * @param int $expected
330 public function testWantSignatures_ExtraSignatureNamespaces( $index, $expected ) {
331 $obj = $this->newObj( [ 'ExtraSignatureNamespaces' =>
332 [ NS_MAIN
, NS_USER
, NS_SPECIAL
, NS_MEDIA
, 123456, -12345 ] ] );
333 $this->assertSame( $expected, $obj->wantSignatures( $index ) );
336 public function provideWantSignatures_ExtraSignatureNamespaces() {
339 // We've added all these as extra signature namespaces, so expect true
340 return [ $arr[0], true ];
342 self
::provideWantSignatures()
345 // Add one more that's false
346 $ret['Another nonexistent subject'] = [ 12345678, false ];
352 * @param bool $expected
353 * @covers NamespaceInfo::isWatchable
354 * @dataProvider provideIsWatchable
356 public function testIsWatchable( $ns, $expected ) {
357 $this->assertSame( $expected, $this->newObj()->isWatchable( $ns ) );
360 public function provideIsWatchable() {
362 // Specials namespaces are not watchable
364 [ NS_SPECIAL
, false ],
366 // Core defined namespaces are watchables
370 // Additional, user defined namespaces are watchables
378 * @param int $expected
379 * @param array|null $namespacesWithSubpages To pass to constructor
380 * @covers NamespaceInfo::hasSubpages
381 * @dataProvider provideHasSubpages
383 public function testHasSubpages( $ns, $expected, array $namespacesWithSubpages = null ) {
384 $obj = $this->newObj( $namespacesWithSubpages
385 ?
[ 'NamespacesWithSubpages' => $namespacesWithSubpages ]
387 $this->assertSame( $expected, $obj->hasSubpages( $ns ) );
390 public function provideHasSubpages() {
392 // Special namespaces:
394 [ NS_SPECIAL
, false ],
396 // Namespaces without subpages
398 [ NS_MAIN
, true, [ NS_MAIN
=> true ] ],
399 [ NS_MAIN
, false, [ NS_MAIN
=> false ] ],
401 // Some namespaces with subpages
404 [ NS_USER_TALK
, true ],
409 * @param mixed $contentNamespaces To pass to constructor
410 * @param array $expected
411 * @dataProvider provideGetContentNamespaces
412 * @covers NamespaceInfo::getContentNamespaces
414 public function testGetContentNamespaces( $contentNamespaces, array $expected ) {
415 $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
416 $this->assertSame( $expected, $obj->getContentNamespaces() );
419 public function provideGetContentNamespaces() {
423 [ false, [ NS_MAIN
] ],
424 [ null, [ NS_MAIN
] ],
430 // NS_MAIN is forced to be content even if unwanted
431 [ [ NS_USER
, NS_CATEGORY
], [ NS_MAIN
, NS_USER
, NS_CATEGORY
] ],
433 // In other cases, return as-is
434 [ [ NS_MAIN
], [ NS_MAIN
] ],
435 [ [ NS_MAIN
, NS_USER
, NS_CATEGORY
], [ NS_MAIN
, NS_USER
, NS_CATEGORY
] ],
440 * @covers NamespaceInfo::getSubjectNamespaces
442 public function testGetSubjectNamespaces() {
443 $subjectsNS = $this->newObj()->getSubjectNamespaces();
444 $this->assertContains( NS_MAIN
, $subjectsNS,
445 "Talk namespaces should have NS_MAIN" );
446 $this->assertNotContains( NS_TALK
, $subjectsNS,
447 "Talk namespaces should have NS_TALK" );
449 $this->assertNotContains( NS_MEDIA
, $subjectsNS,
450 "Talk namespaces should not have NS_MEDIA" );
451 $this->assertNotContains( NS_SPECIAL
, $subjectsNS,
452 "Talk namespaces should not have NS_SPECIAL" );
456 * @covers NamespaceInfo::getTalkNamespaces
458 public function testGetTalkNamespaces() {
459 $talkNS = $this->newObj()->getTalkNamespaces();
460 $this->assertContains( NS_TALK
, $talkNS,
461 "Subject namespaces should have NS_TALK" );
462 $this->assertNotContains( NS_MAIN
, $talkNS,
463 "Subject namespaces should not have NS_MAIN" );
465 $this->assertNotContains( NS_MEDIA
, $talkNS,
466 "Subject namespaces should not have NS_MEDIA" );
467 $this->assertNotContains( NS_SPECIAL
, $talkNS,
468 "Subject namespaces should not have NS_SPECIAL" );
473 * @param bool $expected
474 * @param bool $capitalLinks To pass to constructor
475 * @param array $capitalLinkOverrides To pass to constructor
476 * @dataProvider provideIsCapitalized
477 * @covers NamespaceInfo::isCapitalized
479 public function testIsCapitalized(
480 $ns, $expected, $capitalLinks = true, array $capitalLinkOverrides = []
482 $obj = $this->newObj( [
483 'CapitalLinks' => $capitalLinks,
484 'CapitalLinkOverrides' => $capitalLinkOverrides,
486 $this->assertSame( $expected, $obj->isCapitalized( $ns ) );
489 public function provideIsCapitalized() {
491 // Test default settings
492 [ NS_PROJECT
, true ],
493 [ NS_PROJECT_TALK
, true ],
497 // Always capitalized no matter what
498 [ NS_SPECIAL
, true, false ],
499 [ NS_USER
, true, false ],
500 [ NS_MEDIAWIKI
, true, false ],
502 // Even with an override too
503 [ NS_SPECIAL
, true, false, [ NS_SPECIAL
=> false ] ],
504 [ NS_USER
, true, false, [ NS_USER
=> false ] ],
505 [ NS_MEDIAWIKI
, true, false, [ NS_MEDIAWIKI
=> false ] ],
507 // Overrides work for other namespaces
508 [ NS_PROJECT
, false, true, [ NS_PROJECT
=> false ] ],
509 [ NS_PROJECT
, true, false, [ NS_PROJECT
=> true ] ],
511 // NS_MEDIA is treated like NS_FILE, and ignores NS_MEDIA overrides
512 [ NS_MEDIA
, false, true, [ NS_FILE
=> false, NS_MEDIA
=> true ] ],
513 [ NS_MEDIA
, true, false, [ NS_FILE
=> true, NS_MEDIA
=> false ] ],
514 [ NS_FILE
, false, true, [ NS_FILE
=> false, NS_MEDIA
=> true ] ],
515 [ NS_FILE
, true, false, [ NS_FILE
=> true, NS_MEDIA
=> false ] ],
520 * @covers NamespaceInfo::hasGenderDistinction
522 public function testHasGenderDistinction() {
523 $obj = $this->newObj();
525 // Namespaces with gender distinctions
526 $this->assertTrue( $obj->hasGenderDistinction( NS_USER
) );
527 $this->assertTrue( $obj->hasGenderDistinction( NS_USER_TALK
) );
529 // Other ones, "genderless"
530 $this->assertFalse( $obj->hasGenderDistinction( NS_MEDIA
) );
531 $this->assertFalse( $obj->hasGenderDistinction( NS_SPECIAL
) );
532 $this->assertFalse( $obj->hasGenderDistinction( NS_MAIN
) );
533 $this->assertFalse( $obj->hasGenderDistinction( NS_TALK
) );
537 * @covers NamespaceInfo::isNonincludable
539 public function testIsNonincludable() {
540 $obj = $this->newObj( [ 'NonincludableNamespaces' => [ NS_USER
] ] );
541 $this->assertTrue( $obj->isNonincludable( NS_USER
) );
542 $this->assertFalse( $obj->isNonincludable( NS_TEMPLATE
) );
546 * @dataProvider provideGetNamespaceContentModel
547 * @covers NamespaceInfo::getNamespaceContentModel
550 * @param string $expected
552 public function testGetNamespaceContentModel( $ns, $expected ) {
553 $obj = $this->newObj( [ 'NamespaceContentModels' =>
554 [ NS_USER
=> CONTENT_MODEL_WIKITEXT
, 123 => CONTENT_MODEL_JSON
, 1234 => 'abcdef' ],
556 $this->assertSame( $expected, $obj->getNamespaceContentModel( $ns ) );
559 public function provideGetNamespaceContentModel() {
563 [ NS_USER
, CONTENT_MODEL_WIKITEXT
],
564 [ NS_USER_TALK
, null ],
565 [ NS_SPECIAL
, null ],
567 [ 123, CONTENT_MODEL_JSON
],
574 * @dataProvider provideGetCategoryLinkType
575 * @covers NamespaceInfo::getCategoryLinkType
578 * @param string $expected
580 public function testGetCategoryLinkType( $ns, $expected ) {
581 $this->assertSame( $expected, $this->newObj()->getCategoryLinkType( $ns ) );
584 public function provideGetCategoryLinkType() {
589 [ NS_USER_TALK
, 'page' ],
592 [ NS_FILE_TALK
, 'page' ],
594 [ NS_CATEGORY
, 'subcat' ],
595 [ NS_CATEGORY_TALK
, 'page' ],
602 // %} End basic methods
604 /**********************************************************************************************
605 * getSubject/Talk/Associated
610 * @dataProvider provideSubjectTalk
611 * @covers NamespaceInfo::getSubject
612 * @covers NamespaceInfo::getSubjectPage
613 * @covers NamespaceInfo::isMethodValidFor
614 * @covers Title::getSubjectPage
616 * @param int $subject
619 public function testGetSubject( $subject, $talk ) {
620 $obj = $this->newObj();
621 $this->assertSame( $subject, $obj->getSubject( $subject ) );
622 $this->assertSame( $subject, $obj->getSubject( $talk ) );
624 $subjectTitleVal = new TitleValue( $subject, 'A' );
625 $talkTitleVal = new TitleValue( $talk, 'A' );
626 // Object will be the same one passed in if it's a subject, different but equal object if
628 $this->assertSame( $subjectTitleVal, $obj->getSubjectPage( $subjectTitleVal ) );
629 $this->assertEquals( $subjectTitleVal, $obj->getSubjectPage( $talkTitleVal ) );
631 $subjectTitle = Title
::makeTitle( $subject, 'A' );
632 $talkTitle = Title
::makeTitle( $talk, 'A' );
633 $this->assertSame( $subjectTitle, $subjectTitle->getSubjectPage() );
634 $this->assertEquals( $subjectTitle, $talkTitle->getSubjectPage() );
638 * @dataProvider provideSpecialNamespaces
639 * @covers NamespaceInfo::getSubject
640 * @covers NamespaceInfo::getSubjectPage
644 public function testGetSubject_special( $ns ) {
645 $obj = $this->newObj();
646 $this->assertSame( $ns, $obj->getSubject( $ns ) );
648 $title = new TitleValue( $ns, 'A' );
649 $this->assertSame( $title, $obj->getSubjectPage( $title ) );
653 * @dataProvider provideSubjectTalk
654 * @covers NamespaceInfo::getTalk
655 * @covers NamespaceInfo::getTalkPage
656 * @covers NamespaceInfo::isMethodValidFor
657 * @covers Title::getTalkPage
659 * @param int $subject
662 public function testGetTalk( $subject, $talk ) {
663 $obj = $this->newObj();
664 $this->assertSame( $talk, $obj->getTalk( $subject ) );
665 $this->assertSame( $talk, $obj->getTalk( $talk ) );
667 $subjectTitleVal = new TitleValue( $subject, 'A' );
668 $talkTitleVal = new TitleValue( $talk, 'A' );
669 // Object will be the same one passed in if it's a talk, different but equal object if it's
671 $this->assertEquals( $talkTitleVal, $obj->getTalkPage( $subjectTitleVal ) );
672 $this->assertSame( $talkTitleVal, $obj->getTalkPage( $talkTitleVal ) );
674 $subjectTitle = Title
::makeTitle( $subject, 'A' );
675 $talkTitle = Title
::makeTitle( $talk, 'A' );
676 $this->assertEquals( $talkTitle, $subjectTitle->getTalkPage() );
677 $this->assertSame( $talkTitle, $talkTitle->getTalkPage() );
681 * @dataProvider provideSpecialNamespaces
682 * @covers NamespaceInfo::getTalk
683 * @covers NamespaceInfo::isMethodValidFor
687 public function testGetTalk_special( $ns ) {
688 $this->setExpectedException( MWException
::class,
689 "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
690 $this->newObj()->getTalk( $ns );
694 * @dataProvider provideSpecialNamespaces
695 * @covers NamespaceInfo::getAssociated
696 * @covers NamespaceInfo::isMethodValidFor
700 public function testGetAssociated_special( $ns ) {
701 $this->setExpectedException(
703 "NamespaceInfo::getAssociated does not make any sense for given namespace $ns"
705 $this->newObj()->getAssociated( $ns );
708 public static function provideCanHaveTalkPage() {
710 [ new TitleValue( NS_MAIN
, 'Test' ), true ],
711 [ new TitleValue( NS_TALK
, 'Test' ), true ],
712 [ new TitleValue( NS_USER
, 'Test' ), true ],
713 [ new TitleValue( NS_SPECIAL
, 'Test' ), false ],
714 [ new TitleValue( NS_MEDIA
, 'Test' ), false ],
715 [ new TitleValue( NS_MAIN
, '', 'Kittens' ), false ],
716 [ new TitleValue( NS_MAIN
, 'Kittens', '', 'acme' ), false ],
721 * @dataProvider provideCanHaveTalkPage
722 * @covers NamespaceInfo::canHaveTalkPage
724 public function testCanHaveTalkPage( LinkTarget
$t, $expected ) {
725 $actual = $this->newObj()->canHaveTalkPage( $t );
726 $this->assertEquals( $expected, $actual, $t->getDBkey() );
729 public static function provideGetTalkPage_good() {
731 [ new TitleValue( NS_MAIN
, 'Test' ), new TitleValue( NS_TALK
, 'Test' ) ],
732 [ new TitleValue( NS_TALK
, 'Test' ), new TitleValue( NS_TALK
, 'Test' ) ],
733 [ new TitleValue( NS_USER
, 'Test' ), new TitleValue( NS_USER_TALK
, 'Test' ) ],
738 * @dataProvider provideGetTalkPage_good
739 * @covers NamespaceInfo::getTalk
740 * @covers NamespaceInfo::getTalkPage
741 * @covers NamespaceInfo::isMethodValidFor
743 public function testGetTalkPage_good( LinkTarget
$t, LinkTarget
$expected ) {
744 $actual = $this->newObj()->getTalkPage( $t );
745 $this->assertEquals( $expected, $actual, $t->getDBkey() );
748 public static function provideGetTalkPage_bad() {
750 [ new TitleValue( NS_SPECIAL
, 'Test' ) ],
751 [ new TitleValue( NS_MEDIA
, 'Test' ) ],
752 [ new TitleValue( NS_MAIN
, '', 'Kittens' ) ],
753 [ new TitleValue( NS_MAIN
, 'Kittens', '', 'acme' ) ],
758 * @dataProvider provideGetTalkPage_bad
759 * @covers NamespaceInfo::getTalk
760 * @covers NamespaceInfo::getTalkPage
761 * @covers NamespaceInfo::isMethodValidFor
763 public function testGetTalkPage_bad( LinkTarget
$t ) {
764 $this->setExpectedException( MWException
::class );
765 $this->newObj()->getTalkPage( $t );
769 * @dataProvider provideGetTalkPage_bad
770 * @covers NamespaceInfo::getAssociated
771 * @covers NamespaceInfo::getAssociatedPage
772 * @covers NamespaceInfo::isMethodValidFor
774 public function testGetAssociatedPage_bad( LinkTarget
$t ) {
775 $this->setExpectedException( MWException
::class );
776 $this->newObj()->getAssociatedPage( $t );
780 * @dataProvider provideSubjectTalk
781 * @covers NamespaceInfo::getAssociated
782 * @covers NamespaceInfo::getAssociatedPage
783 * @covers Title::getOtherPage
785 * @param int $subject
788 public function testGetAssociated( $subject, $talk ) {
789 $obj = $this->newObj();
790 $this->assertSame( $talk, $obj->getAssociated( $subject ) );
791 $this->assertSame( $subject, $obj->getAssociated( $talk ) );
793 $subjectTitle = new TitleValue( $subject, 'A' );
794 $talkTitle = new TitleValue( $talk, 'A' );
795 // Object will not be the same
796 $this->assertEquals( $talkTitle, $obj->getAssociatedPage( $subjectTitle ) );
797 $this->assertEquals( $subjectTitle, $obj->getAssociatedPage( $talkTitle ) );
799 $subjectTitle = Title
::makeTitle( $subject, 'A' );
800 $talkTitle = Title
::makeTitle( $talk, 'A' );
801 $this->assertEquals( $talkTitle, $subjectTitle->getOtherPage() );
802 $this->assertEquals( $subjectTitle, $talkTitle->getOtherPage() );
805 public static function provideSubjectTalk() {
807 // Format: [ subject, talk ]
808 'Main/talk' => [ NS_MAIN
, NS_TALK
],
809 'User/user talk' => [ NS_USER
, NS_USER_TALK
],
810 'Unknown namespaces also supported' => [ 106, 107 ],
814 public static function provideSpecialNamespaces() {
816 'Special' => [ NS_SPECIAL
],
817 'Media' => [ NS_MEDIA
],
818 'Unknown negative index' => [ -613 ],
822 // %} End getSubject/Talk/Associated
824 /**********************************************************************************************
825 * Canonical namespaces
829 // Default canonical namespaces
831 private function getDefaultNamespaces() {
832 return [ NS_MAIN
=> '' ] + self
::$defaultOptions['CanonicalNamespaceNames'];
836 * @covers NamespaceInfo::getCanonicalNamespaces
838 public function testGetCanonicalNamespaces() {
840 $this->getDefaultNamespaces(),
841 $this->newObj()->getCanonicalNamespaces()
846 * @dataProvider provideGetCanonicalName
847 * @covers NamespaceInfo::getCanonicalName
850 * @param string|bool $expected
852 public function testGetCanonicalName( $index, $expected ) {
853 $this->assertSame( $expected, $this->newObj()->getCanonicalName( $index ) );
856 public function provideGetCanonicalName() {
858 'Main' => [ NS_MAIN
, '' ],
859 'Talk' => [ NS_TALK
, 'Talk' ],
860 'With underscore not space' => [ NS_USER_TALK
, 'User_talk' ],
861 'Special' => [ NS_SPECIAL
, 'Special' ],
862 'Nonexistent' => [ 12345, false ],
863 'Nonexistent negative' => [ -12345, false ],
868 * @dataProvider provideGetCanonicalIndex
869 * @covers NamespaceInfo::getCanonicalIndex
871 * @param string $name
872 * @param int|null $expected
874 public function testGetCanonicalIndex( $name, $expected ) {
875 $this->assertSame( $expected, $this->newObj()->getCanonicalIndex( $name ) );
878 public function provideGetCanonicalIndex() {
880 'Main' => [ '', NS_MAIN
],
881 'Talk' => [ 'talk', NS_TALK
],
882 'Not lowercase' => [ 'Talk', null ],
883 'With underscore' => [ 'user_talk', NS_USER_TALK
],
884 'Space is not recognized for underscore' => [ 'user talk', null ],
885 '0' => [ '0', null ],
890 * @covers NamespaceInfo::getValidNamespaces
892 public function testGetValidNamespaces() {
894 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
],
895 $this->newObj()->getValidNamespaces()
899 // %} End default canonical namespaces
901 // No canonical namespace names
905 * @covers NamespaceInfo::getCanonicalNamespaces
907 public function testGetCanonicalNamespaces_NoCanonicalNamespaceNames() {
908 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
910 $this->assertSame( [ NS_MAIN
=> '' ], $obj->getCanonicalNamespaces() );
914 * @covers NamespaceInfo::getCanonicalName
916 public function testGetCanonicalName_NoCanonicalNamespaceNames() {
917 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
919 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
920 $this->assertFalse( $obj->getCanonicalName( NS_TALK
) );
924 * @covers NamespaceInfo::getCanonicalIndex
926 public function testGetCanonicalIndex_NoCanonicalNamespaceNames() {
927 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
929 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( '' ) );
930 $this->assertNull( $obj->getCanonicalIndex( 'talk' ) );
934 * @covers NamespaceInfo::getValidNamespaces
936 public function testGetValidNamespaces_NoCanonicalNamespaceNames() {
937 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
939 $this->assertSame( [ NS_MAIN
], $obj->getValidNamespaces() );
942 // %} End no canonical namespace names
944 // Test extension namespaces
946 private function setupExtensionNamespaces() {
947 $this->scopedCallback
= null;
948 $this->scopedCallback
= ExtensionRegistry
::getInstance()->setAttributeForTest(
949 'ExtensionNamespaces',
950 [ NS_MAIN
=> 'No effect', NS_TALK
=> 'No effect', 12345 => 'Extended' ]
955 * @covers NamespaceInfo::getCanonicalNamespaces
957 public function testGetCanonicalNamespaces_ExtensionNamespaces() {
958 $this->setupExtensionNamespaces();
961 $this->getDefaultNamespaces() +
[ 12345 => 'Extended' ],
962 $this->newObj()->getCanonicalNamespaces()
967 * @covers NamespaceInfo::getCanonicalName
969 public function testGetCanonicalName_ExtensionNamespaces() {
970 $this->setupExtensionNamespaces();
971 $obj = $this->newObj();
973 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
974 $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK
) );
975 $this->assertSame( 'Extended', $obj->getCanonicalName( 12345 ) );
979 * @covers NamespaceInfo::getCanonicalIndex
981 public function testGetCanonicalIndex_ExtensionNamespaces() {
982 $this->setupExtensionNamespaces();
983 $obj = $this->newObj();
985 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( '' ) );
986 $this->assertSame( NS_TALK
, $obj->getCanonicalIndex( 'talk' ) );
987 $this->assertSame( 12345, $obj->getCanonicalIndex( 'extended' ) );
991 * @covers NamespaceInfo::getValidNamespaces
993 public function testGetValidNamespaces_ExtensionNamespaces() {
994 $this->setupExtensionNamespaces();
997 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
, 12345 ],
998 $this->newObj()->getValidNamespaces()
1002 // %} End extension namespaces
1008 * @return array Expected canonical namespaces
1010 private function setupHookNamespaces() {
1012 function ( &$canonicalNamespaces ) {
1013 $canonicalNamespaces[NS_MAIN
] = 'Main';
1014 unset( $canonicalNamespaces[NS_MEDIA
] );
1015 $canonicalNamespaces[123456] = 'Hooked';
1017 $this->setTemporaryHook( 'CanonicalNamespaces', $callback );
1018 $expected = $this->getDefaultNamespaces();
1019 ( $callback )( $expected );
1024 * @covers NamespaceInfo::getCanonicalNamespaces
1026 public function testGetCanonicalNamespaces_HookNamespaces() {
1027 $expected = $this->setupHookNamespaces();
1029 $this->assertSame( $expected, $this->newObj()->getCanonicalNamespaces() );
1033 * @covers NamespaceInfo::getCanonicalName
1035 public function testGetCanonicalName_HookNamespaces() {
1036 $this->setupHookNamespaces();
1037 $obj = $this->newObj();
1039 $this->assertSame( 'Main', $obj->getCanonicalName( NS_MAIN
) );
1040 $this->assertFalse( $obj->getCanonicalName( NS_MEDIA
) );
1041 $this->assertSame( 'Hooked', $obj->getCanonicalName( 123456 ) );
1045 * @covers NamespaceInfo::getCanonicalIndex
1047 public function testGetCanonicalIndex_HookNamespaces() {
1048 $this->setupHookNamespaces();
1049 $obj = $this->newObj();
1051 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( 'main' ) );
1052 $this->assertNull( $obj->getCanonicalIndex( 'media' ) );
1053 $this->assertSame( 123456, $obj->getCanonicalIndex( 'hooked' ) );
1057 * @covers NamespaceInfo::getValidNamespaces
1059 public function testGetValidNamespaces_HookNamespaces() {
1060 $this->setupHookNamespaces();
1063 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
, 123456 ],
1064 $this->newObj()->getValidNamespaces()
1068 // %} End hook namespaces
1074 * @return NamespaceInfo
1076 private function setupExtraNamespaces() {
1077 return $this->newObj( [ 'ExtraNamespaces' =>
1078 [ NS_MAIN
=> 'No effect', NS_TALK
=> 'No effect', 1234567 => 'Extra' ]
1083 * @covers NamespaceInfo::getCanonicalNamespaces
1085 public function testGetCanonicalNamespaces_ExtraNamespaces() {
1087 $this->getDefaultNamespaces() +
[ 1234567 => 'Extra' ],
1088 $this->setupExtraNamespaces()->getCanonicalNamespaces()
1093 * @covers NamespaceInfo::getCanonicalName
1095 public function testGetCanonicalName_ExtraNamespaces() {
1096 $obj = $this->setupExtraNamespaces();
1098 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
1099 $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK
) );
1100 $this->assertSame( 'Extra', $obj->getCanonicalName( 1234567 ) );
1104 * @covers NamespaceInfo::getCanonicalIndex
1106 public function testGetCanonicalIndex_ExtraNamespaces() {
1107 $obj = $this->setupExtraNamespaces();
1109 $this->assertNull( $obj->getCanonicalIndex( 'no effect' ) );
1110 $this->assertNull( $obj->getCanonicalIndex( 'no_effect' ) );
1111 $this->assertSame( 1234567, $obj->getCanonicalIndex( 'extra' ) );
1115 * @covers NamespaceInfo::getValidNamespaces
1117 public function testGetValidNamespaces_ExtraNamespaces() {
1119 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
, 1234567 ],
1120 $this->setupExtraNamespaces()->getValidNamespaces()
1124 // %} End extra namespaces
1126 // Canonical namespace caching
1130 * @covers NamespaceInfo::getCanonicalNamespaces
1132 public function testGetCanonicalNamespaces_caching() {
1133 $obj = $this->newObj();
1135 // This should cache the values
1136 $obj->getCanonicalNamespaces();
1138 // Now try to alter them through nefarious means
1139 $this->setupExtensionNamespaces();
1140 $this->setupHookNamespaces();
1142 // Should have no effect
1143 $this->assertSame( $this->getDefaultNamespaces(), $obj->getCanonicalNamespaces() );
1147 * @covers NamespaceInfo::getCanonicalName
1149 public function testGetCanonicalName_caching() {
1150 $obj = $this->newObj();
1152 // This should cache the values
1153 $obj->getCanonicalName( NS_MAIN
);
1155 // Now try to alter them through nefarious means
1156 $this->setupExtensionNamespaces();
1157 $this->setupHookNamespaces();
1159 // Should have no effect
1160 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN
) );
1161 $this->assertSame( 'Media', $obj->getCanonicalName( NS_MEDIA
) );
1162 $this->assertFalse( $obj->getCanonicalName( 12345 ) );
1163 $this->assertFalse( $obj->getCanonicalName( 123456 ) );
1167 * @covers NamespaceInfo::getCanonicalIndex
1169 public function testGetCanonicalIndex_caching() {
1170 $obj = $this->newObj();
1172 // This should cache the values
1173 $obj->getCanonicalIndex( '' );
1175 // Now try to alter them through nefarious means
1176 $this->setupExtensionNamespaces();
1177 $this->setupHookNamespaces();
1179 // Should have no effect
1180 $this->assertSame( NS_MAIN
, $obj->getCanonicalIndex( '' ) );
1181 $this->assertSame( NS_MEDIA
, $obj->getCanonicalIndex( 'media' ) );
1182 $this->assertNull( $obj->getCanonicalIndex( 'extended' ) );
1183 $this->assertNull( $obj->getCanonicalIndex( 'hooked' ) );
1187 * @covers NamespaceInfo::getValidNamespaces
1189 public function testGetValidNamespaces_caching() {
1190 $obj = $this->newObj();
1192 // This should cache the values
1193 $obj->getValidNamespaces();
1195 // Now try to alter through nefarious means
1196 $this->setupExtensionNamespaces();
1197 $this->setupHookNamespaces();
1199 // Should have no effect
1201 [ NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
],
1202 $obj->getValidNamespaces()
1206 // %} End canonical namespace caching
1212 * @dataProvider provideGetValidNamespaces_misc
1213 * @covers NamespaceInfo::getValidNamespaces
1215 * @param array $namespaces List of namespace indices to return from getCanonicalNamespaces()
1216 * (list is overwritten by a hook, so NS_MAIN doesn't have to be present)
1217 * @param array $expected
1219 public function testGetValidNamespaces_misc( array $namespaces, array $expected ) {
1220 // Each namespace's name is just its index
1221 $this->setTemporaryHook( 'CanonicalNamespaces',
1222 function ( &$canonicalNamespaces ) use ( $namespaces ) {
1223 $canonicalNamespaces = array_combine( $namespaces, $namespaces );
1226 $this->assertSame( $expected, $this->newObj()->getValidNamespaces() );
1229 public function provideGetValidNamespaces_misc() {
1231 'Out of order (T109137)' => [ [ 1, 0 ], [ 0, 1 ] ],
1232 'Alphabetical order' => [ [ 10, 2 ], [ 2, 10 ] ],
1233 'Negative' => [ [ -1000, -500, -2, 0 ], [ 0 ] ],
1237 // %} End miscellaneous
1238 // %} End canonical namespaces
1240 /**********************************************************************************************
1241 * Restriction levels
1246 * TODO: This is superceeded by PermissionManagerTest::testGetNamespaceRestrictionLevels
1247 * Remove when deprecated method is removed.
1248 * @dataProvider provideGetRestrictionLevels
1249 * @covers NamespaceInfo::getRestrictionLevels
1251 * @param array $expected
1253 * @param array|null $groups
1254 * @throws MWException
1256 public function testGetRestrictionLevels( array $expected, $ns, array $groups = null ) {
1257 $this->setMwGlobals( [
1258 'wgGroupPermissions' => [
1259 '*' => [ 'edit' => true ],
1260 'autoconfirmed' => [ 'editsemiprotected' => true ],
1262 'editsemiprotected' => true,
1263 'editprotected' => true,
1265 'privileged' => [ 'privileged' => true ],
1267 'wgRevokePermissions' => [
1268 'noeditsemiprotected' => [ 'editsemiprotected' => true ],
1270 'wgNamespaceProtection' => [
1271 NS_MAIN
=> 'autoconfirmed',
1273 101 => [ 'editsemiprotected', 'privileged' ],
1275 'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
1276 'wgAutopromote' => []
1278 $obj = $this->newObj();
1279 $user = is_null( $groups ) ?
null : $this->getTestUser( $groups )->getUser();
1280 $this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
1283 public function provideGetRestrictionLevels() {
1285 'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK
],
1286 'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN
],
1287 'Restricted to sysop' => [ [ '' ], NS_USER
],
1288 'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
1289 'No special permissions' => [ [ '' ], NS_TALK
, [] ],
1290 'autoconfirmed' => [
1291 [ '', 'autoconfirmed' ],
1295 'autoconfirmed revoked' => [
1298 [ 'autoconfirmed', 'noeditsemiprotected' ]
1301 [ '', 'autoconfirmed', 'sysop' ],
1305 'sysop with autoconfirmed revoked (a bit silly)' => [
1308 [ 'sysop', 'noeditsemiprotected' ]
1313 // %} End restriction levels
1318 public function testAllServiceOptionsUsed() {
1319 $this->assertAllServiceOptionsUsed();
1324 * For really cool vim folding this needs to be at the end:
1325 * vim: foldmarker=%{,%} foldmethod=marker