Merge "Revert "Log the reason why revision->getContent() returns null""
[lhc/web/wiklou.git] / tests / phpunit / includes / CommentStoreTest.php
index 4e0210a..a510897 100644 (file)
@@ -20,11 +20,22 @@ class CommentStoreTest extends MediaWikiLangTestCase {
        /**
         * Create a store for a particular stage
         * @param int $stage
+        * @return CommentStore
+        */
+       protected function makeStore( $stage ) {
+               global $wgContLang;
+               $store = new CommentStore( $wgContLang, $stage );
+               return $store;
+       }
+
+       /**
+        * Create a store for a particular stage and key (for testing deprecated behaviour)
+        * @param int $stage
         * @param string $key
         * @return CommentStore
         */
-       protected function makeStore( $stage, $key ) {
-               $store = new CommentStore( $key );
+       protected function makeStoreWithKey( $stage, $key ) {
+               $store = CommentStore::newKey( $key );
                TestingAccessWrapper::newFromObject( $store )->stage = $stage;
                return $store;
        }
@@ -35,12 +46,24 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @param string $key
         * @param array $expect
         */
-       public function testGetFields( $stage, $key, $expect ) {
-               $store = $this->makeStore( $stage, $key );
+       public function testGetFields_withKeyConstruction( $stage, $key, $expect ) {
+               $store = $this->makeStoreWithKey( $stage, $key );
                $result = $store->getFields();
                $this->assertEquals( $expect, $result );
        }
 
+       /**
+        * @dataProvider provideGetFields
+        * @param int $stage
+        * @param string $key
+        * @param array $expect
+        */
+       public function testGetFields( $stage, $key, $expect ) {
+               $store = $this->makeStore( $stage );
+               $result = $store->getFields( $key );
+               $this->assertEquals( $expect, $result );
+       }
+
        public static function provideGetFields() {
                return [
                        'Simple table, old' => [
@@ -110,12 +133,24 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @param string $key
         * @param array $expect
         */
-       public function testGetJoin( $stage, $key, $expect ) {
-               $store = $this->makeStore( $stage, $key );
+       public function testGetJoin_withKeyConstruction( $stage, $key, $expect ) {
+               $store = $this->makeStoreWithKey( $stage, $key );
                $result = $store->getJoin();
                $this->assertEquals( $expect, $result );
        }
 
+       /**
+        * @dataProvider provideGetJoin
+        * @param int $stage
+        * @param string $key
+        * @param array $expect
+        */
+       public function testGetJoin( $stage, $key, $expect ) {
+               $store = $this->makeStore( $stage );
+               $result = $store->getJoin( $key );
+               $this->assertEquals( $expect, $result );
+       }
+
        public static function provideGetJoin() {
                return [
                        'Simple table, old' => [
@@ -343,11 +378,106 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                                $extraFields['ipb_address'] = __CLASS__ . "#$writeStage";
                        }
 
-                       $wstore = $this->makeStore( $writeStage, $key );
+                       $wstore = $this->makeStore( $writeStage );
                        $usesTemp = $key === 'rev_comment';
 
                        if ( $usesTemp ) {
-                               list( $fields, $callback ) = $wstore->insertWithTempTable( $this->db, $comment, $data );
+                               list( $fields, $callback ) = $wstore->insertWithTempTable(
+                                       $this->db, $key, $comment, $data
+                               );
+                       } else {
+                               $fields = $wstore->insert( $this->db, $key, $comment, $data );
+                       }
+
+                       if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
+                               $this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
+                       } else {
+                               $this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
+                       }
+                       if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
+                               $this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
+                       } else {
+                               $this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
+                       }
+
+                       $this->db->insert( $table, $extraFields + $fields, __METHOD__ );
+                       $id = $this->db->insertId();
+                       if ( $usesTemp ) {
+                               $callback( $id );
+                       }
+
+                       for ( $readStage = $readRange[0]; $readStage <= $readRange[1]; $readStage++ ) {
+                               $rstore = $this->makeStore( $readStage );
+
+                               $fieldRow = $this->db->selectRow(
+                                       $table,
+                                       $rstore->getFields( $key ),
+                                       [ $pk => $id ],
+                                       __METHOD__
+                               );
+
+                               $queryInfo = $rstore->getJoin( $key );
+                               $joinRow = $this->db->selectRow(
+                                       [ $table ] + $queryInfo['tables'],
+                                       $queryInfo['fields'],
+                                       [ $pk => $id ],
+                                       __METHOD__,
+                                       [],
+                                       $queryInfo['joins']
+                               );
+
+                               $this->assertComment(
+                                       $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+                                       $rstore->getCommentLegacy( $this->db, $key, $fieldRow ),
+                                       "w=$writeStage, r=$readStage, from getFields()"
+                               );
+                               $this->assertComment(
+                                       $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
+                                       $rstore->getComment( $key, $joinRow ),
+                                       "w=$writeStage, r=$readStage, from getJoin()"
+                               );
+                       }
+               }
+       }
+
+       /**
+        * @dataProvider provideInsertRoundTrip
+        * @param string $table
+        * @param string $key
+        * @param string $pk
+        * @param string $extraFields
+        * @param string|Message $comment
+        * @param array|null $data
+        * @param array $expect
+        */
+       public function testInsertRoundTrip_withKeyConstruction(
+               $table, $key, $pk, $extraFields, $comment, $data, $expect
+       ) {
+               $expectOld = [
+                       'text' => $expect['text'],
+                       'message' => new RawMessage( '$1', [ $expect['text'] ] ),
+                       'data' => null,
+               ];
+
+               $stages = [
+                       MIGRATION_OLD => [ MIGRATION_OLD, MIGRATION_WRITE_NEW ],
+                       MIGRATION_WRITE_BOTH => [ MIGRATION_OLD, MIGRATION_NEW ],
+                       MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
+                       MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
+               ];
+
+               foreach ( $stages as $writeStage => $readRange ) {
+                       if ( $key === 'ipb_reason' ) {
+                               $extraFields['ipb_address'] = __CLASS__ . "#$writeStage";
+                       }
+
+                       $wstore = $this->makeStoreWithKey( $writeStage, $key );
+                       $usesTemp = $key === 'rev_comment';
+
+                       if ( $usesTemp ) {
+                               list( $fields, $callback ) = $wstore->insertWithTempTable(
+                                       $this->db, $comment, $data
+                               );
                        } else {
                                $fields = $wstore->insert( $this->db, $comment, $data );
                        }
@@ -370,7 +500,7 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                        }
 
                        for ( $readStage = $readRange[0]; $readStage <= $readRange[1]; $readStage++ ) {
-                               $rstore = $this->makeStore( $readStage, $key );
+                               $rstore = $this->makeStoreWithKey( $readStage, $key );
 
                                $fieldRow = $this->db->selectRow(
                                        $table,
@@ -412,7 +542,6 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                $ipbfields = [
                        'ipb_range_start' => '',
                        'ipb_range_end' => '',
-                       'ipb_by' => 0,
                        'ipb_timestamp' => $db->timestamp(),
                        'ipb_expiry' => $db->getInfinity(),
                ];
@@ -420,8 +549,6 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                        'rev_page' => 42,
                        'rev_text_id' => 42,
                        'rev_len' => 0,
-                       'rev_user' => 0,
-                       'rev_user_text' => '',
                        'rev_timestamp' => $db->timestamp(),
                ];
                $comStoreComment = new CommentStoreComment(
@@ -518,26 +645,26 @@ class CommentStoreTest extends MediaWikiLangTestCase {
        }
 
        public function testGetCommentErrors() {
-               MediaWiki\suppressWarnings();
-               $reset = new ScopedCallback( 'MediaWiki\restoreWarnings' );
+               Wikimedia\suppressWarnings();
+               $reset = new ScopedCallback( 'Wikimedia\restoreWarnings' );
 
-               $store = $this->makeStore( MIGRATION_OLD, 'dummy' );
-               $res = $store->getComment( [ 'dummy' => 'comment' ] );
+               $store = $this->makeStore( MIGRATION_OLD );
+               $res = $store->getComment( 'dummy', [ 'dummy' => 'comment' ] );
                $this->assertSame( '', $res->text );
-               $res = $store->getComment( [ 'dummy' => 'comment' ], true );
+               $res = $store->getComment( 'dummy', [ 'dummy' => 'comment' ], true );
                $this->assertSame( 'comment', $res->text );
 
-               $store = $this->makeStore( MIGRATION_NEW, 'dummy' );
+               $store = $this->makeStore( MIGRATION_NEW );
                try {
-                       $store->getComment( [ 'dummy' => 'comment' ] );
+                       $store->getComment( 'dummy', [ 'dummy' => 'comment' ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame( '$row does not contain fields needed for comment dummy', $ex->getMessage() );
                }
-               $res = $store->getComment( [ 'dummy' => 'comment' ], true );
+               $res = $store->getComment( 'dummy', [ 'dummy' => 'comment' ], true );
                $this->assertSame( 'comment', $res->text );
                try {
-                       $store->getComment( [ 'dummy_id' => 1 ] );
+                       $store->getComment( 'dummy', [ 'dummy_id' => 1 ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame(
@@ -547,19 +674,19 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                        );
                }
 
-               $store = $this->makeStore( MIGRATION_NEW, 'rev_comment' );
+               $store = $this->makeStore( MIGRATION_NEW );
                try {
-                       $store->getComment( [ 'rev_comment' => 'comment' ] );
+                       $store->getComment( 'rev_comment', [ 'rev_comment' => 'comment' ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame(
                                '$row does not contain fields needed for comment rev_comment', $ex->getMessage()
                        );
                }
-               $res = $store->getComment( [ 'rev_comment' => 'comment' ], true );
+               $res = $store->getComment( 'rev_comment', [ 'rev_comment' => 'comment' ], true );
                $this->assertSame( 'comment', $res->text );
                try {
-                       $store->getComment( [ 'rev_comment_pk' => 1 ] );
+                       $store->getComment( 'rev_comment', [ 'rev_comment_pk' => 1 ] );
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                        $this->assertSame(
@@ -586,8 +713,8 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @expectedExceptionMessage Must use insertWithTempTable() for rev_comment
         */
        public function testInsertWrong( $stage ) {
-               $store = $this->makeStore( $stage, 'rev_comment' );
-               $store->insert( $this->db, 'foo' );
+               $store = $this->makeStore( $stage );
+               $store->insert( $this->db, 'rev_comment', 'foo' );
        }
 
        /**
@@ -597,8 +724,8 @@ class CommentStoreTest extends MediaWikiLangTestCase {
         * @expectedExceptionMessage Must use insert() for ipb_reason
         */
        public function testInsertWithTempTableWrong( $stage ) {
-               $store = $this->makeStore( $stage, 'ipb_reason' );
-               $store->insertWithTempTable( $this->db, 'foo' );
+               $store = $this->makeStore( $stage );
+               $store->insertWithTempTable( $this->db, 'ipb_reason', 'foo' );
        }
 
        /**
@@ -610,12 +737,41 @@ class CommentStoreTest extends MediaWikiLangTestCase {
                $wrap->formerTempTables += [ 'ipb_reason' => '1.30' ];
 
                $this->hideDeprecated( 'CommentStore::insertWithTempTable for ipb_reason' );
-               $store = $this->makeStore( $stage, 'ipb_reason' );
-               list( $fields, $callback ) = $store->insertWithTempTable( $this->db, 'foo' );
+               $store = $this->makeStore( $stage );
+               list( $fields, $callback ) = $store->insertWithTempTable( $this->db, 'ipb_reason', 'foo' );
                $this->assertTrue( is_callable( $callback ) );
        }
 
-       public function testConstructor() {
+       public function testInsertTruncation() {
+               $comment = str_repeat( '💣', 16400 );
+               $truncated1 = str_repeat( '💣', 63 ) . '...';
+               $truncated2 = str_repeat( '💣', CommentStore::COMMENT_CHARACTER_LIMIT - 3 ) . '...';
+
+               $store = $this->makeStore( MIGRATION_WRITE_BOTH );
+               $fields = $store->insert( $this->db, 'ipb_reason', $comment );
+               $this->assertSame( $truncated1, $fields['ipb_reason'] );
+               $stored = $this->db->selectField(
+                       'comment', 'comment_text', [ 'comment_id' => $fields['ipb_reason_id'] ], __METHOD__
+               );
+               $this->assertSame( $truncated2, $stored );
+       }
+
+       /**
+        * @expectedException OverflowException
+        * @expectedExceptionMessage Comment data is too long (65611 bytes, maximum is 65535)
+        */
+       public function testInsertTooMuchData() {
+               $store = $this->makeStore( MIGRATION_WRITE_BOTH );
+               $store->insert( $this->db, 'ipb_reason', 'foo', [
+                       'long' => str_repeat( '💣', 16400 )
+               ] );
+       }
+
+       public function testGetStore() {
+               $this->assertInstanceOf( CommentStore::class, CommentStore::getStore() );
+       }
+
+       public function testNewKey() {
                $this->assertInstanceOf( CommentStore::class, CommentStore::newKey( 'dummy' ) );
        }