3 use Wikimedia\TestingAccessWrapper
;
7 * ^--- trigger DB shadowing because we are using Title magic
9 class ParserOutputTest
extends MediaWikiTestCase
{
11 public static function provideIsLinkInternal() {
14 [ false, 'http://example.org', 'http://mediawiki.org' ],
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' ],
37 * Test to make sure ParserOutput::isLinkInternal behaves properly
38 * @dataProvider provideIsLinkInternal
39 * @covers ParserOutput::isLinkInternal
41 public function testIsLinkInternal( $shouldMatch, $server, $url ) {
42 $this->assertEquals( $shouldMatch, ParserOutput
::isLinkInternal( $server, $url ) );
46 * @covers ParserOutput::setExtensionData
47 * @covers ParserOutput::getExtensionData
49 public function testExtensionData() {
50 $po = new ParserOutput();
52 $po->setExtensionData( "one", "Foo" );
54 $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
55 $this->assertNull( $po->getExtensionData( "spam" ) );
57 $po->setExtensionData( "two", "Bar" );
58 $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
59 $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
61 $po->setExtensionData( "one", null );
62 $this->assertNull( $po->getExtensionData( "one" ) );
63 $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
67 * @covers ParserOutput::setProperty
68 * @covers ParserOutput::getProperty
69 * @covers ParserOutput::unsetProperty
70 * @covers ParserOutput::getProperties
72 public function testProperties() {
73 $po = new ParserOutput();
75 $po->setProperty( 'foo', 'val' );
77 $properties = $po->getProperties();
78 $this->assertEquals( $po->getProperty( 'foo' ), 'val' );
79 $this->assertEquals( $properties['foo'], 'val' );
81 $po->setProperty( 'foo', 'second val' );
83 $properties = $po->getProperties();
84 $this->assertEquals( $po->getProperty( 'foo' ), 'second val' );
85 $this->assertEquals( $properties['foo'], 'second val' );
87 $po->unsetProperty( 'foo' );
89 $properties = $po->getProperties();
90 $this->assertEquals( $po->getProperty( 'foo' ), false );
91 $this->assertArrayNotHasKey( 'foo', $properties );
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
102 public function testGetText( $options, $poState, $text, $expect ) {
103 $this->setMwGlobals( [
104 'wgArticlePath' => '/wiki/$1',
105 'wgScriptPath' => '/w',
106 'wgScript' => '/w/index.php',
108 $this->hideDeprecated( 'ParserOutput stateful allowTOC' );
109 $this->hideDeprecated( 'ParserOutput stateful enableSectionEditLinks' );
111 $po = new ParserOutput( $text );
114 $po->setEditSectionTokens( true );
117 $wrap = TestingAccessWrapper
::newFromObject( $po );
118 foreach ( $poState as $key => $value ) {
119 $wrap->$key = $value;
123 $actual = $po->getText( $options );
124 $this->assertSame( $expect, $actual );
127 public static function provideGetText() {
128 // phpcs:disable Generic.Files.LineLength
130 <div class="mw-parser-output"><p>Test document.
132 <mw:toc><div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
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>
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>
140 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
144 <h2><span class="mw-headline" id="Section_1">Section 1</span><mw:editsection page="Test Page" section="1">Section 1</mw:editsection></h2>
147 <h2><span class="mw-headline" id="Section_2">Section 2</span><mw:editsection page="Test Page" section="2">Section 2</mw:editsection></h2>
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>
153 <h2><span class="mw-headline" id="Section_3">Section 3</span><mw:editsection page="Test Page" section="4">Section 3</mw:editsection></h2>
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>
172 'No stateless options, default state' => [
173 [], [], $text, <<<EOF
174 <div class="mw-parser-output"><p>Test document.
176 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
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>
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>
184 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
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&action=edit&section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
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&action=edit&section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
202 'No stateless options, TOC statefully disabled' => [
203 [], [ 'mTOCEnabled' => false ], $text, <<<EOF
204 <div class="mw-parser-output"><p>Test document.
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&action=edit&section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
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&action=edit&section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
221 'No stateless options, section edits statefully disabled' => [
222 [], [ 'mEditSectionTokens' => false ], $text, <<<EOF
223 <div class="mw-parser-output"><p>Test document.
225 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
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>
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>
233 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
237 <h2><span class="mw-headline" id="Section_1">Section 1</span></h2>
240 <h2><span class="mw-headline" id="Section_2">Section 2</span></h2>
243 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span></h3>
246 <h2><span class="mw-headline" id="Section_3">Section 3</span></h2>
251 'Stateless options override stateful settings' => [
252 [ 'allowTOC' => true, 'enableSectionEditLinks' => true ],
253 [ 'mTOCEnabled' => false, 'mEditSectionTokens' => false ],
255 <div class="mw-parser-output"><p>Test document.
257 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
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>
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>
265 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
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&action=edit&section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
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&action=edit&section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
283 'Statelessly disable section edit links' => [
284 [ 'enableSectionEditLinks' => false ], [], $text, <<<EOF
285 <div class="mw-parser-output"><p>Test document.
287 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
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>
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>
295 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
299 <h2><span class="mw-headline" id="Section_1">Section 1</span></h2>
302 <h2><span class="mw-headline" id="Section_2">Section 2</span></h2>
305 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span></h3>
308 <h2><span class="mw-headline" id="Section_3">Section 3</span></h2>
313 'Statelessly disable TOC' => [
314 [ 'allowTOC' => false ], [], $text, <<<EOF
315 <div class="mw-parser-output"><p>Test document.
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&action=edit&section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
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&action=edit&section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
332 'Statelessly unwrap text' => [
333 [ 'unwrap' => true ], [], $text, <<<EOF
336 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
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>
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>
344 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
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&action=edit&section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=2" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
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&action=edit&section=3" title="Edit section: Section 2.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
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&action=edit&section=4" title="Edit section: Section 3">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
362 'Unwrap without a mw-parser-output wrapper' => [
363 [ 'unwrap' => true ], [], '<div class="foobar">Content</div>', '<div class="foobar">Content</div>'
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... -->'
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>
384 'Style deduplication disabled' => [
385 [ 'deduplicateStyles' => false ], [], $dedupText, $dedupText