Passed
Push — addAtIndexFix ( e7dec5...3a7dae )
by no
03:50 queued 01:01
created

testGivenNonEmptyList_isNotEmpty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
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
 * @license GPL-2.0+
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
		return [
29
			[ new ReferenceList( [] ) ],
30
			[ new ReferenceList( [
31
				new Reference(),
32
				new Reference( [ new PropertyNoValueSnak( 2 ) ] ),
33
				new Reference( [ new PropertyNoValueSnak( 3 ) ] ),
34
			] ) ],
35
		];
36
	}
37
38
	public function testCanConstructWithReferenceListObject() {
39
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
40
		$original = new ReferenceList( [ $reference ] );
41
		$copy = new ReferenceList( $original );
42
43
		$this->assertSame( 1, $copy->count() );
44
		$this->assertNotNull( $copy->getReference( $reference->getHash() ) );
45
	}
46
47
	public function testConstructorIgnoresIdenticalObjects() {
48
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
49
		$list = new ReferenceList( [ $reference, $reference ] );
50
		$this->assertCount( 1, $list );
51
	}
52
53
	public function testConstructorDoesNotIgnoreCopies() {
54
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
55
		$list = new ReferenceList( [ $reference, clone $reference ] );
56
		$this->assertCount( 2, $list );
57
	}
58
59
	/**
60
	 * @dataProvider invalidConstructorArgumentsProvider
61
	 * @expectedException InvalidArgumentException
62
	 */
63
	public function testGivenInvalidConstructorArguments_constructorThrowsException( $input ) {
64
		new ReferenceList( $input );
65
	}
66
67
	public function invalidConstructorArgumentsProvider() {
68
		$id1 = new PropertyId( 'P1' );
69
70
		return [
71
			[ null ],
72
			[ false ],
73
			[ 1 ],
74
			[ 0.1 ],
75
			[ 'string' ],
76
			[ $id1 ],
77
			[ new PropertyNoValueSnak( $id1 ) ],
78
			[ new Reference() ],
79
			[ new SnakList( [ new PropertyNoValueSnak( $id1 ) ] ) ],
80
			[ [ new PropertyNoValueSnak( $id1 ) ] ],
81
			[ [ new ReferenceList() ] ],
82
			[ [ new SnakList() ] ],
83
		];
84
	}
85
86
	public function testGetIterator_isTraversable() {
87
		$references = new ReferenceList();
88
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
89
		$iterator = $references->getIterator();
90
91
		$this->assertInstanceOf( 'Traversable', $iterator );
92
		$this->assertCount( 1, $iterator );
93
		foreach ( $references as $reference ) {
94
			$this->assertInstanceOf( 'Wikibase\DataModel\Reference', $reference );
95
		}
96
	}
97
98
	/**
99
	 * @dataProvider instanceProvider
100
	 */
101
	public function testHasReferenceBeforeRemoveButNotAfter( ReferenceList $array ) {
102
		if ( $array->count() === 0 ) {
103
			$this->assertTrue( true );
104
			return;
105
		}
106
107
		/**
108
		 * @var Reference $hashable
109
		 */
110
		foreach ( iterator_to_array( $array ) as $hashable ) {
111
			$this->assertTrue( $array->hasReference( $hashable ) );
112
			$array->removeReference( $hashable );
113
			$this->assertFalse( $array->hasReference( $hashable ) );
114
		}
115
	}
116
117
	public function testGivenCloneOfReferenceInList_hasReferenceReturnsTrue() {
118
		$list = new ReferenceList();
119
120
		$reference = new Reference( [ new PropertyNoValueSnak( 42 ) ] );
121
		$sameReference = unserialize( serialize( $reference ) );
122
123
		$list->addReference( $reference );
124
125
		$this->assertTrue(
126
			$list->hasReference( $sameReference ),
127
			'hasReference should return true when a reference with the same value is present, even when its another instance'
128
		);
129
	}
130
131
	/**
132
	 * @dataProvider instanceProvider
133
	 */
134
	public function testRemoveReference( ReferenceList $array ) {
135
		$elementCount = count( $array );
136
137
		/**
138
		 * @var Reference $element
139
		 */
140
		foreach ( iterator_to_array( $array ) as $element ) {
141
			$this->assertTrue( $array->hasReference( $element ) );
142
143
			$array->removeReference( $element );
144
145
			$this->assertFalse( $array->hasReference( $element ) );
146
			$this->assertSame( --$elementCount, count( $array ) );
147
		}
148
	}
149
150
	public function testRemoveReferenceRemovesIdenticalObjects() {
151
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
152
		$references = new ReferenceList( [ $reference, $reference ] );
153
154
		$references->removeReference( $reference );
155
156
		$this->assertTrue( $references->isEmpty() );
157
	}
