/vendor/phpunit/phpunit/src/TextUI/Command.php

https://bitbucket.org/alan_cordova/api-sb-map · PHP · 1172 lines · 870 code · 188 blank · 114 comment · 97 complexity · 806fdf8d70183514c1c8039997b47017 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. /**
  11. * A TestRunner for the Command Line Interface (CLI)
  12. * PHP SAPI Module.
  13. */
  14. class PHPUnit_TextUI_Command
  15. {
  16. /**
  17. * @var array
  18. */
  19. protected $arguments = [
  20. 'listGroups' => false,
  21. 'listSuites' => false,
  22. 'loader' => null,
  23. 'useDefaultConfiguration' => true,
  24. 'loadedExtensions' => [],
  25. 'notLoadedExtensions' => []
  26. ];
  27. /**
  28. * @var array
  29. */
  30. protected $options = [];
  31. /**
  32. * @var array
  33. */
  34. protected $longOptions = [
  35. 'atleast-version=' => null,
  36. 'bootstrap=' => null,
  37. 'colors==' => null,
  38. 'columns=' => null,
  39. 'configuration=' => null,
  40. 'coverage-clover=' => null,
  41. 'coverage-crap4j=' => null,
  42. 'coverage-html=' => null,
  43. 'coverage-php=' => null,
  44. 'coverage-text==' => null,
  45. 'coverage-xml=' => null,
  46. 'debug' => null,
  47. 'disallow-test-output' => null,
  48. 'disallow-resource-usage' => null,
  49. 'disallow-todo-tests' => null,
  50. 'enforce-time-limit' => null,
  51. 'exclude-group=' => null,
  52. 'filter=' => null,
  53. 'generate-configuration' => null,
  54. 'group=' => null,
  55. 'help' => null,
  56. 'include-path=' => null,
  57. 'list-groups' => null,
  58. 'list-suites' => null,
  59. 'loader=' => null,
  60. 'log-json=' => null,
  61. 'log-junit=' => null,
  62. 'log-tap=' => null,
  63. 'log-teamcity=' => null,
  64. 'no-configuration' => null,
  65. 'no-coverage' => null,
  66. 'no-extensions' => null,
  67. 'no-globals-backup' => null,
  68. 'printer=' => null,
  69. 'process-isolation' => null,
  70. 'repeat=' => null,
  71. 'report-useless-tests' => null,
  72. 'reverse-list' => null,
  73. 'static-backup' => null,
  74. 'stderr' => null,
  75. 'stop-on-error' => null,
  76. 'stop-on-failure' => null,
  77. 'stop-on-warning' => null,
  78. 'stop-on-incomplete' => null,
  79. 'stop-on-risky' => null,
  80. 'stop-on-skipped' => null,
  81. 'fail-on-warning' => null,
  82. 'fail-on-risky' => null,
  83. 'strict-coverage' => null,
  84. 'disable-coverage-ignore' => null,
  85. 'strict-global-state' => null,
  86. 'tap' => null,
  87. 'teamcity' => null,
  88. 'testdox' => null,
  89. 'testdox-group=' => null,
  90. 'testdox-exclude-group=' => null,
  91. 'testdox-html=' => null,
  92. 'testdox-text=' => null,
  93. 'testdox-xml=' => null,
  94. 'test-suffix=' => null,
  95. 'testsuite=' => null,
  96. 'verbose' => null,
  97. 'version' => null,
  98. 'whitelist=' => null
  99. ];
  100. /**
  101. * @var bool
  102. */
  103. private $versionStringPrinted = false;
  104. /**
  105. * @param bool $exit
  106. */
  107. public static function main($exit = true)
  108. {
  109. $command = new static;
  110. return $command->run($_SERVER['argv'], $exit);
  111. }
  112. /**
  113. * @param array $argv
  114. * @param bool $exit
  115. *
  116. * @return int
  117. */
  118. public function run(array $argv, $exit = true)
  119. {
  120. $this->handleArguments($argv);
  121. $runner = $this->createRunner();
  122. if (is_object($this->arguments['test']) &&
  123. $this->arguments['test'] instanceof PHPUnit_Framework_Test) {
  124. $suite = $this->arguments['test'];
  125. } else {
  126. $suite = $runner->getTest(
  127. $this->arguments['test'],
  128. $this->arguments['testFile'],
  129. $this->arguments['testSuffixes']
  130. );
  131. }
  132. if ($this->arguments['listGroups']) {
  133. $this->printVersionString();
  134. print "Available test group(s):\n";
  135. $groups = $suite->getGroups();
  136. sort($groups);
  137. foreach ($groups as $group) {
  138. print " - $group\n";
  139. }
  140. if ($exit) {
  141. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  142. } else {
  143. return PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
  144. }
  145. }
  146. if ($this->arguments['listSuites']) {
  147. $this->printVersionString();
  148. print "Available test suite(s):\n";
  149. $configuration = PHPUnit_Util_Configuration::getInstance(
  150. $this->arguments['configuration']
  151. );
  152. $suiteNames = $configuration->getTestSuiteNames();
  153. foreach ($suiteNames as $suiteName) {
  154. print " - $suiteName\n";
  155. }
  156. if ($exit) {
  157. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  158. } else {
  159. return PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
  160. }
  161. }
  162. unset($this->arguments['test']);
  163. unset($this->arguments['testFile']);
  164. try {
  165. $result = $runner->doRun($suite, $this->arguments, $exit);
  166. } catch (PHPUnit_Framework_Exception $e) {
  167. print $e->getMessage() . "\n";
  168. }
  169. $return = PHPUnit_TextUI_TestRunner::FAILURE_EXIT;
  170. if (isset($result) && $result->wasSuccessful(false)) {
  171. $return = PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
  172. } elseif (!isset($result) || $result->errorCount() > 0) {
  173. $return = PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT;
  174. }
  175. if ($exit) {
  176. exit($return);
  177. }
  178. return $return;
  179. }
  180. /**
  181. * Create a TestRunner, override in subclasses.
  182. *
  183. * @return PHPUnit_TextUI_TestRunner
  184. */
  185. protected function createRunner()
  186. {
  187. return new PHPUnit_TextUI_TestRunner($this->arguments['loader']);
  188. }
  189. /**
  190. * Handles the command-line arguments.
  191. *
  192. * A child class of PHPUnit_TextUI_Command can hook into the argument
  193. * parsing by adding the switch(es) to the $longOptions array and point to a
  194. * callback method that handles the switch(es) in the child class like this
  195. *
  196. * <code>
  197. * <?php
  198. * class MyCommand extends PHPUnit_TextUI_Command
  199. * {
  200. * public function __construct()
  201. * {
  202. * // my-switch won't accept a value, it's an on/off
  203. * $this->longOptions['my-switch'] = 'myHandler';
  204. * // my-secondswitch will accept a value - note the equals sign
  205. * $this->longOptions['my-secondswitch='] = 'myOtherHandler';
  206. * }
  207. *
  208. * // --my-switch -> myHandler()
  209. * protected function myHandler()
  210. * {
  211. * }
  212. *
  213. * // --my-secondswitch foo -> myOtherHandler('foo')
  214. * protected function myOtherHandler ($value)
  215. * {
  216. * }
  217. *
  218. * // You will also need this - the static keyword in the
  219. * // PHPUnit_TextUI_Command will mean that it'll be
  220. * // PHPUnit_TextUI_Command that gets instantiated,
  221. * // not MyCommand
  222. * public static function main($exit = true)
  223. * {
  224. * $command = new static;
  225. *
  226. * return $command->run($_SERVER['argv'], $exit);
  227. * }
  228. *
  229. * }
  230. * </code>
  231. *
  232. * @param array $argv
  233. */
  234. protected function handleArguments(array $argv)
  235. {
  236. if (defined('__PHPUNIT_PHAR__')) {
  237. $this->longOptions['check-version'] = null;
  238. $this->longOptions['selfupdate'] = null;
  239. $this->longOptions['self-update'] = null;
  240. $this->longOptions['selfupgrade'] = null;
  241. $this->longOptions['self-upgrade'] = null;
  242. }
  243. try {
  244. $this->options = PHPUnit_Util_Getopt::getopt(
  245. $argv,
  246. 'd:c:hv',
  247. array_keys($this->longOptions)
  248. );
  249. } catch (PHPUnit_Framework_Exception $e) {
  250. $this->showError($e->getMessage());
  251. }
  252. foreach ($this->options[0] as $option) {
  253. switch ($option[0]) {
  254. case '--colors':
  255. $this->arguments['colors'] = $option[1] ?: PHPUnit_TextUI_ResultPrinter::COLOR_AUTO;
  256. break;
  257. case '--bootstrap':
  258. $this->arguments['bootstrap'] = $option[1];
  259. break;
  260. case '--columns':
  261. if (is_numeric($option[1])) {
  262. $this->arguments['columns'] = (int) $option[1];
  263. } elseif ($option[1] == 'max') {
  264. $this->arguments['columns'] = 'max';
  265. }
  266. break;
  267. case 'c':
  268. case '--configuration':
  269. $this->arguments['configuration'] = $option[1];
  270. break;
  271. case '--coverage-clover':
  272. $this->arguments['coverageClover'] = $option[1];
  273. break;
  274. case '--coverage-crap4j':
  275. $this->arguments['coverageCrap4J'] = $option[1];
  276. break;
  277. case '--coverage-html':
  278. $this->arguments['coverageHtml'] = $option[1];
  279. break;
  280. case '--coverage-php':
  281. $this->arguments['coveragePHP'] = $option[1];
  282. break;
  283. case '--coverage-text':
  284. if ($option[1] === null) {
  285. $option[1] = 'php://stdout';
  286. }
  287. $this->arguments['coverageText'] = $option[1];
  288. $this->arguments['coverageTextShowUncoveredFiles'] = false;
  289. $this->arguments['coverageTextShowOnlySummary'] = false;
  290. break;
  291. case '--coverage-xml':
  292. $this->arguments['coverageXml'] = $option[1];
  293. break;
  294. case 'd':
  295. $ini = explode('=', $option[1]);
  296. if (isset($ini[0])) {
  297. if (isset($ini[1])) {
  298. ini_set($ini[0], $ini[1]);
  299. } else {
  300. ini_set($ini[0], true);
  301. }
  302. }
  303. break;
  304. case '--debug':
  305. $this->arguments['debug'] = true;
  306. break;
  307. case 'h':
  308. case '--help':
  309. $this->showHelp();
  310. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  311. break;
  312. case '--filter':
  313. $this->arguments['filter'] = $option[1];
  314. break;
  315. case '--testsuite':
  316. $this->arguments['testsuite'] = $option[1];
  317. break;
  318. case '--generate-configuration':
  319. $this->printVersionString();
  320. printf(
  321. "Generating phpunit.xml in %s\n\n",
  322. getcwd()
  323. );
  324. print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): ';
  325. $bootstrapScript = trim(fgets(STDIN));
  326. print 'Tests directory (relative to path shown above; default: tests): ';
  327. $testsDirectory = trim(fgets(STDIN));
  328. print 'Source directory (relative to path shown above; default: src): ';
  329. $src = trim(fgets(STDIN));
  330. if ($bootstrapScript == '') {
  331. $bootstrapScript = 'vendor/autoload.php';
  332. }
  333. if ($testsDirectory == '') {
  334. $testsDirectory = 'tests';
  335. }
  336. if ($src == '') {
  337. $src = 'src';
  338. }
  339. $generator = new PHPUnit_Util_ConfigurationGenerator;
  340. file_put_contents(
  341. 'phpunit.xml',
  342. $generator->generateDefaultConfiguration(
  343. PHPUnit_Runner_Version::series(),
  344. $bootstrapScript,
  345. $testsDirectory,
  346. $src
  347. )
  348. );
  349. printf(
  350. "\nGenerated phpunit.xml in %s\n",
  351. getcwd()
  352. );
  353. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  354. break;
  355. case '--group':
  356. $this->arguments['groups'] = explode(',', $option[1]);
  357. break;
  358. case '--exclude-group':
  359. $this->arguments['excludeGroups'] = explode(
  360. ',',
  361. $option[1]
  362. );
  363. break;
  364. case '--test-suffix':
  365. $this->arguments['testSuffixes'] = explode(
  366. ',',
  367. $option[1]
  368. );
  369. break;
  370. case '--include-path':
  371. $includePath = $option[1];
  372. break;
  373. case '--list-groups':
  374. $this->arguments['listGroups'] = true;
  375. break;
  376. case '--list-suites':
  377. $this->arguments['listSuites'] = true;
  378. break;
  379. case '--printer':
  380. $this->arguments['printer'] = $option[1];
  381. break;
  382. case '--loader':
  383. $this->arguments['loader'] = $option[1];
  384. break;
  385. case '--log-json':
  386. $this->arguments['jsonLogfile'] = $option[1];
  387. break;
  388. case '--log-junit':
  389. $this->arguments['junitLogfile'] = $option[1];
  390. break;
  391. case '--log-tap':
  392. $this->arguments['tapLogfile'] = $option[1];
  393. break;
  394. case '--log-teamcity':
  395. $this->arguments['teamcityLogfile'] = $option[1];
  396. break;
  397. case '--process-isolation':
  398. $this->arguments['processIsolation'] = true;
  399. break;
  400. case '--repeat':
  401. $this->arguments['repeat'] = (int) $option[1];
  402. break;
  403. case '--stderr':
  404. $this->arguments['stderr'] = true;
  405. break;
  406. case '--stop-on-error':
  407. $this->arguments['stopOnError'] = true;
  408. break;
  409. case '--stop-on-failure':
  410. $this->arguments['stopOnFailure'] = true;
  411. break;
  412. case '--stop-on-warning':
  413. $this->arguments['stopOnWarning'] = true;
  414. break;
  415. case '--stop-on-incomplete':
  416. $this->arguments['stopOnIncomplete'] = true;
  417. break;
  418. case '--stop-on-risky':
  419. $this->arguments['stopOnRisky'] = true;
  420. break;
  421. case '--stop-on-skipped':
  422. $this->arguments['stopOnSkipped'] = true;
  423. break;
  424. case '--fail-on-warning':
  425. $this->arguments['failOnWarning'] = true;
  426. break;
  427. case '--fail-on-risky':
  428. $this->arguments['failOnRisky'] = true;
  429. break;
  430. case '--tap':
  431. $this->arguments['printer'] = 'PHPUnit_Util_Log_TAP';
  432. break;
  433. case '--teamcity':
  434. $this->arguments['printer'] = 'PHPUnit_Util_Log_TeamCity';
  435. break;
  436. case '--testdox':
  437. $this->arguments['printer'] = 'PHPUnit_Util_TestDox_ResultPrinter_Text';
  438. break;
  439. case '--testdox-group':
  440. $this->arguments['testdoxGroups'] = explode(
  441. ',',
  442. $option[1]
  443. );
  444. break;
  445. case '--testdox-exclude-group':
  446. $this->arguments['testdoxExcludeGroups'] = explode(
  447. ',',
  448. $option[1]
  449. );
  450. break;
  451. case '--testdox-html':
  452. $this->arguments['testdoxHTMLFile'] = $option[1];
  453. break;
  454. case '--testdox-text':
  455. $this->arguments['testdoxTextFile'] = $option[1];
  456. break;
  457. case '--testdox-xml':
  458. $this->arguments['testdoxXMLFile'] = $option[1];
  459. break;
  460. case '--no-configuration':
  461. $this->arguments['useDefaultConfiguration'] = false;
  462. break;
  463. case '--no-extensions':
  464. $this->arguments['noExtensions'] = true;
  465. break;
  466. case '--no-coverage':
  467. $this->arguments['noCoverage'] = true;
  468. break;
  469. case '--no-globals-backup':
  470. $this->arguments['backupGlobals'] = false;
  471. break;
  472. case '--static-backup':
  473. $this->arguments['backupStaticAttributes'] = true;
  474. break;
  475. case 'v':
  476. case '--verbose':
  477. $this->arguments['verbose'] = true;
  478. break;
  479. case '--atleast-version':
  480. exit(version_compare(PHPUnit_Runner_Version::id(), $option[1], '>=')
  481. ? PHPUnit_TextUI_TestRunner::SUCCESS_EXIT
  482. : PHPUnit_TextUI_TestRunner::FAILURE_EXIT
  483. );
  484. break;
  485. case '--version':
  486. $this->printVersionString();
  487. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  488. break;
  489. case '--report-useless-tests':
  490. $this->arguments['reportUselessTests'] = true;
  491. break;
  492. case '--strict-coverage':
  493. $this->arguments['strictCoverage'] = true;
  494. break;
  495. case '--disable-coverage-ignore':
  496. $this->arguments['disableCodeCoverageIgnore'] = true;
  497. break;
  498. case '--strict-global-state':
  499. $this->arguments['beStrictAboutChangesToGlobalState'] = true;
  500. break;
  501. case '--disallow-test-output':
  502. $this->arguments['disallowTestOutput'] = true;
  503. break;
  504. case '--disallow-resource-usage':
  505. $this->arguments['beStrictAboutResourceUsageDuringSmallTests'] = true;
  506. break;
  507. case '--enforce-time-limit':
  508. $this->arguments['enforceTimeLimit'] = true;
  509. break;
  510. case '--disallow-todo-tests':
  511. $this->arguments['disallowTodoAnnotatedTests'] = true;
  512. break;
  513. case '--reverse-list':
  514. $this->arguments['reverseList'] = true;
  515. break;
  516. case '--check-version':
  517. $this->handleVersionCheck();
  518. break;
  519. case '--selfupdate':
  520. case '--self-update':
  521. $this->handleSelfUpdate();
  522. break;
  523. case '--selfupgrade':
  524. case '--self-upgrade':
  525. $this->handleSelfUpdate(true);
  526. break;
  527. case '--whitelist':
  528. $this->arguments['whitelist'] = $option[1];
  529. break;
  530. default:
  531. $optionName = str_replace('--', '', $option[0]);
  532. $handler = null;
  533. if (isset($this->longOptions[$optionName])) {
  534. $handler = $this->longOptions[$optionName];
  535. } elseif (isset($this->longOptions[$optionName . '='])) {
  536. $handler = $this->longOptions[$optionName . '='];
  537. }
  538. if (isset($handler) && is_callable([$this, $handler])) {
  539. $this->$handler($option[1]);
  540. }
  541. }
  542. }
  543. $this->handleCustomTestSuite();
  544. if (!isset($this->arguments['test'])) {
  545. if (isset($this->options[1][0])) {
  546. $this->arguments['test'] = $this->options[1][0];
  547. }
  548. if (isset($this->options[1][1])) {
  549. $this->arguments['testFile'] = realpath($this->options[1][1]);
  550. } else {
  551. $this->arguments['testFile'] = '';
  552. }
  553. if (isset($this->arguments['test']) &&
  554. is_file($this->arguments['test']) &&
  555. substr($this->arguments['test'], -5, 5) != '.phpt') {
  556. $this->arguments['testFile'] = realpath($this->arguments['test']);
  557. $this->arguments['test'] = substr($this->arguments['test'], 0, strrpos($this->arguments['test'], '.'));
  558. }
  559. }
  560. if (!isset($this->arguments['testSuffixes'])) {
  561. $this->arguments['testSuffixes'] = ['Test.php', '.phpt'];
  562. }
  563. if (isset($includePath)) {
  564. ini_set(
  565. 'include_path',
  566. $includePath . PATH_SEPARATOR . ini_get('include_path')
  567. );
  568. }
  569. if ($this->arguments['loader'] !== null) {
  570. $this->arguments['loader'] = $this->handleLoader($this->arguments['loader']);
  571. }
  572. if (isset($this->arguments['configuration']) &&
  573. is_dir($this->arguments['configuration'])) {
  574. $configurationFile = $this->arguments['configuration'] . '/phpunit.xml';
  575. if (file_exists($configurationFile)) {
  576. $this->arguments['configuration'] = realpath(
  577. $configurationFile
  578. );
  579. } elseif (file_exists($configurationFile . '.dist')) {
  580. $this->arguments['configuration'] = realpath(
  581. $configurationFile . '.dist'
  582. );
  583. }
  584. } elseif (!isset($this->arguments['configuration']) &&
  585. $this->arguments['useDefaultConfiguration']) {
  586. if (file_exists('phpunit.xml')) {
  587. $this->arguments['configuration'] = realpath('phpunit.xml');
  588. } elseif (file_exists('phpunit.xml.dist')) {
  589. $this->arguments['configuration'] = realpath(
  590. 'phpunit.xml.dist'
  591. );
  592. }
  593. }
  594. if (isset($this->arguments['configuration'])) {
  595. try {
  596. $configuration = PHPUnit_Util_Configuration::getInstance(
  597. $this->arguments['configuration']
  598. );
  599. } catch (Throwable $e) {
  600. print $e->getMessage() . "\n";
  601. exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
  602. } catch (Exception $e) {
  603. print $e->getMessage() . "\n";
  604. exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
  605. }
  606. $phpunitConfiguration = $configuration->getPHPUnitConfiguration();
  607. $configuration->handlePHPConfiguration();
  608. /*
  609. * Issue #1216
  610. */
  611. if (isset($this->arguments['bootstrap'])) {
  612. $this->handleBootstrap($this->arguments['bootstrap']);
  613. } elseif (isset($phpunitConfiguration['bootstrap'])) {
  614. $this->handleBootstrap($phpunitConfiguration['bootstrap']);
  615. }
  616. /*
  617. * Issue #657
  618. */
  619. if (isset($phpunitConfiguration['stderr']) && ! isset($this->arguments['stderr'])) {
  620. $this->arguments['stderr'] = $phpunitConfiguration['stderr'];
  621. }
  622. if (isset($phpunitConfiguration['extensionsDirectory']) && !isset($this->arguments['noExtensions']) && extension_loaded('phar')) {
  623. $this->handleExtensions($phpunitConfiguration['extensionsDirectory']);
  624. }
  625. if (isset($phpunitConfiguration['columns']) && ! isset($this->arguments['columns'])) {
  626. $this->arguments['columns'] = $phpunitConfiguration['columns'];
  627. }
  628. if (!isset($this->arguments['printer']) && isset($phpunitConfiguration['printerClass'])) {
  629. if (isset($phpunitConfiguration['printerFile'])) {
  630. $file = $phpunitConfiguration['printerFile'];
  631. } else {
  632. $file = '';
  633. }
  634. $this->arguments['printer'] = $this->handlePrinter(
  635. $phpunitConfiguration['printerClass'],
  636. $file
  637. );
  638. }
  639. if (isset($phpunitConfiguration['testSuiteLoaderClass'])) {
  640. if (isset($phpunitConfiguration['testSuiteLoaderFile'])) {
  641. $file = $phpunitConfiguration['testSuiteLoaderFile'];
  642. } else {
  643. $file = '';
  644. }
  645. $this->arguments['loader'] = $this->handleLoader(
  646. $phpunitConfiguration['testSuiteLoaderClass'],
  647. $file
  648. );
  649. }
  650. if (!isset($this->arguments['test'])) {
  651. $testSuite = $configuration->getTestSuiteConfiguration(isset($this->arguments['testsuite']) ? $this->arguments['testsuite'] : null);
  652. if ($testSuite !== null) {
  653. $this->arguments['test'] = $testSuite;
  654. }
  655. }
  656. } elseif (isset($this->arguments['bootstrap'])) {
  657. $this->handleBootstrap($this->arguments['bootstrap']);
  658. }
  659. if (isset($this->arguments['printer']) &&
  660. is_string($this->arguments['printer'])) {
  661. $this->arguments['printer'] = $this->handlePrinter($this->arguments['printer']);
  662. }
  663. if (isset($this->arguments['test']) && is_string($this->arguments['test']) && substr($this->arguments['test'], -5, 5) == '.phpt') {
  664. $test = new PHPUnit_Extensions_PhptTestCase($this->arguments['test']);
  665. $this->arguments['test'] = new PHPUnit_Framework_TestSuite;
  666. $this->arguments['test']->addTest($test);
  667. }
  668. if (!isset($this->arguments['test']) ||
  669. (isset($this->arguments['testDatabaseLogRevision']) && !isset($this->arguments['testDatabaseDSN']))) {
  670. $this->showHelp();
  671. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  672. }
  673. }
  674. /**
  675. * Handles the loading of the PHPUnit_Runner_TestSuiteLoader implementation.
  676. *
  677. * @param string $loaderClass
  678. * @param string $loaderFile
  679. *
  680. * @return PHPUnit_Runner_TestSuiteLoader
  681. */
  682. protected function handleLoader($loaderClass, $loaderFile = '')
  683. {
  684. if (!class_exists($loaderClass, false)) {
  685. if ($loaderFile == '') {
  686. $loaderFile = PHPUnit_Util_Filesystem::classNameToFilename(
  687. $loaderClass
  688. );
  689. }
  690. $loaderFile = stream_resolve_include_path($loaderFile);
  691. if ($loaderFile) {
  692. require $loaderFile;
  693. }
  694. }
  695. if (class_exists($loaderClass, false)) {
  696. $class = new ReflectionClass($loaderClass);
  697. if ($class->implementsInterface('PHPUnit_Runner_TestSuiteLoader') &&
  698. $class->isInstantiable()) {
  699. return $class->newInstance();
  700. }
  701. }
  702. if ($loaderClass == 'PHPUnit_Runner_StandardTestSuiteLoader') {
  703. return;
  704. }
  705. $this->showError(
  706. sprintf(
  707. 'Could not use "%s" as loader.',
  708. $loaderClass
  709. )
  710. );
  711. }
  712. /**
  713. * Handles the loading of the PHPUnit_Util_Printer implementation.
  714. *
  715. * @param string $printerClass
  716. * @param string $printerFile
  717. *
  718. * @return PHPUnit_Util_Printer|string
  719. */
  720. protected function handlePrinter($printerClass, $printerFile = '')
  721. {
  722. if (!class_exists($printerClass, false)) {
  723. if ($printerFile == '') {
  724. $printerFile = PHPUnit_Util_Filesystem::classNameToFilename(
  725. $printerClass
  726. );
  727. }
  728. $printerFile = stream_resolve_include_path($printerFile);
  729. if ($printerFile) {
  730. require $printerFile;
  731. }
  732. }
  733. if (class_exists($printerClass)) {
  734. $class = new ReflectionClass($printerClass);
  735. if ($class->implementsInterface('PHPUnit_Framework_TestListener') &&
  736. $class->isSubclassOf('PHPUnit_Util_Printer') &&
  737. $class->isInstantiable()) {
  738. if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) {
  739. return $printerClass;
  740. }
  741. $outputStream = isset($this->arguments['stderr']) ? 'php://stderr' : null;
  742. return $class->newInstance($outputStream);
  743. }
  744. }
  745. $this->showError(
  746. sprintf(
  747. 'Could not use "%s" as printer.',
  748. $printerClass
  749. )
  750. );
  751. }
  752. /**
  753. * Loads a bootstrap file.
  754. *
  755. * @param string $filename
  756. */
  757. protected function handleBootstrap($filename)
  758. {
  759. try {
  760. PHPUnit_Util_Fileloader::checkAndLoad($filename);
  761. } catch (PHPUnit_Framework_Exception $e) {
  762. $this->showError($e->getMessage());
  763. }
  764. }
  765. protected function handleSelfUpdate($upgrade = false)
  766. {
  767. $this->printVersionString();
  768. if ($upgrade) {
  769. print "Warning: Deprecated --self-upgrade used\n\n";
  770. } else {
  771. print "Warning: Deprecated --self-update used\n\n";
  772. }
  773. $localFilename = realpath($_SERVER['argv'][0]);
  774. if (!is_writable($localFilename)) {
  775. print 'No write permission to update ' . $localFilename . "\n";
  776. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  777. }
  778. if (!extension_loaded('openssl')) {
  779. print "The OpenSSL extension is not loaded.\n";
  780. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  781. }
  782. if (!$upgrade) {
  783. $remoteFilename = sprintf(
  784. 'https://phar.phpunit.de/phpunit-%s.phar',
  785. file_get_contents(
  786. sprintf(
  787. 'https://phar.phpunit.de/latest-version-of/phpunit-%s',
  788. PHPUnit_Runner_Version::series()
  789. )
  790. )
  791. );
  792. } else {
  793. $remoteFilename = sprintf(
  794. 'https://phar.phpunit.de/phpunit%s.phar',
  795. PHPUnit_Runner_Version::getReleaseChannel()
  796. );
  797. }
  798. $tempFilename = tempnam(sys_get_temp_dir(), 'phpunit') . '.phar';
  799. // Workaround for https://bugs.php.net/bug.php?id=65538
  800. $caFile = dirname($tempFilename) . '/ca.pem';
  801. copy(__PHPUNIT_PHAR_ROOT__ . '/ca.pem', $caFile);
  802. print 'Updating the PHPUnit PHAR ... ';
  803. $options = [
  804. 'ssl' => [
  805. 'allow_self_signed' => false,
  806. 'cafile' => $caFile,
  807. 'verify_peer' => true
  808. ]
  809. ];
  810. file_put_contents(
  811. $tempFilename,
  812. file_get_contents(
  813. $remoteFilename,
  814. false,
  815. stream_context_create($options)
  816. )
  817. );
  818. chmod($tempFilename, 0777 & ~umask());
  819. try {
  820. $phar = new Phar($tempFilename);
  821. unset($phar);
  822. rename($tempFilename, $localFilename);
  823. unlink($caFile);
  824. } catch (Throwable $_e) {
  825. $e = $_e;
  826. } catch (Exception $_e) {
  827. $e = $_e;
  828. }
  829. if (isset($e)) {
  830. unlink($caFile);
  831. unlink($tempFilename);
  832. print " done\n\n" . $e->getMessage() . "\n";
  833. exit(2);
  834. }
  835. print " done\n";
  836. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  837. }
  838. protected function handleVersionCheck()
  839. {
  840. $this->printVersionString();
  841. $latestVersion = file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit');
  842. $isOutdated = version_compare($latestVersion, PHPUnit_Runner_Version::id(), '>');
  843. if ($isOutdated) {
  844. print "You are not using the latest version of PHPUnit.\n";
  845. print 'Use "phpunit --self-upgrade" to install PHPUnit ' . $latestVersion . "\n";
  846. } else {
  847. print "You are using the latest version of PHPUnit.\n";
  848. }
  849. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  850. }
  851. /**
  852. * Show the help message.
  853. */
  854. protected function showHelp()
  855. {
  856. $this->printVersionString();
  857. print <<<EOT
  858. Usage: phpunit [options] UnitTest [UnitTest.php]
  859. phpunit [options] <directory>
  860. Code Coverage Options:
  861. --coverage-clover <file> Generate code coverage report in Clover XML format.
  862. --coverage-crap4j <file> Generate code coverage report in Crap4J XML format.
  863. --coverage-html <dir> Generate code coverage report in HTML format.
  864. --coverage-php <file> Export PHP_CodeCoverage object to file.
  865. --coverage-text=<file> Generate code coverage report in text format.
  866. Default: Standard output.
  867. --coverage-xml <dir> Generate code coverage report in PHPUnit XML format.
  868. --whitelist <dir> Whitelist <dir> for code coverage analysis.
  869. --disable-coverage-ignore Disable annotations for ignoring code coverage.
  870. Logging Options:
  871. --log-junit <file> Log test execution in JUnit XML format to file.
  872. --log-teamcity <file> Log test execution in TeamCity format to file.
  873. --testdox-html <file> Write agile documentation in HTML format to file.
  874. --testdox-text <file> Write agile documentation in Text format to file.
  875. --testdox-xml <file> Write agile documentation in XML format to file.
  876. --reverse-list Print defects in reverse order
  877. Test Selection Options:
  878. --filter <pattern> Filter which tests to run.
  879. --testsuite <name> Filter which testsuite to run.
  880. --group ... Only runs tests from the specified group(s).
  881. --exclude-group ... Exclude tests from the specified group(s).
  882. --list-groups List available test groups.
  883. --list-suites List available test suites.
  884. --test-suffix ... Only search for test in files with specified
  885. suffix(es). Default: Test.php,.phpt
  886. Test Execution Options:
  887. --report-useless-tests Be strict about tests that do not test anything.
  888. --strict-coverage Be strict about @covers annotation usage.
  889. --strict-global-state Be strict about changes to global state
  890. --disallow-test-output Be strict about output during tests.
  891. --disallow-resource-usage Be strict about resource usage during small tests.
  892. --enforce-time-limit Enforce time limit based on test size.
  893. --disallow-todo-tests Disallow @todo-annotated tests.
  894. --process-isolation Run each test in a separate PHP process.
  895. --no-globals-backup Do not backup and restore \$GLOBALS for each test.
  896. --static-backup Backup and restore static attributes for each test.
  897. --colors=<flag> Use colors in output ("never", "auto" or "always").
  898. --columns <n> Number of columns to use for progress output.
  899. --columns max Use maximum number of columns for progress output.
  900. --stderr Write to STDERR instead of STDOUT.
  901. --stop-on-error Stop execution upon first error.
  902. --stop-on-failure Stop execution upon first error or failure.
  903. --stop-on-warning Stop execution upon first warning.
  904. --stop-on-risky Stop execution upon first risky test.
  905. --stop-on-skipped Stop execution upon first skipped test.
  906. --stop-on-incomplete Stop execution upon first incomplete test.
  907. --fail-on-warning Treat tests with warnings as failures.
  908. --fail-on-risky Treat risky tests as failures.
  909. -v|--verbose Output more verbose information.
  910. --debug Display debugging information during test execution.
  911. --loader <loader> TestSuiteLoader implementation to use.
  912. --repeat <times> Runs the test(s) repeatedly.
  913. --teamcity Report test execution progress in TeamCity format.
  914. --testdox Report test execution progress in TestDox format.
  915. --testdox-group Only include tests from the specified group(s).
  916. --testdox-exclude-group Exclude tests from the specified group(s).
  917. --printer <printer> TestListener implementation to use.
  918. Configuration Options:
  919. --bootstrap <file> A "bootstrap" PHP file that is run before the tests.
  920. -c|--configuration <file> Read configuration from XML file.
  921. --no-configuration Ignore default configuration file (phpunit.xml).
  922. --no-coverage Ignore code coverage configuration.
  923. --no-extensions Do not load PHPUnit extensions.
  924. --include-path <path(s)> Prepend PHP's include_path with given path(s).
  925. -d key[=value] Sets a php.ini value.
  926. --generate-configuration Generate configuration file with suggested settings.
  927. Miscellaneous Options:
  928. -h|--help Prints this usage information.
  929. --version Prints the version and exits.
  930. --atleast-version <min> Checks that version is greater than min and exits.
  931. EOT;
  932. if (defined('__PHPUNIT_PHAR__')) {
  933. print "\n --check-version Check whether PHPUnit is the latest version.";
  934. }
  935. }
  936. /**
  937. * Custom callback for test suite discovery.
  938. */
  939. protected function handleCustomTestSuite()
  940. {
  941. }
  942. private function printVersionString()
  943. {
  944. if ($this->versionStringPrinted) {
  945. return;
  946. }
  947. print PHPUnit_Runner_Version::getVersionString() . "\n\n";
  948. $this->versionStringPrinted = true;
  949. }
  950. /**
  951. * @param string $message
  952. */
  953. private function showError($message)
  954. {
  955. $this->printVersionString();
  956. print $message . "\n";
  957. exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
  958. }
  959. /**
  960. * @param string $directory
  961. */
  962. private function handleExtensions($directory)
  963. {
  964. $facade = new File_Iterator_Facade;
  965. foreach ($facade->getFilesAsArray($directory, '.phar') as $file) {
  966. require $file;
  967. $this->arguments['loadedExtensions'][] = $file;
  968. }
  969. }
  970. }