1<?php 2/* 3 * This file is part of PHPUnit. 4 * 5 * (c) Sebastian Bergmann <sebastian@phpunit.de> 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11/** 12 * Base class for printers of TestDox documentation. 13 */ 14abstract class PHPUnit_Util_TestDox_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener 15{ 16 /** 17 * @var PHPUnit_Util_TestDox_NamePrettifier 18 */ 19 protected $prettifier; 20 21 /** 22 * @var string 23 */ 24 protected $testClass = ''; 25 26 /** 27 * @var int 28 */ 29 protected $testStatus = false; 30 31 /** 32 * @var array 33 */ 34 protected $tests = []; 35 36 /** 37 * @var int 38 */ 39 protected $successful = 0; 40 41 /** 42 * @var int 43 */ 44 protected $warned = 0; 45 46 /** 47 * @var int 48 */ 49 protected $failed = 0; 50 51 /** 52 * @var int 53 */ 54 protected $risky = 0; 55 56 /** 57 * @var int 58 */ 59 protected $skipped = 0; 60 61 /** 62 * @var int 63 */ 64 protected $incomplete = 0; 65 66 /** 67 * @var string 68 */ 69 protected $currentTestClassPrettified; 70 71 /** 72 * @var string 73 */ 74 protected $currentTestMethodPrettified; 75 76 /** 77 * @var array 78 */ 79 private $groups; 80 81 /** 82 * @var array 83 */ 84 private $excludeGroups; 85 86 /** 87 * @param resource $out 88 * @param array $groups 89 * @param array $excludeGroups 90 */ 91 public function __construct($out = null, array $groups = [], array $excludeGroups = []) 92 { 93 parent::__construct($out); 94 95 $this->groups = $groups; 96 $this->excludeGroups = $excludeGroups; 97 98 $this->prettifier = new PHPUnit_Util_TestDox_NamePrettifier; 99 $this->startRun(); 100 } 101 102 /** 103 * Flush buffer and close output. 104 */ 105 public function flush() 106 { 107 $this->doEndClass(); 108 $this->endRun(); 109 110 parent::flush(); 111 } 112 113 /** 114 * An error occurred. 115 * 116 * @param PHPUnit_Framework_Test $test 117 * @param Exception $e 118 * @param float $time 119 */ 120 public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) 121 { 122 if (!$this->isOfInterest($test)) { 123 return; 124 } 125 126 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; 127 $this->failed++; 128 } 129 130 /** 131 * A warning occurred. 132 * 133 * @param PHPUnit_Framework_Test $test 134 * @param PHPUnit_Framework_Warning $e 135 * @param float $time 136 */ 137 public function addWarning(PHPUnit_Framework_Test $test, PHPUnit_Framework_Warning $e, $time) 138 { 139 if (!$this->isOfInterest($test)) { 140 return; 141 } 142 143 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_WARNING; 144 $this->warned++; 145 } 146 147 /** 148 * A failure occurred. 149 * 150 * @param PHPUnit_Framework_Test $test 151 * @param PHPUnit_Framework_AssertionFailedError $e 152 * @param float $time 153 */ 154 public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) 155 { 156 if (!$this->isOfInterest($test)) { 157 return; 158 } 159 160 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE; 161 $this->failed++; 162 } 163 164 /** 165 * Incomplete test. 166 * 167 * @param PHPUnit_Framework_Test $test 168 * @param Exception $e 169 * @param float $time 170 */ 171 public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) 172 { 173 if (!$this->isOfInterest($test)) { 174 return; 175 } 176 177 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE; 178 $this->incomplete++; 179 } 180 181 /** 182 * Risky test. 183 * 184 * @param PHPUnit_Framework_Test $test 185 * @param Exception $e 186 * @param float $time 187 */ 188 public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time) 189 { 190 if (!$this->isOfInterest($test)) { 191 return; 192 } 193 194 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_RISKY; 195 $this->risky++; 196 } 197 198 /** 199 * Skipped test. 200 * 201 * @param PHPUnit_Framework_Test $test 202 * @param Exception $e 203 * @param float $time 204 */ 205 public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) 206 { 207 if (!$this->isOfInterest($test)) { 208 return; 209 } 210 211 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED; 212 $this->skipped++; 213 } 214 215 /** 216 * A testsuite started. 217 * 218 * @param PHPUnit_Framework_TestSuite $suite 219 */ 220 public function startTestSuite(PHPUnit_Framework_TestSuite $suite) 221 { 222 } 223 224 /** 225 * A testsuite ended. 226 * 227 * @param PHPUnit_Framework_TestSuite $suite 228 */ 229 public function endTestSuite(PHPUnit_Framework_TestSuite $suite) 230 { 231 } 232 233 /** 234 * A test started. 235 * 236 * @param PHPUnit_Framework_Test $test 237 */ 238 public function startTest(PHPUnit_Framework_Test $test) 239 { 240 if (!$this->isOfInterest($test)) { 241 return; 242 } 243 244 $class = get_class($test); 245 246 if ($this->testClass != $class) { 247 if ($this->testClass != '') { 248 $this->doEndClass(); 249 } 250 251 $classAnnotations = PHPUnit_Util_Test::parseTestMethodAnnotations($class); 252 if (isset($classAnnotations['class']['testdox'][0])) { 253 $this->currentTestClassPrettified = $classAnnotations['class']['testdox'][0]; 254 } else { 255 $this->currentTestClassPrettified = $this->prettifier->prettifyTestClass($class); 256 } 257 258 $this->startClass($class); 259 260 $this->testClass = $class; 261 $this->tests = []; 262 } 263 264 $annotations = $test->getAnnotations(); 265 266 if (isset($annotations['method']['testdox'][0])) { 267 $this->currentTestMethodPrettified = $annotations['method']['testdox'][0]; 268 } else { 269 $this->currentTestMethodPrettified = $this->prettifier->prettifyTestMethod($test->getName(false)); 270 } 271 272 if ($test instanceof PHPUnit_Framework_TestCase && $test->usesDataProvider()) { 273 $this->currentTestMethodPrettified .= ' ' . $test->dataDescription(); 274 } 275 276 $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED; 277 } 278 279 /** 280 * A test ended. 281 * 282 * @param PHPUnit_Framework_Test $test 283 * @param float $time 284 */ 285 public function endTest(PHPUnit_Framework_Test $test, $time) 286 { 287 if (!$this->isOfInterest($test)) { 288 return; 289 } 290 291 if (!isset($this->tests[$this->currentTestMethodPrettified])) { 292 if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { 293 $this->tests[$this->currentTestMethodPrettified]['success'] = 1; 294 $this->tests[$this->currentTestMethodPrettified]['failure'] = 0; 295 } else { 296 $this->tests[$this->currentTestMethodPrettified]['success'] = 0; 297 $this->tests[$this->currentTestMethodPrettified]['failure'] = 1; 298 } 299 } else { 300 if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { 301 $this->tests[$this->currentTestMethodPrettified]['success']++; 302 } else { 303 $this->tests[$this->currentTestMethodPrettified]['failure']++; 304 } 305 } 306 307 $this->currentTestClassPrettified = null; 308 $this->currentTestMethodPrettified = null; 309 } 310 311 protected function doEndClass() 312 { 313 foreach ($this->tests as $name => $data) { 314 $this->onTest($name, $data['failure'] == 0); 315 } 316 317 $this->endClass($this->testClass); 318 } 319 320 /** 321 * Handler for 'start run' event. 322 */ 323 protected function startRun() 324 { 325 } 326 327 /** 328 * Handler for 'start class' event. 329 * 330 * @param string $name 331 */ 332 protected function startClass($name) 333 { 334 } 335 336 /** 337 * Handler for 'on test' event. 338 * 339 * @param string $name 340 * @param bool $success 341 */ 342 protected function onTest($name, $success = true) 343 { 344 } 345 346 /** 347 * Handler for 'end class' event. 348 * 349 * @param string $name 350 */ 351 protected function endClass($name) 352 { 353 } 354 355 /** 356 * Handler for 'end run' event. 357 */ 358 protected function endRun() 359 { 360 } 361 362 /** 363 * @param PHPUnit_Framework_Test $test 364 * 365 * @return bool 366 */ 367 private function isOfInterest(PHPUnit_Framework_Test $test) 368 { 369 if (!$test instanceof PHPUnit_Framework_TestCase) { 370 return false; 371 } 372 373 if ($test instanceof PHPUnit_Framework_WarningTestCase) { 374 return false; 375 } 376 377 if (!empty($this->groups)) { 378 foreach ($test->getGroups() as $group) { 379 if (in_array($group, $this->groups)) { 380 return true; 381 } 382 } 383 384 return false; 385 } 386 387 if (!empty($this->excludeGroups)) { 388 foreach ($test->getGroups() as $group) { 389 if (in_array($group, $this->excludeGroups)) { 390 return false; 391 } 392 } 393 394 return true; 395 } 396 397 return true; 398 } 399} 400