package net.thucydides.core.requirements.reports;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.thucydides.core.issues.IssueTracking;
import net.thucydides.core.model.TestOutcome;
import net.thucydides.core.model.TestResult;
import net.thucydides.core.model.TestType;
import net.thucydides.core.reports.TestOutcomeCounter;
import net.thucydides.core.reports.TestOutcomes;
import net.thucydides.core.reports.html.Formatter;
import net.thucydides.core.requirements.model.Requirement;
import java.util.List;
import java.util.Set;
import static ch.lambdaj.Lambda.on;
import static ch.lambdaj.Lambda.sum;
public class RequirementOutcome {
private final Requirement requirement;
private final TestOutcomes testOutcomes;
private IssueTracking issueTracking;
private final int requirementsWithoutTests;
private final int estimatedUnimplementedTests;
public RequirementOutcome(Requirement requirement, TestOutcomes testOutcomes,
int requirementsWithoutTests, int estimatedUnimplementedTests,
IssueTracking issueTracking) {
this.requirement = requirement;
this.testOutcomes = testOutcomes;
this.requirementsWithoutTests = requirementsWithoutTests;
this.estimatedUnimplementedTests = estimatedUnimplementedTests;
this.issueTracking = issueTracking;
}
public RequirementOutcome(Requirement requirement, TestOutcomes testOutcomes, IssueTracking issueTracking) {
this(requirement, testOutcomes, 0, 0, issueTracking);
}
public RequirementOutcome withTestOutcomes(TestOutcomes testOutcomes) {
return new RequirementOutcome(requirement, testOutcomes, requirementsWithoutTests, estimatedUnimplementedTests, issueTracking);
}
public Requirement getRequirement() {
return requirement;
}
public TestOutcomes getTestOutcomes() {
return testOutcomes;
}
/**
* Is this requirement complete?
* A Requirement is considered complete if it has associated tests to all of the tests are successful.
*/
public boolean isComplete() {
return (!getTestOutcomes().getTests().isEmpty()) && getTestOutcomes().getResult() == TestResult.SUCCESS && allChildRequirementsAreSuccessful();
}
public boolean isFailure() {
return getTestOutcomes().getResult() == TestResult.FAILURE || anyChildRequirementsAreFailures();
}
public boolean isError() {
return getTestOutcomes().getResult() == TestResult.ERROR || anyChildRequirementsAreErrors();
}
public boolean isPending() {
return (getTestOutcomes().getTestCount() == 0) || getTestOutcomes().getResult() == TestResult.PENDING || anyChildRequirementsArePending();
}
public boolean isIgnored() {
return getTestOutcomes().getResult() == TestResult.IGNORED || anyChildRequirementsAreIgnored();
}
public int getFlattenedRequirementCount() {
return getFlattenedRequirements().size();
}
public List<Requirement> getFlattenedRequirements() {
List<Requirement> flattenedRequirements = Lists.newArrayList(requirement);
flattenedRequirements.addAll(requirement.getNestedChildren());
return ImmutableList.copyOf(flattenedRequirements);
}
public List<Requirement> getFlattenedRequirements(Requirement... excludingRequirement) {
List<Requirement> flattenedRequirements = Lists.newArrayList(requirement);
flattenedRequirements.addAll(requirement.getNestedChildren());
flattenedRequirements.removeAll(Lists.newArrayList(excludingRequirement));
return ImmutableList.copyOf(flattenedRequirements);
}
public int getRequirementsWithoutTestsCount() {
return requirementsWithoutTests;
}
private boolean allChildRequirementsAreSuccessful() {
if (requirement.hasChildren()) {
return allChildRequirementsAreSuccessfulFor(requirement.getChildren());
} else {
return true;
}
}
private boolean anyChildRequirementsAreFailures() {
return anyChildRequirementsAreFailuresFor(requirement.getChildren());
}
private boolean anyChildRequirementsAreErrors() {
return anyChildRequirementsAreErrorsFor(requirement.getChildren());
}
private boolean anyChildRequirementsArePending() {
return anyChildRequirementsArePendingFor(requirement.getChildren());
}
private boolean anyChildRequirementsAreIgnored() {
return anyChildRequirementsAreIgnoredFor(requirement.getChildren());
}
private boolean allChildRequirementsAreSuccessfulFor(List<Requirement> requirements) {
for(Requirement childRequirement : requirements) {
RequirementOutcome childOutcomes = new RequirementOutcome(childRequirement,
testOutcomes.forRequirement(requirement),
issueTracking);
if (!childOutcomes.isComplete()) {
return false;
} else if (!allChildRequirementsAreSuccessfulFor(childRequirement.getChildren())) {
return false;
}
}
return true;
}
private boolean anyChildRequirementsAreErrorsFor(List<Requirement> requirements) {
for(Requirement childRequirement : requirements) {
RequirementOutcome childOutcomes = new RequirementOutcome(childRequirement,
testOutcomes.forRequirement(requirement), issueTracking);
if (childOutcomes.isError()) {
return true;
} else if (anyChildRequirementsAreErrorsFor(childRequirement.getChildren())) {
return true;
}
}
return false;
}
private boolean anyChildRequirementsAreFailuresFor(List<Requirement> requirements) {
for(Requirement childRequirement : requirements) {
RequirementOutcome childOutcomes = new RequirementOutcome(childRequirement,
testOutcomes.forRequirement(requirement), issueTracking);
if (childOutcomes.isFailure()) {
return true;
} else if (anyChildRequirementsAreFailuresFor(childRequirement.getChildren())) {
return true;
}
}
return false;
}
private boolean anyChildRequirementsArePendingFor(List<Requirement> requirements) {
for(Requirement childRequirement : requirements) {
RequirementOutcome childOutcomes = new RequirementOutcome(childRequirement,
testOutcomes.forRequirement(requirement), issueTracking);
if (childOutcomes.isPending()) {
return true;
} else if (anyChildRequirementsArePendingFor(childRequirement.getChildren())) {
return true;
}
}
return false;
}
private boolean anyChildRequirementsAreIgnoredFor(List<Requirement> requirements) {
for(Requirement childRequirement : requirements) {
RequirementOutcome childOutcomes = new RequirementOutcome(childRequirement,
testOutcomes.forRequirement(requirement), issueTracking);
if (childOutcomes.isIgnored()) {
return true;
} else if (anyChildRequirementsAreIgnoredFor(childRequirement.getChildren())) {
return true;
}
}
return false;
}
public String getCardNumberWithLinks() {
if (requirement.getCardNumber() != null) {
return getFormatter().addLinks(requirement.getCardNumber());
} else {
return "";
}
}
private Formatter getFormatter() {
return new Formatter(issueTracking);
}
@Override
public String toString() {
return "RequirementOutcome{" +
"requirement=" + requirement +
", testOutcomes=" + testOutcomes +
'}';
}
public int getTestCount() {
return testOutcomes.getTotal();
}
public TestOutcomes getTests() {
return testOutcomes;
}
public int getEstimatedUnimplementedTests() {
return estimatedUnimplementedTests;
}
private int totalEstimatedAndImplementedTests() {
int totalImplementedTests = testOutcomes.getTotal();
return totalImplementedTests + estimatedUnimplementedTests;
}
public RequirementsPercentageFormatter getFormattedPercentage() {
return getFormattedPercentage(TestType.ANY);
}
public RequirementsPercentageFormatter getFormattedPercentage(String testType) {
return new RequirementsPercentageFormatter(percentage(testType));
}
public RequirementsPercentageFormatter getFormattedPercentage(TestType testType) {
return new RequirementsPercentageFormatter(percentage(testType));
}
public boolean testsRequirement(Requirement requirement) {
return requirement.equals(getRequirement()) || testOutcomes.containsTag(requirement.asTag());
}
public RequirementsProportionCounter getPercent() {
return percentage(TestType.ANY);
}
public RequirementsProportionCounter percentage(String testType) {
return percentage(TestType.valueOf(testType.toUpperCase()));
}
public RequirementsProportionCounter percentage(TestType testType) {
return new RequirementsProportionCounter(testType, testOutcomes, totalEstimatedAndImplementedTests());
}
public OutcomeCounter getTotal() {
return new OutcomeCounter(TestType.ANY);
}
public OutcomeCounter count(TestType testType) {
return new OutcomeCounter(testType);
}
public OutcomeCounter count(String testType) {
return new OutcomeCounter(TestType.valueOf(testType.toUpperCase()));
}
public Set<String> getReleaseVersions() {
Set<String> releaseVersions = Sets.newHashSet();
for(TestOutcome outcome : getTestOutcomes().getOutcomes()) {
releaseVersions.addAll(outcome.getVersions());
}
return ImmutableSet.copyOf(releaseVersions);
}
public class OutcomeCounter extends TestOutcomeCounter {
public OutcomeCounter(TestType testType) {
super(testType);
}
public int withResult(String expectedResult) {
return withResult(TestResult.valueOf(expectedResult.toUpperCase()));
}
public int withResult(TestResult expectedResult) {
return sum(testOutcomes.getOutcomes(), on(TestOutcome.class).countResults(expectedResult, testType));
}
public int withIndeterminateResult() {
return testOutcomes.getTotal() - withResult(TestResult.SUCCESS)
- withResult(TestResult.FAILURE)
- withResult(TestResult.ERROR);
}
public int withFailureOrError() {
return withResult(TestResult.FAILURE) + withResult(TestResult.ERROR);
}
public int withAnyResult() {
return testOutcomes.getTotal();
}
}
}