MediaWiki  1.32.0
ParserMethodsTest.php
Go to the documentation of this file.
1 <?php
6 
13 
14  public static function providePreSaveTransform() {
15  return [
16  [ 'hello this is ~~~',
17  "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
18  ],
19  [ 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
20  'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
21  ],
22  ];
23  }
24 
28  public function testPreSaveTransform( $text, $expected ) {
29  global $wgParser;
30 
31  $title = Title::newFromText( str_replace( '::', '__', __METHOD__ ) );
32  $user = new User();
33  $user->setName( "127.0.0.1" );
35  $text = $wgParser->preSaveTransform( $text, $title, $user, $popts );
36 
37  $this->assertEquals( $expected, $text );
38  }
39 
40  public static function provideStripOuterParagraph() {
41  // This mimics the most common use case (stripping paragraphs generated by the parser).
42  $message = new RawMessage( "Message text." );
43 
44  return [
45  [
46  "<p>Text.</p>",
47  "Text.",
48  ],
49  [
50  "<p class='foo'>Text.</p>",
51  "<p class='foo'>Text.</p>",
52  ],
53  [
54  "<p>Text.\n</p>\n",
55  "Text.",
56  ],
57  [
58  "<p>Text.</p><p>More text.</p>",
59  "<p>Text.</p><p>More text.</p>",
60  ],
61  [
62  $message->parse(),
63  "Message text.",
64  ],
65  ];
66  }
67 
71  public function testStripOuterParagraph( $text, $expected ) {
72  $this->assertEquals( $expected, Parser::stripOuterParagraph( $text ) );
73  }
74 
80  public function testRecursiveParse() {
81  global $wgParser;
82  $title = Title::newFromText( 'foo' );
83  $po = new ParserOptions;
84  $wgParser->setHook( 'recursivecallparser', [ $this, 'helperParserFunc' ] );
85  $wgParser->parse( '<recursivecallparser>baz</recursivecallparser>', $title, $po );
86  }
87 
88  public function helperParserFunc( $input, $args, $parser ) {
89  $title = Title::newFromText( 'foo' );
90  $po = new ParserOptions;
91  $parser->parse( $input, $title, $po );
92  return 'bar';
93  }
94 
95  public function testCallParserFunction() {
96  global $wgParser;
97 
98  // Normal parses test passing PPNodes. Test passing an array.
99  $title = Title::newFromText( str_replace( '::', '__', __METHOD__ ) );
100  $wgParser->startExternalParse( $title, new ParserOptions(), Parser::OT_HTML );
101  $frame = $wgParser->getPreprocessor()->newFrame();
102  $ret = $wgParser->callParserFunction( $frame, '#tag',
103  [ 'pre', 'foo', 'style' => 'margin-left: 1.6em' ]
104  );
105  $ret['text'] = $wgParser->mStripState->unstripBoth( $ret['text'] );
106  $this->assertSame( [
107  'found' => true,
108  'text' => '<pre style="margin-left: 1.6em">foo</pre>',
109  ], $ret, 'callParserFunction works for {{#tag:pre|foo|style=margin-left: 1.6em}}' );
110  }
111 
116  public function testGetSections() {
117  global $wgParser;
118 
119  $title = Title::newFromText( str_replace( '::', '__', __METHOD__ ) );
120  $out = $wgParser->parse( "==foo==\n<h2>bar</h2>\n==baz==\n", $title, new ParserOptions() );
121  $this->assertSame( [
122  [
123  'toclevel' => 1,
124  'level' => '2',
125  'line' => 'foo',
126  'number' => '1',
127  'index' => '1',
128  'fromtitle' => $title->getPrefixedDBkey(),
129  'byteoffset' => 0,
130  'anchor' => 'foo',
131  ],
132  [
133  'toclevel' => 1,
134  'level' => '2',
135  'line' => 'bar',
136  'number' => '2',
137  'index' => '',
138  'fromtitle' => false,
139  'byteoffset' => null,
140  'anchor' => 'bar',
141  ],
142  [
143  'toclevel' => 1,
144  'level' => '2',
145  'line' => 'baz',
146  'number' => '3',
147  'index' => '2',
148  'fromtitle' => $title->getPrefixedDBkey(),
149  'byteoffset' => 21,
150  'anchor' => 'baz',
151  ],
152  ], $out->getSections(), 'getSections() with proper value when <h2> is used' );
153  }
154 
158  public function testNormalizeLinkUrl( $explanation, $url, $expected ) {
159  $this->assertEquals( $expected, Parser::normalizeLinkUrl( $url ), $explanation );
160  }
161 
162  public static function provideNormalizeLinkUrl() {
163  return [
164  [
165  'Escaping of unsafe characters',
166  'http://example.org/foo bar?param[]="value"&param[]=valüe',
167  'http://example.org/foo%20bar?param%5B%5D=%22value%22&param%5B%5D=val%C3%BCe',
168  ],
169  [
170  'Case normalization of percent-encoded characters',
171  'http://example.org/%ab%cD%Ef%FF',
172  'http://example.org/%AB%CD%EF%FF',
173  ],
174  [
175  'Unescaping of safe characters',
176  'http://example.org/%3C%66%6f%6F%3E?%3C%66%6f%6F%3E#%3C%66%6f%6F%3E',
177  'http://example.org/%3Cfoo%3E?%3Cfoo%3E#%3Cfoo%3E',
178  ],
179  [
180  'Context-sensitive replacement of sometimes-safe characters',
181  'http://example.org/%23%2F%3F%26%3D%2B%3B?%23%2F%3F%26%3D%2B%3B#%23%2F%3F%26%3D%2B%3B',
182  'http://example.org/%23%2F%3F&=+;?%23/?%26%3D%2B%3B#%23/?&=+;',
183  ],
184  ];
185  }
186 
187  public function testWrapOutput() {
188  global $wgParser;
189  $title = Title::newFromText( 'foo' );
190  $po = new ParserOptions();
191  $wgParser->parse( 'Hello World', $title, $po );
192  $text = $wgParser->getOutput()->getText();
193 
194  $this->assertContains( 'Hello World', $text );
195  $this->assertContains( '<div', $text );
196  $this->assertContains( 'class="mw-parser-output"', $text );
197  }
198 
203  private function getMockTitle( $name ) {
204  $title = $this->getMock( Title::class );
205  $title->method( 'getPrefixedDBkey' )->willReturn( $name );
206  $title->method( 'getPrefixedText' )->willReturn( $name );
207  $title->method( 'getDBkey' )->willReturn( $name );
208  $title->method( 'getText' )->willReturn( $name );
209  $title->method( 'getNamespace' )->willReturn( 0 );
210  $title->method( 'getPageLanguage' )->willReturn( Language::factory( 'en' ) );
211 
212  return $title;
213  }
214 
215  public function provideRevisionAccess() {
216  $title = $this->getMockTitle( 'ParserRevisionAccessTest' );
217 
218  $frank = $this->getMockBuilder( User::class )
219  ->disableOriginalConstructor()
220  ->getMock();
221 
222  $frank->method( 'getName' )->willReturn( 'Frank' );
223 
224  $text = '* user:{{REVISIONUSER}};id:{{REVISIONID}};time:{{REVISIONTIMESTAMP}};';
225  $po = new ParserOptions( $frank );
226 
227  yield 'current' => [ $text, $po, 0, 'user:CurrentAuthor;id:200;time:20160606000000;' ];
228  yield 'current with ID' => [ $text, $po, 200, 'user:CurrentAuthor;id:200;time:20160606000000;' ];
229 
230  $text = '* user:{{REVISIONUSER}};id:{{REVISIONID}};time:{{REVISIONTIMESTAMP}};';
231  $po = new ParserOptions( $frank );
232 
233  yield 'old' => [ $text, $po, 100, 'user:OldAuthor;id:100;time:20140404000000;' ];
234 
235  $oldRevision = new MutableRevisionRecord( $title );
236  $oldRevision->setId( 100 );
237  $oldRevision->setUser( new UserIdentityValue( 7, 'FauxAuthor', 0 ) );
238  $oldRevision->setTimestamp( '20141111111111' );
239  $oldRevision->setContent( SlotRecord::MAIN, new WikitextContent( 'FAUX' ) );
240 
241  $po = new ParserOptions( $frank );
242  $po->setCurrentRevisionCallback( function () use ( $oldRevision ) {
243  return new Revision( $oldRevision );
244  } );
245 
246  yield 'old with override' => [ $text, $po, 100, 'user:FauxAuthor;id:100;time:20141111111111;' ];
247 
248  $text = '* user:{{REVISIONUSER}};user-subst:{{subst:REVISIONUSER}};';
249 
250  $po = new ParserOptions( $frank );
251  $po->setIsPreview( true );
252 
253  yield 'preview without override, using context' => [
254  $text,
255  $po,
256  null,
257  'user:Frank;',
258  'user-subst:Frank;',
259  ];
260 
261  $text = '* user:{{REVISIONUSER}};time:{{REVISIONTIMESTAMP}};'
262  . 'user-subst:{{subst:REVISIONUSER}};time-subst:{{subst:REVISIONTIMESTAMP}};';
263 
264  $newRevision = new MutableRevisionRecord( $title );
265  $newRevision->setUser( new UserIdentityValue( 9, 'NewAuthor', 0 ) );
266  $newRevision->setTimestamp( '20180808000000' );
267  $newRevision->setContent( SlotRecord::MAIN, new WikitextContent( 'NEW' ) );
268 
269  $po = new ParserOptions( $frank );
270  $po->setIsPreview( true );
271  $po->setCurrentRevisionCallback( function () use ( $newRevision ) {
272  return new Revision( $newRevision );
273  } );
274 
275  yield 'preview' => [
276  $text,
277  $po,
278  null,
279  'user:NewAuthor;time:20180808000000;',
280  'user-subst:NewAuthor;time-subst:20180808000000;',
281  ];
282 
283  $po = new ParserOptions( $frank );
284  $po->setCurrentRevisionCallback( function () use ( $newRevision ) {
285  return new Revision( $newRevision );
286  } );
287 
288  yield 'pre-save' => [
289  $text,
290  $po,
291  null,
292  'user:NewAuthor;time:20180808000000;',
293  'user-subst:NewAuthor;time-subst:20180808000000;',
294  ];
295 
296  $text = "(ONE)<includeonly>(TWO)</includeonly>"
297  . "<noinclude>#{{:ParserRevisionAccessTest}}#</noinclude>";
298 
299  $newRevision = new MutableRevisionRecord( $title );
300  $newRevision->setUser( new UserIdentityValue( 9, 'NewAuthor', 0 ) );
301  $newRevision->setTimestamp( '20180808000000' );
302  $newRevision->setContent( SlotRecord::MAIN, new WikitextContent( $text ) );
303 
304  $po = new ParserOptions( $frank );
305  $po->setIsPreview( true );
306  $po->setCurrentRevisionCallback( function () use ( $newRevision ) {
307  return new Revision( $newRevision );
308  } );
309 
310  yield 'preview with self-transclude' => [ $text, $po, null, '(ONE)#(ONE)(TWO)#' ];
311  }
312 
316  public function testRevisionAccess(
317  $text,
318  ParserOptions $po,
319  $revId,
320  $expectedInHtml,
321  $expectedInPst = null
322  ) {
323  global $wgParser;
324 
325  $title = $this->getMockTitle( 'ParserRevisionAccessTest' );
326 
327  $po->enableLimitReport( false );
328 
329  $oldRevision = new MutableRevisionRecord( $title );
330  $oldRevision->setId( 100 );
331  $oldRevision->setUser( new UserIdentityValue( 7, 'OldAuthor', 0 ) );
332  $oldRevision->setTimestamp( '20140404000000' );
333  $oldRevision->setContent( SlotRecord::MAIN, new WikitextContent( 'OLD' ) );
334 
335  $currentRevision = new MutableRevisionRecord( $title );
336  $currentRevision->setId( 200 );
337  $currentRevision->setUser( new UserIdentityValue( 9, 'CurrentAuthor', 0 ) );
338  $currentRevision->setTimestamp( '20160606000000' );
339  $currentRevision->setContent( SlotRecord::MAIN, new WikitextContent( 'CURRENT' ) );
340 
341  $revisionStore = $this->getMockBuilder( RevisionStore::class )
342  ->disableOriginalConstructor()
343  ->getMock();
344 
345  $revisionStore
346  ->method( 'getKnownCurrentRevision' )
347  ->willReturnMap( [
348  [ $title, 100, $oldRevision ],
349  [ $title, 200, $currentRevision ],
350  [ $title, 0, $currentRevision ],
351  ] );
352 
353  $revisionStore
354  ->method( 'getRevisionById' )
355  ->willReturnMap( [
356  [ 100, 0, $oldRevision ],
357  [ 200, 0, $currentRevision ],
358  ] );
359 
360  $this->setService( 'RevisionStore', $revisionStore );
361 
362  $wgParser->parse( $text, $title, $po, true, true, $revId );
363  $html = $wgParser->getOutput()->getText();
364 
365  $this->assertContains( $expectedInHtml, $html, 'In HTML' );
366 
367  if ( $expectedInPst !== null ) {
368  $pst = $wgParser->preSaveTransform( $text, $title, $po->getUser(), $po );
369  $this->assertContains( $expectedInPst, $pst, 'After Pre-Safe Transform' );
370  }
371  }
372 
373  // @todo Add tests for cleanSig() / cleanSigInSig(), getSection(),
374  // replaceSection(), getPreloadText()
375 }
MediaWiki\User\UserIdentityValue
Value object representing a user's identity.
Definition: UserIdentityValue.php:32
ParserOptions
Set options of the Parser.
Definition: ParserOptions.php:42
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:244
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:280
$wgParser
$wgParser
Definition: Setup.php:913
Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:76
ParserMethodsTest\helperParserFunc
helperParserFunc( $input, $args, $parser)
Definition: ParserMethodsTest.php:88
ParserMethodsTest\provideRevisionAccess
provideRevisionAccess()
Definition: ParserMethodsTest.php:215
ParserMethodsTest\getMockTitle
getMockTitle( $name)
Definition: ParserMethodsTest.php:203
User
User
Definition: All_system_messages.txt:425
ParserMethodsTest\testNormalizeLinkUrl
testNormalizeLinkUrl( $explanation, $url, $expected)
provideNormalizeLinkUrl
Definition: ParserMethodsTest.php:158
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Revision
Definition: Revision.php:41
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:2036
ParserMethodsTest\providePreSaveTransform
static providePreSaveTransform()
Definition: ParserMethodsTest.php:14
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:964
ParserMethodsTest
Database Parser BlockLevelPass.
Definition: ParserMethodsTest.php:12
$input
if(is_array( $mode)) switch( $mode) $input
Definition: postprocess-phan.php:141
ParserMethodsTest\testRecursiveParse
testRecursiveParse()
MWException Parser state cleared while parsing.
Definition: ParserMethodsTest.php:80
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
ParserMethodsTest\testPreSaveTransform
testPreSaveTransform( $text, $expected)
providePreSaveTransform
Definition: ParserMethodsTest.php:28
$parser
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
Definition: hooks.txt:1841
ParserMethodsTest\testCallParserFunction
testCallParserFunction()
Definition: ParserMethodsTest.php:95
WikitextContent
Content object for wiki text pages.
Definition: WikitextContent.php:35
ParserMethodsTest\testWrapOutput
testWrapOutput()
Definition: ParserMethodsTest.php:187
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
Revision\MutableRevisionRecord
Mutable RevisionRecord implementation, for building new revision entries programmatically.
Definition: MutableRevisionRecord.php:41
MediaWikiLangTestCase
Base class that store and restore the Language objects.
Definition: MediaWikiLangTestCase.php:8
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:2036
$args
if( $line===false) $args
Definition: cdb.php:64
OT_HTML
const OT_HTML
Definition: Defines.php:184
ParserOptions\enableLimitReport
enableLimitReport( $x=true)
Enable limit report in an HTML comment on output.
Definition: ParserOptions.php:467
ParserMethodsTest\testStripOuterParagraph
testStripOuterParagraph( $text, $expected)
provideStripOuterParagraph
Definition: ParserMethodsTest.php:71
ParserMethodsTest\provideStripOuterParagraph
static provideStripOuterParagraph()
Definition: ParserMethodsTest.php:40
ParserOptions\getUser
getUser()
Current user.
Definition: ParserOptions.php:965
ParserMethodsTest\provideNormalizeLinkUrl
static provideNormalizeLinkUrl()
Definition: ParserMethodsTest.php:162
Language\factory
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:214
ParserMethodsTest\testGetSections
testGetSections()
Parser ParserOutput::getSections.
Definition: ParserMethodsTest.php:116
ParserMethodsTest\testRevisionAccess
testRevisionAccess( $text, ParserOptions $po, $revId, $expectedInHtml, $expectedInPst=null)
provideRevisionAccess
Definition: ParserMethodsTest.php:316
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
RawMessage
Variant of the Message class.
Definition: RawMessage.php:34
MediaWikiTestCase\setService
setService( $name, $object)
Sets a service, maintaining a stashed version of the previous service to be restored in tearDown.
Definition: MediaWikiTestCase.php:646
Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:39
ParserOptions\newFromUser
static newFromUser( $user)
Get a ParserOptions object from a given user.
Definition: ParserOptions.php:1015
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:813