Completed
Push — master ( 237071...fd45e5 )
by
unknown
07:26 queued 10s
created

AffectedPagesFinderTest::getLinkBatchFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace Wikibase\Client\Tests\Integration\Changes;
6
7
use ArrayIterator;
8
use DataValues\DataValue;
9
use DataValues\StringValue;
10
use LinkBatch;
11
use MediaWiki\Cache\LinkBatchFactory;
12
use Title;
13
use TitleFactory;
14
use Traversable;
15
use Wikibase\Client\Changes\AffectedPagesFinder;
16
use Wikibase\Client\Usage\EntityUsage;
17
use Wikibase\Client\Usage\PageEntityUsages;
18
use Wikibase\Client\Usage\UsageLookup;
19
use Wikibase\DataModel\Entity\Item;
20
use Wikibase\DataModel\Entity\ItemId;
21
use Wikibase\DataModel\Entity\PropertyId;
22
use Wikibase\DataModel\Snak\PropertyValueSnak;
23
use Wikibase\Lib\Changes\EntityChange;
24
use Wikibase\Lib\Tests\Changes\TestChanges;
25
26
/**
27
 * @covers \Wikibase\Client\Changes\AffectedPagesFinder
28
 *
29
 * @group Database
30
 * @group WikibaseClient
31
 * @group Wikibase
32
 *
33
 * @license GPL-2.0-or-later
34
 * @author Katie Filbert < [email protected] >
35
 * @author Daniel Kinzler
36
 */
37
class AffectedPagesFinderTest extends \MediaWikiTestCase {
38
39
	/**
40
	 * Returns a TitleFactory that generates Title objects based on the assumption
41
	 * that a page's title is the same as the page's article ID (in decimal notation).
42
	 *
43
	 * @return TitleFactory
44
	 */
45
	private function getTitleFactory() {
46
		$titleFactory = $this->createMock( TitleFactory::class );
47
48
		$titleFactory->expects( $this->any() )
49
			->method( 'newFromID' )
50
			->will( $this->returnCallback( function( $id ) {
51
				$title = Title::makeTitle( NS_MAIN, "$id" );
52
				$title->resetArticleID( $id );
53
				return $title;
54
			} ) );
55
56
		$titleFactory->expects( $this->any() )
57
			->method( 'newFromText' )
58
			->will( $this->returnCallback( function( $text, $defaultNs = \NS_MAIN ) {
59
				$title = Title::newFromText( $text, $defaultNs );
60
61
				if ( !$title ) {
62
					return $title;
63
				}
64
65
				$title->resetArticleID( $text );
66
				return $title;
67
			} ) );
68
69
		return $titleFactory;
70
	}
71
72
	private function getLinkBatchFactory(): LinkBatchFactory {
73
		$linkBatch = $this->createMock( LinkBatch::class );
74
		$linkBatch->method( 'execute' )
75
			->willReturn( null );
76
77
		$linkBatchFactory = $this->createMock( LinkBatchFactory::class );
78
		$linkBatchFactory->method( 'newLinkBatch' )
79
			->willReturn( $linkBatch );
80
81
		return $linkBatchFactory;
82
	}
83
84
	private function getAffectedPagesFinder( array $usage, array $expectedAspects ) {
85
		$usageLookup = $this->createMock( UsageLookup::class );
86
87
		$usageLookup->expects( $this->any() )
88
			->method( 'getPagesUsing' )
89
			->with( $this->anything(), $expectedAspects )
90
			->will( $this->returnValue( new ArrayIterator( $usage ) ) );
91
92
		$affectedPagesFinder = new AffectedPagesFinder(
93
			$usageLookup,
94
			$this->getTitleFactory(),
95
			$this->getLinkBatchFactory(),
96
			'enwiki',
97
			null,
98
			false
99
		);
100
101
		return $affectedPagesFinder;
102
	}
103
104
	public function getChangedAspectsProvider() {
105
		$changeFactory = TestChanges::getEntityChangeFactory();
106
		$cases = [];
107
108
		$q1 = new ItemId( 'Q1' );
109
		$q2 = new ItemId( 'Q2' );
110
111
		$cases['create linked item Q1'] = [
112
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
113
			$changeFactory->newFromUpdate(
114
				EntityChange::ADD,
115
				null,
116
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] )
117
			)
118
		];
