Permalink
Browse files

Merge branch 'master' of github.com:pivotal/robolectric

  • Loading branch information...
2 parents 8f06fa1 + 2f4cde0 commit 0a7ac38b1e4db868e90fec572d19dd1244d7b3db Ryan Richard and Sarah Chandler committed Oct 9, 2012
Showing with 499 additions and 60 deletions.
  1. +12 −10 build.xml
  2. +16 −2 src/main/java/com/xtremelabs/robolectric/Robolectric.java
  3. +3 −2 src/main/java/com/xtremelabs/robolectric/RobolectricConfig.java
  4. +88 −3 src/main/java/com/xtremelabs/robolectric/RobolectricTestRunner.java
  5. +15 −0 src/main/java/com/xtremelabs/robolectric/annotation/WithConstantInt.java
  6. +15 −0 src/main/java/com/xtremelabs/robolectric/annotation/WithConstantString.java
  7. +49 −5 src/main/java/com/xtremelabs/robolectric/res/RobolectricPackageManager.java
  8. +20 −3 src/main/java/com/xtremelabs/robolectric/shadows/ShadowBitmapFactory.java
  9. +9 −1 src/main/java/com/xtremelabs/robolectric/shadows/ShadowBluetoothAdapter.java
  10. +65 −5 src/main/java/com/xtremelabs/robolectric/shadows/ShadowIntentFilter.java
  11. +14 −0 src/main/java/com/xtremelabs/robolectric/shadows/ShadowParcel.java
  12. +1 −2 src/main/java/com/xtremelabs/robolectric/{ → shadows}/ShadowScrollView.java
  13. +27 −0 src/test/java/com/xtremelabs/robolectric/annotation/WithConstantIntTest.java
  14. +28 −0 src/test/java/com/xtremelabs/robolectric/annotation/WithConstantStringTest.java
  15. +1 −1 src/test/java/com/xtremelabs/robolectric/res/DrawableResourceLoaderTest.java
  16. +10 −11 src/test/java/com/xtremelabs/robolectric/res/MenuResourceLoaderTest.java
  17. +7 −6 src/test/java/com/xtremelabs/robolectric/res/ResourceLoaderTest.java
  18. +42 −5 src/test/java/com/xtremelabs/robolectric/res/RobolectricPackageManagerTest.java
  19. +40 −1 src/test/java/com/xtremelabs/robolectric/shadows/BitmapFactoryTest.java
  20. +19 −0 src/test/java/com/xtremelabs/robolectric/shadows/BluetoothAdapterTest.java
  21. +13 −0 src/test/java/com/xtremelabs/robolectric/shadows/ParcelTest.java
  22. +2 −1 src/test/java/com/xtremelabs/robolectric/shadows/ViewGroupTest.java
  23. +2 −1 src/test/java/com/xtremelabs/robolectric/util/TestUtil.java
  24. +1 −1 src/test/resources/TestAndroidManifest.xml
