2012-02-25 21:22:49 +00:00
|
|
|
<?php
|
2019-05-28 14:04:23 +00:00
|
|
|
|
2021-03-04 03:23:56 +00:00
|
|
|
use MediaWiki\Page\PageIdentity;
|
|
|
|
|
use MediaWiki\Permissions\PermissionStatus;
|
|
|
|
|
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
|
2019-10-06 04:54:59 +00:00
|
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
2014-03-12 17:08:40 +00:00
|
|
|
|
2012-03-23 17:18:07 +00:00
|
|
|
/**
|
|
|
|
|
* @group Database
|
|
|
|
|
*/
|
2020-06-30 15:09:24 +00:00
|
|
|
class RecentChangeTest extends MediaWikiIntegrationTestCase {
|
2021-03-04 03:23:56 +00:00
|
|
|
use MockAuthorityTrait;
|
|
|
|
|
|
2012-02-25 21:22:49 +00:00
|
|
|
protected $title;
|
|
|
|
|
protected $target;
|
|
|
|
|
protected $user;
|
|
|
|
|
protected $user_comment;
|
2012-03-05 21:21:34 +00:00
|
|
|
protected $context;
|
2012-02-25 21:22:49 +00:00
|
|
|
|
2020-06-14 10:51:39 +00:00
|
|
|
protected function setUp() : void {
|
2015-09-21 09:25:24 +00:00
|
|
|
parent::setUp();
|
2012-02-25 21:22:49 +00:00
|
|
|
|
2013-02-14 11:36:35 +00:00
|
|
|
$this->title = Title::newFromText( 'SomeTitle' );
|
2012-02-25 21:22:49 +00:00
|
|
|
$this->target = Title::newFromText( 'TestTarget' );
|
2021-03-04 03:23:56 +00:00
|
|
|
$this->user = $this->getTestUser()->getUser();
|
2012-02-25 21:22:49 +00:00
|
|
|
|
|
|
|
|
$this->user_comment = '<User comment about action>';
|
2012-03-05 21:21:34 +00:00
|
|
|
$this->context = RequestContext::newExtraneousContext( $this->title );
|
2012-02-25 21:22:49 +00:00
|
|
|
}
|
|
|
|
|
|
2015-09-21 13:51:44 +00:00
|
|
|
/**
|
|
|
|
|
* @covers RecentChange::newFromRow
|
|
|
|
|
* @covers RecentChange::loadFromRow
|
|
|
|
|
*/
|
|
|
|
|
public function testNewFromRow() {
|
2017-09-12 17:12:29 +00:00
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
$actorId = $user->getActorId();
|
|
|
|
|
|
2020-02-28 15:13:53 +00:00
|
|
|
$row = (object)[
|
|
|
|
|
'rc_foo' => 'AAA',
|
|
|
|
|
'rc_timestamp' => '20150921134808',
|
|
|
|
|
'rc_deleted' => 'bar',
|
|
|
|
|
'rc_comment_text' => 'comment',
|
|
|
|
|
'rc_comment_data' => null,
|
|
|
|
|
'rc_user' => $user->getId(),
|
|
|
|
|
];
|
2015-09-21 13:51:44 +00:00
|
|
|
|
|
|
|
|
$rc = RecentChange::newFromRow( $row );
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$expected = [
|
2015-09-21 13:51:44 +00:00
|
|
|
'rc_foo' => 'AAA',
|
|
|
|
|
'rc_timestamp' => '20150921134808',
|
|
|
|
|
'rc_deleted' => 'bar',
|
2017-06-06 17:39:14 +00:00
|
|
|
'rc_comment' => 'comment',
|
|
|
|
|
'rc_comment_text' => 'comment',
|
|
|
|
|
'rc_comment_data' => null,
|
2017-09-12 17:12:29 +00:00
|
|
|
'rc_user' => $user->getId(),
|
|
|
|
|
'rc_user_text' => $user->getName(),
|
|
|
|
|
'rc_actor' => $actorId,
|
2017-06-06 17:39:14 +00:00
|
|
|
];
|
|
|
|
|
$this->assertEquals( $expected, $rc->getAttributes() );
|
|
|
|
|
|
2020-02-28 15:13:53 +00:00
|
|
|
$row = (object)[
|
|
|
|
|
'rc_foo' => 'AAA',
|
|
|
|
|
'rc_timestamp' => '20150921134808',
|
|
|
|
|
'rc_deleted' => 'bar',
|
|
|
|
|
'rc_comment' => 'comment',
|
|
|
|
|
'rc_user' => $user->getId(),
|
|
|
|
|
];
|
2017-06-06 17:39:14 +00:00
|
|
|
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\suppressWarnings();
|
2017-06-06 17:39:14 +00:00
|
|
|
$rc = RecentChange::newFromRow( $row );
|
2018-02-10 07:52:26 +00:00
|
|
|
Wikimedia\restoreWarnings();
|
2017-06-06 17:39:14 +00:00
|
|
|
|
|
|
|
|
$expected = [
|
|
|
|
|
'rc_foo' => 'AAA',
|
|
|
|
|
'rc_timestamp' => '20150921134808',
|
|
|
|
|
'rc_deleted' => 'bar',
|
|
|
|
|
'rc_comment' => 'comment',
|
|
|
|
|
'rc_comment_text' => 'comment',
|
|
|
|
|
'rc_comment_data' => null,
|
2017-09-12 17:12:29 +00:00
|
|
|
'rc_user' => $user->getId(),
|
|
|
|
|
'rc_user_text' => $user->getName(),
|
|
|
|
|
'rc_actor' => $actorId,
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2015-09-21 13:51:44 +00:00
|
|
|
$this->assertEquals( $expected, $rc->getAttributes() );
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-01 18:39:37 +00:00
|
|
|
public function provideParseParams() {
|
|
|
|
|
// $expected, $raw
|
|
|
|
|
yield 'extracting an array' => [
|
|
|
|
|
[
|
|
|
|
|
'root' => [
|
|
|
|
|
'A' => 1,
|
|
|
|
|
'B' => 'two'
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
'a:1:{s:4:"root";a:2:{s:1:"A";i:1;s:1:"B";s:3:"two";}}'
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2015-06-10 12:39:17 +00:00
|
|
|
|
2021-03-01 18:39:37 +00:00
|
|
|
yield 'null' => [ null, null ];
|
|
|
|
|
yield 'false' => [ null, serialize( false ) ];
|
|
|
|
|
yield 'non-array' => [ null, 'not-an-array' ];
|
2015-06-10 12:39:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-03-01 18:39:37 +00:00
|
|
|
* @covers RecentChange::parseParams
|
|
|
|
|
* @dataProvider provideParseParams
|
2015-06-10 12:39:17 +00:00
|
|
|
* @param array $expectedParseParams
|
|
|
|
|
* @param string|null $rawRcParams
|
|
|
|
|
*/
|
2021-03-01 18:39:37 +00:00
|
|
|
public function testParseParams( $expectedParseParams, $rawRcParams ) {
|
2015-06-10 12:39:17 +00:00
|
|
|
$rc = new RecentChange;
|
2016-02-17 09:09:32 +00:00
|
|
|
$rc->setAttribs( [ 'rc_params' => $rawRcParams ] );
|
2015-06-10 12:39:17 +00:00
|
|
|
|
|
|
|
|
$actualParseParams = $rc->parseParams();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $expectedParseParams, $actualParseParams );
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 09:34:13 +00:00
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function provideIsInRCLifespan() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2017-03-20 21:55:22 +00:00
|
|
|
[ 6000, -3000, 0, true ],
|
|
|
|
|
[ 3000, -6000, 0, false ],
|
|
|
|
|
[ 6000, -3000, 6000, true ],
|
|
|
|
|
[ 3000, -6000, 6000, true ],
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2015-09-21 09:34:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RecentChange::isInRCLifespan
|
|
|
|
|
* @dataProvider provideIsInRCLifespan
|
|
|
|
|
*/
|
2017-03-20 21:55:22 +00:00
|
|
|
public function testIsInRCLifespan( $maxAge, $offset, $tolerance, $expected ) {
|
2015-09-21 09:34:13 +00:00
|
|
|
$this->setMwGlobals( 'wgRCMaxAge', $maxAge );
|
2017-03-20 21:55:22 +00:00
|
|
|
// Calculate this here instead of the data provider because the provider
|
|
|
|
|
// is expanded early on and the full test suite may take longer than 100 minutes
|
|
|
|
|
// when coverage is enabled.
|
|
|
|
|
$timestamp = time() + $offset;
|
2015-09-21 09:34:13 +00:00
|
|
|
$this->assertEquals( $expected, RecentChange::isInRCLifespan( $timestamp, $tolerance ) );
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-21 13:58:56 +00:00
|
|
|
public function provideRCTypes() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[ RC_EDIT, 'edit' ],
|
|
|
|
|
[ RC_NEW, 'new' ],
|
|
|
|
|
[ RC_LOG, 'log' ],
|
|
|
|
|
[ RC_EXTERNAL, 'external' ],
|
|
|
|
|
[ RC_CATEGORIZE, 'categorize' ],
|
|
|
|
|
];
|
2015-09-21 13:58:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideRCTypes
|
|
|
|
|
* @covers RecentChange::parseFromRCType
|
|
|
|
|
*/
|
|
|
|
|
public function testParseFromRCType( $rcType, $type ) {
|
|
|
|
|
$this->assertEquals( $type, RecentChange::parseFromRCType( $rcType ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideRCTypes
|
|
|
|
|
* @covers RecentChange::parseToRCType
|
|
|
|
|
*/
|
|
|
|
|
public function testParseToRCType( $rcType, $type ) {
|
|
|
|
|
$this->assertEquals( $rcType, RecentChange::parseToRCType( $type ) );
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-13 15:52:48 +00:00
|
|
|
/**
|
2019-10-06 04:54:59 +00:00
|
|
|
* @return MockObject|PageProps
|
2016-04-13 15:52:48 +00:00
|
|
|
*/
|
|
|
|
|
private function getMockPageProps() {
|
|
|
|
|
return $this->getMockBuilder( PageProps::class )
|
|
|
|
|
->disableOriginalConstructor()
|
|
|
|
|
->getMock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideCategoryContent() {
|
|
|
|
|
return [
|
|
|
|
|
[ true ],
|
|
|
|
|
[ false ],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideCategoryContent
|
|
|
|
|
* @covers RecentChange::newForCategorization
|
|
|
|
|
*/
|
|
|
|
|
public function testHiddenCategoryChange( $isHidden ) {
|
|
|
|
|
$categoryTitle = Title::newFromText( 'CategoryPage', NS_CATEGORY );
|
|
|
|
|
|
|
|
|
|
$pageProps = $this->getMockPageProps();
|
|
|
|
|
$pageProps->expects( $this->once() )
|
|
|
|
|
->method( 'getProperties' )
|
|
|
|
|
->with( $categoryTitle, 'hiddencat' )
|
2016-05-06 20:25:56 +00:00
|
|
|
->will( $this->returnValue( $isHidden ? [ $categoryTitle->getArticleID() => '' ] : [] ) );
|
2016-04-13 15:52:48 +00:00
|
|
|
|
2020-05-21 03:47:11 +00:00
|
|
|
$this->setService( 'PageProps', $pageProps );
|
2016-04-13 15:52:48 +00:00
|
|
|
|
|
|
|
|
$rc = RecentChange::newForCategorization(
|
|
|
|
|
'0',
|
|
|
|
|
$categoryTitle,
|
|
|
|
|
$this->user,
|
|
|
|
|
$this->user_comment,
|
|
|
|
|
$this->title,
|
|
|
|
|
$categoryTitle->getLatestRevID(),
|
|
|
|
|
$categoryTitle->getLatestRevID(),
|
|
|
|
|
'0',
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $isHidden, $rc->getParam( 'hidden-cat' ) );
|
|
|
|
|
}
|
2021-03-04 03:23:56 +00:00
|
|
|
|
|
|
|
|
private function getDummyEditRecentChange(): RecentChange {
|
|
|
|
|
return RecentChange::notifyEdit(
|
|
|
|
|
MWTimestamp::now(),
|
|
|
|
|
$this->title,
|
|
|
|
|
false,
|
|
|
|
|
$this->user,
|
|
|
|
|
$this->user_comment,
|
|
|
|
|
0,
|
|
|
|
|
MWTimestamp::now(),
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideDoMarkPatrolledPermissions() {
|
|
|
|
|
yield 'auto, no autopatrol' => [
|
|
|
|
|
'lackingPermissions' => [ 'autopatrol' ],
|
|
|
|
|
'auto' => true,
|
|
|
|
|
'expectedError' => 'missing-autopatrol'
|
|
|
|
|
];
|
|
|
|
|
yield 'no patrol' => [
|
|
|
|
|
'lackingPermissions' => [ 'patrol' ],
|
|
|
|
|
'auto' => false,
|
|
|
|
|
'expectedError' => 'missing-patrol'
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideDoMarkPatrolledPermissions
|
|
|
|
|
* @covers RecentChange::doMarkPatrolled
|
|
|
|
|
*/
|
|
|
|
|
public function testDoMarkPatrolledPermissions(
|
|
|
|
|
array $lackingPermissions,
|
|
|
|
|
bool $auto,
|
|
|
|
|
string $expectError
|
|
|
|
|
) {
|
|
|
|
|
$rc = $this->getDummyEditRecentChange();
|
|
|
|
|
$performer = $this->mockRegisteredAuthority( function (
|
|
|
|
|
string $permission,
|
|
|
|
|
PageIdentity $page,
|
|
|
|
|
PermissionStatus $status
|
|
|
|
|
) use ( $lackingPermissions ) {
|
|
|
|
|
if ( in_array( $permission, $lackingPermissions ) ) {
|
|
|
|
|
$status->fatal( "missing-$permission" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} );
|
|
|
|
|
$errors = $rc->doMarkPatrolled(
|
|
|
|
|
$performer,
|
|
|
|
|
$auto
|
|
|
|
|
);
|
|
|
|
|
$this->assertContains( [ $expectError ], $errors );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RecentChange::doMarkPatrolled
|
|
|
|
|
*/
|
|
|
|
|
public function testDoMarkPatrolledPermissions_Hook() {
|
|
|
|
|
$rc = $this->getDummyEditRecentChange();
|
|
|
|
|
$this->setTemporaryHook( 'MarkPatrolled', function () {
|
|
|
|
|
return false;
|
|
|
|
|
} );
|
|
|
|
|
$errors = $rc->doMarkPatrolled( $this->mockRegisteredUltimateAuthority() );
|
|
|
|
|
$this->assertContains( [ 'hookaborted' ], $errors );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RecentChange::doMarkPatrolled
|
|
|
|
|
*/
|
|
|
|
|
public function testDoMarkPatrolledPermissions_Self() {
|
|
|
|
|
$rc = $this->getDummyEditRecentChange();
|
|
|
|
|
$errors = $rc->doMarkPatrolled(
|
|
|
|
|
$this->mockUserAuthorityWithoutPermissions( $this->user, [ 'autopatrol' ] )
|
|
|
|
|
);
|
|
|
|
|
$this->assertContains( [ 'markedaspatrollederror-noautopatrol' ], $errors );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RecentChange::doMarkPatrolled
|
|
|
|
|
*/
|
|
|
|
|
public function testDoMarkPatrolledPermissions_NoRcPatrol() {
|
|
|
|
|
$this->setMwGlobals( [
|
|
|
|
|
'wgUseRCPatrol' => false
|
|
|
|
|
] );
|
|
|
|
|
$rc = $this->getDummyEditRecentChange();
|
|
|
|
|
$errors = $rc->doMarkPatrolled( $this->mockRegisteredUltimateAuthority() );
|
|
|
|
|
$this->assertContains( [ 'rcpatroldisabled' ], $errors );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RecentChange::doMarkPatrolled
|
|
|
|
|
*/
|
|
|
|
|
public function testDoMarkPatrolled() {
|
|
|
|
|
$rc = $this->getDummyEditRecentChange();
|
|
|
|
|
$errors = $rc->doMarkPatrolled(
|
|
|
|
|
$this->mockUserAuthorityWithPermissions( $this->user, [ 'patrol', 'autopatrol' ] )
|
|
|
|
|
);
|
|
|
|
|
$this->assertEmpty( $errors );
|
|
|
|
|
|
|
|
|
|
$reloadedRC = RecentChange::newFromId( $rc->getAttribute( 'rc_id' ) );
|
|
|
|
|
$this->assertSame( '1', $reloadedRC->getAttribute( 'rc_patrolled' ) );
|
|
|
|
|
}
|
2012-02-25 21:22:49 +00:00
|
|
|
}
|