| package com.xtremelabs.robolectric.res; |
| |
| import android.app.Activity; |
| import android.content.Context; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.webkit.WebView; |
| import android.widget.*; |
| import com.google.android.maps.MapView; |
| import com.xtremelabs.robolectric.R; |
| import com.xtremelabs.robolectric.Robolectric; |
| import com.xtremelabs.robolectric.WithTestDefaultsRunner; |
| import com.xtremelabs.robolectric.shadows.ShadowImageView; |
| import com.xtremelabs.robolectric.shadows.ShadowTextView; |
| import com.xtremelabs.robolectric.util.CustomView; |
| import com.xtremelabs.robolectric.util.CustomView2; |
| import com.xtremelabs.robolectric.util.I18nException; |
| import com.xtremelabs.robolectric.util.TestUtil; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import static com.xtremelabs.robolectric.Robolectric.shadowOf; |
| import static com.xtremelabs.robolectric.util.TestUtil.*; |
| import static org.hamcrest.CoreMatchers.*; |
| import static org.junit.Assert.*; |
| |
| @RunWith(WithTestDefaultsRunner.class) |
| public class ViewLoaderTest { |
| private ViewLoader viewLoader; |
| private Context context; |
| |
| @Before |
| public void setUp() throws Exception { |
| Robolectric.bindDefaultShadowClasses(); |
| |
| ResourceExtractor resourceExtractor = new ResourceExtractor(); |
| resourceExtractor.addLocalRClass(R.class); |
| resourceExtractor.addSystemRClass(android.R.class); |
| |
| StringResourceLoader stringResourceLoader = new StringResourceLoader(resourceExtractor); |
| new DocumentLoader(stringResourceLoader).loadResourceXmlDir(resourceFile("res", "values")); |
| new DocumentLoader(stringResourceLoader).loadSystemResourceXmlDir(getSystemResourceDir("values")); |
| |
| viewLoader = new ViewLoader(resourceExtractor, new AttrResourceLoader(resourceExtractor)); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout")); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout-land")); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout-large-v16")); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout-v11")); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout-xlarge")); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout-xlarge-v11")); |
| new DocumentLoader(viewLoader).loadSystemResourceXmlDir(getSystemResourceDir("layout")); |
| |
| context = new Activity(); |
| } |
| |
| @Test |
| public void testCreatesCorrectClasses() throws Exception { |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/media"); |
| TestUtil.assertInstanceOf(LinearLayout.class, view); |
| |
| assertSame(context, view.getContext()); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnDefaultScreenSize() throws Exception { |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("default")); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnSearchPath_choosesFirstFileFoundOnPath() throws Exception { |
| viewLoader.setLayoutQualifierSearchPath("xlarge", "land"); |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("xlarge")); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnSearchPath_respectsOrderOfPath() throws Exception { |
| viewLoader.setLayoutQualifierSearchPath("does-not-exist", "land", "xlarge"); |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("land")); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnDefaultVersion() throws Exception { |
| Robolectric.Reflection.setFinalStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.FROYO); |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("default")); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnNewestVersion() throws Exception { |
| Robolectric.Reflection.setFinalStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN); |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("v11")); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnSearchPath_choosesFirstFileFoundOnPathWithVersionNumber() throws Exception { |
| viewLoader.setLayoutQualifierSearchPath("xlarge", "large"); |
| Robolectric.Reflection.setFinalStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.HONEYCOMB); |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("xlarge-v11")); |
| } |
| |
| @Test |
| public void testChoosesLayoutBasedOnSearchPath_choosesBestFileFoundOnPathWithVersionNumber() throws Exception { |
| viewLoader.setLayoutQualifierSearchPath("xlarge", "large"); |
| Robolectric.Reflection.setFinalStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN); |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/different_screen_sizes"); |
| TextView textView = (TextView) view.findViewById(android.R.id.text1); |
| assertThat(textView.getText().toString(), equalTo("xlarge-v11")); |
| } |
| |
| @Test |
| public void testWebView() throws Exception { |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/webview_holder"); |
| WebView webView = (WebView) view.findViewById(R.id.web_view); |
| |
| webView.loadUrl("www.example.com"); |
| |
| assertThat(shadowOf(webView).getLastLoadedUrl(), equalTo("www.example.com")); |
| } |
| |
| @Test |
| public void testAddsChildren() throws Exception { |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/media"); |
| assertTrue(view.getChildCount() > 0); |
| |
| assertSame(context, view.getChildAt(0).getContext()); |
| } |
| |
| @Test |
| public void testFindsChildrenById() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/media"); |
| TestUtil.assertInstanceOf(TextView.class, mediaView.findViewById(R.id.title)); |
| |
| ViewGroup mainView = (ViewGroup) viewLoader.inflateView(context, "layout/main"); |
| assertInstanceOf(View.class, mainView.findViewById(R.id.title)); |
| } |
| |
| @Test |
| public void testInflatingConflictingSystemAndLocalViewsWorks() throws Exception { |
| ViewGroup view = (ViewGroup) viewLoader.inflateView(context, "layout/activity_list_item"); |
| assertInstanceOf(ImageView.class, view.findViewById(R.id.icon)); |
| |
| view = (ViewGroup) viewLoader.inflateView(context, "android:layout/activity_list_item"); |
| assertInstanceOf(ImageView.class, view.findViewById(android.R.id.icon)); |
| } |
| |
| @Test |
| public void testInclude() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/media"); |
| assertInstanceOf(TextView.class, mediaView.findViewById(R.id.include_id)); |
| } |
| |
| @Test |
| public void testIncludeShouldRetainAttributes() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/media"); |
| assertThat(mediaView.findViewById(R.id.include_id).getVisibility(), is(View.GONE)); |
| } |
| |
| @Test |
| public void shouldOverwriteIdOnIncludedNonMerge() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/media"); |
| assertNull(mediaView.findViewById(R.id.snippet_text)); |
| } |
| |
| @Test |
| public void shouldRetainIdOnIncludedMergeWhenIncludeSpecifiesNoId() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/override_include"); |
| assertInstanceOf(TextView.class, mediaView.findViewById(R.id.inner_text)); |
| } |
| |
| @Test |
| public void shouldRetainIdOnIncludedNonMergeWhenIncludeSpecifiesNoId() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/override_include"); |
| assertInstanceOf(TextView.class, mediaView.findViewById(R.id.snippet_text)); |
| } |
| |
| @Test |
| public void testIncludedIdShouldNotBeFoundWhenIncludedIsMerge() throws Exception { |
| ViewGroup overrideIncludeView = (ViewGroup) viewLoader.inflateView(context, "layout/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) viewLoader.inflateView(context, "layout/override_include"); |
| assertThat(overrideIncludeView.findViewById(R.id.snippet_text).getVisibility(), is(View.INVISIBLE)); |
| } |
| |
| @Test |
| public void shouldNotCountRequestFocusElementAsChild() throws Exception { |
| ViewGroup viewGroup = (ViewGroup) viewLoader.inflateView(context, "layout/request_focus"); |
| ViewGroup frameLayout = (ViewGroup) viewGroup.getChildAt(1); |
| assertEquals(0, frameLayout.getChildCount()); |
| } |
| |
| @Test |
| public void shouldGiveFocusToElementContainingRequestFocusElement() throws Exception { |
| ViewGroup viewGroup = (ViewGroup) viewLoader.inflateView(context, "layout/request_focus"); |
| EditText editText = (EditText) viewGroup.findViewById(R.id.edit_text); |
| assertFalse(editText.isFocused()); |
| } |
| |
| @Test |
| public void shouldGiveFocusToFirstFocusableElement_butThisMightBeTheWrongBehavior() throws Exception { |
| ViewGroup viewGroup = (ViewGroup) viewLoader.inflateView(context, "layout/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) viewLoader.inflateView(context, "layout/outer"); |
| TestUtil.assertInstanceOf(TextView.class, mediaView.findViewById(R.id.inner_text)); |
| } |
| |
| @Test |
| public void mergeIncludesShouldNotCreateAncestryLoops() throws Exception { |
| ViewGroup mediaView = (ViewGroup) viewLoader.inflateView(context, "layout/outer"); |
| mediaView.hasFocus(); |
| } |
| |
| @Test |
| public void testViewGroupsLooksAtItsOwnId() throws Exception { |
| TextView mediaView = (TextView) viewLoader.inflateView(context, "layout/snippet"); |
| assertSame(mediaView, mediaView.findViewById(R.id.snippet_text)); |
| } |
| |
| @Test |
| public void shouldConstructCustomViewsWithAttributesConstructor() throws Exception { |
| CustomView view = (CustomView) viewLoader.inflateView(context, "layout/custom_layout"); |
| assertThat(view.attributeResourceValue, equalTo(R.string.hello)); |
| } |
| |
| @Test |
| public void testViewVisibilityIsSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/media"); |
| assertThat(mediaView.findViewById(R.id.title).getVisibility(), equalTo(View.VISIBLE)); |
| assertThat(mediaView.findViewById(R.id.subtitle).getVisibility(), equalTo(View.GONE)); |
| } |
| |
| @Test |
| public void testTextViewTextIsSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| assertThat(((TextView) mediaView.findViewById(R.id.title)).getText().toString(), equalTo("Main Layout")); |
| assertThat(((TextView) mediaView.findViewById(R.id.subtitle)).getText().toString(), equalTo("Hello")); |
| } |
| |
| @Test |
| public void testTextViewCompoundDrawablesAreSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| ShadowTextView shadowTextView = shadowOf((TextView) mediaView.findViewById(R.id.title)); |
| |
| assertThat(shadowTextView.getCompoundDrawablesImpl().getTop(), equalTo(R.drawable.an_image)); |
| assertThat(shadowTextView.getCompoundDrawablesImpl().getRight(), equalTo(R.drawable.an_other_image)); |
| assertThat(shadowTextView.getCompoundDrawablesImpl().getBottom(), equalTo(R.drawable.third_image)); |
| assertThat(shadowTextView.getCompoundDrawablesImpl().getLeft(), equalTo(R.drawable.fourth_image)); |
| } |
| |
| @Test |
| public void testCheckBoxCheckedIsSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| assertThat(((CheckBox) mediaView.findViewById(R.id.true_checkbox)).isChecked(), equalTo(true)); |
| assertThat(((CheckBox) mediaView.findViewById(R.id.false_checkbox)).isChecked(), equalTo(false)); |
| assertThat(((CheckBox) mediaView.findViewById(R.id.default_checkbox)).isChecked(), equalTo(false)); |
| } |
| |
| @Test |
| public void testImageViewSrcIsSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| assertThat(((ShadowImageView) shadowOf(mediaView.findViewById(R.id.image))).getResourceId(), equalTo(R.drawable.an_image)); |
| } |
| |
| @Test |
| public void shouldInflateMergeLayoutIntoParent() throws Exception { |
| View innerMerge = viewLoader.inflateView(context, R.layout.inner_merge, new LinearLayout(null)); |
| assertNotNull(innerMerge); |
| } |
| |
| @Test |
| public void testMapView() throws Exception { |
| RelativeLayout mainView = (RelativeLayout) viewLoader.inflateView(context, "layout/mapview"); |
| TestUtil.assertInstanceOf(MapView.class, mainView.findViewById(R.id.map_view)); |
| } |
| |
| @Test |
| public void testViewEnabled() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| assertThat(mediaView.findViewById(R.id.time).isEnabled(), equalTo(false)); |
| } |
| |
| @Test |
| public void testContentDescriptionIsSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| assertThat(mediaView.findViewById(R.id.time).getContentDescription().toString(), equalTo("Howdy")); |
| } |
| |
| @Test |
| public void testViewBackgroundIdIsSet() throws Exception { |
| View mediaView = viewLoader.inflateView(context, "layout/main"); |
| ImageView imageView = (ImageView) mediaView.findViewById(R.id.image); |
| ShadowImageView shadowImageView = Robolectric.shadowOf(imageView); |
| |
| assertThat(shadowImageView.getBackgroundResourceId(), equalTo(R.drawable.image_background)); |
| } |
| |
| @Test |
| public void testOnClickAttribute() throws Exception { |
| ClickActivity activity = new ClickActivity(); |
| activity.onCreate(null); |
| |
| assertThat(activity.clicked, equalTo(false)); |
| |
| Button button = (Button)activity.findViewById(R.id.button); |
| button.performClick(); |
| |
| assertThat(activity.clicked, equalTo(true)); |
| } |
| |
| @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); |
| 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) viewLoader.inflateView(context, "layout/custom_layout2"); |
| CustomView2 innerCustomView = (CustomView2) outerCustomView.getChildAt(0); |
| assertThat(outerCustomView.childCountAfterInflate, equalTo(1)); |
| assertThat(innerCustomView.childCountAfterInflate, equalTo(3)); |
| } |
| |
| @Test |
| public void testIncludesLinearLayoutsOnlyOnce() throws Exception { |
| ViewGroup parentView = (ViewGroup) viewLoader.inflateView(context, "layout/included_layout_parent"); |
| assertEquals(1, parentView.getChildCount()); |
| } |
| |
| @Test(expected=I18nException.class) |
| public void shouldThrowI18nExceptionOnLayoutWithBareStrings() throws Exception { |
| viewLoader.setStrictI18n(true); |
| new DocumentLoader(viewLoader).loadResourceXmlDir(resourceFile("res", "layout")); |
| new DocumentLoader(viewLoader).loadSystemResourceXmlDir(getSystemResourceDir("layout")); |
| |
| viewLoader.inflateView(context,"layout/text_views"); |
| } |
| |
| 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; |
| } |
| } |
| } |