wiki.techinc.nl/tests/phpunit/includes/title/NamespaceInfoTest.php
Daimona Eaytoy 8545ce131a Kill the remaining usages of PHPUnit4And6Compat methods
Bug: T192167
Change-Id: I1ea19e9b53683b7d32ff9836990ee73ab3e11104
2019-10-06 10:12:54 +00:00

1325 lines
37 KiB
PHP

<?php
/**
* @author Antoine Musso
* @copyright Copyright © 2011, Antoine Musso
* @file
*/
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Linker\LinkTarget;
class NamespaceInfoTest extends MediaWikiTestCase {
use TestAllServiceOptionsUsed;
/**********************************************************************************************
* Shared code
* %{
*/
private $scopedCallback;
public function setUp() {
parent::setUp();
// Boo, there's still some global state in the class :(
global $wgHooks;
$hooks = $wgHooks;
unset( $hooks['CanonicalNamespaces'] );
$this->setMwGlobals( 'wgHooks', $hooks );
$this->scopedCallback =
ExtensionRegistry::getInstance()->setAttributeForTest( 'ExtensionNamespaces', [] );
}
public function tearDown() {
$this->scopedCallback = null;
parent::tearDown();
}
private const DEFAULT_OPTIONS = [
'AllowImageMoving' => true,
'CanonicalNamespaceNames' => [
NS_TALK => 'Talk',
NS_USER => 'User',
NS_USER_TALK => 'User_talk',
NS_SPECIAL => 'Special',
NS_MEDIA => 'Media',
],
'CapitalLinkOverrides' => [],
'CapitalLinks' => true,
'ContentNamespaces' => [ NS_MAIN ],
'ExtraNamespaces' => [],
'ExtraSignatureNamespaces' => [],
'NamespaceContentModels' => [],
'NamespacesWithSubpages' => [
NS_TALK => true,
NS_USER => true,
NS_USER_TALK => true,
],
'NonincludableNamespaces' => [],
];
private function newObj( array $options = [] ) : NamespaceInfo {
return new NamespaceInfo( new LoggedServiceOptions(
self::$serviceOptionsAccessLog,
NamespaceInfo::CONSTRUCTOR_OPTIONS,
$options, self::DEFAULT_OPTIONS
) );
}
// %} End shared code
/**********************************************************************************************
* Basic methods
* %{
*/
/**
* @covers NamespaceInfo::__construct
* @dataProvider provideConstructor
* @param ServiceOptions $options
* @param string|null $expectedExceptionText
*/
public function testConstructor( ServiceOptions $options, $expectedExceptionText = null ) {
if ( $expectedExceptionText !== null ) {
$this->expectException( \Wikimedia\Assert\PreconditionException::class );
$this->expectExceptionMessage( $expectedExceptionText );
}
new NamespaceInfo( $options );
$this->assertTrue( true );
}
public function provideConstructor() {
return [
[ new ServiceOptions( NamespaceInfo::CONSTRUCTOR_OPTIONS, self::DEFAULT_OPTIONS ) ],
[ new ServiceOptions( [], [] ), 'Required options missing: ' ],
[ new ServiceOptions(
array_merge( NamespaceInfo::CONSTRUCTOR_OPTIONS, [ 'invalid' ] ),
self::DEFAULT_OPTIONS,
[ 'invalid' => '' ]
), 'Unsupported options passed: invalid' ],
];
}
/**
* @dataProvider provideIsMovable
* @covers NamespaceInfo::isMovable
*
* @param bool $expected
* @param int $ns
* @param bool $allowImageMoving
*/
public function testIsMovable( $expected, $ns, $allowImageMoving = true ) {
$obj = $this->newObj( [ 'AllowImageMoving' => $allowImageMoving ] );
$this->assertSame( $expected, $obj->isMovable( $ns ) );
}
public function provideIsMovable() {
return [
'Main' => [ true, NS_MAIN ],
'Talk' => [ true, NS_TALK ],
'Special' => [ false, NS_SPECIAL ],
'Nonexistent even namespace' => [ true, 1234 ],
'Nonexistent odd namespace' => [ true, 12345 ],
'Media with image moving' => [ false, NS_MEDIA, true ],
'Media with no image moving' => [ false, NS_MEDIA, false ],
'File with image moving' => [ true, NS_FILE, true ],
'File with no image moving' => [ false, NS_FILE, false ],
];
}
/**
* @param int $ns
* @param bool $expected
* @dataProvider provideIsSubject
* @covers NamespaceInfo::isSubject
*/
public function testIsSubject( $ns, $expected ) {
$this->assertSame( $expected, $this->newObj()->isSubject( $ns ) );
}
/**
* @param int $ns
* @param bool $expected
* @dataProvider provideIsSubject
* @covers NamespaceInfo::isTalk
*/
public function testIsTalk( $ns, $expected ) {
$this->assertSame( !$expected, $this->newObj()->isTalk( $ns ) );
}
public function provideIsSubject() {
return [
// Special namespaces
[ NS_MEDIA, true ],
[ NS_SPECIAL, true ],
// Subject pages
[ NS_MAIN, true ],
[ NS_USER, true ],
[ 100, true ],
// Talk pages
[ NS_TALK, false ],
[ NS_USER_TALK, false ],
[ 101, false ],
];
}
/**
* @covers NamespaceInfo::exists
* @dataProvider provideExists
* @param int $ns
* @param bool $expected
*/
public function testExists( $ns, $expected ) {
$this->assertSame( $expected, $this->newObj()->exists( $ns ) );
}
public function provideExists() {
return [
'Main' => [ NS_MAIN, true ],
'Talk' => [ NS_TALK, true ],
'Media' => [ NS_MEDIA, true ],
'Special' => [ NS_SPECIAL, true ],
'Nonexistent' => [ 12345, false ],
'Negative nonexistent' => [ -12345, false ],
];
}
/**
* Note if we add a namespace registration system with keys like 'MAIN'
* we should add tests here for equivalence on things like 'MAIN' == 0
* and 'MAIN' == NS_MAIN.
* @covers NamespaceInfo::equals
*/
public function testEquals() {
$obj = $this->newObj();
$this->assertTrue( $obj->equals( NS_MAIN, NS_MAIN ) );
$this->assertTrue( $obj->equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN'
$this->assertTrue( $obj->equals( NS_USER, NS_USER ) );
$this->assertTrue( $obj->equals( NS_USER, 2 ) );
$this->assertTrue( $obj->equals( NS_USER_TALK, NS_USER_TALK ) );
$this->assertTrue( $obj->equals( NS_SPECIAL, NS_SPECIAL ) );
$this->assertFalse( $obj->equals( NS_MAIN, NS_TALK ) );
$this->assertFalse( $obj->equals( NS_USER, NS_USER_TALK ) );
$this->assertFalse( $obj->equals( NS_PROJECT, NS_TEMPLATE ) );
}
/**
* @param int $ns1
* @param int $ns2
* @param bool $expected
* @dataProvider provideSubjectEquals
* @covers NamespaceInfo::subjectEquals
*/
public function testSubjectEquals( $ns1, $ns2, $expected ) {
$this->assertSame( $expected, $this->newObj()->subjectEquals( $ns1, $ns2 ) );
}
public function provideSubjectEquals() {
return [
[ NS_MAIN, NS_MAIN, true ],
// In case we make NS_MAIN 'MAIN'
[ NS_MAIN, 0, true ],
[ NS_USER, NS_USER, true ],
[ NS_USER, 2, true ],
[ NS_USER_TALK, NS_USER_TALK, true ],
[ NS_SPECIAL, NS_SPECIAL, true ],
[ NS_MAIN, NS_TALK, true ],
[ NS_USER, NS_USER_TALK, true ],
[ NS_PROJECT, NS_TEMPLATE, false ],
[ NS_SPECIAL, NS_MAIN, false ],
[ NS_MEDIA, NS_SPECIAL, false ],
[ NS_SPECIAL, NS_MEDIA, false ],
];
}
/**
* @dataProvider provideHasTalkNamespace
* @covers NamespaceInfo::hasTalkNamespace
*
* @param int $ns
* @param bool $expected
*/
public function testHasTalkNamespace( $ns, $expected ) {
$this->assertSame( $expected, $this->newObj()->hasTalkNamespace( $ns ) );
}
public function provideHasTalkNamespace() {
return [
[ NS_MEDIA, false ],
[ NS_SPECIAL, false ],
[ NS_MAIN, true ],
[ NS_TALK, true ],
[ NS_USER, true ],
[ NS_USER_TALK, true ],
[ 100, true ],
[ 101, true ],
];
}
/**
* @param int $ns
* @param bool $expected
* @param array $contentNamespaces
* @covers NamespaceInfo::isContent
* @dataProvider provideIsContent
*/
public function testIsContent( $ns, $expected, $contentNamespaces = [ NS_MAIN ] ) {
$obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
$this->assertSame( $expected, $obj->isContent( $ns ) );
}
public function provideIsContent() {
return [
[ NS_MAIN, true ],
[ NS_MEDIA, false ],
[ NS_SPECIAL, false ],
[ NS_TALK, false ],
[ NS_USER, false ],
[ NS_CATEGORY, false ],
[ 100, false ],
[ 100, true, [ NS_MAIN, 100, 252 ] ],
[ 252, true, [ NS_MAIN, 100, 252 ] ],
[ NS_MAIN, true, [ NS_MAIN, 100, 252 ] ],
// NS_MAIN is always content
[ NS_MAIN, true, [] ],
];
}
/**
* @dataProvider provideWantSignatures
* @covers NamespaceInfo::wantSignatures
*
* @param int $index
* @param bool $expected
*/
public function testWantSignatures( $index, $expected ) {
$this->assertSame( $expected, $this->newObj()->wantSignatures( $index ) );
}
public function provideWantSignatures() {
return [
'Main' => [ NS_MAIN, false ],
'Talk' => [ NS_TALK, true ],
'User' => [ NS_USER, false ],
'User talk' => [ NS_USER_TALK, true ],
'Special' => [ NS_SPECIAL, false ],
'Media' => [ NS_MEDIA, false ],
'Nonexistent talk' => [ 12345, true ],
'Nonexistent subject' => [ 123456, false ],
'Nonexistent negative odd' => [ -12345, false ],
];
}
/**
* @dataProvider provideWantSignatures_ExtraSignatureNamespaces
* @covers NamespaceInfo::wantSignatures
*
* @param int $index
* @param int $expected
*/
public function testWantSignatures_ExtraSignatureNamespaces( $index, $expected ) {
$obj = $this->newObj( [ 'ExtraSignatureNamespaces' =>
[ NS_MAIN, NS_USER, NS_SPECIAL, NS_MEDIA, 123456, -12345 ] ] );
$this->assertSame( $expected, $obj->wantSignatures( $index ) );
}
public function provideWantSignatures_ExtraSignatureNamespaces() {
$ret = array_map(
function ( $arr ) {
// We've added all these as extra signature namespaces, so expect true
return [ $arr[0], true ];
},
self::provideWantSignatures()
);
// Add one more that's false
$ret['Another nonexistent subject'] = [ 12345678, false ];
return $ret;
}
/**
* @param int $ns
* @param bool $expected
* @covers NamespaceInfo::isWatchable
* @dataProvider provideIsWatchable
*/
public function testIsWatchable( $ns, $expected ) {
$this->assertSame( $expected, $this->newObj()->isWatchable( $ns ) );
}
public function provideIsWatchable() {
return [
// Specials namespaces are not watchable
[ NS_MEDIA, false ],
[ NS_SPECIAL, false ],
// Core defined namespaces are watchables
[ NS_MAIN, true ],
[ NS_TALK, true ],
// Additional, user defined namespaces are watchables
[ 100, true ],
[ 101, true ],
];
}
/**
* @param int $ns
* @param int $expected
* @param array|null $namespacesWithSubpages To pass to constructor
* @covers NamespaceInfo::hasSubpages
* @dataProvider provideHasSubpages
*/
public function testHasSubpages( $ns, $expected, array $namespacesWithSubpages = null ) {
$obj = $this->newObj( $namespacesWithSubpages
? [ 'NamespacesWithSubpages' => $namespacesWithSubpages ]
: [] );
$this->assertSame( $expected, $obj->hasSubpages( $ns ) );
}
public function provideHasSubpages() {
return [
// Special namespaces:
[ NS_MEDIA, false ],
[ NS_SPECIAL, false ],
// Namespaces without subpages
[ NS_MAIN, false ],
[ NS_MAIN, true, [ NS_MAIN => true ] ],
[ NS_MAIN, false, [ NS_MAIN => false ] ],
// Some namespaces with subpages
[ NS_TALK, true ],
[ NS_USER, true ],
[ NS_USER_TALK, true ],
];
}
/**
* @param mixed $contentNamespaces To pass to constructor
* @param array $expected
* @dataProvider provideGetContentNamespaces
* @covers NamespaceInfo::getContentNamespaces
*/
public function testGetContentNamespaces( $contentNamespaces, array $expected ) {
$obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
$this->assertSame( $expected, $obj->getContentNamespaces() );
}
public function provideGetContentNamespaces() {
return [
// Non-array
[ '', [ NS_MAIN ] ],
[ false, [ NS_MAIN ] ],
[ null, [ NS_MAIN ] ],
[ 5, [ NS_MAIN ] ],
// Empty array
[ [], [ NS_MAIN ] ],
// NS_MAIN is forced to be content even if unwanted
[ [ NS_USER, NS_CATEGORY ], [ NS_MAIN, NS_USER, NS_CATEGORY ] ],
// In other cases, return as-is
[ [ NS_MAIN ], [ NS_MAIN ] ],
[ [ NS_MAIN, NS_USER, NS_CATEGORY ], [ NS_MAIN, NS_USER, NS_CATEGORY ] ],
];
}
/**
* @covers NamespaceInfo::getSubjectNamespaces
*/
public function testGetSubjectNamespaces() {
$subjectsNS = $this->newObj()->getSubjectNamespaces();
$this->assertContains( NS_MAIN, $subjectsNS,
"Talk namespaces should have NS_MAIN" );
$this->assertNotContains( NS_TALK, $subjectsNS,
"Talk namespaces should have NS_TALK" );
$this->assertNotContains( NS_MEDIA, $subjectsNS,
"Talk namespaces should not have NS_MEDIA" );
$this->assertNotContains( NS_SPECIAL, $subjectsNS,
"Talk namespaces should not have NS_SPECIAL" );
}
/**
* @covers NamespaceInfo::getTalkNamespaces
*/
public function testGetTalkNamespaces() {
$talkNS = $this->newObj()->getTalkNamespaces();
$this->assertContains( NS_TALK, $talkNS,
"Subject namespaces should have NS_TALK" );
$this->assertNotContains( NS_MAIN, $talkNS,
"Subject namespaces should not have NS_MAIN" );
$this->assertNotContains( NS_MEDIA, $talkNS,
"Subject namespaces should not have NS_MEDIA" );
$this->assertNotContains( NS_SPECIAL, $talkNS,
"Subject namespaces should not have NS_SPECIAL" );
}
/**
* @param int $ns
* @param bool $expected
* @param bool $capitalLinks To pass to constructor
* @param array $capitalLinkOverrides To pass to constructor
* @dataProvider provideIsCapitalized
* @covers NamespaceInfo::isCapitalized
*/
public function testIsCapitalized(
$ns, $expected, $capitalLinks = true, array $capitalLinkOverrides = []
) {
$obj = $this->newObj( [
'CapitalLinks' => $capitalLinks,
'CapitalLinkOverrides' => $capitalLinkOverrides,
] );
$this->assertSame( $expected, $obj->isCapitalized( $ns ) );
}
public function provideIsCapitalized() {
return [
// Test default settings
[ NS_PROJECT, true ],
[ NS_PROJECT_TALK, true ],
[ NS_MEDIA, true ],
[ NS_FILE, true ],
// Always capitalized no matter what
[ NS_SPECIAL, true, false ],
[ NS_USER, true, false ],
[ NS_MEDIAWIKI, true, false ],
// Even with an override too
[ NS_SPECIAL, true, false, [ NS_SPECIAL => false ] ],
[ NS_USER, true, false, [ NS_USER => false ] ],
[ NS_MEDIAWIKI, true, false, [ NS_MEDIAWIKI => false ] ],
// Overrides work for other namespaces
[ NS_PROJECT, false, true, [ NS_PROJECT => false ] ],
[ NS_PROJECT, true, false, [ NS_PROJECT => true ] ],
// NS_MEDIA is treated like NS_FILE, and ignores NS_MEDIA overrides
[ NS_MEDIA, false, true, [ NS_FILE => false, NS_MEDIA => true ] ],
[ NS_MEDIA, true, false, [ NS_FILE => true, NS_MEDIA => false ] ],
[ NS_FILE, false, true, [ NS_FILE => false, NS_MEDIA => true ] ],
[ NS_FILE, true, false, [ NS_FILE => true, NS_MEDIA => false ] ],
];
}
/**
* @covers NamespaceInfo::hasGenderDistinction
*/
public function testHasGenderDistinction() {
$obj = $this->newObj();
// Namespaces with gender distinctions
$this->assertTrue( $obj->hasGenderDistinction( NS_USER ) );
$this->assertTrue( $obj->hasGenderDistinction( NS_USER_TALK ) );
// Other ones, "genderless"
$this->assertFalse( $obj->hasGenderDistinction( NS_MEDIA ) );
$this->assertFalse( $obj->hasGenderDistinction( NS_SPECIAL ) );
$this->assertFalse( $obj->hasGenderDistinction( NS_MAIN ) );
$this->assertFalse( $obj->hasGenderDistinction( NS_TALK ) );
}
/**
* @covers NamespaceInfo::isNonincludable
*/
public function testIsNonincludable() {
$obj = $this->newObj( [ 'NonincludableNamespaces' => [ NS_USER ] ] );
$this->assertTrue( $obj->isNonincludable( NS_USER ) );
$this->assertFalse( $obj->isNonincludable( NS_TEMPLATE ) );
}
/**
* @dataProvider provideGetNamespaceContentModel
* @covers NamespaceInfo::getNamespaceContentModel
*
* @param int $ns
* @param string $expected
*/
public function testGetNamespaceContentModel( $ns, $expected ) {
$obj = $this->newObj( [ 'NamespaceContentModels' =>
[ NS_USER => CONTENT_MODEL_WIKITEXT, 123 => CONTENT_MODEL_JSON, 1234 => 'abcdef' ],
] );
$this->assertSame( $expected, $obj->getNamespaceContentModel( $ns ) );
}
public function provideGetNamespaceContentModel() {
return [
[ NS_MAIN, null ],
[ NS_TALK, null ],
[ NS_USER, CONTENT_MODEL_WIKITEXT ],
[ NS_USER_TALK, null ],
[ NS_SPECIAL, null ],
[ 122, null ],
[ 123, CONTENT_MODEL_JSON ],
[ 1234, 'abcdef' ],
[ 1235, null ],
];
}
/**
* @dataProvider provideGetCategoryLinkType
* @covers NamespaceInfo::getCategoryLinkType
*
* @param int $ns
* @param string $expected
*/
public function testGetCategoryLinkType( $ns, $expected ) {
$this->assertSame( $expected, $this->newObj()->getCategoryLinkType( $ns ) );
}
public function provideGetCategoryLinkType() {
return [
[ NS_MAIN, 'page' ],
[ NS_TALK, 'page' ],
[ NS_USER, 'page' ],
[ NS_USER_TALK, 'page' ],
[ NS_FILE, 'file' ],
[ NS_FILE_TALK, 'page' ],
[ NS_CATEGORY, 'subcat' ],
[ NS_CATEGORY_TALK, 'page' ],
[ 100, 'page' ],
[ 101, 'page' ],
];
}
// %} End basic methods
/**********************************************************************************************
* getSubject/Talk/Associated
* %{
*/
/**
* @dataProvider provideSubjectTalk
* @covers NamespaceInfo::getSubject
* @covers NamespaceInfo::getSubjectPage
* @covers NamespaceInfo::isMethodValidFor
* @covers Title::getSubjectPage
*
* @param int $subject
* @param int $talk
*/
public function testGetSubject( $subject, $talk ) {
$obj = $this->newObj();
$this->assertSame( $subject, $obj->getSubject( $subject ) );
$this->assertSame( $subject, $obj->getSubject( $talk ) );
$subjectTitleVal = new TitleValue( $subject, 'A' );
$talkTitleVal = new TitleValue( $talk, 'A' );
// Object will be the same one passed in if it's a subject, different but equal object if
// it's talk
$this->assertSame( $subjectTitleVal, $obj->getSubjectPage( $subjectTitleVal ) );
$this->assertEquals( $subjectTitleVal, $obj->getSubjectPage( $talkTitleVal ) );
$subjectTitle = Title::makeTitle( $subject, 'A' );
$talkTitle = Title::makeTitle( $talk, 'A' );
$this->assertSame( $subjectTitle, $subjectTitle->getSubjectPage() );
$this->assertEquals( $subjectTitle, $talkTitle->getSubjectPage() );
}
/**
* @dataProvider provideSpecialNamespaces
* @covers NamespaceInfo::getSubject
* @covers NamespaceInfo::getSubjectPage
*
* @param int $ns
*/
public function testGetSubject_special( $ns ) {
$obj = $this->newObj();
$this->assertSame( $ns, $obj->getSubject( $ns ) );
$title = new TitleValue( $ns, 'A' );
$this->assertSame( $title, $obj->getSubjectPage( $title ) );
}
/**
* @dataProvider provideSubjectTalk
* @covers NamespaceInfo::getTalk
* @covers NamespaceInfo::getTalkPage
* @covers NamespaceInfo::isMethodValidFor
* @covers Title::getTalkPage
*
* @param int $subject
* @param int $talk
*/
public function testGetTalk( $subject, $talk ) {
$obj = $this->newObj();
$this->assertSame( $talk, $obj->getTalk( $subject ) );
$this->assertSame( $talk, $obj->getTalk( $talk ) );
$subjectTitleVal = new TitleValue( $subject, 'A' );
$talkTitleVal = new TitleValue( $talk, 'A' );
// Object will be the same one passed in if it's a talk, different but equal object if it's
// subject
$this->assertEquals( $talkTitleVal, $obj->getTalkPage( $subjectTitleVal ) );
$this->assertSame( $talkTitleVal, $obj->getTalkPage( $talkTitleVal ) );
$subjectTitle = Title::makeTitle( $subject, 'A' );
$talkTitle = Title::makeTitle( $talk, 'A' );
$this->assertEquals( $talkTitle, $subjectTitle->getTalkPage() );
$this->assertSame( $talkTitle, $talkTitle->getTalkPage() );
}
/**
* @dataProvider provideSpecialNamespaces
* @covers NamespaceInfo::getTalk
* @covers NamespaceInfo::isMethodValidFor
*
* @param int $ns
*/
public function testGetTalk_special( $ns ) {
$this->expectException( MWException::class );
$this->expectExceptionMessage(
"NamespaceInfo::getTalk does not make any sense for given namespace $ns"
);
$this->newObj()->getTalk( $ns );
}
/**
* @dataProvider provideSpecialNamespaces
* @covers NamespaceInfo::getAssociated
* @covers NamespaceInfo::isMethodValidFor
*
* @param int $ns
*/
public function testGetAssociated_special( $ns ) {
$this->expectException( MWException::class );
$this->expectExceptionMessage(
"NamespaceInfo::getAssociated does not make any sense for given namespace $ns"
);
$this->newObj()->getAssociated( $ns );
}
public static function provideCanHaveTalkPage() {
return [
[ new TitleValue( NS_MAIN, 'Test' ), true ],
[ new TitleValue( NS_TALK, 'Test' ), true ],
[ new TitleValue( NS_USER, 'Test' ), true ],
[ new TitleValue( NS_SPECIAL, 'Test' ), false ],
[ new TitleValue( NS_MEDIA, 'Test' ), false ],
[ new TitleValue( NS_MAIN, '', 'Kittens' ), false ],
[ new TitleValue( NS_MAIN, 'Kittens', '', 'acme' ), false ],
];
}
/**
* @dataProvider provideCanHaveTalkPage
* @covers NamespaceInfo::canHaveTalkPage
*/
public function testCanHaveTalkPage( LinkTarget $t, $expected ) {
$actual = $this->newObj()->canHaveTalkPage( $t );
$this->assertEquals( $expected, $actual, $t->getDBkey() );
}
public static function provideGetTalkPage_good() {
return [
[ new TitleValue( NS_MAIN, 'Test' ), new TitleValue( NS_TALK, 'Test' ) ],
[ new TitleValue( NS_TALK, 'Test' ), new TitleValue( NS_TALK, 'Test' ) ],
[ new TitleValue( NS_USER, 'Test' ), new TitleValue( NS_USER_TALK, 'Test' ) ],
];
}
/**
* @dataProvider provideGetTalkPage_good
* @covers NamespaceInfo::getTalk
* @covers NamespaceInfo::getTalkPage
* @covers NamespaceInfo::isMethodValidFor
*/
public function testGetTalkPage_good( LinkTarget $t, LinkTarget $expected ) {
$actual = $this->newObj()->getTalkPage( $t );
$this->assertEquals( $expected, $actual, $t->getDBkey() );
}
public static function provideGetTalkPage_bad() {
return [
[ new TitleValue( NS_SPECIAL, 'Test' ) ],
[ new TitleValue( NS_MEDIA, 'Test' ) ],
[ new TitleValue( NS_MAIN, '', 'Kittens' ) ],
[ new TitleValue( NS_MAIN, 'Kittens', '', 'acme' ) ],
];
}
/**
* @dataProvider provideGetTalkPage_bad
* @covers NamespaceInfo::getTalk
* @covers NamespaceInfo::getTalkPage
* @covers NamespaceInfo::isMethodValidFor
*/
public function testGetTalkPage_bad( LinkTarget $t ) {
$this->expectException( MWException::class );
$this->newObj()->getTalkPage( $t );
}
/**
* @dataProvider provideGetTalkPage_bad
* @covers NamespaceInfo::getAssociated
* @covers NamespaceInfo::getAssociatedPage
* @covers NamespaceInfo::isMethodValidFor
*/
public function testGetAssociatedPage_bad( LinkTarget $t ) {
$this->expectException( MWException::class );
$this->newObj()->getAssociatedPage( $t );
}
/**
* @dataProvider provideSubjectTalk
* @covers NamespaceInfo::getAssociated
* @covers NamespaceInfo::getAssociatedPage
* @covers Title::getOtherPage
*
* @param int $subject
* @param int $talk
*/
public function testGetAssociated( $subject, $talk ) {
$obj = $this->newObj();
$this->assertSame( $talk, $obj->getAssociated( $subject ) );
$this->assertSame( $subject, $obj->getAssociated( $talk ) );
$subjectTitle = new TitleValue( $subject, 'A' );
$talkTitle = new TitleValue( $talk, 'A' );
// Object will not be the same
$this->assertEquals( $talkTitle, $obj->getAssociatedPage( $subjectTitle ) );
$this->assertEquals( $subjectTitle, $obj->getAssociatedPage( $talkTitle ) );
$subjectTitle = Title::makeTitle( $subject, 'A' );
$talkTitle = Title::makeTitle( $talk, 'A' );
$this->assertEquals( $talkTitle, $subjectTitle->getOtherPage() );
$this->assertEquals( $subjectTitle, $talkTitle->getOtherPage() );
}
public static function provideSubjectTalk() {
return [
// Format: [ subject, talk ]
'Main/talk' => [ NS_MAIN, NS_TALK ],
'User/user talk' => [ NS_USER, NS_USER_TALK ],
'Unknown namespaces also supported' => [ 106, 107 ],
];
}
public static function provideSpecialNamespaces() {
return [
'Special' => [ NS_SPECIAL ],
'Media' => [ NS_MEDIA ],
'Unknown negative index' => [ -613 ],
];
}
// %} End getSubject/Talk/Associated
/**********************************************************************************************
* Canonical namespaces
* %{
*/
// Default canonical namespaces
// %{
private function getDefaultNamespaces() {
return [ NS_MAIN => '' ] + self::DEFAULT_OPTIONS['CanonicalNamespaceNames'];
}
/**
* @covers NamespaceInfo::getCanonicalNamespaces
*/
public function testGetCanonicalNamespaces() {
$this->assertSame(
$this->getDefaultNamespaces(),
$this->newObj()->getCanonicalNamespaces()
);
}
/**
* @dataProvider provideGetCanonicalName
* @covers NamespaceInfo::getCanonicalName
*
* @param int $index
* @param string|bool $expected
*/
public function testGetCanonicalName( $index, $expected ) {
$this->assertSame( $expected, $this->newObj()->getCanonicalName( $index ) );
}
public function provideGetCanonicalName() {
return [
'Main' => [ NS_MAIN, '' ],
'Talk' => [ NS_TALK, 'Talk' ],
'With underscore not space' => [ NS_USER_TALK, 'User_talk' ],
'Special' => [ NS_SPECIAL, 'Special' ],
'Nonexistent' => [ 12345, false ],
'Nonexistent negative' => [ -12345, false ],
];
}
/**
* @dataProvider provideGetCanonicalIndex
* @covers NamespaceInfo::getCanonicalIndex
*
* @param string $name
* @param int|null $expected
*/
public function testGetCanonicalIndex( $name, $expected ) {
$this->assertSame( $expected, $this->newObj()->getCanonicalIndex( $name ) );
}
public function provideGetCanonicalIndex() {
return [
'Main' => [ '', NS_MAIN ],
'Talk' => [ 'talk', NS_TALK ],
'Not lowercase' => [ 'Talk', null ],
'With underscore' => [ 'user_talk', NS_USER_TALK ],
'Space is not recognized for underscore' => [ 'user talk', null ],
'0' => [ '0', null ],
];
}
/**
* @covers NamespaceInfo::getValidNamespaces
*/
public function testGetValidNamespaces() {
$this->assertSame(
[ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK ],
$this->newObj()->getValidNamespaces()
);
}
// %} End default canonical namespaces
// No canonical namespace names
// %{
/**
* @covers NamespaceInfo::getCanonicalNamespaces
*/
public function testGetCanonicalNamespaces_NoCanonicalNamespaceNames() {
$obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
$this->assertSame( [ NS_MAIN => '' ], $obj->getCanonicalNamespaces() );
}
/**
* @covers NamespaceInfo::getCanonicalName
*/
public function testGetCanonicalName_NoCanonicalNamespaceNames() {
$obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
$this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
$this->assertFalse( $obj->getCanonicalName( NS_TALK ) );
}
/**
* @covers NamespaceInfo::getCanonicalIndex
*/
public function testGetCanonicalIndex_NoCanonicalNamespaceNames() {
$obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
$this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
$this->assertNull( $obj->getCanonicalIndex( 'talk' ) );
}
/**
* @covers NamespaceInfo::getValidNamespaces
*/
public function testGetValidNamespaces_NoCanonicalNamespaceNames() {
$obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
$this->assertSame( [ NS_MAIN ], $obj->getValidNamespaces() );
}
// %} End no canonical namespace names
// Test extension namespaces
// %{
private function setupExtensionNamespaces() {
$this->scopedCallback = null;
$this->scopedCallback = ExtensionRegistry::getInstance()->setAttributeForTest(
'ExtensionNamespaces',
[ NS_MAIN => 'No effect', NS_TALK => 'No effect', 12345 => 'Extended' ]
);
}
/**
* @covers NamespaceInfo::getCanonicalNamespaces
*/
public function testGetCanonicalNamespaces_ExtensionNamespaces() {
$this->setupExtensionNamespaces();
$this->assertSame(
$this->getDefaultNamespaces() + [ 12345 => 'Extended' ],
$this->newObj()->getCanonicalNamespaces()
);
}
/**
* @covers NamespaceInfo::getCanonicalName
*/
public function testGetCanonicalName_ExtensionNamespaces() {
$this->setupExtensionNamespaces();
$obj = $this->newObj();
$this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
$this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK ) );
$this->assertSame( 'Extended', $obj->getCanonicalName( 12345 ) );
}
/**
* @covers NamespaceInfo::getCanonicalIndex
*/
public function testGetCanonicalIndex_ExtensionNamespaces() {
$this->setupExtensionNamespaces();
$obj = $this->newObj();
$this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
$this->assertSame( NS_TALK, $obj->getCanonicalIndex( 'talk' ) );
$this->assertSame( 12345, $obj->getCanonicalIndex( 'extended' ) );
}
/**
* @covers NamespaceInfo::getValidNamespaces
*/
public function testGetValidNamespaces_ExtensionNamespaces() {
$this->setupExtensionNamespaces();
$this->assertSame(
[ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 12345 ],
$this->newObj()->getValidNamespaces()
);
}
// %} End extension namespaces
// Hook namespaces
// %{
/**
* @return array Expected canonical namespaces
*/
private function setupHookNamespaces() {
$callback =
function ( &$canonicalNamespaces ) {
$canonicalNamespaces[NS_MAIN] = 'Main';
unset( $canonicalNamespaces[NS_MEDIA] );
$canonicalNamespaces[123456] = 'Hooked';
};
$this->setTemporaryHook( 'CanonicalNamespaces', $callback );
$expected = $this->getDefaultNamespaces();
( $callback )( $expected );
return $expected;
}
/**
* @covers NamespaceInfo::getCanonicalNamespaces
*/
public function testGetCanonicalNamespaces_HookNamespaces() {
$expected = $this->setupHookNamespaces();
$this->assertSame( $expected, $this->newObj()->getCanonicalNamespaces() );
}
/**
* @covers NamespaceInfo::getCanonicalName
*/
public function testGetCanonicalName_HookNamespaces() {
$this->setupHookNamespaces();
$obj = $this->newObj();
$this->assertSame( 'Main', $obj->getCanonicalName( NS_MAIN ) );
$this->assertFalse( $obj->getCanonicalName( NS_MEDIA ) );
$this->assertSame( 'Hooked', $obj->getCanonicalName( 123456 ) );
}
/**
* @covers NamespaceInfo::getCanonicalIndex
*/
public function testGetCanonicalIndex_HookNamespaces() {
$this->setupHookNamespaces();
$obj = $this->newObj();
$this->assertSame( NS_MAIN, $obj->getCanonicalIndex( 'main' ) );
$this->assertNull( $obj->getCanonicalIndex( 'media' ) );
$this->assertSame( 123456, $obj->getCanonicalIndex( 'hooked' ) );
}
/**
* @covers NamespaceInfo::getValidNamespaces
*/
public function testGetValidNamespaces_HookNamespaces() {
$this->setupHookNamespaces();
$this->assertSame(
[ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 123456 ],
$this->newObj()->getValidNamespaces()
);
}
// %} End hook namespaces
// Extra namespaces
// %{
/**
* @return NamespaceInfo
*/
private function setupExtraNamespaces() {
return $this->newObj( [ 'ExtraNamespaces' =>
[ NS_MAIN => 'No effect', NS_TALK => 'No effect', 1234567 => 'Extra' ]
] );
}
/**
* @covers NamespaceInfo::getCanonicalNamespaces
*/
public function testGetCanonicalNamespaces_ExtraNamespaces() {
$this->assertSame(
$this->getDefaultNamespaces() + [ 1234567 => 'Extra' ],
$this->setupExtraNamespaces()->getCanonicalNamespaces()
);
}
/**
* @covers NamespaceInfo::getCanonicalName
*/
public function testGetCanonicalName_ExtraNamespaces() {
$obj = $this->setupExtraNamespaces();
$this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
$this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK ) );
$this->assertSame( 'Extra', $obj->getCanonicalName( 1234567 ) );
}
/**
* @covers NamespaceInfo::getCanonicalIndex
*/
public function testGetCanonicalIndex_ExtraNamespaces() {
$obj = $this->setupExtraNamespaces();
$this->assertNull( $obj->getCanonicalIndex( 'no effect' ) );
$this->assertNull( $obj->getCanonicalIndex( 'no_effect' ) );
$this->assertSame( 1234567, $obj->getCanonicalIndex( 'extra' ) );
}
/**
* @covers NamespaceInfo::getValidNamespaces
*/
public function testGetValidNamespaces_ExtraNamespaces() {
$this->assertSame(
[ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 1234567 ],
$this->setupExtraNamespaces()->getValidNamespaces()
);
}
// %} End extra namespaces
// Canonical namespace caching
// %{
/**
* @covers NamespaceInfo::getCanonicalNamespaces
*/
public function testGetCanonicalNamespaces_caching() {
$obj = $this->newObj();
// This should cache the values
$obj->getCanonicalNamespaces();
// Now try to alter them through nefarious means
$this->setupExtensionNamespaces();
$this->setupHookNamespaces();
// Should have no effect
$this->assertSame( $this->getDefaultNamespaces(), $obj->getCanonicalNamespaces() );
}
/**
* @covers NamespaceInfo::getCanonicalName
*/
public function testGetCanonicalName_caching() {
$obj = $this->newObj();
// This should cache the values
$obj->getCanonicalName( NS_MAIN );
// Now try to alter them through nefarious means
$this->setupExtensionNamespaces();
$this->setupHookNamespaces();
// Should have no effect
$this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
$this->assertSame( 'Media', $obj->getCanonicalName( NS_MEDIA ) );
$this->assertFalse( $obj->getCanonicalName( 12345 ) );
$this->assertFalse( $obj->getCanonicalName( 123456 ) );
}
/**
* @covers NamespaceInfo::getCanonicalIndex
*/
public function testGetCanonicalIndex_caching() {
$obj = $this->newObj();
// This should cache the values
$obj->getCanonicalIndex( '' );
// Now try to alter them through nefarious means
$this->setupExtensionNamespaces();
$this->setupHookNamespaces();
// Should have no effect
$this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
$this->assertSame( NS_MEDIA, $obj->getCanonicalIndex( 'media' ) );
$this->assertNull( $obj->getCanonicalIndex( 'extended' ) );
$this->assertNull( $obj->getCanonicalIndex( 'hooked' ) );
}
/**
* @covers NamespaceInfo::getValidNamespaces
*/
public function testGetValidNamespaces_caching() {
$obj = $this->newObj();
// This should cache the values
$obj->getValidNamespaces();
// Now try to alter through nefarious means
$this->setupExtensionNamespaces();
$this->setupHookNamespaces();
// Should have no effect
$this->assertSame(
[ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK ],
$obj->getValidNamespaces()
);
}
// %} End canonical namespace caching
// Miscellaneous
// %{
/**
* @dataProvider provideGetValidNamespaces_misc
* @covers NamespaceInfo::getValidNamespaces
*
* @param array $namespaces List of namespace indices to return from getCanonicalNamespaces()
* (list is overwritten by a hook, so NS_MAIN doesn't have to be present)
* @param array $expected
*/
public function testGetValidNamespaces_misc( array $namespaces, array $expected ) {
// Each namespace's name is just its index
$this->setTemporaryHook( 'CanonicalNamespaces',
function ( &$canonicalNamespaces ) use ( $namespaces ) {
$canonicalNamespaces = array_combine( $namespaces, $namespaces );
}
);
$this->assertSame( $expected, $this->newObj()->getValidNamespaces() );
}
public function provideGetValidNamespaces_misc() {
return [
'Out of order (T109137)' => [ [ 1, 0 ], [ 0, 1 ] ],
'Alphabetical order' => [ [ 10, 2 ], [ 2, 10 ] ],
'Negative' => [ [ -1000, -500, -2, 0 ], [ 0 ] ],
];
}
// %} End miscellaneous
// %} End canonical namespaces
/**********************************************************************************************
* Restriction levels
* %{
*/
/**
* TODO: This is superceeded by PermissionManagerTest::testGetNamespaceRestrictionLevels
* Remove when deprecated method is removed.
* @dataProvider provideGetRestrictionLevels
* @covers NamespaceInfo::getRestrictionLevels
*
* @param array $expected
* @param int $ns
* @param array|null $groups
* @throws MWException
*/
public function testGetRestrictionLevels( array $expected, $ns, array $groups = null ) {
$this->setMwGlobals( [
'wgGroupPermissions' => [
'*' => [ 'edit' => true ],
'autoconfirmed' => [ 'editsemiprotected' => true ],
'sysop' => [
'editsemiprotected' => true,
'editprotected' => true,
],
'privileged' => [ 'privileged' => true ],
],
'wgRevokePermissions' => [
'noeditsemiprotected' => [ 'editsemiprotected' => true ],
],
'wgNamespaceProtection' => [
NS_MAIN => 'autoconfirmed',
NS_USER => 'sysop',
101 => [ 'editsemiprotected', 'privileged' ],
],
'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
'wgAutopromote' => []
] );
$obj = $this->newObj();
$user = is_null( $groups ) ? null : $this->getTestUser( $groups )->getUser();
$this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
}
public function provideGetRestrictionLevels() {
return [
'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK ],
'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN ],
'Restricted to sysop' => [ [ '' ], NS_USER ],
'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
'No special permissions' => [ [ '' ], NS_TALK, [] ],
'autoconfirmed' => [
[ '', 'autoconfirmed' ],
NS_TALK,
[ 'autoconfirmed' ]
],
'autoconfirmed revoked' => [
[ '' ],
NS_TALK,
[ 'autoconfirmed', 'noeditsemiprotected' ]
],
'sysop' => [
[ '', 'autoconfirmed', 'sysop' ],
NS_TALK,
[ 'sysop' ]
],
'sysop with autoconfirmed revoked (a bit silly)' => [
[ '', 'sysop' ],
NS_TALK,
[ 'sysop', 'noeditsemiprotected' ]
],
];
}
// %} End restriction levels
/**
* @coversNothing
*/
public function testAllServiceOptionsUsed() {
$this->assertAllServiceOptionsUsed();
}
}
/**
* For really cool vim folding this needs to be at the end:
* vim: foldmarker=%{,%} foldmethod=marker
*/