package cucumber.runtime;
import cucumber.api.PendingException;
import cucumber.runtime.formatter.StepMatcher;
import cucumber.runtime.io.ClasspathResourceLoader;
import cucumber.runtime.io.Resource;
import cucumber.runtime.model.CucumberFeature;
import gherkin.I18n;
import gherkin.formatter.Formatter;
import gherkin.formatter.Reporter;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;
import junit.framework.AssertionFailedError;
import org.junit.Ignore;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.*;
import static java.util.Arrays.asList;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyCollectionOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.*;
@Ignore
public class TestHelper {
private TestHelper() {
}
public static CucumberFeature feature(final String path, final String source) throws IOException {
ArrayList<CucumberFeature> cucumberFeatures = new ArrayList<CucumberFeature>();
FeatureBuilder featureBuilder = new FeatureBuilder(cucumberFeatures);
featureBuilder.parse(new Resource() {
@Override
public String getPath() {
return path;
}
@Override
public String getAbsolutePath() {
throw new UnsupportedOperationException();
}
@Override
public InputStream getInputStream() {
try {
return new ByteArrayInputStream(source.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Override
public String getClassName(String extension) {
throw new UnsupportedOperationException();
}
}, new ArrayList<Object>());
return cucumberFeatures.get(0);
}
public static Result result(String status) {
if (status.equals(Result.FAILED)) {
return result(status, mockAssertionFailedError());
} else if (status.equals("pending")){
return result(status, new PendingException());
} else {
return new Result(status, 0L, null);
}
}
public static Result result(String status, Throwable error) {
return new Result(status, 0L, error, null);
}
public static void runFeatureWithFormatter(final CucumberFeature feature, final Map<String, Result> stepsToResult, final List<SimpleEntry<String, Result>> hooks,
final long stepHookDuration, final Formatter formatter, final Reporter reporter) throws Throwable, FileNotFoundException {
runFeaturesWithFormatter(Arrays.asList(feature), stepsToResult, Collections.<String,String>emptyMap(), hooks, stepHookDuration, formatter, reporter);
}
public static void runFeaturesWithFormatter(final List<CucumberFeature> features, final Map<String, Result> stepsToResult,
final List<SimpleEntry<String, Result>> hooks, final long stepHookDuration, final Formatter formatter, final Reporter reporter) throws Throwable {
runFeaturesWithFormatter(features, stepsToResult, Collections.<String,String>emptyMap(), hooks, stepHookDuration, formatter, reporter);
}
public static void runFeatureWithFormatter(final CucumberFeature feature, final Map<String, String> stepsToLocation,
final Formatter formatter, final Reporter reporter) throws Throwable { runFeaturesWithFormatter(Arrays.asList(feature), Collections.<String, Result>emptyMap(), stepsToLocation,
Collections.<SimpleEntry<String, Result>>emptyList(), 0L, formatter, reporter);
}
private static void runFeaturesWithFormatter(final List<CucumberFeature> features, final Map<String, Result> stepsToResult, final Map<String, String> stepsToLocation,
final List<SimpleEntry<String, Result>> hooks, final long stepHookDuration, final Formatter formatter,
final Reporter reporter) throws Throwable {
final RuntimeOptions runtimeOptions = new RuntimeOptions("");
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(classLoader);
final RuntimeGlue glue = createMockedRuntimeGlueThatMatchesTheSteps(stepsToResult, stepsToLocation, hooks);
final Runtime runtime = new Runtime(resourceLoader, classLoader, asList(mock(Backend.class)), runtimeOptions, new StopWatch.Stub(stepHookDuration), glue);
for (CucumberFeature feature : features) {
feature.run(formatter, reporter, runtime);
}
formatter.done();
formatter.close();
}
private static RuntimeGlue createMockedRuntimeGlueThatMatchesTheSteps(Map<String, Result> stepsToResult, Map<String, String> stepsToLocation,
final List<SimpleEntry<String, Result>> hooks) throws Throwable {
RuntimeGlue glue = mock(RuntimeGlue.class);
TestHelper.mockSteps(glue, stepsToResult, stepsToLocation);
TestHelper.mockHooks(glue, hooks);
return glue;
}
private static void mockSteps(RuntimeGlue glue, Map<String, Result> stepsToResult, Map<String, String> stepsToLocation) throws Throwable {
for (String stepName : mergeStepSets(stepsToResult, stepsToLocation)) {
Result stepResult = getResultWithDefaultPassed(stepsToResult, stepName);
if (!"undefined".equals(stepResult.getStatus())) {
StepDefinitionMatch matchStep = mock(StepDefinitionMatch.class);
when(glue.stepDefinitionMatch(anyString(), TestHelper.stepWithName(stepName), (I18n) any())).thenReturn(matchStep);
mockStepResult(stepResult, matchStep);
mockStepLocation(getLocationWithDefaultEmptyString(stepsToLocation, stepName), matchStep);
}
}
}
private static void mockStepResult(Result stepResult, StepDefinitionMatch matchStep) throws Throwable {
if ("pending".equals(stepResult.getStatus())) {
doThrow(new PendingException()).when(matchStep).runStep((I18n) any());
} else if (Result.FAILED.equals(stepResult.getStatus())) {
doThrow(stepResult.getError()).when(matchStep).runStep((I18n) any());
} else if (!Result.PASSED.equals(stepResult.getStatus()) &&
!"skipped".equals(stepResult.getStatus())) {
fail("Cannot mock step to the result: " + stepResult.getStatus());
}
}
private static void mockStepLocation(String stepLocation, StepDefinitionMatch matchStep) {
when(matchStep.getLocation()).thenReturn(stepLocation);
}
private static void mockHooks(RuntimeGlue glue, final List<SimpleEntry<String, Result>> hooks) throws Throwable {
List<HookDefinition> beforeHooks = new ArrayList<HookDefinition>();
List<HookDefinition> afterHooks = new ArrayList<HookDefinition>();
for (SimpleEntry<String, Result> hookEntry : hooks) {
TestHelper.mockHook(hookEntry, beforeHooks, afterHooks);
}
if (!beforeHooks.isEmpty()) {
when(glue.getBeforeHooks()).thenReturn(beforeHooks);
}
if (!afterHooks.isEmpty()) {
when(glue.getAfterHooks()).thenReturn(afterHooks);
}
}
private static void mockHook(SimpleEntry<String, Result> hookEntry, List<HookDefinition> beforeHooks,
List<HookDefinition> afterHooks) throws Throwable {
HookDefinition hook = mock(HookDefinition.class);
when(hook.matches(anyCollectionOf(Tag.class))).thenReturn(true);
if (hookEntry.getValue().getStatus().equals("failed")) {
doThrow(hookEntry.getValue().getError()).when(hook).execute((cucumber.api.Scenario) any());
} else if (hookEntry.getValue().getStatus().equals("pending")) {
doThrow(new PendingException()).when(hook).execute((cucumber.api.Scenario) any());
}
if ("before".equals(hookEntry.getKey())) {
beforeHooks.add(hook);
} else if ("after".equals(hookEntry.getKey())) {
afterHooks.add(hook);
} else {
fail("Only before and after hooks are allowed, hook type found was: " + hookEntry.getKey());
}
}
private static Step stepWithName(String name) {
return argThat(new StepMatcher(name));
}
private static AssertionFailedError mockAssertionFailedError() {
AssertionFailedError error = mock(AssertionFailedError.class);
Answer<Object> printStackTraceHandler = new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
PrintWriter writer = (PrintWriter) invocation.getArguments()[0];
writer.print("the stack trace");
return null;
}
};
doAnswer(printStackTraceHandler).when(error).printStackTrace((PrintWriter) any());
return error;
}
public static SimpleEntry<String, Result> hookEntry(String type, Result result) {
return new SimpleEntry<String, Result>(type, result);
}
private static Set<String> mergeStepSets(Map<String, Result> stepsToResult, Map<String, String> stepsToLocation) {
Set<String> steps = new HashSet<String>(stepsToResult.keySet());
steps.addAll(stepsToLocation.keySet());
return steps;
}
private static Result getResultWithDefaultPassed(Map<String, Result> stepsToResult, String step) {
return stepsToResult.containsKey(step) ? stepsToResult.get(step) : new Result(Result.PASSED, 0L, null);
}
private static String getLocationWithDefaultEmptyString(Map<String, String> stepsToLocation, String step) {
return stepsToLocation.containsKey(step) ? stepsToLocation.get(step) : "";
}
}