Merge "Special:Upload should not crash on failing previews"
[lhc/web/wiklou.git] / tests / phpunit / includes / RevisionTest.php
1 <?php
2
3 /**
4 * @group ContentHandler
5 */
6 class RevisionTest extends MediaWikiTestCase {
7 protected function setUp() {
8 global $wgContLang;
9
10 parent::setUp();
11
12 $this->setMwGlobals( [
13 'wgContLang' => Language::factory( 'en' ),
14 'wgLanguageCode' => 'en',
15 'wgLegacyEncoding' => false,
16 'wgCompressRevisions' => false,
17
18 'wgContentHandlerTextFallback' => 'ignore',
19 ] );
20
21 $this->mergeMwGlobalArrayValue(
22 'wgExtraNamespaces',
23 [
24 12312 => 'Dummy',
25 12313 => 'Dummy_talk',
26 ]
27 );
28
29 $this->mergeMwGlobalArrayValue(
30 'wgNamespaceContentModels',
31 [
32 12312 => 'testing',
33 ]
34 );
35
36 $this->mergeMwGlobalArrayValue(
37 'wgContentHandlers',
38 [
39 'testing' => 'DummyContentHandlerForTesting',
40 'RevisionTestModifyableContent' => 'RevisionTestModifyableContentHandler',
41 ]
42 );
43
44 MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
45 $wgContLang->resetNamespaces(); # reset namespace cache
46 }
47
48 function tearDown() {
49 global $wgContLang;
50
51 MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
52 $wgContLang->resetNamespaces(); # reset namespace cache
53
54 parent::tearDown();
55 }
56
57 /**
58 * @covers Revision::getRevisionText
59 */
60 public function testGetRevisionText() {
61 $row = new stdClass;
62 $row->old_flags = '';
63 $row->old_text = 'This is a bunch of revision text.';
64 $this->assertEquals(
65 'This is a bunch of revision text.',
66 Revision::getRevisionText( $row ) );
67 }
68
69 /**
70 * @covers Revision::getRevisionText
71 */
72 public function testGetRevisionTextGzip() {
73 $this->checkPHPExtension( 'zlib' );
74
75 $row = new stdClass;
76 $row->old_flags = 'gzip';
77 $row->old_text = gzdeflate( 'This is a bunch of revision text.' );
78 $this->assertEquals(
79 'This is a bunch of revision text.',
80 Revision::getRevisionText( $row ) );
81 }
82
83 /**
84 * @covers Revision::getRevisionText
85 */
86 public function testGetRevisionTextUtf8Native() {
87 $row = new stdClass;
88 $row->old_flags = 'utf-8';
89 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
90 $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
91 $this->assertEquals(
92 "Wiki est l'\xc3\xa9cole superieur !",
93 Revision::getRevisionText( $row ) );
94 }
95
96 /**
97 * @covers Revision::getRevisionText
98 */
99 public function testGetRevisionTextUtf8Legacy() {
100 $row = new stdClass;
101 $row->old_flags = '';
102 $row->old_text = "Wiki est l'\xe9cole superieur !";
103 $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
104 $this->assertEquals(
105 "Wiki est l'\xc3\xa9cole superieur !",
106 Revision::getRevisionText( $row ) );
107 }
108
109 /**
110 * @covers Revision::getRevisionText
111 */
112 public function testGetRevisionTextUtf8NativeGzip() {
113 $this->checkPHPExtension( 'zlib' );
114
115 $row = new stdClass;
116 $row->old_flags = 'gzip,utf-8';
117 $row->old_text = gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" );
118 $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
119 $this->assertEquals(
120 "Wiki est l'\xc3\xa9cole superieur !",
121 Revision::getRevisionText( $row ) );
122 }
123
124 /**
125 * @covers Revision::getRevisionText
126 */
127 public function testGetRevisionTextUtf8LegacyGzip() {
128 $this->checkPHPExtension( 'zlib' );
129
130 $row = new stdClass;
131 $row->old_flags = 'gzip';
132 $row->old_text = gzdeflate( "Wiki est l'\xe9cole superieur !" );
133 $GLOBALS['wgLegacyEncoding'] = 'iso-8859-1';
134 $this->assertEquals(
135 "Wiki est l'\xc3\xa9cole superieur !",
136 Revision::getRevisionText( $row ) );
137 }
138
139 /**
140 * @covers Revision::compressRevisionText
141 */
142 public function testCompressRevisionTextUtf8() {
143 $row = new stdClass;
144 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
145 $row->old_flags = Revision::compressRevisionText( $row->old_text );
146 $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
147 "Flags should contain 'utf-8'" );
148 $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ),
149 "Flags should not contain 'gzip'" );
150 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
151 $row->old_text, "Direct check" );
152 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
153 Revision::getRevisionText( $row ), "getRevisionText" );
154 }
155
156 /**
157 * @covers Revision::compressRevisionText
158 */
159 public function testCompressRevisionTextUtf8Gzip() {
160 $this->checkPHPExtension( 'zlib' );
161 $this->setMwGlobals( 'wgCompressRevisions', true );
162
163 $row = new stdClass;
164 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
165 $row->old_flags = Revision::compressRevisionText( $row->old_text );
166 $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
167 "Flags should contain 'utf-8'" );
168 $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ),
169 "Flags should contain 'gzip'" );
170 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
171 gzinflate( $row->old_text ), "Direct check" );
172 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
173 Revision::getRevisionText( $row ), "getRevisionText" );
174 }
175
176 # =========================================================================
177
178 /**
179 * @param string $text
180 * @param string $title
181 * @param string $model
182 * @param string $format
183 *
184 * @return Revision
185 */
186 function newTestRevision( $text, $title = "Test",
187 $model = CONTENT_MODEL_WIKITEXT, $format = null
188 ) {
189 if ( is_string( $title ) ) {
190 $title = Title::newFromText( $title );
191 }
192
193 $content = ContentHandler::makeContent( $text, $title, $model, $format );
194
195 $rev = new Revision(
196 [
197 'id' => 42,
198 'page' => 23,
199 'title' => $title,
200
201 'content' => $content,
202 'length' => $content->getSize(),
203 'comment' => "testing",
204 'minor_edit' => false,
205
206 'content_format' => $format,
207 ]
208 );
209
210 return $rev;
211 }
212
213 function dataGetContentModel() {
214 // NOTE: we expect the help namespace to always contain wikitext
215 return [
216 [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ],
217 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ],
218 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, "testing" ],
219 ];
220 }
221
222 /**
223 * @group Database
224 * @dataProvider dataGetContentModel
225 * @covers Revision::getContentModel
226 */
227 public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) {
228 $rev = $this->newTestRevision( $text, $title, $model, $format );
229
230 $this->assertEquals( $expectedModel, $rev->getContentModel() );
231 }
232
233 function dataGetContentFormat() {
234 // NOTE: we expect the help namespace to always contain wikitext
235 return [
236 [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ],
237 [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ],
238 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ],
239 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, "testing" ],
240 ];
241 }
242
243 /**
244 * @group Database
245 * @dataProvider dataGetContentFormat
246 * @covers Revision::getContentFormat
247 */
248 public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) {
249 $rev = $this->newTestRevision( $text, $title, $model, $format );
250
251 $this->assertEquals( $expectedFormat, $rev->getContentFormat() );
252 }
253
254 function dataGetContentHandler() {
255 // NOTE: we expect the help namespace to always contain wikitext
256 return [
257 [ 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ],
258 [ 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ],
259 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, 'DummyContentHandlerForTesting' ],
260 ];
261 }
262
263 /**
264 * @group Database
265 * @dataProvider dataGetContentHandler
266 * @covers Revision::getContentHandler
267 */
268 public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) {
269 $rev = $this->newTestRevision( $text, $title, $model, $format );
270
271 $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) );
272 }
273
274 function dataGetContent() {
275 // NOTE: we expect the help namespace to always contain wikitext
276 return [
277 [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ],
278 [
279 serialize( 'hello world' ),
280 'Hello',
281 "testing",
282 null,
283 Revision::FOR_PUBLIC,
284 serialize( 'hello world' )
285 ],
286 [
287 serialize( 'hello world' ),
288 'Dummy:Hello',
289 null,
290 null,
291 Revision::FOR_PUBLIC,
292 serialize( 'hello world' )
293 ],
294 ];
295 }
296
297 /**
298 * @group Database
299 * @dataProvider dataGetContent
300 * @covers Revision::getContent
301 */
302 public function testGetContent( $text, $title, $model, $format,
303 $audience, $expectedSerialization
304 ) {
305 $rev = $this->newTestRevision( $text, $title, $model, $format );
306 $content = $rev->getContent( $audience );
307
308 $this->assertEquals(
309 $expectedSerialization,
310 is_null( $content ) ? null : $content->serialize( $format )
311 );
312 }
313
314 public function dataGetSize() {
315 return [
316 [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ],
317 [ serialize( "hello world." ), "testing", 12 ],
318 ];
319 }
320
321 /**
322 * @covers Revision::getSize
323 * @group Database
324 * @dataProvider dataGetSize
325 */
326 public function testGetSize( $text, $model, $expected_size ) {
327 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model );
328 $this->assertEquals( $expected_size, $rev->getSize() );
329 }
330
331 public function dataGetSha1() {
332 return [
333 [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ],
334 [
335 serialize( "hello world." ),
336 "testing",
337 Revision::base36Sha1( serialize( "hello world." ) )
338 ],
339 ];
340 }
341
342 /**
343 * @covers Revision::getSha1
344 * @group Database
345 * @dataProvider dataGetSha1
346 */
347 public function testGetSha1( $text, $model, $expected_hash ) {
348 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model );
349 $this->assertEquals( $expected_hash, $rev->getSha1() );
350 }
351
352 /**
353 * @covers Revision::__construct
354 */
355 public function testConstructWithText() {
356 $rev = new Revision( [
357 'text' => 'hello world.',
358 'content_model' => CONTENT_MODEL_JAVASCRIPT
359 ] );
360
361 $this->assertNotNull( $rev->getContent(), 'no content object available' );
362 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
363 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
364 }
365
366 /**
367 * @covers Revision::__construct
368 */
369 public function testConstructWithContent() {
370 $title = Title::newFromText( 'RevisionTest_testConstructWithContent' );
371
372 $rev = new Revision( [
373 'content' => ContentHandler::makeContent( 'hello world.', $title, CONTENT_MODEL_JAVASCRIPT ),
374 ] );
375
376 $this->assertNotNull( $rev->getContent(), 'no content object available' );
377 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
378 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
379 }
380
381 /**
382 * Tests whether $rev->getContent() returns a clone when needed.
383 *
384 * @group Database
385 * @covers Revision::getContent
386 */
387 public function testGetContentClone() {
388 $content = new RevisionTestModifyableContent( "foo" );
389
390 $rev = new Revision(
391 [
392 'id' => 42,
393 'page' => 23,
394 'title' => Title::newFromText( "testGetContentClone_dummy" ),
395
396 'content' => $content,
397 'length' => $content->getSize(),
398 'comment' => "testing",
399 'minor_edit' => false,
400 ]
401 );
402
403 $content = $rev->getContent( Revision::RAW );
404 $content->setText( "bar" );
405
406 $content2 = $rev->getContent( Revision::RAW );
407 // content is mutable, expect clone
408 $this->assertNotSame( $content, $content2, "expected a clone" );
409 // clone should contain the original text
410 $this->assertEquals( "foo", $content2->getText() );
411
412 $content2->setText( "bla bla" );
413 $this->assertEquals( "bar", $content->getText() ); // clones should be independent
414 }
415
416 /**
417 * Tests whether $rev->getContent() returns the same object repeatedly if appropriate.
418 *
419 * @group Database
420 * @covers Revision::getContent
421 */
422 public function testGetContentUncloned() {
423 $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT );
424 $content = $rev->getContent( Revision::RAW );
425 $content2 = $rev->getContent( Revision::RAW );
426
427 // for immutable content like wikitext, this should be the same object
428 $this->assertSame( $content, $content2 );
429 }
430 }
431
432 class RevisionTestModifyableContent extends TextContent {
433 public function __construct( $text ) {
434 parent::__construct( $text, "RevisionTestModifyableContent" );
435 }
436
437 public function copy() {
438 return new RevisionTestModifyableContent( $this->mText );
439 }
440
441 public function getText() {
442 return $this->mText;
443 }
444
445 public function setText( $text ) {
446 $this->mText = $text;
447 }
448 }
449
450 class RevisionTestModifyableContentHandler extends TextContentHandler {
451
452 public function __construct() {
453 parent::__construct( "RevisionTestModifyableContent", [ CONTENT_FORMAT_TEXT ] );
454 }
455
456 public function unserializeContent( $text, $format = null ) {
457 $this->checkFormat( $format );
458
459 return new RevisionTestModifyableContent( $text );
460 }
461
462 public function makeEmptyContent() {
463 return new RevisionTestModifyableContent( '' );
464 }
465 }