package hudson.plugins.nunit; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * Transforms a NUnit report into seperate JUnit reports. The NUnit report can contain several test cases and the JUnit * report that is read by Hudson should only contain one. This class will split up one NUnit report into several JUnit * files. * */ public class NUnitReportTransformer implements TestReportTransformer, Serializable { private static final String ILLEGAL_FILE_CHARS_REGEX = "[\\*/:<>\\?\\|\\\\\";]+"; private static final long serialVersionUID = 1L; public static final String JUNIT_FILE_POSTFIX = ".xml"; public static final String JUNIT_FILE_PREFIX = "TEST-"; private static final String TEMP_JUNIT_FILE_STR = "temp-junit.xml"; public static final String NUNIT_TO_JUNIT_XSLFILE_STR = "nunit-to-junit.xsl"; private transient boolean xslIsInitialized; private transient Transformer nunitTransformer; private transient Transformer writerTransformer; private transient DocumentBuilder xmlDocumentBuilder; /** * Transform the nunit file into several junit files in the output path * * @param nunitFileStream the nunit file stream to transform * @param junitOutputPath the output path to put all junit files * @throws IOException thrown if there was any problem with the transform. * @throws TransformerException * @throws SAXException * @throws ParserConfigurationException */ public void transform(InputStream nunitFileStream, File junitOutputPath) throws IOException, TransformerException, SAXException, ParserConfigurationException { initialize(); File junitTargetFile = new File(junitOutputPath, TEMP_JUNIT_FILE_STR); FileOutputStream fileOutputStream = new FileOutputStream(junitTargetFile); try { nunitTransformer.transform(new StreamSource(nunitFileStream), new StreamResult(fileOutputStream)); } finally { fileOutputStream.close(); } splitJUnitFile(junitTargetFile, junitOutputPath); junitTargetFile.delete(); } private void initialize() throws TransformerFactoryConfigurationError, TransformerConfigurationException, ParserConfigurationException { if (!xslIsInitialized) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); nunitTransformer = transformerFactory.newTransformer(new StreamSource(this.getClass().getResourceAsStream(NUNIT_TO_JUNIT_XSLFILE_STR))); writerTransformer = transformerFactory.newTransformer(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); xmlDocumentBuilder = factory.newDocumentBuilder(); xslIsInitialized = true; } } /** * Splits the junit file into several junit files in the output path * * @param junitFile report containing one or more junit test suite tags * @param junitOutputPath the path to put all junit files * @throws IOException * @throws SAXException * @throws TransformerException */ private void splitJUnitFile(File junitFile, File junitOutputPath) throws SAXException, IOException, TransformerException { Document document = xmlDocumentBuilder.parse(junitFile); NodeList elementsByTagName = ((Element) document.getElementsByTagName("testsuites").item(0)).getElementsByTagName("testsuite"); for (int i = 0; i < elementsByTagName.getLength(); i++) { Element element = (Element) elementsByTagName.item(i); DOMSource source = new DOMSource(element); String filename = JUNIT_FILE_PREFIX + element.getAttribute("name").replaceAll(ILLEGAL_FILE_CHARS_REGEX, "_") + JUNIT_FILE_POSTFIX; File junitOutputFile = new File(junitOutputPath, filename); FileOutputStream fileOutputStream = new FileOutputStream(junitOutputFile); try { StreamResult result = new StreamResult(fileOutputStream); writerTransformer.transform(source, result); } finally { fileOutputStream.close(); } } } }