Completed
Push — master ( e306e7...5688ab )
by Bekh-Ivanov
23:04 queued 19:48
created

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