package org.easyb.listener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.easyb.BehaviorStep;
import org.easyb.result.Result;
import org.easyb.util.BehaviorStepType;
/**
* this centralizes the counting all in one place.
*/
public class ResultsReporter {
protected BehaviorStep genesisStep;
private static final List<BehaviorStepType> EXAMINE_FURTHER = Arrays.asList(BehaviorStepType.WHERE, BehaviorStepType.EXECUTE, BehaviorStepType.GENESIS);
private static final List<BehaviorStepType> LEGAL_BUT_WEIRD = Arrays.asList(BehaviorStepType.WHEN, BehaviorStepType.GIVEN, BehaviorStepType.THEN);
private static final List<BehaviorStepType> IGNORE = Arrays.asList(BehaviorStepType.DESCRIPTION, BehaviorStepType.NARRATIVE, BehaviorStepType.NARRATIVE_ROLE,
BehaviorStepType.NARRATIVE_FEATURE, BehaviorStepType.NARRATIVE_BENEFIT, BehaviorStepType.EXTENSION_POINT);
public class StoryCollection {
BehaviorStep story;
List<BehaviorStep> scenarios = new ArrayList<BehaviorStep>();
List<BehaviorStep> afters = new ArrayList<BehaviorStep>();
List<BehaviorStep> befores = new ArrayList<BehaviorStep>();
BehaviorStep fakeScenario = null; // holder for random given/then/when in a story which is legal syntax but.. weird.
public StoryCollection(BehaviorStep story) {
this.story = story;
}
public long getFailedScenarioCount() {
return status(scenarios, Result.FAILED);
}
public long getPendingScenarioCount() {
return status(scenarios, Result.PENDING);
}
public long getScenarioCount() {
return scenarios.size();
}
private long status(List<BehaviorStep> scenarios, Result.Type status) {
long count = 0;
for (BehaviorStep step : scenarios) {
if (step.getResult() != null && step.getResult().status() == status) {
count++;
}
}
return count; //To change body of created methods use File | Settings | File Templates.
}
public long storyStatus(Result.Type status) {
return status(scenarios, status);
}
public long typeCount(BehaviorStepType type, Result.Type status) {
long count = 0;
for (BehaviorStep step : scenarios) {
for (BehaviorStep child : step.getChildSteps()) {
if (child.getStepType() == type && ( child.getResult() != null && child.getResult().status() == status )) {
count++;
}
}
}
return count;
}
}
public class SpecificationCollection {
BehaviorStep specification;
List<BehaviorStep> its = new ArrayList<BehaviorStep>();
List<BehaviorStep> befores = new ArrayList<BehaviorStep>();
List<BehaviorStep> afters = new ArrayList<BehaviorStep>();
public SpecificationCollection(BehaviorStep s) {
this.specification = s;
}
public long getSpecificationCount() {
return its.size();
}
public long getFailedSpecificationCount() {
return status(its, Result.FAILED);
}
public long getPendingSpecificationCount() {
return status(its, Result.PENDING);
}
private long status(List<BehaviorStep> specs, Result.Type status) {
long count = 0;
for (BehaviorStep step : specs) {
if (step.getResult() != null && step.getResult().status() == status) {
count++;
}
}
return count; //To change body of created methods use File | Settings | File Templates.
}
public long specificationStatus(Result.Type status) {
return status(its, status);
}
}
List<SpecificationCollection> specifications = new ArrayList<SpecificationCollection>();
List<StoryCollection> stories = new ArrayList<StoryCollection>();
public ResultsReporter(BehaviorStep g) {
genesisStep = g;
spelunk(genesisStep);
}
public StoryCollection findStory(BehaviorStep step) {
for( StoryCollection sc : stories ) {
if ( sc.story == step )
return sc;
}
throw new RuntimeException( "Request for non-existent story " + step);
}
public SpecificationCollection findSpecification(BehaviorStep step) {
for( SpecificationCollection sc : specifications ) {
if ( sc.specification == step)
return sc;
}
throw new RuntimeException( "Request for non-existent specification" + step);
}
public long getStoryBehaviorCount() {
return stories.size();
}
public long getSpecificationBehaviorCount() {
return specifications.size();
}
public List<SpecificationCollection> getSpecifications() {
return specifications;
}
public List<StoryCollection> getStories() {
return stories;
}
/*
public List<BehaviorStep> getSpecifications() {
List<BehaviorStep> specs = new ArrayList<BehaviorStep>();
for( SpecificationCollection sc : specifications ) {
specs.add(sc.specification);
}
return specs;
}
public List<BehaviorStep> getStories() {
List<BehaviorStep> st = new ArrayList<BehaviorStep>();
for( StoryCollection sc : stories ) {
st.add(sc.story);
}
return st;
}
*/
private void spelunk(BehaviorStep step) {
if (step.getStepType() == BehaviorStepType.STORY) {
StoryCollection sc = new StoryCollection(step);
collectStories(sc, step);
stories.add(sc);
} else if (step.getStepType() == BehaviorStepType.SPECIFICATION) {
SpecificationCollection sc = new SpecificationCollection(step);
collectSpecifications(sc, step);
specifications.add(sc);
} else if (step.getStepType() == BehaviorStepType.GENESIS) {
for (BehaviorStep child : step.getChildSteps() ) {
spelunk(child);
}
} else if (!IGNORE.contains(step.getStepType())) {
throw new RuntimeException( "Unknown step " + step);
}
}
private void collectSpecifications(SpecificationCollection sc, BehaviorStep step) {
for (BehaviorStep child : step.getChildSteps()) {
examineSpecificationStep(sc, child);
}
}
private void examineSpecificationStep(SpecificationCollection sc, BehaviorStep child) {
if (EXAMINE_FURTHER.contains(child.getStepType())) {
collectSpecifications(sc, child);
} else if (child.getStepType() == BehaviorStepType.IT) {
sc.its.add(child);
} else if (child.getStepType() == BehaviorStepType.BEFORE) {
sc.befores.add(child);
} else if (child.getStepType() == BehaviorStepType.AFTER) {
sc.afters.add(child);
} else if (!IGNORE.contains(child.getStepType())) {
throw new RuntimeException( "Unknown step " + child);
}
}
private void collectStories(StoryCollection sc, BehaviorStep step) {
// if we were to fix the stories so that if before/after were pending, scenarios were as well, we'd do it here.
for (BehaviorStep child : step.getChildSteps()) {
examineStoryStep(sc, child);
}
}
private void examineStoryStep(StoryCollection sc, BehaviorStep child) {
if (EXAMINE_FURTHER.contains(child.getStepType())) {
collectStories(sc, child);
} else if (child.getStepType() == BehaviorStepType.SCENARIO) {
sc.scenarios.add(child);
fixScenarioStatus(child);
} else if (child.getStepType() == BehaviorStepType.BEFORE) {
sc.befores.add(child);
fixScenarioStatus(child);
} else if (child.getStepType() == BehaviorStepType.AFTER) {
sc.afters.add(child);
fixScenarioStatus(child);
} else if (LEGAL_BUT_WEIRD.contains(child.getStepType())) {
if ( sc.fakeScenario == null ) {
sc.fakeScenario = new BehaviorStep(BehaviorStepType.SCENARIO, "fake");
sc.scenarios.add(sc.fakeScenario);
}
sc.fakeScenario.addChildStep(child);
fixScenarioStatus(sc.fakeScenario);
} else if (!IGNORE.contains(child.getStepType())) {
throw new RuntimeException( "Unknown step " + child);
}
}
public static void fixScenarioStatus(BehaviorStep child) {
// if its ignored, don't care about whats inside it
if (child.getResult() != null && child.getResult().status() == Result.IGNORED) {
return;
}
// failed trumps pending
if (fixScenarioStatus(child, Result.FAILED) > 0) {
child.setResult(new Result(Result.FAILED));
} else if (fixScenarioStatus(child, Result.PENDING) > 0) {
child.setResult(new Result(Result.PENDING));
} else if (child.getResult() == null) {
child.setResult(new Result(Result.SUCCEEDED));
}
}
private static int fixScenarioStatus(BehaviorStep step, Result.Type status) {
int count = 0;
for (BehaviorStep child : step.getChildSteps()) {
if (child.getStepType() == BehaviorStepType.BEFORE_EACH || child.getStepType() == BehaviorStepType.AFTER_EACH) {
int subCount = fixScenarioStatus(child, status);
// set the correct status while we are at it
if (subCount > 0)
child.setResult(new Result(status));
count += subCount;
} else if (child.getResult() != null && child.getResult().status() == status) {
count++;
}
}
return count;
}
private long specificationStatus(Result.Type status) {
long count = 0;
for (SpecificationCollection spec : specifications) {
count += spec.specificationStatus(status);
}
return count;
}
private long scenarioStatus(Result.Type status) {
long count = 0;
for (StoryCollection story : stories) {
count += story.storyStatus(status);
}
return count;
}
public long getFailedSpecificationCount() {
return specificationStatus(Result.FAILED);
}
public long getFailedScenarioCount() {
return scenarioStatus(Result.FAILED);
}
public long getIgnoredScenarioCount() {
return scenarioStatus(Result.IGNORED);
}
public long getSuccessBehaviorCount() {
return scenarioStatus(Result.SUCCEEDED) + specificationStatus(Result.SUCCEEDED);
}
public long getSuccessScenarioCount() {
return scenarioStatus(Result.SUCCEEDED);
}
public long getSuccessSpecificationCount() {
return specificationStatus(Result.SUCCEEDED);
}
public long getPendingSpecificationCount() {
return specificationStatus(Result.PENDING);
}
public long getPendingScenarioCount() {
return scenarioStatus(Result.PENDING);
}
public long getSpecificationCount() {
long count = 0;
for (SpecificationCollection spec : specifications) {
count += spec.its.size();
}
return count;
}
public long getScenarioCount() {
long count = 0;
for (StoryCollection story : stories) {
count += story.scenarios.size();
}
return count;
}
public long getBehaviorCount() {
return getScenarioCount() + getSpecificationCount();
}
public long getFailedBehaviorCount() {
return getFailedScenarioCount() + getFailedSpecificationCount();
}
public long getPendingBehaviorCount() {
return getPendingScenarioCount() + getPendingSpecificationCount();
}
public long getTotalBeforeCount(Result.Type type) {
long count = 0;
for (SpecificationCollection spec : specifications) {
count += spec.status(spec.befores, type);
}
for (StoryCollection story : stories) {
count += story.status(story.befores, type);
}
return count;
}
public long getTotalBeforeEachCount(Result.Type type) {
long count = 0;
for (StoryCollection story : stories) {
count += story.typeCount(BehaviorStepType.BEFORE_EACH, type);
}
return count;
}
public long getTotalAfterCount(Result.Type type) {
long count = 0;
for (SpecificationCollection spec : specifications) {
count += spec.status(spec.afters, type);
}
for (StoryCollection story : stories) {
count += story.status(story.afters, type);
}
return count;
}
public long getTotalAfterEachCount(Result.Type type) {
long count = 0;
for (StoryCollection story : stories) {
count += story.typeCount(BehaviorStepType.AFTER_EACH, type);
}
return count;
}
public long getInReviewScenarioCount() {
throw new RuntimeException("what is InReview???");
//return genesisStep.getInReviewScenarioCountRecursively();
}
public BehaviorStep getGenesisStep() {
return genesisStep;
}
public String getSpecificationResultsAsText() {
return ( getSpecificationCount() == 1 ? "1 specification" : getSpecificationCount() + " specifications" ) +
( getPendingSpecificationCount() > 0 ? " (including " + getPendingSpecificationCount() + " pending)" : "" ) + " executed" +
( getFailedSpecificationCount() > 0 ? ", but status is failure! Total failures: " + getFailedSpecificationCount() : " successfully." );
}
public String getScenarioResultsAsText() {
// if (getInReviewScenarioCount() > 0) {
// return getInReviewScenarioCount() + " scenarios in review";
// } else {
long scenariosExecuted = getScenarioCount() - getIgnoredScenarioCount();
return ( scenariosExecuted == 1 ? "1 scenario" : scenariosExecuted +
( getIgnoredScenarioCount() > 0 ? " of " + getScenarioCount() : "" ) + " scenarios" ) +
( getPendingScenarioCount() > 0 ? " (including " + getPendingScenarioCount() + " pending)" : "" ) + " executed" +
( getFailedScenarioCount() > 0 ? ", but status is failure! Total failures: " + getFailedScenarioCount() : " successfully." );
// }
}
}