2018-08-16 15:45:10 +00:00
|
|
|
<?php
|
2019-05-28 14:04:23 +00:00
|
|
|
|
2018-08-16 15:45:10 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2018-09-20 17:29:04 +00:00
|
|
|
use MediaWiki\Revision\MutableRevisionRecord;
|
|
|
|
|
use MediaWiki\Revision\RevisionRecord;
|
|
|
|
|
use MediaWiki\Revision\SlotRecord;
|
2018-08-16 15:45:10 +00:00
|
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
2020-11-05 19:31:26 +00:00
|
|
|
use Wikimedia\TestingAccessWrapper;
|
2018-08-16 15:45:10 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers \Article::view()
|
|
|
|
|
*/
|
2020-06-30 15:09:24 +00:00
|
|
|
class ArticleViewTest extends MediaWikiIntegrationTestCase {
|
2018-08-16 15:45:10 +00:00
|
|
|
|
2019-10-20 18:11:08 +00:00
|
|
|
protected function setUp() : void {
|
2018-08-16 15:45:10 +00:00
|
|
|
parent::setUp();
|
|
|
|
|
|
|
|
|
|
$this->setUserLang( 'qqx' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getHtml( OutputPage $output ) {
|
|
|
|
|
return preg_replace( '/<!--.*?-->/s', '', $output->getHTML() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string|Title $title
|
|
|
|
|
* @param Content[]|string[] $revisionContents Content of the revisions to create
|
|
|
|
|
* (as Content or string).
|
|
|
|
|
* @param RevisionRecord[] &$revisions will be filled with the RevisionRecord for $content.
|
|
|
|
|
*
|
|
|
|
|
* @return WikiPage
|
|
|
|
|
* @throws MWException
|
|
|
|
|
*/
|
|
|
|
|
private function getPage( $title, array $revisionContents = [], array &$revisions = [] ) {
|
|
|
|
|
if ( is_string( $title ) ) {
|
|
|
|
|
$title = Title::makeTitle( $this->getDefaultWikitextNS(), $title );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$page = WikiPage::factory( $title );
|
|
|
|
|
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
|
|
|
|
|
foreach ( $revisionContents as $key => $cont ) {
|
|
|
|
|
if ( is_string( $cont ) ) {
|
|
|
|
|
$cont = new WikitextContent( $cont );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$u = $page->newPageUpdater( $user );
|
2018-09-24 21:10:08 +00:00
|
|
|
$u->setContent( SlotRecord::MAIN, $cont );
|
2018-08-16 15:45:10 +00:00
|
|
|
$rev = $u->saveRevision( CommentStoreComment::newUnsavedComment( 'Rev ' . $key ) );
|
|
|
|
|
|
|
|
|
|
$revisions[ $key ] = $rev;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-04 13:35:38 +00:00
|
|
|
// Clear content model cache to support tests that mock the revision
|
|
|
|
|
$this->getServiceContainer()->getMainWANObjectCache()->clearProcessCache();
|
|
|
|
|
|
2018-08-16 15:45:10 +00:00
|
|
|
return $page;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers Article::getOldId()
|
|
|
|
|
* @covers Article::getRevIdFetched()
|
|
|
|
|
*/
|
|
|
|
|
public function testGetOldId() {
|
2020-04-10 04:37:43 +00:00
|
|
|
$this->hideDeprecated( 'Article::getRevisionFetched' );
|
2020-07-02 06:22:52 +00:00
|
|
|
$this->hideDeprecated( 'Revision::__construct' );
|
2020-04-10 04:37:43 +00:00
|
|
|
|
2018-08-16 15:45:10 +00:00
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
|
|
|
|
|
$idA = $revisions[1]->getId();
|
|
|
|
|
$idB = $revisions[2]->getId();
|
|
|
|
|
|
|
|
|
|
// oldid in constructor
|
|
|
|
|
$article = new Article( $page->getTitle(), $idA );
|
|
|
|
|
$this->assertSame( $idA, $article->getOldID() );
|
|
|
|
|
$article->getRevisionFetched();
|
|
|
|
|
$this->assertSame( $idA, $article->getRevIdFetched() );
|
|
|
|
|
|
|
|
|
|
// oldid 0 in constructor
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$this->assertSame( 0, $article->getOldID() );
|
|
|
|
|
$article->getRevisionFetched();
|
|
|
|
|
$this->assertSame( $idB, $article->getRevIdFetched() );
|
|
|
|
|
|
|
|
|
|
// oldid in request
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
$context->setRequest( new FauxRequest( [ 'oldid' => $idA ] ) );
|
|
|
|
|
$article->setContext( $context );
|
|
|
|
|
$this->assertSame( $idA, $article->getOldID() );
|
|
|
|
|
$article->getRevisionFetched();
|
|
|
|
|
$this->assertSame( $idA, $article->getRevIdFetched() );
|
|
|
|
|
|
|
|
|
|
// no oldid
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
$context->setRequest( new FauxRequest( [] ) );
|
|
|
|
|
$article->setContext( $context );
|
|
|
|
|
$this->assertSame( 0, $article->getOldID() );
|
|
|
|
|
$article->getRevisionFetched();
|
|
|
|
|
$this->assertSame( $idB, $article->getRevIdFetched() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testView() {
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'Test B', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'id="mw-revision-info"', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'id="mw-revision-nav"', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewCached() {
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
|
|
|
|
|
|
|
|
|
|
$po = new ParserOutput( 'Cached Text' );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
$cache = MediaWikiServices::getInstance()->getParserCache();
|
|
|
|
|
$cache->save( $po, $page, $article->getParserOptions() );
|
|
|
|
|
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'Cached Text', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'Test B', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-03-26 00:43:50 +00:00
|
|
|
* @covers Article::getPage()
|
|
|
|
|
* @covers WikiPage::getRedirectTarget()
|
2018-08-16 15:45:10 +00:00
|
|
|
*/
|
|
|
|
|
public function testViewRedirect() {
|
|
|
|
|
$target = Title::makeTitle( $this->getDefaultWikitextNS(), 'Test_Target' );
|
|
|
|
|
$redirectText = '#REDIRECT [[' . $target->getPrefixedText() . ']]';
|
|
|
|
|
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ $redirectText ] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$this->assertNotNull(
|
2020-03-26 00:43:50 +00:00
|
|
|
$article->getPage()->getRedirectTarget()->getPrefixedDBkey()
|
2018-08-16 15:45:10 +00:00
|
|
|
);
|
|
|
|
|
$this->assertSame(
|
|
|
|
|
$target->getPrefixedDBkey(),
|
2020-03-26 00:43:50 +00:00
|
|
|
$article->getPage()->getRedirectTarget()->getPrefixedDBkey()
|
2018-08-16 15:45:10 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'class="redirectText"', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString(
|
2018-08-16 15:45:10 +00:00
|
|
|
'>' . htmlspecialchars( $target->getPrefixedText() ) . '<',
|
|
|
|
|
$this->getHtml( $output )
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewNonText() {
|
|
|
|
|
$dummy = $this->getPage( __METHOD__, [ 'Dummy' ] );
|
2020-04-18 02:39:58 +00:00
|
|
|
$dummyRev = $dummy->getRevisionRecord();
|
2018-08-16 15:45:10 +00:00
|
|
|
$title = $dummy->getTitle();
|
|
|
|
|
|
|
|
|
|
/** @var MockObject|ContentHandler $mockHandler */
|
|
|
|
|
$mockHandler = $this->getMockBuilder( ContentHandler::class )
|
|
|
|
|
->setMethods(
|
|
|
|
|
[
|
|
|
|
|
'isParserCacheSupported',
|
|
|
|
|
'serializeContent',
|
|
|
|
|
'unserializeContent',
|
|
|
|
|
'makeEmptyContent',
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
->setConstructorArgs( [ 'NotText', [ 'application/frobnitz' ] ] )
|
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
|
|
$mockHandler->method( 'isParserCacheSupported' )
|
|
|
|
|
->willReturn( false );
|
|
|
|
|
|
|
|
|
|
$this->setTemporaryHook(
|
|
|
|
|
'ContentHandlerForModelID',
|
|
|
|
|
function ( $id, &$handler ) use ( $mockHandler ) {
|
|
|
|
|
$handler = $mockHandler;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** @var MockObject|Content $content */
|
2019-10-05 05:21:11 +00:00
|
|
|
$content = $this->createMock( Content::class );
|
2018-08-16 15:45:10 +00:00
|
|
|
$content->method( 'getParserOutput' )
|
|
|
|
|
->willReturn( new ParserOutput( 'Structured Output' ) );
|
|
|
|
|
$content->method( 'getModel' )
|
|
|
|
|
->willReturn( 'NotText' );
|
2019-02-07 00:14:23 +00:00
|
|
|
$content->expects( $this->never() )->method( 'getNativeData' );
|
2018-08-16 15:45:10 +00:00
|
|
|
$content->method( 'copy' )
|
|
|
|
|
->willReturn( $content );
|
|
|
|
|
|
|
|
|
|
$rev = new MutableRevisionRecord( $title );
|
|
|
|
|
$rev->setId( $dummyRev->getId() );
|
|
|
|
|
$rev->setPageId( $title->getArticleID() );
|
|
|
|
|
$rev->setUser( $dummyRev->getUser() );
|
|
|
|
|
$rev->setComment( $dummyRev->getComment() );
|
|
|
|
|
$rev->setTimestamp( $dummyRev->getTimestamp() );
|
|
|
|
|
|
2018-09-24 21:10:08 +00:00
|
|
|
$rev->setContent( SlotRecord::MAIN, $content );
|
2018-08-16 15:45:10 +00:00
|
|
|
|
|
|
|
|
/** @var MockObject|WikiPage $page */
|
|
|
|
|
$page = $this->getMockBuilder( WikiPage::class )
|
2020-04-18 02:39:58 +00:00
|
|
|
->setMethods( [ 'getRevisionRecord', 'getLatest' ] )
|
2018-08-16 15:45:10 +00:00
|
|
|
->setConstructorArgs( [ $title ] )
|
|
|
|
|
->getMock();
|
|
|
|
|
|
2020-04-18 02:39:58 +00:00
|
|
|
$page->method( 'getRevisionRecord' )
|
2018-08-16 15:45:10 +00:00
|
|
|
->willReturn( $rev );
|
|
|
|
|
$page->method( 'getLatest' )
|
|
|
|
|
->willReturn( $rev->getId() );
|
|
|
|
|
|
|
|
|
|
$article = Article::newFromWikiPage( $page, RequestContext::getMain() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'Structured Output', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'Dummy', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewOfOldRevision() {
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
$idA = $revisions[1]->getId();
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $idA );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( 'id="mw-revision-info"', $output->getSubtitle() );
|
|
|
|
|
$this->assertStringContainsString( 'id="mw-revision-nav"', $output->getSubtitle() );
|
2018-08-16 15:45:10 +00:00
|
|
|
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( 'id="revision-info-current"', $output->getSubtitle() );
|
|
|
|
|
$this->assertStringNotContainsString( 'Test B', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-09 03:09:26 +00:00
|
|
|
public function testViewOfOldRevisionFromCache() {
|
|
|
|
|
$this->setMwGlobals( [
|
|
|
|
|
'wgOldRevisionParserCacheExpireTime' => 100500,
|
|
|
|
|
'wgMainWANCache' => 'main',
|
|
|
|
|
'wgWANObjectCaches' => [
|
|
|
|
|
'main' => [
|
|
|
|
|
'class' => WANObjectCache::class,
|
|
|
|
|
'cacheId' => 'hash',
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
] );
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
$idA = $revisions[1]->getId();
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $idA );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
// Force cache
|
|
|
|
|
MediaWikiServices::getInstance()
|
|
|
|
|
->getParserOutputAccess()
|
|
|
|
|
->getParserOutput(
|
|
|
|
|
$page,
|
|
|
|
|
ParserOptions::newCanonical( $article->getContext()->getUser() ),
|
|
|
|
|
$revisions[1]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
|
|
|
|
$this->assertStringContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertSame( 1, substr_count( $output->getSubtitle(), 'class="mw-revision warningbox"' ) );
|
2020-12-17 13:22:35 +00:00
|
|
|
$this->assertSame( $idA, $output->getRevisionId() );
|
2020-12-09 03:09:26 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-16 15:45:10 +00:00
|
|
|
public function testViewOfCurrentRevision() {
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
$idB = $revisions[2]->getId();
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $idB );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'Test B', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( 'id="mw-revision-info-current"', $output->getSubtitle() );
|
|
|
|
|
$this->assertStringContainsString( 'id="mw-revision-nav"', $output->getSubtitle() );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewOfMissingRevision() {
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A' ], $revisions );
|
|
|
|
|
$badId = $revisions[1]->getId() + 100;
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $badId );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'missing-revision: ' . $badId, $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( 'Test A', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewOfDeletedRevision() {
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
$idA = $revisions[1]->getId();
|
|
|
|
|
|
2020-11-25 04:28:52 +00:00
|
|
|
$revDelList = $this->getRevDelRevisionList( $page->getTitle(), $idA );
|
2018-08-16 15:45:10 +00:00
|
|
|
$revDelList->setVisibility( [
|
|
|
|
|
'value' => [ RevisionRecord::DELETED_TEXT => 1 ],
|
|
|
|
|
'comment' => "Testing",
|
|
|
|
|
] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $idA );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-04 06:49:47 +00:00
|
|
|
$this->assertStringContainsString( 'rev-deleted-text-permission', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'Test B', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-02 01:33:28 +00:00
|
|
|
public function testUnhiddenViewOfDeletedRevision() {
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
$idA = $revisions[1]->getId();
|
|
|
|
|
|
2020-11-25 04:28:52 +00:00
|
|
|
$revDelList = $this->getRevDelRevisionList( $page->getTitle(), $idA );
|
2018-10-02 01:33:28 +00:00
|
|
|
$revDelList->setVisibility( [
|
|
|
|
|
'value' => [ RevisionRecord::DELETED_TEXT => 1 ],
|
|
|
|
|
'comment' => "Testing",
|
|
|
|
|
] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $idA );
|
|
|
|
|
$context = new DerivativeContext( $article->getContext() );
|
|
|
|
|
$article->setContext( $context );
|
|
|
|
|
$context->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$context->getRequest()->setVal( 'unhide', 1 );
|
|
|
|
|
$context->setUser( $this->getTestUser( [ 'sysop' ] )->getUser() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-04 06:49:47 +00:00
|
|
|
$this->assertStringContainsString( 'rev-deleted-text-view', $this->getHtml( $output ) );
|
2018-10-02 01:33:28 +00:00
|
|
|
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'Test B', $this->getHtml( $output ) );
|
2018-10-02 01:33:28 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-16 15:45:10 +00:00
|
|
|
public function testViewMissingPage() {
|
|
|
|
|
$page = $this->getPage( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( '(noarticletextanon)', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewDeletedPage() {
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
|
2020-03-25 17:05:26 +00:00
|
|
|
$page->doDeleteArticleReal( 'Test', $this->getTestSysop()->getUser() );
|
2018-08-16 15:45:10 +00:00
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( 'moveddeleted', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( 'logentry-delete-delete', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( '(noarticletextanon)', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString( 'Test B', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewMessagePage() {
|
|
|
|
|
$title = Title::makeTitle( NS_MEDIAWIKI, 'Mainpage' );
|
|
|
|
|
$page = $this->getPage( $title );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 12:22:50 +00:00
|
|
|
$this->assertStringContainsString(
|
2018-08-16 15:45:10 +00:00
|
|
|
wfMessage( 'mainpage' )->inContentLanguage()->parse(),
|
|
|
|
|
$this->getHtml( $output )
|
|
|
|
|
);
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( '(noarticletextanon)', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewMissingUserPage() {
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
$user->addToDatabase();
|
|
|
|
|
|
|
|
|
|
$title = Title::makeTitle( NS_USER, $user->getName() );
|
|
|
|
|
|
|
|
|
|
$page = $this->getPage( $title );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( '(noarticletextanon)', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringNotContainsString(
|
|
|
|
|
'(userpage-userdoesnotexist-view)',
|
|
|
|
|
$this->getHtml( $output )
|
|
|
|
|
);
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testViewUserPageOfNonexistingUser() {
|
|
|
|
|
$user = User::newFromName( 'Testing ' . __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$title = Title::makeTitle( NS_USER, $user->getName() );
|
|
|
|
|
|
|
|
|
|
$page = $this->getPage( $title );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( '(noarticletextanon)', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString(
|
|
|
|
|
'(userpage-userdoesnotexist-view:',
|
|
|
|
|
$this->getHtml( $output )
|
|
|
|
|
);
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testArticleViewHeaderHook() {
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A' ] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
$this->setTemporaryHook(
|
|
|
|
|
'ArticleViewHeader',
|
|
|
|
|
function ( Article $articlePage, &$outputDone, &$useParserCache ) use ( $article ) {
|
|
|
|
|
$this->assertSame( $article, $articlePage, '$articlePage' );
|
|
|
|
|
|
|
|
|
|
$outputDone = new ParserOutput( 'Hook Text' );
|
|
|
|
|
$outputDone->setTitleText( 'Hook Title' );
|
|
|
|
|
|
|
|
|
|
$articlePage->getContext()->getOutput()->addParserOutput( $outputDone );
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( 'Hook Text', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
$this->assertSame( 'Hook Title', $output->getPageTitle() );
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-14 16:37:30 +00:00
|
|
|
public function testArticleRevisionViewCustomHook() {
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A' ] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
// use ArticleViewHeader hook to bypass the parser cache
|
|
|
|
|
$this->setTemporaryHook(
|
|
|
|
|
'ArticleViewHeader',
|
|
|
|
|
function ( Article $articlePage, &$outputDone, &$useParserCache ) use ( $article ) {
|
|
|
|
|
$useParserCache = false;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->setTemporaryHook(
|
|
|
|
|
'ArticleRevisionViewCustom',
|
|
|
|
|
function ( RevisionRecord $rev, Title $title, $oldid, OutputPage $output ) use ( $page ) {
|
2018-09-24 21:10:08 +00:00
|
|
|
$content = $rev->getContent( SlotRecord::MAIN );
|
2018-08-14 16:37:30 +00:00
|
|
|
$this->assertSame( $page->getTitle(), $title, '$title' );
|
2019-02-07 00:14:23 +00:00
|
|
|
$this->assertSame( 'Test A', $content->getText(), '$content' );
|
2018-08-14 16:37:30 +00:00
|
|
|
|
|
|
|
|
$output->addHTML( 'Hook Text' );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2018-08-16 15:45:10 +00:00
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringNotContainsString( 'Test A', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( 'Hook Text', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testShowMissingArticleHook() {
|
|
|
|
|
$page = $this->getPage( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle() );
|
|
|
|
|
$article->getContext()->getOutput()->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
$this->setTemporaryHook(
|
|
|
|
|
'ShowMissingArticle',
|
|
|
|
|
function ( Article $articlePage ) use ( $article ) {
|
|
|
|
|
$this->assertSame( $article, $articlePage, '$articlePage' );
|
|
|
|
|
|
|
|
|
|
$articlePage->getContext()->getOutput()->addHTML( 'Hook Text' );
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
2019-12-14 10:27:56 +00:00
|
|
|
$this->assertStringContainsString( '(noarticletextanon)', $this->getHtml( $output ) );
|
|
|
|
|
$this->assertStringContainsString( 'Hook Text', $this->getHtml( $output ) );
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-05 19:31:26 +00:00
|
|
|
/**
|
|
|
|
|
* @covers \Article::showViewError()
|
|
|
|
|
*/
|
|
|
|
|
public function testViewLatestError() {
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A' ] );
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), 0 );
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
|
|
|
|
$output->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
// use ArticleViewHeader hook to bypass the parser cache
|
|
|
|
|
$this->setTemporaryHook(
|
|
|
|
|
'ArticleViewHeader',
|
|
|
|
|
function ( Article $articlePage, &$outputDone, &$useParserCache ) use ( $article ) {
|
|
|
|
|
$useParserCache = false;
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$article = TestingAccessWrapper::newFromObject( $article );
|
|
|
|
|
$article->fetchResult = Status::newFatal(
|
|
|
|
|
'rev-deleted-text-permission',
|
|
|
|
|
$page->getTitle()->getPrefixedDBkey()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$this->assertStringContainsString(
|
|
|
|
|
'rev-deleted-text-permission: ArticleViewTest::testViewLatestError',
|
|
|
|
|
$this->getHtml( $output )
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers \Article::showViewError()
|
|
|
|
|
*/
|
|
|
|
|
public function testViewOldError() {
|
|
|
|
|
$revisions = [];
|
|
|
|
|
$page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
|
|
|
|
|
$idA = $revisions[1]->getId();
|
|
|
|
|
|
|
|
|
|
$article = new Article( $page->getTitle(), $idA );
|
|
|
|
|
$output = $article->getContext()->getOutput();
|
|
|
|
|
$output->setTitle( $page->getTitle() );
|
|
|
|
|
|
|
|
|
|
$article = TestingAccessWrapper::newFromObject( $article );
|
|
|
|
|
$article->fetchResult = Status::newFatal(
|
|
|
|
|
'rev-deleted-text-permission',
|
|
|
|
|
$page->getTitle()->getPrefixedDBkey()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$article->view();
|
|
|
|
|
|
|
|
|
|
$this->assertStringContainsString(
|
|
|
|
|
'rev-deleted-text-permission: ArticleViewTest::testViewOldError',
|
|
|
|
|
$this->getHtml( $output )
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-11-25 04:28:52 +00:00
|
|
|
|
|
|
|
|
private function getRevDelRevisionList( $title, $revisionId ) {
|
|
|
|
|
$services = MediaWikiServices::getInstance();
|
|
|
|
|
return new RevDelRevisionList(
|
|
|
|
|
RequestContext::getMain(),
|
|
|
|
|
$title,
|
|
|
|
|
[ $revisionId ],
|
|
|
|
|
$services->getDBLoadBalancerFactory(),
|
|
|
|
|
$services->getHookContainer(),
|
|
|
|
|
$services->getHtmlCacheUpdater(),
|
|
|
|
|
$services->getRevisionStore(),
|
|
|
|
|
$services->getMainWANObjectCache()
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-08-16 15:45:10 +00:00
|
|
|
}
|