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