PageRenderTime 30ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

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

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