PageRenderTime 27ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/phpunit/phpunit/PHPUnit/Util/Test.php

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