PageRenderTime 59ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

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

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