From a15339a9b55338e72bccf033103e423eedb4c208 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Sun, 18 Mar 2018 21:58:02 +0200 Subject: [PATCH] Improve test coverage for ApiDelete.php Still missing a test for file deletion, because I didn't figure out a simple way to create a file page that I can test on. Change-Id: I276e84b4f7777e5dd5be5520e572b9b9bb0c0633 --- includes/api/ApiDelete.php | 3 +- tests/phpunit/includes/api/ApiDeleteTest.php | 142 ++++++++++++++++--- 2 files changed, 121 insertions(+), 24 deletions(-) diff --git a/includes/api/ApiDelete.php b/includes/api/ApiDelete.php index e19f1f2216..a63dee6fc1 100644 --- a/includes/api/ApiDelete.php +++ b/includes/api/ApiDelete.php @@ -116,7 +116,8 @@ class ApiDelete extends ApiBase { $hasHistory = false; $reason = $page->getAutoDeleteReason( $hasHistory ); if ( $reason === false ) { - return Status::newFatal( 'cannotdelete', $title->getPrefixedText() ); + // Should be reachable only if the page has no revisions + return Status::newFatal( 'cannotdelete', $title->getPrefixedText() ); // @codeCoverageIgnore } } diff --git a/tests/phpunit/includes/api/ApiDeleteTest.php b/tests/phpunit/includes/api/ApiDeleteTest.php index 87167f034f..c9ce28e73a 100644 --- a/tests/phpunit/includes/api/ApiDeleteTest.php +++ b/tests/phpunit/includes/api/ApiDeleteTest.php @@ -20,18 +20,7 @@ class ApiDeleteTest extends ApiTestCase { } public function testDelete() { - $name = 'Help:ApiDeleteTest_testDelete'; - - // test non-existing page - try { - $this->doApiRequestWithToken( [ - 'action' => 'delete', - 'title' => $name, - ] ); - $this->fail( "Should have raised an ApiUsageException" ); - } catch ( ApiUsageException $e ) { - $this->assertTrue( self::apiExceptionHasCode( $e, 'missingtitle' ) ); - } + $name = 'Help:' . ucfirst( __FUNCTION__ ); // create new page $this->editPage( $name, 'Some text' ); @@ -40,23 +29,31 @@ class ApiDeleteTest extends ApiTestCase { $apiResult = $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name, - ] ); - $apiResult = $apiResult[0]; + ] )[0]; $this->assertArrayHasKey( 'delete', $apiResult ); $this->assertArrayHasKey( 'title', $apiResult['delete'] ); - // Normalized $name is used - $this->assertSame( - 'Help:ApiDeleteTest testDelete', - $apiResult['delete']['title'] - ); + $this->assertSame( $name, $apiResult['delete']['title'] ); $this->assertArrayHasKey( 'logid', $apiResult['delete'] ); $this->assertFalse( Title::newFromText( $name )->exists() ); } + public function testDeleteNonexistent() { + $this->setExpectedException( ApiUsageException::class, + "The page you specified doesn't exist." ); + + $this->doApiRequestWithToken( [ + 'action' => 'delete', + 'title' => 'This page deliberately left nonexistent', + ] ); + } + public function testDeletionWithoutPermission() { - $name = 'Help:ApiDeleteTest_testDeleteWithoutPermission'; + $this->setExpectedException( ApiUsageException::class, + 'The action you have requested is limited to users in the group:' ); + + $name = 'Help:' . ucfirst( __FUNCTION__ ); // create new page $this->editPage( $name, 'Some text' ); @@ -69,11 +66,110 @@ class ApiDeleteTest extends ApiTestCase { 'title' => $name, 'token' => $user->getEditToken(), ], null, null, $user ); - $this->fail( "Should have raised an ApiUsageException" ); - } catch ( ApiUsageException $e ) { - $this->assertTrue( self::apiExceptionHasCode( $e, 'permissiondenied' ) ); + } finally { + $this->assertTrue( Title::newFromText( $name )->exists() ); + } + } + + public function testDeleteWithTag() { + $name = 'Help:' . ucfirst( __FUNCTION__ ); + + ChangeTags::defineTag( 'custom tag' ); + + $this->editPage( $name, 'Some text' ); + + $this->doApiRequestWithToken( [ + 'action' => 'delete', + 'title' => $name, + 'tags' => 'custom tag', + ] ); + + $this->assertFalse( Title::newFromText( $name )->exists() ); + + $dbw = wfGetDB( DB_MASTER ); + $this->assertSame( 'custom tag', $dbw->selectField( + [ 'change_tag', 'logging' ], + 'ct_tag', + [ + 'log_namespace' => NS_HELP, + 'log_title' => ucfirst( __FUNCTION__ ), + ], + __METHOD__, + [], + [ 'change_tag' => [ 'INNER JOIN', 'ct_log_id = log_id' ] ] + ) ); + } + + public function testDeleteWithoutTagPermission() { + $this->setExpectedException( ApiUsageException::class, + 'You do not have permission to apply change tags along with your changes.' ); + + $name = 'Help:' . ucfirst( __FUNCTION__ ); + + ChangeTags::defineTag( 'custom tag' ); + $this->setMwGlobals( 'wgRevokePermissions', + [ 'user' => [ 'applychangetags' => true ] ] ); + + $this->editPage( $name, 'Some text' ); + + try { + $this->doApiRequestWithToken( [ + 'action' => 'delete', + 'title' => $name, + 'tags' => 'custom tag', + ] ); + } finally { + $this->assertTrue( Title::newFromText( $name )->exists() ); + } + } + + public function testDeleteAbortedByHook() { + $this->setExpectedException( ApiUsageException::class, + 'Deletion aborted by hook. It gave no explanation.' ); + + $name = 'Help:' . ucfirst( __FUNCTION__ ); + + $this->editPage( $name, 'Some text' ); + + $this->setTemporaryHook( 'ArticleDelete', + function () { + return false; + } + ); + + try { + $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name ] ); + } finally { + $this->assertTrue( Title::newFromText( $name )->exists() ); } + } + + public function testDeleteWatch() { + $name = 'Help:' . ucfirst( __FUNCTION__ ); + $user = self::$users['sysop']->getUser(); + + $this->editPage( $name, 'Some text' ); + $this->assertTrue( Title::newFromText( $name )->exists() ); + $this->assertFalse( $user->isWatched( Title::newFromText( $name ) ) ); + + $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name, 'watch' => '' ] ); + $this->assertFalse( Title::newFromText( $name )->exists() ); + $this->assertTrue( $user->isWatched( Title::newFromText( $name ) ) ); + } + + public function testDeleteUnwatch() { + $name = 'Help:' . ucfirst( __FUNCTION__ ); + $user = self::$users['sysop']->getUser(); + + $this->editPage( $name, 'Some text' ); $this->assertTrue( Title::newFromText( $name )->exists() ); + $user->addWatch( Title::newFromText( $name ) ); + $this->assertTrue( $user->isWatched( Title::newFromText( $name ) ) ); + + $this->doApiRequestWithToken( [ 'action' => 'delete', 'title' => $name, 'unwatch' => '' ] ); + + $this->assertFalse( Title::newFromText( $name )->exists() ); + $this->assertFalse( $user->isWatched( Title::newFromText( $name ) ) ); } } -- 2.20.1