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