package net.thucydides.core.reports.adaptors.xunit;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import net.thucydides.core.reports.adaptors.xunit.model.TestCase;
import net.thucydides.core.reports.adaptors.xunit.model.TestException;
import net.thucydides.core.reports.adaptors.xunit.model.TestSuite;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class BasicXUnitLoader implements XUnitLoader {
@Override
public List<TestSuite> loadFrom(final File xUnitReport) throws IOException {
List<TestSuite> testSuites = Lists.newArrayList();
Document doc = parseDocument(xUnitReport);
NodeList testSuiteElements = doc.getElementsByTagName("testsuite");
shouldHaveAtLeastOneTestSuite(testSuiteElements, xUnitReport);
for (int i = 0; i < testSuiteElements.getLength(); i++) {
Optional<TestSuite> testSuite = testSuiteFrom(testSuiteElements.item(i));
testSuites.addAll(testSuite.asSet());
}
return testSuites;
}
private void shouldHaveAtLeastOneTestSuite(NodeList testSuiteElements, File xUnitReport) {
if (testSuiteElements.getLength() == 0) {
throw new CouldNotReadXUnitFileException("Could not read xUnit file " + xUnitReport.getAbsolutePath());
}
}
private Optional<TestSuite> testSuiteFrom(Node testSuiteNode) {
Element testSuiteElement = (Element) testSuiteNode;
TestSuite testSuite = TestSuite.named(testSuiteElement.getAttribute("name"));
List<TestCase> testCases = testCasesFrom(testSuiteElement);
return Optional.of(testSuite.withTestCases(testCases));
}
private List<TestCase> testCasesFrom(Element testSuiteElement) {
NodeList testCaseElements = testSuiteElement.getElementsByTagName("testcase");
List<TestCase> testCases = Lists.newArrayList();
for (int i = 0; i < testCaseElements.getLength(); i++) {
testCases.add(testCaseFrom(testCaseElements.item(i)));
}
return testCases;
}
private TestCase testCaseFrom(Node item) {
Element testCaseElement = (Element) item;
TestCase testCase = getBasicTestCaseFrom(testCaseElement);
Optional<TestException> failure = exceptionElementIn(testCaseElement).ofType("failure");
if (failure.isPresent()) {
testCase = testCase.withFailure(failure.get());
}
Optional<TestException> error = exceptionElementIn(testCaseElement).ofType("error");
if (error.isPresent()) {
testCase = testCase.withError(error.get());
}
String skipped = skippedTextIn(testCaseElement);
if (StringUtils.isNotEmpty(skipped)) {
testCase = testCase.wasSkipped(skipped);
}
return testCase;
}
private String skippedTextIn(Element testCaseElement) {
String skipMessage = "";
NodeList skipElements = testCaseElement.getElementsByTagName("skipped");
if (skipElements.getLength() > 0) {
skipMessage = ((Element) skipElements.item(0)).getAttribute("type");
skipMessage = StringUtils.isEmpty(skipMessage) ? "unknown" : skipMessage;
}
return skipMessage;
}
private TestCase getBasicTestCaseFrom(Element testCaseElement) {
String name = testCaseElement.getAttribute("name");
String classname = testCaseElement.getAttribute("classname");
double timeValue = timeFrom(testCaseElement);
return TestCase.withName(name).andClassname(classname).andTime(timeValue);
}
private ExceptionElementBuilder exceptionElementIn(Element testCaseElement) {
return new ExceptionElementBuilder(testCaseElement);
}
private double timeFrom(Element testCaseElement) {
String time = testCaseElement.getAttribute("time");
double timeValue = 0.0;
if (StringUtils.isNotEmpty(time)) {
timeValue = Double.parseDouble(time);
}
return timeValue;
}
private Document parseDocument(File xUnitReport) throws IOException {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(xUnitReport);
} catch (Exception e) {
throw new CouldNotReadXUnitFileException(e.getMessage());
}
}
private class ExceptionElementBuilder {
private final Element testCaseElement;
public ExceptionElementBuilder(Element testCaseElement) {
this.testCaseElement = testCaseElement;
}
public Optional<TestException> ofType(String exceptionType) {
NodeList failureElements = testCaseElement.getElementsByTagName(exceptionType);
if (failureElements.getLength() > 0) {
Element failureElement = (Element) failureElements.item(0);
String message = failureElement.getAttribute("message");
String errorOutput = failureElement.getTextContent();
return Optional.of(new TestException(message, errorOutput, exceptionType));
}
return Optional.absent();
}
}
}