Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=1.0.0
version=1.0.1-SNAPSHOT

artifactId=robospock
group=org.robospock
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
2 changes: 1 addition & 1 deletion robospock/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dependencies {
compile "org.spockframework:spock-core:1.0-groovy-2.4"

// Android part
compile "org.robolectric:robolectric:3.0"
compile "org.robolectric:robolectric:3.1"
provided 'com.intellij:annotations:12.0'
provided 'org.robolectric:android-all:5.0.0_r2-robolectric-1'
testCompile 'org.robolectric:android-all:5.0.0_r2-robolectric-1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;

import android.os.Looper;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.ShadowsAdapter;
Expand All @@ -15,6 +19,7 @@
import org.robolectric.internal.ParallelUniverseInterface;
import org.robolectric.internal.SdkConfig;
import org.robolectric.internal.fakes.RoboInstrumentation;
import org.robolectric.manifest.ActivityData;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.res.OverlayResourceLoader;
import org.robolectric.res.PackageResourceLoader;
Expand All @@ -23,14 +28,15 @@
import org.robolectric.res.ResourcePath;
import org.robolectric.res.RoutingResourceLoader;
import org.robolectric.res.builder.DefaultPackageManager;
import org.robolectric.shadows.ShadowActivityThread;
import org.robolectric.shadows.ShadowContextImpl;
import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowResources;
import org.robolectric.res.builder.RobolectricPackageManager;
import org.robolectric.shadows.*;
import org.robolectric.util.ApplicationTestUtil;
import org.robolectric.util.Pair;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.Scheduler;

import java.lang.reflect.Method;
import java.security.Security;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand All @@ -54,6 +60,7 @@ public class ParallelUniverseCompat implements ParallelUniverseInterface {

@Override
public void resetStaticState(Config config) {
RuntimeEnvironment.setMainThread(Thread.currentThread());
Robolectric.reset();

if (!loggingInitialized) {
Expand All @@ -80,29 +87,47 @@ private String addVersionQualifierToQualifiers(String qualifiers) {
@Override
public void setUpApplicationState(Method method, TestLifecycle testLifecycle, ResourceLoader systemResourceLoader, AndroidManifest appManifest, Config config) {
RuntimeEnvironment.application = null;
RuntimeEnvironment.setMasterScheduler(new Scheduler());
RuntimeEnvironment.setMainThread(Thread.currentThread());
RuntimeEnvironment.setRobolectricPackageManager(new DefaultPackageManager(shadowsAdapter));
RuntimeEnvironment.getRobolectricPackageManager().addPackage(DEFAULT_PACKAGE_NAME);
ResourceLoader resourceLoader;
String packageName;
if (appManifest != null) {
// robolectric
// resourceLoader = robolectricTestRunner.getAppResourceLoader(sdkConfig, systemResourceLoader, appManifest);
resourceLoader = getAppResourceLoader(sdkConfig, systemResourceLoader, appManifest);
RuntimeEnvironment.getRobolectricPackageManager().addManifest(appManifest, resourceLoader);
packageName = appManifest.getPackageName();
} else {
packageName = config.packageName() != null && !config.packageName().isEmpty() ? config.packageName() : DEFAULT_PACKAGE_NAME;
RuntimeEnvironment.getRobolectricPackageManager().addPackage(packageName);
resourceLoader = systemResourceLoader;
}

ShadowResources.setSystemResources(systemResourceLoader);
RuntimeEnvironment.setSystemResourceLoader(systemResourceLoader);
RuntimeEnvironment.setAppResourceLoader(resourceLoader);

if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}

String qualifiers = addVersionQualifierToQualifiers(config.qualifiers());
Resources systemResources = Resources.getSystem();
Configuration configuration = systemResources.getConfiguration();
shadowsAdapter.overrideQualifiers(configuration, qualifiers);
systemResources.updateConfiguration(configuration, systemResources.getDisplayMetrics());
RuntimeEnvironment.setQualifiers(qualifiers);
RuntimeEnvironment.setApiLevel(sdkConfig.getApiLevel());

Class<?> contextImplClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), ShadowContextImpl.CLASS_NAME);
Class<?> contextImplClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), shadowsAdapter.getShadowContextImplClassName());

Class<?> activityThreadClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), ShadowActivityThread.CLASS_NAME);
Class<?> activityThreadClass = ReflectionHelpers.loadClass(getClass().getClassLoader(), shadowsAdapter.getShadowActivityThreadClassName());
// Looper needs to be prepared before the activity thread is created
if (Looper.myLooper() == null) {
Looper.prepareMainLooper();
}
ShadowLooper.getShadowMainLooper().resetScheduler();
Object activityThread = ReflectionHelpers.newInstance(activityThreadClass);
RuntimeEnvironment.setActivityThread(activityThread);

