Completed
Push — refListTestMutations ( 38b2f8 )
by no
03:12
created

ReferenceListTest::testGetReference()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
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
		$this->assertSame( 1, $list->indexOf( $reference ), 'pre condition' );
245
246
		$list->addReference( $reference, 0 );
247
248
		$this->assertCount( 2, $list, 'not added' );
249
		$this->assertSame( 0, $list->indexOf( $reference ), 'can decrease index' );
250
251
		$list->addReference( $reference, 2 );
252
253
		$this->assertCount( 2, $list, 'not added' );
254
		$this->assertSame( 0, $list->indexOf( $reference ), 'can not increase index' );
255
	}
256
257
	public function testAddReferenceAtIndexZero() {
258
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
259
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
260
		$reference3 = new Reference( [ new PropertyNoValueSnak( 3 ) ] );
261
262
		$references = new ReferenceList( [ $reference1, $reference2 ] );
263
		$references->addReference( $reference3, 0 );
264
265
		$expectedList = new ReferenceList( [ $reference3, $reference1, $reference2 ] );
266
		$this->assertSameReferenceOrder( $expectedList, $references );
267
	}
268
269
	public function testAddReferenceAtNegativeIndex() {
270
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
271
		$referenceList = new ReferenceList();
272
273
		$this->setExpectedException( 'InvalidArgumentException' );
274
		$referenceList->addReference( $reference, -1 );
275
	}
276
277
	public function testGivenEmptyReference_addReferenceDoesNotAdd() {
278
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
279
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
280
		$emptyReference = new Reference( [] );
281
282
		$references = new ReferenceList( [ $reference1, $reference2 ] );
283
		$references->addReference( $emptyReference );
284
285
		$expectedList = new ReferenceList( [ $reference1, $reference2 ] );
286
		$this->assertSameReferenceOrder( $expectedList, $references );
287
	}
288
289
	public function testGivenEmptyReferenceAndIndex_addReferenceDoesNotAdd() {
290
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
291
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
292
		$emptyReference = new Reference( [] );
293
294
		$references = new ReferenceList( [ $reference1, $reference2 ] );
295
		$references->addReference( $emptyReference, 0 );
296
297
		$expectedList = new ReferenceList( [ $reference1, $reference2 ] );
298
		$this->assertSameReferenceOrder( $expectedList, $references );
299
	}
300
301
	/**
302
	 * @dataProvider instanceProvider
303
	 */
304
	public function testIndexOf( ReferenceList $array ) {
305
		$this->assertFalse( $array->indexOf( new Reference() ) );
306
307
		$i = 0;
308
		foreach ( $array as $reference ) {
309
			$this->assertSame( $i++, $array->indexOf( $reference ) );
310
		}
311
	}
312
313
	public function testIndexOf_checksForIdentity() {
314
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
315
		$reference2 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
316
		$referenceList = new ReferenceList( [ $reference1 ] );
317
318
		$this->assertNotSame( $reference1, $reference2, 'post condition' );
319
		$this->assertTrue( $reference1->equals( $reference2 ), 'post condition' );
320
		$this->assertSame( 0, $referenceList->indexOf( $reference1 ), 'identity' );
321
		$this->assertFalse( $referenceList->indexOf( $reference2 ), 'not equality' );
322
	}
323
324
	/**
325
	 * @dataProvider instanceProvider
326
	 */
327
	public function testEquals( ReferenceList $array ) {
328
		$this->assertTrue( $array->equals( $array ) );
329
		$this->assertFalse( $array->equals( 42 ) );
330
	}
331
332
	/**
333
	 * @dataProvider instanceProvider
334
	 */
335
	public function testGetValueHashReturnsString( ReferenceList $array ) {
336
		$this->assertInternalType( 'string', $array->getValueHash() );
337
	}
338
339
	/**
340
	 * @dataProvider instanceProvider
341
	 */
