Вход Регистрация
Файл: vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
Строк: 368
<?php declare(strict_types=1);
/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace PHPUnitUtilPHP;

use const 
DIRECTORY_SEPARATOR;
use const 
PHP_SAPI;
use function 
array_keys;
use function 
array_merge;
use function 
assert;
use function 
escapeshellarg;
use function 
ini_get_all;
use function 
restore_error_handler;
use function 
set_error_handler;
use function 
sprintf;
use function 
str_replace;
use function 
strpos;
use function 
strrpos;
use function 
substr;
use function 
trim;
use function 
unserialize;
use 
__PHP_Incomplete_Class;
use 
ErrorException;
use 
PHPUnitFrameworkAssertionFailedError;
use 
PHPUnitFrameworkException;
use 
PHPUnitFrameworkSyntheticError;
use 
PHPUnitFrameworkTest;
use 
PHPUnitFrameworkTestCase;
use 
PHPUnitFrameworkTestFailure;
use 
PHPUnitFrameworkTestResult;
use 
SebastianBergmannEnvironmentRuntime;

/**
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
 */
abstract class AbstractPhpProcess
{
    
/**
     * @var Runtime
     */
    
protected $runtime;

    
/**
     * @var bool
     */
    
protected $stderrRedirection false;

    
/**
     * @var string
     */
    
protected $stdin '';

    
/**
     * @var string
     */
    
protected $args '';

    
/**
     * @var array<string, string>
     */
    
protected $env = [];

    
/**
     * @var int
     */
    
protected $timeout 0;

    public static function 
factory(): self
    
{
        if (
DIRECTORY_SEPARATOR === '\') {
            return new WindowsPhpProcess;
        }

        return new DefaultPhpProcess;
    }

    public function __construct()
    {
        $this->runtime = new Runtime;
    }

    /**
     * Defines if should use STDERR redirection or not.
     *
     * Then $stderrRedirection is TRUE, STDERR is redirected to STDOUT.
     */
    public function setUseStderrRedirection(bool $stderrRedirection): void
    {
        $this->stderrRedirection = $stderrRedirection;
    }

    /**
     * Returns TRUE if uses STDERR redirection or FALSE if not.
     */
    public function useStderrRedirection(): bool
    {
        return $this->stderrRedirection;
    }

    /**
     * Sets the input string to be sent via STDIN.
     */
    public function setStdin(string $stdin): void
    {
        $this->stdin = $stdin;
    }

    /**
     * Returns the input string to be sent via STDIN.
     */
    public function getStdin(): string
    {
        return $this->stdin;
    }

    /**
     * Sets the string of arguments to pass to the php job.
     */
    public function setArgs(string $args): void
    {
        $this->args = $args;
    }

    /**
     * Returns the string of arguments to pass to the php job.
     */
    public function getArgs(): string
    {
        return $this->args;
    }

    /**
     * Sets the array of environment variables to start the child process with.
     *
     * @param array<string, string> $env
     */
    public function setEnv(array $env): void
    {
        $this->env = $env;
    }

    /**
     * Returns the array of environment variables to start the child process with.
     */
    public function getEnv(): array
    {
        return $this->env;
    }

    /**
     * Sets the amount of seconds to wait before timing out.
     */
    public function setTimeout(int $timeout): void
    {
        $this->timeout = $timeout;
    }

    /**
     * Returns the amount of seconds to wait before timing out.
     */
    public function getTimeout(): int
    {
        return $this->timeout;
    }

