Merge "Additional tests to keep Parsoid on track."
[lhc/web/wiklou.git] / tests / phpunit / includes / 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 MediaWikiTestCase {
10
11 public function setup() {
12 global $wgUser;
13
14 // anon user
15 $wgUser = new User();
16 $wgUser->setName( '127.0.0.1' );
17
18 $this->context = new RequestContext( new FauxRequest() );
19 $this->context->setTitle( Title::newFromText( "Test" ) );
20 $this->context->setUser( $wgUser );
21 }
22
23 public function newContent( $text ) {
24 return new WikitextContent( $text );
25 }
26
27
28 public function dataGetParserOutput() {
29 return array(
30 array("WikitextContentTest_testGetParserOutput", CONTENT_MODEL_WIKITEXT, "hello ''world''\n", "<p>hello <i>world</i>\n</p>"),
31 // @todo: more...?
32 );
33 }
34
35 /**
36 * @dataProvider dataGetParserOutput
37 */
38 public function testGetParserOutput( $title, $model, $text, $expectedHtml ) {
39 $title = Title::newFromText( $title );
40 $content = ContentHandler::makeContent( $text, $title, $model );
41
42 $po = $content->getParserOutput( $title );
43
44 $this->assertEquals( $expectedHtml, $po->getText() );
45 // @todo: assert more properties
46 }
47
48 public function dataGetSecondaryDataUpdates() {
49 return array(
50 array("WikitextContentTest_testGetSecondaryDataUpdates_1",
51 CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
52 array( 'LinksUpdate' => array( 'mRecursive' => true,
53 'mLinks' => array() ) )
54 ),
55 array("WikitextContentTest_testGetSecondaryDataUpdates_2",
56 CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
57 array( 'LinksUpdate' => array( 'mRecursive' => true,
58 'mLinks' => array( array( 'World_test_21344' => 0 ) ) ) )
59 ),
60 // @todo: more...?
61 );
62 }
63
64 /**
65 * @dataProvider dataGetSecondaryDataUpdates
66 * @group Database
67 */
68 public function testGetSecondaryDataUpdates( $title, $model, $text, $expectedStuff ) {
69 $title = Title::newFromText( $title );
70 $title->resetArticleID( 2342 ); //dummy id. fine as long as we don't try to execute the updates!
71
72 $content = ContentHandler::makeContent( $text, $title, $model );
73
74 $updates = $content->getSecondaryDataUpdates( $title );
75
76 // make updates accessible by class name
77 foreach ( $updates as $update ) {
78 $class = get_class( $update );
79 $updates[$class] = $update;
80 }
81
82 foreach ( $expectedStuff as $class => $fieldValues ) {
83 $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
84
85 $update = $updates[$class];
86
87 foreach ( $fieldValues as $field => $value ) {
88 $v = $update->$field; #if the field doesn't exist, just crash and burn
89 $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
90 }
91 }
92 }
93
94
95 static $sections =
96
97 "Intro
98
99 == stuff ==
100 hello world
101
102 == test ==
103 just a test
104
105 == foo ==
106 more stuff
107 ";
108
109 public function dataGetSection() {
110 return array(
111 array( WikitextContentTest::$sections,
112 "0",
113 "Intro"
114 ),
115 array( WikitextContentTest::$sections,
116 "2",
117 "== test ==
118 just a test"
119 ),
120 array( WikitextContentTest::$sections,
121 "8",
122 false
123 ),
124 );
125 }
126
127 /**
128 * @dataProvider dataGetSection
129 */
130 public function testGetSection( $text, $sectionId, $expectedText ) {
131 $content = $this->newContent( $text );
132
133 $sectionContent = $content->getSection( $sectionId );
134
135 $this->assertEquals( $expectedText, is_null( $sectionContent ) ? null : $sectionContent->getNativeData() );
136 }
137
138 public function dataReplaceSection() {
139 return array(
140 array( WikitextContentTest::$sections,
141 "0",
142 "No more",
143 null,
144 trim( preg_replace( '/^Intro/sm', 'No more', WikitextContentTest::$sections ) )
145 ),
146 array( WikitextContentTest::$sections,
147 "",
148 "No more",
149 null,
150 "No more"
151 ),
152 array( WikitextContentTest::$sections,
153 "2",
154 "== TEST ==\nmore fun",
155 null,
156 trim( preg_replace( '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==", WikitextContentTest::$sections ) )
157 ),
158 array( WikitextContentTest::$sections,
159 "8",
160 "No more",
161 null,
162 WikitextContentTest::$sections
163 ),
164 array( WikitextContentTest::$sections,
165 "new",
166 "No more",
167 "New",
168 trim( WikitextContentTest::$sections ) . "\n\n\n== New ==\n\nNo more"
169 ),
170 );
171 }
172
173 /**
174 * @dataProvider dataReplaceSection
175 */
176 public function testReplaceSection( $text, $section, $with, $sectionTitle, $expected ) {
177 $content = $this->newContent( $text );
178 $c = $content->replaceSection( $section, $this->newContent( $with ), $sectionTitle );
179
180 $this->assertEquals( $expected, is_null( $c ) ? null : $c->getNativeData() );
181 }
182
183 public function testAddSectionHeader( ) {
184 $content = $this->newContent( 'hello world' );
185 $content = $content->addSectionHeader( 'test' );
186
187 $this->assertEquals( "== test ==\n\nhello world", $content->getNativeData() );
188 }
189
190 public function dataPreSaveTransform() {
191 return array(
192 array( 'hello this is ~~~',
193 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
194 ),
195 array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
196 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
197 ),
198 );
199 }
200
201 /**
202 * @dataProvider dataPreSaveTransform
203 */
204 public function testPreSaveTransform( $text, $expected ) {
205 global $wgContLang;
206
207 $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
208
209 $content = $this->newContent( $text );
210 $content = $content->preSaveTransform( $this->context->getTitle(), $this->context->getUser(), $options );
211
212 $this->assertEquals( $expected, $content->getNativeData() );
213 }
214
215 public function dataPreloadTransform() {
216 return array(
217 array( 'hello this is ~~~',
218 "hello this is ~~~",
219 ),
220 array( 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
221 'hello \'\'this\'\' is bar',
222 ),
223 );
224 }
225
226 /**
227 * @dataProvider dataPreloadTransform
228 */
229 public function testPreloadTransform( $text, $expected ) {
230 global $wgContLang;
231 $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
232
233 $content = $this->newContent( $text );
234 $content = $content->preloadTransform( $this->context->getTitle(), $options );
235
236 $this->assertEquals( $expected, $content->getNativeData() );
237 }
238
239 public function dataGetRedirectTarget() {
240 return array(
241 array( '#REDIRECT [[Test]]',
242 'Test',
243 ),
244 array( '#REDIRECT Test',
245 null,
246 ),
247 array( '* #REDIRECT [[Test]]',
248 null,
249 ),
250 );
251 }
252
253 /**
254 * @dataProvider dataGetRedirectTarget
255 */
256 public function testGetRedirectTarget( $text, $expected ) {
257 $content = $this->newContent( $text );
258 $t = $content->getRedirectTarget( );
259
260 if ( is_null( $expected ) ) {
261 $this->assertNull( $t, "text should not have generated a redirect target: $text" );
262 } else {
263 $this->assertEquals( $expected, $t->getPrefixedText() );
264 }
265 }
266
267 /**
268 * @dataProvider dataGetRedirectTarget
269 */
270 public function isRedirect( $text, $expected ) {
271 $content = $this->newContent( $text );
272
273 $this->assertEquals( !is_null($expected), $content->isRedirect() );
274 }
275
276
277 /**
278 * @todo: test needs database! Should be done by a test class in the Database group.
279 */
280 /*
281 public function getRedirectChain() {
282 $text = $this->getNativeData();
283 return Title::newFromRedirectArray( $text );
284 }
285 */
286
287 /**
288 * @todo: test needs database! Should be done by a test class in the Database group.
289 */
290 /*
291 public function getUltimateRedirectTarget() {
292 $text = $this->getNativeData();
293 return Title::newFromRedirectRecurse( $text );
294 }
295 */
296
297
298 public function dataIsCountable() {
299 return array(
300 array( '',
301 null,
302 'any',
303 true
304 ),
305 array( 'Foo',
306 null,
307 'any',
308 true
309 ),
310 array( 'Foo',
311 null,
312 'comma',
313 false
314 ),
315 array( 'Foo, bar',
316 null,
317 'comma',
318 true
319 ),
320 array( 'Foo',
321 null,
322 'link',
323 false
324 ),
325 array( 'Foo [[bar]]',
326 null,
327 'link',
328 true
329 ),
330 array( 'Foo',
331 true,
332 'link',
333 true
334 ),
335 array( 'Foo [[bar]]',
336 false,
337 'link',
338 false
339 ),
340 array( '#REDIRECT [[bar]]',
341 true,
342 'any',
343 false
344 ),
345 array( '#REDIRECT [[bar]]',
346 true,
347 'comma',
348 false
349 ),
350 array( '#REDIRECT [[bar]]',
351 true,
352 'link',
353 false
354 ),
355 );
356 }
357
358
359 /**
360 * @dataProvider dataIsCountable
361 * @group Database
362 */
363 public function testIsCountable( $text, $hasLinks, $mode, $expected ) {
364 global $wgArticleCountMethod;
365
366 $old = $wgArticleCountMethod;
367 $wgArticleCountMethod = $mode;
368
369 $content = $this->newContent( $text );
370
371 $v = $content->isCountable( $hasLinks, $this->context->getTitle() );
372 $wgArticleCountMethod = $old;
373
374 $this->assertEquals( $expected, $v, "isCountable() returned unexpected value " . var_export( $v, true )
375 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
376 }
377
378 public function dataGetTextForSummary() {
379 return array(
380 array( "hello\nworld.",
381 16,
382 'hello world.',
383 ),
384 array( 'hello world.',
385 8,
386 'hello...',
387 ),
388 array( '[[hello world]].',
389 8,
390 'hel...',
391 ),
392 );
393 }
394
395 /**
396 * @dataProvider dataGetTextForSummary
397 */
398 public function testGetTextForSummary( $text, $maxlength, $expected ) {
399 $content = $this->newContent( $text );
400
401 $this->assertEquals( $expected, $content->getTextForSummary( $maxlength ) );
402 }
403
404
405 public function testGetTextForSearchIndex( ) {
406 $content = $this->newContent( "hello world." );
407
408 $this->assertEquals( "hello world.", $content->getTextForSearchIndex() );
409 }
410
411 public function testCopy() {
412 $content = $this->newContent( "hello world." );
413 $copy = $content->copy();
414
415 $this->assertTrue( $content->equals( $copy ), "copy must be equal to original" );
416 $this->assertEquals( "hello world.", $copy->getNativeData() );
417 }
418
419 public function testGetSize( ) {
420 $content = $this->newContent( "hello world." );
421
422 $this->assertEquals( 12, $content->getSize() );
423 }
424
425 public function testGetNativeData( ) {
426 $content = $this->newContent( "hello world." );
427
428 $this->assertEquals( "hello world.", $content->getNativeData() );
429 }
430
431 public function testGetWikitextForTransclusion( ) {
432 $content = $this->newContent( "hello world." );
433
434 $this->assertEquals( "hello world.", $content->getWikitextForTransclusion() );
435 }
436
437 public function testMatchMagicWord( ) {
438 $mw = MagicWord::get( "staticredirect" );
439
440 $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
441 $this->assertTrue( $content->matchMagicWord( $mw ), "should have matched magic word" );
442
443 $content = $this->newContent( "#REDIRECT [[FOO]]" );
444 $this->assertFalse( $content->matchMagicWord( $mw ), "should not have matched magic word" );
445 }
446
447 public function testUpdateRedirect( ) {
448 $target = Title::newFromText( "testUpdateRedirect_target" );
449
450 // test with non-redirect page
451 $content = $this->newContent( "hello world." );
452 $newContent = $content->updateRedirect( $target );
453
454 $this->assertTrue( $content->equals( $newContent ), "content should be unchanged" );
455
456 // test with actual redirect
457 $content = $this->newContent( "#REDIRECT [[Someplace]]" );
458 $newContent = $content->updateRedirect( $target );
459
460 $this->assertFalse( $content->equals( $newContent ), "content should have changed" );
461 $this->assertTrue( $newContent->isRedirect(), "new content should be a redirect" );
462
463 $this->assertEquals( $target->getFullText(), $newContent->getRedirectTarget()->getFullText() );
464 }
465
466 # =================================================================================================================
467
468 public function testGetModel() {
469 $content = $this->newContent( "hello world." );
470
471 $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getModel() );
472 }
473
474 public function testGetContentHandler() {
475 $content = $this->newContent( "hello world." );
476
477 $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getContentHandler()->getModelID() );
478 }
479
480 public function dataIsEmpty( ) {
481 return array(
482 array( '', true ),
483 array( ' ', false ),
484 array( '0', false ),
485 array( 'hallo welt.', false ),
486 );
487 }
488
489 /**
490 * @dataProvider dataIsEmpty
491 */
492 public function testIsEmpty( $text, $empty ) {
493 $content = $this->newContent( $text );
494
495 $this->assertEquals( $empty, $content->isEmpty() );
496 }
497
498 public function dataEquals( ) {
499 return array(
500 array( new WikitextContent( "hallo" ), null, false ),
501 array( new WikitextContent( "hallo" ), new WikitextContent( "hallo" ), true ),
502 array( new WikitextContent( "hallo" ), new JavascriptContent( "hallo" ), false ),
503 array( new WikitextContent( "hallo" ), new WikitextContent( "HALLO" ), false ),
504 );
505 }
506
507 /**
508 * @dataProvider dataEquals
509 */
510 public function testEquals( Content $a, Content $b = null, $equal = false ) {
511 $this->assertEquals( $equal, $a->equals( $b ) );
512 }
513
514 public function dataGetDeletionUpdates() {
515 return array(
516 array("WikitextContentTest_testGetSecondaryDataUpdates_1",
517 CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
518 array( 'LinksDeletionUpdate' => array( ) )
519 ),
520 array("WikitextContentTest_testGetSecondaryDataUpdates_2",
521 CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
522 array( 'LinksDeletionUpdate' => array( ) )
523 ),
524 // @todo: more...?
525 );
526 }
527
528 /**
529 * @dataProvider dataGetDeletionUpdates
530 */
531 public function testDeletionUpdates( $title, $model, $text, $expectedStuff ) {
532 $title = Title::newFromText( $title );
533 $title->resetArticleID( 2342 ); //dummy id. fine as long as we don't try to execute the updates!
534
535 $content = ContentHandler::makeContent( $text, $title, $model );
536
537 $updates = $content->getDeletionUpdates( WikiPage::factory( $title ) );
538
539 // make updates accessible by class name
540 foreach ( $updates as $update ) {
541 $class = get_class( $update );
542 $updates[ $class ] = $update;
543 }
544
545 foreach ( $expectedStuff as $class => $fieldValues ) {
546 $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
547
548 $update = $updates[ $class ];
549
550 foreach ( $fieldValues as $field => $value ) {
551 $v = $update->$field; #if the field doesn't exist, just crash and burn
552 $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
553 }
554 }
555 }
556
557 }