2012-05-02 17:35:42 +00:00
|
|
|
<?php
|
2013-10-21 21:09:13 +00:00
|
|
|
|
2018-08-28 15:34:25 +00:00
|
|
|
use MediaWiki\Edit\PreparedEdit;
|
2018-06-29 09:59:51 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2018-09-20 17:29:04 +00:00
|
|
|
use MediaWiki\Revision\SlotRecord;
|
2018-01-27 01:48:19 +00:00
|
|
|
use MediaWiki\Storage\RevisionSlotsUpdate;
|
2018-03-09 22:05:47 +00:00
|
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
2018-01-27 01:48:19 +00:00
|
|
|
use Wikimedia\TestingAccessWrapper;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage
|
|
|
|
|
*/
|
2017-11-27 14:39:20 +00:00
|
|
|
abstract class WikiPageDbTestBase extends MediaWikiLangTestCase {
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
private $pagesToDelete;
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function __construct( $name = null, array $data = [], $dataName = '' ) {
|
2012-05-02 17:35:42 +00:00
|
|
|
parent::__construct( $name, $data, $dataName );
|
|
|
|
|
|
2013-02-14 11:56:23 +00:00
|
|
|
$this->tablesUsed = array_merge(
|
2012-10-08 15:26:11 +00:00
|
|
|
$this->tablesUsed,
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'page',
|
2013-02-14 11:56:23 +00:00
|
|
|
'revision',
|
2017-12-04 12:11:26 +00:00
|
|
|
'redirect',
|
2017-06-06 17:39:14 +00:00
|
|
|
'archive',
|
2017-11-30 18:23:01 +00:00
|
|
|
'category',
|
2017-04-21 16:17:59 +00:00
|
|
|
'ip_changes',
|
2013-02-14 11:56:23 +00:00
|
|
|
'text',
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2013-02-14 11:56:23 +00:00
|
|
|
'recentchanges',
|
|
|
|
|
'logging',
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2013-02-14 11:56:23 +00:00
|
|
|
'page_props',
|
|
|
|
|
'pagelinks',
|
|
|
|
|
'categorylinks',
|
|
|
|
|
'langlinks',
|
|
|
|
|
'externallinks',
|
|
|
|
|
'imagelinks',
|
|
|
|
|
'templatelinks',
|
2016-02-17 09:09:32 +00:00
|
|
|
'iwlinks' ] );
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-12 16:36:34 +00:00
|
|
|
protected function addCoreDBData() {
|
|
|
|
|
// Blank out. This would fail with a modified schema, and we don't need it.
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-14 11:57:43 +00:00
|
|
|
/**
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
abstract protected function getMcrMigrationStage();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return string[]
|
|
|
|
|
*/
|
|
|
|
|
abstract protected function getMcrTablesToReset();
|
|
|
|
|
|
2012-10-08 10:56:20 +00:00
|
|
|
protected function setUp() {
|
2012-05-23 21:09:15 +00:00
|
|
|
parent::setUp();
|
2018-05-14 11:57:43 +00:00
|
|
|
|
|
|
|
|
$this->tablesUsed += $this->getMcrTablesToReset();
|
|
|
|
|
|
2017-11-27 14:39:20 +00:00
|
|
|
$this->setMwGlobals( 'wgContentHandlerUseDB', $this->getContentHandlerUseDB() );
|
2018-05-14 11:57:43 +00:00
|
|
|
$this->setMwGlobals(
|
|
|
|
|
'wgMultiContentRevisionSchemaMigrationStage',
|
|
|
|
|
$this->getMcrMigrationStage()
|
|
|
|
|
);
|
2017-11-27 13:49:04 +00:00
|
|
|
$this->pagesToDelete = [];
|
2018-05-14 11:57:43 +00:00
|
|
|
|
|
|
|
|
$this->overrideMwServices();
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2012-10-08 10:56:20 +00:00
|
|
|
protected function tearDown() {
|
2017-11-27 13:49:04 +00:00
|
|
|
foreach ( $this->pagesToDelete as $p ) {
|
2012-05-02 17:35:42 +00:00
|
|
|
/* @var $p WikiPage */
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if ( $p->exists() ) {
|
|
|
|
|
$p->doDeleteArticle( "testing done." );
|
|
|
|
|
}
|
|
|
|
|
} catch ( MWException $ex ) {
|
|
|
|
|
// fail silently
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-23 21:09:15 +00:00
|
|
|
parent::tearDown();
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2017-11-27 14:39:20 +00:00
|
|
|
abstract protected function getContentHandlerUseDB();
|
|
|
|
|
|
2012-05-23 06:53:01 +00:00
|
|
|
/**
|
2014-10-31 10:44:16 +00:00
|
|
|
* @param Title|string $title
|
|
|
|
|
* @param string|null $model
|
2012-05-23 06:53:01 +00:00
|
|
|
* @return WikiPage
|
|
|
|
|
*/
|
2017-11-27 13:49:04 +00:00
|
|
|
private function newPage( $title, $model = null ) {
|
2012-09-19 18:07:56 +00:00
|
|
|
if ( is_string( $title ) ) {
|
2012-11-01 12:48:18 +00:00
|
|
|
$ns = $this->getDefaultWikitextNS();
|
|
|
|
|
$title = Title::newFromText( $title, $ns );
|
2012-09-19 18:07:56 +00:00
|
|
|
}
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$p = new WikiPage( $title );
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
$this->pagesToDelete[] = $p;
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-23 06:53:01 +00:00
|
|
|
/**
|
2014-04-17 18:43:42 +00:00
|
|
|
* @param string|Title|WikiPage $page
|
2018-03-09 22:05:47 +00:00
|
|
|
* @param string|Content|Content[] $content
|
2018-06-26 21:14:43 +00:00
|
|
|
* @param int|null $model
|
2012-05-23 06:53:01 +00:00
|
|
|
*
|
|
|
|
|
* @return WikiPage
|
|
|
|
|
*/
|
2018-03-09 22:05:47 +00:00
|
|
|
protected function createPage( $page, $content, $model = null, $user = null ) {
|
2012-11-01 12:48:18 +00:00
|
|
|
if ( is_string( $page ) || $page instanceof Title ) {
|
2012-09-19 18:07:56 +00:00
|
|
|
$page = $this->newPage( $page, $model );
|
2012-05-23 06:53:01 +00:00
|
|
|
}
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2018-03-09 22:05:47 +00:00
|
|
|
if ( !$user ) {
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( is_string( $content ) ) {
|
|
|
|
|
$content = ContentHandler::makeContent( $content, $page->getTitle(), $model );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !is_array( $content ) ) {
|
|
|
|
|
$content = [ 'main' => $content ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$updater = $page->newPageUpdater( $user );
|
|
|
|
|
|
|
|
|
|
foreach ( $content as $role => $cnt ) {
|
|
|
|
|
$updater->setContent( $role, $cnt );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$updater->saveRevision( CommentStoreComment::newUnsavedComment( "testing" ) );
|
2018-11-19 11:39:56 +00:00
|
|
|
if ( !$updater->wasSuccessful() ) {
|
|
|
|
|
$this->fail( $updater->getStatus()->getWikiText() );
|
|
|
|
|
}
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
return $page;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
2018-01-27 01:48:19 +00:00
|
|
|
* @covers WikiPage::prepareContentForEdit
|
|
|
|
|
*/
|
|
|
|
|
public function testPrepareContentForEdit() {
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
$sysop = $this->getTestUser( [ 'sysop' ] )->getUser();
|
|
|
|
|
|
|
|
|
|
$page = $this->createPage( __METHOD__, __METHOD__, null, $user );
|
|
|
|
|
$title = $page->getTitle();
|
|
|
|
|
|
|
|
|
|
$content = ContentHandler::makeContent(
|
|
|
|
|
"[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
|
|
|
|
|
. " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
|
|
|
|
|
$title,
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
|
|
|
|
$content2 = ContentHandler::makeContent(
|
|
|
|
|
"At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
|
|
|
|
|
. "Stet clita kasd [[gubergren]], no sea takimata sanctus est. ~~~~",
|
|
|
|
|
$title,
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$edit = $page->prepareContentForEdit( $content, null, $user, null, false );
|
|
|
|
|
|
|
|
|
|
$this->assertInstanceOf(
|
|
|
|
|
ParserOptions::class,
|
|
|
|
|
$edit->popts,
|
|
|
|
|
"pops"
|
|
|
|
|
);
|
|
|
|
|
$this->assertContains( '</a>', $edit->output->getText(), "output" );
|
|
|
|
|
$this->assertContains(
|
|
|
|
|
'consetetur sadipscing elitr',
|
|
|
|
|
$edit->output->getText(),
|
|
|
|
|
"output"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $content->equals( $edit->newContent ), "newContent field" );
|
|
|
|
|
$this->assertTrue( $content->equals( $edit->pstContent ), "pstContent field" );
|
|
|
|
|
$this->assertSame( $edit->output, $edit->output, "output field" );
|
|
|
|
|
$this->assertSame( $edit->popts, $edit->popts, "popts field" );
|
|
|
|
|
$this->assertSame( null, $edit->revid, "revid field" );
|
|
|
|
|
|
|
|
|
|
// Re-using the prepared info if possible
|
|
|
|
|
$sameEdit = $page->prepareContentForEdit( $content, null, $user, null, false );
|
2018-08-28 15:34:25 +00:00
|
|
|
$this->assertPreparedEditEquals( $edit, $sameEdit, 'equivalent PreparedEdit' );
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertSame( $edit->pstContent, $sameEdit->pstContent, 're-use output' );
|
|
|
|
|
$this->assertSame( $edit->output, $sameEdit->output, 're-use output' );
|
|
|
|
|
|
|
|
|
|
// Not re-using the same PreparedEdit if not possible
|
|
|
|
|
$rev = $page->getRevision();
|
|
|
|
|
$edit2 = $page->prepareContentForEdit( $content2, null, $user, null, false );
|
2018-08-28 15:34:25 +00:00
|
|
|
$this->assertPreparedEditNotEquals( $edit, $edit2 );
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertContains( 'At vero eos', $edit2->pstContent->serialize(), "content" );
|
|
|
|
|
|
|
|
|
|
// Check pre-safe transform
|
|
|
|
|
$this->assertContains( '[[gubergren]]', $edit2->pstContent->serialize() );
|
|
|
|
|
$this->assertNotContains( '~~~~', $edit2->pstContent->serialize() );
|
|
|
|
|
|
|
|
|
|
$edit3 = $page->prepareContentForEdit( $content2, null, $sysop, null, false );
|
2018-08-28 15:34:25 +00:00
|
|
|
$this->assertPreparedEditNotEquals( $edit2, $edit3 );
|
2018-01-27 01:48:19 +00:00
|
|
|
|
|
|
|
|
// TODO: test with passing revision, then same without revision.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2016-10-04 21:06:38 +00:00
|
|
|
* @covers WikiPage::doEditUpdates
|
2013-10-21 21:09:13 +00:00
|
|
|
*/
|
2018-01-27 01:48:19 +00:00
|
|
|
public function testDoEditUpdates() {
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
|
|
|
|
|
// NOTE: if site stats get out of whack and drop below 0,
|
|
|
|
|
// that causes a DB error during tear-down. So bump the
|
|
|
|
|
// numbers high enough to not drop below 0.
|
|
|
|
|
$siteStatsUpdate = SiteStatsUpdate::factory(
|
|
|
|
|
[ 'edits' => 1000, 'articles' => 1000, 'pages' => 1000 ]
|
|
|
|
|
);
|
|
|
|
|
$siteStatsUpdate->doUpdate();
|
|
|
|
|
|
|
|
|
|
$page = $this->createPage( __METHOD__, __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$revision = new Revision(
|
|
|
|
|
[
|
|
|
|
|
'id' => 9989,
|
|
|
|
|
'page' => $page->getId(),
|
|
|
|
|
'title' => $page->getTitle(),
|
|
|
|
|
'comment' => __METHOD__,
|
|
|
|
|
'minor_edit' => true,
|
|
|
|
|
'text' => __METHOD__ . ' [[|foo]][[bar]]', // PST turns [[|foo]] into [[foo]]
|
|
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
|
|
|
|
'timestamp' => '20170707040404',
|
|
|
|
|
'content_model' => CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'content_format' => CONTENT_FORMAT_WIKITEXT,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$page->doEditUpdates( $revision, $user );
|
|
|
|
|
|
|
|
|
|
// TODO: test various options; needs temporary hooks
|
|
|
|
|
|
|
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
|
|
|
|
$res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $page->getId() ] );
|
|
|
|
|
$n = $res->numRows();
|
|
|
|
|
$res->free();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 1, $n, 'pagelinks should contain only one link if PST was not applied' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doEditContent
|
|
|
|
|
* @covers WikiPage::prepareContentForEdit
|
|
|
|
|
*/
|
2012-04-24 16:00:21 +00:00
|
|
|
public function testDoEditContent() {
|
2017-12-22 20:40:13 +00:00
|
|
|
$this->setMwGlobals( 'wgPageCreationLog', true );
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2012-11-01 12:48:18 +00:00
|
|
|
$title = $page->getTitle();
|
2012-04-24 16:00:21 +00:00
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
$user1 = $this->getTestUser()->getUser();
|
|
|
|
|
// Use the confirmed group for user2 to make sure the user is different
|
|
|
|
|
$user2 = $this->getTestUser( [ 'confirmed' ] )->getUser();
|
|
|
|
|
|
2014-04-24 12:50:36 +00:00
|
|
|
$content = ContentHandler::makeContent(
|
|
|
|
|
"[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
|
2013-02-14 11:56:23 +00:00
|
|
|
. " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
|
2014-04-24 12:50:36 +00:00
|
|
|
$title,
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
2012-04-24 16:00:21 +00:00
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
$preparedEditBefore = $page->prepareContentForEdit( $content, null, $user1 );
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
$status = $page->doEditContent( $content, "[[testing]] 1", EDIT_NEW, false, $user1 );
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $status->isOK(), 'OK' );
|
|
|
|
|
$this->assertTrue( $status->value['new'], 'new' );
|
|
|
|
|
$this->assertNotNull( $status->value['revision'], 'revision' );
|
|
|
|
|
$this->assertSame( $status->value['revision']->getId(), $page->getRevision()->getId() );
|
|
|
|
|
$this->assertSame( $status->value['revision']->getSha1(), $page->getRevision()->getSha1() );
|
|
|
|
|
$this->assertTrue( $status->value['revision']->getContent()->equals( $content ), 'equals' );
|
|
|
|
|
|
|
|
|
|
$rev = $page->getRevision();
|
2018-07-08 19:01:32 +00:00
|
|
|
$preparedEditAfter = $page->prepareContentForEdit( $content, $rev, $user1 );
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertNotNull( $rev->getRecentChange() );
|
|
|
|
|
$this->assertSame( $rev->getId(), (int)$rev->getRecentChange()->getAttribute( 'rc_this_oldid' ) );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
// make sure that cached ParserOutput gets re-used throughout
|
|
|
|
|
$this->assertSame( $preparedEditBefore->output, $preparedEditAfter->output );
|
|
|
|
|
|
2017-12-22 20:40:13 +00:00
|
|
|
$id = $page->getId();
|
|
|
|
|
|
|
|
|
|
// Test page creation logging
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'logging',
|
|
|
|
|
[ 'log_type', 'log_action' ],
|
|
|
|
|
[ 'log_page' => $id ],
|
|
|
|
|
[ [ 'create', 'create' ] ]
|
|
|
|
|
);
|
|
|
|
|
|
2012-05-23 06:53:01 +00:00
|
|
|
$this->assertTrue( $title->getArticleID() > 0, "Title object should have new page id" );
|
2017-12-22 20:40:13 +00:00
|
|
|
$this->assertTrue( $id > 0, "WikiPage should have new page id" );
|
2012-04-24 16:00:21 +00:00
|
|
|
$this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
|
|
|
|
|
$this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
|
|
|
|
|
|
2012-05-23 06:53:01 +00:00
|
|
|
# ------------------------
|
2017-08-04 18:53:34 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2016-02-17 09:09:32 +00:00
|
|
|
$res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
|
2012-05-23 06:53:01 +00:00
|
|
|
$n = $res->numRows();
|
|
|
|
|
$res->free();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 1, $n, 'pagelinks should contain one link from the page' );
|
|
|
|
|
|
2012-04-24 16:00:21 +00:00
|
|
|
# ------------------------
|
|
|
|
|
$page = new WikiPage( $title );
|
|
|
|
|
|
|
|
|
|
$retrieved = $page->getContent();
|
|
|
|
|
$this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
# ------------------------
|
|
|
|
|
$page = new WikiPage( $title );
|
|
|
|
|
|
|
|
|
|
// try null edit, with a different user
|
|
|
|
|
$status = $page->doEditContent( $content, 'This changes nothing', EDIT_UPDATE, false, $user2 );
|
|
|
|
|
$this->assertTrue( $status->isOK(), 'OK' );
|
|
|
|
|
$this->assertFalse( $status->value['new'], 'new' );
|
|
|
|
|
$this->assertNull( $status->value['revision'], 'revision' );
|
|
|
|
|
$this->assertNotNull( $page->getRevision() );
|
|
|
|
|
$this->assertTrue( $page->getRevision()->getContent()->equals( $content ), 'equals' );
|
|
|
|
|
|
2012-04-24 16:00:21 +00:00
|
|
|
# ------------------------
|
2014-04-24 12:50:36 +00:00
|
|
|
$content = ContentHandler::makeContent(
|
|
|
|
|
"At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
|
2018-01-27 01:48:19 +00:00
|
|
|
. "Stet clita kasd [[gubergren]], no sea takimata sanctus est. ~~~~",
|
2014-04-24 12:50:36 +00:00
|
|
|
$title,
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
2012-04-24 16:00:21 +00:00
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
$status = $page->doEditContent( $content, "testing 2", EDIT_UPDATE );
|
|
|
|
|
$this->assertTrue( $status->isOK(), 'OK' );
|
|
|
|
|
$this->assertFalse( $status->value['new'], 'new' );
|
|
|
|
|
$this->assertNotNull( $status->value['revision'], 'revision' );
|
|
|
|
|
$this->assertSame( $status->value['revision']->getId(), $page->getRevision()->getId() );
|
|
|
|
|
$this->assertSame( $status->value['revision']->getSha1(), $page->getRevision()->getSha1() );
|
|
|
|
|
$this->assertFalse(
|
|
|
|
|
$status->value['revision']->getContent()->equals( $content ),
|
|
|
|
|
'not equals (PST must substitute signature)'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$rev = $page->getRevision();
|
|
|
|
|
$this->assertNotNull( $rev->getRecentChange() );
|
|
|
|
|
$this->assertSame( $rev->getId(), (int)$rev->getRecentChange()->getAttribute( 'rc_this_oldid' ) );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
|
|
|
|
# ------------------------
|
|
|
|
|
$page = new WikiPage( $title );
|
|
|
|
|
|
|
|
|
|
$retrieved = $page->getContent();
|
2018-01-27 01:48:19 +00:00
|
|
|
$newText = $retrieved->serialize();
|
|
|
|
|
$this->assertContains( '[[gubergren]]', $newText, 'New text must replace old text.' );
|
|
|
|
|
$this->assertNotContains( '~~~~', $newText, 'PST must substitute signature.' );
|
2012-04-30 13:32:31 +00:00
|
|
|
|
|
|
|
|
# ------------------------
|
2017-08-04 18:53:34 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2016-02-17 09:09:32 +00:00
|
|
|
$res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
|
2012-04-30 13:32:31 +00:00
|
|
|
$n = $res->numRows();
|
|
|
|
|
$res->free();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 2, $n, 'pagelinks should contain two links from the page' );
|
2012-04-24 16:00:21 +00:00
|
|
|
}
|
2012-09-19 18:07:56 +00:00
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doEditContent
|
|
|
|
|
*/
|
|
|
|
|
public function testDoEditContent_twice() {
|
|
|
|
|
$title = Title::newFromText( __METHOD__ );
|
|
|
|
|
$page = WikiPage::factory( $title );
|
|
|
|
|
$content = ContentHandler::makeContent( '$1 van $2', $title );
|
|
|
|
|
|
|
|
|
|
// Make sure we can do the exact same save twice.
|
|
|
|
|
// This tests checks that internal caches are reset as appropriate.
|
|
|
|
|
$status1 = $page->doEditContent( $content, __METHOD__ );
|
|
|
|
|
$status2 = $page->doEditContent( $content, __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $status1->isOK(), 'OK' );
|
|
|
|
|
$this->assertTrue( $status2->isOK(), 'OK' );
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( isset( $status1->value['revision'] ), 'OK' );
|
|
|
|
|
$this->assertFalse( isset( $status2->value['revision'] ), 'OK' );
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
2018-02-28 23:03:26 +00:00
|
|
|
* Undeletion is covered in PageArchiveTest::testUndeleteRevisions()
|
|
|
|
|
* TODO: Revision deletion
|
|
|
|
|
*
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::doDeleteArticle
|
2017-11-28 13:41:07 +00:00
|
|
|
* @covers WikiPage::doDeleteArticleReal
|
2013-10-21 21:09:13 +00:00
|
|
|
*/
|
2012-05-02 17:35:42 +00:00
|
|
|
public function testDoDeleteArticle() {
|
2014-04-24 12:50:36 +00:00
|
|
|
$page = $this->createPage(
|
2017-11-27 13:49:04 +00:00
|
|
|
__METHOD__,
|
2014-04-24 12:50:36 +00:00
|
|
|
"[[original text]] foo",
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
$id = $page->getId();
|
|
|
|
|
|
|
|
|
|
$page->doDeleteArticle( "testing deletion" );
|
|
|
|
|
|
2014-04-24 12:50:36 +00:00
|
|
|
$this->assertFalse(
|
|
|
|
|
$page->getTitle()->getArticleID() > 0,
|
|
|
|
|
"Title object should now have page id 0"
|
|
|
|
|
);
|
2012-05-23 06:53:01 +00:00
|
|
|
$this->assertFalse( $page->getId() > 0, "WikiPage should now have page id 0" );
|
2014-04-24 12:50:36 +00:00
|
|
|
$this->assertFalse(
|
|
|
|
|
$page->exists(),
|
|
|
|
|
"WikiPage::exists should return false after page was deleted"
|
|
|
|
|
);
|
|
|
|
|
$this->assertNull(
|
|
|
|
|
$page->getContent(),
|
|
|
|
|
"WikiPage::getContent should return null after page was deleted"
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$t = Title::newFromText( $page->getTitle()->getPrefixedText() );
|
2014-04-24 12:50:36 +00:00
|
|
|
$this->assertFalse(
|
|
|
|
|
$t->exists(),
|
|
|
|
|
"Title::exists should return false after page was deleted"
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2015-09-22 19:07:05 +00:00
|
|
|
// Run the job queue
|
|
|
|
|
JobQueueGroup::destroySingletons();
|
|
|
|
|
$jobs = new RunJobs;
|
2016-02-17 09:09:32 +00:00
|
|
|
$jobs->loadParamsAndArgs( null, [ 'quiet' => true ], null );
|
2015-09-22 19:07:05 +00:00
|
|
|
$jobs->execute();
|
|
|
|
|
|
2012-05-02 17:35:42 +00:00
|
|
|
# ------------------------
|
2017-08-04 18:53:34 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2016-02-17 09:09:32 +00:00
|
|
|
$res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
|
2012-05-02 17:35:42 +00:00
|
|
|
$n = $res->numRows();
|
|
|
|
|
$res->free();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 0, $n, 'pagelinks should contain no more links from the page' );
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-28 23:03:26 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doDeleteArticleReal
|
|
|
|
|
*/
|
|
|
|
|
public function testDoDeleteArticleReal_user0() {
|
|
|
|
|
$page = $this->createPage(
|
|
|
|
|
__METHOD__,
|
|
|
|
|
"[[original text]] foo",
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
|
|
|
|
$id = $page->getId();
|
|
|
|
|
|
|
|
|
|
$errorStack = '';
|
|
|
|
|
$status = $page->doDeleteArticleReal(
|
|
|
|
|
/* reason */ "testing user 0 deletion",
|
|
|
|
|
/* suppress */ false,
|
|
|
|
|
/* unused 1 */ null,
|
|
|
|
|
/* unused 2 */ null,
|
|
|
|
|
/* errorStack */ $errorStack,
|
|
|
|
|
null
|
|
|
|
|
);
|
|
|
|
|
$logId = $status->getValue();
|
|
|
|
|
$actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
|
2018-11-07 19:50:27 +00:00
|
|
|
$commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'log_comment' );
|
2018-02-28 23:03:26 +00:00
|
|
|
$this->assertSelect(
|
2018-11-07 19:50:27 +00:00
|
|
|
[ 'logging' ] + $actorQuery['tables'] + $commentQuery['tables'], /* table */
|
2018-02-28 23:03:26 +00:00
|
|
|
[
|
|
|
|
|
'log_type',
|
|
|
|
|
'log_action',
|
2018-11-07 19:50:27 +00:00
|
|
|
'log_comment' => $commentQuery['fields']['log_comment_text'],
|
2018-02-28 23:03:26 +00:00
|
|
|
'log_user' => $actorQuery['fields']['log_user'],
|
|
|
|
|
'log_user_text' => $actorQuery['fields']['log_user_text'],
|
|
|
|
|
'log_namespace',
|
|
|
|
|
'log_title',
|
|
|
|
|
],
|
|
|
|
|
[ 'log_id' => $logId ],
|
|
|
|
|
[ [
|
|
|
|
|
'delete',
|
|
|
|
|
'delete',
|
|
|
|
|
'testing user 0 deletion',
|
|
|
|
|
'0',
|
|
|
|
|
'127.0.0.1',
|
|
|
|
|
(string)$page->getTitle()->getNamespace(),
|
|
|
|
|
$page->getTitle()->getDBkey(),
|
|
|
|
|
] ],
|
|
|
|
|
[],
|
2018-11-07 19:50:27 +00:00
|
|
|
$actorQuery['joins'] + $commentQuery['joins']
|
2018-02-28 23:03:26 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doDeleteArticleReal
|
|
|
|
|
*/
|
|
|
|
|
public function testDoDeleteArticleReal_userSysop() {
|
|
|
|
|
$page = $this->createPage(
|
|
|
|
|
__METHOD__,
|
|
|
|
|
"[[original text]] foo",
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
|
|
|
|
$id = $page->getId();
|
|
|
|
|
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$errorStack = '';
|
|
|
|
|
$status = $page->doDeleteArticleReal(
|
|
|
|
|
/* reason */ "testing sysop deletion",
|
|
|
|
|
/* suppress */ false,
|
|
|
|
|
/* unused 1 */ null,
|
|
|
|
|
/* unused 2 */ null,
|
|
|
|
|
/* errorStack */ $errorStack,
|
|
|
|
|
$user
|
|
|
|
|
);
|
|
|
|
|
$logId = $status->getValue();
|
|
|
|
|
$actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
|
2018-11-07 19:50:27 +00:00
|
|
|
$commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'log_comment' );
|
2018-02-28 23:03:26 +00:00
|
|
|
$this->assertSelect(
|
2018-11-07 19:50:27 +00:00
|
|
|
[ 'logging' ] + $actorQuery['tables'] + $commentQuery['tables'], /* table */
|
2018-02-28 23:03:26 +00:00
|
|
|
[
|
|
|
|
|
'log_type',
|
|
|
|
|
'log_action',
|
2018-11-07 19:50:27 +00:00
|
|
|
'log_comment' => $commentQuery['fields']['log_comment_text'],
|
2018-02-28 23:03:26 +00:00
|
|
|
'log_user' => $actorQuery['fields']['log_user'],
|
|
|
|
|
'log_user_text' => $actorQuery['fields']['log_user_text'],
|
|
|
|
|
'log_namespace',
|
|
|
|
|
'log_title',
|
|
|
|
|
],
|
|
|
|
|
[ 'log_id' => $logId ],
|
|
|
|
|
[ [
|
|
|
|
|
'delete',
|
|
|
|
|
'delete',
|
|
|
|
|
'testing sysop deletion',
|
|
|
|
|
(string)$user->getId(),
|
|
|
|
|
$user->getName(),
|
|
|
|
|
(string)$page->getTitle()->getNamespace(),
|
|
|
|
|
$page->getTitle()->getDBkey(),
|
|
|
|
|
] ],
|
|
|
|
|
[],
|
2018-11-07 19:50:27 +00:00
|
|
|
$actorQuery['joins'] + $commentQuery['joins']
|
2018-02-28 23:03:26 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO: Test more stuff about suppression.
|
|
|
|
|
*
|
|
|
|
|
* @covers WikiPage::doDeleteArticleReal
|
|
|
|
|
*/
|
|
|
|
|
public function testDoDeleteArticleReal_suppress() {
|
|
|
|
|
$page = $this->createPage(
|
|
|
|
|
__METHOD__,
|
|
|
|
|
"[[original text]] foo",
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
|
|
|
|
$id = $page->getId();
|
|
|
|
|
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$errorStack = '';
|
|
|
|
|
$status = $page->doDeleteArticleReal(
|
|
|
|
|
/* reason */ "testing deletion",
|
|
|
|
|
/* suppress */ true,
|
|
|
|
|
/* unused 1 */ null,
|
|
|
|
|
/* unused 2 */ null,
|
|
|
|
|
/* errorStack */ $errorStack,
|
|
|
|
|
$user
|
|
|
|
|
);
|
|
|
|
|
$logId = $status->getValue();
|
|
|
|
|
$actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
|
2018-11-07 19:50:27 +00:00
|
|
|
$commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'log_comment' );
|
2018-02-28 23:03:26 +00:00
|
|
|
$this->assertSelect(
|
2018-11-07 19:50:27 +00:00
|
|
|
[ 'logging' ] + $actorQuery['tables'] + $commentQuery['tables'], /* table */
|
2018-02-28 23:03:26 +00:00
|
|
|
[
|
|
|
|
|
'log_type',
|
|
|
|
|
'log_action',
|
2018-11-07 19:50:27 +00:00
|
|
|
'log_comment' => $commentQuery['fields']['log_comment_text'],
|
2018-02-28 23:03:26 +00:00
|
|
|
'log_user' => $actorQuery['fields']['log_user'],
|
|
|
|
|
'log_user_text' => $actorQuery['fields']['log_user_text'],
|
|
|
|
|
'log_namespace',
|
|
|
|
|
'log_title',
|
|
|
|
|
],
|
|
|
|
|
[ 'log_id' => $logId ],
|
|
|
|
|
[ [
|
|
|
|
|
'suppress',
|
|
|
|
|
'delete',
|
|
|
|
|
'testing deletion',
|
|
|
|
|
(string)$user->getId(),
|
|
|
|
|
$user->getName(),
|
|
|
|
|
(string)$page->getTitle()->getNamespace(),
|
|
|
|
|
$page->getTitle()->getDBkey(),
|
|
|
|
|
] ],
|
|
|
|
|
[],
|
2018-11-07 19:50:27 +00:00
|
|
|
$actorQuery['joins'] + $commentQuery['joins']
|
2018-02-28 23:03:26 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertNull(
|
|
|
|
|
$page->getContent( Revision::FOR_PUBLIC ),
|
|
|
|
|
"WikiPage::getContent should return null after the page was suppressed for general users"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertNull(
|
|
|
|
|
$page->getContent( Revision::FOR_THIS_USER, null ),
|
|
|
|
|
"WikiPage::getContent should return null after the page was suppressed for user zero"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertNull(
|
|
|
|
|
$page->getContent( Revision::FOR_THIS_USER, $user ),
|
|
|
|
|
"WikiPage::getContent should return null after the page was suppressed even for a sysop"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doDeleteUpdates
|
|
|
|
|
*/
|
2012-05-18 16:58:21 +00:00
|
|
|
public function testDoDeleteUpdates() {
|
2018-03-09 22:05:47 +00:00
|
|
|
$user = $this->getTestUser()->getUser();
|
2014-04-24 12:50:36 +00:00
|
|
|
$page = $this->createPage(
|
2017-11-27 13:49:04 +00:00
|
|
|
__METHOD__,
|
2014-04-24 12:50:36 +00:00
|
|
|
"[[original text]] foo",
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
2012-05-18 16:58:21 +00:00
|
|
|
$id = $page->getId();
|
2018-03-09 22:05:47 +00:00
|
|
|
$page->loadPageData(); // make sure the current revision is cached.
|
2012-05-18 16:58:21 +00:00
|
|
|
|
2015-09-22 19:07:05 +00:00
|
|
|
// Similar to MovePage logic
|
2016-02-17 09:09:32 +00:00
|
|
|
wfGetDB( DB_MASTER )->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
|
2018-03-09 22:05:47 +00:00
|
|
|
$page->doDeleteUpdates( $page->getId(), $page->getContent(), $page->getRevision(), $user );
|
2012-05-18 16:58:21 +00:00
|
|
|
|
2015-09-22 19:07:05 +00:00
|
|
|
// Run the job queue
|
|
|
|
|
JobQueueGroup::destroySingletons();
|
|
|
|
|
$jobs = new RunJobs;
|
2016-02-17 09:09:32 +00:00
|
|
|
$jobs->loadParamsAndArgs( null, [ 'quiet' => true ], null );
|
2015-09-22 19:07:05 +00:00
|
|
|
$jobs->execute();
|
|
|
|
|
|
2012-05-18 16:58:21 +00:00
|
|
|
# ------------------------
|
2017-08-04 18:53:34 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2016-02-17 09:09:32 +00:00
|
|
|
$res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
|
2012-05-18 16:58:21 +00:00
|
|
|
$n = $res->numRows();
|
|
|
|
|
$res->free();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 0, $n, 'pagelinks should contain no more links from the page' );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-09 22:05:47 +00:00
|
|
|
/**
|
|
|
|
|
* @param string $name
|
|
|
|
|
*
|
|
|
|
|
* @return ContentHandler
|
|
|
|
|
*/
|
|
|
|
|
protected function defineMockContentModelForUpdateTesting( $name ) {
|
|
|
|
|
/** @var ContentHandler|MockObject $handler */
|
|
|
|
|
$handler = $this->getMockBuilder( TextContentHandler::class )
|
|
|
|
|
->setConstructorArgs( [ $name ] )
|
|
|
|
|
->setMethods(
|
|
|
|
|
[ 'getSecondaryDataUpdates', 'getDeletionUpdates', 'unserializeContent' ]
|
|
|
|
|
)
|
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
|
|
$dataUpdate = new MWCallableUpdate( 'time' );
|
|
|
|
|
$dataUpdate->_name = "$name data update";
|
|
|
|
|
|
|
|
|
|
$deletionUpdate = new MWCallableUpdate( 'time' );
|
|
|
|
|
$deletionUpdate->_name = "$name deletion update";
|
|
|
|
|
|
|
|
|
|
$handler->method( 'getSecondaryDataUpdates' )->willReturn( [ $dataUpdate ] );
|
|
|
|
|
$handler->method( 'getDeletionUpdates' )->willReturn( [ $deletionUpdate ] );
|
|
|
|
|
$handler->method( 'unserializeContent' )->willReturnCallback(
|
|
|
|
|
function ( $text ) use ( $handler ) {
|
|
|
|
|
return $this->createMockContent( $handler, $text );
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->mergeMwGlobalArrayValue(
|
|
|
|
|
'wgContentHandlers', [
|
|
|
|
|
$name => function () use ( $handler ){
|
|
|
|
|
return $handler;
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param ContentHandler $handler
|
|
|
|
|
* @param string $text
|
|
|
|
|
*
|
|
|
|
|
* @return Content
|
|
|
|
|
*/
|
|
|
|
|
protected function createMockContent( ContentHandler $handler, $text ) {
|
|
|
|
|
/** @var Content|MockObject $content */
|
|
|
|
|
$content = $this->getMockBuilder( TextContent::class )
|
|
|
|
|
->setConstructorArgs( [ $text ] )
|
|
|
|
|
->setMethods( [ 'getModel', 'getContentHandler' ] )
|
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
|
|
$content->method( 'getModel' )->willReturn( $handler->getModelID() );
|
|
|
|
|
$content->method( 'getContentHandler' )->willReturn( $handler );
|
|
|
|
|
|
|
|
|
|
return $content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGetDeletionUpdates() {
|
|
|
|
|
$m1 = $this->defineMockContentModelForUpdateTesting( 'M1' );
|
|
|
|
|
|
|
|
|
|
$mainContent1 = $this->createMockContent( $m1, 'main 1' );
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( Title::newFromText( __METHOD__ ) );
|
|
|
|
|
$page = $this->createPage(
|
|
|
|
|
$page,
|
|
|
|
|
[ 'main' => $mainContent1 ]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$dataUpdates = $page->getDeletionUpdates( $page->getRevisionRecord() );
|
|
|
|
|
$this->assertNotEmpty( $dataUpdates );
|
|
|
|
|
|
|
|
|
|
$updateNames = array_map( function ( $du ) {
|
|
|
|
|
return isset( $du->_name ) ? $du->_name : get_class( $du );
|
|
|
|
|
}, $dataUpdates );
|
|
|
|
|
|
|
|
|
|
$this->assertContains( LinksDeletionUpdate::class, $updateNames );
|
|
|
|
|
$this->assertContains( 'M1 deletion update', $updateNames );
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::getRevision
|
|
|
|
|
*/
|
2012-05-02 17:35:42 +00:00
|
|
|
public function testGetRevision() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$rev = $page->getRevision();
|
|
|
|
|
$this->assertNull( $rev );
|
|
|
|
|
|
|
|
|
|
# -----------------
|
2012-09-19 18:07:56 +00:00
|
|
|
$this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$rev = $page->getRevision();
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $page->getLatest(), $rev->getId() );
|
2012-04-24 16:00:21 +00:00
|
|
|
$this->assertEquals( "some text", $rev->getContent()->getNativeData() );
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::getContent
|
|
|
|
|
*/
|
2012-04-24 16:00:21 +00:00
|
|
|
public function testGetContent() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
|
|
|
|
$content = $page->getContent();
|
|
|
|
|
$this->assertNull( $content );
|
|
|
|
|
|
|
|
|
|
# -----------------
|
2012-09-19 18:07:56 +00:00
|
|
|
$this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
|
|
|
|
$content = $page->getContent();
|
|
|
|
|
$this->assertEquals( "some text", $content->getNativeData() );
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::exists
|
|
|
|
|
*/
|
2012-05-02 17:35:42 +00:00
|
|
|
public function testExists() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2012-05-02 17:35:42 +00:00
|
|
|
$this->assertFalse( $page->exists() );
|
|
|
|
|
|
|
|
|
|
# -----------------
|
2012-09-19 18:07:56 +00:00
|
|
|
$this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
|
2012-05-02 17:35:42 +00:00
|
|
|
$this->assertTrue( $page->exists() );
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$this->assertTrue( $page->exists() );
|
|
|
|
|
|
|
|
|
|
# -----------------
|
|
|
|
|
$page->doDeleteArticle( "done testing" );
|
|
|
|
|
$this->assertFalse( $page->exists() );
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$this->assertFalse( $page->exists() );
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function provideHasViewableContent() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[ 'WikiPageTest_testHasViewableContent', false, true ],
|
|
|
|
|
[ 'Special:WikiPageTest_testHasViewableContent', false ],
|
|
|
|
|
[ 'MediaWiki:WikiPageTest_testHasViewableContent', false ],
|
|
|
|
|
[ 'Special:Userlogin', true ],
|
|
|
|
|
[ 'MediaWiki:help', true ],
|
|
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-10-08 10:56:20 +00:00
|
|
|
* @dataProvider provideHasViewableContent
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::hasViewableContent
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
|
|
|
|
public function testHasViewableContent( $title, $viewable, $create = false ) {
|
|
|
|
|
$page = $this->newPage( $title );
|
|
|
|
|
$this->assertEquals( $viewable, $page->hasViewableContent() );
|
|
|
|
|
|
|
|
|
|
if ( $create ) {
|
2012-09-19 18:07:56 +00:00
|
|
|
$this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
|
2012-05-02 17:35:42 +00:00
|
|
|
$this->assertTrue( $page->hasViewableContent() );
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$this->assertTrue( $page->hasViewableContent() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function provideGetRedirectTarget() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[ 'WikiPageTest_testGetRedirectTarget_1', CONTENT_MODEL_WIKITEXT, "hello world", null ],
|
|
|
|
|
[
|
2014-04-24 12:50:36 +00:00
|
|
|
'WikiPageTest_testGetRedirectTarget_2',
|
|
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
"#REDIRECT [[hello world]]",
|
|
|
|
|
"Hello world"
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2018-10-09 15:51:04 +00:00
|
|
|
// The below added to protect against Media namespace
|
|
|
|
|
// redirects which throw a fatal: (T203942)
|
|
|
|
|
[
|
|
|
|
|
'WikiPageTest_testGetRedirectTarget_3',
|
|
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
"#REDIRECT [[Media:hello_world]]",
|
|
|
|
|
"File:Hello world"
|
|
|
|
|
],
|
2018-10-25 00:09:59 +00:00
|
|
|
// Test fragments longer than 255 bytes (T207876)
|
|
|
|
|
[
|
|
|
|
|
'WikiPageTest_testGetRedirectTarget_4',
|
|
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
// phpcs:ignore Generic.Files.LineLength
|
|
|
|
|
'#REDIRECT [[Foobar#🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴]]',
|
|
|
|
|
// phpcs:ignore Generic.Files.LineLength
|
|
|
|
|
'Foobar#🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴🏴...'
|
|
|
|
|
]
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-10-08 10:56:20 +00:00
|
|
|
* @dataProvider provideGetRedirectTarget
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::getRedirectTarget
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
2012-09-19 18:07:56 +00:00
|
|
|
public function testGetRedirectTarget( $title, $model, $text, $target ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$this->setMwGlobals( [
|
2014-07-07 23:21:09 +00:00
|
|
|
'wgCapitalLinks' => true,
|
2016-02-17 09:09:32 +00:00
|
|
|
] );
|
2014-07-07 23:21:09 +00:00
|
|
|
|
2012-09-19 18:07:56 +00:00
|
|
|
$page = $this->createPage( $title, $text, $model );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
2012-05-02 10:54:27 +00:00
|
|
|
# sanity check, because this test seems to fail for no reason for some people.
|
|
|
|
|
$c = $page->getContent();
|
2018-01-13 00:02:09 +00:00
|
|
|
$this->assertEquals( WikitextContent::class, get_class( $c ) );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
# now, test the actual redirect
|
|
|
|
|
$t = $page->getRedirectTarget();
|
2018-10-25 00:09:59 +00:00
|
|
|
$this->assertEquals( $target, is_null( $t ) ? null : $t->getFullText() );
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-10-08 10:56:20 +00:00
|
|
|
* @dataProvider provideGetRedirectTarget
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::isRedirect
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
2012-09-19 18:07:56 +00:00
|
|
|
public function testIsRedirect( $title, $model, $text, $target ) {
|
|
|
|
|
$page = $this->createPage( $title, $text, $model );
|
2012-05-02 17:35:42 +00:00
|
|
|
$this->assertEquals( !is_null( $target ), $page->isRedirect() );
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function provideIsCountable() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
// any
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'',
|
|
|
|
|
'any',
|
|
|
|
|
true
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'Foo',
|
|
|
|
|
'any',
|
|
|
|
|
true
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
// link
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'Foo',
|
|
|
|
|
'link',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'Foo [[bar]]',
|
|
|
|
|
'link',
|
|
|
|
|
true
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
// redirects
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'#REDIRECT [[bar]]',
|
|
|
|
|
'any',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'#REDIRECT [[bar]]',
|
|
|
|
|
'link',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
// not a content namespace
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'Talk:WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'Foo',
|
|
|
|
|
'any',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'Talk:WikiPageTest_testIsCountable',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'Foo [[bar]]',
|
|
|
|
|
'link',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
// not a content namespace, different model
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'MediaWiki:WikiPageTest_testIsCountable.js',
|
2013-02-14 11:56:23 +00:00
|
|
|
null,
|
|
|
|
|
'Foo',
|
|
|
|
|
'any',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'MediaWiki:WikiPageTest_testIsCountable.js',
|
2013-02-14 11:56:23 +00:00
|
|
|
null,
|
|
|
|
|
'Foo [[bar]]',
|
|
|
|
|
'link',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-10-08 10:56:20 +00:00
|
|
|
* @dataProvider provideIsCountable
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::isCountable
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
2012-09-19 18:07:56 +00:00
|
|
|
public function testIsCountable( $title, $model, $text, $mode, $expected ) {
|
2012-11-01 12:48:18 +00:00
|
|
|
global $wgContentHandlerUseDB;
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2012-11-01 12:48:18 +00:00
|
|
|
$this->setMwGlobals( 'wgArticleCountMethod', $mode );
|
|
|
|
|
|
|
|
|
|
$title = Title::newFromText( $title );
|
|
|
|
|
|
2014-04-24 12:50:36 +00:00
|
|
|
if ( !$wgContentHandlerUseDB
|
|
|
|
|
&& $model
|
|
|
|
|
&& ContentHandler::getDefaultModelFor( $title ) != $model
|
|
|
|
|
) {
|
2012-11-01 12:48:18 +00:00
|
|
|
$this->markTestSkipped( "Can not use non-default content model $model for "
|
2012-12-08 21:04:50 +00:00
|
|
|
. $title->getPrefixedDBkey() . " with \$wgContentHandlerUseDB disabled." );
|
2012-11-01 12:48:18 +00:00
|
|
|
}
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2012-09-19 18:07:56 +00:00
|
|
|
$page = $this->createPage( $title, $text, $model );
|
2012-05-23 06:53:01 +00:00
|
|
|
|
2012-04-24 16:00:21 +00:00
|
|
|
$editInfo = $page->prepareContentForEdit( $page->getContent() );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$v = $page->isCountable();
|
|
|
|
|
$w = $page->isCountable( $editInfo );
|
2012-05-23 06:53:01 +00:00
|
|
|
|
2014-04-24 12:50:36 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
|
$expected,
|
|
|
|
|
$v,
|
|
|
|
|
"isCountable( null ) returned unexpected value " . var_export( $v, true )
|
|
|
|
|
. " instead of " . var_export( $expected, true )
|
|
|
|
|
. " in mode `$mode` for text \"$text\""
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2014-04-24 12:50:36 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
|
$expected,
|
|
|
|
|
$w,
|
|
|
|
|
"isCountable( \$editInfo ) returned unexpected value " . var_export( $v, true )
|
|
|
|
|
. " instead of " . var_export( $expected, true )
|
|
|
|
|
. " in mode `$mode` for text \"$text\""
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function provideGetParserOutput() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2017-04-27 16:58:17 +00:00
|
|
|
[
|
|
|
|
|
CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
"hello ''world''\n",
|
|
|
|
|
"<div class=\"mw-parser-output\"><p>hello <i>world</i></p></div>"
|
|
|
|
|
],
|
2013-05-15 01:12:35 +00:00
|
|
|
// @todo more...?
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-10-08 10:56:20 +00:00
|
|
|
* @dataProvider provideGetParserOutput
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::getParserOutput
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
2012-09-19 18:07:56 +00:00
|
|
|
public function testGetParserOutput( $model, $text, $expectedHtml ) {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->createPage( __METHOD__, $text, $model );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2012-10-14 19:34:26 +00:00
|
|
|
$opt = $page->makeParserOptions( 'canonical' );
|
2012-05-02 17:35:42 +00:00
|
|
|
$po = $page->getParserOutput( $opt );
|
|
|
|
|
$text = $po->getText();
|
|
|
|
|
|
|
|
|
|
$text = trim( preg_replace( '/<!--.*?-->/sm', '', $text ) ); # strip injected comments
|
2017-04-27 16:58:17 +00:00
|
|
|
$text = preg_replace( '!\s*(</p>|</div>)!sm', '\1', $text ); # don't let tidy confuse us
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$this->assertEquals( $expectedHtml, $text );
|
2013-04-26 12:00:22 +00:00
|
|
|
|
2012-05-02 17:35:42 +00:00
|
|
|
return $po;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::getParserOutput
|
|
|
|
|
*/
|
2013-02-14 11:56:23 +00:00
|
|
|
public function testGetParserOutput_nonexisting() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = new WikiPage( Title::newFromText( __METHOD__ ) );
|
2012-10-15 12:36:03 +00:00
|
|
|
|
|
|
|
|
$opt = new ParserOptions();
|
|
|
|
|
$po = $page->getParserOutput( $opt );
|
|
|
|
|
|
|
|
|
|
$this->assertFalse( $po, "getParserOutput() shall return false for non-existing pages." );
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::getParserOutput
|
|
|
|
|
*/
|
2013-02-14 11:56:23 +00:00
|
|
|
public function testGetParserOutput_badrev() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->createPage( __METHOD__, 'dummy', CONTENT_MODEL_WIKITEXT );
|
2012-10-18 12:44:47 +00:00
|
|
|
|
|
|
|
|
$opt = new ParserOptions();
|
|
|
|
|
$po = $page->getParserOutput( $opt, $page->getLatest() + 1234 );
|
|
|
|
|
|
2013-05-15 01:12:35 +00:00
|
|
|
// @todo would be neat to also test deleted revision
|
2012-10-18 12:44:47 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse( $po, "getParserOutput() shall return false for non-existing revisions." );
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-24 12:50:36 +00:00
|
|
|
public static $sections =
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
"Intro
|
|
|
|
|
|
|
|
|
|
== stuff ==
|
|
|
|
|
hello world
|
|
|
|
|
|
|
|
|
|
== test ==
|
|
|
|
|
just a test
|
|
|
|
|
|
|
|
|
|
== foo ==
|
|
|
|
|
more stuff
|
|
|
|
|
";
|
|
|
|
|
|
2012-04-24 16:00:21 +00:00
|
|
|
public function dataReplaceSection() {
|
2015-09-11 13:44:59 +00:00
|
|
|
// NOTE: assume the Help namespace to contain wikitext
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[ 'Help:WikiPageTest_testReplaceSection',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
2017-07-23 01:24:09 +00:00
|
|
|
self::$sections,
|
2013-02-14 11:56:23 +00:00
|
|
|
"0",
|
|
|
|
|
"No more",
|
|
|
|
|
null,
|
2017-07-23 01:24:09 +00:00
|
|
|
trim( preg_replace( '/^Intro/sm', 'No more', self::$sections ) )
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'Help:WikiPageTest_testReplaceSection',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
2017-07-23 01:24:09 +00:00
|
|
|
self::$sections,
|
2013-02-14 11:56:23 +00:00
|
|
|
"",
|
|
|
|
|
"No more",
|
|
|
|
|
null,
|
|
|
|
|
"No more"
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'Help:WikiPageTest_testReplaceSection',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
2017-07-23 01:24:09 +00:00
|
|
|
self::$sections,
|
2013-02-14 11:56:23 +00:00
|
|
|
"2",
|
|
|
|
|
"== TEST ==\nmore fun",
|
|
|
|
|
null,
|
|
|
|
|
trim( preg_replace( '/^== test ==.*== foo ==/sm',
|
|
|
|
|
"== TEST ==\nmore fun\n\n== foo ==",
|
2017-07-23 01:24:09 +00:00
|
|
|
self::$sections ) )
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'Help:WikiPageTest_testReplaceSection',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
2017-07-23 01:24:09 +00:00
|
|
|
self::$sections,
|
2013-02-14 11:56:23 +00:00
|
|
|
"8",
|
|
|
|
|
"No more",
|
|
|
|
|
null,
|
2017-07-23 01:24:09 +00:00
|
|
|
trim( self::$sections )
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'Help:WikiPageTest_testReplaceSection',
|
2013-02-14 11:56:23 +00:00
|
|
|
CONTENT_MODEL_WIKITEXT,
|
2017-07-23 01:24:09 +00:00
|
|
|
self::$sections,
|
2013-02-14 11:56:23 +00:00
|
|
|
"new",
|
|
|
|
|
"No more",
|
|
|
|
|
"New",
|
2017-07-23 01:24:09 +00:00
|
|
|
trim( self::$sections ) . "\n\n== New ==\n\nNo more"
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-24 16:00:21 +00:00
|
|
|
/**
|
|
|
|
|
* @dataProvider dataReplaceSection
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::replaceSectionContent
|
2012-04-24 16:00:21 +00:00
|
|
|
*/
|
2014-04-24 12:50:36 +00:00
|
|
|
public function testReplaceSectionContent( $title, $model, $text, $section,
|
|
|
|
|
$with, $sectionTitle, $expected
|
|
|
|
|
) {
|
2012-09-19 18:07:56 +00:00
|
|
|
$page = $this->createPage( $title, $text, $model );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
2012-05-13 22:02:29 +00:00
|
|
|
$content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModel() );
|
2012-04-24 16:00:21 +00:00
|
|
|
$c = $page->replaceSectionContent( $section, $content, $sectionTitle );
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
|
|
|
|
|
}
|
2012-09-19 18:07:56 +00:00
|
|
|
|
2014-05-18 21:26:17 +00:00
|
|
|
/**
|
|
|
|
|
* @dataProvider dataReplaceSection
|
|
|
|
|
* @covers WikiPage::replaceSectionAtRev
|
|
|
|
|
*/
|
|
|
|
|
public function testReplaceSectionAtRev( $title, $model, $text, $section,
|
|
|
|
|
$with, $sectionTitle, $expected
|
|
|
|
|
) {
|
|
|
|
|
$page = $this->createPage( $title, $text, $model );
|
|
|
|
|
$baseRevId = $page->getLatest();
|
|
|
|
|
|
|
|
|
|
$content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModel() );
|
|
|
|
|
$c = $page->replaceSectionAtRev( $section, $content, $sectionTitle, $baseRevId );
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-01 11:47:20 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::getOldestRevision
|
|
|
|
|
*/
|
|
|
|
|
public function testGetOldestRevision() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2017-02-01 11:47:20 +00:00
|
|
|
$page->doEditContent(
|
|
|
|
|
new WikitextContent( 'one' ),
|
|
|
|
|
"first edit",
|
|
|
|
|
EDIT_NEW
|
|
|
|
|
);
|
|
|
|
|
$rev1 = $page->getRevision();
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$page->doEditContent(
|
|
|
|
|
new WikitextContent( 'two' ),
|
|
|
|
|
"second edit",
|
|
|
|
|
EDIT_UPDATE
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$page->doEditContent(
|
|
|
|
|
new WikitextContent( 'three' ),
|
|
|
|
|
"third edit",
|
|
|
|
|
EDIT_UPDATE
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// sanity check
|
|
|
|
|
$this->assertNotEquals(
|
|
|
|
|
$rev1->getId(),
|
|
|
|
|
$page->getRevision()->getId(),
|
|
|
|
|
'$page->getRevision()->getId()'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// actual test
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
$rev1->getId(),
|
|
|
|
|
$page->getOldestRevision()->getId(),
|
|
|
|
|
'$page->getOldestRevision()->getId()'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 17:35:42 +00:00
|
|
|
/**
|
2017-11-28 14:04:01 +00:00
|
|
|
* @covers WikiPage::doRollback
|
|
|
|
|
* @covers WikiPage::commitRollback
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
2017-11-28 14:04:01 +00:00
|
|
|
public function testDoRollback() {
|
2018-08-01 07:25:32 +00:00
|
|
|
// FIXME: fails under postgres
|
|
|
|
|
$this->markTestSkippedIfDbType( 'postgres' );
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
$admin = $this->getTestSysop()->getUser();
|
2017-11-28 14:04:01 +00:00
|
|
|
$user1 = $this->getTestUser()->getUser();
|
|
|
|
|
// Use the confirmed group for user2 to make sure the user is different
|
|
|
|
|
$user2 = $this->getTestUser( [ 'confirmed' ] )->getUser();
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2018-06-29 09:59:51 +00:00
|
|
|
// make sure we can test autopatrolling
|
|
|
|
|
$this->setMwGlobals( 'wgUseRCPatrol', true );
|
|
|
|
|
|
2018-04-27 14:04:36 +00:00
|
|
|
// TODO: MCR: test rollback of multiple slots!
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2017-11-28 14:04:01 +00:00
|
|
|
|
|
|
|
|
// Make some edits
|
|
|
|
|
$text = "one";
|
|
|
|
|
$status1 = $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ),
|
2013-02-14 11:56:23 +00:00
|
|
|
"section one", EDIT_NEW, false, $admin );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$text .= "\n\ntwo";
|
2017-11-28 14:04:01 +00:00
|
|
|
$status2 = $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ),
|
2013-02-14 11:56:23 +00:00
|
|
|
"adding section two", 0, false, $user1 );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$text .= "\n\nthree";
|
2017-11-28 14:04:01 +00:00
|
|
|
$status3 = $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ),
|
2013-02-14 11:56:23 +00:00
|
|
|
"adding section three", 0, false, $user2 );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2017-11-28 14:04:01 +00:00
|
|
|
/** @var Revision $rev1 */
|
|
|
|
|
/** @var Revision $rev2 */
|
|
|
|
|
/** @var Revision $rev3 */
|
|
|
|
|
$rev1 = $status1->getValue()['revision'];
|
|
|
|
|
$rev2 = $status2->getValue()['revision'];
|
|
|
|
|
$rev3 = $status3->getValue()['revision'];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* We are having issues with doRollback spuriously failing. Apparently
|
|
|
|
|
* the last revision somehow goes missing or not committed under some
|
|
|
|
|
* circumstances. So, make sure the revisions have the correct usernames.
|
|
|
|
|
*/
|
|
|
|
|
$this->assertEquals( 3, Revision::countByPageId( wfGetDB( DB_REPLICA ), $page->getId() ) );
|
|
|
|
|
$this->assertEquals( $admin->getName(), $rev1->getUserText() );
|
|
|
|
|
$this->assertEquals( $user1->getName(), $rev2->getUserText() );
|
|
|
|
|
$this->assertEquals( $user2->getName(), $rev3->getUserText() );
|
|
|
|
|
|
|
|
|
|
// Now, try the actual rollback
|
|
|
|
|
$token = $admin->getEditToken( 'rollback' );
|
|
|
|
|
$rollbackErrors = $page->doRollback(
|
2014-04-24 12:50:36 +00:00
|
|
|
$user2->getName(),
|
2017-11-28 14:04:01 +00:00
|
|
|
"testing rollback",
|
2014-04-24 12:50:36 +00:00
|
|
|
$token,
|
|
|
|
|
false,
|
2017-11-28 14:04:01 +00:00
|
|
|
$resultDetails,
|
2014-04-24 12:50:36 +00:00
|
|
|
$admin
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2017-11-28 14:04:01 +00:00
|
|
|
if ( $rollbackErrors ) {
|
|
|
|
|
$this->fail(
|
|
|
|
|
"Rollback failed:\n" .
|
|
|
|
|
print_r( $rollbackErrors, true ) . ";\n" .
|
|
|
|
|
print_r( $resultDetails, true )
|
|
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
2012-08-20 19:33:07 +00:00
|
|
|
$this->assertEquals( $rev2->getSha1(), $page->getRevision()->getSha1(),
|
2013-02-14 11:56:23 +00:00
|
|
|
"rollback did not revert to the correct revision" );
|
2012-04-24 16:00:21 +00:00
|
|
|
$this->assertEquals( "one\n\ntwo", $page->getContent()->getNativeData() );
|
2018-04-27 14:04:36 +00:00
|
|
|
|
2018-06-29 09:59:51 +00:00
|
|
|
$rc = MediaWikiServices::getInstance()->getRevisionStore()->getRecentChange(
|
|
|
|
|
$page->getRevision()->getRevisionRecord()
|
2014-04-24 12:50:36 +00:00
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2018-06-29 09:59:51 +00:00
|
|
|
$this->assertNotNull( $rc, 'RecentChanges entry' );
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
RecentChange::PRC_AUTOPATROLLED,
|
|
|
|
|
$rc->getAttribute( 'rc_patrolled' ),
|
|
|
|
|
'rc_patrolled'
|
2014-04-24 12:50:36 +00:00
|
|
|
);
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2018-06-29 09:59:51 +00:00
|
|
|
// TODO: MCR: assert origin once we write slot data
|
2018-09-24 21:10:08 +00:00
|
|
|
// $mainSlot = $page->getRevision()->getRevisionRecord()->getSlot( SlotRecord::MAIN );
|
2018-06-29 09:59:51 +00:00
|
|
|
// $this->assertTrue( $mainSlot->isInherited(), 'isInherited' );
|
|
|
|
|
// $this->assertSame( $rev2->getId(), $mainSlot->getOrigin(), 'getOrigin' );
|
2014-02-17 19:24:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doRollback
|
2017-11-28 13:41:07 +00:00
|
|
|
* @covers WikiPage::commitRollback
|
2014-02-17 19:24:13 +00:00
|
|
|
*/
|
|
|
|
|
public function testDoRollbackFailureSameContent() {
|
2017-11-27 13:49:04 +00:00
|
|
|
$admin = $this->getTestSysop()->getUser();
|
2014-02-17 19:24:13 +00:00
|
|
|
|
|
|
|
|
$text = "one";
|
2017-11-27 13:49:04 +00:00
|
|
|
$page = $this->newPage( __METHOD__ );
|
2014-04-24 12:50:36 +00:00
|
|
|
$page->doEditContent(
|
|
|
|
|
ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
|
|
|
|
|
"section one",
|
|
|
|
|
EDIT_NEW,
|
|
|
|
|
false,
|
|
|
|
|
$admin
|
|
|
|
|
);
|
2014-02-17 19:24:13 +00:00
|
|
|
$rev1 = $page->getRevision();
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
$user1 = $this->getTestUser( [ 'sysop' ] )->getUser();
|
2014-02-17 19:24:13 +00:00
|
|
|
$text .= "\n\ntwo";
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
2014-04-24 12:50:36 +00:00
|
|
|
$page->doEditContent(
|
|
|
|
|
ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
|
|
|
|
|
"adding section two",
|
|
|
|
|
0,
|
|
|
|
|
false,
|
|
|
|
|
$user1
|
|
|
|
|
);
|
2014-02-17 19:24:13 +00:00
|
|
|
|
|
|
|
|
# now, do a the rollback from the same user was doing the edit before
|
2016-02-17 09:09:32 +00:00
|
|
|
$resultDetails = [];
|
User group memberships that expire
This patch adds an ug_expiry column to the user_groups table, a timestamp
giving a date when the user group expires. A new UserGroupMembership class,
based on the Block class, manages entries in this table.
When the expiry date passes, the row in user_groups is ignored, and will
eventually be purged from the DB when UserGroupMembership::insert is next
called. Old, expired user group memberships are not kept; instead, the log
entries are available to find the history of these memberships, similar
to the way it has always worked for blocks and protections.
Anyone getting user group info through the User object will get correct
information. However, code that reads the user_groups table directly will
now need to skip over rows with ug_expiry < wfTimestampNow(). See
UsersPager for an example of how to do this.
NULL is used to represent infinite (no) expiry, rather than a string
'infinity' or similar (except in the API). This allows existing user group
assignments and log entries, which are all infinite in duration, to be
treated the same as new, infinite-length memberships, without special
casing everything.
The whole thing is behind the temporary feature flag
$wgDisableUserGroupExpiry, in accordance with the WMF schema change policy.
The opportunity has been taken to refactor some static user-group-related
functions out of User into UserGroupMembership, and also to add a primary
key (ug_user, ug_group) to the user_groups table.
There are a few breaking changes:
- UserRightsProxy-like objects are now required to have a
getGroupMemberships() function.
- $user->mGroups (on a User object) is no longer present.
- Some protected functions in UsersPager are altered or removed.
- The UsersPagerDoBatchLookups hook (unused in any Wikimedia Git-hosted
extension) has a change of parameter.
Bug: T12493
Depends-On: Ia9616e1e35184fed9058d2d39afbe1038f56d7fa
Depends-On: I86eb1d5619347ce54a5f33a591417742ebe5d6f8
Change-Id: I93c955dc7a970f78e32aa503c01c67da30971d1a
2017-01-12 06:07:56 +00:00
|
|
|
$token = $user1->getEditToken( 'rollback' );
|
2014-04-24 12:50:36 +00:00
|
|
|
$errors = $page->doRollback(
|
|
|
|
|
$user1->getName(),
|
|
|
|
|
"testing revert same user",
|
|
|
|
|
$token,
|
|
|
|
|
false,
|
|
|
|
|
$resultDetails,
|
|
|
|
|
$admin
|
|
|
|
|
);
|
2014-02-17 19:24:13 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$this->assertEquals( [], $errors, "Rollback failed same user" );
|
2014-02-17 19:24:13 +00:00
|
|
|
|
|
|
|
|
# now, try the rollback
|
2016-02-17 09:09:32 +00:00
|
|
|
$resultDetails = [];
|
User group memberships that expire
This patch adds an ug_expiry column to the user_groups table, a timestamp
giving a date when the user group expires. A new UserGroupMembership class,
based on the Block class, manages entries in this table.
When the expiry date passes, the row in user_groups is ignored, and will
eventually be purged from the DB when UserGroupMembership::insert is next
called. Old, expired user group memberships are not kept; instead, the log
entries are available to find the history of these memberships, similar
to the way it has always worked for blocks and protections.
Anyone getting user group info through the User object will get correct
information. However, code that reads the user_groups table directly will
now need to skip over rows with ug_expiry < wfTimestampNow(). See
UsersPager for an example of how to do this.
NULL is used to represent infinite (no) expiry, rather than a string
'infinity' or similar (except in the API). This allows existing user group
assignments and log entries, which are all infinite in duration, to be
treated the same as new, infinite-length memberships, without special
casing everything.
The whole thing is behind the temporary feature flag
$wgDisableUserGroupExpiry, in accordance with the WMF schema change policy.
The opportunity has been taken to refactor some static user-group-related
functions out of User into UserGroupMembership, and also to add a primary
key (ug_user, ug_group) to the user_groups table.
There are a few breaking changes:
- UserRightsProxy-like objects are now required to have a
getGroupMemberships() function.
- $user->mGroups (on a User object) is no longer present.
- Some protected functions in UsersPager are altered or removed.
- The UsersPagerDoBatchLookups hook (unused in any Wikimedia Git-hosted
extension) has a change of parameter.
Bug: T12493
Depends-On: Ia9616e1e35184fed9058d2d39afbe1038f56d7fa
Depends-On: I86eb1d5619347ce54a5f33a591417742ebe5d6f8
Change-Id: I93c955dc7a970f78e32aa503c01c67da30971d1a
2017-01-12 06:07:56 +00:00
|
|
|
$token = $admin->getEditToken( 'rollback' );
|
2014-04-24 12:50:36 +00:00
|
|
|
$errors = $page->doRollback(
|
|
|
|
|
$user1->getName(),
|
|
|
|
|
"testing revert",
|
|
|
|
|
$token,
|
|
|
|
|
false,
|
|
|
|
|
$resultDetails,
|
|
|
|
|
$admin
|
|
|
|
|
);
|
2014-02-17 19:24:13 +00:00
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
'alreadyrolled',
|
|
|
|
|
__METHOD__,
|
|
|
|
|
$user1->getName(),
|
|
|
|
|
$admin->getName(),
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
$errors,
|
|
|
|
|
"Rollback not failed"
|
|
|
|
|
);
|
2014-02-17 19:24:13 +00:00
|
|
|
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$this->assertEquals( $rev1->getSha1(), $page->getRevision()->getSha1(),
|
2013-02-14 11:56:23 +00:00
|
|
|
"rollback did not revert to the correct revision" );
|
2012-05-14 21:24:18 +00:00
|
|
|
$this->assertEquals( "one", $page->getContent()->getNativeData() );
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2017-11-09 11:13:16 +00:00
|
|
|
/**
|
|
|
|
|
* Tests tagging for edits that do rollback action
|
|
|
|
|
* @covers WikiPage::doRollback
|
|
|
|
|
*/
|
|
|
|
|
public function testDoRollbackTagging() {
|
|
|
|
|
if ( !in_array( 'mw-rollback', ChangeTags::getSoftwareTags() ) ) {
|
|
|
|
|
$this->markTestSkipped( 'Rollback tag deactivated, skipped the test.' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$admin = new User();
|
|
|
|
|
$admin->setName( 'Administrator' );
|
|
|
|
|
$admin->addToDatabase();
|
|
|
|
|
|
|
|
|
|
$text = 'First line';
|
|
|
|
|
$page = $this->newPage( 'WikiPageTest_testDoRollbackTagging' );
|
|
|
|
|
$page->doEditContent(
|
|
|
|
|
ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
|
|
|
|
|
'Added first line',
|
|
|
|
|
EDIT_NEW,
|
|
|
|
|
false,
|
|
|
|
|
$admin
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$secondUser = new User();
|
|
|
|
|
$secondUser->setName( '92.65.217.32' );
|
|
|
|
|
$text .= '\n\nSecond line';
|
|
|
|
|
$page = new WikiPage( $page->getTitle() );
|
|
|
|
|
$page->doEditContent(
|
|
|
|
|
ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
|
|
|
|
|
'Adding second line',
|
|
|
|
|
0,
|
|
|
|
|
false,
|
|
|
|
|
$secondUser
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Now, try the rollback
|
|
|
|
|
$admin->addGroup( 'sysop' ); // Make the test user a sysop
|
|
|
|
|
$token = $admin->getEditToken( 'rollback' );
|
|
|
|
|
$errors = $page->doRollback(
|
|
|
|
|
$secondUser->getName(),
|
|
|
|
|
'testing rollback',
|
|
|
|
|
$token,
|
|
|
|
|
false,
|
|
|
|
|
$resultDetails,
|
|
|
|
|
$admin
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// If doRollback completed without errors
|
|
|
|
|
if ( $errors === [] ) {
|
|
|
|
|
$tags = $resultDetails[ 'tags' ];
|
|
|
|
|
$this->assertContains( 'mw-rollback', $tags );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function provideGetAutoDeleteReason() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[
|
|
|
|
|
[],
|
2012-05-02 17:35:42 +00:00
|
|
|
false,
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
[ "first edit", null ],
|
|
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
"/first edit.*only contributor/",
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
[ "first edit", null ],
|
|
|
|
|
[ "second edit", null ],
|
|
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
"/second edit.*only contributor/",
|
|
|
|
|
true
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
[ "first edit", "127.0.2.22" ],
|
|
|
|
|
[ "second edit", "127.0.3.33" ],
|
|
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
"/second edit/",
|
|
|
|
|
true
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
[
|
2014-04-24 12:50:36 +00:00
|
|
|
"first edit: "
|
|
|
|
|
. "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
|
|
|
|
|
. " nonumy eirmod tempor invidunt ut labore et dolore magna "
|
|
|
|
|
. "aliquyam erat, sed diam voluptua. At vero eos et accusam "
|
|
|
|
|
. "et justo duo dolores et ea rebum. Stet clita kasd gubergren, "
|
|
|
|
|
. "no sea takimata sanctus est Lorem ipsum dolor sit amet.'",
|
|
|
|
|
null
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
'/first edit:.*\.\.\."/',
|
|
|
|
|
false
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
[ "first edit", "127.0.2.22" ],
|
|
|
|
|
[ "", "127.0.3.33" ],
|
|
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
"/before blanking.*first edit/",
|
|
|
|
|
true
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2012-10-08 10:56:20 +00:00
|
|
|
* @dataProvider provideGetAutoDeleteReason
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers WikiPage::getAutoDeleteReason
|
2012-05-02 17:35:42 +00:00
|
|
|
*/
|
|
|
|
|
public function testGetAutoDeleteReason( $edits, $expectedResult, $expectedHistory ) {
|
|
|
|
|
global $wgUser;
|
|
|
|
|
|
2015-09-11 13:44:59 +00:00
|
|
|
// NOTE: assume Help namespace to contain wikitext
|
2012-09-19 18:07:56 +00:00
|
|
|
$page = $this->newPage( "Help:WikiPageTest_testGetAutoDeleteReason" );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$c = 1;
|
|
|
|
|
|
|
|
|
|
foreach ( $edits as $edit ) {
|
|
|
|
|
$user = new User();
|
|
|
|
|
|
2013-02-14 11:56:23 +00:00
|
|
|
if ( !empty( $edit[1] ) ) {
|
|
|
|
|
$user->setName( $edit[1] );
|
|
|
|
|
} else {
|
|
|
|
|
$user = $wgUser;
|
|
|
|
|
}
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2012-05-13 22:02:29 +00:00
|
|
|
$content = ContentHandler::makeContent( $edit[0], $page->getTitle(), $page->getContentModel() );
|
2012-04-24 16:00:21 +00:00
|
|
|
|
|
|
|
|
$page->doEditContent( $content, "test edit $c", $c < 2 ? EDIT_NEW : 0, false, $user );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$c += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$reason = $page->getAutoDeleteReason( $hasHistory );
|
|
|
|
|
|
2013-02-14 11:56:23 +00:00
|
|
|
if ( is_bool( $expectedResult ) || is_null( $expectedResult ) ) {
|
|
|
|
|
$this->assertEquals( $expectedResult, $reason );
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertTrue( (bool)preg_match( $expectedResult, $reason ),
|
|
|
|
|
"Autosummary didn't match expected pattern $expectedResult: $reason" );
|
|
|
|
|
}
|
2012-05-02 17:35:42 +00:00
|
|
|
|
2012-08-20 19:33:07 +00:00
|
|
|
$this->assertEquals( $expectedHistory, $hasHistory,
|
2013-02-14 11:56:23 +00:00
|
|
|
"expected \$hasHistory to be " . var_export( $expectedHistory, true ) );
|
2012-05-02 17:35:42 +00:00
|
|
|
|
|
|
|
|
$page->doDeleteArticle( "done" );
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function providePreSaveTransform() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
|
|
|
|
[ 'hello this is ~~~',
|
2013-02-14 11:56:23 +00:00
|
|
|
"hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
|
2013-02-14 11:56:23 +00:00
|
|
|
'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
];
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-24 10:54:02 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::factory
|
|
|
|
|
*/
|
|
|
|
|
public function testWikiPageFactory() {
|
|
|
|
|
$title = Title::makeTitle( NS_FILE, 'Someimage.png' );
|
|
|
|
|
$page = WikiPage::factory( $title );
|
2018-01-13 00:02:09 +00:00
|
|
|
$this->assertEquals( WikiFilePage::class, get_class( $page ) );
|
2013-10-24 10:54:02 +00:00
|
|
|
|
|
|
|
|
$title = Title::makeTitle( NS_CATEGORY, 'SomeCategory' );
|
|
|
|
|
$page = WikiPage::factory( $title );
|
2018-01-13 00:02:09 +00:00
|
|
|
$this->assertEquals( WikiCategoryPage::class, get_class( $page ) );
|
2013-10-24 10:54:02 +00:00
|
|
|
|
|
|
|
|
$title = Title::makeTitle( NS_MAIN, 'SomePage' );
|
|
|
|
|
$page = WikiPage::factory( $title );
|
2018-01-13 00:02:09 +00:00
|
|
|
$this->assertEquals( WikiPage::class, get_class( $page ) );
|
2013-10-24 10:54:02 +00:00
|
|
|
}
|
2017-06-06 17:39:14 +00:00
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::loadPageData
|
|
|
|
|
* @covers WikiPage::wasLoadedFrom
|
|
|
|
|
*/
|
|
|
|
|
public function testLoadPageData() {
|
|
|
|
|
$title = Title::makeTitle( NS_MAIN, 'SomePage' );
|
|
|
|
|
$page = WikiPage::factory( $title );
|
|
|
|
|
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_NORMAL ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_LATEST ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_LOCKING ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_EXCLUSIVE ) );
|
|
|
|
|
|
|
|
|
|
$page->loadPageData( IDBAccessObject::READ_NORMAL );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_NORMAL ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_LATEST ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_LOCKING ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_EXCLUSIVE ) );
|
|
|
|
|
|
|
|
|
|
$page->loadPageData( IDBAccessObject::READ_LATEST );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_NORMAL ) );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_LATEST ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_LOCKING ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_EXCLUSIVE ) );
|
|
|
|
|
|
|
|
|
|
$page->loadPageData( IDBAccessObject::READ_LOCKING );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_NORMAL ) );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_LATEST ) );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_LOCKING ) );
|
|
|
|
|
$this->assertFalse( $page->wasLoadedFrom( IDBAccessObject::READ_EXCLUSIVE ) );
|
|
|
|
|
|
|
|
|
|
$page->loadPageData( IDBAccessObject::READ_EXCLUSIVE );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_NORMAL ) );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_LATEST ) );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_LOCKING ) );
|
|
|
|
|
$this->assertTrue( $page->wasLoadedFrom( IDBAccessObject::READ_EXCLUSIVE ) );
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-06 17:39:14 +00:00
|
|
|
/**
|
|
|
|
|
* @dataProvider provideCommentMigrationOnDeletion
|
2017-11-27 13:49:04 +00:00
|
|
|
*
|
|
|
|
|
* @param int $writeStage
|
|
|
|
|
* @param int $readStage
|
2017-06-06 17:39:14 +00:00
|
|
|
*/
|
2017-11-27 13:49:04 +00:00
|
|
|
public function testCommentMigrationOnDeletion( $writeStage, $readStage ) {
|
|
|
|
|
$this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', $writeStage );
|
2018-01-24 23:41:01 +00:00
|
|
|
$this->overrideMwServices();
|
|
|
|
|
|
2017-06-06 17:39:14 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
|
|
|
|
|
|
|
|
|
$page = $this->createPage(
|
2017-11-27 13:49:04 +00:00
|
|
|
__METHOD__,
|
2017-06-06 17:39:14 +00:00
|
|
|
"foo",
|
|
|
|
|
CONTENT_MODEL_WIKITEXT
|
|
|
|
|
);
|
|
|
|
|
$revid = $page->getLatest();
|
2017-11-27 13:49:04 +00:00
|
|
|
if ( $writeStage > MIGRATION_OLD ) {
|
2017-06-06 17:39:14 +00:00
|
|
|
$comment_id = $dbr->selectField(
|
|
|
|
|
'revision_comment_temp',
|
|
|
|
|
'revcomment_comment_id',
|
|
|
|
|
[ 'revcomment_rev' => $revid ],
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
$this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', $readStage );
|
2018-01-24 23:41:01 +00:00
|
|
|
$this->overrideMwServices();
|
2017-06-06 17:39:14 +00:00
|
|
|
|
|
|
|
|
$page->doDeleteArticle( "testing deletion" );
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
if ( $readStage > MIGRATION_OLD ) {
|
2017-06-06 17:39:14 +00:00
|
|
|
// Didn't leave behind any 'revision_comment_temp' rows
|
|
|
|
|
$n = $dbr->selectField(
|
|
|
|
|
'revision_comment_temp', 'COUNT(*)', [ 'revcomment_rev' => $revid ], __METHOD__
|
|
|
|
|
);
|
|
|
|
|
$this->assertEquals( 0, $n, 'no entry in revision_comment_temp after deletion' );
|
|
|
|
|
|
|
|
|
|
// Copied or upgraded the comment_id, as applicable
|
|
|
|
|
$ar_comment_id = $dbr->selectField(
|
|
|
|
|
'archive',
|
|
|
|
|
'ar_comment_id',
|
|
|
|
|
[ 'ar_rev_id' => $revid ],
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
2017-11-27 13:49:04 +00:00
|
|
|
if ( $writeStage > MIGRATION_OLD ) {
|
2017-06-06 17:39:14 +00:00
|
|
|
$this->assertSame( $comment_id, $ar_comment_id );
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertNotEquals( 0, $ar_comment_id );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copied rev_comment, if applicable
|
2017-11-27 13:49:04 +00:00
|
|
|
if ( $readStage <= MIGRATION_WRITE_BOTH && $writeStage <= MIGRATION_WRITE_BOTH ) {
|
2017-06-06 17:39:14 +00:00
|
|
|
$ar_comment = $dbr->selectField(
|
|
|
|
|
'archive',
|
|
|
|
|
'ar_comment',
|
|
|
|
|
[ 'ar_rev_id' => $revid ],
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
$this->assertSame( 'testing', $ar_comment );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 13:49:04 +00:00
|
|
|
public function provideCommentMigrationOnDeletion() {
|
2017-06-06 17:39:14 +00:00
|
|
|
return [
|
|
|
|
|
[ MIGRATION_OLD, MIGRATION_OLD ],
|
|
|
|
|
[ MIGRATION_OLD, MIGRATION_WRITE_BOTH ],
|
|
|
|
|
[ MIGRATION_OLD, MIGRATION_WRITE_NEW ],
|
|
|
|
|
[ MIGRATION_WRITE_BOTH, MIGRATION_OLD ],
|
|
|
|
|
[ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_BOTH ],
|
|
|
|
|
[ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW ],
|
|
|
|
|
[ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
|
|
|
|
|
[ MIGRATION_WRITE_NEW, MIGRATION_WRITE_BOTH ],
|
|
|
|
|
[ MIGRATION_WRITE_NEW, MIGRATION_WRITE_NEW ],
|
|
|
|
|
[ MIGRATION_WRITE_NEW, MIGRATION_NEW ],
|
|
|
|
|
[ MIGRATION_NEW, MIGRATION_WRITE_BOTH ],
|
|
|
|
|
[ MIGRATION_NEW, MIGRATION_WRITE_NEW ],
|
|
|
|
|
[ MIGRATION_NEW, MIGRATION_NEW ],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-30 18:23:01 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::updateCategoryCounts
|
|
|
|
|
*/
|
|
|
|
|
public function testUpdateCategoryCounts() {
|
|
|
|
|
$page = new WikiPage( Title::newFromText( __METHOD__ ) );
|
|
|
|
|
|
|
|
|
|
// Add an initial category
|
|
|
|
|
$page->updateCategoryCounts( [ 'A' ], [], 0 );
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 1, Category::newFromName( 'A' )->getPageCount() );
|
|
|
|
|
$this->assertEquals( 0, Category::newFromName( 'B' )->getPageCount() );
|
|
|
|
|
$this->assertEquals( 0, Category::newFromName( 'C' )->getPageCount() );
|
|
|
|
|
|
|
|
|
|
// Add a new category
|
|
|
|
|
$page->updateCategoryCounts( [ 'B' ], [], 0 );
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 1, Category::newFromName( 'A' )->getPageCount() );
|
|
|
|
|
$this->assertEquals( 1, Category::newFromName( 'B' )->getPageCount() );
|
|
|
|
|
$this->assertEquals( 0, Category::newFromName( 'C' )->getPageCount() );
|
|
|
|
|
|
|
|
|
|
// Add and remove a category
|
|
|
|
|
$page->updateCategoryCounts( [ 'C' ], [ 'A' ], 0 );
|
|
|
|
|
|
|
|
|
|
$this->assertEquals( 0, Category::newFromName( 'A' )->getPageCount() );
|
|
|
|
|
$this->assertEquals( 1, Category::newFromName( 'B' )->getPageCount() );
|
|
|
|
|
$this->assertEquals( 1, Category::newFromName( 'C' )->getPageCount() );
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 12:11:26 +00:00
|
|
|
public function provideUpdateRedirectOn() {
|
|
|
|
|
yield [ '#REDIRECT [[Foo]]', true, null, true, true, 0 ];
|
|
|
|
|
yield [ '#REDIRECT [[Foo]]', true, 'Foo', true, false, 1 ];
|
|
|
|
|
yield [ 'SomeText', false, null, false, true, 0 ];
|
|
|
|
|
yield [ 'SomeText', false, 'Foo', false, false, 1 ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideUpdateRedirectOn
|
|
|
|
|
* @covers WikiPage::updateRedirectOn
|
|
|
|
|
*
|
|
|
|
|
* @param string $initialText
|
|
|
|
|
* @param bool $initialRedirectState
|
|
|
|
|
* @param string|null $redirectTitle
|
|
|
|
|
* @param bool|null $lastRevIsRedirect
|
|
|
|
|
* @param bool $expectedSuccess
|
|
|
|
|
* @param int $expectedRowCount
|
|
|
|
|
*/
|
|
|
|
|
public function testUpdateRedirectOn(
|
|
|
|
|
$initialText,
|
|
|
|
|
$initialRedirectState,
|
|
|
|
|
$redirectTitle,
|
|
|
|
|
$lastRevIsRedirect,
|
|
|
|
|
$expectedSuccess,
|
|
|
|
|
$expectedRowCount
|
|
|
|
|
) {
|
2018-08-01 07:25:32 +00:00
|
|
|
// FIXME: fails under sqlite and postgres
|
2018-08-01 07:19:43 +00:00
|
|
|
$this->markTestSkippedIfDbType( 'sqlite' );
|
2018-08-01 07:25:32 +00:00
|
|
|
$this->markTestSkippedIfDbType( 'postgres' );
|
2017-12-04 12:11:26 +00:00
|
|
|
static $pageCounter = 0;
|
|
|
|
|
$pageCounter++;
|
|
|
|
|
|
|
|
|
|
$page = $this->createPage( Title::newFromText( __METHOD__ . $pageCounter ), $initialText );
|
|
|
|
|
$this->assertSame( $initialRedirectState, $page->isRedirect() );
|
|
|
|
|
|
|
|
|
|
$redirectTitle = is_string( $redirectTitle )
|
|
|
|
|
? Title::newFromText( $redirectTitle )
|
|
|
|
|
: $redirectTitle;
|
|
|
|
|
|
|
|
|
|
$success = $page->updateRedirectOn( $this->db, $redirectTitle, $lastRevIsRedirect );
|
|
|
|
|
$this->assertSame( $expectedSuccess, $success, 'Success assertion' );
|
|
|
|
|
/**
|
|
|
|
|
* updateRedirectOn explicitly updates the redirect table (and not the page table).
|
|
|
|
|
* Most of core checks the page table for redirect status, so we have to be ugly and
|
|
|
|
|
* assert a select from the table here.
|
|
|
|
|
*/
|
2017-12-04 12:59:15 +00:00
|
|
|
$this->assertRedirectTableCountForPageId( $page->getId(), $expectedRowCount );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function assertRedirectTableCountForPageId( $pageId, $expected ) {
|
2017-12-04 12:11:26 +00:00
|
|
|
$this->assertSelect(
|
|
|
|
|
'redirect',
|
|
|
|
|
'COUNT(*)',
|
2017-12-04 12:59:15 +00:00
|
|
|
[ 'rd_from' => $pageId ],
|
|
|
|
|
[ [ strval( $expected ) ] ]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::insertRedirectEntry
|
|
|
|
|
*/
|
|
|
|
|
public function testInsertRedirectEntry_insertsRedirectEntry() {
|
|
|
|
|
$page = $this->createPage( Title::newFromText( __METHOD__ ), 'A' );
|
|
|
|
|
$this->assertRedirectTableCountForPageId( $page->getId(), 0 );
|
|
|
|
|
|
|
|
|
|
$targetTitle = Title::newFromText( 'SomeTarget#Frag' );
|
|
|
|
|
$targetTitle->mInterwiki = 'eninter';
|
|
|
|
|
$page->insertRedirectEntry( $targetTitle, null );
|
|
|
|
|
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'redirect',
|
|
|
|
|
[ 'rd_from', 'rd_namespace', 'rd_title', 'rd_fragment', 'rd_interwiki' ],
|
2017-12-04 12:11:26 +00:00
|
|
|
[ 'rd_from' => $page->getId() ],
|
2017-12-04 12:59:15 +00:00
|
|
|
[ [
|
|
|
|
|
strval( $page->getId() ),
|
|
|
|
|
strval( $targetTitle->getNamespace() ),
|
|
|
|
|
strval( $targetTitle->getDBkey() ),
|
|
|
|
|
strval( $targetTitle->getFragment() ),
|
|
|
|
|
strval( $targetTitle->getInterwiki() ),
|
|
|
|
|
] ]
|
2017-12-04 12:11:26 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 12:59:15 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::insertRedirectEntry
|
|
|
|
|
*/
|
|
|
|
|
public function testInsertRedirectEntry_insertsRedirectEntryWithPageLatest() {
|
|
|
|
|
$page = $this->createPage( Title::newFromText( __METHOD__ ), 'A' );
|
|
|
|
|
$this->assertRedirectTableCountForPageId( $page->getId(), 0 );
|
|
|
|
|
|
|
|
|
|
$targetTitle = Title::newFromText( 'SomeTarget#Frag' );
|
|
|
|
|
$targetTitle->mInterwiki = 'eninter';
|
|
|
|
|
$page->insertRedirectEntry( $targetTitle, $page->getLatest() );
|
|
|
|
|
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'redirect',
|
|
|
|
|
[ 'rd_from', 'rd_namespace', 'rd_title', 'rd_fragment', 'rd_interwiki' ],
|
|
|
|
|
[ 'rd_from' => $page->getId() ],
|
|
|
|
|
[ [
|
|
|
|
|
strval( $page->getId() ),
|
|
|
|
|
strval( $targetTitle->getNamespace() ),
|
|
|
|
|
strval( $targetTitle->getDBkey() ),
|
|
|
|
|
strval( $targetTitle->getFragment() ),
|
|
|
|
|
strval( $targetTitle->getInterwiki() ),
|
|
|
|
|
] ]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::insertRedirectEntry
|
|
|
|
|
*/
|
|
|
|
|
public function testInsertRedirectEntry_doesNotInsertIfPageLatestIncorrect() {
|
|
|
|
|
$page = $this->createPage( Title::newFromText( __METHOD__ ), 'A' );
|
|
|
|
|
$this->assertRedirectTableCountForPageId( $page->getId(), 0 );
|
|
|
|
|
|
|
|
|
|
$targetTitle = Title::newFromText( 'SomeTarget#Frag' );
|
|
|
|
|
$targetTitle->mInterwiki = 'eninter';
|
|
|
|
|
$page->insertRedirectEntry( $targetTitle, 215251 );
|
|
|
|
|
|
|
|
|
|
$this->assertRedirectTableCountForPageId( $page->getId(), 0 );
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 14:03:41 +00:00
|
|
|
private function getRow( array $overrides = [] ) {
|
|
|
|
|
$row = [
|
|
|
|
|
'page_id' => '44',
|
|
|
|
|
'page_len' => '76',
|
|
|
|
|
'page_is_redirect' => '1',
|
|
|
|
|
'page_latest' => '99',
|
|
|
|
|
'page_namespace' => '3',
|
|
|
|
|
'page_title' => 'JaJaTitle',
|
|
|
|
|
'page_restrictions' => 'edit=autoconfirmed,sysop:move=sysop',
|
|
|
|
|
'page_touched' => '20120101020202',
|
|
|
|
|
'page_links_updated' => '20140101020202',
|
|
|
|
|
];
|
|
|
|
|
foreach ( $overrides as $key => $value ) {
|
|
|
|
|
$row[$key] = $value;
|
|
|
|
|
}
|
|
|
|
|
return (object)$row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function provideNewFromRowSuccess() {
|
|
|
|
|
yield 'basic row' => [
|
|
|
|
|
$this->getRow(),
|
|
|
|
|
function ( WikiPage $wikiPage, self $test ) {
|
|
|
|
|
$test->assertSame( 44, $wikiPage->getId() );
|
|
|
|
|
$test->assertSame( 76, $wikiPage->getTitle()->getLength() );
|
|
|
|
|
$test->assertTrue( $wikiPage->isRedirect() );
|
|
|
|
|
$test->assertSame( 99, $wikiPage->getLatest() );
|
|
|
|
|
$test->assertSame( 3, $wikiPage->getTitle()->getNamespace() );
|
|
|
|
|
$test->assertSame( 'JaJaTitle', $wikiPage->getTitle()->getDBkey() );
|
|
|
|
|
$test->assertSame(
|
|
|
|
|
[
|
|
|
|
|
'edit' => [ 'autoconfirmed', 'sysop' ],
|
|
|
|
|
'move' => [ 'sysop' ],
|
|
|
|
|
],
|
|
|
|
|
$wikiPage->getTitle()->getAllRestrictions()
|
|
|
|
|
);
|
|
|
|
|
$test->assertSame( '20120101020202', $wikiPage->getTouched() );
|
|
|
|
|
$test->assertSame( '20140101020202', $wikiPage->getLinksTimestamp() );
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
yield 'different timestamp formats' => [
|
|
|
|
|
$this->getRow( [
|
|
|
|
|
'page_touched' => '2012-01-01 02:02:02',
|
|
|
|
|
'page_links_updated' => '2014-01-01 02:02:02',
|
|
|
|
|
] ),
|
|
|
|
|
function ( WikiPage $wikiPage, self $test ) {
|
|
|
|
|
$test->assertSame( '20120101020202', $wikiPage->getTouched() );
|
|
|
|
|
$test->assertSame( '20140101020202', $wikiPage->getLinksTimestamp() );
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
yield 'no restrictions' => [
|
|
|
|
|
$this->getRow( [
|
|
|
|
|
'page_restrictions' => '',
|
|
|
|
|
] ),
|
|
|
|
|
function ( WikiPage $wikiPage, self $test ) {
|
|
|
|
|
$test->assertSame(
|
|
|
|
|
[
|
|
|
|
|
'edit' => [],
|
|
|
|
|
'move' => [],
|
|
|
|
|
],
|
|
|
|
|
$wikiPage->getTitle()->getAllRestrictions()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
yield 'not redirect' => [
|
|
|
|
|
$this->getRow( [
|
|
|
|
|
'page_is_redirect' => '0',
|
|
|
|
|
] ),
|
|
|
|
|
function ( WikiPage $wikiPage, self $test ) {
|
|
|
|
|
$test->assertFalse( $wikiPage->isRedirect() );
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::newFromRow
|
|
|
|
|
* @covers WikiPage::loadFromRow
|
|
|
|
|
* @dataProvider provideNewFromRowSuccess
|
|
|
|
|
*
|
|
|
|
|
* @param object $row
|
|
|
|
|
* @param callable $assertions
|
|
|
|
|
*/
|
|
|
|
|
public function testNewFromRow( $row, $assertions ) {
|
|
|
|
|
$page = WikiPage::newFromRow( $row, 'fromdb' );
|
|
|
|
|
$assertions( $page, $this );
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 14:14:12 +00:00
|
|
|
public function provideTestNewFromId_returnsNullOnBadPageId() {
|
|
|
|
|
yield[ 0 ];
|
|
|
|
|
yield[ -11 ];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::newFromID
|
|
|
|
|
* @dataProvider provideTestNewFromId_returnsNullOnBadPageId
|
|
|
|
|
*/
|
|
|
|
|
public function testNewFromId_returnsNullOnBadPageId( $pageId ) {
|
|
|
|
|
$this->assertNull( WikiPage::newFromID( $pageId ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::newFromID
|
|
|
|
|
*/
|
|
|
|
|
public function testNewFromId_appearsToFetchCorrectRow() {
|
|
|
|
|
$createdPage = $this->createPage( __METHOD__, 'Xsfaij09' );
|
|
|
|
|
$fetchedPage = WikiPage::newFromID( $createdPage->getId() );
|
|
|
|
|
$this->assertSame( $createdPage->getId(), $fetchedPage->getId() );
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
$createdPage->getContent()->getNativeData(),
|
|
|
|
|
$fetchedPage->getContent()->getNativeData()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::newFromID
|
|
|
|
|
*/
|
|
|
|
|
public function testNewFromId_returnsNullOnNonExistingId() {
|
2018-03-18 02:02:13 +00:00
|
|
|
$this->assertNull( WikiPage::newFromID( 2147483647 ) );
|
2017-12-04 14:14:12 +00:00
|
|
|
}
|
|
|
|
|
|
2017-12-04 15:00:17 +00:00
|
|
|
public function provideTestInsertProtectNullRevision() {
|
2018-01-01 13:10:16 +00:00
|
|
|
// phpcs:disable Generic.Files.LineLength
|
2017-12-04 15:00:17 +00:00
|
|
|
yield [
|
|
|
|
|
'goat-message-key',
|
|
|
|
|
[ 'edit' => 'sysop' ],
|
|
|
|
|
[ 'edit' => '20200101040404' ],
|
|
|
|
|
false,
|
|
|
|
|
'Goat Reason',
|
|
|
|
|
true,
|
|
|
|
|
'(goat-message-key: WikiPageDbTestBase::testInsertProtectNullRevision, UTSysop)(colon-separator)Goat Reason(word-separator)(parentheses: (protect-summary-desc: (restriction-edit), (protect-level-sysop), (protect-expiring: 04:04, 1 (january) 2020, 1 (january) 2020, 04:04)))'
|
|
|
|
|
];
|
|
|
|
|
yield [
|
|
|
|
|
'goat-key',
|
|
|
|
|
[ 'edit' => 'sysop', 'move' => 'something' ],
|
|
|
|
|
[ 'edit' => '20200101040404', 'move' => '20210101050505' ],
|
|
|
|
|
false,
|
|
|
|
|
'Goat Goat',
|
|
|
|
|
true,
|
|
|
|
|
'(goat-key: WikiPageDbTestBase::testInsertProtectNullRevision, UTSysop)(colon-separator)Goat Goat(word-separator)(parentheses: (protect-summary-desc: (restriction-edit), (protect-level-sysop), (protect-expiring: 04:04, 1 (january) 2020, 1 (january) 2020, 04:04))(word-separator)(protect-summary-desc: (restriction-move), (protect-level-something), (protect-expiring: 05:05, 1 (january) 2021, 1 (january) 2021, 05:05)))'
|
|
|
|
|
];
|
2018-01-01 13:10:16 +00:00
|
|
|
// phpcs:enable
|
2017-12-04 15:00:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideTestInsertProtectNullRevision
|
2017-12-07 04:19:25 +00:00
|
|
|
* @covers WikiPage::insertProtectNullRevision
|
|
|
|
|
* @covers WikiPage::protectDescription
|
2017-12-04 15:00:17 +00:00
|
|
|
*
|
|
|
|
|
* @param string $revCommentMsg
|
|
|
|
|
* @param array $limit
|
|
|
|
|
* @param array $expiry
|
|
|
|
|
* @param bool $cascade
|
|
|
|
|
* @param string $reason
|
|
|
|
|
* @param bool|null $user true if the test sysop should be used, or null
|
|
|
|
|
* @param string $expectedComment
|
|
|
|
|
*/
|
|
|
|
|
public function testInsertProtectNullRevision(
|
|
|
|
|
$revCommentMsg,
|
|
|
|
|
array $limit,
|
|
|
|
|
array $expiry,
|
|
|
|
|
$cascade,
|
|
|
|
|
$reason,
|
|
|
|
|
$user,
|
|
|
|
|
$expectedComment
|
|
|
|
|
) {
|
|
|
|
|
$this->setContentLang( 'qqx' );
|
|
|
|
|
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'Goat' );
|
|
|
|
|
|
|
|
|
|
$user = $user === null ? $user : $this->getTestSysop()->getUser();
|
|
|
|
|
|
|
|
|
|
$result = $page->insertProtectNullRevision(
|
|
|
|
|
$revCommentMsg,
|
|
|
|
|
$limit,
|
|
|
|
|
$expiry,
|
|
|
|
|
$cascade,
|
|
|
|
|
$reason,
|
|
|
|
|
$user
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $result instanceof Revision );
|
|
|
|
|
$this->assertSame( $expectedComment, $result->getComment( Revision::RAW ) );
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 15:31:57 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::updateRevisionOn
|
|
|
|
|
*/
|
|
|
|
|
public function testUpdateRevisionOn_existingPage() {
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'StartText' );
|
|
|
|
|
|
|
|
|
|
$revision = new Revision(
|
|
|
|
|
[
|
|
|
|
|
'id' => 9989,
|
|
|
|
|
'page' => $page->getId(),
|
|
|
|
|
'title' => $page->getTitle(),
|
|
|
|
|
'comment' => __METHOD__,
|
|
|
|
|
'minor_edit' => true,
|
|
|
|
|
'text' => __METHOD__ . '-text',
|
|
|
|
|
'len' => strlen( __METHOD__ . '-text' ),
|
|
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
|
|
|
|
'timestamp' => '20170707040404',
|
|
|
|
|
'content_model' => CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'content_format' => CONTENT_FORMAT_WIKITEXT,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$result = $page->updateRevisionOn( $this->db, $revision );
|
|
|
|
|
$this->assertTrue( $result );
|
|
|
|
|
$this->assertSame( 9989, $page->getLatest() );
|
|
|
|
|
$this->assertEquals( $revision, $page->getRevision() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::updateRevisionOn
|
|
|
|
|
*/
|
|
|
|
|
public function testUpdateRevisionOn_NonExistingPage() {
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'StartText' );
|
|
|
|
|
$page->doDeleteArticle( 'reason' );
|
|
|
|
|
|
|
|
|
|
$revision = new Revision(
|
|
|
|
|
[
|
|
|
|
|
'id' => 9989,
|
|
|
|
|
'page' => $page->getId(),
|
|
|
|
|
'title' => $page->getTitle(),
|
|
|
|
|
'comment' => __METHOD__,
|
|
|
|
|
'minor_edit' => true,
|
|
|
|
|
'text' => __METHOD__ . '-text',
|
|
|
|
|
'len' => strlen( __METHOD__ . '-text' ),
|
|
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
|
|
|
|
'timestamp' => '20170707040404',
|
|
|
|
|
'content_model' => CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'content_format' => CONTENT_FORMAT_WIKITEXT,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$result = $page->updateRevisionOn( $this->db, $revision );
|
|
|
|
|
$this->assertFalse( $result );
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 15:39:49 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::updateIfNewerOn
|
|
|
|
|
*/
|
|
|
|
|
public function testUpdateIfNewerOn_olderRevision() {
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'StartText' );
|
|
|
|
|
$initialRevision = $page->getRevision();
|
|
|
|
|
|
|
|
|
|
$olderTimeStamp = wfTimestamp(
|
|
|
|
|
TS_MW,
|
|
|
|
|
wfTimestamp( TS_UNIX, $initialRevision->getTimestamp() ) - 1
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$olderRevison = new Revision(
|
|
|
|
|
[
|
|
|
|
|
'id' => 9989,
|
|
|
|
|
'page' => $page->getId(),
|
|
|
|
|
'title' => $page->getTitle(),
|
|
|
|
|
'comment' => __METHOD__,
|
|
|
|
|
'minor_edit' => true,
|
|
|
|
|
'text' => __METHOD__ . '-text',
|
|
|
|
|
'len' => strlen( __METHOD__ . '-text' ),
|
|
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
|
|
|
|
'timestamp' => $olderTimeStamp,
|
|
|
|
|
'content_model' => CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'content_format' => CONTENT_FORMAT_WIKITEXT,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$result = $page->updateIfNewerOn( $this->db, $olderRevison );
|
|
|
|
|
$this->assertFalse( $result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::updateIfNewerOn
|
|
|
|
|
*/
|
|
|
|
|
public function testUpdateIfNewerOn_newerRevision() {
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'StartText' );
|
|
|
|
|
$initialRevision = $page->getRevision();
|
|
|
|
|
|
|
|
|
|
$newerTimeStamp = wfTimestamp(
|
|
|
|
|
TS_MW,
|
|
|
|
|
wfTimestamp( TS_UNIX, $initialRevision->getTimestamp() ) + 1
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$newerRevision = new Revision(
|
|
|
|
|
[
|
|
|
|
|
'id' => 9989,
|
|
|
|
|
'page' => $page->getId(),
|
|
|
|
|
'title' => $page->getTitle(),
|
|
|
|
|
'comment' => __METHOD__,
|
|
|
|
|
'minor_edit' => true,
|
|
|
|
|
'text' => __METHOD__ . '-text',
|
|
|
|
|
'len' => strlen( __METHOD__ . '-text' ),
|
|
|
|
|
'user' => $user->getId(),
|
|
|
|
|
'user_text' => $user->getName(),
|
|
|
|
|
'timestamp' => $newerTimeStamp,
|
|
|
|
|
'content_model' => CONTENT_MODEL_WIKITEXT,
|
|
|
|
|
'content_format' => CONTENT_FORMAT_WIKITEXT,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
$result = $page->updateIfNewerOn( $this->db, $newerRevision );
|
|
|
|
|
$this->assertTrue( $result );
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 16:09:54 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::insertOn
|
|
|
|
|
*/
|
|
|
|
|
public function testInsertOn() {
|
|
|
|
|
$title = Title::newFromText( __METHOD__ );
|
|
|
|
|
$page = new WikiPage( $title );
|
|
|
|
|
|
|
|
|
|
$startTimeStamp = wfTimestampNow();
|
|
|
|
|
$result = $page->insertOn( $this->db );
|
|
|
|
|
$endTimeStamp = wfTimestampNow();
|
|
|
|
|
|
|
|
|
|
$this->assertInternalType( 'int', $result );
|
|
|
|
|
$this->assertTrue( $result > 0 );
|
|
|
|
|
|
|
|
|
|
$condition = [ 'page_id' => $result ];
|
|
|
|
|
|
|
|
|
|
// Check the default fields have been filled
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'page',
|
|
|
|
|
[
|
|
|
|
|
'page_namespace',
|
|
|
|
|
'page_title',
|
|
|
|
|
'page_restrictions',
|
|
|
|
|
'page_is_redirect',
|
|
|
|
|
'page_is_new',
|
|
|
|
|
'page_latest',
|
|
|
|
|
'page_len',
|
|
|
|
|
],
|
|
|
|
|
$condition,
|
|
|
|
|
[ [
|
|
|
|
|
'0',
|
|
|
|
|
__METHOD__,
|
|
|
|
|
'',
|
|
|
|
|
'0',
|
|
|
|
|
'1',
|
|
|
|
|
'0',
|
|
|
|
|
'0',
|
|
|
|
|
] ]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Check the page_random field has been filled
|
|
|
|
|
$pageRandom = $this->db->selectField( 'page', 'page_random', $condition );
|
|
|
|
|
$this->assertTrue( (float)$pageRandom < 1 && (float)$pageRandom > 0 );
|
|
|
|
|
|
|
|
|
|
// Assert the touched timestamp in the DB is roughly when we inserted the page
|
|
|
|
|
$pageTouched = $this->db->selectField( 'page', 'page_touched', $condition );
|
|
|
|
|
$this->assertTrue(
|
|
|
|
|
wfTimestamp( TS_UNIX, $startTimeStamp )
|
|
|
|
|
<= wfTimestamp( TS_UNIX, $pageTouched )
|
|
|
|
|
);
|
|
|
|
|
$this->assertTrue(
|
|
|
|
|
wfTimestamp( TS_UNIX, $endTimeStamp )
|
|
|
|
|
>= wfTimestamp( TS_UNIX, $pageTouched )
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Try inserting the same page again and checking the result is false (no change)
|
|
|
|
|
$result = $page->insertOn( $this->db );
|
|
|
|
|
$this->assertFalse( $result );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::insertOn
|
|
|
|
|
*/
|
|
|
|
|
public function testInsertOn_idSpecified() {
|
|
|
|
|
$title = Title::newFromText( __METHOD__ );
|
|
|
|
|
$page = new WikiPage( $title );
|
2017-12-15 21:03:07 +00:00
|
|
|
$id = 1478952189;
|
2017-12-04 16:09:54 +00:00
|
|
|
|
|
|
|
|
$result = $page->insertOn( $this->db, $id );
|
|
|
|
|
|
|
|
|
|
$this->assertSame( $id, $result );
|
|
|
|
|
|
|
|
|
|
$condition = [ 'page_id' => $result ];
|
|
|
|
|
|
|
|
|
|
// Check there is actually a row in the db
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'page',
|
|
|
|
|
[ 'page_title' ],
|
|
|
|
|
$condition,
|
|
|
|
|
[ [ __METHOD__ ] ]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 18:23:17 +00:00
|
|
|
public function provideTestDoUpdateRestrictions_setBasicRestrictions() {
|
|
|
|
|
// Note: Once the current dates passes the date in these tests they will fail.
|
|
|
|
|
yield 'move something' => [
|
|
|
|
|
true,
|
|
|
|
|
[ 'move' => 'something' ],
|
|
|
|
|
[],
|
|
|
|
|
[ 'edit' => [], 'move' => [ 'something' ] ],
|
|
|
|
|
[],
|
|
|
|
|
];
|
|
|
|
|
yield 'move something, edit blank' => [
|
|
|
|
|
true,
|
|
|
|
|
[ 'move' => 'something', 'edit' => '' ],
|
|
|
|
|
[],
|
|
|
|
|
[ 'edit' => [], 'move' => [ 'something' ] ],
|
|
|
|
|
[],
|
|
|
|
|
];
|
|
|
|
|
yield 'edit sysop, with expiry' => [
|
|
|
|
|
true,
|
|
|
|
|
[ 'edit' => 'sysop' ],
|
|
|
|
|
[ 'edit' => '21330101020202' ],
|
|
|
|
|
[ 'edit' => [ 'sysop' ], 'move' => [] ],
|
|
|
|
|
[ 'edit' => '21330101020202' ],
|
|
|
|
|
];
|
|
|
|
|
yield 'move and edit, move with expiry' => [
|
|
|
|
|
true,
|
|
|
|
|
[ 'move' => 'something', 'edit' => 'another' ],
|
|
|
|
|
[ 'move' => '22220202010101' ],
|
|
|
|
|
[ 'edit' => [ 'another' ], 'move' => [ 'something' ] ],
|
|
|
|
|
[ 'move' => '22220202010101' ],
|
|
|
|
|
];
|
|
|
|
|
yield 'move and edit, edit with infinity expiry' => [
|
|
|
|
|
true,
|
|
|
|
|
[ 'move' => 'something', 'edit' => 'another' ],
|
|
|
|
|
[ 'edit' => 'infinity' ],
|
|
|
|
|
[ 'edit' => [ 'another' ], 'move' => [ 'something' ] ],
|
|
|
|
|
[ 'edit' => 'infinity' ],
|
|
|
|
|
];
|
|
|
|
|
yield 'non existing, create something' => [
|
|
|
|
|
false,
|
|
|
|
|
[ 'create' => 'something' ],
|
|
|
|
|
[],
|
|
|
|
|
[ 'create' => [ 'something' ] ],
|
|
|
|
|
[],
|
|
|
|
|
];
|
|
|
|
|
yield 'non existing, create something with expiry' => [
|
|
|
|
|
false,
|
|
|
|
|
[ 'create' => 'something' ],
|
|
|
|
|
[ 'create' => '23451212112233' ],
|
|
|
|
|
[ 'create' => [ 'something' ] ],
|
|
|
|
|
[ 'create' => '23451212112233' ],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideTestDoUpdateRestrictions_setBasicRestrictions
|
|
|
|
|
* @covers WikiPage::doUpdateRestrictions
|
|
|
|
|
*/
|
|
|
|
|
public function testDoUpdateRestrictions_setBasicRestrictions(
|
|
|
|
|
$pageExists,
|
|
|
|
|
array $limit,
|
|
|
|
|
array $expiry,
|
|
|
|
|
array $expectedRestrictions,
|
|
|
|
|
array $expectedRestrictionExpiries
|
|
|
|
|
) {
|
|
|
|
|
if ( $pageExists ) {
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'ABC' );
|
|
|
|
|
} else {
|
|
|
|
|
$page = new WikiPage( Title::newFromText( __METHOD__ . '-nonexist' ) );
|
|
|
|
|
}
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$cascade = false;
|
|
|
|
|
|
|
|
|
|
$status = $page->doUpdateRestrictions( $limit, $expiry, $cascade, 'aReason', $user, [] );
|
|
|
|
|
|
|
|
|
|
$logId = $status->getValue();
|
|
|
|
|
$allRestrictions = $page->getTitle()->getAllRestrictions();
|
|
|
|
|
|
|
|
|
|
$this->assertTrue( $status->isGood() );
|
|
|
|
|
$this->assertInternalType( 'int', $logId );
|
|
|
|
|
$this->assertSame( $expectedRestrictions, $allRestrictions );
|
|
|
|
|
foreach ( $expectedRestrictionExpiries as $key => $value ) {
|
|
|
|
|
$this->assertSame( $value, $page->getTitle()->getRestrictionExpiry( $key ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure the log entry looks good
|
|
|
|
|
// log_params is not checked here
|
2017-09-12 17:12:29 +00:00
|
|
|
$actorQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
|
2018-11-07 19:50:27 +00:00
|
|
|
$commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'log_comment' );
|
2017-12-04 18:23:17 +00:00
|
|
|
$this->assertSelect(
|
2018-11-07 19:50:27 +00:00
|
|
|
[ 'logging' ] + $actorQuery['tables'] + $commentQuery['tables'],
|
2017-12-04 18:23:17 +00:00
|
|
|
[
|
2018-11-07 19:50:27 +00:00
|
|
|
'log_comment' => $commentQuery['fields']['log_comment_text'],
|
2017-09-12 17:12:29 +00:00
|
|
|
'log_user' => $actorQuery['fields']['log_user'],
|
|
|
|
|
'log_user_text' => $actorQuery['fields']['log_user_text'],
|
2017-12-04 18:23:17 +00:00
|
|
|
'log_namespace',
|
|
|
|
|
'log_title',
|
|
|
|
|
],
|
|
|
|
|
[ 'log_id' => $logId ],
|
|
|
|
|
[ [
|
|
|
|
|
'aReason',
|
|
|
|
|
(string)$user->getId(),
|
|
|
|
|
$user->getName(),
|
|
|
|
|
(string)$page->getTitle()->getNamespace(),
|
|
|
|
|
$page->getTitle()->getDBkey(),
|
2017-09-12 17:12:29 +00:00
|
|
|
] ],
|
|
|
|
|
[],
|
2018-11-07 19:50:27 +00:00
|
|
|
$actorQuery['joins'] + $commentQuery['joins']
|
2017-12-04 18:23:17 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doUpdateRestrictions
|
|
|
|
|
*/
|
|
|
|
|
public function testDoUpdateRestrictions_failsOnReadOnly() {
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'ABC' );
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$cascade = false;
|
|
|
|
|
|
|
|
|
|
// Set read only
|
|
|
|
|
$readOnly = $this->getMockBuilder( ReadOnlyMode::class )
|
|
|
|
|
->disableOriginalConstructor()
|
|
|
|
|
->setMethods( [ 'isReadOnly', 'getReason' ] )
|
|
|
|
|
->getMock();
|
|
|
|
|
$readOnly->expects( $this->once() )
|
|
|
|
|
->method( 'isReadOnly' )
|
|
|
|
|
->will( $this->returnValue( true ) );
|
|
|
|
|
$readOnly->expects( $this->once() )
|
|
|
|
|
->method( 'getReason' )
|
|
|
|
|
->will( $this->returnValue( 'Some Read Only Reason' ) );
|
|
|
|
|
$this->setService( 'ReadOnlyMode', $readOnly );
|
|
|
|
|
|
|
|
|
|
$status = $page->doUpdateRestrictions( [], [], $cascade, 'aReason', $user, [] );
|
|
|
|
|
$this->assertFalse( $status->isOK() );
|
|
|
|
|
$this->assertSame( 'readonlytext', $status->getMessage()->getKey() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doUpdateRestrictions
|
|
|
|
|
*/
|
|
|
|
|
public function testDoUpdateRestrictions_returnsGoodIfNothingChanged() {
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'ABC' );
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$cascade = false;
|
|
|
|
|
$limit = [ 'edit' => 'sysop' ];
|
|
|
|
|
|
|
|
|
|
$status = $page->doUpdateRestrictions(
|
|
|
|
|
$limit,
|
|
|
|
|
[],
|
|
|
|
|
$cascade,
|
|
|
|
|
'aReason',
|
|
|
|
|
$user,
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// The first entry should have a logId as it did something
|
|
|
|
|
$this->assertTrue( $status->isGood() );
|
|
|
|
|
$this->assertInternalType( 'int', $status->getValue() );
|
|
|
|
|
|
|
|
|
|
$status = $page->doUpdateRestrictions(
|
|
|
|
|
$limit,
|
|
|
|
|
[],
|
|
|
|
|
$cascade,
|
|
|
|
|
'aReason',
|
|
|
|
|
$user,
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// The second entry should not have a logId as nothing changed
|
|
|
|
|
$this->assertTrue( $status->isGood() );
|
|
|
|
|
$this->assertNull( $status->getValue() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::doUpdateRestrictions
|
|
|
|
|
*/
|
|
|
|
|
public function testDoUpdateRestrictions_logEntryTypeAndAction() {
|
|
|
|
|
$page = $this->createPage( __METHOD__, 'ABC' );
|
|
|
|
|
$user = $this->getTestSysop()->getUser();
|
|
|
|
|
$cascade = false;
|
|
|
|
|
|
|
|
|
|
// Protect the page
|
|
|
|
|
$status = $page->doUpdateRestrictions(
|
|
|
|
|
[ 'edit' => 'sysop' ],
|
|
|
|
|
[],
|
|
|
|
|
$cascade,
|
|
|
|
|
'aReason',
|
|
|
|
|
$user,
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
$this->assertTrue( $status->isGood() );
|
|
|
|
|
$this->assertInternalType( 'int', $status->getValue() );
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'logging',
|
|
|
|
|
[ 'log_type', 'log_action' ],
|
|
|
|
|
[ 'log_id' => $status->getValue() ],
|
|
|
|
|
[ [ 'protect', 'protect' ] ]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Modify the protection
|
|
|
|
|
$status = $page->doUpdateRestrictions(
|
|
|
|
|
[ 'edit' => 'somethingElse' ],
|
|
|
|
|
[],
|
|
|
|
|
$cascade,
|
|
|
|
|
'aReason',
|
|
|
|
|
$user,
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
$this->assertTrue( $status->isGood() );
|
|
|
|
|
$this->assertInternalType( 'int', $status->getValue() );
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'logging',
|
|
|
|
|
[ 'log_type', 'log_action' ],
|
|
|
|
|
[ 'log_id' => $status->getValue() ],
|
|
|
|
|
[ [ 'protect', 'modify' ] ]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Remove the protection
|
|
|
|
|
$status = $page->doUpdateRestrictions(
|
|
|
|
|
[],
|
|
|
|
|
[],
|
|
|
|
|
$cascade,
|
|
|
|
|
'aReason',
|
|
|
|
|
$user,
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
$this->assertTrue( $status->isGood() );
|
|
|
|
|
$this->assertInternalType( 'int', $status->getValue() );
|
|
|
|
|
$this->assertSelect(
|
|
|
|
|
'logging',
|
|
|
|
|
[ 'log_type', 'log_action' ],
|
|
|
|
|
[ 'log_id' => $status->getValue() ],
|
|
|
|
|
[ [ 'protect', 'unprotect' ] ]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::newPageUpdater
|
|
|
|
|
* @covers WikiPage::getDerivedDataUpdater
|
|
|
|
|
*/
|
|
|
|
|
public function testNewPageUpdater() {
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
$page = $this->newPage( __METHOD__, __METHOD__ );
|
|
|
|
|
|
|
|
|
|
/** @var Content $content */
|
|
|
|
|
$content = $this->getMockBuilder( WikitextContent::class )
|
|
|
|
|
->setConstructorArgs( [ 'Hello World' ] )
|
|
|
|
|
->setMethods( [ 'getParserOutput' ] )
|
|
|
|
|
->getMock();
|
|
|
|
|
$content->expects( $this->once() )
|
|
|
|
|
->method( 'getParserOutput' )
|
|
|
|
|
->willReturn( new ParserOutput( 'HTML' ) );
|
|
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
$preparedEditBefore = $page->prepareContentForEdit( $content, null, $user );
|
|
|
|
|
|
|
|
|
|
// provide context, so the cache can be kept in place
|
|
|
|
|
$slotsUpdate = new revisionSlotsUpdate();
|
2018-09-24 21:10:08 +00:00
|
|
|
$slotsUpdate->modifyContent( SlotRecord::MAIN, $content );
|
2018-07-08 19:01:32 +00:00
|
|
|
|
|
|
|
|
$updater = $page->newPageUpdater( $user, $slotsUpdate );
|
2018-09-24 21:10:08 +00:00
|
|
|
$updater->setContent( SlotRecord::MAIN, $content );
|
2018-01-27 01:48:19 +00:00
|
|
|
$revision = $updater->saveRevision(
|
|
|
|
|
CommentStoreComment::newUnsavedComment( 'test' ),
|
|
|
|
|
EDIT_NEW
|
|
|
|
|
);
|
|
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
$preparedEditAfter = $page->prepareContentForEdit( $content, $revision, $user );
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertSame( $revision->getId(), $page->getLatest() );
|
2018-07-08 19:01:32 +00:00
|
|
|
|
|
|
|
|
// Parsed output must remain cached throughout.
|
|
|
|
|
$this->assertSame( $preparedEditBefore->output, $preparedEditAfter->output );
|
2018-01-27 01:48:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers WikiPage::newPageUpdater
|
|
|
|
|
* @covers WikiPage::getDerivedDataUpdater
|
|
|
|
|
*/
|
|
|
|
|
public function testGetDerivedDataUpdater() {
|
|
|
|
|
$admin = $this->getTestSysop()->getUser();
|
|
|
|
|
|
|
|
|
|
/** @var object $page */
|
|
|
|
|
$page = $this->createPage( __METHOD__, __METHOD__ );
|
|
|
|
|
$page = TestingAccessWrapper::newFromObject( $page );
|
|
|
|
|
|
|
|
|
|
$revision = $page->getRevision()->getRevisionRecord();
|
|
|
|
|
$user = $revision->getUser();
|
|
|
|
|
|
|
|
|
|
$slotsUpdate = new RevisionSlotsUpdate();
|
2018-09-24 21:10:08 +00:00
|
|
|
$slotsUpdate->modifyContent( SlotRecord::MAIN, new WikitextContent( 'Hello World' ) );
|
2018-01-27 01:48:19 +00:00
|
|
|
|
|
|
|
|
// get a virgin updater
|
|
|
|
|
$updater1 = $page->getDerivedDataUpdater( $user );
|
|
|
|
|
$this->assertFalse( $updater1->isUpdatePrepared() );
|
|
|
|
|
|
|
|
|
|
$updater1->prepareUpdate( $revision );
|
|
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
// Re-use updater with same revision or content, even if base changed
|
2018-01-27 01:48:19 +00:00
|
|
|
$this->assertSame( $updater1, $page->getDerivedDataUpdater( $user, $revision ) );
|
|
|
|
|
|
|
|
|
|
$slotsUpdate = RevisionSlotsUpdate::newFromContent(
|
2018-09-24 21:10:08 +00:00
|
|
|
[ SlotRecord::MAIN => $revision->getContent( SlotRecord::MAIN ) ]
|
2018-01-27 01:48:19 +00:00
|
|
|
);
|
|
|
|
|
$this->assertSame( $updater1, $page->getDerivedDataUpdater( $user, null, $slotsUpdate ) );
|
|
|
|
|
|
2018-07-08 19:01:32 +00:00
|
|
|
// Don't re-use for edit if base revision ID changed
|
|
|
|
|
$this->assertNotSame(
|
|
|
|
|
$updater1,
|
|
|
|
|
$page->getDerivedDataUpdater( $user, null, $slotsUpdate, true )
|
|
|
|
|
);
|
|
|
|
|
|
2018-01-27 01:48:19 +00:00
|
|
|
// Don't re-use with different user
|
|
|
|
|
$updater2a = $page->getDerivedDataUpdater( $admin, null, $slotsUpdate );
|
|
|
|
|
$updater2a->prepareContent( $admin, $slotsUpdate, false );
|
|
|
|
|
|
|
|
|
|
$updater2b = $page->getDerivedDataUpdater( $user, null, $slotsUpdate );
|
|
|
|
|
$updater2b->prepareContent( $user, $slotsUpdate, false );
|
|
|
|
|
$this->assertNotSame( $updater2a, $updater2b );
|
|
|
|
|
|
|
|
|
|
// Don't re-use with different content
|
|
|
|
|
$updater3 = $page->getDerivedDataUpdater( $admin, null, $slotsUpdate );
|
|
|
|
|
$updater3->prepareUpdate( $revision );
|
|
|
|
|
$this->assertNotSame( $updater2b, $updater3 );
|
|
|
|
|
|
|
|
|
|
// Don't re-use if no context given
|
|
|
|
|
$updater4 = $page->getDerivedDataUpdater( $admin );
|
|
|
|
|
$updater4->prepareUpdate( $revision );
|
|
|
|
|
$this->assertNotSame( $updater3, $updater4 );
|
|
|
|
|
|
|
|
|
|
// Don't re-use if AGAIN no context given
|
|
|
|
|
$updater5 = $page->getDerivedDataUpdater( $admin );
|
|
|
|
|
$this->assertNotSame( $updater4, $updater5 );
|
|
|
|
|
|
|
|
|
|
// Don't re-use cached "virgin" unprepared updater
|
|
|
|
|
$updater6 = $page->getDerivedDataUpdater( $admin, $revision );
|
|
|
|
|
$this->assertNotSame( $updater5, $updater6 );
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-28 15:34:25 +00:00
|
|
|
protected function assertPreparedEditEquals(
|
|
|
|
|
PreparedEdit $edit, PreparedEdit $edit2, $message = ''
|
|
|
|
|
) {
|
|
|
|
|
// suppress differences caused by a clock tick between generating the two PreparedEdits
|
|
|
|
|
if ( abs( $edit->timestamp - $edit2->timestamp ) < 3 ) {
|
|
|
|
|
$edit2 = clone $edit2;
|
|
|
|
|
$edit2->timestamp = $edit->timestamp;
|
|
|
|
|
}
|
|
|
|
|
$this->assertEquals( $edit, $edit2, $message );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function assertPreparedEditNotEquals(
|
|
|
|
|
PreparedEdit $edit, PreparedEdit $edit2, $message = ''
|
|
|
|
|
) {
|
|
|
|
|
if ( abs( $edit->timestamp - $edit2->timestamp ) < 3 ) {
|
|
|
|
|
$edit2 = clone $edit2;
|
|
|
|
|
$edit2->timestamp = $edit->timestamp;
|
|
|
|
|
}
|
|
|
|
|
$this->assertNotEquals( $edit, $edit2, $message );
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-02 17:35:42 +00:00
|
|
|
}
|