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