119
120
		$cases['unlink item Q1'] = [
121
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
122
			$changeFactory->newFromUpdate(
123
				EntityChange::UPDATE,
124
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
125
				new Item( $q1 )
126
			)
127
		];
128
129
		$cases['link item Q2'] = [
130
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
131
			$changeFactory->newFromUpdate(
132
				EntityChange::UPDATE,
133
				new Item( $q2 ),
134
				$this->getItemWithSiteLinks( $q2, [ 'enwiki' => '2' ] )
135
			)
136
		];
137
138
		$cases['change link of Q1'] = [
139
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
140
			$changeFactory->newFromUpdate(
141
				EntityChange::UPDATE,
142
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
143
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '2' ] )
144
			)
145
		];
146
147
		$cases['delete linked item Q2'] = [
148
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
149
			$changeFactory->newFromUpdate(
150
				EntityChange::REMOVE,
151
				$this->getItemWithSiteLinks( $q2, [ 'enwiki' => '2' ] ),
152
				null
153
			)
154
		];
155
156
		$cases['add another sitelink to Q2'] = [
157
			[ EntityUsage::SITELINK_USAGE ],
158
			$changeFactory->newFromUpdate(
159
				EntityChange::UPDATE,
160
				$this->getItemWithSiteLinks( $q2, [ 'enwiki' => '2' ] ),
161
				$this->getItemWithSiteLinks( $q2, [
162
					'enwiki' => '2',
163
					'itwiki' => 'DUE',
164
				] )
165
			)
166
		];
167
168
		$cases['alias change on Q1'] = [
169
			[ EntityUsage::OTHER_USAGE ],
170
			$changeFactory->newFromUpdate(
171
				EntityChange::UPDATE,
172
				new Item( $q1 ),
173
				$this->getItemWithAliases( $q1, 'de', [ 'EINS' ] )
174
			)
175
		];
176
177
		$cases['local label change on Q1 (used by Q2)'] = [
178
			[ EntityUsage::makeAspectKey( EntityUsage::LABEL_USAGE, 'en' ), EntityUsage::makeAspectKey( EntityUsage::LABEL_USAGE ) ],
179
			$changeFactory->newFromUpdate(
180
				EntityChange::UPDATE,
181
				new Item( $q1 ),
182
				$this->getItemWithLabel( $q1, 'en', 'ONE' )
183
			)
184
		];
185
186
		$badges = [ new ItemId( 'Q34' ) ];
187
		$cases['badge only change on Q1'] = [
188
			[ EntityUsage::SITELINK_USAGE ],
189
			$changeFactory->newFromUpdate(
190
				EntityChange::UPDATE,
191
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
192
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ], $badges ) )
193
		];
194
195
		$cases['description only change on Q1'] = [
196
			[ EntityUsage::DESCRIPTION_USAGE, EntityUsage::DESCRIPTION_USAGE . '.en' ],
197
			$changeFactory->newFromUpdate(
198
				EntityChange::UPDATE,
199
				$this->getItemWithDescriptions( $q1, [ 'en' => 'Hello' ] ),
200
				$this->getItemWithDescriptions( $q1, [ 'en' => 'Hallo' ] ) )
201
		];
202
203
		$cases['statement change on Q1'] = [
204
			[ EntityUsage::STATEMENT_USAGE, EntityUsage::STATEMENT_USAGE . '.P5' ],
205
			$changeFactory->newFromUpdate(
206
				EntityChange::UPDATE,
207
				new Item( $q1 ),
208
				$this->getItemWithStatement( $q1, new PropertyId( 'P5' ), new StringValue( 'Hello' ) )
209
			)
210
		];
211
212
		return $cases;
213
	}
214
215
	/**
216
	 * @dataProvider getChangedAspectsProvider
217
	 */
218
	public function testGetChangedAspects( array $expected, EntityChange $change ) {
219
		$referencedPagesFinder = $this->getAffectedPagesFinder( [], [] );
220
221
		$actual = $referencedPagesFinder->getChangedAspects( $change );
222
223
		sort( $expected );
224
		sort( $actual );
225
		$this->assertEquals( $expected, $actual );
226
	}
