Completed
Push — master ( fcf711...00bb57 )
by
unknown
02:50
created

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

Severity

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
 * @licence GNU GPL v2+
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
39
		$patcher = new MapPatcher();
40
		$base = array( 'foo', 'bar' => array( 'baz' ) );
41
		$diff = new Diff();
42
		$expected = array( 'foo', 'bar' => array( 'baz' ) );
43
44
		$argLists['empty patch'] = array( $patcher, $base, $diff, $expected );
45
46
47
		$patcher = new MapPatcher();
48
		$base = array( 'foo', 'bar' => array( 'baz' ) );
49
		$diff = new Diff( array( 'bah' => new DiffOpAdd( 'blah' ) ) );
50
		$expected = array( 'foo', 'bar' => array( 'baz' ), 'bah' => 'blah' );
51
52
		$argLists['add'] = array( $patcher, $base, $diff, $expected );
53
54
55
		$patcher = new MapPatcher();
56
		$base = array( 'foo', 'bar' => array( 'baz' ) );
57
		$diff = new Diff( array( 'bah' => new DiffOpAdd( 'blah' ) ) );
58
		$expected = array( 'foo', 'bar' => array( 'baz' ), 'bah' => 'blah' );
59
60
		$argLists['add2'] = array( $patcher, $base, $diff, $expected ); //FIXME: dupe?
61
62
63
		$patcher = new MapPatcher();
64
		$base = array();
65
		$diff = new Diff( array(
66
			'foo' => new DiffOpAdd( 'bar' ),
67
			'bah' => new DiffOpAdd( 'blah' )
68
		) );
69
		$expected = array(
70
			'foo' => 'bar',
71
			'bah' => 'blah'
72
		);
73
74
		$argLists['add to empty base'] = array( $patcher, $base, $diff, $expected );
75
76
77
		$patcher = new MapPatcher();
78
		$base = array(
79
			'enwiki' => array(
80
				'name'   => 'Nyan Cat',
81
				'badges' => array( 'FA' )
82
			)
83
		);
84
		$diff = new Diff( array(
85
			'nlwiki' => new Diff( array(
86
				'name'   => new DiffOpAdd( 'Nyan Cat' ),
87
				'badges' => new Diff( array(
88
					new DiffOpAdd( 'J approves' ),
89
				), false ),
90
			), true ),
91
		), true );
92
		$expected = array(
93
			'enwiki' => array(
94
				'name'   => 'Nyan Cat',
95
				'badges' => array( 'FA' )
96
			),
97
98
			'nlwiki' => array(
99
				'name'   => 'Nyan Cat',
100
				'badges' => array( 'J approves' )
101
			)
102
		);
103
104
		$argLists['add to non-existent key'] = array( $patcher, $base, $diff, $expected );
105
106
107
		$patcher = new MapPatcher();
108
		$base = array(
109
			'foo' => 'bar',
110
			'nyan' => 'cat',
111
			'bah' => 'blah',
112
		);
113
		$diff = new Diff( array(
114
			'foo' => new DiffOpRemove( 'bar' ),
115
			'bah' => new DiffOpRemove( 'blah' ),
116
		) );
117
		$expected = array(
118
			'nyan' => 'cat'
119
		);
120
121
		$argLists['remove'] = array( $patcher, $base, $diff, $expected );
122
123
124
		$patcher = new MapPatcher();
125
		$base = array(
126
			'foo' => 'bar',
127
			'nyan' => 'cat',
128
			'spam' => 'blah',
129
			'bah' => 'blah',
130
		);
131
		$diff = new Diff( array(
132
			'foo' => new DiffOpChange( 'bar', 'baz' ),
133
			'bah' => new DiffOpRemove( 'blah' ),
134
			'oh' => new DiffOpAdd( 'noez' ),
135
		) );
136
		$expected = array(
137
			'foo' => 'baz',
138
			'nyan' => 'cat',
139
			'spam' => 'blah',
140
			'oh' => 'noez',
141
		);
142
143
		$argLists['change/add/remove'] = array( $patcher, $base, $diff, $expected );
144
145
146
		$patcher = new MapPatcher();
147
		$base = array(
148
			'foo' => 'bar',
149
		);
150
		$diff = new Diff( array(
151
			'baz' => new Diff( array( new DiffOpAdd( 'ny' ), new DiffOpAdd( 'an' ) ), false ),
152
		) );
153
		$expected = array(
154
			'foo' => 'bar',
155
			'baz' => array( 'ny', 'an' ),
156
		);
157
158
		$argLists['add to substructure'] = array( $patcher, $base, $diff, $expected );
159
160
161
		// ---- conflicts ----
162
163
		$patcher = new MapPatcher();
164
		$base = array();
165
		$diff = new Diff( array(
166
			'baz' => new DiffOpRemove( 'X' ),
167
		) );
168
		$expected = $base;
169
170
		$argLists['conflict: remove missing'] = array( $patcher, $base, $diff, $expected );
171
172
173
		$patcher = new MapPatcher();
174
		$base = array( 'baz' => 'Y' );
175
		$diff = new Diff( array(
176
			'baz' => new DiffOpRemove( 'X' ),
177
		) );
178
		$expected = $base;
179
180
		$argLists['conflict: remove mismatching value'] = array( $patcher, $base, $diff, $expected );
181
182
183
		$patcher = new MapPatcher();
184
		$base = array( 'baz' => 'Y' );
185
		$diff = new Diff( array(
186
			'baz' => new DiffOpAdd( 'X' ),
187
		) );
188
		$expected = $base;
189
190
		$argLists['conflict: add existing'] = array( $patcher, $base, $diff, $expected );
191
192
193
		$patcher = new MapPatcher();
194
		$base = array( 'baz' => 'Y' );
195
		$diff = new Diff( array(
196
			'baz' => new DiffOpChange( 'X', 'Z' ),
197
		) );
198
		$expected = $base;
199
200
		$argLists['conflict: change mismatching value'] = array( $patcher, $base, $diff, $expected );
201
202
203
		$patcher = new MapPatcher();
204
		$base = array(
205
			'foo' => 'bar',
206
			'nyan' => 'cat',
207
			'spam' => 'blah',
208
			'bah' => 'blah',
209
		);
210
		$diff = new Diff( array(
211
			'foo' => new DiffOpChange( 'bar', 'var' ),
212
			'nyan' => new DiffOpRemove( 'fat' ),
213
			'bah' => new DiffOpChange( 'blubb', 'clubb' ),
214
			'yea' => new DiffOpAdd( 'stuff' ),
215
		) );
216
		$expected = array(
217
			'foo' => 'var',
218
			'nyan' => 'cat',
219
			'spam' => 'blah',
220
			'bah' => 'blah',
221
			'yea' => 'stuff',
222
		);
223
224
		$argLists['some mixed conflicts'] = array( $patcher, $base, $diff, $expected );
225
226
		return $argLists;
227
	}
228
229
	/**
230
	 * @dataProvider patchProvider
231
	 *
232
	 * @param Patcher $patcher
233
	 * @param array $base
234
	 * @param Diff $diff
235
	 * @param array $expected
236
	 */
237
	public function testPatch( Patcher $patcher, array $base, Diff $diff, array $expected ) {
238
		$actual = $patcher->patch( $base, $diff );
239
240
		$this->assertArrayEquals( $expected, $actual, true, true );
241
	}
242
243
	public function getApplicableDiffProvider() {
244
		// Diff, current object, expected
245
		$argLists = array();
246
247
		$diff = new Diff( array(), true );
248
		$currentObject = array();
249
		$expected = clone $diff;
250
251
		$argLists[] = array( $diff, $currentObject, $expected, 'Empty diff should remain empty on empty base' );
252
253
254
		$diff = new Diff( array(), true );
255
256
		$currentObject = array( 'foo' => 0, 'bar' => 1 );
257
258
		$expected = clone $diff;
259
260
		$argLists[] = array( $diff, $currentObject, $expected, 'Empty diff should remain empty on non-empty base' );
261
262
263
		$diff = new Diff( array(
264
			'foo' => new DiffOpChange( 0, 42 ),
265
			'bar' => new DiffOpChange( 1, 9001 ),
266
		), true );
267
268
		$currentObject = array( 'foo' => 0, 'bar' => 1 );
269
270
		$expected = clone $diff;
271
272
		$argLists[] = array( $diff, $currentObject, $expected, 'Diff should not be altered on matching base' );
273
274
275
		$diff = new Diff( array(
276
			'foo' => new DiffOpChange( 0, 42 ),
277
			'bar' => new DiffOpChange( 1, 9001 ),
278
		), true );
279
		$currentObject = array();
280
281
		$expected = new Diff( array(), true );
282
283
		$argLists[] = array( $diff, $currentObject, $expected, 'Diff with only change ops should be empty on empty base' );
284
285
286
		$diff = new Diff( array(
287
			'foo' => new DiffOpChange( 0, 42 ),
288
			'bar' => new DiffOpChange( 1, 9001 ),
289
		), true );
290
291
		$currentObject = array( 'foo' => 'something else', 'bar' => 1, 'baz' => 'o_O' );
292
293
		$expected = new Diff( array(
294
			'bar' => new DiffOpChange( 1, 9001 ),
295
		), true );
296
297
		$argLists[] = array( $diff, $currentObject, $expected, 'Only change ops present in the base should be retained' );
298
299
300
		$diff = new Diff( array(
301
			'bar' => new DiffOpRemove( 9001 ),
302
		), true );
303
304
		$currentObject = array();
305
306
		$expected = new Diff( array(), true );
307
308
		$argLists[] = array( $diff, $currentObject, $expected, 'Remove ops should be removed on empty base' );
309
310
311
		$diff = new Diff( array(
312
			'foo' => new DiffOpAdd( 42 ),
313
			'bar' => new DiffOpRemove( 9001 ),
314
		), true );
315
316
		$currentObject = array( 'foo' => 'bar' );
317
318
		$expected = new Diff( array(), true );
319
320
		$argLists[] = array(
321
			$diff,
322
			$currentObject,
323
			$expected,
324
			'Mismatching add ops and remove ops not present in base should be removed'
325
		);
326
327
328
		$diff = new Diff( array(
329
			'foo' => new DiffOpAdd( 42 ),
330
			'bar' => new DiffOpRemove( 9001 ),
331
		), true );
332
333
		$currentObject = array( 'foo' => 42, 'bar' => 9001 );
334
335
		$expected = new Diff( array(
336
			'bar' => new DiffOpRemove( 9001 ),
337
		), true );
338
339
		$argLists[] = array( $diff, $currentObject, $expected, 'Remove ops present in base should be retained' );
340
341
342
		$diff = new Diff( array(
343
			'foo' => new DiffOpAdd( 42 ),
344
			'bar' => new DiffOpRemove( 9001 ),
345
		), true );
346
347
		$currentObject = array();
348
349
		$expected = new Diff( array(
350
			'foo' => new DiffOpAdd( 42 ),
351
		), true );
352
353
		$argLists[] = array(
354
			$diff,
355
			$currentObject,
356
			$expected,
357
			'Add ops not present in the base should be retained (MapDiff)'
358
		);
359
360
361
		$diff = new Diff( array(
362
			'foo' => new Diff( array( 'bar' => new DiffOpChange( 0, 1 ) ), true ),
363
			'le-non-existing-element' => new Diff( array( 'bar' => new DiffOpChange( 0, 1 ) ), true ),
364
			'spam' => new Diff( array( new DiffOpAdd( 42 ) ), false ),
365
			new DiffOpAdd( 9001 ),
366
		), true );
367
368
		$currentObject = array(
369
			'foo' => array( 'bar' => 0, 'baz' => 'O_o' ),
370
			'spam' => array( 23, 'ohi' )
371
		);
372
373
		$expected = new Diff( array(
374
			'foo' => new Diff( array( 'bar' => new DiffOpChange( 0, 1 ) ), true ),
375
			'spam' => new Diff( array( new DiffOpAdd( 42 ) ), false ),
376
			new DiffOpAdd( 9001 ),
377
		), true );
378
379
		$argLists[] = array( $diff, $currentObject, $expected, 'Recursion should work properly' );
380
381
		return $argLists;
382
	}
