From: addshore Date: Tue, 24 Oct 2017 13:41:21 +0000 (+0100) Subject: Run RevisionIntegrationTest for both ContentHandlerUseDB settings X-Git-Tag: 1.31.0-rc.0~1553 X-Git-Url: http://git.cyclocoop.org/%7B%24admin_url%7Dmembres/cotisations/gestion/rappel_supprimer.php?a=commitdiff_plain;h=aab3e3be884ec98155788c9b9a2d3ed14fbadd43;p=lhc%2Fweb%2Fwiklou.git Run RevisionIntegrationTest for both ContentHandlerUseDB settings core used to have a test case that ran various Revision tests with and without ContentHandlerUseDB set, however it did not run due to the class / file having a bad name. This patch reintroduces the running on Revision tests for both ContentHandlerUseDB settings. The global has to be set in setup / before the page used for testing is created, else this page will be created with the wrong values in the DB for use in the tests. Change-Id: Ied1023e22eeac413fa86ea6946aa31619fd66319 --- diff --git a/tests/common/TestsAutoLoader.php b/tests/common/TestsAutoLoader.php index ca31fbc7ec..f7bf7a6f57 100644 --- a/tests/common/TestsAutoLoader.php +++ b/tests/common/TestsAutoLoader.php @@ -64,6 +64,7 @@ $wgAutoloadClasses += [ 'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php", # tests/phpunit/includes + 'RevisionDbTestBase' => "$testDir/phpunit/includes/RevisionDbTestBase.php", 'RevisionTestModifyableContent' => "$testDir/phpunit/includes/RevisionTestModifyableContent.php", 'RevisionTestModifyableContentHandler' => "$testDir/phpunit/includes/RevisionTestModifyableContentHandler.php", 'TestLogger' => "$testDir/phpunit/includes/TestLogger.php", diff --git a/tests/phpunit/includes/RevisionContentHandlerDbTest.php b/tests/phpunit/includes/RevisionContentHandlerDbTest.php new file mode 100644 index 0000000000..fa0153d3e0 --- /dev/null +++ b/tests/phpunit/includes/RevisionContentHandlerDbTest.php @@ -0,0 +1,14 @@ +tablesUsed = array_merge( $this->tablesUsed, + [ + 'page', + 'revision', + 'ip_changes', + 'text', + 'archive', + + 'recentchanges', + 'logging', + + 'page_props', + 'pagelinks', + 'categorylinks', + 'langlinks', + 'externallinks', + 'imagelinks', + 'templatelinks', + 'iwlinks' + ] + ); + } + + protected function setUp() { + global $wgContLang; + + parent::setUp(); + + $this->mergeMwGlobalArrayValue( + 'wgExtraNamespaces', + [ + 12312 => 'Dummy', + 12313 => 'Dummy_talk', + ] + ); + + $this->mergeMwGlobalArrayValue( + 'wgNamespaceContentModels', + [ + 12312 => DummyContentForTesting::MODEL_ID, + ] + ); + + $this->mergeMwGlobalArrayValue( + 'wgContentHandlers', + [ + DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting', + RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler', + ] + ); + + $this->setMwGlobals( 'wgContentHandlerUseDB', $this->getContentHandlerUseDB() ); + + MWNamespace::clearCaches(); + // Reset namespace cache + $wgContLang->resetNamespaces(); + if ( !$this->testPage ) { + /** + * We have to create a new page for each subclass as the page creation may result + * in different DB fields being filled based on configuration. + */ + $this->testPage = $this->createPage( __CLASS__, __CLASS__ ); + } + } + + protected function tearDown() { + global $wgContLang; + + parent::tearDown(); + + MWNamespace::clearCaches(); + // Reset namespace cache + $wgContLang->resetNamespaces(); + } + + abstract protected function getContentHandlerUseDB(); + + private function makeRevisionWithProps( $props = null ) { + if ( $props === null ) { + $props = []; + } + + if ( !isset( $props['content'] ) && !isset( $props['text'] ) ) { + $props['text'] = 'Lorem Ipsum'; + } + + if ( !isset( $props['comment'] ) ) { + $props['comment'] = 'just a test'; + } + + if ( !isset( $props['page'] ) ) { + $props['page'] = $this->testPage->getId(); + } + + $rev = new Revision( $props ); + + $dbw = wfGetDB( DB_MASTER ); + $rev->insertOn( $dbw ); + + return $rev; + } + + /** + * @param string $titleString + * @param string $text + * @param string|null $model + * + * @return WikiPage + */ + private function createPage( $titleString, $text, $model = null ) { + if ( !preg_match( '/:/', $titleString ) && + ( $model === null || $model === CONTENT_MODEL_WIKITEXT ) + ) { + $ns = $this->getDefaultWikitextNS(); + $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString; + } + + $title = Title::newFromText( $titleString ); + $wikipage = new WikiPage( $title ); + + // Delete the article if it already exists + if ( $wikipage->exists() ) { + $wikipage->doDeleteArticle( "done" ); + } + + $content = ContentHandler::makeContent( $text, $title, $model ); + $wikipage->doEditContent( $content, __METHOD__, EDIT_NEW ); + + return $wikipage; + } + + private function assertRevEquals( Revision $orig, Revision $rev = null ) { + $this->assertNotNull( $rev, 'missing revision' ); + + $this->assertEquals( $orig->getId(), $rev->getId() ); + $this->assertEquals( $orig->getPage(), $rev->getPage() ); + $this->assertEquals( $orig->getTimestamp(), $rev->getTimestamp() ); + $this->assertEquals( $orig->getUser(), $rev->getUser() ); + $this->assertEquals( $orig->getContentModel(), $rev->getContentModel() ); + $this->assertEquals( $orig->getContentFormat(), $rev->getContentFormat() ); + $this->assertEquals( $orig->getSha1(), $rev->getSha1() ); + } + + /** + * @covers Revision::insertOn + */ + public function testInsertOn_success() { + $parentId = $this->testPage->getLatest(); + + // If an ExternalStore is set don't use it. + $this->setMwGlobals( 'wgDefaultExternalStore', false ); + + $rev = new Revision( [ + 'page' => $this->testPage->getId(), + 'title' => $this->testPage->getTitle(), + 'text' => 'Revision Text', + 'comment' => 'Revision comment', + ] ); + + $revId = $rev->insertOn( wfGetDB( DB_MASTER ) ); + + $this->assertInternalType( 'integer', $revId ); + $this->assertInternalType( 'integer', $rev->getTextId() ); + $this->assertSame( $revId, $rev->getId() ); + + $this->assertSelect( + 'text', + [ 'old_id', 'old_text' ], + "old_id = {$rev->getTextId()}", + [ [ strval( $rev->getTextId() ), 'Revision Text' ] ] + ); + $this->assertSelect( + 'revision', + [ + 'rev_id', + 'rev_page', + 'rev_text_id', + 'rev_user', + 'rev_minor_edit', + 'rev_deleted', + 'rev_len', + 'rev_parent_id', + 'rev_sha1', + ], + "rev_id = {$rev->getId()}", + [ [ + strval( $rev->getId() ), + strval( $this->testPage->getId() ), + strval( $rev->getTextId() ), + '0', + '0', + '0', + '13', + strval( $parentId ), + 's0ngbdoxagreuf2vjtuxzwdz64n29xm', + ] ] + ); + } + + /** + * @covers Revision::insertOn + */ + public function testInsertOn_exceptionOnNoPage() { + // If an ExternalStore is set don't use it. + $this->setMwGlobals( 'wgDefaultExternalStore', false ); + $this->setExpectedException( + MWException::class, + "Cannot insert revision: page ID must be nonzero" + ); + + $rev = new Revision( [] ); + + $rev->insertOn( wfGetDB( DB_MASTER ) ); + } + + /** + * @covers Revision::newFromTitle + */ + public function testNewFromTitle_withoutId() { + $latestRevId = $this->testPage->getLatest(); + + $rev = Revision::newFromTitle( $this->testPage->getTitle() ); + + $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) ); + $this->assertEquals( $latestRevId, $rev->getId() ); + } + + /** + * @covers Revision::newFromTitle + */ + public function testNewFromTitle_withId() { + $latestRevId = $this->testPage->getLatest(); + + $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId ); + + $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) ); + $this->assertEquals( $latestRevId, $rev->getId() ); + } + + /** + * @covers Revision::newFromTitle + */ + public function testNewFromTitle_withBadId() { + $latestRevId = $this->testPage->getLatest(); + + $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId + 1 ); + + $this->assertNull( $rev ); + } + + /** + * @covers Revision::newFromRow + */ + public function testNewFromRow() { + $orig = $this->makeRevisionWithProps(); + + $dbr = wfGetDB( DB_REPLICA ); + $revQuery = Revision::getQueryInfo(); + $res = $dbr->select( $revQuery['tables'], $revQuery['fields'], [ 'rev_id' => $orig->getId() ], + __METHOD__, [], $revQuery['joins'] ); + $this->assertTrue( is_object( $res ), 'query failed' ); + + $row = $res->fetchObject(); + $res->free(); + + $rev = Revision::newFromRow( $row ); + + $this->assertRevEquals( $orig, $rev ); + } + + public function provideNewFromArchiveRow() { + yield [ + function ( $f ) { + return $f; + }, + ]; + yield [ + function ( $f ) { + return $f + [ 'ar_namespace', 'ar_title' ]; + }, + ]; + yield [ + function ( $f ) { + unset( $f['ar_text_id'] ); + return $f; + }, + ]; + } + + /** + * @dataProvider provideNewFromArchiveRow + * @covers Revision::newFromArchiveRow + */ + public function testNewFromArchiveRow( $selectModifier ) { + $page = $this->createPage( + 'RevisionStorageTest_testNewFromArchiveRow', + 'Lorem Ipsum', + CONTENT_MODEL_WIKITEXT + ); + $orig = $page->getRevision(); + $page->doDeleteArticle( 'test Revision::newFromArchiveRow' ); + + $dbr = wfGetDB( DB_REPLICA ); + $arQuery = Revision::getArchiveQueryInfo(); + $arQuery['fields'] = $selectModifier( $arQuery['fields'] ); + $res = $dbr->select( + $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ], + __METHOD__, [], $arQuery['joins'] + ); + $this->assertTrue( is_object( $res ), 'query failed' ); + + $row = $res->fetchObject(); + $res->free(); + + $rev = Revision::newFromArchiveRow( $row ); + + $this->assertRevEquals( $orig, $rev ); + } + + /** + * @covers Revision::newFromArchiveRow + */ + public function testNewFromArchiveRowOverrides() { + $page = $this->createPage( + 'RevisionStorageTest_testNewFromArchiveRow', + 'Lorem Ipsum', + CONTENT_MODEL_WIKITEXT + ); + $orig = $page->getRevision(); + $page->doDeleteArticle( 'test Revision::newFromArchiveRow' ); + + $dbr = wfGetDB( DB_REPLICA ); + $arQuery = Revision::getArchiveQueryInfo(); + $res = $dbr->select( + $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ], + __METHOD__, [], $arQuery['joins'] + ); + $this->assertTrue( is_object( $res ), 'query failed' ); + + $row = $res->fetchObject(); + $res->free(); + + $rev = Revision::newFromArchiveRow( $row, [ 'comment' => 'SOMEOVERRIDE' ] ); + + $this->assertNotEquals( $orig->getComment(), $rev->getComment() ); + $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() ); + } + + /** + * @covers Revision::newFromId + */ + public function testNewFromId() { + $orig = $this->testPage->getRevision(); + $rev = Revision::newFromId( $orig->getId() ); + $this->assertRevEquals( $orig, $rev ); + } + + /** + * @covers Revision::newFromPageId + */ + public function testNewFromPageId() { + $rev = Revision::newFromPageId( $this->testPage->getId() ); + $this->assertRevEquals( + $this->testPage->getRevision(), + $rev + ); + } + + /** + * @covers Revision::newFromPageId + */ + public function testNewFromPageIdWithLatestId() { + $rev = Revision::newFromPageId( + $this->testPage->getId(), + $this->testPage->getLatest() + ); + $this->assertRevEquals( + $this->testPage->getRevision(), + $rev + ); + } + + /** + * @covers Revision::newFromPageId + */ + public function testNewFromPageIdWithNotLatestId() { + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $rev = Revision::newFromPageId( + $this->testPage->getId(), + $this->testPage->getRevision()->getPrevious()->getId() + ); + $this->assertRevEquals( + $this->testPage->getRevision()->getPrevious(), + $rev + ); + } + + /** + * @covers Revision::fetchRevision + */ + public function testFetchRevision() { + // Hidden process cache assertion below + $this->testPage->getRevision()->getId(); + + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $id = $this->testPage->getRevision()->getId(); + + $res = Revision::fetchRevision( $this->testPage->getTitle() ); + + # note: order is unspecified + $rows = []; + while ( ( $row = $res->fetchObject() ) ) { + $rows[$row->rev_id] = $row; + } + + $this->assertEquals( 1, count( $rows ), 'expected exactly one revision' ); + $this->assertArrayHasKey( $id, $rows, 'missing revision with id ' . $id ); + } + + /** + * @covers Revision::getPage + */ + public function testGetPage() { + $page = $this->testPage; + + $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] ); + $rev = Revision::newFromId( $orig->getId() ); + + $this->assertEquals( $page->getId(), $rev->getPage() ); + } + + /** + * @covers Revision::isCurrent + */ + public function testIsCurrent() { + $rev1 = $this->testPage->getRevision(); + + # @todo find out if this should be true + # $this->assertTrue( $rev1->isCurrent() ); + + $rev1x = Revision::newFromId( $rev1->getId() ); + $this->assertTrue( $rev1x->isCurrent() ); + + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $rev2 = $this->testPage->getRevision(); + + # @todo find out if this should be true + # $this->assertTrue( $rev2->isCurrent() ); + + $rev1x = Revision::newFromId( $rev1->getId() ); + $this->assertFalse( $rev1x->isCurrent() ); + + $rev2x = Revision::newFromId( $rev2->getId() ); + $this->assertTrue( $rev2x->isCurrent() ); + } + + /** + * @covers Revision::getPrevious + */ + public function testGetPrevious() { + $oldestRevision = $this->testPage->getOldestRevision(); + $latestRevision = $this->testPage->getLatest(); + + $this->assertNull( $oldestRevision->getPrevious() ); + + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $newRevision = $this->testPage->getRevision(); + + $this->assertNotNull( $newRevision->getPrevious() ); + $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() ); + } + + /** + * @covers Revision::getNext + */ + public function testGetNext() { + $rev1 = $this->testPage->getRevision(); + + $this->assertNull( $rev1->getNext() ); + + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $rev2 = $this->testPage->getRevision(); + + $this->assertNotNull( $rev1->getNext() ); + $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() ); + } + + /** + * @covers Revision::newNullRevision + */ + public function testNewNullRevision() { + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $orig = $this->testPage->getRevision(); + + $dbw = wfGetDB( DB_MASTER ); + $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false ); + + $this->assertNotEquals( $orig->getId(), $rev->getId(), + 'new null revision should have a different id from the original revision' ); + $this->assertEquals( $orig->getTextId(), $rev->getTextId(), + 'new null revision should have the same text id as the original revision' ); + $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() ); + } + + /** + * @covers Revision::insertOn + */ + public function testInsertOn() { + $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7'; + + $orig = $this->makeRevisionWithProps( [ + 'user_text' => $ip + ] ); + + // Make sure the revision was copied to ip_changes + $dbr = wfGetDB( DB_REPLICA ); + $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] ); + $row = $res->fetchObject(); + + $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex ); + $this->assertEquals( $orig->getTimestamp(), $row->ipc_rev_timestamp ); + } + + public static function provideUserWasLastToEdit() { + yield 'actually the last edit' => [ 3, true ]; + yield 'not the current edit, but still by this user' => [ 2, true ]; + yield 'edit by another user' => [ 1, false ]; + yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ]; + } + + /** + * @dataProvider provideUserWasLastToEdit + */ + public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) { + $userA = User::newFromName( "RevisionStorageTest_userA" ); + $userB = User::newFromName( "RevisionStorageTest_userB" ); + + if ( $userA->getId() === 0 ) { + $userA = User::createNew( $userA->getName() ); + } + + if ( $userB->getId() === 0 ) { + $userB = User::createNew( $userB->getName() ); + } + + $ns = $this->getDefaultWikitextNS(); + + $dbw = wfGetDB( DB_MASTER ); + $revisions = []; + + // create revisions ----------------------------- + $page = WikiPage::factory( Title::newFromText( + 'RevisionStorageTest_testUserWasLastToEdit', $ns ) ); + $page->insertOn( $dbw ); + + $revisions[0] = new Revision( [ + 'page' => $page->getId(), + // we need the title to determine the page's default content model + 'title' => $page->getTitle(), + 'timestamp' => '20120101000000', + 'user' => $userA->getId(), + 'text' => 'zero', + 'content_model' => CONTENT_MODEL_WIKITEXT, + 'summary' => 'edit zero' + ] ); + $revisions[0]->insertOn( $dbw ); + + $revisions[1] = new Revision( [ + 'page' => $page->getId(), + // still need the title, because $page->getId() is 0 (there's no entry in the page table) + 'title' => $page->getTitle(), + 'timestamp' => '20120101000100', + 'user' => $userA->getId(), + 'text' => 'one', + 'content_model' => CONTENT_MODEL_WIKITEXT, + 'summary' => 'edit one' + ] ); + $revisions[1]->insertOn( $dbw ); + + $revisions[2] = new Revision( [ + 'page' => $page->getId(), + 'title' => $page->getTitle(), + 'timestamp' => '20120101000200', + 'user' => $userB->getId(), + 'text' => 'two', + 'content_model' => CONTENT_MODEL_WIKITEXT, + 'summary' => 'edit two' + ] ); + $revisions[2]->insertOn( $dbw ); + + $revisions[3] = new Revision( [ + 'page' => $page->getId(), + 'title' => $page->getTitle(), + 'timestamp' => '20120101000300', + 'user' => $userA->getId(), + 'text' => 'three', + 'content_model' => CONTENT_MODEL_WIKITEXT, + 'summary' => 'edit three' + ] ); + $revisions[3]->insertOn( $dbw ); + + $revisions[4] = new Revision( [ + 'page' => $page->getId(), + 'title' => $page->getTitle(), + 'timestamp' => '20120101000200', + 'user' => $userA->getId(), + 'text' => 'zero', + 'content_model' => CONTENT_MODEL_WIKITEXT, + 'summary' => 'edit four' + ] ); + $revisions[4]->insertOn( $dbw ); + + // test it --------------------------------- + $since = $revisions[$sinceIdx]->getTimestamp(); + + $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since ); + + $this->assertEquals( $expectedLast, $wasLast ); + } + + /** + * @param string $text + * @param string $title + * @param string $model + * @param string $format + * + * @return Revision + */ + private function newTestRevision( $text, $title = "Test", + $model = CONTENT_MODEL_WIKITEXT, $format = null + ) { + if ( is_string( $title ) ) { + $title = Title::newFromText( $title ); + } + + $content = ContentHandler::makeContent( $text, $title, $model, $format ); + + $rev = new Revision( + [ + 'id' => 42, + 'page' => 23, + 'title' => $title, + + 'content' => $content, + 'length' => $content->getSize(), + 'comment' => "testing", + 'minor_edit' => false, + + 'content_format' => $format, + ] + ); + + return $rev; + } + + public function provideGetContentModel() { + // NOTE: we expect the help namespace to always contain wikitext + return [ + [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ], + [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ], + [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ], + ]; + } + + /** + * @dataProvider provideGetContentModel + * @covers Revision::getContentModel + */ + public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) { + $rev = $this->newTestRevision( $text, $title, $model, $format ); + + $this->assertEquals( $expectedModel, $rev->getContentModel() ); + } + + public function provideGetContentFormat() { + // NOTE: we expect the help namespace to always contain wikitext + return [ + [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ], + [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ], + [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ], + [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ], + ]; + } + + /** + * @dataProvider provideGetContentFormat + * @covers Revision::getContentFormat + */ + public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) { + $rev = $this->newTestRevision( $text, $title, $model, $format ); + + $this->assertEquals( $expectedFormat, $rev->getContentFormat() ); + } + + public function provideGetContentHandler() { + // NOTE: we expect the help namespace to always contain wikitext + return [ + [ 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ], + [ 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ], + [ serialize( 'hello world' ), 'Dummy:Hello', null, null, 'DummyContentHandlerForTesting' ], + ]; + } + + /** + * @dataProvider provideGetContentHandler + * @covers Revision::getContentHandler + */ + public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) { + $rev = $this->newTestRevision( $text, $title, $model, $format ); + + $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) ); + } + + public function provideGetContent() { + // NOTE: we expect the help namespace to always contain wikitext + return [ + [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ], + [ + serialize( 'hello world' ), + 'Hello', + DummyContentForTesting::MODEL_ID, + null, + Revision::FOR_PUBLIC, + serialize( 'hello world' ) + ], + [ + serialize( 'hello world' ), + 'Dummy:Hello', + null, + null, + Revision::FOR_PUBLIC, + serialize( 'hello world' ) + ], + ]; + } + + /** + * @dataProvider provideGetContent + * @covers Revision::getContent + */ + public function testGetContent( $text, $title, $model, $format, + $audience, $expectedSerialization + ) { + $rev = $this->newTestRevision( $text, $title, $model, $format ); + $content = $rev->getContent( $audience ); + + $this->assertEquals( + $expectedSerialization, + is_null( $content ) ? null : $content->serialize( $format ) + ); + } + + /** + * @covers Revision::getContent + */ + public function testGetContent_failure() { + $rev = new Revision( [ + 'page' => $this->testPage->getId(), + 'content_model' => $this->testPage->getContentModel(), + 'text_id' => 123456789, // not in the test DB + ] ); + + $this->assertNull( $rev->getContent(), + "getContent() should return null if the revision's text blob could not be loaded." ); + + // NOTE: check this twice, once for lazy initialization, and once with the cached value. + $this->assertNull( $rev->getContent(), + "getContent() should return null if the revision's text blob could not be loaded." ); + } + + public function provideGetSize() { + return [ + [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ], + [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ], + ]; + } + + /** + * @covers Revision::getSize + * @dataProvider provideGetSize + */ + public function testGetSize( $text, $model, $expected_size ) { + $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model ); + $this->assertEquals( $expected_size, $rev->getSize() ); + } + + public function provideGetSha1() { + return [ + [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ], + [ + serialize( "hello world." ), + DummyContentForTesting::MODEL_ID, + Revision::base36Sha1( serialize( "hello world." ) ) + ], + ]; + } + + /** + * @covers Revision::getSha1 + * @dataProvider provideGetSha1 + */ + public function testGetSha1( $text, $model, $expected_hash ) { + $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model ); + $this->assertEquals( $expected_hash, $rev->getSha1() ); + } + + /** + * Tests whether $rev->getContent() returns a clone when needed. + * + * @covers Revision::getContent + */ + public function testGetContentClone() { + $content = new RevisionTestModifyableContent( "foo" ); + + $rev = new Revision( + [ + 'id' => 42, + 'page' => 23, + 'title' => Title::newFromText( "testGetContentClone_dummy" ), + + 'content' => $content, + 'length' => $content->getSize(), + 'comment' => "testing", + 'minor_edit' => false, + ] + ); + + /** @var RevisionTestModifyableContent $content */ + $content = $rev->getContent( Revision::RAW ); + $content->setText( "bar" ); + + /** @var RevisionTestModifyableContent $content2 */ + $content2 = $rev->getContent( Revision::RAW ); + // content is mutable, expect clone + $this->assertNotSame( $content, $content2, "expected a clone" ); + // clone should contain the original text + $this->assertEquals( "foo", $content2->getText() ); + + $content2->setText( "bla bla" ); + // clones should be independent + $this->assertEquals( "bar", $content->getText() ); + } + + /** + * Tests whether $rev->getContent() returns the same object repeatedly if appropriate. + * @covers Revision::getContent + */ + public function testGetContentUncloned() { + $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT ); + $content = $rev->getContent( Revision::RAW ); + $content2 = $rev->getContent( Revision::RAW ); + + // for immutable content like wikitext, this should be the same object + $this->assertSame( $content, $content2 ); + } + + /** + * @covers Revision::loadFromId + */ + public function testLoadFromId() { + $rev = $this->testPage->getRevision(); + $this->assertRevEquals( + $rev, + Revision::loadFromId( wfGetDB( DB_MASTER ), $rev->getId() ) + ); + } + + /** + * @covers Revision::loadFromPageId + */ + public function testLoadFromPageId() { + $this->assertRevEquals( + $this->testPage->getRevision(), + Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() ) + ); + } + + /** + * @covers Revision::loadFromPageId + */ + public function testLoadFromPageIdWithLatestRevId() { + $this->assertRevEquals( + $this->testPage->getRevision(), + Revision::loadFromPageId( + wfGetDB( DB_MASTER ), + $this->testPage->getId(), + $this->testPage->getLatest() + ) + ); + } + + /** + * @covers Revision::loadFromPageId + */ + public function testLoadFromPageIdWithNotLatestRevId() { + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $this->assertRevEquals( + $this->testPage->getRevision()->getPrevious(), + Revision::loadFromPageId( + wfGetDB( DB_MASTER ), + $this->testPage->getId(), + $this->testPage->getRevision()->getPrevious()->getId() + ) + ); + } + + /** + * @covers Revision::loadFromTitle + */ + public function testLoadFromTitle() { + $this->assertRevEquals( + $this->testPage->getRevision(), + Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() ) + ); + } + + /** + * @covers Revision::loadFromTitle + */ + public function testLoadFromTitleWithLatestRevId() { + $this->assertRevEquals( + $this->testPage->getRevision(), + Revision::loadFromTitle( + wfGetDB( DB_MASTER ), + $this->testPage->getTitle(), + $this->testPage->getLatest() + ) + ); + } + + /** + * @covers Revision::loadFromTitle + */ + public function testLoadFromTitleWithNotLatestRevId() { + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $this->assertRevEquals( + $this->testPage->getRevision()->getPrevious(), + Revision::loadFromTitle( + wfGetDB( DB_MASTER ), + $this->testPage->getTitle(), + $this->testPage->getRevision()->getPrevious()->getId() + ) + ); + } + + /** + * @covers Revision::loadFromTimestamp() + */ + public function testLoadFromTimestamp() { + $this->assertRevEquals( + $this->testPage->getRevision(), + Revision::loadFromTimestamp( + wfGetDB( DB_MASTER ), + $this->testPage->getTitle(), + $this->testPage->getRevision()->getTimestamp() + ) + ); + } + + /** + * @covers Revision::getParentLengths + */ + public function testGetParentLengths_noRevIds() { + $this->assertSame( + [], + Revision::getParentLengths( + wfGetDB( DB_MASTER ), + [] + ) + ); + } + + /** + * @covers Revision::getParentLengths + */ + public function testGetParentLengths_oneRevId() { + $text = '831jr091jr0921kr21kr0921kjr0921j09rj1'; + $textLength = strlen( $text ); + + $this->testPage->doEditContent( new WikitextContent( $text ), __METHOD__ ); + $rev[1] = $this->testPage->getLatest(); + + $this->assertSame( + [ $rev[1] => strval( $textLength ) ], + Revision::getParentLengths( + wfGetDB( DB_MASTER ), + [ $rev[1] ] + ) + ); + } + + /** + * @covers Revision::getParentLengths + */ + public function testGetParentLengths_multipleRevIds() { + $textOne = '831jr091jr0921kr21kr0921kjr0921j09rj1'; + $textOneLength = strlen( $textOne ); + $textTwo = '831jr091jr092121j09rj1'; + $textTwoLength = strlen( $textTwo ); + + $this->testPage->doEditContent( new WikitextContent( $textOne ), __METHOD__ ); + $rev[1] = $this->testPage->getLatest(); + $this->testPage->doEditContent( new WikitextContent( $textTwo ), __METHOD__ ); + $rev[2] = $this->testPage->getLatest(); + + $this->assertSame( + [ $rev[1] => strval( $textOneLength ), $rev[2] => strval( $textTwoLength ) ], + Revision::getParentLengths( + wfGetDB( DB_MASTER ), + [ $rev[1], $rev[2] ] + ) + ); + } + + /** + * @covers Revision::getTitle + */ + public function testGetTitle_fromExistingRevision() { + $this->assertTrue( + $this->testPage->getTitle()->equals( + $this->testPage->getRevision()->getTitle() + ) + ); + } + + /** + * @covers Revision::getTitle + */ + public function testGetTitle_fromRevisionWhichWillLoadTheTitle() { + $rev = new Revision( [ 'id' => $this->testPage->getLatest() ] ); + $this->assertTrue( + $this->testPage->getTitle()->equals( + $rev->getTitle() + ) + ); + } + + /** + * @covers Revision::getTitle + */ + public function testGetTitle_forBadRevision() { + $rev = new Revision( [] ); + $this->assertNull( $rev->getTitle() ); + } + + /** + * @covers Revision::isMinor + */ + public function testIsMinor_true() { + // Use a sysop to ensure we can mark edits as minor + $sysop = $this->getTestSysop()->getUser(); + + $this->testPage->doEditContent( + new WikitextContent( __METHOD__ ), + __METHOD__, + EDIT_MINOR, + false, + $sysop + ); + $rev = $this->testPage->getRevision(); + + $this->assertSame( true, $rev->isMinor() ); + } + + /** + * @covers Revision::isMinor + */ + public function testIsMinor_false() { + $this->testPage->doEditContent( + new WikitextContent( __METHOD__ ), + __METHOD__, + 0 + ); + $rev = $this->testPage->getRevision(); + + $this->assertSame( false, $rev->isMinor() ); + } + + /** + * @covers Revision::getTimestamp + */ + public function testGetTimestamp() { + $testTimestamp = wfTimestampNow(); + + $this->testPage->doEditContent( + new WikitextContent( __METHOD__ ), + __METHOD__ + ); + $rev = $this->testPage->getRevision(); + + $this->assertInternalType( 'string', $rev->getTimestamp() ); + $this->assertTrue( strlen( $rev->getTimestamp() ) == strlen( 'YYYYMMDDHHMMSS' ) ); + $this->assertContains( substr( $testTimestamp, 0, 10 ), $rev->getTimestamp() ); + } + + /** + * @covers Revision::getUser + * @covers Revision::getUserText + */ + public function testGetUserAndText() { + $sysop = $this->getTestSysop()->getUser(); + + $this->testPage->doEditContent( + new WikitextContent( __METHOD__ ), + __METHOD__, + 0, + false, + $sysop + ); + $rev = $this->testPage->getRevision(); + + $this->assertSame( $sysop->getId(), $rev->getUser() ); + $this->assertSame( $sysop->getName(), $rev->getUserText() ); + } + + /** + * @covers Revision::isDeleted + */ + public function testIsDeleted_nothingDeleted() { + $rev = $this->testPage->getRevision(); + + $this->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) ); + $this->assertSame( false, $rev->isDeleted( Revision::DELETED_COMMENT ) ); + $this->assertSame( false, $rev->isDeleted( Revision::DELETED_RESTRICTED ) ); + $this->assertSame( false, $rev->isDeleted( Revision::DELETED_USER ) ); + } + + /** + * @covers Revision::getVisibility + */ + public function testGetVisibility_nothingDeleted() { + $rev = $this->testPage->getRevision(); + + $this->assertSame( 0, $rev->getVisibility() ); + } + + /** + * @covers Revision::getComment + */ + public function testGetComment_notDeleted() { + $expectedSummary = 'goatlicious summary'; + + $this->testPage->doEditContent( + new WikitextContent( __METHOD__ ), + $expectedSummary + ); + $rev = $this->testPage->getRevision(); + + $this->assertSame( $expectedSummary, $rev->getComment() ); + } + + /** + * @covers Revision::isUnpatrolled + */ + public function testIsUnpatrolled_returnsRecentChangesId() { + $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); + $rev = $this->testPage->getRevision(); + + $this->assertGreaterThan( 0, $rev->isUnpatrolled() ); + $this->assertSame( $rev->getRecentChange()->getAttribute( 'rc_id' ), $rev->isUnpatrolled() ); + } + + /** + * @covers Revision::isUnpatrolled + */ + public function testIsUnpatrolled_returnsZeroIfPatrolled() { + // This assumes that sysops are auto patrolled + $sysop = $this->getTestSysop()->getUser(); + $this->testPage->doEditContent( + new WikitextContent( __METHOD__ ), + __METHOD__, + 0, + false, + $sysop + ); + $rev = $this->testPage->getRevision(); + + $this->assertSame( 0, $rev->isUnpatrolled() ); + } + + /** + * This is a simple blanket test for all simple content getters and is methods to provide some + * coverage before the split of Revision into multiple classes for MCR work. + * @covers Revision::getContent + * @covers Revision::getSerializedData + * @covers Revision::getContentModel + * @covers Revision::getContentFormat + * @covers Revision::getContentHandler + */ + public function testSimpleContentGetters() { + $expectedText = 'testSimpleContentGetters in Revision. Goats love MCR...'; + $expectedSummary = 'goatlicious testSimpleContentGetters summary'; + + $this->testPage->doEditContent( + new WikitextContent( $expectedText ), + $expectedSummary + ); + $rev = $this->testPage->getRevision(); + + $this->assertSame( $expectedText, $rev->getContent()->getNativeData() ); + $this->assertSame( $expectedText, $rev->getSerializedData() ); + $this->assertSame( $this->testPage->getContentModel(), $rev->getContentModel() ); + $this->assertSame( $this->testPage->getContent()->getDefaultFormat(), $rev->getContentFormat() ); + $this->assertSame( $this->testPage->getContentHandler(), $rev->getContentHandler() ); + } + +} diff --git a/tests/phpunit/includes/RevisionIntegrationTest.php b/tests/phpunit/includes/RevisionIntegrationTest.php deleted file mode 100644 index b5fa030d4f..0000000000 --- a/tests/phpunit/includes/RevisionIntegrationTest.php +++ /dev/null @@ -1,1241 +0,0 @@ -tablesUsed = array_merge( $this->tablesUsed, - [ - 'page', - 'revision', - 'ip_changes', - 'text', - 'archive', - - 'recentchanges', - 'logging', - - 'page_props', - 'pagelinks', - 'categorylinks', - 'langlinks', - 'externallinks', - 'imagelinks', - 'templatelinks', - 'iwlinks' - ] - ); - } - - protected function setUp() { - global $wgContLang; - - parent::setUp(); - - $this->mergeMwGlobalArrayValue( - 'wgExtraNamespaces', - [ - 12312 => 'Dummy', - 12313 => 'Dummy_talk', - ] - ); - - $this->mergeMwGlobalArrayValue( - 'wgNamespaceContentModels', - [ - 12312 => DummyContentForTesting::MODEL_ID, - ] - ); - - $this->mergeMwGlobalArrayValue( - 'wgContentHandlers', - [ - DummyContentForTesting::MODEL_ID => 'DummyContentHandlerForTesting', - RevisionTestModifyableContent::MODEL_ID => 'RevisionTestModifyableContentHandler', - ] - ); - - MWNamespace::clearCaches(); - // Reset namespace cache - $wgContLang->resetNamespaces(); - if ( !$this->testPage ) { - $this->testPage = WikiPage::factory( Title::newFromText( 'UTPage' ) ); - } - } - - protected function tearDown() { - global $wgContLang; - - parent::tearDown(); - - MWNamespace::clearCaches(); - // Reset namespace cache - $wgContLang->resetNamespaces(); - } - - private function makeRevisionWithProps( $props = null ) { - if ( $props === null ) { - $props = []; - } - - if ( !isset( $props['content'] ) && !isset( $props['text'] ) ) { - $props['text'] = 'Lorem Ipsum'; - } - - if ( !isset( $props['comment'] ) ) { - $props['comment'] = 'just a test'; - } - - if ( !isset( $props['page'] ) ) { - $props['page'] = $this->testPage->getId(); - } - - $rev = new Revision( $props ); - - $dbw = wfGetDB( DB_MASTER ); - $rev->insertOn( $dbw ); - - return $rev; - } - - /** - * @param string $titleString - * @param string $text - * @param string|null $model - * - * @return WikiPage - */ - private function createPage( $titleString, $text, $model = null ) { - if ( !preg_match( '/:/', $titleString ) && - ( $model === null || $model === CONTENT_MODEL_WIKITEXT ) - ) { - $ns = $this->getDefaultWikitextNS(); - $titleString = MWNamespace::getCanonicalName( $ns ) . ':' . $titleString; - } - - $title = Title::newFromText( $titleString ); - $wikipage = new WikiPage( $title ); - - // Delete the article if it already exists - if ( $wikipage->exists() ) { - $wikipage->doDeleteArticle( "done" ); - } - - $content = ContentHandler::makeContent( $text, $title, $model ); - $wikipage->doEditContent( $content, __METHOD__, EDIT_NEW ); - - return $wikipage; - } - - private function assertRevEquals( Revision $orig, Revision $rev = null ) { - $this->assertNotNull( $rev, 'missing revision' ); - - $this->assertEquals( $orig->getId(), $rev->getId() ); - $this->assertEquals( $orig->getPage(), $rev->getPage() ); - $this->assertEquals( $orig->getTimestamp(), $rev->getTimestamp() ); - $this->assertEquals( $orig->getUser(), $rev->getUser() ); - $this->assertEquals( $orig->getContentModel(), $rev->getContentModel() ); - $this->assertEquals( $orig->getContentFormat(), $rev->getContentFormat() ); - $this->assertEquals( $orig->getSha1(), $rev->getSha1() ); - } - - /** - * @covers Revision::insertOn - */ - public function testInsertOn_success() { - $parentId = $this->testPage->getLatest(); - - // If an ExternalStore is set don't use it. - $this->setMwGlobals( 'wgDefaultExternalStore', false ); - - $rev = new Revision( [ - 'page' => $this->testPage->getId(), - 'title' => $this->testPage->getTitle(), - 'text' => 'Revision Text', - 'comment' => 'Revision comment', - ] ); - - $revId = $rev->insertOn( wfGetDB( DB_MASTER ) ); - - $this->assertInternalType( 'integer', $revId ); - $this->assertInternalType( 'integer', $rev->getTextId() ); - $this->assertSame( $revId, $rev->getId() ); - - $this->assertSelect( - 'text', - [ 'old_id', 'old_text' ], - "old_id = {$rev->getTextId()}", - [ [ strval( $rev->getTextId() ), 'Revision Text' ] ] - ); - $this->assertSelect( - 'revision', - [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_user', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - ], - "rev_id = {$rev->getId()}", - [ [ - strval( $rev->getId() ), - strval( $this->testPage->getId() ), - strval( $rev->getTextId() ), - '0', - '0', - '0', - '13', - strval( $parentId ), - 's0ngbdoxagreuf2vjtuxzwdz64n29xm', - ] ] - ); - } - - /** - * @covers Revision::insertOn - */ - public function testInsertOn_exceptionOnNoPage() { - // If an ExternalStore is set don't use it. - $this->setMwGlobals( 'wgDefaultExternalStore', false ); - $this->setExpectedException( - MWException::class, - "Cannot insert revision: page ID must be nonzero" - ); - - $rev = new Revision( [] ); - - $rev->insertOn( wfGetDB( DB_MASTER ) ); - } - - /** - * @covers Revision::newFromTitle - */ - public function testNewFromTitle_withoutId() { - $latestRevId = $this->testPage->getLatest(); - - $rev = Revision::newFromTitle( $this->testPage->getTitle() ); - - $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) ); - $this->assertEquals( $latestRevId, $rev->getId() ); - } - - /** - * @covers Revision::newFromTitle - */ - public function testNewFromTitle_withId() { - $latestRevId = $this->testPage->getLatest(); - - $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId ); - - $this->assertTrue( $this->testPage->getTitle()->equals( $rev->getTitle() ) ); - $this->assertEquals( $latestRevId, $rev->getId() ); - } - - /** - * @covers Revision::newFromTitle - */ - public function testNewFromTitle_withBadId() { - $latestRevId = $this->testPage->getLatest(); - - $rev = Revision::newFromTitle( $this->testPage->getTitle(), $latestRevId + 1 ); - - $this->assertNull( $rev ); - } - - /** - * @covers Revision::newFromRow - */ - public function testNewFromRow() { - $orig = $this->makeRevisionWithProps(); - - $dbr = wfGetDB( DB_REPLICA ); - $revQuery = Revision::getQueryInfo(); - $res = $dbr->select( $revQuery['tables'], $revQuery['fields'], [ 'rev_id' => $orig->getId() ], - __METHOD__, [], $revQuery['joins'] ); - $this->assertTrue( is_object( $res ), 'query failed' ); - - $row = $res->fetchObject(); - $res->free(); - - $rev = Revision::newFromRow( $row ); - - $this->assertRevEquals( $orig, $rev ); - } - - public function provideNewFromArchiveRow() { - yield [ - true, - function ( $f ) { - return $f; - }, - ]; - yield [ - false, - function ( $f ) { - return $f; - }, - ]; - yield [ - true, - function ( $f ) { - return $f + [ 'ar_namespace', 'ar_title' ]; - }, - ]; - yield [ - false, - function ( $f ) { - return $f + [ 'ar_namespace', 'ar_title' ]; - }, - ]; - yield [ - true, - function ( $f ) { - unset( $f['ar_text_id'] ); - return $f; - }, - ]; - yield [ - false, - function ( $f ) { - unset( $f['ar_text_id'] ); - return $f; - }, - ]; - } - - /** - * @dataProvider provideNewFromArchiveRow - * @covers Revision::newFromArchiveRow - */ - public function testNewFromArchiveRow( $contentHandlerUseDB, $selectModifier ) { - $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB ); - - $page = $this->createPage( - 'RevisionStorageTest_testNewFromArchiveRow', - 'Lorem Ipsum', - CONTENT_MODEL_WIKITEXT - ); - $orig = $page->getRevision(); - $page->doDeleteArticle( 'test Revision::newFromArchiveRow' ); - - $dbr = wfGetDB( DB_REPLICA ); - $arQuery = Revision::getArchiveQueryInfo(); - $arQuery['fields'] = $selectModifier( $arQuery['fields'] ); - $res = $dbr->select( - $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ], - __METHOD__, [], $arQuery['joins'] - ); - $this->assertTrue( is_object( $res ), 'query failed' ); - - $row = $res->fetchObject(); - $res->free(); - - $rev = Revision::newFromArchiveRow( $row ); - - $this->assertRevEquals( $orig, $rev ); - } - - /** - * @covers Revision::newFromArchiveRow - */ - public function testNewFromArchiveRowOverrides() { - $page = $this->createPage( - 'RevisionStorageTest_testNewFromArchiveRow', - 'Lorem Ipsum', - CONTENT_MODEL_WIKITEXT - ); - $orig = $page->getRevision(); - $page->doDeleteArticle( 'test Revision::newFromArchiveRow' ); - - $dbr = wfGetDB( DB_REPLICA ); - $arQuery = Revision::getArchiveQueryInfo(); - $res = $dbr->select( - $arQuery['tables'], $arQuery['fields'], [ 'ar_rev_id' => $orig->getId() ], - __METHOD__, [], $arQuery['joins'] - ); - $this->assertTrue( is_object( $res ), 'query failed' ); - - $row = $res->fetchObject(); - $res->free(); - - $rev = Revision::newFromArchiveRow( $row, [ 'comment' => 'SOMEOVERRIDE' ] ); - - $this->assertNotEquals( $orig->getComment(), $rev->getComment() ); - $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() ); - } - - /** - * @covers Revision::newFromId - */ - public function testNewFromId() { - $orig = $this->testPage->getRevision(); - $rev = Revision::newFromId( $orig->getId() ); - $this->assertRevEquals( $orig, $rev ); - } - - /** - * @covers Revision::newFromPageId - */ - public function testNewFromPageId() { - $rev = Revision::newFromPageId( $this->testPage->getId() ); - $this->assertRevEquals( - $this->testPage->getRevision(), - $rev - ); - } - - /** - * @covers Revision::newFromPageId - */ - public function testNewFromPageIdWithLatestId() { - $rev = Revision::newFromPageId( - $this->testPage->getId(), - $this->testPage->getLatest() - ); - $this->assertRevEquals( - $this->testPage->getRevision(), - $rev - ); - } - - /** - * @covers Revision::newFromPageId - */ - public function testNewFromPageIdWithNotLatestId() { - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $rev = Revision::newFromPageId( - $this->testPage->getId(), - $this->testPage->getRevision()->getPrevious()->getId() - ); - $this->assertRevEquals( - $this->testPage->getRevision()->getPrevious(), - $rev - ); - } - - /** - * @covers Revision::fetchRevision - */ - public function testFetchRevision() { - // Hidden process cache assertion below - $this->testPage->getRevision()->getId(); - - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $id = $this->testPage->getRevision()->getId(); - - $res = Revision::fetchRevision( $this->testPage->getTitle() ); - - # note: order is unspecified - $rows = []; - while ( ( $row = $res->fetchObject() ) ) { - $rows[$row->rev_id] = $row; - } - - $this->assertEquals( 1, count( $rows ), 'expected exactly one revision' ); - $this->assertArrayHasKey( $id, $rows, 'missing revision with id ' . $id ); - } - - /** - * @covers Revision::getPage - */ - public function testGetPage() { - $page = $this->testPage; - - $orig = $this->makeRevisionWithProps( [ 'page' => $page->getId() ] ); - $rev = Revision::newFromId( $orig->getId() ); - - $this->assertEquals( $page->getId(), $rev->getPage() ); - } - - /** - * @covers Revision::isCurrent - */ - public function testIsCurrent() { - $rev1 = $this->testPage->getRevision(); - - # @todo find out if this should be true - # $this->assertTrue( $rev1->isCurrent() ); - - $rev1x = Revision::newFromId( $rev1->getId() ); - $this->assertTrue( $rev1x->isCurrent() ); - - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $rev2 = $this->testPage->getRevision(); - - # @todo find out if this should be true - # $this->assertTrue( $rev2->isCurrent() ); - - $rev1x = Revision::newFromId( $rev1->getId() ); - $this->assertFalse( $rev1x->isCurrent() ); - - $rev2x = Revision::newFromId( $rev2->getId() ); - $this->assertTrue( $rev2x->isCurrent() ); - } - - /** - * @covers Revision::getPrevious - */ - public function testGetPrevious() { - $oldestRevision = $this->testPage->getOldestRevision(); - $latestRevision = $this->testPage->getLatest(); - - $this->assertNull( $oldestRevision->getPrevious() ); - - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $newRevision = $this->testPage->getRevision(); - - $this->assertNotNull( $newRevision->getPrevious() ); - $this->assertEquals( $latestRevision, $newRevision->getPrevious()->getId() ); - } - - /** - * @covers Revision::getNext - */ - public function testGetNext() { - $rev1 = $this->testPage->getRevision(); - - $this->assertNull( $rev1->getNext() ); - - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $rev2 = $this->testPage->getRevision(); - - $this->assertNotNull( $rev1->getNext() ); - $this->assertEquals( $rev2->getId(), $rev1->getNext()->getId() ); - } - - /** - * @covers Revision::newNullRevision - */ - public function testNewNullRevision() { - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $orig = $this->testPage->getRevision(); - - $dbw = wfGetDB( DB_MASTER ); - $rev = Revision::newNullRevision( $dbw, $this->testPage->getId(), 'a null revision', false ); - - $this->assertNotEquals( $orig->getId(), $rev->getId(), - 'new null revision should have a different id from the original revision' ); - $this->assertEquals( $orig->getTextId(), $rev->getTextId(), - 'new null revision should have the same text id as the original revision' ); - $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() ); - } - - /** - * @covers Revision::insertOn - */ - public function testInsertOn() { - $ip = '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7'; - - $orig = $this->makeRevisionWithProps( [ - 'user_text' => $ip - ] ); - - // Make sure the revision was copied to ip_changes - $dbr = wfGetDB( DB_REPLICA ); - $res = $dbr->select( 'ip_changes', '*', [ 'ipc_rev_id' => $orig->getId() ] ); - $row = $res->fetchObject(); - - $this->assertEquals( IP::toHex( $ip ), $row->ipc_hex ); - $this->assertEquals( $orig->getTimestamp(), $row->ipc_rev_timestamp ); - } - - public static function provideUserWasLastToEdit() { - yield 'actually the last edit' => [ 3, true ]; - yield 'not the current edit, but still by this user' => [ 2, true ]; - yield 'edit by another user' => [ 1, false ]; - yield 'first edit, by this user, but another user edited in the mean time' => [ 0, false ]; - } - - /** - * @dataProvider provideUserWasLastToEdit - */ - public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) { - $userA = User::newFromName( "RevisionStorageTest_userA" ); - $userB = User::newFromName( "RevisionStorageTest_userB" ); - - if ( $userA->getId() === 0 ) { - $userA = User::createNew( $userA->getName() ); - } - - if ( $userB->getId() === 0 ) { - $userB = User::createNew( $userB->getName() ); - } - - $ns = $this->getDefaultWikitextNS(); - - $dbw = wfGetDB( DB_MASTER ); - $revisions = []; - - // create revisions ----------------------------- - $page = WikiPage::factory( Title::newFromText( - 'RevisionStorageTest_testUserWasLastToEdit', $ns ) ); - $page->insertOn( $dbw ); - - $revisions[0] = new Revision( [ - 'page' => $page->getId(), - // we need the title to determine the page's default content model - 'title' => $page->getTitle(), - 'timestamp' => '20120101000000', - 'user' => $userA->getId(), - 'text' => 'zero', - 'content_model' => CONTENT_MODEL_WIKITEXT, - 'summary' => 'edit zero' - ] ); - $revisions[0]->insertOn( $dbw ); - - $revisions[1] = new Revision( [ - 'page' => $page->getId(), - // still need the title, because $page->getId() is 0 (there's no entry in the page table) - 'title' => $page->getTitle(), - 'timestamp' => '20120101000100', - 'user' => $userA->getId(), - 'text' => 'one', - 'content_model' => CONTENT_MODEL_WIKITEXT, - 'summary' => 'edit one' - ] ); - $revisions[1]->insertOn( $dbw ); - - $revisions[2] = new Revision( [ - 'page' => $page->getId(), - 'title' => $page->getTitle(), - 'timestamp' => '20120101000200', - 'user' => $userB->getId(), - 'text' => 'two', - 'content_model' => CONTENT_MODEL_WIKITEXT, - 'summary' => 'edit two' - ] ); - $revisions[2]->insertOn( $dbw ); - - $revisions[3] = new Revision( [ - 'page' => $page->getId(), - 'title' => $page->getTitle(), - 'timestamp' => '20120101000300', - 'user' => $userA->getId(), - 'text' => 'three', - 'content_model' => CONTENT_MODEL_WIKITEXT, - 'summary' => 'edit three' - ] ); - $revisions[3]->insertOn( $dbw ); - - $revisions[4] = new Revision( [ - 'page' => $page->getId(), - 'title' => $page->getTitle(), - 'timestamp' => '20120101000200', - 'user' => $userA->getId(), - 'text' => 'zero', - 'content_model' => CONTENT_MODEL_WIKITEXT, - 'summary' => 'edit four' - ] ); - $revisions[4]->insertOn( $dbw ); - - // test it --------------------------------- - $since = $revisions[$sinceIdx]->getTimestamp(); - - $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since ); - - $this->assertEquals( $expectedLast, $wasLast ); - } - - /** - * @param string $text - * @param string $title - * @param string $model - * @param string $format - * - * @return Revision - */ - private function newTestRevision( $text, $title = "Test", - $model = CONTENT_MODEL_WIKITEXT, $format = null - ) { - if ( is_string( $title ) ) { - $title = Title::newFromText( $title ); - } - - $content = ContentHandler::makeContent( $text, $title, $model, $format ); - - $rev = new Revision( - [ - 'id' => 42, - 'page' => 23, - 'title' => $title, - - 'content' => $content, - 'length' => $content->getSize(), - 'comment' => "testing", - 'minor_edit' => false, - - 'content_format' => $format, - ] - ); - - return $rev; - } - - public function provideGetContentModel() { - // NOTE: we expect the help namespace to always contain wikitext - return [ - [ 'hello world', 'Help:Hello', null, null, CONTENT_MODEL_WIKITEXT ], - [ 'hello world', 'User:hello/there.css', null, null, CONTENT_MODEL_CSS ], - [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ], - ]; - } - - /** - * @dataProvider provideGetContentModel - * @covers Revision::getContentModel - */ - public function testGetContentModel( $text, $title, $model, $format, $expectedModel ) { - $rev = $this->newTestRevision( $text, $title, $model, $format ); - - $this->assertEquals( $expectedModel, $rev->getContentModel() ); - } - - public function provideGetContentFormat() { - // NOTE: we expect the help namespace to always contain wikitext - return [ - [ 'hello world', 'Help:Hello', null, null, CONTENT_FORMAT_WIKITEXT ], - [ 'hello world', 'Help:Hello', CONTENT_MODEL_CSS, null, CONTENT_FORMAT_CSS ], - [ 'hello world', 'User:hello/there.css', null, null, CONTENT_FORMAT_CSS ], - [ serialize( 'hello world' ), 'Dummy:Hello', null, null, DummyContentForTesting::MODEL_ID ], - ]; - } - - /** - * @dataProvider provideGetContentFormat - * @covers Revision::getContentFormat - */ - public function testGetContentFormat( $text, $title, $model, $format, $expectedFormat ) { - $rev = $this->newTestRevision( $text, $title, $model, $format ); - - $this->assertEquals( $expectedFormat, $rev->getContentFormat() ); - } - - public function provideGetContentHandler() { - // NOTE: we expect the help namespace to always contain wikitext - return [ - [ 'hello world', 'Help:Hello', null, null, 'WikitextContentHandler' ], - [ 'hello world', 'User:hello/there.css', null, null, 'CssContentHandler' ], - [ serialize( 'hello world' ), 'Dummy:Hello', null, null, 'DummyContentHandlerForTesting' ], - ]; - } - - /** - * @dataProvider provideGetContentHandler - * @covers Revision::getContentHandler - */ - public function testGetContentHandler( $text, $title, $model, $format, $expectedClass ) { - $rev = $this->newTestRevision( $text, $title, $model, $format ); - - $this->assertEquals( $expectedClass, get_class( $rev->getContentHandler() ) ); - } - - public function provideGetContent() { - // NOTE: we expect the help namespace to always contain wikitext - return [ - [ 'hello world', 'Help:Hello', null, null, Revision::FOR_PUBLIC, 'hello world' ], - [ - serialize( 'hello world' ), - 'Hello', - DummyContentForTesting::MODEL_ID, - null, - Revision::FOR_PUBLIC, - serialize( 'hello world' ) - ], - [ - serialize( 'hello world' ), - 'Dummy:Hello', - null, - null, - Revision::FOR_PUBLIC, - serialize( 'hello world' ) - ], - ]; - } - - /** - * @dataProvider provideGetContent - * @covers Revision::getContent - */ - public function testGetContent( $text, $title, $model, $format, - $audience, $expectedSerialization - ) { - $rev = $this->newTestRevision( $text, $title, $model, $format ); - $content = $rev->getContent( $audience ); - - $this->assertEquals( - $expectedSerialization, - is_null( $content ) ? null : $content->serialize( $format ) - ); - } - - /** - * @covers Revision::getContent - */ - public function testGetContent_failure() { - $rev = new Revision( [ - 'page' => $this->testPage->getId(), - 'content_model' => $this->testPage->getContentModel(), - 'text_id' => 123456789, // not in the test DB - ] ); - - $this->assertNull( $rev->getContent(), - "getContent() should return null if the revision's text blob could not be loaded." ); - - // NOTE: check this twice, once for lazy initialization, and once with the cached value. - $this->assertNull( $rev->getContent(), - "getContent() should return null if the revision's text blob could not be loaded." ); - } - - public function provideGetSize() { - return [ - [ "hello world.", CONTENT_MODEL_WIKITEXT, 12 ], - [ serialize( "hello world." ), DummyContentForTesting::MODEL_ID, 12 ], - ]; - } - - /** - * @covers Revision::getSize - * @dataProvider provideGetSize - */ - public function testGetSize( $text, $model, $expected_size ) { - $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSize', $model ); - $this->assertEquals( $expected_size, $rev->getSize() ); - } - - public function provideGetSha1() { - return [ - [ "hello world.", CONTENT_MODEL_WIKITEXT, Revision::base36Sha1( "hello world." ) ], - [ - serialize( "hello world." ), - DummyContentForTesting::MODEL_ID, - Revision::base36Sha1( serialize( "hello world." ) ) - ], - ]; - } - - /** - * @covers Revision::getSha1 - * @dataProvider provideGetSha1 - */ - public function testGetSha1( $text, $model, $expected_hash ) { - $rev = $this->newTestRevision( $text, 'RevisionTest_testGetSha1', $model ); - $this->assertEquals( $expected_hash, $rev->getSha1() ); - } - - /** - * Tests whether $rev->getContent() returns a clone when needed. - * - * @covers Revision::getContent - */ - public function testGetContentClone() { - $content = new RevisionTestModifyableContent( "foo" ); - - $rev = new Revision( - [ - 'id' => 42, - 'page' => 23, - 'title' => Title::newFromText( "testGetContentClone_dummy" ), - - 'content' => $content, - 'length' => $content->getSize(), - 'comment' => "testing", - 'minor_edit' => false, - ] - ); - - /** @var RevisionTestModifyableContent $content */ - $content = $rev->getContent( Revision::RAW ); - $content->setText( "bar" ); - - /** @var RevisionTestModifyableContent $content2 */ - $content2 = $rev->getContent( Revision::RAW ); - // content is mutable, expect clone - $this->assertNotSame( $content, $content2, "expected a clone" ); - // clone should contain the original text - $this->assertEquals( "foo", $content2->getText() ); - - $content2->setText( "bla bla" ); - // clones should be independent - $this->assertEquals( "bar", $content->getText() ); - } - - /** - * Tests whether $rev->getContent() returns the same object repeatedly if appropriate. - * @covers Revision::getContent - */ - public function testGetContentUncloned() { - $rev = $this->newTestRevision( "hello", "testGetContentUncloned_dummy", CONTENT_MODEL_WIKITEXT ); - $content = $rev->getContent( Revision::RAW ); - $content2 = $rev->getContent( Revision::RAW ); - - // for immutable content like wikitext, this should be the same object - $this->assertSame( $content, $content2 ); - } - - /** - * @covers Revision::loadFromId - */ - public function testLoadFromId() { - $rev = $this->testPage->getRevision(); - $this->assertRevEquals( - $rev, - Revision::loadFromId( wfGetDB( DB_MASTER ), $rev->getId() ) - ); - } - - /** - * @covers Revision::loadFromPageId - */ - public function testLoadFromPageId() { - $this->assertRevEquals( - $this->testPage->getRevision(), - Revision::loadFromPageId( wfGetDB( DB_MASTER ), $this->testPage->getId() ) - ); - } - - /** - * @covers Revision::loadFromPageId - */ - public function testLoadFromPageIdWithLatestRevId() { - $this->assertRevEquals( - $this->testPage->getRevision(), - Revision::loadFromPageId( - wfGetDB( DB_MASTER ), - $this->testPage->getId(), - $this->testPage->getLatest() - ) - ); - } - - /** - * @covers Revision::loadFromPageId - */ - public function testLoadFromPageIdWithNotLatestRevId() { - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $this->assertRevEquals( - $this->testPage->getRevision()->getPrevious(), - Revision::loadFromPageId( - wfGetDB( DB_MASTER ), - $this->testPage->getId(), - $this->testPage->getRevision()->getPrevious()->getId() - ) - ); - } - - /** - * @covers Revision::loadFromTitle - */ - public function testLoadFromTitle() { - $this->assertRevEquals( - $this->testPage->getRevision(), - Revision::loadFromTitle( wfGetDB( DB_MASTER ), $this->testPage->getTitle() ) - ); - } - - /** - * @covers Revision::loadFromTitle - */ - public function testLoadFromTitleWithLatestRevId() { - $this->assertRevEquals( - $this->testPage->getRevision(), - Revision::loadFromTitle( - wfGetDB( DB_MASTER ), - $this->testPage->getTitle(), - $this->testPage->getLatest() - ) - ); - } - - /** - * @covers Revision::loadFromTitle - */ - public function testLoadFromTitleWithNotLatestRevId() { - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $this->assertRevEquals( - $this->testPage->getRevision()->getPrevious(), - Revision::loadFromTitle( - wfGetDB( DB_MASTER ), - $this->testPage->getTitle(), - $this->testPage->getRevision()->getPrevious()->getId() - ) - ); - } - - /** - * @covers Revision::loadFromTimestamp() - */ - public function testLoadFromTimestamp() { - $this->assertRevEquals( - $this->testPage->getRevision(), - Revision::loadFromTimestamp( - wfGetDB( DB_MASTER ), - $this->testPage->getTitle(), - $this->testPage->getRevision()->getTimestamp() - ) - ); - } - - /** - * @covers Revision::getParentLengths - */ - public function testGetParentLengths_noRevIds() { - $this->assertSame( - [], - Revision::getParentLengths( - wfGetDB( DB_MASTER ), - [] - ) - ); - } - - /** - * @covers Revision::getParentLengths - */ - public function testGetParentLengths_oneRevId() { - $text = '831jr091jr0921kr21kr0921kjr0921j09rj1'; - $textLength = strlen( $text ); - - $this->testPage->doEditContent( new WikitextContent( $text ), __METHOD__ ); - $rev[1] = $this->testPage->getLatest(); - - $this->assertSame( - [ $rev[1] => strval( $textLength ) ], - Revision::getParentLengths( - wfGetDB( DB_MASTER ), - [ $rev[1] ] - ) - ); - } - - /** - * @covers Revision::getParentLengths - */ - public function testGetParentLengths_multipleRevIds() { - $textOne = '831jr091jr0921kr21kr0921kjr0921j09rj1'; - $textOneLength = strlen( $textOne ); - $textTwo = '831jr091jr092121j09rj1'; - $textTwoLength = strlen( $textTwo ); - - $this->testPage->doEditContent( new WikitextContent( $textOne ), __METHOD__ ); - $rev[1] = $this->testPage->getLatest(); - $this->testPage->doEditContent( new WikitextContent( $textTwo ), __METHOD__ ); - $rev[2] = $this->testPage->getLatest(); - - $this->assertSame( - [ $rev[1] => strval( $textOneLength ), $rev[2] => strval( $textTwoLength ) ], - Revision::getParentLengths( - wfGetDB( DB_MASTER ), - [ $rev[1], $rev[2] ] - ) - ); - } - - /** - * @covers Revision::getTitle - */ - public function testGetTitle_fromExistingRevision() { - $this->assertTrue( - $this->testPage->getTitle()->equals( - $this->testPage->getRevision()->getTitle() - ) - ); - } - - /** - * @covers Revision::getTitle - */ - public function testGetTitle_fromRevisionWhichWillLoadTheTitle() { - $rev = new Revision( [ 'id' => $this->testPage->getLatest() ] ); - $this->assertTrue( - $this->testPage->getTitle()->equals( - $rev->getTitle() - ) - ); - } - - /** - * @covers Revision::getTitle - */ - public function testGetTitle_forBadRevision() { - $rev = new Revision( [] ); - $this->assertNull( $rev->getTitle() ); - } - - /** - * @covers Revision::isMinor - */ - public function testIsMinor_true() { - // Use a sysop to ensure we can mark edits as minor - $sysop = $this->getTestSysop()->getUser(); - - $this->testPage->doEditContent( - new WikitextContent( __METHOD__ ), - __METHOD__, - EDIT_MINOR, - false, - $sysop - ); - $rev = $this->testPage->getRevision(); - - $this->assertSame( true, $rev->isMinor() ); - } - - /** - * @covers Revision::isMinor - */ - public function testIsMinor_false() { - $this->testPage->doEditContent( - new WikitextContent( __METHOD__ ), - __METHOD__, - 0 - ); - $rev = $this->testPage->getRevision(); - - $this->assertSame( false, $rev->isMinor() ); - } - - /** - * @covers Revision::getTimestamp - */ - public function testGetTimestamp() { - $testTimestamp = wfTimestampNow(); - - $this->testPage->doEditContent( - new WikitextContent( __METHOD__ ), - __METHOD__ - ); - $rev = $this->testPage->getRevision(); - - $this->assertInternalType( 'string', $rev->getTimestamp() ); - $this->assertTrue( strlen( $rev->getTimestamp() ) == strlen( 'YYYYMMDDHHMMSS' ) ); - $this->assertContains( substr( $testTimestamp, 0, 10 ), $rev->getTimestamp() ); - } - - /** - * @covers Revision::getUser - * @covers Revision::getUserText - */ - public function testGetUserAndText() { - $sysop = $this->getTestSysop()->getUser(); - - $this->testPage->doEditContent( - new WikitextContent( __METHOD__ ), - __METHOD__, - 0, - false, - $sysop - ); - $rev = $this->testPage->getRevision(); - - $this->assertSame( $sysop->getId(), $rev->getUser() ); - $this->assertSame( $sysop->getName(), $rev->getUserText() ); - } - - /** - * @covers Revision::isDeleted - */ - public function testIsDeleted_nothingDeleted() { - $rev = $this->testPage->getRevision(); - - $this->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) ); - $this->assertSame( false, $rev->isDeleted( Revision::DELETED_COMMENT ) ); - $this->assertSame( false, $rev->isDeleted( Revision::DELETED_RESTRICTED ) ); - $this->assertSame( false, $rev->isDeleted( Revision::DELETED_USER ) ); - } - - /** - * @covers Revision::getVisibility - */ - public function testGetVisibility_nothingDeleted() { - $rev = $this->testPage->getRevision(); - - $this->assertSame( 0, $rev->getVisibility() ); - } - - /** - * @covers Revision::getComment - */ - public function testGetComment_notDeleted() { - $expectedSummary = 'goatlicious summary'; - - $this->testPage->doEditContent( - new WikitextContent( __METHOD__ ), - $expectedSummary - ); - $rev = $this->testPage->getRevision(); - - $this->assertSame( $expectedSummary, $rev->getComment() ); - } - - /** - * @covers Revision::isUnpatrolled - */ - public function testIsUnpatrolled_returnsRecentChangesId() { - $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ ); - $rev = $this->testPage->getRevision(); - - $this->assertGreaterThan( 0, $rev->isUnpatrolled() ); - $this->assertSame( $rev->getRecentChange()->getAttribute( 'rc_id' ), $rev->isUnpatrolled() ); - } - - /** - * @covers Revision::isUnpatrolled - */ - public function testIsUnpatrolled_returnsZeroIfPatrolled() { - // This assumes that sysops are auto patrolled - $sysop = $this->getTestSysop()->getUser(); - $this->testPage->doEditContent( - new WikitextContent( __METHOD__ ), - __METHOD__, - 0, - false, - $sysop - ); - $rev = $this->testPage->getRevision(); - - $this->assertSame( 0, $rev->isUnpatrolled() ); - } - - /** - * This is a simple blanket test for all simple content getters and is methods to provide some - * coverage before the split of Revision into multiple classes for MCR work. - * @covers Revision::getContent - * @covers Revision::getSerializedData - * @covers Revision::getContentModel - * @covers Revision::getContentFormat - * @covers Revision::getContentHandler - */ - public function testSimpleContentGetters() { - $expectedText = 'testSimpleContentGetters in Revision. Goats love MCR...'; - $expectedSummary = 'goatlicious testSimpleContentGetters summary'; - - $this->testPage->doEditContent( - new WikitextContent( $expectedText ), - $expectedSummary - ); - $rev = $this->testPage->getRevision(); - - $this->assertSame( $expectedText, $rev->getContent()->getNativeData() ); - $this->assertSame( $expectedText, $rev->getSerializedData() ); - $this->assertSame( $this->testPage->getContentModel(), $rev->getContentModel() ); - $this->assertSame( $this->testPage->getContent()->getDefaultFormat(), $rev->getContentFormat() ); - $this->assertSame( $this->testPage->getContentHandler(), $rev->getContentHandler() ); - } - -} diff --git a/tests/phpunit/includes/RevisionNoContentHandlerDbTest.php b/tests/phpunit/includes/RevisionNoContentHandlerDbTest.php new file mode 100644 index 0000000000..c980a487f7 --- /dev/null +++ b/tests/phpunit/includes/RevisionNoContentHandlerDbTest.php @@ -0,0 +1,14 @@ + [ + [ + 'text' => 'hello world.', + 'content_model' => CONTENT_MODEL_JAVASCRIPT + ], + ]; + yield 'with content' => [ + [ + 'content' => new JavaScriptContent( 'hellow world.' ) + ], + ]; + } + + /** + * @dataProvider provideConstructFromArray + * @covers Revision::__construct + * @covers Revision::constructFromRowArray + */ + public function testConstructFromArray( array $rowArray ) { + $rev = new Revision( $rowArray ); + $this->assertNotNull( $rev->getContent(), 'no content object available' ); + $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() ); + $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() ); + } + + public function provideConstructFromArrayThrowsExceptions() { + yield 'content and text_id both not empty' => [ + [ + 'content' => new WikitextContent( 'GOAT' ), + 'text_id' => 'someid', + ], + new MWException( "Text already stored in external store (id someid), " . + "can't serialize content object" ) + ]; + yield 'with bad content object (class)' => [ + [ 'content' => new stdClass() ], + new MWException( '`content` field must contain a Content object.' ) + ]; + yield 'with bad content object (string)' => [ + [ 'content' => 'ImAGoat' ], + new MWException( '`content` field must contain a Content object.' ) + ]; + yield 'bad row format' => [ + 'imastring, not a row', + new MWException( 'Revision constructor passed invalid row format.' ) + ]; + } + + /** + * @dataProvider provideConstructFromArrayThrowsExceptions + * @covers Revision::__construct + * @covers Revision::constructFromRowArray + */ + public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) { + $this->setExpectedException( + get_class( $expectedException ), + $expectedException->getMessage(), + $expectedException->getCode() + ); + new Revision( $rowArray ); + } + + public function provideConstructFromRow() { + yield 'Full construction' => [ + [ + 'rev_id' => '2', + 'rev_page' => '1', + 'rev_text_id' => '2', + 'rev_timestamp' => '20171017114835', + 'rev_user_text' => '127.0.0.1', + 'rev_user' => '0', + 'rev_minor_edit' => '0', + 'rev_deleted' => '0', + 'rev_len' => '46', + 'rev_parent_id' => '1', + 'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', + 'rev_comment_text' => 'Goat Comment!', + 'rev_comment_data' => null, + 'rev_comment_cid' => null, + 'rev_content_format' => 'GOATFORMAT', + 'rev_content_model' => 'GOATMODEL', + ], + function ( RevisionTest $testCase, Revision $rev ) { + $testCase->assertSame( 2, $rev->getId() ); + $testCase->assertSame( 1, $rev->getPage() ); + $testCase->assertSame( 2, $rev->getTextId() ); + $testCase->assertSame( '20171017114835', $rev->getTimestamp() ); + $testCase->assertSame( '127.0.0.1', $rev->getUserText() ); + $testCase->assertSame( 0, $rev->getUser() ); + $testCase->assertSame( false, $rev->isMinor() ); + $testCase->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) ); + $testCase->assertSame( 46, $rev->getSize() ); + $testCase->assertSame( 1, $rev->getParentId() ); + $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() ); + $testCase->assertSame( 'Goat Comment!', $rev->getComment() ); + $testCase->assertSame( 'GOATFORMAT', $rev->getContentFormat() ); + $testCase->assertSame( 'GOATMODEL', $rev->getContentModel() ); + } + ]; + yield 'null fields' => [ + [ + 'rev_id' => '2', + 'rev_page' => '1', + 'rev_text_id' => '2', + 'rev_timestamp' => '20171017114835', + 'rev_user_text' => '127.0.0.1', + 'rev_user' => '0', + 'rev_minor_edit' => '0', + 'rev_deleted' => '0', + 'rev_comment_text' => 'Goat Comment!', + 'rev_comment_data' => null, + 'rev_comment_cid' => null, + ], + function ( RevisionTest $testCase, Revision $rev ) { + $testCase->assertNull( $rev->getSize() ); + $testCase->assertNull( $rev->getParentId() ); + $testCase->assertNull( $rev->getSha1() ); + $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat() ); + $testCase->assertSame( 'wikitext', $rev->getContentModel() ); + } + ]; + } + + /** + * @dataProvider provideConstructFromRow + * @covers Revision::__construct + * @covers Revision::constructFromDbRowObject + */ + public function testConstructFromRow( array $arrayData, $assertions ) { + $row = (object)$arrayData; + $rev = new Revision( $row ); + $assertions( $this, $rev ); + } + + public function provideGetRevisionText() { + yield 'Generic test' => [ + 'This is a goat of revision text.', + [ + 'old_flags' => '', + 'old_text' => 'This is a goat of revision text.', + ], + ]; + } + + public function provideGetId() { + yield [ + [], + null + ]; + yield [ + [ 'id' => 998 ], + 998 + ]; + } + + /** + * @dataProvider provideGetId + * @covers Revision::getId + */ + public function testGetId( $rowArray, $expectedId ) { + $rev = new Revision( $rowArray ); + $this->assertEquals( $expectedId, $rev->getId() ); + } + + public function provideSetId() { + yield [ '123', 123 ]; + yield [ 456, 456 ]; + } + + /** + * @dataProvider provideSetId + * @covers Revision::setId + */ + public function testSetId( $input, $expected ) { + $rev = new Revision( [] ); + $rev->setId( $input ); + $this->assertSame( $expected, $rev->getId() ); + } + + public function provideSetUserIdAndName() { + yield [ '123', 123, 'GOaT' ]; + yield [ 456, 456, 'GOaT' ]; + } + + /** + * @dataProvider provideSetUserIdAndName + * @covers Revision::setUserIdAndName + */ + public function testSetUserIdAndName( $inputId, $expectedId, $name ) { + $rev = new Revision( [] ); + $rev->setUserIdAndName( $inputId, $name ); + $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) ); + $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) ); + } + + public function provideGetTextId() { + yield [ [], null ]; + yield [ [ 'text_id' => '123' ], 123 ]; + yield [ [ 'text_id' => 456 ], 456 ]; + } + + /** + * @dataProvider provideGetTextId + * @covers Revision::getTextId() + */ + public function testGetTextId( $rowArray, $expected ) { + $rev = new Revision( $rowArray ); + $this->assertSame( $expected, $rev->getTextId() ); + } + + public function provideGetParentId() { + yield [ [], null ]; + yield [ [ 'parent_id' => '123' ], 123 ]; + yield [ [ 'parent_id' => 456 ], 456 ]; + } + + /** + * @dataProvider provideGetParentId + * @covers Revision::getParentId() + */ + public function testGetParentId( $rowArray, $expected ) { + $rev = new Revision( $rowArray ); + $this->assertSame( $expected, $rev->getParentId() ); + } + + /** + * @covers Revision::getRevisionText + * @dataProvider provideGetRevisionText + */ + public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) { + $this->assertEquals( + $expected, + Revision::getRevisionText( (object)$rowData, $prefix, $wiki ) ); + } + + public function provideGetRevisionTextWithZlibExtension() { + yield 'Generic gzip test' => [ + 'This is a small goat of revision text.', + [ + 'old_flags' => 'gzip', + 'old_text' => gzdeflate( 'This is a small goat of revision text.' ), + ], + ]; + } + + /** + * @covers Revision::getRevisionText + * @dataProvider provideGetRevisionTextWithZlibExtension + */ + public function testGetRevisionWithZlibExtension( $expected, $rowData ) { + $this->checkPHPExtension( 'zlib' ); + $this->testGetRevisionText( $expected, $rowData ); + } + + public function provideGetRevisionTextWithLegacyEncoding() { + yield 'Utf8Native' => [ + "Wiki est l'\xc3\xa9cole superieur !", + 'iso-8859-1', + [ + 'old_flags' => 'utf-8', + 'old_text' => "Wiki est l'\xc3\xa9cole superieur !", + ] + ]; + yield 'Utf8Legacy' => [ + "Wiki est l'\xc3\xa9cole superieur !", + 'iso-8859-1', + [ + 'old_flags' => '', + 'old_text' => "Wiki est l'\xe9cole superieur !", + ] + ]; + } + + /** + * @covers Revision::getRevisionText + * @dataProvider provideGetRevisionTextWithLegacyEncoding + */ + public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $rowData ) { + $this->setMwGlobals( 'wgLegacyEncoding', $encoding ); + $this->testGetRevisionText( $expected, $rowData ); + } + + public function provideGetRevisionTextWithGzipAndLegacyEncoding() { + /** + * WARNING! + * Do not set the external flag! + * Otherwise, getRevisionText will hit the live database (if ExternalStore is enabled)! + */ + yield 'Utf8NativeGzip' => [ + "Wiki est l'\xc3\xa9cole superieur !", + 'iso-8859-1', + [ + 'old_flags' => 'gzip,utf-8', + 'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ), + ] + ]; + yield 'Utf8LegacyGzip' => [ + "Wiki est l'\xc3\xa9cole superieur !", + 'iso-8859-1', + [ + 'old_flags' => 'gzip', + 'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ), + ] + ]; + } + + /** + * @covers Revision::getRevisionText + * @dataProvider provideGetRevisionTextWithGzipAndLegacyEncoding + */ + public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $rowData ) { + $this->checkPHPExtension( 'zlib' ); + $this->setMwGlobals( 'wgLegacyEncoding', $encoding ); + $this->testGetRevisionText( $expected, $rowData ); + } + + /** + * @covers Revision::compressRevisionText + */ + public function testCompressRevisionTextUtf8() { + $row = new stdClass; + $row->old_text = "Wiki est l'\xc3\xa9cole superieur !"; + $row->old_flags = Revision::compressRevisionText( $row->old_text ); + $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ), + "Flags should contain 'utf-8'" ); + $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ), + "Flags should not contain 'gzip'" ); + $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", + $row->old_text, "Direct check" ); + $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", + Revision::getRevisionText( $row ), "getRevisionText" ); + } + + /** + * @covers Revision::compressRevisionText + */ + public function testCompressRevisionTextUtf8Gzip() { + $this->checkPHPExtension( 'zlib' ); + $this->setMwGlobals( 'wgCompressRevisions', true ); + + $row = new stdClass; + $row->old_text = "Wiki est l'\xc3\xa9cole superieur !"; + $row->old_flags = Revision::compressRevisionText( $row->old_text ); + $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ), + "Flags should contain 'utf-8'" ); + $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ), + "Flags should contain 'gzip'" ); + $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", + gzinflate( $row->old_text ), "Direct check" ); + $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", + Revision::getRevisionText( $row ), "getRevisionText" ); + } + + public function provideFetchFromConds() { + yield [ 0, [] ]; + yield [ Revision::READ_LOCKING, [ 'FOR UPDATE' ] ]; + } + + /** + * @dataProvider provideFetchFromConds + * @covers Revision::fetchFromConds + */ + public function testFetchFromConds( $flags, array $options ) { + $conditions = [ 'conditionsArray' ]; + + $db = $this->getMock( IDatabase::class ); + $db->expects( $this->once() ) + ->method( 'selectRow' ) + ->with( + $this->equalTo( [ 'revision', 'page', 'user' ] ), + // We don't really care about the fields are they come from the selectField methods + $this->isType( 'array' ), + $this->equalTo( $conditions ), + // Method name + $this->equalTo( 'Revision::fetchFromConds' ), + $this->equalTo( $options ), + // We don't really care about the join conds are they come from the joinCond methods + $this->isType( 'array' ) + ) + ->willReturn( 'RETURNVALUE' ); + + $wrapper = TestingAccessWrapper::newFromClass( Revision::class ); + $result = $wrapper->fetchFromConds( $db, $conditions, $flags ); + + $this->assertEquals( 'RETURNVALUE', $result ); + } +} diff --git a/tests/phpunit/includes/RevisionUnitTest.php b/tests/phpunit/includes/RevisionUnitTest.php deleted file mode 100644 index 7b8d316f47..0000000000 --- a/tests/phpunit/includes/RevisionUnitTest.php +++ /dev/null @@ -1,397 +0,0 @@ - [ - [ - 'text' => 'hello world.', - 'content_model' => CONTENT_MODEL_JAVASCRIPT - ], - ]; - yield 'with content' => [ - [ - 'content' => new JavaScriptContent( 'hellow world.' ) - ], - ]; - } - - /** - * @dataProvider provideConstructFromArray - * @covers Revision::__construct - * @covers Revision::constructFromRowArray - */ - public function testConstructFromArray( array $rowArray ) { - $rev = new Revision( $rowArray ); - $this->assertNotNull( $rev->getContent(), 'no content object available' ); - $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() ); - $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() ); - } - - public function provideConstructFromArrayThrowsExceptions() { - yield 'content and text_id both not empty' => [ - [ - 'content' => new WikitextContent( 'GOAT' ), - 'text_id' => 'someid', - ], - new MWException( "Text already stored in external store (id someid), " . - "can't serialize content object" ) - ]; - yield 'with bad content object (class)' => [ - [ 'content' => new stdClass() ], - new MWException( '`content` field must contain a Content object.' ) - ]; - yield 'with bad content object (string)' => [ - [ 'content' => 'ImAGoat' ], - new MWException( '`content` field must contain a Content object.' ) - ]; - yield 'bad row format' => [ - 'imastring, not a row', - new MWException( 'Revision constructor passed invalid row format.' ) - ]; - } - - /** - * @dataProvider provideConstructFromArrayThrowsExceptions - * @covers Revision::__construct - * @covers Revision::constructFromRowArray - */ - public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) { - $this->setExpectedException( - get_class( $expectedException ), - $expectedException->getMessage(), - $expectedException->getCode() - ); - new Revision( $rowArray ); - } - - public function provideConstructFromRow() { - yield 'Full construction' => [ - [ - 'rev_id' => '2', - 'rev_page' => '1', - 'rev_text_id' => '2', - 'rev_timestamp' => '20171017114835', - 'rev_user_text' => '127.0.0.1', - 'rev_user' => '0', - 'rev_minor_edit' => '0', - 'rev_deleted' => '0', - 'rev_len' => '46', - 'rev_parent_id' => '1', - 'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', - 'rev_comment_text' => 'Goat Comment!', - 'rev_comment_data' => null, - 'rev_comment_cid' => null, - 'rev_content_format' => 'GOATFORMAT', - 'rev_content_model' => 'GOATMODEL', - ], - function ( RevisionUnitTest $testCase, Revision $rev ) { - $testCase->assertSame( 2, $rev->getId() ); - $testCase->assertSame( 1, $rev->getPage() ); - $testCase->assertSame( 2, $rev->getTextId() ); - $testCase->assertSame( '20171017114835', $rev->getTimestamp() ); - $testCase->assertSame( '127.0.0.1', $rev->getUserText() ); - $testCase->assertSame( 0, $rev->getUser() ); - $testCase->assertSame( false, $rev->isMinor() ); - $testCase->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) ); - $testCase->assertSame( 46, $rev->getSize() ); - $testCase->assertSame( 1, $rev->getParentId() ); - $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() ); - $testCase->assertSame( 'Goat Comment!', $rev->getComment() ); - $testCase->assertSame( 'GOATFORMAT', $rev->getContentFormat() ); - $testCase->assertSame( 'GOATMODEL', $rev->getContentModel() ); - } - ]; - yield 'null fields' => [ - [ - 'rev_id' => '2', - 'rev_page' => '1', - 'rev_text_id' => '2', - 'rev_timestamp' => '20171017114835', - 'rev_user_text' => '127.0.0.1', - 'rev_user' => '0', - 'rev_minor_edit' => '0', - 'rev_deleted' => '0', - 'rev_comment_text' => 'Goat Comment!', - 'rev_comment_data' => null, - 'rev_comment_cid' => null, - ], - function ( RevisionUnitTest $testCase, Revision $rev ) { - $testCase->assertNull( $rev->getSize() ); - $testCase->assertNull( $rev->getParentId() ); - $testCase->assertNull( $rev->getSha1() ); - $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat() ); - $testCase->assertSame( 'wikitext', $rev->getContentModel() ); - } - ]; - } - - /** - * @dataProvider provideConstructFromRow - * @covers Revision::__construct - * @covers Revision::constructFromDbRowObject - */ - public function testConstructFromRow( array $arrayData, $assertions ) { - $row = (object)$arrayData; - $rev = new Revision( $row ); - $assertions( $this, $rev ); - } - - public function provideGetRevisionText() { - yield 'Generic test' => [ - 'This is a goat of revision text.', - [ - 'old_flags' => '', - 'old_text' => 'This is a goat of revision text.', - ], - ]; - } - - public function provideGetId() { - yield [ - [], - null - ]; - yield [ - [ 'id' => 998 ], - 998 - ]; - } - - /** - * @dataProvider provideGetId - * @covers Revision::getId - */ - public function testGetId( $rowArray, $expectedId ) { - $rev = new Revision( $rowArray ); - $this->assertEquals( $expectedId, $rev->getId() ); - } - - public function provideSetId() { - yield [ '123', 123 ]; - yield [ 456, 456 ]; - } - - /** - * @dataProvider provideSetId - * @covers Revision::setId - */ - public function testSetId( $input, $expected ) { - $rev = new Revision( [] ); - $rev->setId( $input ); - $this->assertSame( $expected, $rev->getId() ); - } - - public function provideSetUserIdAndName() { - yield [ '123', 123, 'GOaT' ]; - yield [ 456, 456, 'GOaT' ]; - } - - /** - * @dataProvider provideSetUserIdAndName - * @covers Revision::setUserIdAndName - */ - public function testSetUserIdAndName( $inputId, $expectedId, $name ) { - $rev = new Revision( [] ); - $rev->setUserIdAndName( $inputId, $name ); - $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) ); - $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) ); - } - - public function provideGetTextId() { - yield [ [], null ]; - yield [ [ 'text_id' => '123' ], 123 ]; - yield [ [ 'text_id' => 456 ], 456 ]; - } - - /** - * @dataProvider provideGetTextId - * @covers Revision::getTextId() - */ - public function testGetTextId( $rowArray, $expected ) { - $rev = new Revision( $rowArray ); - $this->assertSame( $expected, $rev->getTextId() ); - } - - public function provideGetParentId() { - yield [ [], null ]; - yield [ [ 'parent_id' => '123' ], 123 ]; - yield [ [ 'parent_id' => 456 ], 456 ]; - } - - /** - * @dataProvider provideGetParentId - * @covers Revision::getParentId() - */ - public function testGetParentId( $rowArray, $expected ) { - $rev = new Revision( $rowArray ); - $this->assertSame( $expected, $rev->getParentId() ); - } - - /** - * @covers Revision::getRevisionText - * @dataProvider provideGetRevisionText - */ - public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) { - $this->assertEquals( - $expected, - Revision::getRevisionText( (object)$rowData, $prefix, $wiki ) ); - } - - public function provideGetRevisionTextWithZlibExtension() { - yield 'Generic gzip test' => [ - 'This is a small goat of revision text.', - [ - 'old_flags' => 'gzip', - 'old_text' => gzdeflate( 'This is a small goat of revision text.' ), - ], - ]; - } - - /** - * @covers Revision::getRevisionText - * @dataProvider provideGetRevisionTextWithZlibExtension - */ - public function testGetRevisionWithZlibExtension( $expected, $rowData ) { - $this->checkPHPExtension( 'zlib' ); - $this->testGetRevisionText( $expected, $rowData ); - } - - public function provideGetRevisionTextWithLegacyEncoding() { - yield 'Utf8Native' => [ - "Wiki est l'\xc3\xa9cole superieur !", - 'iso-8859-1', - [ - 'old_flags' => 'utf-8', - 'old_text' => "Wiki est l'\xc3\xa9cole superieur !", - ] - ]; - yield 'Utf8Legacy' => [ - "Wiki est l'\xc3\xa9cole superieur !", - 'iso-8859-1', - [ - 'old_flags' => '', - 'old_text' => "Wiki est l'\xe9cole superieur !", - ] - ]; - } - - /** - * @covers Revision::getRevisionText - * @dataProvider provideGetRevisionTextWithLegacyEncoding - */ - public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $rowData ) { - $this->setMwGlobals( 'wgLegacyEncoding', $encoding ); - $this->testGetRevisionText( $expected, $rowData ); - } - - public function provideGetRevisionTextWithGzipAndLegacyEncoding() { - /** - * WARNING! - * Do not set the external flag! - * Otherwise, getRevisionText will hit the live database (if ExternalStore is enabled)! - */ - yield 'Utf8NativeGzip' => [ - "Wiki est l'\xc3\xa9cole superieur !", - 'iso-8859-1', - [ - 'old_flags' => 'gzip,utf-8', - 'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ), - ] - ]; - yield 'Utf8LegacyGzip' => [ - "Wiki est l'\xc3\xa9cole superieur !", - 'iso-8859-1', - [ - 'old_flags' => 'gzip', - 'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ), - ] - ]; - } - - /** - * @covers Revision::getRevisionText - * @dataProvider provideGetRevisionTextWithGzipAndLegacyEncoding - */ - public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $rowData ) { - $this->checkPHPExtension( 'zlib' ); - $this->setMwGlobals( 'wgLegacyEncoding', $encoding ); - $this->testGetRevisionText( $expected, $rowData ); - } - - /** - * @covers Revision::compressRevisionText - */ - public function testCompressRevisionTextUtf8() { - $row = new stdClass; - $row->old_text = "Wiki est l'\xc3\xa9cole superieur !"; - $row->old_flags = Revision::compressRevisionText( $row->old_text ); - $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ), - "Flags should contain 'utf-8'" ); - $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ), - "Flags should not contain 'gzip'" ); - $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", - $row->old_text, "Direct check" ); - $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", - Revision::getRevisionText( $row ), "getRevisionText" ); - } - - /** - * @covers Revision::compressRevisionText - */ - public function testCompressRevisionTextUtf8Gzip() { - $this->checkPHPExtension( 'zlib' ); - $this->setMwGlobals( 'wgCompressRevisions', true ); - - $row = new stdClass; - $row->old_text = "Wiki est l'\xc3\xa9cole superieur !"; - $row->old_flags = Revision::compressRevisionText( $row->old_text ); - $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ), - "Flags should contain 'utf-8'" ); - $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ), - "Flags should contain 'gzip'" ); - $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", - gzinflate( $row->old_text ), "Direct check" ); - $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", - Revision::getRevisionText( $row ), "getRevisionText" ); - } - - public function provideFetchFromConds() { - yield [ 0, [] ]; - yield [ Revision::READ_LOCKING, [ 'FOR UPDATE' ] ]; - } - - /** - * @dataProvider provideFetchFromConds - * @covers Revision::fetchFromConds - */ - public function testFetchFromConds( $flags, array $options ) { - $conditions = [ 'conditionsArray' ]; - - $db = $this->getMock( IDatabase::class ); - $db->expects( $this->once() ) - ->method( 'selectRow' ) - ->with( - $this->equalTo( [ 'revision', 'page', 'user' ] ), - // We don't really care about the fields are they come from the selectField methods - $this->isType( 'array' ), - $this->equalTo( $conditions ), - // Method name - $this->equalTo( 'Revision::fetchFromConds' ), - $this->equalTo( $options ), - // We don't really care about the join conds are they come from the joinCond methods - $this->isType( 'array' ) - ) - ->willReturn( 'RETURNVALUE' ); - - $wrapper = TestingAccessWrapper::newFromClass( Revision::class ); - $result = $wrapper->fetchFromConds( $db, $conditions, $flags ); - - $this->assertEquals( 'RETURNVALUE', $result ); - } -}