PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

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