ResultBuilderTest::testAddRemovedLabel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 9.536
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Wikibase\Repo\Tests\Api;
4
5
use ApiResult;
6
use DataValues\Serializers\DataValueSerializer;
7
use DataValues\StringValue;
8
use HashSiteStore;
9
use InvalidArgumentException;
10
use Status;
11
use Title;
12
use Wikibase\DataModel\Entity\Item;
13
use Wikibase\DataModel\Entity\ItemId;
14
use Wikibase\DataModel\Entity\PropertyId;
15
use Wikibase\DataModel\Reference;
16
use Wikibase\DataModel\ReferenceList;
17
use Wikibase\DataModel\SerializerFactory;
18
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup;
19
use Wikibase\DataModel\SiteLink;
20
use Wikibase\DataModel\SiteLinkList;
21
use Wikibase\DataModel\Snak\PropertySomeValueSnak;
22
use Wikibase\DataModel\Snak\PropertyValueSnak;
23
use Wikibase\DataModel\Snak\SnakList;
24
use Wikibase\DataModel\Statement\Statement;
25
use Wikibase\DataModel\Statement\StatementList;
26
use Wikibase\DataModel\Term\AliasGroup;
27
use Wikibase\DataModel\Term\AliasGroupList;
28
use Wikibase\DataModel\Term\Term;
29
use Wikibase\DataModel\Term\TermList;
30
use Wikibase\Lib\LanguageFallbackChainFactory;
31
use Wikibase\Lib\Store\EntityRevision;
32
use Wikibase\Lib\Store\EntityTitleLookup;
33
use Wikibase\Repo\Api\ResultBuilder;
34
35
/**
36
 * @covers \Wikibase\Repo\Api\ResultBuilder
37
 * @todo mock and inject serializers to avoid massive expected output?
38
 *
39
 * @group Wikibase
40
 * @group WikibaseAPI
41
 *
42
 * @license GPL-2.0-or-later
43
 * @author Addshore
44
 * @author Thiemo Kreuz
45
 */
