1<?php 2/** 3 * $Id: 65affc464b743a2ef7a41d714b1acb1fa5b8bd3b $ 4 * 5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 * 17 * This software consists of voluntary contributions made by many individuals 18 * and is licensed under the LGPL. For more information please see 19 * <http://phing.info>. 20 */ 21 22require_once 'PHPUnit/Autoload.php'; 23require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; 24require_once 'phing/system/util/Timer.php'; 25 26/** 27 * Simple Testrunner for PHPUnit that runs all tests of a testsuite. 28 * 29 * @author Michiel Rook <mrook@php.net> 30 * @version $Id: 65affc464b743a2ef7a41d714b1acb1fa5b8bd3b $ 31 * @package phing.tasks.ext.phpunit 32 * @since 2.1.0 33 */ 34class PHPUnitTestRunner extends PHPUnit_Runner_BaseTestRunner implements PHPUnit_Framework_TestListener 35{ 36 const SUCCESS = 0; 37 const FAILURES = 1; 38 const ERRORS = 2; 39 const INCOMPLETES = 3; 40 const SKIPPED = 4; 41 42 private $retCode = 0; 43 private $lastErrorMessage = ''; 44 private $lastFailureMessage = ''; 45 private $lastIncompleteMessage = ''; 46 private $lastSkippedMessage = ''; 47 private $formatters = array(); 48 49 private $codecoverage = null; 50 51 private $project = NULL; 52 53 private $groups = array(); 54 private $excludeGroups = array(); 55 56 private $processIsolation = false; 57 58 private $useCustomErrorHandler = true; 59 60 public function __construct(Project $project, $groups = array(), $excludeGroups = array(), $processIsolation = false) 61 { 62 $this->project = $project; 63 $this->groups = $groups; 64 $this->excludeGroups = $excludeGroups; 65 $this->processIsolation = $processIsolation; 66 $this->retCode = self::SUCCESS; 67 } 68 69 public function setCodecoverage($codecoverage) 70 { 71 $this->codecoverage = $codecoverage; 72 } 73 74 public function setUseCustomErrorHandler($useCustomErrorHandler) 75 { 76 $this->useCustomErrorHandler = $useCustomErrorHandler; 77 } 78 79 public function addFormatter($formatter) 80 { 81 $this->formatters[] = $formatter; 82 } 83 84 public function handleError($level, $message, $file, $line) 85 { 86 return PHPUnit_Util_ErrorHandler::handleError($level, $message, $file, $line); 87 } 88 89 /** 90 * Run a test 91 */ 92 public function run(PHPUnit_Framework_TestSuite $suite) 93 { 94 $res = new PHPUnit_Framework_TestResult(); 95 96 if ($this->codecoverage) 97 { 98 $whitelist = CoverageMerger::getWhiteList($this->project); 99 100 $this->codecoverage->filter()->addFilesToWhiteList($whitelist); 101 102 $res->setCodeCoverage($this->codecoverage); 103 } 104 105 $res->addListener($this); 106 107 foreach ($this->formatters as $formatter) 108 { 109 $res->addListener($formatter); 110 } 111 112 /* Set PHPUnit error handler */ 113 if ($this->useCustomErrorHandler) 114 { 115 $oldErrorHandler = set_error_handler(array($this, 'handleError'), E_ALL | E_STRICT); 116 } 117 118 $suite->run($res, false, $this->groups, $this->excludeGroups, $this->processIsolation); 119 120 foreach ($this->formatters as $formatter) 121 { 122 $formatter->processResult($res); 123 } 124 125 /* Restore Phing error handler */ 126 if ($this->useCustomErrorHandler) 127 { 128 restore_error_handler(); 129 } 130 131 if ($this->codecoverage) 132 { 133 CoverageMerger::merge($this->project, $this->codecoverage->getData()); 134 } 135 136 if ($res->errorCount() != 0) 137 { 138 $this->retCode = self::ERRORS; 139 } 140 else if ($res->failureCount() != 0) 141 { 142 $this->retCode = self::FAILURES; 143 } 144 else if ($res->notImplementedCount() != 0) 145 { 146 $this->retCode = self::INCOMPLETES; 147 } 148 else if ($res->skippedCount() != 0) 149 { 150 $this->retCode = self::SKIPPED; 151 } 152 } 153 154 public function getRetCode() 155 { 156 return $this->retCode; 157 } 158 159 public function getLastErrorMessage() 160 { 161 return $this->lastErrorMessage; 162 } 163 164 public function getLastFailureMessage() 165 { 166 return $this->lastFailureMessage; 167 } 168 169 public function getLastIncompleteMessage() 170 { 171 return $this->lastIncompleteMessage; 172 } 173 174 public function getLastSkippedMessage() 175 { 176 return $this->lastSkippedMessage; 177 } 178 179 protected function composeMessage($message, PHPUnit_Framework_Test $test, Exception $e) 180 { 181 $message = "Test $message (" . $test->getName() . " in class " . get_class($test) . "): " . $e->getMessage(); 182 183 if ($e instanceof PHPUnit_Framework_ExpectationFailedException && $e->getComparisonFailure()) { 184 $message .= "\n" . $e->getComparisonFailure()->getDiff(); 185 } 186 187 return $message; 188 } 189 190 /** 191 * An error occurred. 192 * 193 * @param PHPUnit_Framework_Test $test 194 * @param Exception $e 195 * @param float $time 196 */ 197 public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) 198 { 199 $this->lastErrorMessage = $this->composeMessage("ERROR", $test, $e); 200 } 201 202 /** 203 * A failure occurred. 204 * 205 * @param PHPUnit_Framework_Test $test 206 * @param PHPUnit_Framework_AssertionFailedError $e 207 * @param float $time 208 */ 209 public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) 210 { 211 $this->lastFailureMessage = $this->composeMessage("FAILURE", $test, $e); 212 } 213 214 /** 215 * Incomplete test. 216 * 217 * @param PHPUnit_Framework_Test $test 218 * @param Exception $e 219 * @param float $time 220 */ 221 public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) 222 { 223 $this->lastIncompleteMessage = $this->composeMessage("INCOMPLETE", $test, $e); 224 } 225 226 /** 227 * Skipped test. 228 * 229 * @param PHPUnit_Framework_Test $test 230 * @param Exception $e 231 * @param float $time 232 * @since Method available since Release 3.0.0 233 */ 234 public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) 235 { 236 $this->lastSkippedMessage = $this->composeMessage("SKIPPED", $test, $e); 237 } 238 239 /** 240 * A test started. 241 * 242 * @param string $testName 243 */ 244 public function testStarted($testName) 245 { 246 } 247 248 /** 249 * A test ended. 250 * 251 * @param string $testName 252 */ 253 public function testEnded($testName) 254 { 255 } 256 257 /** 258 * A test failed. 259 * 260 * @param integer $status 261 * @param PHPUnit_Framework_Test $test 262 * @param PHPUnit_Framework_AssertionFailedError $e 263 */ 264 public function testFailed($status, PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e) 265 { 266 } 267 268 /** 269 * Override to define how to handle a failed loading of 270 * a test suite. 271 * 272 * @param string $message 273 */ 274 protected function runFailed($message) 275 { 276 throw new BuildException($message); 277 } 278 279 /** 280 * A test suite started. 281 * 282 * @param PHPUnit_Framework_TestSuite $suite 283 * @since Method available since Release 2.2.0 284 */ 285 public function startTestSuite(PHPUnit_Framework_TestSuite $suite) 286 { 287 } 288 289 /** 290 * A test suite ended. 291 * 292 * @param PHPUnit_Framework_TestSuite $suite 293 * @since Method available since Release 2.2.0 294 */ 295 public function endTestSuite(PHPUnit_Framework_TestSuite $suite) 296 { 297 } 298 299 /** 300 * A test started. 301 * 302 * @param PHPUnit_Framework_Test $test 303 */ 304 public function startTest(PHPUnit_Framework_Test $test) 305 { 306 } 307 308 /** 309 * A test ended. 310 * 311 * @param PHPUnit_Framework_Test $test 312 * @param float $time 313 */ 314 public function endTest(PHPUnit_Framework_Test $test, $time) 315 { 316 if ($test instanceof PHPUnit_Framework_TestCase) { 317 if (!$test->hasPerformedExpectationsOnOutput()) { 318 echo $test->getActualOutput(); 319 } 320 } 321 } 322} 323 324