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

/vendor/codeception/codeception/src/Codeception/Subscriber/Console.php

https://gitlab.com/jhonn/rest
PHP | 402 lines | 340 code | 49 blank | 13 comment | 32 complexity | 6411a3e1d0701271a342e434fff1791f MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. namespace Codeception\Subscriber;
  3. use Codeception\Events;
  4. use Codeception\Event\FailEvent;
  5. use Codeception\Event\StepEvent;
  6. use Codeception\Event\SuiteEvent;
  7. use Codeception\Event\TestEvent;
  8. use Codeception\Exception\ConditionalAssertionFailed;
  9. use Codeception\SuiteManager;
  10. use Codeception\TestCase\Interfaces\ScenarioDriven;
  11. use Codeception\TestCase;
  12. use Codeception\Lib\Console\Message;
  13. use Codeception\Lib\Console\Output;
  14. use Codeception\Util\Debug;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Component\Console\Output\OutputInterface;
  17. class Console implements EventSubscriberInterface
  18. {
  19. use Shared\StaticEvents;
  20. static $events = [
  21. Events::SUITE_BEFORE => 'beforeSuite',
  22. Events::SUITE_AFTER => 'afterSuite',
  23. Events::TEST_BEFORE => 'before',
  24. Events::TEST_AFTER => 'afterTest',
  25. Events::TEST_START => 'startTest',
  26. Events::TEST_END => 'endTest',
  27. Events::STEP_BEFORE => 'beforeStep',
  28. Events::STEP_AFTER => 'afterStep',
  29. Events::TEST_SUCCESS => 'testSuccess',
  30. Events::TEST_FAIL => 'testFail',
  31. Events::TEST_ERROR => 'testError',
  32. Events::TEST_INCOMPLETE => 'testIncomplete',
  33. Events::TEST_SKIPPED => 'testSkipped',
  34. Events::TEST_FAIL_PRINT => 'printFail',
  35. ];
  36. protected $steps = true;
  37. protected $debug = false;
  38. protected $color = true;
  39. protected $silent = false;
  40. protected $lastTestFailed = false;
  41. protected $printedTest = null;
  42. protected $rawStackTrace = false;
  43. protected $traceLength = 5;
  44. protected $columns = array(40, 5);
  45. public function __construct($options)
  46. {
  47. $this->debug = $options['debug'] || $options['verbosity'] >= OutputInterface::VERBOSITY_VERY_VERBOSE;
  48. $this->steps = $this->debug || $options['steps'];
  49. $this->rawStackTrace = ($options['verbosity'] === OutputInterface::VERBOSITY_DEBUG);
  50. $this->output = new Output($options);
  51. if ($this->debug) {
  52. Debug::setOutput($this->output);
  53. }
  54. }
  55. // triggered for scenario based tests: cept, cest
  56. public function beforeSuite(SuiteEvent $e)
  57. {
  58. $this->buildResultsTable($e);
  59. $this->message("%s Tests (%d) ")
  60. ->with(ucfirst($e->getSuite()->getName()), count($e->getSuite()->tests()))
  61. ->style('bold')
  62. ->width(array_sum($this->columns), '-')
  63. ->prepend("\n")
  64. ->writeln();
  65. $message = $this->message(implode(', ',array_map(function ($module) {
  66. return $module->_getName();
  67. }, SuiteManager::$modules)));
  68. $message->style('info')
  69. ->prepend('Modules: ')
  70. ->writeln(OutputInterface::VERBOSITY_VERBOSE);
  71. $this->message('')->width(array_sum($this->columns), '-')->writeln(OutputInterface::VERBOSITY_VERBOSE);
  72. }
  73. // triggered for all tests
  74. public function startTest(TestEvent $e)
  75. {
  76. $test = $e->getTest();
  77. $this->printedTest = $test;
  78. if ($test instanceof TestCase) {
  79. return;
  80. }
  81. $this->message($test->toString())
  82. ->style('focus')
  83. ->prepend('Running ')
  84. ->width($this->columns[0])
  85. ->write();
  86. }
  87. public function before(TestEvent $e)
  88. {
  89. $test = $e->getTest();
  90. $filename = $test->getSignature();
  91. if ($test->getFeature()) {
  92. $this->message("Trying to <focus>%s</focus> (%s) ")
  93. ->with($test->getFeature(), $filename)
  94. ->width($this->columns[0])
  95. ->write();
  96. } else {
  97. $this->message("Running <focus>%s</focus> ")
  98. ->with($filename)
  99. ->width($this->columns[0])
  100. ->write();
  101. }
  102. if ($this->steps && $this->isDetailed($test)) {
  103. $this->output->writeln("\nScenario:");
  104. }
  105. }
  106. public function afterTest(TestEvent $e)
  107. {
  108. }
  109. public function testSuccess(TestEvent $e)
  110. {
  111. if ($this->isDetailed($e->getTest())) {
  112. $this->message('PASSED')->center(' ')->style('ok')->append("\n")->writeln();
  113. return;
  114. }
  115. $this->message('Ok')->writeln();
  116. }
  117. public function endTest(TestEvent $e)
  118. {
  119. $this->printedTest = null;
  120. }
  121. public function testFail(FailEvent $e)
  122. {
  123. if (!$this->steps && ($e->getFail() instanceof ConditionalAssertionFailed)) {
  124. $this->message('[F]')->style('error')->prepend(' ')->write();
  125. return;
  126. }
  127. if ($this->isDetailed($e->getTest())) {
  128. $this->message('FAIL')->center(' ')->style('error')->append("\n")->writeln();
  129. return;
  130. }
  131. $this->message('Fail')->style('error')->writeln();
  132. }
  133. public function testError(FailEvent $e)
  134. {
  135. if ($this->isDetailed($e->getTest())) {
  136. $this->message('ERROR')->center(' ')->style('error')->append("\n")->writeln();
  137. return;
  138. }
  139. $this->message('Error')->style('error')->writeln();
  140. }
  141. public function testSkipped(FailEvent $e)
  142. {
  143. if (!$this->printedTest) {
  144. return;
  145. }
  146. $message = $this->message('Skipped');
  147. if ($this->isDetailed($e->getTest())) {
  148. $message->apply('strtoupper')->append("\n");
  149. }
  150. $message->writeln();
  151. }
  152. public function testIncomplete(FailEvent $e)
  153. {
  154. $message = $this->message('Incomplete');
  155. if ($this->isDetailed($e->getTest())) {
  156. $message->apply('strtoupper')->append("\n");
  157. }
  158. $message->writeln();
  159. }
  160. protected function isDetailed($test)
  161. {
  162. if ($test instanceof ScenarioDriven && $this->steps) {
  163. return !$test->getScenario()->isBlocked();
  164. };
  165. return false;
  166. }
  167. public function beforeStep(StepEvent $e)
  168. {
  169. if (!$this->steps or !$e->getTest() instanceof ScenarioDriven) {
  170. return;
  171. }
  172. $this->output->writeln("* " . $e->getStep());
  173. }
  174. public function afterStep(StepEvent $e)
  175. {
  176. }
  177. public function afterSuite(SuiteEvent $e)
  178. {
  179. $this->message()->width(array_sum($this->columns), '-')->writeln();
  180. }
  181. public function printFail(FailEvent $e)
  182. {
  183. $failedTest = $e->getTest();
  184. $fail = $e->getFail();
  185. $this->output->write($e->getCount() . ") ");
  186. if ($e->getTest() instanceof ScenarioDriven) {
  187. $this->printScenarioFail($failedTest, $fail);
  188. return;
  189. }
  190. $failToString = \PHPUnit_Framework_TestFailure::exceptionToString($fail);
  191. $this->message(get_class($failedTest))
  192. ->append('::')
  193. ->append($failedTest->getName())
  194. ->style('bold')
  195. ->append("\n")
  196. ->append($failToString)
  197. ->writeln();
  198. $this->printException($fail);
  199. }
  200. protected function printScenarioFail(ScenarioDriven $failedTest, $fail)
  201. {
  202. $feature = $failedTest->getFeature();
  203. $failToString = \PHPUnit_Framework_TestFailure::exceptionToString($fail);
  204. $failMessage = $this->message($failedTest->getSignature())
  205. ->style('bold')
  206. ->append(' (')
  207. ->append($failedTest->getFileName())
  208. ->append(')');
  209. if ($fail instanceof \PHPUnit_Framework_SkippedTest
  210. or $fail instanceof \PHPUnit_Framework_IncompleteTest
  211. ) {
  212. $this->printSkippedTest($feature, $failedTest->getFileName(), $failToString);
  213. return;
  214. }
  215. if ($feature) {
  216. $failMessage->prepend("Failed to $feature in ");
  217. }
  218. $failMessage->writeln();
  219. $this->printScenarioTrace($failedTest, $failToString);
  220. if ($this->output->getVerbosity() == OutputInterface::VERBOSITY_DEBUG) {
  221. $this->printException($fail);
  222. return;
  223. }
  224. if (!$fail instanceof \PHPUnit_Framework_AssertionFailedError) {
  225. $this->printException($fail);
  226. return;
  227. }
  228. }
  229. public function printException(\Exception $e)
  230. {
  231. static $limit = 10;
  232. $this->message("[%s] %s")->with(get_class($e), $e->getMessage())->block('error')->writeln(
  233. $e instanceof \PHPUnit_Framework_AssertionFailedError
  234. ? OutputInterface::VERBOSITY_DEBUG
  235. : OutputInterface::VERBOSITY_VERBOSE
  236. );
  237. if ($this->rawStackTrace) {
  238. $this->message($e->getTraceAsString())->writeln();
  239. return;
  240. }
  241. $trace = \PHPUnit_Util_Filter::getFilteredStacktrace($e, false);
  242. $i = 0;
  243. foreach ($trace as $step) {
  244. $i++;
  245. $message = $this->message($i)->prepend('#')->width(4);
  246. $message->append($step['file'] . ':' . $step['line']);
  247. $message->writeln();
  248. if ($i >= $limit) {
  249. break;
  250. }
  251. }
  252. $prev = $e->getPrevious();
  253. if ($prev) {
  254. $this->printException($prev);
  255. }
  256. }
  257. protected function message($text = '')
  258. {
  259. return new Message($text, $this->output);
  260. }
  261. /**
  262. * Sample Message: create user in CreateUserCept.php is not ready for release
  263. *
  264. * @param $feature
  265. * @param $fileName
  266. * @param $failToString
  267. */
  268. public function printSkippedTest($feature, $fileName, $failToString)
  269. {
  270. $message = $this->message();
  271. if ($feature) {
  272. $message->append($feature)->style('focus')->append(' in ');
  273. }
  274. $message->append($fileName);
  275. if ($failToString) {
  276. $message->append(": $failToString");
  277. }
  278. $message->write(OutputInterface::VERBOSITY_VERBOSE);
  279. }
  280. /**
  281. * @param $action
  282. * @param $failToString
  283. */
  284. public function printFailMessage($action, $failToString)
  285. {
  286. if (strpos($action, "don't") === 0) {
  287. $action = substr($action, 6);
  288. $this->output->writeln("Unexpectedly managed to $action:\n$failToString");
  289. } elseif (strpos($action, 'am ') === 0) {
  290. $action = substr($action, 3);
  291. $this->output->writeln("Can't be $action:\n$failToString");
  292. } else {
  293. $this->output->writeln("Couldn't $action:\n$failToString");
  294. }
  295. }
  296. /**
  297. * @param $failedTest
  298. * @param $fail
  299. */
  300. public function printScenarioTrace($failedTest, $failToString)
  301. {
  302. $trace = array_reverse($failedTest->getTrace());
  303. $length = $i = count($trace);
  304. $last = array_shift($trace);
  305. if (!method_exists($last, 'getHumanizedAction')) {
  306. return;
  307. }
  308. $this->printFailMessage($last->getHumanizedAction(), $failToString);
  309. $this->output->writeln("Scenario Steps:");
  310. $this->message($last)->style('error')->prepend("$i. ")->writeln();
  311. foreach ($trace as $step) {
  312. $i--;
  313. $this->message($i)->width(strlen($length))->append(". $step")->writeln();
  314. if (($length - $i - 1) >= $this->traceLength) {
  315. break;
  316. }
  317. }
  318. $this->output->writeln("");
  319. }
  320. /**
  321. * @param SuiteEvent $e
  322. */
  323. protected function buildResultsTable(SuiteEvent $e)
  324. {
  325. $this->columns = array(40, 5);
  326. foreach ($e->getSuite()->tests() as $test) {
  327. if ($test instanceof TestCase) {
  328. $this->columns[0] = max(
  329. $this->columns[0],
  330. 20 + strlen($test->getFeature()) + strlen($test->getFileName())
  331. );
  332. continue;
  333. }
  334. if ($test instanceof \PHPUnit_Framework_TestSuite_DataProvider) {
  335. $test = $test->testAt(0);
  336. $output_length = $test instanceof \Codeception\TestCase
  337. ? strlen($test->getFeature()) + strlen($test->getFileName())
  338. : $test->toString();
  339. $this->columns[0] = max(
  340. $this->columns[0],
  341. 15 +$output_length
  342. );
  343. continue;
  344. }
  345. $this->columns[0] = max($this->columns[0], 10 + strlen($test->toString()));
  346. }
  347. }
  348. }