`AttributeSetBuilder` should allow potentially invalid values for style attribute.
Nicer stringification of `Style` implementations, for debugging.
diff --git a/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java b/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java
index 468c86c..06661c2 100644
--- a/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java
+++ b/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java
@@ -71,10 +71,7 @@
}
@Override public String toString() {
- return "StyleData{" +
- "name='" + name + '\'' +
- ", parent='" + parent + '\'' +
- '}';
+ return "Style " + packageName + ":" + name;
}
public String getPackageName() {
diff --git a/robolectric-resources/src/main/java/org/robolectric/res/StyleResolver.java b/robolectric-resources/src/main/java/org/robolectric/res/StyleResolver.java
index 42a34cb..69cb2fc 100644
--- a/robolectric-resources/src/main/java/org/robolectric/res/StyleResolver.java
+++ b/robolectric-resources/src/main/java/org/robolectric/res/StyleResolver.java
@@ -90,8 +90,8 @@
if (typedResource == null) {
StringBuilder builder = new StringBuilder("Could not find any resource ")
.append(" from reference ").append(styleRef)
- .append(" from style ").append(style)
- .append(" with theme ").append(theme);
+ .append(" from ").append(style)
+ .append(" with ").append(theme);
throw new RuntimeException(builder.toString());
}
@@ -102,8 +102,8 @@
StringBuilder builder = new StringBuilder(styleRef.toString())
.append(" does not resolve to a Style.")
.append(" got ").append(data).append(" instead. ")
- .append(" from style ").append(style)
- .append(" with theme ").append(theme);
+ .append(" from ").append(style)
+ .append(" with ").append(theme);
throw new RuntimeException(builder.toString());
}
}
@@ -166,10 +166,7 @@
@Override
public String toString() {
- return "StyleResolver{"
- + "name=" + myResName
- + ", of=" + styles.get(0)
- + "}";
+ return styles.get(0) + " (and parents)";
}
}
\ No newline at end of file
diff --git a/robolectric-resources/src/main/java/org/robolectric/res/ThemeStyleSet.java b/robolectric-resources/src/main/java/org/robolectric/res/ThemeStyleSet.java
index 84a64b9..2c35bcf 100644
--- a/robolectric-resources/src/main/java/org/robolectric/res/ThemeStyleSet.java
+++ b/robolectric-resources/src/main/java/org/robolectric/res/ThemeStyleSet.java
@@ -40,6 +40,15 @@
return themeStyleSet;
}
+ @Override
+ public String toString() {
+ if (styles.isEmpty()) {
+ return "theme with no applied styles";
+ } else {
+ return "theme with applied styles: " + styles + "";
+ }
+ }
+
private static class OverlayedStyle {
Style style;
boolean force;
diff --git a/robolectric-resources/src/main/java/org/robolectric/res/builder/XmlResourceParserImpl.java b/robolectric-resources/src/main/java/org/robolectric/res/builder/XmlResourceParserImpl.java
index 843c5c0..13d858c 100644
--- a/robolectric-resources/src/main/java/org/robolectric/res/builder/XmlResourceParserImpl.java
+++ b/robolectric-resources/src/main/java/org/robolectric/res/builder/XmlResourceParserImpl.java
@@ -1,5 +1,6 @@
package org.robolectric.res.builder;
+import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import com.android.internal.util.XmlUtils;
import org.robolectric.res.AttributeResource;
@@ -772,13 +773,21 @@
if (AttributeResource.isNull(possiblyQualifiedResourceName)) return 0;
if (AttributeResource.isStyleReference(possiblyQualifiedResourceName)) {
- Integer resourceId = resourceLoader.getResourceIndex().getResourceId(AttributeResource.getStyleReference(possiblyQualifiedResourceName, defaultPackageName, defaultType));
- return resourceId == null ? 0 : resourceId;
+ ResName styleReference = AttributeResource.getStyleReference(possiblyQualifiedResourceName, defaultPackageName, defaultType);
+ Integer resourceId = resourceLoader.getResourceIndex().getResourceId(styleReference);
+ if (resourceId == null) {
+ throw new Resources.NotFoundException(styleReference.getFullyQualifiedName());
+ }
+ return resourceId;
}
if (AttributeResource.isResourceReference(possiblyQualifiedResourceName)) {
- Integer resourceId = resourceLoader.getResourceIndex().getResourceId(AttributeResource.getResourceReference(possiblyQualifiedResourceName, defaultPackageName, defaultType));
- return resourceId == null ? 0 : resourceId;
+ ResName resourceReference = AttributeResource.getResourceReference(possiblyQualifiedResourceName, defaultPackageName, defaultType);
+ Integer resourceId = resourceLoader.getResourceIndex().getResourceId(resourceReference);
+ if (resourceId == null) {
+ throw new Resources.NotFoundException(resourceReference.getFullyQualifiedName());
+ }
+ return resourceId;
}
possiblyQualifiedResourceName = removeLeadingSpecialCharsIfAny(possiblyQualifiedResourceName);
ResName resName = ResName.qualifyResName(possiblyQualifiedResourceName, defaultPackageName, defaultType);
diff --git a/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm b/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm
index eed3e8b..b09382c 100644
--- a/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm
+++ b/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm
@@ -376,7 +376,9 @@
while (styleAttributeResName.type.equals("attr")) {
AttributeResource attrValue = themeStyleSet.getAttrValue(styleAttributeResName);
if (attrValue == null) {
- throw new NullPointerException("no value for " + styleAttributeResName.getFullyQualifiedName() + " in theme");
+ throw new RuntimeException(
+ "no value for " + styleAttributeResName.getFullyQualifiedName()
+ + " in " + themeStyleSet);
}
if (attrValue.isResourceReference()) {
styleAttributeResName = attrValue.getResourceReference();
diff --git a/robolectric/src/main/java/org/robolectric/Robolectric.java b/robolectric/src/main/java/org/robolectric/Robolectric.java
index 4978936..52c2aee 100644
--- a/robolectric/src/main/java/org/robolectric/Robolectric.java
+++ b/robolectric/src/main/java/org/robolectric/Robolectric.java
@@ -160,10 +160,6 @@
}
public AttributeSetBuilder setStyleAttribute(String value) {
- if (appResourceLoader.getValue(AttributeResource.getResourceReference(value, RuntimeEnvironment.application.getPackageName(), "style"),
- RuntimeEnvironment.getQualifiers()) == null) {
- throw new Resources.NotFoundException("Invalid style attribute: " + value);
- }
((Element)doc.getFirstChild()).setAttribute("style", value);
return this;
}
diff --git a/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java b/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java
index a77c741..b1ba314 100644
--- a/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java
+++ b/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java
@@ -242,13 +242,21 @@
}
@Test
- public void getStyleAttribute_throwException_whenStyleIsBogus() throws Exception {
- thrown.expect(Resources.NotFoundException.class);
+ public void getStyleAttribute_whenStyleIsBogus() throws Exception {
AttributeSet roboAttributeSet = Robolectric.buildAttributeSet()
- .setStyleAttribute("@style/bogus_style")
+ .setStyleAttribute("@style/non_existent_style")
.build();
- assertThat(roboAttributeSet.getStyleAttribute()).isEqualTo(0);
+ assertThat(roboAttributeSet.getStyleAttribute()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void getStyleAttribute_allowStyleAttrReference() throws Exception {
+ AttributeSet roboAttributeSet = Robolectric.buildAttributeSet()
+ .setStyleAttribute("?attr/parentStyleReference")
+ .build();
+
+ assertThat(roboAttributeSet.getStyleAttribute()).isEqualTo(R.attr.parentStyleReference);
}
@Test
diff --git a/robolectric/src/test/java/org/robolectric/R.java b/robolectric/src/test/java/org/robolectric/R.java
index e466520..b0b43a9 100644
--- a/robolectric/src/test/java/org/robolectric/R.java
+++ b/robolectric/src/test/java/org/robolectric/R.java
@@ -271,6 +271,7 @@
public static final int string2 = 0x10a1b;
public static final int string3 = 0x10a1c;
public static final int parentStyleReference = 0x10a1d;
+ public static final int styleNotSpecifiedInAnyTheme = 0x10a1e;
}
public static final class menu {
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java
index efa934d..5bd0b2f 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java
@@ -10,6 +10,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
+import org.robolectric.R;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.TestRunners;
@@ -29,6 +30,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
import static org.robolectric.util.TestUtil.joinPath;
@RunWith(TestRunners.MultiApiWithDefaults.class)
@@ -37,11 +39,13 @@
@Rule
public ExpectedException expectedException = ExpectedException.none();
- AssetManager assetManager;
+ private AssetManager assetManager;
+ private Resources resources;
@Before
public void setUp() throws Exception {
assetManager = Robolectric.buildActivity(Activity.class).create().get().getAssets();
+ resources = RuntimeEnvironment.application.getResources();
}
@Test
@@ -51,7 +55,7 @@
assetManager = RuntimeEnvironment.application.getAssets();
assertNotNull(assetManager);
- assetManager = RuntimeEnvironment.application.getResources().getAssets();
+ assetManager = resources.getAssets();
assertNotNull(assetManager);
}
@@ -155,14 +159,28 @@
when(mockAttributeSet.getAttributeNameResource(0)).thenReturn(android.R.attr.windowBackground);
when(mockAttributeSet.getAttributeValue(0)).thenReturn("value");
- Resources resources = RuntimeEnvironment.application.getResources();
resources.obtainAttributes(mockAttributeSet, new int[]{android.R.attr.windowBackground});
}
@Test
public void forUntouchedThemes_copyTheme_shouldCopyNothing() throws Exception {
- Resources.Theme theme1 = RuntimeEnvironment.application.getResources().newTheme();
- Resources.Theme theme2 = RuntimeEnvironment.application.getResources().newTheme();
+ Resources.Theme theme1 = resources.newTheme();
+ Resources.Theme theme2 = resources.newTheme();
theme2.setTo(theme1);
}
+
+ @Test
+ public void whenStyleAttrResolutionFails_attrsToTypedArray_returnsNiceErrorMessage() throws Exception {
+ expectedException.expect(RuntimeException.class);
+ expectedException.expectMessage(
+ "no value for org.robolectric:attr/styleNotSpecifiedInAnyTheme " +
+ "in theme with applied styles: [Style org.robolectric:Theme_Robolectric (and parents)]");
+
+ Resources.Theme theme = resources.newTheme();
+ theme.applyStyle(R.style.Theme_Robolectric, false);
+
+ shadowOf(assetManager).attrsToTypedArray(resources,
+ Robolectric.buildAttributeSet().setStyleAttribute("?attr/styleNotSpecifiedInAnyTheme").build(),
+ new int[]{R.attr.string1}, 0, theme, 0);
+ }
}
diff --git a/robolectric/src/test/resources/res/values/attrs.xml b/robolectric/src/test/resources/res/values/attrs.xml
index ef789f9..e553368 100644
--- a/robolectric/src/test/resources/res/values/attrs.xml
+++ b/robolectric/src/test/resources/res/values/attrs.xml
@@ -51,6 +51,7 @@
<attr name="string2" format="string"/>
<attr name="string3" format="string"/>
<attr name="parentStyleReference" format="reference"/>
+ <attr name="styleNotSpecifiedInAnyTheme" format="reference"/>
<declare-styleable name="CustomStateView">
<attr name="stateFoo" format="boolean" />