5 use Wikimedia\ScopedCallback;
6 use Wikimedia\TestingAccessWrapper;
17 'revision_comment_temp',
25 __DIR__ .
'/CommentStoreTest.sql',
28 'create' => [
'commentstore1',
'commentstore2',
'commentstore2_temp' ],
39 $store =
new CommentStore( MediaWikiServices::getInstance()->getContentLanguage(), $stage );
41 TestingAccessWrapper::newFromObject( $store )->tempTables += [
'cs2_comment' => [
42 'table' =>
'commentstore2_temp',
44 'field' =>
'cs2t_comment_id',
47 'deprecatedIn' =>
null,
62 TestingAccessWrapper::newFromObject( $store )->stage = $stage;
64 TestingAccessWrapper::newFromObject( $store )->tempTables += [
'cs2_comment' => [
65 'table' =>
'commentstore2_temp',
67 'field' =>
'cs2t_comment_id',
70 'deprecatedIn' =>
null,
85 $this->assertEquals( $expect,
$result );
96 $result = $store->getFields( $key );
97 $this->assertEquals( $expect,
$result );
102 'Simple table, old' => [
104 [
'ipb_reason_text' =>
'ipb_reason',
'ipb_reason_data' =>
'NULL',
'ipb_reason_cid' =>
'NULL' ],
106 'Simple table, write-both' => [
108 [
'ipb_reason_old' =>
'ipb_reason',
'ipb_reason_id' =>
'ipb_reason_id' ],
110 'Simple table, write-new' => [
112 [
'ipb_reason_old' =>
'ipb_reason',
'ipb_reason_id' =>
'ipb_reason_id' ],
114 'Simple table, new' => [
116 [
'ipb_reason_id' =>
'ipb_reason_id' ],
122 'rev_comment_text' =>
'rev_comment',
123 'rev_comment_data' =>
'NULL',
124 'rev_comment_cid' =>
'NULL',
127 'Revision, write-both' => [
129 [
'rev_comment_old' =>
'rev_comment',
'rev_comment_pk' =>
'rev_id' ],
131 'Revision, write-new' => [
133 [
'rev_comment_old' =>
'rev_comment',
'rev_comment_pk' =>
'rev_id' ],
137 [
'rev_comment_pk' =>
'rev_id' ],
143 'img_description_text' =>
'img_description',
144 'img_description_data' =>
'NULL',
145 'img_description_cid' =>
'NULL',
148 'Image, write-both' => [
151 'img_description_old' =>
'img_description',
152 'img_description_id' =>
'img_description_id'
155 'Image, write-new' => [
158 'img_description_old' =>
'img_description',
159 'img_description_id' =>
'img_description_id'
165 'img_description_id' =>
'img_description_id'
180 $this->assertEquals( $expect,
$result );
191 $result = $store->getJoin( $key );
192 $this->assertEquals( $expect,
$result );
197 'Simple table, old' => [
201 'ipb_reason_text' =>
'ipb_reason',
202 'ipb_reason_data' =>
'NULL',
203 'ipb_reason_cid' =>
'NULL',
208 'Simple table, write-both' => [
210 'tables' => [
'comment_ipb_reason' =>
'comment' ],
212 'ipb_reason_text' =>
'COALESCE( comment_ipb_reason.comment_text, ipb_reason )',
213 'ipb_reason_data' =>
'comment_ipb_reason.comment_data',
214 'ipb_reason_cid' =>
'comment_ipb_reason.comment_id',
217 'comment_ipb_reason' => [
'LEFT JOIN',
'comment_ipb_reason.comment_id = ipb_reason_id' ],
221 'Simple table, write-new' => [
223 'tables' => [
'comment_ipb_reason' =>
'comment' ],
225 'ipb_reason_text' =>
'COALESCE( comment_ipb_reason.comment_text, ipb_reason )',
226 'ipb_reason_data' =>
'comment_ipb_reason.comment_data',
227 'ipb_reason_cid' =>
'comment_ipb_reason.comment_id',
230 'comment_ipb_reason' => [
'LEFT JOIN',
'comment_ipb_reason.comment_id = ipb_reason_id' ],
234 'Simple table, new' => [
236 'tables' => [
'comment_ipb_reason' =>
'comment' ],
238 'ipb_reason_text' =>
'comment_ipb_reason.comment_text',
239 'ipb_reason_data' =>
'comment_ipb_reason.comment_data',
240 'ipb_reason_cid' =>
'comment_ipb_reason.comment_id',
243 'comment_ipb_reason' => [
'JOIN',
'comment_ipb_reason.comment_id = ipb_reason_id' ],
252 'rev_comment_text' =>
'rev_comment',
253 'rev_comment_data' =>
'NULL',
254 'rev_comment_cid' =>
'NULL',
259 'Revision, write-both' => [
262 'temp_rev_comment' =>
'revision_comment_temp',
263 'comment_rev_comment' =>
'comment',
266 'rev_comment_text' =>
'COALESCE( comment_rev_comment.comment_text, rev_comment )',
267 'rev_comment_data' =>
'comment_rev_comment.comment_data',
268 'rev_comment_cid' =>
'comment_rev_comment.comment_id',
271 'temp_rev_comment' => [
'LEFT JOIN',
'temp_rev_comment.revcomment_rev = rev_id' ],
272 'comment_rev_comment' => [
'LEFT JOIN',
273 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
277 'Revision, write-new' => [
280 'temp_rev_comment' =>
'revision_comment_temp',
281 'comment_rev_comment' =>
'comment',
284 'rev_comment_text' =>
'COALESCE( comment_rev_comment.comment_text, rev_comment )',
285 'rev_comment_data' =>
'comment_rev_comment.comment_data',
286 'rev_comment_cid' =>
'comment_rev_comment.comment_id',
289 'temp_rev_comment' => [
'LEFT JOIN',
'temp_rev_comment.revcomment_rev = rev_id' ],
290 'comment_rev_comment' => [
'LEFT JOIN',
291 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
298 'temp_rev_comment' =>
'revision_comment_temp',
299 'comment_rev_comment' =>
'comment',
302 'rev_comment_text' =>
'comment_rev_comment.comment_text',
303 'rev_comment_data' =>
'comment_rev_comment.comment_data',
304 'rev_comment_cid' =>
'comment_rev_comment.comment_id',
307 'temp_rev_comment' => [
'JOIN',
'temp_rev_comment.revcomment_rev = rev_id' ],
308 'comment_rev_comment' => [
'JOIN',
309 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id' ],
318 'img_description_text' =>
'img_description',
319 'img_description_data' =>
'NULL',
320 'img_description_cid' =>
'NULL',
325 'Image, write-both' => [
328 'comment_img_description' =>
'comment',
331 'img_description_text' =>
'COALESCE( comment_img_description.comment_text, img_description )',
332 'img_description_data' =>
'comment_img_description.comment_data',
333 'img_description_cid' =>
'comment_img_description.comment_id',
336 'comment_img_description' => [
'LEFT JOIN',
337 'comment_img_description.comment_id = img_description_id',
342 'Image, write-new' => [
345 'comment_img_description' =>
'comment',
348 'img_description_text' =>
'COALESCE( comment_img_description.comment_text, img_description )',
349 'img_description_data' =>
'comment_img_description.comment_data',
350 'img_description_cid' =>
'comment_img_description.comment_id',
353 'comment_img_description' => [
'LEFT JOIN',
354 'comment_img_description.comment_id = img_description_id',
362 'comment_img_description' =>
'comment',
365 'img_description_text' =>
'comment_img_description.comment_text',
366 'img_description_data' =>
'comment_img_description.comment_data',
367 'img_description_cid' =>
'comment_img_description.comment_id',
370 'comment_img_description' => [
'JOIN',
371 'comment_img_description.comment_id = img_description_id',
380 $this->assertSame( $expect[
'text'], $actual->text,
"text $from" );
381 $this->assertInstanceOf( get_class( $expect[
'message'] ), $actual->message,
382 "message class $from" );
383 $this->assertSame( $expect[
'message']->getKeysToTry(), $actual->message->getKeysToTry(),
384 "message keys $from" );
385 $this->assertEquals( $expect[
'message']->
text(), $actual->message->text(),
386 "message rendering $from" );
387 $this->assertEquals( $expect[
'text'], $actual->message->text(),
388 "message rendering and text $from" );
389 $this->assertEquals( $expect[
'data'], $actual->data,
"data $from" );
405 'text' => $expect[
'text'],
406 'message' =>
new RawMessage(
'$1', [ Message::plaintextParam( $expect[
'text'] ) ] ),
418 foreach ( $stages
as $writeStage => $possibleReadStages ) {
419 $wstore = $this->
makeStore( $writeStage );
420 $usesTemp = $key ===
'cs2_comment';
423 list( $fields, $callback ) = $wstore->insertWithTempTable(
424 $this->db, $key, $comment,
$data
427 $fields = $wstore->insert( $this->db, $key, $comment,
$data );
431 $this->assertSame( $expect[
'text'], $fields[$key],
"old field, stage=$writeStage" );
433 $this->assertArrayNotHasKey( $key, $fields,
"old field, stage=$writeStage" );
436 $this->assertArrayHasKey(
"{$key}_id", $fields,
"new field, stage=$writeStage" );
438 $this->assertArrayNotHasKey(
"{$key}_id", $fields,
"new field, stage=$writeStage" );
441 $this->db->insert( $table, [ $pk => ++$id ] + $fields, __METHOD__ );
446 foreach ( $possibleReadStages
as $readStage ) {
447 $rstore = $this->
makeStore( $readStage );
449 $fieldRow = $this->db->selectRow(
451 $rstore->getFields( $key ),
456 $queryInfo = $rstore->getJoin( $key );
457 $joinRow = $this->db->selectRow(
458 [ $table ] + $queryInfo[
'tables'],
459 $queryInfo[
'fields'],
468 $rstore->getCommentLegacy( $this->db, $key, $fieldRow ),
469 "w=$writeStage, r=$readStage, from getFields()"
473 $rstore->getComment( $key, $joinRow ),
474 "w=$writeStage, r=$readStage, from getJoin()"
490 $table, $key, $pk, $comment,
$data, $expect
495 'text' => $expect[
'text'],
496 'message' =>
new RawMessage(
'$1', [ Message::plaintextParam( $expect[
'text'] ) ] ),
508 foreach ( $stages
as $writeStage => $possibleReadStages ) {
510 $usesTemp = $key ===
'cs2_comment';
513 list( $fields, $callback ) = $wstore->insertWithTempTable(
514 $this->db, $comment,
$data
517 $fields = $wstore->insert( $this->db, $comment,
$data );
521 $this->assertSame( $expect[
'text'], $fields[$key],
"old field, stage=$writeStage" );
523 $this->assertArrayNotHasKey( $key, $fields,
"old field, stage=$writeStage" );
526 $this->assertArrayHasKey(
"{$key}_id", $fields,
"new field, stage=$writeStage" );
528 $this->assertArrayNotHasKey(
"{$key}_id", $fields,
"new field, stage=$writeStage" );
531 $this->db->insert( $table, [ $pk => ++$id ] + $fields, __METHOD__ );
536 foreach ( $possibleReadStages
as $readStage ) {
539 $fieldRow = $this->db->selectRow(
541 $rstore->getFields(),
546 $queryInfo = $rstore->getJoin();
547 $joinRow = $this->db->selectRow(
548 [ $table ] + $queryInfo[
'tables'],
549 $queryInfo[
'fields'],
558 $rstore->getCommentLegacy( $this->db, $fieldRow ),
559 "w=$writeStage, r=$readStage, from getFields()"
563 $rstore->getComment( $joinRow ),
564 "w=$writeStage, r=$readStage, from getJoin()"
573 $msgComment =
new Message(
'parentheses', [
'message comment' ] );
574 $textCommentMsg =
new RawMessage(
'$1', [ Message::plaintextParam(
'{{text}} comment' ) ] );
575 $nestedMsgComment =
new Message( [
'parentheses',
'rawmessage' ], [
new Message(
'mainpage' ) ] );
577 null,
'comment store comment',
null, [
'foo' =>
'bar' ]
581 'Simple table, text comment' => [
582 'commentstore1',
'cs1_comment',
'cs1_id',
'{{text}} comment',
null, [
583 'text' =>
'{{text}} comment',
584 'message' => $textCommentMsg,
588 'Simple table, text comment with data' => [
589 'commentstore1',
'cs1_comment',
'cs1_id',
'{{text}} comment', [
'message' => 42 ], [
590 'text' =>
'{{text}} comment',
591 'message' => $textCommentMsg,
592 'data' => [
'message' => 42 ],
595 'Simple table, message comment' => [
596 'commentstore1',
'cs1_comment',
'cs1_id', $msgComment,
null, [
597 'text' =>
'(message comment)',
598 'message' => $msgComment,
602 'Simple table, message comment with data' => [
603 'commentstore1',
'cs1_comment',
'cs1_id', $msgComment, [
'message' => 42 ], [
604 'text' =>
'(message comment)',
605 'message' => $msgComment,
606 'data' => [
'message' => 42 ],
609 'Simple table, nested message comment' => [
610 'commentstore1',
'cs1_comment',
'cs1_id', $nestedMsgComment,
null, [
611 'text' =>
'(Main Page)',
612 'message' => $nestedMsgComment,
616 'Simple table, CommentStoreComment' => [
617 'commentstore1',
'cs1_comment',
'cs1_id', clone $comStoreComment, [
'baz' =>
'baz' ], [
618 'text' =>
'comment store comment',
619 'message' => $comStoreComment->message,
620 'data' => [
'foo' =>
'bar' ],
624 'Revision, text comment' => [
625 'commentstore2',
'cs2_comment',
'cs2_id',
'{{text}} comment',
null, [
626 'text' =>
'{{text}} comment',
627 'message' => $textCommentMsg,
631 'Revision, text comment with data' => [
632 'commentstore2',
'cs2_comment',
'cs2_id',
'{{text}} comment', [
'message' => 42 ], [
633 'text' =>
'{{text}} comment',
634 'message' => $textCommentMsg,
635 'data' => [
'message' => 42 ],
638 'Revision, message comment' => [
639 'commentstore2',
'cs2_comment',
'cs2_id', $msgComment,
null, [
640 'text' =>
'(message comment)',
641 'message' => $msgComment,
645 'Revision, message comment with data' => [
646 'commentstore2',
'cs2_comment',
'cs2_id', $msgComment, [
'message' => 42 ], [
647 'text' =>
'(message comment)',
648 'message' => $msgComment,
649 'data' => [
'message' => 42 ],
652 'Revision, nested message comment' => [
653 'commentstore2',
'cs2_comment',
'cs2_id', $nestedMsgComment,
null, [
654 'text' =>
'(Main Page)',
655 'message' => $nestedMsgComment,
659 'Revision, CommentStoreComment' => [
660 'commentstore2',
'cs2_comment',
'cs2_id', clone $comStoreComment, [
'baz' =>
'baz' ], [
661 'text' =>
'comment store comment',
662 'message' => $comStoreComment->message,
663 'data' => [
'foo' =>
'bar' ],
670 Wikimedia\suppressWarnings();
671 $reset =
new ScopedCallback(
'Wikimedia\restoreWarnings' );
674 $res = $store->getComment(
'dummy', [
'dummy' =>
'comment' ] );
675 $this->assertSame(
'',
$res->text );
676 $res = $store->getComment(
'dummy', [
'dummy' =>
'comment' ],
true );
677 $this->assertSame(
'comment',
$res->text );
681 $store->getComment(
'dummy', [
'dummy' =>
'comment' ] );
682 $this->fail(
'Expected exception not thrown' );
683 }
catch ( InvalidArgumentException $ex ) {
684 $this->assertSame(
'$row does not contain fields needed for comment dummy', $ex->getMessage() );
686 $res = $store->getComment(
'dummy', [
'dummy' =>
'comment' ],
true );
687 $this->assertSame(
'comment',
$res->text );
689 $store->getComment(
'dummy', [
'dummy_id' => 1 ] );
690 $this->fail(
'Expected exception not thrown' );
691 }
catch ( InvalidArgumentException $ex ) {
693 '$row does not contain fields needed for comment dummy and getComment(), '
694 .
'but does have fields for getCommentLegacy()',
701 $store->getComment(
'rev_comment', [
'rev_comment' =>
'comment' ] );
702 $this->fail(
'Expected exception not thrown' );
703 }
catch ( InvalidArgumentException $ex ) {
705 '$row does not contain fields needed for comment rev_comment', $ex->getMessage()
708 $res = $store->getComment(
'rev_comment', [
'rev_comment' =>
'comment' ],
true );
709 $this->assertSame(
'comment',
$res->text );
711 $store->getComment(
'rev_comment', [
'rev_comment_pk' => 1 ] );
712 $this->fail(
'Expected exception not thrown' );
713 }
catch ( InvalidArgumentException $ex ) {
715 '$row does not contain fields needed for comment rev_comment and getComment(), '
716 .
'but does have fields for getCommentLegacy()',
739 $store->insert( $this->db,
'rev_comment',
'foo' );
750 $store->insertWithTempTable( $this->db,
'ipb_reason',
'foo' );
759 $wrap = TestingAccessWrapper::newFromObject( $store );
760 $wrap->tempTables += [
'ipb_reason' => [
762 'deprecatedIn' =>
'1.30',
765 $this->
hideDeprecated(
'CommentStore::insertWithTempTable for ipb_reason' );
766 list( $fields, $callback ) = $store->insertWithTempTable( $this->db,
'ipb_reason',
'foo' );
767 $this->assertTrue( is_callable( $callback ) );
771 $comment = str_repeat(
'💣', 16400 );
772 $truncated1 = str_repeat(
'💣', 63 ) .
'...';
776 $fields = $store->insert( $this->db,
'ipb_reason', $comment );
777 $this->assertSame( $truncated1, $fields[
'ipb_reason'] );
778 $stored = $this->db->selectField(
779 'comment',
'comment_text', [
'comment_id' => $fields[
'ipb_reason_id'] ], __METHOD__
781 $this->assertSame( $truncated2, $stored );
790 $store->insert( $this->db,
'ipb_reason',
'foo', [
791 'long' => str_repeat(
'💣', 16400 )