createMock( WikiPage::class ); $ret->method( 'canExist' )->willReturn( true ); $ret->method( 'exists' )->willReturn( true ); $ret->method( 'getId' )->willReturn( 123 ); $ret->method( 'getRevisionRecord' )->willReturn( $this->createMock( RevisionRecord::class ) ); return $ret; } /** * @return RevisionStore|MockObject */ private function getMockRevisionStore(): RevisionStore { $ret = $this->createMock( RevisionStore::class ); $ret->method( 'getQueryInfo' )->willReturn( [ 'tables' => [], 'fields' => [], 'joins' => [] ] ); return $ret; } private function getServiceOptions( int $deleteLimit = 100 ): ServiceOptions { return new ServiceOptions( DeletePage::CONSTRUCTOR_OPTIONS, [ 'DeleteRevisionsBatchSize' => 100, 'ActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, 'DeleteRevisionsLimit' => $deleteLimit ] ); } private function getDeletePage( ProperPageIdentity $page, Authority $deleter, ServiceOptions $options = null, RevisionStore $revStore = null ): DeletePage { $wpFactory = $this->createMock( WikiPageFactory::class ); $wpFactory->method( 'newFromTitle' )->willReturn( $this->getMockPage() ); // NOTE: The following could be avoided if the relevant methods were return-typehinted $db = $this->createMock( IDatabase::class ); $db->method( 'select' )->willReturn( $this->createMock( IResultWrapper::class ) ); $lb = $this->createMock( ILoadBalancer::class ); $lb->method( 'getConnectionRef' )->willReturn( $db ); $lbFactory = $this->createMock( LBFactory::class ); $lbFactory->method( 'getMainLB' )->willReturn( $lb ); $ret = new DeletePage( $this->createHookContainer(), $revStore ?? $this->getMockRevisionStore(), $lbFactory, $this->createMock( JobQueueGroup::class ), $this->createMock( CommentStore::class ), $options ?? $this->getServiceOptions(), $this->createMock( BagOStuff::class ), 'wiki-id', 'req-foo-bar', $wpFactory, $this->createMock( UserFactory::class ), $page, $deleter ); $ret->setIsDeletePageUnitTest( true ); return $ret; } /** * @covers ::deleteIfAllowed * @covers ::authorizeDeletion * @covers ::isBigDeletion * @dataProvider providePermissions */ public function testPermissions( Authority $authority, bool $expectedGood, string $expectedMessage = null, ServiceOptions $options = null, RevisionStore $revStore = null ) { $dp = $this->getDeletePage( $this->getMockPage(), $authority, $options, $revStore ); $status = $dp->deleteIfAllowed( 'foobar' ); $this->assertSame( $expectedGood, $status->isGood() ); if ( $expectedMessage !== null ) { $this->assertTrue( $status->hasMessage( $expectedMessage ) ); } } public function providePermissions(): iterable { $cannotDeleteMsg = "You shall not delete!"; $cannotDeleteAuthority = $this->mockAnonAuthority( static function ( string $permission, ?PageIdentity $page, PermissionStatus $status = null ) use ( $cannotDeleteMsg ): bool { if ( $permission === 'delete' ) { if ( $status ) { $status->fatal( $cannotDeleteMsg ); } return false; } return true; } ); yield 'Cannot delete' => [ $cannotDeleteAuthority, false, $cannotDeleteMsg ]; $cannotBigDeleteMsg = 'delete-toobig'; $cannotBigDeleteAuthority = $this->mockAnonAuthority( static function ( string $permission, ?PageIdentity $page, PermissionStatus $status = null ) use ( $cannotBigDeleteMsg ): bool { if ( $permission === 'bigdelete' ) { if ( $status ) { $status->fatal( $cannotBigDeleteMsg ); } return false; } return true; } ); $revDeleteLimit = -1; $cannotBigDeleteOptions = $this->getServiceOptions( $revDeleteLimit ); $revStore = $this->getMockRevisionStore(); $revStore->expects( $this->atLeastOnce() ) ->method( 'countRevisionsByPageId' ) ->willReturn( $revDeleteLimit + 42 ); yield 'Cannot bigdelete' => [ $cannotBigDeleteAuthority, false, $cannotBigDeleteMsg, $cannotBigDeleteOptions, $revStore ]; $successAuthority = new UltimateAuthority( new UserIdentityValue( 42, 'Deleter' ) ); yield 'Successful' => [ $successAuthority, true ]; } }