Merge "Add SPARQL client to core"
[lhc/web/wiklou.git] / tests / phpunit / includes / parser / ParserOutputTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * @group Database
7 * ^--- trigger DB shadowing because we are using Title magic
8 */
9 class ParserOutputTest extends MediaWikiTestCase {
10
11 public static function provideIsLinkInternal() {
12 return [
13 // Different domains
14 [ false, 'http://example.org', 'http://mediawiki.org' ],
15 // Same domains
16 [ true, 'http://example.org', 'http://example.org' ],
17 [ true, 'https://example.org', 'https://example.org' ],
18 [ true, '//example.org', '//example.org' ],
19 // Same domain different cases
20 [ true, 'http://example.org', 'http://EXAMPLE.ORG' ],
21 // Paths, queries, and fragments are not relevant
22 [ true, 'http://example.org', 'http://example.org/wiki/Main_Page' ],
23 [ true, 'http://example.org', 'http://example.org?my=query' ],
24 [ true, 'http://example.org', 'http://example.org#its-a-fragment' ],
25 // Different protocols
26 [ false, 'http://example.org', 'https://example.org' ],
27 [ false, 'https://example.org', 'http://example.org' ],
28 // Protocol relative servers always match http and https links
29 [ true, '//example.org', 'http://example.org' ],
30 [ true, '//example.org', 'https://example.org' ],
31 // But they don't match strange things like this
32 [ false, '//example.org', 'irc://example.org' ],
33 ];
34 }
35
36 /**
37 * Test to make sure ParserOutput::isLinkInternal behaves properly
38 * @dataProvider provideIsLinkInternal
39 * @covers ParserOutput::isLinkInternal
40 */
41 public function testIsLinkInternal( $shouldMatch, $server, $url ) {
42 $this->assertEquals( $shouldMatch, ParserOutput::isLinkInternal( $server, $url ) );
43 }
44
45 /**
46 * @covers ParserOutput::setExtensionData
47 * @covers ParserOutput::getExtensionData
48 */
49 public function testExtensionData() {
50 $po = new ParserOutput();
51
52 $po->setExtensionData( "one", "Foo" );
53
54 $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
55 $this->assertNull( $po->getExtensionData( "spam" ) );
56
57 $po->setExtensionData( "two", "Bar" );
58 $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
59 $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
60
61 $po->setExtensionData( "one", null );
62 $this->assertNull( $po->getExtensionData( "one" ) );
63 $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
64 }
65
66 /**
67 * @covers ParserOutput::setProperty
68 * @covers ParserOutput::getProperty
69 * @covers ParserOutput::unsetProperty
70 * @covers ParserOutput::getProperties
71 */
72 public function testProperties() {
73 $po = new ParserOutput();
74
75 $po->setProperty( 'foo', 'val' );
76
77 $properties = $po->getProperties();
78 $this->assertEquals( $po->getProperty( 'foo' ), 'val' );
79 $this->assertEquals( $properties['foo'], 'val' );
80
81 $po->setProperty( 'foo', 'second val' );
82
83 $properties = $po->getProperties();
84 $this->assertEquals( $po->getProperty( 'foo' ), 'second val' );
85 $this->assertEquals( $properties['foo'], 'second val' );
86
87 $po->unsetProperty( 'foo' );
88
89 $properties = $po->getProperties();
90 $this->assertEquals( $po->getProperty( 'foo' ), false );
91 $this->assertArrayNotHasKey( 'foo', $properties );
92 }
93
94 /**
95 * @covers ParserOutput::getText
96 * @dataProvider provideGetText
97 * @param array $options Options to getText()
98 * @param array $poState ParserOptions state fields to set
99 * @param string $text Parser text
100 * @param string $expect Expected output
101 */
102 public function testGetText( $options, $poState, $text, $expect ) {
103 $this->setMwGlobals( [
104 'wgArticlePath' => '/wiki/$1',
105 'wgScriptPath' => '/w',
106 'wgScript' => '/w/index.php',
107 ] );
108 $this->hideDeprecated( 'ParserOutput stateful allowTOC' );
109 $this->hideDeprecated( 'ParserOutput stateful enableSectionEditLinks' );
110
111 $po = new ParserOutput( $text );
112
113 // Emulate Parser
114 $po->setEditSectionTokens( true );
115
116 if ( $poState ) {
117 $wrap = TestingAccessWrapper::newFromObject( $po );
118 foreach ( $poState as $key => $value ) {
119 $wrap->$key = $value;
120 }
121 }
122
123 $actual = $po->getText( $options );
124 $this->assertSame( $expect, $actual );
125 }
126
127 public static function provideGetText() {
128 // phpcs:disable Generic.Files.LineLength
129 $text = <<<EOF
130 <div class="mw-parser-output"><p>Test document.
131 </p>
132 <mw:toc><div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
133 <ul>
134 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
135 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
136 <ul>
137 <li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
138 </ul>
139 </li>
140 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
141 </ul>
142 </div>
143 </mw:toc>
144 <h2><span class="mw-headline" id="Section_1">Section 1</span><mw:editsection page="Test Page" section="1">Section 1</mw:editsection></h2>
145 <p>One
146 </p>
147 <h2><span class="mw-headline" id="Section_2">Section 2</span><mw:editsection page="Test Page" section="2">Section 2</mw:editsection></h2>
148 <p>Two
149 </p>
150 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><mw:editsection page="Test Page" section="3">Section 2.1</mw:editsection></h3>
151 <p>Two point one
152 </p>
153 <h2><span class="mw-headline" id="Section_3">Section 3</span><mw:editsection page="Test Page" section="4">Section 3</mw:editsection></h2>
154 <p>Three
155 </p></div>
156 EOF;
157
158 $dedupText = <<<EOF
159 <p>This is a test document.</p>
160 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
161 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
162 <style data-mw-deduplicate="duplicate2">.Duplicate2 {}</style>
163 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
164 <style data-mw-deduplicate="duplicate2">.Duplicate2 {}</style>
165 <style data-mw-not-deduplicate="duplicate1">.Duplicate1 {}</style>
166 <style data-mw-deduplicate="duplicate1">.Same-attribute-different-content {}</style>
167 <style data-mw-deduplicate="duplicate3">.Duplicate1 {}</style>
168 <style>.Duplicate1 {}</style>
169 EOF;
170
171 return [
172 'No stateless options, default state' => [
173 [], [], $text, <<<EOF
174 <div class="mw-parser-output"><p>Test document.
175 </p>
176 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
177 <ul>
178 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
179 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
180 <ul>
181 <li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
182 </ul>
183 </li>
184 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
185 </ul>
186 </div>
187
188 <h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
189 <p>One
190 </p>
191 <h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
192 <p>Two
193 </p>
194 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
195 <p>Two point one
196 </p>
197 <h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
198 <p>Three
199 </p></div>
200 EOF
201 ],
202 'No stateless options, TOC statefully disabled' => [
203 [], [ 'mTOCEnabled' => false ], $text, <<<EOF
204 <div class="mw-parser-output"><p>Test document.
205 </p>
206
207 <h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
208 <p>One
209 </p>
210 <h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
211 <p>Two
212 </p>
213 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
214 <p>Two point one
215 </p>
216 <h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
217 <p>Three
218 </p></div>
219 EOF
220 ],
221 'No stateless options, section edits statefully disabled' => [
222 [], [ 'mEditSectionTokens' => false ], $text, <<<EOF
223 <div class="mw-parser-output"><p>Test document.
224 </p>
225 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
226 <ul>
227 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
228 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
229 <ul>
230 <li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
231 </ul>
232 </li>
233 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
234 </ul>
235 </div>
236
237 <h2><span class="mw-headline" id="Section_1">Section 1</span></h2>
238 <p>One
239 </p>
240 <h2><span class="mw-headline" id="Section_2">Section 2</span></h2>
241 <p>Two
242 </p>
243 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span></h3>
244 <p>Two point one
245 </p>
246 <h2><span class="mw-headline" id="Section_3">Section 3</span></h2>
247 <p>Three
248 </p></div>
249 EOF
250 ],
251 'Stateless options override stateful settings' => [
252 [ 'allowTOC' => true, 'enableSectionEditLinks' => true ],
253 [ 'mTOCEnabled' => false, 'mEditSectionTokens' => false ],
254 $text, <<<EOF
255 <div class="mw-parser-output"><p>Test document.
256 </p>
257 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
258 <ul>
259 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
260 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
261 <ul>
262 <li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
263 </ul>
264 </li>
265 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
266 </ul>
267 </div>
268
269 <h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
270 <p>One
271 </p>
272 <h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
273 <p>Two
274 </p>
275 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
276 <p>Two point one
277 </p>
278 <h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
279 <p>Three
280 </p></div>
281 EOF
282 ],
283 'Statelessly disable section edit links' => [
284 [ 'enableSectionEditLinks' => false ], [], $text, <<<EOF
285 <div class="mw-parser-output"><p>Test document.
286 </p>
287 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
288 <ul>
289 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
290 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
291 <ul>
292 <li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
293 </ul>
294 </li>
295 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
296 </ul>
297 </div>
298
299 <h2><span class="mw-headline" id="Section_1">Section 1</span></h2>
300 <p>One
301 </p>
302 <h2><span class="mw-headline" id="Section_2">Section 2</span></h2>
303 <p>Two
304 </p>
305 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span></h3>
306 <p>Two point one
307 </p>
308 <h2><span class="mw-headline" id="Section_3">Section 3</span></h2>
309 <p>Three
310 </p></div>
311 EOF
312 ],
313 'Statelessly disable TOC' => [
314 [ 'allowTOC' => false ], [], $text, <<<EOF
315 <div class="mw-parser-output"><p>Test document.
316 </p>
317
318 <h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
319 <p>One
320 </p>
321 <h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
322 <p>Two
323 </p>
324 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
325 <p>Two point one
326 </p>
327 <h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
328 <p>Three
329 </p></div>
330 EOF
331 ],
332 'Statelessly unwrap text' => [
333 [ 'unwrap' => true ], [], $text, <<<EOF
334 <p>Test document.
335 </p>
336 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
337 <ul>
338 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
339 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
340 <ul>
341 <li class="toclevel-2 tocsection-3"><a href="#Section_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Section 2.1</span></a></li>
342 </ul>
343 </li>
344 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
345 </ul>
346 </div>
347
348 <h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
349 <p>One
350 </p>
351 <h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
352 <p>Two
353 </p>
354 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
355 <p>Two point one
356 </p>
357 <h2><span class="mw-headline" id="Section_3">Section 3</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/w/index.php?title=Test_Page&amp;action=edit&amp;section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
358 <p>Three
359 </p>
360 EOF
361 ],
362 'Unwrap without a mw-parser-output wrapper' => [
363 [ 'unwrap' => true ], [], '<div class="foobar">Content</div>', '<div class="foobar">Content</div>'
364 ],
365 'Unwrap with extra comment at end' => [
366 [ 'unwrap' => true ], [], '<div class="mw-parser-output"><p>Test document.</p></div>
367 <!-- Saved in parser cache... -->', '<p>Test document.</p>
368 <!-- Saved in parser cache... -->'
369 ],
370 'Style deduplication' => [
371 [], [], $dedupText, <<<EOF
372 <p>This is a test document.</p>
373 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
374 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate1"/>
375 <style data-mw-deduplicate="duplicate2">.Duplicate2 {}</style>
376 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate1"/>
377 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate2"/>
378 <style data-mw-not-deduplicate="duplicate1">.Duplicate1 {}</style>
379 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate1"/>
380 <style data-mw-deduplicate="duplicate3">.Duplicate1 {}</style>
381 <style>.Duplicate1 {}</style>
382 EOF
383 ],
384 'Style deduplication disabled' => [
385 [ 'deduplicateStyles' => false ], [], $dedupText, $dedupText
386 ],
387 ];
388 // phpcs:enable
389 }
390
391 }