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