io.cucumber.junitxmlformatter.XmlReportData Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of junit-xml-formatter Show documentation
Show all versions of junit-xml-formatter Show documentation
Renders Cucumber Messages as JUnit XML
package io.cucumber.junitxmlformatter;
import io.cucumber.messages.types.Envelope;
import io.cucumber.messages.types.Examples;
import io.cucumber.messages.types.Feature;
import io.cucumber.messages.types.GherkinDocument;
import io.cucumber.messages.types.Pickle;
import io.cucumber.messages.types.PickleStep;
import io.cucumber.messages.types.Rule;
import io.cucumber.messages.types.Scenario;
import io.cucumber.messages.types.TableRow;
import io.cucumber.messages.types.TestCase;
import io.cucumber.messages.types.TestCaseFinished;
import io.cucumber.messages.types.TestCaseStarted;
import io.cucumber.messages.types.TestRunFinished;
import io.cucumber.messages.types.TestStep;
import io.cucumber.messages.types.TestStepFinished;
import io.cucumber.messages.types.TestStepResult;
import io.cucumber.messages.types.TestStepResultStatus;
import java.time.Duration;
import java.time.Instant;
import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Function;
import java.util.stream.Collectors;
import static io.cucumber.messages.TimeConversion.timestampToJavaInstant;
import static io.cucumber.messages.types.TestStepResultStatus.PASSED;
import static java.util.Comparator.comparing;
import static java.util.Comparator.nullsFirst;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
class XmlReportData {
private static final long MILLIS_PER_SECOND = SECONDS.toMillis(1L);
private final Comparator testStepResultComparator = nullsFirst(
comparing(o -> o.getStatus().ordinal()));
private Instant testRunStarted;
private Instant testRunFinished;
private final Deque testCaseStartedIds = new ConcurrentLinkedDeque<>();
private final Map testCaseStartedIdToStartedInstant = new ConcurrentHashMap<>();
private final Map testCaseStartedIdToFinishedInstant = new ConcurrentHashMap<>();
private final Map testCaseStartedIdToResult = new ConcurrentHashMap<>();
private final Map testStepIdToTestStepResultStatus = new ConcurrentHashMap<>();
private final Map testCaseStartedIdToTestCaseId = new ConcurrentHashMap<>();
private final Map testCaseIdToTestCase = new ConcurrentHashMap<>();
private final Map pickleIdToPickle = new ConcurrentHashMap<>();
private final Map pickleIdToScenarioAstNodeId = new ConcurrentHashMap<>();
private final Map scenarioAstNodeIdToFeatureName = new ConcurrentHashMap<>();
private final Map stepAstNodeIdToStepKeyWord = new ConcurrentHashMap<>();
private final Map pickleAstNodeIdToLongName = new ConcurrentHashMap<>();
void collect(Envelope envelope) {
envelope.getTestRunStarted().ifPresent(event -> this.testRunStarted = timestampToJavaInstant(event.getTimestamp()));
envelope.getTestRunFinished().ifPresent(this::testRunFinished);
envelope.getTestCaseStarted().ifPresent(this::testCaseStarted);
envelope.getTestCaseFinished().ifPresent(this::testCaseFinished);
envelope.getTestStepFinished().ifPresent(this::testStepFinished);
envelope.getGherkinDocument().ifPresent(this::source);
envelope.getPickle().ifPresent(this::pickle);
envelope.getTestCase().ifPresent(this::testCase);
}
private void testRunFinished(TestRunFinished event) {
this.testRunFinished = timestampToJavaInstant(event.getTimestamp());
}
private void testCaseStarted(TestCaseStarted event) {
this.testCaseStartedIds.add(event.getId());
this.testCaseStartedIdToStartedInstant.put(event.getId(), timestampToJavaInstant(event.getTimestamp()));
this.testCaseStartedIdToTestCaseId.put(event.getId(), event.getTestCaseId());
}
private void testCaseFinished(TestCaseFinished event) {
this.testCaseStartedIdToFinishedInstant.put(event.getTestCaseStartedId(),
timestampToJavaInstant(event.getTimestamp()));
}
private void testStepFinished(TestStepFinished event) {
testStepIdToTestStepResultStatus.put(event.getTestStepId(), event.getTestStepResult().getStatus());
testCaseStartedIdToResult.compute(event.getTestCaseStartedId(),
(__, previousStatus) -> mostSevereResult(previousStatus, event.getTestStepResult()));
}
private TestStepResult mostSevereResult(TestStepResult a, TestStepResult b) {
return testStepResultComparator.compare(a, b) >= 0 ? a : b;
}
private void source(GherkinDocument event) {
event.getFeature().ifPresent(feature -> {
feature.getChildren().forEach(featureChild -> {
featureChild.getRule().ifPresent(rule -> {
rule.getChildren().forEach(ruleChild -> {
ruleChild.getScenario().ifPresent(scenario -> {
scenario(feature, rule, scenario);
});
ruleChild.getBackground().ifPresent(background -> {
background.getSteps().forEach(step -> {
stepAstNodeIdToStepKeyWord.put(step.getId(), step.getKeyword());
});
});
});
});
featureChild.getBackground().ifPresent(background -> {
background.getSteps().forEach(step -> {
stepAstNodeIdToStepKeyWord.put(step.getId(), step.getKeyword());
});
});
featureChild.getScenario().ifPresent(scenario -> {
scenario(feature, null, scenario);
});
});
});
}
private void scenario(Feature feature, Rule rule, Scenario scenario) {
scenarioAstNodeIdToFeatureName.put(scenario.getId(), feature.getName());
scenario.getSteps().forEach(step -> {
stepAstNodeIdToStepKeyWord.put(step.getId(), step.getKeyword());
});
String rulePrefix = rule == null ? "" : rule.getName() + " - ";
pickleAstNodeIdToLongName.put(scenario.getId(), rulePrefix + scenario.getName());
List examples = scenario.getExamples();
for (int examplesIndex = 0; examplesIndex < examples.size(); examplesIndex++) {
Examples currentExamples = examples.get(examplesIndex);
List tableRows = currentExamples.getTableBody();
for (int exampleIndex = 0; exampleIndex < tableRows.size(); exampleIndex++) {
TableRow currentExample = tableRows.get(exampleIndex);
StringBuilder suffix = new StringBuilder(" - ");
if (!currentExamples.getName().isEmpty()) {
suffix.append(currentExamples.getName()).append(" - ");
}
suffix.append("Example #").append(examplesIndex + 1).append(".").append(exampleIndex + 1);
pickleAstNodeIdToLongName.put(currentExample.getId(), rulePrefix + scenario.getName() + suffix);
}
}
}
private void pickle(Pickle event) {
pickleIdToPickle.put(event.getId(), event);
// @formatter:off
event.getAstNodeIds().stream()
.findFirst()
.ifPresent(id -> pickleIdToScenarioAstNodeId.put(event.getId(), id));
// @formatter:on
}
private void testCase(TestCase testCase) {
testCaseIdToTestCase.put(testCase.getId(), testCase);
}
double getSuiteDurationInSeconds() {
if (testRunStarted == null || testRunFinished == null) {
return 0;
}
return durationInSeconds(testRunStarted, testRunFinished);
}
double getDurationInSeconds(String testCaseStartedId) {
return durationInSeconds(testCaseStartedIdToStartedInstant.get(testCaseStartedId),
testCaseStartedIdToFinishedInstant.get(testCaseStartedId));
}
private static double durationInSeconds(Instant testRunStarted, Instant testRunFinished) {
return Duration.between(testRunStarted, testRunFinished).toMillis() / (double) MILLIS_PER_SECOND;
}
Map getTestCaseStatusCounts() {
// @formatter:off
return testCaseStartedIdToResult.values().stream()
.map(TestStepResult::getStatus)
.collect(groupingBy(identity(), counting()));
// @formatter:on
}
int getTestCaseCount() {
return testCaseStartedIdToStartedInstant.size();
}
String getPickleName(String testCaseStartedId) {
String testCaseId = testCaseStartedIdToTestCaseId.get(testCaseStartedId);
String pickleId = testCaseIdToTestCase.get(testCaseId).getPickleId();
Pickle pickle = pickleIdToPickle.get(pickleId);
List astNodeIds = pickle.getAstNodeIds();
String pickleAstNodeId = astNodeIds.get(astNodeIds.size() - 1);
return pickleAstNodeIdToLongName.getOrDefault(pickleAstNodeId, pickle.getName());
}
public String getFeatureName(String testCaseStartedId) {
String testCaseId = testCaseStartedIdToTestCaseId.get(testCaseStartedId);
String pickleId = testCaseIdToTestCase.get(testCaseId).getPickleId();
String astNodeId = pickleIdToScenarioAstNodeId.get(pickleId);
return scenarioAstNodeIdToFeatureName.get(astNodeId);
}
LinkedHashMap getStepsAndResult(String testCaseStartedId) {
String testCaseId = testCaseStartedIdToTestCaseId.get(testCaseStartedId);
TestCase testCase = testCaseIdToTestCase.get(testCaseId);
Pickle pickle = pickleIdToPickle.get(testCase.getPickleId());
return testCase.getTestSteps().stream()
.filter(testStep -> testStep.getPickleStepId().isPresent())
.collect(Collectors.toMap(
renderTestStepText(pickle),
this::renderTestStepResult,
(existing, replacement) -> replacement,
LinkedHashMap::new
));
}
private String renderTestStepResult(TestStep testStep) {
return testStepIdToTestStepResultStatus.get(testStep.getId()).value().toLowerCase(Locale.ROOT);
}
private Function renderTestStepText(Pickle pickle) {
return testStep -> {
String pickleId = testStep.getPickleStepId().orElse(null);
Optional pickleStep = pickle.getSteps().stream()
.filter(s -> s.getId().equals(pickleId))
.findFirst();
String stepKeyWord = pickleStep
.map(s -> s.getAstNodeIds().get(0))
.map(stepAstNodeIdToStepKeyWord::get)
.orElse("");
String stepText = pickleStep
.map(PickleStep::getText)
.orElse("");
return stepKeyWord + stepText;
};
}
Deque testCaseStartedIds() {
return testCaseStartedIds;
}
private static final io.cucumber.messages.types.Duration ZERO_DURATION =
new io.cucumber.messages.types.Duration(0L, 0L);
// By definition, but see https://github.com/cucumber/gherkin/issues/11
private static final TestStepResult SCENARIO_WITH_NO_STEPS = new TestStepResult(ZERO_DURATION, null, PASSED, null);
TestStepResult getTestCaseStatus(String testCaseStartedId) {
return testCaseStartedIdToResult.getOrDefault(testCaseStartedId, SCENARIO_WITH_NO_STEPS);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy