Skip to content

Commit cd683d8

Browse files
SpacePossumsebastianbergmann
authored andcommitted
- Remove reference mismatch on finding same ending of array.
- More tests - Do not crash on undefined var. on PHP7
1 parent 86ba64b commit cd683d8

File tree

6 files changed

+269
-51
lines changed

6 files changed

+269
-51
lines changed

src/Differ.php

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public function diff($from, $to, LongestCommonSubsequence $lcs = null)
6767
/**
6868
* Casts variable to string if it is not a string or array.
6969
*
70-
* @param $input
70+
* @param mixed $input
7171
*
7272
* @return string
7373
*/
@@ -123,21 +123,22 @@ private function checkIfDiffInOld(array $diff)
123123
*
124124
* @return string
125125
*/
126-
private function getBuffer($diff, $old, $start, $end)
126+
private function getBuffer(array $diff, array $old, $start, $end)
127127
{
128-
$newChunk = true;
129-
$buffer = $this->header;
128+
$buffer = $this->header;
129+
130+
if (!isset($old[$start])) {
131+
$buffer = $this->getDiffBufferElementNew($diff, $buffer, $start);
132+
++$start;
133+
}
130134

131135
for ($i = $start; $i < $end; $i++) {
132136
if (isset($old[$i])) {
133-
$buffer .= "\n";
134-
$newChunk = true;
135-
$i = $old[$i];
137+
$i = $old[$i];
138+
$buffer = $this->getDiffBufferElementNew($diff, "\n" . $buffer, $i);
139+
} else {
140+
$buffer = $this->getDiffBufferElement($diff, $buffer, $i);
136141
}
137-
138-
$buffer = $this->getDiffBufferElement($diff, $i, $newChunk, $buffer);
139-
140-
$newChunk = false;
141142
}
142143

143144
return $buffer;
@@ -147,31 +148,42 @@ private function getBuffer($diff, $old, $start, $end)
147148
* Gets individual buffer element.
148149
*
149150
* @param array $diff
150-
* @param int $i
151-
* @param bool $newChunk
152151
* @param string $buffer
152+
* @param int $diffIndex
153153
*
154154
* @return string
155155
*/
156-
private function getDiffBufferElement($diff, $i, $newChunk, $buffer)
156+
private function getDiffBufferElement(array $diff, $buffer, $diffIndex)
157157
{
158-
if ($newChunk) {
159-
if ($this->showNonDiffLines === true) {
160-
$buffer .= "@@ @@\n";
161-
}
162-
}
163-
164-
if ($diff[$i][1] === 1 /* ADDED */) {
165-
$buffer .= '+' . $diff[$i][0] . "\n";
166-
} elseif ($diff[$i][1] === 2 /* REMOVED */) {
167-
$buffer .= '-' . $diff[$i][0] . "\n";
158+
if ($diff[$diffIndex][1] === 1 /* ADDED */) {
159+
$buffer .= '+' . $diff[$diffIndex][0] . "\n";
160+
} elseif ($diff[$diffIndex][1] === 2 /* REMOVED */) {
161+
$buffer .= '-' . $diff[$diffIndex][0] . "\n";
168162
} elseif ($this->showNonDiffLines === true) {
169-
$buffer .= ' ' . $diff[$i][0] . "\n";
163+
$buffer .= ' ' . $diff[$diffIndex][0] . "\n";
170164
}
171165

172166
return $buffer;
173167
}
174168

169+
/**
170+
* Gets individual buffer element with opening.
171+
*
172+
* @param array $diff
173+
* @param string $buffer
174+
* @param int $diffIndex
175+
*
176+
* @return string
177+
*/
178+
private function getDiffBufferElementNew(array $diff, $buffer, $diffIndex)
179+
{
180+
if ($this->showNonDiffLines === true) {
181+
$buffer .= "@@ @@\n";
182+
}
183+
184+
return $this->getDiffBufferElement($diff, $buffer, $diffIndex);
185+
}
186+
175187
/**
176188
* Returns the diff between two arrays or strings as array.
177189
*
@@ -197,7 +209,7 @@ public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
197209
} elseif (\is_array($from)) {
198210
$fromMatches = array();
199211
} else {
200-
throw new \UnexpectedValueException('"from" must be an array or string.');
212+
throw new \InvalidArgumentException('"from" must be an array or string.');
201213
}
202214

203215
if (\is_string($to)) {
@@ -206,7 +218,7 @@ public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
206218
} elseif (\is_array($to)) {
207219
$toMatches = array();
208220
} else {
209-
throw new \UnexpectedValueException('"to" must be an array or string.');
221+
throw new \InvalidArgumentException('"to" must be an array or string.');
210222
}
211223

212224
list($from, $to, $start, $end) = self::getArrayDiffParted($from, $to);
@@ -265,9 +277,9 @@ public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
265277
/**
266278
* Get new strings denoting new lines from a given string.
267279
*
268-
* @param $string
280+
* @param string $string
269281
*
270-
* @return mixed
282+
* @return array
271283
*/
272284
private function getNewLineMatches($string)
273285
{
@@ -277,19 +289,15 @@ private function getNewLineMatches($string)
277289
}
278290

279291
/**
280-
* Checks if input is string, if so it will split it line-by-life.
292+
* Checks if input is string, if so it will split it line-by-line.
281293
*
282-
* @param $input
294+
* @param string $input
283295
*
284296
* @return array
285297
*/
286298
private function splitStringByLines($input)
287299
{
288-
if (\is_string($input)) {
289-
return \preg_split('(\r\n|\r|\n)', $input);
290-
}
291-
292-
return $input;
300+
return \preg_split('(\r\n|\r|\n)', $input);
293301
}
294302

295303
/**
@@ -365,17 +373,23 @@ private static function getArrayDiffParted(array &$from, array &$to)
365373
}
366374
}
367375

368-
$keys = \array_reverse(\array_keys($from));
376+
\end($from);
369377
\end($to);
370378

371-
foreach ($keys as $k) {
372-
if (\key($to) === $k && $from[$k] === $to[$k]) {
373-
$end = array($k => $from[$k]) + $end;
374-
unset($from[$k], $to[$k]);
375-
} else {
379+
do {
380+
$fromK = \key($from);
381+
$toK = \key($to);
382+
383+
if (null === $fromK || null === $toK || \current($from) !== \current($to)) {
376384
break;
377385
}
378-
}
386+
387+
\prev($from);
388+
\prev($to);
389+
390+
$end = array($fromK => $from[$fromK]) + $end;
391+
unset($from[$fromK], $to[$toK]);
392+
} while (true);
379393

380394
return array($from, $to, $start, $end);
381395
}

src/Parser.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public function parse($string)
7171
private function parseFileDiff(Diff $diff, array $lines)
7272
{
7373
$chunks = array();
74+
$chunk = null;
7475

7576
foreach ($lines as $line) {
7677
if (\preg_match('/^@@\s+-(?P<start>\d+)(?:,\s*(?P<startrange>\d+))?\s+\+(?P<end>\d+)(?:,\s*(?P<endrange>\d+))?\s+@@/', $line, $match)) {

tests/ChunkTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,13 @@ public function testLinesCanBeRetrieved()
5656
{
5757
$this->assertEquals(array(), $this->chunk->getLines());
5858
}
59+
60+
public function testLinesCanBeSet()
61+
{
62+
$this->assertEquals(array(), $this->chunk->getLines());
63+
64+
$testValue = array('line0', 'line1');
65+
$this->chunk->setLines($testValue);
66+
$this->assertEquals($testValue, $this->chunk->getLines());
67+
}
5968
}

tests/DiffTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/*
3+
* This file is part of sebastian/diff.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace SebastianBergmann\Diff;
12+
13+
use PHPUnit\Framework\TestCase;
14+
15+
/**
16+
* @covers SebastianBergmann\Diff\Diff
17+
*
18+
* @uses SebastianBergmann\Diff\Chunk
19+
*/
20+
final class DiffTest extends TestCase
21+
{
22+
public function testGettersAfterConstructionWithDefault()
23+
{
24+
$from = 'line1a';
25+
$to = 'line2a';
26+
$diff = new Diff($from, $to);
27+
28+
$this->assertSame($from, $diff->getFrom());
29+
$this->assertSame($to, $diff->getTo());
30+
$this->assertSame(array(), $diff->getChunks(), 'Expect chunks to be default value "array()".');
31+
}
32+
33+
public function testGettersAfterConstructionWithChunks()
34+
{
35+
$from = 'line1b';
36+
$to = 'line2b';
37+
$chunks = array(new Chunk(), new Chunk(2, 3));
38+
39+
$diff = new Diff($from, $to, $chunks);
40+
41+
$this->assertSame($from, $diff->getFrom());
42+
$this->assertSame($to, $diff->getTo());
43+
$this->assertSame($chunks, $diff->getChunks(), 'Expect chunks to be passed value.');
44+
}
45+
46+
public function testSetChunksAfterConstruction()
47+
{
48+
$diff = new Diff('line1c', 'line2c');
49+
$this->assertSame(array(), $diff->getChunks(), 'Expect chunks to be default value "array()".');
50+
51+
$chunks = array(new Chunk(), new Chunk(2, 3));
52+
$diff->setChunks($chunks);
53+
$this->assertSame($chunks, $diff->getChunks(), 'Expect chunks to be passed value.');
54+
}
55+
}

tests/DifferTest.php

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ public function testTextRepresentationOfDiffCanBeRenderedUsingTimeEfficientLcsIm
6363
}
6464

6565
/**
66-
* @param array $expected
67-
* @param string $from
68-
* @param string $to
66+
* @param array $expected
67+
* @param string|array $from
68+
* @param string|array $to
6969
* @dataProvider arrayProvider
7070
*/
7171
public function testArrayRepresentationOfDiffCanBeRenderedUsingMemoryEfficientLcsImplementation(array $expected, $from, $to)
@@ -74,9 +74,9 @@ public function testArrayRepresentationOfDiffCanBeRenderedUsingMemoryEfficientLc
7474
}
7575

