Completed
Push — master ( 32c63d...65ca5c )
by Bene
35s
created

ReferenceListTest   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 429
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 13
Bugs 1 Features 5
Metric Value
wmc 48
c 13
b 1
f 5
lcom 1
cbo 6
dl 0
loc 429
rs 8.4864

38 Methods

Rating   Name   Duplication   Size   Complexity  
A instanceProvider() 0 9 2
A getElementInstances() 0 7 1
A getConstructorArg() 0 6 1
A testCanConstructWithReferenceListObject() 0 8 1
A testGivenInvalidConstructorArguments_constructorThrowsException() 0 3 1
A invalidConstructorArgumentsProvider() 0 18 1
A testHasReferenceBeforeRemoveButNotAfter() 0 15 3
A testRemoveReference() 0 23 2
A testGetIterator_isTraversable() 0 11 2
A testGivenCloneOfReferenceInList_hasReferenceReturnsTrue() 0 13 1
A testRemoveReferenceRemovesIdenticalObjects() 0 8 1
A testRemoveReferenceDoesNotRemoveCopies() 0 10 1
A testAddReferenceOnEmptyList() 0 11 1
A assertSameReferenceOrder() 0 6 1
A testAddReferenceOnNonEmptyList() 0 13 1
A testAddReferenceAtIndexZero() 0 11 1
A testAddReferenceAtNegativeIndex() 0 7 1
A testGivenEmptyReference_addReferenceDoesNotAdd() 0 11 1
A testGivenEmptyReferenceAndIndex_addReferenceDoesNotAdd() 0 11 1
A testIndexOf() 0 8 2
A testIndexOf_checksForIdentity() 0 10 1
A testEquals() 0 4 1
A testGetValueHashReturnsString() 0 3 1
A testGetValueHashIsTheSameForClone() 0 4 1
A testHasReferenceHash() 0 10 2
A testGetReference() 0 10 2
A testRemoveReferenceHash() 0 18 3
A testRemoveReferenceHashRemovesIdenticalObjects() 0 8 1
A testRemoveReferenceHashDoesNotRemoveCopies() 0 10 1
A testRemoveReferenceHashUpdatesIndexes() 0 9 1
A testGivenOneSnak_addNewReferenceAddsSnak() 0 7 1
A testGivenMultipleSnaks_addNewReferenceAddsThem() 0 11 1
A testGivenAnArrayOfSnaks_addNewReferenceAddsThem() 0 11 1
A testGivenNoneSnak_addNewReferenceThrowsException() 0 6 1
A testSerializationStability() 0 4 1
A testSerializeRoundtrip() 0 13 1
A testGivenEmptyList_isEmpty() 0 4 1
A testGivenNonEmptyList_isNotEmpty() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like ReferenceListTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ReferenceListTest, and based on these observations, apply Extract Interface, too.

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
	/**
62
	 * @dataProvider invalidConstructorArgumentsProvider
63
	 * @expectedException InvalidArgumentException
64
	 */
65
	public function testGivenInvalidConstructorArguments_constructorThrowsException( $input ) {
66
		new ReferenceList( $input );
67
	}
68
69
	public function invalidConstructorArgumentsProvider() {
70
		$id1 = new PropertyId( 'P1' );
71
72
		return array(
73
			array( null ),
74
			array( false ),
75
			array( 1 ),
76
			array( 0.1 ),
77
			array( 'string' ),
78
			array( $id1 ),
79
			array( new PropertyNoValueSnak( $id1 ) ),
80
			array( new Reference() ),
81
			array( new SnakList( array( new PropertyNoValueSnak( $id1 ) ) ) ),
82
			array( array( new PropertyNoValueSnak( $id1 ) ) ),
83
			array( array( new ReferenceList() ) ),
84
			array( array( new SnakList() ) ),
85
		);
86
	}
87
88
	public function testGetIterator_isTraversable() {
89
		$references = new ReferenceList();
90
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
91
		$iterator = $references->getIterator();
92
93
		$this->assertInstanceOf( 'Traversable', $iterator );
94
		$this->assertCount( 1, $iterator );
95
		foreach ( $references as $reference ) {
96
			$this->assertInstanceOf( 'Wikibase\DataModel\Reference', $reference );
97
		}
98
	}
99
100
	/**
101
	 * @dataProvider instanceProvider
102
	 */
103
	public function testHasReferenceBeforeRemoveButNotAfter( ReferenceList $array ) {
104
		if ( $array->count() === 0 ) {
105
			$this->assertTrue( true );
106
			return;
107
		}
108
109
		/**
110
		 * @var Reference $hashable
111
		 */
112
		foreach ( iterator_to_array( $array ) as $hashable ) {
113
			$this->assertTrue( $array->hasReference( $hashable ) );
114
			$array->removeReference( $hashable );
115
			$this->assertFalse( $array->hasReference( $hashable ) );
116
		}
117
	}
118
119
	public function testGivenCloneOfReferenceInList_hasReferenceReturnsTrue() {
120
		$list = new ReferenceList();
121
122
		$reference = new Reference( array( new PropertyNoValueSnak( 42 ) ) );
123
		$sameReference = unserialize( serialize( $reference ) );
124
125
		$list->addReference( $reference );
126
127
		$this->assertTrue(
128
			$list->hasReference( $sameReference ),
129
			'hasReference should return true when a reference with the same value is present, even when its another instance'
130
		);
131
	}
132
133
	/**
134
	 * @dataProvider instanceProvider
135
	 */
136
	public function testRemoveReference( ReferenceList $array ) {
137
		$elementCount = count( $array );
138
139
		/**
140
		 * @var Reference $element
141
		 */
142
		foreach ( iterator_to_array( $array ) as $element ) {
143
			$this->assertTrue( $array->hasReference( $element ) );
144
145
			$array->removeReference( $element );
146
147
			$this->assertFalse( $array->hasReference( $element ) );
148
			$this->assertEquals( --$elementCount, count( $array ) );
149
		}
150
151
		$elements = $this->getElementInstances();
152
		$element = array_shift( $elements );
153
154
		$array->removeReference( $element );
0 ignored issues
show
Bug introduced by
It seems like $element defined by array_shift($elements) on line 152 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...
155
		$array->removeReference( $element );
0 ignored issues
show
Bug introduced by
It seems like $element defined by array_shift($elements) on line 152 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...
156
157
		$this->assertTrue( true );
158
	}
159
160
	public function testRemoveReferenceRemovesIdenticalObjects() {
161
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
162
		$references = new ReferenceList( array( $reference, $reference ) );
163
164
		$references->removeReference( $reference );
165
166
		$this->assertTrue( $references->isEmpty() );
167
	}
168
169
	public function testRemoveReferenceDoesNotRemoveCopies() {
170
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
171
		$references = new ReferenceList( array( $reference, clone $reference ) );
172
173
		$references->removeReference( $reference );
174
175
		$this->assertFalse( $references->isEmpty() );
176
		$this->assertTrue( $references->hasReference( $reference ) );
177
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
178
	}
179
180
	public function testAddReferenceOnEmptyList() {
181
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
182
183
		$references = new ReferenceList();
184
		$references->addReference( $reference );
185
186
		$this->assertCount( 1, $references );
187
188
		$expectedList = new ReferenceList( array( $reference ) );
189
		$this->assertSameReferenceOrder( $expectedList, $references );
190
	}
191
192
	private function assertSameReferenceOrder( ReferenceList $expectedList, ReferenceList $references ) {
193
		$this->assertEquals(
194
			iterator_to_array( $expectedList ),
195
			iterator_to_array( $references )
196
		);
197
	}
198
199
	public function testAddReferenceOnNonEmptyList() {
200
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
201
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
202
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
203
204
		$references = new ReferenceList( array( $reference1, $reference2 ) );
205
		$references->addReference( $reference3 );
206
207
		$this->assertCount( 3, $references );
208
209
		$expectedList = new ReferenceList( array( $reference1, $reference2, $reference3 ) );
210
		$this->assertSameReferenceOrder( $expectedList, $references );
211
	}
