MediaWiki REL1_32
RevisionDbTestBase.php
Go to the documentation of this file.
1<?php
8
15abstract class RevisionDbTestBase extends MediaWikiTestCase {
16
20 private $testPage;
21
22 public function __construct( $name = null, array $data = [], $dataName = '' ) {
23 parent::__construct( $name, $data, $dataName );
24
25 $this->tablesUsed = array_merge( $this->tablesUsed,
26 [
27 'page',
28 'revision',
29 'ip_changes',
30 'text',
31 'archive',
32
33 'recentchanges',
34 'logging',
35
36 'page_props',
37 'pagelinks',
38 'categorylinks',
39 'langlinks',
40 'externallinks',
41 'imagelinks',
42 'templatelinks',
43 'iwlinks'
44 ]
45 );
46 }
47
48 protected function addCoreDBData() {
49 // Blank out. This would fail with a modified schema, and we don't need it.
50 }
51
55 abstract protected function getMcrMigrationStage();
56
60 abstract protected function getMcrTablesToReset();
61
62 protected function setUp() {
63 $this->tablesUsed += $this->getMcrTablesToReset();
64
65 parent::setUp();
66
68 'wgExtraNamespaces',
69 [
70 12312 => 'Dummy',
71 12313 => 'Dummy_talk',
72 ]
73 );
74
76 'wgNamespaceContentModels',
77 [
79 ]
80 );
81
83 'wgContentHandlers',
84 [
85 DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting',
86 RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler',
87 ]
88 );
89
90 $this->setMwGlobals( [
91 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
92 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
93 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
94 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
95 ] );
96
97 $this->overrideMwServices();
98
99 if ( !$this->testPage ) {
104 $this->testPage = $this->createPage( __CLASS__, __CLASS__ );
105 }
106 }
107
112 protected function getMockTitle() {
113 $mock = $this->getMockBuilder( Title::class )
114 ->disableOriginalConstructor()
115 ->getMock();
116 $mock->expects( $this->any() )
117 ->method( 'getNamespace' )
118 ->will( $this->returnValue( $this->getDefaultWikitextNS() ) );
119 $mock->expects( $this->any() )
120 ->method( 'getPrefixedText' )
121 ->will( $this->returnValue( __CLASS__ ) );
122 $mock->expects( $this->any() )
123 ->method( 'getDBkey' )
124 ->will( $this->returnValue( __CLASS__ ) );
125 $mock->expects( $this->any() )
126 ->method( 'getArticleID' )
127 ->will( $this->returnValue( 23 ) );
128
129 return $mock;
130 }
131
132 abstract protected function getContentHandlerUseDB();
133
134 private function makeRevisionWithProps( $props = null ) {
135 if ( $props === null ) {
136 $props = [];
137 }
138
139 if ( !isset( $props['content'] ) && !isset( $props['text'] ) ) {
140 $props['text'] = 'Lorem Ipsum';
141 }
142
143 if ( !isset( $props['user_text'] ) ) {
144 $user = $this->getTestUser()->getUser();
145 $props['user_text'] = $user->getName();
146 $props['user'] = $user->getId();
147 }
148
149 if ( !isset( $props['user'] ) ) {
150 $props['user'] = 0;
151 }
152
153 if ( !isset( $props['comment'] ) ) {
154 $props['comment'] = 'just a test';
155 }
156
157 if ( !isset( $props['page'] ) ) {
158 $props['page'] = $this->testPage->getId();
159 }
160
161 if ( !isset( $props['content_model'] ) ) {
162 $props['content_model'] = CONTENT_MODEL_WIKITEXT;
163 }
164
165 $rev = new Revision( $props );
166
167 $dbw = wfGetDB( DB_MASTER );
168 $rev->insertOn( $dbw );
169
170 return $rev;
171 }
172
180 private function createPage( $titleString, $text, $model = null ) {
181 if ( !preg_match( '/:/', $titleString ) &&
182 ( $model === null || $model === CONTENT_MODEL_WIKITEXT )
183 ) {
184 $ns = $this->getDefaultWikitextNS();
185 $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString;
186 }
187
188 $title = Title::newFromText( $titleString );
189 $wikipage = new WikiPage( $title );
190
191 // Delete the article if it already exists
192 if ( $wikipage->exists() ) {
193 $wikipage->doDeleteArticle( "done" );
194 }
195
196 $content = ContentHandler::makeContent( $text, $title, $model );
197 $wikipage->doEditContent( $content, __METHOD__, EDIT_NEW );
198
199 return $wikipage;
200 }
201
202 private function assertRevEquals( Revision $orig, Revision $rev = null ) {
203 $this->assertNotNull( $rev, 'missing revision' );
204
205 $this->assertEquals( $orig->getId(), $rev->getId() );
206 $this->assertEquals( $orig->getPage(), $rev->getPage() );
207 $this->assertEquals( $orig->getTimestamp(), $rev->getTimestamp() );
208 $this->assertEquals( $orig->getUser(), $rev->getUser() );
209 $this->assertEquals( $orig->getContentModel(), $rev->getContentModel() );
210 $this->assertEquals( $orig->getContentFormat(), $rev->getContentFormat() );
211 $this->assertEquals( $orig->getSha1(), $rev->getSha1() );
212 }
213
217 public function testGetRecentChange() {
218 $rev = $this->testPage->getRevision();
219 $recentChange = $rev->getRecentChange();
220
221 // Make sure various attributes look right / the correct entry has been retrieved.
222 $this->assertEquals( $rev->getTimestamp(), $recentChange->getAttribute( 'rc_timestamp' ) );
223 $this->assertEquals(
224 $rev->getTitle()->getNamespace(),
225 $recentChange->getAttribute( 'rc_namespace' )
226 );
227 $this->assertEquals(
228 $rev->getTitle()->getDBkey(),
229 $recentChange->getAttribute( 'rc_title' )
230 );
231 $this->assertEquals( $rev->getUser(), $recentChange->getAttribute( 'rc_user' ) );
232 $this->assertEquals( $rev->getUserText(), $recentChange->getAttribute( 'rc_user_text' ) );
233 $this->assertEquals( $rev->getComment(), $recentChange->getAttribute( 'rc_comment' ) );
234 $this->assertEquals( $rev->getPage(), $recentChange->getAttribute( 'rc_cur_id' ) );
235 $this->assertEquals( $rev->getId(), $recentChange->getAttribute( 'rc_this_oldid' ) );
236 }
237
241 public function testInsertOn_success() {
242 $parentId = $this->testPage->getLatest();
243
244 // If an ExternalStore is set don't use it.
245 $this->setMwGlobals( 'wgDefaultExternalStore', false );
246
247 $rev = new Revision( [
248 'page' => $this->testPage->getId(),
249 'title' => $this->testPage->getTitle(),
250 'text' => 'Revision Text',
251 'comment' => 'Revision comment',
252 ] );
253
254 $revId = $rev->insertOn( wfGetDB( DB_MASTER ) );
255
256 $this->assertInternalType( 'integer', $revId );
257 $this->assertSame( $revId, $rev->getId() );
258
259 // getTextId() must be an int!
260 $this->assertInternalType( 'integer', $rev->getTextId() );
261
262 $mainSlot = $rev->getRevisionRecord()->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
263
264 // we currently only support storage in the text table
265 $textId = MediaWikiServices::getInstance()
266 ->getBlobStore()
267 ->getTextIdFromAddress( $mainSlot->getAddress() );
268
269 $this->assertSelect(
270 'text',
271 [ 'old_id', 'old_text' ],
272 "old_id = $textId",
273 [ [ strval( $textId ), 'Revision Text' ] ]
274 );
275 $this->assertSelect(
276 'revision',
277 [
278 'rev_id',
279 'rev_page',
280 'rev_minor_edit',
281 'rev_deleted',
282 'rev_len',
283 'rev_parent_id',
284 'rev_sha1',
285 ],
286 "rev_id = {$rev->getId()}",
287 [ [
288 strval( $rev->getId() ),
289 strval( $this->testPage->getId() ),
290 '0',
291 '0',
292 '13',
293 strval( $parentId ),
294 's0ngbdoxagreuf2vjtuxzwdz64n29xm',
295 ] ]
296 );
297 }
298
300 $content = new TextContent( '' );
301 $user = User::newFromName( 'Foo' );
302
303 yield 'no parent' => [
304 [
305 'content' => $content,
306 'comment' => 'test',
307 'user' => $user,
308 ],
309 IncompleteRevisionException::class,
310 "rev_page field must not be 0!"
311 ];
312
313 yield 'no comment' => [
314 [
315 'content' => $content,
316 'page' => 7,
317 'user' => $user,
318 ],
319 IncompleteRevisionException::class,
320 "comment must not be NULL!"
321 ];
322
323 yield 'no content' => [
324 [
325 'comment' => 'test',
326 'page' => 7,
327 'user' => $user,
328 ],
329 IncompleteRevisionException::class,
330 "Uninitialized field: content_address" // XXX: message may change
331 ];
332 }
333
338 public function testInsertOn_exceptionOnIncomplete( $array, $expException, $expMessage ) {
339 // If an ExternalStore is set don't use it.
340 $this->setMwGlobals( 'wgDefaultExternalStore', false );
341 $this->setExpectedException( $expException, $expMessage );
342
343 $title = Title::newFromText( 'Nonexistant-' . __METHOD__ );
344 $rev = new Revision( $array, 0, $title );
345
346 $rev->insertOn( wfGetDB( DB_MASTER ) );
347 }
348
352 public function testNewFromTitle_withoutId() {
353 $latestRevId = $this->testPage->getLatest();
354
355 $rev = Revision::newFromTitle( $this->testPage->getTitle() );
356
357 $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
358 $this->assertEquals( $latestRevId, $rev->getId() );
359 }
360
364 public function testNewFromTitle_withId() {
365 $latestRevId = $this->testPage->getLatest();
366
367 $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId );
368
369 $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
370 $this->assertEquals( $latestRevId, $rev->getId() );
371 }
372
376 public function testNewFromTitle_withBadId() {
377 $latestRevId = $this->testPage->getLatest();
378
379 $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId + 1 );
380
381 $this->assertNull( $rev );
382 }
383
387 public function testNewFromRow() {
388 $orig = $this->makeRevisionWithProps();
389
392 $res = $dbr->select( $revQuery['tables'], $revQuery['fields'], [ 'rev_id' => $orig->getId() ],
393 __METHOD__, [], $revQuery['joins'] );
394 $this->assertTrue( is_object( $res ), 'query failed' );
395
396 $row = $res->fetchObject();
397 $res->free();
398
399 $rev = Revision::newFromRow( $row );
400
401 $this->assertRevEquals( $orig, $rev );
402 }
403
404 public function provideNewFromArchiveRow() {
405 yield [
406 function ( $f ) {
407 return $f;
408 },
409 ];
410 yield [
411 function ( $f ) {
412 return $f + [ 'ar_namespace', 'ar_title' ];
413 },
414 ];
415 yield [
416 function ( $f ) {
417 unset( $f['ar_text_id'] );
418 return $f;
419 },
420 ];
421 yield [
422 function ( $f ) {
423 unset( $f['ar_page_id'] );
424 return $f;
425 },
426 ];
427 yield [
428 function ( $f ) {
429 unset( $f['ar_parent_id'] );
430 return $f;
431 },
432 ];
433 yield [
434 function ( $f ) {
435 unset( $f['ar_rev_id'] );
436 return $f;
437 },
438 ];
439 yield [
440 function ( $f ) {
441 unset( $f['ar_sha1'] );
442 return $f;
443 },
444 ];
445 }
446
451 public function testNewFromArchiveRow( $selectModifier ) {
452 $services = MediaWikiServices::getInstance();
453
454 $store = new RevisionStore(
455 $services->getDBLoadBalancer(),
456 $services->getService( '_SqlBlobStore' ),
457 $services->getMainWANObjectCache(),
458 $services->getCommentStore(),
459 $services->getContentModelStore(),
460 $services->getSlotRoleStore(),
461 $this->getMcrMigrationStage(),
462 $services->getActorMigration()
463 );
464
465 $store->setContentHandlerUseDB( $this->getContentHandlerUseDB() );
466 $this->setService( 'RevisionStore', $store );
467
468 $page = $this->createPage(
469 'RevisionStorageTest_testNewFromArchiveRow',
470 'Lorem Ipsum',
472 );
473 $orig = $page->getRevision();
474 $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
475
478 $arQuery['fields'] = $selectModifier( $arQuery['fields'] );
479 $res = $dbr->select(
480 $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
481 __METHOD__, [], $arQuery['joins']
482 );
483 $this->assertTrue( is_object( $res ), 'query failed' );
484
485 $row = $res->fetchObject();
486 $res->free();
487
488 // MCR migration note: $row is now required to contain ar_title and ar_namespace.
489 // Alternatively, a Title object can be passed to RevisionStore::newRevisionFromArchiveRow
491
492 $this->assertRevEquals( $orig, $rev );
493 }
494
499 $page = $this->createPage(
500 'RevisionStorageTest_testNewFromArchiveRow',
501 'Lorem Ipsum',
503 );
504 $orig = $page->getRevision();
505 $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
506
509 $res = $dbr->select(
510 $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
511 __METHOD__, [], $arQuery['joins']
512 );
513 $this->assertTrue( is_object( $res ), 'query failed' );
514
515 $row = $res->fetchObject();
516 $res->free();
517
518 $rev = Revision::newFromArchiveRow( $row, [ 'comment_text' => 'SOMEOVERRIDE' ] );
519
520 $this->assertNotEquals( $orig->getComment(), $rev->getComment() );
521 $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() );
522 }
523
527 public function testNewFromId() {
528 $orig = $this->testPage->getRevision();
529 $rev = Revision::newFromId( $orig->getId() );
530 $this->assertRevEquals( $orig, $rev );
531 }
532
536 public function testNewFromPageId() {
537 $rev = Revision::newFromPageId( $this->testPage->getId() );
538 $this->assertRevEquals(
539 $this->testPage->getRevision(),
540 $rev
541 );
542 }
543
549 $this->testPage->getId(),
550 $this->testPage->getLatest()
551 );
552 $this->assertRevEquals(
553 $this->testPage->getRevision(),
554 $rev
555 );
556 }
557
562 $content = new WikitextContent( __METHOD__ );
563 $this->testPage->doEditContent( $content, __METHOD__ );
565 $this->testPage->getId(),
566 $this->testPage->getRevision()->getPrevious()->getId()
567 );
568 $this->assertRevEquals(
569 $this->testPage->getRevision()->getPrevious(),
570 $rev
571 );
572 }
573
577 public function testFetchRevision() {
578 // Hidden process cache assertion below
579 $this->testPage->getRevision()->getId();
580
581 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
582 $id = $this->testPage->getRevision()->getId();
583
584 $this->hideDeprecated( 'Revision::fetchRevision' );
585 $res = Revision::fetchRevision( $this->testPage->getTitle() );
586
587 # note: order is unspecified
588 $rows = [];
589 while ( ( $row = $res->fetchObject() ) ) {
590 $rows[$row->rev_id] = $row;
591 }
592
593 $this->assertEmpty( $rows, 'expected empty set' );
594 }
595
599 public function testGetPage() {
600 $page = $this->testPage;
601
602 $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] );
603 $rev = Revision::newFromId( $orig->getId() );
604
605 $this->assertEquals( $page->getId(), $rev->getPage() );
606 }
607
611 public function testIsCurrent() {
612 $rev1 = $this->testPage->getRevision();
613
614 # @todo find out if this should be true
615 # $this->assertTrue( $rev1->isCurrent() );
616
617 $rev1x = Revision::newFromId( $rev1->getId() );
618 $this->assertTrue( $rev1x->isCurrent() );
619
620 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
621 $rev2 = $this->testPage->getRevision();
622
623 # @todo find out if this should be true
624 # $this->assertTrue( $rev2->isCurrent() );
625
626 $rev1x = Revision::newFromId( $rev1->getId() );
627 $this->assertFalse( $rev1x->isCurrent() );
628
629 $rev2x = Revision::newFromId( $rev2->getId() );
630 $this->assertTrue( $rev2x->isCurrent() );
631 }
632
636 public function testGetPrevious() {
637 $oldestRevision = $this->testPage->getOldestRevision();
638 $latestRevision = $this->testPage->getLatest();
639
640 $this->assertNull( $oldestRevision->getPrevious() );
641
642 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
643 $newRevision = $this->testPage->getRevision();
644
645 $this->assertNotNull( $newRevision->getPrevious() );
646 $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() );
647 }
648
652 public function testGetNext() {
653 $rev1 = $this->testPage->getRevision();
654
655 $this->assertNull( $rev1->getNext() );
656
657 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
658 $rev2 = $this->testPage->getRevision();
659
660 $this->assertNotNull( $rev1->getNext() );
661 $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() );
662 }
663
667 public function testNewNullRevision() {
668 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
669 $orig = $this->testPage->getRevision();
670
671 $dbw = wfGetDB( DB_MASTER );
672 $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false );
673
674 $this->assertNotEquals( $orig->getId(), $rev->getId(),
675 'new null revision should have a different id from the original revision' );
676 $this->assertEquals( $orig->getTextId(), $rev->getTextId(),
677 'new null revision should have the same text id as the original revision' );
678 $this->assertEquals( $orig->getSha1(), $rev->getSha1(),
679 'new null revision should have the same SHA1 as the original revision' );
680 $this->assertTrue( $orig->getRevisionRecord()->hasSameContent( $rev->getRevisionRecord() ),
681 'new null revision should have the same content as the original revision' );
682 $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() );
683 }
684
688 public function testNewNullRevision_badPage() {
689 $dbw = wfGetDB( DB_MASTER );
690 $rev = Revision::newNullRevision( $dbw, -1, 'a null revision', false );
691
692 $this->assertNull( $rev );
693 }
694
698 public function testInsertOn() {
699 $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7';
700
701 $orig = $this->makeRevisionWithProps( [
702 'user_text' => $ip
703 ] );
704
705 // Make sure the revision was copied to ip_changes
707 $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] );
708 $row = $res->fetchObject();
709
710 $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex );
711 $this->assertEquals(
712 $orig->getTimestamp(),
713 wfTimestamp( TS_MW, $row->ipc_rev_timestamp )
714 );
715 }
716
717 public static function provideUserWasLastToEdit() {
718 yield 'actually the last edit' => [ 3, true ];
719 yield 'not the current edit, but still by this user' => [ 2, true ];
720 yield 'edit by another user' => [ 1, false ];
721 yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ];
722 }
723
728 public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) {
729 $userA = User::newFromName( "RevisionStorageTest_userA" );
730 $userB = User::newFromName( "RevisionStorageTest_userB" );
731
732 if ( $userA->getId() === 0 ) {
733 $userA = User::createNew( $userA->getName() );
734 }
735
736 if ( $userB->getId() === 0 ) {
737 $userB = User::createNew( $userB->getName() );
738 }
739
740 $ns = $this->getDefaultWikitextNS();
741
742 $dbw = wfGetDB( DB_MASTER );
743 $revisions = [];
744
745 // create revisions -----------------------------
746 $page = WikiPage::factory( Title::newFromText(
747 'RevisionStorageTest_testUserWasLastToEdit', $ns ) );
748 $page->insertOn( $dbw );
749
750 $revisions[0] = new Revision( [
751 'page' => $page->getId(),
752 // we need the title to determine the page's default content model
753 'title' => $page->getTitle(),
754 'timestamp' => '20120101000000',
755 'user' => $userA->getId(),
756 'text' => 'zero',
757 'content_model' => CONTENT_MODEL_WIKITEXT,
758 'comment' => 'edit zero'
759 ] );
760 $revisions[0]->insertOn( $dbw );
761
762 $revisions[1] = new Revision( [
763 'page' => $page->getId(),
764 // still need the title, because $page->getId() is 0 (there's no entry in the page table)
765 'title' => $page->getTitle(),
766 'timestamp' => '20120101000100',
767 'user' => $userA->getId(),
768 'text' => 'one',
769 'content_model' => CONTENT_MODEL_WIKITEXT,
770 'comment' => 'edit one'
771 ] );
772 $revisions[1]->insertOn( $dbw );
773
774 $revisions[2] = new Revision( [
775 'page' => $page->getId(),
776 'title' => $page->getTitle(),
777 'timestamp' => '20120101000200',
778 'user' => $userB->getId(),
779 'text' => 'two',
780 'content_model' => CONTENT_MODEL_WIKITEXT,
781 'comment' => 'edit two'
782 ] );
783 $revisions[2]->insertOn( $dbw );
784
785 $revisions[3] = new Revision( [
786 'page' => $page->getId(),
787 'title' => $page->getTitle(),
788 'timestamp' => '20120101000300',
789 'user' => $userA->getId(),
790 'text' => 'three',
791 'content_model' => CONTENT_MODEL_WIKITEXT,
792 'comment' => 'edit three'
793 ] );
794 $revisions[3]->insertOn( $dbw );
795
796 $revisions[4] = new Revision( [
797 'page' => $page->getId(),
798 'title' => $page->getTitle(),
799 'timestamp' => '20120101000200',
800 'user' => $userA->getId(),
801 'text' => 'zero',
802 'content_model' => CONTENT_MODEL_WIKITEXT,
803 'comment' => 'edit four'
804 ] );
805 $revisions[4]->insertOn( $dbw );
806
807 // test it ---------------------------------
808 $since = $revisions[$sinceIdx]->getTimestamp();
809
811 $allRows = iterator_to_array( $dbw->select(
812 $revQuery['tables'],
813 [ 'rev_id', 'rev_timestamp', 'rev_user' => $revQuery['fields']['rev_user'] ],
814 [
815 'rev_page' => $page->getId(),
816 //'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $since ) )
817 ],
818 __METHOD__,
819 [ 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ],
820 $revQuery['joins']
821 ) );
822
823 $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since );
824
825 $this->assertEquals( $expectedLast, $wasLast );
826 }
827
836 private function newTestRevision( $text, $title = "Test",
837 $model = CONTENT_MODEL_WIKITEXT, $format = null
838 ) {
839 if ( is_string( $title ) ) {
840 $title = Title::newFromText( $title );
841 }
842
843 $content = ContentHandler::makeContent( $text, $title, $model, $format );
844
845 $rev = new Revision(
846 [
847 'id' => 42,
848 'page' => 23,
849 'title' => $title,
850
851 'content' => $content,
852 'length' => $content->getSize(),
853 'comment' => "testing",
854 'minor_edit' => false,
855
856 'content_format' => $format,
857 ]
858 );
859
860 return $rev;
861 }
862
863 public function provideGetContentModel() {
864 // NOTE: we expect the help namespace to always contain wikitext
865 return [
866 [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ],
867 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ],
868 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
869 ];
870 }
871
876 public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) {
877 $rev = $this->newTestRevision( $text, $title, $model, $format );
878
879 $this->assertEquals( $expectedModel, $rev->getContentModel() );
880 }
881
882 public function provideGetContentFormat() {
883 // NOTE: we expect the help namespace to always contain wikitext
884 return [
885 [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ],
886 [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ],
887 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ],
888 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
889 ];
890 }
891
896 public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) {
897 $rev = $this->newTestRevision( $text, $title, $model, $format );
898
899 $this->assertEquals( $expectedFormat, $rev->getContentFormat() );
900 }
901
902 public function provideGetContentHandler() {
903 // NOTE: we expect the help namespace to always contain wikitext
904 return [
905 [ 'hello world', 'Help:Hello', null, null, WikitextContentHandler::class ],
906 [ 'hello world', 'User:hello/there.css', null, null, CssContentHandler::class ],
907 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentHandlerForTesting::class ],
908 ];
909 }
910
915 public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) {
916 $rev = $this->newTestRevision( $text, $title, $model, $format );
917
918 $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) );
919 }
920
921 public function provideGetContent() {
922 // NOTE: we expect the help namespace to always contain wikitext
923 return [
924 [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ],
925 [
926 serialize( 'hello world' ),
927 'Hello',
929 null,
931 serialize( 'hello world' )
932 ],
933 [
934 serialize( 'hello world' ),
935 'Dummy:Hello',
936 null,
937 null,
939 serialize( 'hello world' )
940 ],
941 ];
942 }
943
948 public function testGetContent( $text, $title, $model, $format,
949 $audience, $expectedSerialization
950 ) {
951 $rev = $this->newTestRevision( $text, $title, $model, $format );
952 $content = $rev->getContent( $audience );
953
954 $this->assertEquals(
955 $expectedSerialization,
956 is_null( $content ) ? null : $content->serialize( $format )
957 );
958 }
959
963 public function testGetContent_failure() {
964 $rev = new Revision( [
965 'page' => $this->testPage->getId(),
966 'content_model' => $this->testPage->getContentModel(),
967 'id' => 123456789, // not in the test DB
968 ] );
969
970 Wikimedia\suppressWarnings(); // bad text_id will trigger a warning.
971
972 $this->assertNull( $rev->getContent(),
973 "getContent() should return null if the revision's text blob could not be loaded." );
974
975 // NOTE: check this twice, once for lazy initialization, and once with the cached value.
976 $this->assertNull( $rev->getContent(),
977 "getContent() should return null if the revision's text blob could not be loaded." );
978
979 Wikimedia\restoreWarnings();
980 }
981
982 public function provideGetSize() {
983 return [
984 [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ],
985 [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ],
986 ];
987 }
988
993 public function testGetSize( $text, $model, $expected_size ) {
994 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model );
995 $this->assertEquals( $expected_size, $rev->getSize() );
996 }
997
998 public function provideGetSha1() {
999 return [
1000 [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ],
1001 [
1002 serialize( "hello world." ),
1004 Revision::base36Sha1( serialize( "hello world." ) )
1005 ],
1006 ];
1007 }
1008
1013 public function testGetSha1( $text, $model, $expected_hash ) {
1014 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model );
1015 $this->assertEquals( $expected_hash, $rev->getSha1() );
1016 }
1017
1023 public function testGetContentClone() {
1025
1026 $rev = new Revision(
1027 [
1028 'id' => 42,
1029 'page' => 23,
1030 'title' => Title::newFromText( "testGetContentClone_dummy" ),
1031
1032 'content' => $content,
1033 'length' => $content->getSize(),
1034 'comment' => "testing",
1035 'minor_edit' => false,
1036 ]
1037 );
1038
1040 $content = $rev->getContent( Revision::RAW );
1041 $content->setText( "bar" );
1042
1044 $content2 = $rev->getContent( Revision::RAW );
1045 // content is mutable, expect clone
1046 $this->assertNotSame( $content, $content2, "expected a clone" );
1047 // clone should contain the original text
1048 $this->assertEquals( "foo", $content2->getText() );
1049
1050 $content2->setText( "bla bla" );
1051 // clones should be independent
1052 $this->assertEquals( "bar", $content->getText() );
1053 }
1054
1059 public function testGetContentUncloned() {
1060 $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT );
1061 $content = $rev->getContent( Revision::RAW );
1062 $content2 = $rev->getContent( Revision::RAW );
1063
1064 // for immutable content like wikitext, this should be the same object
1065 $this->assertSame( $content, $content2 );
1066 }
1067
1071 public function testLoadFromId() {
1072 $rev = $this->testPage->getRevision();
1073 $this->hideDeprecated( 'Revision::loadFromId' );
1074 $this->assertRevEquals(
1075 $rev,
1077 );
1078 }
1079
1083 public function testLoadFromPageId() {
1084 $this->assertRevEquals(
1085 $this->testPage->getRevision(),
1086 Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() )
1087 );
1088 }
1089
1094 $this->assertRevEquals(
1095 $this->testPage->getRevision(),
1097 wfGetDB( DB_MASTER ),
1098 $this->testPage->getId(),
1099 $this->testPage->getLatest()
1100 )
1101 );
1102 }
1103
1108 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1109 $this->assertRevEquals(
1110 $this->testPage->getRevision()->getPrevious(),
1112 wfGetDB( DB_MASTER ),
1113 $this->testPage->getId(),
1114 $this->testPage->getRevision()->getPrevious()->getId()
1115 )
1116 );
1117 }
1118
1122 public function testLoadFromTitle() {
1123 $this->assertRevEquals(
1124 $this->testPage->getRevision(),
1125 Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() )
1126 );
1127 }
1128
1133 $this->assertRevEquals(
1134 $this->testPage->getRevision(),
1136 wfGetDB( DB_MASTER ),
1137 $this->testPage->getTitle(),
1138 $this->testPage->getLatest()
1139 )
1140 );
1141 }
1142
1147 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1148 $this->assertRevEquals(
1149 $this->testPage->getRevision()->getPrevious(),
1151 wfGetDB( DB_MASTER ),
1152 $this->testPage->getTitle(),
1153 $this->testPage->getRevision()->getPrevious()->getId()
1154 )
1155 );
1156 }
1157
1161 public function testLoadFromTimestamp() {
1162 $this->assertRevEquals(
1163 $this->testPage->getRevision(),
1165 wfGetDB( DB_MASTER ),
1166 $this->testPage->getTitle(),
1167 $this->testPage->getRevision()->getTimestamp()
1168 )
1169 );
1170 }
1171
1176 $this->assertSame(
1177 [],
1179 wfGetDB( DB_MASTER ),
1180 []
1181 )
1182 );
1183 }
1184
1189 $text = '831jr091jr0921kr21kr0921kjr0921j09rj1';
1190 $textLength = strlen( $text );
1191
1192 $this->testPage->doEditContent( new WikitextContent( $text ), __METHOD__ );
1193 $rev[1] = $this->testPage->getLatest();
1194
1195 $this->assertSame(
1196 [ $rev[1] => $textLength ],
1198 wfGetDB( DB_MASTER ),
1199 [ $rev[1] ]
1200 )
1201 );
1202 }
1203
1208 $textOne = '831jr091jr0921kr21kr0921kjr0921j09rj1';
1209 $textOneLength = strlen( $textOne );
1210 $textTwo = '831jr091jr092121j09rj1';
1211 $textTwoLength = strlen( $textTwo );
1212
1213 $this->testPage->doEditContent( new WikitextContent( $textOne ), __METHOD__ );
1214 $rev[1] = $this->testPage->getLatest();
1215 $this->testPage->doEditContent( new WikitextContent( $textTwo ), __METHOD__ );
1216 $rev[2] = $this->testPage->getLatest();
1217
1218 $this->assertSame(
1219 [ $rev[1] => $textOneLength, $rev[2] => $textTwoLength ],
1221 wfGetDB( DB_MASTER ),
1222 [ $rev[1], $rev[2] ]
1223 )
1224 );
1225 }
1226
1231 $this->assertTrue(
1232 $this->testPage->getTitle()->equals(
1233 $this->testPage->getRevision()->getTitle()
1234 )
1235 );
1236 }
1237
1242 $rev = new Revision( [ 'id' => $this->testPage->getLatest() ] );
1243 $this->assertTrue(
1244 $this->testPage->getTitle()->equals(
1245 $rev->getTitle()
1246 )
1247 );
1248 }
1249
1253 public function testIsMinor_true() {
1254 // Use a sysop to ensure we can mark edits as minor
1255 $sysop = $this->getTestSysop()->getUser();
1256
1257 $this->testPage->doEditContent(
1258 new WikitextContent( __METHOD__ ),
1259 __METHOD__,
1260 EDIT_MINOR,
1261 false,
1262 $sysop
1263 );
1264 $rev = $this->testPage->getRevision();
1265
1266 $this->assertSame( true, $rev->isMinor() );
1267 }
1268
1272 public function testIsMinor_false() {
1273 $this->testPage->doEditContent(
1274 new WikitextContent( __METHOD__ ),
1275 __METHOD__,
1276 0
1277 );
1278 $rev = $this->testPage->getRevision();
1279
1280 $this->assertSame( false, $rev->isMinor() );
1281 }
1282
1286 public function testGetTimestamp() {
1287 $testTimestamp = wfTimestampNow();
1288
1289 $this->testPage->doEditContent(
1290 new WikitextContent( __METHOD__ ),
1291 __METHOD__
1292 );
1293 $rev = $this->testPage->getRevision();
1294
1295 $this->assertInternalType( 'string', $rev->getTimestamp() );
1296 $this->assertTrue( strlen( $rev->getTimestamp() ) == strlen( 'YYYYMMDDHHMMSS' ) );
1297 $this->assertContains( substr( $testTimestamp, 0, 10 ), $rev->getTimestamp() );
1298 }
1299
1304 public function testGetUserAndText() {
1305 $sysop = $this->getTestSysop()->getUser();
1306
1307 $this->testPage->doEditContent(
1308 new WikitextContent( __METHOD__ ),
1309 __METHOD__,
1310 0,
1311 false,
1312 $sysop
1313 );
1314 $rev = $this->testPage->getRevision();
1315
1316 $this->assertSame( $sysop->getId(), $rev->getUser() );
1317 $this->assertSame( $sysop->getName(), $rev->getUserText() );
1318 }
1319
1324 $rev = $this->testPage->getRevision();
1325
1326 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
1327 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_COMMENT ) );
1328 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_RESTRICTED ) );
1329 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_USER ) );
1330 }
1331
1336 $rev = $this->testPage->getRevision();
1337
1338 $this->assertSame( 0, $rev->getVisibility() );
1339 }
1340
1344 public function testGetComment_notDeleted() {
1345 $expectedSummary = 'goatlicious summary';
1346
1347 $this->testPage->doEditContent(
1348 new WikitextContent( __METHOD__ ),
1349 $expectedSummary
1350 );
1351 $rev = $this->testPage->getRevision();
1352
1353 $this->assertSame( $expectedSummary, $rev->getComment() );
1354 }
1355
1360 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1361 $rev = $this->testPage->getRevision();
1362
1363 $this->assertGreaterThan( 0, $rev->isUnpatrolled() );
1364 $this->assertSame( $rev->getRecentChange()->getAttribute( 'rc_id' ), $rev->isUnpatrolled() );
1365 }
1366
1371 // This assumes that sysops are auto patrolled
1372 $sysop = $this->getTestSysop()->getUser();
1373 $this->testPage->doEditContent(
1374 new WikitextContent( __METHOD__ ),
1375 __METHOD__,
1376 0,
1377 false,
1378 $sysop
1379 );
1380 $rev = $this->testPage->getRevision();
1381
1382 $this->assertSame( 0, $rev->isUnpatrolled() );
1383 }
1384
1394 public function testSimpleContentGetters() {
1395 $expectedText = 'testSimpleContentGetters in Revision. Goats love MCR...';
1396 $expectedSummary = 'goatlicious testSimpleContentGetters summary';
1397
1398 $this->testPage->doEditContent(
1399 new WikitextContent( $expectedText ),
1400 $expectedSummary
1401 );
1402 $rev = $this->testPage->getRevision();
1403
1404 $this->assertSame( $expectedText, $rev->getContent()->getNativeData() );
1405 $this->assertSame( $expectedText, $rev->getSerializedData() );
1406 $this->assertSame( $this->testPage->getContentModel(), $rev->getContentModel() );
1407 $this->assertSame( $this->testPage->getContent()->getDefaultFormat(), $rev->getContentFormat() );
1408 $this->assertSame( $this->testPage->getContentHandler(), $rev->getContentHandler() );
1409 }
1410
1414 public function testNewKnownCurrent() {
1415 // Setup the services
1416 $this->overrideMwServices();
1417 $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
1418 $this->setService( 'MainWANObjectCache', $cache );
1419 $db = wfGetDB( DB_MASTER );
1420
1421 // Get a fresh revision to use during testing
1422 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1423 $rev = $this->testPage->getRevision();
1424
1425 // Clear any previous cache for the revision during creation
1426 $key = $cache->makeGlobalKey(
1427 RevisionStore::ROW_CACHE_KEY,
1428 $db->getDomainID(),
1429 $rev->getPage(),
1430 $rev->getId()
1431 );
1432 $cache->delete( $key, WANObjectCache::HOLDOFF_NONE );
1433 $this->assertFalse( $cache->get( $key ) );
1434
1435 // Get the new revision and make sure it is in the cache and correct
1436 $newRev = Revision::newKnownCurrent( $db, $rev->getPage(), $rev->getId() );
1437 $this->assertRevEquals( $rev, $newRev );
1438
1439 $cachedRow = $cache->get( $key );
1440 $this->assertNotFalse( $cachedRow );
1441 $this->assertEquals( $rev->getId(), $cachedRow->rev_id );
1442 }
1443
1445 $db = wfGetDB( DB_MASTER );
1446
1447 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1448 $rev = $this->testPage->getRevision();
1449
1450 $pageId = $this->testPage->getId();
1451
1452 $newRev = Revision::newKnownCurrent( $db, $pageId, $rev->getId() );
1453 $this->assertRevEquals( $rev, $newRev );
1454 }
1455
1457 $db = wfGetDB( DB_MASTER );
1458
1459 $this->assertFalse( Revision::newKnownCurrent( $db, 0 ) );
1460 }
1461
1462 public function provideUserCanBitfield() {
1463 yield [ 0, 0, [], null, true ];
1464 // Bitfields match, user has no permissions
1469 // Bitfields match, user (admin) does have permissions
1470 yield [ Revision::DELETED_TEXT, Revision::DELETED_TEXT, [ 'sysop' ], null, true ];
1471 yield [ Revision::DELETED_COMMENT, Revision::DELETED_COMMENT, [ 'sysop' ], null, true ];
1472 yield [ Revision::DELETED_USER, Revision::DELETED_USER, [ 'sysop' ], null, true ];
1473 // Bitfields match, user (admin) does not have permissions
1475 // Bitfields match, user (oversight) does have permissions
1476 yield [ Revision::DELETED_RESTRICTED, Revision::DELETED_RESTRICTED, [ 'oversight' ], null, true ];
1477 // Check permissions using the title
1478 yield [
1481 [ 'sysop' ],
1482 __METHOD__,
1483 true,
1484 ];
1485 yield [
1488 [],
1489 __METHOD__,
1490 false,
1491 ];
1492 }
1493
1498 public function testUserCanBitfield( $bitField, $field, $userGroups, $title, $expected ) {
1499 $title = Title::newFromText( $title );
1500
1501 $this->setMwGlobals(
1502 'wgGroupPermissions',
1503 [
1504 'sysop' => [
1505 'deletedtext' => true,
1506 'deletedhistory' => true,
1507 ],
1508 'oversight' => [
1509 'viewsuppressed' => true,
1510 'suppressrevision' => true,
1511 ],
1512 ]
1513 );
1514 $user = $this->getTestUser( $userGroups )->getUser();
1515
1516 $this->assertSame(
1517 $expected,
1518 Revision::userCanBitfield( $bitField, $field, $user, $title )
1519 );
1520
1521 // Fallback to $wgUser
1522 $this->setMwGlobals(
1523 'wgUser',
1524 $user
1525 );
1526 $this->assertSame(
1527 $expected,
1528 Revision::userCanBitfield( $bitField, $field, null, $title )
1529 );
1530 }
1531
1532 public function provideUserCan() {
1533 yield [ 0, 0, [], true ];
1534 // Bitfields match, user has no permissions
1539 // Bitfields match, user (admin) does have permissions
1540 yield [ Revision::DELETED_TEXT, Revision::DELETED_TEXT, [ 'sysop' ], true ];
1542 yield [ Revision::DELETED_USER, Revision::DELETED_USER, [ 'sysop' ], true ];
1543 // Bitfields match, user (admin) does not have permissions
1545 // Bitfields match, user (oversight) does have permissions
1547 }
1548
1553 public function testUserCan( $bitField, $field, $userGroups, $expected ) {
1554 $this->setMwGlobals(
1555 'wgGroupPermissions',
1556 [
1557 'sysop' => [
1558 'deletedtext' => true,
1559 'deletedhistory' => true,
1560 ],
1561 'oversight' => [
1562 'viewsuppressed' => true,
1563 'suppressrevision' => true,
1564 ],
1565 ]
1566 );
1567 $user = $this->getTestUser( $userGroups )->getUser();
1568 $revision = new Revision( [ 'deleted' => $bitField ], 0, $this->testPage->getTitle() );
1569
1570 $this->assertSame(
1571 $expected,
1572 $revision->userCan( $field, $user )
1573 );
1574 }
1575
1576 public function provideGetTextId() {
1577 yield [ [], null ];
1578
1579 $slot = new SlotRecord( (object)[
1580 'slot_revision_id' => 42,
1581 'slot_content_id' => 1,
1582 'content_address' => 'tt:789',
1583 'model_name' => CONTENT_MODEL_WIKITEXT,
1584 'role_name' => SlotRecord::MAIN,
1585 'slot_origin' => 1,
1586 ], new WikitextContent( 'Test' ) );
1587
1588 $rec = new MutableRevisionRecord( $this->testPage->getTitle() );
1589 $rec->setId( 42 );
1590 $rec->setSlot( $slot );
1591
1592 yield [ $rec, 789 ];
1593 }
1594
1599 public function testGetTextId( $spec, $expected ) {
1600 $rev = new Revision( $spec, 0, $this->testPage->getTitle() );
1601 $this->assertSame( $expected, $rev->getTextId() );
1602 }
1603
1604}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
serialize()
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Simple store for keeping values in an associative array for the current process.
getDefaultWikitextNS()
Returns the ID of a namespace that defaults to Wikitext.
Database $db
Primary database.
static getTestSysop()
Convenience method for getting an immutable admin test user.
overrideMwServices(Config $configOverrides=null, array $services=[])
Stashes the global instance of MediaWikiServices, and installs a new one, allowing test cases to over...
mergeMwGlobalArrayValue( $name, $values)
Merges the given values into a MW global array variable.
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown.
hideDeprecated( $function)
Don't throw a warning if $function is deprecated and called later.
setService( $name, $object)
Sets a service, maintaining a stashed version of the previous service to be restored in tearDown.
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
assertSelect( $table, $fields, $condition, array $expectedRows, array $options=[], array $join_conds=[])
Asserts that the given database query yields the rows given by $expectedRows.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Exception throw when trying to access undefined fields on an incomplete RevisionRecord.
Mutable RevisionRecord implementation, for building new revision entries programmatically.
Page revision base class.
Service for looking up page revisions.
Value object representing a content slot associated with a page revision.
RevisionDbTestBase contains test cases for the Revision class that have Database interactions.
testLoadFromTitle()
Revision::loadFromTitle.
testNewNullRevision()
Revision::newNullRevision.
testNewKnownCurrent()
Revision::newKnownCurrent.
testLoadFromTitleWithNotLatestRevId()
Revision::loadFromTitle.
testUserCan( $bitField, $field, $userGroups, $expected)
provideUserCan Revision::userCan
testNewFromArchiveRowOverrides()
Revision::newFromArchiveRow.
testLoadFromPageIdWithNotLatestRevId()
Revision::loadFromPageId.
testGetContentHandler( $text, $title, $model, $format, $expectedClass)
provideGetContentHandler Revision::getContentHandler
testGetParentLengths_noRevIds()
Revision::getParentLengths.
testInsertOn_success()
Revision::insertOn.
assertRevEquals(Revision $orig, Revision $rev=null)
testGetComment_notDeleted()
Revision::getComment.
testGetVisibility_nothingDeleted()
Revision::getVisibility.
testGetContent_failure()
Revision::getContent.
testGetParentLengths_multipleRevIds()
Revision::getParentLengths.
testLoadFromId()
Revision::loadFromId.
testLoadFromPageId()
Revision::loadFromPageId.
testGetTitle_fromExistingRevision()
Revision::getTitle.
testNewFromTitle_withBadId()
Revision::newFromTitle.
testGetSize( $text, $model, $expected_size)
Revision::getSize provideGetSize.
createPage( $titleString, $text, $model=null)
testGetContentModel( $text, $title, $model, $format, $expectedModel)
provideGetContentModel Revision::getContentModel
testGetContent( $text, $title, $model, $format, $audience, $expectedSerialization)
provideGetContent Revision::getContent
testInsertOn()
Revision::insertOn.
testGetTimestamp()
Revision::getTimestamp.
testNewFromPageId()
Revision::newFromPageId.
testInsertOn_exceptionOnIncomplete( $array, $expException, $expMessage)
provideInsertOn_exceptionOnIncomplete Revision::insertOn
testFetchRevision()
Revision::fetchRevision.
testGetUserAndText()
Revision::getUser Revision::getUserText.
testLoadFromTitleWithLatestRevId()
Revision::loadFromTitle.
testGetRecentChange()
Revision::getRecentChange.
testGetSha1( $text, $model, $expected_hash)
Revision::getSha1 provideGetSha1.
testGetTitle_fromRevisionWhichWillLoadTheTitle()
Revision::getTitle.
testNewFromArchiveRow( $selectModifier)
provideNewFromArchiveRow Revision::newFromArchiveRow
testGetContentFormat( $text, $title, $model, $format, $expectedFormat)
provideGetContentFormat Revision::getContentFormat
testGetTextId( $spec, $expected)
provideGetTextId Revision::getTextId()
makeRevisionWithProps( $props=null)
testGetContentClone()
Tests whether $rev->getContent() returns a clone when needed.
testLoadFromTimestamp()
Revision::loadFromTimestamp()
testNewFromRow()
Revision::newFromRow.
testIsUnpatrolled_returnsRecentChangesId()
Revision::isUnpatrolled.
testNewNullRevision_badPage()
Revision::newNullRevision.
testIsDeleted_nothingDeleted()
Revision::isDeleted.
testNewFromTitle_withId()
Revision::newFromTitle.
testIsMinor_false()
Revision::isMinor.
testLoadFromPageIdWithLatestRevId()
Revision::loadFromPageId.
testNewFromId()
Revision::newFromId.
testNewFromTitle_withoutId()
Revision::newFromTitle.
testUserCanBitfield( $bitField, $field, $userGroups, $title, $expected)
provideUserCanBitfield Revision::userCanBitfield
testNewFromPageIdWithLatestId()
Revision::newFromPageId.
testGetContentUncloned()
Tests whether $rev->getContent() returns the same object repeatedly if appropriate.
testIsCurrent()
Revision::isCurrent.
testGetPrevious()
Revision::getPrevious.
testGetParentLengths_oneRevId()
Revision::getParentLengths.
testSimpleContentGetters()
This is a simple blanket test for all simple content getters and is methods to provide some coverage ...
testNewFromPageIdWithNotLatestId()
Revision::newFromPageId.
testIsMinor_true()
Revision::isMinor.
testIsUnpatrolled_returnsZeroIfPatrolled()
Revision::isUnpatrolled.
testGetNext()
Revision::getNext.
__construct( $name=null, array $data=[], $dataName='')
testUserWasLastToEdit( $sinceIdx, $expectedLast)
Revision::userWasLastToEdit provideUserWasLastToEdit.
newTestRevision( $text, $title="Test", $model=CONTENT_MODEL_WIKITEXT, $format=null)
testGetPage()
Revision::getPage.
getId()
Get revision ID.
Definition Revision.php:646
static newKnownCurrent(IDatabase $db, $pageIdOrTitle, $revId=0)
Load a revision based on a known page ID and current revision ID from the DB.
static loadFromTitle( $db, $title, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
Definition Revision.php:273
static newFromPageId( $pageId, $revId=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given page ID.
Definition Revision.php:152
getContentFormat()
Returns the content format for the main slot of this revision.
Definition Revision.php:979
static loadFromTimestamp( $db, $title, $timestamp)
Load the revision for the given title with the given timestamp.
Definition Revision.php:291
getPage()
Get the page ID.
Definition Revision.php:790
static getArchiveQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archived revision objec...
Definition Revision.php:535
static newFromRow( $row)
Definition Revision.php:218
static newNullRevision( $dbw, $pageId, $summary, $minor, $user=null)
Create a new null-revision for insertion into a page's history.
static loadFromId( $db, $id)
Load a page revision from a given revision ID number.
Definition Revision.php:238
getContentModel()
Returns the content model for the main slot of this revision.
Definition Revision.php:964
getUser( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision's user id if it's available to the specified audience.
Definition Revision.php:807
static newFromArchiveRow( $row, $overrides=[])
Make a fake revision object from an archive table row.
Definition Revision.php:167
const DELETED_USER
Definition Revision.php:49
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
Definition Revision.php:521
const DELETED_TEXT
Definition Revision.php:47
static base36Sha1( $text)
Get the base 36 SHA-1 value for a string of text.
getSha1()
Returns the base36 sha1 of the content in this revision, or null if unknown.
Definition Revision.php:747
const DELETED_RESTRICTED
Definition Revision.php:50
static loadFromPageId( $db, $pageid, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
Definition Revision.php:256
static userCanBitfield( $bitfield, $field, User $user=null, Title $title=null)
Determine if the current user is allowed to view a particular field of this revision,...
static userWasLastToEdit( $db, $pageId, $userId, $since)
Check if no edits were made by other users since the time a user started editing the page.
static getParentLengths( $db, array $revIds)
Do a batched query to get the parent revision lengths.
Definition Revision.php:548
static fetchRevision(LinkTarget $title)
Return a wrapper for a series of database rows to fetch all of a given page's revisions in turn.
Definition Revision.php:305
const FOR_PUBLIC
Definition Revision.php:55
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that's attached to a given link target.
Definition Revision.php:133
const RAW
Definition Revision.php:57
const DELETED_COMMENT
Definition Revision.php:48
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition Revision.php:114
Content object implementation for representing flat text.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition User.php:592
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition User.php:4301
Multi-datacenter aware caching interface.
Class representing a MediaWiki article and history.
Definition WikiPage.php:44
getDomainID()
Return the currently selected domain ID.
Definition Database.php:835
Content object for wiki text pages.
$res
Definition database.txt:21
const SCHEMA_COMPAT_OLD
Definition Defines.php:290
const CONTENT_MODEL_CSS
Definition Defines.php:237
const CONTENT_FORMAT_CSS
Definition Defines.php:254
const CONTENT_MODEL_WIKITEXT
Definition Defines.php:235
const CONTENT_FORMAT_WIKITEXT
Definition Defines.php:250
const MIGRATION_OLD
Definition Defines.php:315
const EDIT_MINOR
Definition Defines.php:154
const EDIT_NEW
Definition Defines.php:152
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction $rows
Definition hooks.txt:2857
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:994
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition hooks.txt:2055
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response after the basic globals have been set but before ordinary actions take place or wrap services the preferred way to define a new service is the $wgServiceWiringFiles array $services
Definition hooks.txt:2335
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition hooks.txt:1818
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition hooks.txt:247
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
$cache
Definition mcc.php:33
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
$content
$newRev
const DB_REPLICA
Definition defines.php:25
const DB_MASTER
Definition defines.php:26