227
228
	public function getAffectedUsagesByPageProvider() {
229
		$labelUsage = EntityUsage::LABEL_USAGE;
230
		$labelUsageDe = EntityUsage::LABEL_USAGE . '.de';
231
		$labelUsageEn = EntityUsage::LABEL_USAGE . '.en';
232
233
		$changeFactory = TestChanges::getEntityChangeFactory();
234
235
		$q1 = new ItemId( 'Q1' );
236
		$q2 = new ItemId( 'Q2' );
237
238
		$q1SitelinkUsage = new EntityUsage( $q1, EntityUsage::SITELINK_USAGE );
239
		$q2SitelinkUsage = new EntityUsage( $q2, EntityUsage::SITELINK_USAGE );
240
		$q2OtherUsage = new EntityUsage( $q2, EntityUsage::OTHER_USAGE );
241
242
		$q1LabelUsage_en = new EntityUsage( $q1, EntityUsage::LABEL_USAGE, 'en' );
243
		$q2LabelUsage = new EntityUsage( $q2, EntityUsage::LABEL_USAGE );
244
		$q2LabelUsage_en = new EntityUsage( $q2, EntityUsage::LABEL_USAGE, 'en' );
245
		$q2LabelUsage_de = new EntityUsage( $q2, EntityUsage::LABEL_USAGE, 'de' );
246
247
		$q1TitleUsage = new EntityUsage( $q1, EntityUsage::TITLE_USAGE );
248
		$q2TitleUsage = new EntityUsage( $q2, EntityUsage::TITLE_USAGE );
249
250
		$q2DescriptionUsage = new EntityUsage( $q2, EntityUsage::DESCRIPTION_USAGE );
251
		$q2DescriptionUsage_en = new EntityUsage( $q2, EntityUsage::DESCRIPTION_USAGE, 'en' );
252
253
		$q2StatementUsage_p1 = new EntityUsage( $q2, EntityUsage::STATEMENT_USAGE, 'P1' );
254
		$q2StatementUsage_p2 = new EntityUsage( $q2, EntityUsage::STATEMENT_USAGE, 'P2' );
0 ignored issues
show
Unused Code introduced by
$q2StatementUsage_p2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
255
256
		// Page 1 is linked to Q1
257
		$page1Q1Usages = new PageEntityUsages( 1, [
258
			$q1SitelinkUsage,
259
		] );
260
261
		// Page 2 uses label and title to link to Q1
262
		$page2Q1Usages = new PageEntityUsages( 2, [
263
			$q1LabelUsage_en,
264
			$q1TitleUsage,
265
			$q2DescriptionUsage_en,
266
		] );
267
268
		// Page 1 uses label and title to link to Q2, and shows the German label too.
269
		$page1Q2Usages = new PageEntityUsages( 1, [
270
			$q2LabelUsage, // "all languages" usage
271
			$q2TitleUsage,
272
		] );
273
274
		// Page 2 uses Q2 to render an infobox
275
		$page2Q2Usages = new PageEntityUsages( 2, [
276
			$q2StatementUsage_p1,
277
			$q2TitleUsage,
278
			$q2SitelinkUsage,
279
			$q2OtherUsage,
280
			$q2LabelUsage,
281
			$q2DescriptionUsage
282
		] );
283
284
		// Cases
285
		// item with link created
286
		// item with link deleted
287
		// link added
288
		// removed added
289
		// link changed
290
		// direct aspect match
291
		// no aspect match
292
		// all matches any
293
		// any matches all
294
295
		$cases = [];
296
297
		$cases['create linked item Q1'] = [
298
			[
299
				new PageEntityUsages( 1, [ $q1SitelinkUsage ] ),
300
			],
301
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
302
			[], // No usages recorded yet
303
			$changeFactory->newFromUpdate(
304
				EntityChange::ADD,
305
				null,
306
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] )
307
			)
308
		];
309
310
		$cases['unlink item Q1'] = [
311
			[
312
				new PageEntityUsages( 1, [ $q1SitelinkUsage ] ),
313
				new PageEntityUsages( 2, [ $q1TitleUsage ] ),
314
			],
315
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
316
			[ $page1Q1Usages, $page2Q1Usages ], // "1" was recorded to be linked to Q1 and the local title used on page "2"
317
			$changeFactory->newFromUpdate(
318
				EntityChange::UPDATE,
319
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
320
				new Item( $q1 )
321
			)
322
		];
