LimeOutputConsoleSummary.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. /*
  3. * This file is part of the Lime test framework.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. * (c) Bernhard Schussek <bernhard.schussek@symfony-project.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. /**
  12. * Colorizes test results and summarizes them in the console.
  13. *
  14. * For each test file, one line is printed in the console with a few optional
  15. * lines in case the file contains errors or failed tests.
  16. *
  17. * @package Lime
  18. * @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
  19. * @version SVN: $Id: LimeOutputConsoleSummary.php 23701 2009-11-08 21:23:40Z bschussek $
  20. */
  21. class LimeOutputConsoleSummary implements LimeOutputInterface
  22. {
  23. protected
  24. $printer = null,
  25. $options = array(),
  26. $startTime = 0,
  27. $file = null,
  28. $actualFiles = 0,
  29. $failedFiles = 0,
  30. $actualTests = 0,
  31. $failedTests = 0,
  32. $expected = array(),
  33. $actual = array(),
  34. $passed = array(),
  35. $failed = array(),
  36. $errors = array(),
  37. $warnings = array(),
  38. $todos = array(),
  39. $line = array();
  40. /**
  41. * Constructor.
  42. *
  43. * @param LimePrinter $printer The printer for printing text to the console
  44. * @param array $options The options of this output
  45. */
  46. public function __construct(LimePrinter $printer, array $options = array())
  47. {
  48. $this->printer = $printer;
  49. $this->startTime = time();
  50. $this->options = array_merge(array(
  51. 'base_dir' => null,
  52. 'processes' => 1,
  53. 'verbose' => false,
  54. ), $options);
  55. }
  56. public function supportsThreading()
  57. {
  58. return true;
  59. }
  60. public function focus($file)
  61. {
  62. $this->file = $file;
  63. if (!array_key_exists($file, $this->line))
  64. {
  65. $this->line[$file] = count($this->line);
  66. $this->expected[$file] = 0;
  67. $this->actual[$file] = 0;
  68. $this->passed[$file] = 0;
  69. $this->failed[$file] = array();
  70. $this->errors[$file] = array();
  71. $this->warnings[$file] = array();
  72. $this->todos[$file] = array();
  73. }
  74. }
  75. public function close()
  76. {
  77. if (!is_null($this->file))
  78. {
  79. $this->actualFiles++;
  80. $this->actualTests += $this->getActual();
  81. $this->failedTests += $this->getFailed();
  82. $path = $this->truncate($this->file);
  83. if (strlen($path) > 71)
  84. {
  85. $path = substr($path, -71);
  86. }
  87. $this->printer->printText(str_pad($path, 73, '.'));
  88. $incomplete = ($this->getExpected() > 0 && $this->getActual() != $this->getExpected());
  89. if ($this->getErrors() || $this->getFailed() || $incomplete)
  90. {
  91. $this->failedFiles++;
  92. $this->printer->printLine("not ok", LimePrinter::NOT_OK);
  93. }
  94. else if ($this->getWarnings())
  95. {
  96. $this->printer->printLine("warning", LimePrinter::WARNING);
  97. }
  98. else
  99. {
  100. $this->printer->printLine("ok", LimePrinter::OK);
  101. }
  102. if ($this->getExpected() > 0 && $this->getActual() != $this->getExpected())
  103. {
  104. $this->printer->printLine(' Plan Mismatch:', LimePrinter::COMMENT);
  105. if ($this->getActual() > $this->getExpected())
  106. {
  107. $this->printer->printLine(sprintf(' Looks like you only planned %s tests but ran %s.', $this->getExpected(), $this->getActual()));
  108. }
  109. else
  110. {
  111. $this->printer->printLine(sprintf(' Looks like you planned %s tests but only ran %s.', $this->getExpected(), $this->getActual()));
  112. }
  113. }
  114. if ($this->getFailed())
  115. {
  116. $this->printer->printLine(' Failed Tests:', LimePrinter::COMMENT);
  117. $i = 0;
  118. foreach ($this->failed[$this->file] as $number => $failed)
  119. {
  120. if (!$this->options['verbose'] && $i > 2)
  121. {
  122. $this->printer->printLine(sprintf(' ... and %s more', $this->getFailed()-$i));
  123. break;
  124. }
  125. ++$i;
  126. $this->printer->printLine(' not ok '.$number.' - '.$failed[0]);
  127. }
  128. }
  129. if ($this->getWarnings())
  130. {
  131. $this->printer->printLine(' Warnings:', LimePrinter::COMMENT);
  132. foreach ($this->warnings[$this->file] as $i => $warning)
  133. {
  134. if (!$this->options['verbose'] && $i > 2)
  135. {
  136. $this->printer->printLine(sprintf(' ... and %s more', $this->getWarnings()-$i));
  137. break;
  138. }
  139. $this->printer->printLine(' '.$warning[0]);
  140. if ($this->options['verbose'])
  141. {
  142. $this->printer->printText(' (in ');
  143. $this->printer->printText($this->truncate($warning[1]), LimePrinter::TRACE);
  144. $this->printer->printText(' on line ');
  145. $this->printer->printText($warning[2], LimePrinter::TRACE);
  146. $this->printer->printLine(')');
  147. }
  148. }
  149. }
  150. if ($this->getErrors())
  151. {
  152. $this->printer->printLine(' Errors:', LimePrinter::COMMENT);
  153. foreach ($this->errors[$this->file] as $i => $error)
  154. {
  155. if (!$this->options['verbose'] && $i > 2)
  156. {
  157. $this->printer->printLine(sprintf(' ... and %s more', $this->getErrors()-$i));
  158. break;
  159. }
  160. $this->printer->printLine(' '.$error->getMessage());
  161. if ($this->options['verbose'])
  162. {
  163. $this->printer->printText(' (in ');
  164. $this->printer->printText($this->truncate($error->getFile()), LimePrinter::TRACE);
  165. $this->printer->printText(' on line ');
  166. $this->printer->printText($error->getLine(), LimePrinter::TRACE);
  167. $this->printer->printLine(')');
  168. }
  169. }
  170. }
  171. if ($this->getTodos())
  172. {
  173. $this->printer->printLine(' TODOs:', LimePrinter::COMMENT);
  174. foreach ($this->todos[$this->file] as $i => $todo)
  175. {
  176. if (!$this->options['verbose'] && $i > 2)
  177. {
  178. $this->printer->printLine(sprintf(' ... and %s more', $this->getTodos()-$i));
  179. break;
  180. }
  181. $this->printer->printLine(' '.$todo);
  182. }
  183. }
  184. }
  185. }
  186. protected function getExpected()
  187. {
  188. return $this->expected[$this->file];
  189. }
  190. protected function getActual()
  191. {
  192. return $this->actual[$this->file];
  193. }
  194. protected function getPassed()
  195. {
  196. return $this->passed[$this->file];
  197. }
  198. protected function getFailed()
  199. {
  200. return count($this->failed[$this->file]);
  201. }
  202. protected function getErrors()
  203. {
  204. return count($this->errors[$this->file]);
  205. }
  206. protected function getWarnings()
  207. {
  208. return count($this->warnings[$this->file]);
  209. }
  210. protected function getTodos()
  211. {
  212. return count($this->todos[$this->file]);
  213. }
  214. public function plan($amount)
  215. {
  216. $this->expected[$this->file] = $amount;
  217. }
  218. public function pass($message, $file, $line)
  219. {
  220. $this->passed[$this->file]++;
  221. $this->actual[$this->file]++;
  222. }
  223. public function fail($message, $file, $line, $error = null)
  224. {
  225. $this->actual[$this->file]++;
  226. $this->failed[$this->file][$this->actual[$this->file]] = array($message, $file, $line, $error);
  227. }
  228. public function skip($message, $file, $line)
  229. {
  230. $this->actual[$this->file]++;
  231. }
  232. public function todo($message, $file, $line)
  233. {
  234. $this->actual[$this->file]++;
  235. $this->todos[$this->file][] = $message;
  236. }
  237. public function warning($message, $file, $line)
  238. {
  239. $this->warnings[$this->file][] = array($message, $file, $line);
  240. }
  241. public function error(LimeError $error)
  242. {
  243. $this->errors[$this->file][] = $error;
  244. }
  245. public function comment($message) {}
  246. public function flush()
  247. {
  248. if ($this->failedFiles > 0)
  249. {
  250. $stats = sprintf(' Failed %d/%d test scripts, %.2f%% okay. %d/%d subtests failed, %.2f%% okay.',
  251. $this->failedFiles, $this->actualFiles, 100 - 100*$this->failedFiles/max(1,$this->actualFiles),
  252. $this->failedTests, $this->actualTests, 100 - 100*$this->failedTests/max(1,$this->actualTests));
  253. $this->printer->printBox($stats, LimePrinter::NOT_OK);
  254. }
  255. else
  256. {
  257. $time = max(1, time() - $this->startTime);
  258. $stats = sprintf(' Files=%d, Tests=%d, Time=%02d:%02d, Processes=%d',
  259. $this->actualFiles, $this->actualTests, floor($time/60), $time%60, $this->options['processes']);
  260. $this->printer->printBox(' All tests successful.', LimePrinter::HAPPY);
  261. $this->printer->printBox($stats, LimePrinter::HAPPY);
  262. }
  263. }
  264. protected function truncate($file)
  265. {
  266. $extension = pathinfo($file, PATHINFO_EXTENSION);
  267. $file = substr($file, 0, strlen($file)-strlen($extension));
  268. if (!is_null($this->options['base_dir']))
  269. {
  270. return str_replace($this->options['base_dir'], '', $file);
  271. }
  272. else
  273. {
  274. return $file;
  275. }
  276. }
  277. }