Passed
Push — remove-hashable-object-storage ( d8c663 )
by Bene
05:55 queued 02:35
created

invalidConstructorArgumentsProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 18
rs 9.4285
cc 1
eloc 15
nc 1
nop 0
1
<?php
2
3
namespace Wikibase\DataModel\Tests;
4
5
use Hashable;
6
use InvalidArgumentException;
7
use Wikibase\DataModel\Entity\PropertyId;
8
use Wikibase\DataModel\Reference;
9
use Wikibase\DataModel\ReferenceList;
10
use Wikibase\DataModel\Snak\PropertyNoValueSnak;
11
use Wikibase\DataModel\Snak\SnakList;
12
13
/**
14
 * @covers Wikibase\DataModel\ReferenceList
15
 *
16
 * @group Wikibase
17
 * @group WikibaseDataModel
18
 * @group WikibaseReference
19
 *
20
 * @licence GNU GPL v2+
21
 * @author Jeroen De Dauw < [email protected] >
22
 * @author Thiemo Mättig
23
 */
24
class ReferenceListTest extends \PHPUnit_Framework_TestCase {
25
26
	public function instanceProvider() {
27
		$instances = array();
28
29
		foreach ( $this->getConstructorArg() as $arg ) {
30
			$instances[] = array( new ReferenceList( $arg ) );
31
		}
32
33
		return $instances;
34
	}
35
36
	public function getElementInstances() {
37
		return array(
38
			new Reference(),
39
			new Reference( array( new PropertyNoValueSnak( 2 ) ) ),
40
			new Reference( array( new PropertyNoValueSnak( 3 ) ) ),
41
		);
42
	}
43
44
	public function getConstructorArg() {
45
		return array(
46
			array(),
47
			$this->getElementInstances(),
48
		);
49
	}
50
51
	public function testCanConstructWithReferenceListObject() {
52
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
53
		$original = new ReferenceList( array( $reference ) );
54
		$copy = new ReferenceList( $original );
55
56
		$this->assertSame( 1, $copy->count() );
57
		$this->assertNotNull( $copy->getReference( $reference->getHash() ) );
58
	}
59
60
	/**
61
	 * @dataProvider invalidConstructorArgumentsProvider
62
	 * @expectedException InvalidArgumentException
63
	 */
64
	public function testGivenInvalidConstructorArguments_constructorThrowsException( $input ) {
65
		new ReferenceList( $input );
66
	}
67
68
	public function invalidConstructorArgumentsProvider() {
69
		$id1 = new PropertyId( 'P1' );
70
71
		return array(
72
			array( null ),
73
			array( false ),
74
			array( 1 ),
75
			array( 0.1 ),
76
			array( 'string' ),
77
			array( $id1 ),
78
			array( new PropertyNoValueSnak( $id1 ) ),
79
			array( new Reference() ),
80
			array( new SnakList( array( new PropertyNoValueSnak( $id1 ) ) ) ),
81
			array( array( new PropertyNoValueSnak( $id1 ) ) ),
82
			array( array( new ReferenceList() ) ),
83
			array( array( new SnakList() ) ),
84
		);
85
	}
86
87
	/**
88
	 * @dataProvider instanceProvider
89
	 * @param ReferenceList $array
90
	 */
91
	public function testHasReferenceBeforeRemoveButNotAfter( ReferenceList $array ) {
92
		if ( $array->count() === 0 ) {
93
			$this->assertTrue( true );
94
			return;
95
		}
96
97
		/**
98
		 * @var Reference $hashable
99
		 */
100
		foreach ( iterator_to_array( $array ) as $hashable ) {
101
			$this->assertTrue( $array->hasReference( $hashable ) );
102
			$array->removeReference( $hashable );
103
			$this->assertFalse( $array->hasReference( $hashable ) );
104
		}
105
	}
106
107
	public function testGivenCloneOfReferenceInList_hasReferenceReturnsTrue() {
108
		$list = new ReferenceList();
109
110
		$reference = new Reference( array( new PropertyNoValueSnak( 42 ) ) );
111
		$sameReference = unserialize( serialize( $reference ) );
112
113
		$list->addReference( $reference );
114
115
		$this->assertTrue(
116
			$list->hasReference( $sameReference ),
117
			'hasReference should return true when a reference with the same value is present, even when its another instance'
118
		);
119
	}
120
121
	/**
122
	 * @dataProvider instanceProvider
123
	 * @param ReferenceList $array
124
	 */
125
	public function testRemoveReference( ReferenceList $array ) {
126
		$elementCount = count( $array );
127
128
		/**
129
		 * @var Reference $element
130
		 */
131
		foreach ( iterator_to_array( $array ) as $element ) {
132
			$this->assertTrue( $array->hasReference( $element ) );
133
134
			$array->removeReference( $element );
135
136
			$this->assertFalse( $array->hasReference( $element ) );
137
			$this->assertEquals( --$elementCount, count( $array ) );
138
		}
139
140
		$elements = $this->getElementInstances();
141
		$element = array_shift( $elements );
142
143
		$array->removeReference( $element );
0 ignored issues
show
Bug introduced by
It seems like $element defined by array_shift($elements) on line 141 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...
144
		$array->removeReference( $element );
0 ignored issues
show
Bug introduced by
It seems like $element defined by array_shift($elements) on line 141 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...
145
146
		$this->assertTrue( true );
147
	}
148
149
	public function testAddReferenceOnEmptyList() {
150
		$reference = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
151
152
		$references = new ReferenceList();
153
		$references->addReference( $reference );
154
155
		$this->assertCount( 1, $references );
156
157
		$expectedList = new ReferenceList( array( $reference ) );
158
		$this->assertSameReferenceOrder( $expectedList, $references );
159
	}
160
161
	private function assertSameReferenceOrder( ReferenceList $expectedList, ReferenceList $references ) {
162
		$this->assertEquals(
163
			iterator_to_array( $expectedList ),
164
			iterator_to_array( $references )
165
		);
166
	}
167
168
	public function testAddReferenceOnNonEmptyList() {
169
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
170
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
171
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
172
173
		$references = new ReferenceList( array( $reference1, $reference2 ) );
174
		$references->addReference( $reference3 );
175
176
		$this->assertCount( 3, $references );
177
178
		$expectedList = new ReferenceList( array( $reference1, $reference2, $reference3 ) );
179
		$this->assertSameReferenceOrder( $expectedList, $references );
180
	}
181
182
	public function testAddReferenceAtIndexZero() {
183
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
184
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
185
		$reference3 = new Reference( array( new PropertyNoValueSnak( 3 ) ) );
186
187
		$references = new ReferenceList( array( $reference1, $reference2 ) );
188
		$references->addReference( $reference3, 0 );
189
190
		$expectedList = new ReferenceList( array( $reference3, $reference1, $reference2 ) );
191
		$this->assertSameReferenceOrder( $expectedList, $references );
192
	}
193
194
	public function testGivenEmptyReference_addReferenceDoesNotAdd() {
195
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
196
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
197
		$emptyReference = new Reference( array() );
198
199
		$references = new ReferenceList( array( $reference1, $reference2 ) );
200
		$references->addReference( $emptyReference );
201
202
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
203
		$this->assertSameReferenceOrder( $expectedList, $references );
204
	}
205
206
	public function testGivenEmptyReferenceAndIndex_addReferenceDoesNotAdd() {
207
		$reference1 = new Reference( array( new PropertyNoValueSnak( 1 ) ) );
208
		$reference2 = new Reference( array( new PropertyNoValueSnak( 2 ) ) );
209
		$emptyReference = new Reference( array() );
210
211
		$references = new ReferenceList( array( $reference1, $reference2 ) );
212
		$references->addReference( $emptyReference, 0 );
213
214
		$expectedList = new ReferenceList( array( $reference1, $reference2 ) );
215
		$this->assertSameReferenceOrder( $expectedList, $references );
216
	}
217
218
	/**
219
	 * @dataProvider instanceProvider
220
	 * @param ReferenceList $array
221
	 */
222
	public function testIndexOf( ReferenceList $array ) {
223
		$this->assertFalse( $array->indexOf( new Reference() ) );
224
225
		$i = 0;
226
		foreach ( $array as $reference ) {
227
			$this->assertEquals( $i++, $array->indexOf( $reference ) );
228
		}
229
	}
230
231
	/**
232
	 * @dataProvider instanceProvider
233
	 * @param ReferenceList $array
234
	 */
235
	public function testEquals( ReferenceList $array ) {
236
		$this->assertTrue( $array->equals( $array ) );
237
		$this->assertFalse( $array->equals( 42 ) );
238
	}
239
240
	/**
241
	 * @dataProvider instanceProvider
242
	 * @param ReferenceList $array
243
	 */
244
	public function testGetHashReturnsString( ReferenceList $array ) {
245
		$this->assertInternalType( 'string', $array->getValueHash() );
246
	}
247
248
	/**
249
	 * @dataProvider instanceProvider
250
	 * @param ReferenceList $array
251
	 */
252
	public function testGetHashValueIsTheSameForClone( ReferenceList $array ) {
253
		$copy = unserialize( serialize( $array ) );
254
		$this->assertEquals( $array->getValueHash(), $copy->getValueHash() );
255
	}
256
257
	/**
258
	 * @dataProvider instanceProvider
259
	 * @param ReferenceList $references
260
	 */
261
	public function testHasReferenceHash( ReferenceList $references ) {
262
		$this->assertFalse( $references->hasReferenceHash( '~=[,,_,,]:3' ) );
263
264
		/**
265
		 * @var Hashable $reference
266
		 */
267
		foreach ( $references as $reference ) {
268
			$this->assertTrue( $references->hasReferenceHash( $reference->getHash() ) );
269
		}
270
	}
271
272
	/**
273
	 * @dataProvider instanceProvider
274
	 * @param ReferenceList $references
275
	 */
276
	public function testGetReference( ReferenceList $references ) {
277
		$this->assertNull( $references->getReference( '~=[,,_,,]:3' ) );
278
279
		/**
280
		 * @var Reference $reference
281
		 */
282
		foreach ( $references as $reference ) {
283
			$this->assertTrue( $reference->equals( $references->getReference( $reference->getHash() ) ) );
284
		}
285
	}
286
287
	/**
288
	 * @dataProvider instanceProvider
289
	 * @param ReferenceList $references
290
	 */
291
	public function testRemoveReferenceHash( ReferenceList $references ) {
292
		$references->removeReferenceHash( '~=[,,_,,]:3' );
293
294
		$hashes = array();
295
296
		/**
297
		 * @var Reference $reference
298
		 */
299
		foreach ( $references as $reference ) {
300
			$hashes[] = $reference->getHash();
301
		}
302
303
		foreach ( $hashes as $hash ) {
304
			$references->removeReferenceHash( $hash );
305
		}
306
307
		$this->assertEquals( 0, count( $references ) );
308
	}
309
310
	public function testGivenOneSnak_addNewReferenceAddsSnak() {
311
		$references = new ReferenceList();
312
		$snak = new PropertyNoValueSnak( 1 );
313
314
		$references->addNewReference( $snak );
315
		$this->assertTrue( $references->hasReference( new Reference( array( $snak ) ) ) );
316
	}
317
318
	public function testGivenMultipleSnaks_addNewReferenceAddsThem() {
319
		$references = new ReferenceList();
320
		$snak1 = new PropertyNoValueSnak( 1 );
321
		$snak2 = new PropertyNoValueSnak( 3 );
322
		$snak3 = new PropertyNoValueSnak( 2 );
323
324
		$references->addNewReference( $snak1, $snak2, $snak3 );
325
326
		$expectedSnaks = array( $snak1, $snak2, $snak3 );
327
		$this->assertTrue( $references->hasReference( new Reference( $expectedSnaks ) ) );
328
	}
329
330
	public function testGivenAnArrayOfSnaks_addNewReferenceAddsThem() {
331
		$references = new ReferenceList();
332
		$snaks = array(
333
			new PropertyNoValueSnak( 1 ),
334
			new PropertyNoValueSnak( 3 ),
335
			new PropertyNoValueSnak( 2 )
336
		);
337
338
		$references->addNewReference( $snaks );
339
		$this->assertTrue( $references->hasReference( new Reference( $snaks ) ) );
340
	}
341
342
	public function testGivenNoneSnak_addNewReferenceThrowsException() {
343
		$references = new ReferenceList();
344
345
		$this->setExpectedException( 'InvalidArgumentException' );
346
		$references->addNewReference( new PropertyNoValueSnak( 1 ), null );
347
	}
348
349
	public function testSerializeRoundtrip() {
350
		$references = new ReferenceList();
351
352
		$references->addReference( new Reference() );
353
354
		$references->addReference( new Reference( array(
355
			new PropertyNoValueSnak( 2 ),
356
			new PropertyNoValueSnak( 3 ),
357
		) ) );
358
359
		$serialized = serialize( $references );
360
		$this->assertTrue( $references->equals( unserialize( $serialized ) ) );
361
	}
362
363
	public function testGivenEmptyList_isEmpty() {
364
		$references = new ReferenceList();
365
		$this->assertTrue( $references->isEmpty() );
366
	}
367
368
	public function testGivenNonEmptyList_isNotEmpty() {
369
		$references = new ReferenceList();
370
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
371
372
		$this->assertFalse( $references->isEmpty() );
373
	}
374
375
	public function testGivenNonEmptyListWithForwardedIterator_isNotEmpty() {
376
		$references = new ReferenceList();
377
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
378
		$references->next();
379
380
		$this->assertFalse( $references->valid(), 'post condition' );
381
		$this->assertFalse( $references->isEmpty() );
382
		$this->assertFalse( $references->valid(), 'pre condition' );
383
	}
384
385
	public function testRemoveDuplicates_noDuplicatesPresent() {
386
		$list = new ReferenceList();
387
388
		$list->attach( new Reference( array( new PropertyNoValueSnak( 1 ) ) ) );
389
		$list->attach( new Reference( array( new PropertyNoValueSnak( 2 ) ) ) );
390
		$list->attach( new Reference( array( new PropertyNoValueSnak( 3 ) ) ) );
391
392
		$list->removeDuplicates();
393
394
		$this->assertEquals( 3, count( $list ) );
395
	}
396
397
	public function testRemoveDuplicates_duplicatesGetRemoved() {
398
		$list = new ReferenceList();
399
400
		$list->attach( new Reference( array( new PropertyNoValueSnak( 1 ) ) ) );
401
		$list->attach( new Reference( array( new PropertyNoValueSnak( 2 ) ) ) );
402
		$list->attach( new Reference( array( new PropertyNoValueSnak( 3 ) ) ) );
403
		$list->attach( new Reference( array( new PropertyNoValueSnak( 1 ) ) ) );
404
		$list->attach( new Reference( array( new PropertyNoValueSnak( 2 ) ) ) );
405
		$list->attach( new Reference( array( new PropertyNoValueSnak( 4 ) ) ) );
406
407
		$list->removeDuplicates();
408
409
		$this->assertEquals( 4, count( $list ) );
410
	}
411
412
}
413