* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Behat\Testwork\Output\Printer; use Behat\Testwork\Output\Printer\Factory\FilesystemOutputFactory; use Symfony\Component\Console\Output\OutputInterface; /** * A convenient wrapper around the ConsoleOutputPrinter to write valid JUnit * reports. * * @author Wouter J * @author James Watson */ final class JUnitOutputPrinter extends StreamOutputPrinter { const XML_VERSION = '1.0'; const XML_ENCODING = 'UTF-8'; /** * @var \DOMDocument */ private $domDocument; /** * @var \DOMElement */ private $currentTestsuite; /** * @var \DOMElement */ private $currentTestcase; /** * @var \DOMElement */ private $testSuites; public function __construct(FilesystemOutputFactory $outputFactory) { parent::__construct($outputFactory); } /** * Creates a new JUnit file. * * The file will be initialized with an XML definition and the root element. * * @param string $name The filename (without extension) and default value of the name attribute * @param array $testsuitesAttributes Attributes for the root element */ public function createNewFile($name, array $testsuitesAttributes = array()) { $this->setFileName(strtolower(trim(preg_replace('/[^[:alnum:]_]+/', '_', $name), '_'))); $this->domDocument = new \DOMDocument(self::XML_VERSION, self::XML_ENCODING); $this->domDocument->formatOutput = true; $this->testSuites = $this->domDocument->createElement('testsuites'); $this->domDocument->appendChild($this->testSuites); $this->addAttributesToNode($this->testSuites, array_merge(array('name' => $name), $testsuitesAttributes)); $this->flush(); } /** * Adds a new node. * * @param array $testsuiteAttributes */ public function addTestsuite(array $testsuiteAttributes = array()) { $this->currentTestsuite = $this->domDocument->createElement('testsuite'); $this->testSuites->appendChild($this->currentTestsuite); $this->addAttributesToNode($this->currentTestsuite, $testsuiteAttributes); } /** * Adds a new node. * * @param array $testcaseAttributes */ public function addTestcase(array $testcaseAttributes = array()) { $this->currentTestcase = $this->domDocument->createElement('testcase'); $this->currentTestsuite->appendChild($this->currentTestcase); $this->addAttributesToNode($this->currentTestcase, $testcaseAttributes); } /** * Add a testcase child element. * * @param string $nodeName * @param array $nodeAttributes * @param string $nodeValue */ public function addTestcaseChild($nodeName, array $nodeAttributes = array(), $nodeValue = null) { $childNode = $this->domDocument->createElement($nodeName, $nodeValue); $this->currentTestcase->appendChild($childNode); $this->addAttributesToNode($childNode, $nodeAttributes); } private function addAttributesToNode(\DOMElement $node, array $attributes) { foreach ($attributes as $name => $value){ $node->setAttribute($name, $value); } } /** * Sets file name. * * @param string $fileName * @param string $extension The file extension, defaults to "xml" */ public function setFileName($fileName, $extension = 'xml') { if ('.'.$extension !== substr($fileName, strlen($extension) + 1)) { $fileName .= '.'.$extension; } $this->getOutputFactory()->setFileName($fileName); $this->flush(); } /** * Generate XML from the DOMDocument and parse to the the writing stream */ public function flush() { if($this->domDocument instanceof \DOMDocument){ $this->getWritingStream()->write( $this->domDocument->saveXML(null, LIBXML_NOEMPTYTAG), false, OutputInterface::OUTPUT_RAW ); } parent::flush(); } }