blob: 6a2081f8ff131716789195d95f2bed48b17dee3c [file] [log] [blame]
package org.robolectric.shadows;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.robolectric.R.layout;
import static org.robolectric.Robolectric.buildActivity;
import static org.robolectric.Shadows.shadowOf;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.R;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.CustomStateView;
import org.robolectric.android.CustomView;
import org.robolectric.android.CustomView2;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class ShadowLayoutInflaterTest {
private Context context;
@Before
public void setUp() throws Exception {
context = RuntimeEnvironment.application;
}
@Test
public void testCreatesCorrectClasses() throws Exception {
ViewGroup view = inflate(R.layout.media);
assertThat(view).isInstanceOf((Class<? extends ViewGroup>) LinearLayout.class);
assertSame(context, view.getContext());
}
@Test
public void testChoosesLayoutBasedOnDefaultScreenSize() throws Exception {
ViewGroup view = inflate(R.layout.different_screen_sizes);
TextView textView = view.findViewById(android.R.id.text1);
assertThat(textView.getText().toString()).isEqualTo("default");
}
@Test
@Config(qualifiers = "xlarge")
public void testChoosesLayoutBasedOnScreenSize() throws Exception {
ViewGroup view = inflate(R.layout.different_screen_sizes);
TextView textView = view.findViewById(android.R.id.text1);
assertThat(textView.getText().toString()).isEqualTo("xlarge");
}
@Test @Config(qualifiers = "land")
public void testChoosesLayoutBasedOnQualifiers() throws Exception {
ViewGroup view = inflate(R.layout.different_screen_sizes);
TextView textView = view.findViewById(android.R.id.text1);
assertThat(textView.getText().toString()).isEqualTo("land");
}
@Test
public void testWebView() throws Exception {
ViewGroup view = inflate(R.layout.webview_holder);
WebView webView = view.findViewById(R.id.web_view);
webView.loadUrl("www.example.com");
assertThat(shadowOf(webView).getLastLoadedUrl()).isEqualTo("www.example.com");
}
@Test
public void testAddsChildren() throws Exception {
ViewGroup view = inflate(R.layout.media);
assertTrue(view.getChildCount() > 0);
assertSame(context, view.getChildAt(0).getContext());
}
@Test
public void testFindsChildrenById() throws Exception {
ViewGroup mediaView = inflate(R.layout.media);
assertThat(mediaView.<TextView>findViewById(R.id.title)).isInstanceOf((Class<? extends TextView>) TextView.class);
ViewGroup mainView = inflate(R.layout.main);
assertThat(mainView.<View>findViewById(R.id.title)).isInstanceOf((Class<? extends View>) View.class);
}
@Test
public void testInflatingConflictingSystemAndLocalViewsWorks() throws Exception {
ViewGroup view = inflate(R.layout.activity_list_item);
assertThat(view.<ImageView>findViewById(R.id.icon)).isInstanceOf((Class<? extends ImageView>) ImageView.class);
view = inflate(android.R.layout.activity_list_item);
assertThat(view.<ImageView>findViewById(android.R.id.icon)).isInstanceOf((Class<? extends ImageView>) ImageView.class);
}
@Test
public void testInclude() throws Exception {
ViewGroup mediaView = inflate(R.layout.media);
assertThat(mediaView.<TextView>findViewById(R.id.include_id)).isInstanceOf((Class<? extends TextView>) TextView.class);
}
@Test
public void testIncludeShouldRetainAttributes() throws Exception {
ViewGroup mediaView = inflate(R.layout.media);
assertThat(mediaView.findViewById(R.id.include_id).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void shouldOverwriteIdOnIncludedNonMerge() throws Exception {
ViewGroup mediaView = inflate(R.layout.media);
assertNull(mediaView.findViewById(R.id.snippet_text));
}
@Test
public void shouldRetainIdOnIncludedMergeWhenIncludeSpecifiesNoId() throws Exception {
ViewGroup mediaView = inflate(R.layout.override_include);
assertThat(mediaView.<TextView>findViewById(R.id.inner_text)).isInstanceOf((Class<? extends TextView>) TextView.class);
}
@Test
public void shouldRetainIdOnIncludedNonMergeWhenIncludeSpecifiesNoId() throws Exception {
ViewGroup mediaView = inflate(R.layout.override_include);
assertThat(mediaView.<TextView>findViewById(R.id.snippet_text)).isInstanceOf((Class<? extends TextView>) TextView.class);
}
@Test
public void testIncludedIdShouldNotBeFoundWhenIncludedIsMerge() throws Exception {
ViewGroup overrideIncludeView = inflate(R.layout.outer);
assertThat(overrideIncludeView.<LinearLayout>findViewById(R.id.outer_merge)).isInstanceOf((Class<? extends LinearLayout>) LinearLayout.class);
assertThat(overrideIncludeView.<TextView>findViewById(R.id.inner_text)).isInstanceOf((Class<? extends TextView>) TextView.class);
assertNull(overrideIncludeView.findViewById(R.id.include_id));
assertEquals(1, overrideIncludeView.getChildCount());
}
@Test
public void testIncludeShouldOverrideAttributesOfIncludedRootNode() throws Exception {
ViewGroup overrideIncludeView = inflate(R.layout.override_include);
assertThat(overrideIncludeView.findViewById(R.id.snippet_text).getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void shouldNotCountRequestFocusElementAsChild() throws Exception {
ViewGroup viewGroup = inflate(R.layout.request_focus);
ViewGroup frameLayout = (ViewGroup) viewGroup.getChildAt(1);
assertEquals(0, frameLayout.getChildCount());
}
@Test
public void focusRequest_shouldNotExplodeOnViewRootImpl() throws Exception {
LinearLayout parent = new LinearLayout(context);
shadowOf(parent).setMyParent(ReflectionHelpers.createNullProxy(ViewParent.class));
LayoutInflater.from(context).inflate(R.layout.request_focus, parent);
}
@Test
public void shouldGiveFocusToElementContainingRequestFocusElement() throws Exception {
ViewGroup viewGroup = inflate(R.layout.request_focus);
EditText editText = viewGroup.findViewById(R.id.edit_text);
assertFalse(editText.isFocused());
}
@Test
public void testMerge() throws Exception {
ViewGroup mediaView = inflate(R.layout.outer);
assertThat(mediaView.<TextView>findViewById(R.id.inner_text)).isInstanceOf((Class<? extends TextView>) TextView.class);
}
@Test
public void mergeIncludesShouldNotCreateAncestryLoops() throws Exception {
ViewGroup mediaView = inflate(R.layout.outer);
mediaView.hasFocus();
}
@Test
public void testViewGroupsLooksAtItsOwnId() throws Exception {
TextView mediaView = inflate(layout.snippet);
assertSame(mediaView, mediaView.findViewById(R.id.snippet_text));
}
@Test
public void shouldConstructCustomViewsWithAttributesConstructor() throws Exception {
CustomView view = inflate(layout.custom_layout);
assertThat(view.attributeResourceValue).isEqualTo(R.string.hello);
}
@Test
public void shouldConstructCustomViewsWithCustomState() throws Exception {
CustomStateView view = inflate(layout.custom_layout6);
assertThat(view.getDrawableState()).doesNotContain(R.attr.stateFoo);
view.isFoo = true;
view.refreshDrawableState();
assertThat(view.getDrawableState()).contains(R.attr.stateFoo);
}
@Test
public void shouldConstructCustomViewsWithAttributesInResAutoNamespace() throws Exception {
CustomView view = inflate(layout.custom_layout5);
assertThat(view.attributeResourceValue).isEqualTo(R.string.hello);
}
@Test
public void shouldConstructCustomViewsWithAttributesWithURLEncodedNamespaces() throws Exception {
CustomView view = inflate(layout.custom_layout4)
.findViewById(R.id.custom_view);
assertThat(view.namespacedResourceValue).isEqualTo(R.layout.text_views);
}
@Test
public void testViewVisibilityIsSet() throws Exception {
View mediaView = inflate(layout.media);
assertThat(mediaView.findViewById(R.id.title).getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mediaView.findViewById(R.id.subtitle).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testTextViewTextIsSet() throws Exception {
View mediaView = inflate(layout.main);
assertThat(((TextView) mediaView.findViewById(R.id.title)).getText().toString()).isEqualTo("Main Layout");
assertThat(((TextView) mediaView.findViewById(R.id.subtitle)).getText().toString()).isEqualTo("Hello");
}
@Test
public void testTextViewCompoundDrawablesAreSet() throws Exception {
View mediaView = inflate(layout.main);
TextView view = mediaView.findViewById(R.id.title);
assertThat(view.getCompoundDrawables()[0]).isEqualTo(drawable(R.drawable.fourth_image));
assertThat(view.getCompoundDrawables()[1]).isEqualTo(drawable(R.drawable.an_image));
assertThat(view.getCompoundDrawables()[2]).isEqualTo(drawable(R.drawable.an_other_image));
assertThat(view.getCompoundDrawables()[3]).isEqualTo(drawable(R.drawable.third_image));
}
@Test
public void testCheckBoxCheckedIsSet() throws Exception {
View mediaView = inflate(layout.main);
assertThat(((CheckBox) mediaView.findViewById(R.id.true_checkbox)).isChecked()).isTrue();
assertThat(((CheckBox) mediaView.findViewById(R.id.false_checkbox)).isChecked()).isFalse();
assertThat(((CheckBox) mediaView.findViewById(R.id.default_checkbox)).isChecked()).isFalse();
}
@Test
public void testImageViewSrcIsSet() throws Exception {
View mediaView = inflate(layout.main);
ImageView imageView = mediaView.findViewById(R.id.image);
BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
assertThat(shadowOf(drawable.getBitmap()).getCreatedFromResId()).isEqualTo(R.drawable.an_image);
}
@Test
public void testImageViewSrcIsSetFromMipmap() throws Exception {
View mediaView = inflate(layout.main);
ImageView imageView = mediaView.findViewById(R.id.mipmapImage);
BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
assertThat(shadowOf(drawable.getBitmap()).getCreatedFromResId()).isEqualTo(R.mipmap.robolectric);
}
@Test
public void shouldInflateMergeLayoutIntoParent() throws Exception {
LinearLayout linearLayout = new LinearLayout(context);
LayoutInflater.from(context).inflate(R.layout.inner_merge, linearLayout);
assertThat(linearLayout.getChildAt(0)).isInstanceOf(TextView.class);
}
@Test
public void testMultiOrientation() throws Exception {
Activity activity = buildActivity(Activity.class).create().start().resume().get();
// Default screen orientation should be portrait.
ViewGroup view = (ViewGroup) LayoutInflater.from(activity).inflate(layout.multi_orientation, null);
assertThat(view).isInstanceOf((Class<? extends ViewGroup>) LinearLayout.class);
assertEquals(view.getId(), R.id.portrait);
assertSame(activity, view.getContext());
// Confirm explicit "orientation = portrait" works.
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
int layoutResId = R.layout.multi_orientation;
view = (ViewGroup) LayoutInflater.from(activity).inflate(layoutResId, null);
assertThat(view).isInstanceOf((Class<? extends ViewGroup>) LinearLayout.class);
assertEquals(view.getId(), R.id.portrait);
assertSame(activity, view.getContext());
}
@Test
@Config(qualifiers = "land")
public void testMultiOrientation_explicitLandscape() throws Exception {
Activity activity = buildActivity(Activity.class).create().start().resume().get();
// Confirm explicit "orientation = landscape" works.
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
ViewGroup view = (ViewGroup) LayoutInflater.from(activity).inflate(layout.multi_orientation, null);
assertEquals(view.getId(), R.id.landscape);
assertThat(view).isInstanceOf((Class<? extends ViewGroup>) LinearLayout.class);
}
@Test
@Config(qualifiers = "w0dp")
public void testSetContentViewByItemResource() throws Exception {
Activity activity = buildActivity(Activity.class).create().get();
activity.setContentView(R.layout.main_layout);
TextView tv1 = activity.findViewById(R.id.hello);
TextView tv2 = activity.findViewById(R.id.world);
assertNotNull(tv1);
assertNull(tv2);
}
@Test
@Config(qualifiers = "w820dp")
public void testSetContentViewByItemResourceWithW820dp() throws Exception {
Activity activity = buildActivity(Activity.class).create().get();
activity.setContentView(R.layout.main_layout);
TextView tv1 = activity.findViewById(R.id.hello);
TextView tv2 = activity.findViewById(R.id.world);
assertNotNull(tv1);
assertNotNull(tv2);
}
@Test
public void testViewEnabled() throws Exception {
View mediaView = inflate(layout.main);
assertThat(mediaView.findViewById(R.id.time).isEnabled()).isFalse();
}
@Test
public void testContentDescriptionIsSet() throws Exception {
View mediaView = inflate(layout.main);
assertThat(mediaView.findViewById(R.id.time).getContentDescription().toString()).isEqualTo("Howdy");
}
@Test
public void testAlphaIsSet() throws Exception {
View mediaView = inflate(layout.main);
assertThat(mediaView.findViewById(R.id.time).getAlpha()).isEqualTo(.3f);
}
@Test
public void testViewBackgroundIdIsSet() throws Exception {
View mediaView = inflate(layout.main);
ImageView imageView = mediaView.findViewById(R.id.image);
assertThat(shadowOf(imageView.getBackground()).getCreatedFromResId())
.isEqualTo(R.drawable.image_background);
}
@Test
public void testOnClickAttribute() throws Exception {
ClickActivity activity = buildActivity(ClickActivity.class).create().get();
assertThat(activity.clicked).isFalse();
Button button = activity.findViewById(R.id.button);
button.performClick();
assertThat(activity.clicked).isTrue();
}
@Test
public void testInvalidOnClickAttribute() throws Exception {
Activity activity = buildActivity(Activity.class).create().get();
activity.setContentView(R.layout.with_invalid_onclick);
Button button = activity.findViewById(R.id.invalid_onclick_button);
IllegalStateException exception = null;
try {
button.performClick();
} catch (IllegalStateException e) {
exception = e;
}
assertNotNull(exception);
assertThat(exception.getMessage())
.as("The error message should contain the id name of the faulty button")
.contains("invalid_onclick_button");
}
@Test
public void shouldInvokeOnFinishInflate() throws Exception {
int layoutResId = R.layout.custom_layout2;
CustomView2 outerCustomView = inflate(layoutResId);
CustomView2 innerCustomView = (CustomView2) outerCustomView.getChildAt(0);
assertThat(outerCustomView.childCountAfterInflate).isEqualTo(1);
assertThat(innerCustomView.childCountAfterInflate).isEqualTo(3);
}
@SuppressWarnings("UnusedDeclaration")
public static class CustomView3 extends TextView {
public CustomView3(Context context) { super(context); }
public CustomView3(Context context, AttributeSet attrs) { super(context, attrs); }
public CustomView3(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
}
@Test
public void shouldInflateViewsWithClassAttr() throws Exception {
CustomView3 outerCustomView = inflate(layout.custom_layout3);
assertThat(outerCustomView.getText().toString()).isEqualTo("Hello bonjour");
}
@Test
public void testIncludesLinearLayoutsOnlyOnce() throws Exception {
ViewGroup parentView = inflate(R.layout.included_layout_parent);
assertEquals(1, parentView.getChildCount());
}
@Test
public void testConverterAcceptsEnumOrdinal() throws Exception {
ViewGroup view = inflate(R.layout.ordinal_scrollbar);
assertThat(view).isInstanceOf((Class<? extends ViewGroup>) RelativeLayout.class);
ListView listView = (ListView)
view.findViewById(org.robolectric.R.id.list_view_with_enum_scrollbar);
assertThat(listView).isInstanceOf((Class<? extends ListView>) ListView.class);
}
/////////////////////////
@SuppressWarnings("TypeParameterUnusedInFormals")
private <T extends View> T inflate(int layoutResId) {
return (T) LayoutInflater.from(context).inflate(layoutResId, null);
}
private Drawable drawable(int id) {
Drawable drawable = context.getResources().getDrawable(id);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
return drawable;
}
public static class ClickActivity extends Activity {
public boolean clicked = false;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onButtonClick(View v) {
clicked = true;
}
}
}