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' );
84 ->disableOriginalConstructor()
87 $mock->expects( $this->
any() )
88 ->method(
'makeList' )
90 $this->isType(
'array' ),
91 $this->isType(
'int' )
93 ->will( $this->returnCallback(
function ( $a, $conj ) {
94 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
96 foreach ( $a
as $k => $v ) {
99 } elseif ( is_array( $v ) ) {
100 $conds[] =
"($k IN ('" . implode(
"','", $v ) .
"'))";
102 $conds[] =
"($k = '$v')";
105 return implode( $sqlConj, $conds );
108 $mock->expects( $this->
any() )
109 ->method(
'addQuotes' )
110 ->will( $this->returnCallback(
function (
$value ) {
114 $mock->expects( $this->
any() )
115 ->method(
'timestamp' )
116 ->will( $this->returnArgument( 0 ) );
118 $mock->expects( $this->
any() )
120 ->willReturnCallback(
function ( $a, $b ) {
133 ->disableOriginalConstructor()
135 $mock->expects( $this->
any() )
136 ->method(
'getConnectionRef' )
138 ->will( $this->returnValue( $mockDb ) );
147 $mock = $this->getMockBuilder(
User::class )->getMock();
148 $mock->expects( $this->
any() )
150 ->will( $this->returnValue(
false ) );
151 $mock->expects( $this->
any() )
153 ->will( $this->returnValue( $id ) );
163 $mock->expects( $this->
any() )
164 ->method(
'isAllowed' )
165 ->will( $this->returnValue(
true ) );
166 $mock->expects( $this->
any() )
167 ->method(
'isAllowedAny' )
168 ->will( $this->returnValue(
true ) );
169 $mock->expects( $this->
any() )
170 ->method(
'useRCPatrol' )
171 ->will( $this->returnValue(
true ) );
183 $mock->expects( $this->
any() )
184 ->method(
'isAllowed' )
185 ->will( $this->returnCallback(
function ( $action )
use ( $notAllowedAction ) {
186 return $action !== $notAllowedAction;
188 $mock->expects( $this->
any() )
189 ->method(
'isAllowedAny' )
190 ->will( $this->returnCallback(
function ()
use ( $notAllowedAction ) {
191 $actions = func_get_args();
192 return !in_array( $notAllowedAction, $actions );
205 $mock->expects( $this->
any() )
206 ->method(
'isAllowed' )
207 ->will( $this->returnValue(
true ) );
208 $mock->expects( $this->
any() )
209 ->method(
'isAllowedAny' )
210 ->will( $this->returnValue(
true ) );
212 $mock->expects( $this->
any() )
213 ->method(
'useRCPatrol' )
214 ->will( $this->returnValue(
false ) );
215 $mock->expects( $this->
any() )
216 ->method(
'useNPPatrol' )
217 ->will( $this->returnValue(
false ) );
223 $mock = $this->getMockBuilder(
User::class )->getMock();
224 $mock->expects( $this->
any() )
226 ->will( $this->returnValue(
true ) );
231 $fakeRow =
new stdClass();
232 foreach ( $rowValues
as $valueName =>
$value ) {
233 $fakeRow->$valueName =
$value;
240 $mockDb->expects( $this->once() )
243 [
'recentchanges',
'watchlist',
'page' ],
251 'wl_notificationtimestamp',
258 '(rc_this_oldid=page_latest) OR (rc_type=3)',
260 $this->isType(
'string' ),
268 'wl_namespace=rc_namespace',
278 ->will( $this->returnValue( [
282 'rc_title' =>
'Foo1',
283 'rc_timestamp' =>
'20151212010101',
286 'wl_notificationtimestamp' =>
'20151212010101',
291 'rc_title' =>
'Foo2',
292 'rc_timestamp' =>
'20151212010102',
295 'wl_notificationtimestamp' =>
null,
300 'rc_title' =>
'Foo3',
301 'rc_timestamp' =>
'20151212010103',
304 'wl_notificationtimestamp' =>
null,
312 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
313 $user, [
'limit' => 2 ], $startFrom
316 $this->assertInternalType(
'array', $items );
317 $this->assertCount( 2, $items );
319 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
321 $this->assertInternalType(
'array', $recentChangeInfo );
332 'rc_title' =>
'Foo1',
333 'rc_timestamp' =>
'20151212010101',
348 'rc_title' =>
'Foo2',
349 'rc_timestamp' =>
'20151212010102',
356 $this->assertEquals( [
'20151212010103', 3 ], $startFrom );
361 $mockDb->expects( $this->once() )
364 [
'recentchanges',
'watchlist',
'page',
'extension_dummy_table' ],
372 'wl_notificationtimestamp',
376 'extension_dummy_field',
380 '(rc_this_oldid=page_latest) OR (rc_type=3)',
381 'extension_dummy_cond',
383 $this->isType(
'string' ),
385 'extension_dummy_option',
391 'wl_namespace=rc_namespace',
399 'extension_dummy_join_cond' => [],
402 ->will( $this->returnValue( [
406 'rc_title' =>
'Foo1',
407 'rc_timestamp' =>
'20151212010101',
410 'wl_notificationtimestamp' =>
'20151212010101',
415 'rc_title' =>
'Foo2',
416 'rc_timestamp' =>
'20151212010102',
419 'wl_notificationtimestamp' =>
null,
427 $mockExtension->expects( $this->once() )
428 ->method(
'modifyWatchedItemsWithRCInfoQuery' )
430 $this->identicalTo(
$user ),
431 $this->isType(
'array' ),
433 $this->isType(
'array' ),
434 $this->isType(
'array' ),
435 $this->isType(
'array' ),
436 $this->isType(
'array' ),
437 $this->isType(
'array' )
439 ->will( $this->returnCallback(
function (
442 $tables[] =
'extension_dummy_table';
443 $fields[] =
'extension_dummy_field';
444 $conds[] =
'extension_dummy_cond';
445 $dbOptions[] =
'extension_dummy_option';
446 $joinConds[
'extension_dummy_join_cond'] = [];
448 $mockExtension->expects( $this->once() )
449 ->method(
'modifyWatchedItemsWithRCInfo' )
451 $this->identicalTo(
$user ),
452 $this->isType(
'array' ),
454 $this->isType(
'array' ),
459 foreach ( $items
as $i => &$item ) {
460 $item[1][
'extension_dummy_field'] = $i;
464 $this->assertNull( $startFrom );
465 $startFrom = [
'20160203123456', 42 ];
469 TestingAccessWrapper::newFromObject( $queryService )->extensions = [ $mockExtension ];
472 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
473 $user, [], $startFrom
476 $this->assertInternalType(
'array', $items );
477 $this->assertCount( 2, $items );
479 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
481 $this->assertInternalType(
'array', $recentChangeInfo );
492 'rc_title' =>
'Foo1',
493 'rc_timestamp' =>
'20151212010101',
496 'extension_dummy_field' => 0,
509 'rc_title' =>
'Foo2',
510 'rc_timestamp' =>
'20151212010102',
513 'extension_dummy_field' => 1,
518 $this->assertEquals( [
'20160203123456', 42 ], $startFrom );
527 [
'rc_type',
'rc_minor',
'rc_bot' ],
535 [
'actormigration' =>
'table' ],
536 [
'rc_user_text' =>
'actormigration_user_text' ],
539 [
'actormigration' =>
'join' ],
544 [
'actormigration' =>
'table' ],
545 [
'rc_user' =>
'actormigration_user' ],
548 [
'actormigration' =>
'join' ],
553 [
'commentstore' =>
'table' ],
554 [
'commentstore' =>
'field' ],
557 [
'commentstore' =>
'join' ],
563 [
'rc_patrolled',
'rc_log_type' ],
572 [
'rc_old_len',
'rc_new_len' ],
581 [
'rc_logid',
'rc_log_type',
'rc_log_action',
'rc_params' ],
587 [
'namespaceIds' => [ 0, 1 ] ],
591 [
'wl_namespace' => [ 0, 1 ] ],
596 [
'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ] ],
600 [
'wl_namespace' => [ 0, 1 ] ],
619 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
628 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
636 [
"rc_timestamp <= '20151212010101'" ],
637 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
645 [
"rc_timestamp >= '20151212010101'" ],
646 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
652 'start' =>
'20151212020101',
653 'end' =>
'20151212010101'
658 [
"rc_timestamp <= '20151212020101'",
"rc_timestamp >= '20151212010101'" ],
659 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
667 [
"rc_timestamp >= '20151212010101'" ],
668 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
676 [
"rc_timestamp <= '20151212010101'" ],
677 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
683 'start' =>
'20151212010101',
684 'end' =>
'20151212020101'
689 [
"rc_timestamp >= '20151212010101'",
"rc_timestamp <= '20151212020101'" ],
690 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
703 [
'limit' =>
"10; DROP TABLE watchlist;\n--" ],
750 [
'actormigration' =>
'table' ],
752 [
'actormigration is anon' ],
754 [
'actormigration' =>
'join' ],
759 [
'actormigration' =>
'table' ],
761 [
'actormigration is not anon' ],
763 [
'actormigration' =>
'join' ],
770 [
'rc_patrolled != 0' ],
779 [
'rc_patrolled' => 0 ],
788 [
'rc_timestamp >= wl_notificationtimestamp' ],
797 [
'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp' ],
802 [
'onlyByUser' =>
'SomeOtherUser' ],
804 [
'actormigration' =>
'table' ],
806 [
'actormigration_conds' ],
808 [
'actormigration' =>
'join' ],
811 [
'notByUser' =>
'SomeOtherUser' ],
813 [
'actormigration' =>
'table' ],
815 [
'NOT(actormigration_conds)' ],
817 [
'actormigration' =>
'join' ],
821 [
'20151212010101', 123 ],
825 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
827 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
832 [
'20151212010101', 123 ],
836 "(rc_timestamp > '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id >= 123))"
838 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
843 [
'20151212010101',
"123; DROP TABLE watchlist;\n--" ],
847 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
849 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
861 array $expectedExtraTables,
862 array $expectedExtraFields,
863 array $expectedExtraConds,
864 array $expectedDbOptions,
865 array $expectedExtraJoinConds
867 $expectedTables = array_merge( [
'recentchanges',
'watchlist',
'page' ], $expectedExtraTables );
868 $expectedFields = array_merge(
876 'wl_notificationtimestamp',
884 $expectedConds = array_merge(
885 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)', ],
888 $expectedJoinConds = array_merge(
893 'wl_namespace=rc_namespace',
902 $expectedExtraJoinConds
906 $mockDb->expects( $this->once() )
912 $this->isType(
'string' ),
916 ->will( $this->returnValue( [] ) );
921 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
923 $this->assertEmpty( $items );
924 $this->assertNull( $startFrom );
941 $mockDb->expects( $this->once() )
944 [
'recentchanges',
'watchlist',
'page' ],
945 $this->isType(
'array' ),
946 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
947 $this->isType(
'string' ),
948 $this->isType(
'array' ),
949 $this->isType(
'array' )
951 ->will( $this->returnValue( [] ) );
956 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
958 [
'filters' => [ $filtersOption ] ]
961 $this->assertEmpty( $items );
969 [
"rc_timestamp > ''" ],
974 [
"rc_timestamp <= '20151212010101'" ],
979 [
"rc_timestamp >= '20151212010101'" ],
995 array $expectedExtraConds
997 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
998 $conds = array_merge( $commonConds, $expectedExtraConds );
1001 $mockDb->expects( $this->once() )
1002 ->method(
'select' )
1004 [
'recentchanges',
'watchlist',
'page' ],
1005 $this->isType(
'array' ),
1007 $this->isType(
'string' ),
1008 $this->isType(
'array' ),
1009 $this->isType(
'array' )
1011 ->will( $this->returnValue( [] ) );
1012 $mockDb->expects( $this->
any() )
1013 ->method(
'getType' )
1014 ->will( $this->returnValue( $dbType ) );
1016 $queryService = $this->
newService( $mockDb );
1019 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
1021 $this->assertEmpty( $items );
1041 '(rc_type != ' .
RC_LOG .
') OR (' .
1052 '(rc_type != ' .
RC_LOG .
') OR (' .
1059 [
'onlyByUser' =>
'SomeOtherUser' ],
1061 [
'actormigration' =>
'table' ],
1063 'actormigration_conds',
1068 [
'actormigration' =>
'join' ],
1071 [
'onlyByUser' =>
'SomeOtherUser' ],
1073 [
'actormigration' =>
'table' ],
1075 'actormigration_conds',
1078 '(rc_type != ' .
RC_LOG .
') OR (' .
1082 [
'actormigration' =>
'join' ],
1085 [
'onlyByUser' =>
'SomeOtherUser' ],
1087 [
'actormigration' =>
'table' ],
1089 'actormigration_conds',
1092 '(rc_type != ' .
RC_LOG .
') OR (' .
1096 [
'actormigration' =>
'join' ],
1107 array $expectedExtraTables,
1108 array $expectedExtraConds,
1109 array $expectedExtraJoins
1111 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
1112 $conds = array_merge( $commonConds, $expectedExtraConds );
1115 $mockDb->expects( $this->once() )
1116 ->method(
'select' )
1118 array_merge( [
'recentchanges',
'watchlist',
'page' ], $expectedExtraTables ),
1119 $this->isType(
'array' ),
1121 $this->isType(
'string' ),
1122 $this->isType(
'array' ),
1124 'watchlist' => [
'INNER JOIN', [
'wl_namespace=rc_namespace',
'wl_title=rc_title' ] ],
1125 'page' => [
'LEFT JOIN',
'rc_cur_id=page_id' ],
1126 ], $expectedExtraJoins )
1128 ->will( $this->returnValue( [] ) );
1132 $queryService = $this->
newService( $mockDb );
1133 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
1135 $this->assertEmpty( $items );
1140 $mockDb->expects( $this->once() )
1141 ->method(
'select' )
1143 [
'recentchanges',
'watchlist' ],
1151 'wl_notificationtimestamp',
1157 [
'wl_user' => 1, ],
1158 $this->isType(
'string' ),
1164 'wl_namespace=rc_namespace',
1170 ->will( $this->returnValue( [] ) );
1172 $queryService = $this->
newService( $mockDb );
1175 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user, [
'allRevisions' =>
true ] );
1177 $this->assertEmpty( $items );
1183 [
'rcTypes' => [ 1337 ] ],
1185 'Bad value for parameter $options[\'rcTypes\']',
1188 [
'rcTypes' => [
'edit' ] ],
1190 'Bad value for parameter $options[\'rcTypes\']',
1193 [
'rcTypes' => [
RC_EDIT, 1337 ] ],
1195 'Bad value for parameter $options[\'rcTypes\']',
1200 'Bad value for parameter $options[\'dir\']',
1203 [
'start' =>
'20151212010101' ],
1205 'Bad value for parameter $options[\'dir\']: must be provided',
1208 [
'end' =>
'20151212010101' ],
1210 'Bad value for parameter $options[\'dir\']: must be provided',
1214 [
'20151212010101', 123 ],
1215 'Bad value for parameter $options[\'dir\']: must be provided',
1220 'Bad value for parameter $startFrom: must be a two-element array',
1224 [
'20151212010101' ],
1225 'Bad value for parameter $startFrom: must be a two-element array',
1229 [
'20151212010101', 123,
'foo' ],
1230 'Bad value for parameter $startFrom: must be a two-element array',
1235 'Bad value for parameter $options[\'watchlistOwnerToken\']',
1238 [
'watchlistOwner' =>
'Other User',
'watchlistOwnerToken' =>
'some-token' ],
1240 'Bad value for parameter $options[\'watchlistOwner\']',
1251 $expectedInExceptionMessage
1254 $mockDb->expects( $this->never() )
1257 $queryService = $this->
newService( $mockDb );
1261 $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
1266 $mockDb->expects( $this->once() )
1267 ->method(
'select' )
1269 [
'recentchanges',
'watchlist',
'page' ],
1277 'wl_notificationtimestamp',
1280 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
1281 $this->isType(
'string' ),
1287 'wl_namespace=rc_namespace',
1293 'rc_cur_id=page_id',
1297 ->will( $this->returnValue( [] ) );
1299 $queryService = $this->
newService( $mockDb );
1302 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1304 [
'usedInGenerator' =>
true ]
1307 $this->assertEmpty( $items );
1312 $mockDb->expects( $this->once() )
1313 ->method(
'select' )
1315 [
'recentchanges',
'watchlist' ],
1323 'wl_notificationtimestamp',
1327 $this->isType(
'string' ),
1333 'wl_namespace=rc_namespace',
1339 ->will( $this->returnValue( [] ) );
1341 $queryService = $this->
newService( $mockDb );
1344 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1346 [
'usedInGenerator' =>
true,
'allRevisions' =>
true, ]
1349 $this->assertEmpty( $items );
1354 $mockDb->expects( $this->once() )
1355 ->method(
'select' )
1357 $this->isType(
'array' ),
1358 $this->isType(
'array' ),
1361 '(rc_this_oldid=page_latest) OR (rc_type=3)',
1363 $this->isType(
'string' ),
1364 $this->isType(
'array' ),
1365 $this->isType(
'array' )
1367 ->will( $this->returnValue( [] ) );
1369 $queryService = $this->
newService( $mockDb );
1372 $otherUser->expects( $this->once() )
1373 ->method(
'getOption' )
1374 ->with(
'watchlisttoken' )
1375 ->willReturn(
'0123456789abcdef' );
1377 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1379 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' =>
'0123456789abcdef' ]
1382 $this->assertEmpty( $items );
1397 $mockDb->expects( $this->never() )
1400 $queryService = $this->
newService( $mockDb );
1403 $otherUser->expects( $this->once() )
1404 ->method(
'getOption' )
1405 ->with(
'watchlisttoken' )
1406 ->willReturn(
'0123456789abcdef' );
1409 $queryService->getWatchedItemsWithRecentChangeInfo(
1411 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' => $token ]
1417 $mockDb->expects( $this->once() )
1418 ->method(
'select' )
1421 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1424 ->will( $this->returnValue( [
1426 'wl_namespace' => 0,
1427 'wl_title' =>
'Foo1',
1428 'wl_notificationtimestamp' =>
'20151212010101',
1431 'wl_namespace' => 1,
1432 'wl_title' =>
'Foo2',
1433 'wl_notificationtimestamp' =>
null,
1437 $queryService = $this->
newService( $mockDb );
1440 $items = $queryService->getWatchedItemsForUser(
$user );
1442 $this->assertInternalType(
'array', $items );
1443 $this->assertCount( 2, $items );
1445 $this->assertEquals(
1449 $this->assertEquals(
1458 [
'namespaceIds' => [ 0, 1 ], ],
1459 [
'wl_namespace' => [ 0, 1 ], ],
1465 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1469 'namespaceIds' => [ 0 ],
1472 [
'wl_namespace' => [ 0 ], ],
1473 [
'ORDER BY' =>
'wl_title ASC' ]
1482 'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ],
1483 'limit' =>
"10; DROP TABLE watchlist;\n--",
1485 [
'wl_namespace' => [ 0, 1 ], ],
1490 [
'wl_notificationtimestamp IS NOT NULL' ],
1495 [
'wl_notificationtimestamp IS NULL' ],
1501 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1505 'namespaceIds' => [ 0 ],
1508 [
'wl_namespace' => [ 0 ], ],
1509 [
'ORDER BY' =>
'wl_title DESC' ]
1519 array $expectedConds,
1520 array $expectedDbOptions
1525 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1526 $mockDb->expects( $this->once() )
1527 ->method(
'select' )
1530 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1532 $this->isType(
'string' ),
1535 ->will( $this->returnValue( [] ) );
1537 $queryService = $this->
newService( $mockDb );
1539 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1540 $this->assertEmpty( $items );
1550 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1551 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1558 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1559 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1566 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1567 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1574 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1575 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1579 'from' =>
new TitleValue( 0,
'AnotherDbKey' ),
1580 'until' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1581 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1585 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1586 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1587 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))",
1589 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1593 'from' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1594 'until' =>
new TitleValue( 0,
'AnotherDbKey' ),
1595 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1599 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1600 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1601 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))",
1603 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1613 array $expectedConds,
1614 array $expectedDbOptions
1618 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1621 $mockDb->expects( $this->
any() )
1622 ->method(
'addQuotes' )
1623 ->will( $this->returnCallback(
function (
$value ) {
1626 $mockDb->expects( $this->
any() )
1627 ->method(
'makeList' )
1629 $this->isType(
'array' ),
1630 $this->isType(
'int' )
1632 ->will( $this->returnCallback(
function ( $a, $conj ) {
1633 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
1634 return implode( $sqlConj, array_map(
function (
$s ) {
1635 return '(' .
$s .
')';
1639 $mockDb->expects( $this->once() )
1640 ->method(
'select' )
1643 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1645 $this->isType(
'string' ),
1648 ->will( $this->returnValue( [] ) );
1650 $queryService = $this->
newService( $mockDb );
1652 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1653 $this->assertEmpty( $items );
1659 [
'sort' =>
'foo' ],
1660 'Bad value for parameter $options[\'sort\']'
1663 [
'filter' =>
'foo' ],
1664 'Bad value for parameter $options[\'filter\']'
1667 [
'from' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1668 'Bad value for parameter $options[\'sort\']: must be provided'
1671 [
'until' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1672 'Bad value for parameter $options[\'sort\']: must be provided'
1675 [
'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1676 'Bad value for parameter $options[\'sort\']: must be provided'
1686 $expectedInExceptionMessage
1697 $mockDb->expects( $this->never() )
1700 $queryService = $this->
newService( $mockDb );
1702 $items = $queryService->getWatchedItemsForUser( $this->
getMockAnonUser() );
1703 $this->assertEmpty( $items );