From 3414e91bae6012fc75e8ffb0da93c598120c6eed Mon Sep 17 00:00:00 2001 From: Daniel Friesen Date: Tue, 22 Nov 2011 13:34:55 +0000 Subject: [PATCH] Implement a number of namespace related equals functions: * MWNamespace::equals to test equivalence of two namespaces (forward compatible with any changes we may make like introducing namespace keys like 'USER') * MWNamespace::subjectEquals to test equivalence of the subject of two namespaces e.g.: MWNamespace::subjectEquals( NS_USER, $ns ); instead of testing for equivalence to both NS_USER and NS_USER_TALK * Title::inNamespace to use instead of $title->getNamespace() == NS_??? * Title::inNamespaces for use like $title->inNamespaces( NS_USER, NS_PROJECT ) when you only care if it's in one of a number of namespaces (also accepts an array) * Title::hasSubjectNamespace for use instead of testing for equivalence to both the subject and talk such as NS_USER and NS_USER_TALK. Include phpunit tests for all this new code, and also add some tests for some existing code. --- includes/Namespace.php | 45 ++++++++++- includes/Title.php | 51 ++++++++++++ tests/phpunit/includes/MWNamespaceTest.php | 87 +++++++++++++++------ tests/phpunit/includes/TitleMethodsTest.php | 78 ++++++++++++++++++ 4 files changed, 237 insertions(+), 24 deletions(-) create mode 100644 tests/phpunit/includes/TitleMethodsTest.php diff --git a/includes/Namespace.php b/includes/Namespace.php index 0883011fc0..57840c9bd1 100644 --- a/includes/Namespace.php +++ b/includes/Namespace.php @@ -58,11 +58,20 @@ class MWNamespace { * * @param $index Int: namespace index * @return bool + * @since 1.19 */ - public static function isMain( $index ) { + public static function isSubject( $index ) { return !self::isTalk( $index ); } + /** + * @see self::isSubject + * @deprecated Please use the more consistently named isSubject (since 1.19) + */ + public static function isMain( $index ) { + return self::isSubject( $index ); + } + /** * Is the given namespace a talk namespace? * @@ -131,12 +140,46 @@ class MWNamespace { * @param $index * * @return bool + * @since 1.19 */ public static function exists( $index ) { $nslist = self::getCanonicalNamespaces(); return isset( $nslist[$index] ); } + /** + * Returns whether the specified namespaces are the same namespace + * + * @note It's possible that in the future we may start using something + * other than just namespace indexes. Under that circumstance making use + * of this function rather than directly doing comparison will make + * sure that code will not potentially break. + * + * @param $ns1 The first namespace index + * @param $ns2 The second namespae index + * + * @return bool + * @since 1.19 + */ + public static function equals( $ns1, $ns2 ) { + return $ns1 == $ns2; + } + + /** + * Returns whether the specified namespaces share the same subject. + * eg: NS_USER and NS_USER wil return true, as well + * NS_USER and NS_USER_TALK will return true. + * + * @param $ns1 The first namespace index + * @param $ns2 The second namespae index + * + * @return bool + * @since 1.19 + */ + public static function subjectEquals( $ns1, $ns2 ) { + return self::getSubject( $ns1 ) == self::getSubject( $ns2 ); + } + /** * Returns array of all defined namespaces with their canonical * (English) names. diff --git a/includes/Title.php b/includes/Title.php index 4048e5fe49..4c2ccda8dc 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -1945,6 +1945,57 @@ class Title { : false; } + /** + * Returns true if the title is inside the specified namespace. + * + * Please make use of this instead of comparing to getNamespace() + * This function is much more resistant to changes we may make + * to namespaces than code that makes direct comparisons. + * @param $ns The namespace + * @return bool + * @since 1.19 + */ + public function inNamespace( $ns ) { + return MWNamespace::equals( $this->getNamespace(), $ns ); + } + + /** + * Returns true if the title is inside one of the specified namespaces. + * + * @param ...$namespaces The namespaces to check for + * @return bool + * @since 1.19 + */ + public function inNamespaces( /* ... */ ) { + $namespaces = func_get_args(); + if ( count( $namespaces ) > 0 && is_array( $namespaces[0] ) ) { + $namespaces = $namespaces[0]; + } + + foreach ( $namespaces as $ns ) { + if ( $this->inNamespace( $ns ) ) { + return true; + } + } + + return false; + } + + /** + * Returns true if the title has the same subject namespace as the + * namespace specified. + * For example this method will take NS_USER and return true if namespace + * is either NS_USER or NS_USER_TALK since both of them have NS_USER + * as their subject namespace. + * + * This is MUCH simpler than individually testing for equivilance + * against both NS_USER and NS_USER_TALK, and is also forward compatible. + * @since 1.19 + */ + public function hasSubjectNamespace( $ns ) { + return MWNamespace::subjectEquals( $this->getNamespace(), $ns ); + } + /** * Does this have subpages? (Warning, usually requires an extra DB query.) * diff --git a/tests/phpunit/includes/MWNamespaceTest.php b/tests/phpunit/includes/MWNamespaceTest.php index 2dc8babab4..17104f9638 100644 --- a/tests/phpunit/includes/MWNamespaceTest.php +++ b/tests/phpunit/includes/MWNamespaceTest.php @@ -39,25 +39,29 @@ class MWNamespaceTest extends MediaWikiTestCase { /** * Please make sure to change testIsTalk() if you change the assertions below */ - public function testIsMain() { + public function testIsSubject() { // Special namespaces - $this->assertTrue( MWNamespace::isMain( NS_MEDIA ) ); - $this->assertTrue( MWNamespace::isMain( NS_SPECIAL ) ); + $this->assertTrue( MWNamespace::isSubject( NS_MEDIA ) ); + $this->assertTrue( MWNamespace::isSubject( NS_SPECIAL ) ); // Subject pages - $this->assertTrue( MWNamespace::isMain( NS_MAIN ) ); - $this->assertTrue( MWNamespace::isMain( NS_USER ) ); - $this->assertTrue( MWNamespace::isMain( 100 ) ); # user defined + $this->assertTrue( MWNamespace::isSubject( NS_MAIN ) ); + $this->assertTrue( MWNamespace::isSubject( NS_USER ) ); + $this->assertTrue( MWNamespace::isSubject( 100 ) ); # user defined // Talk pages - $this->assertFalse( MWNamespace::isMain( NS_TALK ) ); - $this->assertFalse( MWNamespace::isMain( NS_USER_TALK ) ); - $this->assertFalse( MWNamespace::isMain( 101 ) ); # user defined + $this->assertFalse( MWNamespace::isSubject( NS_TALK ) ); + $this->assertFalse( MWNamespace::isSubject( NS_USER_TALK ) ); + $this->assertFalse( MWNamespace::isSubject( 101 ) ); # user defined + + // Back compat + $this->assertTrue( MWNamespace::isMain( NS_MAIN ) == MWNamespace::isSubject( NS_MAIN ) ); + $this->assertTrue( MWNamespace::isMain( NS_USER_TALK ) == MWNamespace::isSubject( NS_USER_TALK ) ); } /** - * Reverse of testIsMain(). - * Please update testIsMain() if you change assertions below + * Reverse of testIsSubject(). + * Please update testIsSubject() if you change assertions below */ public function testIsTalk() { // Special namespaces @@ -75,6 +79,17 @@ class MWNamespaceTest extends MediaWikiTestCase { $this->assertTrue( MWNamespace::isTalk( 101 ) ); # user defined } + /** + */ + public function testGetSubject() { + // Special namespaces are their own subjects + $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) ); + $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) ); + + $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) ); + $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) ); + } + /** * Regular getTalk() calls * Namespaces without a talk page (NS_MEDIA, NS_SPECIAL) are tested in @@ -82,6 +97,9 @@ class MWNamespaceTest extends MediaWikiTestCase { */ public function testGetTalk() { $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_MAIN ) ); + $this->assertEquals( NS_TALK, MWNamespace::getTalk( NS_TALK ) ); + $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER ) ); + $this->assertEquals( NS_USER_TALK, MWNamespace::getTalk( NS_USER_TALK ) ); } /** @@ -108,7 +126,7 @@ class MWNamespaceTest extends MediaWikiTestCase { * the function testGetAssociatedExceptions() */ public function testGetAssociated() { - $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) ); + $this->assertEquals( NS_TALK, MWNamespace::getAssociated( NS_MAIN ) ); $this->assertEquals( NS_MAIN, MWNamespace::getAssociated( NS_TALK ) ); } @@ -130,17 +148,6 @@ class MWNamespaceTest extends MediaWikiTestCase { $this->assertNull( MWNamespace::getAssociated( NS_SPECIAL ) ); } - /** - */ - public function testGetSubject() { - // Special namespaces are their own subjects - $this->assertEquals( NS_MEDIA, MWNamespace::getSubject( NS_MEDIA ) ); - $this->assertEquals( NS_SPECIAL, MWNamespace::getSubject( NS_SPECIAL ) ); - - $this->assertEquals( NS_MAIN, MWNamespace::getSubject( NS_TALK ) ); - $this->assertEquals( NS_USER, MWNamespace::getSubject( NS_USER_TALK ) ); - } - /** * @todo Implement testExists(). */ @@ -152,6 +159,40 @@ class MWNamespaceTest extends MediaWikiTestCase { ); } */ + + /** + * Test MWNamespace::equals + * Note if we add a namespace registration system with keys like 'MAIN' + * we should add tests here for equivilance on things like 'MAIN' == 0 + * and 'MAIN' == NS_MAIN. + */ + public function testEquals() { + $this->assertTrue( MWNamespace::equals( NS_MAIN, NS_MAIN ) ); + $this->assertTrue( MWNamespace::equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN' + $this->assertTrue( MWNamespace::equals( NS_USER, NS_USER ) ); + $this->assertTrue( MWNamespace::equals( NS_USER, 2 ) ); + $this->assertTrue( MWNamespace::equals( NS_USER_TALK, NS_USER_TALK ) ); + $this->assertTrue( MWNamespace::equals( NS_SPECIAL, NS_SPECIAL ) ); + $this->assertFalse( MWNamespace::equals( NS_MAIN, NS_TALK ) ); + $this->assertFalse( MWNamespace::equals( NS_USER, NS_USER_TALK ) ); + $this->assertFalse( MWNamespace::equals( NS_PROJECT, NS_TEMPLATE ) ); + } + + /** + * Test MWNamespace::subjectEquals + */ + public function testSubjectEquals() { + $this->assertTrue( MWNamespace::subjectEquals( NS_MAIN, NS_MAIN ) ); + $this->assertTrue( MWNamespace::subjectEquals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN' + $this->assertTrue( MWNamespace::subjectEquals( NS_USER, NS_USER ) ); + $this->assertTrue( MWNamespace::subjectEquals( NS_USER, 2 ) ); + $this->assertTrue( MWNamespace::subjectEquals( NS_USER_TALK, NS_USER_TALK ) ); + $this->assertTrue( MWNamespace::subjectEquals( NS_SPECIAL, NS_SPECIAL ) ); + $this->assertTrue( MWNamespace::subjectEquals( NS_MAIN, NS_TALK ) ); + $this->assertTrue( MWNamespace::subjectEquals( NS_USER, NS_USER_TALK ) ); + $this->assertFalse( MWNamespace::subjectEquals( NS_PROJECT, NS_TEMPLATE ) ); + } + /** * @todo Implement testGetCanonicalNamespaces(). */ diff --git a/tests/phpunit/includes/TitleMethodsTest.php b/tests/phpunit/includes/TitleMethodsTest.php new file mode 100644 index 0000000000..2f1103e8cb --- /dev/null +++ b/tests/phpunit/includes/TitleMethodsTest.php @@ -0,0 +1,78 @@ +assertEquals( $titleA->equals( $titleB ), $expectedBool ); + $this->assertEquals( $titleB->equals( $titleA ), $expectedBool ); + } + + public function dataInNamespace() { + return array( + array( 'Main Page', NS_MAIN, true ), + array( 'Main Page', NS_TALK, false ), + array( 'Main Page', NS_USER, false ), + array( 'User:Foo', NS_USER, true ), + array( 'User:Foo', NS_USER_TALK, false ), + array( 'User:Foo', NS_TEMPLATE, false ), + array( 'User_talk:Foo', NS_USER_TALK, true ), + array( 'User_talk:Foo', NS_USER, false ), + ); + } + + /** + * @dataProvider dataInNamespace + */ + public function testInNamespace( $title, $ns, $expectedBool ) { + $title = Title::newFromText( $title ); + $this->assertEquals( $title->inNamespace( $ns ), $expectedBool ); + } + + public function testInNamespaces() { + $mainpage = Title::newFromText( 'Main Page' ); + $this->assertTrue( $mainpage->inNamespaces( NS_MAIN, NS_USER ) ); + $this->assertTrue( $mainpage->inNamespaces( array( NS_MAIN, NS_USER ) ) ); + $this->assertTrue( $mainpage->inNamespaces( array( NS_USER, NS_MAIN ) ) ); + $this->assertFalse( $mainpage->inNamespaces( array( NS_PROJECT, NS_TEMPLATE ) ) ); + } + + public function dataHasSubjectNamespace() { + return array( + array( 'Main Page', NS_MAIN, true ), + array( 'Main Page', NS_TALK, true ), + array( 'Main Page', NS_USER, false ), + array( 'User:Foo', NS_USER, true ), + array( 'User:Foo', NS_USER_TALK, true ), + array( 'User:Foo', NS_TEMPLATE, false ), + array( 'User_talk:Foo', NS_USER_TALK, true ), + array( 'User_talk:Foo', NS_USER, true ), + ); + } + + /** + * @dataProvider dataHasSubjectNamespace + */ + public function testHasSubjectNamespace( $title, $ns, $expectedBool ) { + $title = Title::newFromText( $title ); + $this->assertEquals( $title->hasSubjectNamespace( $ns ), $expectedBool ); + } + +} -- 2.20.1