testWhenSettingFingerprint_getFingerprintReturnsIt()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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