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