3 use Wikimedia\TestingAccessWrapper;
15 ->disableOriginalConstructor()
18 $mock->expects( $this->
any() )
19 ->method(
'makeList' )
21 $this->isType(
'array' ),
22 $this->isType(
'int' )
24 ->will( $this->returnCallback(
function( $a, $conj ) {
25 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
26 return join( $sqlConj, array_map(
function(
$s ) {
27 return '(' .
$s .
')';
32 $mock->expects( $this->
any() )
33 ->method(
'addQuotes' )
34 ->will( $this->returnCallback(
function(
$value ) {
38 $mock->expects( $this->
any() )
39 ->method(
'timestamp' )
40 ->will( $this->returnArgument( 0 ) );
42 $mock->expects( $this->
any() )
44 ->willReturnCallback(
function( $a, $b ) {
57 ->disableOriginalConstructor()
59 $mock->expects( $this->
any() )
60 ->method(
'getConnectionRef' )
62 ->will( $this->returnValue( $mockDb ) );
71 $mock = $this->getMockBuilder(
User::class )->getMock();
72 $mock->expects( $this->
any() )
74 ->will( $this->returnValue(
false ) );
75 $mock->expects( $this->
any() )
77 ->will( $this->returnValue( $id ) );
87 $mock->expects( $this->
any() )
88 ->method(
'isAllowed' )
89 ->will( $this->returnValue(
true ) );
90 $mock->expects( $this->
any() )
91 ->method(
'isAllowedAny' )
92 ->will( $this->returnValue(
true ) );
93 $mock->expects( $this->
any() )
94 ->method(
'useRCPatrol' )
95 ->will( $this->returnValue(
true ) );
107 $mock->expects( $this->
any() )
108 ->method(
'isAllowed' )
109 ->will( $this->returnCallback(
function( $action )
use ( $notAllowedAction ) {
110 return $action !== $notAllowedAction;
112 $mock->expects( $this->
any() )
113 ->method(
'isAllowedAny' )
114 ->will( $this->returnCallback(
function()
use ( $notAllowedAction ) {
115 $actions = func_get_args();
116 return !in_array( $notAllowedAction, $actions );
129 $mock->expects( $this->
any() )
130 ->method(
'isAllowed' )
131 ->will( $this->returnValue(
true ) );
132 $mock->expects( $this->
any() )
133 ->method(
'isAllowedAny' )
134 ->will( $this->returnValue(
true ) );
136 $mock->expects( $this->
any() )
137 ->method(
'useRCPatrol' )
138 ->will( $this->returnValue(
false ) );
139 $mock->expects( $this->
any() )
140 ->method(
'useNPPatrol' )
141 ->will( $this->returnValue(
false ) );
147 $mock = $this->getMockBuilder(
User::class )->getMock();
148 $mock->expects( $this->
any() )
150 ->will( $this->returnValue(
true ) );
155 $fakeRow =
new stdClass();
156 foreach ( $rowValues
as $valueName =>
$value ) {
157 $fakeRow->$valueName =
$value;
164 $mockDb->expects( $this->once() )
167 [
'recentchanges',
'watchlist',
'page' ],
175 'wl_notificationtimestamp',
182 '(rc_this_oldid=page_latest) OR (rc_type=3)',
184 $this->isType(
'string' ),
192 'wl_namespace=rc_namespace',
202 ->will( $this->returnValue( [
206 'rc_title' =>
'Foo1',
207 'rc_timestamp' =>
'20151212010101',
210 'wl_notificationtimestamp' =>
'20151212010101',
215 'rc_title' =>
'Foo2',
216 'rc_timestamp' =>
'20151212010102',
219 'wl_notificationtimestamp' =>
null,
224 'rc_title' =>
'Foo3',
225 'rc_timestamp' =>
'20151212010103',
228 'wl_notificationtimestamp' =>
null,
236 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
237 $user, [
'limit' => 2 ], $startFrom
240 $this->assertInternalType(
'array', $items );
241 $this->assertCount( 2, $items );
243 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
245 $this->assertInternalType(
'array', $recentChangeInfo );
256 'rc_title' =>
'Foo1',
257 'rc_timestamp' =>
'20151212010101',
272 'rc_title' =>
'Foo2',
273 'rc_timestamp' =>
'20151212010102',
280 $this->assertEquals( [
'20151212010103', 3 ], $startFrom );
285 $mockDb->expects( $this->once() )
288 [
'recentchanges',
'watchlist',
'page',
'extension_dummy_table' ],
296 'wl_notificationtimestamp',
300 'extension_dummy_field',
304 '(rc_this_oldid=page_latest) OR (rc_type=3)',
305 'extension_dummy_cond',
307 $this->isType(
'string' ),
309 'extension_dummy_option',
315 'wl_namespace=rc_namespace',
323 'extension_dummy_join_cond' => [],
326 ->will( $this->returnValue( [
330 'rc_title' =>
'Foo1',
331 'rc_timestamp' =>
'20151212010101',
334 'wl_notificationtimestamp' =>
'20151212010101',
339 'rc_title' =>
'Foo2',
340 'rc_timestamp' =>
'20151212010102',
343 'wl_notificationtimestamp' =>
null,
351 $mockExtension->expects( $this->once() )
352 ->method(
'modifyWatchedItemsWithRCInfoQuery' )
354 $this->identicalTo(
$user ),
355 $this->isType(
'array' ),
357 $this->isType(
'array' ),
358 $this->isType(
'array' ),
359 $this->isType(
'array' ),
360 $this->isType(
'array' ),
361 $this->isType(
'array' )
363 ->will( $this->returnCallback(
function (
366 $tables[] =
'extension_dummy_table';
367 $fields[] =
'extension_dummy_field';
368 $conds[] =
'extension_dummy_cond';
369 $dbOptions[] =
'extension_dummy_option';
370 $joinConds[
'extension_dummy_join_cond'] = [];
372 $mockExtension->expects( $this->once() )
373 ->method(
'modifyWatchedItemsWithRCInfo' )
375 $this->identicalTo(
$user ),
376 $this->isType(
'array' ),
378 $this->isType(
'array' ),
382 ->will( $this->returnCallback(
function (
$user,
$options, $db, &$items,
$res, &$startFrom ) {
383 foreach ( $items
as $i => &$item ) {
384 $item[1][
'extension_dummy_field'] = $i;
388 $this->assertNull( $startFrom );
389 $startFrom = [
'20160203123456', 42 ];
393 TestingAccessWrapper::newFromObject( $queryService )->extensions = [ $mockExtension ];
396 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
397 $user, [], $startFrom
400 $this->assertInternalType(
'array', $items );
401 $this->assertCount( 2, $items );
403 foreach ( $items
as list( $watchedItem, $recentChangeInfo ) ) {
405 $this->assertInternalType(
'array', $recentChangeInfo );
416 'rc_title' =>
'Foo1',
417 'rc_timestamp' =>
'20151212010101',
420 'extension_dummy_field' => 0,
433 'rc_title' =>
'Foo2',
434 'rc_timestamp' =>
'20151212010102',
437 'extension_dummy_field' => 1,
442 $this->assertEquals( [
'20160203123456', 42 ], $startFrom );
450 [
'rc_type',
'rc_minor',
'rc_bot' ],
478 [
'rc_patrolled',
'rc_log_type' ],
485 [
'rc_old_len',
'rc_new_len' ],
492 [
'rc_logid',
'rc_log_type',
'rc_log_action',
'rc_params' ],
497 [
'namespaceIds' => [ 0, 1 ] ],
500 [
'wl_namespace' => [ 0, 1 ] ],
504 [
'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ] ],
507 [
'wl_namespace' => [ 0, 1 ] ],
522 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ]
529 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ]
535 [
"rc_timestamp <= '20151212010101'" ],
536 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ]
542 [
"rc_timestamp >= '20151212010101'" ],
543 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ]
548 'start' =>
'20151212020101',
549 'end' =>
'20151212010101'
553 [
"rc_timestamp <= '20151212020101'",
"rc_timestamp >= '20151212010101'" ],
554 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ]
560 [
"rc_timestamp >= '20151212010101'" ],
561 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ]
567 [
"rc_timestamp <= '20151212010101'" ],
568 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ]
573 'start' =>
'20151212010101',
574 'end' =>
'20151212020101'
578 [
"rc_timestamp >= '20151212010101'",
"rc_timestamp <= '20151212020101'" ],
579 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ]
589 [
'limit' =>
"10; DROP TABLE watchlist;\n--" ],
641 [
'rc_patrolled != 0' ],
648 [
'rc_patrolled = 0' ],
655 [
'rc_timestamp >= wl_notificationtimestamp' ],
662 [
'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp' ],
666 [
'onlyByUser' =>
'SomeOtherUser' ],
669 [
'rc_user_text' =>
'SomeOtherUser' ],
673 [
'notByUser' =>
'SomeOtherUser' ],
676 [
"rc_user_text != 'SomeOtherUser'" ],
681 [
'20151212010101', 123 ],
684 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
686 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
690 [
'20151212010101', 123 ],
693 "(rc_timestamp > '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id >= 123))"
695 [
'ORDER BY' => [
'rc_timestamp',
'rc_id' ] ],
699 [
'20151212010101',
"123; DROP TABLE watchlist;\n--" ],
702 "(rc_timestamp < '20151212010101') OR ((rc_timestamp = '20151212010101') AND (rc_id <= 123))"
704 [
'ORDER BY' => [
'rc_timestamp DESC',
'rc_id DESC' ] ],
715 array $expectedExtraFields,
716 array $expectedExtraConds,
717 array $expectedDbOptions
719 $expectedFields = array_merge(
727 'wl_notificationtimestamp',
735 $expectedConds = array_merge(
736 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)', ],
741 $mockDb->expects( $this->once() )
744 [
'recentchanges',
'watchlist',
'page' ],
747 $this->isType(
'string' ),
753 'wl_namespace=rc_namespace',
763 ->will( $this->returnValue( [] ) );
768 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
770 $this->assertEmpty( $items );
771 $this->assertNull( $startFrom );
788 $mockDb->expects( $this->once() )
791 [
'recentchanges',
'watchlist',
'page' ],
792 $this->isType(
'array' ),
793 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
794 $this->isType(
'string' ),
795 $this->isType(
'array' ),
796 $this->isType(
'array' )
798 ->will( $this->returnValue( [] ) );
803 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
805 [
'filters' => [ $filtersOption ] ]
808 $this->assertEmpty( $items );
816 [
"rc_timestamp > ''" ],
821 [
"rc_timestamp <= '20151212010101'" ],
826 [
"rc_timestamp >= '20151212010101'" ],
842 array $expectedExtraConds
844 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
845 $conds = array_merge( $commonConds, $expectedExtraConds );
848 $mockDb->expects( $this->once() )
851 [
'recentchanges',
'watchlist',
'page' ],
852 $this->isType(
'array' ),
854 $this->isType(
'string' ),
855 $this->isType(
'array' ),
856 $this->isType(
'array' )
858 ->will( $this->returnValue( [] ) );
859 $mockDb->expects( $this->
any() )
860 ->method(
'getType' )
861 ->will( $this->returnValue( $dbType ) );
866 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
868 $this->assertEmpty( $items );
885 '(rc_type != ' .
RC_LOG .
') OR (' .
894 '(rc_type != ' .
RC_LOG .
') OR (' .
900 [
'onlyByUser' =>
'SomeOtherUser' ],
903 'rc_user_text' =>
'SomeOtherUser',
910 [
'onlyByUser' =>
'SomeOtherUser' ],
913 'rc_user_text' =>
'SomeOtherUser',
916 '(rc_type != ' .
RC_LOG .
') OR (' .
922 [
'onlyByUser' =>
'SomeOtherUser' ],
925 'rc_user_text' =>
'SomeOtherUser',
928 '(rc_type != ' .
RC_LOG .
') OR (' .
942 array $expectedExtraConds
944 $commonConds = [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ];
945 $conds = array_merge( $commonConds, $expectedExtraConds );
948 $mockDb->expects( $this->once() )
951 [
'recentchanges',
'watchlist',
'page' ],
952 $this->isType(
'array' ),
954 $this->isType(
'string' ),
955 $this->isType(
'array' ),
956 $this->isType(
'array' )
958 ->will( $this->returnValue( [] ) );
963 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options );
965 $this->assertEmpty( $items );
970 $mockDb->expects( $this->once() )
973 [
'recentchanges',
'watchlist' ],
981 'wl_notificationtimestamp',
988 $this->isType(
'string' ),
994 'wl_namespace=rc_namespace',
1000 ->will( $this->returnValue( [] ) );
1005 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
$user, [
'allRevisions' =>
true ] );
1007 $this->assertEmpty( $items );
1013 [
'rcTypes' => [ 1337 ] ],
1015 'Bad value for parameter $options[\'rcTypes\']',
1018 [
'rcTypes' => [
'edit' ] ],
1020 'Bad value for parameter $options[\'rcTypes\']',
1023 [
'rcTypes' => [
RC_EDIT, 1337 ] ],
1025 'Bad value for parameter $options[\'rcTypes\']',
1030 'Bad value for parameter $options[\'dir\']',
1033 [
'start' =>
'20151212010101' ],
1035 'Bad value for parameter $options[\'dir\']: must be provided',
1038 [
'end' =>
'20151212010101' ],
1040 'Bad value for parameter $options[\'dir\']: must be provided',
1044 [
'20151212010101', 123 ],
1045 'Bad value for parameter $options[\'dir\']: must be provided',
1050 'Bad value for parameter $startFrom: must be a two-element array',
1054 [
'20151212010101' ],
1055 'Bad value for parameter $startFrom: must be a two-element array',
1059 [
'20151212010101', 123,
'foo' ],
1060 'Bad value for parameter $startFrom: must be a two-element array',
1065 'Bad value for parameter $options[\'watchlistOwnerToken\']',
1068 [
'watchlistOwner' =>
'Other User',
'watchlistOwnerToken' =>
'some-token' ],
1070 'Bad value for parameter $options[\'watchlistOwner\']',
1081 $expectedInExceptionMessage
1084 $mockDb->expects( $this->never() )
1091 $queryService->getWatchedItemsWithRecentChangeInfo(
$user,
$options, $startFrom );
1096 $mockDb->expects( $this->once() )
1097 ->method(
'select' )
1099 [
'recentchanges',
'watchlist',
'page' ],
1107 'wl_notificationtimestamp',
1110 [
'wl_user' => 1,
'(rc_this_oldid=page_latest) OR (rc_type=3)' ],
1111 $this->isType(
'string' ),
1117 'wl_namespace=rc_namespace',
1123 'rc_cur_id=page_id',
1127 ->will( $this->returnValue( [] ) );
1132 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1134 [
'usedInGenerator' =>
true ]
1137 $this->assertEmpty( $items );
1142 $mockDb->expects( $this->once() )
1143 ->method(
'select' )
1145 [
'recentchanges',
'watchlist' ],
1153 'wl_notificationtimestamp',
1157 $this->isType(
'string' ),
1163 'wl_namespace=rc_namespace',
1169 ->will( $this->returnValue( [] ) );
1174 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1176 [
'usedInGenerator' =>
true,
'allRevisions' =>
true, ]
1179 $this->assertEmpty( $items );
1184 $mockDb->expects( $this->once() )
1185 ->method(
'select' )
1187 $this->isType(
'array' ),
1188 $this->isType(
'array' ),
1191 '(rc_this_oldid=page_latest) OR (rc_type=3)',
1193 $this->isType(
'string' ),
1194 $this->isType(
'array' ),
1195 $this->isType(
'array' )
1197 ->will( $this->returnValue( [] ) );
1202 $otherUser->expects( $this->once() )
1203 ->method(
'getOption' )
1204 ->with(
'watchlisttoken' )
1205 ->willReturn(
'0123456789abcdef' );
1207 $items = $queryService->getWatchedItemsWithRecentChangeInfo(
1209 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' =>
'0123456789abcdef' ]
1212 $this->assertEmpty( $items );
1227 $mockDb->expects( $this->never() )
1233 $otherUser->expects( $this->once() )
1234 ->method(
'getOption' )
1235 ->with(
'watchlisttoken' )
1236 ->willReturn(
'0123456789abcdef' );
1239 $queryService->getWatchedItemsWithRecentChangeInfo(
1241 [
'watchlistOwner' => $otherUser,
'watchlistOwnerToken' => $token ]
1247 $mockDb->expects( $this->once() )
1248 ->method(
'select' )
1251 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1254 ->will( $this->returnValue( [
1256 'wl_namespace' => 0,
1257 'wl_title' =>
'Foo1',
1258 'wl_notificationtimestamp' =>
'20151212010101',
1261 'wl_namespace' => 1,
1262 'wl_title' =>
'Foo2',
1263 'wl_notificationtimestamp' =>
null,
1270 $items = $queryService->getWatchedItemsForUser(
$user );
1272 $this->assertInternalType(
'array', $items );
1273 $this->assertCount( 2, $items );
1275 $this->assertEquals(
1279 $this->assertEquals(
1288 [
'namespaceIds' => [ 0, 1 ], ],
1289 [
'wl_namespace' => [ 0, 1 ], ],
1295 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1299 'namespaceIds' => [ 0 ],
1302 [
'wl_namespace' => [ 0 ], ],
1303 [
'ORDER BY' =>
'wl_title ASC' ]
1312 'namespaceIds' => [ 0,
"1; DROP TABLE watchlist;\n--" ],
1313 'limit' =>
"10; DROP TABLE watchlist;\n--",
1315 [
'wl_namespace' => [ 0, 1 ], ],
1320 [
'wl_notificationtimestamp IS NOT NULL' ],
1325 [
'wl_notificationtimestamp IS NULL' ],
1331 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1335 'namespaceIds' => [ 0 ],
1338 [
'wl_namespace' => [ 0 ], ],
1339 [
'ORDER BY' =>
'wl_title DESC' ]
1349 array $expectedConds,
1350 array $expectedDbOptions
1355 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1356 $mockDb->expects( $this->once() )
1357 ->method(
'select' )
1360 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1362 $this->isType(
'string' ),
1365 ->will( $this->returnValue( [] ) );
1369 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1370 $this->assertEmpty( $items );
1380 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1381 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1388 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1389 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1396 [
"(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))", ],
1397 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1404 [
"(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))", ],
1405 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1409 'from' =>
new TitleValue( 0,
'AnotherDbKey' ),
1410 'until' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1411 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1415 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1416 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1417 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'SomeDbKey'))",
1419 [
'ORDER BY' => [
'wl_namespace ASC',
'wl_title ASC' ] ]
1423 'from' =>
new TitleValue( 0,
'SomeOtherDbKey' ),
1424 'until' =>
new TitleValue( 0,
'AnotherDbKey' ),
1425 'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ),
1429 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeOtherDbKey'))",
1430 "(wl_namespace > 0) OR ((wl_namespace = 0) AND (wl_title >= 'AnotherDbKey'))",
1431 "(wl_namespace < 0) OR ((wl_namespace = 0) AND (wl_title <= 'SomeDbKey'))",
1433 [
'ORDER BY' => [
'wl_namespace DESC',
'wl_title DESC' ] ]
1443 array $expectedConds,
1444 array $expectedDbOptions
1448 $expectedConds = array_merge( [
'wl_user' => 1 ], $expectedConds );
1451 $mockDb->expects( $this->
any() )
1452 ->method(
'addQuotes' )
1453 ->will( $this->returnCallback(
function(
$value ) {
1456 $mockDb->expects( $this->
any() )
1457 ->method(
'makeList' )
1459 $this->isType(
'array' ),
1460 $this->isType(
'int' )
1462 ->will( $this->returnCallback(
function( $a, $conj ) {
1463 $sqlConj = $conj ===
LIST_AND ?
' AND ' :
' OR ';
1464 return join( $sqlConj, array_map(
function(
$s ) {
1465 return '(' .
$s .
')';
1469 $mockDb->expects( $this->once() )
1470 ->method(
'select' )
1473 [
'wl_namespace',
'wl_title',
'wl_notificationtimestamp' ],
1475 $this->isType(
'string' ),
1478 ->will( $this->returnValue( [] ) );
1482 $items = $queryService->getWatchedItemsForUser(
$user,
$options );
1483 $this->assertEmpty( $items );
1489 [
'sort' =>
'foo' ],
1490 'Bad value for parameter $options[\'sort\']'
1493 [
'filter' =>
'foo' ],
1494 'Bad value for parameter $options[\'filter\']'
1497 [
'from' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1498 'Bad value for parameter $options[\'sort\']: must be provided'
1501 [
'until' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1502 'Bad value for parameter $options[\'sort\']: must be provided'
1505 [
'startFrom' =>
new TitleValue( 0,
'SomeDbKey' ), ],
1506 'Bad value for parameter $options[\'sort\']: must be provided'
1516 $expectedInExceptionMessage
1527 $mockDb->expects( $this->never() )
1532 $items = $queryService->getWatchedItemsForUser( $this->
getMockAnonUser() );
1533 $this->assertEmpty( $items );