Test Failed
Push — refDuplicates ( 2ea7b8 )
by no
03:46
created

ReferenceListTest::testConstructorIgnoresCopies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
namespace Wikibase\DataModel\Tests;
4
5
use Hashable;
6
use InvalidArgumentException;
7
use PHPUnit_Framework_TestCase;
8
use Wikibase\DataModel\Entity\PropertyId;
9
use Wikibase\DataModel\Reference;
10
use Wikibase\DataModel\ReferenceList;
11
use Wikibase\DataModel\Snak\PropertyNoValueSnak;
12
use Wikibase\DataModel\Snak\SnakList;
13
14
/**
15
 * @covers Wikibase\DataModel\ReferenceList
16
 *
17
 * @group Wikibase
18
 * @group WikibaseDataModel
19
 * @group WikibaseReference
20
 *
21
 * @licence GNU GPL v2+
22
 * @author Jeroen De Dauw < [email protected] >
23
 * @author Thiemo Mättig
24
 */
25
class ReferenceListTest extends PHPUnit_Framework_TestCase {
26
27
	public function instanceProvider() {
28
		$instances = array();
29
30
		foreach ( $this->getConstructorArg() as $arg ) {
31
			$instances[] = array( new ReferenceList( $arg ) );
32
		}
33
34
		return $instances;
35
	}
36
37
	public function getElementInstances() {
38
		return array(
39
			new Reference(),
40
			new Reference( array( new PropertyNoValueSnak( 2 ) ) ),
41
			new Reference( array( new PropertyNoValueSnak( 3 ) ) ),
42
		);
43
	}
44
45
	public function getConstructorArg() {
46
		return array(
47
			array(),
48
			$this->getElementInstances(),
49
		);
50
	}
51
52
	public function testCanConstructWithReferenceListObject() {
53
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
54
		$original = new ReferenceList( array( $reference ) );
55
		$copy = new ReferenceList( $original );
56
57
		$this->assertSame( 1, $copy->count() );
58
		$this->assertNotNull( $copy->getReference( $reference->getHash() ) );
59
	}
60
61
	public function testConstructorIgnoresIdenticalObjects() {
62
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
63
		$original = new ReferenceList( array( $reference, $reference ) );
64
		$this->assertCount( 1, $original );
65
	}
66
67
	public function testConstructorIgnoresCopies() {
68
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
69
		$original = new ReferenceList( array( $reference, clone $reference ) );
70
		$this->assertCount( 1, $original );
71
	}
72
73
	/**
74
	 * @dataProvider invalidConstructorArgumentsProvider
75
	 * @expectedException InvalidArgumentException
76
	 */
77
	public function testGivenInvalidConstructorArguments_constructorThrowsException( $input ) {
78
		new ReferenceList( $input );
79
	}
80
81
	public function invalidConstructorArgumentsProvider() {
82
		$id1 = new PropertyId( 'P1' );
83
84
		return array(
85
			array( null ),
86
			array( false ),
87
			array( 1 ),
88
			array( 0.1 ),
89
			array( 'string' ),
90
			array( $id1 ),
91
			array( new PropertyNoValueSnak( $id1 ) ),
92
			array( new Reference() ),
93
			array( new SnakList( array( new PropertyNoValueSnak( $id1 ) ) ) ),
94
			array( array( new PropertyNoValueSnak( $id1 ) ) ),
95
			array( array( new ReferenceList() ) ),
96
			array( array( new SnakList() ) ),
97
		);
98
	}
99
100
	public function testGetIterator_isTraversable() {
101
		$references = new ReferenceList();
102
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
103
		$iterator = $references->getIterator();
104
105
		$this->assertInstanceOf( 'Traversable', $iterator );
106
		$this->assertCount( 1, $iterator );
107
		foreach ( $references as $reference ) {
108
			$this->assertInstanceOf( 'Wikibase\DataModel\Reference', $reference );
109
		}
110
	}
111
112
	/**
113
	 * @dataProvider instanceProvider
114
	 */
115
	public function testHasReferenceBeforeRemoveButNotAfter( ReferenceList $array ) {
116
		if ( $array->count() === 0 ) {
117
			$this->assertTrue( true );
118
			return;
119
		}
120
121
		/**
122
		 * @var Reference $hashable
123
		 */
124
		foreach ( iterator_to_array( $array ) as $hashable ) {
125
			$this->assertTrue( $array->hasReference( $hashable ) );
126
			$array->removeReference( $hashable );
127
			$this->assertFalse( $array->hasReference( $hashable ) );
128
		}
129
	}
130
131
	public function testGivenCloneOfReferenceInList_hasReferenceReturnsTrue() {
132
		$list = new ReferenceList();
133
134
		$reference = new Reference( array( new PropertyNoValueSnak( 42 ) ) );
135
		$sameReference = unserialize( serialize( $reference ) );
136
137
		$list->addReference( $reference );
138
139
		$this->assertTrue(
140
			$list->hasReference( $sameReference ),
141
			'hasReference should return true when a reference with the same value is present, even when its another instance'
142
		);
143
	}
144
145
	/**
146
	 * @dataProvider instanceProvider
147
	 */
148
	public function testRemoveReference( ReferenceList $array ) {
149
		$elementCount = count( $array );
150
151
		/**
152
		 * @var Reference $element
153
		 */
154
		foreach ( iterator_to_array( $array ) as $element ) {
155
			$this->assertTrue( $array->hasReference( $element ) );
156
157
			$array->removeReference( $element );
158
159
			$this->assertFalse( $array->hasReference( $element ) );
160
			$this->assertEquals( --$elementCount, count( $array ) );
161
		}
162
163
		$elements = $this->getElementInstances();
164
		$element = array_shift( $elements );
165
166
		$array->removeReference( $element );
0 ignored issues
show
Bug introduced by
It seems like $element defined by array_shift($elements) on line 164 can be null; however, Wikibase\DataModel\Refer...List::removeReference() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
167
		$array->removeReference( $element );
0 ignored issues
show
Bug introduced by
It seems like $element defined by array_shift($elements) on line 164 can be null; however, Wikibase\DataModel\Refer...List::removeReference() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
168
169
		$this->assertTrue( true );
170
	}
171
172
	public function testRemoveReferenceRemovesIdenticalObjects() {
173
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
174
		$references = new ReferenceList( array( $reference, $reference ) );
175
176
		$references->removeReference( $reference );
177
178
		$this->assertTrue( $references->isEmpty() );
179
	}
180
181
	public function testRemoveReferenceDoesNotRemoveCopies() {
182
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
183
		$references = new ReferenceList( array( $reference, clone $reference ) );
184
185
		$references->removeReference( $reference );
186
187
		$this->assertFalse( $references->isEmpty() );
188
		$this->assertTrue( $references->hasReference( $reference ) );
189
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
190
	}
191
192
	public function testAddReferenceOnEmptyList() {
193
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
194
195
		$references = new ReferenceList();
196
		$references->addReference( $reference );
197
198
		$this->assertCount( 1, $references );
199
200
		$expectedList = new ReferenceList( array( $reference ) );
201
		$this->assertSameReferenceOrder( $expectedList, $references );
202
	}
203
204
	private function assertSameReferenceOrder( ReferenceList $expectedList, ReferenceList $references ) {
205
		$this->assertEquals(
206
			iterator_to_array( $expectedList ),
207
			iterator_to_array( $references )
208
		);
209
	}
210
211
	public function testAddReferenceOnNonEmptyList() {
212
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
213
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
214
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
215
216
		$references = new ReferenceList( array( $reference1, $reference2 ) );
217
		$references->addReference( $reference3 );
218
219
		$this->assertCount( 3, $references );
220
221
		$expectedList = new ReferenceList( array( $reference1, $reference2, $reference3 ) );
222
		$this->assertSameReferenceOrder( $expectedList, $references );
223
	}
224
225
	public function testAddReferenceAtIndexZero() {
226
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
227
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
228
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
229
230
		$references = new ReferenceList( array( $reference1, $reference2 ) );
231
		$references->addReference( $reference3, 0 );
232
233
		$expectedList = new ReferenceList( array( $reference3, $reference1, $reference2 ) );
234
		$this->assertSameReferenceOrder( $expectedList, $references );
235
	}
236
237
	public function testAddReferenceAtNegativeIndex() {
238
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
239
		$referenceList = new ReferenceList();
240
241
		$this->setExpectedException( 'InvalidArgumentException' );
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
242
		$referenceList->addReference( $reference, -1 );
243
	}
244
245
	public function testGivenEmptyReference_addReferenceDoesNotAdd() {
246
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
247
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
248
		$emptyReference = new Reference( array() );
249
250
		$references = new ReferenceList( array( $reference1, $reference2 ) );
251
		$references->addReference( $emptyReference );
252
253
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
254
		$this->assertSameReferenceOrder( $expectedList, $references );
255
	}
256
257
	public function testGivenEmptyReferenceAndIndex_addReferenceDoesNotAdd() {
258
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
259
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
260
		$emptyReference = new Reference( array() );
261
262
		$references = new ReferenceList( array( $reference1, $reference2 ) );
263
		$references->addReference( $emptyReference, 0 );
264
265
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
266
		$this->assertSameReferenceOrder( $expectedList, $references );
267
	}
268
269
	/**
270
	 * @dataProvider instanceProvider
271
	 */
272
	public function testIndexOf( ReferenceList $array ) {
273
		$this->assertFalse( $array->indexOf( new Reference() ) );
274
275
		$i = 0;
276
		foreach ( $array as $reference ) {
277
			$this->assertEquals( $i++, $array->indexOf( $reference ) );
278
		}
279
	}
280
281
	public function testIndexOf_checksForIdentity() {
282
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
283
		$reference2 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
284
		$referenceList = new ReferenceList( array( $reference1 ) );
285
286
		$this->assertNotSame( $reference1, $reference2, 'post condition' );
287
		$this->assertTrue( $reference1->equals( $reference2 ), 'post condition' );
288
		$this->assertSame( 0, $referenceList->indexOf( $reference1 ), 'identity' );
289
		$this->assertFalse( $referenceList->indexOf( $reference2 ), 'not equality' );
290
	}
291
292
	/**
293
	 * @dataProvider instanceProvider
294
	 */
295
	public function testEquals( ReferenceList $array ) {
296
		$this->assertTrue( $array->equals( $array ) );
297
		$this->assertFalse( $array->equals( 42 ) );
298
	}
299
300
	/**
301
	 * @dataProvider instanceProvider
302
	 */
303
	public function testGetValueHashReturnsString( ReferenceList $array ) {
304
		$this->assertInternalType( 'string', $array->getValueHash() );
305
	}
306
307
	/**
308
	 * @dataProvider instanceProvider
309
	 */
310
	public function testGetValueHashIsTheSameForClone( ReferenceList $array ) {
311
		$copy = unserialize( serialize( $array ) );
312
		$this->assertEquals( $array->getValueHash(), $copy->getValueHash() );
313
	}
314
315
	/**
316
	 * @dataProvider instanceProvider
317
	 */
318
	public function testHasReferenceHash( ReferenceList $references ) {
319
		$this->assertFalse( $references->hasReferenceHash( '~=[,,_,,]:3' ) );
320
321
		/**
322
		 * @var Hashable $reference
323
		 */
324
		foreach ( $references as $reference ) {
325
			$this->assertTrue( $references->hasReferenceHash( $reference->getHash() ) );
326
		}
327
	}
328
329
	/**
330
	 * @dataProvider instanceProvider
331
	 */
332
	public function testGetReference( ReferenceList $references ) {
333
		$this->assertNull( $references->getReference( '~=[,,_,,]:3' ) );
334
335
		/**
336
		 * @var Reference $reference
337
		 */
338
		foreach ( $references as $reference ) {
339
			$this->assertTrue( $reference->equals( $references->getReference( $reference->getHash() ) ) );
340
		}
341
	}
342
343
	/**
344
	 * @dataProvider instanceProvider
345
	 */
346
	public function testRemoveReferenceHash( ReferenceList $references ) {
347
		$references->removeReferenceHash( '~=[,,_,,]:3' );
348
349
		$hashes = array();
350
351
		/**
352
		 * @var Reference $reference
353
		 */
354
		foreach ( $references as $reference ) {
355
			$hashes[] = $reference->getHash();
356
		}
357
358
		foreach ( $hashes as $hash ) {
359
			$references->removeReferenceHash( $hash );
360
		}
361
362
		$this->assertEquals( 0, count( $references ) );
363
	}
364
365
	public function testRemoveReferenceHashRemovesIdenticalObjects() {
366
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
367
		$references = new ReferenceList( array( $reference, $reference ) );
368
369
		$references->removeReferenceHash( $reference->getHash() );
370
371
		$this->assertTrue( $references->isEmpty() );
372
	}
373
374
	public function testRemoveReferenceHashDoesNotRemoveCopies() {
375
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
376
		$references = new ReferenceList( array( $reference, clone $reference ) );
377
378
		$references->removeReferenceHash( $reference->getHash() );
379
380
		$this->assertFalse( $references->isEmpty() );
381
		$this->assertTrue( $references->hasReference( $reference ) );
382
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
383
	}
384
385
	public function testRemoveReferenceHashUpdatesIndexes() {
386
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
387
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
388
		$references = new ReferenceList( array( $reference1, $reference2 ) );
389
390
		$references->removeReferenceHash( $reference1->getHash() );
391
392
		$this->assertSame( 0, $references->indexOf( $reference2 ) );
393
	}
394
395
	public function testGivenOneSnak_addNewReferenceAddsSnak() {
396
		$references = new ReferenceList();
397
		$snak = new PropertyNoValueSnak( 1 );
398
399
		$references->addNewReference( $snak );
400
		$this->assertTrue( $references->hasReference( new Reference( array( $snak ) ) ) );
401
	}
402
403
	public function testGivenMultipleSnaks_addNewReferenceAddsThem() {
404
		$references = new ReferenceList();
405
		$snak1 = new PropertyNoValueSnak( 1 );
406
		$snak2 = new PropertyNoValueSnak( 3 );
407
		$snak3 = new PropertyNoValueSnak( 2 );
408
409
		$references->addNewReference( $snak1, $snak2, $snak3 );
410
411
		$expectedSnaks = array( $snak1, $snak2, $snak3 );
412
		$this->assertTrue( $references->hasReference( new Reference( $expectedSnaks ) ) );
413
	}
414
415
	public function testGivenAnArrayOfSnaks_addNewReferenceAddsThem() {
416
		$references = new ReferenceList();
417
		$snaks = array(
418
			new PropertyNoValueSnak( 1 ),
419
			new PropertyNoValueSnak( 3 ),
420
			new PropertyNoValueSnak( 2 )
421
		);
422
423
		$references->addNewReference( $snaks );
424
		$this->assertTrue( $references->hasReference( new Reference( $snaks ) ) );
425
	}
426
427
	public function testGivenNoneSnak_addNewReferenceThrowsException() {
428
		$references = new ReferenceList();
429
430
		$this->setExpectedException( 'InvalidArgumentException' );
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
431
		$references->addNewReference( new PropertyNoValueSnak( 1 ), null );
432
	}
433
434
	public function testSerializationStability() {
435
		$references = new ReferenceList();
436
		$this->assertSame( 'a:0:{}', $references->serialize() );
437
	}
438
439
	public function testSerializeRoundtrip() {
440
		$references = new ReferenceList();
441
442
		$references->addReference( new Reference() );
443
444
		$references->addReference( new Reference( array(
445
			new PropertyNoValueSnak( 2 ),
446
			new PropertyNoValueSnak( 3 ),
447
		) ) );
448
449
		$serialized = serialize( $references );
450
		$this->assertTrue( $references->equals( unserialize( $serialized ) ) );
451
	}
452
453
	public function testGivenEmptyList_isEmpty() {
454
		$references = new ReferenceList();
455
		$this->assertTrue( $references->isEmpty() );
456
	}
457
458
	public function testGivenNonEmptyList_isNotEmpty() {
459
		$references = new ReferenceList();
460
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
461
462
		$this->assertFalse( $references->isEmpty() );
463
	}
464
465
}
466