Skip to content

Commit

Permalink
added documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
SierraGolf committed Aug 31, 2014
1 parent b7645de commit e8a54b1
Show file tree
Hide file tree
Showing 17 changed files with 326 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,27 @@
import android.app.Instrumentation;
import android.os.Bundle;

/**
* A simple extension of the {@link android.app.Instrumentation} utilizing the {@link cucumber.api.android.CucumberInstrumentationCore}.
*/
public class CucumberInstrumentation extends Instrumentation {

private CucumberInstrumentationCore instrumentationCore = new CucumberInstrumentationCore(this);
/**
* The {@link cucumber.api.android.CucumberInstrumentationCore} which will run the actual logic using this {@link android.app.Instrumentation}
* implementation.
*/
private CucumberInstrumentationCore cucumberInstrumentationCore = new CucumberInstrumentationCore(this);

@Override
public void onCreate(final Bundle arguments) {
super.onCreate(arguments);
instrumentationCore.create(arguments);
public void onCreate(final Bundle bundle) {
super.onCreate(bundle);
cucumberInstrumentationCore.create(bundle);
start();
}

@Override
public void onStart() {
instrumentationCore.start();
cucumberInstrumentationCore.start();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,84 @@
import cucumber.runtime.android.Arguments;
import cucumber.runtime.android.CoverageDumper;
import cucumber.runtime.android.CucumberExecutor;
import cucumber.runtime.android.Waiter;
import cucumber.runtime.android.DebuggerWaiter;


/**
* The composition based instrumentation logic for running cucumber scenarios.
*/
public class CucumberInstrumentationCore {

/**
* The value to be used for the {@link Instrumentation#REPORT_KEY_IDENTIFIER}.
*/
public static final String REPORT_VALUE_ID = CucumberInstrumentationCore.class.getSimpleName();

/**
* The report key for storing the number of to be executed scenarios.
*/
public static final String REPORT_KEY_NUM_TOTAL = "numtests";

/**
* The {@link android.app.Instrumentation} to report results to.
*/
private final Instrumentation instrumentation;
private Waiter waiter;

/**
* Used to wait for the debugger to be attached before actually running the scenarios.
*/
private DebuggerWaiter debuggerWaiter;

/**
* Used to dump code coverage results at the end of the test execution
*/
private CoverageDumper coverageDumper;

/**
* Responsible for the actual execution of the scenarios.
*/
private CucumberExecutor cucumberExecutor;

/**
* Holds all cucumber relevant arguments passed to the {@link android.app.Instrumentation} inside the {@link Bundle}.
*/
private Arguments arguments;

/**
* Creates a new instance for the given {@code instrumentation}.
*
* @param instrumentation the {@link android.app.Instrumentation} to use when running scenarios
*/
public CucumberInstrumentationCore(final Instrumentation instrumentation) {
this.instrumentation = instrumentation;
}

/**
* This method should be used to forward the {@link android.app.Instrumentation#onCreate(android.os.Bundle)} parameter
* to this classes logic. It must be called before the call to {@link android.app.Instrumentation#start()}.
*
* @param bundle the bundle passed to the {@link android.app.Instrumentation#onCreate(android.os.Bundle)} method.
*/
public void create(final Bundle bundle) {
arguments = new Arguments(bundle);
cucumberExecutor = new CucumberExecutor(arguments, instrumentation);
coverageDumper = new CoverageDumper(arguments);
waiter = new Waiter(arguments);
debuggerWaiter = new DebuggerWaiter(arguments);
}

/**
* This method should be used to forward the event of the start of the instrumentation, meaning it should be called in the
* {@link android.app.Instrumentation#onStart()} method.
*/
public void start() {
Looper.prepare();

final Bundle results = new Bundle();
if (arguments.isCountEnabled()) {
results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
results.putInt(REPORT_KEY_NUM_TOTAL, cucumberExecutor.getNumberOfTests());
results.putInt(REPORT_KEY_NUM_TOTAL, cucumberExecutor.getNumberOfConcreteScenarios());
} else {
waiter.requestWaitForDebugger();
debuggerWaiter.requestWaitForDebugger();
cucumberExecutor.execute();
coverageDumper.requestDump(results);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ public static class StatusCodes {
*/
private Feature currentFeature;

/**
* Creates a new instance for the given parameters
*
* @param runtime the {@link cucumber.runtime.Runtime} to use
* @param instrumentation the {@link android.app.Instrumentation} to report statuses to
* @param numberOfTests the total number of tests to be executed, this is expected to include all scenario outline runs
*/
public AndroidInstrumentationReporter(
final Runtime runtime,
final Instrumentation instrumentation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,28 @@
* Logs information about the currently executed statements to androids logcat.
*/
public class AndroidLogcatReporter extends NoOpFormattingReporter {

/**
* The {@link cucumber.runtime.Runtime} to get the errors and snippets from for writing them to the logcat at the end of the execution.
*/
private final Runtime runtime;

/**
* The log tag to be used when logging to logcat.
*/
private final String logTag;

/**
* Holds the feature's uri.
*/
private String uri;

/**
* Creates a new instance for the given parameters.
*
* @param runtime the {@link cucumber.runtime.Runtime} to get the errors and snippets from
* @param logTag the tag to use for logging to logcat
*/
public AndroidLogcatReporter(final Runtime runtime, final String logTag) {
this.runtime = runtime;
this.logTag = logTag;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,59 @@
import android.test.InstrumentationTestCase;
import cucumber.runtime.java.ObjectFactory;

/**
* Android specific implementation of {@link cucumber.runtime.java.ObjectFactory} which will
* make sure that created test classes have all necessary references to the executing {@link android.app.Instrumentation}
* and the associated {@link android.content.Context}.
*/
public class AndroidObjectFactory implements ObjectFactory {

/**
* The actual {@link cucumber.runtime.java.ObjectFactory} responsible for creating instances.
*/
private final ObjectFactory delegate;

/**
* The instrumentation to set to the objects.
*/
private final Instrumentation instrumentation;

/**
* Creates a new instance using the given delegate {@link cucumber.runtime.java.ObjectFactory} to
* forward all calls to and using the given {@link android.app.Instrumentation} to set to the instantiated
* android test classes.
*
* @param delegate the {@link cucumber.runtime.java.ObjectFactory} to delegate to
* @param instrumentation the {@link android.app.Instrumentation} to set to the tests
*/
public AndroidObjectFactory(final ObjectFactory delegate, final Instrumentation instrumentation) {
this.delegate = delegate;
this.instrumentation = instrumentation;
}

@Override
public void start() {
delegate.start();
}

@Override
public void stop() {
delegate.stop();
}

@Override
public void addClass(final Class<?> clazz) {
delegate.addClass(clazz);
}

@Override
public <T> T getInstance(final Class<T> type) {
T instance = delegate.getInstance(type);
decorate(instance);
return instance;
}

private void decorate(Object instance) {
private void decorate(final Object instance) {
if (instance instanceof ActivityInstrumentationTestCase2) {
final ActivityInstrumentationTestCase2 activityInstrumentationTestCase2 = (ActivityInstrumentationTestCase2) instance;
activityInstrumentationTestCase2.injectInstrumentation(instrumentation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,28 @@
import java.io.IOException;
import java.io.InputStream;

class AndroidResource implements Resource {
/**
* Android specific implementation of {@link cucumber.runtime.io.Resource} which is apple
* to create {@link java.io.InputStream}s for android assets.
*/
public class AndroidResource implements Resource {

/**
* The {@link android.content.Context} to get the {@link java.io.InputStream} from
*/
private final Context context;

/**
* The path of the resource.
*/
private final String path;

/**
* Creates a new instance for the given parameters.
*
* @param context the {@link android.content.Context} to create the {@link java.io.InputStream} from
* @param path the path to the ressource
*/
public AndroidResource(final Context context, final String path) {
this.context = context;
this.path = path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,25 @@
import java.util.List;

/**
* Loads non-class resources such as .feature files.
* Android specific implementation of {@link cucumber.runtime.io.ResourceLoader} which loads non-class resources such as .feature files.
*/
public class AndroidResourceLoader implements ResourceLoader {

/**
* The format of the resource path.
*/
public static final String RESOURCE_PATH_FORMAT = "%s/%s";

/**
* The {@link android.content.Context} to get the resources from.
*/
private final Context context;

/**
* Creates a new instance for the given parameter.
*
* @param context the {@link android.content.Context} to get resources from
*/
public AndroidResourceLoader(final Context context) {
this.context = context;
}
Expand Down
20 changes: 11 additions & 9 deletions android/src/main/java/cucumber/runtime/android/CoverageDumper.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ public CoverageDumper(final Arguments arguments) {
}

/**
* Dumps the coverage data into the given file.
* Dumps the coverage data into the given file, if code coverage is enabled.
*
* @param bundle the {@link Bundle} to put coverage information into
*/
public void requestDump(final Bundle results) {
public void requestDump(final Bundle bundle) {

if (!arguments.isCoverageEnabled()) {
return;
Expand All @@ -74,18 +76,18 @@ public void requestDump(final Bundle results) {
final Method dumperMethod = dumperClass.getMethod(IMPLEMENTATION_METHOD, coverageFile.getClass(), boolean.class, boolean.class);
dumperMethod.invoke(null, coverageFile, false, false);

results.putString(RESULT_KEY_COVERAGE_PATH, coverageDateFilePath);
appendNewLineToResultStream(results, String.format(RESULT_STREAM_SUCCESS_OUTPUT_FORMAT, coverageDateFilePath));
bundle.putString(RESULT_KEY_COVERAGE_PATH, coverageDateFilePath);
appendNewLineToResultStream(bundle, String.format(RESULT_STREAM_SUCCESS_OUTPUT_FORMAT, coverageDateFilePath));
} catch (final ClassNotFoundException e) {
reportError(results, e);
reportError(bundle, e);
} catch (final SecurityException e) {
reportError(results, e);
reportError(bundle, e);
} catch (final NoSuchMethodException e) {
reportError(results, e);
reportError(bundle, e);
} catch (final IllegalAccessException e) {
reportError(results, e);
reportError(bundle, e);
} catch (final InvocationTargetException e) {
reportError(results, e);
reportError(bundle, e);
}
}

Expand Down
Loading

0 comments on commit e8a54b1

Please sign in to comment.