Passed
Push — master ( c145f7...3ce0e8 )
by Jeroen De
38s
created

SnakListTest::instanceProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 14
nc 1
nop 0
1
<?php
2
3
namespace Wikibase\DataModel\Tests\Snak;
4
5
use Comparable;
6
use DataValues\StringValue;
7
use Hashable;
8
use InvalidArgumentException;
9
use Wikibase\DataModel\Entity\PropertyId;
10
use Wikibase\DataModel\Snak\PropertyNoValueSnak;
11
use Wikibase\DataModel\Snak\PropertyValueSnak;
12
use Wikibase\DataModel\Snak\Snak;
13
use Wikibase\DataModel\Snak\SnakList;
14
use Wikibase\DataModel\Tests\HashArray\HashArrayTest;
15
16
/**
17
 * @covers Wikibase\DataModel\Snak\SnakList
18
 * @uses DataValues\StringValue
19
 * @uses Wikibase\DataModel\Entity\PropertyId
20
 * @uses Wikibase\DataModel\Snak\PropertyNoValueSnak
21
 * @uses Wikibase\DataModel\Snak\PropertyValueSnak
22
 * @uses Wikibase\DataModel\Snak\Snak
23
 * @uses Wikibase\DataModel\Snak\SnakList
24
 * @uses Wikibase\DataModel\HashArray
25
 * @uses Wikibase\DataModel\Snak\SnakObject
26
 * @uses Wikibase\DataModel\Internal\MapValueHasher
27
 * @uses Wikibase\DataModel\Entity\EntityId
28
 *
29
 * @license GPL-2.0+
30
 * @author Jeroen De Dauw < [email protected] >
31
 * @author Addshore
32
 * @author Thiemo Mättig
33
 */
