package betsy.bpmn.engines;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import betsy.common.tasks.FileTasks;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class BPMNTestcaseMerger {
static class MergeResult {
private String name = "";
private int errors;
private int failures;
private int skipped;
private int tests;
private double time;
private List<Node> testCases = new ArrayList<>();
private Node properties;
}
private final Path reportPath;
public BPMNTestcaseMerger(Path reportPath) {
this.reportPath = reportPath;
}
public void mergeTestCases() {
// remove "Test-" from the file names
removePrefixOfTestResults(reportPath);
//information needed for the generated test suite
MergeResult result = new MergeResult();
//extract information
DocumentBuilder dBuilder = createDocumentBuilder();
try {
Files.walkFileTree(reportPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Document document = parseFile(file, dBuilder);
document.getDocumentElement().normalize();
Element testSuite = document.getDocumentElement();
result.name = testSuite.getAttribute("name");
result.errors += Integer.parseInt(testSuite.getAttribute("errors"));
result.failures += Integer.parseInt(testSuite.getAttribute("failures"));
result.skipped += Integer.parseInt(testSuite.getAttribute("skipped"));
result.tests += Integer.parseInt(testSuite.getAttribute("tests"));
result.time += Double.parseDouble(testSuite.getAttribute("time"));
result.testCases.add(testSuite.getElementsByTagName("testcase").item(0));
result.properties = testSuite.getElementsByTagName("properties").item(0);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
throw new RuntimeException("could not read files in file tree", e);
}
//create merged test suite xml file
Document doc = dBuilder.newDocument();
Element testSuite = doc.createElement("testsuite");
doc.appendChild(testSuite);
testSuite.setAttribute("name", result.name);
testSuite.setAttribute("errors", String.valueOf(result.errors));
testSuite.setAttribute("failures", ((Integer) result.failures).toString());
testSuite.setAttribute("tests", ((Integer) result.tests).toString());
testSuite.setAttribute("skipped", ((Integer) result.skipped).toString());
testSuite.setAttribute("time", ((Double) result.time).toString());
//add properties
Element propertiesElement = doc.createElement("properties");
testSuite.appendChild(propertiesElement);
for (int i = 0; i < result.properties.getChildNodes().getLength(); i++) {
Node propertyOld = result.properties.getChildNodes().item(i);
//ignore text content
if (propertyOld.getNodeName().contentEquals("#text")) {
continue;
}
Element property = doc.createElement("property");
propertiesElement.appendChild(property);
//set property attributes
if (propertyOld.hasAttributes()) {
for (int j = 0; j < propertyOld.getAttributes().getLength(); j++) {
Node attributeOld = propertyOld.getAttributes().item(j);
property.setAttribute(attributeOld.getNodeName(), attributeOld.getNodeValue());
}
}
}
//add test cases
for (Node testCaseOld : result.testCases) {
Element testCase = doc.createElement(testCaseOld.getNodeName());
testSuite.appendChild(testCase);
//set test case attributes
for (int i = 0; i < testCaseOld.getAttributes().getLength(); i++) {
Node attribute = testCaseOld.getAttributes().item(i);
testCase.setAttribute(attribute.getNodeName(), attribute.getNodeValue());
}
NodeList children = testCaseOld.getChildNodes();
// set test ase child nodes
for (int i = 0; i < children.getLength(); i++) {
//ignore text content
if (children.item(i).getNodeName().contentEquals("#text")) {
continue;
}
Element child = doc.createElement(children.item(i).getNodeName());
testCase.appendChild(child);
//set test case child node attributes
for (int j = 0; j < children.item(i).getAttributes().getLength(); j++) {
Node attributeOld = children.item(i).getAttributes().item(j);
child.setAttribute(attributeOld.getNodeName(), attributeOld.getNodeValue());
}
child.setTextContent(children.item(i).getTextContent());
}
}
createAggregatedTestSuite(doc);
}
private Document parseFile(Path file, DocumentBuilder dBuilder) throws IOException {
try {
return dBuilder.parse(file.toFile());
} catch (SAXException e) {
throw new RuntimeException("could not parse " + file, e);
}
}
private DocumentBuilder createDocumentBuilder() {
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
return dbFactory.newDocumentBuilder();
} catch (ParserConfigurationException e){
throw new RuntimeException("Could not create a DOM parser", e);
}
}
private void createAggregatedTestSuite(Document doc) {
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(reportPath.resolve("TEST-Complete.TestSuite.xml").toFile());
transformer.transform(source, result);
} catch (TransformerException e) {
throw new RuntimeException("cannot create final TEST-Complete.TestSuite.xml", e);
}
}
/**
* // remove "Test-" from the file names
*/
private void removePrefixOfTestResults(Path path) {
try {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//remove 'Test-' that this file is not detected by junit html report generation
if (file.getFileName().toString().startsWith("TEST-")) {
FileTasks.move(file, file.getParent().resolve(file.getFileName().toString().substring(5)));
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
throw new RuntimeException("could not rename the files in " + path, e);
}
}
}