Completed
Push — 7.x ( b1de80...30e315 )
by adam
19:03 queued 16:07
created

PropertyTest::aliasesProvider()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
1
<?php
2
3
namespace Wikibase\DataModel\Tests\Entity;
4
5
use InvalidArgumentException;
6
use PHPUnit_Framework_TestCase;
7
use Wikibase\DataModel\Entity\Property;
8
use Wikibase\DataModel\Entity\PropertyId;
9
use Wikibase\DataModel\Snak\PropertyNoValueSnak;
10
use Wikibase\DataModel\Snak\PropertySomeValueSnak;
11
use Wikibase\DataModel\Statement\Statement;
12
use Wikibase\DataModel\Statement\StatementList;
13
use Wikibase\DataModel\Term\AliasGroup;
14
use Wikibase\DataModel\Term\AliasGroupList;
15
use Wikibase\DataModel\Term\Fingerprint;
16
use Wikibase\DataModel\Term\Term;
17
use Wikibase\DataModel\Term\TermList;
18
19
/**
20
 * @covers Wikibase\DataModel\Entity\Property
21
 *
22
 * @group Wikibase
23
 * @group WikibaseDataModel
24
 *
25
 * @license GPL-2.0+
26
 * @author Jeroen De Dauw < [email protected] >
27
 */
