Merge "Improve rendering of Living Style Guide sections, examples, and modifiers."
[lhc/web/wiklou.git] / tests / phpunit / includes / content / TextContentTest.php
1 <?php
2
3 /**
4 * @group ContentHandler
5 * @group Database
6 * ^--- needed, because we do need the database to test link updates
7 */
8 class TextContentTest extends MediaWikiLangTestCase {
9 protected $context;
10 protected $savedContentGetParserOutput;
11
12 protected function setUp() {
13 global $wgHooks;
14
15 parent::setUp();
16
17 // Anon user
18 $user = new User();
19 $user->setName( '127.0.0.1' );
20
21 $this->context = new RequestContext( new FauxRequest() );
22 $this->context->setTitle( Title::newFromText( 'Test' ) );
23 $this->context->setUser( $user );
24
25 $this->setMwGlobals( array(
26 'wgUser' => $user,
27 'wgTextModelsToParse' => array(
28 CONTENT_MODEL_WIKITEXT,
29 CONTENT_MODEL_CSS,
30 CONTENT_MODEL_JAVASCRIPT,
31 ),
32 'wgUseTidy' => false,
33 'wgAlwaysUseTidy' => false,
34 ) );
35
36 // bypass hooks that force custom rendering
37 if ( isset( $wgHooks['ContentGetParserOutput'] ) ) {
38 $this->savedContentGetParserOutput = $wgHooks['ContentGetParserOutput'];
39 unset( $wgHooks['ContentGetParserOutput'] );
40 }
41 }
42
43 public function teardown() {
44 global $wgHooks;
45
46 // restore hooks that force custom rendering
47 if ( $this->savedContentGetParserOutput !== null ) {
48 $wgHooks['ContentGetParserOutput'] = $this->savedContentGetParserOutput;
49 }
50
51 parent::teardown();
52 }
53
54 public function newContent( $text ) {
55 return new TextContent( $text );
56 }
57
58 public static function dataGetParserOutput() {
59 return array(
60 array(
61 'TextContentTest_testGetParserOutput',
62 CONTENT_MODEL_TEXT,
63 "hello ''world'' & [[stuff]]\n", "hello ''world'' &amp; [[stuff]]",
64 array(
65 'Links' => array()
66 )
67 ),
68 // TODO: more...?
69 );
70 }
71
72 /**
73 * @dataProvider dataGetParserOutput
74 * @covers TextContent::getParserOutput
75 */
76 public function testGetParserOutput( $title, $model, $text, $expectedHtml,
77 $expectedFields = null
78 ) {
79 $title = Title::newFromText( $title );
80 $content = ContentHandler::makeContent( $text, $title, $model );
81
82 $po = $content->getParserOutput( $title );
83
84 $html = $po->getText();
85 $html = preg_replace( '#<!--.*?-->#sm', '', $html ); // strip comments
86
87 $this->assertEquals( $expectedHtml, trim( $html ) );
88
89 if ( $expectedFields ) {
90 foreach ( $expectedFields as $field => $exp ) {
91 $f = 'get' . ucfirst( $field );
92 $v = call_user_func( array( $po, $f ) );
93
94 if ( is_array( $exp ) ) {
95 $this->assertArrayEquals( $exp, $v );
96 } else {
97 $this->assertEquals( $exp, $v );
98 }
99 }
100 }
101
102 // TODO: assert more properties
103 }
104
105 public static function dataPreSaveTransform() {
106 return array(
107 array(
108 #0: no signature resolution
109 'hello this is ~~~',
110 'hello this is ~~~',
111 ),
112 array(
113 #1: rtrim
114 " Foo \n ",
115 ' Foo',
116 ),
117 );
118 }
119
120 /**
121 * @dataProvider dataPreSaveTransform
122 * @covers TextContent::preSaveTransform
123 */
124 public function testPreSaveTransform( $text, $expected ) {
125 global $wgContLang;
126
127 $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
128
129 $content = $this->newContent( $text );
130 $content = $content->preSaveTransform(
131 $this->context->getTitle(),
132 $this->context->getUser(),
133 $options
134 );
135
136 $this->assertEquals( $expected, $content->getNativeData() );
137 }
138
139 public static function dataPreloadTransform() {
140 return array(
141 array(
142 'hello this is ~~~',
143 'hello this is ~~~',
144 ),
145 );
146 }
147
148 /**
149 * @dataProvider dataPreloadTransform
150 * @covers TextContent::preloadTransform
151 */
152 public function testPreloadTransform( $text, $expected ) {
153 global $wgContLang;
154 $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
155
156 $content = $this->newContent( $text );
157 $content = $content->preloadTransform( $this->context->getTitle(), $options );
158
159 $this->assertEquals( $expected, $content->getNativeData() );
160 }
161
162 public static function dataGetRedirectTarget() {
163 return array(
164 array( '#REDIRECT [[Test]]',
165 null,
166 ),
167 );
168 }
169
170 /**
171 * @dataProvider dataGetRedirectTarget
172 * @covers TextContent::getRedirectTarget
173 */
174 public function testGetRedirectTarget( $text, $expected ) {
175 $content = $this->newContent( $text );
176 $t = $content->getRedirectTarget();
177
178 if ( is_null( $expected ) ) {
179 $this->assertNull( $t, "text should not have generated a redirect target: $text" );
180 } else {
181 $this->assertEquals( $expected, $t->getPrefixedText() );
182 }
183 }
184
185 /**
186 * @dataProvider dataGetRedirectTarget
187 * @covers TextContent::isRedirect
188 */
189 public function testIsRedirect( $text, $expected ) {
190 $content = $this->newContent( $text );
191
192 $this->assertEquals( !is_null( $expected ), $content->isRedirect() );
193 }
194
195 /**
196 * @todo Test needs database! Should be done by a test class in the Database group.
197 */
198 /*
199 public function getRedirectChain() {
200 $text = $this->getNativeData();
201 return Title::newFromRedirectArray( $text );
202 }
203 */
204
205 /**
206 * @todo Test needs database! Should be done by a test class in the Database group.
207 */
208 /*
209 public function getUltimateRedirectTarget() {
210 $text = $this->getNativeData();
211 return Title::newFromRedirectRecurse( $text );
212 }
213 */
214
215 public static function dataIsCountable() {
216 return array(
217 array( '',
218 null,
219 'any',
220 true
221 ),
222 array( 'Foo',
223 null,
224 'any',
225 true
226 ),
227 array( 'Foo',
228 null,
229 'comma',
230 false
231 ),
232 array( 'Foo, bar',
233 null,
234 'comma',
235 false
236 ),
237 );
238 }
239
240 /**
241 * @dataProvider dataIsCountable
242 * @group Database
243 * @covers TextContent::isCountable
244 */
245 public function testIsCountable( $text, $hasLinks, $mode, $expected ) {
246 $this->setMwGlobals( 'wgArticleCountMethod', $mode );
247
248 $content = $this->newContent( $text );
249
250 $v = $content->isCountable( $hasLinks, $this->context->getTitle() );
251
252 $this->assertEquals(
253 $expected,
254 $v,
255 'isCountable() returned unexpected value ' . var_export( $v, true )
256 . ' instead of ' . var_export( $expected, true )
257 . " in mode `$mode` for text \"$text\""
258 );
259 }
260
261 public static function dataGetTextForSummary() {
262 return array(
263 array( "hello\nworld.",
264 16,
265 'hello world.',
266 ),
267 array( 'hello world.',
268 8,
269 'hello...',
270 ),
271 array( '[[hello world]].',
272 8,
273 '[[hel...',
274 ),
275 );
276 }
277
278 /**
279 * @dataProvider dataGetTextForSummary
280 * @covers TextContent::getTextForSummary
281 */
282 public function testGetTextForSummary( $text, $maxlength, $expected ) {
283 $content = $this->newContent( $text );
284
285 $this->assertEquals( $expected, $content->getTextForSummary( $maxlength ) );
286 }
287
288 /**
289 * @covers TextContent::getTextForSearchIndex
290 */
291 public function testGetTextForSearchIndex() {
292 $content = $this->newContent( 'hello world.' );
293
294 $this->assertEquals( 'hello world.', $content->getTextForSearchIndex() );
295 }
296
297 /**
298 * @covers TextContent::copy
299 */
300 public function testCopy() {
301 $content = $this->newContent( 'hello world.' );
302 $copy = $content->copy();
303
304 $this->assertTrue( $content->equals( $copy ), 'copy must be equal to original' );
305 $this->assertEquals( 'hello world.', $copy->getNativeData() );
306 }
307
308 /**
309 * @covers TextContent::getSize
310 */
311 public function testGetSize() {
312 $content = $this->newContent( 'hello world.' );
313
314 $this->assertEquals( 12, $content->getSize() );
315 }
316
317 /**
318 * @covers TextContent::getNativeData
319 */
320 public function testGetNativeData() {
321 $content = $this->newContent( 'hello world.' );
322
323 $this->assertEquals( 'hello world.', $content->getNativeData() );
324 }
325
326 /**
327 * @covers TextContent::getWikitextForTransclusion
328 */
329 public function testGetWikitextForTransclusion() {
330 $content = $this->newContent( 'hello world.' );
331
332 $this->assertEquals( 'hello world.', $content->getWikitextForTransclusion() );
333 }
334
335 /**
336 * @covers TextContent::getModel
337 */
338 public function testGetModel() {
339 $content = $this->newContent( "hello world." );
340
341 $this->assertEquals( CONTENT_MODEL_TEXT, $content->getModel() );
342 }
343
344 /**
345 * @covers TextContent::getContentHandler
346 */
347 public function testGetContentHandler() {
348 $content = $this->newContent( "hello world." );
349
350 $this->assertEquals( CONTENT_MODEL_TEXT, $content->getContentHandler()->getModelID() );
351 }
352
353 public static function dataIsEmpty() {
354 return array(
355 array( '', true ),
356 array( ' ', false ),
357 array( '0', false ),
358 array( 'hallo welt.', false ),
359 );
360 }
361
362 /**
363 * @dataProvider dataIsEmpty
364 * @covers TextContent::isEmpty
365 */
366 public function testIsEmpty( $text, $empty ) {
367 $content = $this->newContent( $text );
368
369 $this->assertEquals( $empty, $content->isEmpty() );
370 }
371
372 public static function dataEquals() {
373 return array(
374 array( new TextContent( "hallo" ), null, false ),
375 array( new TextContent( "hallo" ), new TextContent( "hallo" ), true ),
376 array( new TextContent( "hallo" ), new JavaScriptContent( "hallo" ), false ),
377 array( new TextContent( "hallo" ), new WikitextContent( "hallo" ), false ),
378 array( new TextContent( "hallo" ), new TextContent( "HALLO" ), false ),
379 );
380 }
381
382 /**
383 * @dataProvider dataEquals
384 * @covers TextContent::equals
385 */
386 public function testEquals( Content $a, Content $b = null, $equal = false ) {
387 $this->assertEquals( $equal, $a->equals( $b ) );
388 }
389
390 public static function dataGetDeletionUpdates() {
391 return array(
392 array( "TextContentTest_testGetSecondaryDataUpdates_1",
393 CONTENT_MODEL_TEXT, "hello ''world''\n",
394 array()
395 ),
396 array( "TextContentTest_testGetSecondaryDataUpdates_2",
397 CONTENT_MODEL_TEXT, "hello [[world test 21344]]\n",
398 array()
399 ),
400 // TODO: more...?
401 );
402 }
403
404 /**
405 * @dataProvider dataGetDeletionUpdates
406 * @covers TextContent::getDeletionUpdates
407 */
408 public function testDeletionUpdates( $title, $model, $text, $expectedStuff ) {
409 $ns = $this->getDefaultWikitextNS();
410 $title = Title::newFromText( $title, $ns );
411
412 $content = ContentHandler::makeContent( $text, $title, $model );
413
414 $page = WikiPage::factory( $title );
415 $page->doEditContent( $content, '' );
416
417 $updates = $content->getDeletionUpdates( $page );
418
419 // make updates accessible by class name
420 foreach ( $updates as $update ) {
421 $class = get_class( $update );
422 $updates[$class] = $update;
423 }
424
425 if ( !$expectedStuff ) {
426 $this->assertTrue( true ); // make phpunit happy
427 return;
428 }
429
430 foreach ( $expectedStuff as $class => $fieldValues ) {
431 $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
432
433 $update = $updates[$class];
434
435 foreach ( $fieldValues as $field => $value ) {
436 $v = $update->$field; #if the field doesn't exist, just crash and burn
437 $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
438 }
439 }
440
441 $page->doDeleteArticle( '' );
442 }
443
444 public static function provideConvert() {
445 return array(
446 array( // #0
447 'Hallo Welt',
448 CONTENT_MODEL_WIKITEXT,
449 'lossless',
450 'Hallo Welt'
451 ),
452 array( // #1
453 'Hallo Welt',
454 CONTENT_MODEL_WIKITEXT,
455 'lossless',
456 'Hallo Welt'
457 ),
458 array( // #1
459 'Hallo Welt',
460 CONTENT_MODEL_CSS,
461 'lossless',
462 'Hallo Welt'
463 ),
464 array( // #1
465 'Hallo Welt',
466 CONTENT_MODEL_JAVASCRIPT,
467 'lossless',
468 'Hallo Welt'
469 ),
470 );
471 }
472
473 /**
474 * @dataProvider provideConvert
475 * @covers TextContent::convert
476 */
477 public function testConvert( $text, $model, $lossy, $expectedNative ) {
478 $content = $this->newContent( $text );
479
480 $converted = $content->convert( $model, $lossy );
481
482 if ( $expectedNative === false ) {
483 $this->assertFalse( $converted, "conversion to $model was expected to fail!" );
484 } else {
485 $this->assertInstanceOf( 'Content', $converted );
486 $this->assertEquals( $expectedNative, $converted->getNativeData() );
487 }
488 }
489 }