PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/frapi/tests/phpunit/PHPUnit/TextUI/Command.php

http://github.com/frapi/frapi
PHP | 728 lines | 542 code | 117 blank | 69 comment | 89 complexity | 34b3131d0cba555f974cabb8d4e6df3f MD5 | raw file
Possible License(s): BSD-2-Clause
  1. <?php
  2. /**
  3. * PHPUnit
  4. *
  5. * Copyright (c) 2002-2009, Sebastian Bergmann <sb@sebastian-bergmann.de>.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * * Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * * Neither the name of Sebastian Bergmann nor the names of his
  21. * contributors may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  25. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  26. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  27. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  28. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  29. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  30. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  31. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  32. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  34. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35. * POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. * @category Testing
  38. * @package PHPUnit
  39. * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
  40. * @copyright 2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
  41. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  42. * @version SVN: $Id: Command.php 4686 2009-02-25 15:28:47Z sb $
  43. * @link http://www.phpunit.de/
  44. * @since File available since Release 3.0.0
  45. */
  46. require_once 'PHPUnit/TextUI/TestRunner.php';
  47. require_once 'PHPUnit/Util/Configuration.php';
  48. require_once 'PHPUnit/Util/Fileloader.php';
  49. require_once 'PHPUnit/Util/Filter.php';
  50. require_once 'PHPUnit/Util/Getopt.php';
  51. PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
  52. /**
  53. * A TestRunner for the Command Line Interface (CLI)
  54. * PHP SAPI Module.
  55. *
  56. * @category Testing
  57. * @package PHPUnit
  58. * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
  59. * @copyright 2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
  60. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  61. * @version Release: @package_version@
  62. * @link http://www.phpunit.de/
  63. * @since Class available since Release 3.0.0
  64. */
  65. class PHPUnit_TextUI_Command
  66. {
  67. /**
  68. */
  69. public static function main($exit = TRUE)
  70. {
  71. $arguments = self::handleArguments();
  72. $runner = new PHPUnit_TextUI_TestRunner;
  73. if (is_object($arguments['test']) && $arguments['test'] instanceof PHPUnit_Framework_Test) {
  74. $suite = $arguments['test'];
  75. } else {
  76. $suite = $runner->getTest(
  77. $arguments['test'],
  78. $arguments['testFile'],
  79. $arguments['syntaxCheck']
  80. );
  81. }
  82. if ($suite->testAt(0) instanceof PHPUnit_Framework_Warning &&
  83. strpos($suite->testAt(0)->getMessage(), 'No tests found in class') !== FALSE) {
  84. $message = $suite->testAt(0)->getMessage();
  85. $start = strpos($message, '"') + 1;
  86. $end = strpos($message, '"', $start);
  87. $className = substr($message, $start, $end - $start);
  88. require_once 'PHPUnit/Util/Skeleton/Test.php';
  89. $skeleton = new PHPUnit_Util_Skeleton_Test(
  90. $className,
  91. $arguments['testFile']
  92. );
  93. $result = $skeleton->generate(TRUE);
  94. if (!$result['incomplete']) {
  95. eval(str_replace(array('<?php', '?>'), '', $result['code']));
  96. $suite = new PHPUnit_Framework_TestSuite($arguments['test'] . 'Test');
  97. }
  98. }
  99. if ($arguments['listGroups']) {
  100. PHPUnit_TextUI_TestRunner::printVersionString();
  101. print "Available test group(s):\n";
  102. $groups = $suite->getGroups();
  103. sort($groups);
  104. foreach ($groups as $group) {
  105. print " - $group\n";
  106. }
  107. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  108. }
  109. try {
  110. $result = $runner->doRun(
  111. $suite,
  112. $arguments
  113. );
  114. }
  115. catch (Exception $e) {
  116. throw new RuntimeException(
  117. 'Could not create and run test suite: ' . $e->getMessage()
  118. );
  119. }
  120. if ($exit) {
  121. if ($result->wasSuccessful()) {
  122. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  123. }
  124. else if ($result->errorCount() > 0) {
  125. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  126. }
  127. else {
  128. exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
  129. }
  130. }
  131. }
  132. /**
  133. */
  134. protected static function handleArguments()
  135. {
  136. $arguments = array(
  137. 'listGroups' => FALSE,
  138. 'syntaxCheck' => TRUE
  139. );
  140. $longOptions = array(
  141. 'ansi',
  142. 'colors',
  143. 'bootstrap=',
  144. 'configuration=',
  145. 'coverage-html=',
  146. 'coverage-clover=',
  147. 'coverage-source=',
  148. 'coverage-xml=',
  149. 'debug',
  150. 'exclude-group=',
  151. 'filter=',
  152. 'group=',
  153. 'help',
  154. 'list-groups',
  155. 'loader=',
  156. 'log-graphviz=',
  157. 'log-json=',
  158. 'log-metrics=',
  159. 'log-pmd=',
  160. 'log-tap=',
  161. 'log-xml=',
  162. 'repeat=',
  163. 'report=',
  164. 'skeleton',
  165. 'skeleton-class',
  166. 'skeleton-test',
  167. 'stop-on-failure',
  168. 'story',
  169. 'story-html=',
  170. 'story-text=',
  171. 'tap',
  172. 'test-db-dsn=',
  173. 'test-db-log-rev=',
  174. 'test-db-log-prefix=',
  175. 'test-db-log-info=',
  176. 'testdox',
  177. 'testdox-html=',
  178. 'testdox-text=',
  179. 'no-syntax-check',
  180. 'verbose',
  181. 'version',
  182. 'wait'
  183. );
  184. try {
  185. $options = PHPUnit_Util_Getopt::getopt(
  186. $_SERVER['argv'],
  187. 'd:',
  188. $longOptions
  189. );
  190. }
  191. catch (RuntimeException $e) {
  192. PHPUnit_TextUI_TestRunner::showError($e->getMessage());
  193. }
  194. if (isset($options[1][0])) {
  195. $arguments['test'] = $options[1][0];
  196. }
  197. if (isset($options[1][1])) {
  198. $arguments['testFile'] = $options[1][1];
  199. } else {
  200. $arguments['testFile'] = '';
  201. }
  202. if (isset($arguments['test']) && is_file($arguments['test'])) {
  203. $arguments['testFile'] = realpath($arguments['test']);
  204. $arguments['test'] = substr($arguments['test'], 0, strrpos($arguments['test'], '.'));
  205. }
  206. $skeletonClass = FALSE;
  207. $skeletonTest = FALSE;
  208. foreach ($options[0] as $option) {
  209. switch ($option[0]) {
  210. case '--ansi':
  211. case '--colors': {
  212. $arguments['colors'] = TRUE;
  213. }
  214. break;
  215. case '--bootstrap': {
  216. $arguments['bootstrap'] = $option[1];
  217. }
  218. break;
  219. case '--configuration': {
  220. $arguments['configuration'] = $option[1];
  221. }
  222. break;
  223. case '--coverage-clover':
  224. case '--coverage-xml': {
  225. if (extension_loaded('tokenizer') && extension_loaded('xdebug')) {
  226. $arguments['coverageClover'] = $option[1];
  227. } else {
  228. if (!extension_loaded('tokenizer')) {
  229. self::showMissingDependency('The tokenizer extension is not loaded.');
  230. } else {
  231. self::showMissingDependency('The Xdebug extension is not loaded.');
  232. }
  233. }
  234. }
  235. break;
  236. case '--coverage-source': {
  237. if (extension_loaded('tokenizer') && extension_loaded('xdebug')) {
  238. $arguments['coverageSource'] = $option[1];
  239. } else {
  240. if (!extension_loaded('tokenizer')) {
  241. self::showMissingDependency('The tokenizer extension is not loaded.');
  242. } else {
  243. self::showMissingDependency('The Xdebug extension is not loaded.');
  244. }
  245. }
  246. }
  247. break;
  248. case '--coverage-html':
  249. case '--report': {
  250. if (extension_loaded('tokenizer') && extension_loaded('xdebug')) {
  251. $arguments['reportDirectory'] = $option[1];
  252. } else {
  253. if (!extension_loaded('tokenizer')) {
  254. self::showMissingDependency('The tokenizer extension is not loaded.');
  255. } else {
  256. self::showMissingDependency('The Xdebug extension is not loaded.');
  257. }
  258. }
  259. }
  260. break;
  261. case 'd': {
  262. $ini = explode('=', $option[1]);
  263. if (isset($ini[0])) {
  264. if (isset($ini[1])) {
  265. ini_set($ini[0], $ini[1]);
  266. } else {
  267. ini_set($ini[0], TRUE);
  268. }
  269. }
  270. }
  271. break;
  272. case '--debug': {
  273. $arguments['debug'] = TRUE;
  274. }
  275. break;
  276. case '--help': {
  277. self::showHelp();
  278. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  279. }
  280. break;
  281. case '--filter': {
  282. $arguments['filter'] = $option[1];
  283. }
  284. break;
  285. case '--group': {
  286. $arguments['groups'] = explode(',', $option[1]);
  287. }
  288. break;
  289. case '--exclude-group': {
  290. $arguments['excludeGroups'] = explode(',', $option[1]);
  291. }
  292. break;
  293. case '--list-groups': {
  294. $arguments['listGroups'] = TRUE;
  295. }
  296. break;
  297. case '--loader': {
  298. self::handleLoader($option[1]);
  299. }
  300. break;
  301. case '--log-json': {
  302. $arguments['jsonLogfile'] = $option[1];
  303. }
  304. break;
  305. case '--log-graphviz': {
  306. if (PHPUnit_Util_Filesystem::fileExistsInIncludePath('Image/GraphViz.php')) {
  307. $arguments['graphvizLogfile'] = $option[1];
  308. } else {
  309. self::showMissingDependency('The Image_GraphViz package is not installed.');
  310. }
  311. }
  312. break;
  313. case '--log-tap': {
  314. $arguments['tapLogfile'] = $option[1];
  315. }
  316. break;
  317. case '--log-xml': {
  318. $arguments['xmlLogfile'] = $option[1];
  319. }
  320. break;
  321. case '--log-pmd': {
  322. if (extension_loaded('tokenizer') && extension_loaded('xdebug')) {
  323. $arguments['pmdXML'] = $option[1];
  324. } else {
  325. if (!extension_loaded('tokenizer')) {
  326. self::showMissingDependency('The tokenizer extension is not loaded.');
  327. } else {
  328. self::showMissingDependency('The Xdebug extension is not loaded.');
  329. }
  330. }
  331. }
  332. break;
  333. case '--log-metrics': {
  334. if (extension_loaded('tokenizer') && extension_loaded('xdebug')) {
  335. $arguments['metricsXML'] = $option[1];
  336. } else {
  337. if (!extension_loaded('tokenizer')) {
  338. self::showMissingDependency('The tokenizer extension is not loaded.');
  339. } else {
  340. self::showMissingDependency('The Xdebug extension is not loaded.');
  341. }
  342. }
  343. }
  344. break;
  345. case '--repeat': {
  346. $arguments['repeat'] = (int)$option[1];
  347. }
  348. break;
  349. case '--stop-on-failure': {
  350. $arguments['stopOnFailure'] = TRUE;
  351. }
  352. break;
  353. case '--test-db-dsn': {
  354. if (extension_loaded('pdo')) {
  355. $arguments['testDatabaseDSN'] = $option[1];
  356. } else {
  357. self::showMissingDependency('The PDO extension is not loaded.');
  358. }
  359. }
  360. break;
  361. case '--test-db-log-rev': {
  362. if (extension_loaded('pdo')) {
  363. $arguments['testDatabaseLogRevision'] = $option[1];
  364. } else {
  365. self::showMissingDependency('The PDO extension is not loaded.');
  366. }
  367. }
  368. break;
  369. case '--test-db-prefix': {
  370. if (extension_loaded('pdo')) {
  371. $arguments['testDatabasePrefix'] = $option[1];
  372. } else {
  373. self::showMissingDependency('The PDO extension is not loaded.');
  374. }
  375. }
  376. break;
  377. case '--test-db-log-info': {
  378. if (extension_loaded('pdo')) {
  379. $arguments['testDatabaseLogInfo'] = $option[1];
  380. } else {
  381. self::showMissingDependency('The PDO extension is not loaded.');
  382. }
  383. }
  384. break;
  385. case '--skeleton':
  386. case '--skeleton-test': {
  387. $skeletonTest = TRUE;
  388. $skeletonClass = FALSE;
  389. }
  390. break;
  391. case '--skeleton-class': {
  392. $skeletonClass = TRUE;
  393. $skeletonTest = FALSE;
  394. }
  395. break;
  396. case '--tap': {
  397. require_once 'PHPUnit/Util/Log/TAP.php';
  398. $arguments['printer'] = new PHPUnit_Util_Log_TAP;
  399. }
  400. break;
  401. case '--story': {
  402. require_once 'PHPUnit/Extensions/Story/ResultPrinter/Text.php';
  403. $arguments['printer'] = new PHPUnit_Extensions_Story_ResultPrinter_Text;
  404. }
  405. break;
  406. case '--story-html': {
  407. $arguments['storyHTMLFile'] = $option[1];
  408. }
  409. break;
  410. case '--story-text': {
  411. $arguments['storyTextFile'] = $option[1];
  412. }
  413. break;
  414. case '--testdox': {
  415. require_once 'PHPUnit/Util/TestDox/ResultPrinter/Text.php';
  416. $arguments['printer'] = new PHPUnit_Util_TestDox_ResultPrinter_Text;
  417. }
  418. break;
  419. case '--testdox-html': {
  420. $arguments['testdoxHTMLFile'] = $option[1];
  421. }
  422. break;
  423. case '--testdox-text': {
  424. $arguments['testdoxTextFile'] = $option[1];
  425. }
  426. break;
  427. case '--no-syntax-check': {
  428. $arguments['syntaxCheck'] = FALSE;
  429. }
  430. break;
  431. case '--verbose': {
  432. $arguments['verbose'] = TRUE;
  433. }
  434. break;
  435. case '--version': {
  436. PHPUnit_TextUI_TestRunner::printVersionString();
  437. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  438. }
  439. break;
  440. case '--wait': {
  441. $arguments['wait'] = TRUE;
  442. }
  443. break;
  444. }
  445. }
  446. if (isset($arguments['bootstrap'])) {
  447. PHPUnit_Util_Fileloader::load($arguments['bootstrap']);
  448. }
  449. if (!isset($arguments['configuration']) && file_exists('phpunit.xml')) {
  450. $arguments['configuration'] = realpath('phpunit.xml');
  451. }
  452. if (isset($arguments['configuration'])) {
  453. $configuration = new PHPUnit_Util_Configuration(
  454. $arguments['configuration']
  455. );
  456. $configuration->handlePHPConfiguration();
  457. if (!isset($arguments['bootstrap'])) {
  458. $phpunitConfiguration = $configuration->getPHPUnitConfiguration();
  459. if (isset($phpunitConfiguration['bootstrap'])) {
  460. PHPUnit_Util_Fileloader::load($phpunitConfiguration['bootstrap']);
  461. }
  462. }
  463. $browsers = $configuration->getSeleniumBrowserConfiguration();
  464. if (!empty($browsers)) {
  465. require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
  466. PHPUnit_Extensions_SeleniumTestCase::$browsers = $browsers;
  467. }
  468. if (!isset($arguments['test'])) {
  469. $testSuite = $configuration->getTestSuiteConfiguration(
  470. $arguments['syntaxCheck']
  471. );
  472. if ($testSuite !== NULL) {
  473. $arguments['test'] = $testSuite;
  474. }
  475. }
  476. }
  477. if (isset($arguments['test']) && is_string($arguments['test']) && substr($arguments['test'], -5, 5) == '.phpt') {
  478. require_once 'PHPUnit/Extensions/PhptTestCase.php';
  479. $test = new PHPUnit_Extensions_PhptTestCase($arguments['test']);
  480. $arguments['test'] = new PHPUnit_Framework_TestSuite;
  481. $arguments['test']->addTest($test);
  482. }
  483. if (!isset($arguments['test']) ||
  484. (isset($arguments['testDatabaseLogRevision']) && !isset($arguments['testDatabaseDSN']))) {
  485. self::showHelp();
  486. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  487. }
  488. if ($skeletonClass || $skeletonTest) {
  489. if (isset($arguments['test']) && $arguments['test'] !== FALSE) {
  490. PHPUnit_TextUI_TestRunner::printVersionString();
  491. if ($skeletonClass) {
  492. require_once 'PHPUnit/Util/Skeleton/Class.php';
  493. $class = 'PHPUnit_Util_Skeleton_Class';
  494. } else {
  495. require_once 'PHPUnit/Util/Skeleton/Test.php';
  496. $class = 'PHPUnit_Util_Skeleton_Test';
  497. }
  498. try {
  499. $args = array();
  500. $reflector = new ReflectionClass($class);
  501. for ($i = 0; $i <= 3; $i++) {
  502. if (isset($options[1][$i])) {
  503. $args[] = $options[1][$i];
  504. }
  505. }
  506. $skeleton = $reflector->newInstanceArgs($args);
  507. $skeleton->write();
  508. }
  509. catch (Exception $e) {
  510. print $e->getMessage() . "\n";
  511. exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
  512. }
  513. printf(
  514. 'Wrote skeleton for "%s" to "%s".' . "\n",
  515. $skeleton->getOutClassName(),
  516. $skeleton->getOutSourceFile()
  517. );
  518. exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
  519. } else {
  520. self::showHelp();
  521. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  522. }
  523. }
  524. return $arguments;
  525. }
  526. /**
  527. * @param string $loaderName
  528. */
  529. protected static function handleLoader($loaderName)
  530. {
  531. if (!class_exists($loaderName, FALSE)) {
  532. PHPUnit_Util_Fileloader::checkAndLoad(
  533. str_replace('_', '/', $loaderName) . '.php'
  534. );
  535. }
  536. if (class_exists($loaderName, FALSE)) {
  537. $class = new ReflectionClass($loaderName);
  538. if ($class->implementsInterface('PHPUnit_Runner_TestSuiteLoader') &&
  539. $class->isInstantiable()) {
  540. $loader = $class->newInstance();
  541. }
  542. }
  543. if (!isset($loader)) {
  544. PHPUnit_TextUI_TestRunner::showError(
  545. sprintf(
  546. 'Could not use "%s" as loader.',
  547. $loaderName
  548. )
  549. );
  550. }
  551. PHPUnit_TextUI_TestRunner::setLoader($loader);
  552. }
  553. /**
  554. * @param string $message
  555. */
  556. public static function showMissingDependency($message)
  557. {
  558. PHPUnit_TextUI_TestRunner::printVersionString();
  559. print $message . "\n";
  560. exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
  561. }
  562. /**
  563. */
  564. public static function showHelp()
  565. {
  566. PHPUnit_TextUI_TestRunner::printVersionString();
  567. print <<<EOT
  568. Usage: phpunit [switches] UnitTest [UnitTest.php]
  569. phpunit [switches] <directory>
  570. --log-graphviz <file> Log test execution in GraphViz markup.
  571. --log-json <file> Log test execution in JSON format.
  572. --log-tap <file> Log test execution in TAP format to file.
  573. --log-xml <file> Log test execution in XML format to file.
  574. --log-metrics <file> Write metrics report in XML format.
  575. --log-pmd <file> Write violations report in PMD XML format.
  576. --coverage-html <dir> Generate code coverage report in HTML format.
  577. --coverage-clover <file> Write code coverage data in Clover XML format.
  578. --coverage-source <dir> Write code coverage / source data in XML format.
  579. --test-db-dsn <dsn> DSN for the test database.
  580. --test-db-log-rev <rev> Revision information for database logging.
  581. --test-db-prefix ... Prefix that should be stripped from filenames.
  582. --test-db-log-info ... Additional information for database logging.
  583. --story-html <file> Write Story/BDD results in HTML format to file.
  584. --story-text <file> Write Story/BDD results in Text format to file.
  585. --testdox-html <file> Write agile documentation in HTML format to file.
  586. --testdox-text <file> Write agile documentation in Text format to file.
  587. --filter <pattern> Filter which tests to run.
  588. --group ... Only runs tests from the specified group(s).
  589. --exclude-group ... Exclude tests from the specified group(s).
  590. --list-groups List available test groups.
  591. --loader <loader> TestSuiteLoader implementation to use.
  592. --repeat <times> Runs the test(s) repeatedly.
  593. --story Report test execution progress in Story/BDD format.
  594. --tap Report test execution progress in TAP format.
  595. --testdox Report test execution progress in TestDox format.
  596. --no-syntax-check Disable syntax check of test source files.
  597. --stop-on-failure Stop execution upon first error or failure.
  598. --colors Use colors in output.
  599. --verbose Output more verbose information.
  600. --wait Waits for a keystroke after each test.
  601. --skeleton-class Generate Unit class for UnitTest in UnitTest.php.
  602. --skeleton-test Generate UnitTest class for Unit in Unit.php.
  603. --help Prints this usage information.
  604. --version Prints the version and exits.
  605. --bootstrap <file> A "bootstrap" PHP file that is run before the tests.
  606. --configuration <file> Read configuration from XML file.
  607. -d key[=value] Sets a php.ini value.
  608. EOT;
  609. }
  610. }
  611. ?>