Merge "Revert "Log the reason why revision->getContent() returns null""
[lhc/web/wiklou.git] / tests / phpunit / includes / Storage / RevisionStoreRecordTest.php
1 <?php
2
3 namespace MediaWiki\Tests\Storage;
4
5 use CommentStoreComment;
6 use InvalidArgumentException;
7 use LogicException;
8 use MediaWiki\Storage\RevisionRecord;
9 use MediaWiki\Storage\RevisionSlots;
10 use MediaWiki\Storage\RevisionStoreRecord;
11 use MediaWiki\Storage\SlotRecord;
12 use MediaWiki\Storage\SuppressedDataException;
13 use MediaWiki\User\UserIdentity;
14 use MediaWiki\User\UserIdentityValue;
15 use MediaWikiTestCase;
16 use TextContent;
17 use Title;
18
19 /**
20 * @covers \MediaWiki\Storage\RevisionStoreRecord
21 */
22 class RevisionStoreRecordTest extends MediaWikiTestCase {
23
24 /**
25 * @param array $rowOverrides
26 *
27 * @return RevisionStoreRecord
28 */
29 public function newRevision( array $rowOverrides = [] ) {
30 $title = Title::newFromText( 'Dummy' );
31 $title->resetArticleID( 17 );
32
33 $user = new UserIdentityValue( 11, 'Tester', 0 );
34 $comment = CommentStoreComment::newUnsavedComment( 'Hello World' );
35
36 $main = SlotRecord::newUnsaved( 'main', new TextContent( 'Lorem Ipsum' ) );
37 $aux = SlotRecord::newUnsaved( 'aux', new TextContent( 'Frumious Bandersnatch' ) );
38 $slots = new RevisionSlots( [ $main, $aux ] );
39
40 $row = [
41 'rev_id' => '7',
42 'rev_page' => strval( $title->getArticleID() ),
43 'rev_timestamp' => '20200101000000',
44 'rev_deleted' => 0,
45 'rev_minor_edit' => 0,
46 'rev_parent_id' => '5',
47 'rev_len' => $slots->computeSize(),
48 'rev_sha1' => $slots->computeSha1(),
49 'page_latest' => '18',
50 ];
51
52 $row = array_merge( $row, $rowOverrides );
53
54 return new RevisionStoreRecord( $title, $user, $comment, (object)$row, $slots );
55 }
56
57 public function provideConstructor() {
58 $title = Title::newFromText( 'Dummy' );
59 $title->resetArticleID( 17 );
60
61 $user = new UserIdentityValue( 11, 'Tester', 0 );
62 $comment = CommentStoreComment::newUnsavedComment( 'Hello World' );
63
64 $main = SlotRecord::newUnsaved( 'main', new TextContent( 'Lorem Ipsum' ) );
65 $aux = SlotRecord::newUnsaved( 'aux', new TextContent( 'Frumious Bandersnatch' ) );
66 $slots = new RevisionSlots( [ $main, $aux ] );
67
68 $protoRow = [
69 'rev_id' => '7',
70 'rev_page' => strval( $title->getArticleID() ),
71 'rev_timestamp' => '20200101000000',
72 'rev_deleted' => 0,
73 'rev_minor_edit' => 0,
74 'rev_parent_id' => '5',
75 'rev_len' => $slots->computeSize(),
76 'rev_sha1' => $slots->computeSha1(),
77 'page_latest' => '18',
78 ];
79
80 $row = $protoRow;
81 yield 'all info' => [
82 $title,
83 $user,
84 $comment,
85 (object)$row,
86 $slots,
87 'acmewiki'
88 ];
89
90 $row = $protoRow;
91 $row['rev_minor_edit'] = '1';
92 $row['rev_deleted'] = strval( RevisionRecord::DELETED_USER );
93
94 yield 'minor deleted' => [
95 $title,
96 $user,
97 $comment,
98 (object)$row,
99 $slots
100 ];
101
102 $row = $protoRow;
103 $row['page_latest'] = $row['rev_id'];
104
105 yield 'latest' => [
106 $title,
107 $user,
108 $comment,
109 (object)$row,
110 $slots
111 ];
112
113 $row = $protoRow;
114 unset( $row['rev_parent'] );
115
116 yield 'no parent' => [
117 $title,
118 $user,
119 $comment,
120 (object)$row,
121 $slots
122 ];
123
124 $row = $protoRow;
125 unset( $row['rev_len'] );
126 unset( $row['rev_sha1'] );
127
128 yield 'no length, no hash' => [
129 $title,
130 $user,
131 $comment,
132 (object)$row,
133 $slots
134 ];
135
136 $row = $protoRow;
137 yield 'no length, no hash' => [
138 Title::newFromText( 'DummyDoesNotExist' ),
139 $user,
140 $comment,
141 (object)$row,
142 $slots
143 ];
144 }
145
146 /**
147 * @dataProvider provideConstructor
148 *
149 * @param Title $title
150 * @param UserIdentity $user
151 * @param CommentStoreComment $comment
152 * @param object $row
153 * @param RevisionSlots $slots
154 * @param bool $wikiId
155 */
156 public function testConstructorAndGetters(
157 Title $title,
158 UserIdentity $user,
159 CommentStoreComment $comment,
160 $row,
161 RevisionSlots $slots,
162 $wikiId = false
163 ) {
164 $rec = new RevisionStoreRecord( $title, $user, $comment, $row, $slots, $wikiId );
165
166 $this->assertSame( $title, $rec->getPageAsLinkTarget(), 'getPageAsLinkTarget' );
167 $this->assertSame( $user, $rec->getUser( RevisionRecord::RAW ), 'getUser' );
168 $this->assertSame( $comment, $rec->getComment(), 'getComment' );
169
170 $this->assertSame( $slots->getSlotRoles(), $rec->getSlotRoles(), 'getSlotRoles' );
171 $this->assertSame( $wikiId, $rec->getWikiId(), 'getWikiId' );
172
173 $this->assertSame( (int)$row->rev_id, $rec->getId(), 'getId' );
174 $this->assertSame( (int)$row->rev_page, $rec->getPageId(), 'getId' );
175 $this->assertSame( $row->rev_timestamp, $rec->getTimestamp(), 'getTimestamp' );
176 $this->assertSame( (int)$row->rev_deleted, $rec->getVisibility(), 'getVisibility' );
177 $this->assertSame( (bool)$row->rev_minor_edit, $rec->isMinor(), 'getIsMinor' );
178
179 if ( isset( $row->rev_parent_id ) ) {
180 $this->assertSame( (int)$row->rev_parent_id, $rec->getParentId(), 'getParentId' );
181 } else {
182 $this->assertSame( 0, $rec->getParentId(), 'getParentId' );
183 }
184
185 if ( isset( $row->rev_len ) ) {
186 $this->assertSame( (int)$row->rev_len, $rec->getSize(), 'getSize' );
187 } else {
188 $this->assertSame( $slots->computeSize(), $rec->getSize(), 'getSize' );
189 }
190
191 if ( isset( $row->rev_sha1 ) ) {
192 $this->assertSame( $row->rev_sha1, $rec->getSha1(), 'getSha1' );
193 } else {
194 $this->assertSame( $slots->computeSha1(), $rec->getSha1(), 'getSha1' );
195 }
196
197 if ( isset( $row->page_latest ) ) {
198 $this->assertSame(
199 (int)$row->rev_id === (int)$row->page_latest,
200 $rec->isCurrent(),
201 'isCurrent'
202 );
203 } else {
204 $this->assertSame(
205 false,
206 $rec->isCurrent(),
207 'isCurrent'
208 );
209 }
210 }
211
212 public function provideConstructorFailure() {
213 $title = Title::newFromText( 'Dummy' );
214 $title->resetArticleID( 17 );
215
216 $user = new UserIdentityValue( 11, 'Tester', 0 );
217
218 $comment = CommentStoreComment::newUnsavedComment( 'Hello World' );
219
220 $main = SlotRecord::newUnsaved( 'main', new TextContent( 'Lorem Ipsum' ) );
221 $aux = SlotRecord::newUnsaved( 'aux', new TextContent( 'Frumious Bandersnatch' ) );
222 $slots = new RevisionSlots( [ $main, $aux ] );
223
224 $protoRow = [
225 'rev_id' => '7',
226 'rev_page' => strval( $title->getArticleID() ),
227 'rev_timestamp' => '20200101000000',
228 'rev_deleted' => 0,
229 'rev_minor_edit' => 0,
230 'rev_parent_id' => '5',
231 'rev_len' => $slots->computeSize(),
232 'rev_sha1' => $slots->computeSha1(),
233 'page_latest' => '18',
234 ];
235
236 yield 'not a row' => [
237 $title,
238 $user,
239 $comment,
240 'not a row',
241 $slots,
242 'acmewiki'
243 ];
244
245 $row = $protoRow;
246 $row['rev_timestamp'] = 'kittens';
247
248 yield 'bad timestamp' => [
249 $title,
250 $user,
251 $comment,
252 (object)$row,
253 $slots
254 ];
255
256 $row = $protoRow;
257 $row['rev_page'] = 99;
258
259 yield 'page ID mismatch' => [
260 $title,
261 $user,
262 $comment,
263 (object)$row,
264 $slots
265 ];
266
267 $row = $protoRow;
268
269 yield 'bad wiki' => [
270 $title,
271 $user,
272 $comment,
273 (object)$row,
274 $slots,
275 12345
276 ];
277 }
278
279 /**
280 * @dataProvider provideConstructorFailure
281 *
282 * @param Title $title
283 * @param UserIdentity $user
284 * @param CommentStoreComment $comment
285 * @param object $row
286 * @param RevisionSlots $slots
287 * @param bool $wikiId
288 */
289 public function testConstructorFailure(
290 Title $title,
291 UserIdentity $user,
292 CommentStoreComment $comment,
293 $row,
294 RevisionSlots $slots,
295 $wikiId = false
296 ) {
297 $this->setExpectedException( InvalidArgumentException::class );
298 new RevisionStoreRecord( $title, $user, $comment, $row, $slots, $wikiId );
299 }
300
301 private function provideAudienceCheckData( $field ) {
302 yield 'field accessible for oversighter (ALL)' => [
303 RevisionRecord::SUPPRESSED_ALL,
304 [ 'oversight' ],
305 true,
306 false
307 ];
308
309 yield 'field accessible for oversighter' => [
310 RevisionRecord::DELETED_RESTRICTED | $field,
311 [ 'oversight' ],
312 true,
313 false
314 ];
315
316 yield 'field not accessible for sysops (ALL)' => [
317 RevisionRecord::SUPPRESSED_ALL,
318 [ 'sysop' ],
319 false,
320 false
321 ];
322
323 yield 'field not accessible for sysops' => [
324 RevisionRecord::DELETED_RESTRICTED | $field,
325 [ 'sysop' ],
326 false,
327 false
328 ];
329
330 yield 'field accessible for sysops' => [
331 $field,
332 [ 'sysop' ],
333 true,
334 false
335 ];
336
337 yield 'field suppressed for logged in users' => [
338 $field,
339 [ 'user' ],
340 false,
341 false
342 ];
343
344 yield 'unrelated field suppressed' => [
345 $field === RevisionRecord::DELETED_COMMENT
346 ? RevisionRecord::DELETED_USER
347 : RevisionRecord::DELETED_COMMENT,
348 [ 'user' ],
349 true,
350 true
351 ];
352
353 yield 'nothing suppressed' => [
354 0,
355 [ 'user' ],
356 true,
357 true
358 ];
359 }
360
361 public function testSerialization_fails() {
362 $this->setExpectedException( LogicException::class );
363 $rev = $this->newRevision();
364 serialize( $rev );
365 }
366
367 public function provideGetComment_audience() {
368 return $this->provideAudienceCheckData( RevisionRecord::DELETED_COMMENT );
369 }
370
371 private function forceStandardPermissions() {
372 $this->setMwGlobals(
373 'wgGroupPermissions',
374 [
375 'user' => [
376 'viewsuppressed' => false,
377 'suppressrevision' => false,
378 'deletedtext' => false,
379 'deletedhistory' => false,
380 ],
381 'sysop' => [
382 'viewsuppressed' => false,
383 'suppressrevision' => false,
384 'deletedtext' => true,
385 'deletedhistory' => true,
386 ],
387 'oversight' => [
388 'deletedtext' => true,
389 'deletedhistory' => true,
390 'viewsuppressed' => true,
391 'suppressrevision' => true,
392 ],
393 ]
394 );
395 }
396
397 /**
398 * @dataProvider provideGetComment_audience
399 */
400 public function testGetComment_audience( $visibility, $groups, $userCan, $publicCan ) {
401 $this->forceStandardPermissions();
402
403 $user = $this->getTestUser( $groups )->getUser();
404 $rev = $this->newRevision( [ 'rev_deleted' => $visibility ] );
405
406 $this->assertNotNull( $rev->getComment( RevisionRecord::RAW ), 'raw can' );
407
408 $this->assertSame(
409 $publicCan,
410 $rev->getComment( RevisionRecord::FOR_PUBLIC ) !== null,
411 'public can'
412 );
413 $this->assertSame(
414 $userCan,
415 $rev->getComment( RevisionRecord::FOR_THIS_USER, $user ) !== null,
416 'user can'
417 );
418 }
419
420 public function provideGetUser_audience() {
421 return $this->provideAudienceCheckData( RevisionRecord::DELETED_USER );
422 }
423
424 /**
425 * @dataProvider provideGetUser_audience
426 */
427 public function testGetUser_audience( $visibility, $groups, $userCan, $publicCan ) {
428 $this->forceStandardPermissions();
429
430 $user = $this->getTestUser( $groups )->getUser();
431 $rev = $this->newRevision( [ 'rev_deleted' => $visibility ] );
432
433 $this->assertNotNull( $rev->getUser( RevisionRecord::RAW ), 'raw can' );
434
435 $this->assertSame(
436 $publicCan,
437 $rev->getUser( RevisionRecord::FOR_PUBLIC ) !== null,
438 'public can'
439 );
440 $this->assertSame(
441 $userCan,
442 $rev->getUser( RevisionRecord::FOR_THIS_USER, $user ) !== null,
443 'user can'
444 );
445 }
446
447 public function provideGetSlot_audience() {
448 return $this->provideAudienceCheckData( RevisionRecord::DELETED_TEXT );
449 }
450
451 /**
452 * @dataProvider provideGetSlot_audience
453 */
454 public function testGetSlot_audience( $visibility, $groups, $userCan, $publicCan ) {
455 $this->forceStandardPermissions();
456
457 $user = $this->getTestUser( $groups )->getUser();
458 $rev = $this->newRevision( [ 'rev_deleted' => $visibility ] );
459
460 // NOTE: slot meta-data is never suppressed, just the content is!
461 $this->assertTrue( $rev->hasSlot( 'main' ), 'hasSlot is never suppressed' );
462 $this->assertNotNull( $rev->getSlot( 'main', RevisionRecord::RAW ), 'raw meta' );
463 $this->assertNotNull( $rev->getSlot( 'main', RevisionRecord::FOR_PUBLIC ), 'public meta' );
464
465 $this->assertNotNull(
466 $rev->getSlot( 'main', RevisionRecord::FOR_THIS_USER, $user ),
467 'user can'
468 );
469
470 try {
471 $rev->getSlot( 'main', RevisionRecord::FOR_PUBLIC )->getContent();
472 $exception = null;
473 } catch ( SuppressedDataException $ex ) {
474 $exception = $ex;
475 }
476
477 $this->assertSame(
478 $publicCan,
479 $exception === null,
480 'public can'
481 );
482
483 try {
484 $rev->getSlot( 'main', RevisionRecord::FOR_THIS_USER, $user )->getContent();
485 $exception = null;
486 } catch ( SuppressedDataException $ex ) {
487 $exception = $ex;
488 }
489
490 $this->assertSame(
491 $userCan,
492 $exception === null,
493 'user can'
494 );
495 }
496
497 public function provideGetSlot_audience_latest() {
498 return $this->provideAudienceCheckData( RevisionRecord::DELETED_TEXT );
499 }
500
501 /**
502 * @dataProvider provideGetSlot_audience_latest
503 */
504 public function testGetSlot_audience_latest( $visibility, $groups, $userCan, $publicCan ) {
505 $this->forceStandardPermissions();
506
507 $user = $this->getTestUser( $groups )->getUser();
508 $rev = $this->newRevision(
509 [
510 'rev_deleted' => $visibility,
511 'rev_id' => 11,
512 'page_latest' => 11, // revision is current
513 ]
514 );
515
516 // sanity check
517 $this->assertTrue( $rev->isCurrent(), 'isCurrent()' );
518
519 // NOTE: slot meta-data is never suppressed, just the content is!
520 $this->assertNotNull( $rev->getSlot( 'main', RevisionRecord::RAW ), 'raw can' );
521 $this->assertNotNull( $rev->getSlot( 'main', RevisionRecord::FOR_PUBLIC ), 'public can' );
522
523 $this->assertNotNull(
524 $rev->getSlot( 'main', RevisionRecord::FOR_THIS_USER, $user ),
525 'user can'
526 );
527
528 // NOTE: the content of the current revision is never suppressed!
529 // Check that getContent() doesn't throw SuppressedDataException
530 $rev->getSlot( 'main', RevisionRecord::RAW )->getContent();
531 $rev->getSlot( 'main', RevisionRecord::FOR_PUBLIC )->getContent();
532 $rev->getSlot( 'main', RevisionRecord::FOR_THIS_USER, $user )->getContent();
533 }
534
535 /**
536 * @dataProvider provideGetSlot_audience
537 */
538 public function testGetContent_audience( $visibility, $groups, $userCan, $publicCan ) {
539 $this->forceStandardPermissions();
540
541 $user = $this->getTestUser( $groups )->getUser();
542 $rev = $this->newRevision( [ 'rev_deleted' => $visibility ] );
543
544 $this->assertNotNull( $rev->getContent( 'main', RevisionRecord::RAW ), 'raw can' );
545
546 $this->assertSame(
547 $publicCan,
548 $rev->getContent( 'main', RevisionRecord::FOR_PUBLIC ) !== null,
549 'public can'
550 );
551 $this->assertSame(
552 $userCan,
553 $rev->getContent( 'main', RevisionRecord::FOR_THIS_USER, $user ) !== null,
554 'user can'
555 );
556 }
557
558 public function testGetSlot() {
559 $rev = $this->newRevision();
560
561 $slot = $rev->getSlot( 'main' );
562 $this->assertNotNull( $slot, 'getSlot()' );
563 $this->assertSame( 'main', $slot->getRole(), 'getRole()' );
564 }
565
566 public function testHasSlot() {
567 $rev = $this->newRevision();
568
569 $this->assertTrue( $rev->hasSlot( 'main' ) );
570 $this->assertFalse( $rev->hasSlot( 'xyz' ) );
571 }
572
573 public function testGetContent() {
574 $rev = $this->newRevision();
575
576 $content = $rev->getSlot( 'main' );
577 $this->assertNotNull( $content, 'getContent()' );
578 $this->assertSame( CONTENT_MODEL_TEXT, $content->getModel(), 'getModel()' );
579 }
580
581 public function provideUserCanBitfield() {
582 yield [ 0, 0, [], null, true ];
583 // Bitfields match, user has no permissions
584 yield [
585 RevisionRecord::DELETED_TEXT,
586 RevisionRecord::DELETED_TEXT,
587 [],
588 null,
589 false
590 ];
591 yield [
592 RevisionRecord::DELETED_COMMENT,
593 RevisionRecord::DELETED_COMMENT,
594 [],
595 null,
596 false,
597 ];
598 yield [
599 RevisionRecord::DELETED_USER,
600 RevisionRecord::DELETED_USER,
601 [],
602 null,
603 false
604 ];
605 yield [
606 RevisionRecord::DELETED_RESTRICTED,
607 RevisionRecord::DELETED_RESTRICTED,
608 [],
609 null,
610 false,
611 ];
612 // Bitfields match, user (admin) does have permissions
613 yield [
614 RevisionRecord::DELETED_TEXT,
615 RevisionRecord::DELETED_TEXT,
616 [ 'sysop' ],
617 null,
618 true,
619 ];
620 yield [
621 RevisionRecord::DELETED_COMMENT,
622 RevisionRecord::DELETED_COMMENT,
623 [ 'sysop' ],
624 null,
625 true,
626 ];
627 yield [
628 RevisionRecord::DELETED_USER,
629 RevisionRecord::DELETED_USER,
630 [ 'sysop' ],
631 null,
632 true,
633 ];
634 // Bitfields match, user (admin) does not have permissions
635 yield [
636 RevisionRecord::DELETED_RESTRICTED,
637 RevisionRecord::DELETED_RESTRICTED,
638 [ 'sysop' ],
639 null,
640 false,
641 ];
642 // Bitfields match, user (oversight) does have permissions
643 yield [
644 RevisionRecord::DELETED_RESTRICTED,
645 RevisionRecord::DELETED_RESTRICTED,
646 [ 'oversight' ],
647 null,
648 true,
649 ];
650 // Check permissions using the title
651 yield [
652 RevisionRecord::DELETED_TEXT,
653 RevisionRecord::DELETED_TEXT,
654 [ 'sysop' ],
655 Title::newFromText( __METHOD__ ),
656 true,
657 ];
658 yield [
659 RevisionRecord::DELETED_TEXT,
660 RevisionRecord::DELETED_TEXT,
661 [],
662 Title::newFromText( __METHOD__ ),
663 false,
664 ];
665 }
666
667 /**
668 * @dataProvider provideUserCanBitfield
669 * @covers \MediaWiki\Storage\RevisionRecord::userCanBitfield
670 */
671 public function testUserCanBitfield( $bitField, $field, $userGroups, $title, $expected ) {
672 $this->forceStandardPermissions();
673
674 $user = $this->getTestUser( $userGroups )->getUser();
675
676 $this->assertSame(
677 $expected,
678 RevisionRecord::userCanBitfield( $bitField, $field, $user, $title )
679 );
680 }
681
682 private function getSlotRecord( $role, $contentString ) {
683 return SlotRecord::newUnsaved( $role, new TextContent( $contentString ) );
684 }
685
686 public function provideHasSameContent() {
687 /**
688 * @param SlotRecord[] $slots
689 * @param int $revId
690 * @return RevisionStoreRecord
691 */
692 $recordCreator = function ( array $slots, $revId ) {
693 $title = Title::newFromText( 'provideHasSameContent' );
694 $title->resetArticleID( 19 );
695 $slots = new RevisionSlots( $slots );
696
697 return new RevisionStoreRecord(
698 $title,
699 new UserIdentityValue( 11, __METHOD__, 0 ),
700 CommentStoreComment::newUnsavedComment( __METHOD__ ),
701 (object)[
702 'rev_id' => strval( $revId ),
703 'rev_page' => strval( $title->getArticleID() ),
704 'rev_timestamp' => '20200101000000',
705 'rev_deleted' => 0,
706 'rev_minor_edit' => 0,
707 'rev_parent_id' => '5',
708 'rev_len' => $slots->computeSize(),
709 'rev_sha1' => $slots->computeSha1(),
710 'page_latest' => '18',
711 ],
712 $slots
713 );
714 };
715
716 // Create some slots with content
717 $mainA = SlotRecord::newUnsaved( 'main', new TextContent( 'A' ) );
718 $mainB = SlotRecord::newUnsaved( 'main', new TextContent( 'B' ) );
719 $auxA = SlotRecord::newUnsaved( 'aux', new TextContent( 'A' ) );
720 $auxB = SlotRecord::newUnsaved( 'aux', new TextContent( 'A' ) );
721
722 $initialRecord = $recordCreator( [ $mainA ], 12 );
723
724 return [
725 'same record object' => [
726 true,
727 $initialRecord,
728 $initialRecord,
729 ],
730 'same record content, different object' => [
731 true,
732 $recordCreator( [ $mainA ], 12 ),
733 $recordCreator( [ $mainA ], 13 ),
734 ],
735 'same record content, aux slot, different object' => [
736 true,
737 $recordCreator( [ $auxA ], 12 ),
738 $recordCreator( [ $auxB ], 13 ),
739 ],
740 'different content' => [
741 false,
742 $recordCreator( [ $mainA ], 12 ),
743 $recordCreator( [ $mainB ], 13 ),
744 ],
745 'different content and number of slots' => [
746 false,
747 $recordCreator( [ $mainA ], 12 ),
748 $recordCreator( [ $mainA, $mainB ], 13 ),
749 ],
750 ];
751 }
752
753 /**
754 * @dataProvider provideHasSameContent
755 * @covers \MediaWiki\Storage\RevisionRecord::hasSameContent
756 * @group Database
757 */
758 public function testHasSameContent(
759 $expected,
760 RevisionRecord $record1,
761 RevisionRecord $record2
762 ) {
763 $this->assertSame(
764 $expected,
765 $record1->hasSameContent( $record2 )
766 );
767 }
768
769 public function provideIsDeleted() {
770 yield 'no deletion' => [
771 0,
772 [
773 RevisionRecord::DELETED_TEXT => false,
774 RevisionRecord::DELETED_COMMENT => false,
775 RevisionRecord::DELETED_USER => false,
776 RevisionRecord::DELETED_RESTRICTED => false,
777 ]
778 ];
779 yield 'text deleted' => [
780 RevisionRecord::DELETED_TEXT,
781 [
782 RevisionRecord::DELETED_TEXT => true,
783 RevisionRecord::DELETED_COMMENT => false,
784 RevisionRecord::DELETED_USER => false,
785 RevisionRecord::DELETED_RESTRICTED => false,
786 ]
787 ];
788 yield 'text and comment deleted' => [
789 RevisionRecord::DELETED_TEXT + RevisionRecord::DELETED_COMMENT,
790 [
791 RevisionRecord::DELETED_TEXT => true,
792 RevisionRecord::DELETED_COMMENT => true,
793 RevisionRecord::DELETED_USER => false,
794 RevisionRecord::DELETED_RESTRICTED => false,
795 ]
796 ];
797 yield 'all 4 deleted' => [
798 RevisionRecord::DELETED_TEXT +
799 RevisionRecord::DELETED_COMMENT +
800 RevisionRecord::DELETED_RESTRICTED +
801 RevisionRecord::DELETED_USER,
802 [
803 RevisionRecord::DELETED_TEXT => true,
804 RevisionRecord::DELETED_COMMENT => true,
805 RevisionRecord::DELETED_USER => true,
806 RevisionRecord::DELETED_RESTRICTED => true,
807 ]
808 ];
809 }
810
811 /**
812 * @dataProvider provideIsDeleted
813 * @covers \MediaWiki\Storage\RevisionRecord::isDeleted
814 */
815 public function testIsDeleted( $revDeleted, $assertionMap ) {
816 $rev = $this->newRevision( [ 'rev_deleted' => $revDeleted ] );
817 foreach ( $assertionMap as $deletionLevel => $expected ) {
818 $this->assertSame( $expected, $rev->isDeleted( $deletionLevel ) );
819 }
820 }
821
822 }