diff options
Diffstat (limited to 'library/test/robotest/src')
20 files changed, 2528 insertions, 2233 deletions
diff --git a/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java b/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java index 2a4a8c0..d77838f 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java @@ -16,14 +16,8 @@ package com.android.setupwizardlib; -import static org.hamcrest.Matchers.instanceOf; -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.assertThat; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.robolectric.RuntimeEnvironment.application; import android.content.Context; @@ -34,328 +28,337 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import androidx.annotation.IdRes; import android.view.ContextThemeWrapper; import android.view.View; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; - -import androidx.annotation.IdRes; - -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; import com.android.setupwizardlib.template.ColoredHeaderMixin; import com.android.setupwizardlib.template.HeaderMixin; import com.android.setupwizardlib.template.IconMixin; import com.android.setupwizardlib.template.ProgressBarMixin; import com.android.setupwizardlib.view.StatusBarBackgroundLayout; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class GlifLayoutTest { - private Context mContext; - - @Before - public void setUp() throws Exception { - mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); - } - - @Test - public void testDefaultTemplate() { - GlifLayout layout = new GlifLayout(mContext); - assertDefaultTemplateInflated(layout); - } - - @Test - public void testSetHeaderText() { - GlifLayout layout = new GlifLayout(mContext); - TextView title = (TextView) layout.findViewById(R.id.suw_layout_title); - layout.setHeaderText("Abracadabra"); - assertEquals("Header text should be \"Abracadabra\"", "Abracadabra", title.getText()); - } - - @Test - public void testAddView() { - @IdRes int testViewId = 123456; - GlifLayout layout = new GlifLayout(mContext); - TextView tv = new TextView(mContext); - tv.setId(testViewId); - layout.addView(tv); - assertDefaultTemplateInflated(layout); - View view = layout.findViewById(testViewId); - assertSame("The view added should be the same text view", tv, view); - } - - @Test - public void testGetScrollView() { - GlifLayout layout = new GlifLayout(mContext); - assertNotNull("Get scroll view should not be null with default template", - layout.getScrollView()); - } - - @Test - public void testSetPrimaryColor() { - GlifLayout layout = new GlifLayout(mContext); - layout.setProgressBarShown(true); - layout.setPrimaryColor(ColorStateList.valueOf(Color.RED)); - assertEquals("Primary color should be red", - ColorStateList.valueOf(Color.RED), layout.getPrimaryColor()); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - ProgressBar progressBar = (ProgressBar) layout.findViewById(R.id.suw_layout_progress); - assertEquals("Progress bar should be tinted red", - ColorStateList.valueOf(Color.RED), progressBar.getIndeterminateTintList()); - assertEquals("Determinate progress bar should also be tinted red", - ColorStateList.valueOf(Color.RED), progressBar.getProgressBackgroundTintList()); - } - } - - @Config(qualifiers = "sw600dp") - @Test - public void testSetPrimaryColorTablet() { - GlifLayout layout = new GlifLayout(mContext); - layout.setProgressBarShown(true); - layout.setPrimaryColor(ColorStateList.valueOf(Color.RED)); - assertEquals("Primary color should be red", - ColorStateList.valueOf(Color.RED), layout.getPrimaryColor()); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - ProgressBar progressBar = (ProgressBar) layout.findViewById(R.id.suw_layout_progress); - assertEquals("Progress bar should be tinted red", - ColorStateList.valueOf(Color.RED), progressBar.getIndeterminateTintList()); - assertEquals("Determinate progress bar should also be tinted red", - ColorStateList.valueOf(Color.RED), progressBar.getProgressBackgroundTintList()); - } - - assertEquals(Color.RED, ((GlifPatternDrawable) getTabletBackground(layout)).getColor()); - } - - @Test - public void testSetBackgroundBaseColor() { - GlifLayout layout = new GlifLayout(mContext); - layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE)); - layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED)); - - assertEquals(Color.RED, ((GlifPatternDrawable) getPhoneBackground(layout)).getColor()); - assertEquals(Color.RED, layout.getBackgroundBaseColor().getDefaultColor()); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testSetBackgroundBaseColorTablet() { - GlifLayout layout = new GlifLayout(mContext); - layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE)); - layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED)); - - assertEquals(Color.RED, ((GlifPatternDrawable) getTabletBackground(layout)).getColor()); - assertEquals(Color.RED, layout.getBackgroundBaseColor().getDefaultColor()); - } - - @Test - public void testSetBackgroundPatternedTrue() { - GlifLayout layout = new GlifLayout(mContext); - layout.setBackgroundPatterned(true); - - assertThat(getPhoneBackground(layout), instanceOf(GlifPatternDrawable.class)); - assertTrue("Background should be patterned", layout.isBackgroundPatterned()); - } - - @Test - public void testSetBackgroundPatternedFalse() { - GlifLayout layout = new GlifLayout(mContext); - layout.setBackgroundPatterned(false); - - assertThat(getPhoneBackground(layout), instanceOf(ColorDrawable.class)); - assertFalse("Background should not be patterned", layout.isBackgroundPatterned()); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testSetBackgroundPatternedTrueTablet() { - GlifLayout layout = new GlifLayout(mContext); - layout.setBackgroundPatterned(true); - - assertThat(getTabletBackground(layout), instanceOf(GlifPatternDrawable.class)); - assertTrue("Background should be patterned", layout.isBackgroundPatterned()); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testSetBackgroundPatternedFalseTablet() { - GlifLayout layout = new GlifLayout(mContext); - layout.setBackgroundPatterned(false); - - assertThat(getTabletBackground(layout), instanceOf(ColorDrawable.class)); - assertFalse("Background should not be patterned", layout.isBackgroundPatterned()); - } - - @Test - public void testNonGlifTheme() { - mContext = new ContextThemeWrapper(application, android.R.style.Theme); - new GlifLayout(mContext); - // Inflating with a non-GLIF theme should not crash - } - - @Test - public void testPeekProgressBarNull() { - GlifLayout layout = new GlifLayout(mContext); - assertNull("PeekProgressBar should return null initially", layout.peekProgressBar()); - } - - @Test - public void testPeekProgressBar() { - GlifLayout layout = new GlifLayout(mContext); - layout.setProgressBarShown(true); - assertNotNull("Peek progress bar should return the bar after setProgressBarShown(true)", - layout.peekProgressBar()); - } - - @Test - public void testMixins() { - GlifLayout layout = new GlifLayout(mContext); - final HeaderMixin header = layout.getMixin(HeaderMixin.class); - assertTrue("Header should be instance of ColoredHeaderMixin. " - + "Found " + header.getClass() + " instead.", header instanceof ColoredHeaderMixin); - - assertNotNull("GlifLayout should have icon mixin", layout.getMixin(IconMixin.class)); - assertNotNull("GlifLayout should have progress bar mixin", - layout.getMixin(ProgressBarMixin.class)); - } - - @Test - public void testInflateFooter() { - GlifLayout layout = new GlifLayout(mContext); - - final View view = layout.inflateFooter(android.R.layout.simple_list_item_1); - assertEquals(android.R.id.text1, view.getId()); - assertNotNull(layout.findViewById(android.R.id.text1)); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testInflateFooterTablet() { - testInflateFooter(); - } - - @Test - public void testInflateFooterBlankTemplate() { - GlifLayout layout = new GlifLayout(mContext, R.layout.suw_glif_blank_template); - - final View view = layout.inflateFooter(android.R.layout.simple_list_item_1); - assertEquals(android.R.id.text1, view.getId()); - assertNotNull(layout.findViewById(android.R.id.text1)); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testInflateFooterBlankTemplateTablet() { - testInflateFooterBlankTemplate(); - } - - @Test - public void testFooterXml() { - GlifLayout layout = new GlifLayout( - mContext, - Robolectric.buildAttributeSet() - .addAttribute(R.attr.suwFooter, "@android:layout/simple_list_item_1") - .build()); - - assertNotNull(layout.findViewById(android.R.id.text1)); - } - - @Test - public void inflateStickyHeader_shouldAddViewToLayout() { - GlifLayout layout = new GlifLayout(mContext); - - final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1); - assertEquals(android.R.id.text1, view.getId()); - assertNotNull(layout.findViewById(android.R.id.text1)); - } - - @Config(qualifiers = "sw600dp") - @Test - public void inflateStickyHeader_whenOnTablets_shouldAddViewToLayout() { - inflateStickyHeader_shouldAddViewToLayout(); - } - - @Test - public void inflateStickyHeader_whenInXml_shouldAddViewToLayout() { - GlifLayout layout = new GlifLayout( - mContext, - Robolectric.buildAttributeSet() - .addAttribute(R.attr.suwStickyHeader, "@android:layout/simple_list_item_1") - .build()); - - assertNotNull(layout.findViewById(android.R.id.text1)); - } - - @Test - public void inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout() { - GlifLayout layout = new GlifLayout(mContext, R.layout.suw_glif_blank_template); - - final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1); - assertEquals(android.R.id.text1, view.getId()); - assertNotNull(layout.findViewById(android.R.id.text1)); - } - - @Config(qualifiers = "sw600dp") - @Test - public void inflateStickyHeader_whenOnBlankTemplateTablet_shouldAddViewToLayout() { - inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout(); - } - - @Config(minSdk = Config.OLDEST_SDK, maxSdk = Config.NEWEST_SDK) - @Test - public void createFromXml_shouldSetLayoutFullscreen_whenLayoutFullscreenIsNotSet() { - GlifLayout layout = new GlifLayout( - mContext, - Robolectric.buildAttributeSet() - .build()); - if (VERSION.SDK_INT >= VERSION_CODES.M) { - assertEquals( - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, - layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - } - } - - @Test - public void createFromXml_shouldNotSetLayoutFullscreen_whenLayoutFullscreenIsFalse() { - GlifLayout layout = new GlifLayout( - mContext, - Robolectric.buildAttributeSet() - .addAttribute(R.attr.suwLayoutFullscreen, "false") - .build()); - - assertEquals( - 0, - layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - } - - private Drawable getPhoneBackground(GlifLayout layout) { - final StatusBarBackgroundLayout patternBg = - (StatusBarBackgroundLayout) layout.findManagedViewById(R.id.suw_pattern_bg); - return patternBg.getStatusBarBackground(); - } - - private Drawable getTabletBackground(GlifLayout layout) { - final View patternBg = layout.findManagedViewById(R.id.suw_pattern_bg); - return patternBg.getBackground(); - } - - private void assertDefaultTemplateInflated(GlifLayout layout) { - View title = layout.findViewById(R.id.suw_layout_title); - assertNotNull("@id/suw_layout_title should not be null", title); - - View icon = layout.findViewById(R.id.suw_layout_icon); - assertNotNull("@id/suw_layout_icon should not be null", icon); - - View scrollView = layout.findViewById(R.id.suw_scroll_view); - assertTrue("@id/suw_scroll_view should be a ScrollView", scrollView instanceof ScrollView); - } + private Context context; + + @Before + public void setUpContext() { + context = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); + } + + @Test + public void testDefaultTemplate() { + GlifLayout layout = new GlifLayout(context); + assertDefaultTemplateInflated(layout); + } + + @Test + public void testSetHeaderText() { + GlifLayout layout = new GlifLayout(context); + TextView title = layout.findViewById(R.id.suw_layout_title); + layout.setHeaderText("Abracadabra"); + assertWithMessage("Header text should be \"Abracadabra\"") + .that(title.getText().toString()) + .isEqualTo("Abracadabra"); + } + + @Test + public void testAddView() { + @IdRes int testViewId = 123456; + GlifLayout layout = new GlifLayout(context); + TextView tv = new TextView(context); + tv.setId(testViewId); + layout.addView(tv); + assertDefaultTemplateInflated(layout); + View view = layout.findViewById(testViewId); + assertThat(view).named("Text view added").isSameAs(tv); + } + + @Test + public void testGetScrollView() { + GlifLayout layout = new GlifLayout(context); + assertWithMessage("Get scroll view should not be null with default template") + .that(layout.getScrollView()) + .isNotNull(); + } + + @Test + public void testSetPrimaryColor() { + GlifLayout layout = new GlifLayout(context); + layout.setProgressBarShown(true); + layout.setPrimaryColor(ColorStateList.valueOf(Color.RED)); + assertWithMessage("Primary color should be red") + .that(layout.getPrimaryColor()) + .isEqualTo(ColorStateList.valueOf(Color.RED)); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ProgressBar progressBar = layout.findViewById(R.id.suw_layout_progress); + assertThat(progressBar.getIndeterminateTintList()) + .named("indeterminate progress bar tint") + .isEqualTo(ColorStateList.valueOf(Color.RED)); + assertThat(progressBar.getProgressBackgroundTintList()) + .named("determinate progress bar tint") + .isEqualTo(ColorStateList.valueOf(Color.RED)); + } + } + + @Config(qualifiers = "sw600dp") + @Test + public void testSetPrimaryColorTablet() { + GlifLayout layout = new GlifLayout(context); + layout.setProgressBarShown(true); + layout.setPrimaryColor(ColorStateList.valueOf(Color.RED)); + assertWithMessage("Primary color should be red") + .that(layout.getPrimaryColor()) + .isEqualTo(ColorStateList.valueOf(Color.RED)); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ProgressBar progressBar = layout.findViewById(R.id.suw_layout_progress); + assertWithMessage("Progress bar should be tinted red") + .that(progressBar.getIndeterminateTintList()) + .isEqualTo(ColorStateList.valueOf(Color.RED)); + assertWithMessage("Determinate progress bar should also be tinted red") + .that(progressBar.getProgressBackgroundTintList()) + .isEqualTo(ColorStateList.valueOf(Color.RED)); + } + + assertThat(((GlifPatternDrawable) getTabletBackground(layout)).getColor()).isEqualTo(Color.RED); + } + + @Test + public void testSetBackgroundBaseColor() { + GlifLayout layout = new GlifLayout(context); + layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE)); + layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED)); + + assertThat(((GlifPatternDrawable) getPhoneBackground(layout)).getColor()).isEqualTo(Color.RED); + assertThat(layout.getBackgroundBaseColor().getDefaultColor()).isEqualTo(Color.RED); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testSetBackgroundBaseColorTablet() { + GlifLayout layout = new GlifLayout(context); + layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE)); + layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED)); + + assertThat(((GlifPatternDrawable) getTabletBackground(layout)).getColor()).isEqualTo(Color.RED); + assertThat(layout.getBackgroundBaseColor().getDefaultColor()).isEqualTo(Color.RED); + } + + @Test + public void testSetBackgroundPatternedTrue() { + GlifLayout layout = new GlifLayout(context); + layout.setBackgroundPatterned(true); + + assertThat(getPhoneBackground(layout)).isInstanceOf(GlifPatternDrawable.class); + assertThat(layout.isBackgroundPatterned()).named("background is patterned").isTrue(); + } + + @Test + public void testSetBackgroundPatternedFalse() { + GlifLayout layout = new GlifLayout(context); + layout.setBackgroundPatterned(false); + + assertThat(getPhoneBackground(layout)).isInstanceOf(ColorDrawable.class); + assertThat(layout.isBackgroundPatterned()).named("background is patterned").isFalse(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testSetBackgroundPatternedTrueTablet() { + GlifLayout layout = new GlifLayout(context); + layout.setBackgroundPatterned(true); + + assertThat(getTabletBackground(layout)).isInstanceOf(GlifPatternDrawable.class); + assertThat(layout.isBackgroundPatterned()).named("background is patterned").isTrue(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testSetBackgroundPatternedFalseTablet() { + GlifLayout layout = new GlifLayout(context); + layout.setBackgroundPatterned(false); + + assertThat(getTabletBackground(layout)).isInstanceOf(ColorDrawable.class); + assertThat(layout.isBackgroundPatterned()).named("background is patterned").isFalse(); + } + + @Test + public void testNonGlifTheme() { + context = new ContextThemeWrapper(application, android.R.style.Theme); + new GlifLayout(context); + // Inflating with a non-GLIF theme should not crash + } + + @Test + public void testPeekProgressBarNull() { + GlifLayout layout = new GlifLayout(context); + assertWithMessage("PeekProgressBar should return null initially") + .that(layout.peekProgressBar()) + .isNull(); + } + + @Test + public void testPeekProgressBar() { + GlifLayout layout = new GlifLayout(context); + layout.setProgressBarShown(true); + assertWithMessage("Peek progress bar should return the bar after setProgressBarShown(true)") + .that(layout.peekProgressBar()) + .isNotNull(); + } + + @Test + public void testMixins() { + GlifLayout layout = new GlifLayout(context); + final HeaderMixin header = layout.getMixin(HeaderMixin.class); + assertThat(header).named("header").isInstanceOf(ColoredHeaderMixin.class); + + assertWithMessage("GlifLayout should have icon mixin") + .that(layout.getMixin(IconMixin.class)) + .isNotNull(); + assertWithMessage("GlifLayout should have progress bar mixin") + .that(layout.getMixin(ProgressBarMixin.class)) + .isNotNull(); + } + + @Test + public void testInflateFooter() { + GlifLayout layout = new GlifLayout(context); + + final View view = layout.inflateFooter(android.R.layout.simple_list_item_1); + assertThat(view.getId()).isEqualTo(android.R.id.text1); + assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testInflateFooterTablet() { + testInflateFooter(); + } + + @Test + public void testInflateFooterBlankTemplate() { + GlifLayout layout = new GlifLayout(context, R.layout.suw_glif_blank_template); + + final View view = layout.inflateFooter(android.R.layout.simple_list_item_1); + assertThat(view.getId()).isEqualTo(android.R.id.text1); + assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testInflateFooterBlankTemplateTablet() { + testInflateFooterBlankTemplate(); + } + + @Test + public void testFooterXml() { + GlifLayout layout = + new GlifLayout( + context, + Robolectric.buildAttributeSet() + .addAttribute(R.attr.suwFooter, "@android:layout/simple_list_item_1") + .build()); + + assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull(); + } + + @Test + public void inflateStickyHeader_shouldAddViewToLayout() { + GlifLayout layout = new GlifLayout(context); + + final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1); + assertThat(view.getId()).isEqualTo(android.R.id.text1); + assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void inflateStickyHeader_whenOnTablets_shouldAddViewToLayout() { + inflateStickyHeader_shouldAddViewToLayout(); + } + + @Test + public void inflateStickyHeader_whenInXml_shouldAddViewToLayout() { + GlifLayout layout = + new GlifLayout( + context, + Robolectric.buildAttributeSet() + .addAttribute(R.attr.suwStickyHeader, "@android:layout/simple_list_item_1") + .build()); + + assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull(); + } + + @Test + public void inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout() { + GlifLayout layout = new GlifLayout(context, R.layout.suw_glif_blank_template); + + final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1); + assertThat(view.getId()).isEqualTo(android.R.id.text1); + assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void inflateStickyHeader_whenOnBlankTemplateTablet_shouldAddViewToLayout() { + inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout(); + } + + @Config(minSdk = Config.OLDEST_SDK, maxSdk = Config.NEWEST_SDK) + @Test + public void createFromXml_shouldSetLayoutFullscreen_whenLayoutFullscreenIsNotSet() { + GlifLayout layout = new GlifLayout(context, Robolectric.buildAttributeSet().build()); + if (VERSION.SDK_INT >= VERSION_CODES.M) { + assertThat(layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) + .isEqualTo(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } + } + + @Test + public void createFromXml_shouldNotSetLayoutFullscreen_whenLayoutFullscreenIsFalse() { + GlifLayout layout = + new GlifLayout( + context, + Robolectric.buildAttributeSet() + .addAttribute(R.attr.suwLayoutFullscreen, "false") + .build()); + + assertThat(layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN).isEqualTo(0); + } + + private Drawable getPhoneBackground(GlifLayout layout) { + final StatusBarBackgroundLayout patternBg = layout.findManagedViewById(R.id.suw_pattern_bg); + return patternBg.getStatusBarBackground(); + } + + private Drawable getTabletBackground(GlifLayout layout) { + final View patternBg = layout.findManagedViewById(R.id.suw_pattern_bg); + return patternBg.getBackground(); + } + + private void assertDefaultTemplateInflated(GlifLayout layout) { + View title = layout.findViewById(R.id.suw_layout_title); + assertWithMessage("@id/suw_layout_title should not be null").that(title).isNotNull(); + + View icon = layout.findViewById(R.id.suw_layout_icon); + assertWithMessage("@id/suw_layout_icon should not be null").that(icon).isNotNull(); + + View scrollView = layout.findViewById(R.id.suw_scroll_view); + assertWithMessage("@id/suw_scroll_view should be a ScrollView") + .that(scrollView instanceof ScrollView) + .isTrue(); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java b/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java index aa2cce3..ba3e2c5 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java @@ -23,96 +23,93 @@ import static org.robolectric.RuntimeEnvironment.application; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; - -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) -@RunWith(SuwLibRobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) +@RunWith(RobolectricTestRunner.class) public class ConsecutiveTapsGestureDetectorTest { - @Mock - private ConsecutiveTapsGestureDetector.OnConsecutiveTapsListener mListener; + @Mock private ConsecutiveTapsGestureDetector.OnConsecutiveTapsListener listener; - private ConsecutiveTapsGestureDetector mDetector; - private int mSlop; - private int mTapTimeout; + private ConsecutiveTapsGestureDetector detector; + private int slop; + private int tapTimeout; - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); - View view = new View(application); - view.measure(500, 500); - view.layout(0, 0, 500, 500); - mDetector = new ConsecutiveTapsGestureDetector(mListener, view); + View view = new View(application); + view.measure(500, 500); + view.layout(0, 0, 500, 500); + detector = new ConsecutiveTapsGestureDetector(listener, view); - mSlop = ViewConfiguration.get(application).getScaledDoubleTapSlop(); - mTapTimeout = ViewConfiguration.getDoubleTapTimeout(); - } + slop = ViewConfiguration.get(application).getScaledDoubleTapSlop(); + tapTimeout = ViewConfiguration.getDoubleTapTimeout(); + } - @Test - public void onTouchEvent_shouldTriggerCallbackOnFourTaps() { - InOrder inOrder = inOrder(mListener); + @Test + public void onTouchEvent_shouldTriggerCallbackOnFourTaps() { + InOrder inOrder = inOrder(listener); - tap(0, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(1)); + tap(0, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(1)); - tap(100, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(2)); + tap(100, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(2)); - tap(200, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(3)); + tap(200, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(3)); - tap(300, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(4)); - } + tap(300, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(4)); + } - @Test - public void onTouchEvent_tapOnDifferentLocation_shouldResetCounter() { - InOrder inOrder = inOrder(mListener); + @Test + public void onTouchEvent_tapOnDifferentLocation_shouldResetCounter() { + InOrder inOrder = inOrder(listener); - tap(0, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(1)); + tap(0, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(1)); - tap(100, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(2)); + tap(100, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(2)); - tap(200, 25f + mSlop * 2, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(1)); + tap(200, 25f + slop * 2, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(1)); - tap(300, 25f + mSlop * 2, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(2)); - } + tap(300, 25f + slop * 2, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(2)); + } - @Test - public void onTouchEvent_tapAfterTimeout_shouldResetCounter() { - InOrder inOrder = inOrder(mListener); + @Test + public void onTouchEvent_tapAfterTimeout_shouldResetCounter() { + InOrder inOrder = inOrder(listener); - tap(0, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(1)); + tap(0, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(1)); - tap(100, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(2)); + tap(100, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(2)); - tap(200 + mTapTimeout, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(1)); + tap(200 + tapTimeout, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(1)); - tap(300 + mTapTimeout, 25f, 25f); - inOrder.verify(mListener).onConsecutiveTaps(eq(2)); - } + tap(300 + tapTimeout, 25f, 25f); + inOrder.verify(listener).onConsecutiveTaps(eq(2)); + } - private void tap(int timeMillis, float x, float y) { - mDetector.onTouchEvent( - MotionEvent.obtain(timeMillis, timeMillis, MotionEvent.ACTION_DOWN, x, y, 0)); - mDetector.onTouchEvent( - MotionEvent.obtain(timeMillis, timeMillis + 10, MotionEvent.ACTION_UP, x, y, 0)); - } + private void tap(int timeMillis, float x, float y) { + detector.onTouchEvent( + MotionEvent.obtain(timeMillis, timeMillis, MotionEvent.ACTION_DOWN, x, y, 0)); + detector.onTouchEvent( + MotionEvent.obtain(timeMillis, timeMillis + 10, MotionEvent.ACTION_UP, x, y, 0)); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java b/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java index 40e5da8..b51e875 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java @@ -16,12 +16,8 @@ package com.android.setupwizardlib.items; -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 com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.same; @@ -31,152 +27,157 @@ import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; import android.content.Context; -import android.text.TextUtils; import android.view.ContextThemeWrapper; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; - import com.android.setupwizardlib.R; import com.android.setupwizardlib.items.ButtonItem.OnClickListener; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class ButtonItemTest { - private ViewGroup mParent; - private Context mContext; - - @Before - public void setUp() { - mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); - mParent = new LinearLayout(mContext); - } - - @Test - public void testDefaultItem() { - ButtonItem item = new ButtonItem(); - - assertTrue("ButtonItem should be enabled by default", item.isEnabled()); - assertEquals("ButtonItem should return count = 0", 0, item.getCount()); - assertEquals("ButtonItem should return layout resource = 0", 0, item.getLayoutResource()); - assertEquals("Default theme should be @style/SuwButtonItem", R.style.SuwButtonItem, - item.getTheme()); - assertNull("Default text should be null", item.getText()); - } - - @Test - public void testOnBindView() { - ButtonItem item = new ButtonItem(); - - try { - item.onBindView(new View(mContext)); - fail("Calling onBindView on ButtonItem should throw UnsupportedOperationException"); - } catch (UnsupportedOperationException e) { - // pass - } - } - - @Test - public void testCreateButton() { - TestButtonItem item = new TestButtonItem(); - final Button button = item.createButton(mParent); - - assertTrue("Default button should be enabled", button.isEnabled()); - assertTrue("Default button text should be empty", TextUtils.isEmpty(button.getText())); - } - - @Test - public void testButtonItemSetsItsId() { - TestButtonItem item = new TestButtonItem(); - final int id = 12345; - item.setId(id); - - assertEquals("Button's id should be set", item.createButton(mParent).getId(), id); - } - - @Test - public void testCreateButtonTwice() { - TestButtonItem item = new TestButtonItem(); - final Button button = item.createButton(mParent); - - FrameLayout frameLayout = new FrameLayout(mContext); - frameLayout.addView(button); - - final Button button2 = item.createButton(mParent); - assertSame("createButton should be reused", button, button2); - assertNull("Should be removed from parent after createButton", button2.getParent()); + private ViewGroup parent; + private Context context; + + @Before + public void setUp() { + context = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); + parent = new LinearLayout(context); + } + + @Test + public void testDefaultItem() { + ButtonItem item = new ButtonItem(); + + assertThat(item.isEnabled()).named("enabled").isTrue(); + assertThat(item.getCount()).named("count").isEqualTo(0); + assertThat(item.getLayoutResource()).named("layout resource").isEqualTo(0); + assertThat(item.getTheme()).named("theme").isEqualTo(R.style.SuwButtonItem); + assertThat(item.getText()).named("text").isNull(); + } + + @Test + public void testOnBindView() { + ButtonItem item = new ButtonItem(); + + try { + item.onBindView(new View(context)); + fail("Calling onBindView on ButtonItem should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // pass } - - @Test - public void testSetEnabledTrue() { - TestButtonItem item = new TestButtonItem(); - item.setEnabled(true); - - final Button button = item.createButton(mParent); - assertTrue("ButtonItem should be enabled", item.isEnabled()); - assertTrue("Button should be enabled", button.isEnabled()); - } - - @Test - public void testSetEnabledFalse() { - TestButtonItem item = new TestButtonItem(); - item.setEnabled(false); - - final Button button = item.createButton(mParent); - assertFalse("ButtonItem should be disabled", item.isEnabled()); - assertFalse("Button should be disabled", button.isEnabled()); - } - - @Test - public void testSetText() { - TestButtonItem item = new TestButtonItem(); - item.setText("lorem ipsum"); - - final Button button = item.createButton(mParent); - assertEquals("ButtonItem text should be \"lorem ipsum\"", "lorem ipsum", item.getText()); - assertEquals("Button text should be \"lorem ipsum\"", "lorem ipsum", button.getText()); - } - - @Test - public void testSetTheme() { - TestButtonItem item = new TestButtonItem(); - item.setTheme(R.style.SuwButtonItem_Colored); - - final Button button = item.createButton(mParent); - assertEquals("ButtonItem theme should be SuwButtonItem.Colored", - R.style.SuwButtonItem_Colored, item.getTheme()); - assertNotNull(button.getContext().getTheme()); - } - - @Test - public void testOnClickListener() { - TestButtonItem item = new TestButtonItem(); - final OnClickListener listener = mock(OnClickListener.class); - item.setOnClickListener(listener); - - verify(listener, never()).onClick(any(ButtonItem.class)); - - final Button button = item.createButton(mParent); - button.performClick(); - - verify(listener).onClick(same(item)); - } - - private static class TestButtonItem extends ButtonItem { - - @Override - public Button createButton(ViewGroup parent) { - // Make this method public for testing - return super.createButton(parent); - } + } + + @Test + public void testCreateButton() { + TestButtonItem item = new TestButtonItem(); + final Button button = item.createButton(parent); + + assertThat(button.isEnabled()).named("enabled").isTrue(); + assertThat(button.getText().toString()).isEmpty(); + } + + @Test + public void testButtonItemSetsItsId() { + TestButtonItem item = new TestButtonItem(); + final int id = 12345; + item.setId(id); + + assertWithMessage("Button's id should be set") + .that(item.createButton(parent).getId()) + .isEqualTo(id); + } + + @Test + public void testCreateButtonTwice() { + TestButtonItem item = new TestButtonItem(); + final Button button = item.createButton(parent); + + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.addView(button); + + final Button button2 = item.createButton(parent); + assertWithMessage("createButton should be reused").that(button2).isSameAs(button); + assertWithMessage("Should be removed from parent after createButton") + .that(button2.getParent()) + .isNull(); + } + + @Test + public void testSetEnabledTrue() { + TestButtonItem item = new TestButtonItem(); + item.setEnabled(true); + + final Button button = item.createButton(parent); + assertWithMessage("ButtonItem should be enabled").that(item.isEnabled()).isTrue(); + assertWithMessage("Button should be enabled").that(button.isEnabled()).isTrue(); + } + + @Test + public void testSetEnabledFalse() { + TestButtonItem item = new TestButtonItem(); + item.setEnabled(false); + + final Button button = item.createButton(parent); + assertWithMessage("ButtonItem should be disabled").that(item.isEnabled()).isFalse(); + assertWithMessage("Button should be disabled").that(button.isEnabled()).isFalse(); + } + + @Test + public void testSetText() { + TestButtonItem item = new TestButtonItem(); + item.setText("lorem ipsum"); + + final Button button = item.createButton(parent); + assertWithMessage("ButtonItem text should be \"lorem ipsum\"") + .that(item.getText().toString()) + .isEqualTo("lorem ipsum"); + assertWithMessage("Button text should be \"lorem ipsum\"") + .that(button.getText().toString()) + .isEqualTo("lorem ipsum"); + } + + @Test + public void testSetTheme() { + TestButtonItem item = new TestButtonItem(); + item.setTheme(R.style.SuwButtonItem_Colored); + + final Button button = item.createButton(parent); + assertWithMessage("ButtonItem theme should be SuwButtonItem.Colored") + .that(item.getTheme()) + .isEqualTo(R.style.SuwButtonItem_Colored); + assertThat(button.getContext().getTheme()).isNotNull(); + } + + @Test + public void testOnClickListener() { + TestButtonItem item = new TestButtonItem(); + final OnClickListener listener = mock(OnClickListener.class); + item.setOnClickListener(listener); + + verify(listener, never()).onClick(any(ButtonItem.class)); + + final Button button = item.createButton(parent); + button.performClick(); + + verify(listener).onClick(same(item)); + } + + private static class TestButtonItem extends ButtonItem { + + @Override + public Button createButton(ViewGroup parent) { + // Make this method public for testing + return super.createButton(parent); } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java b/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java index ecaec71..3cbc576 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java @@ -16,289 +16,308 @@ package com.android.setupwizardlib.items; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class ItemGroupTest { - private static final Item CHILD_1 = new EqualsItem("Child 1"); - private static final Item CHILD_2 = new EqualsItem("Child 2"); - private static final Item CHILD_3 = new EqualsItem("Child 3"); - private static final Item CHILD_4 = new EqualsItem("Child 4"); - - private ItemGroup mItemGroup; - - @Mock - private ItemHierarchy.Observer mObserver; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mItemGroup = new ItemGroup(); - mItemGroup.registerObserver(mObserver); - } - - @Test - public void testGroup() { - mItemGroup.addChild(CHILD_1); - mItemGroup.addChild(CHILD_2); - - assertSame("Item at position 0 should be child1", CHILD_1, mItemGroup.getItemAt(0)); - assertSame("Item at position 1 should be child2", CHILD_2, mItemGroup.getItemAt(1)); - assertEquals("Should have 2 children", 2, mItemGroup.getCount()); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(mItemGroup), eq(0), eq(1)); - inOrder.verify(mObserver).onItemRangeInserted(eq(mItemGroup), eq(1), eq(1)); - } - - @Test - public void testRemoveChild() { - mItemGroup.addChild(CHILD_1); - mItemGroup.addChild(CHILD_2); - mItemGroup.addChild(CHILD_3); - - mItemGroup.removeChild(CHILD_2); - - assertSame("Item at position 0 should be child1", CHILD_1, mItemGroup.getItemAt(0)); - assertSame("Item at position 1 should be child3", CHILD_3, mItemGroup.getItemAt(1)); - assertEquals("Should have 2 children", 2, mItemGroup.getCount()); - - verify(mObserver).onItemRangeRemoved(eq(mItemGroup), eq(1), eq(1)); - } - - @Test - public void testClear() { - mItemGroup.addChild(CHILD_1); - mItemGroup.addChild(CHILD_2); - - mItemGroup.clear(); - - assertEquals("Should have 0 child", 0, mItemGroup.getCount()); - - verify(mObserver).onItemRangeRemoved(eq(mItemGroup), eq(0), eq(2)); - } - - @Test - public void testNestedGroup() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup = new ItemGroup(); - parentGroup.registerObserver(mObserver); - - parentGroup.addChild(CHILD_1); - childGroup.addChild(CHILD_2); - childGroup.addChild(CHILD_3); - parentGroup.addChild(childGroup); - parentGroup.addChild(CHILD_4); - - assertSame("Position 0 should be child 1", CHILD_1, parentGroup.getItemAt(0)); - assertSame("Position 1 should be child 2", CHILD_2, parentGroup.getItemAt(1)); - assertSame("Position 2 should be child 3", CHILD_3, parentGroup.getItemAt(2)); - assertSame("Position 3 should be child 4", CHILD_4, parentGroup.getItemAt(3)); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(3), eq(1)); - verifyNoMoreInteractions(mObserver); - } - - @Test - public void testNestedGroupClearNotification() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup = new ItemGroup(); - parentGroup.registerObserver(mObserver); - - parentGroup.addChild(CHILD_1); - childGroup.addChild(CHILD_2); - childGroup.addChild(CHILD_3); - parentGroup.addChild(childGroup); - parentGroup.addChild(CHILD_4); - - childGroup.clear(); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(3), eq(1)); - verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2)); - verifyNoMoreInteractions(mObserver); - } - - @Test - public void testNestedGroupRemoveNotification() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup = new ItemGroup(); - parentGroup.registerObserver(mObserver); - - parentGroup.addChild(CHILD_1); - childGroup.addChild(CHILD_2); - childGroup.addChild(CHILD_3); - parentGroup.addChild(childGroup); - parentGroup.addChild(CHILD_4); - - childGroup.removeChild(CHILD_3); - childGroup.removeChild(CHILD_2); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(3), eq(1)); - inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1)); - inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(1), eq(1)); - verifyNoMoreInteractions(mObserver); + private static final Item CHILD_1 = new EqualsItem("Child 1"); + private static final Item CHILD_2 = new EqualsItem("Child 2"); + private static final Item CHILD_3 = new EqualsItem("Child 3"); + private static final Item CHILD_4 = new EqualsItem("Child 4"); + + private ItemGroup itemGroup; + + @Mock private ItemHierarchy.Observer observer; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + itemGroup = new ItemGroup(); + itemGroup.registerObserver(observer); + } + + @Test + public void testGroup() { + itemGroup.addChild(CHILD_1); + itemGroup.addChild(CHILD_2); + + assertWithMessage("Item at position 0 should be child1") + .that(itemGroup.getItemAt(0)) + .isSameAs(CHILD_1); + assertWithMessage("Item at position 1 should be child2") + .that(itemGroup.getItemAt(1)) + .isSameAs(CHILD_2); + assertWithMessage("Should have 2 children").that(itemGroup.getCount()).isEqualTo(2); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(itemGroup), eq(0), eq(1)); + inOrder.verify(observer).onItemRangeInserted(eq(itemGroup), eq(1), eq(1)); + } + + @Test + public void testRemoveChild() { + itemGroup.addChild(CHILD_1); + itemGroup.addChild(CHILD_2); + itemGroup.addChild(CHILD_3); + + itemGroup.removeChild(CHILD_2); + + assertWithMessage("Item at position 0 should be child1") + .that(itemGroup.getItemAt(0)) + .isSameAs(CHILD_1); + assertWithMessage("Item at position 1 should be child3") + .that(itemGroup.getItemAt(1)) + .isSameAs(CHILD_3); + assertWithMessage("Should have 2 children").that(itemGroup.getCount()).isEqualTo(2); + + verify(observer).onItemRangeRemoved(eq(itemGroup), eq(1), eq(1)); + } + + @Test + public void testClear() { + itemGroup.addChild(CHILD_1); + itemGroup.addChild(CHILD_2); + + itemGroup.clear(); + + assertWithMessage("Should have 0 child").that(itemGroup.getCount()).isEqualTo(0); + + verify(observer).onItemRangeRemoved(eq(itemGroup), eq(0), eq(2)); + } + + @Test + public void testNestedGroup() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup = new ItemGroup(); + parentGroup.registerObserver(observer); + + parentGroup.addChild(CHILD_1); + childGroup.addChild(CHILD_2); + childGroup.addChild(CHILD_3); + parentGroup.addChild(childGroup); + parentGroup.addChild(CHILD_4); + + assertWithMessage("Position 0 should be child 1") + .that(parentGroup.getItemAt(0)) + .isSameAs(CHILD_1); + assertWithMessage("Position 1 should be child 2") + .that(parentGroup.getItemAt(1)) + .isSameAs(CHILD_2); + assertWithMessage("Position 2 should be child 3") + .that(parentGroup.getItemAt(2)) + .isSameAs(CHILD_3); + assertWithMessage("Position 3 should be child 4") + .that(parentGroup.getItemAt(3)) + .isSameAs(CHILD_4); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(3), eq(1)); + verifyNoMoreInteractions(observer); + } + + @Test + public void testNestedGroupClearNotification() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup = new ItemGroup(); + parentGroup.registerObserver(observer); + + parentGroup.addChild(CHILD_1); + childGroup.addChild(CHILD_2); + childGroup.addChild(CHILD_3); + parentGroup.addChild(childGroup); + parentGroup.addChild(CHILD_4); + + childGroup.clear(); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(3), eq(1)); + verify(observer).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2)); + verifyNoMoreInteractions(observer); + } + + @Test + public void testNestedGroupRemoveNotification() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup = new ItemGroup(); + parentGroup.registerObserver(observer); + + parentGroup.addChild(CHILD_1); + childGroup.addChild(CHILD_2); + childGroup.addChild(CHILD_3); + parentGroup.addChild(childGroup); + parentGroup.addChild(CHILD_4); + + childGroup.removeChild(CHILD_3); + childGroup.removeChild(CHILD_2); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(3), eq(1)); + inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1)); + inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(1), eq(1)); + verifyNoMoreInteractions(observer); + } + + @Test + public void testNestedGroupClear() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup = new ItemGroup(); + parentGroup.registerObserver(observer); + + parentGroup.addChild(CHILD_1); + childGroup.addChild(CHILD_2); + childGroup.addChild(CHILD_3); + parentGroup.addChild(childGroup); + + childGroup.clear(); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); + inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2)); + verifyNoMoreInteractions(observer); + } + + @Test + public void testNestedGroupRemoveLastChild() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup1 = new ItemGroup(); + ItemGroup childGroup2 = new ItemGroup(); + parentGroup.registerObserver(observer); + + childGroup1.addChild(CHILD_1); + childGroup1.addChild(CHILD_2); + parentGroup.addChild(childGroup1); + childGroup2.addChild(CHILD_3); + childGroup2.addChild(CHILD_4); + parentGroup.addChild(childGroup2); + + childGroup2.removeChild(CHILD_4); + childGroup2.removeChild(CHILD_3); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(2)); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(2), eq(2)); + inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(3), eq(1)); + inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1)); + verifyNoMoreInteractions(observer); + } + + @Test + public void testNestedGroupClearOnlyChild() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup = new ItemGroup(); + parentGroup.registerObserver(observer); + + childGroup.addChild(CHILD_1); + childGroup.addChild(CHILD_2); + parentGroup.addChild(childGroup); + + childGroup.clear(); + + final InOrder inOrder = inOrder(observer); + inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(2)); + inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(0), eq(2)); + verifyNoMoreInteractions(observer); + } + + @Test + public void testNotifyChange() { + itemGroup.addChild(CHILD_1); + itemGroup.addChild(CHILD_2); + + CHILD_2.setTitle("Child 2 modified"); + + verify(observer).onItemRangeChanged(eq(itemGroup), eq(1), eq(1)); + } + + @Test + public void testEmptyChildGroup() { + ItemGroup parentGroup = new ItemGroup(); + ItemGroup childGroup = new ItemGroup(); + + parentGroup.addChild(CHILD_1); + parentGroup.addChild(childGroup); + parentGroup.addChild(CHILD_2); + + assertWithMessage("Position 0 should be child 1") + .that(parentGroup.getItemAt(0)) + .isSameAs(CHILD_1); + assertWithMessage("Position 1 should be child 2") + .that(parentGroup.getItemAt(1)) + .isSameAs(CHILD_2); + } + + @Test + public void testFindItemById() { + CHILD_1.setId(12345); + CHILD_2.setId(23456); + + itemGroup.addChild(CHILD_1); + itemGroup.addChild(CHILD_2); + + assertWithMessage("Find item 23456 should return child 2") + .that(itemGroup.findItemById(23456)) + .isSameAs(CHILD_2); + } + + @Test + public void testFindItemByIdNotFound() { + CHILD_1.setId(12345); + CHILD_2.setId(23456); + + itemGroup.addChild(CHILD_1); + itemGroup.addChild(CHILD_2); + + assertWithMessage("ID not found should return null") + .that(itemGroup.findItemById(56789)) + .isNull(); + } + + /** + * This class will always return true on {@link #equals(Object)}. Used to ensure that ItemGroup is + * using identity rather than equals(). Be sure to use assertSame rather than assertEquals when + * comparing items of this class. + */ + private static class EqualsItem extends Item { + + EqualsItem(String name) { + setTitle(name); } - @Test - public void testNestedGroupClear() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup = new ItemGroup(); - parentGroup.registerObserver(mObserver); - - parentGroup.addChild(CHILD_1); - childGroup.addChild(CHILD_2); - childGroup.addChild(CHILD_3); - parentGroup.addChild(childGroup); - - childGroup.clear(); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2)); - inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2)); - verifyNoMoreInteractions(mObserver); - } - - @Test - public void testNestedGroupRemoveLastChild() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup1 = new ItemGroup(); - ItemGroup childGroup2 = new ItemGroup(); - parentGroup.registerObserver(mObserver); - - childGroup1.addChild(CHILD_1); - childGroup1.addChild(CHILD_2); - parentGroup.addChild(childGroup1); - childGroup2.addChild(CHILD_3); - childGroup2.addChild(CHILD_4); - parentGroup.addChild(childGroup2); - - childGroup2.removeChild(CHILD_4); - childGroup2.removeChild(CHILD_3); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(2)); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(2), eq(2)); - inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(3), eq(1)); - inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1)); - verifyNoMoreInteractions(mObserver); - } - - @Test - public void testNestedGroupClearOnlyChild() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup = new ItemGroup(); - parentGroup.registerObserver(mObserver); - - childGroup.addChild(CHILD_1); - childGroup.addChild(CHILD_2); - parentGroup.addChild(childGroup); - - childGroup.clear(); - - final InOrder inOrder = inOrder(mObserver); - inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(2)); - inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(0), eq(2)); - verifyNoMoreInteractions(mObserver); - } - - @Test - public void testNotifyChange() { - mItemGroup.addChild(CHILD_1); - mItemGroup.addChild(CHILD_2); - - CHILD_2.setTitle("Child 2 modified"); - - verify(mObserver).onItemRangeChanged(eq(mItemGroup), eq(1), eq(1)); - } - - @Test - public void testEmptyChildGroup() { - ItemGroup parentGroup = new ItemGroup(); - ItemGroup childGroup = new ItemGroup(); - - parentGroup.addChild(CHILD_1); - parentGroup.addChild(childGroup); - parentGroup.addChild(CHILD_2); - - assertSame("Position 0 should be child 1", CHILD_1, parentGroup.getItemAt(0)); - assertSame("Position 1 should be child 2", CHILD_2, parentGroup.getItemAt(1)); + @Override + public int hashCode() { + return 1; } - @Test - public void testFindItemById() { - CHILD_1.setId(12345); - CHILD_2.setId(23456); - - mItemGroup.addChild(CHILD_1); - mItemGroup.addChild(CHILD_2); - - assertSame("Find item 23456 should return child 2", - CHILD_2, mItemGroup.findItemById(23456)); - } - - @Test - public void testFindItemByIdNotFound() { - CHILD_1.setId(12345); - CHILD_2.setId(23456); - - mItemGroup.addChild(CHILD_1); - mItemGroup.addChild(CHILD_2); - - assertNull("ID not found should return null", mItemGroup.findItemById(56789)); + @Override + public boolean equals(Object obj) { + return obj instanceof Item; } - /** - * This class will always return true on {@link #equals(Object)}. Used to ensure that ItemGroup - * is using identity rather than equals(). Be sure to use assertSame rather than assertEquals - * when comparing items of this class. - */ - private static class EqualsItem extends Item { - - EqualsItem(String name) { - setTitle(name); - } - - @Override - public int hashCode() { - return 1; - } - - @Override - public boolean equals(Object obj) { - return obj instanceof Item; - } - - @Override - public String toString() { - return "EqualsItem{title=" + getTitle() + "}"; - } + @Override + public String toString() { + return "EqualsItem{title=" + getTitle() + "}"; } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java b/library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java new file mode 100644 index 0000000..06ef508 --- /dev/null +++ b/library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.setupwizardlib.robolectric; + +import static org.robolectric.RuntimeEnvironment.application; +import static org.robolectric.Shadows.shadowOf; + +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import androidx.annotation.AnyRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import android.util.DisplayMetrics; +import java.util.HashMap; +import java.util.Map; +import org.robolectric.res.ResName; +import org.robolectric.res.ResType; +import org.robolectric.res.TypedResource; +import org.robolectric.shadows.ShadowPackageManager; + +/** + * Utility class to inject resources for an "external" application in Robolectric tests. This can be + * used with {@link org.robolectric.shadows.ShadowPackageManager#resources} to simulate loading + * resources from another package. + */ +public final class ExternalResources { + + public static Resources injectExternalResources(String packageName) { + return injectExternalResources(createPackageInfo(packageName)); + } + + public static Resources injectExternalResources(PackageInfo packageInfo) { + try { + application.getPackageManager().getPackageInfo(packageInfo.packageName, 0); + } catch (NameNotFoundException e) { + // Add the package if it does not exist + shadowOf(application.getPackageManager()).addPackage(packageInfo); + } + Resources resources = Resources.forPackageName(packageInfo.packageName); + ShadowPackageManager.resources.put(packageInfo.packageName, resources); + return resources; + } + + /** + * Constructed resources for testing, representing resources external to the current package under + * test. + */ + public static class Resources extends android.content.res.Resources { + + private final String packageName; + + public static Resources forPackageName(String packageName) { + android.content.res.Resources res = application.getResources(); + return new Resources( + packageName, res.getAssets(), res.getDisplayMetrics(), res.getConfiguration()); + } + + private Resources( + String packageName, AssetManager assets, DisplayMetrics metrics, Configuration config) { + super(assets, metrics, config); + this.packageName = packageName; + } + + @Override + public int getIdentifier(String name, String defType, String defPackage) { + Integer resourceId = resourceIds.get(ResName.qualifyResName(name, defPackage, defType)); + if (resourceId == null) { + return 0; + } + return resourceId; + } + + @Override + public int getInteger(int id) { + return (int) get(id, ResType.INTEGER); + } + + public void putInteger(String name, int value) { + put( + ResName.qualifyResName(name, packageName, "integer"), + new TypedResource<>(value, ResType.INTEGER, null)); + } + + @Override + public int getColor(int id) { + return (int) get(id, ResType.COLOR); + } + + @Override + public int getColor(int id, @Nullable Theme theme) { + return (int) get(id, ResType.COLOR); + } + + public void putColor(String name, int value) { + put( + ResName.qualifyResName(name, packageName, "color"), + new TypedResource<>(value, ResType.COLOR, null)); + } + + @NonNull + @Override + public CharSequence getText(int id) { + return (CharSequence) get(id, ResType.CHAR_SEQUENCE); + } + + @NonNull + @Override + public String getString(int id) { + return get(id, ResType.CHAR_SEQUENCE).toString(); + } + + public void putText(String name, CharSequence value) { + put( + ResName.qualifyResName(name, packageName, "string"), + new TypedResource<>(value, ResType.CHAR_SEQUENCE, null)); + } + + private final Map<Integer, TypedResource<?>> overrideResources = new HashMap<>(); + private final Map<ResName, Integer> resourceIds = new HashMap<>(); + private int nextId = 1; + + private <T> void put(ResName resName, TypedResource<T> value) { + int id = nextId++; + overrideResources.put(id, value); + resourceIds.put(resName, id); + } + + private Object get(@AnyRes int id, ResType type) { + TypedResource<?> override = overrideResources.get(id); + if (override != null && override.getResType() == type) { + return override.getData(); + } + throw new NotFoundException(); + } + } + + private static PackageInfo createPackageInfo(String packageName) { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; + return packageInfo; + } + + private ExternalResources() {} +} diff --git a/library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java b/library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java deleted file mode 100644 index 61baa23..0000000 --- a/library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.setupwizardlib.robolectric; - -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; -import org.robolectric.RobolectricTestRunner; - -public class SuwLibRobolectricTestRunner extends RobolectricTestRunner { - - public SuwLibRobolectricTestRunner(Class<?> testClass) throws InitializationError { - super(testClass); - } - - @Override - protected void runChild(FrameworkMethod method, RunNotifier notifier) { - System.out.println("===== Running " + method + " ====="); - super.runChild(method, notifier); - } -} diff --git a/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java b/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java deleted file mode 100644 index f1d37c8..0000000 --- a/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.setupwizardlib.shadow; - -import android.util.Log; - -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -@Implements(Log.class) -public class ShadowLog extends org.robolectric.shadows.ShadowLog { - - public static boolean sWtfIsFatal = true; - - public static class TerribleFailure extends RuntimeException { - - public TerribleFailure(String msg, Throwable cause) { - super(msg, cause); - } - } - - @Implementation - public static void wtf(String tag, String msg) { - org.robolectric.shadows.ShadowLog.wtf(tag, msg); - if (sWtfIsFatal) { - throw new TerribleFailure(msg, null); - } - } - - @Implementation - public static void wtf(String tag, String msg, Throwable throwable) { - org.robolectric.shadows.ShadowLog.wtf(tag, msg, throwable); - if (sWtfIsFatal) { - throw new TerribleFailure(msg, throwable); - } - } -} diff --git a/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java b/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java index 3aafa7d..3bc9fd1 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java @@ -17,8 +17,7 @@ package com.android.setupwizardlib.span; import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertSame; +import static com.google.common.truth.Truth.assertWithMessage; import static org.robolectric.RuntimeEnvironment.application; import android.content.Context; @@ -27,82 +26,83 @@ import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.method.LinkMovementMethod; import android.widget.TextView; - -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; -@RunWith(SuwLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) public class LinkSpanTest { - @Test - public void onClick_shouldCallListenerOnContext() { - final TestContext context = new TestContext(application); - final TextView textView = new TextView(context); - final LinkSpan linkSpan = new LinkSpan("test_id"); - - linkSpan.onClick(textView); - - assertSame("Clicked LinkSpan should be passed to setup", linkSpan, context.clickedSpan); - } - - @Test - public void onClick_contextDoesNotImplementOnClickListener_shouldBeNoOp() { - final TextView textView = new TextView(application); - final LinkSpan linkSpan = new LinkSpan("test_id"); - - linkSpan.onClick(textView); - - // This would be no-op, because the context doesn't implement LinkSpan.OnClickListener. - // Just check that no uncaught exception here. + @Test + public void onClick_shouldCallListenerOnContext() { + final TestContext context = new TestContext(application); + final TextView textView = new TextView(context); + final LinkSpan linkSpan = new LinkSpan("test_id"); + + linkSpan.onClick(textView); + + assertWithMessage("Clicked LinkSpan should be passed to setup") + .that(context.clickedSpan) + .isSameAs(linkSpan); + } + + @Test + public void onClick_contextDoesNotImplementOnClickListener_shouldBeNoOp() { + final TextView textView = new TextView(application); + final LinkSpan linkSpan = new LinkSpan("test_id"); + + linkSpan.onClick(textView); + + // This would be no-op, because the context doesn't implement LinkSpan.OnClickListener. + // Just check that no uncaught exception here. + } + + @Test + public void onClick_contextWrapsOnClickListener_shouldCallWrappedListener() { + final TestContext context = new TestContext(application); + final Context wrapperContext = new ContextWrapper(context); + final TextView textView = new TextView(wrapperContext); + final LinkSpan linkSpan = new LinkSpan("test_id"); + + linkSpan.onClick(textView); + assertWithMessage("Clicked LinkSpan should be passed to setup") + .that(context.clickedSpan) + .isSameAs(linkSpan); + } + + @Test + public void onClick_shouldClearSelection() { + final TestContext context = new TestContext(application); + final TextView textView = new TextView(context); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + textView.setFocusable(true); + textView.setFocusableInTouchMode(true); + final LinkSpan linkSpan = new LinkSpan("test_id"); + + SpannableStringBuilder text = new SpannableStringBuilder("Lorem ipsum dolor sit"); + textView.setText(text); + text.setSpan(linkSpan, /* start= */ 0, /* end= */ 5, /* flags= */ 0); + // Simulate the touch effect set by TextView when touched. + Selection.setSelection(text, /* start= */ 0, /* stop= */ 5); + + linkSpan.onClick(textView); + + assertThat(Selection.getSelectionStart(textView.getText())).isEqualTo(0); + assertThat(Selection.getSelectionEnd(textView.getText())).isEqualTo(0); + } + + @SuppressWarnings("deprecation") + private static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener { + + public LinkSpan clickedSpan = null; + + TestContext(Context base) { + super(base); } - @Test - public void onClick_contextWrapsOnClickListener_shouldCallWrappedListener() { - final TestContext context = new TestContext(application); - final Context wrapperContext = new ContextWrapper(context); - final TextView textView = new TextView(wrapperContext); - final LinkSpan linkSpan = new LinkSpan("test_id"); - - - linkSpan.onClick(textView); - assertSame("Clicked LinkSpan should be passed to setup", linkSpan, context.clickedSpan); - } - - @Test - public void onClick_shouldClearSelection() { - final TestContext context = new TestContext(application); - final TextView textView = new TextView(context); - textView.setMovementMethod(LinkMovementMethod.getInstance()); - textView.setFocusable(true); - textView.setFocusableInTouchMode(true); - final LinkSpan linkSpan = new LinkSpan("test_id"); - - SpannableStringBuilder text = new SpannableStringBuilder("Lorem ipsum dolor sit"); - textView.setText(text); - text.setSpan(linkSpan, /* start= */ 0, /* end= */ 5, /* flags= */ 0); - // Simulate the touch effect set by TextView when touched. - Selection.setSelection(text, /* start= */ 0, /* end= */ 5); - - linkSpan.onClick(textView); - - assertThat(Selection.getSelectionStart(textView.getText())).isEqualTo(0); - assertThat(Selection.getSelectionEnd(textView.getText())).isEqualTo(0); - } - - @SuppressWarnings("deprecation") - private static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener { - - public LinkSpan clickedSpan = null; - - TestContext(Context base) { - super(base); - } - - @Override - public void onClick(LinkSpan span) { - clickedSpan = span; - } + @Override + public void onClick(LinkSpan span) { + clickedSpan = span; } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java b/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java index ec3622d..9b99a68 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java @@ -16,105 +16,93 @@ package com.android.setupwizardlib.template; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; import android.content.Context; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView.OnScrollListener; import android.widget.BaseAdapter; import android.widget.ListView; - -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) -@RunWith(SuwLibRobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) +@RunWith(RobolectricTestRunner.class) public class ListViewScrollHandlingDelegateTest { - @Mock - private RequireScrollMixin mRequireScrollMixin; + @Mock private RequireScrollMixin requireScrollMixin; - private ListView mListView; - private ListViewScrollHandlingDelegate mDelegate; - private ArgumentCaptor<OnScrollListener> mListenerCaptor; + private ListView listView; + private ListViewScrollHandlingDelegate delegate; - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); - mListView = spy(new TestListView(application)); - mDelegate = new ListViewScrollHandlingDelegate(mRequireScrollMixin, mListView); + listView = new TestListView(application); + delegate = new ListViewScrollHandlingDelegate(requireScrollMixin, listView); - mListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class); - doNothing().when(mListView).setOnScrollListener(mListenerCaptor.capture()); + listView.layout(0, 0, 50, 50); + } - mListView.layout(0, 0, 50, 50); - } + @Test + public void testRequireScroll() throws Throwable { + delegate.startListening(); - @Test - public void testRequireScroll() throws Throwable { - mDelegate.startListening(); + verify(requireScrollMixin).notifyScrollabilityChange(true); + } - verify(mRequireScrollMixin).notifyScrollabilityChange(true); - } + @Test + public void testScrolledToBottom() throws Throwable { + delegate.startListening(); - @Test - public void testScrolledToBottom() throws Throwable { - mDelegate.startListening(); + verify(requireScrollMixin).notifyScrollabilityChange(true); - verify(mRequireScrollMixin).notifyScrollabilityChange(true); + Shadows.shadowOf(listView).getOnScrollListener().onScroll(listView, 2, 20, 20); - doReturn(20).when(mListView).getLastVisiblePosition(); - mListenerCaptor.getValue().onScroll(mListView, 2, 20, 20); + verify(requireScrollMixin).notifyScrollabilityChange(false); + } - verify(mRequireScrollMixin).notifyScrollabilityChange(false); - } + @Test + public void testPageScrollDown() throws Throwable { + delegate.pageScrollDown(); + assertThat(Shadows.shadowOf(listView).getLastSmoothScrollByDistance()).isEqualTo(50); + } - @Test - public void testPageScrollDown() throws Throwable { - mDelegate.pageScrollDown(); - verify(mListView).smoothScrollBy(eq(50), anyInt()); - } + private static class TestListView extends ListView { + + TestListView(Context context) { + super(context); + setAdapter( + new BaseAdapter() { + @Override + public int getCount() { + return 20; + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return position; + } - private static class TestListView extends ListView { - - TestListView(Context context) { - super(context); - setAdapter(new BaseAdapter() { - @Override - public int getCount() { - return 20; - } - - @Override - public Object getItem(int position) { - return null; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - return new View(parent.getContext()); - } - }); - } + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return new View(parent.getContext()); + } + }); } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java b/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java index c641449..fe45d5f 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java @@ -16,13 +16,10 @@ package com.android.setupwizardlib.template; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -33,135 +30,138 @@ import android.annotation.SuppressLint; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; - +import com.android.setupwizardlib.GlifLayout; import com.android.setupwizardlib.TemplateLayout; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; import com.android.setupwizardlib.template.RequireScrollMixin.OnRequireScrollStateChangedListener; import com.android.setupwizardlib.template.RequireScrollMixin.ScrollHandlingDelegate; import com.android.setupwizardlib.view.NavigationBar; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) -@RunWith(SuwLibRobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) +@RunWith(RobolectricTestRunner.class) public class RequireScrollMixinTest { - @Mock - private TemplateLayout mTemplateLayout; - - @Mock - private ScrollHandlingDelegate mDelegate; - - private RequireScrollMixin mRequireScrollMixin; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - doReturn(application).when(mTemplateLayout).getContext(); - mRequireScrollMixin = new RequireScrollMixin(mTemplateLayout); - mRequireScrollMixin.setScrollHandlingDelegate(mDelegate); - } - - @Test - public void testRequireScroll() { - mRequireScrollMixin.requireScroll(); - - verify(mDelegate).startListening(); - } - - @Test - public void testScrollStateChangedListener() { - OnRequireScrollStateChangedListener listener = - mock(OnRequireScrollStateChangedListener.class); - mRequireScrollMixin.setOnRequireScrollStateChangedListener(listener); - assertFalse("Scrolling should not be required initially", - mRequireScrollMixin.isScrollingRequired()); - - mRequireScrollMixin.notifyScrollabilityChange(true); - verify(listener).onRequireScrollStateChanged(true); - assertTrue("Scrolling should be required when there is more content below the fold", - mRequireScrollMixin.isScrollingRequired()); - - mRequireScrollMixin.notifyScrollabilityChange(false); - verify(listener).onRequireScrollStateChanged(false); - assertFalse("Scrolling should not be required after scrolling to bottom", - mRequireScrollMixin.isScrollingRequired()); - - // Once the user has scrolled to the bottom, they should not be forced to scroll down again - mRequireScrollMixin.notifyScrollabilityChange(true); - verifyNoMoreInteractions(listener); - - assertFalse("Scrolling should not be required after scrolling to bottom once", - mRequireScrollMixin.isScrollingRequired()); - - assertSame(listener, mRequireScrollMixin.getOnRequireScrollStateChangedListener()); - } - - @Test - public void testCreateOnClickListener() { - OnClickListener wrappedListener = mock(OnClickListener.class); - final OnClickListener onClickListener = - mRequireScrollMixin.createOnClickListener(wrappedListener); - - mRequireScrollMixin.notifyScrollabilityChange(true); - onClickListener.onClick(null); - - verify(wrappedListener, never()).onClick(any(View.class)); - verify(mDelegate).pageScrollDown(); - - mRequireScrollMixin.notifyScrollabilityChange(false); - onClickListener.onClick(null); - - verify(wrappedListener).onClick(any(View.class)); - } - - @Test - public void testRequireScrollWithNavigationBar() { - final NavigationBar navigationBar = new NavigationBar(application); - mRequireScrollMixin.requireScrollWithNavigationBar(navigationBar); - - mRequireScrollMixin.notifyScrollabilityChange(true); - assertEquals("More button should be visible", - View.VISIBLE, navigationBar.getMoreButton().getVisibility()); - assertEquals("Next button should be hidden", - View.GONE, navigationBar.getNextButton().getVisibility()); - - navigationBar.getMoreButton().performClick(); - verify(mDelegate).pageScrollDown(); - - mRequireScrollMixin.notifyScrollabilityChange(false); - assertEquals("More button should be hidden", - View.GONE, navigationBar.getMoreButton().getVisibility()); - assertEquals("Next button should be visible", - View.VISIBLE, navigationBar.getNextButton().getVisibility()); - } - - @SuppressLint("SetTextI18n") // It's OK for testing - @Test - public void testRequireScrollWithButton() { - final Button button = new Button(application); - button.setText("OriginalLabel"); - OnClickListener wrappedListener = mock(OnClickListener.class); - mRequireScrollMixin.requireScrollWithButton( - button, "TestMoreLabel", wrappedListener); - - assertEquals("Button label should be kept initially", "OriginalLabel", button.getText()); - - mRequireScrollMixin.notifyScrollabilityChange(true); - assertEquals("TestMoreLabel", button.getText()); - button.performClick(); - verify(wrappedListener, never()).onClick(eq(button)); - verify(mDelegate).pageScrollDown(); - - mRequireScrollMixin.notifyScrollabilityChange(false); - assertEquals("OriginalLabel", button.getText()); - button.performClick(); - verify(wrappedListener).onClick(eq(button)); - } + @Mock private ScrollHandlingDelegate delegate; + + private RequireScrollMixin requireScrollMixin; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + TemplateLayout templateLayout = new GlifLayout(application); + requireScrollMixin = new RequireScrollMixin(templateLayout); + requireScrollMixin.setScrollHandlingDelegate(delegate); + } + + @Test + public void testRequireScroll() { + requireScrollMixin.requireScroll(); + + verify(delegate).startListening(); + } + + @Test + public void testScrollStateChangedListener() { + OnRequireScrollStateChangedListener listener = mock(OnRequireScrollStateChangedListener.class); + requireScrollMixin.setOnRequireScrollStateChangedListener(listener); + assertWithMessage("Scrolling should not be required initially") + .that(requireScrollMixin.isScrollingRequired()) + .isFalse(); + + requireScrollMixin.notifyScrollabilityChange(true); + verify(listener).onRequireScrollStateChanged(true); + assertWithMessage("Scrolling should be required when there is more content below the fold") + .that(requireScrollMixin.isScrollingRequired()) + .isTrue(); + + requireScrollMixin.notifyScrollabilityChange(false); + verify(listener).onRequireScrollStateChanged(false); + assertWithMessage("Scrolling should not be required after scrolling to bottom") + .that(requireScrollMixin.isScrollingRequired()) + .isFalse(); + + // Once the user has scrolled to the bottom, they should not be forced to scroll down again + requireScrollMixin.notifyScrollabilityChange(true); + verifyNoMoreInteractions(listener); + + assertWithMessage("Scrolling should not be required after scrolling to bottom once") + .that(requireScrollMixin.isScrollingRequired()) + .isFalse(); + + assertThat(requireScrollMixin.getOnRequireScrollStateChangedListener()).isSameAs(listener); + } + + @Test + public void testCreateOnClickListener() { + OnClickListener wrappedListener = mock(OnClickListener.class); + final OnClickListener onClickListener = + requireScrollMixin.createOnClickListener(wrappedListener); + + requireScrollMixin.notifyScrollabilityChange(true); + onClickListener.onClick(null); + + verify(wrappedListener, never()).onClick(any(View.class)); + verify(delegate).pageScrollDown(); + + requireScrollMixin.notifyScrollabilityChange(false); + onClickListener.onClick(null); + + verify(wrappedListener).onClick(any(View.class)); + } + + @Test + public void testRequireScrollWithNavigationBar() { + final NavigationBar navigationBar = new NavigationBar(application); + requireScrollMixin.requireScrollWithNavigationBar(navigationBar); + + requireScrollMixin.notifyScrollabilityChange(true); + assertWithMessage("More button should be visible") + .that(navigationBar.getMoreButton().getVisibility()) + .isEqualTo(View.VISIBLE); + assertWithMessage("Next button should be hidden") + .that(navigationBar.getNextButton().getVisibility()) + .isEqualTo(View.GONE); + + navigationBar.getMoreButton().performClick(); + verify(delegate).pageScrollDown(); + + requireScrollMixin.notifyScrollabilityChange(false); + assertWithMessage("More button should be hidden") + .that(navigationBar.getMoreButton().getVisibility()) + .isEqualTo(View.GONE); + assertWithMessage("Next button should be visible") + .that(navigationBar.getNextButton().getVisibility()) + .isEqualTo(View.VISIBLE); + } + + @SuppressLint("SetTextI18n") // It's OK for testing + @Test + public void testRequireScrollWithButton() { + final Button button = new Button(application); + button.setText("OriginalLabel"); + OnClickListener wrappedListener = mock(OnClickListener.class); + requireScrollMixin.requireScrollWithButton(button, "TestMoreLabel", wrappedListener); + + assertWithMessage("Button label should be kept initially") + .that(button.getText().toString()) + .isEqualTo("OriginalLabel"); + + requireScrollMixin.notifyScrollabilityChange(true); + assertThat(button.getText().toString()).isEqualTo("TestMoreLabel"); + button.performClick(); + verify(wrappedListener, never()).onClick(eq(button)); + verify(delegate).pageScrollDown(); + + requireScrollMixin.notifyScrollabilityChange(false); + assertThat(button.getText().toString()).isEqualTo("OriginalLabel"); + button.performClick(); + verify(wrappedListener).onClick(eq(button)); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java b/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java index 429445c..b07e2a3 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java @@ -16,72 +16,65 @@ package com.android.setupwizardlib.template; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.spy; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; +import android.view.View; import com.android.setupwizardlib.view.BottomScrollView; -import com.android.setupwizardlib.view.BottomScrollView.BottomScrollListener; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) -@RunWith(SuwLibRobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) +@RunWith(RobolectricTestRunner.class) public class ScrollViewScrollHandlingDelegateTest { - @Mock - private RequireScrollMixin mRequireScrollMixin; - - private BottomScrollView mScrollView; - private ScrollViewScrollHandlingDelegate mDelegate; - private ArgumentCaptor<BottomScrollListener> mListenerCaptor; + @Mock private RequireScrollMixin requireScrollMixin; - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); + private BottomScrollView scrollView; + private ScrollViewScrollHandlingDelegate delegate; - mScrollView = spy(new BottomScrollView(application)); - mDelegate = new ScrollViewScrollHandlingDelegate(mRequireScrollMixin, mScrollView); + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); - mListenerCaptor = ArgumentCaptor.forClass(BottomScrollListener.class); - doNothing().when(mScrollView).setBottomScrollListener(mListenerCaptor.capture()); + scrollView = new BottomScrollView(application); + View childView = new View(application); + scrollView.addView(childView); + delegate = new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView); - mScrollView.layout(0, 0, 50, 50); - } + scrollView.layout(0, 0, 500, 500); + childView.layout(0, 0, 1000, 1000); + } - @Test - public void testRequireScroll() throws Throwable { - mDelegate.startListening(); + @Test + public void testRequireScroll() throws Throwable { + delegate.startListening(); - mListenerCaptor.getValue().onRequiresScroll(); - verify(mRequireScrollMixin).notifyScrollabilityChange(true); - } + scrollView.getBottomScrollListener().onRequiresScroll(); + verify(requireScrollMixin).notifyScrollabilityChange(true); + } - @Test - public void testScrolledToBottom() throws Throwable { - mDelegate.startListening(); + @Test + public void testScrolledToBottom() throws Throwable { + delegate.startListening(); - mListenerCaptor.getValue().onRequiresScroll(); - verify(mRequireScrollMixin).notifyScrollabilityChange(true); + scrollView.getBottomScrollListener().onRequiresScroll(); + verify(requireScrollMixin).notifyScrollabilityChange(true); - mListenerCaptor.getValue().onScrolledToBottom(); + scrollView.getBottomScrollListener().onScrolledToBottom(); - verify(mRequireScrollMixin).notifyScrollabilityChange(false); - } + verify(requireScrollMixin).notifyScrollabilityChange(false); + } - @Test - public void testPageScrollDown() throws Throwable { - mDelegate.pageScrollDown(); - verify(mScrollView).smoothScrollBy(anyInt(), eq(50)); - } + @Test + public void testPageScrollDown() throws Throwable { + delegate.pageScrollDown(); + assertThat(scrollView.getScrollY()).isEqualTo(500); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java index c10c122..a0c688c 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java @@ -16,7 +16,7 @@ package com.android.setupwizardlib.util; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertWithMessage; import static org.robolectric.RuntimeEnvironment.application; import android.content.Context; @@ -25,90 +25,88 @@ import android.content.res.TypedArray; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.ContextThemeWrapper; - import com.android.setupwizardlib.R; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(sdk = Config.ALL_SDKS) public class GlifDimensionTest { - private Context mContext; - - @Before - public void setUp() { - mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); - } - - @Test - public void testDividerInsetPhone() { - assertDividerInset(); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testDividerInsetSw600dp() { - assertDividerInset(); - } - - private void assertDividerInset() { - final Resources res = mContext.getResources(); - - final TypedArray a = mContext.obtainStyledAttributes(new int[]{R.attr.suwMarginSides}); - final int marginSides = a.getDimensionPixelSize(0, 0); - a.recycle(); - - assertEquals( - "Dimensions should satisfy constraint: " - + "?attr/suwMarginSides = suw_items_glif_text_divider_inset", - marginSides, - res.getDimensionPixelSize(R.dimen.suw_items_glif_text_divider_inset)); - - assertEquals( - "Dimensions should satisfy constraint: ?attr/suwMarginSides + " - + "suw_items_icon_container_width = suw_items_glif_icon_divider_inset", - marginSides + res.getDimensionPixelSize(R.dimen.suw_items_icon_container_width), - res.getDimensionPixelSize(R.dimen.suw_items_glif_icon_divider_inset)); - } - - @Test - public void testButtonMargin() { - assertButtonMargin(); - } - - @Config(qualifiers = "sw600dp") - @Test - public void testButtonMarginSw600dp() { - assertButtonMargin(); - } - - private void assertButtonMargin() { - final Resources res = mContext.getResources(); - - final TypedArray a = mContext.obtainStyledAttributes(new int[]{R.attr.suwMarginSides}); - final int marginSides = a.getDimensionPixelSize(0, 0); - a.recycle(); - - assertEquals( - "Dimensions should satisfy constraint: ?attr/suwMarginSides - " - + "4dp (internal padding of button) = suw_glif_button_margin_end", - marginSides - dp2Px(4), - res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_end)); - - assertEquals( - "Dimensions should satisfy constraint: ?attr/suwMarginSides - " - + "suw_glif_button_padding = suw_glif_button_margin_start", - marginSides - res.getDimensionPixelSize(R.dimen.suw_glif_button_padding), - res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_start)); - } - - private int dp2Px(float dp) { - DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics); - } + private Context context; + + @Before + public void setUp() { + context = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); + } + + @Test + public void testDividerInsetPhone() { + assertDividerInset(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testDividerInsetSw600dp() { + assertDividerInset(); + } + + private void assertDividerInset() { + final Resources res = context.getResources(); + + final TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.suwMarginSides}); + final int marginSides = a.getDimensionPixelSize(0, 0); + a.recycle(); + + assertWithMessage( + "Dimensions should satisfy constraint: " + + "?attr/suwMarginSides = suw_items_glif_text_divider_inset") + .that(res.getDimensionPixelSize(R.dimen.suw_items_glif_text_divider_inset)) + .isEqualTo(marginSides); + + assertWithMessage( + "Dimensions should satisfy constraint: ?attr/suwMarginSides + " + + "suw_items_icon_container_width = suw_items_glif_icon_divider_inset") + .that(res.getDimensionPixelSize(R.dimen.suw_items_glif_icon_divider_inset)) + .isEqualTo(marginSides + res.getDimensionPixelSize(R.dimen.suw_items_icon_container_width)); + } + + @Test + public void testButtonMargin() { + assertButtonMargin(); + } + + @Config(qualifiers = "sw600dp") + @Test + public void testButtonMarginSw600dp() { + assertButtonMargin(); + } + + private void assertButtonMargin() { + final Resources res = context.getResources(); + + final TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.suwMarginSides}); + final int marginSides = a.getDimensionPixelSize(0, 0); + a.recycle(); + + assertWithMessage( + "Dimensions should satisfy constraint: ?attr/suwMarginSides - " + + "4dp (internal padding of button) = suw_glif_button_margin_end") + .that(res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_end)) + .isEqualTo(marginSides - dp2Px(4)); + + assertWithMessage( + "Dimensions should satisfy constraint: ?attr/suwMarginSides - " + + "suw_glif_button_padding = suw_glif_button_margin_start") + .that(res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_start)) + .isEqualTo(marginSides - res.getDimensionPixelSize(R.dimen.suw_glif_button_padding)); + } + + private int dp2Px(float dp) { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java index d8e318d..61b84bb 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java @@ -17,9 +17,6 @@ package com.android.setupwizardlib.util; import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.robolectric.RuntimeEnvironment.application; import android.annotation.TargetApi; @@ -28,71 +25,82 @@ import android.content.Context; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import androidx.annotation.Nullable; +import android.util.AttributeSet; import android.view.ContextThemeWrapper; +import android.view.View; import android.widget.Button; import android.widget.ProgressBar; - -import androidx.annotation.Nullable; - import com.android.setupwizardlib.R; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; +import org.robolectric.util.ReflectionHelpers.ClassParameter; -@RunWith(SuwLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class GlifStyleTest { - private Context mContext; - - @Before - public void setUp() { - mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light); + @Test + public void testSuwGlifButtonTertiary() { + Button button = + createButton( + new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light), + Robolectric.buildAttributeSet() + .setStyleAttribute("@style/SuwGlifButton.Tertiary") + .build()); + assertThat(button.getBackground()).named("background").isNotNull(); + assertThat(button.getTransformationMethod()).named("transformation method").isNull(); + if (VERSION.SDK_INT < VERSION_CODES.M) { + // Robolectric resolved the wrong theme attribute on versions >= M + // https://github.com/robolectric/robolectric/issues/2940 + assertThat(Integer.toHexString(button.getTextColors().getDefaultColor())) + .isEqualTo("ff4285f4"); } - - @Test - public void testSuwGlifButtonTertiary() { - Button button = new Button( - mContext, - Robolectric.buildAttributeSet() - .setStyleAttribute("@style/SuwGlifButton.Tertiary") - .build()); - assertThat(button.getBackground()).named("background").isNotNull(); - assertThat(button.getTransformationMethod()).named("transformation method").isNull(); - if (VERSION.SDK_INT < VERSION_CODES.M) { - // Robolectric resolved the wrong theme attribute on versions >= M - // https://github.com/robolectric/robolectric/issues/2940 - assertEquals("ff4285f4", Integer.toHexString(button.getTextColors().getDefaultColor())); - } + } + + @TargetApi(VERSION_CODES.LOLLIPOP) + @Config(sdk = Config.NEWEST_SDK) + @Test + public void glifThemeLight_statusBarColorShouldBeTransparent() { + GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); + assertThat(activity.getWindow().getStatusBarColor()).isEqualTo(0x00000000); + } + + @Test + public void glifLoadingScreen_shouldHaveProgressBar() { + GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); + activity.setContentView(R.layout.suw_glif_loading_screen); + + assertThat((View) activity.findViewById(R.id.suw_large_progress_bar)) + .isInstanceOf(ProgressBar.class); + } + + private Button createButton(Context context, AttributeSet attrs) { + Class<? extends Button> buttonClass; + try { + // Use AppCompatButton in builds that have them (i.e. gingerbreadCompat) + // noinspection unchecked + buttonClass = + (Class<? extends Button>) Class.forName("androidx.appcompat.widget.AppCompatButton"); + } catch (ClassNotFoundException e) { + buttonClass = Button.class; } - - @TargetApi(VERSION_CODES.LOLLIPOP) - @Config(sdk = Config.NEWEST_SDK) - @Test - public void glifThemeLight_statusBarColorShouldBeTransparent() { - GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); - assertEquals(0x00000000, activity.getWindow().getStatusBarColor()); - } - - @Test - public void glifLoadingScreen_shouldHaveProgressBar() { - GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); - activity.setContentView(R.layout.suw_glif_loading_screen); - - assertTrue("Progress bar should exist", - activity.findViewById(R.id.suw_large_progress_bar) instanceof ProgressBar); - } - - private static class GlifThemeActivity extends Activity { - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - setTheme(R.style.SuwThemeGlif_Light); - super.onCreate(savedInstanceState); - } + return ReflectionHelpers.callConstructor( + buttonClass, + ClassParameter.from(Context.class, context), + ClassParameter.from(AttributeSet.class, attrs)); + } + + private static class GlifThemeActivity extends Activity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + setTheme(R.style.SuwThemeGlif_Light); + super.onCreate(savedInstanceState); } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java index 44b8886..13e29f6 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java @@ -18,68 +18,59 @@ package com.android.setupwizardlib.util; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import android.app.Activity; import android.graphics.Color; import android.graphics.Typeface; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import androidx.annotation.Nullable; import android.view.View; import android.widget.Button; - -import androidx.annotation.Nullable; - import com.android.setupwizardlib.R; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(minSdk = Config.OLDEST_SDK, maxSdk = Config.NEWEST_SDK) public class GlifV3StyleTest { - @Test - public void activityWithGlifV3Theme_shouldUseLightNavBarOnV27OrAbove() { - GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); - if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) { - assertEquals( - activity.getWindow().getNavigationBarColor(), - Color.WHITE); - int vis = activity.getWindow().getDecorView().getSystemUiVisibility(); - assertTrue((vis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0); - } else if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - assertEquals( - activity.getWindow().getNavigationBarColor(), - Color.BLACK); - } - // Nav bar color is not customizable pre-L + @Test + public void activityWithGlifV3Theme_shouldUseLightNavBarOnV27OrAbove() { + GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); + if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) { + assertThat(activity.getWindow().getNavigationBarColor()).isEqualTo(Color.WHITE); + int vis = activity.getWindow().getDecorView().getSystemUiVisibility(); + assertThat((vis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0).isTrue(); + } else if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + assertThat(activity.getWindow().getNavigationBarColor()).isEqualTo(Color.BLACK); } + // Nav bar color is not customizable pre-L + } - @Test - public void buttonWithGlifV3_shouldBeGoogleSans() { - GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); - Button button = new Button( - activity, - Robolectric.buildAttributeSet() - .setStyleAttribute("@style/SuwGlifButton.Primary") - .build()); - assertThat(button.getTypeface()).isEqualTo(Typeface.create("google-sans", 0)); - // Button should not be all caps - assertThat(button.getTransformationMethod()).isNull(); - } + @Test + public void buttonWithGlifV3_shouldBeGoogleSans() { + GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class); + Button button = + new Button( + activity, + Robolectric.buildAttributeSet() + .setStyleAttribute("@style/SuwGlifButton.Primary") + .build()); + assertThat(button.getTypeface()).isEqualTo(Typeface.create("google-sans", 0)); + // Button should not be all caps + assertThat(button.getTransformationMethod()).isNull(); + } - private static class GlifThemeActivity extends Activity { + private static class GlifThemeActivity extends Activity { - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - setTheme(R.style.SuwThemeGlifV3_Light); - super.onCreate(savedInstanceState); - } + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + setTheme(R.style.SuwThemeGlifV3_Light); + super.onCreate(savedInstanceState); } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java index 2285cd5..f301e43 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java @@ -17,211 +17,164 @@ package com.android.setupwizardlib.util; import static com.google.common.truth.Truth.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.assertTrue; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; import static org.robolectric.RuntimeEnvironment.application; +import static org.robolectric.Shadows.shadowOf; -import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; - import com.android.setupwizardlib.R; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; +import com.android.setupwizardlib.robolectric.ExternalResources; +import com.android.setupwizardlib.robolectric.ExternalResources.Resources; import com.android.setupwizardlib.util.Partner.ResourceEntry; -import com.android.setupwizardlib.util.PartnerTest.ShadowApplicationPackageManager; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Shadows; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowResources; -import java.util.Arrays; -import java.util.Collections; - -@RunWith(SuwLibRobolectricTestRunner.class) -@Config( - sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }, - shadows = ShadowApplicationPackageManager.class) +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class PartnerTest { - private static final String ACTION_PARTNER_CUSTOMIZATION = - "com.android.setupwizard.action.PARTNER_CUSTOMIZATION"; - - private Context mContext; - private Resources mPartnerResources; - - private ShadowApplicationPackageManager mPackageManager; - - @Before - public void setUp() throws Exception { - Partner.resetForTesting(); - - mContext = spy(application); - mPartnerResources = spy(ShadowResources.getSystem()); - - mPackageManager = - (ShadowApplicationPackageManager) Shadows.shadowOf(application.getPackageManager()); - mPackageManager.partnerResources = mPartnerResources; - } - - @Test - public void testLoadPartner() { - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Arrays.asList( - createResolveInfo("foo.bar", false, true), - createResolveInfo("test.partner.package", true, true)) - ); - - Partner partner = Partner.get(mContext); - assertNotNull("Partner should not be null", partner); - } - - @Test - public void testLoadNoPartner() { - Partner partner = Partner.get(mContext); - assertNull("Partner should be null", partner); - } - - @Test - public void testLoadNonSystemPartner() { - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Arrays.asList( - createResolveInfo("foo.bar", false, true), - createResolveInfo("test.partner.package", false, true)) - ); - - Partner partner = Partner.get(mContext); - assertNull("Partner should be null", partner); - } - - @Test - public void testLoadPartnerValue() { - doReturn(0x7f010000).when(mPartnerResources) - .getIdentifier(eq("suwTransitionDuration"), eq("integer"), anyString()); - doReturn(5000).when(mPartnerResources).getInteger(eq(0x7f010000)); - - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Arrays.asList( - createResolveInfo("foo.bar", false, true), - createResolveInfo("test.partner.package", true, true)) - ); - - ResourceEntry entry = Partner.getResourceEntry(mContext, R.integer.suwTransitionDuration); - int partnerValue = entry.resources.getInteger(entry.id); - assertEquals("Partner value should be overlaid to 5000", 5000, partnerValue); - assertTrue("Partner value should come from overlay", entry.isOverlay); - } - - @Test - public void getColor_shouldReturnPartnerValueIfPresent() { - final int expectedPartnerColor = 1111; - doReturn(12345).when(mPartnerResources) - .getIdentifier(eq("suw_color_accent_dark"), eq("color"), anyString()); - doReturn(expectedPartnerColor).when(mPartnerResources).getColor(eq(12345)); - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Arrays.asList(createResolveInfo("test.partner.package", true, true))); - final int foundColor = Partner.getColor(mContext, R.color.suw_color_accent_dark); - assertEquals("Partner color should be overlayed to: " + expectedPartnerColor, - expectedPartnerColor, foundColor); - } - - @Test - public void getText_shouldReturnPartnerValueIfPresent() { - final CharSequence expectedPartnerText = "partner"; - doReturn(12345).when(mPartnerResources) - .getIdentifier(eq("suw_next_button_label"), eq("string"), anyString()); - doReturn(expectedPartnerText).when(mPartnerResources).getText(eq(12345)); - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Collections.singletonList(createResolveInfo("test.partner.package", true, true))); - final CharSequence partnerText = Partner.getText(mContext, R.string.suw_next_button_label); - assertThat(partnerText).isEqualTo(expectedPartnerText); + private static final String ACTION_PARTNER_CUSTOMIZATION = + "com.android.setupwizard.action.PARTNER_CUSTOMIZATION"; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + Partner.resetForTesting(); + } + + @Test + public void get_withPartnerPackage_shouldReturnNonNull() { + new PartnerPackageBuilder("foo.bar") + .setIsSystem(false) + .setDirectBootAware(true) + .injectResources(); + new PartnerPackageBuilder("test.partner.package").setDirectBootAware(true).injectResources(); + + Partner partner = Partner.get(application); + assertThat(partner).isNotNull(); + assertThat(partner.getPackageName()).isEqualTo("test.partner.package"); + } + + @Test + public void get_noPartnerPackage_shouldReturnNull() { + Partner partner = Partner.get(application); + assertThat(partner).isNull(); + } + + @Test + public void get_nonSystemPartnerPackage_shouldIgnoreAndReturnNull() { + new PartnerPackageBuilder("foo.bar") + .setIsSystem(false) + .setDirectBootAware(true) + .injectResources(); + new PartnerPackageBuilder("test.partner.package") + .setIsSystem(false) + .setDirectBootAware(true) + .injectResources(); + + Partner partner = Partner.get(application); + assertThat(partner).isNull(); + } + + @Test + public void getResourceEntry_hasOverlay_shouldReturnOverlayValue() { + new PartnerPackageBuilder("test.partner.package") + .injectResources() + .putInteger("suwTransitionDuration", 5000); + + ResourceEntry entry = Partner.getResourceEntry(application, R.integer.suwTransitionDuration); + int partnerValue = entry.resources.getInteger(entry.id); + assertThat(partnerValue).named("partner value").isEqualTo(5000); + assertThat(entry.isOverlay).isTrue(); + } + + @Test + public void getColor_partnerValuePresent_shouldReturnPartnerValue() { + new PartnerPackageBuilder("test.partner.package") + .injectResources() + .putColor("suw_color_accent_dark", 0xffff00ff); + + final int color = Partner.getColor(application, R.color.suw_color_accent_dark); + assertThat(color).isEqualTo(0xffff00ff); + } + + @Test + public void getText_partnerValuePresent_shouldReturnPartnerValue() { + new PartnerPackageBuilder("test.partner.package") + .injectResources() + .putText("suw_next_button_label", "partner"); + + final CharSequence partnerText = Partner.getText(application, R.string.suw_next_button_label); + assertThat(partnerText.toString()).isEqualTo("partner"); + } + + @Test + public void getResourceEntry_partnerValueNotPresent_shouldReturnDefault() { + new PartnerPackageBuilder("test.partner.package").injectResources(); + + ResourceEntry entry = Partner.getResourceEntry(application, R.color.suw_color_accent_dark); + int partnerValue = entry.resources.getColor(entry.id); + assertThat(partnerValue).isEqualTo(0xff448aff); + assertThat(entry.isOverlay).isFalse(); + } + + @Test + public void getResourceEntry_directBootUnawareNoValueDefined_shouldReturnDefaultValue() { + new PartnerPackageBuilder("test.partner.package").injectResources(); + + ResourceEntry entry = Partner.getResourceEntry(application, R.color.suw_color_accent_dark); + int partnerValue = entry.resources.getColor(entry.id); + assertThat(partnerValue).isEqualTo(0xff448aff); + assertThat(entry.isOverlay).isFalse(); + } + + private static class PartnerPackageBuilder { + private final String packageName; + private final ResolveInfo resolveInfo; + + PartnerPackageBuilder(String packageName) { + this.packageName = packageName; + + resolveInfo = new ResolveInfo(); + resolveInfo.resolvePackageName = packageName; + ActivityInfo activityInfo = new ActivityInfo(); + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.flags = ApplicationInfo.FLAG_SYSTEM; + appInfo.packageName = packageName; + activityInfo.applicationInfo = appInfo; + activityInfo.packageName = packageName; + activityInfo.name = packageName; + resolveInfo.activityInfo = activityInfo; } - @Test - public void testLoadDefaultValue() { - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Arrays.asList( - createResolveInfo("foo.bar", false, true), - createResolveInfo("test.partner.package", true, true)) - ); - - ResourceEntry entry = Partner.getResourceEntry(mContext, R.color.suw_color_accent_dark); - int partnerValue = entry.resources.getColor(entry.id); - assertEquals("Partner value should default to 0xff448aff", 0xff448aff, partnerValue); - assertFalse("Partner value should come from fallback", entry.isOverlay); - } - - @Test - public void testNotDirectBootAware() { - mPackageManager.addResolveInfoForIntent( - new Intent(ACTION_PARTNER_CUSTOMIZATION), - Collections.singletonList(createResolveInfo("test.partner.package", true, false))); - - ResourceEntry entry = Partner.getResourceEntry(mContext, R.color.suw_color_accent_dark); - int partnerValue = entry.resources.getColor(entry.id); - assertEquals("Partner value should default to 0xff448aff", 0xff448aff, partnerValue); - assertFalse("Partner value should come from fallback", entry.isOverlay); + PartnerPackageBuilder setIsSystem(boolean isSystem) { + if (isSystem) { + resolveInfo.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + } else { + resolveInfo.activityInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; + } + return this; } - private ResolveInfo createResolveInfo( - String packageName, - boolean isSystem, - boolean directBootAware) { - ResolveInfo info = new ResolveInfo(); - info.resolvePackageName = packageName; - ActivityInfo activityInfo = new ActivityInfo(); - ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.flags = isSystem ? ApplicationInfo.FLAG_SYSTEM : 0; - appInfo.packageName = packageName; - activityInfo.applicationInfo = appInfo; - activityInfo.packageName = packageName; - activityInfo.name = packageName; - if (VERSION.SDK_INT >= VERSION_CODES.N) { - activityInfo.directBootAware = directBootAware; - } - info.activityInfo = activityInfo; - return info; + PartnerPackageBuilder setDirectBootAware(boolean directBootAware) { + if (VERSION.SDK_INT >= VERSION_CODES.N) { + resolveInfo.activityInfo.directBootAware = directBootAware; + } + return this; } - @Implements(className = "android.app.ApplicationPackageManager") - public static class ShadowApplicationPackageManager extends - org.robolectric.shadows.ShadowApplicationPackageManager { - - public Resources partnerResources; - - @Implementation - @Override - public Resources getResourcesForApplication(ApplicationInfo app) - throws NameNotFoundException { - if (app != null && "test.partner.package".equals(app.packageName)) { - return partnerResources; - } else { - return super.getResourcesForApplication(app); - } - } + Resources injectResources() { + shadowOf(application.getPackageManager()) + .addResolveInfoForIntent(new Intent(ACTION_PARTNER_CUSTOMIZATION), resolveInfo); + return ExternalResources.injectExternalResources(packageName); } + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java new file mode 100644 index 0000000..6489961 --- /dev/null +++ b/library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.setupwizardlib.util; + +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Activity; +import android.content.Intent; +import androidx.annotation.StyleRes; +import com.android.setupwizardlib.R; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = Config.NEWEST_SDK) +public class ThemeResolverTest { + + @After + public void resetDefaultThemeResolver() { + ThemeResolver.setDefault(null); + } + + @Test + public void resolve_nonDayNight_shouldReturnCorrespondingTheme() { + @StyleRes int defaultTheme = 12345; + ThemeResolver themeResolver = + new ThemeResolver.Builder().setDefaultTheme(defaultTheme).setUseDayNight(false).build(); + assertThat(themeResolver.resolve("material")).isEqualTo(R.style.SuwThemeMaterial); + assertThat(themeResolver.resolve("material_light")).isEqualTo(R.style.SuwThemeMaterial_Light); + assertThat(themeResolver.resolve("glif")).isEqualTo(R.style.SuwThemeGlif); + assertThat(themeResolver.resolve("glif_light")).isEqualTo(R.style.SuwThemeGlif_Light); + assertThat(themeResolver.resolve("glif_v2")).isEqualTo(R.style.SuwThemeGlifV2); + assertThat(themeResolver.resolve("glif_v2_light")).isEqualTo(R.style.SuwThemeGlifV2_Light); + assertThat(themeResolver.resolve("glif_v3")).isEqualTo(R.style.SuwThemeGlifV3); + assertThat(themeResolver.resolve("glif_v3_light")).isEqualTo(R.style.SuwThemeGlifV3_Light); + assertThat(themeResolver.resolve("unknown_theme")).isEqualTo(defaultTheme); + } + + @Test + public void resolve_dayNight_shouldReturnDayNightTheme() { + @StyleRes int defaultTheme = 12345; + ThemeResolver themeResolver = new ThemeResolver.Builder().setDefaultTheme(defaultTheme).build(); + assertThat(themeResolver.resolve("material")).isEqualTo(R.style.SuwThemeMaterial_DayNight); + assertThat(themeResolver.resolve("material_light")) + .isEqualTo(R.style.SuwThemeMaterial_DayNight); + assertThat(themeResolver.resolve("glif")).isEqualTo(R.style.SuwThemeGlif_DayNight); + assertThat(themeResolver.resolve("glif_light")).isEqualTo(R.style.SuwThemeGlif_DayNight); + assertThat(themeResolver.resolve("glif_v2")).isEqualTo(R.style.SuwThemeGlifV2_DayNight); + assertThat(themeResolver.resolve("glif_v2_light")).isEqualTo(R.style.SuwThemeGlifV2_DayNight); + assertThat(themeResolver.resolve("glif_v3")).isEqualTo(R.style.SuwThemeGlifV3_DayNight); + assertThat(themeResolver.resolve("glif_v3_light")).isEqualTo(R.style.SuwThemeGlifV3_DayNight); + assertThat(themeResolver.resolve("unknown_theme")).isEqualTo(defaultTheme); + } + + @Test + public void resolve_newerThanOldestSupportedTheme_shouldReturnSpecifiedTheme() { + ThemeResolver themeResolver = + new ThemeResolver.Builder() + .setOldestSupportedTheme(WizardManagerHelper.THEME_GLIF_V2) + .build(); + assertThat(themeResolver.resolve("glif_v2")).isEqualTo(R.style.SuwThemeGlifV2_DayNight); + assertThat(themeResolver.resolve("glif_v2_light")).isEqualTo(R.style.SuwThemeGlifV2_DayNight); + assertThat(themeResolver.resolve("glif_v3")).isEqualTo(R.style.SuwThemeGlifV3_DayNight); + assertThat(themeResolver.resolve("glif_v3_light")).isEqualTo(R.style.SuwThemeGlifV3_DayNight); + } + + @Test + public void resolve_olderThanOldestSupportedTheme_shouldReturnDefault() { + @StyleRes int defaultTheme = 12345; + ThemeResolver themeResolver = + new ThemeResolver.Builder() + .setDefaultTheme(defaultTheme) + .setOldestSupportedTheme(WizardManagerHelper.THEME_GLIF_V2) + .build(); + assertThat(themeResolver.resolve("material")).isEqualTo(defaultTheme); + assertThat(themeResolver.resolve("material_light")).isEqualTo(defaultTheme); + assertThat(themeResolver.resolve("glif")).isEqualTo(defaultTheme); + assertThat(themeResolver.resolve("glif_light")).isEqualTo(defaultTheme); + } + + @Test + public void resolve_intentTheme_shouldReturnCorrespondingTheme() { + @StyleRes int defaultTheme = 12345; + ThemeResolver themeResolver = + new ThemeResolver.Builder().setDefaultTheme(defaultTheme).setUseDayNight(false).build(); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "material"))) + .isEqualTo(R.style.SuwThemeMaterial); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "material_light"))) + .isEqualTo(R.style.SuwThemeMaterial_Light); + assertThat( + themeResolver.resolve(new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif"))) + .isEqualTo(R.style.SuwThemeGlif); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_light"))) + .isEqualTo(R.style.SuwThemeGlif_Light); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2"))) + .isEqualTo(R.style.SuwThemeGlifV2); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2_light"))) + .isEqualTo(R.style.SuwThemeGlifV2_Light); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3"))) + .isEqualTo(R.style.SuwThemeGlifV3); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3_light"))) + .isEqualTo(R.style.SuwThemeGlifV3_Light); + assertThat( + themeResolver.resolve( + new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "unknown_theme"))) + .isEqualTo(defaultTheme); + } + + @Test + public void resolve_suwIntent_shouldForceNonDayNightTheme() { + @StyleRes int defaultTheme = 12345; + ThemeResolver themeResolver = + new ThemeResolver.Builder().setDefaultTheme(defaultTheme).setUseDayNight(true).build(); + Intent originalIntent = new Intent().putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true); + assertThat( + themeResolver.resolve( + new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "material"))) + .isEqualTo(R.style.SuwThemeMaterial); + assertThat( + themeResolver.resolve( + new Intent(originalIntent) + .putExtra(WizardManagerHelper.EXTRA_THEME, "material_light"))) + .isEqualTo(R.style.SuwThemeMaterial_Light); + assertThat( + themeResolver.resolve( + new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif"))) + .isEqualTo(R.style.SuwThemeGlif); + assertThat( + themeResolver.resolve( + new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif_light"))) + .isEqualTo(R.style.SuwThemeGlif_Light); + assertThat( + themeResolver.resolve( + new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2"))) + .isEqualTo(R.style.SuwThemeGlifV2); + assertThat( + themeResolver.resolve( + new Intent(originalIntent) + .putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2_light"))) + .isEqualTo(R.style.SuwThemeGlifV2_Light); + assertThat( + themeResolver.resolve( + new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3"))) + .isEqualTo(R.style.SuwThemeGlifV3); + assertThat( + themeResolver.resolve( + new Intent(originalIntent) + .putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3_light"))) + .isEqualTo(R.style.SuwThemeGlifV3_Light); + assertThat( + themeResolver.resolve( + new Intent(originalIntent) + .putExtra(WizardManagerHelper.EXTRA_THEME, "unknown_theme"))) + .isEqualTo(defaultTheme); + } + + @Test + public void applyTheme_glifV3_shouldSetActivityThemeToGlifV3() { + @StyleRes int defaultTheme = 12345; + ThemeResolver themeResolver = + new ThemeResolver.Builder().setUseDayNight(false).setDefaultTheme(defaultTheme).build(); + + Activity activity = + Robolectric.buildActivity( + Activity.class, + new Intent() + .putExtra(WizardManagerHelper.EXTRA_THEME, WizardManagerHelper.THEME_GLIF_V3)) + .setup() + .get(); + + themeResolver.applyTheme(activity); + + assertThat(shadowOf(activity).callGetThemeResId()).isEqualTo(R.style.SuwThemeGlifV3); + } + + @Test + public void setDefault_shouldSetDefaultResolver() { + ThemeResolver themeResolver = new ThemeResolver.Builder().setUseDayNight(false).build(); + + ThemeResolver.setDefault(themeResolver); + assertThat(ThemeResolver.getDefault()).isSameAs(themeResolver); + } +} diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java index 616ccdd..e302cab 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java @@ -16,10 +16,10 @@ package com.android.setupwizardlib.util; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.robolectric.RuntimeEnvironment.application; +import static org.robolectric.Shadows.shadowOf; import android.annotation.TargetApi; import android.app.Activity; @@ -29,299 +29,343 @@ import android.os.Bundle; import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Settings.Secure; - import androidx.annotation.StyleRes; - import com.android.setupwizardlib.R; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(sdk = Config.NEWEST_SDK) public class WizardManagerHelperTest { - @Test - public void testGetNextIntent() { - final Intent intent = new Intent("test.intent.ACTION"); - intent.putExtra("scriptUri", "android-resource://test-script"); - intent.putExtra("actionId", "test_action_id"); - intent.putExtra("theme", "test_theme"); - intent.putExtra("ignoreExtra", "poof"); // extra is ignored because it's not known - - final Intent data = new Intent(); - data.putExtra("extraData", "shazam"); - - final Intent nextIntent = - WizardManagerHelper.getNextIntent(intent, Activity.RESULT_OK, data); - assertEquals("Next intent action should be NEXT", "com.android.wizard.NEXT", - nextIntent.getAction()); - assertEquals("Script URI should be the same as original intent", - "android-resource://test-script", nextIntent.getStringExtra("scriptUri")); - assertEquals("Action ID should be the same as original intent", "test_action_id", - nextIntent.getStringExtra("actionId")); - assertEquals("Theme extra should be the same as original intent", "test_theme", - nextIntent.getStringExtra("theme")); - assertFalse("ignoreExtra should not be in nextIntent", nextIntent.hasExtra("ignoreExtra")); - assertEquals("Result code extra should be RESULT_OK", Activity.RESULT_OK, - nextIntent.getIntExtra("com.android.setupwizard.ResultCode", 0)); - assertEquals("Extra data should surface as extra in nextIntent", "shazam", - nextIntent.getStringExtra("extraData")); - } - - @Test - public void testIsSetupWizardTrue() { - final Intent intent = new Intent(); - intent.putExtra("firstRun", true); - assertTrue("Is setup wizard should be true", - WizardManagerHelper.isSetupWizardIntent(intent)); - } - - @Test - public void testIsDeferredSetupTrue() { - final Intent intent = new Intent(); - intent.putExtra("deferredSetup", true); - assertTrue("Is deferred setup wizard should be true", - WizardManagerHelper.isDeferredSetupWizard(intent)); - } - - @Test - public void testIsPreDeferredSetupTrue() { - final Intent intent = new Intent(); - intent.putExtra("preDeferredSetup", true); - assertTrue("Is pre-deferred setup wizard should be true", - WizardManagerHelper.isPreDeferredSetupWizard(intent)); - } - - @Test - public void testIsSetupWizardFalse() { - final Intent intent = new Intent(); - intent.putExtra("firstRun", false); - assertFalse("Is setup wizard should be true", - WizardManagerHelper.isSetupWizardIntent(intent)); - } - - @Test - public void isLightTheme_shouldReturnTrue_whenThemeIsLight() { - List<String> lightThemes = Arrays.asList( - "holo_light", - "material_light", - "glif_light", - "glif_v2_light", - "glif_v3_light" - ); - ArrayList<String> unexpectedIntentThemes = new ArrayList<>(); - ArrayList<String> unexpectedStringThemes = new ArrayList<>(); - for (final String theme : lightThemes) { - Intent intent = new Intent(); - intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme); - if (!WizardManagerHelper.isLightTheme(intent, false)) { - unexpectedIntentThemes.add(theme); - } - if (!WizardManagerHelper.isLightTheme(theme, false)) { - unexpectedStringThemes.add(theme); - } - } - assertTrue("Intent themes " + unexpectedIntentThemes + " should be light", - unexpectedIntentThemes.isEmpty()); - assertTrue("String themes " + unexpectedStringThemes + " should be light", - unexpectedStringThemes.isEmpty()); - } - - @Test - public void isLightTheme_shouldReturnFalse_whenThemeIsNotLight() { - List<String> lightThemes = Arrays.asList( - "holo", - "material", - "glif", - "glif_v2", - "glif_v3" - ); - ArrayList<String> unexpectedIntentThemes = new ArrayList<>(); - ArrayList<String> unexpectedStringThemes = new ArrayList<>(); - for (final String theme : lightThemes) { - Intent intent = new Intent(); - intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme); - if (WizardManagerHelper.isLightTheme(intent, true)) { - unexpectedIntentThemes.add(theme); - } - if (WizardManagerHelper.isLightTheme(theme, true)) { - unexpectedStringThemes.add(theme); - } - } - assertTrue("Intent themes " + unexpectedIntentThemes + " should not be light", - unexpectedIntentThemes.isEmpty()); - assertTrue("String themes " + unexpectedStringThemes + " should not be light", - unexpectedStringThemes.isEmpty()); - } - - @Test - public void testIsLightThemeDefault() { - final Intent intent = new Intent(); - intent.putExtra("theme", "abracadabra"); - assertTrue("isLightTheme should return default value true", - WizardManagerHelper.isLightTheme(intent, true)); - assertFalse("isLightTheme should return default value false", - WizardManagerHelper.isLightTheme(intent, false)); - } - - @Test - public void testIsLightThemeUnspecified() { - final Intent intent = new Intent(); - assertTrue("isLightTheme should return default value true", - WizardManagerHelper.isLightTheme(intent, true)); - assertFalse("isLightTheme should return default value false", - WizardManagerHelper.isLightTheme(intent, false)); - } - - @Test - public void testGetThemeResGlifV3Light() { - assertEquals(R.style.SuwThemeGlifV3_Light, - WizardManagerHelper.getThemeRes("glif_v3_light", 0)); - } - - @Test - public void testGetThemeResGlifV3() { - assertEquals(R.style.SuwThemeGlifV3, - WizardManagerHelper.getThemeRes("glif_v3", 0)); + @Test + public void testGetNextIntent() { + final Intent intent = new Intent("test.intent.ACTION"); + intent.putExtra("scriptUri", "android-resource://test-script"); + intent.putExtra("actionId", "test_action_id"); + intent.putExtra("theme", "test_theme"); + intent.putExtra("ignoreExtra", "poof"); // extra is ignored because it's not known + + final Intent data = new Intent(); + data.putExtra("extraData", "shazam"); + + final Intent nextIntent = WizardManagerHelper.getNextIntent(intent, Activity.RESULT_OK, data); + assertWithMessage("Next intent action should be NEXT") + .that(nextIntent.getAction()) + .isEqualTo("com.android.wizard.NEXT"); + assertWithMessage("Script URI should be the same as original intent") + .that(nextIntent.getStringExtra("scriptUri")) + .isEqualTo("android-resource://test-script"); + assertWithMessage("Action ID should be the same as original intent") + .that(nextIntent.getStringExtra("actionId")) + .isEqualTo("test_action_id"); + assertWithMessage("Theme extra should be the same as original intent") + .that(nextIntent.getStringExtra("theme")) + .isEqualTo("test_theme"); + assertWithMessage("ignoreExtra should not be in nextIntent") + .that(nextIntent.hasExtra("ignoreExtra")) + .isFalse(); + assertWithMessage("Result code extra should be RESULT_OK") + .that(nextIntent.getIntExtra("com.android.setupwizard.ResultCode", 0)) + .isEqualTo(Activity.RESULT_OK); + assertWithMessage("Extra data should surface as extra in nextIntent") + .that(nextIntent.getStringExtra("extraData")) + .isEqualTo("shazam"); + } + + @Test + public void testIsSetupWizardTrue() { + final Intent intent = new Intent(); + intent.putExtra("firstRun", true); + assertWithMessage("Is setup wizard should be true") + .that(WizardManagerHelper.isSetupWizardIntent(intent)) + .isTrue(); + } + + @Test + public void testIsDeferredSetupTrue() { + final Intent intent = new Intent(); + intent.putExtra("deferredSetup", true); + assertWithMessage("Is deferred setup wizard should be true") + .that(WizardManagerHelper.isDeferredSetupWizard(intent)) + .isTrue(); + } + + @Test + public void testIsPreDeferredSetupTrue() { + final Intent intent = new Intent(); + intent.putExtra("preDeferredSetup", true); + assertWithMessage("Is pre-deferred setup wizard should be true") + .that(WizardManagerHelper.isPreDeferredSetupWizard(intent)) + .isTrue(); + } + + @Test + public void testIsSetupWizardFalse() { + final Intent intent = new Intent(); + intent.putExtra("firstRun", false); + assertWithMessage("Is setup wizard should be true") + .that(WizardManagerHelper.isSetupWizardIntent(intent)) + .isFalse(); + } + + @Test + public void isLightTheme_shouldReturnTrue_whenThemeIsLight() { + List<String> lightThemes = + Arrays.asList( + "holo_light", "material_light", "glif_light", "glif_v2_light", "glif_v3_light"); + ArrayList<String> unexpectedIntentThemes = new ArrayList<>(); + ArrayList<String> unexpectedStringThemes = new ArrayList<>(); + for (final String theme : lightThemes) { + Intent intent = new Intent(); + intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme); + if (!WizardManagerHelper.isLightTheme(intent, false)) { + unexpectedIntentThemes.add(theme); + } + if (!WizardManagerHelper.isLightTheme(theme, false)) { + unexpectedStringThemes.add(theme); + } } - - @Test - public void testGetThemeResGlifV2Light() { - assertEquals(R.style.SuwThemeGlifV2_Light, - WizardManagerHelper.getThemeRes("glif_v2_light", 0)); - } - - @Test - public void testGetThemeResGlifV2() { - assertEquals(R.style.SuwThemeGlifV2, - WizardManagerHelper.getThemeRes("glif_v2", 0)); - } - - @Test - public void testGetThemeResGlifLight() { - assertEquals(R.style.SuwThemeGlif_Light, - WizardManagerHelper.getThemeRes("glif_light", 0)); - } - - @Test - public void testGetThemeResGlif() { - assertEquals(R.style.SuwThemeGlif, - WizardManagerHelper.getThemeRes("glif", 0)); - } - - @Test - public void testGetThemeResMaterialLight() { - assertEquals(R.style.SuwThemeMaterial_Light, - WizardManagerHelper.getThemeRes("material_light", 0)); - } - - @Test - public void testGetThemeResMaterial() { - assertEquals(R.style.SuwThemeMaterial, - WizardManagerHelper.getThemeRes("material", 0)); - } - - @Test - public void testGetThemeResDefault() { - @StyleRes int def = 123; - assertEquals(def, WizardManagerHelper.getThemeRes("abracadabra", def)); - } - - @Test - public void testGetThemeResNull() { - @StyleRes int def = 123; - assertEquals(def, WizardManagerHelper.getThemeRes((String) null, def)); - } - - @Test - public void testGetThemeResFromIntent() { - Intent intent = new Intent(); - intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material"); - assertEquals(R.style.SuwThemeMaterial, WizardManagerHelper.getThemeRes(intent, 0)); - } - - @Test - public void testCopyWizardManagerIntent() { - Bundle wizardBundle = new Bundle(); - wizardBundle.putString("foo", "bar"); - Intent originalIntent = new Intent() - .putExtra(WizardManagerHelper.EXTRA_THEME, "test_theme") - .putExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE, wizardBundle) - .putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true) - .putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, true) - .putExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, true) - // Script URI and Action ID are kept for backwards compatibility - .putExtra(WizardManagerHelper.EXTRA_SCRIPT_URI, "test_script_uri") - .putExtra(WizardManagerHelper.EXTRA_ACTION_ID, "test_action_id"); - - Intent intent = new Intent("test.intent.action"); - WizardManagerHelper.copyWizardManagerExtras(originalIntent, intent); - - assertEquals("Intent action should be kept", "test.intent.action", intent.getAction()); - assertEquals("EXTRA_THEME should be copied", - "test_theme", intent.getStringExtra(WizardManagerHelper.EXTRA_THEME)); - Bundle copiedWizardBundle = - intent.getParcelableExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE); - assertEquals("Wizard bundle should be copied", "bar", copiedWizardBundle.getString("foo")); - - assertTrue("EXTRA_IS_FIRST_RUN should be copied", - intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, false)); - assertTrue("EXTRA_IS_DEFERRED_SETUP should be copied", - intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, false)); - assertTrue("EXTRA_IS_PRE_DEFERRED_SETUP should be copied", - intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, false)); - - // Script URI and Action ID are replaced by Wizard Bundle in M, but are kept for backwards - // compatibility - assertEquals("EXTRA_SCRIPT_URI should be copied", - "test_script_uri", intent.getStringExtra(WizardManagerHelper.EXTRA_SCRIPT_URI)); - assertEquals("EXTRA_ACTION_ID should be copied", - "test_action_id", intent.getStringExtra(WizardManagerHelper.EXTRA_ACTION_ID)); - } - - @TargetApi(VERSION_CODES.JELLY_BEAN_MR1) - @Test - public void testIsUserSetupComplete() { - Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1); - Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 1); - assertTrue(WizardManagerHelper.isUserSetupComplete(application)); - - Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 0); - assertFalse(WizardManagerHelper.isUserSetupComplete(application)); - } - - @Test - @Config(sdk = VERSION_CODES.JELLY_BEAN) - public void testIsUserSetupCompleteCompat() { - Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1); - assertTrue(WizardManagerHelper.isUserSetupComplete(application)); - - Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0); - assertFalse(WizardManagerHelper.isUserSetupComplete(application)); - } - - @TargetApi(VERSION_CODES.JELLY_BEAN_MR1) - @Test - public void testIsDeviceProvisioned() { - Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1); - assertTrue(WizardManagerHelper.isDeviceProvisioned(application)); - Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 0); - assertFalse(WizardManagerHelper.isDeviceProvisioned(application)); - } - - @Test - @Config(sdk = VERSION_CODES.JELLY_BEAN) - public void testIsDeviceProvisionedCompat() { - Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1); - assertTrue(WizardManagerHelper.isDeviceProvisioned(application)); - Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0); - assertFalse(WizardManagerHelper.isDeviceProvisioned(application)); + assertWithMessage("Intent themes " + unexpectedIntentThemes + " should be light") + .that(unexpectedIntentThemes.isEmpty()) + .isTrue(); + assertWithMessage("String themes " + unexpectedStringThemes + " should be light") + .that(unexpectedStringThemes.isEmpty()) + .isTrue(); + } + + @Test + public void isLightTheme_shouldReturnFalse_whenThemeIsNotLight() { + List<String> lightThemes = Arrays.asList("holo", "material", "glif", "glif_v2", "glif_v3"); + ArrayList<String> unexpectedIntentThemes = new ArrayList<>(); + ArrayList<String> unexpectedStringThemes = new ArrayList<>(); + for (final String theme : lightThemes) { + Intent intent = new Intent(); + intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme); + if (WizardManagerHelper.isLightTheme(intent, true)) { + unexpectedIntentThemes.add(theme); + } + if (WizardManagerHelper.isLightTheme(theme, true)) { + unexpectedStringThemes.add(theme); + } } + assertWithMessage("Intent themes " + unexpectedIntentThemes + " should not be light") + .that(unexpectedIntentThemes.isEmpty()) + .isTrue(); + assertWithMessage("String themes " + unexpectedStringThemes + " should not be light") + .that(unexpectedStringThemes.isEmpty()) + .isTrue(); + } + + @Test + public void getThemeRes_whenOldestSupportedThemeTakeEffect_shouldReturnDefault() { + Intent intent = new Intent(); + intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material"); + assertThat(WizardManagerHelper.getThemeRes(intent, 0, WizardManagerHelper.THEME_GLIF_V2)) + .isEqualTo(0); + } + + @Test + public void getThemeRes_whenOldestSupportedThemeNotTakeEffect_shouldReturnCurrent() { + Intent intent = new Intent(); + intent.putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3"); + assertThat(WizardManagerHelper.getThemeRes(intent, 0, WizardManagerHelper.THEME_GLIF_V2)) + .isEqualTo(R.style.SuwThemeGlifV3); + } + + @Test + public void testIsLightThemeDefault() { + final Intent intent = new Intent(); + intent.putExtra("theme", "abracadabra"); + assertWithMessage("isLightTheme should return default value true") + .that(WizardManagerHelper.isLightTheme(intent, true)) + .isTrue(); + assertWithMessage("isLightTheme should return default value false") + .that(WizardManagerHelper.isLightTheme(intent, false)) + .isFalse(); + } + + @Test + public void testIsLightThemeUnspecified() { + final Intent intent = new Intent(); + assertWithMessage("isLightTheme should return default value true") + .that(WizardManagerHelper.isLightTheme(intent, true)) + .isTrue(); + assertWithMessage("isLightTheme should return default value false") + .that(WizardManagerHelper.isLightTheme(intent, false)) + .isFalse(); + } + + @Test + public void testGetThemeResGlifV3Light() { + assertThat(WizardManagerHelper.getThemeRes("glif_v3_light", 0)) + .isEqualTo(R.style.SuwThemeGlifV3_Light); + } + + @Test + public void testGetThemeResGlifV3() { + assertThat(WizardManagerHelper.getThemeRes("glif_v3", 0)).isEqualTo(R.style.SuwThemeGlifV3); + } + + @Test + public void testGetThemeResGlifV2Light() { + assertThat(WizardManagerHelper.getThemeRes("glif_v2_light", 0)) + .isEqualTo(R.style.SuwThemeGlifV2_Light); + } + + @Test + public void testGetThemeResGlifV2() { + assertThat(WizardManagerHelper.getThemeRes("glif_v2", 0)).isEqualTo(R.style.SuwThemeGlifV2); + } + + @Test + public void testGetThemeResGlifLight() { + assertThat(WizardManagerHelper.getThemeRes("glif_light", 0)) + .isEqualTo(R.style.SuwThemeGlif_Light); + } + + @Test + public void testGetThemeResGlif() { + assertThat(WizardManagerHelper.getThemeRes("glif", 0)).isEqualTo(R.style.SuwThemeGlif); + } + + @Test + public void testGetThemeResMaterialLight() { + assertThat(WizardManagerHelper.getThemeRes("material_light", 0)) + .isEqualTo(R.style.SuwThemeMaterial_Light); + } + + @Test + public void testGetThemeResMaterial() { + assertThat(WizardManagerHelper.getThemeRes("material", 0)).isEqualTo(R.style.SuwThemeMaterial); + } + + @Test + public void testGetThemeResDefault() { + @StyleRes int def = 123; + assertThat(WizardManagerHelper.getThemeRes("abracadabra", def)).isEqualTo(def); + } + + @Test + public void testGetThemeResNull() { + @StyleRes int def = 123; + assertThat(WizardManagerHelper.getThemeRes((String) null, def)).isEqualTo(def); + } + + @Test + public void testGetThemeResFromIntent() { + Intent intent = new Intent(); + intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material"); + assertThat(WizardManagerHelper.getThemeRes(intent, 0)).isEqualTo(R.style.SuwThemeMaterial); + } + + @Test + public void testCopyWizardManagerIntent() { + Bundle wizardBundle = new Bundle(); + wizardBundle.putString("foo", "bar"); + Intent originalIntent = + new Intent() + .putExtra(WizardManagerHelper.EXTRA_THEME, "test_theme") + .putExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE, wizardBundle) + .putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true) + .putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, true) + .putExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, true) + // Script URI and Action ID are kept for backwards compatibility + .putExtra(WizardManagerHelper.EXTRA_SCRIPT_URI, "test_script_uri") + .putExtra(WizardManagerHelper.EXTRA_ACTION_ID, "test_action_id"); + + Intent intent = new Intent("test.intent.action"); + WizardManagerHelper.copyWizardManagerExtras(originalIntent, intent); + + assertWithMessage("Intent action should be kept") + .that(intent.getAction()) + .isEqualTo("test.intent.action"); + assertWithMessage("EXTRA_THEME should be copied") + .that(intent.getStringExtra(WizardManagerHelper.EXTRA_THEME)) + .isEqualTo("test_theme"); + Bundle copiedWizardBundle = intent.getParcelableExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE); + assertWithMessage("Wizard bundle should be copied") + .that(copiedWizardBundle.getString("foo")) + .isEqualTo("bar"); + + assertWithMessage("EXTRA_IS_FIRST_RUN should be copied") + .that(intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, false)) + .isTrue(); + assertWithMessage("EXTRA_IS_DEFERRED_SETUP should be copied") + .that(intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, false)) + .isTrue(); + assertWithMessage("EXTRA_IS_PRE_DEFERRED_SETUP should be copied") + .that(intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, false)) + .isTrue(); + + // Script URI and Action ID are replaced by Wizard Bundle in M, but are kept for backwards + // compatibility + assertWithMessage("EXTRA_SCRIPT_URI should be copied") + .that(intent.getStringExtra(WizardManagerHelper.EXTRA_SCRIPT_URI)) + .isEqualTo("test_script_uri"); + assertWithMessage("EXTRA_ACTION_ID should be copied") + .that(intent.getStringExtra(WizardManagerHelper.EXTRA_ACTION_ID)) + .isEqualTo("test_action_id"); + } + + @TargetApi(VERSION_CODES.JELLY_BEAN_MR1) + @Test + public void testIsUserSetupComplete() { + Settings.Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1); + Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 1); + assertThat(WizardManagerHelper.isUserSetupComplete(application)).isTrue(); + + Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 0); + assertThat(WizardManagerHelper.isUserSetupComplete(application)).isFalse(); + } + + @Test + @Config(sdk = VERSION_CODES.JELLY_BEAN) + public void testIsUserSetupCompleteCompat() { + Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1); + assertThat(WizardManagerHelper.isUserSetupComplete(application)).isTrue(); + + Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0); + assertThat(WizardManagerHelper.isUserSetupComplete(application)).isFalse(); + } + + @TargetApi(VERSION_CODES.JELLY_BEAN_MR1) + @Test + public void testIsDeviceProvisioned() { + Settings.Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1); + assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isTrue(); + Settings.Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 0); + assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isFalse(); + } + + @Test + @Config(sdk = VERSION_CODES.JELLY_BEAN) + public void testIsDeviceProvisionedCompat() { + Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1); + assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isTrue(); + Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0); + assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isFalse(); + } + + @Test + public void applyTheme_glifDayNight_shouldApplyThemeToActivity() { + Activity activity = + Robolectric.buildActivity( + Activity.class, + new Intent() + .putExtra( + WizardManagerHelper.EXTRA_THEME, WizardManagerHelper.THEME_GLIF_LIGHT)) + .setup() + .get(); + + WizardManagerHelper.applyTheme(activity); + + assertThat(shadowOf(activity).callGetThemeResId()).isEqualTo(R.style.SuwThemeGlif_DayNight); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java index ae4f3d1..001f1da 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java @@ -16,72 +16,73 @@ package com.android.setupwizardlib.view; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; import static org.robolectric.RuntimeEnvironment.application; import android.view.View; import android.view.View.MeasureSpec; - -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; - import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(SuwLibRobolectricTestRunner.class) +@RunWith(RobolectricTestRunner.class) @Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class FillContentLayoutTest { - @Test - public void testMeasureMinSize() { - FillContentLayout layout = new FillContentLayout( - application, - Robolectric.buildAttributeSet() - .addAttribute(android.R.attr.minWidth, "123dp") - .addAttribute(android.R.attr.minHeight, "123dp") - .build()); - layout.measure( - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + @Test + public void testMeasureMinSize() { + FillContentLayout layout = + new FillContentLayout( + application, + Robolectric.buildAttributeSet() + .addAttribute(android.R.attr.minWidth, "123dp") + .addAttribute(android.R.attr.minHeight, "123dp") + .build()); + layout.measure( + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - assertEquals(123, layout.getMeasuredWidth()); - assertEquals(123, layout.getMeasuredHeight()); - } + assertThat(layout.getMeasuredWidth()).isEqualTo(123); + assertThat(layout.getMeasuredHeight()).isEqualTo(123); + } - @Test - public void testMeasureChildIsSmallerThanMaxSize() { - View child = new View(application); - FillContentLayout layout = new FillContentLayout( - application, - Robolectric.buildAttributeSet() - .addAttribute(android.R.attr.maxWidth, "123dp") - .addAttribute(android.R.attr.maxHeight, "123dp") - .build()); - layout.addView(child); - layout.measure( - MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY)); + @Test + public void testMeasureChildIsSmallerThanMaxSize() { + View child = new View(application); + FillContentLayout layout = + new FillContentLayout( + application, + Robolectric.buildAttributeSet() + .addAttribute(android.R.attr.maxWidth, "123dp") + .addAttribute(android.R.attr.maxHeight, "123dp") + .build()); + layout.addView(child); + layout.measure( + MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY)); - assertEquals(123, child.getMeasuredWidth()); - assertEquals(123, child.getMeasuredHeight()); - } + assertThat(child.getMeasuredWidth()).isEqualTo(123); + assertThat(child.getMeasuredHeight()).isEqualTo(123); + } - @Test - public void testMeasureChildIsSmallerThanParent() { - View child = new View(application); - FillContentLayout layout = new FillContentLayout( - application, - Robolectric.buildAttributeSet() - .addAttribute(android.R.attr.maxWidth, "123dp") - .addAttribute(android.R.attr.maxHeight, "123dp") - .build()); - layout.addView(child); - layout.measure( - MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY)); + @Test + public void testMeasureChildIsSmallerThanParent() { + View child = new View(application); + FillContentLayout layout = + new FillContentLayout( + application, + Robolectric.buildAttributeSet() + .addAttribute(android.R.attr.maxWidth, "123dp") + .addAttribute(android.R.attr.maxHeight, "123dp") + .build()); + layout.addView(child); + layout.measure( + MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY)); - assertEquals(88, child.getMeasuredWidth()); - assertEquals(88, child.getMeasuredHeight()); - } + assertThat(child.getMeasuredWidth()).isEqualTo(88); + assertThat(child.getMeasuredHeight()).isEqualTo(88); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java index 0e0e99c..e980563 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java @@ -17,204 +17,223 @@ package com.android.setupwizardlib.view; import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; -import android.annotation.TargetApi; -import android.content.Context; +import android.app.Activity; import android.graphics.SurfaceTexture; -import android.media.MediaPlayer; -import android.os.Build.VERSION_CODES; -import android.view.Surface; -import android.view.View; - +import android.net.Uri; import androidx.annotation.RawRes; - +import android.view.View; import com.android.setupwizardlib.R; -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; -import com.android.setupwizardlib.shadow.ShadowLog; -import com.android.setupwizardlib.shadow.ShadowLog.TerribleFailure; -import com.android.setupwizardlib.view.IllustrationVideoViewTest.ShadowMockMediaPlayer; -import com.android.setupwizardlib.view.IllustrationVideoViewTest.ShadowSurface; - -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.RealObject; -import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowMediaPlayer; +import org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior; +import org.robolectric.shadows.ShadowMediaPlayer.MediaInfo; +import org.robolectric.shadows.util.DataSource; import org.robolectric.util.ReflectionHelpers; +import org.robolectric.util.ReflectionHelpers.ClassParameter; -@RunWith(SuwLibRobolectricTestRunner.class) -@Config( - sdk = Config.NEWEST_SDK, - shadows = { - ShadowLog.class, - ShadowMockMediaPlayer.class, - ShadowSurface.class - }) +@RunWith(RobolectricTestRunner.class) +@Config(sdk = Config.NEWEST_SDK) public class IllustrationVideoViewTest { - @Mock - private SurfaceTexture mSurfaceTexture; - - private IllustrationVideoView mView; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - } - - @After - public void tearDown() { - ShadowMockMediaPlayer.reset(); - } - - @Test - public void nullMediaPlayer_shouldThrowWtf() { - ShadowMockMediaPlayer.sMediaPlayer = null; - try { - createDefaultView(); - fail("WTF should be thrown for null media player"); - } catch (TerribleFailure e) { - // pass - } - } - - @Test - public void onVisibilityChanged_notVisible_shouldRelease() { - createDefaultView(); - mView.onWindowVisibilityChanged(View.GONE); - - verify(ShadowMockMediaPlayer.sMediaPlayer).release(); - assertThat(mView.mSurface).isNull(); - assertThat(mView.mMediaPlayer).isNull(); - } - - @Test - public void onVisibilityChanged_visible_shouldPlay() { - createDefaultView(); - - mView.onWindowVisibilityChanged(View.GONE); - assertThat(mView.mSurface).isNull(); - assertThat(mView.mMediaPlayer).isNull(); - - mView.onWindowVisibilityChanged(View.VISIBLE); - - assertThat(mView.mSurface).isNotNull(); - assertThat(mView.mMediaPlayer).isNotNull(); - } - - @Test - public void testPausedWhenWindowFocusLost() { - createDefaultView(); - mView.start(); - - assertNotNull(mView.mMediaPlayer); - assertNotNull(mView.mSurface); - - mView.onWindowFocusChanged(false); - verify(ShadowMockMediaPlayer.getMock()).pause(); - } - - @Test - public void testStartedWhenWindowFocusRegained() { - testPausedWhenWindowFocusLost(); - - // Clear verifications for calls in the other test - reset(ShadowMockMediaPlayer.getMock()); - - mView.onWindowFocusChanged(true); - verify(ShadowMockMediaPlayer.getMock()).start(); - } - - @Test - public void testSurfaceReleasedWhenTextureDestroyed() { - createDefaultView(); - mView.start(); - - assertNotNull(mView.mMediaPlayer); - assertNotNull(mView.mSurface); - - mView.onSurfaceTextureDestroyed(mSurfaceTexture); - verify(ShadowMockMediaPlayer.getMock()).release(); - } - - @Test - public void testXmlSetVideoResId() { - createDefaultView(); - assertEquals(android.R.color.white, ShadowMockMediaPlayer.sResId); - } - - @Test - public void testSetVideoResId() { - createDefaultView(); - - @RawRes int black = android.R.color.black; - mView.setVideoResource(black); - - assertEquals(android.R.color.black, ShadowMockMediaPlayer.sResId); - } - - private void createDefaultView() { - mView = new IllustrationVideoView( - application, - Robolectric.buildAttributeSet() - // Any resource attribute should work, since the media player is mocked - .addAttribute(R.attr.suwVideo, "@android:color/white") - .build()); - mView.setSurfaceTexture(mock(SurfaceTexture.class)); - mView.onSurfaceTextureAvailable(mSurfaceTexture, 500, 500); - } - - @Implements(MediaPlayer.class) - public static class ShadowMockMediaPlayer extends ShadowMediaPlayer { - - private static MediaPlayer sMediaPlayer = mock(MediaPlayer.class); - private static int sResId; - - public static void reset() { - sMediaPlayer = mock(MediaPlayer.class); - sResId = 0; - } - - @Implementation - public static MediaPlayer create(Context context, int resId) { - sResId = resId; - return sMediaPlayer; - } - - public static MediaPlayer getMock() { - return sMediaPlayer; - } - } - - @Implements(Surface.class) - @TargetApi(VERSION_CODES.HONEYCOMB) - public static class ShadowSurface extends org.robolectric.shadows.ShadowSurface { - - @RealObject - private Surface mRealSurface; - - public void __constructor__(SurfaceTexture surfaceTexture) { - // Call the constructor on the real object, so that critical fields such as mLock is - // initialized properly. - Shadow.invokeConstructor(Surface.class, mRealSurface, - ReflectionHelpers.ClassParameter.from(SurfaceTexture.class, surfaceTexture)); - super.__constructor__(surfaceTexture); - } - } + @Mock private SurfaceTexture surfaceTexture; + + private IllustrationVideoView view; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowMediaPlayer.addMediaInfo( + DataSource.toDataSource( + "android.resource://" + application.getPackageName() + "/" + android.R.color.white), + new ShadowMediaPlayer.MediaInfo(100, 10)); + ShadowMediaPlayer.addMediaInfo( + DataSource.toDataSource( + "android.resource://" + application.getPackageName() + "/" + android.R.color.black), + new ShadowMediaPlayer.MediaInfo(100, 10)); + } + + @Test + public void testPausedWhenWindowFocusLost() { + createDefaultView(); + Robolectric.flushForegroundThreadScheduler(); + view.start(); + + assertThat(view.mMediaPlayer).isNotNull(); + assertThat(view.surface).isNotNull(); + + view.onWindowFocusChanged(false); + assertThat(getShadowMediaPlayer().getState()).isEqualTo(ShadowMediaPlayer.State.PAUSED); + } + + @Test + public void testStartedWhenWindowFocusRegained() { + testPausedWhenWindowFocusLost(); + Robolectric.flushForegroundThreadScheduler(); + + view.onWindowFocusChanged(true); + assertThat(getShadowMediaPlayer().getState()).isEqualTo(ShadowMediaPlayer.State.STARTED); + } + + @Test + public void testSurfaceReleasedWhenTextureDestroyed() { + createDefaultView(); + view.start(); + + assertThat(view.mMediaPlayer).isNotNull(); + assertThat(view.surface).isNotNull(); + + // MediaPlayer is set to null after destroy. Retrieve it first before we call destroy. + ShadowMediaPlayer shadowMediaPlayer = getShadowMediaPlayer(); + view.onSurfaceTextureDestroyed(surfaceTexture); + assertThat(shadowMediaPlayer.getState()).isEqualTo(ShadowMediaPlayer.State.END); + } + + @Test + public void testXmlSetVideoResId() { + createDefaultView(); + assertThat(getShadowMediaPlayer().getSourceUri().toString()) + .isEqualTo("android.resource://com.android.setupwizardlib/" + android.R.color.white); + } + + @Test + public void testSetVideoResId() { + createDefaultView(); + + @RawRes int black = android.R.color.black; + view.setVideoResource(black); + + assertThat(getShadowMediaPlayer().getSourceUri().toString()) + .isEqualTo("android.resource://com.android.setupwizardlib/" + android.R.color.black); + } + + @Test + public void prepareVideo_shouldSetAspectRatio() { + createDefaultView(); + + ReflectionHelpers.setField(getShadowMediaPlayer(), "videoWidth", 720); + ReflectionHelpers.setField(getShadowMediaPlayer(), "videoHeight", 1280); + + Robolectric.flushForegroundThreadScheduler(); + view.start(); + + view.measure( + View.MeasureSpec.makeMeasureSpec(720, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(720, View.MeasureSpec.EXACTLY)); + + final float aspectRatio = (float) view.getMeasuredHeight() / view.getMeasuredWidth(); + assertThat(aspectRatio).isWithin(0.001f).of(1280f / 720f); + } + + @Test + public void prepareVideo_zeroHeight_shouldSetAspectRatioToZero() { + createDefaultView(); + + ReflectionHelpers.setField(getShadowMediaPlayer(), "videoWidth", 720); + ReflectionHelpers.setField(getShadowMediaPlayer(), "videoHeight", 0); + + Robolectric.flushForegroundThreadScheduler(); + view.start(); + + final float aspectRatio = (float) view.getHeight() / view.getWidth(); + assertThat(aspectRatio).isEqualTo(0.0f); + } + + @Test + public void setVideoResId_resetDiffVideoResFromDiffPackage_videoResShouldBeSet() { + // VideoRes default set as android.R.color.white with + // default package(com.android.setupwizardlib) + createDefaultView(); + + // reset different videoRes from different package + String newPackageName = "com.android.fakepackage"; + @RawRes int black = android.R.color.black; + addMediaInfo(black, newPackageName); + view.setVideoResource(black, newPackageName); + + // should be reset to black with the new package + assertThat(getShadowMediaPlayer().getSourceUri().toString()) + .isEqualTo("android.resource://" + newPackageName + "/" + android.R.color.black); + } + + @Test + public void setVideoResId_resetDiffVideoResFromSamePackage_videoResShouldBeSet() { + // VideoRes default set as android.R.color.white with + // default package(com.android.setupwizardlib) + createDefaultView(); + + // reset different videoRes from the same package(default package) + String defaultPackageName = "com.android.setupwizardlib"; + @RawRes int black = android.R.color.black; + addMediaInfo(black, defaultPackageName); + view.setVideoResource(black, defaultPackageName); + + // should be reset to black with the same package(default package) + assertThat(getShadowMediaPlayer().getSourceUri().toString()) + .isEqualTo("android.resource://" + defaultPackageName + "/" + android.R.color.black); + } + + @Test + public void setVideoResId_resetSameVideoResFromDifferentPackage_videoResShouldBeSet() { + // VideoRes default set as android.R.color.white with + // default package(com.android.setupwizardlib) + createDefaultView(); + + // reset same videoRes from different package + @RawRes int white = android.R.color.white; + String newPackageName = "com.android.fakepackage"; + addMediaInfo(white, newPackageName); + view.setVideoResource(white, newPackageName); + + // should be white with the new package + assertThat(getShadowMediaPlayer().getSourceUri().toString()) + .isEqualTo("android.resource://" + newPackageName + "/" + android.R.color.white); + } + + private ShadowMediaPlayer getShadowMediaPlayer() { + return Shadows.shadowOf(view.mMediaPlayer); + } + + private void createDefaultView() { + view = + new IllustrationVideoView( + application, + Robolectric.buildAttributeSet() + // Any resource attribute should work, since the data source is fake + .addAttribute(R.attr.suwVideo, "@android:color/white") + .build()); + + Activity activity = Robolectric.setupActivity(Activity.class); + activity.setContentView(view); + setWindowVisible(); + + view.setSurfaceTexture(mock(SurfaceTexture.class)); + view.onSurfaceTextureAvailable(surfaceTexture, 500, 500); + getShadowMediaPlayer().setInvalidStateBehavior(InvalidStateBehavior.EMULATE); + } + + private void setWindowVisible() { + Object viewRootImpl = ReflectionHelpers.callInstanceMethod(view, "getViewRootImpl"); + ReflectionHelpers.callInstanceMethod( + viewRootImpl, "handleAppVisibility", ClassParameter.from(boolean.class, true)); + assertThat(view.isAttachedToWindow()).isTrue(); + assertThat(view.getWindowVisibility()).isEqualTo(View.VISIBLE); + } + + private void addMediaInfo(@RawRes int res, String packageName) { + ShadowMediaPlayer.addMediaInfo( + DataSource.toDataSource( + application, Uri.parse("android.resource://" + packageName + "/" + res), null), + new MediaInfo(5000, 1)); + } } diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java index f77de68..477c42a 100644 --- a/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java +++ b/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java @@ -17,15 +17,10 @@ package com.android.setupwizardlib.view; import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; @@ -39,201 +34,196 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.TextAppearanceSpan; import android.view.MotionEvent; - -import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner; import com.android.setupwizardlib.span.LinkSpan; import com.android.setupwizardlib.span.LinkSpan.OnLinkClickListener; import com.android.setupwizardlib.view.TouchableMovementMethod.TouchableLinkMovementMethod; - import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import java.util.Arrays; - -@RunWith(SuwLibRobolectricTestRunner.class) -@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK }) +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK}) public class RichTextViewTest { - @Test - public void testLinkAnnotation() { - Annotation link = new Annotation("link", "foobar"); - SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); - ssb.setSpan(link, 1, 2, 0 /* flags */); - - RichTextView textView = new RichTextView(application); - textView.setText(ssb); - - final CharSequence text = textView.getText(); - assertTrue("Text should be spanned", text instanceof Spanned); - - assertThat(textView.getMovementMethod()).isInstanceOf(TouchableLinkMovementMethod.class); - - Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class); - assertEquals("Annotation should be removed " + Arrays.toString(spans), 0, spans.length); - - spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class); - assertEquals("There should be one span " + Arrays.toString(spans), 1, spans.length); - assertTrue("The span should be a LinkSpan", spans[0] instanceof LinkSpan); - assertEquals("The LinkSpan should have id \"foobar\"", - "foobar", ((LinkSpan) spans[0]).getId()); - } - - @Test - public void testOnLinkClickListener() { - Annotation link = new Annotation("link", "foobar"); - SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); - ssb.setSpan(link, 1, 2, 0 /* flags */); + @Test + public void testLinkAnnotation() { + Annotation link = new Annotation("link", "foobar"); + SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); + ssb.setSpan(link, 1, 2, 0 /* flags */); + + RichTextView textView = new RichTextView(application); + textView.setText(ssb); + + final CharSequence text = textView.getText(); + assertThat(text).isInstanceOf(Spanned.class); + + assertThat(textView.getMovementMethod()).isInstanceOf(TouchableLinkMovementMethod.class); - RichTextView textView = new RichTextView(application); - textView.setText(ssb); + Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class); + assertThat(spans).isEmpty(); - OnLinkClickListener listener = mock(OnLinkClickListener.class); - textView.setOnLinkClickListener(listener); + spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class); + assertThat(spans).hasLength(1); + assertThat(spans[0]).isInstanceOf(LinkSpan.class); + assertWithMessage("The LinkSpan should have id \"foobar\"") + .that(((LinkSpan) spans[0]).getId()) + .isEqualTo("foobar"); + } + + @Test + public void testOnLinkClickListener() { + Annotation link = new Annotation("link", "foobar"); + SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); + ssb.setSpan(link, 1, 2, 0 /* flags */); + + RichTextView textView = new RichTextView(application); + textView.setText(ssb); - assertSame(listener, textView.getOnLinkClickListener()); - - CharSequence text = textView.getText(); - LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class); - spans[0].onClick(textView); - - verify(listener).onLinkClick(eq(spans[0])); + OnLinkClickListener listener = mock(OnLinkClickListener.class); + textView.setOnLinkClickListener(listener); + + assertThat(textView.getOnLinkClickListener()).isSameAs(listener); + + CharSequence text = textView.getText(); + LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class); + spans[0].onClick(textView); + + verify(listener).onLinkClick(eq(spans[0])); + } + + @Test + public void testLegacyContextOnClickListener() { + // Click listener implemented by context should still be invoked for compatibility. + Annotation link = new Annotation("link", "foobar"); + SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); + ssb.setSpan(link, 1, 2, 0 /* flags */); + + TestContext context = new TestContext(application); + context.delegate = mock(LinkSpan.OnClickListener.class); + RichTextView textView = new RichTextView(context); + textView.setText(ssb); + + CharSequence text = textView.getText(); + LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class); + spans[0].onClick(textView); + + verify(context.delegate).onClick(eq(spans[0])); + } + + @Test + public void onTouchEvent_clickOnLinks_shouldReturnTrue() { + Annotation link = new Annotation("link", "foobar"); + SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); + ssb.setSpan(link, 0, 2, 0 /* flags */); + + RichTextView textView = new RichTextView(application); + textView.setText(ssb); + + TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class); + textView.setMovementMethod(mockMovementMethod); + + MotionEvent motionEvent = MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0); + doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent(); + doReturn(true).when(mockMovementMethod).isLastTouchEventHandled(); + assertThat(textView.onTouchEvent(motionEvent)).isTrue(); + } + + @Test + public void onTouchEvent_clickOutsideLinks_shouldReturnFalse() { + Annotation link = new Annotation("link", "foobar"); + SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); + ssb.setSpan(link, 0, 2, 0 /* flags */); + + RichTextView textView = new RichTextView(application); + textView.setText(ssb); + + TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class); + textView.setMovementMethod(mockMovementMethod); + + MotionEvent motionEvent = MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0); + doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent(); + doReturn(false).when(mockMovementMethod).isLastTouchEventHandled(); + assertThat(textView.onTouchEvent(motionEvent)).isFalse(); + } + + @Test + public void testTextStyle() { + Annotation link = new Annotation("textAppearance", "foobar"); + SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); + ssb.setSpan(link, 1, 2, 0 /* flags */); + + RichTextView textView = new RichTextView(application); + textView.setText(ssb); + + final CharSequence text = textView.getText(); + assertThat(text).isInstanceOf(Spanned.class); + + Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class); + assertThat(spans).isEmpty(); + + spans = ((Spanned) text).getSpans(0, text.length(), TextAppearanceSpan.class); + assertThat(spans).hasLength(1); + assertThat(spans[0]).isInstanceOf(TextAppearanceSpan.class); + } + + @Test + public void testTextContainingLinksAreFocusable() { + Annotation testLink = new Annotation("link", "value"); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("Linked"); + spannableStringBuilder.setSpan(testLink, 0, 3, 0); + + RichTextView view = new RichTextView(application); + view.setText(spannableStringBuilder); + + assertThat(view.isFocusable()).named("view focusable").isTrue(); + } + + @SuppressLint("SetTextI18n") // It's OK. This is just a test. + @Test + public void testTextContainingNoLinksAreNotFocusable() { + RichTextView textView = new RichTextView(application); + textView.setText("Thou shall not be focusable!"); + + assertThat(textView.isFocusable()).named("view focusable").isFalse(); + } + + // Based on the text contents of the text view, the "focusable" property of the element + // should also be automatically changed. + @SuppressLint("SetTextI18n") // It's OK. This is just a test. + @Test + public void testRichTextViewFocusChangesWithTextChange() { + RichTextView textView = new RichTextView(application); + textView.setText("Thou shall not be focusable!"); + + assertThat(textView.isFocusable()).isFalse(); + assertThat(textView.isFocusableInTouchMode()).isFalse(); + + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("I am focusable"); + spannableStringBuilder.setSpan(new Annotation("link", "focus:on_me"), 0, 1, 0); + textView.setText(spannableStringBuilder); + assertThat(textView.isFocusable()).isTrue(); + if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) { + assertThat(textView.isFocusableInTouchMode()).isTrue(); + assertThat(textView.getRevealOnFocusHint()).isFalse(); + } else { + assertThat(textView.isFocusableInTouchMode()).isFalse(); } + } - @Test - public void testLegacyContextOnClickListener() { - // Click listener implemented by context should still be invoked for compatibility. - Annotation link = new Annotation("link", "foobar"); - SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); - ssb.setSpan(link, 1, 2, 0 /* flags */); - - TestContext context = spy(new TestContext(application)); - RichTextView textView = new RichTextView(context); - textView.setText(ssb); + public static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener { - CharSequence text = textView.getText(); - LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class); - spans[0].onClick(textView); + LinkSpan.OnClickListener delegate; - verify(context).onClick(eq(spans[0])); + public TestContext(Context base) { + super(base); } - @Test - public void onTouchEvent_clickOnLinks_shouldReturnTrue() { - Annotation link = new Annotation("link", "foobar"); - SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); - ssb.setSpan(link, 0, 2, 0 /* flags */); - - RichTextView textView = new RichTextView(application); - textView.setText(ssb); - - TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class); - textView.setMovementMethod(mockMovementMethod); - - MotionEvent motionEvent = - MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0); - doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent(); - doReturn(true).when(mockMovementMethod).isLastTouchEventHandled(); - assertThat(textView.onTouchEvent(motionEvent)).isTrue(); - } - - @Test - public void onTouchEvent_clickOutsideLinks_shouldReturnFalse() { - Annotation link = new Annotation("link", "foobar"); - SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); - ssb.setSpan(link, 0, 2, 0 /* flags */); - - RichTextView textView = new RichTextView(application); - textView.setText(ssb); - - TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class); - textView.setMovementMethod(mockMovementMethod); - - MotionEvent motionEvent = - MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0); - doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent(); - doReturn(false).when(mockMovementMethod).isLastTouchEventHandled(); - assertThat(textView.onTouchEvent(motionEvent)).isFalse(); - } - - @Test - public void testTextStyle() { - Annotation link = new Annotation("textAppearance", "foobar"); - SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world"); - ssb.setSpan(link, 1, 2, 0 /* flags */); - - RichTextView textView = new RichTextView(application); - textView.setText(ssb); - - final CharSequence text = textView.getText(); - assertTrue("Text should be spanned", text instanceof Spanned); - - Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class); - assertEquals("Annotation should be removed " + Arrays.toString(spans), 0, spans.length); - - spans = ((Spanned) text).getSpans(0, text.length(), TextAppearanceSpan.class); - assertEquals("There should be one span " + Arrays.toString(spans), 1, spans.length); - assertTrue("The span should be a TextAppearanceSpan", - spans[0] instanceof TextAppearanceSpan); - } - - @Test - public void testTextContainingLinksAreFocusable() { - Annotation testLink = new Annotation("link", "value"); - SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("Linked"); - spannableStringBuilder.setSpan(testLink, 0, 3, 0); - - RichTextView view = new RichTextView(application); - view.setText(spannableStringBuilder); - - assertTrue("TextView should be focusable since it contains spans", view.isFocusable()); - } - - - @SuppressLint("SetTextI18n") // It's OK. This is just a test. - @Test - public void testTextContainingNoLinksAreNotFocusable() { - RichTextView textView = new RichTextView(application); - textView.setText("Thou shall not be focusable!"); - - assertFalse("TextView should not be focusable since it does not contain any span", - textView.isFocusable()); - } - - - // Based on the text contents of the text view, the "focusable" property of the element - // should also be automatically changed. - @SuppressLint("SetTextI18n") // It's OK. This is just a test. - @Test - public void testRichTextViewFocusChangesWithTextChange() { - RichTextView textView = new RichTextView(application); - textView.setText("Thou shall not be focusable!"); - - assertFalse(textView.isFocusable()); - assertFalse(textView.isFocusableInTouchMode()); - - SpannableStringBuilder spannableStringBuilder = - new SpannableStringBuilder("I am focusable"); - spannableStringBuilder.setSpan(new Annotation("link", "focus:on_me"), 0, 1, 0); - textView.setText(spannableStringBuilder); - assertTrue(textView.isFocusable()); - if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) { - assertTrue(textView.isFocusableInTouchMode()); - assertFalse(textView.getRevealOnFocusHint()); - } else { - assertFalse(textView.isFocusableInTouchMode()); - } - } - - public static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener { - - public TestContext(Context base) { - super(base); - } - - @Override - public void onClick(LinkSpan span) { - // Ignore. Can be verified using Mockito - } + @Override + public void onClick(LinkSpan span) { + if (delegate != null) { + delegate.onClick(span); + } } + } } |