aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/src/com/android/tv/data/ChannelImplTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/src/com/android/tv/data/ChannelImplTest.java')
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelImplTest.java381
1 files changed, 381 insertions, 0 deletions
diff --git a/tests/unit/src/com/android/tv/data/ChannelImplTest.java b/tests/unit/src/com/android/tv/data/ChannelImplTest.java
new file mode 100644
index 00000000..b791a7e4
--- /dev/null
+++ b/tests/unit/src/com/android/tv/data/ChannelImplTest.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2015 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.tv.data;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.tv.data.api.Channel;
+import com.android.tv.testing.ComparatorTester;
+import com.android.tv.util.TvInputManagerHelper;
+import java.util.Comparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/** Tests for {@link ChannelImpl}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ChannelImplTest {
+ // Used for testing TV inputs with invalid input package. This could happen when a TV input is
+ // uninstalled while drawing an app link card.
+ private static final String INVALID_TV_INPUT_PACKAGE_NAME = "com.android.tv.invalid_tv_input";
+ // Used for testing TV inputs defined inside of Live TV.
+ private static final String LIVE_CHANNELS_PACKAGE_NAME = "com.android.tv";
+ // Used for testing a TV input which doesn't have its leanback launcher activity.
+ private static final String NONE_LEANBACK_TV_INPUT_PACKAGE_NAME =
+ "com.android.tv.none_leanback_tv_input";
+ // Used for testing a TV input which has its leanback launcher activity.
+ private static final String LEANBACK_TV_INPUT_PACKAGE_NAME = "com.android.tv.leanback_tv_input";
+ private static final String TEST_APP_LINK_TEXT = "test_app_link_text";
+ private static final String PARTNER_INPUT_ID = "partner";
+ private static final ActivityInfo TEST_ACTIVITY_INFO = new ActivityInfo();
+
+ private Context mMockContext;
+ private Intent mInvalidIntent;
+ private Intent mValidIntent;
+
+ @Before
+ public void setUp() throws NameNotFoundException {
+ mInvalidIntent = new Intent(Intent.ACTION_VIEW);
+ mInvalidIntent.setComponent(new ComponentName(INVALID_TV_INPUT_PACKAGE_NAME, ".test"));
+ mValidIntent = new Intent(Intent.ACTION_VIEW);
+ mValidIntent.setComponent(new ComponentName(LEANBACK_TV_INPUT_PACKAGE_NAME, ".test"));
+ Intent liveChannelsIntent = new Intent(Intent.ACTION_VIEW);
+ liveChannelsIntent.setComponent(
+ new ComponentName(LIVE_CHANNELS_PACKAGE_NAME, ".MainActivity"));
+ Intent leanbackTvInputIntent = new Intent(Intent.ACTION_VIEW);
+ leanbackTvInputIntent.setComponent(
+ new ComponentName(LEANBACK_TV_INPUT_PACKAGE_NAME, ".test"));
+
+ PackageManager mockPackageManager = Mockito.mock(PackageManager.class);
+ Mockito.when(
+ mockPackageManager.getLeanbackLaunchIntentForPackage(
+ INVALID_TV_INPUT_PACKAGE_NAME))
+ .thenReturn(null);
+ Mockito.when(
+ mockPackageManager.getLeanbackLaunchIntentForPackage(
+ LIVE_CHANNELS_PACKAGE_NAME))
+ .thenReturn(liveChannelsIntent);
+ Mockito.when(
+ mockPackageManager.getLeanbackLaunchIntentForPackage(
+ NONE_LEANBACK_TV_INPUT_PACKAGE_NAME))
+ .thenReturn(null);
+ Mockito.when(
+ mockPackageManager.getLeanbackLaunchIntentForPackage(
+ LEANBACK_TV_INPUT_PACKAGE_NAME))
+ .thenReturn(leanbackTvInputIntent);
+
+ // Channel.getAppLinkIntent() calls initAppLinkTypeAndIntent() which calls
+ // Intent.resolveActivityInfo() which calls PackageManager.getActivityInfo().
+ Mockito.doAnswer(
+ new Answer<ActivityInfo>() {
+ @Override
+ public ActivityInfo answer(InvocationOnMock invocation) {
+ // We only check the package name, since the class name can be
+ // changed
+ // when an intent is changed to an uri and created from the uri.
+ // (ex, ".className" -> "packageName.className")
+ return mValidIntent
+ .getComponent()
+ .getPackageName()
+ .equals(
+ ((ComponentName)
+ invocation
+ .getArguments()[0])
+ .getPackageName())
+ ? TEST_ACTIVITY_INFO
+ : null;
+ }
+ })
+ .when(mockPackageManager)
+ .getActivityInfo(Mockito.<ComponentName>any(), Mockito.anyInt());
+
+ mMockContext = Mockito.mock(Context.class);
+ Mockito.when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ Mockito.when(mMockContext.getPackageName()).thenReturn(LIVE_CHANNELS_PACKAGE_NAME);
+ Mockito.when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
+ }
+
+ @Test
+ public void testGetAppLinkType_NoText_NoIntent() {
+ assertAppLinkType(Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, null);
+ assertAppLinkType(Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, null);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE, NONE_LEANBACK_TV_INPUT_PACKAGE_NAME, null, null);
+ assertAppLinkType(Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, null);
+ }
+
+ @Test
+ public void testGetAppLinkType_NoText_InvalidIntent() {
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, mInvalidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
+ null,
+ mInvalidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mInvalidIntent);
+ }
+
+ @Test
+ public void testGetAppLinkType_NoText_ValidIntent() {
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE, INVALID_TV_INPUT_PACKAGE_NAME, null, mValidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, null, mValidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
+ null,
+ mValidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_APP, LEANBACK_TV_INPUT_PACKAGE_NAME, null, mValidIntent);
+ }
+
+ @Test
+ public void testGetAppLinkType_HasText_NoIntent() {
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ INVALID_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ null);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE, LIVE_CHANNELS_PACKAGE_NAME, TEST_APP_LINK_TEXT, null);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ null);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_APP,
+ LEANBACK_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ null);
+ }
+
+ @Test
+ public void testGetAppLinkType_HasText_InvalidIntent() {
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ INVALID_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mInvalidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ LIVE_CHANNELS_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mInvalidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_NONE,
+ NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mInvalidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_APP,
+ LEANBACK_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mInvalidIntent);
+ }
+
+ @Test
+ public void testGetAppLinkType_HasText_ValidIntent() {
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_CHANNEL,
+ INVALID_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mValidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_CHANNEL,
+ LIVE_CHANNELS_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mValidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_CHANNEL,
+ NONE_LEANBACK_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mValidIntent);
+ assertAppLinkType(
+ Channel.APP_LINK_TYPE_CHANNEL,
+ LEANBACK_TV_INPUT_PACKAGE_NAME,
+ TEST_APP_LINK_TEXT,
+ mValidIntent);
+ }
+
+ private void assertAppLinkType(
+ int expectedType, String inputPackageName, String appLinkText, Intent appLinkIntent) {
+ // In ChannelImpl, Intent.URI_INTENT_SCHEME is used to parse the URI. So the same flag
+ // should be
+ // used when the URI is created.
+ ChannelImpl testChannel =
+ new ChannelImpl.Builder()
+ .setPackageName(inputPackageName)
+ .setAppLinkText(appLinkText)
+ .setAppLinkIntentUri(
+ appLinkIntent == null
+ ? null
+ : appLinkIntent.toUri(Intent.URI_INTENT_SCHEME))
+ .build();
+ assertWithMessage("Unexpected app-link type for for " + testChannel)
+ .that(testChannel.getAppLinkType(mMockContext))
+ .isEqualTo(expectedType);
+ }
+
+ @Test
+ public void testComparator() {
+ TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class);
+ Mockito.when(manager.isPartnerInput(Matchers.anyString()))
+ .thenAnswer(
+ new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock invocation) throws Throwable {
+ String inputId = (String) invocation.getArguments()[0];
+ return PARTNER_INPUT_ID.equals(inputId);
+ }
+ });
+ Comparator<Channel> comparator = new TestChannelComparator(manager);
+ ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator);
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).build());
+ comparatorTester.addComparableGroup(new ChannelImpl.Builder().setInputId("1").build());
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setInputId("1").setDisplayNumber("2").build());
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setInputId("2").setDisplayNumber("1.0").build());
+
+ // display name does not affect comparator
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder()
+ .setInputId("2")
+ .setDisplayNumber("1.62")
+ .setDisplayName("test1")
+ .build(),
+ new ChannelImpl.Builder()
+ .setInputId("2")
+ .setDisplayNumber("1.62")
+ .setDisplayName("test2")
+ .build(),
+ new ChannelImpl.Builder()
+ .setInputId("2")
+ .setDisplayNumber("1.62")
+ .setDisplayName("test3")
+ .build());
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setInputId("2").setDisplayNumber("2.0").build());
+ // Numeric display number sorting
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setInputId("2").setDisplayNumber("12.2").build());
+ comparatorTester.test();
+ }
+
+ /**
+ * Test Input Label handled by {@link ChannelImpl.DefaultComparator}.
+ *
+ * <p>Sort partner inputs first, then sort by input label, then by input id. See <a
+ * href="http://b/23031603">b/23031603</a>.
+ */
+ @Test
+ public void testComparatorLabel() {
+ TvInputManagerHelper manager = Mockito.mock(TvInputManagerHelper.class);
+ Mockito.when(manager.isPartnerInput(Matchers.anyString()))
+ .thenAnswer(
+ new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock invocation) throws Throwable {
+ String inputId = (String) invocation.getArguments()[0];
+ return PARTNER_INPUT_ID.equals(inputId);
+ }
+ });
+ Comparator<Channel> comparator = new ChannelComparatorWithDescriptionAsLabel(manager);
+ ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator);
+
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build());
+
+ // The description is used as a label for this test.
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setDescription("A").setInputId("1").build());
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setDescription("A").setInputId("2").build());
+ comparatorTester.addComparableGroup(
+ new ChannelImpl.Builder().setDescription("B").setInputId("1").build());
+
+ comparatorTester.test();
+ }
+
+ @Test
+ public void testNormalizeChannelNumber() {
+ assertNormalizedDisplayNumber(null, null);
+ assertNormalizedDisplayNumber("", "");
+ assertNormalizedDisplayNumber("1", "1");
+ assertNormalizedDisplayNumber("abcde", "abcde");
+ assertNormalizedDisplayNumber("1-1", "1-1");
+ assertNormalizedDisplayNumber("1.1", "1-1");
+ assertNormalizedDisplayNumber("1 1", "1-1");
+ assertNormalizedDisplayNumber("1\u058a1", "1-1");
+ assertNormalizedDisplayNumber("1\u05be1", "1-1");
+ assertNormalizedDisplayNumber("1\u14001", "1-1");
+ assertNormalizedDisplayNumber("1\u18061", "1-1");
+ assertNormalizedDisplayNumber("1\u20101", "1-1");
+ assertNormalizedDisplayNumber("1\u20111", "1-1");
+ assertNormalizedDisplayNumber("1\u20121", "1-1");
+ assertNormalizedDisplayNumber("1\u20131", "1-1");
+ assertNormalizedDisplayNumber("1\u20141", "1-1");
+ }
+
+ private void assertNormalizedDisplayNumber(String displayNumber, String normalized) {
+ assertThat(ChannelImpl.normalizeDisplayNumber(displayNumber)).isEqualTo(normalized);
+ }
+
+ private static final class TestChannelComparator extends ChannelImpl.DefaultComparator {
+ public TestChannelComparator(TvInputManagerHelper manager) {
+ super(null, manager);
+ }
+
+ @Override
+ public String getInputLabelForChannel(Channel channel) {
+ return channel.getInputId();
+ }
+ }
+
+ private static final class ChannelComparatorWithDescriptionAsLabel
+ extends ChannelImpl.DefaultComparator {
+ public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) {
+ super(null, manager);
+ }
+
+ @Override
+ public String getInputLabelForChannel(Channel channel) {
+ return channel.getDescription();
+ }
+ }
+}