323
324
		$cases['link item Q2'] = [
325
			[
326
				new PageEntityUsages( 1, [ $q2TitleUsage ] ),
327
				new PageEntityUsages( 2, [ $q2TitleUsage, $q2SitelinkUsage ] ),
328
			],
329
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
330
			[ $page1Q2Usages, $page2Q2Usages ],
331
			$changeFactory->newFromUpdate(
332
				EntityChange::UPDATE,
333
				new Item( $q2 ),
334
				$this->getItemWithSiteLinks( $q2, [ 'enwiki' => '2' ] )
335
			)
336
		];
337
338
		$cases['change link of Q1, with NO prior record'] = [
339
			[
340
				new PageEntityUsages( 1, [ $q1SitelinkUsage ] ),
341
				new PageEntityUsages( 2, [ $q1SitelinkUsage ] ),
342
			],
343
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
344
			[],
345
			$changeFactory->newFromUpdate(
346
				EntityChange::UPDATE,
347
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
348
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '2' ] )
349
			)
350
		];
351
352
		$cases['change link of Q1, with prior record'] = [
353
			[
354
				new PageEntityUsages( 1, [ $q1SitelinkUsage ] ),
355
				new PageEntityUsages( 2, [ $q1SitelinkUsage, $q1TitleUsage ] ),
356
			],
357
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
358
			[ $page1Q1Usages, $page2Q1Usages ],
359
			$changeFactory->newFromUpdate(
360
				EntityChange::UPDATE,
361
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
362
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '2' ] )
363
			)
364
		];
365
366
		$badges = [ new ItemId( 'Q34' ) ];
367
		$cases['badge only change on Q1'] = [
368
			[
369
				new PageEntityUsages( 1, [ $q1SitelinkUsage ] ),
370
			],
371
			[ EntityUsage::SITELINK_USAGE ],
372
			[ $page1Q1Usages, $page2Q1Usages ],
373
			$changeFactory->newFromUpdate(
374
				EntityChange::UPDATE,
375
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ] ),
376
				$this->getItemWithSiteLinks( $q1, [ 'enwiki' => '1' ], $badges ) )
377
		];
378
379
		$cases['delete linked item Q2'] = [
380
			[
381
				new PageEntityUsages( 1, [ $q2TitleUsage ] ),
382
				new PageEntityUsages( 2, [ $q2TitleUsage, $q2SitelinkUsage ] ),
383
			],
384
			[ EntityUsage::SITELINK_USAGE, EntityUsage::TITLE_USAGE ],
385
			[ $page1Q2Usages, $page2Q2Usages ],
386
			$changeFactory->newFromUpdate(
387
				EntityChange::REMOVE,
388
				$this->getItemWithSiteLinks( $q2, [ 'enwiki' => '2' ] ),
389
				null
390
			)
391
		];
392
393
		$cases['add another sitelink to Q2'] = [
394
			[
395
				new PageEntityUsages( 2, [ $q2SitelinkUsage ] ),
396
			],
397
			[ EntityUsage::SITELINK_USAGE ],
398
			[ $page2Q2Usages ],
399
			$changeFactory->newFromUpdate(
400
				EntityChange::UPDATE,
401
				$this->getItemWithSiteLinks( $q2, [ 'enwiki' => '2' ] ),
402
				$this->getItemWithSiteLinks( $q2, [
403
					'enwiki' => '2',
404
					'itwiki' => 'DUE',
405
				] )
406
			)
407
		];
408
409
		$cases['other language label change on Q1 (not used on any page)'] = [
410
			[],
411
			[ $labelUsageDe, $labelUsage ],
412
			[ $page1Q1Usages, $page2Q1Usages ],
413
			$changeFactory->newFromUpdate(
414
				EntityChange::UPDATE,
415
				new Item( $q1 ),
416
				$this->getItemWithLabel( $q1, 'de', 'EINS' )
417
			)
418
		];
419
420
		$cases['other change on Q2 (used on page 2)'] = [
421
			[
422
				new PageEntityUsages( 2, [ $q2OtherUsage ] ),
423
			],
424
			[ EntityUsage::OTHER_USAGE ],
425
			[ $page1Q2Usages, $page2Q2Usages ],
426
			$changeFactory->newFromUpdate(
427
				EntityChange::UPDATE,
428
				new Item( $q2 ),
429
				$this->getItemWithAliases( $q2, 'fr', [ 'X', 'Y' ] )
430
			)
431
		];
432
433
		$cases['other language label change on Q2 (used on page 1 and 2)'] = [
434
			[
435
				new PageEntityUsages( 1, [ $q2LabelUsage, $q2LabelUsage_de ] ),
436
				new PageEntityUsages( 2, [ $q2LabelUsage, $q2LabelUsage_de ] ),
437
			],
438
			[ $labelUsageDe, $labelUsage ],
439
			[ $page1Q2Usages, $page2Q2Usages ],
440
			$changeFactory->newFromUpdate(
441
				EntityChange::UPDATE,
442
				new Item( $q2 ),
443
				$this->getItemWithLabel( $q2, 'de', 'EINS' )
444
			)
445
		];
446
447
		$cases['local label change on Q1 (used by page 2)'] = [
448
			[
449
				new PageEntityUsages( 2, [ $q1LabelUsage_en ] ),
450
			],
451
			[ $labelUsageEn, $labelUsage ],
452
			[ $page1Q1Usages, $page2Q1Usages ],
453
			$changeFactory->newFromUpdate(
454
				EntityChange::UPDATE,
455
				new Item( $q1 ),
456
				$this->getItemWithLabel( $q1, 'en', 'ONE' )
457
			)
458
		];
459
460
		$cases['local label change on Q2 (used by page 1 and page 2)'] = [
461
			[
462
				new PageEntityUsages( 1, [ $q2LabelUsage, $q2LabelUsage_en ] ),
463
				new PageEntityUsages( 2, [ $q2LabelUsage, $q2LabelUsage_en ] ),
464
			],
465
			[ $labelUsageEn, $labelUsage ],
466
			[ $page1Q2Usages, $page2Q2Usages ],
467
			$changeFactory->newFromUpdate(
468
				EntityChange::UPDATE,
469
				new Item( $q2 ),
470
				$this->getItemWithLabel( $q2, 'en', 'TWO' )
471
			)
472
		];
473
474
		$cases['local description change on Q2 (used by page 2)'] = [
475
			[
476
				new PageEntityUsages( 2, [ $q2DescriptionUsage, $q2DescriptionUsage_en ] ),
477
			],
478
			[ EntityUsage::DESCRIPTION_USAGE . '.en', EntityUsage::DESCRIPTION_USAGE ],
479
			[ $page2Q2Usages ],
480
			$changeFactory->newFromUpdate(
481
				EntityChange::UPDATE,
482
				new Item( $q2 ),
483
				$this->getItemWithDescriptions( $q2, [ 'en' => 'Wow' ] )
484
			)
485
		];
486
487
		$cases['local statement change on Q2 (used by page 2)'] = [
488
			[
489
				new PageEntityUsages( 2, [ $q2StatementUsage_p1 ] ),
490
			],
491
			[ EntityUsage::STATEMENT_USAGE . '.P1', EntityUsage::STATEMENT_USAGE ],
492
			[ $page2Q2Usages ],
493
			$changeFactory->newFromUpdate(
494
				EntityChange::UPDATE,
495
				new Item( $q2 ),
496
				$this->getItemWithStatement( $q2, new PropertyId( 'P1' ), new StringValue( 'Hello' ) )
497
			)
498
		];
499
500
		$cases['unrelated statement change on Q2 (used by page 2)'] = [
501
			[],
502
			[ EntityUsage::STATEMENT_USAGE . '.P2', EntityUsage::STATEMENT_USAGE ],
503
			[ $page2Q2Usages ],
504
			$changeFactory->newFromUpdate(
505
				EntityChange::UPDATE,
506
				new Item( $q2 ),
507
				$this->getItemWithStatement( $q2, new PropertyId( 'P2' ), new StringValue( 'Hello' ) )
508
			)
509
		];
510
511
		return $cases;
512
	}
513
514
	/**
515
	 * @dataProvider getAffectedUsagesByPageProvider
516
	 */
517
	public function testGetAffectedUsagesByPage( array $expected, array $expectedAspects, array $usage, EntityChange $change ) {
518
		// Everything will affect pages with ALL_USAGE.
519
		$expectedAspects = array_merge( $expectedAspects, [ EntityUsage::ALL_USAGE ] );
520
521
		$referencedPagesFinder = $this->getAffectedPagesFinder( $usage, $expectedAspects );
522
523
		$actual = $referencedPagesFinder->getAffectedUsagesByPage( $change );
524
525
		$this->assertPageEntityUsages( $expected, $actual );
526
	}
527
528
	public function testGetAffectedUsagesByPage_withDeletedPage() {
529
		$pageTitle = 'RandomKitten-2x5jsg8j3bvmpm4!5';
530
531
		$affectedPagesFinder = new AffectedPagesFinder(
532
			$this->getSiteLinkUsageLookup( $pageTitle ),
533
			new TitleFactory(),
534
			$this->getLinkBatchFactory(),
535
			'enwiki',
536
			null,
537
			false
538
		);
539
540
		$itemId = new ItemId( 'Q1' );
541
542
		$changeFactory = TestChanges::getEntityChangeFactory();
543
544
		$change = $changeFactory->newFromUpdate(
545
			EntityChange::UPDATE,
546
			$this->getItemWithSiteLinks( $itemId, [ 'enwiki' => $pageTitle ] ),
547
			new Item( $itemId )
548
		);
549
550
		$usages = $affectedPagesFinder->getAffectedUsagesByPage( $change );
551
552
		$this->assertSame( [], $usages );
553
	}
554
555
	private function getSiteLinkUsageLookup() {
556
		$pageEntityUsages = [ new PageEntityUsages( 1, [] ) ];
557
		$mock = $this->createMock( UsageLookup::class );
558
559
		$mock->expects( $this->any() )
560
			->method( 'getPagesUsing' )
561
			->will( $this->returnValue( new ArrayIterator( $pageEntityUsages ) ) );
562
563
		return $mock;
564
	}
565
566
	/**
567
	 * @param ItemId $id
568
	 * @param string[] $links
569
	 * @param ItemId[] $badges
570
	 *
571
	 * @return Item
572
	 */
573
	private function getItemWithSiteLinks( ItemId $id, array $links, array $badges = [] ) {
574
		$item = new Item( $id );
575
576
		foreach ( $links as $siteId => $page ) {
577
			$item->getSiteLinkList()->addNewSiteLink( $siteId, $page, $badges );
578
		}
579
580
		return $item;
581
	}
582
583
	/**
584
	 * @param ItemId $id
585
	 * @param string $languageCode
586
	 * @param string $label
587
	 *
588
	 * @return Item
589
	 */
590
	private function getItemWithLabel( ItemId $id, $languageCode, $label ) {
591
		$item = new Item( $id );
592
		$item->setLabel( $languageCode, $label );
593
594
		return $item;
595
	}
596
597
	/**
598
	 * @param ItemId $id
599
	 * @param string[] $descriptions
600
	 *
601
	 * @return Item
602
	 */
603
	private function getItemWithDescriptions( ItemId $id, $descriptions ) {
604
		$item = new Item( $id );
605
		foreach ( $descriptions as $language => $value ) {
606
			$item->setDescription( $language, $value );
607
		}
608
609
		return $item;
610
	}
611
612
	/**
613
	 * @param ItemId $id
614
	 * @param string $languageCode
615
	 * @param string[] $aliases
616
	 *
617
	 * @return Item
618
	 */
619
	private function getItemWithAliases( ItemId $id, $languageCode, array $aliases ) {
620
		$item = new Item( $id );
621
		$item->setAliases( $languageCode, $aliases );
622
623
		return $item;
624
	}
625
626
	/**
627
	 * @param ItemId $qid
628
	 * @param PropertyId $pid
629
	 * @param DataValue $value
630
	 *
631
	 * @return Item
632
	 */
633
	private function getItemWithStatement( ItemId $qid, PropertyId $pid, DataValue $value ) {
634
		$snak = new PropertyValueSnak( $pid, $value );
635
636
		$item = new Item( $qid );
637
		$item->getStatements()->addNewStatement( $snak );
638
639
		return $item;
640
	}
641
642
	/**
643
	 * @param PageEntityUsages[]|Traversable $usagesPerPage An array or traversable of
644
	 *  PageEntityUsages.
645
	 *
646
	 * @return PageEntityUsages[]
647
	 */
648
	private function getPageEntityUsageStrings( $usagesPerPage ) {
649
		$strings = [];
650
651
		foreach ( $usagesPerPage as $pageUsages ) {
652
			$strings[] = "$pageUsages";
653
		}
654
655
		sort( $strings );
656
		return $strings;
657
	}
658
659
	private function assertPageEntityUsages( $expected, $actual, $message = '' ) {
660
		$this->assertEquals(
661
			$this->getPageEntityUsageStrings( $expected ),
662
			$this->getPageEntityUsageStrings( $actual ),
663
			$message
664
		);
665
	}
666
667
}
668