Update framework testing infrastructure and standards
- Add phpt test runner and suite for app functions - Introduce testing workflow to AGENT.md - Add tests for cache, content, context, helpers, hooks, plugins, rendering - Mount tests directory in dev container
This commit is contained in:
parent
33943a907b
commit
449e6f8e03
22 changed files with 909 additions and 7 deletions
112
devel/tests/run.php
Normal file
112
devel/tests/run.php
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
// phpt test runner — execute via run.sh, runs inside the container
|
||||
|
||||
const GREEN = "\033[32m";
|
||||
const RED = "\033[31m";
|
||||
const YELLOW = "\033[33m";
|
||||
const RESET = "\033[0m";
|
||||
const BOLD = "\033[1m";
|
||||
|
||||
$filter = $argv[1] ?? null;
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator(__DIR__, FilesystemIterator::SKIP_DOTS)
|
||||
);
|
||||
$files = [];
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->getExtension() === 'phpt') {
|
||||
$files[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
sort($files);
|
||||
|
||||
$pass = 0;
|
||||
$fail = 0;
|
||||
$skip = 0;
|
||||
|
||||
foreach ($files as $file) {
|
||||
$rel = ltrim(substr($file, strlen(__DIR__), -5), '/');
|
||||
|
||||
if ($filter !== null && !str_contains($rel, $filter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sections = parse_phpt(file_get_contents($file));
|
||||
$title = trim($sections['TEST'] ?? $rel);
|
||||
|
||||
if (!isset($sections['FILE']) || !isset($sections['EXPECT'])) {
|
||||
echo RED . 'INVALID' . RESET . " $name (missing --FILE-- or --EXPECT--)\n";
|
||||
$fail++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($sections['SKIPIF'])) {
|
||||
$result = trim(run_php($sections['SKIPIF']));
|
||||
if (str_starts_with($result, 'skip')) {
|
||||
$reason = ltrim(substr($result, 4));
|
||||
echo YELLOW . 'SKIP' . RESET . " $title" . ($reason ? " — $reason" : '') . "\n";
|
||||
$skip++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$actual = trim(run_php($sections['FILE']));
|
||||
$expected = trim($sections['EXPECT']);
|
||||
|
||||
if ($actual === $expected) {
|
||||
echo GREEN . 'PASS' . RESET . " $title\n";
|
||||
$pass++;
|
||||
} else {
|
||||
echo RED . 'FAIL' . RESET . " $title\n";
|
||||
show_diff($expected, $actual);
|
||||
$fail++;
|
||||
}
|
||||
}
|
||||
|
||||
$total = $pass + $fail + $skip;
|
||||
echo "\n" . BOLD . "Results: $pass/$total passed" . ($skip ? ", $skip skipped" : '') . RESET . "\n";
|
||||
exit($fail > 0 ? 1 : 0);
|
||||
|
||||
// ---- helpers ----
|
||||
|
||||
function parse_phpt(string $content): array
|
||||
{
|
||||
$sections = [];
|
||||
$current = null;
|
||||
foreach (explode("\n", $content) as $line) {
|
||||
if (preg_match('/^--([A-Z]+)--$/', rtrim($line), $m)) {
|
||||
$current = $m[1];
|
||||
$sections[$current] = '';
|
||||
} elseif ($current !== null) {
|
||||
$sections[$current] .= $line . "\n";
|
||||
}
|
||||
}
|
||||
return $sections;
|
||||
}
|
||||
|
||||
function run_php(string $code): string
|
||||
{
|
||||
$tmp = tempnam('/tmp', 'phpt_');
|
||||
file_put_contents($tmp, $code);
|
||||
$output = shell_exec("php $tmp 2>&1");
|
||||
unlink($tmp);
|
||||
return $output ?? '';
|
||||
}
|
||||
|
||||
function show_diff(string $expected, string $actual): void
|
||||
{
|
||||
$exp = explode("\n", $expected);
|
||||
$act = explode("\n", $actual);
|
||||
$max = max(count($exp), count($act));
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
$e = $exp[$i] ?? null;
|
||||
$a = $act[$i] ?? null;
|
||||
if ($e === $a) {
|
||||
echo " $e\n";
|
||||
} else {
|
||||
if ($e !== null) echo RED . " - $e" . RESET . "\n";
|
||||
if ($a !== null) echo GREEN . " + $a" . RESET . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue