2017-08-27 15:29:18 +00:00
|
|
|
<?php
|
|
|
|
|
|
2018-09-20 17:29:04 +00:00
|
|
|
namespace MediaWiki\Tests\Revision;
|
2017-08-27 15:29:18 +00:00
|
|
|
|
|
|
|
|
use CommentStoreComment;
|
|
|
|
|
use InvalidArgumentException;
|
2018-09-20 17:29:04 +00:00
|
|
|
use MediaWiki\Revision\RevisionRecord;
|
|
|
|
|
use MediaWiki\Revision\RevisionSlots;
|
|
|
|
|
use MediaWiki\Revision\RevisionStoreRecord;
|
|
|
|
|
use MediaWiki\Revision\SlotRecord;
|
2017-08-27 15:29:18 +00:00
|
|
|
use MediaWiki\User\UserIdentity;
|
|
|
|
|
use MediaWiki\User\UserIdentityValue;
|
|
|
|
|
use MediaWikiTestCase;
|
|
|
|
|
use TextContent;
|
|
|
|
|
use Title;
|
|
|
|
|
|
|
|
|
|
/**
|
2018-09-20 17:29:04 +00:00
|
|
|
* @covers \MediaWiki\Revision\RevisionStoreRecord
|
|
|
|
|
* @covers \MediaWiki\Revision\RevisionRecord
|
2017-08-27 15:29:18 +00:00
|
|
|
*/
|
|
|
|
|
class RevisionStoreRecordTest extends MediaWikiTestCase {
|
|
|
|
|
|
2018-04-17 16:51:38 +00:00
|
|
|
use RevisionRecordTests;
|
|
|
|
|
|
2017-08-27 15:29:18 +00:00
|
|
|
/**
|
2017-11-15 12:02:40 +00:00
|
|
|
* @param array $rowOverrides
|
|
|
|
|
*
|
2017-08-27 15:29:18 +00:00
|
|
|
* @return RevisionStoreRecord
|
|
|
|
|
*/
|
2018-04-17 16:51:38 +00:00
|
|
|
protected function newRevision( array $rowOverrides = [] ) {
|
2017-08-27 15:29:18 +00:00
|
|
|
$title = Title::newFromText( 'Dummy' );
|
|
|
|
|
$title->resetArticleID( 17 );
|
|
|
|
|
|
2017-09-12 17:12:29 +00:00
|
|
|
$user = new UserIdentityValue( 11, 'Tester', 0 );
|
2017-08-27 15:29:18 +00:00
|
|
|
$comment = CommentStoreComment::newUnsavedComment( 'Hello World' );
|
|
|
|
|
|
2018-09-24 21:10:08 +00:00
|
|
|
$main = SlotRecord::newUnsaved( SlotRecord::MAIN, new TextContent( 'Lorem Ipsum' ) );
|
2017-08-27 15:29:18 +00:00
|
|
|
$aux = SlotRecord::newUnsaved( 'aux', new TextContent( 'Frumious Bandersnatch' ) );
|
|
|
|
|
$slots = new RevisionSlots( [ $main, $aux ] );
|
|
|
|
|
|
|
|
|
|
$row = [
|
|
|
|
|
'rev_id' => '7',
|
|
|
|
|
'rev_page' => strval( $title->getArticleID() ),
|
|
|
|
|
'rev_timestamp' => '20200101000000',
|
|
|
|
|
'rev_deleted' => 0,
|
|
|
|
|
'rev_minor_edit' => 0,
|
|
|
|
|
'rev_parent_id' => '5',
|
|
|
|
|
'rev_len' => $slots->computeSize(),
|
|
|
|
|
'rev_sha1' => $slots->computeSha1(),
|
|
|
|
|
'page_latest' => '18',
|
|
|
|
|
];
|
|
|
|
|
|
2017-11-15 12:02:40 +00:00
|
|
|
$row = array_merge( $row, $rowOverrides );
|
2017-08-27 15:29:18 +00:00
|
|
|
|
|
|
|
|
return new RevisionStoreRecord( $title, $user, $comment, (object)$row, $slots );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideConstructor() {
|
|
|
|
|
$title = Title::newFromText( 'Dummy' );
|
|
|
|
|
$title->resetArticleID( 17 );
|
|
|
|
|
|
2017-09-12 17:12:29 +00:00
|
|
|
$user = new UserIdentityValue( 11, 'Tester', 0 );
|
2017-08-27 15:29:18 +00:00
|
|
|
$comment = CommentStoreComment::newUnsavedComment( 'Hello World' );
|
|
|
|
|
|
2018-09-24 21:10:08 +00:00
|
|
|
$main = SlotRecord::newUnsaved( SlotRecord::MAIN, new TextContent( 'Lorem Ipsum' ) );
|
2017-08-27 15:29:18 +00:00
|
|
|
$aux = SlotRecord::newUnsaved( 'aux', new TextContent( 'Frumious Bandersnatch' ) );
|
|
|
|
|
$slots = new RevisionSlots( [ $main, $aux ] );
|
|
|
|
|
|
|
|
|
|
$protoRow = [
|
|
|
|
|
'rev_id' => '7',
|
|
|
|
|
'rev_page' => strval( $title->getArticleID() ),
|
|
|
|
|
'rev_timestamp' => '20200101000000',
|
|
|
|
|
'rev_deleted' => 0,
|
|
|
|
|
'rev_minor_edit' => 0,
|
|
|
|
|
'rev_parent_id' => '5',
|
|
|
|
|
'rev_len' => $slots->computeSize(),
|
|
|
|
|
'rev_sha1' => $slots->computeSha1(),
|
|
|
|
|
'page_latest' => '18',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
yield 'all info' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots,
|
|
|
|
|
'acmewiki'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
$row['rev_minor_edit'] = '1';
|
|
|
|
|
$row['rev_deleted'] = strval( RevisionRecord::DELETED_USER );
|
|
|
|
|
|
|
|
|
|
yield 'minor deleted' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
$row['page_latest'] = $row['rev_id'];
|
|
|
|
|
|
|
|
|
|
yield 'latest' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
unset( $row['rev_parent'] );
|
|
|
|
|
|
|
|
|
|
yield 'no parent' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
2018-04-17 16:51:38 +00:00
|
|
|
$row['rev_len'] = null;
|
|
|
|
|
$row['rev_sha1'] = '';
|
2017-08-27 15:29:18 +00:00
|
|
|
|
2018-04-17 16:51:38 +00:00
|
|
|
yield 'rev_len is null, rev_sha1 is ""' => [
|
2017-08-27 15:29:18 +00:00
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
yield 'no length, no hash' => [
|
|
|
|
|
Title::newFromText( 'DummyDoesNotExist' ),
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideConstructor
|
|
|
|
|
*
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @param UserIdentity $user
|
|
|
|
|
* @param CommentStoreComment $comment
|
|
|
|
|
* @param object $row
|
|
|
|
|
* @param RevisionSlots $slots
|
|
|
|
|
* @param bool $wikiId
|
|
|
|
|
*/
|
|
|
|
|
public function testConstructorAndGetters(
|
|
|
|
|
Title $title,
|
|
|
|
|
UserIdentity $user,
|
|
|
|
|
CommentStoreComment $comment,
|
|
|
|
|
$row,
|
|
|
|
|
RevisionSlots $slots,
|
|
|
|
|
$wikiId = false
|
|
|
|
|
) {
|
|
|
|
|
$rec = new RevisionStoreRecord( $title, $user, $comment, $row, $slots, $wikiId );
|
|
|
|
|
|
|
|
|
|
$this->assertSame( $title, $rec->getPageAsLinkTarget(), 'getPageAsLinkTarget' );
|
|
|
|
|
$this->assertSame( $user, $rec->getUser( RevisionRecord::RAW ), 'getUser' );
|
|
|
|
|
$this->assertSame( $comment, $rec->getComment(), 'getComment' );
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertSame( $slots, $rec->getSlots(), 'getSlots' );
|
2017-08-27 15:29:18 +00:00
|
|
|
$this->assertSame( $slots->getSlotRoles(), $rec->getSlotRoles(), 'getSlotRoles' );
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertSame( $slots->getSlots(), $rec->getSlots()->getSlots(), 'getSlots' );
|
2017-08-27 15:29:18 +00:00
|
|
|
$this->assertSame( $wikiId, $rec->getWikiId(), 'getWikiId' );
|
|
|
|
|
|
|
|
|
|
$this->assertSame( (int)$row->rev_id, $rec->getId(), 'getId' );
|
|
|
|
|
$this->assertSame( (int)$row->rev_page, $rec->getPageId(), 'getId' );
|
|
|
|
|
$this->assertSame( $row->rev_timestamp, $rec->getTimestamp(), 'getTimestamp' );
|
|
|
|
|
$this->assertSame( (int)$row->rev_deleted, $rec->getVisibility(), 'getVisibility' );
|
|
|
|
|
$this->assertSame( (bool)$row->rev_minor_edit, $rec->isMinor(), 'getIsMinor' );
|
|
|
|
|
|
|
|
|
|
if ( isset( $row->rev_parent_id ) ) {
|
|
|
|
|
$this->assertSame( (int)$row->rev_parent_id, $rec->getParentId(), 'getParentId' );
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertSame( 0, $rec->getParentId(), 'getParentId' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isset( $row->rev_len ) ) {
|
|
|
|
|
$this->assertSame( (int)$row->rev_len, $rec->getSize(), 'getSize' );
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertSame( $slots->computeSize(), $rec->getSize(), 'getSize' );
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-17 16:51:38 +00:00
|
|
|
if ( !empty( $row->rev_sha1 ) ) {
|
2017-08-27 15:29:18 +00:00
|
|
|
$this->assertSame( $row->rev_sha1, $rec->getSha1(), 'getSha1' );
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertSame( $slots->computeSha1(), $rec->getSha1(), 'getSha1' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isset( $row->page_latest ) ) {
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
(int)$row->rev_id === (int)$row->page_latest,
|
|
|
|
|
$rec->isCurrent(),
|
|
|
|
|
'isCurrent'
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
false,
|
|
|
|
|
$rec->isCurrent(),
|
|
|
|
|
'isCurrent'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideConstructorFailure() {
|
|
|
|
|
$title = Title::newFromText( 'Dummy' );
|
|
|
|
|
$title->resetArticleID( 17 );
|
|
|
|
|
|
2017-09-12 17:12:29 +00:00
|
|
|
$user = new UserIdentityValue( 11, 'Tester', 0 );
|
2017-08-27 15:29:18 +00:00
|
|
|
|
|
|
|
|
$comment = CommentStoreComment::newUnsavedComment( 'Hello World' );
|
|
|
|
|
|
2018-09-24 21:10:08 +00:00
|
|
|
$main = SlotRecord::newUnsaved( SlotRecord::MAIN, new TextContent( 'Lorem Ipsum' ) );
|
2017-08-27 15:29:18 +00:00
|
|
|
$aux = SlotRecord::newUnsaved( 'aux', new TextContent( 'Frumious Bandersnatch' ) );
|
|
|
|
|
$slots = new RevisionSlots( [ $main, $aux ] );
|
|
|
|
|
|
|
|
|
|
$protoRow = [
|
|
|
|
|
'rev_id' => '7',
|
|
|
|
|
'rev_page' => strval( $title->getArticleID() ),
|
|
|
|
|
'rev_timestamp' => '20200101000000',
|
|
|
|
|
'rev_deleted' => 0,
|
|
|
|
|
'rev_minor_edit' => 0,
|
|
|
|
|
'rev_parent_id' => '5',
|
|
|
|
|
'rev_len' => $slots->computeSize(),
|
|
|
|
|
'rev_sha1' => $slots->computeSha1(),
|
|
|
|
|
'page_latest' => '18',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
yield 'not a row' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
'not a row',
|
|
|
|
|
$slots,
|
|
|
|
|
'acmewiki'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
$row['rev_timestamp'] = 'kittens';
|
|
|
|
|
|
|
|
|
|
yield 'bad timestamp' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
$row['rev_page'] = 99;
|
|
|
|
|
|
|
|
|
|
yield 'page ID mismatch' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$row = $protoRow;
|
|
|
|
|
|
|
|
|
|
yield 'bad wiki' => [
|
|
|
|
|
$title,
|
|
|
|
|
$user,
|
|
|
|
|
$comment,
|
|
|
|
|
(object)$row,
|
|
|
|
|
$slots,
|
|
|
|
|
12345
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideConstructorFailure
|
|
|
|
|
*
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @param UserIdentity $user
|
|
|
|
|
* @param CommentStoreComment $comment
|
|
|
|
|
* @param object $row
|
|
|
|
|
* @param RevisionSlots $slots
|
|
|
|
|
* @param bool $wikiId
|
|
|
|
|
*/
|
|
|
|
|
public function testConstructorFailure(
|
|
|
|
|
Title $title,
|
|
|
|
|
UserIdentity $user,
|
|
|
|
|
CommentStoreComment $comment,
|
|
|
|
|
$row,
|
|
|
|
|
RevisionSlots $slots,
|
|
|
|
|
$wikiId = false
|
|
|
|
|
) {
|
|
|
|
|
$this->setExpectedException( InvalidArgumentException::class );
|
|
|
|
|
new RevisionStoreRecord( $title, $user, $comment, $row, $slots, $wikiId );
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-17 16:51:38 +00:00
|
|
|
public function provideIsCurrent() {
|
|
|
|
|
yield [
|
|
|
|
|
[
|
|
|
|
|
'rev_id' => 11,
|
|
|
|
|
'page_latest' => 11,
|
|
|
|
|
],
|
2017-08-27 15:29:18 +00:00
|
|
|
true,
|
|
|
|
|
];
|
2018-04-17 16:51:38 +00:00
|
|
|
yield [
|
|
|
|
|
[
|
|
|
|
|
'rev_id' => 11,
|
|
|
|
|
'page_latest' => 10,
|
|
|
|
|
],
|
2017-08-27 15:29:18 +00:00
|
|
|
false,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2018-04-17 16:51:38 +00:00
|
|
|
* @dataProvider provideIsCurrent
|
2017-08-27 15:29:18 +00:00
|
|
|
*/
|
2018-04-17 16:51:38 +00:00
|
|
|
public function testIsCurrent( $row, $current ) {
|
|
|
|
|
$rev = $this->newRevision( $row );
|
2017-08-27 15:29:18 +00:00
|
|
|
|
2018-04-17 16:51:38 +00:00
|
|
|
$this->assertSame( $current, $rev->isCurrent(), 'isCurrent()' );
|
2017-08-27 15:29:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideGetSlot_audience_latest() {
|
|
|
|
|
return $this->provideAudienceCheckData( RevisionRecord::DELETED_TEXT );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideGetSlot_audience_latest
|
|
|
|
|
*/
|
|
|
|
|
public function testGetSlot_audience_latest( $visibility, $groups, $userCan, $publicCan ) {
|
|
|
|
|
$this->forceStandardPermissions();
|
|
|
|
|
|
|
|
|
|
$user = $this->getTestUser( $groups )->getUser();
|
|
|
|
|
$rev = $this->newRevision(
|
|
|
|
|
[
|
|
|
|
|
'rev_deleted' => $visibility,
|
|
|
|
|
'rev_id' => 11,
|
|
|
|
|
'page_latest' => 11, // revision is current
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// NOTE: slot meta-data is never suppressed, just the content is!
|
2018-09-24 21:10:08 +00:00
|
|
|
$this->assertNotNull( $rev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW ), 'raw can' );
|
|
|
|
|
$this->assertNotNull( $rev->getSlot( SlotRecord::MAIN, RevisionRecord::FOR_PUBLIC ),
|
|
|
|
|
'public can' );
|
2017-08-27 15:29:18 +00:00
|
|
|
|
|
|
|
|
$this->assertNotNull(
|
2018-09-24 21:10:08 +00:00
|
|
|
$rev->getSlot( SlotRecord::MAIN, RevisionRecord::FOR_THIS_USER, $user ),
|
2017-08-27 15:29:18 +00:00
|
|
|
'user can'
|
|
|
|
|
);
|
|
|
|
|
|
2018-09-24 21:10:08 +00:00
|
|
|
$rev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getContent();
|
2017-08-27 15:29:18 +00:00
|
|
|
// NOTE: the content of the current revision is never suppressed!
|
|
|
|
|
// Check that getContent() doesn't throw SuppressedDataException
|
2018-09-24 21:10:08 +00:00
|
|
|
$rev->getSlot( SlotRecord::MAIN, RevisionRecord::FOR_PUBLIC )->getContent();
|
|
|
|
|
$rev->getSlot( SlotRecord::MAIN, RevisionRecord::FOR_THIS_USER, $user )->getContent();
|
2017-08-27 15:29:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|