package org.easyb.junit; import org.easyb.BehaviorStep; import org.easyb.domain.Behavior; import org.easyb.listener.ExecutionListenerAdaptor; import org.easyb.result.Result; import org.easyb.util.BehaviorStepType; import org.junit.runner.Description; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; import java.util.Arrays; import java.util.List; import static org.easyb.junit.RunProperties.isEclipse; import static org.easyb.junit.RunProperties.isIDEA; import static org.easyb.util.BehaviorStepType.*; import static org.junit.runner.Description.createSuiteDescription; public class JUnitExecutionListener extends ExecutionListenerAdaptor { private static final List<BehaviorStepType> typesToTrack = Arrays.asList(SCENARIO, GIVEN, WHEN, THEN, AND, IT, BEFORE, AFTER); private final Description behaviorDescription; private Description scenarioDescription; private final RunNotifier notifier; private BehaviorStep behaviorStep; private Description currentDescription; private boolean stepRunning; private static int counter; public JUnitExecutionListener(Description behaviorDescription, RunNotifier notifier) { this.behaviorDescription = behaviorDescription; this.notifier = notifier; } public void gotResult(Result result) { testForFailure(result); } private void testForFailure(Result result) { if (result.failed()) { notifier.fireTestFailure(new Failure(currentDescription, result.cause)); final Throwable cause = result.cause; String msg = cause == null? "unknown cause" : cause.getMessage(); System.out.print(" -> Failed: " + msg); } } public void startStep(BehaviorStep behaviorStep) { if (shouldStart(behaviorStep)) { this.behaviorStep = behaviorStep; startBehaviorStep(); } } private boolean shouldStart(BehaviorStep behaviorStep) { return typesToTrack.contains(behaviorStep.getStepType()); } @Override public void startBehavior(Behavior behavior) { System.out.println(behavior.getPhrase()); } private void startBehaviorStep() { stopStepIfRunning(); if (behaviorStep.getStepType() == SCENARIO) System.out.println(); if (shouldPrintDescription()) System.out.print(getStepDescriptionText()); createStepDescription(); notifier.fireTestStarted(currentDescription); stepRunning = true; } private boolean shouldPrintDescription() { return behaviorStep.getStepType() != BEFORE && behaviorStep.getStepType() != AFTER; } public void stopStep() { stopStepIfRunning(); } private void stopStepIfRunning() { if (stepRunning) { notifier.fireTestFinished(currentDescription); stepRunning = false; if (shouldPrintDescription()) System.out.println(); } } private void createStepDescription() { if (behaviorStep.getStepType() == SCENARIO && (isEclipse() || isIDEA()) ) { scenarioDescription = createSuiteDescription(getStepDescriptionText()); behaviorDescription.addChild(scenarioDescription); currentDescription = scenarioDescription; } else { currentDescription = createSuiteDescription(getStepDescriptionText() + "(" + getBehaviorHiddenName() + ")"); if (scenarioDescription == null) { behaviorDescription.addChild(currentDescription); } else { scenarioDescription.addChild(currentDescription); } } } /* * This is a bit of a hack, but in order to make sure the description for a * step is unique in Eclipse here we are just incrementing a number as the * behavior hidden name. But we don't want to do this when jUnit is being * run through Ant because ant can handle duplicate descriptions names just * fine, and using the counter will mess up the Ant output. */ private String getBehaviorHiddenName() { return isEclipse() ? String.valueOf(counter++) : behaviorDescription.getDisplayName(); } private String getStepDescriptionText() { return format(behaviorStep.getStepType()) + " " + behaviorStep.getName(); } private String format(BehaviorStepType type) { return typeShouldHaveSemiColon(type) ? type.type() + ":" : type.type(); } private boolean typeShouldHaveSemiColon(BehaviorStepType type) { return type == SCENARIO || type == BEFORE || type == AFTER; } public void stopBehavior(BehaviorStep behaviorStep, Behavior behavior) { stopStepIfRunning(); System.out.println(); System.out.println(); } }