4 * This file is part of the Behat Testwork.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
11 namespace Behat\Testwork\Output\Printer;
13 use Behat\Testwork\Output\Printer\Factory\FilesystemOutputFactory;
14 use Symfony\Component\Console\Output\OutputInterface;
17 * A convenient wrapper around the ConsoleOutputPrinter to write valid JUnit
20 * @author Wouter J <wouter@wouterj.nl>
21 * @author James Watson <james@sitepulse.org>
23 final class JUnitOutputPrinter extends StreamOutputPrinter
25 const XML_VERSION = '1.0';
26 const XML_ENCODING = 'UTF-8';
35 private $currentTestsuite;
39 private $currentTestcase;
45 public function __construct(FilesystemOutputFactory $outputFactory)
47 parent::__construct($outputFactory);
51 * Creates a new JUnit file.
53 * The file will be initialized with an XML definition and the root element.
55 * @param string $name The filename (without extension) and default value of the name attribute
56 * @param array $testsuitesAttributes Attributes for the root element
58 public function createNewFile($name, array $testsuitesAttributes = array())
60 $this->setFileName(strtolower(trim(preg_replace('/[^[:alnum:]_]+/', '_', $name), '_')));
62 $this->domDocument = new \DOMDocument(self::XML_VERSION, self::XML_ENCODING);
63 $this->domDocument->formatOutput = true;
65 $this->testSuites = $this->domDocument->createElement('testsuites');
66 $this->domDocument->appendChild($this->testSuites);
67 $this->addAttributesToNode($this->testSuites, array_merge(array('name' => $name), $testsuitesAttributes));
72 * Adds a new <testsuite> node.
74 * @param array $testsuiteAttributes
76 public function addTestsuite(array $testsuiteAttributes = array())
78 $this->currentTestsuite = $this->domDocument->createElement('testsuite');
79 $this->testSuites->appendChild($this->currentTestsuite);
80 $this->addAttributesToNode($this->currentTestsuite, $testsuiteAttributes);
85 * Adds a new <testcase> node.
87 * @param array $testcaseAttributes
89 public function addTestcase(array $testcaseAttributes = array())
91 $this->currentTestcase = $this->domDocument->createElement('testcase');
92 $this->currentTestsuite->appendChild($this->currentTestcase);
93 $this->addAttributesToNode($this->currentTestcase, $testcaseAttributes);
97 * Add a testcase child element.
99 * @param string $nodeName
100 * @param array $nodeAttributes
101 * @param string $nodeValue
103 public function addTestcaseChild($nodeName, array $nodeAttributes = array(), $nodeValue = null)
105 $childNode = $this->domDocument->createElement($nodeName, $nodeValue);
106 $this->currentTestcase->appendChild($childNode);
107 $this->addAttributesToNode($childNode, $nodeAttributes);
110 private function addAttributesToNode(\DOMElement $node, array $attributes)
112 foreach ($attributes as $name => $value){
113 $node->setAttribute($name, $value);
120 * @param string $fileName
121 * @param string $extension The file extension, defaults to "xml"
123 public function setFileName($fileName, $extension = 'xml')
125 if ('.'.$extension !== substr($fileName, strlen($extension) + 1)) {
126 $fileName .= '.'.$extension;
129 $this->getOutputFactory()->setFileName($fileName);
134 * Generate XML from the DOMDocument and parse to the the writing stream
136 public function flush()
138 if($this->domDocument instanceof \DOMDocument){
139 $this->getWritingStream()->write(
140 $this->domDocument->saveXML(null, LIBXML_NOEMPTYTAG),
142 OutputInterface::OUTPUT_RAW