FestinHegre/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php
2024-09-26 17:26:04 +02:00

469 lines
19 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
// Please update when phpunit needs to be reinstalled with fresh deps:
// Cache-Id: 2021-02-04 11:00 UTC
if ('cli' !== \PHP_SAPI && 'phpdbg' !== \PHP_SAPI) {
throw new Exception('This script must be run from the command line.');
}
error_reporting(-1);
global $argv, $argc;
$argv = $_SERVER['argv'] ?? [];
$argc = $_SERVER['argc'] ?? 0;
$getEnvVar = function ($name, $default = false) use ($argv) {
if (false !== $value = getenv($name)) {
return $value;
}
static $phpunitConfig = null;
if (null === $phpunitConfig) {
$phpunitConfigFilename = null;
$getPhpUnitConfig = function ($probableConfig) use (&$getPhpUnitConfig) {
if (!$probableConfig) {
return null;
}
if (is_dir($probableConfig)) {
return $getPhpUnitConfig($probableConfig.\DIRECTORY_SEPARATOR.'phpunit.xml');
}
if (file_exists($probableConfig)) {
return $probableConfig;
}
if (file_exists($probableConfig.'.dist')) {
return $probableConfig.'.dist';
}
return null;
};
foreach ($argv as $cliArgumentIndex => $cliArgument) {
if ('--' === $cliArgument) {
break;
}
// long option
if ('--configuration' === $cliArgument && array_key_exists($cliArgumentIndex + 1, $argv)) {
$phpunitConfigFilename = $getPhpUnitConfig($argv[$cliArgumentIndex + 1]);
break;
}
// short option
if (0 === strpos($cliArgument, '-c')) {
if ('-c' === $cliArgument && array_key_exists($cliArgumentIndex + 1, $argv)) {
$phpunitConfigFilename = $getPhpUnitConfig($argv[$cliArgumentIndex + 1]);
} else {
$phpunitConfigFilename = $getPhpUnitConfig(substr($cliArgument, 2));
}
break;
}
}
$phpunitConfigFilename = $phpunitConfigFilename ?: $getPhpUnitConfig('phpunit.xml');
if ($phpunitConfigFilename) {
$phpunitConfig = new DOMDocument();
$phpunitConfig->load($phpunitConfigFilename);
} else {
$phpunitConfig = false;
}
}
if (false !== $phpunitConfig) {
$var = new DOMXPath($phpunitConfig);
foreach ($var->query('//php/server[@name="'.$name.'"]') as $var) {
return $var->getAttribute('value');
}
foreach ($var->query('//php/env[@name="'.$name.'"]') as $var) {
return $var->getAttribute('value');
}
}
return $default;
};
$passthruOrFail = function ($command) {
passthru($command, $status);
if ($status) {
exit($status);
}
};
if (\PHP_VERSION_ID >= 80000) {
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.6') ?: '9.6';
} else {
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.5') ?: '8.5';
}
$MAX_PHPUNIT_VERSION = $getEnvVar('SYMFONY_MAX_PHPUNIT_VERSION', false);
if ($MAX_PHPUNIT_VERSION && version_compare($MAX_PHPUNIT_VERSION, $PHPUNIT_VERSION, '<')) {
$PHPUNIT_VERSION = $MAX_PHPUNIT_VERSION;
}
$PHPUNIT_REMOVE_RETURN_TYPEHINT = filter_var($getEnvVar('SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT', '0'), \FILTER_VALIDATE_BOOLEAN);
$COMPOSER_JSON = getenv('COMPOSER') ?: 'composer.json';
$root = __DIR__;
while (!file_exists($root.'/'.$COMPOSER_JSON) || file_exists($root.'/DeprecationErrorHandler.php')) {
if ($root === dirname($root)) {
break;
}
$root = dirname($root);
}
$oldPwd = getcwd();
$PHPUNIT_DIR = rtrim($getEnvVar('SYMFONY_PHPUNIT_DIR', $root.'/vendor/bin/.phpunit'), '/'.\DIRECTORY_SEPARATOR);
$PHP = defined('PHP_BINARY') ? \PHP_BINARY : 'php';
$PHP = escapeshellarg($PHP);
if ('phpdbg' === \PHP_SAPI) {
$PHP .= ' -qrr';
}
$defaultEnvs = [
'COMPOSER' => 'composer.json',
'COMPOSER_VENDOR_DIR' => 'vendor',
'COMPOSER_BIN_DIR' => 'bin',
'SYMFONY_SIMPLE_PHPUNIT_BIN_DIR' => __DIR__,
];
foreach ($defaultEnvs as $envName => $envValue) {
if ($envValue !== getenv($envName)) {
putenv("$envName=$envValue");
$_SERVER[$envName] = $_ENV[$envName] = $envValue;
}
}
if ('disabled' === $getEnvVar('SYMFONY_DEPRECATIONS_HELPER')) {
putenv('SYMFONY_DEPRECATIONS_HELPER=disabled');
}
if (!$getEnvVar('DOCTRINE_DEPRECATIONS')) {
putenv('DOCTRINE_DEPRECATIONS=trigger');
$_SERVER['DOCTRINE_DEPRECATIONS'] = $_ENV['DOCTRINE_DEPRECATIONS'] = 'trigger';
}
$COMPOSER = ($COMPOSER = getenv('COMPOSER_BINARY'))
|| file_exists($COMPOSER = $oldPwd.'/composer.phar')
|| ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', shell_exec('where.exe composer.phar 2> NUL')) : shell_exec('which composer.phar 2> /dev/null'))))
|| ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', shell_exec('where.exe composer 2> NUL')) : shell_exec('which composer 2> /dev/null'))))
|| file_exists($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? shell_exec('git rev-parse --show-toplevel 2> NUL') : shell_exec('git rev-parse --show-toplevel 2> /dev/null'))).\DIRECTORY_SEPARATOR.'composer.phar')
? ('#!/usr/bin/env php' === file_get_contents($COMPOSER, false, null, 0, 18) ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang
: 'composer';
$prevCacheDir = getenv('COMPOSER_CACHE_DIR');
if ($prevCacheDir) {
if (false === $absoluteCacheDir = realpath($prevCacheDir)) {
@mkdir($prevCacheDir, 0777, true);
$absoluteCacheDir = realpath($prevCacheDir);
}
if ($absoluteCacheDir) {
putenv("COMPOSER_CACHE_DIR=$absoluteCacheDir");
} else {
$prevCacheDir = false;
}
}
$SYMFONY_PHPUNIT_REMOVE = $getEnvVar('SYMFONY_PHPUNIT_REMOVE', 'phpspec/prophecy'.($PHPUNIT_VERSION < 6.0 ? ' symfony/yaml' : ''));
$SYMFONY_PHPUNIT_REQUIRE = $getEnvVar('SYMFONY_PHPUNIT_REQUIRE', '');
$configurationHash = md5(implode(\PHP_EOL, [md5_file(__FILE__), $SYMFONY_PHPUNIT_REMOVE, $SYMFONY_PHPUNIT_REQUIRE, (int) $PHPUNIT_REMOVE_RETURN_TYPEHINT]));
$PHPUNIT_VERSION_DIR = sprintf('phpunit-%s-%d', $PHPUNIT_VERSION, $PHPUNIT_REMOVE_RETURN_TYPEHINT);
if (!file_exists("$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR/phpunit") || $configurationHash !== @file_get_contents("$PHPUNIT_DIR/.$PHPUNIT_VERSION_DIR.md5")) {
// Build a standalone phpunit without symfony/yaml nor prophecy by default
@mkdir($PHPUNIT_DIR, 0777, true);
chdir($PHPUNIT_DIR);
if (file_exists("$PHPUNIT_VERSION_DIR")) {
passthru(sprintf('\\' === \DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s 2> NUL' : 'rm -rf %s', escapeshellarg("$PHPUNIT_VERSION_DIR.old")));
rename("$PHPUNIT_VERSION_DIR", "$PHPUNIT_VERSION_DIR.old");
passthru(sprintf('\\' === \DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s' : 'rm -rf %s', escapeshellarg("$PHPUNIT_VERSION_DIR.old")));
}
$info = [];
foreach (explode("\n", `$COMPOSER info --no-ansi -a -n phpunit/phpunit "$PHPUNIT_VERSION.*"`) as $line) {
$line = rtrim($line);
if (!$info && preg_match('/^versions +: /', $line)) {
$info['versions'] = explode(', ', ltrim(substr($line, 9), ': '));
} elseif (isset($info['requires'])) {
if ('' === $line) {
break;
}
$line = explode(' ', $line, 2);
$info['requires'][$line[0]] = $line[1];
} elseif ($info && 'requires' === $line) {
$info['requires'] = [];
}
}
if (in_array('--colors=never', $argv, true) || (isset($argv[$i = array_search('never', $argv, true) - 1]) && '--colors' === $argv[$i])) {
$COMPOSER .= ' --no-ansi';
} else {
$COMPOSER .= ' --ansi';
}
$info += [
'versions' => [],
'requires' => ['php' => '*'],
];
$stableVersions = array_filter($info['versions'], function ($v) {
return !preg_match('/-dev$|^dev-/', $v);
});
if (!$stableVersions) {
$passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress -s dev phpunit/phpunit $PHPUNIT_VERSION_DIR \"$PHPUNIT_VERSION.*\"");
} else {
$passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress phpunit/phpunit $PHPUNIT_VERSION_DIR \"$PHPUNIT_VERSION.*\"");
}
@copy("$PHPUNIT_VERSION_DIR/phpunit.xsd", 'phpunit.xsd');
chdir("$PHPUNIT_VERSION_DIR");
if ($SYMFONY_PHPUNIT_REMOVE) {
$passthruOrFail("$COMPOSER remove --no-update --no-interaction ".$SYMFONY_PHPUNIT_REMOVE);
}
if ($SYMFONY_PHPUNIT_REQUIRE) {
$passthruOrFail("$COMPOSER require --no-update --no-interaction ".$SYMFONY_PHPUNIT_REQUIRE);
}
if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) {
$passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\"");
}
if (preg_match('{\^((\d++\.)\d++)[\d\.]*$}', $info['requires']['php'], $phpVersion) && version_compare($phpVersion[2].'99', \PHP_VERSION, '<')) {
$passthruOrFail("$COMPOSER config platform.php \"$phpVersion[1].99\"");
} else {
$passthruOrFail("$COMPOSER config --unset platform.php");
}
if (file_exists($path = $root.'/vendor/symfony/phpunit-bridge')) {
$haystack = "$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR";
$rootLen = strlen($root);
$p = ($rootLen <= strlen($haystack) ? str_repeat('../', substr_count($haystack, '/', $rootLen)) : '').'vendor/symfony/phpunit-bridge';
if (realpath($p) === realpath($path)) {
$path = $p;
}
$passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\"");
$passthruOrFail("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', \DIRECTORY_SEPARATOR, $path)));
if ('\\' === \DIRECTORY_SEPARATOR) {
file_put_contents('composer.json', preg_replace('/^( {8})"phpunit-bridge": \{$/m', "$0\n$1 ".'"options": {"symlink": false},', file_get_contents('composer.json')));
}
} else {
$passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*\"");
}
$prevRoot = getenv('COMPOSER_ROOT_VERSION');
putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99");
$q = '\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 80000 ? '"' : '';
// --no-suggest is not in the list to keep compat with composer 1.0, which is shipped with Ubuntu 16.04LTS
$exit = proc_close(proc_open("$q$COMPOSER update --no-dev --prefer-dist --no-progress $q", [], $p, getcwd()));
putenv('COMPOSER_ROOT_VERSION'.(false !== $prevRoot ? '='.$prevRoot : ''));
if ($prevCacheDir) {
putenv("COMPOSER_CACHE_DIR=$prevCacheDir");
}
if ($exit) {
exit($exit);
}
// Mutate TestCase code
$alteredCode = file_get_contents($alteredFile = './src/Framework/TestCase.php');
if ($PHPUNIT_REMOVE_RETURN_TYPEHINT) {
$alteredCode = preg_replace('/^ ((?:protected|public)(?: static)? function \w+\(\)): void/m', ' $1', $alteredCode);
}
$alteredCode = preg_replace('/abstract class TestCase[^\{]+\{/', '$0 '.\PHP_EOL." use \Symfony\Bridge\PhpUnit\Legacy\PolyfillTestCaseTrait;", $alteredCode, 1);
file_put_contents($alteredFile, $alteredCode);
// Mutate Assert code
$alteredCode = file_get_contents($alteredFile = './src/Framework/Assert.php');
$alteredCode = preg_replace('/abstract class Assert[^\{]+\{/', '$0 '.\PHP_EOL." use \Symfony\Bridge\PhpUnit\Legacy\PolyfillAssertTrait;", $alteredCode, 1);
file_put_contents($alteredFile, $alteredCode);
file_put_contents('phpunit', <<<'EOPHP'
<?php
define('PHPUNIT_COMPOSER_INSTALL', __DIR__.'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
if (!class_exists(\SymfonyExcludeListPhpunit::class, false)) {
class SymfonyExcludeListPhpunit {}
}
if (method_exists(\PHPUnit\Util\ExcludeList::class, 'addDirectory')) {
(new PHPUnit\Util\Excludelist())->getExcludedDirectories();
PHPUnit\Util\ExcludeList::addDirectory(\dirname((new \ReflectionClass(\SymfonyExcludeListPhpunit::class))->getFileName()));
class_exists(\SymfonyExcludeListSimplePhpunit::class, false) && PHPUnit\Util\ExcludeList::addDirectory(\dirname((new \ReflectionClass(\SymfonyExcludeListSimplePhpunit::class))->getFileName()));
} elseif (method_exists(\PHPUnit\Util\Blacklist::class, 'addDirectory')) {
(new PHPUnit\Util\BlackList())->getBlacklistedDirectories();
PHPUnit\Util\Blacklist::addDirectory(\dirname((new \ReflectionClass(\SymfonyExcludeListPhpunit::class))->getFileName()));
class_exists(\SymfonyExcludeListSimplePhpunit::class, false) && PHPUnit\Util\Blacklist::addDirectory(\dirname((new \ReflectionClass(\SymfonyExcludeListSimplePhpunit::class))->getFileName()));
} else {
PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyExcludeListPhpunit'] = 1;
PHPUnit\Util\Blacklist::$blacklistedClassNames['SymfonyExcludeListSimplePhpunit'] = 1;
}
Symfony\Bridge\PhpUnit\TextUI\Command::main();
EOPHP
);
chdir('..');
file_put_contents(".$PHPUNIT_VERSION_DIR.md5", $configurationHash);
chdir($oldPwd);
}
// Create a symlink with a predictable path pointing to the currently used version.
// This is useful for static analytics tools such as PHPStan having to load PHPUnit's classes
// and for other testing libraries such as Behat using PHPUnit's assertions.
chdir($PHPUNIT_DIR);
if ('\\' === \DIRECTORY_SEPARATOR) {
passthru('rmdir /S /Q phpunit 2> NUL');
passthru(sprintf('mklink /j phpunit %s > NUL 2>&1', escapeshellarg($PHPUNIT_VERSION_DIR)));
} else {
if (file_exists('phpunit')) {
@unlink('phpunit');
}
@symlink($PHPUNIT_VERSION_DIR, 'phpunit');
}
chdir($oldPwd);
if ($PHPUNIT_VERSION < 8.0) {
$argv = array_filter($argv, function ($v) use (&$argc) {
if ('--do-not-cache-result' !== $v) {
return true;
}
--$argc;
return false;
});
} elseif (filter_var(getenv('SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE'), \FILTER_VALIDATE_BOOLEAN)) {
$argv[] = '--do-not-cache-result';
++$argc;
}
$components = [];
$cmd = array_map('escapeshellarg', $argv);
$exit = 0;
if (isset($argv[1]) && 'symfony' === $argv[1] && !file_exists('symfony') && file_exists('src/Symfony')) {
$argv[1] = 'src/Symfony';
}
if (isset($argv[1]) && is_dir($argv[1]) && !file_exists($argv[1].'/phpunit.xml.dist')) {
// Find Symfony components in plain php for Windows portability
$finder = new RecursiveDirectoryIterator($argv[1], FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::UNIX_PATHS);
$finder = new RecursiveIteratorIterator($finder);
$finder->setMaxDepth(getenv('SYMFONY_PHPUNIT_MAX_DEPTH') ?: 3);
foreach ($finder as $file => $fileInfo) {
if ('phpunit.xml.dist' === $file) {
$components[] = dirname($fileInfo->getPathname());
}
}
if ($components) {
array_shift($cmd);
}
}
$cmd[0] = sprintf('%s %s --colors=%s', $PHP, escapeshellarg("$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR/phpunit"), '' === $getEnvVar('NO_COLOR', '') ? 'always' : 'never');
$cmd = str_replace('%', '%%', implode(' ', $cmd)).' %1$s';
if ('\\' === \DIRECTORY_SEPARATOR) {
$cmd = 'cmd /v:on /d /c "('.$cmd.')%2$s"';
} else {
$cmd .= '%2$s';
}
if ($components) {
$skippedTests = $_SERVER['SYMFONY_PHPUNIT_SKIPPED_TESTS'] ?? false;
$runningProcs = [];
foreach ($components as $component) {
// Run phpunit tests in parallel
if ($skippedTests) {
putenv("SYMFONY_PHPUNIT_SKIPPED_TESTS=$component/$skippedTests");
}
$c = escapeshellarg($component);
if ($proc = proc_open(sprintf($cmd, $c, " > $c/phpunit.stdout 2> $c/phpunit.stderr"), [], $pipes)) {
$runningProcs[$component] = $proc;
} else {
$exit = 1;
echo "\033[41mKO\033[0m $component\n\n";
}
}
$lastOutput = null;
$lastOutputTime = null;
while ($runningProcs) {
usleep(300000);
$terminatedProcs = [];
foreach ($runningProcs as $component => $proc) {
$procStatus = proc_get_status($proc);
if (!$procStatus['running']) {
$terminatedProcs[$component] = $procStatus['exitcode'];
unset($runningProcs[$component]);
proc_close($proc);
}
}
if (!$terminatedProcs && 1 === count($runningProcs)) {
$component = key($runningProcs);
$output = file_get_contents("$component/phpunit.stdout");
$output .= file_get_contents("$component/phpunit.stderr");
if ($lastOutput !== $output) {
$lastOutput = $output;
$lastOutputTime = microtime(true);
} elseif (microtime(true) - $lastOutputTime > 60) {
echo "\033[41mTimeout\033[0m $component\n\n";
if ('\\' === \DIRECTORY_SEPARATOR) {
exec(sprintf('taskkill /F /T /PID %d 2>&1', $procStatus['pid']), $output, $exitCode);
} else {
proc_terminate(current($runningProcs));
}
}
}
foreach ($terminatedProcs as $component => $procStatus) {
foreach (['out', 'err'] as $file) {
$file = "$component/phpunit.std$file";
readfile($file);
unlink($file);
}
// Fail on any individual component failures but ignore some error codes on Windows when APCu is enabled:
// STATUS_STACK_BUFFER_OVERRUN (-1073740791/0xC0000409)
// STATUS_ACCESS_VIOLATION (-1073741819/0xC0000005)
// STATUS_HEAP_CORRUPTION (-1073740940/0xC0000374)
if ($procStatus && ('\\' !== \DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN) || !in_array($procStatus, [-1073740791, -1073741819, -1073740940]))) {
$exit = $procStatus;
echo "\033[41mKO\033[0m $component\n\n";
} else {
echo "\033[32mOK\033[0m $component\n\n";
}
}
}
} elseif (!isset($argv[1]) || 'install' !== $argv[1] || file_exists('install')) {
if (!class_exists(\SymfonyExcludeListSimplePhpunit::class, false)) {
class SymfonyExcludeListSimplePhpunit
{
}
}
array_splice($argv, 1, 0, ['--colors='.('' === $getEnvVar('NO_COLOR', '') ? 'always' : 'never')]);
$_SERVER['argv'] = $argv;
$_SERVER['argc'] = ++$argc;
include "$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR/phpunit";
}
exit($exit);