Viewing file: JUnit.php (11.27 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php declare(strict_types=1); /* * This file is part of PHPUnit. * * (c) Sebastian Bergmann <sebastian@phpunit.de> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Util\Log;
use function class_exists; use function get_class; use function method_exists; use function sprintf; use function str_replace; use function trim; use DOMDocument; use DOMElement; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\ExceptionWrapper; use PHPUnit\Framework\SelfDescribing; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestFailure; use PHPUnit\Framework\TestListener; use PHPUnit\Framework\TestSuite; use PHPUnit\Framework\Warning; use PHPUnit\Util\Exception; use PHPUnit\Util\Filter; use PHPUnit\Util\Printer; use PHPUnit\Util\Xml; use ReflectionClass; use ReflectionException; use Throwable;
/** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class JUnit extends Printer implements TestListener { /** * @var DOMDocument */ private $document;
/** * @var DOMElement */ private $root;
/** * @var bool */ private $reportRiskyTests = false;
/** * @var DOMElement[] */ private $testSuites = [];
/** * @var int[] */ private $testSuiteTests = [0];
/** * @var int[] */ private $testSuiteAssertions = [0];
/** * @var int[] */ private $testSuiteErrors = [0];
/** * @var int[] */ private $testSuiteWarnings = [0];
/** * @var int[] */ private $testSuiteFailures = [0];
/** * @var int[] */ private $testSuiteSkipped = [0];
/** * @var int[] */ private $testSuiteTimes = [0];
/** * @var int */ private $testSuiteLevel = 0;
/** * @var DOMElement */ private $currentTestCase;
/** * @param null|mixed $out */ public function __construct($out = null, bool $reportRiskyTests = false) { $this->document = new DOMDocument('1.0', 'UTF-8'); $this->document->formatOutput = true;
$this->root = $this->document->createElement('testsuites'); $this->document->appendChild($this->root);
parent::__construct($out);
$this->reportRiskyTests = $reportRiskyTests; }
/** * Flush buffer and close output. */ public function flush(): void { $this->write($this->getXML());
parent::flush(); }
/** * An error occurred. */ public function addError(Test $test, Throwable $t, float $time): void { $this->doAddFault($test, $t, 'error'); $this->testSuiteErrors[$this->testSuiteLevel]++; }
/** * A warning occurred. */ public function addWarning(Test $test, Warning $e, float $time): void { $this->doAddFault($test, $e, 'warning'); $this->testSuiteWarnings[$this->testSuiteLevel]++; }
/** * A failure occurred. */ public function addFailure(Test $test, AssertionFailedError $e, float $time): void { $this->doAddFault($test, $e, 'failure'); $this->testSuiteFailures[$this->testSuiteLevel]++; }
/** * Incomplete test. */ public function addIncompleteTest(Test $test, Throwable $t, float $time): void { $this->doAddSkipped(); }
/** * Risky test. */ public function addRiskyTest(Test $test, Throwable $t, float $time): void { if (!$this->reportRiskyTests) { return; }
$this->doAddFault($test, $t, 'error'); $this->testSuiteErrors[$this->testSuiteLevel]++; }
/** * Skipped test. */ public function addSkippedTest(Test $test, Throwable $t, float $time): void { $this->doAddSkipped(); }
/** * A testsuite started. */ public function startTestSuite(TestSuite $suite): void { $testSuite = $this->document->createElement('testsuite'); $testSuite->setAttribute('name', $suite->getName());
if (class_exists($suite->getName(), false)) { try { $class = new ReflectionClass($suite->getName());
$testSuite->setAttribute('file', $class->getFileName()); } catch (ReflectionException $e) { } }
if ($this->testSuiteLevel > 0) { $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); } else { $this->root->appendChild($testSuite); }
$this->testSuiteLevel++; $this->testSuites[$this->testSuiteLevel] = $testSuite; $this->testSuiteTests[$this->testSuiteLevel] = 0; $this->testSuiteAssertions[$this->testSuiteLevel] = 0; $this->testSuiteErrors[$this->testSuiteLevel] = 0; $this->testSuiteWarnings[$this->testSuiteLevel] = 0; $this->testSuiteFailures[$this->testSuiteLevel] = 0; $this->testSuiteSkipped[$this->testSuiteLevel] = 0; $this->testSuiteTimes[$this->testSuiteLevel] = 0; }
/** * A testsuite ended. */ public function endTestSuite(TestSuite $suite): void { $this->testSuites[$this->testSuiteLevel]->setAttribute( 'tests', (string) $this->testSuiteTests[$this->testSuiteLevel], );
$this->testSuites[$this->testSuiteLevel]->setAttribute( 'assertions', (string) $this->testSuiteAssertions[$this->testSuiteLevel], );
$this->testSuites[$this->testSuiteLevel]->setAttribute( 'errors', (string) $this->testSuiteErrors[$this->testSuiteLevel], );
$this->testSuites[$this->testSuiteLevel]->setAttribute( 'warnings', (string) $this->testSuiteWarnings[$this->testSuiteLevel], );
$this->testSuites[$this->testSuiteLevel]->setAttribute( 'failures', (string) $this->testSuiteFailures[$this->testSuiteLevel], );
$this->testSuites[$this->testSuiteLevel]->setAttribute( 'skipped', (string) $this->testSuiteSkipped[$this->testSuiteLevel], );
$this->testSuites[$this->testSuiteLevel]->setAttribute( 'time', sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel]), );
if ($this->testSuiteLevel > 1) { $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel]; $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; $this->testSuiteWarnings[$this->testSuiteLevel - 1] += $this->testSuiteWarnings[$this->testSuiteLevel]; $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; $this->testSuiteSkipped[$this->testSuiteLevel - 1] += $this->testSuiteSkipped[$this->testSuiteLevel]; $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; }
$this->testSuiteLevel--; }
/** * A test started. */ public function startTest(Test $test): void { $usesDataprovider = false;
if (method_exists($test, 'usesDataProvider')) { $usesDataprovider = $test->usesDataProvider(); }
$testCase = $this->document->createElement('testcase'); $testCase->setAttribute('name', $test->getName());
try { $class = new ReflectionClass($test); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e, ); } // @codeCoverageIgnoreEnd
$methodName = $test->getName(!$usesDataprovider);
if ($class->hasMethod($methodName)) { try { $method = $class->getMethod($methodName); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e, ); } // @codeCoverageIgnoreEnd
$testCase->setAttribute('class', $class->getName()); $testCase->setAttribute('classname', str_replace('\\', '.', $class->getName())); $testCase->setAttribute('file', $class->getFileName()); $testCase->setAttribute('line', (string) $method->getStartLine()); }
$this->currentTestCase = $testCase; }
/** * A test ended. */ public function endTest(Test $test, float $time): void { $numAssertions = 0;
if (method_exists($test, 'getNumAssertions')) { $numAssertions = $test->getNumAssertions(); }
$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
$this->currentTestCase->setAttribute( 'assertions', (string) $numAssertions, );
$this->currentTestCase->setAttribute( 'time', sprintf('%F', $time), );
$this->testSuites[$this->testSuiteLevel]->appendChild( $this->currentTestCase, );
$this->testSuiteTests[$this->testSuiteLevel]++; $this->testSuiteTimes[$this->testSuiteLevel] += $time;
$testOutput = '';
if (method_exists($test, 'hasOutput') && method_exists($test, 'getActualOutput')) { $testOutput = $test->hasOutput() ? $test->getActualOutput() : ''; }
if (!empty($testOutput)) { $systemOut = $this->document->createElement( 'system-out', Xml::prepareString($testOutput), );
$this->currentTestCase->appendChild($systemOut); }
$this->currentTestCase = null; }
/** * Returns the XML as a string. */ public function getXML(): string { return $this->document->saveXML(); }
private function doAddFault(Test $test, Throwable $t, string $type): void { if ($this->currentTestCase === null) { return; }
if ($test instanceof SelfDescribing) { $buffer = $test->toString() . "\n"; } else { $buffer = ''; }
$buffer .= trim( TestFailure::exceptionToString($t) . "\n" . Filter::getFilteredStacktrace($t), );
$fault = $this->document->createElement( $type, Xml::prepareString($buffer), );
if ($t instanceof ExceptionWrapper) { $fault->setAttribute('type', $t->getClassName()); } else { $fault->setAttribute('type', get_class($t)); }
$this->currentTestCase->appendChild($fault); }
private function doAddSkipped(): void { if ($this->currentTestCase === null) { return; }
$skipped = $this->document->createElement('skipped');
$this->currentTestCase->appendChild($skipped);
$this->testSuiteSkipped[$this->testSuiteLevel]++; } }
|