Completed
Push — master ( f4f4da...605cf2 )
by Jeroen De
41s
created

tests/phpunit/Patcher/MapPatcherTest.php (2 issues)

parameters are used.

Unused Code Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Diff\Tests\Patcher;
4
5
use Diff\Comparer\CallbackComparer;
6
use Diff\DiffOp\Diff\Diff;
7
use Diff\DiffOp\DiffOpAdd;
8
use Diff\DiffOp\DiffOpChange;
9
use Diff\DiffOp\DiffOpRemove;
10
use Diff\Patcher\MapPatcher;
11
use Diff\Patcher\Patcher;
12
use Diff\Tests\DiffTestCase;
13
14
/**
15
 * @covers Diff\Patcher\MapPatcher
16
 * @covers Diff\Patcher\ThrowingPatcher
17
 *
18
 * @group Diff
19
 * @group DiffPatcher
20
 * @group MapPatcherTest
21
 *
22
 * @license GPL-2.0+
23
 * @author Jeroen De Dauw < [email protected] >
24
 * @author Daniel Kinzler
25
 */
26
class MapPatcherTest extends DiffTestCase {
27
28
	public function patchProvider() {
29
		$argLists = array();
30
31
		$patcher = new MapPatcher();
32
		$base = array();
33
		$diff = new Diff();
34
		$expected = array();
35
36
		$argLists['all empty'] = array( $patcher, $base, $diff, $expected );
37
38
		$patcher = new MapPatcher();
39
		$base = array( 'foo', 'bar' => array( 'baz' ) );
40
		$diff = new Diff();
41
		$expected = array( 'foo', 'bar' => array( 'baz' ) );
42
43
		$argLists['empty patch'] = array( $patcher, $base, $diff, $expected );
44
45
		$patcher = new MapPatcher();
46
		$base = array( 'foo', 'bar' => array( 'baz' ) );
47
		$diff = new Diff( array( 'bah' => new DiffOpAdd( 'blah' ) ) );
48
		$expected = array( 'foo', 'bar' => array( 'baz' ), 'bah' => 'blah' );
49
50
		$argLists['add'] = array( $patcher, $base, $diff, $expected );
51
52
		$patcher = new MapPatcher();
53
		$base = array( 'foo', 'bar' => array( 'baz' ) );
54
		$diff = new Diff( array( 'bah' => new DiffOpAdd( 'blah' ) ) );
55
		$expected = array( 'foo', 'bar' => array( 'baz' ), 'bah' => 'blah' );
56
57
		$argLists['add2'] = array( $patcher, $base, $diff, $expected ); //FIXME: dupe?
58
59
		$patcher = new MapPatcher();
60
		$base = array();
61
		$diff = new Diff( array(
62
			'foo' => new DiffOpAdd( 'bar' ),
63
			'bah' => new DiffOpAdd( 'blah' )
64
		) );
65
		$expected = array(
66
			'foo' => 'bar',
67
			'bah' => 'blah'
68
		);
69
70
		$argLists['add to empty base'] = array( $patcher, $base, $diff, $expected );
71
72
		$patcher = new MapPatcher();
73
		$base = array(
74
			'enwiki' => array(
75
				'name'   => 'Nyan Cat',
76
				'badges' => array( 'FA' )
77
			)
78
		);
79
		$diff = new Diff( array(
80
			'nlwiki' => new Diff( array(
81
				'name'   => new DiffOpAdd( 'Nyan Cat' ),
82
				'badges' => new Diff( array(
83
					new DiffOpAdd( 'J approves' ),
84
				), false ),
85
			), true ),
86
		), true );
87
		$expected = array(
88
			'enwiki' => array(
89
				'name'   => 'Nyan Cat',
90
				'badges' => array( 'FA' )
91
			),
92
93
			'nlwiki' => array(
94
				'name'   => 'Nyan Cat',
95
				'badges' => array( 'J approves' )
96
			)
97
		);
98
99
		$argLists['add to non-existent key'] = array( $patcher, $base, $diff, $expected );
100
101
		$patcher = new MapPatcher();
102
		$base = array(
103
			'foo' => 'bar',
104
			'nyan' => 'cat',
105
			'bah' => 'blah',
106
		);
107
		$diff = new Diff( array(
108
			'foo' => new DiffOpRemove( 'bar' ),
109
			'bah' => new DiffOpRemove( 'blah' ),
110
		) );
111
		$expected = array(
112
			'nyan' => 'cat'
113
		);
114
115
		$argLists['remove'] = array( $patcher, $base, $diff, $expected );
116
117
		$patcher = new MapPatcher();
118
		$base = array(
119
			'foo' => 'bar',
120
			'nyan' => 'cat',
121
			'spam' => 'blah',
122
			'bah' => 'blah',
123
		);
124
		$diff = new Diff( array(
125
			'foo' => new DiffOpChange( 'bar', 'baz' ),
126
			'bah' => new DiffOpRemove( 'blah' ),
127
			'oh' => new DiffOpAdd( 'noez' ),
128
		) );
129
		$expected = array(
130
			'foo' => 'baz',
131
			'nyan' => 'cat',
132
			'spam' => 'blah',
133
			'oh' => 'noez',
134
		);
135
136
		$argLists['change/add/remove'] = array( $patcher, $base, $diff, $expected );
137
138
		$patcher = new MapPatcher();
139
		$base = array(
140
			'foo' => 'bar',
141
		);
142
		$diff = new Diff( array(
143
			'baz' => new Diff( array( new DiffOpAdd( 'ny' ), new DiffOpAdd( 'an' ) ), false ),
144
		) );
145
		$expected = array(
146
			'foo' => 'bar',
147
			'baz' => array( 'ny', 'an' ),
148
		);
149
150
		$argLists['add to substructure'] = array( $patcher, $base, $diff, $expected );
151
152
		// ---- conflicts ----
153
154
		$patcher = new MapPatcher();
155
		$base = array();
156
		$diff = new Diff( array(
157
			'baz' => new DiffOpRemove( 'X' ),
158
		) );
159
		$expected = $base;
160
161
		$argLists['conflict: remove missing'] = array( $patcher, $base, $diff, $expected );
162
163
		$patcher = new MapPatcher();
164
		$base = array( 'baz' => 'Y' );
165
		$diff = new Diff( array(
166
			'baz' => new DiffOpRemove( 'X' ),
167
		) );
168
		$expected = $base;
169
170
		$argLists['conflict: remove mismatching value'] = array( $patcher, $base, $diff, $expected );
171
172
		$patcher = new MapPatcher();
173
		$base = array( 'baz' => 'Y' );
174
		$diff = new Diff( array(
175
			'baz' => new DiffOpAdd( 'X' ),
176
		) );
177
		$expected = $base;
178
179
		$argLists['conflict: add existing'] = array( $patcher, $base, $diff, $expected );
180
181
		$patcher = new MapPatcher();
182
		$base = array( 'baz' => 'Y' );
183
		$diff = new Diff( array(
184
			'baz' => new DiffOpChange( 'X', 'Z' ),
185
		) );
186
		$expected = $base;
187
188
		$argLists['conflict: change mismatching value'] = array( $patcher, $base, $diff, $expected );
189
190
		$patcher = new MapPatcher();
191
		$base = array(
192
			'foo' => 'bar',
193
			'nyan' => 'cat',
194
			'spam' => 'blah',
195
			'bah' => 'blah',
196
		);
197
		$diff = new Diff( array(
198
			'foo' => new DiffOpChange( 'bar', 'var' ),
199
			'nyan' => new DiffOpRemove( 'fat' ),
200
			'bah' => new DiffOpChange( 'blubb', 'clubb' ),
201
			'yea' => new DiffOpAdd( 'stuff' ),
202
		) );
203
		$expected = array(
204
			'foo' => 'var',
205
			'nyan' => 'cat',
206
			'spam' => 'blah',
207
			'bah' => 'blah',
208
			'yea' => 'stuff',
209
		);
210
211
		$argLists['some mixed conflicts'] = array( $patcher, $base, $diff, $expected );
212
213
		return $argLists;
214
	}
215
216
	/**
217
	 * @dataProvider patchProvider
218
	 *
219
	 * @param Patcher $patcher
220
	 * @param array $base
221
	 * @param Diff $diff
222
	 * @param array $expected
223
	 */
224
	public function testPatch( Patcher $patcher, array $base, Diff $diff, array $expected ) {
225
		$actual = $patcher->patch( $base, $diff );
226
227
		$this->assertArrayEquals( $expected, $actual, true, true );
228
	}
229
230
	public function getApplicableDiffProvider() {
231
		// Diff, current object, expected
232
		$argLists = array();
233
234
		$diff = new Diff( array(), true );
235
		$currentObject = array();
236
		$expected = clone $diff;
237
238
		$argLists[] = array( $diff, $currentObject, $expected, 'Empty diff should remain empty on empty base' );
239
240
		$diff = new Diff( array(), true );
241
242
		$currentObject = array( 'foo' => 0, 'bar' => 1 );
243
244
		$expected = clone $diff;
245
246
		$argLists[] = array( $diff, $currentObject, $expected, 'Empty diff should remain empty on non-empty base' );
247
248
		$diff = new Diff( array(
249
			'foo' => new DiffOpChange( 0, 42 ),
250
			'bar' => new DiffOpChange( 1, 9001 ),
251
		), true );
252
253
		$currentObject = array( 'foo' => 0, 'bar' => 1 );
254
255
		$expected = clone $diff;
256
257
		$argLists[] = array( $diff, $currentObject, $expected, 'Diff should not be altered on matching base' );
258
259
		$diff = new Diff( array(
260
			'foo' => new DiffOpChange( 0, 42 ),
261
			'bar' => new DiffOpChange( 1, 9001 ),
262
		), true );
263
		$currentObject = array();
264
265
		$expected = new Diff( array(), true );
266
267
		$argLists[] = array( $diff, $currentObject, $expected, 'Diff with only change ops should be empty on empty base' );
268
269
		$diff = new Diff( array(
270
			'foo' => new DiffOpChange( 0, 42 ),
271
			'bar' => new DiffOpChange( 1, 9001 ),
272
		), true );
273
274
		$currentObject = array( 'foo' => 'something else', 'bar' => 1, 'baz' => 'o_O' );
275
276
		$expected = new Diff( array(
277
			'bar' => new DiffOpChange( 1, 9001 ),
278
		), true );
279
280
		$argLists[] = array( $diff, $currentObject, $expected, 'Only change ops present in the base should be retained' );
281
282
		$diff = new Diff( array(
283
			'bar' => new DiffOpRemove( 9001 ),
284
		), true );
285
286
		$currentObject = array();
287
288
		$expected = new Diff( array(), true );
289
290
		$argLists[] = array( $diff, $currentObject, $expected, 'Remove ops should be removed on empty base' );
291
292
		$diff = new Diff( array(
293
			'foo' => new DiffOpAdd( 42 ),
294
			'bar' => new DiffOpRemove( 9001 ),
295
		), true );
296
297
		$currentObject = array( 'foo' => 'bar' );
298
299
		$expected = new Diff( array(), true );
300
301
		$argLists[] = array(
302
			$diff,
303
			$currentObject,
304
			$expected,
305
			'Mismatching add ops and remove ops not present in base should be removed'
306
		);
307
308
		$diff = new Diff( array(
309
			'foo' => new DiffOpAdd( 42 ),
310
			'bar' => new DiffOpRemove( 9001 ),
311
		), true );
312
313
		$currentObject = array( 'foo' => 42, 'bar' => 9001 );
314
315
		$expected = new Diff( array(
316
			'bar' => new DiffOpRemove( 9001 ),
317
		), true );
318
319
		$argLists[] = array( $diff, $currentObject, $expected, 'Remove ops present in base should be retained' );
320
321
		$diff = new Diff( array(
322
			'foo' => new DiffOpAdd( 42 ),
323
			'bar' => new DiffOpRemove( 9001 ),
324
		), true );
325
326
		$currentObject = array();
327
328
		$expected = new Diff( array(
329
			'foo' => new DiffOpAdd( 42 ),
330
		), true );
331
332
		$argLists[] = array(
333
			$diff,
334
			$currentObject,
335
			$expected,
336
			'Add ops not present in the base should be retained (MapDiff)'
337
		);
338
339
		$diff = new Diff( array(
340
			'foo' => new Diff( array( 'bar' => new DiffOpChange( 0, 1 ) ), true ),
341
			'le-non-existing-element' => new Diff( array( 'bar' => new DiffOpChange( 0, 1 ) ), true ),
342
			'spam' => new Diff( array( new DiffOpAdd( 42 ) ), false ),
343
			new DiffOpAdd( 9001 ),
344
		), true );
345
346
		$currentObject = array(
347
			'foo' => array( 'bar' => 0, 'baz' => 'O_o' ),
348
			'spam' => array( 23, 'ohi' )
349
		);
350
351
		$expected = new Diff( array(
352
			'foo' => new Diff( array( 'bar' => new DiffOpChange( 0, 1 ) ), true ),
353
			'spam' => new Diff( array( new DiffOpAdd( 42 ) ), false ),
354
			new DiffOpAdd( 9001 ),
355
		), true );
356
357
		$argLists[] = array( $diff, $currentObject, $expected, 'Recursion should work properly' );
358
359
		return $argLists;
360
	}
361
362
	/**
363
	 * @dataProvider getApplicableDiffProvider
364
	 *
365
	 * @param Diff $diff
366
	 * @param array $currentObject
367
	 * @param Diff $expected
368
	 * @param string|null $message
369
	 */
370
	public function testGetApplicableDiff( Diff $diff, array $currentObject, Diff $expected, $message = null ) {
371
		$patcher = new MapPatcher();
372
		$actual = $patcher->getApplicableDiff( $currentObject, $diff );
373
374
		$this->assertEquals( $expected->getOperations(), $actual->getOperations(), $message );
375
	}
376
377
	public function testSetValueComparerToAlwaysFalse() {
378
		$patcher = new MapPatcher();
379
380
		$patcher->setValueComparer( new CallbackComparer( function( $firstValue, $secondValue ) {
381
			return false;
382
		} ) );
383
384
		$baseMap = array(
385
			'foo' => 42,
386
			'bar' => 9001,
387
		);
388
389
		$patch = new Diff( array(
390
			'foo' => new DiffOpChange( 42, 1337 ),
391
			'bar' => new DiffOpChange( 9001, 1337 ),
392
		) );
393
394
		$patchedMap = $patcher->patch( $baseMap, $patch );
395
396
		$this->assertEquals( $baseMap, $patchedMap );
397
	}
398
399
	public function testSetValueComparerToAlwaysTrue() {
400
		$patcher = new MapPatcher();
401
402
		$patcher->setValueComparer( new CallbackComparer( function( $firstValue, $secondValue ) {
0 ignored issues
show
The parameter $firstValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $secondValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
403
			return true;
404
		} ) );
405
406
		$baseMap = array(
407
			'foo' => 42,
408
			'bar' => 9001,
409
		);
410
411
		$patch = new Diff( array(
412
			'foo' => new DiffOpChange( 3, 1337 ),
413
			'bar' => new DiffOpChange( 3, 1337 ),
414
		) );
415
416
		$expectedMap = array(
417
			'foo' => 1337,
418
			'bar' => 1337,
419
		);
420
421
		$patchedMap = $patcher->patch( $baseMap, $patch );
422
423
		$this->assertEquals( $expectedMap, $patchedMap );
424
	}
425
426
	public function testErrorOnUnknownDiffOpType() {
427
		$patcher = new MapPatcher();
428
429
		$diffOp = $this->getMock( 'Diff\DiffOp\DiffOp' );
430
431
		$diffOp->expects( $this->any() )
432
			->method( 'getType' )
433
			->will( $this->returnValue( 'diff' ) );
434
435
		$diff = new Diff( array( $diffOp ), true );
436
437
		$patcher->patch( array(), $diff );
438
439
		$patcher->throwErrors();
440
		$this->setExpectedException( 'Diff\Patcher\PatcherException' );
441
442
		$patcher->patch( array(), $diff );
443
	}
444
445
}
446