瀏覽代碼

DeckApi unit test

Signed-off-by: Chris Narkiewicz <hello@ezaquarii.com>
Chris Narkiewicz 5 年之前
父節點
當前提交
b10038cced

+ 177 - 0
src/androidTest/java/com/nextcloud/client/integration/deck/DeckApiTest.kt

@@ -0,0 +1,177 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Chris Narkiewicz
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.client.integration.deck
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import androidx.test.platform.app.InstrumentationRegistry
+import com.nextcloud.client.account.User
+import com.nhaarman.mockitokotlin2.any
+import com.nhaarman.mockitokotlin2.anyOrNull
+import com.nhaarman.mockitokotlin2.never
+import com.nhaarman.mockitokotlin2.times
+import com.nhaarman.mockitokotlin2.verify
+import com.nhaarman.mockitokotlin2.whenever
+import com.owncloud.android.lib.resources.notifications.models.Notification
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Suite
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(Suite::class)
+@Suite.SuiteClasses(
+    DeckApiTest.DeckIsInstalled::class,
+    DeckApiTest.DeckIsNotInstalled::class
+)
+class DeckApiTest {
+
+    abstract class Fixture {
+        @Mock
+        lateinit var packageManager: PackageManager
+
+        lateinit var context: Context
+
+        @Mock
+        lateinit var user: User
+
+        lateinit var deck: DeckApiImpl
+
+        @Before
+        fun setUpFixture() {
+            MockitoAnnotations.initMocks(this)
+            context = InstrumentationRegistry.getInstrumentation().targetContext
+            deck = DeckApiImpl(context, packageManager)
+        }
+    }
+
+    @RunWith(Parameterized::class)
+    class DeckIsInstalled : Fixture() {
+
+        @Parameterized.Parameter(0)
+        lateinit var installedDeckPackage: String
+
+        companion object {
+            @Parameterized.Parameters
+            @JvmStatic
+            fun initParametrs(): Array<String> {
+                return DeckApiImpl.DECK_APP_PACKAGES
+            }
+        }
+
+        @Before
+        fun setUp() {
+            whenever(packageManager.resolveActivity(any(), any())).thenAnswer {
+                val intent = it.getArgument<Intent>(0)
+                return@thenAnswer if (intent.component?.packageName == installedDeckPackage) {
+                    ResolveInfo()
+                } else {
+                    null
+                }
+            }
+        }
+
+        @Test
+        fun can_forward_deck_notification() {
+            // GIVEN
+            //      notification to deck arrives
+            val notification = Notification().apply { app = "deck" }
+
+            // WHEN
+            //      deck action is created
+            val forwardActionIntent = deck.createForwardToDeckActionIntent(notification, user)
+
+            // THEN
+            //      open action is created
+            assertTrue("Failed for $installedDeckPackage", forwardActionIntent.isPresent)
+        }
+
+        @Test
+        fun notifications_from_other_apps_are_ignored() {
+            // GIVEN
+            //      notification from other app arrives
+            val deckNotification = Notification().apply {
+                app = "some_other_app"
+            }
+
+            // WHEN
+            //      deck action is created
+            val openDeckActionIntent = deck.createForwardToDeckActionIntent(deckNotification, user)
+
+            // THEN
+            //      deck application is not being resolved
+            //      open action is not created
+            verify(packageManager, never()).resolveActivity(anyOrNull(), anyOrNull())
+            assertFalse(openDeckActionIntent.isPresent)
+        }
+    }
+
+    class DeckIsNotInstalled : Fixture() {
+
+        @Before
+        fun setUp() {
+            whenever(packageManager.resolveActivity(any(), any())).thenReturn(null)
+        }
+
+        @Test
+        fun cannot_forward_deck_notification() {
+            // GIVEN
+            //      notification is coming from deck app
+            val notification = Notification().apply {
+                app = DeckApiImpl.APP_NAME
+            }
+
+            // WHEN
+            //      creating open in deck action
+            val openDeckActionIntent = deck.createForwardToDeckActionIntent(notification, user)
+
+            // THEN
+            //      deck application is being resolved using all known packages
+            //      open action is not created
+            verify(packageManager, times(DeckApiImpl.DECK_APP_PACKAGES.size)).resolveActivity(anyOrNull(), anyOrNull())
+            assertFalse(openDeckActionIntent.isPresent)
+        }
+
+        @Test
+        fun notifications_from_other_apps_are_ignored() {
+            // GIVEN
+            //      notification is coming from other app
+            val notification = Notification().apply {
+                app = "some_other_app"
+            }
+
+            // WHEN
+            //      creating open in deck action
+            val openDeckActionIntent = deck.createForwardToDeckActionIntent(notification, user)
+
+            // THEN
+            //      deck application is not being resolved
+            //      open action is not created
+            verify(packageManager, never()).resolveActivity(anyOrNull(), anyOrNull())
+            assertFalse(openDeckActionIntent.isPresent)
+        }
+    }
+}

