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