212
213
	public function testAddReferenceAtIndexZero() {
214
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
215
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
216
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
217
218
		$references = new ReferenceList( array( $reference1, $reference2 ) );
219
		$references->addReference( $reference3, 0 );
220
221
		$expectedList = new ReferenceList( array( $reference3, $reference1, $reference2 ) );
222
		$this->assertSameReferenceOrder( $expectedList, $references );
223
	}
224
225
	public function testAddReferenceAtNegativeIndex() {
226
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
227
		$referenceList = new ReferenceList();
228
229
		$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...
230
		$referenceList->addReference( $reference, -1 );
231
	}
232
233
	public function testGivenEmptyReference_addReferenceDoesNotAdd() {
234
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
235
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
236
		$emptyReference = new Reference( array() );
237
238
		$references = new ReferenceList( array( $reference1, $reference2 ) );
239
		$references->addReference( $emptyReference );
240
241
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
242
		$this->assertSameReferenceOrder( $expectedList, $references );
243
	}
244
245
	public function testGivenEmptyReferenceAndIndex_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, 0 );
252
253
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
254
		$this->assertSameReferenceOrder( $expectedList, $references );
255
	}
256
257
	/**
258
	 * @dataProvider instanceProvider
259
	 */
260
	public function testIndexOf( ReferenceList $array ) {
261
		$this->assertFalse( $array->indexOf( new Reference() ) );
262
263
		$i = 0;
264
		foreach ( $array as $reference ) {
265
			$this->assertEquals( $i++, $array->indexOf( $reference ) );
266
		}
267
	}
268
269
	public function testIndexOf_checksForIdentity() {
270
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
271
		$reference2 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
272
		$referenceList = new ReferenceList( array( $reference1 ) );
273
274
		$this->assertNotSame( $reference1, $reference2, 'post condition' );
275
		$this->assertTrue( $reference1->equals( $reference2 ), 'post condition' );
276
		$this->assertSame( 0, $referenceList->indexOf( $reference1 ), 'identity' );
277
		$this->assertFalse( $referenceList->indexOf( $reference2 ), 'not equality' );
278
	}
279
280
	/**
281
	 * @dataProvider instanceProvider
282
	 */
283
	public function testEquals( ReferenceList $array ) {
284
		$this->assertTrue( $array->equals( $array ) );
285
		$this->assertFalse( $array->equals( 42 ) );
286
	}
287
288
	/**
289
	 * @dataProvider instanceProvider
290
	 */
291
	public function testGetValueHashReturnsString( ReferenceList $array ) {
292
		$this->assertInternalType( 'string', $array->getValueHash() );
293
	}
294
295
	/**
296
	 * @dataProvider instanceProvider
297
	 */
298
	public function testGetValueHashIsTheSameForClone( ReferenceList $array ) {
299
		$copy = unserialize( serialize( $array ) );
300
		$this->assertEquals( $array->getValueHash(), $copy->getValueHash() );
301
	}
302
303
	/**
304
	 * @dataProvider instanceProvider
305
	 */
306
	public function testHasReferenceHash( ReferenceList $references ) {
307
		$this->assertFalse( $references->hasReferenceHash( '~=[,,_,,]:3' ) );
308
309
		/**
310
		 * @var Hashable $reference
311
		 */
312
		foreach ( $references as $reference ) {
313
			$this->assertTrue( $references->hasReferenceHash( $reference->getHash() ) );
314
		}
315
	}
316
317
	/**
318
	 * @dataProvider instanceProvider
319
	 */
320
	public function testGetReference( ReferenceList $references ) {
321
		$this->assertNull( $references->getReference( '~=[,,_,,]:3' ) );
322
323
		/**
324
		 * @var Reference $reference
325
		 */
326
		foreach ( $references as $reference ) {
327
			$this->assertTrue( $reference->equals( $references->getReference( $reference->getHash() ) ) );
328
		}
329
	}
330
331
	/**
332
	 * @dataProvider instanceProvider
333
	 */
