Skip to content

Commit

Permalink
[Android] Updated android for the use of Gherkin v4.0.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
brasmusson committed Dec 18, 2016
1 parent d66b876 commit de5fe34
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 561 deletions.
Expand Up @@ -2,11 +2,15 @@

import android.app.Instrumentation;
import android.os.Bundle;
import cucumber.api.Result;
import cucumber.api.TestCase;
import cucumber.api.event.EventHandler;
import cucumber.api.event.EventPublisher;
import cucumber.api.event.TestCaseFinished;
import cucumber.api.event.TestCaseStarted;
import cucumber.api.event.TestStepFinished;
import cucumber.api.formatter.Formatter;
import cucumber.runtime.Runtime;
import gherkin.formatter.model.Feature;
import gherkin.formatter.model.Match;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Scenario;

import java.io.PrintWriter;
import java.io.StringWriter;
Expand All @@ -30,7 +34,7 @@
* hook threw an exception other than an {@link AssertionError}</li>
* </ul>
*/
public class AndroidInstrumentationReporter extends NoOpFormattingReporter {
public class AndroidInstrumentationReporter implements Formatter {

/**
* Tests status keys.
Expand Down Expand Up @@ -74,9 +78,44 @@ public static class StatusCodes {
private Result severestResult;

/**
* The feature of the current test execution.
* The location in the feature file of the current test case.
*/
private Feature currentFeature;
private String currentPath;

/**
* The name of the current test case.
*/
private String currentTestCaseName;

/**
* The event handler for the {@link TestCaseStarted} events.
*/
private final EventHandler<TestCaseStarted> testCaseStartedHandler = new EventHandler<TestCaseStarted>() {
@Override
public void receive(TestCaseStarted event) {
startTestCase(event.testCase);
}
};

/**
* The event handler for the {@link TestStepFinished} events.
*/
private final EventHandler<TestStepFinished> testStepFinishedHandler = new EventHandler<TestStepFinished>() {
@Override
public void receive(TestStepFinished event) {
finishTestStep(event.result);
}
};

/**
* The event handler for the {@link TestCaseFinished} events.
*/
private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
@Override
public void receive(TestCaseFinished event) {
finishTestCase();
}
};

/**
* Creates a new instance for the given parameters
Expand All @@ -96,36 +135,26 @@ public AndroidInstrumentationReporter(
}

@Override
public void feature(final Feature feature) {
currentFeature = feature;
public void setEventPublisher(final EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, testCaseStartedHandler);
publisher.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
publisher.registerHandlerFor(TestStepFinished.class, testStepFinishedHandler);
}

@Override
public void startOfScenarioLifeCycle(final Scenario scenario) {
void startTestCase(final TestCase testCase) {
currentPath = testCase.getPath();
currentTestCaseName = testCase.getName();
resetSeverestResult();
final Bundle testStart = createBundle(currentFeature, scenario);
final Bundle testStart = createBundle(currentPath, currentTestCaseName);
instrumentation.sendStatus(StatusCodes.START, testStart);
}

@Override
public void before(final Match match, final Result result) {
checkAndSetSeverestStepResult(result);
}

@Override
public void result(final Result result) {
void finishTestStep(final Result result) {
checkAndSetSeverestStepResult(result);
}

@Override
public void after(final Match match, final Result result) {
checkAndSetSeverestStepResult(result);
}

@Override
public void endOfScenarioLifeCycle(final Scenario scenario) {

final Bundle testResult = createBundle(currentFeature, scenario);
void finishTestCase() {
final Bundle testResult = createBundle(currentPath, currentTestCaseName);

if (severestResult.getStatus().equals(Result.FAILED)) {

Expand All @@ -149,7 +178,7 @@ public void endOfScenarioLifeCycle(final Scenario scenario) {
return;
}

if (severestResult.getStatus().equals(Result.UNDEFINED.getStatus())) {
if (severestResult.getStatus().equals(Result.UNDEFINED)) {
testResult.putString(StatusKeys.STACK, getStackTrace(new MissingStepDefinitionError(getLastSnippet())));
instrumentation.sendStatus(StatusCodes.ERROR, testResult);
return;
Expand All @@ -161,15 +190,15 @@ public void endOfScenarioLifeCycle(final Scenario scenario) {
/**
* Creates a template bundle for reporting the start and end of a test.
*
* @param feature the {@link Feature} of the current execution
* @param scenario the {@link Scenario} of the current execution
* @param path of the feature file of the current execution
* @param name of the test case of the current execution
* @return the new {@link Bundle}
*/
private Bundle createBundle(final Feature feature, final Scenario scenario) {
private Bundle createBundle(final String path, final String testCaseName) {
final Bundle bundle = new Bundle();
bundle.putInt(StatusKeys.NUMTESTS, numberOfTests);
bundle.putString(StatusKeys.CLASS, String.format("%s %s", feature.getKeyword(), feature.getName()));
bundle.putString(StatusKeys.TEST, String.format("%s %s", scenario.getKeyword(), scenario.getName()));
bundle.putString(StatusKeys.CLASS, String.format("%s", path));
bundle.putString(StatusKeys.TEST, String.format("%s", testCaseName));
return bundle;
}

Expand Down
@@ -1,19 +1,18 @@
package cucumber.runtime.android;

import android.util.Log;
import cucumber.api.event.EventHandler;
import cucumber.api.event.EventPublisher;
import cucumber.api.event.TestCaseStarted;
import cucumber.api.event.TestRunFinished;
import cucumber.api.event.TestStepStarted;
import cucumber.api.formatter.Formatter;
import cucumber.runtime.Runtime;
import gherkin.formatter.model.Background;
import gherkin.formatter.model.Examples;
import gherkin.formatter.model.Feature;
import gherkin.formatter.model.Scenario;
import gherkin.formatter.model.ScenarioOutline;
import gherkin.formatter.model.Step;
import java.util.List;

/**
* Logs information about the currently executed statements to androids logcat.
*/
public class AndroidLogcatReporter extends NoOpFormattingReporter {
public class AndroidLogcatReporter implements Formatter {

/**
* The {@link cucumber.runtime.Runtime} to get the errors and snippets from for writing them to the logcat at the end of the execution.
Expand All @@ -26,9 +25,43 @@ public class AndroidLogcatReporter extends NoOpFormattingReporter {
private final String logTag;

/**
* Holds the feature's uri.
* The event handler that logs the {@link TestCaseStarted} events.
*/
private String uri;
private final EventHandler<TestCaseStarted> testCaseStartedHandler = new EventHandler<TestCaseStarted>() {
@Override
public void receive(TestCaseStarted event) {
Log.d(logTag, String.format("%s", event.testCase.getName()));
}
};

/**
* The event handler that logs the {@link TestStepStarted} events.
*/
private final EventHandler<TestStepStarted> testStepStartedHandler = new EventHandler<TestStepStarted>() {
@Override
public void receive(TestStepStarted event) {
if (!event.testStep.isHook()) {
Log.d(logTag, String.format("%s", event.testStep.getStepText()));
}
}
};

/**
* The event handler that logs the {@link TestRunFinished} events.
*/
private EventHandler<TestRunFinished> runFinishHandler = new EventHandler<TestRunFinished>() {

@Override
public void receive(TestRunFinished event) {
for (final Throwable throwable : runtime.getErrors()) {
Log.e(logTag, throwable.toString());
}

for (final String snippet : runtime.getSnippets()) {
Log.w(logTag, snippet);
}
}
};

/**
* Creates a new instance for the given parameters.
Expand All @@ -42,53 +75,9 @@ public AndroidLogcatReporter(final Runtime runtime, final String logTag) {
}

@Override
public void uri(final String uri) {
this.uri = uri;
}

@Override
public void feature(final Feature feature) {
Log.d(logTag, String.format("%s: %s (%s)%n%s", feature.getKeyword(), feature.getName(), uri, feature.getDescription()));
}

@Override
public void background(final Background background) {
Log.d(logTag, background.getName());
}

@Override
public void scenario(final Scenario scenario) {
Log.d(logTag, String.format("%s: %s", scenario.getKeyword(), scenario.getName()));
}

@Override
public void scenarioOutline(final ScenarioOutline scenarioOutline) {
Log.d(logTag, String.format("%s: %s", scenarioOutline.getKeyword(), scenarioOutline.getName()));
}

@Override
public void examples(final Examples examples) {
Log.d(logTag, String.format("%s: %s", examples.getKeyword(), examples.getName()));
}

@Override
public void step(final Step step) {
Log.d(logTag, String.format("%s%s", step.getKeyword(), step.getName()));
}

@Override
public void syntaxError(final String state, final String event, final List<String> legalEvents, final String uri, final Integer line) {
Log.e(logTag, String.format("syntax error '%s' %s:%d", event, uri, line));
}

@Override
public void done() {
for (final Throwable throwable : runtime.getErrors()) {
Log.e(logTag, throwable.toString());
}

for (final String snippet : runtime.getSnippets()) {
Log.w(logTag, snippet);
}
public void setEventPublisher(final EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, testCaseStartedHandler);
publisher.registerHandlerFor(TestStepStarted.class, testStepStartedHandler);
publisher.registerHandlerFor(TestRunFinished.class, runFinishHandler);
}
}
Expand Up @@ -5,6 +5,9 @@
import android.util.Log;
import cucumber.api.CucumberOptions;
import cucumber.api.StepDefinitionReporter;
import cucumber.api.event.TestRunFinished;
import cucumber.api.formatter.Formatter;
import cucumber.api.java.ObjectFactory;
import cucumber.runtime.Backend;
import cucumber.runtime.ClassFinder;
import cucumber.runtime.CucumberException;
Expand All @@ -14,12 +17,10 @@
import cucumber.runtime.RuntimeOptionsFactory;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.java.JavaBackend;
import cucumber.api.java.ObjectFactory;
import cucumber.runtime.java.ObjectFactoryLoader;
import cucumber.runtime.model.CucumberFeature;
import dalvik.system.DexFile;
import gherkin.formatter.Formatter;
import gherkin.formatter.Reporter;
import gherkin.pickles.Pickle;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -67,9 +68,9 @@ public class CucumberExecutor {
private final Runtime runtime;

/**
* The actual {@link CucumberFeature}s to run.
* The actual {@link Pickle}s to run stored in {@link PickleStruct}s.
*/
private final List<CucumberFeature> cucumberFeatures;
private final List<PickleStruct> pickles;

/**
* Creates a new instance for the given parameters.
Expand All @@ -89,7 +90,8 @@ public CucumberExecutor(final Arguments arguments, final Instrumentation instrum

ResourceLoader resourceLoader = new AndroidResourceLoader(context);
this.runtime = new Runtime(resourceLoader, classLoader, createBackends(), runtimeOptions);
this.cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader);
List<CucumberFeature> cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader, runtime.getEventBus());
this.pickles = FeatureCompiler.compile(cucumberFeatures, this.runtime);
}

/**
Expand All @@ -102,25 +104,23 @@ public void execute() {

// TODO: This is duplicated in info.cucumber.Runtime.

final Reporter reporter = runtimeOptions.reporter(classLoader);
final Formatter formatter = runtimeOptions.formatter(classLoader);

final StepDefinitionReporter stepDefinitionReporter = runtimeOptions.stepDefinitionReporter(classLoader);
runtime.getGlue().reportStepDefinitions(stepDefinitionReporter);
runtime.reportStepDefinitions(stepDefinitionReporter);

for (final CucumberFeature cucumberFeature : cucumberFeatures) {
cucumberFeature.run(formatter, reporter, runtime);
for (final PickleStruct pickle : pickles) {
runtime.getRunner().runPickle(pickle.pickle, pickle.language);
}

formatter.done();
formatter.close();
runtime.getEventBus().send(new TestRunFinished());
}

/**
* @return the number of actual scenarios, including outlined
*/
public int getNumberOfConcreteScenarios() {
return ScenarioCounter.countScenarios(cucumberFeatures);
return pickles.size();
}

private void trySetCucumberOptionsToSystemProperties(final Arguments arguments) {
Expand Down
@@ -0,0 +1,35 @@
package cucumber.runtime.android;

import cucumber.runtime.Runtime;
import cucumber.runtime.model.CucumberFeature;
import gherkin.pickles.Compiler;
import gherkin.pickles.Pickle;

import java.util.ArrayList;
import java.util.List;

/**
* Utility class to count scenarios, including outlined.
*/
public class FeatureCompiler {

/**
* Compilers the given {@code cucumberFeatures} to {@link Pickle}s.
*
* @param cucumberFeatures the list of {@link CucumberFeature} to compile
* @return the compiled pickles in {@link PickleStruct}s
*/
public static List<PickleStruct> compile(final List<CucumberFeature> cucumberFeatures, final Runtime runtime) {
List<PickleStruct> pickles = new ArrayList<PickleStruct>();
Compiler compiler = new Compiler();
for (final CucumberFeature feature : cucumberFeatures) {
for (final Pickle pickle : compiler.compile(feature.getGherkinFeature(), feature.getPath())) {
if (runtime.matchesFilters(pickle)) {
pickles.add(new PickleStruct(pickle, feature.getLanguage()));
}
}
}
return pickles;
}

}

0 comments on commit de5fe34

Please sign in to comment.