Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static com.google.common.truth.Truth.assertThat;
      4 import static org.robolectric.Robolectric.buildActivity;
      5 
      6 import android.app.Activity;
      7 import android.content.res.Resources;
      8 import android.content.res.Resources.Theme;
      9 import android.content.res.TypedArray;
     10 import android.content.res.XmlResourceParser;
     11 import android.graphics.drawable.ColorDrawable;
     12 import android.os.Bundle;
     13 import android.util.AttributeSet;
     14 import android.util.Xml;
     15 import android.view.View;
     16 import android.widget.Button;
     17 import androidx.test.core.app.ApplicationProvider;
     18 import androidx.test.ext.junit.runners.AndroidJUnit4;
     19 import org.junit.After;
     20 import org.junit.Before;
     21 import org.junit.Test;
     22 import org.junit.runner.RunWith;
     23 import org.robolectric.R;
     24 import org.robolectric.Robolectric;
     25 import org.robolectric.android.controller.ActivityController;
     26 import org.xmlpull.v1.XmlPullParser;
     27 
     28 @RunWith(AndroidJUnit4.class)
     29 public class ShadowThemeTest {
     30   private Resources resources;
     31 
     32   @Before
     33   public void setUp() throws Exception {
     34     resources = ApplicationProvider.getApplicationContext().getResources();
     35   }
     36 
     37   @After
     38   public void tearDown() {
     39     ShadowLegacyAssetManager.strictErrors = false;
     40   }
     41 
     42   @Test public void whenExplicitlySetOnActivity_afterSetContentView_activityGetsThemeFromActivityInManifest() throws Exception {
     43     TestActivity activity = buildActivity(TestActivityWithAnotherTheme.class).create().get();
     44     activity.setTheme(R.style.Theme_Robolectric);
     45     Button theButton = (Button) activity.findViewById(R.id.button);
     46     ColorDrawable background = (ColorDrawable) theButton.getBackground();
     47     assertThat(background.getColor()).isEqualTo(0xffff0000);
     48   }
     49 
     50   @Test public void whenExplicitlySetOnActivity_beforeSetContentView_activityUsesNewTheme() throws Exception {
     51     ActivityController<TestActivityWithAnotherTheme> activityController = buildActivity(TestActivityWithAnotherTheme.class);
     52     TestActivity activity = activityController.get();
     53     activity.setTheme(R.style.Theme_Robolectric);
     54     activityController.create();
     55     Button theButton = (Button) activity.findViewById(R.id.button);
     56     ColorDrawable background = (ColorDrawable) theButton.getBackground();
     57     assertThat(background.getColor()).isEqualTo(0xff00ff00);
     58   }
     59 
     60   @Test public void whenSetOnActivityInManifest_activityGetsThemeFromActivityInManifest() throws Exception {
     61     TestActivity activity = buildActivity(TestActivityWithAnotherTheme.class).create().get();
     62     Button theButton = (Button) activity.findViewById(R.id.button);
     63     ColorDrawable background = (ColorDrawable) theButton.getBackground();
     64     assertThat(background.getColor()).isEqualTo(0xffff0000);
     65   }
     66 
     67   @Test public void whenNotSetOnActivityInManifest_activityGetsThemeFromApplicationInManifest() throws Exception {
     68     TestActivity activity = buildActivity(TestActivity.class).create().get();
     69     Button theButton = (Button) activity.findViewById(R.id.button);
     70     ColorDrawable background = (ColorDrawable) theButton.getBackground();
     71     assertThat(background.getColor()).isEqualTo(0xff00ff00);
     72   }
     73 
     74   @Test public void shouldResolveReferencesThatStartWithAQuestionMark() throws Exception {
     75     TestActivity activity = buildActivity(TestActivityWithAnotherTheme.class).create().get();
     76     Button theButton = (Button) activity.findViewById(R.id.button);
     77     assertThat(theButton.getMinWidth()).isEqualTo(8);
     78     assertThat(theButton.getMinHeight()).isEqualTo(8);
     79   }
     80 
     81   @Test public void forStylesWithImplicitParents_shouldInheritValuesNotDefinedInChild() throws Exception {
     82     Resources.Theme theme = resources.newTheme();
     83     theme.applyStyle(R.style.Theme_Robolectric_EmptyParent, true);
     84     assertThat(theme.obtainStyledAttributes(new int[] {R.attr.string1}).hasValue(0)).isFalse();
     85   }
     86 
     87   @Test public void shouldApplyParentStylesFromAttrs() throws Exception {
     88     Resources.Theme theme = resources.newTheme();
     89     theme.applyStyle(R.style.SimpleParent, true);
     90     assertThat(theme.obtainStyledAttributes(new int[] {R.attr.parent_string}).getString(0))
     91         .isEqualTo("parent string");
     92   }
     93 
     94   @Test public void applyStyle_shouldOverrideParentAttrs() throws Exception {
     95     Resources.Theme theme = resources.newTheme();
     96     theme.applyStyle(R.style.SimpleChildWithOverride, true);
     97     assertThat(theme.obtainStyledAttributes(new int[] {R.attr.parent_string}).getString(0))
     98         .isEqualTo("parent string overridden by child");
     99   }
    100 
    101   @Test public void applyStyle_shouldOverrideImplicitParentAttrs() throws Exception {
    102     Resources.Theme theme = resources.newTheme();
    103     theme.applyStyle(R.style.SimpleParent_ImplicitChild, true);
    104     assertThat(theme.obtainStyledAttributes(new int[] {R.attr.parent_string}).getString(0))
    105         .isEqualTo("parent string overridden by child");
    106   }
    107 
    108   @Test public void applyStyle_shouldInheritParentAttrs() throws Exception {
    109     Resources.Theme theme = resources.newTheme();
    110     theme.applyStyle(R.style.SimpleChildWithAdditionalAttributes, true);
    111     assertThat(theme.obtainStyledAttributes(new int[] {R.attr.child_string}).getString(0))
    112         .isEqualTo("child string");
    113     assertThat(theme.obtainStyledAttributes(new int[] {R.attr.parent_string}).getString(0))
    114         .isEqualTo("parent string");
    115   }
    116 
    117   @Test
    118   public void setTo_shouldCopyAllAttributesToEmptyTheme() throws Exception {
    119     Resources.Theme theme1 = resources.newTheme();
    120     theme1.applyStyle(R.style.Theme_Robolectric, false);
    121     assertThat(theme1.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    122         .isEqualTo("string 1 from Theme.Robolectric");
    123 
    124     Resources.Theme theme2 = resources.newTheme();
    125     theme2.setTo(theme1);
    126 
    127     assertThat(theme2.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    128         .isEqualTo("string 1 from Theme.Robolectric");
    129   }
    130 
    131   @Test
    132   public void setTo_whenDestThemeIsModified_sourceThemeShouldNotMutate() throws Exception {
    133     Resources.Theme sourceTheme = resources.newTheme();
    134     sourceTheme.applyStyle(R.style.StyleA, false);
    135 
    136     Resources.Theme destTheme = resources.newTheme();
    137     destTheme.setTo(sourceTheme);
    138     destTheme.applyStyle(R.style.StyleB, true);
    139 
    140     assertThat(destTheme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    141         .isEqualTo("string 1 from style B");
    142     assertThat(sourceTheme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    143         .isEqualTo("string 1 from style A");
    144   }
    145 
    146   @Test
    147   public void setTo_whenSourceThemeIsModified_destThemeShouldNotMutate() throws Exception {
    148     Resources.Theme sourceTheme = resources.newTheme();
    149     sourceTheme.applyStyle(R.style.StyleA, false);
    150 
    151     Resources.Theme destTheme = resources.newTheme();
    152     destTheme.setTo(sourceTheme);
    153     sourceTheme.applyStyle(R.style.StyleB, true);
    154 
    155     assertThat(destTheme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    156         .isEqualTo("string 1 from style A");
    157     assertThat(sourceTheme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    158         .isEqualTo("string 1 from style B");
    159   }
    160 
    161   @Test
    162   public void applyStyle_withForceFalse_shouldApplyButNotOverwriteExistingAttributeValues() throws Exception {
    163     Resources.Theme theme = resources.newTheme();
    164     theme.applyStyle(R.style.StyleA, false);
    165     assertThat(theme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    166         .isEqualTo("string 1 from style A");
    167 
    168     theme.applyStyle(R.style.StyleB, false);
    169     assertThat(theme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    170         .isEqualTo("string 1 from style A");
    171   }
    172 
    173   @Test
    174   public void applyStyle_withForceTrue_shouldApplyAndOverwriteExistingAttributeValues() throws Exception {
    175     Resources.Theme theme = resources.newTheme();
    176     theme.applyStyle(R.style.StyleA, false);
    177     assertThat(theme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    178         .isEqualTo("string 1 from style A");
    179 
    180     theme.applyStyle(R.style.StyleB, true);
    181     assertThat(theme.obtainStyledAttributes(new int[]{R.attr.string1}).getString(0))
    182         .isEqualTo("string 1 from style B");
    183   }
    184 
    185   @Test
    186   public void whenStyleSpecifiesAttr_obtainStyledAttribute_findsCorrectValue() throws Exception {
    187     Resources.Theme theme = resources.newTheme();
    188     theme.applyStyle(R.style.Theme_Robolectric, false);
    189     theme.applyStyle(R.style.Theme_ThemeContainingStyleReferences, true);
    190 
    191     assertThat(theme.obtainStyledAttributes(
    192         Robolectric.buildAttributeSet().setStyleAttribute("?attr/styleReference").build(),
    193         new int[]{R.attr.string2}, 0, 0).getString(0))
    194         .isEqualTo("string 2 from YetAnotherStyle");
    195 
    196     assertThat(theme.obtainStyledAttributes(
    197         Robolectric.buildAttributeSet().setStyleAttribute("?styleReference").build(),
    198         new int[]{R.attr.string2}, 0, 0).getString(0))
    199         .isEqualTo("string 2 from YetAnotherStyle");
    200   }
    201 
    202   @Test
    203   public void xml_whenStyleSpecifiesAttr_obtainStyledAttribute_findsCorrectValue() throws Exception {
    204     Resources.Theme theme = resources.newTheme();
    205     theme.applyStyle(R.style.Theme_Robolectric, false);
    206     theme.applyStyle(R.style.Theme_ThemeContainingStyleReferences, true);
    207 
    208     assertThat(theme.obtainStyledAttributes(getFirstElementAttrSet(R.xml.temp),
    209         new int[]{R.attr.string2}, 0, 0).getString(0))
    210         .isEqualTo("string 2 from YetAnotherStyle");
    211 
    212     assertThat(theme.obtainStyledAttributes(getFirstElementAttrSet(R.xml.temp_parent),
    213         new int[]{R.attr.string2}, 0, 0).getString(0))
    214         .isEqualTo("string 2 from YetAnotherStyle");
    215   }
    216 
    217   @Test
    218   public void whenAttrSetAttrSpecifiesAttr_obtainStyledAttribute_returnsItsValue() throws Exception {
    219     Resources.Theme theme = resources.newTheme();
    220     theme.applyStyle(R.style.Theme_Robolectric, false);
    221     theme.applyStyle(R.style.Theme_ThemeContainingStyleReferences, true);
    222 
    223     assertThat(theme.obtainStyledAttributes(
    224         Robolectric.buildAttributeSet().addAttribute(R.attr.string2, "?attr/string1").build(),
    225         new int[]{R.attr.string2}, 0, 0).getString(0))
    226         .isEqualTo("string 1 from Theme.Robolectric");
    227   }
    228 
    229   public static class TestActivity extends Activity {
    230     @Override protected void onCreate(Bundle savedInstanceState) {
    231       super.onCreate(savedInstanceState);
    232       setContentView(R.layout.styles_button_layout);
    233     }
    234   }
    235 
    236   @Test
    237   public void dimenRef() throws Exception {
    238     AttributeSet attributeSet = Robolectric.buildAttributeSet()
    239         .addAttribute(android.R.attr.layout_height, "@dimen/test_px_dimen")
    240         .build();
    241     TypedArray typedArray = resources.newTheme().obtainStyledAttributes(
    242         attributeSet, new int[]{android.R.attr.layout_height}, 0, 0);
    243     assertThat(typedArray.getDimensionPixelSize(0, -1)).isEqualTo(15);
    244   }
    245 
    246   @Test
    247   public void dimenRefRef() throws Exception {
    248     AttributeSet attributeSet = Robolectric.buildAttributeSet()
    249         .addAttribute(android.R.attr.layout_height, "@dimen/ref_to_px_dimen")
    250         .build();
    251     TypedArray typedArray = resources.newTheme().obtainStyledAttributes(
    252         attributeSet, new int[]{android.R.attr.layout_height}, 0, 0);
    253     assertThat(typedArray.getDimensionPixelSize(0, -1)).isEqualTo(15);
    254   }
    255 
    256   @Test public void obtainStyledAttributes_shouldFindAttributeInDefaultStyle() throws Exception {
    257     Theme theme = resources.newTheme();
    258     TypedArray typedArray = theme.obtainStyledAttributes(R.style.StyleA, new int[]{R.attr.string1});
    259     assertThat(typedArray.getString(0)).isEqualTo("string 1 from style A");
    260   }
    261 
    262   @Test public void shouldApplyFromStyleAttribute() throws Exception {
    263     TestWithStyleAttrActivity activity = buildActivity(TestWithStyleAttrActivity.class).create().get();
    264     View button = activity.findViewById(R.id.button);
    265     assertThat(button.getLayoutParams().width).isEqualTo(42); // comes via style attr
    266   }
    267 
    268   ////////////////////////////
    269 
    270   private XmlResourceParser getFirstElementAttrSet(int resId) throws Exception {
    271     XmlResourceParser xml = resources.getXml(resId);
    272     assertThat(xml.next()).isEqualTo(XmlPullParser.START_DOCUMENT);
    273     assertThat(xml.nextTag()).isEqualTo(XmlPullParser.START_TAG);
    274     return (XmlResourceParser) Xml.asAttributeSet(xml);
    275   }
    276 
    277   public static class TestActivityWithAnotherTheme extends TestActivity {
    278   }
    279 
    280   public static class TestWithStyleAttrActivity extends Activity {
    281     @Override protected void onCreate(Bundle savedInstanceState) {
    282       super.onCreate(savedInstanceState);
    283       setContentView(R.layout.styles_button_with_style_layout);
    284     }
    285   }
    286 }
    287