Completed
Push — master ( 5688ab...989ec2 )
by Daniel
16:00 queued 13:11
created

testGivenMultipleSnaks_addNewReferenceAddsThem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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