Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4154664
ArticleViewTest.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
26 KB
Referenced Files
None
Subscribers
None
ArticleViewTest.php
View Options
<?php
use
MediaWiki\CommentStore\CommentStoreComment
;
use
MediaWiki\Content\Content
;
use
MediaWiki\Content\ContentHandler
;
use
MediaWiki\Content\WikitextContent
;
use
MediaWiki\Context\DerivativeContext
;
use
MediaWiki\Context\RequestContext
;
use
MediaWiki\MainConfigNames
;
use
MediaWiki\Output\OutputPage
;
use
MediaWiki\Parser\ParserOutput
;
use
MediaWiki\Request\FauxRequest
;
use
MediaWiki\Revision\MutableRevisionRecord
;
use
MediaWiki\Revision\RevisionRecord
;
use
MediaWiki\Revision\SlotRecord
;
use
MediaWiki\Status\Status
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\User
;
use
MediaWiki\Utils\MWTimestamp
;
use
PHPUnit\Framework\MockObject\MockObject
;
use
Wikimedia\TestingAccessWrapper
;
/**
* @covers \Article::view()
* @group Database
*/
class
ArticleViewTest
extends
MediaWikiIntegrationTestCase
{
protected
function
setUp
():
void
{
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
*/
private
function
getPage
(
$title
,
array
$revisionContents
=
[],
array
&
$revisions
=
[]
)
{
if
(
is_string
(
$title
)
)
{
$title
=
Title
::
makeTitle
(
$this
->
getDefaultWikitextNS
(),
$title
);
}
$page
=
$this
->
getServiceContainer
()->
getWikiPageFactory
()->
newFromTitle
(
$title
);
$user
=
$this
->
getTestUser
()->
getUser
();
// Make sure all revision have different timestamps all the time,
// to make timestamp asserts below deterministic.
$time
=
time
()
-
86400
;
MWTimestamp
::
setFakeTime
(
$time
);
foreach
(
$revisionContents
as
$key
=>
$cont
)
{
if
(
is_string
(
$cont
)
)
{
$cont
=
new
WikitextContent
(
$cont
);
}
$rev
=
$page
->
newPageUpdater
(
$user
)
->
setContent
(
SlotRecord
::
MAIN
,
$cont
)
->
saveRevision
(
CommentStoreComment
::
newUnsavedComment
(
'Rev '
.
$key
)
);
$revisions
[
$key
]
=
$rev
;
MWTimestamp
::
setFakeTime
(
++
$time
);
}
MWTimestamp
::
setFakeTime
(
false
);
// Clear content model cache to support tests that mock the revision
$this
->
getServiceContainer
()->
getMainWANObjectCache
()->
clearProcessCache
();
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
->
fetchRevisionRecord
();
$this
->
assertSame
(
$idA
,
$article
->
getRevIdFetched
()
);
// oldid 0 in constructor
$article
=
new
Article
(
$page
->
getTitle
(),
0
);
$this
->
assertSame
(
0
,
$article
->
getOldID
()
);
$article
->
fetchRevisionRecord
();
$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
->
fetchRevisionRecord
();
$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
->
fetchRevisionRecord
();
$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
->
assertStringContainsString
(
'Test B'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'id="mw-revision-info"'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'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
=
$this
->
getServiceContainer
()->
getParserCache
();
$cache
->
save
(
$po
,
$page
,
$article
->
getParserOptions
()
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringContainsString
(
'Cached Text'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'Test B'
,
$this
->
getHtml
(
$output
)
);
}
/**
* @covers \Article::getPage
* @covers \WikiPage::getRedirectTarget
* @covers \MediaWiki\Page\RedirectLookup::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
();
$redirectStore
=
$this
->
getServiceContainer
()->
getRedirectStore
();
$titleFormatter
=
$this
->
getServiceContainer
()->
getTitleFormatter
();
$this
->
assertNotNull
(
$redirectStore
->
getRedirectTarget
(
$article
->
getPage
()
)
);
$this
->
assertSame
(
$target
->
getPrefixedDBkey
(),
$titleFormatter
->
getPrefixedDBkey
(
$redirectStore
->
getRedirectTarget
(
$article
->
getPage
()
)
)
);
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringContainsString
(
'class="redirectText"'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'>'
.
htmlspecialchars
(
$target
->
getPrefixedText
()
)
.
'<'
,
$this
->
getHtml
(
$output
)
);
}
public
function
testViewNonText
()
{
$dummy
=
$this
->
getPage
(
__METHOD__
,
[
'Dummy'
]
);
$dummyRev
=
$dummy
->
getRevisionRecord
();
$title
=
$dummy
->
getTitle
();
/** @var MockObject|ContentHandler $mockHandler */
$mockHandler
=
$this
->
getMockBuilder
(
ContentHandler
::
class
)
->
onlyMethods
(
[
'isParserCacheSupported'
,
'serializeContent'
,
'unserializeContent'
,
'makeEmptyContent'
,
'getParserOutput'
,
]
)
->
setConstructorArgs
(
[
'NotText'
,
[
'application/frobnitz'
]
]
)
->
getMock
();
$mockHandler
->
method
(
'isParserCacheSupported'
)
->
willReturn
(
false
);
$mockHandler
->
method
(
'getParserOutput'
)
->
willReturn
(
new
ParserOutput
(
'Structured Output'
)
);
$this
->
setTemporaryHook
(
'ContentHandlerForModelID'
,
static
function
(
$id
,
&
$handler
)
use
(
$mockHandler
)
{
$handler
=
$mockHandler
;
}
);
/** @var MockObject|Content $content */
$content
=
$this
->
createMock
(
Content
::
class
);
$content
->
method
(
'getModel'
)
->
willReturn
(
'NotText'
);
$content
->
expects
(
$this
->
never
()
)->
method
(
'getNativeData'
);
$content
->
method
(
'copy'
)->
willReturnSelf
();
$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
(
SlotRecord
::
MAIN
,
$content
);
/** @var MockObject|WikiPage $page */
$page
=
$this
->
getMockBuilder
(
WikiPage
::
class
)
->
onlyMethods
(
[
'getRevisionRecord'
,
'getLatest'
,
'getContentHandler'
]
)
->
setConstructorArgs
(
[
$title
]
)
->
getMock
();
$page
->
method
(
'getRevisionRecord'
)
->
willReturn
(
$rev
);
$page
->
method
(
'getLatest'
)
->
willReturn
(
$rev
->
getId
()
);
$page
->
method
(
'getContentHandler'
)
->
willReturn
(
$mockHandler
);
$article
=
Article
::
newFromWikiPage
(
$page
,
RequestContext
::
getMain
()
);
$article
->
getContext
()->
getOutput
()->
setTitle
(
$page
->
getTitle
()
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringContainsString
(
'Structured Output'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'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
->
assertStringContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'id="mw-revision-info"'
,
$output
->
getSubtitle
()
);
$this
->
assertStringContainsString
(
'id="mw-revision-nav"'
,
$output
->
getSubtitle
()
);
$this
->
assertStringNotContainsString
(
'id="revision-info-current"'
,
$output
->
getSubtitle
()
);
$this
->
assertStringNotContainsString
(
'Test B'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertSame
(
$idA
,
$output
->
getRevisionId
()
);
$this
->
assertSame
(
$revisions
[
1
]->
getTimestamp
(),
$output
->
getRevisionTimestamp
()
);
}
public
function
testViewOfOldRevisionFromCache
()
{
$this
->
overrideConfigValues
(
[
MainConfigNames
::
OldRevisionParserCacheExpireTime
=>
100500
,
MainConfigNames
::
MainCacheType
=>
CACHE_HASH
,
]
);
$revisions
=
[];
$page
=
$this
->
getPage
(
__METHOD__
,
[
1
=>
'Test A'
,
2
=>
'Test B'
],
$revisions
);
$idA
=
$revisions
[
1
]->
getId
();
$context
=
RequestContext
::
getMain
();
$context
->
setTitle
(
$page
->
getTitle
()
);
// View the revision once (to get it into the cache)
$article
=
new
Article
(
$page
->
getTitle
(),
$idA
);
$article
->
view
();
// Reset the output page and view the revision again (from ParserCache)
$article
=
new
Article
(
$page
->
getTitle
(),
$idA
);
$context
->
setOutput
(
new
OutputPage
(
$context
)
);
$article
->
setContext
(
$context
);
$outputPageBeforeHTMLRevisionId
=
null
;
$this
->
setTemporaryHook
(
'OutputPageBeforeHTML'
,
static
function
(
OutputPage
$out
)
use
(
&
$outputPageBeforeHTMLRevisionId
)
{
$outputPageBeforeHTMLRevisionId
=
$out
->
getRevisionId
();
}
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertSame
(
1
,
substr_count
(
$output
->
getSubtitle
(),
'cdx-message--warning'
)
);
$this
->
assertSame
(
$idA
,
$output
->
getRevisionId
()
);
$this
->
assertSame
(
$idA
,
$outputPageBeforeHTMLRevisionId
);
$this
->
assertSame
(
$revisions
[
1
]->
getTimestamp
(),
$output
->
getRevisionTimestamp
()
);
}
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
->
assertStringContainsString
(
'Test B'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'id="mw-revision-info-current"'
,
$output
->
getSubtitle
()
);
$this
->
assertStringContainsString
(
'id="mw-revision-nav"'
,
$output
->
getSubtitle
()
);
}
public
function
testViewOfCurrentRevisionDirty
()
{
$this
->
overrideConfigValue
(
MainConfigNames
::
PoolCounterConf
,
[
'ArticleView'
=>
[
'class'
=>
MockPoolCounterFailing
::
class
,
]
]
);
$revisions
=
[];
$page
=
$this
->
getPage
(
__METHOD__
,
[
1
=>
'Test A'
],
$revisions
);
$idA
=
$revisions
[
1
]->
getId
();
// Do the next edit without ParserCache produce an outdated cache entry
$parserCacheFactory
=
$this
->
getServiceContainer
()->
getParserCacheFactory
();
$this
->
overrideConfigValue
(
MainConfigNames
::
ParserCacheType
,
CACHE_NONE
);
$latestEditStatus
=
$this
->
editPage
(
$page
,
'Test B'
);
// Restore the old cache instance with the now outdated cache entry
$this
->
setService
(
'ParserCacheFactory'
,
$parserCacheFactory
);
// Request the article for the latest
$article
=
new
Article
(
$page
->
getTitle
()
);
$article
->
getContext
()->
getOutput
()->
setTitle
(
$page
->
getTitle
()
);
$article
->
view
();
// Expected the old values to return
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertSame
(
$idA
,
$output
->
getRevisionId
()
);
$this
->
assertSame
(
$revisions
[
1
]->
getTimestamp
(),
$output
->
getRevisionTimestamp
()
);
}
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
->
assertStringContainsString
(
'missing-revision: '
.
$badId
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'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
=
$this
->
getRevDelRevisionList
(
$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
->
assertStringContainsString
(
'rev-deleted-text-permission'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'Test B'
,
$this
->
getHtml
(
$output
)
);
}
public
function
testUnhiddenViewOfDeletedRevision
()
{
$revisions
=
[];
$page
=
$this
->
getPage
(
__METHOD__
,
[
1
=>
'Test A'
,
2
=>
'Test B'
],
$revisions
);
$idA
=
$revisions
[
1
]->
getId
();
$revDelList
=
$this
->
getRevDelRevisionList
(
$page
->
getTitle
(),
$idA
);
$revDelList
->
setVisibility
(
[
'value'
=>
[
RevisionRecord
::
DELETED_TEXT
=>
1
,
RevisionRecord
::
DELETED_COMMENT
=>
1
,
RevisionRecord
::
DELETED_USER
=>
1
,
],
'comment'
=>
"Testing"
,
]
);
$realContext
=
RequestContext
::
getMain
();
$oldUser
=
$realContext
->
getUser
();
$oldLanguage
=
$realContext
->
getLanguage
();
$article
=
new
Article
(
$page
->
getTitle
(),
$idA
);
$context
=
new
DerivativeContext
(
$realContext
);
$article
->
setContext
(
$context
);
$context
->
getOutput
()->
setTitle
(
$page
->
getTitle
()
);
$context
->
getRequest
()->
setVal
(
'unhide'
,
1
);
$context
->
setUser
(
$this
->
getTestUser
(
[
'sysop'
]
)->
getUser
()
);
// Need global user set to sysop, global state in Linker::revUserTools/Linker::revComment (T309479)
$realContext
->
setUser
(
$context
->
getUser
()
);
// Language is resetted in setUser
$this
->
setUserLang
(
$oldLanguage
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$subtitle
=
$output
->
getSubtitle
();
$html
=
$this
->
getHtml
(
$output
);
// Test that oldid is select, not the current version
$this
->
assertStringNotContainsString
(
'Test B'
,
$html
);
// Warning about rev-del must exists
$this
->
assertStringContainsString
(
'rev-deleted-text-view'
,
$html
);
// Test for the hidden values
$this
->
assertStringContainsString
(
'Test A'
,
$html
);
$this
->
assertStringContainsString
(
$revisions
[
1
]->
getUser
()->
getName
(),
$subtitle
);
$this
->
assertStringContainsString
(
'(parentheses: Rev 1)'
,
$subtitle
);
// Should not contain the rev-del messages
$this
->
assertStringNotContainsString
(
'(rev-deleted-user)'
,
$subtitle
);
$this
->
assertStringNotContainsString
(
'(rev-deleted-comment)'
,
$subtitle
);
$realContext
->
setUser
(
$oldUser
);
}
public
function
testHiddenViewOfDeletedRevision
()
{
$revisions
=
[];
$page
=
$this
->
getPage
(
__METHOD__
,
[
1
=>
'Test A'
,
2
=>
'Test B'
],
$revisions
);
$idA
=
$revisions
[
1
]->
getId
();
$revDelList
=
$this
->
getRevDelRevisionList
(
$page
->
getTitle
(),
$idA
);
$revDelList
->
setVisibility
(
[
'value'
=>
[
RevisionRecord
::
DELETED_TEXT
=>
1
,
RevisionRecord
::
DELETED_COMMENT
=>
1
,
RevisionRecord
::
DELETED_USER
=>
1
,
],
'comment'
=>
"Testing"
,
]
);
$realContext
=
RequestContext
::
getMain
();
$oldUser
=
$realContext
->
getUser
();
$oldLanguage
=
$realContext
->
getLanguage
();
$article
=
new
Article
(
$page
->
getTitle
(),
$idA
);
$context
=
new
DerivativeContext
(
$realContext
);
$article
->
setContext
(
$context
);
$context
->
getOutput
()->
setTitle
(
$page
->
getTitle
()
);
// No unhide=1 is set in this test case
$context
->
setUser
(
$this
->
getTestUser
(
[
'sysop'
]
)->
getUser
()
);
// Need global user set to sysop, global state in Linker::revUserTools/Linker::revComment (T309479)
$realContext
->
setUser
(
$context
->
getUser
()
);
// Language is resetted in setUser
$this
->
setUserLang
(
$oldLanguage
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$subtitle
=
$output
->
getSubtitle
();
$html
=
$this
->
getHtml
(
$output
);
// Test that oldid is select, not the current version
$this
->
assertStringNotContainsString
(
'Test B'
,
$html
);
// Warning about rev-del must exists
$this
->
assertStringContainsString
(
'rev-deleted-text-unhide'
,
$html
);
// Test for the rev-del messages
$this
->
assertStringContainsString
(
'(rev-deleted-user)'
,
$subtitle
);
$this
->
assertStringContainsString
(
'(rev-deleted-comment)'
,
$subtitle
);
// Should not contain the hidden values
$this
->
assertStringNotContainsString
(
'Test A'
,
$html
);
$this
->
assertStringNotContainsString
(
$revisions
[
1
]->
getUser
()->
getName
(),
$subtitle
);
$this
->
assertStringNotContainsString
(
'(parentheses: Rev 1)'
,
$subtitle
);
$realContext
->
setUser
(
$oldUser
);
}
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
->
assertStringContainsString
(
'(noarticletextanon)'
,
$this
->
getHtml
(
$output
)
);
}
public
function
testViewDeletedPage
()
{
$page
=
$this
->
getPage
(
__METHOD__
,
[
1
=>
'Test A'
,
2
=>
'Test B'
]
);
$this
->
deletePage
(
$page
);
$article
=
new
Article
(
$page
->
getTitle
()
);
$article
->
getContext
()->
getOutput
()->
setTitle
(
$page
->
getTitle
()
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringContainsString
(
'moveddeleted'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'logentry-delete-delete'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'(noarticletextanon)'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'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
->
assertStringContainsString
(
wfMessage
(
'mainpage'
)->
inContentLanguage
()->
parse
(),
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'(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
->
assertStringContainsString
(
'(noarticletextanon)'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringNotContainsString
(
'(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
->
assertStringContainsString
(
'(noarticletextanon)'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'(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
->
assertStringNotContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'Hook Text'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertSame
(
'Hook Title'
,
$output
->
getPageTitle
()
);
}
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'
,
static
function
(
Article
$articlePage
,
&
$outputDone
,
&
$useParserCache
)
{
$useParserCache
=
false
;
}
);
$this
->
setTemporaryHook
(
'ArticleRevisionViewCustom'
,
function
(
RevisionRecord
$rev
,
Title
$title
,
$oldid
,
OutputPage
$output
)
use
(
$page
)
{
$content
=
$rev
->
getContent
(
SlotRecord
::
MAIN
);
$this
->
assertSame
(
$page
->
getTitle
(),
$title
,
'$title'
);
$this
->
assertSame
(
'Test A'
,
$content
->
getText
(),
'$content'
);
$output
->
addHTML
(
'Hook Text'
);
return
false
;
}
);
$article
->
view
();
$output
=
$article
->
getContext
()->
getOutput
();
$this
->
assertStringNotContainsString
(
'Test A'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'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
->
assertStringContainsString
(
'(noarticletextanon)'
,
$this
->
getHtml
(
$output
)
);
$this
->
assertStringContainsString
(
'Hook Text'
,
$this
->
getHtml
(
$output
)
);
}
/**
* @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'
,
static
function
(
Article
$articlePage
,
&
$outputDone
,
&
$useParserCache
)
{
$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
)
);
}
private
function
getRevDelRevisionList
(
$title
,
$revisionId
)
{
$services
=
$this
->
getServiceContainer
();
$context
=
new
DerivativeContext
(
RequestContext
::
getMain
()
);
$context
->
setUser
(
$this
->
getTestUser
(
[
'sysop'
]
)->
getUser
()
);
return
new
RevDelRevisionList
(
$context
,
$title
,
[
$revisionId
],
$services
->
getConnectionProvider
(),
$services
->
getHookContainer
(),
$services
->
getHtmlCacheUpdater
(),
$services
->
getRevisionStore
()
);
}
/**
* Test the "useParsoid" parser option and the ArticleParserOptions
* hook.
*/
public
function
testUseParsoid
()
{
// Create an appropriate test page.
$title
=
Title
::
makeTitle
(
NS_MAIN
,
'UseParsoidTest'
);
$article
=
new
Article
(
$title
);
$page
=
$this
->
getExistingTestPage
(
$title
);
$page
->
doUserEditContent
(
ContentHandler
::
makeContent
(
'[[Foo]]'
,
$title
,
// Force this page to be wikitext
CONTENT_MODEL_WIKITEXT
),
$this
->
getTestSysop
()->
getUser
(),
'TestUseParsoid Summary'
,
EDIT_SUPPRESS_RC
);
$article
->
view
();
$html
=
$this
->
getHtml
(
$article
->
getContext
()->
getOutput
()
);
// Confirm that this is NOT parsoid-generated HTML
$this
->
assertStringNotContainsString
(
'rel="mw:WikiLink"'
,
$html
);
// Now enable Parsoid via the ArticleParserOptions hook
$article
=
new
Article
(
$title
);
$this
->
setTemporaryHook
(
'ArticleParserOptions'
,
static
function
(
$article
,
$popts
)
{
$popts
->
setUseParsoid
();
}
);
$article
->
view
();
$html
=
$this
->
getHtml
(
$article
->
getContext
()->
getOutput
()
);
// Look for a marker that this is Parsoid-generated HTML
$this
->
assertStringContainsString
(
'rel="mw:WikiLink"'
,
$html
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 19 2026, 21:18 (7 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
e2/eb/02bd31a7334d9a788033b75bdffe
Default Alt Text
ArticleViewTest.php (26 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment