3 use Wikimedia\ScopedCallback;
4 use Wikimedia\TestingAccessWrapper;
16 ->disableOriginalConstructor()
19 $mock->expects( $this->
any() )
20 ->method(
'makeList' )
22 $this->isType(
'array' ),
23 $this->isType(
'int' )
25 ->will( $this->returnCallback(
function ( $a, $conj ) {
26 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
27 return join( $sqlConj, array_map(
function (
$s ) {
28 return '(' .
$s .
')';
33 $mock->expects( $this->
any() )
34 ->method(
'addQuotes' )
35 ->will( $this->returnCallback(
function (
$value ) {
39 $mock->expects( $this->
any() )
40 ->method(
'timestamp' )
41 ->will( $this->returnArgument( 0 ) );
43 $mock->expects( $this->
any() )
45 ->willReturnCallback(
function ( $a, $b ) {
58 ->disableOriginalConstructor()
60 $mock->expects( $this->
any() )
61 ->method(
'getConnectionRef' )
63 ->will( $this->returnValue( $mockDb ) );
72 $mock = $this->getMockBuilder(
User::class )->getMock();
73 $mock->expects( $this->
any() )
75 ->will( $this->returnValue(
false ) );
76 $mock->expects( $this->
any() )
78 ->will( $this->returnValue( $id ) );
88 $mock->expects( $this->
any() )
89 ->method(
'isAllowed' )
90 ->will( $this->returnValue(
true ) );
91 $mock->expects( $this->
any() )
92 ->method(
'isAllowedAny' )
93 ->will( $this->returnValue(
true ) );
94 $mock->expects( $this->
any() )
95 ->method(
'useRCPatrol' )
96 ->will( $this->returnValue(
true ) );
108 $mock->expects( $this->
any() )
109 ->method(
'isAllowed' )
110 ->will( $this->returnCallback(
function ( $action )
use ( $notAllowedAction ) {
111 return $action !== $notAllowedAction;
113 $mock->expects( $this->
any() )
114 ->method(
'isAllowedAny' )
115 ->will( $this->returnCallback(
function ()
use ( $notAllowedAction ) {
116 $actions = func_get_args();
117 return !in_array( $notAllowedAction, $actions );
130 $mock->expects( $this->
any() )
131 ->method(
'isAllowed' )
132 ->will( $this->returnValue(
true ) );
133 $mock->expects( $this->
any() )
134 ->method(
'isAllowedAny' )
135 ->will( $this->returnValue(
true ) );
137 $mock->expects( $this->
any() )
138 ->method(
'useRCPatrol' )
139 ->will( $this->returnValue(
false ) );
140 $mock->expects( $this->
any() )
141 ->method(
'useNPPatrol' )
142 ->will( $this->returnValue(
false ) );
148 $mock = $this->getMockBuilder(
User::class )->getMock();
149 $mock->expects( $this->
any() )
151 ->will( $this->returnValue(
true ) );
156 $fakeRow =
new stdClass();
157 foreach ( $rowValues
as $valueName =>
$value ) {
158 $fakeRow->$valueName =
$value;
165 $mockDb->expects( $this->once() )
168 [
'recentchanges',
'watchlist',
'page' ],
176 'wl_notificationtimestamp',
183 '(rc_this_oldid=page_latest) OR (rc_type=3)',
185 $this->isType(
'string' ),
193 'wl_namespace=rc_namespace',
203 ->will( $this->returnValue( [
207 'rc_title' =>
'Foo1',
208 'rc_timestamp' =>
'20151212010101',
211 'wl_notificationtimestamp' =>
'20151212010101',
216 'rc_title' =>
'Foo2',
217 'rc_timestamp' =>
'20151212010102',
220 'wl_notificationtimestamp' =>
null,
225 'rc_title' =>
'Foo3',
226 'rc_timestamp' =>
'20151212010103',
229 'wl_notificationtimestamp' =>
null,
237 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
238 $user, [
'limit' => 2 ], $startFrom
241 $this->assertInternalType(
'array', $items );
242 $this->assertCount( 2, $items );
244 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
246 $this->assertInternalType(
'array', $recentChangeInfo );
257 'rc_title' =>
'Foo1',
258 'rc_timestamp' =>
'20151212010101',
273 'rc_title' =>
'Foo2',
274 'rc_timestamp' =>
'20151212010102',
281 $this->assertEquals( [
'20151212010103', 3 ], $startFrom );
286 $mockDb->expects( $this->once() )
289 [
'recentchanges',
'watchlist',
'page',
'extension_dummy_table' ],
297 'wl_notificationtimestamp',
301 'extension_dummy_field',
305 '(rc_this_oldid=page_latest) OR (rc_type=3)',
306 'extension_dummy_cond',
308 $this->isType(
'string' ),
310 'extension_dummy_option',
316 'wl_namespace=rc_namespace',
324 'extension_dummy_join_cond' => [],
327 ->will( $this->returnValue( [
331 'rc_title' =>
'Foo1',
332 'rc_timestamp' =>
'20151212010101',
335 'wl_notificationtimestamp' =>
'20151212010101',
340 'rc_title' =>
'Foo2',
341 'rc_timestamp' =>
'20151212010102',
344 'wl_notificationtimestamp' =>
null,
352 $mockExtension->expects( $this->once() )
353 ->method(
'modifyWatchedItemsWithRCInfoQuery' )
355 $this->identicalTo(
$user ),
356 $this->isType(
'array' ),
358 $this->isType(
'array' ),
359 $this->isType(
'array' ),
360 $this->isType(
'array' ),
361 $this->isType(
'array' ),
362 $this->isType(
'array' )
364 ->will( $this->returnCallback(
function (
367 $tables[] =
'extension_dummy_table';
368 $fields[] =
'extension_dummy_field';
369 $conds[] =
'extension_dummy_cond';
370 $dbOptions[] =
'extension_dummy_option';
371 $joinConds[
'extension_dummy_join_cond'] = [];
373 $mockExtension->expects( $this->once() )
374 ->method(
'modifyWatchedItemsWithRCInfo' )
376 $this->identicalTo(
$user ),
377 $this->isType(
'array' ),
379 $this->isType(
'array' ),
383 ->will( $this->returnCallback(
function (
$user,
$options, $db, &$items,
$res, &$startFrom ) {
384 foreach ( $items
as $i => &$item ) {
385 $item[1][
'extension_dummy_field'] = $i;
389 $this->assertNull( $startFrom );
390 $startFrom = [
'20160203123456', 42 ];
394 TestingAccessWrapper::newFromObject( $queryService )->extensions = [ $mockExtension ];
397 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
398 $user, [], $startFrom
401 $this->assertInternalType(
'array', $items );
402 $this->assertCount( 2, $items );
404 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
406 $this->assertInternalType(
'array', $recentChangeInfo );
417 'rc_title' =>
'Foo1',
418 'rc_timestamp' =>
'20151212010101',
421 'extension_dummy_field' => 0,
434 'rc_title' =>
'Foo2',
435 'rc_timestamp' =>
'20151212010102',
438 'extension_dummy_field' => 1,
443 $this->assertEquals( [
'20160203123456', 42 ], $startFrom );
452 [
'rc_type',
'rc_minor',
'rc_bot' ],
480 'rc_comment_text' =>
'rc_comment',
481 'rc_comment_data' =>
'NULL',
482 'rc_comment_cid' =>
'NULL',
492 [
'comment_rc_comment' =>
'comment' ],
494 'rc_comment_text' =>
'COALESCE( comment_rc_comment.comment_text, rc_comment )',
495 'rc_comment_data' =>
'comment_rc_comment.comment_data',
496 'rc_comment_cid' =>
'comment_rc_comment.comment_id',
500 [
'comment_rc_comment' => [
'LEFT JOIN',
'comment_rc_comment.comment_id = rc_comment_id' ] ],
506 [
'comment_rc_comment' =>
'comment' ],
508 'rc_comment_text' =>
'COALESCE( comment_rc_comment.comment_text, rc_comment )',
509 'rc_comment_data' =>
'comment_rc_comment.comment_data',
510 'rc_comment_cid' =>
'comment_rc_comment.comment_id',
514 [
'comment_rc_comment' => [
'LEFT JOIN',
'comment_rc_comment.comment_id = rc_comment_id' ] ],
520 [
'comment_rc_comment' =>
'comment' ],
522 'rc_comment_text' =>
'comment_rc_comment.comment_text',
523 'rc_comment_data' =>
'comment_rc_comment.comment_data',
524 'rc_comment_cid' =>
'comment_rc_comment.comment_id',
528 [
'comment_rc_comment' => [
'JOIN',
'comment_rc_comment.comment_id = rc_comment_id' ] ],
535 [
'rc_patrolled',
'rc_log_type' ],
544 [
'rc_old_len',
'rc_new_len' ],
553 [
'rc_logid',
'rc_log_type',
'rc_log_action',
'rc_params' ],
559 [
'namespaceIds' => [ 0, 1 ] ],
563 [
'wl_namespace' => [ 0, 1 ] ],
568 [
'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ] ],
572 [
'wl_namespace' => [ 0, 1 ] ],
591 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
600 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
608 [
"rc_timestamp <= '20151212010101'" ],
609 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
617 [
"rc_timestamp >= '20151212010101'" ],
618 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
624 'start' =>
'20151212020101',
625 'end' =>
'20151212010101'
630 [
"rc_timestamp <= '20151212020101'",
"rc_timestamp >= '20151212010101'" ],
631 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
639 [
"rc_timestamp >= '20151212010101'" ],
640 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
648 [
"rc_timestamp <= '20151212010101'" ],
649 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
655 'start' =>
'20151212010101',
656 'end' =>
'20151212020101'
661 [
"rc_timestamp >= '20151212010101'",
"rc_timestamp <= '20151212020101'" ],
662 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
675 [
'limit' =>
"10; DROP TABLE watchlist;\n--" ],
742 [
'rc_patrolled != 0' ],
751 [
'rc_patrolled = 0' ],
760 [
'rc_timestamp >= wl_notificationtimestamp' ],
769 [
'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp' ],
774 [
'onlyByUser' =>
'SomeOtherUser' ],
778 [
'rc_user_text' =>
'SomeOtherUser' ],
783 [
'notByUser' =>
'SomeOtherUser' ],
787 [
"rc_user_text != 'SomeOtherUser'" ],
793 [
'20151212010101', 123 ],
797 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
799 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
804 [
'20151212010101', 123 ],
808 "(rc_timestamp > '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id >= 123))"
810 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
815 [
'20151212010101',
"123; DROP TABLE watchlist;\n--" ],
819 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
821 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
833 array $expectedExtraTables,
834 array $expectedExtraFields,
835 array $expectedExtraConds,
836 array $expectedDbOptions,
837 array $expectedExtraJoinConds,
843 foreach ( $globals
as $k => $v ) {
847 $reset =
new ScopedCallback(
function ()
use ( $resetGlobals ) {
848 foreach ( $resetGlobals
as $k => $v ) {
854 $expectedTables = array_merge( [
'recentchanges',
'watchlist',
'page' ], $expectedExtraTables );
855 $expectedFields = array_merge(
863 'wl_notificationtimestamp',
871 $expectedConds = array_merge(
872 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)', ],
875 $expectedJoinConds = array_merge(
880 'wl_namespace=rc_namespace',
889 $expectedExtraJoinConds
893 $mockDb->expects( $this->once() )
899 $this->isType(
'string' ),
903 ->will( $this->returnValue( [] ) );
908 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
910 $this->assertEmpty( $items );
911 $this->assertNull( $startFrom );
928 $mockDb->expects( $this->once() )
931 [
'recentchanges',
'watchlist',
'page' ],
932 $this->isType(
'array' ),
933 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
934 $this->isType(
'string' ),
935 $this->isType(
'array' ),
936 $this->isType(
'array' )
938 ->will( $this->returnValue( [] ) );
943 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
945 [
'filters' => [ $filtersOption ] ]
948 $this->assertEmpty( $items );
956 [
"rc_timestamp > ''" ],
961 [
"rc_timestamp <= '20151212010101'" ],
966 [
"rc_timestamp >= '20151212010101'" ],
982 array $expectedExtraConds
984 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
985 $conds = array_merge( $commonConds, $expectedExtraConds );
988 $mockDb->expects( $this->once() )
991 [
'recentchanges',
'watchlist',
'page' ],
992 $this->isType(
'array' ),
994 $this->isType(
'string' ),
995 $this->isType(
'array' ),
996 $this->isType(
'array' )
998 ->will( $this->returnValue( [] ) );
999 $mockDb->expects( $this->
any() )
1000 ->method(
'getType' )
1001 ->will( $this->returnValue( $dbType ) );
1006 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
1008 $this->assertEmpty( $items );
1025 '(rc_type != ' .
RC_LOG .
') OR (' .
1034 '(rc_type != ' .
RC_LOG .
') OR (' .
1040 [
'onlyByUser' =>
'SomeOtherUser' ],
1043 'rc_user_text' =>
'SomeOtherUser',
1050 [
'onlyByUser' =>
'SomeOtherUser' ],
1053 'rc_user_text' =>
'SomeOtherUser',
1056 '(rc_type != ' .
RC_LOG .
') OR (' .
1062 [
'onlyByUser' =>
'SomeOtherUser' ],
1065 'rc_user_text' =>
'SomeOtherUser',
1068 '(rc_type != ' .
RC_LOG .
') OR (' .
1082 array $expectedExtraConds
1084 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
1085 $conds = array_merge( $commonConds, $expectedExtraConds );
1088 $mockDb->expects( $this->once() )
1089 ->method(
'select' )
1091 [
'recentchanges',
'watchlist',
'page' ],
1092 $this->isType(
'array' ),
1094 $this->isType(
'string' ),
1095 $this->isType(
'array' ),
1096 $this->isType(
'array' )
1098 ->will( $this->returnValue( [] ) );
1103 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
1105 $this->assertEmpty( $items );
1110 $mockDb->expects( $this->once() )
1111 ->method(
'select' )
1113 [
'recentchanges',
'watchlist' ],
1121 'wl_notificationtimestamp',
1127 [
'wl_user' => 1, ],
1128 $this->isType(
'string' ),
1134 'wl_namespace=rc_namespace',
1140 ->will( $this->returnValue( [] ) );
1145 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user, [
'allRevisions' =>
true ] );
1147 $this->assertEmpty( $items );
1153 [
'rcTypes' => [ 1337 ] ],
1155 'Bad value for parameter $options[\'rcTypes\']',
1158 [
'rcTypes' => [
'edit' ] ],
1160 'Bad value for parameter $options[\'rcTypes\']',
1163 [
'rcTypes' => [
RC_EDIT, 1337 ] ],
1165 'Bad value for parameter $options[\'rcTypes\']',
1170 'Bad value for parameter $options[\'dir\']',
1173 [
'start' =>
'20151212010101' ],
1175 'Bad value for parameter $options[\'dir\']: must be provided',
1178 [
'end' =>
'20151212010101' ],
1180 'Bad value for parameter $options[\'dir\']: must be provided',
1184 [
'20151212010101', 123 ],
1185 'Bad value for parameter $options[\'dir\']: must be provided',
1190 'Bad value for parameter $startFrom: must be a two-element array',
1194 [
'20151212010101' ],
1195 'Bad value for parameter $startFrom: must be a two-element array',
1199 [
'20151212010101', 123,
'foo' ],
1200 'Bad value for parameter $startFrom: must be a two-element array',
1205 'Bad value for parameter $options[\'watchlistOwnerToken\']',
1208 [
'watchlistOwner' =>
'Other User',
'watchlistOwnerToken' =>
'some-token' ],
1210 'Bad value for parameter $options[\'watchlistOwner\']',
1221 $expectedInExceptionMessage
1224 $mockDb->expects( $this->never() )
1231 $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
1236 $mockDb->expects( $this->once() )
1237 ->method(
'select' )
1239 [
'recentchanges',
'watchlist',
'page' ],
1247 'wl_notificationtimestamp',
1250 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
1251 $this->isType(
'string' ),
1257 'wl_namespace=rc_namespace',
1263 'rc_cur_id=page_id',
1267 ->will( $this->returnValue( [] ) );
1272 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1274 [
'usedInGenerator' =>
true ]
1277 $this->assertEmpty( $items );
1282 $mockDb->expects( $this->once() )
1283 ->method(
'select' )
1285 [
'recentchanges',
'watchlist' ],
1293 'wl_notificationtimestamp',
1297 $this->isType(
'string' ),
1303 'wl_namespace=rc_namespace',
1309 ->will( $this->returnValue( [] ) );
1314 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1316 [
'usedInGenerator' =>
true,
'allRevisions' =>
true, ]
1319 $this->assertEmpty( $items );
1324 $mockDb->expects( $this->once() )
1325 ->method(
'select' )
1327 $this->isType(
'array' ),
1328 $this->isType(
'array' ),
1331 '(rc_this_oldid=page_latest) OR (rc_type=3)',
1333 $this->isType(
'string' ),
1334 $this->isType(
'array' ),
1335 $this->isType(
'array' )
1337 ->will( $this->returnValue( [] ) );
1342 $otherUser->expects( $this->once() )
1343 ->method(
'getOption' )
1344 ->with(
'watchlisttoken' )
1345 ->willReturn(
'0123456789abcdef' );
1347 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1349 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' =>
'0123456789abcdef' ]
1352 $this->assertEmpty( $items );
1367 $mockDb->expects( $this->never() )
1373 $otherUser->expects( $this->once() )
1374 ->method(
'getOption' )
1375 ->with(
'watchlisttoken' )
1376 ->willReturn(
'0123456789abcdef' );
1379 $queryService->getWatchedItemsWithRecentChangeInfo(
1381 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' => $token ]
1387 $mockDb->expects( $this->once() )
1388 ->method(
'select' )
1391 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1394 ->will( $this->returnValue( [
1396 'wl_namespace' => 0,
1397 'wl_title' =>
'Foo1',
1398 'wl_notificationtimestamp' =>
'20151212010101',
1401 'wl_namespace' => 1,
1402 'wl_title' =>
'Foo2',
1403 'wl_notificationtimestamp' =>
null,
1410 $items = $queryService->getWatchedItemsForUser(
$user );
1412 $this->assertInternalType(
'array', $items );
1413 $this->assertCount( 2, $items );
1415 $this->assertEquals(
1419 $this->assertEquals(
1428 [
'namespaceIds' => [ 0, 1 ], ],
1429 [
'wl_namespace' => [ 0, 1 ], ],
1435 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1439 'namespaceIds' => [ 0 ],
1442 [
'wl_namespace' => [ 0 ], ],
1443 [
'ORDER BY' =>
'wl_title ASC' ]
1452 'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ],
1453 'limit' =>
"10; DROP TABLE watchlist;\n--",
1455 [
'wl_namespace' => [ 0, 1 ], ],
1460 [
'wl_notificationtimestamp IS NOT NULL' ],
1465 [
'wl_notificationtimestamp IS NULL' ],
1471 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1475 'namespaceIds' => [ 0 ],
1478 [
'wl_namespace' => [ 0 ], ],
1479 [
'ORDER BY' =>
'wl_title DESC' ]
1489 array $expectedConds,
1490 array $expectedDbOptions
1495 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1496 $mockDb->expects( $this->once() )
1497 ->method(
'select' )
1500 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1502 $this->isType(
'string' ),
1505 ->will( $this->returnValue( [] ) );
1509 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1510 $this->assertEmpty( $items );
1520 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1521 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1528 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1529 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1536 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1537 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1544 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1545 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1549 'from' =>
new TitleValue( 0,
'AnotherDbKey' ),
1550 'until' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1551 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1555 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1556 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1557 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))",
1559 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1563 'from' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1564 'until' =>
new TitleValue( 0,
'AnotherDbKey' ),
1565 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1569 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1570 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1571 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))",
1573 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1583 array $expectedConds,
1584 array $expectedDbOptions
1588 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1591 $mockDb->expects( $this->
any() )
1592 ->method(
'addQuotes' )
1593 ->will( $this->returnCallback(
function (
$value ) {
1596 $mockDb->expects( $this->
any() )
1597 ->method(
'makeList' )
1599 $this->isType(
'array' ),
1600 $this->isType(
'int' )
1602 ->will( $this->returnCallback(
function ( $a, $conj ) {
1603 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
1604 return join( $sqlConj, array_map(
function (
$s ) {
1605 return '(' .
$s .
')';
1609 $mockDb->expects( $this->once() )
1610 ->method(
'select' )
1613 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1615 $this->isType(
'string' ),
1618 ->will( $this->returnValue( [] ) );
1622 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1623 $this->assertEmpty( $items );
1629 [
'sort' =>
'foo' ],
1630 'Bad value for parameter $options[\'sort\']'
1633 [
'filter' =>
'foo' ],
1634 'Bad value for parameter $options[\'filter\']'
1637 [
'from' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1638 'Bad value for parameter $options[\'sort\']: must be provided'
1641 [
'until' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1642 'Bad value for parameter $options[\'sort\']: must be provided'
1645 [
'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1646 'Bad value for parameter $options[\'sort\']: must be provided'
1656 $expectedInExceptionMessage
1667 $mockDb->expects( $this->never() )
1672 $items = $queryService->getWatchedItemsForUser( $this->
getMockAnonUser() );
1673 $this->assertEmpty( $items );