TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.4 KiB
146 lines
4.4 KiB
#!/usr/bin/env php
|
|
<?php
|
|
/**
|
|
* This file is part of Swoole-Compiler(AOT).
|
|
*
|
|
* @link https://www.swoole.com/
|
|
* @contact service@swoole.com
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
use TypePhp\Testing\TestCoverageAnalyzer;
|
|
|
|
require __DIR__ . '/bootstrap.php';
|
|
|
|
$format = 'summary';
|
|
$output = null;
|
|
$includePhpUnit = true;
|
|
$strict = false;
|
|
$phpVersions = ['8.4', '8.5'];
|
|
$paths = [];
|
|
|
|
foreach (array_slice($argv, 1) as $argument) {
|
|
if ($argument === '--help' || $argument === '-h') {
|
|
printUsage($argv[0]);
|
|
exit(0);
|
|
}
|
|
if ($argument === '--no-phpunit') {
|
|
$includePhpUnit = false;
|
|
continue;
|
|
}
|
|
if ($argument === '--strict') {
|
|
$strict = true;
|
|
continue;
|
|
}
|
|
if (str_starts_with($argument, '--format=')) {
|
|
$format = substr($argument, strlen('--format='));
|
|
continue;
|
|
}
|
|
if (str_starts_with($argument, '--output=')) {
|
|
$output = substr($argument, strlen('--output='));
|
|
continue;
|
|
}
|
|
if (str_starts_with($argument, '--php-versions=')) {
|
|
$phpVersions = array_values(array_filter(array_map('trim', explode(',', substr($argument, strlen('--php-versions='))))));
|
|
continue;
|
|
}
|
|
if (str_starts_with($argument, '-')) {
|
|
fwrite(STDERR, 'Unknown option: ' . $argument . PHP_EOL);
|
|
exit(2);
|
|
}
|
|
$paths[] = $argument;
|
|
}
|
|
|
|
if (!in_array($format, ['summary', 'json', 'markdown'], true)) {
|
|
fwrite(STDERR, 'Invalid format. Expected summary, json or markdown.' . PHP_EOL);
|
|
exit(2);
|
|
}
|
|
if ($phpVersions === []) {
|
|
fwrite(STDERR, 'At least one target PHP version is required.' . PHP_EOL);
|
|
exit(2);
|
|
}
|
|
foreach ($phpVersions as $version) {
|
|
if (!preg_match('/^\d+\.\d+$/', $version)) {
|
|
fwrite(STDERR, 'Invalid PHP version: ' . $version . PHP_EOL);
|
|
exit(2);
|
|
}
|
|
}
|
|
if ($paths === []) {
|
|
$paths = ['tests/compiler'];
|
|
}
|
|
|
|
try {
|
|
$analyzer = new TestCoverageAnalyzer(ROOT_PATH, $phpVersions);
|
|
$report = $analyzer->analyze(
|
|
$paths,
|
|
$includePhpUnit ? ROOT_PATH . '/phpunit/src' : null,
|
|
$includePhpUnit ? ROOT_PATH . '/phpunit/code' : null,
|
|
);
|
|
} catch (Throwable $error) {
|
|
fwrite(STDERR, 'Coverage analysis failed: ' . $error->getMessage() . PHP_EOL);
|
|
exit(1);
|
|
}
|
|
|
|
$rendered = match ($format) {
|
|
'summary' => $analyzer->renderSummary($report),
|
|
'markdown' => $analyzer->renderMarkdown($report),
|
|
'json' => json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR) . PHP_EOL,
|
|
};
|
|
|
|
if ($output === null) {
|
|
echo $rendered;
|
|
} else {
|
|
$outputPath = isAbsolutePath($output) ? $output : ROOT_PATH . DIRECTORY_SEPARATOR . $output;
|
|
$directory = dirname($outputPath);
|
|
if (!is_dir($directory) && !mkdir($directory, 0777, true) && !is_dir($directory)) {
|
|
fwrite(STDERR, 'Unable to create output directory: ' . $directory . PHP_EOL);
|
|
exit(1);
|
|
}
|
|
if (file_put_contents($outputPath, $rendered) === false) {
|
|
fwrite(STDERR, 'Unable to write report: ' . $outputPath . PHP_EOL);
|
|
exit(1);
|
|
}
|
|
echo 'Wrote ', $format, ' coverage report: ', relativePath(ROOT_PATH, $outputPath), PHP_EOL;
|
|
}
|
|
|
|
if ($strict && ($report['parse_errors'] !== [] || $report['unresolved_phpunit_fixtures'] !== [])) {
|
|
exit(1);
|
|
}
|
|
|
|
function printUsage(string $script): void
|
|
{
|
|
echo <<<USAGE
|
|
Usage:
|
|
php {$script} [options] [PHPT path ...]
|
|
|
|
Options:
|
|
--format=summary|json|markdown Output format (default: summary)
|
|
--output=<file> Write the report to a file
|
|
--php-versions=8.4,8.5 Target PHP version columns
|
|
--no-phpunit Do not scan PHPUnit compiler fixtures
|
|
--strict Fail on parse issues or unresolved fixture links
|
|
-h, --help Show this help
|
|
|
|
Examples:
|
|
php {$script}
|
|
php {$script} --format=markdown --output=build/test-coverage.md
|
|
php {$script} --format=json tests/compiler/type_decl tests/compiler/basic
|
|
|
|
The tool reports separate, explicitly denominated AST-node, positive compile,
|
|
runtime semantic and negative diagnostic coverage. It never emits a combined
|
|
overall percentage.
|
|
|
|
USAGE;
|
|
}
|
|
|
|
function isAbsolutePath(string $path): bool
|
|
{
|
|
return $path !== '' && ($path[0] === '/' || preg_match('/^[A-Za-z]:[\\\\\/]/', $path) === 1);
|
|
}
|
|
|
|
function relativePath(string $root, string $path): string
|
|
{
|
|
$prefix = rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
|
return str_starts_with($path, $prefix) ? substr($path, strlen($prefix)) : $path;
|
|
}
|
|
|