46
class ResultBuilderTest extends \PHPUnit\Framework\TestCase {
47
48
	private function getDefaultResult() {
49
		return new ApiResult( false );
50
	}
51
52
	private function getResultBuilder( ApiResult $result, $addMetaData = false ) {
53
		$mockTitle = $this->getMockBuilder( Title::class )
54
			->disableOriginalConstructor()
55
			->getMock();
56
		$mockTitle->expects( $this->any() )
57
			->method( 'getArticleID' )
58
			->will( $this->returnValue( 123 ) );
59
		$mockTitle->expects( $this->any() )
60
			->method( 'getNamespace' )
61
			->will( $this->returnValue( 456 ) );
62
		$mockTitle->expects( $this->any() )
63
			->method( 'getPrefixedText' )
64
			->will( $this->returnValue( 'MockPrefixedText' ) );
65
66
		$mockEntityTitleLookup = $this->createMock( EntityTitleLookup::class );
67
		$mockEntityTitleLookup->expects( $this->any() )
68
			->method( 'getTitleForId' )
69
			->will( $this->returnValue( $mockTitle ) );
70
71
		$mockPropertyDataTypeLookup = $this->createMock( PropertyDataTypeLookup::class );
72
		$mockPropertyDataTypeLookup->expects( $this->any() )
73
			->method( 'getDataTypeIdForProperty' )
74
			->will( $this->returnCallback( function( PropertyId $id ) {
75
				return 'DtIdFor_' . $id->getSerialization();
76
			} ) );
77
78
		$serializerFactory = new SerializerFactory(
79
			new DataValueSerializer(),
80
			SerializerFactory::OPTION_SERIALIZE_MAIN_SNAKS_WITHOUT_HASH +
0 ignored issues
show
Deprecated Code introduced by
The constant Wikibase\DataModel\Seria...MAIN_SNAKS_WITHOUT_HASH has been deprecated with message: since 2.5 use OPTION_SERIALIZE_SNAKS_WITHOUT_HASH

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
81
			SerializerFactory::OPTION_SERIALIZE_REFERENCE_SNAKS_WITHOUT_HASH
0 ignored issues
show
Deprecated Code introduced by
The constant Wikibase\DataModel\Seria...ENCE_SNAKS_WITHOUT_HASH has been deprecated with message: since 2.5 use OPTION_SERIALIZE_SNAKS_WITHOUT_HASH

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
82
		);
83
84
		$builder = new ResultBuilder(
85
			$result,
86
			$mockEntityTitleLookup,
87
			$serializerFactory,
88
			$serializerFactory->newItemSerializer(),
89
			new HashSiteStore(),
90
			$mockPropertyDataTypeLookup,
91
			$addMetaData
92
		);
93
94
		return $builder;
95
	}
96
97
	/**
98
	 * Removes all metadata keys as recognised by the MW Api.
99
	 * These all start with a '_' character.
100
	 *
101
	 * @param array $array
102
	 *
103
	 * @return array
104
	 */
105
	private function removeMetaData( array $array ) {
106
		foreach ( $array as $key => &$value ) {
107
			if ( substr( $key, 0, 1 ) === '_' ) {
108
				unset( $array[$key] );
109
			} else {
110
				if ( is_array( $value ) ) {
111
					$value = $this->removeMetaData( $value );
112
				}
113
			}
114
		}
115
		return $array;
116
	}
117
118
	public function testCanConstruct() {
119
		$result = $this->getDefaultResult();
120
		$resultBuilder = $this->getResultBuilder( $result );
121
		$this->assertInstanceOf( ResultBuilder::class, $resultBuilder );
122
	}
123
124
	/**
125
	 * @dataProvider provideMarkResultSuccess
126
	 */
127
	public function testMarkResultSuccess( $param, $expected ) {
128
		$result = $this->getDefaultResult();
129
		$resultBuilder = $this->getResultBuilder( $result );
130
		$resultBuilder->markSuccess( $param );
131
		$data = $result->getResultData();
132
133
		$this->assertEquals(
134
			[
135
				'success' => $expected,
136
				'_type' => 'assoc',
137
			],
138
			$data
139
		);
140
	}
141
142
	public function provideMarkResultSuccess() {
143
		return [
144
			[ true, 1 ],
145
			[ 1, 1 ],
146
			[ false, 0 ],
147
			[ 0, 0 ],
148
			[ null, 0 ],
149
		];
150
	}
151
152
	/**
153
	 * @dataProvider provideMarkResultSuccessExceptions
154
	 */
155
	public function testMarkResultSuccessExceptions( $param ) {
156
		$this->expectException( InvalidArgumentException::class );
157
		$result = $this->getDefaultResult();
158
		$resultBuilder = $this->getResultBuilder( $result );
159
		$resultBuilder->markSuccess( $param );
160
	}
161
162
	public function provideMarkResultSuccessExceptions() {
163
		return [ [ 3 ], [ -1 ] ];
164
	}
165
166
	public function provideTestAddEntityRevision() {
167
		$expected = [
168
			'entities' => [
169
				'Q1230000' => [
170
					'pageid' => 123, //mocked
171
					'ns' => 456, //mocked
172
					'title' => 'MockPrefixedText', //mocked
173
					'id' => 'Q123098',
174
					'type' => 'item',
175
					'lastrevid' => 33,
176
					'modified' => '2013-11-26T20:29:23Z',
177
					'redirects' => [
178
						'from' => 'Q1230000',
179
						'to' => 'Q123098',
180
					],
181
					'aliases' => [
182
						'en' => [
183
							[
184
								'language' => 'en',
185
								'value' => 'bar',
186
							],
187
							[
188
								'language' => 'en',
189
								'value' => 'baz',
190
							],
191
							'_element' => 'alias',
192
						],
193
						'zh' => [
194
							[
195
								'language' => 'zh',
196
								'value' => '????????',
197
							],
198
							'_element' => 'alias',
199
						],
200
						'_element' => 'language',
201
						'_type' => 'kvp',
202
						'_kvpkeyname' => 'id',
203
					],
204
					'descriptions' => [
205
						'pt' => [
206
							'language' => 'pt',
207
							'value' => 'ptDesc'
208
						],
209
						'pl' => [
210
							'language' => 'pl',
211
							'value' => 'Longer Description For An Item'
212
						],
213
						'_element' => 'description',
214
						'_type' => 'kvp',
215
						'_kvpkeyname' => 'language',
216
						'_kvpmerge' => true,
217
218
					],
219
					'labels' => [
220
						'de' => [
221
							'language' => 'de',
222
							'value' => 'foo'
223
						],
224
						'zh_classical' => [
225
							'language' => 'zh_classical',
226
							'value' => 'Longer Label'
227
						],
228
						'_element' => 'label',
229
						'_type' => 'kvp',
230
						'_kvpkeyname' => 'language',
231
						'_kvpmerge' => true,
232
					],
233
					'claims' => [
234
						'P65' => [
235
							[
236
								'id' => 'imaguid',
237
								'mainsnak' => [
238
									'snaktype' => 'value',
239
									'property' => 'P65',
240
									'datavalue' => [
241
										'value' => 'snakStringValue',
242
										'type' => 'string',
243
									],
244
									'datatype' => 'DtIdFor_P65',
245
								],
246
								'type' => 'statement',
247
								'qualifiers' => [
248
									'P65' => [
249
										[
250
											'hash' => '3ea0f5404dd4e631780b3386d17a15a583e499a6',
251
											'snaktype' => 'value',
252
											'property' => 'P65',
253
											'datavalue' => [
254
												'value' => 'string!',
255
												'type' => 'string',
256
											],
257
											'datatype' => 'DtIdFor_P65',
258
										],
259
										[
260
											'hash' => 'aa9a5f05e20d7fa5cda7d98371e44c0bdd5de35e',
261
											'snaktype' => 'somevalue',
262
											'property' => 'P65',
263
											'datatype' => 'DtIdFor_P65',
264
										],
265
										'_element' => 'qualifiers',
266
									],
267
									'_element' => 'property',
268
									'_type' => 'kvp',
269
									'_kvpkeyname' => 'id',
270
								],
271
								'rank' => 'normal',
272
								'qualifiers-order' => [
273
									'P65',
274
									'_element' => 'property',
275
								],
276
								'references' => [
277
									[
278
										'hash' => '8445204eb74e636cb53687e2f947c268d5186075',
279
										'snaks' => [
280
											'P65' => [
281
												[
282
													'snaktype' => 'somevalue',
283
													'property' => 'P65',
284
													'datatype' => 'DtIdFor_P65',
285
												],
286
												'_element' => 'snak',
287
											],
288
											'P68' => [
289
												[
290
													'snaktype' => 'somevalue',
291
													'property' => 'P68',
292
													'datatype' => 'DtIdFor_P68',
293
												],
294
												'_element' => 'snak',
295
											],
296
											'_element' => 'property',
297
											'_type' => 'kvp',
298
											'_kvpkeyname' => 'id',
299
										],
300
										'snaks-order' => [
301
											'P65',
302
											'P68',
303
											'_element' => 'property',
304
										]
305
									],
306
									'_element' => 'reference',
307
								],
308
							],
309
							'_element' => 'claim',
310
						],
311
						'_element' => 'property',
312
						'_type' => 'kvp',
313
						'_kvpkeyname' => 'id',
314
					],
315
					'sitelinks' => [
316
						'enwiki' => [
317
							'site' => 'enwiki',
318
							'title' => 'Berlin',
319
							'badges' => [
320
								'Q333',
321
								'_element' => 'badge',
322
							]
323
						],
324
						'zh_classicalwiki' => [
325
							'site' => 'zh_classicalwiki',
326
							'title' => 'User:Addshore',
327
							'badges' => [
328
								'_element' => 'badge',
329
							]
330
						],
331
						'_element' => 'sitelink',
332
						'_type' => 'kvp',
333
						'_kvpkeyname' => 'site',
334
						'_kvpmerge' => true,
335
					],
336
				],
337
				'_element' => 'entity',
338
				'_type' => 'kvp',
339
				'_kvpkeyname' => 'id',
340
				'_kvpmerge' => true,
341
			],
342
			'_type' => 'assoc',
343
		];
344
345
		$expectedNoMetaData = $this->removeMetaData( $expected );
346
		// The api always starts with this
347
		$expectedNoMetaData['_type'] = 'assoc';
348
349
		return [
350
			[ false, $expectedNoMetaData ],
351
			[ true, $expected ],
352
		];
353
	}
354
355
	/**
356
	 * @dataProvider provideTestAddEntityRevision
357
	 */
358
	public function testAddEntityRevision( $addMetaData, array $expected ) {
359
		$result = $this->getDefaultResult();
360
		$item = new Item( new ItemId( 'Q123098' ) );
361
362
		//Basic
363
		$item->setLabel( 'de', 'foo' );
364
		$item->setLabel( 'zh_classical', 'Longer Label' );
365
		$item->setAliases( 'en', [ 'bar', 'baz' ] );
366
		$item->setAliases( 'zh', [ '????????' ] );
367
		$item->setDescription( 'pt', 'ptDesc' );
368
		$item->setDescription( 'pl', 'Longer Description For An Item' );
369
		$item->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Berlin', [ new ItemId( 'Q333' ) ] );
370
		$item->getSiteLinkList()->addNewSiteLink( 'zh_classicalwiki', 'User:Addshore', [] );
371
372
		$snak = new PropertyValueSnak( new PropertyId( 'P65' ), new StringValue( 'snakStringValue' ) );
373
374
		$qualifiers = new SnakList();
375
		$qualifiers->addSnak( new PropertyValueSnak( new PropertyId( 'P65' ), new StringValue( 'string!' ) ) );
376
		$qualifiers->addSnak( new PropertySomeValueSnak( new PropertyId( 'P65' ) ) );
377
378
		$references = new ReferenceList();
379
		$referenceSnaks = new SnakList();
380
		$referenceSnaks->addSnak( new PropertySomeValueSnak( new PropertyId( 'P65' ) ) );
381
		$referenceSnaks->addSnak( new PropertySomeValueSnak( new PropertyId( 'P68' ) ) );
382
		$references->addReference( new Reference( $referenceSnaks ) );
383
384
		$guid = 'imaguid';
385
		$item->getStatements()->addNewStatement( $snak, $qualifiers, $references, $guid );
386
387
		$entityRevision = new EntityRevision( $item, 33, '20131126202923' );
388
389
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
390
		$resultBuilder->addEntityRevision( 'Q1230000', $entityRevision );
391
392
		$data = $result->getResultData();
393
394
		$this->assertEquals( $expected, $data );
395
	}
396
397
	public function testAddEntityRevisionKey() {
398
		$item = new Item( new ItemId( 'Q11' ) );
399
400
		$entityRevision = new EntityRevision( $item, 33, '20131126202923' );
401
402
		$props = [];
403
		$result = $this->getDefaultResult();
404
		$resultBuilder = $this->getResultBuilder( $result );
405
406
		// automatic key
407
		$resultBuilder->addEntityRevision( null, $entityRevision, $props );
408
409
		$data = $result->getResultData();
410
		$this->assertArrayHasKey( 'Q11', $data['entities'] );
411
412
		// explicit key
413
		$resultBuilder->addEntityRevision( 'FOO', $entityRevision, $props );
414
415
		$data = $result->getResultData();
416
		$this->assertArrayHasKey( 'FOO', $data['entities'] );
417
	}
418
419
	public function provideTestAddEntityRevisionFallback() {
420
		$expected = [
421
			'entities' => [
422
				'Q123101' => [
423
					'id' => 'Q123101',
424
					'type' => 'item',
425
					'labels' => [
426
						'de-formal' => [
427
							'language' => 'de',
428
							'value' => 'Oslo-de',
429
							'for-language' => 'de-formal'
430
						],
431
						'es' => [
432
							'language' => 'en',
433
							'value' => 'Oslo-en',
434
							'for-language' => 'es',
435
						],
436
						'qug' => [
437
							'language' => 'en',
438
							'value' => 'Oslo-en',
439
							'for-language' => 'qug'
440
						],
441
						'zh-my' => [
442
							'language' => 'en',
443
							'value' => 'Oslo-en',
444
							'for-language' => 'zh-my'
445
						],
446
						'_element' => 'label',
447
						'_type' => 'kvp',
448
						'_kvpkeyname' => 'language',
449
						'_kvpmerge' => true,
450
					],
451
					'descriptions' => [
452
						'es' => [
453
							'language' => 'es',
454
							'value' => 'desc-es',
455
						],
456
						'qug' => [
457
							'language' => 'es',
458
							'value' => 'desc-es',
459
							'for-language' => 'qug'
460
						],
461
						'zh-my' => [
462
							'language' => 'zh-my',
463
							'value' => 'desc-zh-sg',
464
							'source-language' => 'zh-sg',
465
						],
466
						'_element' => 'description',
467
						'_type' => 'kvp',
468
						'_kvpkeyname' => 'language',
469
						'_kvpmerge' => true,
470
					],
471
				],
472
				'_element' => 'entity',
473
				'_type' => 'kvp',
474
				'_kvpkeyname' => 'id',
475
				'_kvpmerge' => true,
476
			],
477
			'_type' => 'assoc',
478
		];
479
480
		$expectedNoMetaData = $this->removeMetaData( $expected );
481
		// The api always starts with this
482
		$expectedNoMetaData['_type'] = 'assoc';
483
484
		return [
485
			[ false, $expectedNoMetaData ],
486
			[ true, $expected ],
487
		];
488
	}
489
490
	/**
491
	 * @dataProvider provideTestAddEntityRevisionFallback
492
	 */
493
	public function testAddEntityRevisionFallback( $addMetaData, array $expected ) {
494
		$item = new Item( new ItemId( 'Q123101' ) );
495
		$item->getFingerprint()->setLabel( 'de', 'Oslo-de' );
496
		$item->getFingerprint()->setLabel( 'en', 'Oslo-en' );
497
		$item->getFingerprint()->setDescription( 'es', 'desc-es' );
498
		$item->getFingerprint()->setDescription( 'zh-sg', 'desc-zh-sg' );
499
		$entityRevision = new EntityRevision( $item );
500
501
		$fallbackChainFactory = new LanguageFallbackChainFactory();
502
		$fallbackMode = LanguageFallbackChainFactory::FALLBACK_ALL;
503
		$fallbackChains = [
504
			'de-formal' => $fallbackChainFactory->newFromLanguageCode( 'de-formal', $fallbackMode ),
505
			'es' => $fallbackChainFactory->newFromLanguageCode( 'es', $fallbackMode ),
506
			'qug' => $fallbackChainFactory->newFromLanguageCode( 'qug', $fallbackMode ),
507
			'zh-my' => $fallbackChainFactory->newFromLanguageCode( 'zh-my', $fallbackMode ),
508
		];
509
		$filterLangCodes = array_keys( $fallbackChains );
510
511
		$result = $this->getDefaultResult();
512
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
513
		$resultBuilder->addEntityRevision(
514
			null,
515
			$entityRevision,
516
			[ 'labels', 'descriptions' ],
517
			[],
518
			$filterLangCodes,
519
			$fallbackChains
520
		);
521
522
		$data = $result->getResultData();
523
524
		$this->assertEquals( $expected, $data );
525
	}
526
527
	public function testAddEntityRevisionWithLanguagesFilter() {
528
		$item = new Item( new ItemId( 'Q123099' ) );
529
		$item->setLabel( 'en', 'text' );
530
		$item->setLabel( 'de', 'text' );
531
		$item->setDescription( 'en', 'text' );
532
		$item->setDescription( 'de', 'text' );
533
		$item->setAliases( 'en', [ 'text' ] );
534
		$item->setAliases( 'de', [ 'text' ] );
535
		$entityRevision = new EntityRevision( $item );
536
537
		$result = $this->getDefaultResult();
538
		$resultBuilder = $this->getResultBuilder( $result );
539
		$resultBuilder->addEntityRevision(
540
			null,
541
			$entityRevision,
542
			[ 'labels', 'descriptions', 'aliases' ],
543
			[],
544
			[ 'de' ]
545
		);
546
547
		$expected = [
548
			'entities' => [
549
				'Q123099' => [
550
					'id' => 'Q123099',
551
					'type' => 'item',
552
					'labels' => [
553
						'de' => [
554
							'language' => 'de',
555
							'value' => 'text',
556
						],
557
					],
558
					'descriptions' => [
559
						'de' => [
560
							'language' => 'de',
561
							'value' => 'text',
562
						],
563
					],
564
					'aliases' => [
565
						'de' => [
566
							[
567
								'language' => 'de',
568
								'value' => 'text',
569
							],
570
						],
571
					],
572
				],
573
			],
574
			// This meta data element is always present in ApiResult
575
			'_type' => 'assoc',
576
		];
577
578
		$data = $result->getResultData();
579
580
		$this->assertEquals( $expected, $data );
581
	}
582
583
	public function testAddEntityRevisionWithSiteLinksFilter() {
584
		$item = new Item( new ItemId( 'Q123099' ) );
585
		$item->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Berlin' );
586
		$item->getSiteLinkList()->addNewSiteLink( 'dewiki', 'Berlin' );
587
		$entityRevision = new EntityRevision( $item );
588
589
		$props = [ 'sitelinks' ];
590
		$siteIds = [ 'enwiki' ];
591
592
		$result = $this->getDefaultResult();
593
		$resultBuilder = $this->getResultBuilder( $result );
594
		$resultBuilder->addEntityRevision( null, $entityRevision, $props, $siteIds );
595
596
		$expected = [
597
			'entities' => [
598
				'Q123099' => [
599
					'id' => 'Q123099',
600
					'type' => 'item',
601
					'sitelinks' => [
602
						'enwiki' => [
603
							'site' => 'enwiki',
604
							'title' => 'Berlin',
605
							'badges' => [],
606
						],
607
					],
608
				],
609
			],
610
			// This meta data element is always present in ApiResult
611
			'_type' => 'assoc',
612
		];
613
614
		$data = $result->getResultData();
615
616
		$this->assertEquals( $expected, $data );
617
	}
618
619
	/**
620
	 * @see https://phabricator.wikimedia.org/T68181
621
	 */
622
	public function testAddEntityRevisionInIndexedModeWithSiteLinksFilter() {
623
		$item = new Item( new ItemId( 'Q123100' ) );
624
		$item->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Berlin' );
625
		$item->getSiteLinkList()->addNewSiteLink( 'dewiki', 'Berlin' );
626
		$entityRevision = new EntityRevision( $item );
627
628
		$props = [ 'sitelinks' ];
629
		$siteIds = [ 'enwiki' ];
630
631
		$result = $this->getDefaultResult();
632
		$resultBuilder = $this->getResultBuilder( $result, true );
633
		$resultBuilder->addEntityRevision( null, $entityRevision, $props, $siteIds );
634
635
		$expected = [
636
			'entities' => [
637
				'Q123100' => [
638
					'id' => 'Q123100',
639
					'type' => 'item',
640
					'sitelinks' => [
641
						'enwiki' => [
642
							'site' => 'enwiki',
643
							'title' => 'Berlin',
644
							'badges' => [
645
								'_element' => 'badge',
646
							],
647
						],
648
						'_element' => 'sitelink',
649
						'_type' => 'kvp',
650
						'_kvpkeyname' => 'site',
651
						'_kvpmerge' => true,
652
					],
653
				],
654
				'_element' => 'entity',
655
				'_type' => 'kvp',
656
				'_kvpkeyname' => 'id',
657
				'_kvpmerge' => true,
658
			],
659
			'_type' => 'assoc',
660
		];
661
662
		$data = $result->getResultData();
663
664
		$this->assertEquals( $expected, $data );
665
	}
666
667
	public function testAddBasicEntityInformation() {
668
		$result = $this->getDefaultResult();
669
		$entityId = new ItemId( 'Q67' );
670
		$expected = [
671
			'entity' => [
672
				'id' => 'Q67',
673
				'type' => 'item',
674
			],
675
			'_type' => 'assoc',
676
		];
677
678
		$resultBuilder = $this->getResultBuilder( $result );
679
		$resultBuilder->addBasicEntityInformation( $entityId, 'entity' );
680
681
		$data = $result->getResultData();
682
683
		$this->assertEquals( $expected, $data );
684
	}
685
686
	public function testAddLabels() {
687
		$result = $this->getDefaultResult();
688
		$labels = new TermList( [
689
			new Term( 'en', 'foo' ),
690
			new Term( 'de', 'bar' ),
691
		] );
692
		$path = [ 'entities', 'Q1' ];
693
		$expected = [
694
			'entities' => [
695
				'Q1' => [
696
					'labels' => [
697
						'en' => [
698
							'language' => 'en',
699
							'value' => 'foo',
700
						],
701
						'de' => [
702
							'language' => 'de',
703
							'value' => 'bar',
704
						],
705
					],
706
				],
707
			],
708
			'_type' => 'assoc',
709
		];
710
711
		$resultBuilder = $this->getResultBuilder( $result );
712
		$resultBuilder->addLabels( $labels, $path );
713
714
		$data = $result->getResultData();
715
716
		$this->assertEquals( $expected, $data );
717
	}
718
719
	public function testAddRemovedLabel() {
720
		$result = $this->getDefaultResult();
721
		$path = [ 'entities', 'Q1' ];
722
		$expected = [
723
			'entities' => [
724
				'Q1' => [
725
					'labels' => [
726
						'en' => [
727
							'language' => 'en',
728
							'removed' => '',
729
						],
730
					],
731
				],
732
			],
733
			'_type' => 'assoc',
734
		];
735
736
		$resultBuilder = $this->getResultBuilder( $result );
737
		$resultBuilder->addRemovedLabel( 'en', $path );
738
739
		$data = $result->getResultData();
740
741
		$this->assertEquals( $expected, $data );
742
	}
743
744
	public function testAddDescriptions() {
745
		$result = $this->getDefaultResult();
746
		$descriptions = new TermList( [
747
			new Term( 'en', 'foo' ),
748
			new Term( 'de', 'bar' ),
749
		] );
750
		$path = [ 'entities', 'Q1' ];
751
		$expected = [
752
			'entities' => [
753
				'Q1' => [
754
					'descriptions' => [
755
						'en' => [
756
							'language' => 'en',
757
							'value' => 'foo',
758
						],
759
						'de' => [
760
							'language' => 'de',
761
							'value' => 'bar',
762
						],
763
					],
764
				],
765
			],
766
			'_type' => 'assoc',
767
		];
768
769
		$resultBuilder = $this->getResultBuilder( $result );
770
		$resultBuilder->addDescriptions( $descriptions, $path );
771
772
		$data = $result->getResultData();
773
774
		$this->assertEquals( $expected, $data );
775
	}
776
777
	public function testAddRemovedDescription() {
778
		$result = $this->getDefaultResult();
779
		$path = [ 'entities', 'Q1' ];
780
		$expected = [
781
			'entities' => [
782
				'Q1' => [
783
					'descriptions' => [
784
						'en' => [
785
							'language' => 'en',
786
							'removed' => '',
787
						],
788
					],
789
				],
790
			],
791
			'_type' => 'assoc',
792
		];
793
794
		$resultBuilder = $this->getResultBuilder( $result );
795
		$resultBuilder->addRemovedDescription( 'en', $path );
796
797
		$data = $result->getResultData();
798
799
		$this->assertEquals( $expected, $data );
800
	}
801
802
	public function provideAddAliasGroupList() {
803
		$expected = [
804
			'entities' => [
805
				'Q1' => [
806
					'aliases' => [
807
						'en' => [
808
							[
809
								'language' => 'en',
810
								'value' => 'boo',
811
							],
812
							[
813
								'language' => 'en',
814
								'value' => 'hoo',
815
							],
816
							'_element' => 'alias',
817
						],
818
						'de' => [
819
							[
820
								'language' => 'de',
821
								'value' => 'ham',
822
							],
823
							[
824
								'language' => 'de',
825
								'value' => 'cheese',
826
							],
827
							'_element' => 'alias',
828
						],
829
						'_element' => 'language',
830
						'_type' => 'kvp',
831
						'_kvpkeyname' => 'id',
832
					],
833
				],
834
			],
835
			'_type' => 'assoc',
836
		];
837
838
		$expectedNoMetaData = $this->removeMetaData( $expected );
839
		// The api always starts with this
840
		$expectedNoMetaData['_type'] = 'assoc';
841
842
		return [
843
			[ false, $expectedNoMetaData ],
844
			[ true, $expected ],
845
		];
846
	}
847
848
	/**
849
	 * @dataProvider provideAddAliasGroupList
850
	 */
851
	public function testAddAliasGroupList( $metaData, array $expected ) {
852
		$result = $this->getDefaultResult();
853
		$aliasGroupList = new AliasGroupList(
854
			[
855
				new AliasGroup( 'en', [ 'boo', 'hoo' ] ),
856
				new AliasGroup( 'de', [ 'ham', 'cheese' ] ),
857
			]
858
		);
859
		$path = [ 'entities', 'Q1' ];
860
861
		$resultBuilder = $this->getResultBuilder( $result, $metaData );
862
		$resultBuilder->addAliasGroupList( $aliasGroupList, $path );
863
864
		$data = $result->getResultData();
865
866
		$this->assertEquals( $expected, $data );
867
	}
868
869
	public function provideAddSiteLinkList() {
870
		$expected = [
871
			'entities' => [
872
				'Q1' => [
873
					'sitelinks' => [
874
						'enwiki' => [
875
							'site' => 'enwiki',
876
							'title' => 'User:Addshore',
877
							'badges' => [ '_element' => 'badge' ],
878
						],
879
						'dewikivoyage' => [
880
							'site' => 'dewikivoyage',
881
							'title' => 'Berlin',
882
							'badges' => [ '_element' => 'badge' ],
883
						],
884
						'_element' => 'sitelink',
885
						'_type' => 'kvp',
886
						'_kvpkeyname' => 'site',
887
						'_kvpmerge' => true,
888
					],
889
				],
890
			],
891
			'_type' => 'assoc',
892
		];
893
894
		$expectedNoMetaData = $this->removeMetaData( $expected );
895
		// The api always starts with this
896
		$expectedNoMetaData['_type'] = 'assoc';
897
898
		return [
899
			[ false, $expectedNoMetaData ],
900
			[ true, $expected ],
901
		];
902
	}
903
904
	/**
905
	 * @dataProvider provideAddSiteLinkList
906
	 */
907
	public function testAddSiteLinkList( $addMetaData, array $expected ) {
908
		$result = $this->getDefaultResult();
909
		$siteLinkList = new SiteLinkList(
910
			[
911
				new SiteLink( 'enwiki', 'User:Addshore' ),
912
				new SiteLink( 'dewikivoyage', 'Berlin' ),
913
			]
914
		);
915
		$path = [ 'entities', 'Q1' ];
916
917
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
918
		$resultBuilder->addSiteLinkList( $siteLinkList, $path );
919
920
		$data = $result->getResultData();
921
922
		$this->assertEquals( $expected, $data );
923
	}
924
925
	public function testAddRemovedSiteLinks() {
926
		//TODO test with metadata....
927
		$result = $this->getDefaultResult();
928
		$siteLinkList = new SiteLinkList( [
929
			new SiteLink( 'enwiki', 'User:Addshore' ),
930
			new SiteLink( 'dewikivoyage', 'Berlin' ),
931
		] );
932
		$path = [ 'entities', 'Q1' ];
933
		$expected = [
934
			'entities' => [
935
				'Q1' => [
936
					'sitelinks' => [
937
						'enwiki' => [
938
							'site' => 'enwiki',
939
							'title' => 'User:Addshore',
940
							'removed' => '',
941
							'badges' => [],
942
						],
943
						'dewikivoyage' => [
944
							'site' => 'dewikivoyage',
945
							'title' => 'Berlin',
946
							'removed' => '',
947
							'badges' => [],
948
						],
949
					],
950
				],
951
			],
952
			'_type' => 'assoc',
953
		];
954
955
		$resultBuilder = $this->getResultBuilder( $result );
956
		$resultBuilder->addRemovedSiteLinks( $siteLinkList, $path );
957
958
		$data = $result->getResultData();
959
960
		$this->assertEquals( $expected, $data );
961
	}
962
963
	public function testAddAndRemoveSiteLinks() {
964
		$result = $this->getDefaultResult();
965
		$siteLinkListAdd = new SiteLinkList(
966
			[
967
				new SiteLink( 'enwiki', 'User:Addshore' ),
968
				new SiteLink( 'dewikivoyage', 'Berlin' ),
969
			]
970
		);
971
		$siteLinkListRemove = new SiteLinkList( [
972
			new SiteLink( 'ptwiki', 'Port' ),
973
			new SiteLink( 'dewiki', 'Gin' ),
974
		] );
975
		$path = [ 'entities', 'Q1' ];
976
		$expected = [
977
			'entities' => [
978
				'Q1' => [
979
					'sitelinks' => [
980
						'enwiki' => [
981
							'site' => 'enwiki',
982
							'title' => 'User:Addshore',
983
							'badges' => [],
984
						],
985
						'dewikivoyage' => [
986
							'site' => 'dewikivoyage',
987
							'title' => 'Berlin',
988
							'badges' => [],
989
						],
990
						'ptwiki' => [
991
							'site' => 'ptwiki',
992
							'title' => 'Port',
993
							'removed' => '',
994
							'badges' => [],
995
						],
996
						'dewiki' => [
997
							'site' => 'dewiki',
998
							'title' => 'Gin',
999
							'removed' => '',
1000
							'badges' => [],
1001
						],
1002
					],
1003
				],
1004
			],
1005
			'_type' => 'assoc',
1006
		];
1007
1008
		$resultBuilder = $this->getResultBuilder( $result );
1009
		$resultBuilder->addSiteLinkList( $siteLinkListAdd, $path );
1010
		$resultBuilder->addRemovedSiteLinks( $siteLinkListRemove, $path );
1011
1012
		$data = $result->getResultData();
1013
1014
		$this->assertEquals( $expected, $data );
1015
	}
1016
1017
	/**
1018
	 * @dataProvider statementSerializationProvider
1019
	 */
1020
	public function testAddStatements( Statement $statement, $addMetaData, array $statementSerialization ) {
1021
		$result = $this->getDefaultResult();
1022
		$path = [ 'entities', 'Q1' ];
1023
1024
		$expected = [
1025
			'entities' => [
1026
				'Q1' => [
1027
					'claims' => [
1028
						'P12' => [
1029
							$statementSerialization,
1030
							'_element' => 'claim',
1031
						],
1032
						'_element' => 'property',
1033
						'_type' => 'kvp',
1034
						'_kvpkeyname' => 'id',
1035
					],
1036
				],
1037
			],
1038
			'_type' => 'assoc',
1039
		];
1040
1041
		if ( !$addMetaData ) {
1042
			$expected = $this->removeMetaData( $expected );
1043
			$expected['_type'] = 'assoc';
1044
		}
1045
1046
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
1047
		$resultBuilder->addStatements( new StatementList( $statement ), $path );
1048
1049
		$data = $result->getResultData();
1050
1051
		$this->assertEquals( $expected, $data );
1052
	}
1053
1054
	public function testAddStatementsNoProps() {
1055
		$result = $this->getDefaultResult();
1056
		$path = [ 'entities', 'Q1' ];
1057
1058
		$statement = new Statement(
1059
			new PropertySomeValueSnak( new PropertyId( 'P12' ) ),
1060
			null,
1061
			new Referencelist( [
1062
				new Reference( [
1063
					new PropertyValueSnak( new PropertyId( 'P12' ), new StringValue( 'refSnakVal' ) ),
1064
				] ),
1065
			] ),
1066
			'fooguidbar'
1067
		);
1068
1069
		$expected = [
1070
			'entities' => [
1071
				'Q1' => [
1072
					'claims' => [
1073
						'P12' => [
1074
							[
1075
								'id' => 'fooguidbar',
1076
								'mainsnak' => [
1077
									'snaktype' => 'somevalue',
1078
									'property' => 'P12',
1079
									'datatype' => 'DtIdFor_P12',
1080
								],
1081
								'type' => 'statement',
1082
								'rank' => 'normal',
1083
							],
1084
						],
1085
					],
1086
				],
1087
			],
1088
			'_type' => 'assoc',
1089
		];
1090
1091
		$props = [];
1092
1093
		$resultBuilder = $this->getResultBuilder( $result );
1094
		$resultBuilder->addStatements( new StatementList( $statement ), $path, $props );
1095
1096
		$data = $result->getResultData();
1097
1098
		$this->assertEquals( $expected, $data );
1099
	}
1100
1101
	/**
1102
	 * @dataProvider statementSerializationProvider
1103
	 */
1104
	public function testAddStatement( Statement $statement, $addMetaData, array $statementSerialization ) {
1105
		$result = $this->getDefaultResult();
1106
		$expected = [
1107
			'claim' => $statementSerialization,
1108
			'_type' => 'assoc',
1109
		];
1110
1111
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
1112
		$resultBuilder->addStatement( $statement );
1113
1114
		$data = $result->getResultData();
1115
1116
		$this->assertEquals( $expected, $data );
1117
	}
1118
1119
	public function statementSerializationProvider() {
1120
		$statement = new Statement(
1121
			new PropertyValueSnak( new PropertyId( 'P12' ), new StringValue( 'stringVal' ) ),
1122
			new SnakList( [
1123
				new PropertyValueSnak( new PropertyId( 'P12' ), new StringValue( 'qualiferVal' ) ),
1124
			] ),
1125
			new Referencelist( [
1126
				new Reference( [
1127
					new PropertyValueSnak( new PropertyId( 'P12' ), new StringValue( 'refSnakVal' ) ),
1128
				] ),
1129
			] ),
1130
			'fooguidbar'
1131
		);
1132
1133
		$expected = [
1134
			'id' => 'fooguidbar',
1135
			'mainsnak' => [
1136
				'snaktype' => 'value',
1137
				'property' => 'P12',
1138
				'datavalue' => [
1139
					'value' => 'stringVal',
1140
					'type' => 'string',
1141
				],
1142
				'datatype' => 'DtIdFor_P12',
1143
			],
1144
			'type' => 'statement',
1145
			'rank' => 'normal',
1146
			'qualifiers-order' => [
1147
				'P12',
1148
				'_element' => 'property',
1149
			],
1150
			'references' => [
1151
				[
1152
					'hash' => '4db26028db87a994581ef9cd832e60635321bca9',
1153
					'snaks' => [
1154
						'P12' => [
1155
							[
1156
								'snaktype' => 'value',
1157
								'property' => 'P12',
1158
								'datatype' => 'DtIdFor_P12',
1159
								'datavalue' => [
1160
									'value' => 'refSnakVal',
1161
									'type' => 'string',
1162
								],
1163
							],
1164
							'_element' => 'snak',
1165
						],
1166
						'_element' => 'property',
1167
						'_type' => 'kvp',
1168
						'_kvpkeyname' => 'id',
1169
					],
1170
					'snaks-order' => [
1171
						'P12',
1172
						'_element' => 'property',
1173
					],
1174
				],
1175
				'_element' => 'reference',
1176
			],
1177
			'qualifiers' => [
1178
				'P12' => [
1179
					[
1180
						'snaktype' => 'value',
1181
						'property' => 'P12',
1182
						'datatype' => 'DtIdFor_P12',
1183
						'datavalue' => [
1184
							'value' => 'qualiferVal',
1185
							'type' => 'string',
1186
						],
1187
						'hash' => '16c37f4d851c37f7495a31ebc539e52227918a5e',
1188
					],
1189
					'_element' => 'qualifiers',
1190
				],
1191
				'_element' => 'property',
1192
				'_type' => 'kvp',
1193
				'_kvpkeyname' => 'id',
1194
			],
1195
		];
1196
1197
		$expectedNoMetaData = $this->removeMetaData( $expected );
1198
1199
		return [
1200
			[ $statement, false, $expectedNoMetaData ],
1201
			[ $statement, true, $expected ],
1202
		];
1203
	}
1204
1205
	public function provideAddReference() {
1206
		$expected = [
1207
			'reference' => [
1208
				'hash' => '27ff8ea8cc011639f959481465c175fe7f07ecbd',
1209
				'snaks' => [
1210
					'P12' => [
1211
						[
1212
							'snaktype' => 'value',
1213
							'property' => 'P12',
1214
							'datavalue' => [
1215
								'value' => 'stringVal',
1216
								'type' => 'string',
1217
							],
1218
							'datatype' => 'DtIdFor_P12',
1219
						],
1220
						'_element' => 'snak',
1221
					],
1222
					'_element' => 'property',
1223
					'_type' => 'kvp',
1224
					'_kvpkeyname' => 'id',
1225
				],
1226
				'snaks-order' => [
1227
					'P12',
1228
					'_element' => 'property',
1229
				],
1230
			],
1231
			'_type' => 'assoc',
1232
		];
1233
1234
		$expectedNoMetaData = $this->removeMetaData( $expected );
1235
		// The api always starts with this
1236
		$expectedNoMetaData['_type'] = 'assoc';
1237
1238
		return [
1239
			[ false, $expectedNoMetaData ],
1240
			[ true, $expected ],
1241
		];
1242
	}
1243
1244
	/**
1245
	 * @dataProvider provideAddReference
1246
	 */
1247
	public function testAddReference( $addMetaData, array $expected ) {
1248
		$result = $this->getDefaultResult();
1249
		$reference = new Reference(
1250
			new SnakList( [
1251
				new PropertyValueSnak( new PropertyId( 'P12' ), new StringValue( 'stringVal' ) )
1252
			] )
1253
		);
1254
1255
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
1256
		$resultBuilder->addReference( $reference );
1257
1258
		$data = $result->getResultData();
1259
1260
		$this->assertEquals( $expected, $data );
1261
	}
1262
1263
	/**
1264
	 * @dataProvider provideMissingEntity
1265
	 */
1266
	public function testAddMissingEntityWithMetaData( array $missingEntities, array $expected ) {
1267
		$result = $this->getDefaultResult();
1268
		$resultBuilder = $this->getResultBuilder( $result, true );
1269
1270
		foreach ( $missingEntities as $key => $missingDetails ) {
1271
			if ( is_int( $key ) ) {
1272
				// string keys are kept for use in the result structure, integer keys aren't
1273
				$key = null;
1274
			}
1275
1276
			$resultBuilder->addMissingEntity( $key, $missingDetails );
1277
		}
1278
1279
		$data = $result->getResultData();
1280
1281
		$this->assertEquals( $expected, $data );
1282
	}
1283
1284
	public function provideMissingEntity() {
1285
		return [
1286
			[
1287
				[
1288
					[ 'site' => 'enwiki', 'title' => 'Berlin' ],
1289
				],
1290
				[
1291
					'entities' => [
1292
						'-1' => [
1293
							'site' => 'enwiki',
1294
							'title' => 'Berlin',
1295
							'missing' => '',
1296
						],
1297
						'_element' => 'entity',
1298
						'_type' => 'kvp',
1299
						'_kvpkeyname' => 'id',
1300
						'_kvpmerge' => true,
1301
					],
1302
					'_type' => 'assoc',
1303
				]
1304
			],
1305
			[
1306
				[
1307
					[ 'id' => 'Q77' ],
1308
				],
1309
				[
1310
					'entities' => [
1311
						'Q77' => [
1312
							'id' => 'Q77',
1313
							'missing' => '',
1314
						],
1315
						'_element' => 'entity',
1316
						'_type' => 'kvp',
1317
						'_kvpkeyname' => 'id',
1318
						'_kvpmerge' => true,
1319
					],
1320
					'_type' => 'assoc',
1321
				]
1322
			],
1323
			[
1324
				[
1325
					'Q77' => [ 'foo' => 'bar' ],
1326
				],
1327
				[
1328
					'entities' => [
1329
						'Q77' => [
1330
							'foo' => 'bar',
1331
							'missing' => '',
1332
						],
1333
						'_element' => 'entity',
1334
						'_type' => 'kvp',
1335
						'_kvpkeyname' => 'id',
1336
						'_kvpmerge' => true,
1337
					],
1338
					'_type' => 'assoc',
1339
				]
1340
			],
1341
			[
1342
				[
1343
					[ 'site' => 'enwiki', 'title' => 'Berlin' ],
1344
					[ 'site' => 'dewiki', 'title' => 'Foo' ],
1345
				],
1346
				[
1347
					'entities' => [
1348
						'-1' => [
1349
							'site' => 'enwiki',
1350
							'title' => 'Berlin',
1351
							'missing' => '',
1352
						],
1353
						'-2' => [
1354
							'site' => 'dewiki',
1355
							'title' => 'Foo',
1356
							'missing' => '',
1357
						],
1358
						'_element' => 'entity',
1359
						'_type' => 'kvp',
1360
						'_kvpkeyname' => 'id',
1361
						'_kvpmerge' => true,
1362
					],
1363
					'_type' => 'assoc',
1364
				]
1365
			],
1366
		];
1367
	}
1368
1369
	public function testAddNormalizedTitle() {
1370
		$result = $this->getDefaultResult();
1371
		$from = 'berlin';
1372
		$to = 'Berlin';
1373
		$expected = [
1374
			'normalized' => [
1375
				'n' => [
1376
					'from' => 'berlin',
1377
					'to' => 'Berlin'
1378
				],
1379
			],
1380
			'_type' => 'assoc',
1381
		];
1382
1383
		$resultBuilder = $this->getResultBuilder( $result );
1384
		$resultBuilder->addNormalizedTitle( $from, $to );
1385
1386
		$data = $result->getResultData();
1387
1388
		$this->assertEquals( $expected, $data );
1389
	}
1390
1391
	public function testAddRevisionIdFromStatusToResult() {
1392
		$result = $this->getDefaultResult();
1393
		$mockRevision = $this->getMockBuilder( EntityRevision::class )
1394
			->disableOriginalConstructor()
1395
			->getMock();
1396
		$mockRevision->expects( $this->once() )
1397
			->method( 'getRevisionId' )
1398
			->will( $this->returnValue( 123 ) );
1399
		$mockStatus = $this->createMock( Status::class );
1400
		$mockStatus->expects( $this->once() )
1401
			->method( 'getValue' )
1402
			->will( $this->returnValue( [ 'revision' => $mockRevision ] ) );
1403
		$expected = [
1404
			'entity' => [ 'lastrevid' => '123' ],
1405
			'_type' => 'assoc',
1406
		];
1407
1408
		$resultBuilder = $this->getResultBuilder( $result );
1409
		$resultBuilder->addRevisionIdFromStatusToResult( $mockStatus, 'entity' );
1410
1411
		$data = $result->getResultData();
1412
1413
		$this->assertEquals( $expected, $data );
1414
	}
1415
1416
	public function provideSetList() {
1417
		return [
1418
			'null path' => [ null, 'foo', [], 'letter', false,
1419
				[ 'foo' => [], '_type' => 'assoc' ]
1420
			],
1421
			'empty path' => [ [], 'foo', [ 'x', 'y' ], 'letter', false,
1422
				[
1423
					'foo' => [ 'x', 'y' ], '_type' => 'assoc'
1424
				]
1425
			],
1426
			'string path' => [ 'ROOT', 'foo', [ 'x', 'y' ], 'letter', false,
1427
				[
1428
					'ROOT' => [
1429
						'foo' => [ 'x', 'y' ]
1430
					],
1431
					'_type' => 'assoc',
1432
				]
1433
			],
1434
			'actual path' => [ [ 'one', 'two' ], 'foo', [ 'X' => 'x', 'Y' => 'y' ], 'letter', false,
1435
				[
1436
					'one' => [
1437
						'two' => [
1438
							'foo' => [ 'X' => 'x', 'Y' => 'y' ]
1439
						]
1440
					],
1441
					'_type' => 'assoc',
1442
				]
1443
			],
1444
			'indexed' => [ 'ROOT', 'foo', [ 'X' => 'x', 'Y' => 'y' ], 'letter', true,
1445
				[
1446
					'ROOT' => [
1447
						'foo' => [ 'X' => 'x', 'Y' => 'y', '_element' => 'letter', '_type' => 'array' ],
1448
					],
1449
					'_type' => 'assoc',
1450
				],
1451
			],
1452
			'pre-set element name' => [ 'ROOT', 'foo', [ 'x', 'y', '_element' => '_thingy' ], 'letter', true,
1453
				[
1454
					'ROOT' => [
1455
						'foo' => [ 'x', 'y', '_element' => '_thingy', '_type' => 'array' ]
1456
					],
1457
					'_type' => 'assoc',
1458
				]
1459
			],
1460
		];
1461
	}
1462
1463
	/**
1464
	 * @dataProvider provideSetList
1465
	 */
1466
	public function testSetList( $path, $name, array $values, $tag, $addMetaData, array $expected ) {
1467
		$result = $this->getDefaultResult();
1468
		$builder = $this->getResultBuilder( $result, $addMetaData );
1469
1470
		$builder->setList( $path, $name, $values, $tag );
1471
		$data = $result->getResultData();
1472
1473
		$this->assertEquals( $expected, $data );
1474
	}
1475
1476
	public function provideSetList_InvalidArgument() {
1477
		return [
1478
			'null name' => [ 'ROOT', null, [ 10, 20 ], 'Q' ],
1479
			'int name' => [ 'ROOT', 6, [ 10, 20 ], 'Q' ],
1480
			'array name' => [ 'ROOT', [ 'x' ], [ 10, 20 ], 'Q' ],
1481
1482
			'null tag' => [ 'ROOT', 'foo', [ 10, 20 ], null ],
1483
			'int tag' => [ 'ROOT', 'foo', [ 10, 20 ], 6 ],
1484
			'array tag' => [ 'ROOT', 'foo', [ 10, 20 ], [ 'x' ] ],
1485
		];
1486
	}
1487
1488
	/**
1489
	 * @dataProvider provideSetList_InvalidArgument
1490
	 */
1491
	public function testSetList_InvalidArgument( $path, $name, array $values, $tag ) {
1492
		$result = $this->getDefaultResult();
1493
		$builder = $this->getResultBuilder( $result );
1494
1495
		$this->expectException( InvalidArgumentException::class );
1496
		$builder->setList( $path, $name, $values, $tag );
1497
	}
1498
1499
	public function provideSetValue() {
1500
		return [
1501
			'null path' => [ null, 'foo', 'value', false, [ 'foo' => 'value', '_type' => 'assoc' ] ],
1502
			'empty path' => [ [], 'foo', 'value', false,
1503
				[
1504
					'foo' => 'value',
1505
					'_type' => 'assoc',
1506
				]
1507
			],
1508
			'string path' => [ 'ROOT', 'foo', 'value', false,
1509
				[
1510
					'ROOT' => [ 'foo' => 'value' ],
1511
					'_type' => 'assoc'
1512
				]
1513
			],
1514
			'actual path' => [ [ 'one', 'two' ], 'foo', [ 'X' => 'x', 'Y' => 'y' ], true,
1515
				[
1516
					'one' => [
1517
						'two' => [
1518
							'foo' => [ 'X' => 'x', 'Y' => 'y' ]
1519
						]
1520
					],
1521
					'_type' => 'assoc'
1522
				]
1523
			],
1524
			'indexed' => [ 'ROOT', 'foo', 'value', true,
1525
				[
1526
					'ROOT' => [ 'foo' => 'value' ],
1527
					'_type' => 'assoc'
1528
				]
1529
			],
1530
		];
1531
	}
1532
1533
	/**
1534
	 * @dataProvider provideSetValue
1535
	 */
1536
	public function testSetValue( $path, $name, $value, $addMetaData, array $expected ) {
1537
		$result = $this->getDefaultResult();
1538
		$builder = $this->getResultBuilder( $result, $addMetaData );
1539
1540
		$builder->setValue( $path, $name, $value );
1541
		$data = $result->getResultData();
1542
1543
		$this->assertEquals( $expected, $data );
1544
	}
1545
1546
	public function provideSetValue_InvalidArgument() {
1547
		return [
1548
			'null name' => [ 'ROOT', null, 'X' ],
1549
			'int name' => [ 'ROOT', 6, 'X' ],
1550
			'array name' => [ 'ROOT', [ 'x' ], 'X' ],
1551
1552
			'list value' => [ 'ROOT', 'foo', [ 10, 20 ] ],
1553
		];
1554
	}
1555
1556
	/**
1557
	 * @dataProvider provideSetValue_InvalidArgument
1558
	 */
1559
	public function testSetValue_InvalidArgument( $path, $name, $value ) {
1560
		$result = $this->getDefaultResult();
1561
		$builder = $this->getResultBuilder( $result );
1562
1563
		$this->expectException( InvalidArgumentException::class );
1564
		$builder->setValue( $path, $name, $value );
1565
	}
1566
1567
	public function provideAppendValue() {
1568
		return [
1569
			'null path' => [ null, null, 'value', 'letter', false,
1570
				[ 'value', '_type' => 'assoc' ],
1571
			],
1572
			'empty path' => [ [], null, 'value', 'letter', false,
1573
				[ 'value', '_type' => 'assoc' ]
1574
			],
1575
			'string path' => [ 'ROOT', null, 'value', 'letter', false,
1576
				[
1577
					'ROOT' => [ 'value' ],
1578
					'_type' => 'assoc'
1579
				]
1580
			],
1581
			'actual path' => [ [ 'one', 'two' ], null, [ 'X' => 'x', 'Y' => 'y' ], 'letter', false,
1582
				[
1583
					'one' => [
1584
						'two' => [ [ 'X' => 'x', 'Y' => 'y' ] ],
1585
					],
1586
					'_type' => 'assoc'
1587
				]
1588
			],
1589
			'int key' => [ 'ROOT', -2, 'value', 'letter', false,
1590
				[
1591
					'ROOT' => [ -2 => 'value' ],
1592
					'_type' => 'assoc',
1593
				]
1594
			],
1595
			'string key' => [ 'ROOT', 'Q7', 'value', 'letter', false,
1596
				[
1597
					'ROOT' => [ 'Q7' => 'value' ],
1598
					'_type' => 'assoc',
1599
				]
1600
			],
1601
			'null key indexed' => [ 'ROOT', null, 'value', 'letter', true,
1602
				[
1603
					'ROOT' => [ 'value', '_element' => 'letter' ],
1604
					'_type' => 'assoc',
1605
				]
1606
			],
1607
			'int key indexed' => [ 'ROOT', -2, 'value', 'letter', true,
1608
				[
1609
					'ROOT' => [ -2 => 'value', '_element' => 'letter' ],
1610
					'_type' => 'assoc',
1611
				]
1612
			],
1613
			'string key indexed' => [ 'ROOT', 'Q7', 'value', 'letter', true,
1614
				[
1615
					'ROOT' => [ 'Q7' => 'value', '_element' => 'letter' ],
1616
					'_type' => 'assoc',
1617
				]
1618
			],
1619
		];
1620
	}
1621
1622
	/**
1623
	 * @dataProvider provideAppendValue
1624
	 */
1625
	public function testAppendValue( $path, $key, $value, $tag, $addMetaData, array $expected ) {
1626
		$result = $this->getDefaultResult();
1627
		$builder = $this->getResultBuilder( $result, $addMetaData );
1628
1629
		$builder->appendValue( $path, $key, $value, $tag );
1630
		$data = $result->getResultData();
1631
1632
		$this->assertEquals( $expected, $data );
1633
	}
1634
1635
	public function provideAppendValue_InvalidArgument() {
1636
		return [
1637
			'list value' => [ 'ROOT', null, [ 1, 2, 3 ], 'Q' ],
1638
			'array key' => [ 'ROOT', [ 'x' ], 'value', 'Q' ],
1639
1640
			'null tag' => [ 'ROOT', 'foo', 'value', null ],
1641
			'int tag' => [ 'ROOT', 'foo', 'value', 6 ],
1642
			'array tag' => [ 'ROOT', 'foo', 'value', [ 'x' ] ],
1643
		];
1644
	}
1645
1646
	/**
1647
	 * @dataProvider provideAppendValue_InvalidArgument
1648
	 */
1649
	public function testAppendValue_InvalidArgument( $path, $key, $value, $tag ) {
1650
		$result = $this->getDefaultResult();
1651
		$builder = $this->getResultBuilder( $result );
1652
1653
		$this->expectException( InvalidArgumentException::class );
1654
		$builder->appendValue( $path, $key, $value, $tag );
1655
	}
1656
1657
	public function provideTestEmptyListsMetaData() {
1658
		$expected = [
1659
			'entities' => [
1660
				'Q123000' => [
1661
					'pageid' => 123, //mocked
1662
					'ns' => 456, //mocked
1663
					'title' => 'MockPrefixedText', //mocked
1664
					'lastrevid' => 33,
1665
					'modified' => '2013-11-26T20:29:23Z',
1666
					'type' => 'item',
1667
					'id' => 'Q123000',
1668
					'aliases' => [
1669
						'_element' => 'language',
1670
						'_type' => 'kvp',
1671
						'_kvpkeyname' => 'id'
1672
					],
1673
					'descriptions' => [
1674
						'_element' => 'description',
1675
						'_type' => 'kvp',
1676
						'_kvpkeyname' => 'language',
1677
						'_kvpmerge' => true
1678
					],
1679
					'labels' => [
1680
						'_element' => 'label',
1681
						'_type' => 'kvp',
1682
						'_kvpkeyname' => 'language',
1683
						'_kvpmerge' => true
1684
					],
1685
					'claims' => [
1686
						'_element' => 'property',
1687
						'_type' => 'kvp',
1688
						'_kvpkeyname' => 'id'
1689
					],
1690
					'sitelinks' => [
1691
						'_element' => 'sitelink',
1692
						'_type' => 'kvp',
1693
						'_kvpkeyname' => 'site',
1694
						'_kvpmerge' => true
1695
					],
1696
				],
1697
				'_element' => 'entity',
1698
				'_type' => 'kvp',
1699
				'_kvpkeyname' => 'id',
1700
				'_kvpmerge' => true,
1701
			],
1702
			'_type' => 'assoc',
1703
		];
1704
1705
		$expectedNoMetaData = $this->removeMetaData( $expected );
1706
		// The api always starts with this
1707
		$expectedNoMetaData['_type'] = 'assoc';
1708
1709
		return [
1710
			[ false, $expectedNoMetaData ],
1711
			[ true, $expected ],
1712
		];
1713
	}
1714
1715
	/**
1716
	 * @dataProvider provideTestEmptyListsMetaData
1717
	 */
1718
	public function testEmptyLists( $addMetaData, array $expected ) {
1719
		$result = $this->getDefaultResult();
1720
		$item = new Item( new ItemId( 'Q123000' ) );
1721
1722
		$entityRevision = new EntityRevision( $item, 33, '20131126202923' );
1723
1724
		$resultBuilder = $this->getResultBuilder( $result, $addMetaData );
1725
		$resultBuilder->addEntityRevision( 'Q123000', $entityRevision );
1726
1727
		$data = $result->getResultData();
1728
1729
		$this->assertEquals( $expected, $data );
1730
	}
1731
}
1732