4 use Wikimedia\TestingAccessWrapper;
11 use MediaWikiCoversValidator;
18 ->disableOriginalConstructor()
20 $mockStore->expects( $this->
any() )
21 ->method(
'getFields' )
22 ->willReturn( [
'commentstore' =>
'fields' ] );
23 $mockStore->expects( $this->
any() )
26 'tables' => [
'commentstore' =>
'table' ],
27 'fields' => [
'commentstore' =>
'field' ],
28 'joins' => [
'commentstore' =>
'join' ],
38 ->disableOriginalConstructor()
40 $mockStore->expects( $this->
any() )
43 'tables' => [
'actormigration' =>
'table' ],
45 'rc_user' =>
'actormigration_user',
46 'rc_user_text' =>
'actormigration_user_text',
47 'rc_actor' =>
'actormigration_actor',
49 'joins' => [
'actormigration' =>
'join' ],
51 $mockStore->expects( $this->
any() )
52 ->method(
'getWhere' )
54 'tables' => [
'actormigration' =>
'table' ],
55 'conds' =>
'actormigration_conds',
56 'joins' => [
'actormigration' =>
'join' ],
58 $mockStore->expects( $this->
any() )
60 ->willReturn(
'actormigration is anon' );
61 $mockStore->expects( $this->
any() )
62 ->method(
'isNotAnon' )
63 ->willReturn(
'actormigration is not anon' );
85 ->disableOriginalConstructor()
88 $mock->expects( $this->
any() )
89 ->method(
'makeList' )
91 $this->isType(
'array' ),
92 $this->isType(
'int' )
94 ->will( $this->returnCallback(
function ( $a, $conj ) {
95 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
97 foreach ( $a
as $k => $v ) {
100 } elseif ( is_array( $v ) ) {
101 $conds[] =
"($k IN ('" . implode(
"','", $v ) .
"'))";
103 $conds[] =
"($k = '$v')";
106 return implode( $sqlConj, $conds );
109 $mock->expects( $this->
any() )
110 ->method(
'addQuotes' )
111 ->will( $this->returnCallback(
function (
$value ) {
115 $mock->expects( $this->
any() )
116 ->method(
'timestamp' )
117 ->will( $this->returnArgument( 0 ) );
119 $mock->expects( $this->
any() )
121 ->willReturnCallback(
function ( $a, $b ) {
134 ->disableOriginalConstructor()
136 $mock->expects( $this->
any() )
137 ->method(
'getConnectionRef' )
139 ->will( $this->returnValue( $mockDb ) );
149 ->disableOriginalConstructor()
151 $mock->expects( $this->
any() )
152 ->method(
'getLatestNotificationTimestamp' )
153 ->will( $this->returnCallback(
function ( $timestamp ) {
164 $mock = $this->getMockBuilder(
User::class )->getMock();
165 $mock->expects( $this->
any() )
167 ->will( $this->returnValue(
false ) );
168 $mock->expects( $this->
any() )
170 ->will( $this->returnValue( $id ) );
180 $mock->expects( $this->
any() )
181 ->method(
'isAllowed' )
182 ->will( $this->returnValue(
true ) );
183 $mock->expects( $this->
any() )
184 ->method(
'isAllowedAny' )
185 ->will( $this->returnValue(
true ) );
186 $mock->expects( $this->
any() )
187 ->method(
'useRCPatrol' )
188 ->will( $this->returnValue(
true ) );
200 $mock->expects( $this->
any() )
201 ->method(
'isAllowed' )
202 ->will( $this->returnCallback(
function ( $action )
use ( $notAllowedAction ) {
203 return $action !== $notAllowedAction;
205 $mock->expects( $this->
any() )
206 ->method(
'isAllowedAny' )
207 ->will( $this->returnCallback(
function ()
use ( $notAllowedAction ) {
208 $actions = func_get_args();
209 return !in_array( $notAllowedAction, $actions );
222 $mock->expects( $this->
any() )
223 ->method(
'isAllowed' )
224 ->will( $this->returnValue(
true ) );
225 $mock->expects( $this->
any() )
226 ->method(
'isAllowedAny' )
227 ->will( $this->returnValue(
true ) );
229 $mock->expects( $this->
any() )
230 ->method(
'useRCPatrol' )
231 ->will( $this->returnValue(
false ) );
232 $mock->expects( $this->
any() )
233 ->method(
'useNPPatrol' )
234 ->will( $this->returnValue(
false ) );
240 $mock = $this->getMockBuilder(
User::class )->getMock();
241 $mock->expects( $this->
any() )
243 ->will( $this->returnValue(
true ) );
248 $fakeRow =
new stdClass();
249 foreach ( $rowValues
as $valueName =>
$value ) {
250 $fakeRow->$valueName =
$value;
257 $mockDb->expects( $this->once() )
260 [
'recentchanges',
'watchlist',
'page' ],
268 'wl_notificationtimestamp',
275 '(rc_this_oldid=page_latest) OR (rc_type=3)',
277 $this->isType(
'string' ),
285 'wl_namespace=rc_namespace',
295 ->will( $this->returnValue( [
299 'rc_title' =>
'Foo1',
300 'rc_timestamp' =>
'20151212010101',
303 'wl_notificationtimestamp' =>
'20151212010101',
308 'rc_title' =>
'Foo2',
309 'rc_timestamp' =>
'20151212010102',
312 'wl_notificationtimestamp' =>
null,
317 'rc_title' =>
'Foo3',
318 'rc_timestamp' =>
'20151212010103',
321 'wl_notificationtimestamp' =>
null,
329 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
330 $user, [
'limit' => 2 ], $startFrom
333 $this->assertInternalType(
'array', $items );
334 $this->assertCount( 2, $items );
336 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
338 $this->assertInternalType(
'array', $recentChangeInfo );
349 'rc_title' =>
'Foo1',
350 'rc_timestamp' =>
'20151212010101',
365 'rc_title' =>
'Foo2',
366 'rc_timestamp' =>
'20151212010102',
373 $this->assertEquals( [
'20151212010103', 3 ], $startFrom );
378 $mockDb->expects( $this->once() )
381 [
'recentchanges',
'watchlist',
'page',
'extension_dummy_table' ],
389 'wl_notificationtimestamp',
393 'extension_dummy_field',
397 '(rc_this_oldid=page_latest) OR (rc_type=3)',
398 'extension_dummy_cond',
400 $this->isType(
'string' ),
402 'extension_dummy_option',
408 'wl_namespace=rc_namespace',
416 'extension_dummy_join_cond' => [],
419 ->will( $this->returnValue( [
423 'rc_title' =>
'Foo1',
424 'rc_timestamp' =>
'20151212010101',
427 'wl_notificationtimestamp' =>
'20151212010101',
432 'rc_title' =>
'Foo2',
433 'rc_timestamp' =>
'20151212010102',
436 'wl_notificationtimestamp' =>
null,
444 $mockExtension->expects( $this->once() )
445 ->method(
'modifyWatchedItemsWithRCInfoQuery' )
447 $this->identicalTo(
$user ),
448 $this->isType(
'array' ),
450 $this->isType(
'array' ),
451 $this->isType(
'array' ),
452 $this->isType(
'array' ),
453 $this->isType(
'array' ),
454 $this->isType(
'array' )
456 ->will( $this->returnCallback(
function (
459 $tables[] =
'extension_dummy_table';
460 $fields[] =
'extension_dummy_field';
461 $conds[] =
'extension_dummy_cond';
462 $dbOptions[] =
'extension_dummy_option';
463 $joinConds[
'extension_dummy_join_cond'] = [];
465 $mockExtension->expects( $this->once() )
466 ->method(
'modifyWatchedItemsWithRCInfo' )
468 $this->identicalTo(
$user ),
469 $this->isType(
'array' ),
471 $this->isType(
'array' ),
476 foreach ( $items
as $i => &$item ) {
477 $item[1][
'extension_dummy_field'] = $i;
481 $this->assertNull( $startFrom );
482 $startFrom = [
'20160203123456', 42 ];
486 TestingAccessWrapper::newFromObject( $queryService )->extensions = [ $mockExtension ];
489 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
490 $user, [], $startFrom
493 $this->assertInternalType(
'array', $items );
494 $this->assertCount( 2, $items );
496 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
498 $this->assertInternalType(
'array', $recentChangeInfo );
509 'rc_title' =>
'Foo1',
510 'rc_timestamp' =>
'20151212010101',
513 'extension_dummy_field' => 0,
526 'rc_title' =>
'Foo2',
527 'rc_timestamp' =>
'20151212010102',
530 'extension_dummy_field' => 1,
535 $this->assertEquals( [
'20160203123456', 42 ], $startFrom );
544 [
'rc_type',
'rc_minor',
'rc_bot' ],
552 [
'actormigration' =>
'table' ],
553 [
'rc_user_text' =>
'actormigration_user_text' ],
556 [
'actormigration' =>
'join' ],
561 [
'actormigration' =>
'table' ],
562 [
'rc_user' =>
'actormigration_user' ],
565 [
'actormigration' =>
'join' ],
570 [
'commentstore' =>
'table' ],
571 [
'commentstore' =>
'field' ],
574 [
'commentstore' =>
'join' ],
580 [
'rc_patrolled',
'rc_log_type' ],
589 [
'rc_old_len',
'rc_new_len' ],
598 [
'rc_logid',
'rc_log_type',
'rc_log_action',
'rc_params' ],
604 [
'namespaceIds' => [ 0, 1 ] ],
608 [
'wl_namespace' => [ 0, 1 ] ],
613 [
'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ] ],
617 [
'wl_namespace' => [ 0, 1 ] ],
636 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
645 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
653 [
"rc_timestamp <= '20151212010101'" ],
654 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
662 [
"rc_timestamp >= '20151212010101'" ],
663 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
669 'start' =>
'20151212020101',
670 'end' =>
'20151212010101'
675 [
"rc_timestamp <= '20151212020101'",
"rc_timestamp >= '20151212010101'" ],
676 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
684 [
"rc_timestamp >= '20151212010101'" ],
685 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
693 [
"rc_timestamp <= '20151212010101'" ],
694 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
700 'start' =>
'20151212010101',
701 'end' =>
'20151212020101'
706 [
"rc_timestamp >= '20151212010101'",
"rc_timestamp <= '20151212020101'" ],
707 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
720 [
'limit' =>
"10; DROP TABLE watchlist;\n--" ],
767 [
'actormigration' =>
'table' ],
769 [
'actormigration is anon' ],
771 [
'actormigration' =>
'join' ],
776 [
'actormigration' =>
'table' ],
778 [
'actormigration is not anon' ],
780 [
'actormigration' =>
'join' ],
787 [
'rc_patrolled != 0' ],
796 [
'rc_patrolled' => 0 ],
805 [
'rc_timestamp >= wl_notificationtimestamp' ],
814 [
'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp' ],
819 [
'onlyByUser' =>
'SomeOtherUser' ],
821 [
'actormigration' =>
'table' ],
823 [
'actormigration_conds' ],
825 [
'actormigration' =>
'join' ],
828 [
'notByUser' =>
'SomeOtherUser' ],
830 [
'actormigration' =>
'table' ],
832 [
'NOT(actormigration_conds)' ],
834 [
'actormigration' =>
'join' ],
838 [
'20151212010101', 123 ],
842 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
844 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
849 [
'20151212010101', 123 ],
853 "(rc_timestamp > '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id >= 123))"
855 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
860 [
'20151212010101',
"123; DROP TABLE watchlist;\n--" ],
864 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
866 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
878 array $expectedExtraTables,
879 array $expectedExtraFields,
880 array $expectedExtraConds,
881 array $expectedDbOptions,
882 array $expectedExtraJoinConds
884 $expectedTables = array_merge( [
'recentchanges',
'watchlist',
'page' ], $expectedExtraTables );
885 $expectedFields = array_merge(
893 'wl_notificationtimestamp',
901 $expectedConds = array_merge(
902 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)', ],
905 $expectedJoinConds = array_merge(
910 'wl_namespace=rc_namespace',
919 $expectedExtraJoinConds
923 $mockDb->expects( $this->once() )
929 $this->isType(
'string' ),
933 ->will( $this->returnValue( [] ) );
938 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
940 $this->assertEmpty( $items );
941 $this->assertNull( $startFrom );
958 $mockDb->expects( $this->once() )
961 [
'recentchanges',
'watchlist',
'page' ],
962 $this->isType(
'array' ),
963 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
964 $this->isType(
'string' ),
965 $this->isType(
'array' ),
966 $this->isType(
'array' )
968 ->will( $this->returnValue( [] ) );
973 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
975 [
'filters' => [ $filtersOption ] ]
978 $this->assertEmpty( $items );
986 [
"rc_timestamp > ''" ],
991 [
"rc_timestamp <= '20151212010101'" ],
996 [
"rc_timestamp >= '20151212010101'" ],
1012 array $expectedExtraConds
1014 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
1015 $conds = array_merge( $commonConds, $expectedExtraConds );
1018 $mockDb->expects( $this->once() )
1019 ->method(
'select' )
1021 [
'recentchanges',
'watchlist',
'page' ],
1022 $this->isType(
'array' ),
1024 $this->isType(
'string' ),
1025 $this->isType(
'array' ),
1026 $this->isType(
'array' )
1028 ->will( $this->returnValue( [] ) );
1029 $mockDb->expects( $this->
any() )
1030 ->method(
'getType' )
1031 ->will( $this->returnValue( $dbType ) );
1033 $queryService = $this->
newService( $mockDb );
1036 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
1038 $this->assertEmpty( $items );
1058 '(rc_type != ' .
RC_LOG .
') OR (' .
1069 '(rc_type != ' .
RC_LOG .
') OR (' .
1076 [
'onlyByUser' =>
'SomeOtherUser' ],
1078 [
'actormigration' =>
'table' ],
1080 'actormigration_conds',
1085 [
'actormigration' =>
'join' ],
1088 [
'onlyByUser' =>
'SomeOtherUser' ],
1090 [
'actormigration' =>
'table' ],
1092 'actormigration_conds',
1095 '(rc_type != ' .
RC_LOG .
') OR (' .
1099 [
'actormigration' =>
'join' ],
1102 [
'onlyByUser' =>
'SomeOtherUser' ],
1104 [
'actormigration' =>
'table' ],
1106 'actormigration_conds',
1109 '(rc_type != ' .
RC_LOG .
') OR (' .
1113 [
'actormigration' =>
'join' ],
1124 array $expectedExtraTables,
1125 array $expectedExtraConds,
1126 array $expectedExtraJoins
1128 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
1129 $conds = array_merge( $commonConds, $expectedExtraConds );
1132 $mockDb->expects( $this->once() )
1133 ->method(
'select' )
1135 array_merge( [
'recentchanges',
'watchlist',
'page' ], $expectedExtraTables ),
1136 $this->isType(
'array' ),
1138 $this->isType(
'string' ),
1139 $this->isType(
'array' ),
1141 'watchlist' => [
'JOIN', [
'wl_namespace=rc_namespace',
'wl_title=rc_title' ] ],
1142 'page' => [
'LEFT JOIN',
'rc_cur_id=page_id' ],
1143 ], $expectedExtraJoins )
1145 ->will( $this->returnValue( [] ) );
1149 $queryService = $this->
newService( $mockDb );
1150 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
1152 $this->assertEmpty( $items );
1157 $mockDb->expects( $this->once() )
1158 ->method(
'select' )
1160 [
'recentchanges',
'watchlist' ],
1168 'wl_notificationtimestamp',
1174 [
'wl_user' => 1, ],
1175 $this->isType(
'string' ),
1181 'wl_namespace=rc_namespace',
1187 ->will( $this->returnValue( [] ) );
1189 $queryService = $this->
newService( $mockDb );
1192 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user, [
'allRevisions' =>
true ] );
1194 $this->assertEmpty( $items );
1200 [
'rcTypes' => [ 1337 ] ],
1202 'Bad value for parameter $options[\'rcTypes\']',
1205 [
'rcTypes' => [
'edit' ] ],
1207 'Bad value for parameter $options[\'rcTypes\']',
1210 [
'rcTypes' => [
RC_EDIT, 1337 ] ],
1212 'Bad value for parameter $options[\'rcTypes\']',
1217 'Bad value for parameter $options[\'dir\']',
1220 [
'start' =>
'20151212010101' ],
1222 'Bad value for parameter $options[\'dir\']: must be provided',
1225 [
'end' =>
'20151212010101' ],
1227 'Bad value for parameter $options[\'dir\']: must be provided',
1231 [
'20151212010101', 123 ],
1232 'Bad value for parameter $options[\'dir\']: must be provided',
1237 'Bad value for parameter $startFrom: must be a two-element array',
1241 [
'20151212010101' ],
1242 'Bad value for parameter $startFrom: must be a two-element array',
1246 [
'20151212010101', 123,
'foo' ],
1247 'Bad value for parameter $startFrom: must be a two-element array',
1252 'Bad value for parameter $options[\'watchlistOwnerToken\']',
1255 [
'watchlistOwner' =>
'Other User',
'watchlistOwnerToken' =>
'some-token' ],
1257 'Bad value for parameter $options[\'watchlistOwner\']',
1268 $expectedInExceptionMessage
1271 $mockDb->expects( $this->never() )
1274 $queryService = $this->
newService( $mockDb );
1278 $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
1283 $mockDb->expects( $this->once() )
1284 ->method(
'select' )
1286 [
'recentchanges',
'watchlist',
'page' ],
1294 'wl_notificationtimestamp',
1297 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
1298 $this->isType(
'string' ),
1304 'wl_namespace=rc_namespace',
1310 'rc_cur_id=page_id',
1314 ->will( $this->returnValue( [] ) );
1316 $queryService = $this->
newService( $mockDb );
1319 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1321 [
'usedInGenerator' =>
true ]
1324 $this->assertEmpty( $items );
1329 $mockDb->expects( $this->once() )
1330 ->method(
'select' )
1332 [
'recentchanges',
'watchlist' ],
1340 'wl_notificationtimestamp',
1344 $this->isType(
'string' ),
1350 'wl_namespace=rc_namespace',
1356 ->will( $this->returnValue( [] ) );
1358 $queryService = $this->
newService( $mockDb );
1361 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1363 [
'usedInGenerator' =>
true,
'allRevisions' =>
true, ]
1366 $this->assertEmpty( $items );
1371 $mockDb->expects( $this->once() )
1372 ->method(
'select' )
1374 $this->isType(
'array' ),
1375 $this->isType(
'array' ),
1378 '(rc_this_oldid=page_latest) OR (rc_type=3)',
1380 $this->isType(
'string' ),
1381 $this->isType(
'array' ),
1382 $this->isType(
'array' )
1384 ->will( $this->returnValue( [] ) );
1386 $queryService = $this->
newService( $mockDb );
1389 $otherUser->expects( $this->once() )
1390 ->method(
'getOption' )
1391 ->with(
'watchlisttoken' )
1392 ->willReturn(
'0123456789abcdef' );
1394 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1396 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' =>
'0123456789abcdef' ]
1399 $this->assertEmpty( $items );
1414 $mockDb->expects( $this->never() )
1417 $queryService = $this->
newService( $mockDb );
1420 $otherUser->expects( $this->once() )
1421 ->method(
'getOption' )
1422 ->with(
'watchlisttoken' )
1423 ->willReturn(
'0123456789abcdef' );
1426 $queryService->getWatchedItemsWithRecentChangeInfo(
1428 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' => $token ]
1434 $mockDb->expects( $this->once() )
1435 ->method(
'select' )
1438 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1441 ->will( $this->returnValue( [
1443 'wl_namespace' => 0,
1444 'wl_title' =>
'Foo1',
1445 'wl_notificationtimestamp' =>
'20151212010101',
1448 'wl_namespace' => 1,
1449 'wl_title' =>
'Foo2',
1450 'wl_notificationtimestamp' =>
null,
1454 $queryService = $this->
newService( $mockDb );
1457 $items = $queryService->getWatchedItemsForUser(
$user );
1459 $this->assertInternalType(
'array', $items );
1460 $this->assertCount( 2, $items );
1462 $this->assertEquals(
1466 $this->assertEquals(
1475 [
'namespaceIds' => [ 0, 1 ], ],
1476 [
'wl_namespace' => [ 0, 1 ], ],
1482 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1486 'namespaceIds' => [ 0 ],
1489 [
'wl_namespace' => [ 0 ], ],
1490 [
'ORDER BY' =>
'wl_title ASC' ]
1499 'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ],
1500 'limit' =>
"10; DROP TABLE watchlist;\n--",
1502 [
'wl_namespace' => [ 0, 1 ], ],
1507 [
'wl_notificationtimestamp IS NOT NULL' ],
1512 [
'wl_notificationtimestamp IS NULL' ],
1518 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1522 'namespaceIds' => [ 0 ],
1525 [
'wl_namespace' => [ 0 ], ],
1526 [
'ORDER BY' =>
'wl_title DESC' ]
1536 array $expectedConds,
1537 array $expectedDbOptions
1542 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1543 $mockDb->expects( $this->once() )
1544 ->method(
'select' )
1547 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1549 $this->isType(
'string' ),
1552 ->will( $this->returnValue( [] ) );
1554 $queryService = $this->
newService( $mockDb );
1556 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1557 $this->assertEmpty( $items );
1567 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1568 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1575 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1576 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1583 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1584 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1591 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1592 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1596 'from' =>
new TitleValue( 0,
'AnotherDbKey' ),
1597 'until' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1598 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1602 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1603 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1604 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))",
1606 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1610 'from' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1611 'until' =>
new TitleValue( 0,
'AnotherDbKey' ),
1612 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1616 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1617 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1618 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))",
1620 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1630 array $expectedConds,
1631 array $expectedDbOptions
1635 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1638 $mockDb->expects( $this->
any() )
1639 ->method(
'addQuotes' )
1640 ->will( $this->returnCallback(
function (
$value ) {
1643 $mockDb->expects( $this->
any() )
1644 ->method(
'makeList' )
1646 $this->isType(
'array' ),
1647 $this->isType(
'int' )
1649 ->will( $this->returnCallback(
function ( $a, $conj ) {
1650 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
1651 return implode( $sqlConj, array_map(
function (
$s ) {
1652 return '(' .
$s .
')';
1656 $mockDb->expects( $this->once() )
1657 ->method(
'select' )
1660 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1662 $this->isType(
'string' ),
1665 ->will( $this->returnValue( [] ) );
1667 $queryService = $this->
newService( $mockDb );
1669 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1670 $this->assertEmpty( $items );
1676 [
'sort' =>
'foo' ],
1677 'Bad value for parameter $options[\'sort\']'
1680 [
'filter' =>
'foo' ],
1681 'Bad value for parameter $options[\'filter\']'
1684 [
'from' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1685 'Bad value for parameter $options[\'sort\']: must be provided'
1688 [
'until' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1689 'Bad value for parameter $options[\'sort\']: must be provided'
1692 [
'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1693 'Bad value for parameter $options[\'sort\']: must be provided'
1703 $expectedInExceptionMessage
1714 $mockDb->expects( $this->never() )
1717 $queryService = $this->
newService( $mockDb );
1719 $items = $queryService->getWatchedItemsForUser( $this->
getMockAnonUser() );
1720 $this->assertEmpty( $items );