158
159
	public function testRemoveReferenceDoesNotRemoveCopies() {
160
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
161
		$references = new ReferenceList( [ $reference, clone $reference ] );
162
163
		$references->removeReference( $reference );
164
165
		$this->assertFalse( $references->isEmpty() );
166
		$this->assertTrue( $references->hasReference( $reference ) );
167
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
168
	}
169
170
	public function testAddReferenceOnEmptyList() {
171
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
172
173
		$references = new ReferenceList();
174
		$references->addReference( $reference );
175
176
		$this->assertCount( 1, $references );
177
178
		$expectedList = new ReferenceList( [ $reference ] );
179
		$this->assertSameReferenceOrder( $expectedList, $references );
180
	}
181
182
	private function assertSameReferenceOrder( ReferenceList $expectedList, ReferenceList $references ) {
183
		$this->assertSame(
184
			iterator_to_array( $expectedList ),
185
			iterator_to_array( $references )
186
		);
187
	}
188
189
	public function testAddReferenceAtTheEnd() {
190
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
191
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
192
		$reference3 = new Reference( [ new PropertyNoValueSnak( 3 ) ] );
193
194
		$references = new ReferenceList( [ $reference1, $reference2 ] );
195
		$references->addReference( $reference3 );
196
197
		$this->assertCount( 3, $references );
198
199
		$expectedList = new ReferenceList( [ $reference1, $reference2, $reference3 ] );
200
		$this->assertSameReferenceOrder( $expectedList, $references );
201
	}
202
203
	public function testAddReferenceBetweenExistingReferences() {
204
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
205
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
206
		$list = new ReferenceList( [ $reference1, $reference2 ] );
207
208
		$reference3 = new Reference( [ new PropertyNoValueSnak( 3 ) ] );
209
		$list->addReference( $reference3, 1 );
210
211
		$this->assertCount( 3, $list );
212
		$this->assertSame( 1, $list->indexOf( $reference3 ) );
213
	}
214
215
	public function testAddReferenceIgnoresIdenticalObjects() {
216
		$list = new ReferenceList();
217
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
218
		$list->addReference( $reference );
219
		$list->addReference( $reference );
220
		$this->assertCount( 1, $list );
221
	}
222
223
	public function testAddReferenceDoesNotIgnoreCopies() {
224
		$list = new ReferenceList();
225
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
226
		$list->addReference( $reference );
227
		$list->addReference( clone $reference );
228
		$this->assertCount( 2, $list );
229
	}
230
231
	public function testAddReferenceAtIndexIgnoresIdenticalObjects() {
232
		$list = new ReferenceList();
233
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
234
		$list->addReference( $reference, 0 );
235
		$list->addReference( $reference, 0 );
236
		$this->assertCount( 1, $list );
237
	}
238
239
	public function testAddReferenceAtIndexMovesIdenticalObjects() {
240
		$list = new ReferenceList();
241
		$list->addNewReference( new PropertyNoValueSnak( 1 ) );
242
		$reference = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
243
		$list->addReference( $reference );
244
		$list->addNewReference( new PropertyNoValueSnak( 3 ) );
245
246
		$this->assertSame( 1, $list->indexOf( $reference ), 'pre condition' );
247
248
		$list->addReference( $reference, 0 );
249
250
		$this->assertCount( 3, $list, 'not added' );
251
		$this->assertSame( 1, $list->indexOf( $reference ), 'can not decrease index' );
252
253
		$list->addReference( $reference, 2 );
254
255
		$this->assertCount( 3, $list, 'not added' );
256
		$this->assertSame( 1, $list->indexOf( $reference ), 'can not increase index' );
257
	}
258
259
	public function testAddReferenceAtIndexZero() {
260
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
261
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
262
		$reference3 = new Reference( [ new PropertyNoValueSnak( 3 ) ] );
263
264
		$references = new ReferenceList( [ $reference1, $reference2 ] );
265
		$references->addReference( $reference3, 0 );
266
267
		$expectedList = new ReferenceList( [ $reference3, $reference1, $reference2 ] );
268
		$this->assertSameReferenceOrder( $expectedList, $references );
269
	}
270
271
	public function testAddReferenceAtNegativeIndex() {
272
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
273
		$referenceList = new ReferenceList();
274
275
		$this->setExpectedException( 'InvalidArgumentException' );
276
		$referenceList->addReference( $reference, -1 );
277
	}
278
279
	public function testGivenEmptyReference_addReferenceDoesNotAdd() {
280
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
281
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
282
		$emptyReference = new Reference( [] );
283
284
		$references = new ReferenceList( [ $reference1, $reference2 ] );
285
		$references->addReference( $emptyReference );
286
287
		$expectedList = new ReferenceList( [ $reference1, $reference2 ] );
288
		$this->assertSameReferenceOrder( $expectedList, $references );
289
	}
