5 * Copyright (c) 2002-2011, Sebastian Bergmann <sebastian@phpunit.de>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * * Neither the name of Sebastian Bergmann nor the names of his
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * @author Sebastian Bergmann <sebastian@phpunit.de>
40 * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
42 * @link http://www.phpunit.de/
43 * @since File available since Release 3.0.0
51 * @author Sebastian Bergmann <sebastian@phpunit.de>
52 * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
53 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
54 * @version Release: 3.5.14
55 * @link http://www.phpunit.de/
56 * @since Class available since Release 3.0.0
58 class PHPUnit_Util_Test
60 const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';
61 const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m';
63 private static $annotationCache = array();
65 protected static $templateMethods = array(
66 'setUp', 'assertPreConditions', 'assertPostConditions', 'tearDown'
70 * @param PHPUnit_Framework_Test $test
71 * @param boolean $asString
74 public static function describe(PHPUnit_Framework_Test $test, $asString = TRUE)
77 if ($test instanceof PHPUnit_Framework_SelfDescribing) {
78 return $test->toString();
80 return get_class($test);
83 if ($test instanceof PHPUnit_Framework_TestCase) {
85 get_class($test), $test->getName()
89 else if ($test instanceof PHPUnit_Framework_SelfDescribing) {
90 return array('', $test->toString());
94 return array('', get_class($test));
100 * Returns the expected exception for a test.
102 * @param string $className
103 * @param string $methodName
105 * @since Method available since Release 3.3.6
107 public static function getExpectedException($className, $methodName)
109 $reflector = new ReflectionMethod($className, $methodName);
110 $docComment = $reflector->getDocComment();
112 if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) {
113 $annotations = self::parseTestMethodAnnotations(
114 $className, $methodName
117 $class = $matches[1];
121 if (isset($matches[2])) {
122 $message = trim($matches[2]);
125 else if (isset($annotations['method']['expectedExceptionMessage'])) {
126 $message = $annotations['method']['expectedExceptionMessage'][0];
129 if (isset($matches[3])) {
130 $code = (int)$matches[3];
133 else if (isset($annotations['method']['expectedExceptionCode'])) {
134 $code = (int)$annotations['method']['expectedExceptionCode'][0];
138 'class' => $class, 'code' => $code, 'message' => $message
146 * Returns the provided data for a method.
148 * @param string $className
149 * @param string $methodName
150 * @param string $docComment
151 * @return mixed array|Iterator when a data provider is specified and exists
152 * false when a data provider is specified and does not exist
153 * null when no data provider is specified
154 * @since Method available since Release 3.2.0
156 public static function getProvidedData($className, $methodName)
158 $reflector = new ReflectionMethod($className, $methodName);
159 $docComment = $reflector->getDocComment();
162 if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
163 $dataProviderMethodNameNamespace = explode('\\', $matches[1]);
164 $leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
165 $dataProviderMethodName = array_pop($leaf);
167 if (!empty($dataProviderMethodNameNamespace)) {
168 $dataProviderMethodNameNamespace = join('\\', $dataProviderMethodNameNamespace) . '\\';
170 $dataProviderMethodNameNamespace = '';
174 $dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
176 $dataProviderClassName = $className;
179 $dataProviderClass = new ReflectionClass($dataProviderClassName);
180 $dataProviderMethod = $dataProviderClass->getMethod(
181 $dataProviderMethodName
184 if ($dataProviderMethod->isStatic()) {
187 $object = $dataProviderClass->newInstance();
190 if ($dataProviderMethod->getNumberOfParameters() == 0) {
191 $data = $dataProviderMethod->invoke($object);
193 $data = $dataProviderMethod->invoke($object, $methodName);
197 if ($data !== NULL) {
198 foreach ($data as $key => $value) {
199 if (!is_array($value)) {
200 throw new InvalidArgumentException(
202 'Data set %s is invalid.',
203 is_int($key) ? '#' . $key : '"' . $key . '"'
214 * @param string $className
215 * @param string $methodName
217 * @throws ReflectionException
218 * @since Method available since Release 3.4.0
220 public static function parseTestMethodAnnotations($className, $methodName = '')
222 if (!isset(self::$annotationCache[$className])) {
223 $class = new ReflectionClass($className);
224 self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
227 if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) {
228 $method = new ReflectionMethod($className, $methodName);
229 self::$annotationCache[$className . '::' . $methodName] = self::parseAnnotations($method->getDocComment());
233 'class' => self::$annotationCache[$className],
234 'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array()
239 * @param string $docblock
241 * @since Method available since Release 3.4.0
243 private static function parseAnnotations($docblock)
245 $annotations = array();
247 if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docblock, $matches)) {
248 $numMatches = count($matches[0]);
250 for ($i = 0; $i < $numMatches; ++$i) {
251 $annotations[$matches['name'][$i]][] = $matches['value'][$i];
259 * Returns the backup settings for a test.
261 * @param string $className
262 * @param string $methodName
264 * @since Method available since Release 3.4.0
266 public static function getBackupSettings($className, $methodName)
269 'backupGlobals' => self::getBooleanAnnotationSetting(
270 $className, $methodName, 'backupGlobals'
272 'backupStaticAttributes' => self::getBooleanAnnotationSetting(
273 $className, $methodName, 'backupStaticAttributes'
279 * Returns the dependencies for a test class or method.
281 * @param string $className
282 * @param string $methodName
284 * @since Method available since Release 3.4.0
286 public static function getDependencies($className, $methodName)
288 $annotations = self::parseTestMethodAnnotations(
289 $className, $methodName
292 $dependencies = array();
294 if (isset($annotations['class']['depends'])) {
295 $dependencies = $annotations['class']['depends'];
298 if (isset($annotations['method']['depends'])) {
299 $dependencies = array_merge(
300 $dependencies, $annotations['method']['depends']
304 return array_unique($dependencies);
308 * Returns the error handler settings for a test.
310 * @param string $className
311 * @param string $methodName
313 * @since Method available since Release 3.4.0
315 public static function getErrorHandlerSettings($className, $methodName)
317 return self::getBooleanAnnotationSetting(
318 $className, $methodName, 'errorHandler'
323 * Returns the groups for a test class or method.
325 * @param string $className
326 * @param string $methodName
328 * @since Method available since Release 3.2.0
330 public static function getGroups($className, $methodName = '')
332 $annotations = self::parseTestMethodAnnotations(
333 $className, $methodName
338 if (isset($annotations['method']['author'])) {
339 $groups = $annotations['method']['author'];
342 else if (isset($annotations['class']['author'])) {
343 $groups = $annotations['class']['author'];
346 if (isset($annotations['class']['group'])) {
347 $groups = array_merge($groups, $annotations['class']['group']);
350 if (isset($annotations['method']['group'])) {
351 $groups = array_merge($groups, $annotations['method']['group']);
354 return array_unique($groups);
358 * Returns the tickets for a test class or method.
360 * @param string $className
361 * @param string $methodName
363 * @since Method available since Release 3.4.0
365 public static function getTickets($className, $methodName)
367 $annotations = self::parseTestMethodAnnotations(
368 $className, $methodName
373 if (isset($annotations['class']['ticket'])) {
374 $tickets = $annotations['class']['ticket'];
377 if (isset($annotations['method']['ticket'])) {
378 $tickets = array_merge($tickets, $annotations['method']['ticket']);
381 return array_unique($tickets);
385 * Returns the output buffering settings for a test.
387 * @param string $className
388 * @param string $methodName
390 * @since Method available since Release 3.4.0
392 public static function getOutputBufferingSettings($className, $methodName)
394 return self::getBooleanAnnotationSetting(
395 $className, $methodName, 'outputBuffering'
400 * Returns the process isolation settings for a test.
402 * @param string $className
403 * @param string $methodName
405 * @since Method available since Release 3.4.1
407 public static function getProcessIsolationSettings($className, $methodName)
409 $annotations = self::parseTestMethodAnnotations(
410 $className, $methodName
413 if (isset($annotations['class']['runTestsInSeparateProcesses']) ||
414 isset($annotations['method']['runInSeparateProcess'])) {
422 * Returns the preserve global state settings for a test.
424 * @param string $className
425 * @param string $methodName
427 * @since Method available since Release 3.4.0
429 public static function getPreserveGlobalStateSettings($className, $methodName)
431 return self::getBooleanAnnotationSetting(
432 $className, $methodName, 'preserveGlobalState'
437 * @param string $className
438 * @param string $methodName
439 * @param string $settingName
441 * @since Method available since Release 3.4.0
443 private static function getBooleanAnnotationSetting($className, $methodName, $settingName)
445 $annotations = self::parseTestMethodAnnotations(
446 $className, $methodName
451 if (isset($annotations['class'][$settingName])) {
452 if ($annotations['class'][$settingName][0] == 'enabled') {
456 else if ($annotations['class'][$settingName][0] == 'disabled') {
461 if (isset($annotations['method'][$settingName])) {
462 if ($annotations['method'][$settingName][0] == 'enabled') {
466 else if ($annotations['method'][$settingName][0] == 'disabled') {