Passed
Push — fixcs ( 48b817 )
by Jeroen De
07:35
created

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