7676
/**
77-
* @param string $expected
78-
* @param string|array $from
79-
* @param string|array $to
77+
* @param string $expected
78+
* @param string $from
79+
* @param string $to
8080
* @dataProvider textProvider
8181
*/
8282
public function testTextRepresentationOfDiffCanBeRenderedUsingMemoryEfficientLcsImplementation($expected, $from, $to)
@@ -104,10 +104,10 @@ public function testTypesOtherThanArrayAndStringCanBePassed()
104104

105105
/**
106106
* @param string $diff
107-
* @param array $expected
107+
* @param Diff[] $expected
108108
* @dataProvider diffProvider
109109
*/
110-
public function testParser($diff, $expected)
110+
public function testParser($diff, array $expected)
111111
{
112112
$parser = new Parser;
113113
$result = $parser->parse($diff);
@@ -301,6 +301,11 @@ public function textProvider()
301301
'abcdde',
302302
'abcde'
303303
),
304+
array(
305+
"--- Original\n+++ New\n@@ @@\n-A\n+A1\n B\n",
306+
"A\nB",
307+
"A1\nB",
308+
),
304309
);
305310
}
306311

@@ -317,4 +322,56 @@ public function diffProvider()
317322
)
318323
);
319324
}
325+
326+
/**
327+
* @param string $expected
328+
* @param string $from
329+
* @param string $to
330+
* @dataProvider textForNoNonDiffLinesProvider
331+
*/
332+
public function testDiffDoNotShowNonDiffLines($expected, $from, $to)
333+
{
334+
$differ = new Differ('', false);
335+
$this->assertSame($expected, $differ->diff($from, $to));
336+
}
337+
338+
public function textForNoNonDiffLinesProvider()
339+
{
340+
return array(
341+
array(
342+
'', 'a', 'a'
343+
),
344+
array(
345+
"-A\n+C\n",
346+
"A\n\n\nB",
347+
"C\n\n\nB",
348+
),
349+
);
350+
}
351+
352+
/**
353+
* @requires PHPUnit 5.7
354+
*/
355+
public function testDiffToArrayInvalidFromType()
356+
{
357+
$differ = new Differ;
358+
359+
$this->expectException('\InvalidArgumentException');
360+
$this->expectExceptionMessageRegExp('#^"from" must be an array or string\.$#');
361+
362+
$differ->diffToArray(null, '');
363+
}
364+
365+
/**
366+
* @requires PHPUnit 5.7
367+
*/
368+
public function testDiffInvalidToType()
369+
{
370+
$differ = new Differ;
371+
372+
$this->expectException('\InvalidArgumentException');
373+
$this->expectExceptionMessageRegExp('#^"to" must be an array or string\.$#');
374+
375+
$differ->diffToArray('', new \stdClass);
376+
}
320377
}

0 commit comments

Comments
 (0)