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
 * @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