    /**
     * Runs a single test in a separate PHP process.
     *
     * @throws SebastianBergmannRecursionContextInvalidArgumentException
     */
    public function runTestJob(string $job, Test $test, TestResult $result): void
    {
        $result->startTest($test);

        $_result = $this->runJob($job);

        $this->processChildResult(
            $test,
            $result,
            $_result['
stdout'],
            $_result['
stderr']
        );
    }

    /**
     * Returns the command based into the configurations.
     */
    public function getCommand(array $settings, string $file = null): string
    {
        $command = $this->runtime->getBinary();

        if ($this->runtime->hasPCOV()) {
            $settings = array_merge(
                $settings,
                $this->runtime->getCurrentSettings(
                    array_keys(ini_get_all('
pcov'))
                )
            );
        } elseif ($this->runtime->hasXdebug()) {
            $settings = array_merge(
                $settings,
                $this->runtime->getCurrentSettings(
                    array_keys(ini_get_all('
xdebug'))
                )
            );
        }

        $command .= $this->settingsToParameters($settings);

        if (PHP_SAPI === '
phpdbg') {
            $command .= ' 
-qrr';

            if (!$file) {
                $command .= '
s=';
            }
        }

        if ($file) {
            $command .= ' ' . escapeshellarg($file);
        }

        if ($this->args) {
            if (!$file) {
                $command .= ' 
--';
            }
            $command .= ' ' . $this->args;
        }

        if ($this->stderrRedirection) {
            $command .= ' 
2>&1';
        }

        return $command;
    }

    /**
     * Runs a single job (PHP code) using a separate PHP process.
     */
    abstract public function runJob(string $job, array $settings = []): array;

    protected function settingsToParameters(array $settings): string
    {
        $buffer = '';

        foreach ($settings as $setting) {
            $buffer .= ' 
-' . escapeshellarg($setting);
        }

        return $buffer;
    }

    /**
     * Processes the TestResult object from an isolated process.
     *
     * @throws SebastianBergmannRecursionContextInvalidArgumentException
     */
    private function processChildResult(Test $test, TestResult $result, string $stdout, string $stderr): void
    {
        $time = 0;

        if (!empty($stderr)) {
            $result->addError(
                $test,
                new Exception(trim($stderr)),
                $time
            );
        } else {
            set_error_handler(
                /**
                 * @throws ErrorException
                 */
                static function ($errno, $errstr, $errfile, $errline): void
                {
                    throw new ErrorException($errstr, $errno, $errno, $errfile, $errline);
                }
            );

            try {
                if (strpos($stdout, "#!/usr/bin/env phpn") === 0) {
                    $stdout = substr($stdout, 19);
                }

                $childResult = unserialize(str_replace("#!/usr/bin/env phpn", '', $stdout));
                restore_error_handler();

                if ($childResult === false) {
                    $result->addFailure(
                        $test,
                        new AssertionFailedError('
Test was run in child process and ended unexpectedly'),
                        $time
                    );
                }
            } catch (ErrorException $e) {
                restore_error_handler();
                $childResult = false;

                $result->addError(
                    $test,
                    new Exception(trim($stdout), 0, $e),
                    $time
                );
            }

            if ($childResult !== false) {
                if (!empty($childResult['
output'])) {
                    $output = $childResult['
output'];
                }

                /* @var TestCase $test */

                $test->setResult($childResult['
testResult']);
                $test->addToAssertionCount($childResult['
numAssertions']);

                $childResult = $childResult['
result'];
                assert($childResult instanceof TestResult);

                if ($result->getCollectCodeCoverageInformation()) {
                    $result->getCodeCoverage()->merge(
                        $childResult->getCodeCoverage()
                    );
                }

                $time           = $childResult->time();
                $notImplemented = $childResult->notImplemented();
                $risky          = $childResult->risky();
                $skipped        = $childResult->skipped();
                $errors         = $childResult->errors();
                $warnings       = $childResult->warnings();
                $failures       = $childResult->failures();

                if (!empty($notImplemented)) {
                    $result->addError(
                        $test,
                        $this->getException($notImplemented[0]),
                        $time
                    );
                } elseif (!empty($risky)) {
                    $result->addError(
                        $test,
                        $this->getException($risky[0]),
                        $time
                    );
                } elseif (!empty($skipped)) {
                    $result->addError(
                        $test,
                        $this->getException($skipped[0]),
                        $time
                    );
                } elseif (!empty($errors)) {
                    $result->addError(
                        $test,
                        $this->getException($errors[0]),
                        $time
                    );
                } elseif (!empty($warnings)) {
                    $result->addWarning(
                        $test,
                        $this->getException($warnings[0]),
                        $time
                    );
                } elseif (!empty($failures)) {
                    $result->addFailure(
                        $test,
                        $this->getException($failures[0]),
                        $time
                    );
                }
            }
        }

        $result->endTest($test, $time);

        if (!empty($output)) {
            print $output;
        }
    }

    /**
     * Gets the thrown exception from a PHPUnitFrameworkTestFailure.
     *
     * @see https://github.com/sebastianbergmann/phpunit/issues/74
     */
    private function getException(TestFailure $error): Exception
    {
        $exception = $error->thrownException();

        if ($exception instanceof __PHP_Incomplete_Class) {
            $exceptionArray = [];

            foreach ((array) $exception as $key => $value) {
                $key                  = substr($key, strrpos($key, "") + 1);
                $exceptionArray[$key] = $value;
            }

            $exception = new SyntheticError(
                sprintf(
                    '
%s: %s',
                    $exceptionArray['
_PHP_Incomplete_Class_Name'],
                    $exceptionArray['
message']
                ),
                $exceptionArray['
code'],
                $exceptionArray['
file'],
                $exceptionArray['
line'],
                $exceptionArray['
trace']
            );
        }

        return $exception;
    }
}
Онлайн: 0
Реклама