ResultPrinter.php (17879B)
1 <?php 2 /** 3 * PHPUnit 4 * 5 * Copyright (c) 2001-2014, Sebastian Bergmann <sebastian@phpunit.de>. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * * Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * * Neither the name of Sebastian Bergmann nor the names of his 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 * 37 * @package PHPUnit 38 * @subpackage TextUI 39 * @author Sebastian Bergmann <sebastian@phpunit.de> 40 * @copyright 2001-2014 Sebastian Bergmann <sebastian@phpunit.de> 41 * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License 42 * @link http://www.phpunit.de/ 43 * @since File available since Release 2.0.0 44 */ 45 46 /** 47 * Prints the result of a TextUI TestRunner run. 48 * 49 * @package PHPUnit 50 * @subpackage TextUI 51 * @author Sebastian Bergmann <sebastian@phpunit.de> 52 * @copyright 2001-2014 Sebastian Bergmann <sebastian@phpunit.de> 53 * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License 54 * @link http://www.phpunit.de/ 55 * @since Class available since Release 2.0.0 56 */ 57 class PHPUnit_TextUI_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener 58 { 59 const EVENT_TEST_START = 0; 60 const EVENT_TEST_END = 1; 61 const EVENT_TESTSUITE_START = 2; 62 const EVENT_TESTSUITE_END = 3; 63 64 /** 65 * @var integer 66 */ 67 protected $column = 0; 68 69 /** 70 * @var integer 71 */ 72 protected $maxColumn; 73 74 /** 75 * @var boolean 76 */ 77 protected $lastTestFailed = FALSE; 78 79 /** 80 * @var integer 81 */ 82 protected $numAssertions = 0; 83 84 /** 85 * @var integer 86 */ 87 protected $numTests = -1; 88 89 /** 90 * @var integer 91 */ 92 protected $numTestsRun = 0; 93 94 /** 95 * @var integer 96 */ 97 protected $numTestsWidth; 98 99 /** 100 * @var boolean 101 */ 102 protected $colors = FALSE; 103 104 /** 105 * @var boolean 106 */ 107 protected $debug = FALSE; 108 109 /** 110 * @var boolean 111 */ 112 protected $verbose = FALSE; 113 114 /** 115 * Constructor. 116 * 117 * @param mixed $out 118 * @param boolean $verbose 119 * @param boolean $colors 120 * @param boolean $debug 121 * @throws PHPUnit_Framework_Exception 122 * @since Method available since Release 3.0.0 123 */ 124 public function __construct($out = NULL, $verbose = FALSE, $colors = FALSE, $debug = FALSE) 125 { 126 parent::__construct($out); 127 128 if (is_bool($verbose)) { 129 $this->verbose = $verbose; 130 } else { 131 throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'boolean'); 132 } 133 134 if (is_bool($colors)) { 135 $this->colors = $colors; 136 } else { 137 throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'boolean'); 138 } 139 140 if (is_bool($debug)) { 141 $this->debug = $debug; 142 } else { 143 throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean'); 144 } 145 } 146 147 /** 148 * @param PHPUnit_Framework_TestResult $result 149 */ 150 public function printResult(PHPUnit_Framework_TestResult $result) 151 { 152 $this->printHeader(); 153 154 if ($result->errorCount() > 0) { 155 $this->printErrors($result); 156 } 157 158 if ($result->failureCount() > 0) { 159 if ($result->errorCount() > 0) { 160 print "\n--\n\n"; 161 } 162 163 $this->printFailures($result); 164 } 165 166 if ($this->verbose) { 167 if ($result->deprecatedFeaturesCount() > 0) { 168 if ($result->failureCount() > 0) { 169 print "\n--\n\nDeprecated PHPUnit features are being used"; 170 } 171 172 foreach ($result->deprecatedFeatures() as $deprecatedFeature) { 173 $this->write($deprecatedFeature . "\n\n"); 174 } 175 } 176 177 if ($result->notImplementedCount() > 0) { 178 if ($result->failureCount() > 0) { 179 print "\n--\n\n"; 180 } 181 182 $this->printIncompletes($result); 183 } 184 185 if ($result->skippedCount() > 0) { 186 if ($result->notImplementedCount() > 0) { 187 print "\n--\n\n"; 188 } 189 190 $this->printSkipped($result); 191 } 192 } 193 194 $this->printFooter($result); 195 } 196 197 /** 198 * @param array $defects 199 * @param integer $count 200 * @param string $type 201 */ 202 protected function printDefects(array $defects, $count, $type) 203 { 204 static $called = FALSE; 205 206 if ($count == 0) { 207 return; 208 } 209 210 $this->write( 211 sprintf( 212 "%sThere %s %d %s%s:\n", 213 214 $called ? "\n" : '', 215 ($count == 1) ? 'was' : 'were', 216 $count, 217 $type, 218 ($count == 1) ? '' : 's' 219 ) 220 ); 221 222 $i = 1; 223 224 foreach ($defects as $defect) { 225 $this->printDefect($defect, $i++); 226 } 227 228 $called = TRUE; 229 } 230 231 /** 232 * @param PHPUnit_Framework_TestFailure $defect 233 * @param integer $count 234 */ 235 protected function printDefect(PHPUnit_Framework_TestFailure $defect, $count) 236 { 237 $this->printDefectHeader($defect, $count); 238 $this->printDefectTrace($defect); 239 } 240 241 /** 242 * @param PHPUnit_Framework_TestFailure $defect 243 * @param integer $count 244 */ 245 protected function printDefectHeader(PHPUnit_Framework_TestFailure $defect, $count) 246 { 247 $failedTest = $defect->failedTest(); 248 249 if ($failedTest instanceof PHPUnit_Framework_SelfDescribing) { 250 $testName = $failedTest->toString(); 251 } else { 252 $testName = get_class($failedTest); 253 } 254 255 $this->write( 256 sprintf( 257 "\n%d) %s\n", 258 259 $count, 260 $testName 261 ) 262 ); 263 } 264 265 /** 266 * @param PHPUnit_Framework_TestFailure $defect 267 */ 268 protected function printDefectTrace(PHPUnit_Framework_TestFailure $defect) 269 { 270 $this->write( 271 $defect->getExceptionAsString() . "\n" . 272 PHPUnit_Util_Filter::getFilteredStacktrace( 273 $defect->thrownException() 274 ) 275 ); 276 277 $e = $defect->thrownException()->getPrevious(); 278 279 while ($e) { 280 $this->write( 281 "\nCaused by\n" . 282 PHPUnit_Framework_TestFailure::exceptionToString($e). "\n" . 283 PHPUnit_Util_Filter::getFilteredStacktrace($e) 284 ); 285 286 $e = $e->getPrevious(); 287 } 288 } 289 290 /** 291 * @param PHPUnit_Framework_TestResult $result 292 */ 293 protected function printErrors(PHPUnit_Framework_TestResult $result) 294 { 295 $this->printDefects($result->errors(), $result->errorCount(), 'error'); 296 } 297 298 /** 299 * @param PHPUnit_Framework_TestResult $result 300 */ 301 protected function printFailures(PHPUnit_Framework_TestResult $result) 302 { 303 $this->printDefects( 304 $result->failures(), 305 $result->failureCount(), 306 'failure' 307 ); 308 } 309 310 /** 311 * @param PHPUnit_Framework_TestResult $result 312 */ 313 protected function printIncompletes(PHPUnit_Framework_TestResult $result) 314 { 315 $this->printDefects( 316 $result->notImplemented(), 317 $result->notImplementedCount(), 318 'incomplete test' 319 ); 320 } 321 322 /** 323 * @param PHPUnit_Framework_TestResult $result 324 * @since Method available since Release 3.0.0 325 */ 326 protected function printSkipped(PHPUnit_Framework_TestResult $result) 327 { 328 $this->printDefects( 329 $result->skipped(), 330 $result->skippedCount(), 331 'skipped test' 332 ); 333 } 334 335 protected function printHeader() 336 { 337 $this->write("\n\n" . PHP_Timer::resourceUsage() . "\n\n"); 338 } 339 340 /** 341 * @param PHPUnit_Framework_TestResult $result 342 */ 343 protected function printFooter(PHPUnit_Framework_TestResult $result) 344 { 345 if (count($result) === 0) { 346 if ($this->colors) { 347 $this->write("\x1b[30;43m\x1b[2K"); 348 } 349 350 $this->write( 351 "No tests executed!\n" 352 ); 353 354 if ($this->colors) { 355 $this->write("\x1b[0m\x1b[2K"); 356 } 357 } 358 359 else if ($result->wasSuccessful() && 360 $result->allCompletelyImplemented() && 361 $result->noneSkipped()) { 362 if ($this->colors) { 363 $this->write("\x1b[30;42m\x1b[2K"); 364 } 365 366 $this->write( 367 sprintf( 368 "OK (%d test%s, %d assertion%s)\n", 369 370 count($result), 371 (count($result) == 1) ? '' : 's', 372 $this->numAssertions, 373 ($this->numAssertions == 1) ? '' : 's' 374 ) 375 ); 376 377 if ($this->colors) { 378 $this->write("\x1b[0m\x1b[2K"); 379 } 380 } 381 382 else if ((!$result->allCompletelyImplemented() || 383 !$result->noneSkipped()) && 384 $result->wasSuccessful()) { 385 if ($this->colors) { 386 $this->write( 387 "\x1b[30;43m\x1b[2KOK, but incomplete or skipped tests!\n" . 388 "\x1b[0m\x1b[30;43m\x1b[2K" 389 ); 390 } else { 391 $this->write("OK, but incomplete or skipped tests!\n"); 392 } 393 394 $this->write( 395 sprintf( 396 "Tests: %d, Assertions: %d%s%s.\n", 397 398 count($result), 399 $this->numAssertions, 400 $this->getCountString( 401 $result->notImplementedCount(), 'Incomplete' 402 ), 403 $this->getCountString( 404 $result->skippedCount(), 'Skipped' 405 ) 406 ) 407 ); 408 409 if ($this->colors) { 410 $this->write("\x1b[0m\x1b[2K"); 411 } 412 } 413 414 else { 415 $this->write("\n"); 416 417 if ($this->colors) { 418 $this->write( 419 "\x1b[37;41m\x1b[2KFAILURES!\n\x1b[0m\x1b[37;41m\x1b[2K" 420 ); 421 } else { 422 $this->write("FAILURES!\n"); 423 } 424 425 $this->write( 426 sprintf( 427 "Tests: %d, Assertions: %s%s%s%s%s.\n", 428 429 count($result), 430 $this->numAssertions, 431 $this->getCountString($result->failureCount(), 'Failures'), 432 $this->getCountString($result->errorCount(), 'Errors'), 433 $this->getCountString( 434 $result->notImplementedCount(), 'Incomplete' 435 ), 436 $this->getCountString($result->skippedCount(), 'Skipped') 437 ) 438 ); 439 440 if ($this->colors) { 441 $this->write("\x1b[0m\x1b[2K"); 442 } 443 } 444 445 if (!$this->verbose && 446 $result->deprecatedFeaturesCount() > 0) { 447 $message = sprintf( 448 "Warning: Deprecated PHPUnit features are being used %s times!\n" . 449 "Use --verbose for more information.\n", 450 $result->deprecatedFeaturesCount() 451 ); 452 453 if ($this->colors) { 454 $message = "\x1b[37;41m\x1b[2K" . $message . 455 "\x1b[0m"; 456 } 457 458 $this->write("\n" . $message); 459 } 460 } 461 462 /** 463 * @param integer $count 464 * @param string $name 465 * @return string 466 * @since Method available since Release 3.0.0 467 */ 468 protected function getCountString($count, $name) 469 { 470 $string = ''; 471 472 if ($count > 0) { 473 $string = sprintf( 474 ', %s: %d', 475 476 $name, 477 $count 478 ); 479 } 480 481 return $string; 482 } 483 484 /** 485 */ 486 public function printWaitPrompt() 487 { 488 $this->write("\n<RETURN> to continue\n"); 489 } 490 491 /** 492 * An error occurred. 493 * 494 * @param PHPUnit_Framework_Test $test 495 * @param Exception $e 496 * @param float $time 497 */ 498 public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) 499 { 500 if ($this->colors) { 501 $this->writeProgress("\x1b[31;1mE\x1b[0m"); 502 } else { 503 $this->writeProgress('E'); 504 } 505 506 $this->lastTestFailed = TRUE; 507 } 508 509 /** 510 * A failure occurred. 511 * 512 * @param PHPUnit_Framework_Test $test 513 * @param PHPUnit_Framework_AssertionFailedError $e 514 * @param float $time 515 */ 516 public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) 517 { 518 if ($this->colors) { 519 $this->writeProgress("\x1b[41;37mF\x1b[0m"); 520 } else { 521 $this->writeProgress('F'); 522 } 523 524 $this->lastTestFailed = TRUE; 525 } 526 527 /** 528 * Incomplete test. 529 * 530 * @param PHPUnit_Framework_Test $test 531 * @param Exception $e 532 * @param float $time 533 */ 534 public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) 535 { 536 if ($this->colors) { 537 $this->writeProgress("\x1b[33;1mI\x1b[0m"); 538 } else { 539 $this->writeProgress('I'); 540 } 541 542 $this->lastTestFailed = TRUE; 543 } 544 545 /** 546 * Skipped test. 547 * 548 * @param PHPUnit_Framework_Test $test 549 * @param Exception $e 550 * @param float $time 551 * @since Method available since Release 3.0.0 552 */ 553 public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) 554 { 555 if ($this->colors) { 556 $this->writeProgress("\x1b[36;1mS\x1b[0m"); 557 } else { 558 $this->writeProgress('S'); 559 } 560 561 $this->lastTestFailed = TRUE; 562 } 563 564 /** 565 * A testsuite started. 566 * 567 * @param PHPUnit_Framework_TestSuite $suite 568 * @since Method available since Release 2.2.0 569 */ 570 public function startTestSuite(PHPUnit_Framework_TestSuite $suite) 571 { 572 if ($this->numTests == -1) { 573 $this->numTests = count($suite); 574 $this->numTestsWidth = strlen((string)$this->numTests); 575 $this->maxColumn = 69 - (2 * $this->numTestsWidth); 576 } 577 } 578 579 /** 580 * A testsuite ended. 581 * 582 * @param PHPUnit_Framework_TestSuite $suite 583 * @since Method available since Release 2.2.0 584 */ 585 public function endTestSuite(PHPUnit_Framework_TestSuite $suite) 586 { 587 } 588 589 /** 590 * A test started. 591 * 592 * @param PHPUnit_Framework_Test $test 593 */ 594 public function startTest(PHPUnit_Framework_Test $test) 595 { 596 if ($this->debug) { 597 $this->write( 598 sprintf( 599 "\nStarting test '%s'.\n", PHPUnit_Util_Test::describe($test) 600 ) 601 ); 602 } 603 } 604 605 /** 606 * A test ended. 607 * 608 * @param PHPUnit_Framework_Test $test 609 * @param float $time 610 */ 611 public function endTest(PHPUnit_Framework_Test $test, $time) 612 { 613 if (!$this->lastTestFailed) { 614 $this->writeProgress('.'); 615 } 616 617 if ($test instanceof PHPUnit_Framework_TestCase) { 618 $this->numAssertions += $test->getNumAssertions(); 619 } 620 621 else if ($test instanceof PHPUnit_Extensions_PhptTestCase) { 622 $this->numAssertions++; 623 } 624 625 $this->lastTestFailed = FALSE; 626 627 if ($test instanceof PHPUnit_Framework_TestCase) { 628 if (!$test->hasPerformedExpectationsOnOutput()) { 629 $this->write($test->getActualOutput()); 630 } 631 } 632 } 633 634 /** 635 * @param string $progress 636 */ 637 protected function writeProgress($progress) 638 { 639 $this->write($progress); 640 $this->column++; 641 $this->numTestsRun++; 642 643 if ($this->column == $this->maxColumn) { 644 $this->write( 645 sprintf( 646 ' %' . $this->numTestsWidth . 'd / %' . 647 $this->numTestsWidth . 'd (%3s%%)', 648 649 $this->numTestsRun, 650 $this->numTests, 651 floor(($this->numTestsRun / $this->numTests) * 100) 652 ) 653 ); 654 655 $this->writeNewLine(); 656 } 657 } 658 659 protected function writeNewLine() 660 { 661 $this->column = 0; 662 $this->write("\n"); 663 } 664 }