diff options
Diffstat (limited to 'tests/unit/src/com/android/tv/data/ChannelImplTest.java')
-rw-r--r-- | tests/unit/src/com/android/tv/data/ChannelImplTest.java | 381 |
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(); + } + } +} |