Completed
Pull Request — master (#634)
by Bene
04:24 queued 01:18
created

testRemoveReferenceHash_allHashesGetRemoved()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 11
rs 9.4285
cc 1
eloc 7
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
	/**
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 testRemoveReferenceHash_allHashesGetRemoved() {
161
		$reference = new Reference( array( new PropertyNoValueSnak( 42 ) ) );
162
		$references = new ReferenceList( array(
163
			clone $reference,
164
			clone $reference
165
		) );
166
167
		$references->removeReferenceHash( $reference->getHash() );
168
169
		$this->assertTrue( $references->isEmpty() );
170
	}
171
172
	public function testAddReferenceOnEmptyList() {
173
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
174
175
		$references = new ReferenceList();
176
		$references->addReference( $reference );
177
178
		$this->assertCount( 1, $references );
179
180
		$expectedList = new ReferenceList( array( $reference ) );
181
		$this->assertSameReferenceOrder( $expectedList, $references );
182
	}
183
184
	private function assertSameReferenceOrder( ReferenceList $expectedList, ReferenceList $references ) {
185
		$this->assertEquals(
186
			iterator_to_array( $expectedList ),
187
			iterator_to_array( $references )
188
		);
189
	}
190
191
	public function testAddReferenceOnNonEmptyList() {
192
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
193
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
194
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
195
196
		$references = new ReferenceList( array( $reference1, $reference2 ) );
197
		$references->addReference( $reference3 );
198
199
		$this->assertCount( 3, $references );
200
201
		$expectedList = new ReferenceList( array( $reference1, $reference2, $reference3 ) );
202
		$this->assertSameReferenceOrder( $expectedList, $references );
203
	}
204
205
	public function testAddReferenceAtIndexZero() {
206
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
207
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
208
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
209
210
		$references = new ReferenceList( array( $reference1, $reference2 ) );
211
		$references->addReference( $reference3, 0 );
212
213
		$expectedList = new ReferenceList( array( $reference3, $reference1, $reference2 ) );
214
		$this->assertSameReferenceOrder( $expectedList, $references );
215
	}
216
217
	public function testAddReferenceAtNegativeIndex() {
218
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
219
		$referenceList = new ReferenceList();
220
221
		$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...
222
		$referenceList->addReference( $reference, -1 );
223
	}
224
225
	public function testGivenEmptyReference_addReferenceDoesNotAdd() {
226
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
227
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
228
		$emptyReference = new Reference( array() );
229
230
		$references = new ReferenceList( array( $reference1, $reference2 ) );
231
		$references->addReference( $emptyReference );
232
233
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
234
		$this->assertSameReferenceOrder( $expectedList, $references );
235
	}
236
237
	public function testGivenEmptyReferenceAndIndex_addReferenceDoesNotAdd() {
238
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
239
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
240
		$emptyReference = new Reference( array() );
241
242
		$references = new ReferenceList( array( $reference1, $reference2 ) );
243
		$references->addReference( $emptyReference, 0 );
244
245
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
246
		$this->assertSameReferenceOrder( $expectedList, $references );
247
	}
248
249
	/**
250
	 * @dataProvider instanceProvider
251
	 */
252
	public function testIndexOf( ReferenceList $array ) {
253
		$this->assertFalse( $array->indexOf( new Reference() ) );
254
255
		$i = 0;
256
		foreach ( $array as $reference ) {
257
			$this->assertEquals( $i++, $array->indexOf( $reference ) );
258
		}
259
	}
260
261
	public function testIndexOf_checksForIdentity() {
262
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
263
		$reference2 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
264
		$referenceList = new ReferenceList( array( $reference1 ) );
265
266
		$this->assertNotSame( $reference1, $reference2, 'post condition' );
267
		$this->assertTrue( $reference1->equals( $reference2 ), 'post condition' );
268
		$this->assertSame( 0, $referenceList->indexOf( $reference1 ), 'identity' );
269
		$this->assertFalse( $referenceList->indexOf( $reference2 ), 'not equality' );
270
	}
271
272
	/**
273
	 * @dataProvider instanceProvider
274
	 */
275
	public function testEquals( ReferenceList $array ) {
276
		$this->assertTrue( $array->equals( $array ) );
277
		$this->assertFalse( $array->equals( 42 ) );
278
	}
279
280
	/**
281
	 * @dataProvider instanceProvider
282
	 */
283
	public function testGetValueHashReturnsString( ReferenceList $array ) {
284
		$this->assertInternalType( 'string', $array->getValueHash() );
285
	}
286
287
	/**
288
	 * @dataProvider instanceProvider
289
	 */
290
	public function testGetValueHashIsTheSameForClone( ReferenceList $array ) {
291
		$copy = unserialize( serialize( $array ) );
292
		$this->assertEquals( $array->getValueHash(), $copy->getValueHash() );
293
	}
294
295
	/**
296
	 * @dataProvider instanceProvider
297
	 */
298
	public function testHasReferenceHash( ReferenceList $references ) {
299
		$this->assertFalse( $references->hasReferenceHash( '~=[,,_,,]:3' ) );
300
301
		/**
302
		 * @var Hashable $reference
303
		 */
304
		foreach ( $references as $reference ) {
305
			$this->assertTrue( $references->hasReferenceHash( $reference->getHash() ) );
306
		}
307
	}
308
309
	/**
310
	 * @dataProvider instanceProvider
311
	 */
312
	public function testGetReference( ReferenceList $references ) {
313
		$this->assertNull( $references->getReference( '~=[,,_,,]:3' ) );
314
315
		/**
316
		 * @var Reference $reference
317
		 */
318
		foreach ( $references as $reference ) {
319
			$this->assertTrue( $reference->equals( $references->getReference( $reference->getHash() ) ) );
320
		}
321
	}
322
323
	/**
324
	 * @dataProvider instanceProvider
325
	 */
326
	public function testRemoveReferenceHash( ReferenceList $references ) {
327
		$references->removeReferenceHash( '~=[,,_,,]:3' );
328
329
		$hashes = array();
330
331
		/**
332
		 * @var Reference $reference
333
		 */
334
		foreach ( $references as $reference ) {
335
			$hashes[] = $reference->getHash();
336
		}
337
338
		foreach ( $hashes as $hash ) {
339
			$references->removeReferenceHash( $hash );
340
		}
341
342
		$this->assertEquals( 0, count( $references ) );
343
	}
344
345
	public function testGivenOneSnak_addNewReferenceAddsSnak() {
346
		$references = new ReferenceList();
347
		$snak = new PropertyNoValueSnak( 1 );
348
349
		$references->addNewReference( $snak );
350
		$this->assertTrue( $references->hasReference( new Reference( array( $snak ) ) ) );
351
	}
352
353
	public function testGivenMultipleSnaks_addNewReferenceAddsThem() {
354
		$references = new ReferenceList();
355
		$snak1 = new PropertyNoValueSnak( 1 );
356
		$snak2 = new PropertyNoValueSnak( 3 );
357
		$snak3 = new PropertyNoValueSnak( 2 );
358
359
		$references->addNewReference( $snak1, $snak2, $snak3 );
360
361
		$expectedSnaks = array( $snak1, $snak2, $snak3 );
362
		$this->assertTrue( $references->hasReference( new Reference( $expectedSnaks ) ) );
363
	}
364
365
	public function testGivenAnArrayOfSnaks_addNewReferenceAddsThem() {
366
		$references = new ReferenceList();
367
		$snaks = array(
368
			new PropertyNoValueSnak( 1 ),
369
			new PropertyNoValueSnak( 3 ),
370
			new PropertyNoValueSnak( 2 )
371
		);
372
373
		$references->addNewReference( $snaks );
374
		$this->assertTrue( $references->hasReference( new Reference( $snaks ) ) );
375
	}
376
377
	public function testGivenNoneSnak_addNewReferenceThrowsException() {
378
		$references = new ReferenceList();
379
380
		$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...
381
		$references->addNewReference( new PropertyNoValueSnak( 1 ), null );
382
	}
383
384
	public function testSerializationStability() {
385
		$references = new ReferenceList();
386
		$this->assertSame( 'a:0:{}', $references->serialize() );
387
	}
388
389
	public function testSerializeRoundtrip() {
390
		$references = new ReferenceList();
391
392
		$references->addReference( new Reference() );
393
394
		$references->addReference( new Reference( array(
395
			new PropertyNoValueSnak( 2 ),
396
			new PropertyNoValueSnak( 3 ),
397
		) ) );
398
399
		$serialized = serialize( $references );
400
		$this->assertTrue( $references->equals( unserialize( $serialized ) ) );
401
	}
402
403
	public function testGivenEmptyList_isEmpty() {
404
		$references = new ReferenceList();
405
		$this->assertTrue( $references->isEmpty() );
406
	}
407
408
	public function testGivenNonEmptyList_isNotEmpty() {
409
		$references = new ReferenceList();
410
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
411
412
		$this->assertFalse( $references->isEmpty() );
413
	}
414
415
}
416