Skip to content

Commit f32b411

Browse files
SpacePossumsebastianbergmann
authored andcommitted
Fix trailing common block detection.
1 parent 064ad5d commit f32b411

File tree

2 files changed

+165
-14
lines changed

2 files changed

+165
-14
lines changed

src/Differ.php

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,27 +76,35 @@ private function validateDiffInput($input): string
7676
*/
7777
private function getCommonChunks(array $diff, int $lineThreshold = 5): array
7878
{
79-
$inOld = false;
80-
$i = 0;
81-
$old = [];
82-
83-
foreach ($diff as $line) {
84-
if ($line[1] === 0 /* OLD */) {
85-
if ($inOld === false) {
86-
$inOld = $i;
79+
$diffSize = \count($diff);
80+
$capturing = false;
81+
$chunkStart = 0;
82+
$chunkSize = 0;
83+
$commonChunks = [];
84+
85+
for ($i = 0; $i < $diffSize; ++$i) {
86+
if ($diff[$i][1] === 0 /* OLD */) {
87+
if ($capturing === false) {
88+
$capturing = true;
89+
$chunkStart = $i;
90+
$chunkSize = 0;
91+
} else {
92+
++$chunkSize;
8793
}
88-
} elseif ($inOld !== false) {
89-
if (($i - $inOld) > $lineThreshold) {
90-
$old[$inOld] = $i - 1;
94+
} elseif ($capturing !== false) {
95+
if ($chunkSize >= $lineThreshold) {
96+
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
9197
}
9298

93-
$inOld = false;
99+
$capturing = false;
94100
}
101+
}
95102

96-
++$i;
103+
if ($capturing !== false && $chunkSize >= $lineThreshold) {
104+
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
97105
}
98106

99-
return $old;
107+
return $commonChunks;
100108
}
101109

102110
/**
@@ -112,6 +120,15 @@ private function getDiff(array $diff): string
112120
$start = isset($old[0]) ? $old[0] : 0;
113121
$end = \count($diff);
114122

123+
if (\count($old)) {
124+
\end($old);
125+
$tmp = \key($old);
126+
\reset($old);
127+
if ($old[$tmp] === $end - 1) {
128+
$end = $tmp;
129+
}
130+
}
131+
115132
$buffer = $this->header;
116133

117134
if (!isset($old[$start])) {

tests/DifferTest.php

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,19 @@ public function textProvider(): array
323323
"a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk",
324324
"a\np\nc\nd\ne\nf\ng\nh\ni\nw\nk",
325325
],
326+
[
327+
<<<EOF
328+
--- Original
329+
+++ New
330+
@@ @@
331+
-A
332+
+B
333+
334+
EOF
335+
,
336+
"A\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1",
337+
"B\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1",
338+
],
326339
];
327340
}
328341

@@ -381,4 +394,125 @@ public function testDiffInvalidToType()
381394

382395
$this->differ->diffToArray('', new \stdClass);
383396
}
397+
398+
/**
399+
* @param array $expected
400+
* @param string $from
401+
* @param string $to
402+
* @param int $lineThreshold
403+
* @dataProvider provideGetCommonChunks
404+
*/
405+
public function testGetCommonChunks(array $expected, string $from, string $to, int $lineThreshold = 5)
406+
{
407+
$method = (new \ReflectionObject($this->differ))->getMethod('getCommonChunks');
408+
$method->setAccessible(true);
409+
410+
$result = $method->invoke(
411+
$this->differ,
412+
$this->differ->diffToArray($from, $to),
413+
$lineThreshold
414+
);
415+
416+
$this->assertSame($expected, $result);
417+
}
418+
419+
public function provideGetCommonChunks(): array
420+
{
421+
return[
422+
'same (with default threshold)' => [
423+
[],
424+
'A',
425+
'A',
426+
],
427+
'same (threshold 0)' => [
428+
[0 => 0],
429+
'A',
430+
'A',
431+
0,
432+
],
433+
'empty' => [
434+
[],
435+
'',
436+
'',
437+
],
438+
'single line diff' => [
439+
[],
440+
'A',
441+
'B',
442+
],
443+
'below threshold I' => [
444+
[],
445+
"A\nX\nC",
446+
"A\nB\nC",
447+
],
448+
'below threshold II' => [
449+
[],
450+
"A\n\n\n\nX\nC",
451+
"A\n\n\n\nB\nC",
452+
],
453+
'below threshold III' => [
454+
[0 => 5],
455+
"A\n\n\n\n\n\nB",
456+
"A\n\n\n\n\n\nA",
457+
],
458+
'same start' => [
459+
[0 => 5],
460+
"A\n\n\n\n\n\nX\nC",
461+
"A\n\n\n\n\n\nB\nC",
462+
],
463+
'same start long' => [
464+
[0 => 13],
465+
"\n\n\n\n\n\n\n\n\n\n\n\n\n\nA",
466+
"\n\n\n\n\n\n\n\n\n\n\n\n\n\nB",
467+
],
468+
'same part in between' => [
469+
[2 => 8],
470+
"A\n\n\n\n\n\n\nX\nY\nZ\n\n",
471+
"B\n\n\n\n\n\n\nX\nA\nZ\n\n",
472+
],
473+
'same trailing' => [
474+
[2 => 15],
475+
"A\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
476+
"B\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
477+
],
478+
'same part in between, same trailing' => [
479+
[2 => 7, 10 => 16],
480+
"A\n\n\n\n\n\n\nA\n\n\n\n\n\n\n",
481+
"B\n\n\n\n\n\n\nB\n\n\n\n\n\n\n",
482+
],
483+
'below custom threshold I' => [
484+
[],
485+
"A\n\nB",
486+
"A\n\nD",
487+
2
488+
],
489+
'custom threshold I' => [
490+
[0 => 1],
491+
"A\n\nB",
492+
"A\n\nD",
493+
1
494+
],
495+
'custom threshold II' => [
496+
[],
497+
"A\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
498+
"A\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
499+
19
500+
],
501+
[
502+
[3 => 9],
503+
"a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk",
504+
"a\np\nc\nd\ne\nf\ng\nh\ni\nw\nk",
505+
],
506+
[
507+
[0 => 5, 8 => 13],
508+
"A\nA\nA\nA\nA\nA\nX\nC\nC\nC\nC\nC\nC",
509+
"A\nA\nA\nA\nA\nA\nB\nC\nC\nC\nC\nC\nC",
510+
],
511+
[
512+
[0 => 5, 8 => 13],
513+
"A\nA\nA\nA\nA\nA\nX\nC\nC\nC\nC\nC\nC\nX",
514+
"A\nA\nA\nA\nA\nA\nB\nC\nC\nC\nC\nC\nC\nY",
515+
],
516+
];
517+
}
384518
}

0 commit comments

Comments
 (0)