Mercurial > hg > cmmr2012-drupal-site
comparison vendor/symfony/phpunit-bridge/DeprecationErrorHandler.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | a9cd425dd02b |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony package. | |
5 * | |
6 * (c) Fabien Potencier <fabien@symfony.com> | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Bridge\PhpUnit; | |
13 | |
14 /** | |
15 * Catch deprecation notices and print a summary report at the end of the test suite. | |
16 * | |
17 * @author Nicolas Grekas <p@tchwork.com> | |
18 */ | |
19 class DeprecationErrorHandler | |
20 { | |
21 const MODE_WEAK = 'weak'; | |
22 const MODE_WEAK_VENDORS = 'weak_vendors'; | |
23 const MODE_DISABLED = 'disabled'; | |
24 | |
25 private static $isRegistered = false; | |
26 | |
27 /** | |
28 * Registers and configures the deprecation handler. | |
29 * | |
30 * The following reporting modes are supported: | |
31 * - use "weak" to hide the deprecation report but keep a global count; | |
32 * - use "weak_vendors" to act as "weak" but only for vendors; | |
33 * - use "/some-regexp/" to stop the test suite whenever a deprecation | |
34 * message matches the given regular expression; | |
35 * - use a number to define the upper bound of allowed deprecations, | |
36 * making the test suite fail whenever more notices are trigerred. | |
37 * | |
38 * @param int|string|false $mode The reporting mode, defaults to not allowing any deprecations | |
39 */ | |
40 public static function register($mode = 0) | |
41 { | |
42 if (self::$isRegistered) { | |
43 return; | |
44 } | |
45 | |
46 $UtilPrefix = class_exists('PHPUnit_Util_ErrorHandler') ? 'PHPUnit_Util_' : 'PHPUnit\Util\\'; | |
47 | |
48 $getMode = function () use ($mode) { | |
49 static $memoizedMode = false; | |
50 | |
51 if (false !== $memoizedMode) { | |
52 return $memoizedMode; | |
53 } | |
54 if (false === $mode) { | |
55 $mode = getenv('SYMFONY_DEPRECATIONS_HELPER'); | |
56 } | |
57 if (DeprecationErrorHandler::MODE_WEAK !== $mode && DeprecationErrorHandler::MODE_WEAK_VENDORS !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) { | |
58 $mode = preg_match('/^[1-9][0-9]*$/', $mode) ? (int) $mode : 0; | |
59 } | |
60 | |
61 return $memoizedMode = $mode; | |
62 }; | |
63 | |
64 $inVendors = function ($path) { | |
65 /** @var string[] absolute paths to vendor directories */ | |
66 static $vendors; | |
67 if (null === $vendors) { | |
68 foreach (get_declared_classes() as $class) { | |
69 if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { | |
70 $r = new \ReflectionClass($class); | |
71 $v = dirname(dirname($r->getFileName())); | |
72 if (file_exists($v.'/composer/installed.json')) { | |
73 $vendors[] = $v; | |
74 } | |
75 } | |
76 } | |
77 } | |
78 $realPath = realpath($path); | |
79 if (false === $realPath && '-' !== $path && 'Standard input code' !== $path) { | |
80 return true; | |
81 } | |
82 foreach ($vendors as $vendor) { | |
83 if (0 === strpos($realPath, $vendor) && false !== strpbrk(substr($realPath, strlen($vendor), 1), '/'.DIRECTORY_SEPARATOR)) { | |
84 return true; | |
85 } | |
86 } | |
87 | |
88 return false; | |
89 }; | |
90 | |
91 $deprecations = array( | |
92 'unsilencedCount' => 0, | |
93 'remainingCount' => 0, | |
94 'legacyCount' => 0, | |
95 'otherCount' => 0, | |
96 'remaining vendorCount' => 0, | |
97 'unsilenced' => array(), | |
98 'remaining' => array(), | |
99 'legacy' => array(), | |
100 'other' => array(), | |
101 'remaining vendor' => array(), | |
102 ); | |
103 $deprecationHandler = function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, $getMode, $UtilPrefix, $inVendors) { | |
104 $mode = $getMode(); | |
105 if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || DeprecationErrorHandler::MODE_DISABLED === $mode) { | |
106 $ErrorHandler = $UtilPrefix.'ErrorHandler'; | |
107 | |
108 return $ErrorHandler::handleError($type, $msg, $file, $line, $context); | |
109 } | |
110 | |
111 $trace = debug_backtrace(true); | |
112 $group = 'other'; | |
113 $isVendor = DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $inVendors($file); | |
114 | |
115 $i = count($trace); | |
116 while (1 < $i && (!isset($trace[--$i]['class']) || ('ReflectionMethod' === $trace[$i]['class'] || 0 === strpos($trace[$i]['class'], 'PHPUnit_') || 0 === strpos($trace[$i]['class'], 'PHPUnit\\')))) { | |
117 // No-op | |
118 } | |
119 | |
120 if (isset($trace[$i]['object']) || isset($trace[$i]['class'])) { | |
121 if (isset($trace[$i]['class']) && 0 === strpos($trace[$i]['class'], 'Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor')) { | |
122 $parsedMsg = unserialize($msg); | |
123 $msg = $parsedMsg['deprecation']; | |
124 $class = $parsedMsg['class']; | |
125 $method = $parsedMsg['method']; | |
126 // If the deprecation has been triggered via | |
127 // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest() | |
128 // then we need to use the serialized information to determine | |
129 // if the error has been triggered from vendor code. | |
130 $isVendor = DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && isset($parsedMsg['triggering_file']) && $inVendors($parsedMsg['triggering_file']); | |
131 } else { | |
132 $class = isset($trace[$i]['object']) ? get_class($trace[$i]['object']) : $trace[$i]['class']; | |
133 $method = $trace[$i]['function']; | |
134 } | |
135 | |
136 $Test = $UtilPrefix.'Test'; | |
137 | |
138 if (0 !== error_reporting()) { | |
139 $group = 'unsilenced'; | |
140 } elseif (0 === strpos($method, 'testLegacy') | |
141 || 0 === strpos($method, 'provideLegacy') | |
142 || 0 === strpos($method, 'getLegacy') | |
143 || strpos($class, '\Legacy') | |
144 || in_array('legacy', $Test::getGroups($class, $method), true) | |
145 ) { | |
146 $group = 'legacy'; | |
147 } elseif ($isVendor) { | |
148 $group = 'remaining vendor'; | |
149 } else { | |
150 $group = 'remaining'; | |
151 } | |
152 | |
153 if (isset($mode[0]) && '/' === $mode[0] && preg_match($mode, $msg)) { | |
154 $e = new \Exception($msg); | |
155 $r = new \ReflectionProperty($e, 'trace'); | |
156 $r->setAccessible(true); | |
157 $r->setValue($e, array_slice($trace, 1, $i)); | |
158 | |
159 echo "\n".ucfirst($group).' deprecation triggered by '.$class.'::'.$method.':'; | |
160 echo "\n".$msg; | |
161 echo "\nStack trace:"; | |
162 echo "\n".str_replace(' '.getcwd().DIRECTORY_SEPARATOR, ' ', $e->getTraceAsString()); | |
163 echo "\n"; | |
164 | |
165 exit(1); | |
166 } | |
167 if ('legacy' !== $group && DeprecationErrorHandler::MODE_WEAK !== $mode) { | |
168 $ref = &$deprecations[$group][$msg]['count']; | |
169 ++$ref; | |
170 $ref = &$deprecations[$group][$msg][$class.'::'.$method]; | |
171 ++$ref; | |
172 } | |
173 } elseif (DeprecationErrorHandler::MODE_WEAK !== $mode) { | |
174 $ref = &$deprecations[$group][$msg]['count']; | |
175 ++$ref; | |
176 } | |
177 ++$deprecations[$group.'Count']; | |
178 }; | |
179 $oldErrorHandler = set_error_handler($deprecationHandler); | |
180 | |
181 if (null !== $oldErrorHandler) { | |
182 restore_error_handler(); | |
183 if (array($UtilPrefix.'ErrorHandler', 'handleError') === $oldErrorHandler) { | |
184 restore_error_handler(); | |
185 self::register($mode); | |
186 } | |
187 } else { | |
188 self::$isRegistered = true; | |
189 if (self::hasColorSupport()) { | |
190 $colorize = function ($str, $red) { | |
191 $color = $red ? '41;37' : '43;30'; | |
192 | |
193 return "\x1B[{$color}m{$str}\x1B[0m"; | |
194 }; | |
195 } else { | |
196 $colorize = function ($str) { return $str; }; | |
197 } | |
198 register_shutdown_function(function () use ($getMode, &$deprecations, $deprecationHandler, $colorize) { | |
199 $mode = $getMode(); | |
200 if (isset($mode[0]) && '/' === $mode[0]) { | |
201 return; | |
202 } | |
203 $currErrorHandler = set_error_handler('var_dump'); | |
204 restore_error_handler(); | |
205 | |
206 if (DeprecationErrorHandler::MODE_WEAK === $mode) { | |
207 $colorize = function ($str) { return $str; }; | |
208 } | |
209 if ($currErrorHandler !== $deprecationHandler) { | |
210 echo "\n", $colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n"; | |
211 } | |
212 | |
213 $cmp = function ($a, $b) { | |
214 return $b['count'] - $a['count']; | |
215 }; | |
216 | |
217 $groups = array('unsilenced', 'remaining'); | |
218 if (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode) { | |
219 $groups[] = 'remaining vendor'; | |
220 } | |
221 array_push($groups, 'legacy', 'other'); | |
222 | |
223 $displayDeprecations = function ($deprecations) use ($colorize, $cmp, $groups) { | |
224 foreach ($groups as $group) { | |
225 if ($deprecations[$group.'Count']) { | |
226 echo "\n", $colorize( | |
227 sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']), | |
228 'legacy' !== $group && 'remaining vendor' !== $group | |
229 ), "\n"; | |
230 | |
231 uasort($deprecations[$group], $cmp); | |
232 | |
233 foreach ($deprecations[$group] as $msg => $notices) { | |
234 echo "\n ", $notices['count'], 'x: ', $msg, "\n"; | |
235 | |
236 arsort($notices); | |
237 | |
238 foreach ($notices as $method => $count) { | |
239 if ('count' !== $method) { | |
240 echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n"; | |
241 } | |
242 } | |
243 } | |
244 } | |
245 } | |
246 if (!empty($notices)) { | |
247 echo "\n"; | |
248 } | |
249 }; | |
250 | |
251 $displayDeprecations($deprecations); | |
252 | |
253 // store failing status | |
254 $isFailing = DeprecationErrorHandler::MODE_WEAK !== $mode && $mode < $deprecations['unsilencedCount'] + $deprecations['remainingCount'] + $deprecations['otherCount']; | |
255 | |
256 // reset deprecations array | |
257 foreach ($deprecations as $group => $arrayOrInt) { | |
258 $deprecations[$group] = is_int($arrayOrInt) ? 0 : array(); | |
259 } | |
260 | |
261 register_shutdown_function(function () use (&$deprecations, $isFailing, $displayDeprecations, $mode) { | |
262 foreach ($deprecations as $group => $arrayOrInt) { | |
263 if (0 < (is_int($arrayOrInt) ? $arrayOrInt : count($arrayOrInt))) { | |
264 echo "Shutdown-time deprecations:\n"; | |
265 break; | |
266 } | |
267 } | |
268 $displayDeprecations($deprecations); | |
269 if ($isFailing || DeprecationErrorHandler::MODE_WEAK !== $mode && $mode < $deprecations['unsilencedCount'] + $deprecations['remainingCount'] + $deprecations['otherCount']) { | |
270 exit(1); | |
271 } | |
272 }); | |
273 }); | |
274 } | |
275 } | |
276 | |
277 public static function collectDeprecations($outputFile) | |
278 { | |
279 $deprecations = array(); | |
280 $previousErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, &$previousErrorHandler) { | |
281 if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) { | |
282 if ($previousErrorHandler) { | |
283 return $previousErrorHandler($type, $msg, $file, $line, $context); | |
284 } | |
285 static $autoload = true; | |
286 | |
287 $ErrorHandler = class_exists('PHPUnit_Util_ErrorHandler', $autoload) ? 'PHPUnit_Util_ErrorHandler' : 'PHPUnit\Util\ErrorHandler'; | |
288 $autoload = false; | |
289 | |
290 return $ErrorHandler::handleError($type, $msg, $file, $line, $context); | |
291 } | |
292 $deprecations[] = array(error_reporting(), $msg, $file); | |
293 }); | |
294 | |
295 register_shutdown_function(function () use ($outputFile, &$deprecations) { | |
296 file_put_contents($outputFile, serialize($deprecations)); | |
297 }); | |
298 } | |
299 | |
300 /** | |
301 * Returns true if STDOUT is defined and supports colorization. | |
302 * | |
303 * Reference: Composer\XdebugHandler\Process::supportsColor | |
304 * https://github.com/composer/xdebug-handler | |
305 * | |
306 * @return bool | |
307 */ | |
308 private static function hasColorSupport() | |
309 { | |
310 if (!defined('STDOUT')) { | |
311 return false; | |
312 } | |
313 | |
314 if (DIRECTORY_SEPARATOR === '\\') { | |
315 return (function_exists('sapi_windows_vt100_support') | |
316 && sapi_windows_vt100_support(STDOUT)) | |
317 || false !== getenv('ANSICON') | |
318 || 'ON' === getenv('ConEmuANSI') | |
319 || 'xterm' === getenv('TERM'); | |
320 } | |
321 | |
322 if (function_exists('stream_isatty')) { | |
323 return stream_isatty(STDOUT); | |
324 } | |
325 | |
326 if (function_exists('posix_isatty')) { | |
327 return posix_isatty(STDOUT); | |
328 } | |
329 | |
330 $stat = fstat(STDOUT); | |
331 // Check if formatted mode is S_IFCHR | |
332 return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; | |
333 } | |
334 } |