290
291
	public function testGivenEmptyReferenceAndIndex_addReferenceDoesNotAdd() {
292
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
293
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
294
		$emptyReference = new Reference( [] );
295
296
		$references = new ReferenceList( [ $reference1, $reference2 ] );
297
		$references->addReference( $emptyReference, 0 );
298
299
		$expectedList = new ReferenceList( [ $reference1, $reference2 ] );
300
		$this->assertSameReferenceOrder( $expectedList, $references );
301
	}
302
303
	/**
304
	 * @dataProvider instanceProvider
305
	 */
306
	public function testIndexOf( ReferenceList $array ) {
307
		$this->assertFalse( $array->indexOf( new Reference() ) );
308
309
		$i = 0;
310
		foreach ( $array as $reference ) {
311
			$this->assertSame( $i++, $array->indexOf( $reference ) );
312
		}
313
	}
314
315
	public function testIndexOf_checksForIdentity() {
316
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
317
		$reference2 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
318
		$referenceList = new ReferenceList( [ $reference1 ] );
319
320
		$this->assertNotSame( $reference1, $reference2, 'post condition' );
321
		$this->assertTrue( $reference1->equals( $reference2 ), 'post condition' );
322
		$this->assertSame( 0, $referenceList->indexOf( $reference1 ), 'identity' );
323
		$this->assertFalse( $referenceList->indexOf( $reference2 ), 'not equality' );
324
	}
325
326
	/**
327
	 * @dataProvider instanceProvider
328
	 */
329
	public function testEquals( ReferenceList $array ) {
330
		$this->assertTrue( $array->equals( $array ) );
331
		$this->assertFalse( $array->equals( 42 ) );
332
	}
333
334
	/**
335
	 * @dataProvider instanceProvider
336
	 */
337
	public function testGetValueHashReturnsString( ReferenceList $array ) {
338
		$this->assertInternalType( 'string', $array->getValueHash() );
339
	}
340
341
	/**
342
	 * @dataProvider instanceProvider
343
	 */
344
	public function testGetValueHashIsTheSameForClone( ReferenceList $array ) {
345
		$copy = unserialize( serialize( $array ) );
346
		$this->assertSame( $array->getValueHash(), $copy->getValueHash() );
347
	}
348
349
	/**
350
	 * @dataProvider instanceProvider
351
	 */
352
	public function testHasReferenceHash( ReferenceList $references ) {
353
		$this->assertFalse( $references->hasReferenceHash( '~=[,,_,,]:3' ) );
354
355
		/**
356
		 * @var Hashable $reference
357
		 */
358
		foreach ( $references as $reference ) {
359
			$this->assertTrue( $references->hasReferenceHash( $reference->getHash() ) );
360
		}
361
	}
362
363
	/**
364
	 * @dataProvider instanceProvider
365
	 */
366
	public function testGetReference( ReferenceList $references ) {
367
		$this->assertNull( $references->getReference( '~=[,,_,,]:3' ) );
368
369
		/**
370
		 * @var Reference $reference
371
		 */
372
		foreach ( $references as $reference ) {
373
			$this->assertTrue( $reference->equals( $references->getReference( $reference->getHash() ) ) );
374
		}
375
	}
376
377
	/**
378
	 * @dataProvider instanceProvider
379
	 */
380
	public function testRemoveReferenceHash( ReferenceList $references ) {
381
		$references->removeReferenceHash( '~=[,,_,,]:3' );
382
383
		$hashes = [];
384
385
		/**
386
		 * @var Reference $reference
387
		 */
388
		foreach ( $references as $reference ) {
389
			$hashes[] = $reference->getHash();
390
		}
391
392
		foreach ( $hashes as $hash ) {
393
			$references->removeReferenceHash( $hash );
394
		}
395
396
		$this->assertTrue( $references->isEmpty() );
397
	}
398
399
	public function testRemoveReferenceHashRemovesIdenticalObjects() {
400
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
401
		$references = new ReferenceList( [ $reference, $reference ] );
402
403
		$references->removeReferenceHash( $reference->getHash() );
404
405
		$this->assertTrue( $references->isEmpty() );
406
	}
407
408
	public function testRemoveReferenceHashDoesNotRemoveCopies() {
409
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
410
		$references = new ReferenceList( [ $reference, clone $reference ] );
411
412
		$references->removeReferenceHash( $reference->getHash() );
413
414
		$this->assertFalse( $references->isEmpty() );
415
		$this->assertTrue( $references->hasReference( $reference ) );
416
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
417
	}
418
419
	public function testRemoveReferenceHashUpdatesIndexes() {
420
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
421
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
422
		$references = new ReferenceList( [ $reference1, $reference2 ] );
423
424
		$references->removeReferenceHash( $reference1->getHash() );
425
426
		$this->assertSame( 0, $references->indexOf( $reference2 ) );
427
	}
