Merge "Make registerTempTableOperation() detect TRUNCATE operations"
[lhc/web/wiklou.git] / tests / phpunit / includes / content / WikitextContentTest.php
1 <?php
2
3 /**
4 * @group ContentHandler
5 *
6 * @group Database
7 * ^--- needed, because we do need the database to test link updates
8 */
9 class WikitextContentTest extends TextContentTest {
10 public static $sections = "Intro
11
12 == stuff ==
13 hello world
14
15 == test ==
16 just a test
17
18 == foo ==
19 more stuff
20 ";
21
22 public function newContent( $text ) {
23 return new WikitextContent( $text );
24 }
25
26 public static function dataGetParserOutput() {
27 return [
28 [
29 "WikitextContentTest_testGetParserOutput",
30 CONTENT_MODEL_WIKITEXT,
31 "hello ''world''\n",
32 "<div class=\"mw-parser-output\"><p>hello <i>world</i>\n</p>\n\n\n</div>"
33 ],
34 // TODO: more...?
35 ];
36 }
37
38 public static function dataGetSecondaryDataUpdates() {
39 return [
40 [ "WikitextContentTest_testGetSecondaryDataUpdates_1",
41 CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
42 [
43 'LinksUpdate' => [
44 'mRecursive' => true,
45 'mLinks' => []
46 ]
47 ]
48 ],
49 [ "WikitextContentTest_testGetSecondaryDataUpdates_2",
50 CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
51 [
52 'LinksUpdate' => [
53 'mRecursive' => true,
54 'mLinks' => [
55 [ 'World_test_21344' => 0 ]
56 ]
57 ]
58 ]
59 ],
60 // TODO: more...?
61 ];
62 }
63
64 /**
65 * @dataProvider dataGetSecondaryDataUpdates
66 * @group Database
67 * @covers WikitextContent::getSecondaryDataUpdates
68 */
69 public function testGetSecondaryDataUpdates( $title, $model, $text, $expectedStuff ) {
70 $ns = $this->getDefaultWikitextNS();
71 $title = Title::newFromText( $title, $ns );
72
73 $content = ContentHandler::makeContent( $text, $title, $model );
74
75 $page = WikiPage::factory( $title );
76 $page->doEditContent( $content, '' );
77
78 $updates = $content->getSecondaryDataUpdates( $title );
79
80 // make updates accessible by class name
81 foreach ( $updates as $update ) {
82 $class = get_class( $update );
83 $updates[$class] = $update;
84 }
85
86 foreach ( $expectedStuff as $class => $fieldValues ) {
87 $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
88
89 $update = $updates[$class];
90
91 foreach ( $fieldValues as $field => $value ) {
92 $v = $update->$field; # if the field doesn't exist, just crash and burn
93 $this->assertEquals(
94 $value,
95 $v,
96 "unexpected value for field $field in instance of $class"
97 );
98 }
99 }
100
101 $page->doDeleteArticle( '' );
102 }
103
104 public static function dataGetSection() {
105 return [
106 [ WikitextContentTest::$sections,
107 "0",
108 "Intro"
109 ],
110 [ WikitextContentTest::$sections,
111 "2",
112 "== test ==
113 just a test"
114 ],
115 [ WikitextContentTest::$sections,
116 "8",
117 false
118 ],
119 ];
120 }
121
122 /**
123 * @dataProvider dataGetSection
124 * @covers WikitextContent::getSection
125 */
126 public function testGetSection( $text, $sectionId, $expectedText ) {
127 $content = $this->newContent( $text );
128
129 $sectionContent = $content->getSection( $sectionId );
130 if ( is_object( $sectionContent ) ) {
131 $sectionText = $sectionContent->getNativeData();
132 } else {
133 $sectionText = $sectionContent;
134 }
135
136 $this->assertEquals( $expectedText, $sectionText );
137 }
138
139 public static function dataReplaceSection() {
140 return [
141 [ WikitextContentTest::$sections,
142 "0",
143 "No more",
144 null,
145 trim( preg_replace( '/^Intro/sm', 'No more', WikitextContentTest::$sections ) )
146 ],
147 [ WikitextContentTest::$sections,
148 "",
149 "No more",
150 null,
151 "No more"
152 ],
153 [ WikitextContentTest::$sections,
154 "2",
155 "== TEST ==\nmore fun",
156 null,
157 trim( preg_replace(
158 '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==",
159 WikitextContentTest::$sections
160 ) )
161 ],
162 [ WikitextContentTest::$sections,
163 "8",
164 "No more",
165 null,
166 WikitextContentTest::$sections
167 ],
168 [ WikitextContentTest::$sections,
169 "new",
170 "No more",
171 "New",
172 trim( WikitextContentTest::$sections ) . "\n\n\n== New ==\n\nNo more"
173 ],
174 ];
175 }
176
177 /**
178 * @dataProvider dataReplaceSection
179 * @covers WikitextContent::replaceSection
180 */
181 public function testReplaceSection( $text, $section, $with, $sectionTitle, $expected ) {
182 $content = $this->newContent( $text );
183 $c = $content->replaceSection( $section, $this->newContent( $with ), $sectionTitle );
184
185 $this->assertEquals( $expected, is_null( $c ) ? null : $c->getNativeData() );
186 }
187
188 /**
189 * @covers WikitextContent::addSectionHeader
190 */
191 public function testAddSectionHeader() {
192 $content = $this->newContent( 'hello world' );
193 $content = $content->addSectionHeader( 'test' );
194
195 $this->assertEquals( "== test ==\n\nhello world", $content->getNativeData() );
196 }
197
198 public static function dataPreSaveTransform() {
199 return [
200 [ 'hello this is ~~~',
201 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
202 ],
203 [ 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
204 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
205 ],
206 [ // rtrim
207 " Foo \n ",
208 " Foo",
209 ],
210 ];
211 }
212
213 public static function dataPreloadTransform() {
214 return [
215 [
216 'hello this is ~~~',
217 "hello this is ~~~",
218 ],
219 [
220 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
221 'hello \'\'this\'\' is bar',
222 ],
223 ];
224 }
225
226 public static function dataGetRedirectTarget() {
227 return [
228 [ '#REDIRECT [[Test]]',
229 'Test',
230 ],
231 [ '#REDIRECT Test',
232 null,
233 ],
234 [ '* #REDIRECT [[Test]]',
235 null,
236 ],
237 ];
238 }
239
240 public static function dataGetTextForSummary() {
241 return [
242 [ "hello\nworld.",
243 16,
244 'hello world.',
245 ],
246 [ 'hello world.',
247 8,
248 'hello...',
249 ],
250 [ '[[hello world]].',
251 8,
252 'hel...',
253 ],
254 ];
255 }
256
257 public static function dataIsCountable() {
258 return [
259 [ '',
260 null,
261 'any',
262 true
263 ],
264 [ 'Foo',
265 null,
266 'any',
267 true
268 ],
269 [ 'Foo',
270 null,
271 'comma',
272 false
273 ],
274 [ 'Foo, bar',
275 null,
276 'comma',
277 true
278 ],
279 [ 'Foo',
280 null,
281 'link',
282 false
283 ],
284 [ 'Foo [[bar]]',
285 null,
286 'link',
287 true
288 ],
289 [ 'Foo',
290 true,
291 'link',
292 true
293 ],
294 [ 'Foo [[bar]]',
295 false,
296 'link',
297 false
298 ],
299 [ '#REDIRECT [[bar]]',
300 true,
301 'any',
302 false
303 ],
304 [ '#REDIRECT [[bar]]',
305 true,
306 'comma',
307 false
308 ],
309 [ '#REDIRECT [[bar]]',
310 true,
311 'link',
312 false
313 ],
314 ];
315 }
316
317 /**
318 * @covers WikitextContent::matchMagicWord
319 */
320 public function testMatchMagicWord() {
321 $mw = MagicWord::get( "staticredirect" );
322
323 $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
324 $this->assertTrue( $content->matchMagicWord( $mw ), "should have matched magic word" );
325
326 $content = $this->newContent( "#REDIRECT [[FOO]]" );
327 $this->assertFalse(
328 $content->matchMagicWord( $mw ),
329 "should not have matched magic word"
330 );
331 }
332
333 /**
334 * @covers WikitextContent::updateRedirect
335 */
336 public function testUpdateRedirect() {
337 $target = Title::newFromText( "testUpdateRedirect_target" );
338
339 // test with non-redirect page
340 $content = $this->newContent( "hello world." );
341 $newContent = $content->updateRedirect( $target );
342
343 $this->assertTrue( $content->equals( $newContent ), "content should be unchanged" );
344
345 // test with actual redirect
346 $content = $this->newContent( "#REDIRECT [[Someplace]]" );
347 $newContent = $content->updateRedirect( $target );
348
349 $this->assertFalse( $content->equals( $newContent ), "content should have changed" );
350 $this->assertTrue( $newContent->isRedirect(), "new content should be a redirect" );
351
352 $this->assertEquals(
353 $target->getFullText(),
354 $newContent->getRedirectTarget()->getFullText()
355 );
356 }
357
358 /**
359 * @covers WikitextContent::getModel
360 */
361 public function testGetModel() {
362 $content = $this->newContent( "hello world." );
363
364 $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getModel() );
365 }
366
367 /**
368 * @covers WikitextContent::getContentHandler
369 */
370 public function testGetContentHandler() {
371 $content = $this->newContent( "hello world." );
372
373 $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getContentHandler()->getModelID() );
374 }
375
376 public function testRedirectParserOption() {
377 $title = Title::newFromText( 'testRedirectParserOption' );
378
379 // Set up hook and its reporting variables
380 $wikitext = null;
381 $redirectTarget = null;
382 $this->mergeMwGlobalArrayValue( 'wgHooks', [
383 'InternalParseBeforeLinks' => [
384 function ( &$parser, &$text, &$stripState ) use ( &$wikitext, &$redirectTarget ) {
385 $wikitext = $text;
386 $redirectTarget = $parser->getOptions()->getRedirectTarget();
387 }
388 ]
389 ] );
390
391 // Test with non-redirect page
392 $wikitext = false;
393 $redirectTarget = false;
394 $content = $this->newContent( 'hello world.' );
395 $options = $content->getContentHandler()->makeParserOptions( 'canonical' );
396 $options->setRedirectTarget( $title );
397 $content->getParserOutput( $title, null, $options );
398 $this->assertEquals( 'hello world.', $wikitext,
399 'Wikitext passed to hook was not as expected'
400 );
401 $this->assertEquals( null, $redirectTarget, 'Redirect seen in hook was not null' );
402 $this->assertEquals( $title, $options->getRedirectTarget(),
403 'ParserOptions\' redirectTarget was changed'
404 );
405
406 // Test with a redirect page
407 $wikitext = false;
408 $redirectTarget = false;
409 $content = $this->newContent(
410 "#REDIRECT [[TestRedirectParserOption/redir]]\nhello redirect."
411 );
412 $options = $content->getContentHandler()->makeParserOptions( 'canonical' );
413 $content->getParserOutput( $title, null, $options );
414 $this->assertEquals(
415 'hello redirect.',
416 $wikitext,
417 'Wikitext passed to hook was not as expected'
418 );
419 $this->assertNotEquals(
420 null,
421 $redirectTarget,
422 'Redirect seen in hook was null' );
423 $this->assertEquals(
424 'TestRedirectParserOption/redir',
425 $redirectTarget->getFullText(),
426 'Redirect seen in hook was not the expected title'
427 );
428 $this->assertEquals(
429 null,
430 $options->getRedirectTarget(),
431 'ParserOptions\' redirectTarget was changed'
432 );
433 }
434
435 public static function dataEquals() {
436 return [
437 [ new WikitextContent( "hallo" ), null, false ],
438 [ new WikitextContent( "hallo" ), new WikitextContent( "hallo" ), true ],
439 [ new WikitextContent( "hallo" ), new JavaScriptContent( "hallo" ), false ],
440 [ new WikitextContent( "hallo" ), new TextContent( "hallo" ), false ],
441 [ new WikitextContent( "hallo" ), new WikitextContent( "HALLO" ), false ],
442 ];
443 }
444
445 public static function dataGetDeletionUpdates() {
446 return [
447 [ "WikitextContentTest_testGetSecondaryDataUpdates_1",
448 CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
449 [ 'LinksDeletionUpdate' => [] ]
450 ],
451 [ "WikitextContentTest_testGetSecondaryDataUpdates_2",
452 CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
453 [ 'LinksDeletionUpdate' => [] ]
454 ],
455 // @todo more...?
456 ];
457 }
458 }