3 use MediaWiki\CommentStore\CommentStoreComment
;
4 use MediaWiki\Content\WikitextContent
;
5 use MediaWiki\Logger\Spi
as LoggerSpi
;
6 use MediaWiki\Parser\ParserOptions
;
7 use MediaWiki\PoolCounter\PoolWorkArticleView
;
8 use MediaWiki\Revision\MutableRevisionRecord
;
9 use MediaWiki\Revision\RevisionRecord
;
10 use MediaWiki\Revision\SlotRecord
;
11 use MediaWiki\Status\Status
;
12 use Psr\Log\LoggerInterface
;
13 use Psr\Log\NullLogger
;
16 * @covers \MediaWiki\PoolCounter\PoolWorkArticleView
19 class PoolWorkArticleViewTest
extends MediaWikiIntegrationTestCase
{
22 * @param LoggerInterface|null $logger
26 protected function getLoggerSpi( $logger = null ) {
27 $spi = $this->createNoOpMock( LoggerSpi
::class, [ 'getLogger' ] );
28 $spi->method( 'getLogger' )->willReturn( $logger ??
new NullLogger() );
33 * @param WikiPage $page
34 * @param RevisionRecord|null $rev
35 * @param ParserOptions|null $options
37 * @return PoolWorkArticleView
39 protected function newPoolWorkArticleView(
41 ?RevisionRecord
$rev = null,
45 $options = ParserOptions
::newFromAnon();
49 $rev = $page->getRevisionRecord();
52 $revisionRenderer = $this->getServiceContainer()->getRevisionRenderer();
54 return new PoolWorkArticleView(
55 'test:' . $rev->getId(),
63 private function makeRevision( WikiPage
$page, $text ) {
64 $user = $this->getTestUser()->getUser();
65 $revision = $page->newPageUpdater( $user )
66 ->setContent( SlotRecord
::MAIN
, new WikitextContent( $text ) )
67 ->saveRevision( CommentStoreComment
::newUnsavedComment( 'testing' ) );
72 public function testDoWorkLoadRevision() {
73 $options = ParserOptions
::newFromAnon();
74 $page = $this->getExistingTestPage( __METHOD__
);
75 $rev1 = $this->makeRevision( $page, 'First!' );
76 $rev2 = $this->makeRevision( $page, 'Second!' );
78 $work = $this->newPoolWorkArticleView( $page, $rev1, $options );
79 /** @var Status $status */
80 $status = $work->execute();
81 $this->assertStringContainsString( 'First', $status->getValue()->getText() );
83 $work = $this->newPoolWorkArticleView( $page, $rev2, $options );
84 /** @var Status $status */
85 $status = $work->execute();
86 $this->assertStringContainsString( 'Second', $status->getValue()->getText() );
89 public function testDoWorkParserCache() {
90 $options = ParserOptions
::newFromAnon();
91 $page = $this->getExistingTestPage( __METHOD__
);
92 $rev1 = $this->makeRevision( $page, 'First!' );
94 $work = $this->newPoolWorkArticleView( $page, $rev1, $options );
97 $cache = $this->getServiceContainer()->getParserCache();
98 $out = $cache->get( $page, $options );
100 $this->assertNotNull( $out );
101 $this->assertNotFalse( $out );
102 $this->assertStringContainsString( 'First', $out->getRawText() );
105 public function testDoWorkWithFakeRevision() {
106 $options = ParserOptions
::newFromAnon();
107 $page = $this->getExistingTestPage( __METHOD__
);
108 $rev = $this->makeRevision( $page, 'NOPE' );
110 // Make a fake revision with different content and no revision ID or page ID,
111 // and make sure the fake content is used.
112 $fakeRev = new MutableRevisionRecord( $page->getTitle() );
113 $fakeRev->setContent( SlotRecord
::MAIN
, new WikitextContent( 'YES!' ) );
115 $work = $this->newPoolWorkArticleView( $page, $fakeRev, $options );
116 /** @var Status $status */
117 $status = $work->execute();
119 $text = $status->getValue()->getText();
120 $this->assertStringContainsString( 'YES!', $text );
121 $this->assertStringNotContainsString( 'NOPE', $text );
124 public static function provideMagicWords() {
126 'Test {{PAGEID}} Test',
127 static function ( RevisionRecord
$rev ) {
128 return $rev->getPageId();
131 yield
'REVISIONID' => [
132 'Test {{REVISIONID}} Test',
133 static function ( RevisionRecord
$rev ) {
134 return $rev->getId();
137 yield
'REVISIONUSER' => [
138 'Test {{REVISIONUSER}} Test',
139 static function ( RevisionRecord
$rev ) {
140 return $rev->getUser()->getName();
143 yield
'REVISIONTIMESTAMP' => [
144 'Test {{REVISIONTIMESTAMP}} Test',
145 static function ( RevisionRecord
$rev ) {
146 return $rev->getTimestamp();
152 * @dataProvider provideMagicWords
154 public function testMagicWords( $wikitext, $callback ) {
157 $options = ParserOptions
::newFromAnon();
158 $page = $this->getNonexistingTestPage( __METHOD__
. $counter++
);
159 $this->editPage( $page, $wikitext );
160 $rev = $page->getRevisionRecord();
162 // NOTE: provide the input as a string and let the PoolWorkArticleView create a fake
163 // revision internally, to see if the magic words work with that fake. They should
164 // work if the Parser causes the actual revision to be loaded when needed.
165 $work = $this->newPoolWorkArticleView(
167 $page->getRevisionRecord(),
171 /** @var Status $status */
172 $status = $work->execute();
174 $expected = strval( $callback( $rev ) );
175 $output = $status->getValue();
177 $this->assertStringContainsString( $expected, $output->getText() );
180 public function testDoWorkDeletedContent() {
181 $options = ParserOptions
::newFromAnon();
182 $page = $this->getExistingTestPage( __METHOD__
);
183 $rev1 = $page->getRevisionRecord();
185 // make another revision, since the latest revision cannot be deleted.
186 $rev2 = $this->makeRevision( $page, 'Next' );
188 // make a fake revision with deleted different content
189 $fakeRev = new MutableRevisionRecord( $page->getTitle() );
190 $fakeRev->setId( $rev1->getId() );
191 $fakeRev->setPageId( $page->getId() );
192 $fakeRev->setContent( SlotRecord
::MAIN
, new WikitextContent( 'SECRET' ) );
193 $fakeRev->setVisibility( RevisionRecord
::DELETED_TEXT
);
195 // rendering of a deleted revision should work, audience checks are bypassed
196 $work = $this->newPoolWorkArticleView( $page, $fakeRev, $options );
197 /** @var Status $status */
198 $status = $work->execute();
199 $this->assertStatusGood( $status );