* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Utility methods for PHP sub-processes. * * @since Class available since Release 3.4.0 */ abstract class PHPUnit_Util_PHP { /** * @return PHPUnit_Util_PHP * * @since Method available since Release 3.5.12 */ public static function factory() { if (DIRECTORY_SEPARATOR == '\\') { return new PHPUnit_Util_PHP_Windows; } return new PHPUnit_Util_PHP_Default; } /** * Runs a single test in a separate PHP process. * * @param string $job * @param PHPUnit_Framework_Test $test * @param PHPUnit_Framework_TestResult $result * * @throws PHPUnit_Framework_Exception */ public function runTestJob($job, PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result) { $result->startTest($test); $_result = $this->runJob($job); $this->processChildResult( $test, $result, $_result['stdout'], $_result['stderr'] ); } /** * Runs a single job (PHP code) using a separate PHP process. * * @param string $job * @param array $settings * * @return array * * @throws PHPUnit_Framework_Exception */ abstract public function runJob($job, array $settings = array()); /** * @param array $settings * * @return string * * @since Method available since Release 4.0.0 */ protected function settingsToParameters(array $settings) { $buffer = ''; foreach ($settings as $setting) { $buffer .= ' -d ' . $setting; } return $buffer; } /** * Processes the TestResult object from an isolated process. * * @param PHPUnit_Framework_Test $test * @param PHPUnit_Framework_TestResult $result * @param string $stdout * @param string $stderr * * @since Method available since Release 3.5.0 */ private function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr) { $time = 0; if (!empty($stderr)) { $result->addError( $test, new PHPUnit_Framework_Exception(trim($stderr)), $time ); } else { set_error_handler(function ($errno, $errstr, $errfile, $errline) { throw new ErrorException($errstr, $errno, $errno, $errfile, $errline); }); try { if (strpos($stdout, "#!/usr/bin/env php\n") === 0) { $stdout = substr($stdout, 19); } $childResult = unserialize(str_replace("#!/usr/bin/env php\n", '', $stdout)); restore_error_handler(); } catch (ErrorException $e) { restore_error_handler(); $childResult = false; $result->addError( $test, new PHPUnit_Framework_Exception(trim($stdout), 0, $e), $time ); } if ($childResult !== false) { if (!empty($childResult['output'])) { $output = $childResult['output']; } $test->setResult($childResult['testResult']); $test->addToAssertionCount($childResult['numAssertions']); $childResult = $childResult['result']; if ($result->getCollectCodeCoverageInformation()) { $result->getCodeCoverage()->merge( $childResult->getCodeCoverage() ); } $time = $childResult->time(); $notImplemented = $childResult->notImplemented(); $risky = $childResult->risky(); $skipped = $childResult->skipped(); $errors = $childResult->errors(); $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($failures)) { $result->addFailure( $test, $this->getException($failures[0]), $time ); } } } $result->endTest($test, $time); if (!empty($output)) { print $output; } } /** * Gets the thrown exception from a PHPUnit_Framework_TestFailure. * * @param PHPUnit_Framework_TestFailure $error * * @return Exception * * @since Method available since Release 3.6.0 * @see https://github.com/sebastianbergmann/phpunit/issues/74 */ private function getException(PHPUnit_Framework_TestFailure $error) { $exception = $error->thrownException(); if ($exception instanceof __PHP_Incomplete_Class) { $exceptionArray = array(); foreach ((array) $exception as $key => $value) { $key = substr($key, strrpos($key, "\0") + 1); $exceptionArray[$key] = $value; } $exception = new PHPUnit_Framework_SyntheticError( sprintf( '%s: %s', $exceptionArray['_PHP_Incomplete_Class_Name'], $exceptionArray['message'] ), $exceptionArray['code'], $exceptionArray['file'], $exceptionArray['line'], $exceptionArray['trace'] ); } return $exception; } }