Viewing file: XmlResultPrinter.php (7.14 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\TestDox;
use function array_filter; use function get_class; use function implode; use function strpos; use DOMDocument; use DOMElement; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Exception; use PHPUnit\Framework\Test; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestListener; use PHPUnit\Framework\TestSuite; use PHPUnit\Framework\Warning; use PHPUnit\Framework\WarningTestCase; use PHPUnit\Util\Printer; use PHPUnit\Util\Test as TestUtil; use ReflectionClass; use ReflectionException; use Throwable;
/** * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class XmlResultPrinter extends Printer implements TestListener { /** * @var DOMDocument */ private $document;
/** * @var DOMElement */ private $root;
/** * @var NamePrettifier */ private $prettifier;
/** * @var null|Throwable */ private $exception;
/** * @param resource|string $out * * @throws Exception */ public function __construct($out = null) { $this->document = new DOMDocument('1.0', 'UTF-8'); $this->document->formatOutput = true;
$this->root = $this->document->createElement('tests'); $this->document->appendChild($this->root);
$this->prettifier = new NamePrettifier;
parent::__construct($out); }
/** * Flush buffer and close output. */ public function flush(): void { $this->write($this->document->saveXML());
parent::flush(); }
/** * An error occurred. */ public function addError(Test $test, Throwable $t, float $time): void { $this->exception = $t; }
/** * A warning occurred. */ public function addWarning(Test $test, Warning $e, float $time): void { }
/** * A failure occurred. */ public function addFailure(Test $test, AssertionFailedError $e, float $time): void { $this->exception = $e; }
/** * Incomplete test. */ public function addIncompleteTest(Test $test, Throwable $t, float $time): void { }
/** * Risky test. */ public function addRiskyTest(Test $test, Throwable $t, float $time): void { }
/** * Skipped test. */ public function addSkippedTest(Test $test, Throwable $t, float $time): void { }
/** * A test suite started. */ public function startTestSuite(TestSuite $suite): void { }
/** * A test suite ended. */ public function endTestSuite(TestSuite $suite): void { }
/** * A test started. */ public function startTest(Test $test): void { $this->exception = null; }
/** * A test ended. * * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException */ public function endTest(Test $test, float $time): void { if (!$test instanceof TestCase || $test instanceof WarningTestCase) { return; }
$groups = array_filter( $test->getGroups(), static function ($group) { return !($group === 'small' || $group === 'medium' || $group === 'large' || strpos($group, '__phpunit_') === 0); }, );
$testNode = $this->document->createElement('test');
$testNode->setAttribute('className', get_class($test)); $testNode->setAttribute('methodName', $test->getName()); $testNode->setAttribute('prettifiedClassName', $this->prettifier->prettifyTestClass(get_class($test))); $testNode->setAttribute('prettifiedMethodName', $this->prettifier->prettifyTestCase($test)); $testNode->setAttribute('status', (string) $test->getStatus()); $testNode->setAttribute('time', (string) $time); $testNode->setAttribute('size', (string) $test->getSize()); $testNode->setAttribute('groups', implode(',', $groups));
foreach ($groups as $group) { $groupNode = $this->document->createElement('group');
$groupNode->setAttribute('name', $group);
$testNode->appendChild($groupNode); }
$annotations = TestUtil::parseTestMethodAnnotations( get_class($test), $test->getName(false), );
foreach (['class', 'method'] as $type) { foreach ($annotations[$type] as $annotation => $values) { if ($annotation !== 'covers' && $annotation !== 'uses') { continue; }
foreach ($values as $value) { $coversNode = $this->document->createElement($annotation);
$coversNode->setAttribute('target', $value);
$testNode->appendChild($coversNode); } } }
foreach ($test->doubledTypes() as $doubledType) { $testDoubleNode = $this->document->createElement('testDouble');
$testDoubleNode->setAttribute('type', $doubledType);
$testNode->appendChild($testDoubleNode); }
$inlineAnnotations = \PHPUnit\Util\Test::getInlineAnnotations(get_class($test), $test->getName(false));
if (isset($inlineAnnotations['given'], $inlineAnnotations['when'], $inlineAnnotations['then'])) { $testNode->setAttribute('given', $inlineAnnotations['given']['value']); $testNode->setAttribute('givenStartLine', (string) $inlineAnnotations['given']['line']); $testNode->setAttribute('when', $inlineAnnotations['when']['value']); $testNode->setAttribute('whenStartLine', (string) $inlineAnnotations['when']['line']); $testNode->setAttribute('then', $inlineAnnotations['then']['value']); $testNode->setAttribute('thenStartLine', (string) $inlineAnnotations['then']['line']); }
if ($this->exception !== null) { if ($this->exception instanceof Exception) { $steps = $this->exception->getSerializableTrace(); } else { $steps = $this->exception->getTrace(); }
try { $file = (new ReflectionClass($test))->getFileName(); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e, ); } // @codeCoverageIgnoreEnd
foreach ($steps as $step) { if (isset($step['file']) && $step['file'] === $file) { $testNode->setAttribute('exceptionLine', (string) $step['line']);
break; } }
$testNode->setAttribute('exceptionMessage', $this->exception->getMessage()); }
$this->root->appendChild($testNode); } }
|