Merge "Fix some warnings from phan-taint-check"
[lhc/web/wiklou.git] / tests / phpunit / includes / parser / ParserOutputTest.php
1 <?php
2
3 /**
4 * @group Database
5 * ^--- trigger DB shadowing because we are using Title magic
6 */
7 class ParserOutputTest extends MediaWikiTestCase {
8
9 public static function provideIsLinkInternal() {
10 return [
11 // Different domains
12 [ false, 'http://example.org', 'http://mediawiki.org' ],
13 // Same domains
14 [ true, 'http://example.org', 'http://example.org' ],
15 [ true, 'https://example.org', 'https://example.org' ],
16 [ true, '//example.org', '//example.org' ],
17 // Same domain different cases
18 [ true, 'http://example.org', 'http://EXAMPLE.ORG' ],
19 // Paths, queries, and fragments are not relevant
20 [ true, 'http://example.org', 'http://example.org/wiki/Main_Page' ],
21 [ true, 'http://example.org', 'http://example.org?my=query' ],
22 [ true, 'http://example.org', 'http://example.org#its-a-fragment' ],
23 // Different protocols
24 [ false, 'http://example.org', 'https://example.org' ],
25 [ false, 'https://example.org', 'http://example.org' ],
26 // Protocol relative servers always match http and https links
27 [ true, '//example.org', 'http://example.org' ],
28 [ true, '//example.org', 'https://example.org' ],
29 // But they don't match strange things like this
30 [ false, '//example.org', 'irc://example.org' ],
31 ];
32 }
33
34 /**
35 * Test to make sure ParserOutput::isLinkInternal behaves properly
36 * @dataProvider provideIsLinkInternal
37 * @covers ParserOutput::isLinkInternal
38 */
39 public function testIsLinkInternal( $shouldMatch, $server, $url ) {
40 $this->assertEquals( $shouldMatch, ParserOutput::isLinkInternal( $server, $url ) );
41 }
42
43 /**
44 * @covers ParserOutput::setExtensionData
45 * @covers ParserOutput::getExtensionData
46 */
47 public function testExtensionData() {
48 $po = new ParserOutput();
49
50 $po->setExtensionData( "one", "Foo" );
51
52 $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
53 $this->assertNull( $po->getExtensionData( "spam" ) );
54
55 $po->setExtensionData( "two", "Bar" );
56 $this->assertEquals( "Foo", $po->getExtensionData( "one" ) );
57 $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
58
59 $po->setExtensionData( "one", null );
60 $this->assertNull( $po->getExtensionData( "one" ) );
61 $this->assertEquals( "Bar", $po->getExtensionData( "two" ) );
62 }
63
64 /**
65 * @covers ParserOutput::setProperty
66 * @covers ParserOutput::getProperty
67 * @covers ParserOutput::unsetProperty
68 * @covers ParserOutput::getProperties
69 */
70 public function testProperties() {
71 $po = new ParserOutput();
72
73 $po->setProperty( 'foo', 'val' );
74
75 $properties = $po->getProperties();
76 $this->assertEquals( $po->getProperty( 'foo' ), 'val' );
77 $this->assertEquals( $properties['foo'], 'val' );
78
79 $po->setProperty( 'foo', 'second val' );
80
81 $properties = $po->getProperties();
82 $this->assertEquals( $po->getProperty( 'foo' ), 'second val' );
83 $this->assertEquals( $properties['foo'], 'second val' );
84
85 $po->unsetProperty( 'foo' );
86
87 $properties = $po->getProperties();
88 $this->assertEquals( $po->getProperty( 'foo' ), false );
89 $this->assertArrayNotHasKey( 'foo', $properties );
90 }
91
92 /**
93 * @covers ParserOutput::getWrapperDivClass
94 * @covers ParserOutput::addWrapperDivClass
95 * @covers ParserOutput::clearWrapperDivClass
96 * @covers ParserOutput::getText
97 */
98 public function testWrapperDivClass() {
99 $po = new ParserOutput();
100
101 $po->setText( 'Kittens' );
102 $this->assertContains( 'Kittens', $po->getText() );
103 $this->assertNotContains( '<div', $po->getText() );
104 $this->assertSame( 'Kittens', $po->getRawText() );
105
106 $po->addWrapperDivClass( 'foo' );
107 $text = $po->getText();
108 $this->assertContains( 'Kittens', $text );
109 $this->assertContains( '<div', $text );
110 $this->assertContains( 'class="foo"', $text );
111
112 $po->addWrapperDivClass( 'bar' );
113 $text = $po->getText();
114 $this->assertContains( 'Kittens', $text );
115 $this->assertContains( '<div', $text );
116 $this->assertContains( 'class="foo bar"', $text );
117
118 $po->addWrapperDivClass( 'bar' ); // second time does nothing, no "foo bar bar".
119 $text = $po->getText( [ 'unwrap' => true ] );
120 $this->assertContains( 'Kittens', $text );
121 $this->assertNotContains( '<div', $text );
122 $this->assertNotContains( 'class="foo bar"', $text );
123
124 $text = $po->getText( [ 'wrapperDivClass' => '' ] );
125 $this->assertContains( 'Kittens', $text );
126 $this->assertNotContains( '<div', $text );
127 $this->assertNotContains( 'class="foo bar"', $text );
128
129 $text = $po->getText( [ 'wrapperDivClass' => 'xyzzy' ] );
130 $this->assertContains( 'Kittens', $text );
131 $this->assertContains( '<div', $text );
132 $this->assertContains( 'class="xyzzy"', $text );
133 $this->assertNotContains( 'class="foo bar"', $text );
134
135 $text = $po->getRawText();
136 $this->assertSame( 'Kittens', $text );
137
138 $po->clearWrapperDivClass();
139 $text = $po->getText();
140 $this->assertContains( 'Kittens', $text );
141 $this->assertNotContains( '<div', $text );
142 $this->assertNotContains( 'class="foo bar"', $text );
143 }
144
145 /**
146 * @covers ParserOutput::getText
147 * @dataProvider provideGetText
148 * @param array $options Options to getText()
149 * @param string $text Parser text
150 * @param string $expect Expected output
151 */
152 public function testGetText( $options, $text, $expect ) {
153 $this->setMwGlobals( [
154 'wgArticlePath' => '/wiki/$1',
155 'wgScriptPath' => '/w',
156 'wgScript' => '/w/index.php',
157 ] );
158
159 $po = new ParserOutput( $text );
160 $actual = $po->getText( $options );
161 $this->assertSame( $expect, $actual );
162 }
163
164 public static function provideGetText() {
165 // phpcs:disable Generic.Files.LineLength
166 $text = <<<EOF
167 <p>Test document.
168 </p>
169 <mw:toc><div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
170 <ul>
171 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
172 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
173 <ul>
174 <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>
175 </ul>
176 </li>
177 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
178 </ul>
179 </div>
180 </mw:toc>
181 <h2><span class="mw-headline" id="Section_1">Section 1</span><mw:editsection page="Test Page" section="1">Section 1</mw:editsection></h2>
182 <p>One
183 </p>
184 <h2><span class="mw-headline" id="Section_2">Section 2</span><mw:editsection page="Test Page" section="2">Section 2</mw:editsection></h2>
185 <p>Two
186 </p>
187 <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>
188 <p>Two point one
189 </p>
190 <h2><span class="mw-headline" id="Section_3">Section 3</span><mw:editsection page="Test Page" section="4">Section 3</mw:editsection></h2>
191 <p>Three
192 </p>
193 EOF;
194
195 $dedupText = <<<EOF
196 <p>This is a test document.</p>
197 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
198 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
199 <style data-mw-deduplicate="duplicate2">.Duplicate2 {}</style>
200 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
201 <style data-mw-deduplicate="duplicate2">.Duplicate2 {}</style>
202 <style data-mw-not-deduplicate="duplicate1">.Duplicate1 {}</style>
203 <style data-mw-deduplicate="duplicate1">.Same-attribute-different-content {}</style>
204 <style data-mw-deduplicate="duplicate3">.Duplicate1 {}</style>
205 <style>.Duplicate1 {}</style>
206 EOF;
207
208 return [
209 'No options' => [
210 [], $text, <<<EOF
211 <p>Test document.
212 </p>
213 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
214 <ul>
215 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
216 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
217 <ul>
218 <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>
219 </ul>
220 </li>
221 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
222 </ul>
223 </div>
224
225 <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>
226 <p>One
227 </p>
228 <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>
229 <p>Two
230 </p>
231 <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>
232 <p>Two point one
233 </p>
234 <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>
235 <p>Three
236 </p>
237 EOF
238 ],
239 'Disable section edit links' => [
240 [ 'enableSectionEditLinks' => false ], $text, <<<EOF
241 <p>Test document.
242 </p>
243 <div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
244 <ul>
245 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a></li>
246 <li class="toclevel-1 tocsection-2"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a>
247 <ul>
248 <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>
249 </ul>
250 </li>
251 <li class="toclevel-1 tocsection-4"><a href="#Section_3"><span class="tocnumber">3</span> <span class="toctext">Section 3</span></a></li>
252 </ul>
253 </div>
254
255 <h2><span class="mw-headline" id="Section_1">Section 1</span></h2>
256 <p>One
257 </p>
258 <h2><span class="mw-headline" id="Section_2">Section 2</span></h2>
259 <p>Two
260 </p>
261 <h3><span class="mw-headline" id="Section_2.1">Section 2.1</span></h3>
262 <p>Two point one
263 </p>
264 <h2><span class="mw-headline" id="Section_3">Section 3</span></h2>
265 <p>Three
266 </p>
267 EOF
268 ],
269 'Disable TOC, but wrap' => [
270 [ 'allowTOC' => false, 'wrapperDivClass' => 'mw-parser-output' ], $text, <<<EOF
271 <div class="mw-parser-output"><p>Test document.
272 </p>
273
274 <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>
275 <p>One
276 </p>
277 <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>
278 <p>Two
279 </p>
280 <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>
281 <p>Two point one
282 </p>
283 <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>
284 <p>Three
285 </p></div>
286 EOF
287 ],
288 'Style deduplication' => [
289 [], $dedupText, <<<EOF
290 <p>This is a test document.</p>
291 <style data-mw-deduplicate="duplicate1">.Duplicate1 {}</style>
292 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate1"/>
293 <style data-mw-deduplicate="duplicate2">.Duplicate2 {}</style>
294 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate1"/>
295 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate2"/>
296 <style data-mw-not-deduplicate="duplicate1">.Duplicate1 {}</style>
297 <link rel="mw-deduplicated-inline-style" href="mw-data:duplicate1"/>
298 <style data-mw-deduplicate="duplicate3">.Duplicate1 {}</style>
299 <style>.Duplicate1 {}</style>
300 EOF
301 ],
302 'Style deduplication disabled' => [
303 [ 'deduplicateStyles' => false ], $dedupText, $dedupText
304 ],
305 ];
306 // phpcs:enable
307 }
308
309 }