34
class SnakListTest extends HashArrayTest {
35
36
	public function elementInstancesProvider() {
37
		$id42 = new PropertyId( 'P42' );
38
39
		$argLists = [];
40
41
		$argLists[] = [ [ new PropertyNoValueSnak( $id42 ) ] ];
42
		$argLists[] = [ [ new PropertyNoValueSnak( new PropertyId( 'P9001' ) ) ] ];
43
		$argLists[] = [ [ new PropertyValueSnak( $id42, new StringValue( 'a' ) ) ] ];
44
45
		return $argLists;
46
	}
47
48
	public function instanceProvider() {
49
		$id42 = new PropertyId( 'P42' );
50
		$id9001 = new PropertyId( 'P9001' );
51
52
		return [
53
			[ new SnakList() ],
54
			[ new SnakList( [
55
				new PropertyNoValueSnak( $id42 )
56
			] ) ],
57
			[ new SnakList( [
58
				new PropertyNoValueSnak( $id42 ),
59
				new PropertyNoValueSnak( $id9001 ),
60
			] ) ],
61
			[ new SnakList( [
62
				new PropertyNoValueSnak( $id42 ),
63
				new PropertyNoValueSnak( $id9001 ),
64
				new PropertyValueSnak( $id42, new StringValue( 'a' ) ),
65
			] ) ],
66
		];
67
	}
68
69
	/**
70
	 * @dataProvider invalidConstructorArgumentsProvider
71
	 * @expectedException InvalidArgumentException
72
	 */
73
	public function testGivenInvalidConstructorArguments_constructorThrowsException( $input ) {
74
		new SnakList( $input );
75
	}
76
77
	public function invalidConstructorArgumentsProvider() {
78
		$id1 = new PropertyId( 'P1' );
79
80
		return [
81
			[ null ],
82
			[ false ],
83
			[ 1 ],
84
			[ 0.1 ],
85
			[ 'string' ],
86
			[ $id1 ],
87
			[ new PropertyNoValueSnak( $id1 ) ],
88
			[ new PropertyValueSnak( $id1, new StringValue( 'a' ) ) ],
89
			[ [ null ] ],
90
			[ [ $id1 ] ],
91
			[ [ new SnakList() ] ],
92
		];
93
	}
94
95
	public function testGivenAssociativeArray_constructorPreservesArrayKeys() {
96
		$snakList = new SnakList( [ 'key' => new PropertyNoValueSnak( 1 ) ] );
97
		$this->assertSame( [ 'key' ], array_keys( iterator_to_array( $snakList ) ) );
98
	}
99
100
	/**
101
	 * @dataProvider instanceProvider
102
	 * @param SnakList $array
103
	 */
104
	public function testHasSnak( SnakList $array ) {
105
		/**
106
		 * @var Snak $hashable
107
		 */
108
		foreach ( iterator_to_array( $array ) as $hashable ) {
109
			$this->assertTrue( $array->hasSnak( $hashable ) );
110
			$this->assertTrue( $array->hasSnakHash( $hashable->getHash() ) );
111
			$array->removeSnak( $hashable );
112
			$this->assertFalse( $array->hasSnak( $hashable ) );
113
			$this->assertFalse( $array->hasSnakHash( $hashable->getHash() ) );
114
		}
115
116
		$this->assertTrue( true );
117
	}
118
119
	/**
120
	 * @dataProvider instanceProvider
121
	 * @param SnakList $array
122
	 */
123
	public function testRemoveSnak( SnakList $array ) {
124
		$elementCount = $array->count();
125
126
		/**
127
		 * @var Snak $element
128
		 */
129
		foreach ( iterator_to_array( $array ) as $element ) {
130
			$this->assertTrue( $array->hasSnak( $element ) );
131
132
			if ( $elementCount % 2 === 0 ) {
133
				$array->removeSnak( $element );
134
			}
135
			else {
136
				$array->removeSnakHash( $element->getHash() );
137
			}
138
139
			$this->assertFalse( $array->hasSnak( $element ) );
140
			$this->assertEquals( --$elementCount, $array->count() );
141
		}
142
143
		$element = new PropertyNoValueSnak( new PropertyId( 'P42' ) );
144
145
		$array->removeSnak( $element );
146
		$array->removeSnakHash( $element->getHash() );
147
148
		$this->assertTrue( true );
149
	}
150
151
	/**
152
	 * @dataProvider instanceProvider
153
	 * @param SnakList $array
154
	 */
155
	public function testAddSnak( SnakList $array ) {
156
		$elementCount = $array->count();
157
158
		$elements = $this->elementInstancesProvider();
159
		$element = array_shift( $elements );
160
		$element = $element[0][0];
161
162
		if ( !$array->hasSnak( $element ) ) {
163
			++$elementCount;
164
		}
165
166
		$this->assertEquals( !$array->hasSnak( $element ), $array->addSnak( $element ) );
167
168
		$this->assertEquals( $elementCount, $array->count() );
169
170
		$this->assertFalse( $array->addSnak( $element ) );
171
172
		$this->assertEquals( $elementCount, $array->count() );
173
	}
174
175
	public function orderByPropertyProvider() {
176
		$id1 = new PropertyId( 'P1' );
177
		$id2 = new PropertyId( 'P2' );
178
		$id3 = new PropertyId( 'P3' );
179
180
		/**
181
		 * List of test data containing snaks to initialize SnakList objects. The first list of
182
		 * snaks represents the snak list to be used as test input while the second represents the
183
		 * expected result.
184
		 * @var array
185
		 */
186
		$rawArguments = [
187
			'Default order' => [
188
				[],
189
				[],
190
			],
191
			'Unknown id in order' => [
192
				[],
193
				[],
194
				[ 'P1' ]
195
			],
196
			[
197
				[ new PropertyNoValueSnak( $id1 ) ],
198
				[ new PropertyNoValueSnak( $id1 ) ],
199
			],
200
			[
201
				[
202
					new PropertyNoValueSnak( $id2 ),
203
					new PropertyNoValueSnak( $id1 ),
204
				],
205
				[
206
					new PropertyNoValueSnak( $id2 ),
207
					new PropertyNoValueSnak( $id1 ),
208
				],
209
			],
210
			[
211
				[
212
					new PropertyNoValueSnak( $id1 ),
213
					new PropertyNoValueSnak( $id2 ),
214
					new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
215
				],
216
				[
217
					new PropertyNoValueSnak( $id1 ),
218
					new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
219
					new PropertyNoValueSnak( $id2 ),
220
				],
221
			],
222
			'With additional order' => [
223
				[
224
					new PropertyNoValueSnak( $id3 ),
225
					new PropertyNoValueSnak( $id2 ),
226
					new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
227
				],
228
				[
229
					new PropertyNoValueSnak( $id2 ),
230
					new PropertyNoValueSnak( $id3 ),
231
					new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
232
				],
233
				[ 'P2' ]
234
			],
235
			[
236
				[
237
					new PropertyNoValueSnak( $id3 ),
238
					new PropertyNoValueSnak( $id2 ),
239
					new PropertyNoValueSnak( $id2 ),
240
					new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
241
					new PropertyNoValueSnak( $id1 ),
242
				],
243
				[
244
					new PropertyValueSnak( $id1, new StringValue( 'a' ) ),
245
					new PropertyNoValueSnak( $id1 ),
246
					new PropertyNoValueSnak( $id3 ),
247
					new PropertyNoValueSnak( $id2 ),
248
					new PropertyNoValueSnak( $id2 ),
249
				],
250
				[ 'P1' ]
251
			],
252
		];
253
254
		$arguments = [];
255
256
		foreach ( $rawArguments as $key => $rawArgument ) {
257
			$arguments[$key] = [
258
				new SnakList( $rawArgument[0] ),
259
				new SnakList( $rawArgument[1] ),
260
				array_key_exists( 2, $rawArgument ) ? $rawArgument[2] : []
261
			];
262
		}
263
264
		return $arguments;
265
	}
266
267
	/**
268
	 * @dataProvider orderByPropertyProvider
269
	 */
270
	public function testOrderByProperty( SnakList $snakList, SnakList $expected, array $order = [] ) {
271
		$initialSnakList = new SnakList( array_values( iterator_to_array( $snakList ) ) );
272
273
		$snakList->orderByProperty( $order );
274
275
		// Instantiate new SnakList resetting the snaks' array keys. This allows comparing the
276
		// reordered SnakList to the expected SnakList.
277
		$orderedSnakList = new SnakList( array_values( iterator_to_array( $snakList ) ) );
278
279
		$this->assertEquals( $expected, $orderedSnakList );
280
281
		if ( $orderedSnakList->equals( $initialSnakList ) ) {
282
			$this->assertSame( $initialSnakList->getHash(), $snakList->getHash() );
283
		} else {
284
			$this->assertNotSame( $initialSnakList->getHash(), $snakList->getHash() );
285
		}
286
	}
287
288
	public function testComparableInterface() {
289
		$this->assertInstanceOf( Comparable::class, new SnakList() );
290
	}
291
292
	/**
293
	 * @dataProvider equalsProvider
294
	 */
295
	public function testEquals( SnakList $list1, SnakList $list2, $expected ) {
296
		$this->assertSame( $expected, $list1->equals( $list2 ) );
297
	}
298
299
	public function equalsProvider() {
300
		$empty = new SnakList();
301
		$oneSnak = new SnakList( [ new PropertyNoValueSnak( 1 ) ] );
302
303
		return [
304
			'empty object is equal to itself' => [
305
				$empty,
306
				$empty,
307
				true
308
			],
309
			'non-empty object is equal to itself' => [
310
				$oneSnak,
311
				$oneSnak,
312
				true
313
			],
314
			'different empty objects are equal' => [
315
				$empty,
316
				new SnakList(),
317
				true
318
			],
319
			'different objects with same content are equal' => [
320
				$oneSnak,
321
				new SnakList( [ new PropertyNoValueSnak( 1 ) ] ),
322
				true
323
			],
324
			'different objects with different content are not equal' => [
325
				$oneSnak,
326
				new SnakList( [ new PropertyNoValueSnak( 2 ) ] ),
327
				false
328
			],
329
		];
330
	}
331
332
	public function testHashableInterface() {
333
		$this->assertInstanceOf( Hashable::class, new SnakList() );
334
	}
335
336
	public function testGetHash() {
337
		$snakList = new SnakList( [ new PropertyNoValueSnak( 1 ) ] );
338
		$hash = $snakList->getHash();
339
340
		$this->assertInternalType( 'string', $hash, 'must be a string' );
341
		$this->assertNotSame( '', $hash, 'must not be empty' );
342
		$this->assertSame( $hash, $snakList->getHash(), 'second call must return the same hash' );
343
344
		$otherList = new SnakList( [ new PropertyNoValueSnak( 2 ) ] );
345
		$this->assertNotSame( $hash, $otherList->getHash() );
346
	}
347
348
	/**
349
	 * This integration test (relies on SnakObject::getHash) is supposed to break whenever the hash
350
	 * calculation changes.
351
	 */
352
	public function testHashStability() {
353
		$snakList = new SnakList();
354
		$this->assertSame( 'da39a3ee5e6b4b0d3255bfef95601890afd80709', $snakList->getHash() );
355
356
		$snakList = new SnakList( [ new PropertyNoValueSnak( 1 ) ] );
357
		$this->assertSame( '4327ac5109aaf437ccce05580c563a5857d96c82', $snakList->getHash() );
358
	}
359
360
	/**
361
	 * @dataProvider provideEqualSnakLists
362
	 */
363
	public function testGivenEqualSnakLists_getHashIsTheSame( SnakList $self, SnakList $other ) {
364
		$this->assertSame( $self->getHash(), $other->getHash() );
365
	}
366
367
	public function provideEqualSnakLists() {
368
		$empty = new SnakList();
369
		$oneSnak = new SnakList( [ new PropertyNoValueSnak( 1 ) ] );
370
371
		return [
372
			'same empty object' => [ $empty, $empty ],
373
			'same non-empty object' => [ $oneSnak, $oneSnak ],
374
			'equal empty objects' => [ $empty, new SnakList() ],
375
			'equal non-empty objects' => [ $oneSnak, new SnakList( [ new PropertyNoValueSnak( 1 ) ] ) ],
376
		];
377
	}
378
379
}
380