Deprecate additional public methods of Parser
[lhc/web/wiklou.git] / tests / phpunit / includes / ExtraParserTest.php
1 <?php
2
3 use MediaWiki\MediaWikiServices;
4 use Wikimedia\TestingAccessWrapper;
5
6 /**
7 * Parser-related tests that don't suit for parserTests.txt
8 *
9 * @group Database
10 */
11 class ExtraParserTest extends MediaWikiTestCase {
12
13 /** @var ParserOptions */
14 protected $options;
15 /** @var Parser */
16 protected $parser;
17
18 protected function setUp() {
19 parent::setUp();
20
21 $contLang = Language::factory( 'en' );
22 $this->setMwGlobals( [
23 'wgShowExceptionDetails' => true,
24 'wgCleanSignatures' => true,
25 ] );
26 $this->setUserLang( 'en' );
27 $this->setContentLang( $contLang );
28
29 // FIXME: This test should pass without setting global content language
30 $this->options = ParserOptions::newFromUserAndLang( new User, $contLang );
31 $this->options->setTemplateCallback( [ __CLASS__, 'statelessFetchTemplate' ] );
32 $this->parser = new Parser;
33
34 MediaWikiServices::getInstance()->resetServiceForTesting( 'MagicWordFactory' );
35 }
36
37 /**
38 * @see T10689
39 * @covers Parser::parse
40 */
41 public function testLongNumericLinesDontKillTheParser() {
42 $longLine = '1.' . str_repeat( '1234567890', 100000 ) . "\n";
43
44 $title = Title::newFromText( 'Unit test' );
45 $options = ParserOptions::newFromUser( new User() );
46 $this->assertEquals( "<p>$longLine</p>",
47 $this->parser->parse( $longLine, $title, $options )->getText( [ 'unwrap' => true ] ) );
48 }
49
50 /**
51 * @covers Parser::braceSubstitution
52 * @covers SpecialPageFactory::capturePath
53 */
54 public function testSpecialPageTransclusionRestoresGlobalState() {
55 $text = "{{Special:ApiHelp/help}}";
56 $title = Title::newFromText( 'testSpecialPageTransclusionRestoresGlobalState' );
57 $options = ParserOptions::newFromUser( new User() );
58
59 RequestContext::getMain()->setTitle( $title );
60 RequestContext::getMain()->getWikiPage()->CustomTestProp = true;
61
62 $parsed = $this->parser->parse( $text, $title, $options )->getText();
63 $this->assertContains( 'apihelp-header', $parsed );
64
65 // Verify that this property wasn't wiped out by the parse
66 $this->assertTrue( RequestContext::getMain()->getWikiPage()->CustomTestProp );
67 }
68
69 /**
70 * Test the parser entry points
71 * @covers Parser::parse
72 */
73 public function testParse() {
74 $title = Title::newFromText( __FUNCTION__ );
75 $parserOutput = $this->parser->parse( "Test\n{{Foo}}\n{{Bar}}", $title, $this->options );
76 $this->assertEquals(
77 "<p>Test\nContent of <i>Template:Foo</i>\nContent of <i>Template:Bar</i>\n</p>",
78 $parserOutput->getText( [ 'unwrap' => true ] )
79 );
80 }
81
82 /**
83 * @covers Parser::preSaveTransform
84 */
85 public function testPreSaveTransform() {
86 $title = Title::newFromText( __FUNCTION__ );
87 $outputText = $this->parser->preSaveTransform(
88 "Test\r\n{{subst:Foo}}\n{{Bar}}",
89 $title,
90 new User(),
91 $this->options
92 );
93
94 $this->assertEquals( "Test\nContent of ''Template:Foo''\n{{Bar}}", $outputText );
95 }
96
97 /**
98 * @covers Parser::preprocess
99 */
100 public function testPreprocess() {
101 $title = Title::newFromText( __FUNCTION__ );
102 $outputText = $this->parser->preprocess( "Test\n{{Foo}}\n{{Bar}}", $title, $this->options );
103
104 $this->assertEquals(
105 "Test\nContent of ''Template:Foo''\nContent of ''Template:Bar''",
106 $outputText
107 );
108 }
109
110 /**
111 * cleanSig() makes all templates substs and removes tildes
112 * @covers Parser::cleanSig
113 */
114 public function testCleanSig() {
115 $title = Title::newFromText( __FUNCTION__ );
116 $outputText = $this->parser->cleanSig( "{{Foo}} ~~~~" );
117
118 $this->assertEquals( "{{SUBST:Foo}} ", $outputText );
119 }
120
121 /**
122 * cleanSig() should do nothing if disabled
123 * @covers Parser::cleanSig
124 */
125 public function testCleanSigDisabled() {
126 $this->setMwGlobals( 'wgCleanSignatures', false );
127
128 $title = Title::newFromText( __FUNCTION__ );
129 $outputText = $this->parser->cleanSig( "{{Foo}} ~~~~" );
130
131 $this->assertEquals( "{{Foo}} ~~~~", $outputText );
132 }
133
134 /**
135 * cleanSigInSig() just removes tildes
136 * @dataProvider provideStringsForCleanSigInSig
137 * @covers Parser::cleanSigInSig
138 */
139 public function testCleanSigInSig( $in, $out ) {
140 $this->assertEquals( Parser::cleanSigInSig( $in ), $out );
141 }
142
143 public static function provideStringsForCleanSigInSig() {
144 return [
145 [ "{{Foo}} ~~~~", "{{Foo}} " ],
146 [ "~~~", "" ],
147 [ "~~~~~", "" ],
148 ];
149 }
150
151 /**
152 * @covers Parser::getSection
153 */
154 public function testGetSection() {
155 $outputText2 = $this->parser->getSection(
156 "Section 0\n== Heading 1 ==\nSection 1\n=== Heading 2 ===\n"
157 . "Section 2\n== Heading 3 ==\nSection 3\n",
158 2
159 );
160 $outputText1 = $this->parser->getSection(
161 "Section 0\n== Heading 1 ==\nSection 1\n=== Heading 2 ===\n"
162 . "Section 2\n== Heading 3 ==\nSection 3\n",
163 1
164 );
165
166 $this->assertEquals( "=== Heading 2 ===\nSection 2", $outputText2 );
167 $this->assertEquals( "== Heading 1 ==\nSection 1\n=== Heading 2 ===\nSection 2", $outputText1 );
168 }
169
170 /**
171 * @covers Parser::replaceSection
172 */
173 public function testReplaceSection() {
174 $outputText = $this->parser->replaceSection(
175 "Section 0\n== Heading 1 ==\nSection 1\n=== Heading 2 ===\n"
176 . "Section 2\n== Heading 3 ==\nSection 3\n",
177 1,
178 "New section 1"
179 );
180
181 $this->assertEquals( "Section 0\nNew section 1\n\n== Heading 3 ==\nSection 3", $outputText );
182 }
183
184 /**
185 * Templates and comments are not affected, but noinclude/onlyinclude is.
186 * @covers Parser::getPreloadText
187 */
188 public function testGetPreloadText() {
189 $title = Title::newFromText( __FUNCTION__ );
190 $outputText = $this->parser->getPreloadText(
191 "{{Foo}}<noinclude> censored</noinclude> information <!-- is very secret -->",
192 $title,
193 $this->options
194 );
195
196 $this->assertEquals( "{{Foo}} information <!-- is very secret -->", $outputText );
197 }
198
199 /**
200 * @param Title $title
201 * @param bool $parser
202 *
203 * @return array
204 */
205 static function statelessFetchTemplate( $title, $parser = false ) {
206 $text = "Content of ''" . $title->getFullText() . "''";
207 $deps = [];
208
209 return [
210 'text' => $text,
211 'finalTitle' => $title,
212 'deps' => $deps ];
213 }
214
215 /**
216 * @covers Parser::parse
217 */
218 public function testTrackingCategory() {
219 $title = Title::newFromText( __FUNCTION__ );
220 $catName = wfMessage( 'broken-file-category' )->inContentLanguage()->text();
221 $cat = Title::makeTitleSafe( NS_CATEGORY, $catName );
222 $expected = [ $cat->getDBkey() ];
223 $parserOutput = $this->parser->parse( "[[file:nonexistent]]", $title, $this->options );
224 $result = $parserOutput->getCategoryLinks();
225 $this->assertEquals( $expected, $result );
226 }
227
228 /**
229 * @covers Parser::parse
230 */
231 public function testTrackingCategorySpecial() {
232 // Special pages shouldn't have tracking cats.
233 $title = SpecialPage::getTitleFor( 'Contributions' );
234 $parserOutput = $this->parser->parse( "[[file:nonexistent]]", $title, $this->options );
235 $result = $parserOutput->getCategoryLinks();
236 $this->assertEmpty( $result );
237 }
238
239 /**
240 * @covers Parser::parseLinkParameterPrivate
241 * @dataProvider provideParseLinkParameter
242 */
243 public function testParseLinkParameter( $input, $expected, $expectedLinks, $desc ) {
244 $this->parser->startExternalParse( Title::newFromText( __FUNCTION__ ),
245 $this->options, Parser::OT_HTML );
246 $output = TestingAccessWrapper::newFromObject( $this->parser )
247 ->parseLinkParameterPrivate( $input );
248
249 $this->assertEquals( $expected[0], $output[0], "$desc (type)" );
250
251 if ( $expected[0] === 'link-title' ) {
252 $this->assertTrue( $expected[1]->equals( $output[1] ), "$desc (target)" );
253 } else {
254 $this->assertEquals( $expected[1], $output[1], "$desc (target)" );
255 }
256
257 foreach ( $expectedLinks as $func => $expected ) {
258 $output = $this->parser->getOutput()->$func();
259 $this->assertEquals( $expected, $output, "$desc ($func)" );
260 }
261 }
262
263 public static function provideParseLinkParameter() {
264 return [
265 [
266 '',
267 [ 'no-link', false ],
268 [],
269 'Return no link when requested',
270 ],
271 [
272 'https://example.com/',
273 [ 'link-url', 'https://example.com/' ],
274 [ 'getExternalLinks' => [ 'https://example.com/' => 1 ] ],
275 'External link',
276 ],
277 [
278 '//example.com/',
279 [ 'link-url', '//example.com/' ],
280 [ 'getExternalLinks' => [ '//example.com/' => 1 ] ],
281 'External link',
282 ],
283 [
284 'Test',
285 [ 'link-title', Title::newFromText( 'Test' ) ],
286 [ 'getLinks' => [ 0 => [ 'Test' => 0 ] ] ],
287 'Internal link',
288 ],
289 [
290 'mw:Test',
291 [ 'link-title', Title::newFromText( 'mw:Test' ) ],
292 [ 'getInterwikiLinks' => [ 'mw' => [ 'Test' => 1 ] ] ],
293 'Internal link (interwiki)',
294 ],
295 [
296 'https://',
297 [ null, false ],
298 [],
299 'Invalid link target',
300 ],
301 [
302 '<>',
303 [ null, false ],
304 [],
305 'Invalid link target',
306 ],
307 [
308 ' ',
309 [ null, false ],
310 [],
311 'Invalid link target',
312 ],
313 ];
314 }
315 }