342
	public function testGetValueHashIsTheSameForClone( ReferenceList $array ) {
343
		$copy = unserialize( serialize( $array ) );
344
		$this->assertSame( $array->getValueHash(), $copy->getValueHash() );
345
	}
346
347
	/**
348
	 * @dataProvider instanceProvider
349
	 */
350
	public function testHasReferenceHash( ReferenceList $references ) {
351
		$this->assertFalse( $references->hasReferenceHash( '~=[,,_,,]:3' ) );
352
353
		/**
354
		 * @var Hashable $reference
355
		 */
356
		foreach ( $references as $reference ) {
357
			$this->assertTrue( $references->hasReferenceHash( $reference->getHash() ) );
358
		}
359
	}
360
361
	/**
362
	 * @dataProvider instanceProvider
363
	 */
364
	public function testGetReference( ReferenceList $references ) {
365
		$this->assertNull( $references->getReference( '~=[,,_,,]:3' ) );
366
367
		/**
368
		 * @var Reference $reference
369
		 */
370
		foreach ( $references as $reference ) {
371
			$this->assertTrue( $reference->equals( $references->getReference( $reference->getHash() ) ) );
372
		}
373
	}
374
375
	/**
376
	 * @dataProvider instanceProvider
377
	 */
378
	public function testRemoveReferenceHash( ReferenceList $references ) {
379
		$references->removeReferenceHash( '~=[,,_,,]:3' );
380
381
		$hashes = [];
382
383
		/**
384
		 * @var Reference $reference
385
		 */
386
		foreach ( $references as $reference ) {
387
			$hashes[] = $reference->getHash();
388
		}
389
390
		foreach ( $hashes as $hash ) {
391
			$references->removeReferenceHash( $hash );
392
		}
393
394
		$this->assertTrue( $references->isEmpty() );
395
	}
396
397
	public function testRemoveReferenceHashRemovesIdenticalObjects() {
398
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
399
		$references = new ReferenceList( [ $reference, $reference ] );
400
401
		$references->removeReferenceHash( $reference->getHash() );
402
403
		$this->assertTrue( $references->isEmpty() );
404
	}
405
406
	public function testRemoveReferenceHashDoesNotRemoveCopies() {
407
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
408
		$references = new ReferenceList( [ $reference, clone $reference ] );
409
410
		$references->removeReferenceHash( $reference->getHash() );
411
412
		$this->assertFalse( $references->isEmpty() );
413
		$this->assertTrue( $references->hasReference( $reference ) );
414
		$this->assertNotSame( $reference, $references->getReference( $reference->getHash() ) );
415
	}
416
417
	public function testRemoveReferenceHashUpdatesIndexes() {
418
		$reference1 = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
419
		$reference2 = new Reference( [ new PropertyNoValueSnak( 2 ) ] );
420
		$references = new ReferenceList( [ $reference1, $reference2 ] );
421
422
		$references->removeReferenceHash( $reference1->getHash() );
423
424
		$this->assertSame( 0, $references->indexOf( $reference2 ) );
425
	}
426
427
	public function testGivenOneSnak_addNewReferenceAddsSnak() {
428
		$references = new ReferenceList();
429
		$snak = new PropertyNoValueSnak( 1 );
430
431
		$references->addNewReference( $snak );
432
		$this->assertTrue( $references->hasReference( new Reference( [ $snak ] ) ) );
433
	}
434
435
	public function testGivenMultipleSnaks_addNewReferenceAddsThem() {
436
		$references = new ReferenceList();
437
		$snak1 = new PropertyNoValueSnak( 1 );
438
		$snak2 = new PropertyNoValueSnak( 3 );
439
		$snak3 = new PropertyNoValueSnak( 2 );
440
441
		$references->addNewReference( $snak1, $snak2, $snak3 );
442
443
		$expectedSnaks = [ $snak1, $snak2, $snak3 ];
444
		$this->assertTrue( $references->hasReference( new Reference( $expectedSnaks ) ) );
445
	}