334
	public function testRemoveReferenceHash( ReferenceList $references ) {
335
		$references->removeReferenceHash( '~=[,,_,,]:3' );
336
337
		$hashes = array();
338
339
		/**
340
		 * @var Reference $reference
341
		 */
342
		foreach ( $references as $reference ) {
343
			$hashes[] = $reference->getHash();
344
		}
345
346
		foreach ( $hashes as $hash ) {
347
			$references->removeReferenceHash( $hash );
348
		}
349
350
		$this->assertEquals( 0, count( $references ) );
351
	}
352
353
	public function testRemoveReferenceHashRemovesIdenticalObjects() {
354
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
355
		$references = new ReferenceList( array( $reference, $reference ) );
356
357
		$references->removeReferenceHash( $reference->getHash() );
358
359
		$this->assertTrue( $references->isEmpty() );
360
	}
361
362
	public function testRemoveReferenceHashDoesNotRemoveCopies() {
363
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
364
		$references = new ReferenceList( array( $reference, clone $reference ) );
365
366
		$references->removeReferenceHash( $reference->getHash() );
367
368
		$this->assertFalse( $references->isEmpty() );
369
		$this->assertTrue( $references->hasReference( $reference ) );
370
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
371
	}
372
373
	public function testRemoveReferenceHashUpdatesIndexes() {
374
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
375
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
376
		$references = new ReferenceList( array( $reference1, $reference2 ) );
377
378
		$references->removeReferenceHash( $reference1->getHash() );
379
380
		$this->assertSame( 0, $references->indexOf( $reference2 ) );
381
	}
382
383
	public function testGivenOneSnak_addNewReferenceAddsSnak() {
384
		$references = new ReferenceList();
385
		$snak = new PropertyNoValueSnak( 1 );
386
387
		$references->addNewReference( $snak );
388
		$this->assertTrue( $references->hasReference( new Reference( array( $snak ) ) ) );
389
	}
390
391
	public function testGivenMultipleSnaks_addNewReferenceAddsThem() {
392
		$references = new ReferenceList();
393
		$snak1 = new PropertyNoValueSnak( 1 );
394
		$snak2 = new PropertyNoValueSnak( 3 );
395
		$snak3 = new PropertyNoValueSnak( 2 );
396
397
		$references->addNewReference( $snak1, $snak2, $snak3 );
398
399
		$expectedSnaks = array( $snak1, $snak2, $snak3 );
400
		$this->assertTrue( $references->hasReference( new Reference( $expectedSnaks ) ) );
401
	}
402
403
	public function testGivenAnArrayOfSnaks_addNewReferenceAddsThem() {
404
		$references = new ReferenceList();
405
		$snaks = array(
406
			new PropertyNoValueSnak( 1 ),
407
			new PropertyNoValueSnak( 3 ),
408
			new PropertyNoValueSnak( 2 )
409
		);
410
411
		$references->addNewReference( $snaks );
412
		$this->assertTrue( $references->hasReference( new Reference( $snaks ) ) );
413
	}
414
415
	public function testGivenNoneSnak_addNewReferenceThrowsException() {
416
		$references = new ReferenceList();
417
418
		$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...
419
		$references->addNewReference( new PropertyNoValueSnak( 1 ), null );
420
	}
421
422
	public function testSerializationStability() {
423
		$references = new ReferenceList();
424
		$this->assertSame( 'a:0:{}', $references->serialize() );
425
	}
426
427
	public function testSerializeRoundtrip() {
428
		$references = new ReferenceList();
429
430
		$references->addReference( new Reference() );
431
432
		$references->addReference( new Reference( array(
433
			new PropertyNoValueSnak( 2 ),
434
			new PropertyNoValueSnak( 3 ),
435
		) ) );
436
437
		$serialized = serialize( $references );
438
		$this->assertTrue( $references->equals( unserialize( $serialized ) ) );
439
	}
440
441
	public function testGivenEmptyList_isEmpty() {
442
		$references = new ReferenceList();
443
		$this->assertTrue( $references->isEmpty() );
444
	}
445
446
	public function testGivenNonEmptyList_isNotEmpty() {
447
		$references = new ReferenceList();
448
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
449
450
		$this->assertFalse( $references->isEmpty() );
451
	}
452
453
}
454