package net.thucydides.junit.runners; import com.google.common.collect.Lists; import net.thucydides.core.model.*; import org.apache.commons.lang3.StringUtils; import org.junit.runner.Runner; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static ch.lambdaj.Lambda.extract; import static ch.lambdaj.Lambda.on; public class ParameterizedTestsOutcomeAggregator { private final ThucydidesParameterizedRunner thucydidesParameterizedRunner; private ParameterizedTestsOutcomeAggregator(ThucydidesParameterizedRunner thucydidesParameterizedRunner) { this.thucydidesParameterizedRunner = thucydidesParameterizedRunner; } public static ParameterizedTestsOutcomeAggregator from(ThucydidesParameterizedRunner thucydidesParameterizedRunner) { return new ParameterizedTestsOutcomeAggregator(thucydidesParameterizedRunner); } public List<TestOutcome> aggregateTestOutcomesByTestMethods() { List<TestOutcome> allOutcomes = getTestOutcomesForAllParameterSets(); if (allOutcomes.isEmpty()) { return Lists.<TestOutcome>newArrayList(); } else { return aggregatedScenarioOutcomes(allOutcomes); } } private List<TestOutcome> aggregatedScenarioOutcomes(List<TestOutcome> allOutcomes) { Map<String, TestOutcome> scenarioOutcomes = new HashMap<>(); for (TestOutcome testOutcome : allOutcomes) { String normalizedMethodName = normalizeMethodName(testOutcome); if (scenarioOutcomes.containsKey(normalizedMethodName)) { List<TestStep> testSteps = testOutcome.getTestSteps(); if (testSteps.isEmpty()) { TestStep nestedStep = TestStep.forStepCalled(testOutcome.getTitle()).withResult(testOutcome.getResult()); scenarioOutcomes.get(normalizedMethodName).recordStep(nestedStep); } else { TestStep nextStep = testSteps.get(0); nextStep.setDescription(normalizeTestStepDescription(nextStep.getDescription(), scenarioOutcomes.get(normalizedMethodName).getTestSteps().size() + 1)); scenarioOutcomes.get(normalizedMethodName).recordStep(nextStep); } if (testOutcome.isDataDriven()) { updateResultsForAnyExternalFailures(scenarioOutcomes.get(normalizedMethodName), testOutcome); scenarioOutcomes.get(normalizedMethodName).getDataTable().addRows(testOutcome.getDataTable().getRows()); } } else { TestOutcome scenarioOutcome = createScenarioOutcome(testOutcome); if (scenarioOutcome.getTestSteps().isEmpty()) { scenarioOutcome.startGroup(); } scenarioOutcomes.put(scenarioOutcome.getMethodName(), scenarioOutcome); } } List<TestOutcome> aggregatedScenarioOutcomes = new ArrayList<TestOutcome>(); aggregatedScenarioOutcomes.addAll(scenarioOutcomes.values()); return aggregatedScenarioOutcomes; } private void updateResultsForAnyExternalFailures(TestOutcome scenarioOutcome, TestOutcome testOutcome) { if (rowResultsAreInconsistantWithOverallResult(testOutcome)) { testOutcome.getDataTable().getRows().get(0).updateResult(testOutcome.getResult()); scenarioOutcome.addFailingExternalStep(new AssertionError(testOutcome.getTestFailureMessage())); } } private boolean rowResultsAreInconsistantWithOverallResult(TestOutcome testOutcome) { TestResult overallRowResult = overallResultFrom(testOutcome.getDataTable().getRows()); return (testOutcome.isError() || testOutcome.isFailure()) && (!testOutcome.getDataTable().getRows().isEmpty()) && (testOutcome.getResult() != overallRowResult); } private TestResult overallResultFrom(List<DataTableRow> rows) { TestResultList rowResults = TestResultList.of(extract(rows, on(DataTableRow.class).getResult())); return rowResults.getOverallResult(); } private String normalizeTestStepDescription(String description, int index) { return StringUtils.replace(description, "[1]", "[" + index + "]"); } private TestOutcome createScenarioOutcome(TestOutcome parameterizedOutcome) { TestOutcome scenarioOutcome = parameterizedOutcome.withMethodName(normalizeMethodName(parameterizedOutcome)); if (scenarioOutcome.getTestSteps().isEmpty()) { TestStep firstStep = TestStep.forStepCalled(parameterizedOutcome.getTitle()).withResult(scenarioOutcome.getResult()); scenarioOutcome.recordStep(firstStep); } scenarioOutcome.endGroup(); //pop group stack so next item gets added as sibling return scenarioOutcome; } private String normalizeMethodName(TestOutcome testOutcome) { return testOutcome.getMethodName().replaceAll("\\[\\d+\\]", ""); } public List<TestOutcome> getTestOutcomesForAllParameterSets() { List<TestOutcome> testOutcomes = new ArrayList<TestOutcome>(); for (Runner runner : thucydidesParameterizedRunner.getRunners()) { for (TestOutcome testOutcome : ((ThucydidesRunner) runner).getTestOutcomes()) { if (!testOutcomes.contains(testOutcome)) { testOutcomes.add(testOutcome); } } } return testOutcomes; } }