Skip to content

Commit a2604e6

Browse files
committed
Backport bless_tests.php changes from PHP 8
1 parent b69a98c commit a2604e6

File tree

1 file changed

+168
-3
lines changed

1 file changed

+168
-3
lines changed

scripts/dev/bless_tests.php

+168-3
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,26 @@
1919
}
2020

2121
$phpt = file_get_contents($path);
22+
$out = file_get_contents($outPath);
23+
2224
if (false !== strpos($phpt, '--XFAIL--')) {
2325
// Don't modify expected output of XFAIL tests
2426
continue;
2527
}
2628

27-
$out = file_get_contents($outPath);
28-
$out = normalizeOutput($out);
29+
// Don't update EXPECTREGEX tests
30+
if (!preg_match('/--EXPECT(F?)--(.*)$/s', $phpt, $matches)) {
31+
continue;
32+
}
33+
34+
$oldExpect = trim($matches[2]);
35+
$isFormat = $matches[1] == 'F';
36+
if ($isFormat) {
37+
$out = generateMinimallyDifferingOutput($out, $oldExpect);
38+
} else {
39+
$out = normalizeOutput($out);
40+
}
41+
2942
$phpt = insertOutput($phpt, $out);
3043
file_put_contents($path, $phpt);
3144
}
@@ -62,9 +75,161 @@ function normalizeOutput(string $out): string {
6275
return $out;
6376
}
6477

78+
function formatToRegex(string $format): string {
79+
$result = preg_quote($format, '/');
80+
$result = str_replace('%d', '\d+', $result);
81+
$result = str_replace('%s', '[^\r\n]+', $result);
82+
return "/^$result$/s";
83+
}
84+
85+
function generateMinimallyDifferingOutput(string $out, string $oldExpect) {
86+
$outLines = explode("\n", $out);
87+
$oldExpectLines = explode("\n", $oldExpect);
88+
$differ = new Differ(function($oldExpect, $new) {
89+
if (strpos($oldExpect, '%') === false) {
90+
return $oldExpect === $new;
91+
}
92+
return preg_match(formatToRegex($oldExpect), $new);
93+
});
94+
$diff = $differ->diff($oldExpectLines, $outLines);
95+
96+
$result = [];
97+
foreach ($diff as $elem) {
98+
if ($elem->type == DiffElem::TYPE_KEEP) {
99+
$result[] = $elem->old;
100+
} else if ($elem->type == DiffElem::TYPE_ADD) {
101+
$result[] = normalizeOutput($elem->new);
102+
}
103+
}
104+
return implode("\n", $result);
105+
}
106+
65107
function insertOutput(string $phpt, string $out): string {
66108
return preg_replace_callback('/--EXPECTF?--.*$/s', function($matches) use($out) {
67-
$F = strpos($out, '%') !== false ? 'F' : '';
109+
$hasWildcard = preg_match('/%[resSaAwidxfc]/', $out);
110+
$F = $hasWildcard ? 'F' : '';
68111
return "--EXPECT$F--\n" . $out . "\n";
69112
}, $phpt);
70113
}
114+
115+
/**
116+
* Implementation of the the Myers diff algorithm.
117+
*
118+
* Myers, Eugene W. "An O (ND) difference algorithm and its variations."
119+
* Algorithmica 1.1 (1986): 251-266.
120+
*/
121+
122+
class DiffElem
123+
{
124+
const TYPE_KEEP = 0;
125+
const TYPE_REMOVE = 1;
126+
const TYPE_ADD = 2;
127+
128+
/** @var int One of the TYPE_* constants */
129+
public $type;
130+
/** @var mixed Is null for add operations */
131+
public $old;
132+
/** @var mixed Is null for remove operations */
133+
public $new;
134+
135+
public function __construct(int $type, $old, $new) {
136+
$this->type = $type;
137+
$this->old = $old;
138+
$this->new = $new;
139+
}
140+
}
141+
142+
class Differ
143+
{
144+
private $isEqual;
145+
146+
/**
147+
* Create differ over the given equality relation.
148+
*
149+
* @param callable $isEqual Equality relation with signature function($a, $b) : bool
150+
*/
151+
public function __construct(callable $isEqual) {
152+
$this->isEqual = $isEqual;
153+
}
154+
155+
/**
156+
* Calculate diff (edit script) from $old to $new.
157+
*
158+
* @param array $old Original array
159+
* @param array $new New array
160+
*
161+
* @return DiffElem[] Diff (edit script)
162+
*/
163+
public function diff(array $old, array $new) {
164+
list($trace, $x, $y) = $this->calculateTrace($old, $new);
165+
return $this->extractDiff($trace, $x, $y, $old, $new);
166+
}
167+
168+
private function calculateTrace(array $a, array $b) {
169+
$n = \count($a);
170+
$m = \count($b);
171+
$max = $n + $m;
172+
$v = [1 => 0];
173+
$trace = [];
174+
for ($d = 0; $d <= $max; $d++) {
175+
$trace[] = $v;
176+
for ($k = -$d; $k <= $d; $k += 2) {
177+
if ($k === -$d || ($k !== $d && $v[$k-1] < $v[$k+1])) {
178+
$x = $v[$k+1];
179+
} else {
180+
$x = $v[$k-1] + 1;
181+
}
182+
183+
$y = $x - $k;
184+
while ($x < $n && $y < $m && ($this->isEqual)($a[$x], $b[$y])) {
185+
$x++;
186+
$y++;
187+
}
188+
189+
$v[$k] = $x;
190+
if ($x >= $n && $y >= $m) {
191+
return [$trace, $x, $y];
192+
}
193+
}
194+
}
195+
throw new \Exception('Should not happen');
196+
}
197+
198+
private function extractDiff(array $trace, int $x, int $y, array $a, array $b) {
199+
$result = [];
200+
for ($d = \count($trace) - 1; $d >= 0; $d--) {
201+
$v = $trace[$d];
202+
$k = $x - $y;
203+
204+
if ($k === -$d || ($k !== $d && $v[$k-1] < $v[$k+1])) {
205+
$prevK = $k + 1;
206+
} else {
207+
$prevK = $k - 1;
208+
}
209+
210+
$prevX = $v[$prevK];
211+
$prevY = $prevX - $prevK;
212+
213+
while ($x > $prevX && $y > $prevY) {
214+
$result[] = new DiffElem(DiffElem::TYPE_KEEP, $a[$x-1], $b[$y-1]);
215+
$x--;
216+
$y--;
217+
}
218+
219+
if ($d === 0) {
220+
break;
221+
}
222+
223+
while ($x > $prevX) {
224+
$result[] = new DiffElem(DiffElem::TYPE_REMOVE, $a[$x-1], null);
225+
$x--;
226+
}
227+
228+
while ($y > $prevY) {
229+
$result[] = new DiffElem(DiffElem::TYPE_ADD, null, $b[$y-1]);
230+
$y--;
231+
}
232+
}
233+
return array_reverse($result);
234+
}
235+
}

0 commit comments

Comments
 (0)