blob: 55c20fe8924c33488480a519212f737589fe4f75 [file] [log] [blame]
package org.robolectric.res;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
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.RelativeLayout;
import android.widget.TextView;
import com.google.android.maps.MapView;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.R;
import org.robolectric.Robolectric;
import org.robolectric.TestRunners;
import org.robolectric.annotation.Config;
import org.robolectric.res.builder.LayoutBuilder;
import org.robolectric.shadows.ShadowImageView;
import org.robolectric.shadows.ShadowTextView;
import org.robolectric.util.CustomView;
import org.robolectric.util.CustomView2;
import org.robolectric.util.I18nException;
import org.robolectric.util.TestUtil;
import java.util.ArrayList;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.*;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.robolectric.Robolectric.shadowOf;
import static org.robolectric.util.TestUtil.TEST_PACKAGE;
import static org.robolectric.util.TestUtil.assertInstanceOf;
@RunWith(TestRunners.WithDefaults.class)
public class ViewLoaderTest {
private Activity context;
private ResourceLoader resourceLoader;
@Before
public void setUp() throws Exception {
resourceLoader = Robolectric.getShadowApplication().getResourceLoader();
context = new Activity() {};
}
@Test
public void testCreatesCorrectClasses() throws Exception {
ViewGroup view = (ViewGroup) inflate("media");
TestUtil.assertInstanceOf(LinearLayout.class, view);
assertSame(context, view.getContext());
}
@Test
public void testChoosesLayoutBasedOnDefaultScreenSize() throws Exception {
ViewGroup view = (ViewGroup) inflate("different_screen_sizes");
TextView textView = (TextView) view.findViewById(android.R.id.text1);
assertThat(textView.getText().toString()).isEqualTo("default");
}
@Test @Config(qualifiers = "xlarge-land")
public void testChoosesLayoutBasedOnSearchPath_choosesFirstFileFoundOnPath() throws Exception {
// resourceLoader.setLayoutQualifierSearchPath("xlarge", "land");
ViewGroup view = (ViewGroup) inflate("different_screen_sizes", "xlarge-land");
TextView textView = (TextView) view.findViewById(android.R.id.text1);
assertThat(textView.getText().toString()).isEqualTo("xlarge");
}
@Test @Config(qualifiers = "doesnotexist-land-xlarge")
public void testChoosesLayoutBasedOnSearchPath_respectsOrderOfPath() throws Exception {
ViewGroup view = (ViewGroup) inflate("different_screen_sizes", "doesnotexist-land-xlarge");
TextView textView = (TextView) view.findViewById(android.R.id.text1);
assertThat(textView.getText().toString()).isEqualTo("land");
}
@Test
public void testWebView() throws Exception {
ViewGroup view = (ViewGroup) inflate("webview_holder");
WebView 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 = (ViewGroup) inflate("media");
assertTrue(view.getChildCount() > 0);
assertSame(context, view.getChildAt(0).getContext());
}
@Test
public void testFindsChildrenById() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("media");
TestUtil.assertInstanceOf(TextView.class, mediaView.findViewById(R.id.title));
ViewGroup mainView = (ViewGroup) inflate("main");
assertInstanceOf(View.class, mainView.findViewById(R.id.title));
}
@Test
public void testInflatingConflictingSystemAndLocalViewsWorks() throws Exception {
ViewGroup view = (ViewGroup) inflate("activity_list_item");
assertInstanceOf(ImageView.class, view.findViewById(R.id.icon));
view = (ViewGroup) inflate("android", "activity_list_item", "");
assertInstanceOf(ImageView.class, view.findViewById(android.R.id.icon));
}
@Test
public void testInclude() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("media");
assertInstanceOf(TextView.class, mediaView.findViewById(R.id.include_id));
}
@Test
public void testIncludeShouldRetainAttributes() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("media");
assertThat(mediaView.findViewById(R.id.include_id).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void shouldOverwriteIdOnIncludedNonMerge() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("media");
assertNull(mediaView.findViewById(R.id.snippet_text));
}
@Test
public void shouldRetainIdOnIncludedMergeWhenIncludeSpecifiesNoId() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("override_include");
assertInstanceOf(TextView.class, mediaView.findViewById(R.id.inner_text));
}
@Test
public void shouldRetainIdOnIncludedNonMergeWhenIncludeSpecifiesNoId() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("override_include");
assertInstanceOf(TextView.class, mediaView.findViewById(R.id.snippet_text));
}
@Test
public void testIncludedIdShouldNotBeFoundWhenIncludedIsMerge() throws Exception {
ViewGroup overrideIncludeView = (ViewGroup) inflate("outer");
assertInstanceOf(LinearLayout.class, overrideIncludeView.findViewById(R.id.outer_merge));
assertInstanceOf(TextView.class, overrideIncludeView.findViewById(R.id.inner_text));
assertNull(overrideIncludeView.findViewById(R.id.include_id));
assertEquals(1, overrideIncludeView.getChildCount());
}
@Test
public void testIncludeShouldOverrideAttributesOfIncludedRootNode() throws Exception {
ViewGroup overrideIncludeView = (ViewGroup) inflate("override_include");
assertThat(overrideIncludeView.findViewById(R.id.snippet_text).getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void shouldNotCountRequestFocusElementAsChild() throws Exception {
ViewGroup viewGroup = (ViewGroup) inflate("request_focus");
ViewGroup frameLayout = (ViewGroup) viewGroup.getChildAt(1);
assertEquals(0, frameLayout.getChildCount());
}
@Test
public void shouldGiveFocusToElementContainingRequestFocusElement() throws Exception {
ViewGroup viewGroup = (ViewGroup) inflate("request_focus");
EditText editText = (EditText) viewGroup.findViewById(R.id.edit_text);
assertFalse(editText.isFocused());
}
@Test
public void shouldGiveFocusToFirstFocusableElement_butThisMightBeTheWrongBehavior() throws Exception {
ViewGroup viewGroup = (ViewGroup) inflate("request_focus_with_two_edit_texts");
assertTrue(viewGroup.findViewById(R.id.edit_text).isFocused());
assertFalse(viewGroup.findViewById(R.id.edit_text2).isFocused());
}
@Test
public void testMerge() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("outer");
TestUtil.assertInstanceOf(TextView.class, mediaView.findViewById(R.id.inner_text));
}
@Test
public void mergeIncludesShouldNotCreateAncestryLoops() throws Exception {
ViewGroup mediaView = (ViewGroup) inflate("outer");
mediaView.hasFocus();
}
@Test
public void testViewGroupsLooksAtItsOwnId() throws Exception {
TextView mediaView = (TextView) inflate("snippet");
assertSame(mediaView, mediaView.findViewById(R.id.snippet_text));
}
@Test
public void shouldConstructCustomViewsWithAttributesConstructor() throws Exception {
CustomView view = (CustomView) inflate("custom_layout");
assertThat(view.attributeResourceValue).isEqualTo(R.string.hello);
}
@Test
public void shouldConstructCustomViewsWithAttributesWithURLEncodedNamespaces() throws Exception {
CustomView view = (CustomView) inflate("custom_layout4")
.findViewById(R.id.custom_view);
assertThat(view.namespacedResourceValue).isEqualTo(R.layout.text_views);
}
@Test
public void testViewVisibilityIsSet() throws Exception {
View mediaView = inflate("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("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("main");
ShadowTextView shadowTextView = shadowOf((TextView) mediaView.findViewById(R.id.title));
assertThat(shadowTextView.getCompoundDrawablesImpl().getTop()).isEqualTo(R.drawable.an_image);
assertThat(shadowTextView.getCompoundDrawablesImpl().getRight()).isEqualTo(R.drawable.an_other_image);
assertThat(shadowTextView.getCompoundDrawablesImpl().getBottom()).isEqualTo(R.drawable.third_image);
assertThat(shadowTextView.getCompoundDrawablesImpl().getLeft()).isEqualTo(R.drawable.fourth_image);
}
@Test
public void testCheckBoxCheckedIsSet() throws Exception {
View mediaView = inflate("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("main");
assertThat(((ShadowImageView) shadowOf(mediaView.findViewById(R.id.image))).getResourceId()).isEqualTo(R.drawable.an_image);
}
@Test
public void shouldInflateMergeLayoutIntoParent() throws Exception {
View innerMerge = new LayoutBuilder(resourceLoader).inflateView(context, R.layout.inner_merge, new LinearLayout(Robolectric.application), "");
assertNotNull(innerMerge);
}
@Test
public void testMapView() throws Exception {
RelativeLayout mainView = (RelativeLayout) inflate("mapview");
TestUtil.assertInstanceOf(MapView.class, mainView.findViewById(R.id.map_view));
}
@Test
@Ignore
public void testFragment() throws Exception {
FragmentActivity fragmentActivity = new FragmentActivity();
context = fragmentActivity;
View v = inflate("fragment");
TestUtil.assertInstanceOf(TextView.class, v);
final FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.my_fragment);
assertNotNull(fragment);
}
@Test
public void testMultiOrientation() throws Exception {
context = new FragmentActivity();
shadowOf(context).callOnCreate(null);
shadowOf(context).callOnStart();
shadowOf(context).callOnResume();
// Default screen orientation should be portrait.
ViewGroup view = (ViewGroup) inflate("multi_orientation");
TestUtil.assertInstanceOf(LinearLayout.class, view);
assertEquals(view.getId(), R.id.portrait);
assertSame(context, view.getContext());
// Confirm explicit "orientation = portrait" works.
context.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
view = (ViewGroup) inflate("multi_orientation");
TestUtil.assertInstanceOf(LinearLayout.class, view);
assertEquals(view.getId(), R.id.portrait);
assertSame(context, view.getContext());
// Confirm explicit "orientation = landscape" works.
context.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
view = (ViewGroup) inflate("multi_orientation", "land");
assertEquals(view.getId(), R.id.landscape);
TestUtil.assertInstanceOf(LinearLayout.class, view);
}
@Test
public void testViewEnabled() throws Exception {
View mediaView = inflate("main");
assertThat(mediaView.findViewById(R.id.time).isEnabled()).isFalse();
}
@Test
public void testContentDescriptionIsSet() throws Exception {
View mediaView = inflate("main");
assertThat(mediaView.findViewById(R.id.time).getContentDescription().toString()).isEqualTo("Howdy");
}
@Test
public void testAlphaIsSet() throws Exception {
View mediaView = inflate("main");
assertThat(mediaView.findViewById(R.id.time).getAlpha()).isEqualTo(.3f);
}
@Test
public void testViewBackgroundIdIsSet() throws Exception {
View mediaView = inflate("main");
ImageView imageView = (ImageView) mediaView.findViewById(R.id.image);
ShadowImageView shadowImageView = Robolectric.shadowOf(imageView);
assertThat(shadowImageView.getBackgroundResourceId()).isEqualTo(R.drawable.image_background);
}
@Test
public void testOnClickAttribute() throws Exception {
ClickActivity activity = new ClickActivity();
activity.onCreate(null);
assertThat(activity.clicked).isFalse();
Button button = (Button)activity.findViewById(R.id.button);
button.performClick();
assertThat(activity.clicked).isTrue();
}
@Test
public void testInvalidOnClickAttribute() throws Exception {
Activity activity = new Activity();
activity.setContentView(R.layout.with_invalid_onclick);
Button button =
(Button)activity.findViewById(R.id.invalid_onclick_button);
IllegalStateException exception = null;
try {
button.performClick();
} catch (IllegalStateException e) {
exception = e;
} finally {
assertNotNull(exception);
org.junit.Assert.assertThat("The error message should contain the id name of the "
+ "faulty button",
exception.getMessage(),
containsString("invalid_onclick_button"));
}
}
@Test
public void shouldInvokeOnFinishInflate() throws Exception {
CustomView2 outerCustomView = (CustomView2) inflate("custom_layout2");
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 = (CustomView3) inflate("custom_layout3");
assertThat(outerCustomView.getText().toString()).isEqualTo("Hello bonjour");
}
@Test
public void testIncludesLinearLayoutsOnlyOnce() throws Exception {
ViewGroup parentView = (ViewGroup) inflate("included_layout_parent");
assertEquals(1, parentView.getChildCount());
}
@Test(expected=I18nException.class)
public void shouldThrowI18nExceptionOnLayoutWithBareStrings() throws Exception {
Robolectric.getShadowApplication().setStrictI18n(true);
inflate("text_views");
}
private View inflate(String packageName, String layoutName, String qualifiers) {
return inflate(context, packageName, layoutName, null, qualifiers);
}
public View inflate(Context context, String packageName, String key, ViewGroup parent, String qualifiers) {
ResourceLoader resourceLoader = shadowOf(context.getResources()).getResourceLoader();
return new LayoutBuilder(resourceLoader).inflateView(context, new ResName(packageName + ":layout/" + key),
new ArrayList<Attribute>(), parent, qualifiers);
}
private View inflate(String layoutName) {
return inflate(layoutName, "");
}
private View inflate(String layoutName, String qualifiers) {
return inflate(TEST_PACKAGE, layoutName, qualifiers);
}
public static class ClickActivity extends FragmentActivity {
public boolean clicked = false;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onButtonClick(View v) {
clicked = true;
}
}
}