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 * A TestListener that generates a logfile of the 13 * test execution using the Test Anything Protocol (TAP). 14 */ 15class PHPUnit_Util_Log_TAP extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener 16{ 17 /** 18 * @var int 19 */ 20 protected $testNumber = 0; 21 22 /** 23 * @var int 24 */ 25 protected $testSuiteLevel = 0; 26 27 /** 28 * @var bool 29 */ 30 protected $testSuccessful = true; 31 32 /** 33 * Constructor. 34 * 35 * @param mixed $out 36 * 37 * @throws PHPUnit_Framework_Exception 38 */ 39 public function __construct($out = null) 40 { 41 parent::__construct($out); 42 $this->write("TAP version 13\n"); 43 } 44 45 /** 46 * An error occurred. 47 * 48 * @param PHPUnit_Framework_Test $test 49 * @param Exception $e 50 * @param float $time 51 */ 52 public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) 53 { 54 $this->writeNotOk($test, 'Error'); 55 } 56 57 /** 58 * A warning occurred. 59 * 60 * @param PHPUnit_Framework_Test $test 61 * @param PHPUnit_Framework_Warning $e 62 * @param float $time 63 */ 64 public function addWarning(PHPUnit_Framework_Test $test, PHPUnit_Framework_Warning $e, $time) 65 { 66 $this->writeNotOk($test, 'Warning'); 67 } 68 69 /** 70 * A failure occurred. 71 * 72 * @param PHPUnit_Framework_Test $test 73 * @param PHPUnit_Framework_AssertionFailedError $e 74 * @param float $time 75 */ 76 public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) 77 { 78 $this->writeNotOk($test, 'Failure'); 79 80 $message = explode( 81 "\n", 82 PHPUnit_Framework_TestFailure::exceptionToString($e) 83 ); 84 85 $diagnostic = [ 86 'message' => $message[0], 87 'severity' => 'fail' 88 ]; 89 90 if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { 91 $cf = $e->getComparisonFailure(); 92 93 if ($cf !== null) { 94 $diagnostic['data'] = [ 95 'got' => $cf->getActual(), 96 'expected' => $cf->getExpected() 97 ]; 98 } 99 } 100 101 $yaml = new Symfony\Component\Yaml\Dumper; 102 103 $this->write( 104 sprintf( 105 " ---\n%s ...\n", 106 $yaml->dump($diagnostic, 2, 2) 107 ) 108 ); 109 } 110 111 /** 112 * Incomplete test. 113 * 114 * @param PHPUnit_Framework_Test $test 115 * @param Exception $e 116 * @param float $time 117 */ 118 public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) 119 { 120 $this->writeNotOk($test, '', 'TODO Incomplete Test'); 121 } 122 123 /** 124 * Risky test. 125 * 126 * @param PHPUnit_Framework_Test $test 127 * @param Exception $e 128 * @param float $time 129 */ 130 public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time) 131 { 132 $this->write( 133 sprintf( 134 "ok %d - # RISKY%s\n", 135 $this->testNumber, 136 $e->getMessage() != '' ? ' ' . $e->getMessage() : '' 137 ) 138 ); 139 140 $this->testSuccessful = false; 141 } 142 143 /** 144 * Skipped test. 145 * 146 * @param PHPUnit_Framework_Test $test 147 * @param Exception $e 148 * @param float $time 149 */ 150 public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) 151 { 152 $this->write( 153 sprintf( 154 "ok %d - # SKIP%s\n", 155 $this->testNumber, 156 $e->getMessage() != '' ? ' ' . $e->getMessage() : '' 157 ) 158 ); 159 160 $this->testSuccessful = false; 161 } 162 163 /** 164 * A testsuite started. 165 * 166 * @param PHPUnit_Framework_TestSuite $suite 167 */ 168 public function startTestSuite(PHPUnit_Framework_TestSuite $suite) 169 { 170 $this->testSuiteLevel++; 171 } 172 173 /** 174 * A testsuite ended. 175 * 176 * @param PHPUnit_Framework_TestSuite $suite 177 */ 178 public function endTestSuite(PHPUnit_Framework_TestSuite $suite) 179 { 180 $this->testSuiteLevel--; 181 182 if ($this->testSuiteLevel == 0) { 183 $this->write(sprintf("1..%d\n", $this->testNumber)); 184 } 185 } 186 187 /** 188 * A test started. 189 * 190 * @param PHPUnit_Framework_Test $test 191 */ 192 public function startTest(PHPUnit_Framework_Test $test) 193 { 194 $this->testNumber++; 195 $this->testSuccessful = true; 196 } 197 198 /** 199 * A test ended. 200 * 201 * @param PHPUnit_Framework_Test $test 202 * @param float $time 203 */ 204 public function endTest(PHPUnit_Framework_Test $test, $time) 205 { 206 if ($this->testSuccessful === true) { 207 $this->write( 208 sprintf( 209 "ok %d - %s\n", 210 $this->testNumber, 211 PHPUnit_Util_Test::describe($test) 212 ) 213 ); 214 } 215 216 $this->writeDiagnostics($test); 217 } 218 219 /** 220 * @param PHPUnit_Framework_Test $test 221 * @param string $prefix 222 * @param string $directive 223 */ 224 protected function writeNotOk(PHPUnit_Framework_Test $test, $prefix = '', $directive = '') 225 { 226 $this->write( 227 sprintf( 228 "not ok %d - %s%s%s\n", 229 $this->testNumber, 230 $prefix != '' ? $prefix . ': ' : '', 231 PHPUnit_Util_Test::describe($test), 232 $directive != '' ? ' # ' . $directive : '' 233 ) 234 ); 235 236 $this->testSuccessful = false; 237 } 238 239 /** 240 * @param PHPUnit_Framework_Test $test 241 */ 242 private function writeDiagnostics(PHPUnit_Framework_Test $test) 243 { 244 if (!$test instanceof PHPUnit_Framework_TestCase) { 245 return; 246 } 247 248 if (!$test->hasOutput()) { 249 return; 250 } 251 252 foreach (explode("\n", trim($test->getActualOutput())) as $line) { 253 $this->write( 254 sprintf( 255 "# %s\n", 256 $line 257 ) 258 ); 259 } 260 } 261} 262