Merge pull request #305 from zoodles/master
This pull request provides the ability for a test case to specify a locale, using the @Values annotation. Example: @Values( locale="fr" )
diff --git a/src/main/java/com/xtremelabs/robolectric/RobolectricConfig.java b/src/main/java/com/xtremelabs/robolectric/RobolectricConfig.java
index 3dbbc33..ccbf71e 100644
--- a/src/main/java/com/xtremelabs/robolectric/RobolectricConfig.java
+++ b/src/main/java/com/xtremelabs/robolectric/RobolectricConfig.java
@@ -31,6 +31,8 @@
private int applicationFlags;
private final List<ReceiverAndIntentFilter> receivers = new ArrayList<ReceiverAndIntentFilter>();
private boolean strictI18n = false;
+ private String locale = "";
+ private String oldLocale = "";
/**
* Creates a Robolectric configuration using default Android files relative to the specified base directory.
@@ -248,6 +250,19 @@
strictI18n = strict;
}
+ public void setLocale( String locale ){
+ this.oldLocale = this.locale;
+ this.locale = locale;
+ }
+
+ public String getLocale() {
+ return this.locale;
+ }
+
+ public boolean isLocaleChanged() {
+ return !locale.equals( oldLocale );
+ }
+
private static String getTagAttributeText(final Document doc, final String tag, final String attribute) {
NodeList elementsByTagName = doc.getElementsByTagName(tag);
for (int i = 0; i < elementsByTagName.getLength(); ++i) {
diff --git a/src/main/java/com/xtremelabs/robolectric/RobolectricTestRunner.java b/src/main/java/com/xtremelabs/robolectric/RobolectricTestRunner.java
index 46a6f42..8947159 100644
--- a/src/main/java/com/xtremelabs/robolectric/RobolectricTestRunner.java
+++ b/src/main/java/com/xtremelabs/robolectric/RobolectricTestRunner.java
@@ -1,7 +1,31 @@
package com.xtremelabs.robolectric;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import javassist.Loader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
import android.app.Application;
import android.net.Uri__FromAndroid;
+
import com.xtremelabs.robolectric.bytecode.ClassHandler;
import com.xtremelabs.robolectric.bytecode.RobolectricClassLoader;
import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
@@ -14,23 +38,6 @@
import com.xtremelabs.robolectric.util.DatabaseConfig.DatabaseMap;
import com.xtremelabs.robolectric.util.DatabaseConfig.UsingDatabaseMap;
import com.xtremelabs.robolectric.util.SQLiteMap;
-import javassist.Loader;
-import org.junit.runners.BlockJUnit4ClassRunner;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.Statement;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.*;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
/**
* Installs a {@link RobolectricClassLoader} and {@link com.xtremelabs.robolectric.res.ResourceLoader} in order to
@@ -265,7 +272,8 @@
@Override protected Statement methodBlock(final FrameworkMethod method) {
setupI18nStrictState(method.getMethod(), robolectricConfig);
-
+ lookForLocaleAnnotation( method.getMethod(), robolectricConfig );
+
if (classHandler != null) {
classHandler.configure(robolectricConfig);
classHandler.beforeTest();
@@ -342,7 +350,8 @@
public void setupApplicationState(final RobolectricConfig robolectricConfig) {
setupLogging();
- ResourceLoader resourceLoader = createResourceLoader(robolectricConfig);
+
+ ResourceLoader resourceLoader = createResourceLoader(robolectricConfig );
Robolectric.bindDefaultShadowClasses();
bindShadowClasses();
@@ -355,9 +364,7 @@
Robolectric.application = ShadowApplication.bind(createApplication(), resourceLoader);
}
-
-
-
+
/**
* Override this method to bind your own shadow classes
*/
@@ -442,6 +449,27 @@
return strictI18n;
}
+ private void lookForLocaleAnnotation( Method method, RobolectricConfig robolectricConfig ){
+ String locale = "";
+ // TODO: there are maybe better implementation for getAnnotation
+ // Have tried to use several other simple ways, but failed.
+ Annotation[] annos = method.getDeclaredAnnotations();
+ for( Annotation anno: annos ){
+
+ if( anno.annotationType().getName().equals( "com.xtremelabs.robolectric.annotation.Values" )){
+ String annotationString = anno.toString();
+ int startIndex = annotationString.indexOf( '=' );
+ int endIndex = annotationString.indexOf( ')' );
+
+ if( startIndex < 0 || endIndex < 0 ){ return; }
+
+ locale = annotationString.substring( startIndex + 1, endIndex );
+ }
+ }
+
+ robolectricConfig.setLocale( locale );
+ }
+
private void setupLogging() {
String logging = System.getProperty("robolectric.logging");
if (logging != null && ShadowLog.stream == null) {
@@ -481,13 +509,14 @@
private ResourceLoader createResourceLoader(final RobolectricConfig robolectricConfig) {
ResourceLoader resourceLoader = resourceLoaderForRootAndDirectory.get(robolectricConfig);
- if (resourceLoader == null) {
+ // When locale has changed, reload the resource files.
+ if (resourceLoader == null || robolectricConfig.isLocaleChanged() ) {
try {
robolectricConfig.validate();
String rClassName = robolectricConfig.getRClassName();
Class rClass = Class.forName(rClassName);
- resourceLoader = new ResourceLoader(robolectricConfig.getRealSdkVersion(), rClass, robolectricConfig.getResourceDirectory(), robolectricConfig.getAssetsDirectory());
+ resourceLoader = new ResourceLoader(robolectricConfig.getRealSdkVersion(), rClass, robolectricConfig.getResourceDirectory(), robolectricConfig.getAssetsDirectory(), robolectricConfig.getLocale() );
resourceLoaderForRootAndDirectory.put(robolectricConfig, resourceLoader);
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/src/main/java/com/xtremelabs/robolectric/annotation/Values.java b/src/main/java/com/xtremelabs/robolectric/annotation/Values.java
new file mode 100644
index 0000000..c592304
--- /dev/null
+++ b/src/main/java/com/xtremelabs/robolectric/annotation/Values.java
@@ -0,0 +1,12 @@
+package com.xtremelabs.robolectric.annotation;
+
+/**
+ * Indicate that roboletric should look for values that is specific for the locale
+ *
+ */
+@java.lang.annotation.Documented
+@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+public @interface Values {
+ String locale();
+}
diff --git a/src/main/java/com/xtremelabs/robolectric/res/ResourceLoader.java b/src/main/java/com/xtremelabs/robolectric/res/ResourceLoader.java
index 9d9a4a8..f24bab6 100644
--- a/src/main/java/com/xtremelabs/robolectric/res/ResourceLoader.java
+++ b/src/main/java/com/xtremelabs/robolectric/res/ResourceLoader.java
@@ -6,6 +6,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceScreen;
+import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
@@ -60,13 +61,20 @@
private final IntegerResourceLoader integerResourceLoader;
private boolean isInitialized = false;
private boolean strictI18n = false;
+ private String locale="";
private final Set<Integer> ninePatchDrawableIds = new HashSet<Integer>();
- public ResourceLoader( int sdkVersion, Class rClass, File resourceDir, File assetsDir ) throws Exception {
+ public ResourceLoader( int sdkVersion, Class rClass, File resourceDir, File assetsDir ) throws Exception {
+ this( sdkVersion, rClass, resourceDir, assetsDir, "");
+ }
+
+ public ResourceLoader( int sdkVersion, Class rClass, File resourceDir, File assetsDir, String locale ) throws Exception {
this.sdkVersion = sdkVersion;
this.assetsDir = assetsDir;
this.rClass = rClass;
+ this.locale = locale;
+
resourceExtractor = new ResourceExtractor();
resourceExtractor.addLocalRClass( rClass );
resourceExtractor.addSystemRClass( R.class );
@@ -236,7 +244,15 @@
}
private File getValueResourceDir( File xmlResourceDir ) {
- return xmlResourceDir != null ? new File( xmlResourceDir, "values" ) : null;
+ String valuesDir = "values";
+ if( !TextUtils.isEmpty( locale ) ){
+ valuesDir += "-"+ locale;
+ }
+ File result = ( xmlResourceDir != null ) ? new File( xmlResourceDir, valuesDir ) : null;
+ if( result == null || !result.exists() ){
+ throw new RuntimeException("Couldn't find value resource directory: " + result.getAbsolutePath() );
+ }
+ return result;
}
private File getPreferenceResourceDir( File xmlResourceDir ) {
diff --git a/src/test/java/com/xtremelabs/robolectric/RobolectricTestRunnerTest.java b/src/test/java/com/xtremelabs/robolectric/RobolectricTestRunnerTest.java
index 00c44a9..a7859d9 100644
--- a/src/test/java/com/xtremelabs/robolectric/RobolectricTestRunnerTest.java
+++ b/src/test/java/com/xtremelabs/robolectric/RobolectricTestRunnerTest.java
@@ -7,24 +7,15 @@
import org.junit.runner.RunWith;
import org.junit.runners.model.InitializationError;
-import com.xtremelabs.robolectric.annotation.DisableStrictI18n;
-import com.xtremelabs.robolectric.annotation.EnableStrictI18n;
-import com.xtremelabs.robolectric.internal.Implements;
-import com.xtremelabs.robolectric.res.ResourceLoader;
-import com.xtremelabs.robolectric.shadows.ShadowActivity;
-import com.xtremelabs.robolectric.shadows.ShadowApplication;
-
import android.app.Activity;
import android.app.Application;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
import android.widget.TextView;
+import com.xtremelabs.robolectric.annotation.DisableStrictI18n;
+import com.xtremelabs.robolectric.annotation.EnableStrictI18n;
+import com.xtremelabs.robolectric.annotation.Values;
+import com.xtremelabs.robolectric.res.ResourceLoader;
+
@RunWith(RobolectricTestRunnerTest.RunnerForTesting.class)
public class RobolectricTestRunnerTest {
@@ -56,6 +47,12 @@
}
@Test
+ @Values( locale="fr")
+ public void internalBeforeTest_setLocale(){
+ assertEquals( RunnerForTesting.instance.robolectricConfig.getLocale(), "fr" );
+ }
+
+ @Test
public void internalBeforeTest_doesNotsetI18nStrictModeFromSystemIfPropertyAbsent() {
assertFalse(RunnerForTesting.instance.robolectricConfig.getStrictI18n());
}
diff --git a/src/test/java/com/xtremelabs/robolectric/shadows/ResourcesTest.java b/src/test/java/com/xtremelabs/robolectric/shadows/ResourcesTest.java
index de91496..e6a240a 100644
--- a/src/test/java/com/xtremelabs/robolectric/shadows/ResourcesTest.java
+++ b/src/test/java/com/xtremelabs/robolectric/shadows/ResourcesTest.java
@@ -1,5 +1,16 @@
package com.xtremelabs.robolectric.shadows;
+import static com.xtremelabs.robolectric.Robolectric.shadowOf;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import android.app.Activity;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -8,20 +19,12 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.NinePatchDrawable;
+import com.xtremelabs.robolectric.R;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.WithTestDefaultsRunner;
-import com.xtremelabs.robolectric.R;
+import com.xtremelabs.robolectric.RobolectricTestRunnerTest.RunnerForTesting;
+import com.xtremelabs.robolectric.annotation.Values;
import com.xtremelabs.robolectric.util.TestR;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static com.xtremelabs.robolectric.Robolectric.shadowOf;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
@RunWith(WithTestDefaultsRunner.class)
@@ -77,6 +80,13 @@
assertThat( resources.getDrawable( TestR.anim.test_anim_1 ), instanceOf( AnimationDrawable.class ) );
}
+ @Test
+ @Values( locale="fr" )
+ public void testGetResourceFromSpecificLocale(){
+ String hello=resources.getString( R.string.hello );
+ assertThat( hello, equalTo( "Bonjour" ) );
+ }
+
/**
* given an R.color.id value, will return a ColorDrawable
*/
@@ -129,4 +139,6 @@
assertThat(activity.getResources().getDisplayMetrics().heightPixels, equalTo(800));
assertThat(activity.getResources().getDisplayMetrics().widthPixels, equalTo(480));
}
+
+
}
diff --git a/src/test/resources/res/values-fr/strings.xml b/src/test/resources/res/values-fr/strings.xml
new file mode 100644
index 0000000..04fdf3f
--- /dev/null
+++ b/src/test/resources/res/values-fr/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="hello">Bonjour</string>
+</resources>
\ No newline at end of file