]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - tests/phpunit/includes/CommentStoreTest.php
MediaWiki 1.30.2-scripts
[autoinstalls/mediawiki.git] / tests / phpunit / includes / CommentStoreTest.php
1 <?php
2
3 use Wikimedia\ScopedCallback;
4 use Wikimedia\TestingAccessWrapper;
5
6 /**
7  * @group Database
8  * @covers CommentStore
9  * @covers CommentStoreComment
10  */
11 class CommentStoreTest extends MediaWikiLangTestCase {
12
13         protected $tablesUsed = [
14                 'revision',
15                 'revision_comment_temp',
16                 'ipblocks',
17                 'comment',
18         ];
19
20         /**
21          * Create a store for a particular stage
22          * @param int $stage
23          * @param string $key
24          * @return CommentStore
25          */
26         protected function makeStore( $stage, $key ) {
27                 $store = new CommentStore( $key );
28                 TestingAccessWrapper::newFromObject( $store )->stage = $stage;
29                 return $store;
30         }
31
32         /**
33          * @dataProvider provideGetFields
34          * @param int $stage
35          * @param string $key
36          * @param array $expect
37          */
38         public function testGetFields( $stage, $key, $expect ) {
39                 $store = $this->makeStore( $stage, $key );
40                 $result = $store->getFields();
41                 $this->assertEquals( $expect, $result );
42         }
43
44         public static function provideGetFields() {
45                 return [
46                         'Simple table, old' => [
47                                 MIGRATION_OLD, 'ipb_reason',
48                                 [ 'ipb_reason_text' => 'ipb_reason', 'ipb_reason_data' => 'NULL', 'ipb_reason_cid' => 'NULL' ],
49                         ],
50                         'Simple table, write-both' => [
51                                 MIGRATION_WRITE_BOTH, 'ipb_reason',
52                                 [ 'ipb_reason_old' => 'ipb_reason', 'ipb_reason_id' => 'ipb_reason_id' ],
53                         ],
54                         'Simple table, write-new' => [
55                                 MIGRATION_WRITE_NEW, 'ipb_reason',
56                                 [ 'ipb_reason_old' => 'ipb_reason', 'ipb_reason_id' => 'ipb_reason_id' ],
57                         ],
58                         'Simple table, new' => [
59                                 MIGRATION_NEW, 'ipb_reason',
60                                 [ 'ipb_reason_id' => 'ipb_reason_id' ],
61                         ],
62
63                         'Revision, old' => [
64                                 MIGRATION_OLD, 'rev_comment',
65                                 [
66                                         'rev_comment_text' => 'rev_comment',
67                                         'rev_comment_data' => 'NULL',
68                                         'rev_comment_cid' => 'NULL',
69                                 ],
70                         ],
71                         'Revision, write-both' => [
72                                 MIGRATION_WRITE_BOTH, 'rev_comment',
73                                 [ 'rev_comment_old' => 'rev_comment', 'rev_comment_pk' => 'rev_id' ],
74                         ],
75                         'Revision, write-new' => [
76                                 MIGRATION_WRITE_NEW, 'rev_comment',
77                                 [ 'rev_comment_old' => 'rev_comment', 'rev_comment_pk' => 'rev_id' ],
78                         ],
79                         'Revision, new' => [
80                                 MIGRATION_NEW, 'rev_comment',
81                                 [ 'rev_comment_pk' => 'rev_id' ],
82                         ],
83
84                         'Image, old' => [
85                                 MIGRATION_OLD, 'img_description',
86                                 [
87                                         'img_description_text' => 'img_description',
88                                         'img_description_data' => 'NULL',
89                                         'img_description_cid' => 'NULL',
90                                 ],
91                         ],
92                         'Image, write-both' => [
93                                 MIGRATION_WRITE_BOTH, 'img_description',
94                                 [ 'img_description_old' => 'img_description', 'img_description_pk' => 'img_name' ],
95                         ],
96                         'Image, write-new' => [
97                                 MIGRATION_WRITE_NEW, 'img_description',
98                                 [ 'img_description_old' => 'img_description', 'img_description_pk' => 'img_name' ],
99                         ],
100                         'Image, new' => [
101                                 MIGRATION_NEW, 'img_description',
102                                 [ 'img_description_pk' => 'img_name' ],
103                         ],
104                 ];
105         }
106
107         /**
108          * @dataProvider provideGetJoin
109          * @param int $stage
110          * @param string $key
111          * @param array $expect
112          */
113         public function testGetJoin( $stage, $key, $expect ) {
114                 $store = $this->makeStore( $stage, $key );
115                 $result = $store->getJoin();
116                 $this->assertEquals( $expect, $result );
117         }
118
119         public static function provideGetJoin() {
120                 return [
121                         'Simple table, old' => [
122                                 MIGRATION_OLD, 'ipb_reason', [
123                                         'tables' => [],
124                                         'fields' => [
125                                                 'ipb_reason_text' => 'ipb_reason',
126                                                 'ipb_reason_data' => 'NULL',
127                                                 'ipb_reason_cid' => 'NULL',
128                                         ],
129                                         'joins' => [],
130                                 ],
131                         ],
132                         'Simple table, write-both' => [
133                                 MIGRATION_WRITE_BOTH, 'ipb_reason', [
134                                         'tables' => [ 'comment_ipb_reason' => 'comment' ],
135                                         'fields' => [
136                                                 'ipb_reason_text' => 'COALESCE( comment_ipb_reason.comment_text, ipb_reason )',
137                                                 'ipb_reason_data' => 'comment_ipb_reason.comment_data',
138                                                 'ipb_reason_cid' => 'comment_ipb_reason.comment_id',
139                                         ],
140                                         'joins' => [
141                                                 'comment_ipb_reason' => [ 'LEFT JOIN', 'comment_ipb_reason.comment_id = ipb_reason_id' ],
142                                         ],
143                                 ],
144                         ],
145                         'Simple table, write-new' => [
146                                 MIGRATION_WRITE_NEW, 'ipb_reason', [
147                                         'tables' => [ 'comment_ipb_reason' => 'comment' ],
148                                         'fields' => [
149                                                 'ipb_reason_text' => 'COALESCE( comment_ipb_reason.comment_text, ipb_reason )',
150                                                 'ipb_reason_data' => 'comment_ipb_reason.comment_data',
151                                                 'ipb_reason_cid' => 'comment_ipb_reason.comment_id',
152                                         ],
153                                         'joins' => [
154                                                 'comment_ipb_reason' => [ 'LEFT JOIN', 'comment_ipb_reason.comment_id = ipb_reason_id' ],
155                                         ],
156                                 ],
157                         ],
158                         'Simple table, new' => [
159                                 MIGRATION_NEW, 'ipb_reason', [
160                                         'tables' => [ 'comment_ipb_reason' => 'comment' ],
161                                         'fields' => [
162                                                 'ipb_reason_text' => 'comment_ipb_reason.comment_text',
163                                                 'ipb_reason_data' => 'comment_ipb_reason.comment_data',
164                                                 'ipb_reason_cid' => 'comment_ipb_reason.comment_id',
165                                         ],
166                                         'joins' => [
167                                                 'comment_ipb_reason' => [ 'JOIN', 'comment_ipb_reason.comment_id = ipb_reason_id' ],
168                                         ],
169                                 ],
170                         ],
171
172                         'Revision, old' => [
173                                 MIGRATION_OLD, 'rev_comment', [
174                                         'tables' => [],
175                                         'fields' => [
176                                                 'rev_comment_text' => 'rev_comment',
177                                                 'rev_comment_data' => 'NULL',
178                                                 'rev_comment_cid' => 'NULL',
179                                         ],
180                                         'joins' => [],
181                                 ],
182                         ],
183                         'Revision, write-both' => [
184                                 MIGRATION_WRITE_BOTH, 'rev_comment', [
185                                         'tables' => [
186                                                 'temp_rev_comment' => 'revision_comment_temp',
187                                                 'comment_rev_comment' => 'comment',
188                                         ],
189                                         'fields' => [
190                                                 'rev_comment_text' => 'COALESCE( comment_rev_comment.comment_text, rev_comment )',
191                                                 'rev_comment_data' => 'comment_rev_comment.comment_data',
192                                                 'rev_comment_cid' => 'comment_rev_comment.comment_id',
193                                         ],
194                                         'joins' => [
195                                                 'temp_rev_comment' => [ 'LEFT JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ],
196                                                 'comment_rev_comment' => [ 'LEFT JOIN',
197                                                         'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
198                                         ],
199                                 ],
200                         ],
201                         'Revision, write-new' => [
202                                 MIGRATION_WRITE_NEW, 'rev_comment', [
203                                         'tables' => [
204                                                 'temp_rev_comment' => 'revision_comment_temp',
205                                                 'comment_rev_comment' => 'comment',
206                                         ],
207                                         'fields' => [
208                                                 'rev_comment_text' => 'COALESCE( comment_rev_comment.comment_text, rev_comment )',
209                                                 'rev_comment_data' => 'comment_rev_comment.comment_data',
210                                                 'rev_comment_cid' => 'comment_rev_comment.comment_id',
211                                         ],
212                                         'joins' => [
213                                                 'temp_rev_comment' => [ 'LEFT JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ],
214                                                 'comment_rev_comment' => [ 'LEFT JOIN',
215                                                         'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
216                                         ],
217                                 ],
218                         ],
219                         'Revision, new' => [
220                                 MIGRATION_NEW, 'rev_comment', [
221                                         'tables' => [
222                                                 'temp_rev_comment' => 'revision_comment_temp',
223                                                 'comment_rev_comment' => 'comment',
224                                         ],
225                                         'fields' => [
226                                                 'rev_comment_text' => 'comment_rev_comment.comment_text',
227                                                 'rev_comment_data' => 'comment_rev_comment.comment_data',
228                                                 'rev_comment_cid' => 'comment_rev_comment.comment_id',
229                                         ],
230                                         'joins' => [
231                                                 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ],
232                                                 'comment_rev_comment' => [ 'JOIN',
233                                                         'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
234                                         ],
235                                 ],
236                         ],
237
238                         'Image, old' => [
239                                 MIGRATION_OLD, 'img_description', [
240                                         'tables' => [],
241                                         'fields' => [
242                                                 'img_description_text' => 'img_description',
243                                                 'img_description_data' => 'NULL',
244                                                 'img_description_cid' => 'NULL',
245                                         ],
246                                         'joins' => [],
247                                 ],
248                         ],
249                         'Image, write-both' => [
250                                 MIGRATION_WRITE_BOTH, 'img_description', [
251                                         'tables' => [
252                                                 'temp_img_description' => 'image_comment_temp',
253                                                 'comment_img_description' => 'comment',
254                                         ],
255                                         'fields' => [
256                                                 'img_description_text' => 'COALESCE( comment_img_description.comment_text, img_description )',
257                                                 'img_description_data' => 'comment_img_description.comment_data',
258                                                 'img_description_cid' => 'comment_img_description.comment_id',
259                                         ],
260                                         'joins' => [
261                                                 'temp_img_description' => [ 'LEFT JOIN', 'temp_img_description.imgcomment_name = img_name' ],
262                                                 'comment_img_description' => [ 'LEFT JOIN',
263                                                         'comment_img_description.comment_id = temp_img_description.imgcomment_description_id' ],
264                                         ],
265                                 ],
266                         ],
267                         'Image, write-new' => [
268                                 MIGRATION_WRITE_NEW, 'img_description', [
269                                         'tables' => [
270                                                 'temp_img_description' => 'image_comment_temp',
271                                                 'comment_img_description' => 'comment',
272                                         ],
273                                         'fields' => [
274                                                 'img_description_text' => 'COALESCE( comment_img_description.comment_text, img_description )',
275                                                 'img_description_data' => 'comment_img_description.comment_data',
276                                                 'img_description_cid' => 'comment_img_description.comment_id',
277                                         ],
278                                         'joins' => [
279                                                 'temp_img_description' => [ 'LEFT JOIN', 'temp_img_description.imgcomment_name = img_name' ],
280                                                 'comment_img_description' => [ 'LEFT JOIN',
281                                                         'comment_img_description.comment_id = temp_img_description.imgcomment_description_id' ],
282                                         ],
283                                 ],
284                         ],
285                         'Image, new' => [
286                                 MIGRATION_NEW, 'img_description', [
287                                         'tables' => [
288                                                 'temp_img_description' => 'image_comment_temp',
289                                                 'comment_img_description' => 'comment',
290                                         ],
291                                         'fields' => [
292                                                 'img_description_text' => 'comment_img_description.comment_text',
293                                                 'img_description_data' => 'comment_img_description.comment_data',
294                                                 'img_description_cid' => 'comment_img_description.comment_id',
295                                         ],
296                                         'joins' => [
297                                                 'temp_img_description' => [ 'JOIN', 'temp_img_description.imgcomment_name = img_name' ],
298                                                 'comment_img_description' => [ 'JOIN',
299                                                         'comment_img_description.comment_id = temp_img_description.imgcomment_description_id' ],
300                                         ],
301                                 ],
302                         ],
303                 ];
304         }
305
306         private function assertComment( $expect, $actual, $from ) {
307                 $this->assertSame( $expect['text'], $actual->text, "text $from" );
308                 $this->assertInstanceOf( get_class( $expect['message'] ), $actual->message,
309                         "message class $from" );
310                 $this->assertSame( $expect['message']->getKeysToTry(), $actual->message->getKeysToTry(),
311                         "message keys $from" );
312                 $this->assertEquals( $expect['message']->text(), $actual->message->text(),
313                         "message rendering $from" );
314                 $this->assertEquals( $expect['data'], $actual->data, "data $from" );
315         }
316
317         /**
318          * @dataProvider provideInsertRoundTrip
319          * @param string $table
320          * @param string $key
321          * @param string $pk
322          * @param string $extraFields
323          * @param string|Message $comment
324          * @param array|null $data
325          * @param array $expect
326          */
327         public function testInsertRoundTrip( $table, $key, $pk, $extraFields, $comment, $data, $expect ) {
328                 $expectOld = [
329                         'text' => $expect['text'],
330                         'message' => new RawMessage( '$1', [ $expect['text'] ] ),
331                         'data' => null,
332                 ];
333
334                 $stages = [
335                         MIGRATION_OLD => [ MIGRATION_OLD, MIGRATION_WRITE_NEW ],
336                         MIGRATION_WRITE_BOTH => [ MIGRATION_OLD, MIGRATION_NEW ],
337                         MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
338                         MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_NEW ],
339                 ];
340
341                 foreach ( $stages as $writeStage => $readRange ) {
342                         if ( $key === 'ipb_reason' ) {
343                                 $extraFields['ipb_address'] = __CLASS__ . "#$writeStage";
344                         }
345
346                         $wstore = $this->makeStore( $writeStage, $key );
347                         $usesTemp = $key === 'rev_comment';
348
349                         if ( $usesTemp ) {
350                                 list( $fields, $callback ) = $wstore->insertWithTempTable( $this->db, $comment, $data );
351                         } else {
352                                 $fields = $wstore->insert( $this->db, $comment, $data );
353                         }
354
355                         if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
356                                 $this->assertSame( $expect['text'], $fields[$key], "old field, stage=$writeStage" );
357                         } else {
358                                 $this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
359                         }
360                         if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
361                                 $this->assertArrayHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
362                         } else {
363                                 $this->assertArrayNotHasKey( "{$key}_id", $fields, "new field, stage=$writeStage" );
364                         }
365
366                         $this->db->insert( $table, $extraFields + $fields, __METHOD__ );
367                         $id = $this->db->insertId();
368                         if ( $usesTemp ) {
369                                 $callback( $id );
370                         }
371
372                         for ( $readStage = $readRange[0]; $readStage <= $readRange[1]; $readStage++ ) {
373                                 $rstore = $this->makeStore( $readStage, $key );
374
375                                 $fieldRow = $this->db->selectRow(
376                                         $table,
377                                         $rstore->getFields(),
378                                         [ $pk => $id ],
379                                         __METHOD__
380                                 );
381
382                                 $queryInfo = $rstore->getJoin();
383                                 $joinRow = $this->db->selectRow(
384                                         [ $table ] + $queryInfo['tables'],
385                                         $queryInfo['fields'],
386                                         [ $pk => $id ],
387                                         __METHOD__,
388                                         [],
389                                         $queryInfo['joins']
390                                 );
391
392                                 $this->assertComment(
393                                         $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
394                                         $rstore->getCommentLegacy( $this->db, $fieldRow ),
395                                         "w=$writeStage, r=$readStage, from getFields()"
396                                 );
397                                 $this->assertComment(
398                                         $writeStage === MIGRATION_OLD || $readStage === MIGRATION_OLD ? $expectOld : $expect,
399                                         $rstore->getComment( $joinRow ),
400                                         "w=$writeStage, r=$readStage, from getJoin()"
401                                 );
402                         }
403                 }
404         }
405
406         public static function provideInsertRoundTrip() {
407                 $db = wfGetDB( DB_REPLICA ); // for timestamps
408
409                 $msgComment = new Message( 'parentheses', [ 'message comment' ] );
410                 $textCommentMsg = new RawMessage( '$1', [ 'text comment' ] );
411                 $nestedMsgComment = new Message( [ 'parentheses', 'rawmessage' ], [ new Message( 'mainpage' ) ] );
412                 $ipbfields = [
413                         'ipb_range_start' => '',
414                         'ipb_range_end' => '',
415                         'ipb_by' => 0,
416                         'ipb_timestamp' => $db->timestamp(),
417                         'ipb_expiry' => $db->getInfinity(),
418                 ];
419                 $revfields = [
420                         'rev_page' => 42,
421                         'rev_text_id' => 42,
422                         'rev_len' => 0,
423                         'rev_user' => 0,
424                         'rev_user_text' => '',
425                         'rev_timestamp' => $db->timestamp(),
426                 ];
427                 $comStoreComment = new CommentStoreComment(
428                         null, 'comment store comment', null, [ 'foo' => 'bar' ]
429                 );
430
431                 return [
432                         'Simple table, text comment' => [
433                                 'ipblocks', 'ipb_reason', 'ipb_id', $ipbfields, 'text comment', null, [
434                                         'text' => 'text comment',
435                                         'message' => $textCommentMsg,
436                                         'data' => null,
437                                 ]
438                         ],
439                         'Simple table, text comment with data' => [
440                                 'ipblocks', 'ipb_reason', 'ipb_id', $ipbfields, 'text comment', [ 'message' => 42 ], [
441                                         'text' => 'text comment',
442                                         'message' => $textCommentMsg,
443                                         'data' => [ 'message' => 42 ],
444                                 ]
445                         ],
446                         'Simple table, message comment' => [
447                                 'ipblocks', 'ipb_reason', 'ipb_id', $ipbfields, $msgComment, null, [
448                                         'text' => '(message comment)',
449                                         'message' => $msgComment,
450                                         'data' => null,
451                                 ]
452                         ],
453                         'Simple table, message comment with data' => [
454                                 'ipblocks', 'ipb_reason', 'ipb_id', $ipbfields, $msgComment, [ 'message' => 42 ], [
455                                         'text' => '(message comment)',
456                                         'message' => $msgComment,
457                                         'data' => [ 'message' => 42 ],
458                                 ]
459                         ],
460                         'Simple table, nested message comment' => [
461                                 'ipblocks', 'ipb_reason', 'ipb_id', $ipbfields, $nestedMsgComment, null, [
462                                         'text' => '(Main Page)',
463                                         'message' => $nestedMsgComment,
464                                         'data' => null,
465                                 ]
466                         ],
467                         'Simple table, CommentStoreComment' => [
468                                 'ipblocks', 'ipb_reason', 'ipb_id', $ipbfields, clone $comStoreComment, [ 'baz' => 'baz' ], [
469                                         'text' => 'comment store comment',
470                                         'message' => $comStoreComment->message,
471                                         'data' => [ 'foo' => 'bar' ],
472                                 ]
473                         ],
474
475                         'Revision, text comment' => [
476                                 'revision', 'rev_comment', 'rev_id', $revfields, 'text comment', null, [
477                                         'text' => 'text comment',
478                                         'message' => $textCommentMsg,
479                                         'data' => null,
480                                 ]
481                         ],
482                         'Revision, text comment with data' => [
483                                 'revision', 'rev_comment', 'rev_id', $revfields, 'text comment', [ 'message' => 42 ], [
484                                         'text' => 'text comment',
485                                         'message' => $textCommentMsg,
486                                         'data' => [ 'message' => 42 ],
487                                 ]
488                         ],
489                         'Revision, message comment' => [
490                                 'revision', 'rev_comment', 'rev_id', $revfields, $msgComment, null, [
491                                         'text' => '(message comment)',
492                                         'message' => $msgComment,
493                                         'data' => null,
494                                 ]
495                         ],
496                         'Revision, message comment with data' => [
497                                 'revision', 'rev_comment', 'rev_id', $revfields, $msgComment, [ 'message' => 42 ], [
498                                         'text' => '(message comment)',
499                                         'message' => $msgComment,
500                                         'data' => [ 'message' => 42 ],
501                                 ]
502                         ],
503                         'Revision, nested message comment' => [
504                                 'revision', 'rev_comment', 'rev_id', $revfields, $nestedMsgComment, null, [
505                                         'text' => '(Main Page)',
506                                         'message' => $nestedMsgComment,
507                                         'data' => null,
508                                 ]
509                         ],
510                         'Revision, CommentStoreComment' => [
511                                 'revision', 'rev_comment', 'rev_id', $revfields, clone $comStoreComment, [ 'baz' => 'baz' ], [
512                                         'text' => 'comment store comment',
513                                         'message' => $comStoreComment->message,
514                                         'data' => [ 'foo' => 'bar' ],
515                                 ]
516                         ],
517                 ];
518         }
519
520         public function testGetCommentErrors() {
521                 MediaWiki\suppressWarnings();
522                 $reset = new ScopedCallback( 'MediaWiki\restoreWarnings' );
523
524                 $store = $this->makeStore( MIGRATION_OLD, 'dummy' );
525                 $res = $store->getComment( [ 'dummy' => 'comment' ] );
526                 $this->assertSame( '', $res->text );
527                 $res = $store->getComment( [ 'dummy' => 'comment' ], true );
528                 $this->assertSame( 'comment', $res->text );
529
530                 $store = $this->makeStore( MIGRATION_NEW, 'dummy' );
531                 try {
532                         $store->getComment( [ 'dummy' => 'comment' ] );
533                         $this->fail( 'Expected exception not thrown' );
534                 } catch ( InvalidArgumentException $ex ) {
535                         $this->assertSame( '$row does not contain fields needed for comment dummy', $ex->getMessage() );
536                 }
537                 $res = $store->getComment( [ 'dummy' => 'comment' ], true );
538                 $this->assertSame( 'comment', $res->text );
539                 try {
540                         $store->getComment( [ 'dummy_id' => 1 ] );
541                         $this->fail( 'Expected exception not thrown' );
542                 } catch ( InvalidArgumentException $ex ) {
543                         $this->assertSame(
544                                 '$row does not contain fields needed for comment dummy and getComment(), '
545                                 . 'but does have fields for getCommentLegacy()',
546                                 $ex->getMessage()
547                         );
548                 }
549
550                 $store = $this->makeStore( MIGRATION_NEW, 'rev_comment' );
551                 try {
552                         $store->getComment( [ 'rev_comment' => 'comment' ] );
553                         $this->fail( 'Expected exception not thrown' );
554                 } catch ( InvalidArgumentException $ex ) {
555                         $this->assertSame(
556                                 '$row does not contain fields needed for comment rev_comment', $ex->getMessage()
557                         );
558                 }
559                 $res = $store->getComment( [ 'rev_comment' => 'comment' ], true );
560                 $this->assertSame( 'comment', $res->text );
561                 try {
562                         $store->getComment( [ 'rev_comment_pk' => 1 ] );
563                         $this->fail( 'Expected exception not thrown' );
564                 } catch ( InvalidArgumentException $ex ) {
565                         $this->assertSame(
566                                 '$row does not contain fields needed for comment rev_comment and getComment(), '
567                                 . 'but does have fields for getCommentLegacy()',
568                                 $ex->getMessage()
569                         );
570                 }
571         }
572
573         public static function provideStages() {
574                 return [
575                         'MIGRATION_OLD' => [ MIGRATION_OLD ],
576                         'MIGRATION_WRITE_BOTH' => [ MIGRATION_WRITE_BOTH ],
577                         'MIGRATION_WRITE_NEW' => [ MIGRATION_WRITE_NEW ],
578                         'MIGRATION_NEW' => [ MIGRATION_NEW ],
579                 ];
580         }
581
582         /**
583          * @dataProvider provideStages
584          * @param int $stage
585          * @expectedException InvalidArgumentException
586          * @expectedExceptionMessage Must use insertWithTempTable() for rev_comment
587          */
588         public function testInsertWrong( $stage ) {
589                 $store = $this->makeStore( $stage, 'rev_comment' );
590                 $store->insert( $this->db, 'foo' );
591         }
592
593         /**
594          * @dataProvider provideStages
595          * @param int $stage
596          * @expectedException InvalidArgumentException
597          * @expectedExceptionMessage Must use insert() for ipb_reason
598          */
599         public function testInsertWithTempTableWrong( $stage ) {
600                 $store = $this->makeStore( $stage, 'ipb_reason' );
601                 $store->insertWithTempTable( $this->db, 'foo' );
602         }
603
604         /**
605          * @dataProvider provideStages
606          * @param int $stage
607          */
608         public function testInsertWithTempTableDeprecated( $stage ) {
609                 $wrap = TestingAccessWrapper::newFromClass( CommentStore::class );
610                 $wrap->formerTempTables += [ 'ipb_reason' => '1.30' ];
611
612                 $this->hideDeprecated( 'CommentStore::insertWithTempTable for ipb_reason' );
613                 $store = $this->makeStore( $stage, 'ipb_reason' );
614                 list( $fields, $callback ) = $store->insertWithTempTable( $this->db, 'foo' );
615                 $this->assertTrue( is_callable( $callback ) );
616         }
617
618         public function testInsertTruncation() {
619                 $comment = str_repeat( '💣', 16400 );
620                 $truncated1 = str_repeat( '💣', 63 ) . '...';
621                 $truncated2 = str_repeat( '💣', CommentStore::COMMENT_CHARACTER_LIMIT - 3 ) . '...';
622
623                 $store = $this->makeStore( MIGRATION_WRITE_BOTH, 'ipb_reason' );
624                 $fields = $store->insert( $this->db, $comment );
625                 $this->assertSame( $truncated1, $fields['ipb_reason'] );
626                 $stored = $this->db->selectField(
627                         'comment', 'comment_text', [ 'comment_id' => $fields['ipb_reason_id'] ], __METHOD__
628                 );
629                 $this->assertSame( $truncated2, $stored );
630         }
631
632         /**
633          * @expectedException OverflowException
634          * @expectedExceptionMessage Comment data is too long (65611 bytes, maximum is 65535)
635          */
636         public function testInsertTooMuchData() {
637                 $store = $this->makeStore( MIGRATION_WRITE_BOTH, 'ipb_reason' );
638                 $store->insert( $this->db, 'foo', [
639                         'long' => str_repeat( '💣', 16400 )
640                 ] );
641         }
642
643         public function testConstructor() {
644                 $this->assertInstanceOf( CommentStore::class, CommentStore::newKey( 'dummy' ) );
645         }
646
647 }