View
@@ -21,8 +21,10 @@
should be checked in in Version Control Systems.
-->
- <property file="build.properties"/>
+ <!-- this should match whatever is defined in Robolectic.DEFAULT_SDK_VERSION -->
+ <property name="default.sdk.version" value="16"/>
+ <property file="build.properties"/>
<!-- The default.properties file is created and updated by the 'android' tool, as well
as ADT.
This file is an integral part of the build system for your application and
@@ -52,10 +54,10 @@
</path>
<path id="android.target.classpath">
- <pathelement path="${sdk.dir}/platforms/android-16/android.jar"/>
- <pathelement path="${sdk.dir}/add-ons/addon_google_apis_google_inc_16/libs/maps.jar"/>
- <pathelement path="${sdk.dir}/add-ons/addon-google_apis-google_inc_-16/libs/maps.jar"/>
- <pathelement path="${sdk.dir}/add-ons/addon-google_apis-google-16/libs/maps.jar"/>
+ <pathelement path="${sdk.dir}/platforms/android-${default.sdk.version}/android.jar"/>
+ <pathelement path="${sdk.dir}/add-ons/addon_google_apis_google_inc_${default.sdk.version}/libs/maps.jar"/>
+ <pathelement path="${sdk.dir}/add-ons/addon-google_apis-google_inc_-${default.sdk.version}/libs/maps.jar"/>
+ <pathelement path="${sdk.dir}/add-ons/addon-google_apis-google-${default.sdk.version}/libs/maps.jar"/>
<pathelement path="${sdk.dir}/extras/android/support/v4/android-support-v4.jar"/>
<pathelement path="${sdk.dir}/android-compatibility/v4/android-support-v4.jar"/>
</path>
@@ -217,13 +219,13 @@
<target name="maven-install-jars" description="Install the jar files that Maven can't find for itself">
<exec executable="mvn">
- <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=${sdk.dir}/add-ons/addon_google_apis_google_inc_10/libs/maps.jar" />
+ <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=${sdk.dir}/add-ons/addon_google_apis_google_inc_${default.sdk.version}/libs/maps.jar" />
</exec>
<exec executable="mvn">
- <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=${sdk.dir}/add-ons/addon-google_apis-google_inc_-10/libs/maps.jar" />
+ <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=${sdk.dir}/add-ons/addon-google_apis-google_inc_-${default.sdk.version}/libs/maps.jar" />
</exec>
<exec executable="mvn">
- <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=${sdk.dir}/add-ons/addon-google_apis-google-10/libs/maps.jar" />
+ <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=${sdk.dir}/add-ons/addon-google_apis-google-${default.sdk.version}/libs/maps.jar" />
</exec>
</target>
@@ -236,7 +238,7 @@
ANDROID="tmp/sdk/android-sdk-linux/tools/android"
chmod +x $ANDROID
SDKS=$($ANDROID list sdk --all | awk \
- '/SDK Platform.* API 10/ || /Google APIs, Android API 10, revision 2/ \
+ '/SDK Platform.* API ${default.sdk.version}/ || /Google APIs, Android API ${default.sdk.version}, revision 2/ \
{ s=s "," int($1) } \
END { print substr(s, 2, length(s)) }' \
)
@@ -248,7 +250,7 @@
<entry key="sdk.dir" value="${basedir}/tmp/sdk/android-sdk-linux/"/>
</propertyfile>
<exec executable="mvn">
- <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=tmp/sdk/android-sdk-linux/add-ons/addon-google_apis-google-10/libs/maps.jar"/>
+ <arg line="install:install-file -DgroupId=com.google.android.maps -DartifactId=maps -Dversion=10_r2 -Dpackaging=jar -Dfile=tmp/sdk/android-sdk-linux/add-ons/addon-google_apis-google-${default.sdk.version}/libs/maps.jar"/>
</exec>
</target>
</project>
@@ -74,6 +74,7 @@
public class Robolectric {
public static Application application;
+ public static final int DEFAULT_SDK_VERSION = 16;
public static <T> T newInstanceOf(Class<T> clazz) {
return RobolectricInternals.newInstanceOf(clazz);
@@ -1276,18 +1277,31 @@ public static Object newInstanceOf(String className) {
public static void setFinalStaticField(Class classWhichContainsField, String fieldName, Object newValue) {
try {
Field field = classWhichContainsField.getDeclaredField(fieldName);
- field.setAccessible(true);
+ setFinalStaticField(field, newValue);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static Object setFinalStaticField(Field field, Object newValue) {
+ Object oldValue = null;
+
+ try {
+ field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- field.set(null, newValue);
+ oldValue = field.get(null);
+ field.set(null, newValue);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
+
+ return oldValue;
}
}
@@ -14,6 +14,7 @@
import java.util.List;
import static android.content.pm.ApplicationInfo.*;
+import static com.xtremelabs.robolectric.Robolectric.DEFAULT_SDK_VERSION;
public class RobolectricConfig {
private final File androidManifestFile;
@@ -92,13 +93,13 @@ private void parseAndroidManifest() {
Integer minSdkVer = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:minSdkVersion");
Integer sdkVer = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:targetSdkVersion");
if (minSdkVer == null) {
- minSdkVersion = 10;
+ minSdkVersion = DEFAULT_SDK_VERSION;
minSdkVersionSpecified = false;
} else {
minSdkVersion = minSdkVer;
}
if (sdkVer == null) {
- sdkVersion = 10;
+ sdkVersion = DEFAULT_SDK_VERSION;
sdkVersionSpecified = false;
} else {
sdkVersion = sdkVer;
@@ -6,7 +6,9 @@
import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -26,6 +28,7 @@
import android.app.Application;
import android.net.Uri__FromAndroid;
+import com.xtremelabs.robolectric.annotation.WithConstantString;
import com.xtremelabs.robolectric.bytecode.ClassHandler;
import com.xtremelabs.robolectric.bytecode.RobolectricClassLoader;
import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
@@ -283,9 +286,20 @@ protected void delegateLoadingOf(final String className) {
final Statement statement = super.methodBlock(method);
return new Statement() {
@Override public void evaluate() throws Throwable {
- // todo: this try/finally probably isn't right -- should mimic RunAfters? [xw]
+ HashMap<Field,Object> withConstantAnnos = getWithConstantAnnotations(method.getMethod());
+
+ // todo: this try/finally probably isn't right -- should mimic RunAfters? [xw]
try {
- statement.evaluate();
+ if (withConstantAnnos.isEmpty()) {
+ statement.evaluate();
+ }
+ else {
+ synchronized(this) {
+ setupConstants(withConstantAnnos);
+ statement.evaluate();
+ setupConstants(withConstantAnnos);
+ }
+ }
} finally {
delegate.internalAfterTest(method.getMethod());
if (classHandler != null) {
@@ -409,7 +423,7 @@ private void setupI18nStrictState(Method method, RobolectricConfig robolectricCo
robolectricConfig.setStrictI18n(strictI18n);
}
-
+
/**
* Default implementation of global switch for i18n-strict mode.
* To enable i18n-strict mode globally, set the system property
@@ -469,6 +483,77 @@ private void lookForLocaleAnnotation( Method method, RobolectricConfig robolectr
robolectricConfig.setLocale( locale );
}
+
+ /**
+ * Find all the class and method annotations and pass them to
+ * addConstantFromAnnotation() for evaluation.
+ *
+ * TODO: Add compound annotations to suport defining more than one int and string at a time
+ * TODO: See http://stackoverflow.com/questions/1554112/multiple-annotations-of-the-same-type-on-one-element
+ *
+ * @param method
+ * @return
+ */
+ private HashMap<Field,Object> getWithConstantAnnotations(Method method) {
+ HashMap<Field,Object> constants = new HashMap<Field,Object>();
+
+ for(Annotation anno:method.getDeclaringClass().getAnnotations()) {
+ addConstantFromAnnotation(constants, anno);
+ }
+
+ for(Annotation anno:method.getAnnotations()) {
+ addConstantFromAnnotation(constants, anno);
+ }
+
+ return constants;
+ }
+
+ /**
+ * If the annotation is a constant redefinition, add it to the provided hash
+ *
+ * @param constants
+ * @param anno
+ */
+ private void addConstantFromAnnotation(HashMap<Field,Object> constants, Annotation anno) {
+ try {
+ String name = anno.annotationType().getName();
+ Object newValue = null;
+
+ if (name.equals( "com.xtremelabs.robolectric.annotation.WithConstantString" )) {
+ newValue = (String) anno.annotationType().getMethod("newValue").invoke(anno);
+ }
+ else if (name.equals( "com.xtremelabs.robolectric.annotation.WithConstantInt" )) {
+ newValue = (Integer) anno.annotationType().getMethod("newValue").invoke(anno);
+ }
+ else {
+ return;
+ }
+
+ @SuppressWarnings("rawtypes")
+ Class classWithField = (Class) anno.annotationType().getMethod("classWithField").invoke(anno);
+ String fieldName = (String) anno.annotationType().getMethod("fieldName").invoke(anno);
+ Field field = classWithField.getDeclaredField(fieldName);
+ constants.put(field, newValue);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Defines static finals from the provided hash and stores the old values back
+ * into the hash.
+ *
+ * Call it twice with the same hash, and it puts everything back the way it was originally.
+ *
+ * @param constants
+ */
+ private void setupConstants(HashMap<Field,Object> constants) {
+ for(Field field:constants.keySet()) {
+ Object newValue = constants.get(field);
+ Object oldValue = Robolectric.Reflection.setFinalStaticField(field, newValue);
+ constants.put(field,oldValue);
+ }
+ }
private void setupLogging() {
String logging = System.getProperty("robolectric.logging");
@@ -0,0 +1,15 @@
+package com.xtremelabs.robolectric.annotation;
+
+/**
+ * Annotation to run test with setFinalStaticField() defined in a synchronized
+ * block with automatic reversion to the original value.
+ */
+@java.lang.annotation.Documented
+@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE,java.lang.annotation.ElementType.METHOD})
+public @interface WithConstantInt {
+ @SuppressWarnings("rawtypes")
+ Class classWithField();
+ String fieldName();
+ int newValue();
+}
@@ -0,0 +1,15 @@
+package com.xtremelabs.robolectric.annotation;
+
+/**
+ * Annotation to run test with setFinalStaticField() defined in a synchronized
+ * block with automatic reversion to the original value.
+ */
+@java.lang.annotation.Documented
+@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE,java.lang.annotation.ElementType.METHOD})
+public @interface WithConstantString {
+ @SuppressWarnings("rawtypes")
+ Class classWithField();
+ String fieldName();
+ String newValue();
+}
@@ -1,13 +1,12 @@
package com.xtremelabs.robolectric.res;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.Map.Entry;
import android.content.ComponentName;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
@@ -23,7 +22,8 @@
private Map<ComponentName, ComponentState> componentList = new HashMap<ComponentName,ComponentState>();
private Map<ComponentName, Drawable> drawableList = new HashMap<ComponentName, Drawable>();
private Map<String, Boolean> systemFeatureList = new HashMap<String, Boolean>();
-
+ private Map<IntentFilter, ComponentName > preferredActivities = new HashMap<IntentFilter, ComponentName>();
+
private ContextWrapper contextWrapper;
private RobolectricConfig config;
private ApplicationInfo applicationInfo;
@@ -135,6 +135,50 @@ public CharSequence getApplicationLabel(ApplicationInfo info) {
public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) {
componentList.put(componentName, new ComponentState(newState, flags));
}
+
+ public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
+ preferredActivities.put(filter, activity);
+ }
+
+ @Override
+ public int getPreferredActivities(List<IntentFilter> outFilters, List<ComponentName> outActivities, String packageName) {
+ if( outFilters == null ){ return 0; }
+
+ Set< IntentFilter> filters = preferredActivities.keySet();
+ for( IntentFilter filter: outFilters ){
+ step:
+ for ( IntentFilter testFilter : filters ) {
+ ComponentName name = preferredActivities.get( testFilter );
+ // filter out based on the given packageName;
+ if( packageName != null && !name.getPackageName().equals( packageName ) ){
+ continue step;
+ }
+
+ // Check actions
+ Iterator< String > iterator = filter.actionsIterator();
+ while ( iterator.hasNext() ) {
+ if ( !testFilter.matchAction( iterator.next() ) ) {
+ continue step;
+ }
+ }
+
+ iterator = filter.categoriesIterator();
+ while ( iterator.hasNext() ) {
+ if ( !filter.hasCategory( iterator.next() ) ) {
+ continue step;
+ }
+ }
+
+ if( outActivities == null ){
+ outActivities = new ArrayList<ComponentName>();
+ }
+
+ outActivities.add( name );
+ }
+ }
+
+ return 0;
+ }
/**
* Non-Android accessor. Use to make assertions on values passed to
Oops, something went wrong.

0 comments on commit 0a7ac38

Please sign in to comment.