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