28
class PropertyTest extends PHPUnit_Framework_TestCase {
29
30
	/**
31
	 * @return Property
32
	 */
33
	private function getNewEmpty() {
34
		return Property::newFromType( 'string' );
35
	}
36
37
	public function testConstructorWithAllParameters() {
38
		$property = new Property(
39
			new PropertyId( 'P42' ),
40
			new Fingerprint(),
41
			'string',
42
			new StatementList()
43
		);
44
		$this->assertInstanceOf( Property::class, $property );
45
		$this->assertEquals( new PropertyId( 'P42' ), $property->getId() );
46
		$this->assertEquals( new Fingerprint(), $property->getFingerprint() );
47
		$this->assertSame( 'string', $property->getDataTypeId() );
48
		$this->assertEquals( new StatementList(), $property->getStatements() );
49
	}
50
51
	public function testConstructorWithMinimalParameters() {
52
		$property = new Property( null, null, '' );
53
		$this->assertInstanceOf( Property::class, $property );
54
		$this->assertNull( $property->getId() );
55
		$this->assertEquals( new Fingerprint(), $property->getFingerprint() );
56
		$this->assertSame( '', $property->getDataTypeId() );
57
		$this->assertEquals( new StatementList(), $property->getStatements() );
58
	}
59
60
	/**
61
	 * @expectedException InvalidArgumentException
62
	 */
63
	public function testGivenInvalidType_ConstructorThrowsException() {
64
		new Property( null, null, null );
65
	}
66
67
	public function testNewFromType() {
68
		$property = Property::newFromType( 'string' );
69
		$this->assertInstanceOf( Property::class, $property );
70
		$this->assertSame( 'string', $property->getDataTypeId() );
71
	}
72
73
	public function testSetAndGetDataTypeId() {
74
		$property = Property::newFromType( 'string' );
75
76
		foreach ( [ 'string', 'foobar', 'nyan', 'string' ] as $typeId ) {
77
			$property->setDataTypeId( $typeId );
78
			$this->assertSame( $typeId, $property->getDataTypeId() );
79
		}
80
	}
81
82
	public function testWhenIdSetWithNumber_GetIdReturnsPropertyId() {
83
		$property = Property::newFromType( 'string' );
84
		$property->setId( 42 );
85
86
		$this->assertHasCorrectIdType( $property );
87
	}
88
89
	protected function assertHasCorrectIdType( Property $property ) {
90
		$this->assertInstanceOf( PropertyId::class, $property->getId() );
91
	}
92
93
	public function testWhenIdSetWithPropertyId_GetIdReturnsPropertyId() {
94
		$property = Property::newFromType( 'string' );
95
		$property->setId( new PropertyId( 'P42' ) );
96
97
		$this->assertHasCorrectIdType( $property );
98
	}
99
100
	public function testPropertyWithTypeIsEmpty() {
101
		$this->assertTrue( Property::newFromType( 'string' )->isEmpty() );
102
	}
103
104
	public function testPropertyWithIdIsEmpty() {
105
		$property = Property::newFromType( 'string' );
106
		$property->setId( 1337 );
107
		$this->assertTrue( $property->isEmpty() );
108
	}
109
110
	public function testPropertyWithFingerprintIsNotEmpty() {
111
		$property = Property::newFromType( 'string' );
112
		$property->setAliases( 'en', [ 'foo' ] );
113
		$this->assertFalse( $property->isEmpty() );
114
	}
115
116
	public function testGetStatementsReturnsEmptyListForEmptyProperty() {
117
		$property = Property::newFromType( 'string' );
118
119
		$this->assertEquals( new StatementList(), $property->getStatements() );
120
	}
121
122
	public function testSetAndGetStatements() {
123
		$property = Property::newFromType( 'string' );
124
125
		$statementList = $this->newNonEmptyStatementList();
126
		$property->setStatements( $statementList );
127
128
		$this->assertEquals( $statementList, $property->getStatements() );
129
	}
130
131
	private function newNonEmptyStatementList() {
132
		$statementList = new StatementList();
133
		$statementList->addNewStatement( new PropertyNoValueSnak( 42 ) );
134
		$statementList->addNewStatement( new PropertyNoValueSnak( 1337 ) );
135
136
		return $statementList;
137
	}
138
139
	public function equalsProvider() {
140
		$firstProperty = Property::newFromType( 'string' );
141
		$firstProperty->setStatements( $this->newNonEmptyStatementList() );
142
143
		$secondProperty = Property::newFromType( 'string' );
144
		$secondProperty->setStatements( $this->newNonEmptyStatementList() );
145
146
		$secondPropertyWithId = $secondProperty->copy();
147
		$secondPropertyWithId->setId( 42 );
148
149
		$differentId = $secondPropertyWithId->copy();
150
		$differentId->setId( 43 );
151
152
		return [
153
			[ Property::newFromType( 'string' ), Property::newFromType( 'string' ) ],
154
			[ $firstProperty, $secondProperty ],
155
			[ $secondProperty, $secondPropertyWithId ],
156
			[ $secondPropertyWithId, $differentId ],
157
		];
158
	}
159
160
	/**
161
	 * @dataProvider equalsProvider
162
	 */
163
	public function testEquals( Property $firstProperty, Property $secondProperty ) {
164
		$this->assertTrue( $firstProperty->equals( $secondProperty ) );
165
		$this->assertTrue( $secondProperty->equals( $firstProperty ) );
166
	}
167
168
	private function getBaseProperty() {
169
		$property = Property::newFromType( 'string' );
170
171
		$property->setId( 42 );
172
		$property->setLabel( 'en', 'Same' );
173
		$property->setDescription( 'en', 'Same' );
174
		$property->setAliases( 'en', [ 'Same' ] );
175
		$property->setStatements( $this->newNonEmptyStatementList() );
176
177
		return $property;
178
	}
179
180
	public function notEqualsProvider() {
181
		$differentLabel = $this->getBaseProperty();
182
		$differentLabel->setLabel( 'en', 'Different' );
183
184
		$differentDescription = $this->getBaseProperty();
185
		$differentDescription->setDescription( 'en', 'Different' );
186
187
		$differentAlias = $this->getBaseProperty();
188
		$differentAlias->setAliases( 'en', [ 'Different' ] );
189
190
		$differentStatement = $this->getBaseProperty();
191
		$differentStatement->setStatements( new StatementList() );
192
193
		$property = $this->getBaseProperty();
194
195
		return [
196
			'empty' => [ $property, Property::newFromType( 'string' ) ],
197
			'label' => [ $property, $differentLabel ],
198
			'description' => [ $property, $differentDescription ],
199
			'alias' => [ $property, $differentAlias ],
200
			'dataType' => [ Property::newFromType( 'string' ), Property::newFromType( 'foo' ) ],
201
			'statement' => [ $property, $differentStatement ],
202
		];
203
	}
204
205
	/**
206
	 * @dataProvider notEqualsProvider
207
	 */
208
	public function testNotEquals( Property $firstProperty, Property $secondProperty ) {
209
		$this->assertFalse( $firstProperty->equals( $secondProperty ) );
210
		$this->assertFalse( $secondProperty->equals( $firstProperty ) );
211
	}
212
213
	public function testPropertyWithStatementsIsNotEmpty() {
214
		$property = Property::newFromType( 'string' );
215
		$property->setStatements( $this->newNonEmptyStatementList() );
216
217
		$this->assertFalse( $property->isEmpty() );
218
	}
219
220
	public function cloneProvider() {
221
		$property = new Property( new PropertyId( 'P1' ), null, 'string' );
222
		$property->setLabel( 'en', 'original' );
223
		$property->getStatements()->addNewStatement( new PropertyNoValueSnak( 1 ) );
224
225
		return [
226
			'copy' => [ $property, $property->copy() ],
227
			'native clone' => [ $property, clone $property ],
228
		];
229
	}
230
231
	/**
232
	 * @dataProvider cloneProvider
233
	 */
234
	public function testCloneIsEqualButNotIdentical( Property $original, Property $clone ) {
235
		$this->assertNotSame( $original, $clone );
236
		$this->assertTrue( $original->equals( $clone ) );
237
		$this->assertSame(
238
			$original->getId(),
239
			$clone->getId(),
240
			'id is immutable and must not be cloned'
241
		);
242
243
		// The clone must not reference the same mutable objects
244
		$this->assertNotSame( $original->getFingerprint(), $clone->getFingerprint() );
245
		$this->assertNotSame( $original->getStatements(), $clone->getStatements() );
246
		$this->assertNotSame(
247
			$original->getStatements()->getFirstStatementWithGuid( null ),
248
			$clone->getStatements()->getFirstStatementWithGuid( null )
249
		);
250
	}
251
252
	/**
253
	 * @dataProvider cloneProvider
254
	 */
255
	public function testOriginalDoesNotChangeWithClone( Property $original, Property $clone ) {
256
		$originalStatement = $original->getStatements()->getFirstStatementWithGuid( null );
257
		$clonedStatement = $clone->getStatements()->getFirstStatementWithGuid( null );
258
259
		$clone->setLabel( 'en', 'clone' );
260
		$clone->setDescription( 'en', 'clone' );
261
		$clone->setAliases( 'en', [ 'clone' ] );
262
		$clonedStatement->setGuid( 'clone' );
263
		$clonedStatement->setMainSnak( new PropertySomeValueSnak( 666 ) );
264
		$clonedStatement->setRank( Statement::RANK_DEPRECATED );
265
		$clonedStatement->getQualifiers()->addSnak( new PropertyNoValueSnak( 1 ) );
266
		$clonedStatement->getReferences()->addNewReference( new PropertyNoValueSnak( 1 ) );
267
268
		$this->assertSame( 'original', $original->getLabels()->getByLanguage( 'en' )->getText() );
269
		$this->assertFalse( $original->getDescriptions()->hasTermForLanguage( 'en' ) );
270
		$this->assertFalse( $original->getAliasGroups()->hasGroupForLanguage( 'en' ) );
271
		$this->assertNull( $originalStatement->getGuid() );
272
		$this->assertSame( 'novalue', $originalStatement->getMainSnak()->getType() );
273
		$this->assertSame( Statement::RANK_NORMAL, $originalStatement->getRank() );
274
		$this->assertTrue( $originalStatement->getQualifiers()->isEmpty() );
275
		$this->assertTrue( $originalStatement->getReferences()->isEmpty() );
276
	}
277
278
	// Below are tests copied from EntityTest
279
280
	public function labelProvider() {
281
		return [
282
			[ 'en', 'spam' ],
283
			[ 'en', 'spam', 'spam' ],
284
			[ 'de', 'foo bar baz' ],
285
		];
286
	}
287
288
	/**
289
	 * @dataProvider labelProvider
290
	 * @param string $languageCode
291
	 * @param string $labelText
292
	 * @param string $moarText
293
	 */
294
	public function testSetLabel( $languageCode, $labelText, $moarText = 'ohi there' ) {
295
		$entity = $this->getNewEmpty();
296
297
		$entity->setLabel( $languageCode, $labelText );
298
299
		$this->assertSame( $labelText, $entity->getFingerprint()->getLabel( $languageCode )->getText() );
300
301
		$entity->setLabel( $languageCode, $moarText );
302
303
		$this->assertSame( $moarText, $entity->getFingerprint()->getLabel( $languageCode )->getText() );
304
	}
305
306
	public function descriptionProvider() {
307
		return [
308
			[ 'en', 'spam' ],
309
			[ 'en', 'spam', 'spam' ],
310
			[ 'de', 'foo bar baz' ],
311
		];
312
	}
313
314
	/**
315
	 * @dataProvider descriptionProvider
316
	 * @param string $languageCode
317
	 * @param string $description
318
	 * @param string $moarText
319
	 */
320
	public function testSetDescription( $languageCode, $description, $moarText = 'ohi there' ) {
321
		$entity = $this->getNewEmpty();
322
323
		$entity->setDescription( $languageCode, $description );
324
325
		$this->assertSame( $description, $entity->getFingerprint()->getDescription( $languageCode )->getText() );
326
327
		$entity->setDescription( $languageCode, $moarText );
328
329
		$this->assertSame( $moarText, $entity->getFingerprint()->getDescription( $languageCode )->getText() );
330
	}
331
332
	public function aliasesProvider() {
333
		return [
334
			[ [
335
				       'en' => [ [ 'spam' ] ]
336
			       ] ],
337
			[ [
338
				       'en' => [ [ 'foo', 'bar', 'baz' ] ]
339
			       ] ],
340
			[ [
341
				       'en' => [ [ 'foo', 'bar' ], [ 'baz', 'spam' ] ]
342
			       ] ],
343
			[ [
344
				       'en' => [ [ 'foo', 'bar', 'baz' ] ],
345
				       'de' => [ [ 'foobar' ], [ 'baz' ] ],
346
			       ] ],
347
			// with duplicates
348
			[ [
349
				       'en' => [ [ 'spam', 'ham', 'ham' ] ]
350
			       ] ],
351
			[ [
352
				       'en' => [ [ 'foo', 'bar' ], [ 'bar', 'spam' ] ]
353
			       ] ],
354
		];
355
	}
356
357
	/**
358
	 * @dataProvider aliasesProvider
359
	 */
360
	public function testSetAliases( array $aliasesLists ) {
361
		$entity = $this->getNewEmpty();
362
363
		foreach ( $aliasesLists as $langCode => $aliasesList ) {
364
			foreach ( $aliasesList as $aliases ) {
365
				$entity->setAliases( $langCode, $aliases );
366
			}
367
		}
368
369
		foreach ( $aliasesLists as $langCode => $aliasesList ) {
370
			$expected = array_values( array_unique( array_pop( $aliasesList ) ) );
371
			$actual = $entity->getFingerprint()->getAliasGroup( $langCode )->getAliases();
372
			$this->assertSame( $expected, $actual );
373
		}
374
	}
375
376
	public function testSetEmptyAlias() {
377
		$property = Property::newFromType( 'string' );
378
379
		$property->setAliases( 'en', [ 'wind', 'air', '', 'fire' ] );
380
		$this->assertSame(
381
			[ 'wind', 'air', 'fire' ],
382
			$property->getAliasGroups()->getByLanguage( 'en' )->getAliases()
383
		);
384
385
		$property->setAliases( 'en', [ '', '' ] );
386
		$this->assertFalse( $property->getAliasGroups()->hasGroupForLanguage( 'en' ) );
387
	}
388
389
	public function instanceProvider() {
390
		$entities = [];
391
392
		// empty
393
		$entity = $this->getNewEmpty();
394
		$entities[] = $entity;
395
396
		// ID only
397
		$entity = clone $entity;
398
		$entity->setId( 44 );
399
400
		$entities[] = $entity;
401
402
		// with labels and stuff
403
		$entity = $this->getNewEmpty();
404
		$entity->setAliases( 'en', [ 'o', 'noez' ] );
405
		$entity->setLabel( 'de', 'spam' );
406
		$entity->setDescription( 'en', 'foo bar baz' );
407
408
		$entities[] = $entity;
409
410
		// with labels etc and ID
411
		$entity = clone $entity;
412
		$entity->setId( 42 );
413
414
		$entities[] = $entity;
415
416
		$argLists = [];
417
418
		foreach ( $entities as $entity ) {
419
			$argLists[] = [ $entity ];
420
		}
421
422
		return $argLists;
423
	}
424
425
	/**
426
	 * @dataProvider instanceProvider
427
	 * @param Property $entity
428
	 */
429
	public function testCopy( Property $entity ) {
430
		$copy = $entity->copy();
431
432
		// The equality method alone is not enough since it does not check the IDs.
433
		$this->assertTrue( $entity->equals( $copy ) );
434
		$this->assertEquals( $entity->getId(), $copy->getId() );
435
436
		$this->assertNotSame( $entity, $copy );
437
	}
438
439
	public function testCopyRetainsLabels() {
440
		$property = Property::newFromType( 'string' );
441
442
		$property->getFingerprint()->setLabel( 'en', 'foo' );
443
		$property->getFingerprint()->setLabel( 'de', 'bar' );
444
445
		$newProperty = $property->copy();
446
447
		$this->assertTrue( $newProperty->getFingerprint()->getLabels()->hasTermForLanguage( 'en' ) );
448
		$this->assertTrue( $newProperty->getFingerprint()->getLabels()->hasTermForLanguage( 'de' ) );
449
	}
450
451
	/**
452
	 * @dataProvider instanceProvider
453
	 * @param Property $entity
454
	 */
455
	public function testSerialize( Property $entity ) {
456
		$string = serialize( $entity );
457
458
		$this->assertInternalType( 'string', $string );
459
460
		$instance = unserialize( $string );
461
462
		$this->assertTrue( $entity->equals( $instance ) );
463
		$this->assertEquals( $entity->getId(), $instance->getId() );
464
	}
465
466
	public function testWhenNoStuffIsSet_getFingerprintReturnsEmptyFingerprint() {
467
		$entity = $this->getNewEmpty();
468
469
		$this->assertEquals(
470
			new Fingerprint(),
471
			$entity->getFingerprint()
472
		);
473
	}
474
475
	public function testWhenLabelsAreSet_getFingerprintReturnsFingerprintWithLabels() {
476
		$entity = $this->getNewEmpty();
477
478
		$entity->setLabel( 'en', 'foo' );
479
		$entity->setLabel( 'de', 'bar' );
480
481
		$this->assertEquals(
482
			new Fingerprint(
483
				new TermList( [
484
					new Term( 'en', 'foo' ),
485
					new Term( 'de', 'bar' ),
486
				] )
487
			),
488
			$entity->getFingerprint()
489
		);
490
	}
491
492
	public function testWhenTermsAreSet_getFingerprintReturnsFingerprintWithTerms() {
493
		$entity = $this->getNewEmpty();
494
495
		$entity->setLabel( 'en', 'foo' );
496
		$entity->setDescription( 'en', 'foo bar' );
497
		$entity->setAliases( 'en', [ 'foo', 'bar' ] );
498
499
		$this->assertEquals(
500
			new Fingerprint(
501
				new TermList( [
502
					new Term( 'en', 'foo' ),
503
				] ),
504
				new TermList( [
505
					new Term( 'en', 'foo bar' )
506
				] ),
507
				new AliasGroupList( [
508
					new AliasGroup( 'en', [ 'foo', 'bar' ] )
509
				] )
510
			),
511
			$entity->getFingerprint()
512
		);
513
	}
514
515
	public function testGivenEmptyFingerprint_noTermsAreSet() {
516
		$entity = $this->getNewEmpty();
517
		$entity->setFingerprint( new Fingerprint() );
518
519
		$this->assertTrue( $entity->getFingerprint()->isEmpty() );
520
	}
521
522
	public function testGivenEmptyFingerprint_existingTermsAreRemoved() {
523
		$entity = $this->getNewEmpty();
524
525
		$entity->setLabel( 'en', 'foo' );
526
		$entity->setDescription( 'en', 'foo bar' );
527
		$entity->setAliases( 'en', [ 'foo', 'bar' ] );
528
529
		$entity->setFingerprint( new Fingerprint() );
530
531
		$this->assertTrue( $entity->getFingerprint()->isEmpty() );
532
	}
533
534
	public function testWhenSettingFingerprint_getFingerprintReturnsIt() {
535
		$fingerprint = new Fingerprint(
536
			new TermList( [
537
				new Term( 'en', 'english label' ),
538
			] ),
539
			new TermList( [
540
				new Term( 'en', 'english description' )
541
			] ),
542
			new AliasGroupList( [
543
				new AliasGroup( 'en', [ 'first en alias', 'second en alias' ] )
544
			] )
545
		);
546
547
		$entity = $this->getNewEmpty();
548
		$entity->setFingerprint( $fingerprint );
549
		$newFingerprint = $entity->getFingerprint();
550
551
		$this->assertSame( $fingerprint, $newFingerprint );
552
	}
553
554
	public function testGetLabels() {
555
		$property = Property::newFromType( 'string' );
556
		$property->setLabel( 'en', 'foo' );
557
558
		$this->assertEquals(
559
			new TermList( [
560
				new Term( 'en', 'foo' )
561
			] ),
562
			$property->getLabels()
563
		);
564
	}
565
566
	public function testGetDescriptions() {
567
		$property = Property::newFromType( 'string' );
568
		$property->setDescription( 'en', 'foo bar' );
569
570
		$this->assertEquals(
571
			new TermList( [
572
				new Term( 'en', 'foo bar' )
573
			] ),
574
			$property->getDescriptions()
575
		);
576
	}
577
578
	public function testGetAliasGroups() {
579
		$property = Property::newFromType( 'string' );
580
		$property->setAliases( 'en', [ 'foo', 'bar' ] );
581
582
		$this->assertEquals(
583
			new AliasGroupList( [
584
				new AliasGroup( 'en', [ 'foo', 'bar' ] )
585
			] ),
586
			$property->getAliasGroups()
587
		);
588
	}
589
590
	public function testGetLabels_sameListAsFingerprint() {
591
		$property = Property::newFromType( 'string' );
592
593
		$this->assertSame(
594
			$property->getFingerprint()->getLabels(),
595
			$property->getLabels()
596
		);
597
	}
598
599
	public function testGetDescriptions_sameListAsFingerprint() {
600
		$property = Property::newFromType( 'string' );
601
602
		$this->assertSame(
603
			$property->getFingerprint()->getDescriptions(),
604
			$property->getDescriptions()
605
		);
606
	}
607
608
	public function testGetAliasGroups_sameListAsFingerprint() {
609
		$property = Property::newFromType( 'string' );
610
611
		$this->assertSame(
612
			$property->getFingerprint()->getAliasGroups(),
613
			$property->getAliasGroups()
614
		);
615
	}
616
617
	/**
618
	 * @dataProvider clearableProvider
619
	 */
620
	public function testClear( Property $property ) {
621
		$clone = $property->copy();
622
623
		$property->clear();
624
625
		$this->assertEquals(
626
			$clone->getId(),
627
			$property->getId(),
628
			'cleared Property should keep its id'
629
		);
630
		$this->assertEquals(
631
			$clone->getDataTypeId(),
632
			$property->getDataTypeId(),
633
			'cleared Property should keep its data type'
634
		);
635
		$this->assertTrue( $property->isEmpty(), 'cleared Property should be empty' );
636
	}
637
638
	public function clearableProvider() {
639
		return [
640
			'empty' => [
641
				new Property( new PropertyId( 'P123' ), null, 'string' ),
642
			],
643
			'with fingerprint' => [
644
				new Property(
645
					new PropertyId( 'P321' ),
646
					new Fingerprint( new TermList( [ new Term( 'en', 'foo' ) ] ) ),
647
					'time'
648
				),
649
			],
650
			'with statement' => [
651
				new Property(
652
					new PropertyId( 'P234' ),
653
					null,
654
					'wikibase-entityid',
655
					$this->newNonEmptyStatementList()
656
				)
657
			],
658
		];
659
	}
660
661
}
662