446
447
	public function testGivenAnArrayOfSnaks_addNewReferenceAddsThem() {
448
		$references = new ReferenceList();
449
		$snaks = [
450
			new PropertyNoValueSnak( 1 ),
451
			new PropertyNoValueSnak( 3 ),
452
			new PropertyNoValueSnak( 2 )
453
		];
454
455
		$references->addNewReference( $snaks );
456
		$this->assertTrue( $references->hasReference( new Reference( $snaks ) ) );
457
	}
458
459
	public function testAddNewReferenceDoesNotIgnoreIdenticalObjects() {
460
		$list = new ReferenceList();
461
		$snak = new PropertyNoValueSnak( 1 );
462
		$list->addNewReference( $snak );
463
		$list->addNewReference( $snak );
464
		$this->assertCount( 2, $list );
465
	}
466
467
	public function testAddNewReferenceDoesNotIgnoreCopies() {
468
		$list = new ReferenceList();
469
		$snak = new PropertyNoValueSnak( 1 );
470
		$list->addNewReference( $snak );
471
		$list->addNewReference( clone $snak );
472
		$this->assertCount( 2, $list );
473
	}
474
475
	public function testGivenNoneSnak_addNewReferenceThrowsException() {
476
		$references = new ReferenceList();
477
478
		$this->setExpectedException( 'InvalidArgumentException' );
479
		$references->addNewReference( new PropertyNoValueSnak( 1 ), null );
480
	}
481
482
	public function testEmptySerializationStability() {
483
		$list = new ReferenceList();
484
		$this->assertSame( 'a:0:{}', $list->serialize() );
485
	}
486
487
	public function testSerializationStability() {
488
		$list = new ReferenceList();
489
		$list->addNewReference( new PropertyNoValueSnak( 1 ) );
490
		$this->assertSame(
491
			"a:1:{i:0;O:28:\"Wikibase\\DataModel\\Reference\":1:{s:35:\"\x00Wikibase\\DataModel\\"
492
			. "Reference\x00snaks\";C:32:\"Wikibase\\DataModel\\Snak\\SnakList\":102:{a:2:{s:4:\""
493
			. 'data";a:1:{i:0;C:43:"Wikibase\\DataModel\\Snak\\PropertyNoValueSnak":4:{i:1;}}s:5'
494
			. ':"index";i:0;}}}}',
495
			$list->serialize()
496
		);
497
	}
498
499
	public function testSerializeUnserializeRoundtrip() {
500
		$original = new ReferenceList();
501
		$original->addNewReference( new PropertyNoValueSnak( 1 ) );
502
503
		/** @var ReferenceList $clone */
504
		$clone = unserialize( serialize( $original ) );
505
506
		$this->assertTrue( $original->equals( $clone ) );
507
		$this->assertSame( $original->getValueHash(), $clone->getValueHash() );
508
		$this->assertSame( $original->serialize(), $clone->serialize() );
509
	}
510
511
	public function testUnserializeCreatesNonIdenticalClones() {
512
		$original = new ReferenceList();
513
		$reference = new Reference( [ new PropertyNoValueSnak( 1 ) ] );
514
		$original->addReference( $reference );
515
516
		/** @var ReferenceList $clone */
517
		$clone = unserialize( serialize( $original ) );
518
		$clone->addReference( $reference );
519
520
		$this->assertCount( 2, $clone );
521
	}
522
523
	public function testGivenEmptyList_isEmpty() {
524
		$references = new ReferenceList();
525
		$this->assertTrue( $references->isEmpty() );
526
	}
527
528
	public function testGivenNonEmptyList_isNotEmpty() {
529
		$references = new ReferenceList();
530
		$references->addNewReference( new PropertyNoValueSnak( 1 ) );
531
532
		$this->assertFalse( $references->isEmpty() );
533
	}
534
535
}
536