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

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