383
384
	/**
385
	 * @dataProvider getApplicableDiffProvider
386
	 *
387
	 * @param Diff $diff
388
	 * @param array $currentObject
389
	 * @param Diff $expected
390
	 * @param string|null $message
391
	 */
392
	public function testGetApplicableDiff( Diff $diff, array $currentObject, Diff $expected, $message = null ) {
393
		$patcher = new MapPatcher();
394
		$actual = $patcher->getApplicableDiff( $currentObject, $diff );
395
396
		$this->assertEquals( $expected->getOperations(), $actual->getOperations(), $message );
397
	}
398
399
	public function testSetValueComparerToAlwaysFalse() {
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 false;
404
		} ) );
405
406
		$baseMap = array(
407
			'foo' => 42,
408
			'bar' => 9001,
409
		);
410
411
		$patch = new Diff( array(
412
			'foo' => new DiffOpChange( 42, 1337 ),
413
			'bar' => new DiffOpChange( 9001, 1337 ),
414
		) );
415
416
		$patchedMap = $patcher->patch( $baseMap, $patch );
417
418
		$this->assertEquals( $baseMap, $patchedMap );
419
	}
420
421
	public function testSetValueComparerToAlwaysTrue() {
422
		$patcher = new MapPatcher();
423
424
		$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...
425
			return true;
426
		} ) );
427
428
		$baseMap = array(
429
			'foo' => 42,
430
			'bar' => 9001,
431
		);
432
433
		$patch = new Diff( array(
434
			'foo' => new DiffOpChange( 3, 1337 ),
435
			'bar' => new DiffOpChange( 3, 1337 ),
436
		) );
437
438
		$expectedMap = array(
439
			'foo' => 1337,
440
			'bar' => 1337,
441
		);
442
443
		$patchedMap = $patcher->patch( $baseMap, $patch );
444
445
		$this->assertEquals( $expectedMap, $patchedMap );
446
	}
447
448
	public function testErrorOnUnknownDiffOpType() {
449
		$patcher = new MapPatcher();
450
451
		$diffOp = $this->getMock( 'Diff\DiffOp\DiffOp' );
452
453
		$diffOp->expects( $this->any() )
454
			->method( 'getType' )
455
			->will( $this->returnValue( 'diff' ) );
456
457
		$diff = new Diff( array( $diffOp ), true );
458
459
		$patcher->patch( array(), $diff );
460
461
		$patcher->throwErrors();
462
		$this->setExpectedException( 'Diff\Patcher\PatcherException' );
463
464
		$patcher->patch( array(), $diff );
465
	}
466
467
}
468