MediaWiki REL1_33
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 'comment',
30 'ip_changes',
31 'text',
32 'archive',
33
34 'recentchanges',
35 'logging',
36
37 'page_props',
38 'pagelinks',
39 'categorylinks',
40 'langlinks',
41 'externallinks',
42 'imagelinks',
43 'templatelinks',
44 'iwlinks'
45 ]
46 );
47 }
48
49 protected function addCoreDBData() {
50 // Blank out. This would fail with a modified schema, and we don't need it.
51 }
52
56 abstract protected function getMcrMigrationStage();
57
61 abstract protected function getMcrTablesToReset();
62
63 protected function setUp() {
64 $this->tablesUsed += $this->getMcrTablesToReset();
65
66 parent::setUp();
67
69 'wgExtraNamespaces',
70 [
71 12312 => 'Dummy',
72 12313 => 'Dummy_talk',
73 ]
74 );
75
77 'wgNamespaceContentModels',
78 [
80 ]
81 );
82
84 'wgContentHandlers',
85 [
86 DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting',
87 RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler',
88 ]
89 );
90
91 $this->setMwGlobals( [
92 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
93 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
94 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
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 $services->getSlotRoleRegistry(),
462 $this->getMcrMigrationStage(),
463 $services->getActorMigration()
464 );
465
466 $store->setContentHandlerUseDB( $this->getContentHandlerUseDB() );
467 $this->setService( 'RevisionStore', $store );
468
469 $page = $this->createPage(
470 'RevisionStorageTest_testNewFromArchiveRow',
471 'Lorem Ipsum',
473 );
474 $orig = $page->getRevision();
475 $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
476
479 $arQuery['fields'] = $selectModifier( $arQuery['fields'] );
480 $res = $dbr->select(
481 $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
482 __METHOD__, [], $arQuery['joins']
483 );
484 $this->assertTrue( is_object( $res ), 'query failed' );
485
486 $row = $res->fetchObject();
487 $res->free();
488
489 // MCR migration note: $row is now required to contain ar_title and ar_namespace.
490 // Alternatively, a Title object can be passed to RevisionStore::newRevisionFromArchiveRow
492
493 $this->assertRevEquals( $orig, $rev );
494 }
495
500 $page = $this->createPage(
501 'RevisionStorageTest_testNewFromArchiveRow',
502 'Lorem Ipsum',
504 );
505 $orig = $page->getRevision();
506 $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
507
510 $res = $dbr->select(
511 $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ],
512 __METHOD__, [], $arQuery['joins']
513 );
514 $this->assertTrue( is_object( $res ), 'query failed' );
515
516 $row = $res->fetchObject();
517 $res->free();
518
519 $rev = Revision::newFromArchiveRow( $row, [ 'comment_text' => 'SOMEOVERRIDE' ] );
520
521 $this->assertNotEquals( $orig->getComment(), $rev->getComment() );
522 $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() );
523 }
524
528 public function testNewFromId() {
529 $orig = $this->testPage->getRevision();
530 $rev = Revision::newFromId( $orig->getId() );
531 $this->assertRevEquals( $orig, $rev );
532 }
533
537 public function testNewFromPageId() {
538 $rev = Revision::newFromPageId( $this->testPage->getId() );
539 $this->assertRevEquals(
540 $this->testPage->getRevision(),
541 $rev
542 );
543 }
544
550 $this->testPage->getId(),
551 $this->testPage->getLatest()
552 );
553 $this->assertRevEquals(
554 $this->testPage->getRevision(),
555 $rev
556 );
557 }
558
563 $content = new WikitextContent( __METHOD__ );
564 $this->testPage->doEditContent( $content, __METHOD__ );
566 $this->testPage->getId(),
567 $this->testPage->getRevision()->getPrevious()->getId()
568 );
569 $this->assertRevEquals(
570 $this->testPage->getRevision()->getPrevious(),
571 $rev
572 );
573 }
574
578 public function testGetPage() {
579 $page = $this->testPage;
580
581 $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] );
582 $rev = Revision::newFromId( $orig->getId() );
583
584 $this->assertEquals( $page->getId(), $rev->getPage() );
585 }
586
590 public function testIsCurrent() {
591 $rev1 = $this->testPage->getRevision();
592
593 # @todo find out if this should be true
594 # $this->assertTrue( $rev1->isCurrent() );
595
596 $rev1x = Revision::newFromId( $rev1->getId() );
597 $this->assertTrue( $rev1x->isCurrent() );
598
599 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
600 $rev2 = $this->testPage->getRevision();
601
602 # @todo find out if this should be true
603 # $this->assertTrue( $rev2->isCurrent() );
604
605 $rev1x = Revision::newFromId( $rev1->getId() );
606 $this->assertFalse( $rev1x->isCurrent() );
607
608 $rev2x = Revision::newFromId( $rev2->getId() );
609 $this->assertTrue( $rev2x->isCurrent() );
610 }
611
615 public function testGetPrevious() {
616 $oldestRevision = $this->testPage->getOldestRevision();
617 $latestRevision = $this->testPage->getLatest();
618
619 $this->assertNull( $oldestRevision->getPrevious() );
620
621 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
622 $newRevision = $this->testPage->getRevision();
623
624 $this->assertNotNull( $newRevision->getPrevious() );
625 $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() );
626 }
627
631 public function testGetNext() {
632 $rev1 = $this->testPage->getRevision();
633
634 $this->assertNull( $rev1->getNext() );
635
636 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
637 $rev2 = $this->testPage->getRevision();
638
639 $this->assertNotNull( $rev1->getNext() );
640 $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() );
641 }
642
646 public function testNewNullRevision() {
647 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
648 $orig = $this->testPage->getRevision();
649
650 $dbw = wfGetDB( DB_MASTER );
651 $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false );
652
653 $this->assertNotEquals( $orig->getId(), $rev->getId(),
654 'new null revision should have a different id from the original revision' );
655 $this->assertEquals( $orig->getTextId(), $rev->getTextId(),
656 'new null revision should have the same text id as the original revision' );
657 $this->assertEquals( $orig->getSha1(), $rev->getSha1(),
658 'new null revision should have the same SHA1 as the original revision' );
659 $this->assertTrue( $orig->getRevisionRecord()->hasSameContent( $rev->getRevisionRecord() ),
660 'new null revision should have the same content as the original revision' );
661 $this->assertEquals( __METHOD__, $rev->getContent()->getText() );
662 }
663
667 public function testNewNullRevision_badPage() {
668 $dbw = wfGetDB( DB_MASTER );
669 $rev = Revision::newNullRevision( $dbw, -1, 'a null revision', false );
670
671 $this->assertNull( $rev );
672 }
673
677 public function testInsertOn() {
678 $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7';
679
680 $orig = $this->makeRevisionWithProps( [
681 'user_text' => $ip
682 ] );
683
684 // Make sure the revision was copied to ip_changes
686 $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] );
687 $row = $res->fetchObject();
688
689 $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex );
690 $this->assertEquals(
691 $orig->getTimestamp(),
692 wfTimestamp( TS_MW, $row->ipc_rev_timestamp )
693 );
694 }
695
696 public static function provideUserWasLastToEdit() {
697 yield 'actually the last edit' => [ 3, true ];
698 yield 'not the current edit, but still by this user' => [ 2, true ];
699 yield 'edit by another user' => [ 1, false ];
700 yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ];
701 }
702
707 public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) {
708 $userA = User::newFromName( "RevisionStorageTest_userA" );
709 $userB = User::newFromName( "RevisionStorageTest_userB" );
710
711 if ( $userA->getId() === 0 ) {
712 $userA = User::createNew( $userA->getName() );
713 }
714
715 if ( $userB->getId() === 0 ) {
716 $userB = User::createNew( $userB->getName() );
717 }
718
719 $ns = $this->getDefaultWikitextNS();
720
721 $dbw = wfGetDB( DB_MASTER );
722 $revisions = [];
723
724 // create revisions -----------------------------
725 $page = WikiPage::factory( Title::newFromText(
726 'RevisionStorageTest_testUserWasLastToEdit', $ns ) );
727 $page->insertOn( $dbw );
728
729 $revisions[0] = new Revision( [
730 'page' => $page->getId(),
731 // we need the title to determine the page's default content model
732 'title' => $page->getTitle(),
733 'timestamp' => '20120101000000',
734 'user' => $userA->getId(),
735 'text' => 'zero',
736 'content_model' => CONTENT_MODEL_WIKITEXT,
737 'comment' => 'edit zero'
738 ] );
739 $revisions[0]->insertOn( $dbw );
740
741 $revisions[1] = new Revision( [
742 'page' => $page->getId(),
743 // still need the title, because $page->getId() is 0 (there's no entry in the page table)
744 'title' => $page->getTitle(),
745 'timestamp' => '20120101000100',
746 'user' => $userA->getId(),
747 'text' => 'one',
748 'content_model' => CONTENT_MODEL_WIKITEXT,
749 'comment' => 'edit one'
750 ] );
751 $revisions[1]->insertOn( $dbw );
752
753 $revisions[2] = new Revision( [
754 'page' => $page->getId(),
755 'title' => $page->getTitle(),
756 'timestamp' => '20120101000200',
757 'user' => $userB->getId(),
758 'text' => 'two',
759 'content_model' => CONTENT_MODEL_WIKITEXT,
760 'comment' => 'edit two'
761 ] );
762 $revisions[2]->insertOn( $dbw );
763
764 $revisions[3] = new Revision( [
765 'page' => $page->getId(),
766 'title' => $page->getTitle(),
767 'timestamp' => '20120101000300',
768 'user' => $userA->getId(),
769 'text' => 'three',
770 'content_model' => CONTENT_MODEL_WIKITEXT,
771 'comment' => 'edit three'
772 ] );
773 $revisions[3]->insertOn( $dbw );
774
775 $revisions[4] = new Revision( [
776 'page' => $page->getId(),
777 'title' => $page->getTitle(),
778 'timestamp' => '20120101000200',
779 'user' => $userA->getId(),
780 'text' => 'zero',
781 'content_model' => CONTENT_MODEL_WIKITEXT,
782 'comment' => 'edit four'
783 ] );
784 $revisions[4]->insertOn( $dbw );
785
786 // test it ---------------------------------
787 $since = $revisions[$sinceIdx]->getTimestamp();
788
790 $allRows = iterator_to_array( $dbw->select(
791 $revQuery['tables'],
792 [ 'rev_id', 'rev_timestamp', 'rev_user' => $revQuery['fields']['rev_user'] ],
793 [
794 'rev_page' => $page->getId(),
795 //'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $since ) )
796 ],
797 __METHOD__,
798 [ 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ],
799 $revQuery['joins']
800 ) );
801
802 $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since );
803
804 $this->assertEquals( $expectedLast, $wasLast );
805 }
806
815 private function newTestRevision( $text, $title = "Test",
816 $model = CONTENT_MODEL_WIKITEXT, $format = null
817 ) {
818 if ( is_string( $title ) ) {
819 $title = Title::newFromText( $title );
820 }
821
822 $content = ContentHandler::makeContent( $text, $title, $model, $format );
823
824 $rev = new Revision(
825 [
826 'id' => 42,
827 'page' => 23,
828 'title' => $title,
829
830 'content' => $content,
831 'length' => $content->getSize(),
832 'comment' => "testing",
833 'minor_edit' => false,
834
835 'content_format' => $format,
836 ]
837 );
838
839 return $rev;
840 }
841
842 public function provideGetContentModel() {
843 // NOTE: we expect the help namespace to always contain wikitext
844 return [
845 [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ],
846 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ],
847 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
848 ];
849 }
850
855 public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) {
856 $rev = $this->newTestRevision( $text, $title, $model, $format );
857
858 $this->assertEquals( $expectedModel, $rev->getContentModel() );
859 }
860
861 public function provideGetContentFormat() {
862 // NOTE: we expect the help namespace to always contain wikitext
863 return [
864 [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ],
865 [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ],
866 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ],
867 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
868 ];
869 }
870
875 public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) {
876 $rev = $this->newTestRevision( $text, $title, $model, $format );
877
878 $this->assertEquals( $expectedFormat, $rev->getContentFormat() );
879 }
880
881 public function provideGetContentHandler() {
882 // NOTE: we expect the help namespace to always contain wikitext
883 return [
884 [ 'hello world', 'Help:Hello', null, null, WikitextContentHandler::class ],
885 [ 'hello world', 'User:hello/there.css', null, null, CssContentHandler::class ],
886 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentHandlerForTesting::class ],
887 ];
888 }
889
894 public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) {
895 $rev = $this->newTestRevision( $text, $title, $model, $format );
896
897 $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) );
898 }
899
900 public function provideGetContent() {
901 // NOTE: we expect the help namespace to always contain wikitext
902 return [
903 [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ],
904 [
905 serialize( 'hello world' ),
906 'Hello',
908 null,
910 serialize( 'hello world' )
911 ],
912 [
913 serialize( 'hello world' ),
914 'Dummy:Hello',
915 null,
916 null,
918 serialize( 'hello world' )
919 ],
920 ];
921 }
922
927 public function testGetContent( $text, $title, $model, $format,
928 $audience, $expectedSerialization
929 ) {
930 $rev = $this->newTestRevision( $text, $title, $model, $format );
931 $content = $rev->getContent( $audience );
932
933 $this->assertEquals(
934 $expectedSerialization,
935 is_null( $content ) ? null : $content->serialize( $format )
936 );
937 }
938
942 public function testGetContent_failure() {
943 $rev = new Revision( [
944 'page' => $this->testPage->getId(),
945 'content_model' => $this->testPage->getContentModel(),
946 'id' => 123456789, // not in the test DB
947 ] );
948
949 Wikimedia\suppressWarnings(); // bad text_id will trigger a warning.
950
951 $this->assertNull( $rev->getContent(),
952 "getContent() should return null if the revision's text blob could not be loaded." );
953
954 // NOTE: check this twice, once for lazy initialization, and once with the cached value.
955 $this->assertNull( $rev->getContent(),
956 "getContent() should return null if the revision's text blob could not be loaded." );
957
958 Wikimedia\restoreWarnings();
959 }
960
961 public function provideGetSize() {
962 return [
963 [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ],
964 [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ],
965 ];
966 }
967
972 public function testGetSize( $text, $model, $expected_size ) {
973 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model );
974 $this->assertEquals( $expected_size, $rev->getSize() );
975 }
976
977 public function provideGetSha1() {
978 return [
979 [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ],
980 [
981 serialize( "hello world." ),
983 Revision::base36Sha1( serialize( "hello world." ) )
984 ],
985 ];
986 }
987
992 public function testGetSha1( $text, $model, $expected_hash ) {
993 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model );
994 $this->assertEquals( $expected_hash, $rev->getSha1() );
995 }
996
1002 public function testGetContentClone() {
1004
1005 $rev = new Revision(
1006 [
1007 'id' => 42,
1008 'page' => 23,
1009 'title' => Title::newFromText( "testGetContentClone_dummy" ),
1010
1011 'content' => $content,
1012 'length' => $content->getSize(),
1013 'comment' => "testing",
1014 'minor_edit' => false,
1015 ]
1016 );
1017
1019 $content = $rev->getContent( Revision::RAW );
1020 $content->setText( "bar" );
1021
1023 $content2 = $rev->getContent( Revision::RAW );
1024 // content is mutable, expect clone
1025 $this->assertNotSame( $content, $content2, "expected a clone" );
1026 // clone should contain the original text
1027 $this->assertEquals( "foo", $content2->getText() );
1028
1029 $content2->setText( "bla bla" );
1030 // clones should be independent
1031 $this->assertEquals( "bar", $content->getText() );
1032 }
1033
1038 public function testGetContentUncloned() {
1039 $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT );
1040 $content = $rev->getContent( Revision::RAW );
1041 $content2 = $rev->getContent( Revision::RAW );
1042
1043 // for immutable content like wikitext, this should be the same object
1044 $this->assertSame( $content, $content2 );
1045 }
1046
1050 public function testLoadFromId() {
1051 $rev = $this->testPage->getRevision();
1052 $this->hideDeprecated( 'Revision::loadFromId' );
1053 $this->assertRevEquals(
1054 $rev,
1056 );
1057 }
1058
1062 public function testLoadFromPageId() {
1063 $this->assertRevEquals(
1064 $this->testPage->getRevision(),
1065 Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() )
1066 );
1067 }
1068
1073 $this->assertRevEquals(
1074 $this->testPage->getRevision(),
1076 wfGetDB( DB_MASTER ),
1077 $this->testPage->getId(),
1078 $this->testPage->getLatest()
1079 )
1080 );
1081 }
1082
1087 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1088 $this->assertRevEquals(
1089 $this->testPage->getRevision()->getPrevious(),
1091 wfGetDB( DB_MASTER ),
1092 $this->testPage->getId(),
1093 $this->testPage->getRevision()->getPrevious()->getId()
1094 )
1095 );
1096 }
1097
1101 public function testLoadFromTitle() {
1102 $this->assertRevEquals(
1103 $this->testPage->getRevision(),
1104 Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() )
1105 );
1106 }
1107
1112 $this->assertRevEquals(
1113 $this->testPage->getRevision(),
1115 wfGetDB( DB_MASTER ),
1116 $this->testPage->getTitle(),
1117 $this->testPage->getLatest()
1118 )
1119 );
1120 }
1121
1126 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1127 $this->assertRevEquals(
1128 $this->testPage->getRevision()->getPrevious(),
1130 wfGetDB( DB_MASTER ),
1131 $this->testPage->getTitle(),
1132 $this->testPage->getRevision()->getPrevious()->getId()
1133 )
1134 );
1135 }
1136
1140 public function testLoadFromTimestamp() {
1141 $this->assertRevEquals(
1142 $this->testPage->getRevision(),
1144 wfGetDB( DB_MASTER ),
1145 $this->testPage->getTitle(),
1146 $this->testPage->getRevision()->getTimestamp()
1147 )
1148 );
1149 }
1150
1155 $this->assertSame(
1156 [],
1158 wfGetDB( DB_MASTER ),
1159 []
1160 )
1161 );
1162 }
1163
1168 $text = '831jr091jr0921kr21kr0921kjr0921j09rj1';
1169 $textLength = strlen( $text );
1170
1171 $this->testPage->doEditContent( new WikitextContent( $text ), __METHOD__ );
1172 $rev[1] = $this->testPage->getLatest();
1173
1174 $this->assertSame(
1175 [ $rev[1] => $textLength ],
1177 wfGetDB( DB_MASTER ),
1178 [ $rev[1] ]
1179 )
1180 );
1181 }
1182
1187 $textOne = '831jr091jr0921kr21kr0921kjr0921j09rj1';
1188 $textOneLength = strlen( $textOne );
1189 $textTwo = '831jr091jr092121j09rj1';
1190 $textTwoLength = strlen( $textTwo );
1191
1192 $this->testPage->doEditContent( new WikitextContent( $textOne ), __METHOD__ );
1193 $rev[1] = $this->testPage->getLatest();
1194 $this->testPage->doEditContent( new WikitextContent( $textTwo ), __METHOD__ );
1195 $rev[2] = $this->testPage->getLatest();
1196
1197 $this->assertSame(
1198 [ $rev[1] => $textOneLength, $rev[2] => $textTwoLength ],
1200 wfGetDB( DB_MASTER ),
1201 [ $rev[1], $rev[2] ]
1202 )
1203 );
1204 }
1205
1210 $this->assertTrue(
1211 $this->testPage->getTitle()->equals(
1212 $this->testPage->getRevision()->getTitle()
1213 )
1214 );
1215 }
1216
1221 $rev = new Revision( [ 'id' => $this->testPage->getLatest() ] );
1222 $this->assertTrue(
1223 $this->testPage->getTitle()->equals(
1224 $rev->getTitle()
1225 )
1226 );
1227 }
1228
1232 public function testIsMinor_true() {
1233 // Use a sysop to ensure we can mark edits as minor
1234 $sysop = $this->getTestSysop()->getUser();
1235
1236 $this->testPage->doEditContent(
1237 new WikitextContent( __METHOD__ ),
1238 __METHOD__,
1239 EDIT_MINOR,
1240 false,
1241 $sysop
1242 );
1243 $rev = $this->testPage->getRevision();
1244
1245 $this->assertSame( true, $rev->isMinor() );
1246 }
1247
1251 public function testIsMinor_false() {
1252 $this->testPage->doEditContent(
1253 new WikitextContent( __METHOD__ ),
1254 __METHOD__,
1255 0
1256 );
1257 $rev = $this->testPage->getRevision();
1258
1259 $this->assertSame( false, $rev->isMinor() );
1260 }
1261
1265 public function testGetTimestamp() {
1266 $testTimestamp = wfTimestampNow();
1267
1268 $this->testPage->doEditContent(
1269 new WikitextContent( __METHOD__ ),
1270 __METHOD__
1271 );
1272 $rev = $this->testPage->getRevision();
1273
1274 $this->assertInternalType( 'string', $rev->getTimestamp() );
1275 $this->assertTrue( strlen( $rev->getTimestamp() ) == strlen( 'YYYYMMDDHHMMSS' ) );
1276 $this->assertContains( substr( $testTimestamp, 0, 10 ), $rev->getTimestamp() );
1277 }
1278
1283 public function testGetUserAndText() {
1284 $sysop = $this->getTestSysop()->getUser();
1285
1286 $this->testPage->doEditContent(
1287 new WikitextContent( __METHOD__ ),
1288 __METHOD__,
1289 0,
1290 false,
1291 $sysop
1292 );
1293 $rev = $this->testPage->getRevision();
1294
1295 $this->assertSame( $sysop->getId(), $rev->getUser() );
1296 $this->assertSame( $sysop->getName(), $rev->getUserText() );
1297 }
1298
1303 $rev = $this->testPage->getRevision();
1304
1305 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
1306 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_COMMENT ) );
1307 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_RESTRICTED ) );
1308 $this->assertSame( false, $rev->isDeleted( Revision::DELETED_USER ) );
1309 }
1310
1315 $rev = $this->testPage->getRevision();
1316
1317 $this->assertSame( 0, $rev->getVisibility() );
1318 }
1319
1323 public function testGetComment_notDeleted() {
1324 $expectedSummary = 'goatlicious summary';
1325
1326 $this->testPage->doEditContent(
1327 new WikitextContent( __METHOD__ ),
1328 $expectedSummary
1329 );
1330 $rev = $this->testPage->getRevision();
1331
1332 $this->assertSame( $expectedSummary, $rev->getComment() );
1333 }
1334
1339 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1340 $rev = $this->testPage->getRevision();
1341
1342 $this->assertGreaterThan( 0, $rev->isUnpatrolled() );
1343 $this->assertSame( $rev->getRecentChange()->getAttribute( 'rc_id' ), $rev->isUnpatrolled() );
1344 }
1345
1350 // This assumes that sysops are auto patrolled
1351 $sysop = $this->getTestSysop()->getUser();
1352 $this->testPage->doEditContent(
1353 new WikitextContent( __METHOD__ ),
1354 __METHOD__,
1355 0,
1356 false,
1357 $sysop
1358 );
1359 $rev = $this->testPage->getRevision();
1360
1361 $this->assertSame( 0, $rev->isUnpatrolled() );
1362 }
1363
1373 public function testSimpleContentGetters() {
1374 $expectedText = 'testSimpleContentGetters in Revision. Goats love MCR...';
1375 $expectedSummary = 'goatlicious testSimpleContentGetters summary';
1376
1377 $this->testPage->doEditContent(
1378 new WikitextContent( $expectedText ),
1379 $expectedSummary
1380 );
1381 $rev = $this->testPage->getRevision();
1382
1383 $this->assertSame( $expectedText, $rev->getContent()->getText() );
1384 $this->assertSame( $expectedText, $rev->getSerializedData() );
1385 $this->assertSame( $this->testPage->getContentModel(), $rev->getContentModel() );
1386 $this->assertSame( $this->testPage->getContent()->getDefaultFormat(), $rev->getContentFormat() );
1387 $this->assertSame( $this->testPage->getContentHandler(), $rev->getContentHandler() );
1388 }
1389
1393 public function testNewKnownCurrent() {
1394 // Setup the services
1395 $this->overrideMwServices();
1396 $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
1397 $this->setService( 'MainWANObjectCache', $cache );
1398 $db = wfGetDB( DB_MASTER );
1399
1400 $now = 1553893742;
1401 $cache->setMockTime( $now );
1402
1403 // Get a fresh revision to use during testing
1404 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1405 $rev = $this->testPage->getRevision();
1406
1407 // Clear any previous cache for the revision during creation
1408 $key = $cache->makeGlobalKey(
1409 RevisionStore::ROW_CACHE_KEY,
1410 $db->getDomainID(),
1411 $rev->getPage(),
1412 $rev->getId()
1413 );
1414 $cache->delete( $key, WANObjectCache::HOLDOFF_NONE );
1415 $this->assertFalse( $cache->get( $key ) );
1416
1417 ++$now;
1418
1419 // Get the new revision and make sure it is in the cache and correct
1420 $newRev = Revision::newKnownCurrent( $db, $rev->getPage(), $rev->getId() );
1421 $this->assertRevEquals( $rev, $newRev );
1422
1423 $cachedRow = $cache->get( $key );
1424 $this->assertNotFalse( $cachedRow );
1425 $this->assertEquals( $rev->getId(), $cachedRow->rev_id );
1426 }
1427
1429 $db = wfGetDB( DB_MASTER );
1430
1431 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
1432 $rev = $this->testPage->getRevision();
1433
1434 $pageId = $this->testPage->getId();
1435
1436 $newRev = Revision::newKnownCurrent( $db, $pageId, $rev->getId() );
1437 $this->assertRevEquals( $rev, $newRev );
1438 }
1439
1441 $db = wfGetDB( DB_MASTER );
1442
1443 $this->assertFalse( Revision::newKnownCurrent( $db, 0 ) );
1444 }
1445
1446 public function provideUserCanBitfield() {
1447 yield [ 0, 0, [], null, true ];
1448 // Bitfields match, user has no permissions
1453 // Bitfields match, user (admin) does have permissions
1454 yield [ Revision::DELETED_TEXT, Revision::DELETED_TEXT, [ 'sysop' ], null, true ];
1455 yield [ Revision::DELETED_COMMENT, Revision::DELETED_COMMENT, [ 'sysop' ], null, true ];
1456 yield [ Revision::DELETED_USER, Revision::DELETED_USER, [ 'sysop' ], null, true ];
1457 // Bitfields match, user (admin) does not have permissions
1459 // Bitfields match, user (oversight) does have permissions
1460 yield [ Revision::DELETED_RESTRICTED, Revision::DELETED_RESTRICTED, [ 'oversight' ], null, true ];
1461 // Check permissions using the title
1462 yield [
1465 [ 'sysop' ],
1466 __METHOD__,
1467 true,
1468 ];
1469 yield [
1472 [],
1473 __METHOD__,
1474 false,
1475 ];
1476 }
1477
1482 public function testUserCanBitfield( $bitField, $field, $userGroups, $title, $expected ) {
1483 $title = Title::newFromText( $title );
1484
1485 $this->setMwGlobals(
1486 'wgGroupPermissions',
1487 [
1488 'sysop' => [
1489 'deletedtext' => true,
1490 'deletedhistory' => true,
1491 ],
1492 'oversight' => [
1493 'viewsuppressed' => true,
1494 'suppressrevision' => true,
1495 ],
1496 ]
1497 );
1498 $user = $this->getTestUser( $userGroups )->getUser();
1499
1500 $this->assertSame(
1501 $expected,
1502 Revision::userCanBitfield( $bitField, $field, $user, $title )
1503 );
1504
1505 // Fallback to $wgUser
1506 $this->setMwGlobals(
1507 'wgUser',
1508 $user
1509 );
1510 $this->assertSame(
1511 $expected,
1512 Revision::userCanBitfield( $bitField, $field, null, $title )
1513 );
1514 }
1515
1516 public function provideUserCan() {
1517 yield [ 0, 0, [], true ];
1518 // Bitfields match, user has no permissions
1523 // Bitfields match, user (admin) does have permissions
1524 yield [ Revision::DELETED_TEXT, Revision::DELETED_TEXT, [ 'sysop' ], true ];
1526 yield [ Revision::DELETED_USER, Revision::DELETED_USER, [ 'sysop' ], true ];
1527 // Bitfields match, user (admin) does not have permissions
1529 // Bitfields match, user (oversight) does have permissions
1531 }
1532
1537 public function testUserCan( $bitField, $field, $userGroups, $expected ) {
1538 $this->setMwGlobals(
1539 'wgGroupPermissions',
1540 [
1541 'sysop' => [
1542 'deletedtext' => true,
1543 'deletedhistory' => true,
1544 ],
1545 'oversight' => [
1546 'viewsuppressed' => true,
1547 'suppressrevision' => true,
1548 ],
1549 ]
1550 );
1551 $user = $this->getTestUser( $userGroups )->getUser();
1552 $revision = new Revision( [ 'deleted' => $bitField ], 0, $this->testPage->getTitle() );
1553
1554 $this->assertSame(
1555 $expected,
1556 $revision->userCan( $field, $user )
1557 );
1558 }
1559
1560 public function provideGetTextId() {
1561 yield [ [], null ];
1562
1563 $slot = new SlotRecord( (object)[
1564 'slot_revision_id' => 42,
1565 'slot_content_id' => 1,
1566 'content_address' => 'tt:789',
1567 'model_name' => CONTENT_MODEL_WIKITEXT,
1568 'role_name' => SlotRecord::MAIN,
1569 'slot_origin' => 1,
1570 ], new WikitextContent( 'Test' ) );
1571
1572 $rec = new MutableRevisionRecord( $this->testPage->getTitle() );
1573 $rec->setId( 42 );
1574 $rec->setSlot( $slot );
1575
1576 yield [ $rec, 789 ];
1577 }
1578
1583 public function testGetTextId( $spec, $expected ) {
1584 $rev = new Revision( $spec, 0, $this->testPage->getTitle() );
1585 $this->assertSame( $expected, $rev->getTextId() );
1586 }
1587
1588 public function provideGetRevisionText() {
1589 yield [
1590 [ 'text' ]
1591 ];
1592 }
1593
1598 public function testGetRevisionText( array $queryInfoOptions, array $queryInfoExtra = [] ) {
1599 $rev = $this->testPage->getRevisionRecord();
1600
1601 $queryInfo = Revision::getQueryInfo( $queryInfoOptions );
1602 $queryInfo['tables'] = array_merge( $queryInfo['tables'], $queryInfoExtra['tables'] ?? [] );
1603 $queryInfo['fields'] = array_merge( $queryInfo['fields'], $queryInfoExtra['fields'] ?? [] );
1604 $queryInfo['joins'] = array_merge( $queryInfo['joins'], $queryInfoExtra['joins'] ?? [] );
1605
1606 $conds = [ 'rev_id' => $rev->getId() ];
1607 $row = $this->db->selectRow(
1608 $queryInfo['tables'],
1609 $queryInfo['fields'],
1610 $conds,
1611 __METHOD__,
1612 [],
1613 $queryInfo['joins']
1614 );
1615
1616 $expected = $rev->getContent( SlotRecord::MAIN )->serialize();
1617
1618 $this->hideDeprecated( 'Revision::getRevisionText (MCR without SCHEMA_COMPAT_WRITE_OLD)' );
1619 $this->assertSame( $expected, Revision::getRevisionText( $row ) );
1620 }
1621
1622}
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
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.
testGetRevisionText(array $queryInfoOptions, array $queryInfoExtra=[])
provideGetRevisionText Revision::getRevisionText
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:638
static newKnownCurrent(IDatabase $db, $pageIdOrTitle, $revId=0)
Load a revision based on a known page ID and current revision ID from the DB.
static getRevisionText( $row, $prefix='old_', $wiki=false)
Get revision text associated with an old or archive row.
static loadFromTitle( $db, $title, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
Definition Revision.php:277
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:156
getContentFormat()
Returns the content format for the main slot of this revision.
Definition Revision.php:970
static loadFromTimestamp( $db, $title, $timestamp)
Load the revision for the given title with the given timestamp.
Definition Revision.php:295
getPage()
Get the page ID.
Definition Revision.php:782
static getArchiveQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new archived revision objec...
Definition Revision.php:525
static newFromRow( $row)
Definition Revision.php:222
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:242
getContentModel()
Returns the content model for the main slot of this revision.
Definition Revision.php:955
getUser( $audience=self::FOR_PUBLIC, User $user=null)
Fetch revision's user id if it's available to the specified audience.
Definition Revision.php:799
static newFromArchiveRow( $row, $overrides=[])
Make a fake revision object from an archive table row.
Definition Revision.php:171
const DELETED_USER
Definition Revision.php:48
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
Definition Revision.php:511
const DELETED_TEXT
Definition Revision.php:46
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:739
const DELETED_RESTRICTED
Definition Revision.php:49
static loadFromPageId( $db, $pageid, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
Definition Revision.php:260
getTimestamp()
Definition Revision.php:994
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:538
const FOR_PUBLIC
Definition Revision.php:54
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:137
const RAW
Definition Revision.php:56
const DELETED_COMMENT
Definition Revision.php:47
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition Revision.php:118
Content object implementation for representing flat text.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition User.php:585
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition User.php:4300
Multi-datacenter aware caching interface.
Class representing a MediaWiki article and history.
Definition WikiPage.php:45
getDomainID()
Return the currently selected domain ID.
Definition Database.php:853
Content object for wiki text pages.
$res
Definition database.txt:21
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
const CONTENT_MODEL_CSS
Definition Defines.php:246
const CONTENT_FORMAT_CSS
Definition Defines.php:263
const CONTENT_MODEL_WIKITEXT
Definition Defines.php:244
const CONTENT_FORMAT_WIKITEXT
Definition Defines.php:259
const SCHEMA_COMPAT_NEW
Definition Defines.php:300
const EDIT_MINOR
Definition Defines.php:163
const EDIT_NEW
Definition Defines.php:161
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:955
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition hooks.txt:783
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:2004
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:2290
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:271
return true to allow those checks to and false if checking is done & $user
Definition hooks.txt:1510
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:1779
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
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
$f
Definition router.php:79