Expand All @@ -112,9 +137,10 @@ public void setUpApplicationState(Method method, TestLifecycle testLifecycle, Re
Context systemContextImpl = ReflectionHelpers.callStaticMethod(contextImplClass, "createSystemContext", ClassParameter.from(activityThreadClass, activityThread));

final Application application = (Application) testLifecycle.createApplication(method, appManifest, config);
RuntimeEnvironment.application = application;

if (application != null) {
String packageName = appManifest != null ? appManifest.getPackageName() : null;
if (packageName == null) packageName = DEFAULT_PACKAGE_NAME;
shadowsAdapter.bind(application, appManifest);

ApplicationInfo applicationInfo;
try {
Expand All @@ -130,29 +156,50 @@ public void setUpApplicationState(Method method, TestLifecycle testLifecycle, Re
ClassParameter.from(compatibilityInfoClass, null),
ClassParameter.from(int.class, Context.CONTEXT_INCLUDE_CODE));

shadowsAdapter.bind(application, appManifest, resourceLoader);
if (appManifest == null) {
// todo: make this cleaner...
shadowsAdapter.setPackageName(application, applicationInfo.packageName);
}
Resources appResources = application.getResources();
ReflectionHelpers.setField(loadedApk, "mResources", appResources);
try {
Context contextImpl = systemContextImpl.createPackageContext(applicationInfo.packageName, Context.CONTEXT_INCLUDE_CODE);
ReflectionHelpers.setField(activityThreadClass, activityThread, "mInitialApplication", application);
ReflectionHelpers.callInstanceMethod(Application.class, application, "attach", ReflectionHelpers.ClassParameter.from(Context.class, contextImpl));
ApplicationTestUtil.attach(application, contextImpl);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}

addManifestActivitiesToPackageManager(appManifest, application);

Resources appResources = application.getResources();
ReflectionHelpers.setField(loadedApk, "mResources", appResources);
ReflectionHelpers.setField(loadedApk, "mApplication", application);

appResources.updateConfiguration(configuration, appResources.getDisplayMetrics());
shadowsAdapter.setAssetsQualifiers(appResources.getAssets(), qualifiers);

RuntimeEnvironment.application = application;
application.onCreate();
}
}

private void addManifestActivitiesToPackageManager(AndroidManifest appManifest, Application application) {
if (appManifest != null) {
Map<String,ActivityData> activityDatas = appManifest.getActivityDatas();

RobolectricPackageManager packageManager = (RobolectricPackageManager) application.getPackageManager();

for (ActivityData data : activityDatas.values()) {
String name = data.getName();
String activityName = name.startsWith(".") ? appManifest.getPackageName() + name : name;
packageManager.addResolveInfoForIntent(new Intent(activityName), new ResolveInfo());
}
}
}

@Override
public Thread getMainThread() {
return RuntimeEnvironment.getMainThread();
}

@Override
public void setMainThread(Thread newMainThread) {
RuntimeEnvironment.setMainThread(newMainThread);
}

@Override
public void tearDownApplication() {
if (RuntimeEnvironment.application != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ protected AndroidManifest createAppManifest(FsFile manifestFile, FsFile resDir,
public InstrumentationConfiguration createClassLoaderConfig() {
return InstrumentationConfiguration.newBuilder()
// .doNotAquireClass(ShadowMap.class.getName())
.doNotAquireClass(DependencyResolver.class.getName())
.doNotAcquireClass(DependencyResolver.class.getName())
.build();
}

Expand Down
13 changes: 8 additions & 5 deletions sample/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
buildscript {
repositories {
jcenter()
maven {
url "https://jitpack.io"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.6'
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0'
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.10'
classpath "com.github.JakeWharton:sdk-manager-plugin:e05218601b1274ea0721e13b33a426f641156f69"
}
}

Expand All @@ -20,8 +23,8 @@ repositories {
}

android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
compileSdkVersion 23
buildToolsVersion "23.0.3"

defaultConfig {
versionCode 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.example.robospock.web;

import org.apache.http.client.ClientProtocolException;

import java.io.File;
import java.io.IOException;

public interface WebInterface {
String execute(String resource) throws IllegalStateException, ClientProtocolException, IOException;
String execute(String resource) throws IllegalStateException, IOException;

File downloadFile(String resource, String path) throws ClientProtocolException, IOException;
File downloadFile(String resource, String path) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
package com.example.robospock.web;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

public class WebInterfaceImpl implements WebInterface {
@Override
public String execute(final String resource) throws IllegalStateException, ClientProtocolException, IOException {
public String execute(final String resource) throws IllegalStateException, IOException {
final InputStream content = getStream(resource);
return convertStreamToString(content);
}

@Override
public File downloadFile(final String resource, final String path) throws ClientProtocolException, IOException {
public File downloadFile(final String resource, final String path) throws IOException {
final InputStream content = getStream(resource);
final File file = new File(path);
saveStreamToFile(content, file);
return file;

}

private InputStream getStream(final String resource) throws IOException, ClientProtocolException {
return new DefaultHttpClient().execute(new HttpGet(resource)).getEntity().getContent();
private InputStream getStream(final String resource) throws IOException {
URL url = new URL(resource);
HttpURLConnection connection = null;
connection = (HttpURLConnection) url.openConnection();
connection.connect();

// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage());
}
return connection.getInputStream();
}

public static String convertStreamToString(final InputStream is) throws IOException {
Expand Down