Skip to content

Commit bc8c1bb

Browse files
jfcherngclaude
andauthored
fix(Differ): use strict identity for old/new comparison to avoid nume… (#96)
Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Jack Cherng <jfcherng@gmail.com>
1 parent 15a54b6 commit bc8c1bb

3 files changed

Lines changed: 46 additions & 9 deletions

File tree

‎src/Differ.php‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ final class Differ
3939
'groupedOpcodesGnu' => [],
4040
'oldNoEolAtEofIdx' => -1,
4141
'newNoEolAtEofIdx' => -1,
42-
'oldNewComparison' => 0,
42+
'oldNewAreSame' => false,
4343
];
4444

4545
/**
@@ -84,10 +84,9 @@ final class Differ
8484
private int $newNoEolAtEofIdx = -1;
8585

8686
/**
87-
* @var int the result of comparing the old and the new with the spaceship operator
88-
* `-1` means `old < new`, `0` means `old == new`, `1` means `old > new`
87+
* @var bool the result of spaceship operator comparing old and new (0 if they are the same, 1 if they are different)
8988
*/
90-
private int $oldNewComparison = 0;
89+
private bool $oldNewAreSame = false;
9190

9291
/**
9392
* @var int[][][] array containing the generated opcodes for the differences between the two items
@@ -232,12 +231,22 @@ public function getNewNoEolAtEofIdx(): int
232231
return $this->finalize()->newNoEolAtEofIdx;
233232
}
234233

234+
/**
235+
* Check whether the old and the new are the same.
236+
*/
237+
public function getOldNewAreSame(): bool
238+
{
239+
return $this->finalize()->oldNewAreSame;
240+
}
241+
235242
/**
236243
* Compare the old and the new with the spaceship operator.
244+
*
245+
* @deprecated Use getOldNewAreSame() instead
237246
*/
238247
public function getOldNewComparison(): int
239248
{
240-
return $this->finalize()->oldNewComparison;
249+
return $this->getOldNewAreSame() ? 0 : 1;
241250
}
242251

243252
/**
@@ -302,7 +311,7 @@ public function getGroupedOpcodes(): array
302311

303312
$this->getGroupedOpcodesPre($old, $new);
304313

305-
if ($this->oldNewComparison === 0 && $this->options->fullContextIfIdentical) {
314+
if ($this->oldNewAreSame && $this->options->fullContextIfIdentical) {
306315
$opcodes = [
307316
[
308317
[SequenceMatcher::OP_EQ, 0, \count($old), 0, \count($new)],
@@ -338,7 +347,7 @@ public function getGroupedOpcodesGnu(): array
338347

339348
$this->getGroupedOpcodesGnuPre($old, $new);
340349

341-
if ($this->oldNewComparison === 0 && $this->options->fullContextIfIdentical) {
350+
if ($this->oldNewAreSame && $this->options->fullContextIfIdentical) {
342351
$opcodes = [
343352
[
344353
[SequenceMatcher::OP_EQ, 0, \count($old), 0, \count($new)],
@@ -483,7 +492,7 @@ private function finalize(): self
483492

484493
$this->oldNoEolAtEofIdx = $this->getOld(-1) === [''] ? -1 : \count($this->old);
485494
$this->newNoEolAtEofIdx = $this->getNew(-1) === [''] ? -1 : \count($this->new);
486-
$this->oldNewComparison = $this->old <=> $this->new;
495+
$this->oldNewAreSame = $this->old === $this->new;
487496

488497
$this->sequenceMatcher->setOptions($this->options->toSequenceMatcherOptions());
489498
}

‎src/Renderer/AbstractRenderer.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ final public function render(Differ $differ): string
114114
$this->changesAreRaw = true;
115115

116116
// the "no difference" situation may happen frequently
117-
return $differ->getOldNewComparison() === 0 && !$differ->options->fullContextIfIdentical
117+
return $differ->getOldNewAreSame() && !$differ->options->fullContextIfIdentical
118118
? $this->getResultForIdenticals()
119119
: $this->renderWorker($differ);
120120
}

‎tests/DifferTest.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,32 @@ public static function provideGetGroupedOpcodesCases(): iterable
6767
],
6868
];
6969
}
70+
71+
/**
72+
* Test that numeric strings are compared as strings, not numbers.
73+
*
74+
* @covers \Jfcherng\Diff\Differ::getOldNewAreSame
75+
*
76+
* @see https://github.com/jfcherng/php-diff/issues/94
77+
*/
78+
#[DataProvider('provideNumericStringComparisonCases')]
79+
public function testNumericStringComparison(string $old, string $new, bool $expectedAreSame): void
80+
{
81+
$differ = new Differ(explode("\n", $old), explode("\n", $new));
82+
83+
self::assertSame($expectedAreSame, $differ->getOldNewAreSame());
84+
}
85+
86+
/**
87+
* Data provider for testNumericStringComparison.
88+
*/
89+
public static function provideNumericStringComparisonCases(): iterable
90+
{
91+
return [
92+
'zero vs multiple zeros' => ['0', '00000', false],
93+
'identical zeros' => ['0', '0', true],
94+
'numeric strings with different values' => ['1', '01', false],
95+
'leading zeros' => ['007', '7', false],
96+
];
97+
}
7098
}

0 commit comments

Comments
 (0)