RevisionUnitTest for fetchFromConds
[lhc/web/wiklou.git] / tests / phpunit / includes / RevisionUnitTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * @group ContentHandler
7 */
8 class RevisionUnitTest extends MediaWikiTestCase {
9
10 public function provideConstructFromArray() {
11 yield 'with text' => [
12 [
13 'text' => 'hello world.',
14 'content_model' => CONTENT_MODEL_JAVASCRIPT
15 ],
16 ];
17 yield 'with content' => [
18 [
19 'content' => new JavaScriptContent( 'hellow world.' )
20 ],
21 ];
22 }
23
24 /**
25 * @dataProvider provideConstructFromArray
26 */
27 public function testConstructFromArray( $rowArray ) {
28 $rev = new Revision( $rowArray );
29 $this->assertNotNull( $rev->getContent(), 'no content object available' );
30 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
31 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
32 }
33
34 public function provideConstructFromArrayThrowsExceptions() {
35 yield 'content and text_id both not empty' => [
36 [
37 'content' => new WikitextContent( 'GOAT' ),
38 'text_id' => 'someid',
39 ],
40 new MWException( "Text already stored in external store (id someid), " .
41 "can't serialize content object" )
42 ];
43 yield 'with bad content object (class)' => [
44 [ 'content' => new stdClass() ],
45 new MWException( '`content` field must contain a Content object.' )
46 ];
47 yield 'with bad content object (string)' => [
48 [ 'content' => 'ImAGoat' ],
49 new MWException( '`content` field must contain a Content object.' )
50 ];
51 yield 'bad row format' => [
52 'imastring, not a row',
53 new MWException( 'Revision constructor passed invalid row format.' )
54 ];
55 }
56
57 /**
58 * @dataProvider provideConstructFromArrayThrowsExceptions
59 */
60 public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) {
61 $this->setExpectedException(
62 get_class( $expectedException ),
63 $expectedException->getMessage(),
64 $expectedException->getCode()
65 );
66 new Revision( $rowArray );
67 }
68
69 public function provideGetRevisionText() {
70 yield 'Generic test' => [
71 'This is a goat of revision text.',
72 [
73 'old_flags' => '',
74 'old_text' => 'This is a goat of revision text.',
75 ],
76 ];
77 }
78
79 public function provideGetId() {
80 yield [
81 [],
82 null
83 ];
84 yield [
85 [ 'id' => 998 ],
86 998
87 ];
88 }
89
90 /**
91 * @dataProvider provideGetId
92 * @covers Revision::getId
93 */
94 public function testGetId( $rowArray, $expectedId ) {
95 $rev = new Revision( $rowArray );
96 $this->assertEquals( $expectedId, $rev->getId() );
97 }
98
99 public function provideSetId() {
100 yield [ '123', 123 ];
101 yield [ 456, 456 ];
102 }
103
104 /**
105 * @dataProvider provideSetId
106 * @covers Revision::setId
107 */
108 public function testSetId( $input, $expected ) {
109 $rev = new Revision( [] );
110 $rev->setId( $input );
111 $this->assertSame( $expected, $rev->getId() );
112 }
113
114 public function provideSetUserIdAndName() {
115 yield [ '123', 123, 'GOaT' ];
116 yield [ 456, 456, 'GOaT' ];
117 }
118
119 /**
120 * @dataProvider provideSetUserIdAndName
121 * @covers Revision::setUserIdAndName
122 */
123 public function testSetUserIdAndName( $inputId, $expectedId, $name ) {
124 $rev = new Revision( [] );
125 $rev->setUserIdAndName( $inputId, $name );
126 $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) );
127 $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) );
128 }
129
130 public function provideGetTextId() {
131 yield [ [], null ];
132 yield [ [ 'text_id' => '123' ], 123 ];
133 yield [ [ 'text_id' => 456 ], 456 ];
134 }
135
136 /**
137 * @dataProvider provideGetTextId
138 * @covers Revision::getTextId()
139 */
140 public function testGetTextId( $rowArray, $expected ) {
141 $rev = new Revision( $rowArray );
142 $this->assertSame( $expected, $rev->getTextId() );
143 }
144
145 public function provideGetParentId() {
146 yield [ [], null ];
147 yield [ [ 'parent_id' => '123' ], 123 ];
148 yield [ [ 'parent_id' => 456 ], 456 ];
149 }
150
151 /**
152 * @dataProvider provideGetParentId
153 * @covers Revision::getParentId()
154 */
155 public function testGetParentId( $rowArray, $expected ) {
156 $rev = new Revision( $rowArray );
157 $this->assertSame( $expected, $rev->getParentId() );
158 }
159
160 /**
161 * @covers Revision::getRevisionText
162 * @dataProvider provideGetRevisionText
163 */
164 public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) {
165 $this->assertEquals(
166 $expected,
167 Revision::getRevisionText( (object)$rowData, $prefix, $wiki ) );
168 }
169
170 public function provideGetRevisionTextWithZlibExtension() {
171 yield 'Generic gzip test' => [
172 'This is a small goat of revision text.',
173 [
174 'old_flags' => 'gzip',
175 'old_text' => gzdeflate( 'This is a small goat of revision text.' ),
176 ],
177 ];
178 }
179
180 /**
181 * @covers Revision::getRevisionText
182 * @dataProvider provideGetRevisionTextWithZlibExtension
183 */
184 public function testGetRevisionWithZlibExtension( $expected, $rowData ) {
185 $this->checkPHPExtension( 'zlib' );
186 $this->testGetRevisionText( $expected, $rowData );
187 }
188
189 public function provideGetRevisionTextWithLegacyEncoding() {
190 yield 'Utf8Native' => [
191 "Wiki est l'\xc3\xa9cole superieur !",
192 'iso-8859-1',
193 [
194 'old_flags' => 'utf-8',
195 'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
196 ]
197 ];
198 yield 'Utf8Legacy' => [
199 "Wiki est l'\xc3\xa9cole superieur !",
200 'iso-8859-1',
201 [
202 'old_flags' => '',
203 'old_text' => "Wiki est l'\xe9cole superieur !",
204 ]
205 ];
206 }
207
208 /**
209 * @covers Revision::getRevisionText
210 * @dataProvider provideGetRevisionTextWithLegacyEncoding
211 */
212 public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $rowData ) {
213 $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
214 $this->testGetRevisionText( $expected, $rowData );
215 }
216
217 public function provideGetRevisionTextWithGzipAndLegacyEncoding() {
218 /**
219 * WARNING!
220 * Do not set the external flag!
221 * Otherwise, getRevisionText will hit the live database (if ExternalStore is enabled)!
222 */
223 yield 'Utf8NativeGzip' => [
224 "Wiki est l'\xc3\xa9cole superieur !",
225 'iso-8859-1',
226 [
227 'old_flags' => 'gzip,utf-8',
228 'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
229 ]
230 ];
231 yield 'Utf8LegacyGzip' => [
232 "Wiki est l'\xc3\xa9cole superieur !",
233 'iso-8859-1',
234 [
235 'old_flags' => 'gzip',
236 'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
237 ]
238 ];
239 }
240
241 /**
242 * @covers Revision::getRevisionText
243 * @dataProvider provideGetRevisionTextWithGzipAndLegacyEncoding
244 */
245 public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $rowData ) {
246 $this->checkPHPExtension( 'zlib' );
247 $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
248 $this->testGetRevisionText( $expected, $rowData );
249 }
250
251 /**
252 * @covers Revision::compressRevisionText
253 */
254 public function testCompressRevisionTextUtf8() {
255 $row = new stdClass;
256 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
257 $row->old_flags = Revision::compressRevisionText( $row->old_text );
258 $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
259 "Flags should contain 'utf-8'" );
260 $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ),
261 "Flags should not contain 'gzip'" );
262 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
263 $row->old_text, "Direct check" );
264 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
265 Revision::getRevisionText( $row ), "getRevisionText" );
266 }
267
268 /**
269 * @covers Revision::compressRevisionText
270 */
271 public function testCompressRevisionTextUtf8Gzip() {
272 $this->checkPHPExtension( 'zlib' );
273 $this->setMwGlobals( 'wgCompressRevisions', true );
274
275 $row = new stdClass;
276 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
277 $row->old_flags = Revision::compressRevisionText( $row->old_text );
278 $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
279 "Flags should contain 'utf-8'" );
280 $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ),
281 "Flags should contain 'gzip'" );
282 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
283 gzinflate( $row->old_text ), "Direct check" );
284 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
285 Revision::getRevisionText( $row ), "getRevisionText" );
286 }
287
288 /**
289 * @covers Revision::userJoinCond
290 */
291 public function testUserJoinCond() {
292 $this->assertEquals(
293 [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ],
294 Revision::userJoinCond()
295 );
296 }
297
298 /**
299 * @covers Revision::pageJoinCond
300 */
301 public function testPageJoinCond() {
302 $this->assertEquals(
303 [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
304 Revision::pageJoinCond()
305 );
306 }
307
308 public function provideSelectFields() {
309 yield [
310 true,
311 [
312 'rev_id',
313 'rev_page',
314 'rev_text_id',
315 'rev_timestamp',
316 'rev_user_text',
317 'rev_user',
318 'rev_minor_edit',
319 'rev_deleted',
320 'rev_len',
321 'rev_parent_id',
322 'rev_sha1',
323 'rev_comment_text' => 'rev_comment',
324 'rev_comment_data' => 'NULL',
325 'rev_comment_cid' => 'NULL',
326 'rev_content_format',
327 'rev_content_model',
328 ]
329 ];
330 yield [
331 false,
332 [
333 'rev_id',
334 'rev_page',
335 'rev_text_id',
336 'rev_timestamp',
337 'rev_user_text',
338 'rev_user',
339 'rev_minor_edit',
340 'rev_deleted',
341 'rev_len',
342 'rev_parent_id',
343 'rev_sha1',
344 'rev_comment_text' => 'rev_comment',
345 'rev_comment_data' => 'NULL',
346 'rev_comment_cid' => 'NULL',
347 ]
348 ];
349 }
350
351 /**
352 * @dataProvider provideSelectFields
353 * @covers Revision::selectFields
354 * @todo a true unit test would mock CommentStore
355 */
356 public function testSelectFields( $contentHandlerUseDB, $expected ) {
357 $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
358 $this->assertEquals( $expected, Revision::selectFields() );
359 }
360
361 public function provideSelectArchiveFields() {
362 yield [
363 true,
364 [
365 'ar_id',
366 'ar_page_id',
367 'ar_rev_id',
368 'ar_text',
369 'ar_text_id',
370 'ar_timestamp',
371 'ar_user_text',
372 'ar_user',
373 'ar_minor_edit',
374 'ar_deleted',
375 'ar_len',
376 'ar_parent_id',
377 'ar_sha1',
378 'ar_comment_text' => 'ar_comment',
379 'ar_comment_data' => 'NULL',
380 'ar_comment_cid' => 'NULL',
381 'ar_content_format',
382 'ar_content_model',
383 ]
384 ];
385 yield [
386 false,
387 [
388 'ar_id',
389 'ar_page_id',
390 'ar_rev_id',
391 'ar_text',
392 'ar_text_id',
393 'ar_timestamp',
394 'ar_user_text',
395 'ar_user',
396 'ar_minor_edit',
397 'ar_deleted',
398 'ar_len',
399 'ar_parent_id',
400 'ar_sha1',
401 'ar_comment_text' => 'ar_comment',
402 'ar_comment_data' => 'NULL',
403 'ar_comment_cid' => 'NULL',
404 ]
405 ];
406 }
407
408 /**
409 * @dataProvider provideSelectArchiveFields
410 * @covers Revision::selectArchiveFields
411 * @todo a true unit test would mock CommentStore
412 */
413 public function testSelectArchiveFields( $contentHandlerUseDB, $expected ) {
414 $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
415 $this->assertEquals( $expected, Revision::selectArchiveFields() );
416 }
417
418 /**
419 * @covers Revision::selectTextFields
420 */
421 public function testSelectTextFields() {
422 $this->assertEquals(
423 [
424 'old_text',
425 'old_flags',
426 ],
427 Revision::selectTextFields()
428 );
429 }
430
431 /**
432 * @covers Revision::selectPageFields
433 */
434 public function testSelectPageFields() {
435 $this->assertEquals(
436 [
437 'page_namespace',
438 'page_title',
439 'page_id',
440 'page_latest',
441 'page_is_redirect',
442 'page_len',
443 ],
444 Revision::selectPageFields()
445 );
446 }
447
448 /**
449 * @covers Revision::selectUserFields
450 */
451 public function testSelectUserFields() {
452 $this->assertEquals(
453 [
454 'user_name',
455 ],
456 Revision::selectUserFields()
457 );
458 }
459
460 public function provideFetchFromConds() {
461 yield [ 0, [] ];
462 yield [ Revision::READ_LOCKING, [ 'FOR UPDATE' ] ];
463 }
464
465 /**
466 * @dataProvider provideFetchFromConds
467 * @covers Revision::fetchFromConds
468 */
469 public function testFetchFromConds( $flags, array $options ) {
470 $conditions = [ 'conditionsArray' ];
471
472 $db = $this->getMock( IDatabase::class );
473 $db->expects( $this->once() )
474 ->method( 'selectRow' )
475 ->with(
476 $this->equalTo( [ 'revision', 'page', 'user' ] ),
477 // We don't really care about the fields are they come from the selectField methods
478 $this->isType( 'array' ),
479 $this->equalTo( $conditions ),
480 // Method name
481 $this->equalTo( 'Revision::fetchFromConds' ),
482 $this->equalTo( $options ),
483 // We don't really care about the join conds are they come from the joinCond methods
484 $this->isType( 'array' )
485 )
486 ->willReturn( 'RETURNVALUE' );
487
488 $wrapper = TestingAccessWrapper::newFromClass( Revision::class );
489 $result = $wrapper->fetchFromConds( $db, $conditions, $flags );
490
491 $this->assertEquals( 'RETURNVALUE', $result );
492 }
493 }