Passed
Push — int32EntityId ( fa80fb )
by no
05:13
created

PropertyTest::testCloneIsEqualButNotIdentical()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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