123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- <?php
- use MediaWiki\MediaWikiServices;
- use MediaWiki\Storage\MutableRevisionRecord;
- use MediaWiki\Storage\RevisionRecord;
- use PHPUnit\Framework\MockObject\MockObject;
- /**
- * @covers \Article::view()
- */
- class ArticleViewTest extends MediaWikiTestCase {
- protected function setUp() {
- 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 );
- $u->setContent( 'main', $cont );
- $rev = $u->saveRevision( CommentStoreComment::newUnsavedComment( 'Rev ' . $key ) );
- $revisions[ $key ] = $rev;
- }
- return $page;
- }
- /**
- * @covers Article::getOldId()
- * @covers Article::getRevIdFetched()
- */
- public function testGetOldId() {
- $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();
- $this->assertContains( 'Test B', $this->getHtml( $output ) );
- $this->assertNotContains( 'id="mw-revision-info"', $this->getHtml( $output ) );
- $this->assertNotContains( 'id="mw-revision-nav"', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains( 'Cached Text', $this->getHtml( $output ) );
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
- }
- /**
- * @covers Article::getRedirectTarget()
- */
- 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(
- $article->getRedirectTarget()->getPrefixedDBkey()
- );
- $this->assertSame(
- $target->getPrefixedDBkey(),
- $article->getRedirectTarget()->getPrefixedDBkey()
- );
- $output = $article->getContext()->getOutput();
- $this->assertContains( 'class="redirectText"', $this->getHtml( $output ) );
- $this->assertContains(
- '>' . htmlspecialchars( $target->getPrefixedText() ) . '<',
- $this->getHtml( $output )
- );
- }
- public function testViewNonText() {
- $dummy = $this->getPage( __METHOD__, [ 'Dummy' ] );
- $dummyRev = $dummy->getRevision()->getRevisionRecord();
- $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 */
- $content = $this->getMock( Content::class );
- $content->method( 'getParserOutput' )
- ->willReturn( new ParserOutput( 'Structured Output' ) );
- $content->method( 'getModel' )
- ->willReturn( 'NotText' );
- $content->method( 'getNativeData' )
- ->willReturn( [ (object)[ 'x' => 'stuff' ] ] );
- $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() );
- $rev->setContent( 'main', $content );
- $rev = new Revision( $rev );
- /** @var MockObject|WikiPage $page */
- $page = $this->getMockBuilder( WikiPage::class )
- ->setMethods( [ 'getRevision', 'getLatest' ] )
- ->setConstructorArgs( [ $title ] )
- ->getMock();
- $page->method( 'getRevision' )
- ->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();
- $this->assertContains( 'Structured Output', $this->getHtml( $output ) );
- $this->assertNotContains( 'Dummy', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains( 'Test A', $this->getHtml( $output ) );
- $this->assertContains( 'id="mw-revision-info"', $output->getSubtitle() );
- $this->assertContains( 'id="mw-revision-nav"', $output->getSubtitle() );
- $this->assertNotContains( 'id="revision-info-current"', $output->getSubtitle() );
- $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains( 'Test B', $this->getHtml( $output ) );
- $this->assertContains( 'id="mw-revision-info-current"', $output->getSubtitle() );
- $this->assertContains( 'id="mw-revision-nav"', $output->getSubtitle() );
- }
- 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();
- $this->assertContains( 'missing-revision: ' . $badId, $this->getHtml( $output ) );
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- }
- public function testViewOfDeletedRevision() {
- $revisions = [];
- $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ], $revisions );
- $idA = $revisions[1]->getId();
- $revDelList = new RevDelRevisionList(
- RequestContext::getMain(), $page->getTitle(), [ $idA ]
- );
- $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();
- $this->assertContains( '(rev-deleted-text-permission)', $this->getHtml( $output ) );
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
- }
- public function testViewMissingPage() {
- $page = $this->getPage( __METHOD__ );
- $article = new Article( $page->getTitle() );
- $article->getContext()->getOutput()->setTitle( $page->getTitle() );
- $article->view();
- $output = $article->getContext()->getOutput();
- $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
- }
- public function testViewDeletedPage() {
- $page = $this->getPage( __METHOD__, [ 1 => 'Test A', 2 => 'Test B' ] );
- $page->doDeleteArticle( 'Test' );
- $article = new Article( $page->getTitle() );
- $article->getContext()->getOutput()->setTitle( $page->getTitle() );
- $article->view();
- $output = $article->getContext()->getOutput();
- $this->assertContains( 'moveddeleted', $this->getHtml( $output ) );
- $this->assertContains( 'logentry-delete-delete', $this->getHtml( $output ) );
- $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertNotContains( 'Test B', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains(
- wfMessage( 'mainpage' )->inContentLanguage()->parse(),
- $this->getHtml( $output )
- );
- $this->assertNotContains( '(noarticletextanon)', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
- $this->assertNotContains( '(userpage-userdoesnotexist-view)', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
- $this->assertContains( '(userpage-userdoesnotexist-view:', $this->getHtml( $output ) );
- }
- 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();
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
- $this->assertSame( 'Hook Title', $output->getPageTitle() );
- }
- public function testArticleContentViewCustomHook() {
- $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(
- 'ArticleContentViewCustom',
- function ( Content $content, Title $title, OutputPage $output ) use ( $page ) {
- $this->assertSame( $page->getTitle(), $title, '$title' );
- $this->assertSame( 'Test A', $content->getNativeData(), '$content' );
- $output->addHTML( 'Hook Text' );
- return false;
- }
- );
- $this->hideDeprecated(
- 'ArticleContentViewCustom hook (used in hook-ArticleContentViewCustom-closure)'
- );
- $article->view();
- $output = $article->getContext()->getOutput();
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
- }
- 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 ) {
- $content = $rev->getContent( 'main' );
- $this->assertSame( $page->getTitle(), $title, '$title' );
- $this->assertSame( 'Test A', $content->getNativeData(), '$content' );
- $output->addHTML( 'Hook Text' );
- return false;
- }
- );
- $article->view();
- $output = $article->getContext()->getOutput();
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
- }
- public function testArticleAfterFetchContentObjectHook() {
- $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(
- 'ArticleAfterFetchContentObject',
- function ( Article &$articlePage, Content &$content ) use ( $page, $article ) {
- $this->assertSame( $article, $articlePage, '$articlePage' );
- $this->assertSame( 'Test A', $content->getNativeData(), '$content' );
- $content = new WikitextContent( 'Hook Text' );
- }
- );
- $this->hideDeprecated(
- 'ArticleAfterFetchContentObject hook'
- . ' (used in hook-ArticleAfterFetchContentObject-closure)'
- );
- $article->view();
- $output = $article->getContext()->getOutput();
- $this->assertNotContains( 'Test A', $this->getHtml( $output ) );
- $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
- }
- 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();
- $this->assertContains( '(noarticletextanon)', $this->getHtml( $output ) );
- $this->assertContains( 'Hook Text', $this->getHtml( $output ) );
- }
- }
|