Merge "registration: Only allow one extension to set a specific config setting"
[lhc/web/wiklou.git] / tests / phpunit / includes / RevisionIntegrationTest.php
1 <?php
2
3 /**
4 * @group ContentHandler
5 * @group Database
6 *
7 * @group medium
8 */
9 class RevisionIntegrationTest extends MediaWikiTestCase {
10
11 /**
12 * @var WikiPage $testPage
13 */
14 private $testPage;
15
16 public function __construct( $name = null, array $data = [], $dataName = '' ) {
17 parent::__construct( $name, $data, $dataName );
18
19 $this->tablesUsed = array_merge( $this->tablesUsed,
20 [
21 'page',
22 'revision',
23 'ip_changes',
24 'text',
25 'archive',
26
27 'recentchanges',
28 'logging',
29
30 'page_props',
31 'pagelinks',
32 'categorylinks',
33 'langlinks',
34 'externallinks',
35 'imagelinks',
36 'templatelinks',
37 'iwlinks'
38 ]
39 );
40 }
41
42 protected function setUp() {
43 global $wgContLang;
44
45 parent::setUp();
46
47 $this->mergeMwGlobalArrayValue(
48 'wgExtraNamespaces',
49 [
50 12312 => 'Dummy',
51 12313 => 'Dummy_talk',
52 ]
53 );
54
55 $this->mergeMwGlobalArrayValue(
56 'wgNamespaceContentModels',
57 [
58 12312 => DummyContentForTesting::MODEL_ID,
59 ]
60 );
61
62 $this->mergeMwGlobalArrayValue(
63 'wgContentHandlers',
64 [
65 DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting',
66 RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler',
67 ]
68 );
69
70 MWNamespace::clearCaches();
71 // Reset namespace cache
72 $wgContLang->resetNamespaces();
73 if ( !$this->testPage ) {
74 $this->testPage = WikiPage::factory( Title::newFromText( 'UTPage' ) );
75 }
76 }
77
78 protected function tearDown() {
79 global $wgContLang;
80
81 parent::tearDown();
82
83 MWNamespace::clearCaches();
84 // Reset namespace cache
85 $wgContLang->resetNamespaces();
86 }
87
88 private function makeRevisionWithProps( $props = null ) {
89 if ( $props === null ) {
90 $props = [];
91 }
92
93 if ( !isset( $props['content'] ) && !isset( $props['text'] ) ) {
94 $props['text'] = 'Lorem Ipsum';
95 }
96
97 if ( !isset( $props['comment'] ) ) {
98 $props['comment'] = 'just a test';
99 }
100
101 if ( !isset( $props['page'] ) ) {
102 $props['page'] = $this->testPage->getId();
103 }
104
105 $rev = new Revision( $props );
106
107 $dbw = wfGetDB( DB_MASTER );
108 $rev->insertOn( $dbw );
109
110 return $rev;
111 }
112
113 /**
114 * @param string $titleString
115 * @param string $text
116 * @param string|null $model
117 *
118 * @return WikiPage
119 */
120 private function createPage( $titleString, $text, $model = null ) {
121 if ( !preg_match( '/:/', $titleString ) &&
122 ( $model === null || $model === CONTENT_MODEL_WIKITEXT )
123 ) {
124 $ns = $this->getDefaultWikitextNS();
125 $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString;
126 }
127
128 $title = Title::newFromText( $titleString );
129 $wikipage = new WikiPage( $title );
130
131 // Delete the article if it already exists
132 if ( $wikipage->exists() ) {
133 $wikipage->doDeleteArticle( "done" );
134 }
135
136 $content = ContentHandler::makeContent( $text, $title, $model );
137 $wikipage->doEditContent( $content, __METHOD__, EDIT_NEW );
138
139 return $wikipage;
140 }
141
142 private function assertRevEquals( Revision $orig, Revision $rev = null ) {
143 $this->assertNotNull( $rev, 'missing revision' );
144
145 $this->assertEquals( $orig->getId(), $rev->getId() );
146 $this->assertEquals( $orig->getPage(), $rev->getPage() );
147 $this->assertEquals( $orig->getTimestamp(), $rev->getTimestamp() );
148 $this->assertEquals( $orig->getUser(), $rev->getUser() );
149 $this->assertEquals( $orig->getContentModel(), $rev->getContentModel() );
150 $this->assertEquals( $orig->getContentFormat(), $rev->getContentFormat() );
151 $this->assertEquals( $orig->getSha1(), $rev->getSha1() );
152 }
153
154 /**
155 * @covers Revision::newFromTitle
156 */
157 public function testNewFromTitle_withoutId() {
158 $latestRevId = $this->testPage->getLatest();
159
160 $rev = Revision::newFromTitle( $this->testPage->getTitle() );
161
162 $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
163 $this->assertEquals( $latestRevId, $rev->getId() );
164 }
165
166 /**
167 * @covers Revision::newFromTitle
168 */
169 public function testNewFromTitle_withId() {
170 $latestRevId = $this->testPage->getLatest();
171
172 $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId );
173
174 $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) );
175 $this->assertEquals( $latestRevId, $rev->getId() );
176 }
177
178 /**
179 * @covers Revision::newFromTitle
180 */
181 public function testNewFromTitle_withBadId() {
182 $latestRevId = $this->testPage->getLatest();
183
184 $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId + 1 );
185
186 $this->assertNull( $rev );
187 }
188
189 /**
190 * @covers Revision::newFromRow
191 */
192 public function testNewFromRow() {
193 $orig = $this->makeRevisionWithProps();
194
195 $dbr = wfGetDB( DB_REPLICA );
196 $res = $dbr->select( 'revision', Revision::selectFields(), [ 'rev_id' => $orig->getId() ] );
197 $this->assertTrue( is_object( $res ), 'query failed' );
198
199 $row = $res->fetchObject();
200 $res->free();
201
202 $rev = Revision::newFromRow( $row );
203
204 $this->assertRevEquals( $orig, $rev );
205 }
206
207 public function provideNewFromArchiveRow() {
208 yield [
209 true,
210 function ( $f ) {
211 return $f;
212 },
213 ];
214 yield [
215 false,
216 function ( $f ) {
217 return $f;
218 },
219 ];
220 yield [
221 true,
222 function ( $f ) {
223 return $f + [ 'ar_namespace', 'ar_title' ];
224 },
225 ];
226 yield [
227 false,
228 function ( $f ) {
229 return $f + [ 'ar_namespace', 'ar_title' ];
230 },
231 ];
232 yield [
233 true,
234 function ( $f ) {
235 unset( $f['ar_text_id'] );
236 return $f;
237 },
238 ];
239 yield [
240 false,
241 function ( $f ) {
242 unset( $f['ar_text_id'] );
243 return $f;
244 },
245 ];
246 }
247
248 /**
249 * @dataProvider provideNewFromArchiveRow
250 * @covers Revision::newFromArchiveRow
251 */
252 public function testNewFromArchiveRow( $contentHandlerUseDB, $selectModifier ) {
253 $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB );
254
255 $page = $this->createPage(
256 'RevisionStorageTest_testNewFromArchiveRow',
257 'Lorem Ipsum',
258 CONTENT_MODEL_WIKITEXT
259 );
260 $orig = $page->getRevision();
261 $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
262
263 $dbr = wfGetDB( DB_REPLICA );
264 $selectFields = $selectModifier( Revision::selectArchiveFields() );
265 $res = $dbr->select(
266 'archive', $selectFields, [ 'ar_rev_id' => $orig->getId() ]
267 );
268 $this->assertTrue( is_object( $res ), 'query failed' );
269
270 $row = $res->fetchObject();
271 $res->free();
272
273 $rev = Revision::newFromArchiveRow( $row );
274
275 $this->assertRevEquals( $orig, $rev );
276 }
277
278 /**
279 * @covers Revision::newFromArchiveRow
280 */
281 public function testNewFromArchiveRowOverrides() {
282 $page = $this->createPage(
283 'RevisionStorageTest_testNewFromArchiveRow',
284 'Lorem Ipsum',
285 CONTENT_MODEL_WIKITEXT
286 );
287 $orig = $page->getRevision();
288 $page->doDeleteArticle( 'test Revision::newFromArchiveRow' );
289
290 $dbr = wfGetDB( DB_REPLICA );
291 $res = $dbr->select(
292 'archive', Revision::selectArchiveFields(), [ 'ar_rev_id' => $orig->getId() ]
293 );
294 $this->assertTrue( is_object( $res ), 'query failed' );
295
296 $row = $res->fetchObject();
297 $res->free();
298
299 $rev = Revision::newFromArchiveRow( $row, [ 'comment' => 'SOMEOVERRIDE' ] );
300
301 $this->assertNotEquals( $orig->getComment(), $rev->getComment() );
302 $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() );
303 }
304
305 /**
306 * @covers Revision::newFromId
307 */
308 public function testNewFromId() {
309 $orig = $this->testPage->getRevision();
310 $rev = Revision::newFromId( $orig->getId() );
311 $this->assertRevEquals( $orig, $rev );
312 }
313
314 /**
315 * @covers Revision::newFromPageId
316 */
317 public function testNewFromPageId() {
318 $rev = Revision::newFromPageId( $this->testPage->getId() );
319 $this->assertRevEquals(
320 $this->testPage->getRevision(),
321 $rev
322 );
323 }
324
325 /**
326 * @covers Revision::newFromPageId
327 */
328 public function testNewFromPageIdWithLatestId() {
329 $rev = Revision::newFromPageId(
330 $this->testPage->getId(),
331 $this->testPage->getLatest()
332 );
333 $this->assertRevEquals(
334 $this->testPage->getRevision(),
335 $rev
336 );
337 }
338
339 /**
340 * @covers Revision::newFromPageId
341 */
342 public function testNewFromPageIdWithNotLatestId() {
343 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
344 $rev = Revision::newFromPageId(
345 $this->testPage->getId(),
346 $this->testPage->getRevision()->getPrevious()->getId()
347 );
348 $this->assertRevEquals(
349 $this->testPage->getRevision()->getPrevious(),
350 $rev
351 );
352 }
353
354 /**
355 * @covers Revision::fetchRevision
356 */
357 public function testFetchRevision() {
358 // Hidden process cache assertion below
359 $this->testPage->getRevision()->getId();
360
361 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
362 $id = $this->testPage->getRevision()->getId();
363
364 $res = Revision::fetchRevision( $this->testPage->getTitle() );
365
366 # note: order is unspecified
367 $rows = [];
368 while ( ( $row = $res->fetchObject() ) ) {
369 $rows[$row->rev_id] = $row;
370 }
371
372 $this->assertEquals( 1, count( $rows ), 'expected exactly one revision' );
373 $this->assertArrayHasKey( $id, $rows, 'missing revision with id ' . $id );
374 }
375
376 /**
377 * @covers Revision::getPage
378 */
379 public function testGetPage() {
380 $page = $this->testPage;
381
382 $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] );
383 $rev = Revision::newFromId( $orig->getId() );
384
385 $this->assertEquals( $page->getId(), $rev->getPage() );
386 }
387
388 /**
389 * @covers Revision::isCurrent
390 */
391 public function testIsCurrent() {
392 $rev1 = $this->testPage->getRevision();
393
394 # @todo find out if this should be true
395 # $this->assertTrue( $rev1->isCurrent() );
396
397 $rev1x = Revision::newFromId( $rev1->getId() );
398 $this->assertTrue( $rev1x->isCurrent() );
399
400 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
401 $rev2 = $this->testPage->getRevision();
402
403 # @todo find out if this should be true
404 # $this->assertTrue( $rev2->isCurrent() );
405
406 $rev1x = Revision::newFromId( $rev1->getId() );
407 $this->assertFalse( $rev1x->isCurrent() );
408
409 $rev2x = Revision::newFromId( $rev2->getId() );
410 $this->assertTrue( $rev2x->isCurrent() );
411 }
412
413 /**
414 * @covers Revision::getPrevious
415 */
416 public function testGetPrevious() {
417 $oldestRevision = $this->testPage->getOldestRevision();
418 $latestRevision = $this->testPage->getLatest();
419
420 $this->assertNull( $oldestRevision->getPrevious() );
421
422 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
423 $newRevision = $this->testPage->getRevision();
424
425 $this->assertNotNull( $newRevision->getPrevious() );
426 $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() );
427 }
428
429 /**
430 * @covers Revision::getNext
431 */
432 public function testGetNext() {
433 $rev1 = $this->testPage->getRevision();
434
435 $this->assertNull( $rev1->getNext() );
436
437 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
438 $rev2 = $this->testPage->getRevision();
439
440 $this->assertNotNull( $rev1->getNext() );
441 $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() );
442 }
443
444 /**
445 * @covers Revision::newNullRevision
446 */
447 public function testNewNullRevision() {
448 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
449 $orig = $this->testPage->getRevision();
450
451 $dbw = wfGetDB( DB_MASTER );
452 $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false );
453
454 $this->assertNotEquals( $orig->getId(), $rev->getId(),
455 'new null revision should have a different id from the original revision' );
456 $this->assertEquals( $orig->getTextId(), $rev->getTextId(),
457 'new null revision should have the same text id as the original revision' );
458 $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() );
459 }
460
461 /**
462 * @covers Revision::insertOn
463 */
464 public function testInsertOn() {
465 $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7';
466
467 $orig = $this->makeRevisionWithProps( [
468 'user_text' => $ip
469 ] );
470
471 // Make sure the revision was copied to ip_changes
472 $dbr = wfGetDB( DB_REPLICA );
473 $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] );
474 $row = $res->fetchObject();
475
476 $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex );
477 $this->assertEquals( $orig->getTimestamp(), $row->ipc_rev_timestamp );
478 }
479
480 public static function provideUserWasLastToEdit() {
481 yield 'actually the last edit' => [ 3, true ];
482 yield 'not the current edit, but still by this user' => [ 2, true ];
483 yield 'edit by another user' => [ 1, false ];
484 yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ];
485 }
486
487 /**
488 * @dataProvider provideUserWasLastToEdit
489 */
490 public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) {
491 $userA = User::newFromName( "RevisionStorageTest_userA" );
492 $userB = User::newFromName( "RevisionStorageTest_userB" );
493
494 if ( $userA->getId() === 0 ) {
495 $userA = User::createNew( $userA->getName() );
496 }
497
498 if ( $userB->getId() === 0 ) {
499 $userB = User::createNew( $userB->getName() );
500 }
501
502 $ns = $this->getDefaultWikitextNS();
503
504 $dbw = wfGetDB( DB_MASTER );
505 $revisions = [];
506
507 // create revisions -----------------------------
508 $page = WikiPage::factory( Title::newFromText(
509 'RevisionStorageTest_testUserWasLastToEdit', $ns ) );
510 $page->insertOn( $dbw );
511
512 $revisions[0] = new Revision( [
513 'page' => $page->getId(),
514 // we need the title to determine the page's default content model
515 'title' => $page->getTitle(),
516 'timestamp' => '20120101000000',
517 'user' => $userA->getId(),
518 'text' => 'zero',
519 'content_model' => CONTENT_MODEL_WIKITEXT,
520 'summary' => 'edit zero'
521 ] );
522 $revisions[0]->insertOn( $dbw );
523
524 $revisions[1] = new Revision( [
525 'page' => $page->getId(),
526 // still need the title, because $page->getId() is 0 (there's no entry in the page table)
527 'title' => $page->getTitle(),
528 'timestamp' => '20120101000100',
529 'user' => $userA->getId(),
530 'text' => 'one',
531 'content_model' => CONTENT_MODEL_WIKITEXT,
532 'summary' => 'edit one'
533 ] );
534 $revisions[1]->insertOn( $dbw );
535
536 $revisions[2] = new Revision( [
537 'page' => $page->getId(),
538 'title' => $page->getTitle(),
539 'timestamp' => '20120101000200',
540 'user' => $userB->getId(),
541 'text' => 'two',
542 'content_model' => CONTENT_MODEL_WIKITEXT,
543 'summary' => 'edit two'
544 ] );
545 $revisions[2]->insertOn( $dbw );
546
547 $revisions[3] = new Revision( [
548 'page' => $page->getId(),
549 'title' => $page->getTitle(),
550 'timestamp' => '20120101000300',
551 'user' => $userA->getId(),
552 'text' => 'three',
553 'content_model' => CONTENT_MODEL_WIKITEXT,
554 'summary' => 'edit three'
555 ] );
556 $revisions[3]->insertOn( $dbw );
557
558 $revisions[4] = new Revision( [
559 'page' => $page->getId(),
560 'title' => $page->getTitle(),
561 'timestamp' => '20120101000200',
562 'user' => $userA->getId(),
563 'text' => 'zero',
564 'content_model' => CONTENT_MODEL_WIKITEXT,
565 'summary' => 'edit four'
566 ] );
567 $revisions[4]->insertOn( $dbw );
568
569 // test it ---------------------------------
570 $since = $revisions[$sinceIdx]->getTimestamp();
571
572 $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since );
573
574 $this->assertEquals( $expectedLast, $wasLast );
575 }
576
577 /**
578 * @param string $text
579 * @param string $title
580 * @param string $model
581 * @param string $format
582 *
583 * @return Revision
584 */
585 private function newTestRevision( $text, $title = "Test",
586 $model = CONTENT_MODEL_WIKITEXT, $format = null
587 ) {
588 if ( is_string( $title ) ) {
589 $title = Title::newFromText( $title );
590 }
591
592 $content = ContentHandler::makeContent( $text, $title, $model, $format );
593
594 $rev = new Revision(
595 [
596 'id' => 42,
597 'page' => 23,
598 'title' => $title,
599
600 'content' => $content,
601 'length' => $content->getSize(),
602 'comment' => "testing",
603 'minor_edit' => false,
604
605 'content_format' => $format,
606 ]
607 );
608
609 return $rev;
610 }
611
612 public function provideGetContentModel() {
613 // NOTE: we expect the help namespace to always contain wikitext
614 return [
615 [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ],
616 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ],
617 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
618 ];
619 }
620
621 /**
622 * @dataProvider provideGetContentModel
623 * @covers Revision::getContentModel
624 */
625 public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) {
626 $rev = $this->newTestRevision( $text, $title, $model, $format );
627
628 $this->assertEquals( $expectedModel, $rev->getContentModel() );
629 }
630
631 public function provideGetContentFormat() {
632 // NOTE: we expect the help namespace to always contain wikitext
633 return [
634 [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ],
635 [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ],
636 [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ],
637 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ],
638 ];
639 }
640
641 /**
642 * @dataProvider provideGetContentFormat
643 * @covers Revision::getContentFormat
644 */
645 public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) {
646 $rev = $this->newTestRevision( $text, $title, $model, $format );
647
648 $this->assertEquals( $expectedFormat, $rev->getContentFormat() );
649 }
650
651 public function provideGetContentHandler() {
652 // NOTE: we expect the help namespace to always contain wikitext
653 return [
654 [ 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ],
655 [ 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ],
656 [ serialize( 'hello world' ), 'Dummy:Hello', null, null, 'DummyContentHandlerForTesting' ],
657 ];
658 }
659
660 /**
661 * @dataProvider provideGetContentHandler
662 * @covers Revision::getContentHandler
663 */
664 public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) {
665 $rev = $this->newTestRevision( $text, $title, $model, $format );
666
667 $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) );
668 }
669
670 public function provideGetContent() {
671 // NOTE: we expect the help namespace to always contain wikitext
672 return [
673 [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ],
674 [
675 serialize( 'hello world' ),
676 'Hello',
677 DummyContentForTesting::MODEL_ID,
678 null,
679 Revision::FOR_PUBLIC,
680 serialize( 'hello world' )
681 ],
682 [
683 serialize( 'hello world' ),
684 'Dummy:Hello',
685 null,
686 null,
687 Revision::FOR_PUBLIC,
688 serialize( 'hello world' )
689 ],
690 ];
691 }
692
693 /**
694 * @dataProvider provideGetContent
695 * @covers Revision::getContent
696 */
697 public function testGetContent( $text, $title, $model, $format,
698 $audience, $expectedSerialization
699 ) {
700 $rev = $this->newTestRevision( $text, $title, $model, $format );
701 $content = $rev->getContent( $audience );
702
703 $this->assertEquals(
704 $expectedSerialization,
705 is_null( $content ) ? null : $content->serialize( $format )
706 );
707 }
708
709 /**
710 * @covers Revision::getContent
711 */
712 public function testGetContent_failure() {
713 $rev = new Revision( [
714 'page' => $this->testPage->getId(),
715 'content_model' => $this->testPage->getContentModel(),
716 'text_id' => 123456789, // not in the test DB
717 ] );
718
719 $this->assertNull( $rev->getContent(),
720 "getContent() should return null if the revision's text blob could not be loaded." );
721
722 // NOTE: check this twice, once for lazy initialization, and once with the cached value.
723 $this->assertNull( $rev->getContent(),
724 "getContent() should return null if the revision's text blob could not be loaded." );
725 }
726
727 public function provideGetSize() {
728 return [
729 [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ],
730 [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ],
731 ];
732 }
733
734 /**
735 * @covers Revision::getSize
736 * @dataProvider provideGetSize
737 */
738 public function testGetSize( $text, $model, $expected_size ) {
739 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model );
740 $this->assertEquals( $expected_size, $rev->getSize() );
741 }
742
743 public function provideGetSha1() {
744 return [
745 [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ],
746 [
747 serialize( "hello world." ),
748 DummyContentForTesting::MODEL_ID,
749 Revision::base36Sha1( serialize( "hello world." ) )
750 ],
751 ];
752 }
753
754 /**
755 * @covers Revision::getSha1
756 * @dataProvider provideGetSha1
757 */
758 public function testGetSha1( $text, $model, $expected_hash ) {
759 $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model );
760 $this->assertEquals( $expected_hash, $rev->getSha1() );
761 }
762
763 /**
764 * Tests whether $rev->getContent() returns a clone when needed.
765 *
766 * @covers Revision::getContent
767 */
768 public function testGetContentClone() {
769 $content = new RevisionTestModifyableContent( "foo" );
770
771 $rev = new Revision(
772 [
773 'id' => 42,
774 'page' => 23,
775 'title' => Title::newFromText( "testGetContentClone_dummy" ),
776
777 'content' => $content,
778 'length' => $content->getSize(),
779 'comment' => "testing",
780 'minor_edit' => false,
781 ]
782 );
783
784 /** @var RevisionTestModifyableContent $content */
785 $content = $rev->getContent( Revision::RAW );
786 $content->setText( "bar" );
787
788 /** @var RevisionTestModifyableContent $content2 */
789 $content2 = $rev->getContent( Revision::RAW );
790 // content is mutable, expect clone
791 $this->assertNotSame( $content, $content2, "expected a clone" );
792 // clone should contain the original text
793 $this->assertEquals( "foo", $content2->getText() );
794
795 $content2->setText( "bla bla" );
796 // clones should be independent
797 $this->assertEquals( "bar", $content->getText() );
798 }
799
800 /**
801 * Tests whether $rev->getContent() returns the same object repeatedly if appropriate.
802 * @covers Revision::getContent
803 */
804 public function testGetContentUncloned() {
805 $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT );
806 $content = $rev->getContent( Revision::RAW );
807 $content2 = $rev->getContent( Revision::RAW );
808
809 // for immutable content like wikitext, this should be the same object
810 $this->assertSame( $content, $content2 );
811 }
812
813 /**
814 * @covers Revision::loadFromId
815 */
816 public function testLoadFromId() {
817 $rev = $this->testPage->getRevision();
818 $this->assertRevEquals(
819 $rev,
820 Revision::loadFromId( wfGetDB( DB_MASTER ), $rev->getId() )
821 );
822 }
823
824 /**
825 * @covers Revision::loadFromPageId
826 */
827 public function testLoadFromPageId() {
828 $this->assertRevEquals(
829 $this->testPage->getRevision(),
830 Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() )
831 );
832 }
833
834 /**
835 * @covers Revision::loadFromPageId
836 */
837 public function testLoadFromPageIdWithLatestRevId() {
838 $this->assertRevEquals(
839 $this->testPage->getRevision(),
840 Revision::loadFromPageId(
841 wfGetDB( DB_MASTER ),
842 $this->testPage->getId(),
843 $this->testPage->getLatest()
844 )
845 );
846 }
847
848 /**
849 * @covers Revision::loadFromPageId
850 */
851 public function testLoadFromPageIdWithNotLatestRevId() {
852 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
853 $this->assertRevEquals(
854 $this->testPage->getRevision()->getPrevious(),
855 Revision::loadFromPageId(
856 wfGetDB( DB_MASTER ),
857 $this->testPage->getId(),
858 $this->testPage->getRevision()->getPrevious()->getId()
859 )
860 );
861 }
862
863 /**
864 * @covers Revision::loadFromTitle
865 */
866 public function testLoadFromTitle() {
867 $this->assertRevEquals(
868 $this->testPage->getRevision(),
869 Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() )
870 );
871 }
872
873 /**
874 * @covers Revision::loadFromTitle
875 */
876 public function testLoadFromTitleWithLatestRevId() {
877 $this->assertRevEquals(
878 $this->testPage->getRevision(),
879 Revision::loadFromTitle(
880 wfGetDB( DB_MASTER ),
881 $this->testPage->getTitle(),
882 $this->testPage->getLatest()
883 )
884 );
885 }
886
887 /**
888 * @covers Revision::loadFromTitle
889 */
890 public function testLoadFromTitleWithNotLatestRevId() {
891 $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
892 $this->assertRevEquals(
893 $this->testPage->getRevision()->getPrevious(),
894 Revision::loadFromTitle(
895 wfGetDB( DB_MASTER ),
896 $this->testPage->getTitle(),
897 $this->testPage->getRevision()->getPrevious()->getId()
898 )
899 );
900 }
901
902 /**
903 * @covers Revision::loadFromTimestamp()
904 */
905 public function testLoadFromTimestamp() {
906 $this->assertRevEquals(
907 $this->testPage->getRevision(),
908 Revision::loadFromTimestamp(
909 wfGetDB( DB_MASTER ),
910 $this->testPage->getTitle(),
911 $this->testPage->getRevision()->getTimestamp()
912 )
913 );
914 }
915
916 }