reporter.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. <?php
  2. /**
  3. * base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage UnitTester
  6. * @version $Id: reporter.php 1788 2008-04-27 11:01:59Z pp11 $
  7. */
  8. /**#@+
  9. * include other SimpleTest class files
  10. */
  11. require_once(dirname(__FILE__) . '/scorer.php');
  12. /**#@-*/
  13. /**
  14. * Sample minimal test displayer. Generates only
  15. * failure messages and a pass count.
  16. * @package SimpleTest
  17. * @subpackage UnitTester
  18. */
  19. class HtmlReporter extends SimpleReporter {
  20. private $character_set;
  21. /**
  22. * Does nothing yet. The first output will
  23. * be sent on the first test start. For use
  24. * by a web browser.
  25. * @access public
  26. */
  27. function __construct($character_set = 'ISO-8859-1') {
  28. parent::__construct();
  29. $this->character_set = $character_set;
  30. }
  31. /**
  32. * Paints the top of the web page setting the
  33. * title to the name of the starting test.
  34. * @param string $test_name Name class of test.
  35. * @access public
  36. */
  37. function paintHeader($test_name) {
  38. $this->sendNoCacheHeaders();
  39. print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">";
  40. print "<html>\n<head>\n<title>$test_name</title>\n";
  41. print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" .
  42. $this->character_set . "\">\n";
  43. print "<style type=\"text/css\">\n";
  44. print $this->getCss() . "\n";
  45. print "</style>\n";
  46. print "</head>\n<body>\n";
  47. print "<h1>$test_name</h1>\n";
  48. flush();
  49. }
  50. /**
  51. * Send the headers necessary to ensure the page is
  52. * reloaded on every request. Otherwise you could be
  53. * scratching your head over out of date test data.
  54. * @access public
  55. */
  56. static function sendNoCacheHeaders() {
  57. if (! headers_sent()) {
  58. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  59. header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  60. header("Cache-Control: no-store, no-cache, must-revalidate");
  61. header("Cache-Control: post-check=0, pre-check=0", false);
  62. header("Pragma: no-cache");
  63. }
  64. }
  65. /**
  66. * Paints the CSS. Add additional styles here.
  67. * @return string CSS code as text.
  68. * @access protected
  69. */
  70. protected function getCss() {
  71. return ".fail { background-color: inherit; color: red; }" .
  72. ".pass { background-color: inherit; color: green; }" .
  73. " pre { background-color: lightgray; color: inherit; }";
  74. }
  75. /**
  76. * Paints the end of the test with a summary of
  77. * the passes and failures.
  78. * @param string $test_name Name class of test.
  79. * @access public
  80. */
  81. function paintFooter($test_name) {
  82. $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green");
  83. print "<div style=\"";
  84. print "padding: 8px; margin-top: 1em; background-color: $colour; color: white;";
  85. print "\">";
  86. print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount();
  87. print " test cases complete:\n";
  88. print "<strong>" . $this->getPassCount() . "</strong> passes, ";
  89. print "<strong>" . $this->getFailCount() . "</strong> fails and ";
  90. print "<strong>" . $this->getExceptionCount() . "</strong> exceptions.";
  91. print "</div>\n";
  92. print "</body>\n</html>\n";
  93. }
  94. /**
  95. * Paints the test failure with a breadcrumbs
  96. * trail of the nesting test suites below the
  97. * top level test.
  98. * @param string $message Failure message displayed in
  99. * the context of the other tests.
  100. * @access public
  101. */
  102. function paintFail($message) {
  103. parent::paintFail($message);
  104. print "<span class=\"fail\">Fail</span>: ";
  105. $breadcrumb = $this->getTestList();
  106. array_shift($breadcrumb);
  107. print implode(" -&gt; ", $breadcrumb);
  108. print " -&gt; " . $this->htmlEntities($message) . "<br />\n";
  109. }
  110. /**
  111. * Paints a PHP error.
  112. * @param string $message Message is ignored.
  113. * @access public
  114. */
  115. function paintError($message) {
  116. parent::paintError($message);
  117. print "<span class=\"fail\">Exception</span>: ";
  118. $breadcrumb = $this->getTestList();
  119. array_shift($breadcrumb);
  120. print implode(" -&gt; ", $breadcrumb);
  121. print " -&gt; <strong>" . $this->htmlEntities($message) . "</strong><br />\n";
  122. }
  123. /**
  124. * Paints a PHP exception.
  125. * @param Exception $exception Exception to display.
  126. * @access public
  127. */
  128. function paintException($exception) {
  129. parent::paintException($exception);
  130. print "<span class=\"fail\">Exception</span>: ";
  131. $breadcrumb = $this->getTestList();
  132. array_shift($breadcrumb);
  133. print implode(" -&gt; ", $breadcrumb);
  134. $message = 'Unexpected exception of type [' . get_class($exception) .
  135. '] with message ['. $exception->getMessage() .
  136. '] in ['. $exception->getFile() .
  137. ' line ' . $exception->getLine() . ']';
  138. print " -&gt; <strong>" . $this->htmlEntities($message) . "</strong><br />\n";
  139. }
  140. /**
  141. * Prints the message for skipping tests.
  142. * @param string $message Text of skip condition.
  143. * @access public
  144. */
  145. function paintSkip($message) {
  146. parent::paintSkip($message);
  147. print "<span class=\"pass\">Skipped</span>: ";
  148. $breadcrumb = $this->getTestList();
  149. array_shift($breadcrumb);
  150. print implode(" -&gt; ", $breadcrumb);
  151. print " -&gt; " . $this->htmlEntities($message) . "<br />\n";
  152. }
  153. /**
  154. * Paints formatted text such as dumped privateiables.
  155. * @param string $message Text to show.
  156. * @access public
  157. */
  158. function paintFormattedMessage($message) {
  159. print '<pre>' . $this->htmlEntities($message) . '</pre>';
  160. }
  161. /**
  162. * Character set adjusted entity conversion.
  163. * @param string $message Plain text or Unicode message.
  164. * @return string Browser readable message.
  165. * @access protected
  166. */
  167. protected function htmlEntities($message) {
  168. return htmlentities($message, ENT_COMPAT, $this->character_set);
  169. }
  170. }
  171. /**
  172. * Sample minimal test displayer. Generates only
  173. * failure messages and a pass count. For command
  174. * line use. I've tried to make it look like JUnit,
  175. * but I wanted to output the errors as they arrived
  176. * which meant dropping the dots.
  177. * @package SimpleTest
  178. * @subpackage UnitTester
  179. */
  180. class TextReporter extends SimpleReporter {
  181. /**
  182. * Does nothing yet. The first output will
  183. * be sent on the first test start.
  184. * @access public
  185. */
  186. function __construct() {
  187. parent::__construct();
  188. }
  189. /**
  190. * Paints the title only.
  191. * @param string $test_name Name class of test.
  192. * @access public
  193. */
  194. function paintHeader($test_name) {
  195. if (! SimpleReporter::inCli()) {
  196. header('Content-type: text/plain');
  197. }
  198. print "$test_name\n";
  199. flush();
  200. }
  201. /**
  202. * Paints the end of the test with a summary of
  203. * the passes and failures.
  204. * @param string $test_name Name class of test.
  205. * @access public
  206. */
  207. function paintFooter($test_name) {
  208. if ($this->getFailCount() + $this->getExceptionCount() == 0) {
  209. print "OK\n";
  210. } else {
  211. print "FAILURES!!!\n";
  212. }
  213. print "Test cases run: " . $this->getTestCaseProgress() .
  214. "/" . $this->getTestCaseCount() .
  215. ", Passes: " . $this->getPassCount() .
  216. ", Failures: " . $this->getFailCount() .
  217. ", Exceptions: " . $this->getExceptionCount() . "\n";
  218. }
  219. /**
  220. * Paints the test failure as a stack trace.
  221. * @param string $message Failure message displayed in
  222. * the context of the other tests.
  223. * @access public
  224. */
  225. function paintFail($message) {
  226. parent::paintFail($message);
  227. print $this->getFailCount() . ") $message\n";
  228. $breadcrumb = $this->getTestList();
  229. array_shift($breadcrumb);
  230. print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
  231. print "\n";
  232. }
  233. /**
  234. * Paints a PHP error or exception.
  235. * @param string $message Message to be shown.
  236. * @access public
  237. * @abstract
  238. */
  239. function paintError($message) {
  240. parent::paintError($message);
  241. print "Exception " . $this->getExceptionCount() . "!\n$message\n";
  242. $breadcrumb = $this->getTestList();
  243. array_shift($breadcrumb);
  244. print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
  245. print "\n";
  246. }
  247. /**
  248. * Paints a PHP error or exception.
  249. * @param Exception $exception Exception to describe.
  250. * @access public
  251. * @abstract
  252. */
  253. function paintException($exception) {
  254. parent::paintException($exception);
  255. $message = 'Unexpected exception of type [' . get_class($exception) .
  256. '] with message ['. $exception->getMessage() .
  257. '] in ['. $exception->getFile() .
  258. ' line ' . $exception->getLine() . ']';
  259. print "Exception " . $this->getExceptionCount() . "!\n$message\n";
  260. $breadcrumb = $this->getTestList();
  261. array_shift($breadcrumb);
  262. print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
  263. print "\n";
  264. }
  265. /**
  266. * Prints the message for skipping tests.
  267. * @param string $message Text of skip condition.
  268. * @access public
  269. */
  270. function paintSkip($message) {
  271. parent::paintSkip($message);
  272. print "Skip: $message\n";
  273. }
  274. /**
  275. * Paints formatted text such as dumped privateiables.
  276. * @param string $message Text to show.
  277. * @access public
  278. */
  279. function paintFormattedMessage($message) {
  280. print "$message\n";
  281. flush();
  282. }
  283. }
  284. /**
  285. * Runs just a single test group, a single case or
  286. * even a single test within that case.
  287. * @package SimpleTest
  288. * @subpackage UnitTester
  289. */
  290. class SelectiveReporter extends SimpleReporterDecorator {
  291. private $just_this_case = false;
  292. private $just_this_test = false;
  293. private $on;
  294. /**
  295. * Selects the test case or group to be run,
  296. * and optionally a specific test.
  297. * @param SimpleScorer $reporter Reporter to receive events.
  298. * @param string $just_this_case Only this case or group will run.
  299. * @param string $just_this_test Only this test method will run.
  300. */
  301. function __construct($reporter, $just_this_case = false, $just_this_test = false) {
  302. if (isset($just_this_case) && $just_this_case) {
  303. $this->just_this_case = strtolower($just_this_case);
  304. $this->off();
  305. } else {
  306. $this->on();
  307. }
  308. if (isset($just_this_test) && $just_this_test) {
  309. $this->just_this_test = strtolower($just_this_test);
  310. }
  311. parent::__construct($reporter);
  312. }
  313. /**
  314. * Compares criteria to actual the case/group name.
  315. * @param string $test_case The incoming test.
  316. * @return boolean True if matched.
  317. * @access protected
  318. */
  319. protected function matchesTestCase($test_case) {
  320. return $this->just_this_case == strtolower($test_case);
  321. }
  322. /**
  323. * Compares criteria to actual the test name. If no
  324. * name was specified at the beginning, then all tests
  325. * can run.
  326. * @param string $method The incoming test method.
  327. * @return boolean True if matched.
  328. * @access protected
  329. */
  330. protected function shouldRunTest($test_case, $method) {
  331. if ($this->isOn() || $this->matchesTestCase($test_case)) {
  332. if ($this->just_this_test) {
  333. return $this->just_this_test == strtolower($method);
  334. } else {
  335. return true;
  336. }
  337. }
  338. return false;
  339. }
  340. /**
  341. * Switch on testing for the group or subgroup.
  342. * @access private
  343. */
  344. protected function on() {
  345. $this->on = true;
  346. }
  347. /**
  348. * Switch off testing for the group or subgroup.
  349. * @access private
  350. */
  351. protected function off() {
  352. $this->on = false;
  353. }
  354. /**
  355. * Is this group actually being tested?
  356. * @return boolean True if the current test group is active.
  357. * @access private
  358. */
  359. protected function isOn() {
  360. return $this->on;
  361. }
  362. /**
  363. * Veto everything that doesn't match the method wanted.
  364. * @param string $test_case Name of test case.
  365. * @param string $method Name of test method.
  366. * @return boolean True if test should be run.
  367. * @access public
  368. */
  369. function shouldInvoke($test_case, $method) {
  370. if ($this->shouldRunTest($test_case, $method)) {
  371. return $this->reporter->shouldInvoke($test_case, $method);
  372. }
  373. return false;
  374. }
  375. /**
  376. * Paints the start of a group test.
  377. * @param string $test_case Name of test or other label.
  378. * @param integer $size Number of test cases starting.
  379. * @access public
  380. */
  381. function paintGroupStart($test_case, $size) {
  382. if ($this->just_this_case && $this->matchesTestCase($test_case)) {
  383. $this->on();
  384. }
  385. $this->reporter->paintGroupStart($test_case, $size);
  386. }
  387. /**
  388. * Paints the end of a group test.
  389. * @param string $test_case Name of test or other label.
  390. * @access public
  391. */
  392. function paintGroupEnd($test_case) {
  393. $this->reporter->paintGroupEnd($test_case);
  394. if ($this->just_this_case && $this->matchesTestCase($test_case)) {
  395. $this->off();
  396. }
  397. }
  398. }
  399. /**
  400. * Suppresses skip messages.
  401. * @package SimpleTest
  402. * @subpackage UnitTester
  403. */
  404. class NoSkipsReporter extends SimpleReporterDecorator {
  405. /**
  406. * Does nothing.
  407. * @param string $message Text of skip condition.
  408. * @access public
  409. */
  410. function paintSkip($message) { }
  411. }
  412. ?>