+ 14 - 9
src/main/java/com/nextcloud/client/integration/deck/DeckApiImpl.java

@@ -23,7 +23,7 @@ package com.nextcloud.client.integration.deck;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
+import android.content.pm.PackageManager;
 
 import com.nextcloud.client.account.User;
 import com.nextcloud.java.util.Optional;
@@ -35,10 +35,13 @@ public class DeckApiImpl implements DeckApi {
 
     private static final String TAG = DeckApiImpl.class.getSimpleName();
 
-    private static final String APP_NAME = "deck";
-    private static final String DECK_APP_ID_BASE = "it.niedermann.nextcloud.deck";
-    private static final String[] DECK_APP_ID_FLAVOR_SUFFIXES = new String[]{"", ".play", ".dev"};
-    private static final String DECK_ACTIVITY_TO_START = "it.niedermann.nextcloud.deck.ui.PushNotificationActivity";
+    static final String APP_NAME = "deck";
+    static final String[] DECK_APP_PACKAGES = new String[] {
+        "it.niedermann.nextcloud.deck",
+        "it.niedermann.nextcloud.deck.play",
+        "it.niedermann.nextcloud.deck.dev"
+    };
+    static final String DECK_ACTIVITY_TO_START = "it.niedermann.nextcloud.deck.ui.PushNotificationActivity";
 
     private static final String EXTRA_ACCOUNT = "account";
     private static final String EXTRA_LINK = "link";
@@ -51,9 +54,11 @@ public class DeckApiImpl implements DeckApi {
     private static final String EXTRA_NID = "nid";
 
     private final Context context;
+    private final PackageManager packageManager;
 
-    public DeckApiImpl(@NonNull Context context) {
+    public DeckApiImpl(@NonNull Context context, @NonNull PackageManager packageManager) {
         this.context = context;
+        this.packageManager = packageManager;
     }
 
     @NonNull
@@ -61,9 +66,9 @@ public class DeckApiImpl implements DeckApi {
     public Optional<PendingIntent> createForwardToDeckActionIntent(@NonNull Notification notification, @NonNull User user) {
         if (APP_NAME.equalsIgnoreCase(notification.app)) {
             final Intent intent = new Intent();
-            for (String flavor : DECK_APP_ID_FLAVOR_SUFFIXES) {
-                intent.setClassName(DECK_APP_ID_BASE + flavor, DECK_ACTIVITY_TO_START);
-                if (context.getPackageManager().resolveActivity(intent, 0) != null) {
+            for (String appPackage : DECK_APP_PACKAGES) {
+                intent.setClassName(appPackage, DECK_ACTIVITY_TO_START);
+                if (packageManager.resolveActivity(intent, 0) != null) {
                     return Optional.of(createPendingIntent(intent, notification, user));
                 }
             }