PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/phpunit/phpunit/src/Util/Test.php

https://gitlab.com/geeta7/drupal
PHP | 1023 lines | 829 code | 74 blank | 120 comment | 76 complexity | 256fc0f6938c29ed1fc9ad57a40a4270 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of PHPUnit.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. if (!function_exists('trait_exists')) {
  11. function trait_exists($traitname, $autoload = true)
  12. {
  13. return false;
  14. }
  15. }
  16. /**
  17. * Test helpers.
  18. *
  19. * @since Class available since Release 3.0.0
  20. */
  21. class PHPUnit_Util_Test
  22. {
  23. const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';
  24. const REGEX_TEST_WITH = '/@testWith\s+/';
  25. const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m';
  26. const REGEX_REQUIRES_VERSION = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<value>[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m';
  27. const REGEX_REQUIRES_OS = '/@requires\s+OS\s+(?P<value>.+?)[ \t]*\r?$/m';
  28. const REGEX_REQUIRES = '/@requires\s+(?P<name>function|extension)\s+(?P<value>([^ ]+?))[ \t]*\r?$/m';
  29. const UNKNOWN = -1;
  30. const SMALL = 0;
  31. const MEDIUM = 1;
  32. const LARGE = 2;
  33. private static $annotationCache = array();
  34. private static $hookMethods = array();
  35. /**
  36. * @param PHPUnit_Framework_Test $test
  37. * @param bool $asString
  38. * @return mixed
  39. */
  40. public static function describe(PHPUnit_Framework_Test $test, $asString = true)
  41. {
  42. if ($asString) {
  43. if ($test instanceof PHPUnit_Framework_SelfDescribing) {
  44. return $test->toString();
  45. } else {
  46. return get_class($test);
  47. }
  48. } else {
  49. if ($test instanceof PHPUnit_Framework_TestCase) {
  50. return array(
  51. get_class($test), $test->getName()
  52. );
  53. } elseif ($test instanceof PHPUnit_Framework_SelfDescribing) {
  54. return array('', $test->toString());
  55. } else {
  56. return array('', get_class($test));
  57. }
  58. }
  59. }
  60. /**
  61. * @param string $className
  62. * @param string $methodName
  63. * @return array|bool
  64. * @throws PHPUnit_Framework_CodeCoverageException
  65. * @since Method available since Release 4.0.0
  66. */
  67. public static function getLinesToBeCovered($className, $methodName)
  68. {
  69. $annotations = self::parseTestMethodAnnotations(
  70. $className,
  71. $methodName
  72. );
  73. if (isset($annotations['class']['coversNothing']) || isset($annotations['method']['coversNothing'])) {
  74. return false;
  75. }
  76. return self::getLinesToBeCoveredOrUsed($className, $methodName, 'covers');
  77. }
  78. /**
  79. * Returns lines of code specified with the @uses annotation.
  80. *
  81. * @param string $className
  82. * @param string $methodName
  83. * @return array
  84. * @since Method available since Release 4.0.0
  85. */
  86. public static function getLinesToBeUsed($className, $methodName)
  87. {
  88. return self::getLinesToBeCoveredOrUsed($className, $methodName, 'uses');
  89. }
  90. /**
  91. * @param string $className
  92. * @param string $methodName
  93. * @param string $mode
  94. * @return array
  95. * @throws PHPUnit_Framework_CodeCoverageException
  96. * @since Method available since Release 4.2.0
  97. */
  98. private static function getLinesToBeCoveredOrUsed($className, $methodName, $mode)
  99. {
  100. $annotations = self::parseTestMethodAnnotations(
  101. $className,
  102. $methodName
  103. );
  104. $classShortcut = null;
  105. if (!empty($annotations['class'][$mode . 'DefaultClass'])) {
  106. if (count($annotations['class'][$mode . 'DefaultClass']) > 1) {
  107. throw new PHPUnit_Framework_CodeCoverageException(
  108. sprintf(
  109. 'More than one @%sClass annotation in class or interface "%s".',
  110. $mode,
  111. $className
  112. )
  113. );
  114. }
  115. $classShortcut = $annotations['class'][$mode . 'DefaultClass'][0];
  116. }
  117. $list = array();
  118. if (isset($annotations['class'][$mode])) {
  119. $list = $annotations['class'][$mode];
  120. }
  121. if (isset($annotations['method'][$mode])) {
  122. $list = array_merge($list, $annotations['method'][$mode]);
  123. }
  124. $codeList = array();
  125. foreach (array_unique($list) as $element) {
  126. if ($classShortcut && strncmp($element, '::', 2) === 0) {
  127. $element = $classShortcut . $element;
  128. }
  129. $element = preg_replace('/[\s()]+$/', '', $element);
  130. $element = explode(' ', $element);
  131. $element = $element[0];
  132. $codeList = array_merge(
  133. $codeList,
  134. self::resolveElementToReflectionObjects($element)
  135. );
  136. }
  137. return self::resolveReflectionObjectsToLines($codeList);
  138. }
  139. /**
  140. * Returns the requirements for a test.
  141. *
  142. * @param string $className
  143. * @param string $methodName
  144. * @return array
  145. * @since Method available since Release 3.6.0
  146. */
  147. public static function getRequirements($className, $methodName)
  148. {
  149. $reflector = new ReflectionClass($className);
  150. $docComment = $reflector->getDocComment();
  151. $reflector = new ReflectionMethod($className, $methodName);
  152. $docComment .= "\n" . $reflector->getDocComment();
  153. $requires = array();
  154. if ($count = preg_match_all(self::REGEX_REQUIRES_OS, $docComment, $matches)) {
  155. $requires['OS'] = sprintf(
  156. '/%s/i',
  157. addcslashes($matches['value'][$count - 1], '/')
  158. );
  159. }
  160. if ($count = preg_match_all(self::REGEX_REQUIRES_VERSION, $docComment, $matches)) {
  161. for ($i = 0; $i < $count; $i++) {
  162. $requires[$matches['name'][$i]] = $matches['value'][$i];
  163. }
  164. }
  165. // https://bugs.php.net/bug.php?id=63055
  166. $matches = array();
  167. if ($count = preg_match_all(self::REGEX_REQUIRES, $docComment, $matches)) {
  168. for ($i = 0; $i < $count; $i++) {
  169. $name = $matches['name'][$i] . 's';
  170. if (!isset($requires[$name])) {
  171. $requires[$name] = array();
  172. }
  173. $requires[$name][] = $matches['value'][$i];
  174. }
  175. }
  176. return $requires;
  177. }
  178. /**
  179. * Returns the missing requirements for a test.
  180. *
  181. * @param string $className
  182. * @param string $methodName
  183. * @return array
  184. * @since Method available since Release 4.3.0
  185. */
  186. public static function getMissingRequirements($className, $methodName)
  187. {
  188. $required = static::getRequirements($className, $methodName);
  189. $missing = array();
  190. if (!empty($required['PHP']) && version_compare(PHP_VERSION, $required['PHP'], '<')) {
  191. $missing[] = sprintf('PHP %s (or later) is required.', $required['PHP']);
  192. }
  193. if (!empty($required['PHPUnit'])) {
  194. $phpunitVersion = PHPUnit_Runner_Version::id();
  195. if (version_compare($phpunitVersion, $required['PHPUnit'], '<')) {
  196. $missing[] = sprintf('PHPUnit %s (or later) is required.', $required['PHPUnit']);
  197. }
  198. }
  199. if (!empty($required['OS']) && !preg_match($required['OS'], PHP_OS)) {
  200. $missing[] = sprintf('Operating system matching %s is required.', $required['OS']);
  201. }
  202. if (!empty($required['functions'])) {
  203. foreach ($required['functions'] as $function) {
  204. $pieces = explode('::', $function);
  205. if (2 === count($pieces) && method_exists($pieces[0], $pieces[1])) {
  206. continue;
  207. }
  208. if (function_exists($function)) {
  209. continue;
  210. }
  211. $missing[] = sprintf('Function %s is required.', $function);
  212. }
  213. }
  214. if (!empty($required['extensions'])) {
  215. foreach ($required['extensions'] as $extension) {
  216. if (!extension_loaded($extension)) {
  217. $missing[] = sprintf('Extension %s is required.', $extension);
  218. }
  219. }
  220. }
  221. return $missing;
  222. }
  223. /**
  224. * Returns the expected exception for a test.
  225. *
  226. * @param string $className
  227. * @param string $methodName
  228. * @return array
  229. * @since Method available since Release 3.3.6
  230. */
  231. public static function getExpectedException($className, $methodName)
  232. {
  233. $reflector = new ReflectionMethod($className, $methodName);
  234. $docComment = $reflector->getDocComment();
  235. $docComment = substr($docComment, 3, -2);
  236. if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) {
  237. $annotations = self::parseTestMethodAnnotations(
  238. $className,
  239. $methodName
  240. );
  241. $class = $matches[1];
  242. $code = null;
  243. $message = '';
  244. $messageRegExp = '';
  245. if (isset($matches[2])) {
  246. $message = trim($matches[2]);
  247. } elseif (isset($annotations['method']['expectedExceptionMessage'])) {
  248. $message = self::parseAnnotationContent(
  249. $annotations['method']['expectedExceptionMessage'][0]
  250. );
  251. }
  252. if (isset($annotations['method']['expectedExceptionMessageRegExp'])) {
  253. $messageRegExp = self::parseAnnotationContent(
  254. $annotations['method']['expectedExceptionMessageRegExp'][0]
  255. );
  256. }
  257. if (isset($matches[3])) {
  258. $code = $matches[3];
  259. } elseif (isset($annotations['method']['expectedExceptionCode'])) {
  260. $code = self::parseAnnotationContent(
  261. $annotations['method']['expectedExceptionCode'][0]
  262. );
  263. }
  264. if (is_numeric($code)) {
  265. $code = (int) $code;
  266. } elseif (is_string($code) && defined($code)) {
  267. $code = (int) constant($code);
  268. }
  269. return array(
  270. 'class' => $class, 'code' => $code, 'message' => $message, 'message_regex' => $messageRegExp
  271. );
  272. }
  273. return false;
  274. }
  275. /**
  276. * Parse annotation content to use constant/class constant values
  277. *
  278. * Constants are specified using a starting '@'. For example: @ClassName::CONST_NAME
  279. *
  280. * If the constant is not found the string is used as is to ensure maximum BC.
  281. *
  282. * @param string $message
  283. * @return string
  284. */
  285. private static function parseAnnotationContent($message)
  286. {
  287. if (strpos($message, '::') !== false && count(explode('::', $message) == 2)) {
  288. if (defined($message)) {
  289. $message = constant($message);
  290. }
  291. }
  292. return $message;
  293. }
  294. /**
  295. * Returns the provided data for a method.
  296. *
  297. * @param string $className
  298. * @param string $methodName
  299. * @return array|Iterator when a data provider is specified and exists
  300. * null when no data provider is specified
  301. * @throws PHPUnit_Framework_Exception
  302. * @since Method available since Release 3.2.0
  303. */
  304. public static function getProvidedData($className, $methodName)
  305. {
  306. $reflector = new ReflectionMethod($className, $methodName);
  307. $docComment = $reflector->getDocComment();
  308. $data = null;
  309. if ($dataProviderData = self::getDataFromDataProviderAnnotation($docComment, $className, $methodName)) {
  310. $data = $dataProviderData;
  311. }
  312. if ($testWithData = self::getDataFromTestWithAnnotation($docComment)) {
  313. $data = $testWithData;
  314. }
  315. if ($data !== null) {
  316. if (is_object($data)) {
  317. $data = iterator_to_array($data);
  318. }
  319. foreach ($data as $key => $value) {
  320. if (!is_array($value)) {
  321. throw new PHPUnit_Framework_Exception(
  322. sprintf(
  323. 'Data set %s is invalid.',
  324. is_int($key) ? '#' . $key : '"' . $key . '"'
  325. )
  326. );
  327. }
  328. }
  329. }
  330. return $data;
  331. }
  332. /**
  333. * Returns the provided data for a method.
  334. *
  335. * @param string $docComment
  336. * @param string $className
  337. * @param string $methodName
  338. * @return array|Iterator when a data provider is specified and exists
  339. * null when no data provider is specified
  340. * @throws PHPUnit_Framework_Exception
  341. */
  342. private static function getDataFromDataProviderAnnotation($docComment, $className, $methodName)
  343. {
  344. if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
  345. $dataProviderMethodNameNamespace = explode('\\', $matches[1]);
  346. $leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
  347. $dataProviderMethodName = array_pop($leaf);
  348. if (!empty($dataProviderMethodNameNamespace)) {
  349. $dataProviderMethodNameNamespace = implode('\\', $dataProviderMethodNameNamespace) . '\\';
  350. } else {
  351. $dataProviderMethodNameNamespace = '';
  352. }
  353. if (!empty($leaf)) {
  354. $dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
  355. } else {
  356. $dataProviderClassName = $className;
  357. }
  358. $dataProviderClass = new ReflectionClass($dataProviderClassName);
  359. $dataProviderMethod = $dataProviderClass->getMethod(
  360. $dataProviderMethodName
  361. );
  362. if ($dataProviderMethod->isStatic()) {
  363. $object = null;
  364. } else {
  365. $object = $dataProviderClass->newInstance();
  366. }
  367. if ($dataProviderMethod->getNumberOfParameters() == 0) {
  368. $data = $dataProviderMethod->invoke($object);
  369. } else {
  370. $data = $dataProviderMethod->invoke($object, $methodName);
  371. }
  372. return $data;
  373. }
  374. }
  375. /**
  376. * @param string $docComment full docComment string
  377. * @return array when @testWith annotation is defined
  378. * null when @testWith annotation is omitted
  379. * @throws PHPUnit_Framework_Exception when @testWith annotation is defined but cannot be parsed
  380. */
  381. public static function getDataFromTestWithAnnotation($docComment)
  382. {
  383. $docComment = self::cleanUpMultiLineAnnotation($docComment);
  384. if (preg_match(self::REGEX_TEST_WITH, $docComment, $matches, PREG_OFFSET_CAPTURE)) {
  385. $offset = strlen($matches[0][0]) + $matches[0][1];
  386. $annotationContent = substr($docComment, $offset);
  387. $data = array();
  388. foreach (explode("\n", $annotationContent) as $candidateRow) {
  389. $candidateRow = trim($candidateRow);
  390. $dataSet = json_decode($candidateRow, true);
  391. if (json_last_error() != JSON_ERROR_NONE) {
  392. break;
  393. }
  394. $data[] = $dataSet;
  395. }
  396. if (!$data) {
  397. throw new PHPUnit_Framework_Exception('The dataset for the @testWith annotation cannot be parsed.');
  398. }
  399. return $data;
  400. }
  401. }
  402. private static function cleanUpMultiLineAnnotation($docComment)
  403. {
  404. //removing initial ' * ' for docComment
  405. $docComment = preg_replace('/' . '\n' . '\s*' . '\*' . '\s?' . '/', "\n", $docComment);
  406. $docComment = substr($docComment, 0, -1);
  407. $docComment = rtrim($docComment, "\n");
  408. return $docComment;
  409. }
  410. /**
  411. * @param string $className
  412. * @param string $methodName
  413. * @return array
  414. * @throws ReflectionException
  415. * @since Method available since Release 3.4.0
  416. */
  417. public static function parseTestMethodAnnotations($className, $methodName = '')
  418. {
  419. if (!isset(self::$annotationCache[$className])) {
  420. $class = new ReflectionClass($className);
  421. self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
  422. }
  423. if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) {
  424. try {
  425. $method = new ReflectionMethod($className, $methodName);
  426. $annotations = self::parseAnnotations($method->getDocComment());
  427. } catch (ReflectionException $e) {
  428. $annotations = array();
  429. }
  430. self::$annotationCache[$className . '::' . $methodName] = $annotations;
  431. }
  432. return array(
  433. 'class' => self::$annotationCache[$className],
  434. 'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array()
  435. );
  436. }
  437. /**
  438. * @param string $docblock
  439. * @return array
  440. * @since Method available since Release 3.4.0
  441. */
  442. private static function parseAnnotations($docblock)
  443. {
  444. $annotations = array();
  445. // Strip away the docblock header and footer to ease parsing of one line annotations
  446. $docblock = substr($docblock, 3, -2);
  447. if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docblock, $matches)) {
  448. $numMatches = count($matches[0]);
  449. for ($i = 0; $i < $numMatches; ++$i) {
  450. $annotations[$matches['name'][$i]][] = $matches['value'][$i];
  451. }
  452. }
  453. return $annotations;
  454. }
  455. /**
  456. * Returns the backup settings for a test.
  457. *
  458. * @param string $className
  459. * @param string $methodName
  460. * @return array
  461. * @since Method available since Release 3.4.0
  462. */
  463. public static function getBackupSettings($className, $methodName)
  464. {
  465. return array(
  466. 'backupGlobals' => self::getBooleanAnnotationSetting(
  467. $className,
  468. $methodName,
  469. 'backupGlobals'
  470. ),
  471. 'backupStaticAttributes' => self::getBooleanAnnotationSetting(
  472. $className,
  473. $methodName,
  474. 'backupStaticAttributes'
  475. )
  476. );
  477. }
  478. /**
  479. * Returns the dependencies for a test class or method.
  480. *
  481. * @param string $className
  482. * @param string $methodName
  483. * @return array
  484. * @since Method available since Release 3.4.0
  485. */
  486. public static function getDependencies($className, $methodName)
  487. {
  488. $annotations = self::parseTestMethodAnnotations(
  489. $className,
  490. $methodName
  491. );
  492. $dependencies = array();
  493. if (isset($annotations['class']['depends'])) {
  494. $dependencies = $annotations['class']['depends'];
  495. }
  496. if (isset($annotations['method']['depends'])) {
  497. $dependencies = array_merge(
  498. $dependencies,
  499. $annotations['method']['depends']
  500. );
  501. }
  502. return array_unique($dependencies);
  503. }
  504. /**
  505. * Returns the error handler settings for a test.
  506. *
  507. * @param string $className
  508. * @param string $methodName
  509. * @return bool
  510. * @since Method available since Release 3.4.0
  511. */
  512. public static function getErrorHandlerSettings($className, $methodName)
  513. {
  514. return self::getBooleanAnnotationSetting(
  515. $className,
  516. $methodName,
  517. 'errorHandler'
  518. );
  519. }
  520. /**
  521. * Returns the groups for a test class or method.
  522. *
  523. * @param string $className
  524. * @param string $methodName
  525. * @return array
  526. * @since Method available since Release 3.2.0
  527. */
  528. public static function getGroups($className, $methodName = '')
  529. {
  530. $annotations = self::parseTestMethodAnnotations(
  531. $className,
  532. $methodName
  533. );
  534. $groups = array();
  535. if (isset($annotations['method']['author'])) {
  536. $groups = $annotations['method']['author'];
  537. } elseif (isset($annotations['class']['author'])) {
  538. $groups = $annotations['class']['author'];
  539. }
  540. if (isset($annotations['class']['group'])) {
  541. $groups = array_merge($groups, $annotations['class']['group']);
  542. }
  543. if (isset($annotations['method']['group'])) {
  544. $groups = array_merge($groups, $annotations['method']['group']);
  545. }
  546. if (isset($annotations['class']['ticket'])) {
  547. $groups = array_merge($groups, $annotations['class']['ticket']);
  548. }
  549. if (isset($annotations['method']['ticket'])) {
  550. $groups = array_merge($groups, $annotations['method']['ticket']);
  551. }
  552. foreach (array('method', 'class') as $element) {
  553. foreach (array('small', 'medium', 'large') as $size) {
  554. if (isset($annotations[$element][$size])) {
  555. $groups[] = $size;
  556. break 2;
  557. }
  558. if (isset($annotations[$element][$size])) {
  559. $groups[] = $size;
  560. break 2;
  561. }
  562. }
  563. }
  564. return array_unique($groups);
  565. }
  566. /**
  567. * Returns the size of the test.
  568. *
  569. * @param string $className
  570. * @param string $methodName
  571. * @return int
  572. * @since Method available since Release 3.6.0
  573. */
  574. public static function getSize($className, $methodName)
  575. {
  576. $groups = array_flip(self::getGroups($className, $methodName));
  577. $size = self::UNKNOWN;
  578. $class = new ReflectionClass($className);
  579. if (isset($groups['large']) ||
  580. (class_exists('PHPUnit_Extensions_Database_TestCase', false) &&
  581. $class->isSubclassOf('PHPUnit_Extensions_Database_TestCase')) ||
  582. (class_exists('PHPUnit_Extensions_SeleniumTestCase', false) &&
  583. $class->isSubclassOf('PHPUnit_Extensions_SeleniumTestCase'))) {
  584. $size = self::LARGE;
  585. } elseif (isset($groups['medium'])) {
  586. $size = self::MEDIUM;
  587. } elseif (isset($groups['small'])) {
  588. $size = self::SMALL;
  589. }
  590. return $size;
  591. }
  592. /**
  593. * Returns the tickets for a test class or method.
  594. *
  595. * @param string $className
  596. * @param string $methodName
  597. * @return array
  598. * @since Method available since Release 3.4.0
  599. */
  600. public static function getTickets($className, $methodName)
  601. {
  602. $annotations = self::parseTestMethodAnnotations(
  603. $className,
  604. $methodName
  605. );
  606. $tickets = array();
  607. if (isset($annotations['class']['ticket'])) {
  608. $tickets = $annotations['class']['ticket'];
  609. }
  610. if (isset($annotations['method']['ticket'])) {
  611. $tickets = array_merge($tickets, $annotations['method']['ticket']);
  612. }
  613. return array_unique($tickets);
  614. }
  615. /**
  616. * Returns the process isolation settings for a test.
  617. *
  618. * @param string $className
  619. * @param string $methodName
  620. * @return bool
  621. * @since Method available since Release 3.4.1
  622. */
  623. public static function getProcessIsolationSettings($className, $methodName)
  624. {
  625. $annotations = self::parseTestMethodAnnotations(
  626. $className,
  627. $methodName
  628. );
  629. if (isset($annotations['class']['runTestsInSeparateProcesses']) ||
  630. isset($annotations['method']['runInSeparateProcess'])) {
  631. return true;
  632. } else {
  633. return false;
  634. }
  635. }
  636. /**
  637. * Returns the preserve global state settings for a test.
  638. *
  639. * @param string $className
  640. * @param string $methodName
  641. * @return bool
  642. * @since Method available since Release 3.4.0
  643. */
  644. public static function getPreserveGlobalStateSettings($className, $methodName)
  645. {
  646. return self::getBooleanAnnotationSetting(
  647. $className,
  648. $methodName,
  649. 'preserveGlobalState'
  650. );
  651. }
  652. /**
  653. * @param string $className
  654. * @return array
  655. * @since Method available since Release 4.0.8
  656. */
  657. public static function getHookMethods($className)
  658. {
  659. if (!class_exists($className, false)) {
  660. return self::emptyHookMethodsArray();
  661. }
  662. if (!isset(self::$hookMethods[$className])) {
  663. self::$hookMethods[$className] = self::emptyHookMethodsArray();
  664. try {
  665. $class = new ReflectionClass($className);
  666. foreach ($class->getMethods() as $method) {
  667. if (self::isBeforeClassMethod($method)) {
  668. self::$hookMethods[$className]['beforeClass'][] = $method->getName();
  669. }
  670. if (self::isBeforeMethod($method)) {
  671. self::$hookMethods[$className]['before'][] = $method->getName();
  672. }
  673. if (self::isAfterMethod($method)) {
  674. self::$hookMethods[$className]['after'][] = $method->getName();
  675. }
  676. if (self::isAfterClassMethod($method)) {
  677. self::$hookMethods[$className]['afterClass'][] = $method->getName();
  678. }
  679. }
  680. } catch (ReflectionException $e) {
  681. }
  682. }
  683. return self::$hookMethods[$className];
  684. }
  685. /**
  686. * @return array
  687. * @since Method available since Release 4.0.9
  688. */
  689. private static function emptyHookMethodsArray()
  690. {
  691. return array(
  692. 'beforeClass' => array('setUpBeforeClass'),
  693. 'before' => array('setUp'),
  694. 'after' => array('tearDown'),
  695. 'afterClass' => array('tearDownAfterClass')
  696. );
  697. }
  698. /**
  699. * @param string $className
  700. * @param string $methodName
  701. * @param string $settingName
  702. * @return bool
  703. * @since Method available since Release 3.4.0
  704. */
  705. private static function getBooleanAnnotationSetting($className, $methodName, $settingName)
  706. {
  707. $annotations = self::parseTestMethodAnnotations(
  708. $className,
  709. $methodName
  710. );
  711. $result = null;
  712. if (isset($annotations['class'][$settingName])) {
  713. if ($annotations['class'][$settingName][0] == 'enabled') {
  714. $result = true;
  715. } elseif ($annotations['class'][$settingName][0] == 'disabled') {
  716. $result = false;
  717. }
  718. }
  719. if (isset($annotations['method'][$settingName])) {
  720. if ($annotations['method'][$settingName][0] == 'enabled') {
  721. $result = true;
  722. } elseif ($annotations['method'][$settingName][0] == 'disabled') {
  723. $result = false;
  724. }
  725. }
  726. return $result;
  727. }
  728. /**
  729. * @param string $element
  730. * @return array
  731. * @throws PHPUnit_Framework_InvalidCoversTargetException
  732. * @since Method available since Release 4.0.0
  733. */
  734. private static function resolveElementToReflectionObjects($element)
  735. {
  736. $codeToCoverList = array();
  737. if (strpos($element, '\\') !== false && function_exists($element)) {
  738. $codeToCoverList[] = new ReflectionFunction($element);
  739. } else if (strpos($element, '::') !== false) {
  740. list($className, $methodName) = explode('::', $element);
  741. if (isset($methodName[0]) && $methodName[0] == '<') {
  742. $classes = array($className);
  743. foreach ($classes as $className) {
  744. if (!class_exists($className) &&
  745. !interface_exists($className)) {
  746. throw new PHPUnit_Framework_InvalidCoversTargetException(
  747. sprintf(
  748. 'Trying to @cover or @use not existing class or ' .
  749. 'interface "%s".',
  750. $className
  751. )
  752. );
  753. }
  754. $class = new ReflectionClass($className);
  755. $methods = $class->getMethods();
  756. $inverse = isset($methodName[1]) && $methodName[1] == '!';
  757. if (strpos($methodName, 'protected')) {
  758. $visibility = 'isProtected';
  759. } elseif (strpos($methodName, 'private')) {
  760. $visibility = 'isPrivate';
  761. } elseif (strpos($methodName, 'public')) {
  762. $visibility = 'isPublic';
  763. }
  764. foreach ($methods as $method) {
  765. if ($inverse && !$method->$visibility()) {
  766. $codeToCoverList[] = $method;
  767. } elseif (!$inverse && $method->$visibility()) {
  768. $codeToCoverList[] = $method;
  769. }
  770. }
  771. }
  772. } else {
  773. $classes = array($className);
  774. foreach ($classes as $className) {
  775. if ($className == '' && function_exists($methodName)) {
  776. $codeToCoverList[] = new ReflectionFunction(
  777. $methodName
  778. );
  779. } else {
  780. if (!((class_exists($className) ||
  781. interface_exists($className) ||
  782. trait_exists($className)) &&
  783. method_exists($className, $methodName))) {
  784. throw new PHPUnit_Framework_InvalidCoversTargetException(
  785. sprintf(
  786. 'Trying to @cover or @use not existing method "%s::%s".',
  787. $className,
  788. $methodName
  789. )
  790. );
  791. }
  792. $codeToCoverList[] = new ReflectionMethod(
  793. $className,
  794. $methodName
  795. );
  796. }
  797. }
  798. }
  799. } else {
  800. $extended = false;
  801. if (strpos($element, '<extended>') !== false) {
  802. $element = str_replace('<extended>', '', $element);
  803. $extended = true;
  804. }
  805. $classes = array($element);
  806. if ($extended) {
  807. $classes = array_merge(
  808. $classes,
  809. class_implements($element),
  810. class_parents($element)
  811. );
  812. }
  813. foreach ($classes as $className) {
  814. if (!class_exists($className) &&
  815. !interface_exists($className) &&
  816. !trait_exists($className)) {
  817. throw new PHPUnit_Framework_InvalidCoversTargetException(
  818. sprintf(
  819. 'Trying to @cover or @use not existing class or ' .
  820. 'interface "%s".',
  821. $className
  822. )
  823. );
  824. }
  825. $codeToCoverList[] = new ReflectionClass($className);
  826. }
  827. }
  828. return $codeToCoverList;
  829. }
  830. /**
  831. * @param array $reflectors
  832. * @return array
  833. */
  834. private static function resolveReflectionObjectsToLines(array $reflectors)
  835. {
  836. $result = array();
  837. foreach ($reflectors as $reflector) {
  838. $filename = $reflector->getFileName();
  839. if (!isset($result[$filename])) {
  840. $result[$filename] = array();
  841. }
  842. $result[$filename] = array_unique(
  843. array_merge(
  844. $result[$filename],
  845. range($reflector->getStartLine(), $reflector->getEndLine())
  846. )
  847. );
  848. }
  849. return $result;
  850. }
  851. /**
  852. * @param ReflectionMethod $method
  853. * @return bool
  854. * @since Method available since Release 4.0.8
  855. */
  856. private static function isBeforeClassMethod(ReflectionMethod $method)
  857. {
  858. return $method->isStatic() && strpos($method->getDocComment(), '@beforeClass') !== false;
  859. }
  860. /**
  861. * @param ReflectionMethod $method
  862. * @return bool
  863. * @since Method available since Release 4.0.8
  864. */
  865. private static function isBeforeMethod(ReflectionMethod $method)
  866. {
  867. return preg_match('/@before\b/', $method->getDocComment());
  868. }
  869. /**
  870. * @param ReflectionMethod $method
  871. * @return bool
  872. * @since Method available since Release 4.0.8
  873. */
  874. private static function isAfterClassMethod(ReflectionMethod $method)
  875. {
  876. return $method->isStatic() && strpos($method->getDocComment(), '@afterClass') !== false;
  877. }
  878. /**
  879. * @param ReflectionMethod $method
  880. * @return bool
  881. * @since Method available since Release 4.0.8
  882. */
  883. private static function isAfterMethod(ReflectionMethod $method)
  884. {
  885. return preg_match('/@after\b/', $method->getDocComment());
  886. }
  887. }