eclipse.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <?php
  2. /**
  3. * base include file for eclipse plugin
  4. * @package SimpleTest
  5. * @subpackage Eclipse
  6. * @version $Id: eclipse.php 2011 2011-04-29 08:22:48Z pp11 $
  7. */
  8. /**#@+
  9. * simpletest include files
  10. */
  11. include_once 'unit_tester.php';
  12. include_once 'test_case.php';
  13. include_once 'invoker.php';
  14. include_once 'socket.php';
  15. include_once 'mock_objects.php';
  16. /**#@-*/
  17. /**
  18. * base reported class for eclipse plugin
  19. * @package SimpleTest
  20. * @subpackage Eclipse
  21. */
  22. class EclipseReporter extends SimpleScorer {
  23. /**
  24. * Reporter to be run inside of Eclipse interface.
  25. * @param object $listener Eclipse listener (?).
  26. * @param boolean $cc Whether to include test coverage.
  27. */
  28. function __construct(&$listener, $cc=false){
  29. $this->listener = &$listener;
  30. $this->SimpleScorer();
  31. $this->case = "";
  32. $this->group = "";
  33. $this->method = "";
  34. $this->cc = $cc;
  35. $this->error = false;
  36. $this->fail = false;
  37. }
  38. /**
  39. * Means to display human readable object comparisons.
  40. * @return SimpleDumper Visual comparer.
  41. */
  42. function getDumper() {
  43. return new SimpleDumper();
  44. }
  45. /**
  46. * Localhost connection from Eclipse.
  47. * @param integer $port Port to connect to Eclipse.
  48. * @param string $host Normally localhost.
  49. * @return SimpleSocket Connection to Eclipse.
  50. */
  51. function &createListener($port, $host="127.0.0.1"){
  52. $tmplistener = &new SimpleSocket($host, $port, 5);
  53. return $tmplistener;
  54. }
  55. /**
  56. * Wraps the test in an output buffer.
  57. * @param SimpleInvoker $invoker Current test runner.
  58. * @return EclipseInvoker Decorator with output buffering.
  59. * @access public
  60. */
  61. function &createInvoker(&$invoker){
  62. $eclinvoker = &new EclipseInvoker($invoker, $this->listener);
  63. return $eclinvoker;
  64. }
  65. /**
  66. * C style escaping.
  67. * @param string $raw String with backslashes, quotes and whitespace.
  68. * @return string Replaced with C backslashed tokens.
  69. */
  70. function escapeVal($raw){
  71. $needle = array("\\","\"","/","\b","\f","\n","\r","\t");
  72. $replace = array('\\\\','\"','\/','\b','\f','\n','\r','\t');
  73. return str_replace($needle, $replace, $raw);
  74. }
  75. /**
  76. * Stash the first passing item. Clicking the test
  77. * item goes to first pass.
  78. * @param string $message Test message, but we only wnat the first.
  79. * @access public
  80. */
  81. function paintPass($message){
  82. if (! $this->pass){
  83. $this->message = $this->escapeVal($message);
  84. }
  85. $this->pass = true;
  86. }
  87. /**
  88. * Stash the first failing item. Clicking the test
  89. * item goes to first fail.
  90. * @param string $message Test message, but we only wnat the first.
  91. * @access public
  92. */
  93. function paintFail($message){
  94. //only get the first failure or error
  95. if (! $this->fail && ! $this->error){
  96. $this->fail = true;
  97. $this->message = $this->escapeVal($message);
  98. $this->listener->write('{status:"fail",message:"'.$this->message.'",group:"'.$this->group.'",case:"'.$this->case.'",method:"'.$this->method.'"}');
  99. }
  100. }
  101. /**
  102. * Stash the first error. Clicking the test
  103. * item goes to first error.
  104. * @param string $message Test message, but we only wnat the first.
  105. * @access public
  106. */
  107. function paintError($message){
  108. if (! $this->fail && ! $this->error){
  109. $this->error = true;
  110. $this->message = $this->escapeVal($message);
  111. $this->listener->write('{status:"error",message:"'.$this->message.'",group:"'.$this->group.'",case:"'.$this->case.'",method:"'.$this->method.'"}');
  112. }
  113. }
  114. /**
  115. * Stash the first exception. Clicking the test
  116. * item goes to first message.
  117. * @param string $message Test message, but we only wnat the first.
  118. * @access public
  119. */
  120. function paintException($exception){
  121. if (! $this->fail && ! $this->error){
  122. $this->error = true;
  123. $message = 'Unexpected exception of type[' . get_class($exception) .
  124. '] with message [' . $exception->getMessage() . '] in [' .
  125. $exception->getFile() .' line '. $exception->getLine() . ']';
  126. $this->message = $this->escapeVal($message);
  127. $this->listener->write(
  128. '{status:"error",message:"' . $this->message . '",group:"' .
  129. $this->group . '",case:"' . $this->case . '",method:"' . $this->method
  130. . '"}');
  131. }
  132. }
  133. /**
  134. * We don't display any special header.
  135. * @param string $test_name First test top level
  136. * to start.
  137. * @access public
  138. */
  139. function paintHeader($test_name) {
  140. }
  141. /**
  142. * We don't display any special footer.
  143. * @param string $test_name The top level test.
  144. * @access public
  145. */
  146. function paintFooter($test_name) {
  147. }
  148. /**
  149. * Paints nothing at the start of a test method, but stash
  150. * the method name for later.
  151. * @param string $test_name Name of test that is starting.
  152. * @access public
  153. */
  154. function paintMethodStart($method) {
  155. $this->pass = false;
  156. $this->fail = false;
  157. $this->error = false;
  158. $this->method = $this->escapeVal($method);
  159. }
  160. /**
  161. * Only send one message if the test passes, after that
  162. * suppress the message.
  163. * @param string $test_name Name of test that is ending.
  164. * @access public
  165. */
  166. function paintMethodEnd($method){
  167. if ($this->fail || $this->error || ! $this->pass){
  168. } else {
  169. $this->listener->write(
  170. '{status:"pass",message:"' . $this->message . '",group:"' .
  171. $this->group . '",case:"' . $this->case . '",method:"' .
  172. $this->method . '"}');
  173. }
  174. }
  175. /**
  176. * Stashes the test case name for the later failure message.
  177. * @param string $test_name Name of test or other label.
  178. * @access public
  179. */
  180. function paintCaseStart($case){
  181. $this->case = $this->escapeVal($case);
  182. }
  183. /**
  184. * Drops the name.
  185. * @param string $test_name Name of test or other label.
  186. * @access public
  187. */
  188. function paintCaseEnd($case){
  189. $this->case = "";
  190. }
  191. /**
  192. * Stashes the name of the test suite. Starts test coverage
  193. * if enabled.
  194. * @param string $group Name of test or other label.
  195. * @param integer $size Number of test cases starting.
  196. * @access public
  197. */
  198. function paintGroupStart($group, $size){
  199. $this->group = $this->escapeVal($group);
  200. if ($this->cc){
  201. if (extension_loaded('xdebug')){
  202. xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
  203. }
  204. }
  205. }
  206. /**
  207. * Paints coverage report if enabled.
  208. * @param string $group Name of test or other label.
  209. * @access public
  210. */
  211. function paintGroupEnd($group){
  212. $this->group = "";
  213. $cc = "";
  214. if ($this->cc){
  215. if (extension_loaded('xdebug')){
  216. $arrfiles = xdebug_get_code_coverage();
  217. xdebug_stop_code_coverage();
  218. $thisdir = dirname(__FILE__);
  219. $thisdirlen = strlen($thisdir);
  220. foreach ($arrfiles as $index=>$file){
  221. if (substr($index, 0, $thisdirlen)===$thisdir){
  222. continue;
  223. }
  224. $lcnt = 0;
  225. $ccnt = 0;
  226. foreach ($file as $line){
  227. if ($line == -2){
  228. continue;
  229. }
  230. $lcnt++;
  231. if ($line==1){
  232. $ccnt++;
  233. }
  234. }
  235. if ($lcnt > 0){
  236. $cc .= round(($ccnt/$lcnt) * 100, 2) . '%';
  237. }else{
  238. $cc .= "0.00%";
  239. }
  240. $cc.= "\t". $index . "\n";
  241. }
  242. }
  243. }
  244. $this->listener->write('{status:"coverage",message:"' .
  245. EclipseReporter::escapeVal($cc) . '"}');
  246. }
  247. }
  248. /**
  249. * Invoker decorator for Eclipse. Captures output until
  250. * the end of the test.
  251. * @package SimpleTest
  252. * @subpackage Eclipse
  253. */
  254. class EclipseInvoker extends SimpleInvokerDecorator{
  255. function __construct(&$invoker, &$listener) {
  256. $this->listener = &$listener;
  257. $this->SimpleInvokerDecorator($invoker);
  258. }
  259. /**
  260. * Starts output buffering.
  261. * @param string $method Test method to call.
  262. * @access public
  263. */
  264. function before($method){
  265. ob_start();
  266. $this->invoker->before($method);
  267. }
  268. /**
  269. * Stops output buffering and send the captured output
  270. * to the listener.
  271. * @param string $method Test method to call.
  272. * @access public
  273. */
  274. function after($method) {
  275. $this->invoker->after($method);
  276. $output = ob_get_contents();
  277. ob_end_clean();
  278. if ($output !== ""){
  279. $result = $this->listener->write('{status:"info",message:"' .
  280. EclipseReporter::escapeVal($output) . '"}');
  281. }
  282. }
  283. }
  284. ?>