428
429
	public function testGivenOneSnak_addNewReferenceAddsSnak() {
430
		$references = new ReferenceList();
431
		$snak = new PropertyNoValueSnak( 1 );
432
433
		$references->addNewReference( $snak );
434
		$this->assertTrue( $references->hasReference( new Reference( [ $snak ] ) ) );
435
	}
436
437
	public function testGivenMultipleSnaks_addNewReferenceAddsThem() {
438
		$references = new ReferenceList();
439
		$snak1 = new PropertyNoValueSnak( 1 );
440
		$snak2 = new PropertyNoValueSnak( 3 );
441
		$snak3 = new PropertyNoValueSnak( 2 );
442
443
		$references->addNewReference( $snak1, $snak2, $snak3 );
444
445
		$expectedSnaks = [ $snak1, $snak2, $snak3 ];
446
		$this->assertTrue( $references->hasReference( new Reference( $expectedSnaks ) ) );
447
	}
448
449
	public function testGivenAnArrayOfSnaks_addNewReferenceAddsThem() {
450
		$references = new ReferenceList();
451
		$snaks = [
452
			new PropertyNoValueSnak( 1 ),
453
			new PropertyNoValueSnak( 3 ),
454
			new PropertyNoValueSnak( 2 )
455
		];
456
457
		$references->addNewReference( $snaks );
458
		$this->assertTrue( $references->hasReference( new Reference( $snaks ) ) );
459
	}
460
461
	public function testAddNewReferenceDoesNotIgnoreIdenticalObjects() {
462
		$list = new ReferenceList();
463
		$snak = new PropertyNoValueSnak( 1 );
464
		$list->addNewReference( $snak );
465
		$list->addNewReference( $snak );
466
		$this->assertCount( 2, $list );
467
	}
468
469
	public function testAddNewReferenceDoesNotIgnoreCopies() {
470
		$list = new ReferenceList();
471
		$snak = new PropertyNoValueSnak( 1 );
472
		$list->addNewReference( $snak );
473
		$list->addNewReference( clone $snak );
474
		$this->assertCount( 2, $list );
475
	}
476
477
	public function testGivenNoneSnak_addNewReferenceThrowsException() {
478
		$references = new ReferenceList();
479
480
		$this->setExpectedException( 'InvalidArgumentException' );
481
		$references->addNewReference( new PropertyNoValueSnak( 1 ), null );
482
	}
483
484
	public function testEmptySerializationStability() {
485
		$list = new ReferenceList();
486
		$this->assertSame( 'a:0:{}', $list->serialize() );
487
	}
488
489
	public function testSerializationStability() {
490
		$list = new ReferenceList();
491
		$list->addNewReference( new PropertyNoValueSnak( 1 ) );
492
		$this->assertSame(
493
			"a:1:{i:0;O:28:\"Wikibase\\DataModel\\Reference\":1:{s:35:\"\x00Wikibase\\DataModel\\"
494
			. "Reference\x00snaks\";C:32:\"Wikibase\\DataModel\\Snak\\SnakList\":102:{a:2:{s:4:\""
495
			. 'data";a:1:{i:0;C:43:"Wikibase\\DataModel\\Snak\\PropertyNoValueSnak":4:{i:1;}}s:5'
496
			. ':"index";i:0;}}}}',
497
			$list->serialize()
498
		);
499
	}
500
501
	public function testSerializeUnserializeRoundtrip() {
502
		$original = new ReferenceList();
503
		$original->addNewReference( new PropertyNoValueSnak( 1 ) );
504
505
		/** @var ReferenceList $clone */
506
		$clone = unserialize( serialize( $original ) );
507
508
		$this->assertTrue( $original->equals( $clone ) );
509
		$this->assertSame( $original->getValueHash(), $clone->getValueHash() );
510
		$this->assertSame( $original->serialize(), $clone->serialize() );
511
	}
512
513
	public function testUnserializeCreatesNonIdenticalClones() {
514
		$original = new ReferenceList();
515
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
516
		$original->addReference( $reference );
517
518
		/** @var ReferenceList $clone */
519
		$clone = unserialize( serialize( $original ) );
520
		$clone->addReference( $reference );
521
522
		$this->assertCount( 2, $clone );
523
	}
524
525
	public function testGivenEmptyList_isEmpty() {
526
		$references = new ReferenceList();
527
		$this->assertTrue( $references->isEmpty() );
528
	}
529
530
	public function testGivenNonEmptyList_isNotEmpty() {
531
		$references = new ReferenceList();
532
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
533
534
		$this->assertFalse( $references->isEmpty() );
535
	}
536
537
}
538