PageRenderTime 75ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/php-phpunit-PHPUnit-3.6.11/PHPUnit-3.6.11/PHPUnit/Util/Test.php

#
PHP | 566 lines | 317 code | 70 blank | 179 comment | 60 complexity | 2969e8f6d584a60898f69f206be305c4 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * PHPUnit
  4. *
  5. * Copyright (c) 2001-2012, Sebastian Bergmann <sebastian@phpunit.de>.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  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
  18. * distribution.
  19. *
  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.
  23. *
  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.
  36. *
  37. * @package PHPUnit
  38. * @subpackage Util
  39. * @author Sebastian Bergmann <sebastian@phpunit.de>
  40. * @copyright 2001-2012 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
  44. */
  45. /**
  46. * Test helpers.
  47. *
  48. * @package PHPUnit
  49. * @subpackage Util
  50. * @author Sebastian Bergmann <sebastian@phpunit.de>
  51. * @copyright 2001-2012 Sebastian Bergmann <sebastian@phpunit.de>
  52. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  53. * @version Release: 3.6.11
  54. * @link http://www.phpunit.de/
  55. * @since Class available since Release 3.0.0
  56. */
  57. class PHPUnit_Util_Test
  58. {
  59. const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';
  60. const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m';
  61. const REGEX_REQUIRES = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<value>[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m';
  62. const SMALL = 0;
  63. const MEDIUM = 1;
  64. const LARGE = 2;
  65. private static $annotationCache = array();
  66. protected static $templateMethods = array(
  67. 'setUp', 'assertPreConditions', 'assertPostConditions', 'tearDown'
  68. );
  69. /**
  70. * @param PHPUnit_Framework_Test $test
  71. * @param boolean $asString
  72. * @return mixed
  73. */
  74. public static function describe(PHPUnit_Framework_Test $test, $asString = TRUE)
  75. {
  76. if ($asString) {
  77. if ($test instanceof PHPUnit_Framework_SelfDescribing) {
  78. return $test->toString();
  79. } else {
  80. return get_class($test);
  81. }
  82. } else {
  83. if ($test instanceof PHPUnit_Framework_TestCase) {
  84. return array(
  85. get_class($test), $test->getName()
  86. );
  87. }
  88. else if ($test instanceof PHPUnit_Framework_SelfDescribing) {
  89. return array('', $test->toString());
  90. }
  91. else {
  92. return array('', get_class($test));
  93. }
  94. }
  95. }
  96. /**
  97. * Returns the requirements for a test.
  98. *
  99. * @param string $className
  100. * @param string $methodName
  101. * @return array
  102. * @since Method available since Release 3.6.0
  103. */
  104. public static function getRequirements($className, $methodName)
  105. {
  106. $reflector = new ReflectionMethod($className, $methodName);
  107. $docComment = $reflector->getDocComment();
  108. $requires = array();
  109. if ($count = preg_match_all(self::REGEX_REQUIRES, $docComment, $matches)) {
  110. for ($i = 0; $i < $count; $i++) {
  111. $requires[$matches['name'][$i]] = $matches['value'][$i];
  112. }
  113. }
  114. return $requires;
  115. }
  116. /**
  117. * Returns the expected exception for a test.
  118. *
  119. * @param string $className
  120. * @param string $methodName
  121. * @return array
  122. * @since Method available since Release 3.3.6
  123. */
  124. public static function getExpectedException($className, $methodName)
  125. {
  126. $reflector = new ReflectionMethod($className, $methodName);
  127. $docComment = $reflector->getDocComment();
  128. if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) {
  129. $annotations = self::parseTestMethodAnnotations(
  130. $className, $methodName
  131. );
  132. $class = $matches[1];
  133. $code = NULL;
  134. $message = '';
  135. if (isset($matches[2])) {
  136. $message = trim($matches[2]);
  137. }
  138. else if (isset($annotations['method']['expectedExceptionMessage'])) {
  139. $message = $annotations['method']['expectedExceptionMessage'][0];
  140. }
  141. if (isset($matches[3])) {
  142. $code = $matches[3];
  143. }
  144. else if (isset($annotations['method']['expectedExceptionCode'])) {
  145. $code = $annotations['method']['expectedExceptionCode'][0];
  146. }
  147. if (is_numeric($code)) {
  148. $code = (int)$code;
  149. }
  150. else if (is_string($code) && defined($code)) {
  151. $code = (int)constant($code);
  152. }
  153. return array(
  154. 'class' => $class, 'code' => $code, 'message' => $message
  155. );
  156. }
  157. return FALSE;
  158. }
  159. /**
  160. * Returns the provided data for a method.
  161. *
  162. * @param string $className
  163. * @param string $methodName
  164. * @param string $docComment
  165. * @return mixed array|Iterator when a data provider is specified and exists
  166. * false when a data provider is specified and does not exist
  167. * null when no data provider is specified
  168. * @since Method available since Release 3.2.0
  169. */
  170. public static function getProvidedData($className, $methodName)
  171. {
  172. $reflector = new ReflectionMethod($className, $methodName);
  173. $docComment = $reflector->getDocComment();
  174. $data = NULL;
  175. if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
  176. $dataProviderMethodNameNamespace = explode('\\', $matches[1]);
  177. $leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
  178. $dataProviderMethodName = array_pop($leaf);
  179. if (!empty($dataProviderMethodNameNamespace)) {
  180. $dataProviderMethodNameNamespace = join('\\', $dataProviderMethodNameNamespace) . '\\';
  181. } else {
  182. $dataProviderMethodNameNamespace = '';
  183. }
  184. if (!empty($leaf)) {
  185. $dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
  186. } else {
  187. $dataProviderClassName = $className;
  188. }
  189. $dataProviderClass = new ReflectionClass($dataProviderClassName);
  190. $dataProviderMethod = $dataProviderClass->getMethod(
  191. $dataProviderMethodName
  192. );
  193. if ($dataProviderMethod->isStatic()) {
  194. $object = NULL;
  195. } else {
  196. $object = $dataProviderClass->newInstance();
  197. }
  198. if ($dataProviderMethod->getNumberOfParameters() == 0) {
  199. $data = $dataProviderMethod->invoke($object);
  200. } else {
  201. $data = $dataProviderMethod->invoke($object, $methodName);
  202. }
  203. }
  204. if ($data !== NULL) {
  205. foreach ($data as $key => $value) {
  206. if (!is_array($value)) {
  207. throw new InvalidArgumentException(
  208. sprintf(
  209. 'Data set %s is invalid.',
  210. is_int($key) ? '#' . $key : '"' . $key . '"'
  211. )
  212. );
  213. }
  214. }
  215. }
  216. return $data;
  217. }
  218. /**
  219. * @param string $className
  220. * @param string $methodName
  221. * @return array
  222. * @throws ReflectionException
  223. * @since Method available since Release 3.4.0
  224. */
  225. public static function parseTestMethodAnnotations($className, $methodName = '')
  226. {
  227. if (!isset(self::$annotationCache[$className])) {
  228. $class = new ReflectionClass($className);
  229. self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
  230. }
  231. if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) {
  232. try {
  233. $method = new ReflectionMethod($className, $methodName);
  234. $annotations = self::parseAnnotations($method->getDocComment());
  235. } catch (ReflectionException $e) {
  236. $annotations = array();
  237. }
  238. self::$annotationCache[$className . '::' . $methodName] = $annotations;
  239. }
  240. return array(
  241. 'class' => self::$annotationCache[$className],
  242. 'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array()
  243. );
  244. }
  245. /**
  246. * @param string $docblock
  247. * @return array
  248. * @since Method available since Release 3.4.0
  249. */
  250. private static function parseAnnotations($docblock)
  251. {
  252. $annotations = array();
  253. // Strip away the docblock header and footer to ease parsing of one line annotations
  254. $docblock = substr($docblock, 3, -2);
  255. if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docblock, $matches)) {
  256. $numMatches = count($matches[0]);
  257. for ($i = 0; $i < $numMatches; ++$i) {
  258. $annotations[$matches['name'][$i]][] = $matches['value'][$i];
  259. }
  260. }
  261. return $annotations;
  262. }
  263. /**
  264. * Returns the backup settings for a test.
  265. *
  266. * @param string $className
  267. * @param string $methodName
  268. * @return array
  269. * @since Method available since Release 3.4.0
  270. */
  271. public static function getBackupSettings($className, $methodName)
  272. {
  273. return array(
  274. 'backupGlobals' => self::getBooleanAnnotationSetting(
  275. $className, $methodName, 'backupGlobals'
  276. ),
  277. 'backupStaticAttributes' => self::getBooleanAnnotationSetting(
  278. $className, $methodName, 'backupStaticAttributes'
  279. )
  280. );
  281. }
  282. /**
  283. * Returns the dependencies for a test class or method.
  284. *
  285. * @param string $className
  286. * @param string $methodName
  287. * @return array
  288. * @since Method available since Release 3.4.0
  289. */
  290. public static function getDependencies($className, $methodName)
  291. {
  292. $annotations = self::parseTestMethodAnnotations(
  293. $className, $methodName
  294. );
  295. $dependencies = array();
  296. if (isset($annotations['class']['depends'])) {
  297. $dependencies = $annotations['class']['depends'];
  298. }
  299. if (isset($annotations['method']['depends'])) {
  300. $dependencies = array_merge(
  301. $dependencies, $annotations['method']['depends']
  302. );
  303. }
  304. return array_unique($dependencies);
  305. }
  306. /**
  307. * Returns the error handler settings for a test.
  308. *
  309. * @param string $className
  310. * @param string $methodName
  311. * @return boolean
  312. * @since Method available since Release 3.4.0
  313. */
  314. public static function getErrorHandlerSettings($className, $methodName)
  315. {
  316. return self::getBooleanAnnotationSetting(
  317. $className, $methodName, 'errorHandler'
  318. );
  319. }
  320. /**
  321. * Returns the groups for a test class or method.
  322. *
  323. * @param string $className
  324. * @param string $methodName
  325. * @return array
  326. * @since Method available since Release 3.2.0
  327. */
  328. public static function getGroups($className, $methodName = '')
  329. {
  330. $annotations = self::parseTestMethodAnnotations(
  331. $className, $methodName
  332. );
  333. $groups = array();
  334. if (isset($annotations['method']['author'])) {
  335. $groups = $annotations['method']['author'];
  336. }
  337. else if (isset($annotations['class']['author'])) {
  338. $groups = $annotations['class']['author'];
  339. }
  340. if (isset($annotations['class']['group'])) {
  341. $groups = array_merge($groups, $annotations['class']['group']);
  342. }
  343. if (isset($annotations['method']['group'])) {
  344. $groups = array_merge($groups, $annotations['method']['group']);
  345. }
  346. if (isset($annotations['class']['ticket'])) {
  347. $groups = array_merge($groups, $annotations['class']['ticket']);
  348. }
  349. if (isset($annotations['method']['ticket'])) {
  350. $groups = array_merge($groups, $annotations['method']['ticket']);
  351. }
  352. foreach (array('small', 'medium', 'large') as $size) {
  353. if (isset($annotations['method'][$size])) {
  354. $groups[] = $size;
  355. }
  356. else if (isset($annotations['class'][$size])) {
  357. $groups[] = $size;
  358. }
  359. }
  360. return array_unique($groups);
  361. }
  362. /**
  363. * Returns the size of the test.
  364. *
  365. * @param string $className
  366. * @param string $methodName
  367. * @return integer
  368. * @since Method available since Release 3.6.0
  369. */
  370. public static function getSize($className, $methodName)
  371. {
  372. $groups = array_flip(self::getGroups($className, $methodName));
  373. $size = self::SMALL;
  374. $class = new ReflectionClass($className);
  375. if ((class_exists('PHPUnit_Extensions_Database_TestCase', FALSE) &&
  376. $class->isSubclassOf('PHPUnit_Extensions_Database_TestCase')) ||
  377. (class_exists('PHPUnit_Extensions_SeleniumTestCase', FALSE) &&
  378. $class->isSubclassOf('PHPUnit_Extensions_SeleniumTestCase'))) {
  379. $size = self::LARGE;
  380. }
  381. else if (isset($groups['medium'])) {
  382. $size = self::MEDIUM;
  383. }
  384. else if (isset($groups['large'])) {
  385. $size = self::LARGE;
  386. }
  387. return $size;
  388. }
  389. /**
  390. * Returns the tickets for a test class or method.
  391. *
  392. * @param string $className
  393. * @param string $methodName
  394. * @return array
  395. * @since Method available since Release 3.4.0
  396. */
  397. public static function getTickets($className, $methodName)
  398. {
  399. $annotations = self::parseTestMethodAnnotations(
  400. $className, $methodName
  401. );
  402. $tickets = array();
  403. if (isset($annotations['class']['ticket'])) {
  404. $tickets = $annotations['class']['ticket'];
  405. }
  406. if (isset($annotations['method']['ticket'])) {
  407. $tickets = array_merge($tickets, $annotations['method']['ticket']);
  408. }
  409. return array_unique($tickets);
  410. }
  411. /**
  412. * Returns the output buffering settings for a test.
  413. *
  414. * @param string $className
  415. * @param string $methodName
  416. * @return boolean
  417. * @since Method available since Release 3.4.0
  418. */
  419. public static function getOutputBufferingSettings($className, $methodName)
  420. {
  421. return self::getBooleanAnnotationSetting(
  422. $className, $methodName, 'outputBuffering'
  423. );
  424. }
  425. /**
  426. * Returns the process isolation settings for a test.
  427. *
  428. * @param string $className
  429. * @param string $methodName
  430. * @return boolean
  431. * @since Method available since Release 3.4.1
  432. */
  433. public static function getProcessIsolationSettings($className, $methodName)
  434. {
  435. $annotations = self::parseTestMethodAnnotations(
  436. $className, $methodName
  437. );
  438. if (isset($annotations['class']['runTestsInSeparateProcesses']) ||
  439. isset($annotations['method']['runInSeparateProcess'])) {
  440. return TRUE;
  441. } else {
  442. return FALSE;
  443. }
  444. }
  445. /**
  446. * Returns the preserve global state settings for a test.
  447. *
  448. * @param string $className
  449. * @param string $methodName
  450. * @return boolean
  451. * @since Method available since Release 3.4.0
  452. */
  453. public static function getPreserveGlobalStateSettings($className, $methodName)
  454. {
  455. return self::getBooleanAnnotationSetting(
  456. $className, $methodName, 'preserveGlobalState'
  457. );
  458. }
  459. /**
  460. * @param string $className
  461. * @param string $methodName
  462. * @param string $settingName
  463. * @return boolean
  464. * @since Method available since Release 3.4.0
  465. */
  466. private static function getBooleanAnnotationSetting($className, $methodName, $settingName)
  467. {
  468. $annotations = self::parseTestMethodAnnotations(
  469. $className, $methodName
  470. );
  471. $result = NULL;
  472. if (isset($annotations['class'][$settingName])) {
  473. if ($annotations['class'][$settingName][0] == 'enabled') {
  474. $result = TRUE;
  475. }
  476. else if ($annotations['class'][$settingName][0] == 'disabled') {
  477. $result = FALSE;
  478. }
  479. }
  480. if (isset($annotations['method'][$settingName])) {
  481. if ($annotations['method'][$settingName][0] == 'enabled') {
  482. $result = TRUE;
  483. }
  484. else if ($annotations['method'][$settingName][0] == 'disabled') {
  485. $result = FALSE;
  486. }
  487. }
  488. return $result;
  489. }
  490. }