84c2ead7790199d9a6e1bcdaf23865a4b50a3c8c
[yaffs-website] / PHP.php
1 <?php
2 /*
3  * This file is part of PHPUnit.
4  *
5  * (c) Sebastian Bergmann <sebastian@phpunit.de>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * Utility methods for PHP sub-processes.
13  *
14  * @since Class available since Release 3.4.0
15  */
16 abstract class PHPUnit_Util_PHP
17 {
18     /**
19      * @return PHPUnit_Util_PHP
20      *
21      * @since  Method available since Release 3.5.12
22      */
23     public static function factory()
24     {
25         if (DIRECTORY_SEPARATOR == '\\') {
26             return new PHPUnit_Util_PHP_Windows;
27         }
28
29         return new PHPUnit_Util_PHP_Default;
30     }
31
32     /**
33      * Runs a single test in a separate PHP process.
34      *
35      * @param string                       $job
36      * @param PHPUnit_Framework_Test       $test
37      * @param PHPUnit_Framework_TestResult $result
38      *
39      * @throws PHPUnit_Framework_Exception
40      */
41     public function runTestJob($job, PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result)
42     {
43         $result->startTest($test);
44
45         $_result = $this->runJob($job);
46
47         $this->processChildResult(
48             $test,
49             $result,
50             $_result['stdout'],
51             $_result['stderr']
52         );
53     }
54
55     /**
56      * Runs a single job (PHP code) using a separate PHP process.
57      *
58      * @param string $job
59      * @param array  $settings
60      *
61      * @return array
62      *
63      * @throws PHPUnit_Framework_Exception
64      */
65     abstract public function runJob($job, array $settings = array());
66
67     /**
68      * @param array $settings
69      *
70      * @return string
71      *
72      * @since Method available since Release 4.0.0
73      */
74     protected function settingsToParameters(array $settings)
75     {
76         $buffer = '';
77
78         foreach ($settings as $setting) {
79             $buffer .= ' -d ' . $setting;
80         }
81
82         return $buffer;
83     }
84
85     /**
86      * Processes the TestResult object from an isolated process.
87      *
88      * @param PHPUnit_Framework_Test       $test
89      * @param PHPUnit_Framework_TestResult $result
90      * @param string                       $stdout
91      * @param string                       $stderr
92      *
93      * @since Method available since Release 3.5.0
94      */
95     private function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr)
96     {
97         $time = 0;
98
99         if (!empty($stderr)) {
100             $result->addError(
101                 $test,
102                 new PHPUnit_Framework_Exception(trim($stderr)),
103                 $time
104             );
105         } else {
106             set_error_handler(function ($errno, $errstr, $errfile, $errline) {
107                 throw new ErrorException($errstr, $errno, $errno, $errfile, $errline);
108             });
109             try {
110                 if (strpos($stdout, "#!/usr/bin/env php\n") === 0) {
111                     $stdout = substr($stdout, 19);
112                 }
113
114                 $childResult = unserialize(str_replace("#!/usr/bin/env php\n", '', $stdout));
115                 restore_error_handler();
116             } catch (ErrorException $e) {
117                 restore_error_handler();
118                 $childResult = false;
119
120                 $result->addError(
121                     $test,
122                     new PHPUnit_Framework_Exception(trim($stdout), 0, $e),
123                     $time
124                 );
125             }
126
127             if ($childResult !== false) {
128                 if (!empty($childResult['output'])) {
129                     $output = $childResult['output'];
130                 }
131
132                 $test->setResult($childResult['testResult']);
133                 $test->addToAssertionCount($childResult['numAssertions']);
134
135                 $childResult = $childResult['result'];
136
137                 if ($result->getCollectCodeCoverageInformation()) {
138                     $result->getCodeCoverage()->merge(
139                         $childResult->getCodeCoverage()
140                     );
141                 }
142
143                 $time           = $childResult->time();
144                 $notImplemented = $childResult->notImplemented();
145                 $risky          = $childResult->risky();
146                 $skipped        = $childResult->skipped();
147                 $errors         = $childResult->errors();
148                 $failures       = $childResult->failures();
149
150                 if (!empty($notImplemented)) {
151                     $result->addError(
152                         $test,
153                         $this->getException($notImplemented[0]),
154                         $time
155                     );
156                 } elseif (!empty($risky)) {
157                     $result->addError(
158                         $test,
159                         $this->getException($risky[0]),
160                         $time
161                     );
162                 } elseif (!empty($skipped)) {
163                     $result->addError(
164                         $test,
165                         $this->getException($skipped[0]),
166                         $time
167                     );
168                 } elseif (!empty($errors)) {
169                     $result->addError(
170                         $test,
171                         $this->getException($errors[0]),
172                         $time
173                     );
174                 } elseif (!empty($failures)) {
175                     $result->addFailure(
176                         $test,
177                         $this->getException($failures[0]),
178                         $time
179                     );
180                 }
181             }
182         }
183
184         $result->endTest($test, $time);
185
186         if (!empty($output)) {
187             print $output;
188         }
189     }
190
191     /**
192      * Gets the thrown exception from a PHPUnit_Framework_TestFailure.
193      *
194      * @param PHPUnit_Framework_TestFailure $error
195      *
196      * @return Exception
197      *
198      * @since  Method available since Release 3.6.0
199      * @see    https://github.com/sebastianbergmann/phpunit/issues/74
200      */
201     private function getException(PHPUnit_Framework_TestFailure $error)
202     {
203         $exception = $error->thrownException();
204
205         if ($exception instanceof __PHP_Incomplete_Class) {
206             $exceptionArray = array();
207             foreach ((array) $exception as $key => $value) {
208                 $key                  = substr($key, strrpos($key, "\0") + 1);
209                 $exceptionArray[$key] = $value;
210             }
211
212             $exception = new PHPUnit_Framework_SyntheticError(
213                 sprintf(
214                     '%s: %s',
215                     $exceptionArray['_PHP_Incomplete_Class_Name'],
216                     $exceptionArray['message']
217                 ),
218                 $exceptionArray['code'],
219                 $exceptionArray['file'],
220                 $exceptionArray['line'],
221                 $exceptionArray['trace']
222             );
223         }
224
225         return $exception;
226     }
227 }