From b0813b61107802bac290a81e01c0c442b3569fda Mon Sep 17 00:00:00 2001
From: ksergeevit <64887317+ksergeevit@users.noreply.github.com>
Date: Tue, 9 Jun 2020 10:20:35 +0300
Subject: [PATCH] EN tests (#284)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Jakob Möller <jakob.moeller@sap.com>
---
 Corona-Warn-App/build.gradle                  |   3 +-
 .../java/de/rki/coronawarnapp/TestFragment.kt |  20 +++
 ...xposureNotificationPermissionHelperTest.kt | 158 ++++++++++++++++++
 .../ExposureStateUpdateReceiverTest.kt        |  56 +++++++
 4 files changed, 236 insertions(+), 1 deletion(-)
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt
 create mode 100644 Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt
 create mode 100644 Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt

diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index 3ad809646..179b21c57 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -181,7 +181,8 @@ dependencies {
     androidTestImplementation 'androidx.test:rules:1.2.0'
     androidTestImplementation 'androidx.test.ext:truth:1.2.0'
     androidTestImplementation 'androidx.test.ext:junit:1.1.1'
-
+    androidTestImplementation "io.mockk:mockk-android:1.10.0"
+    debugImplementation 'androidx.fragment:fragment-testing:1.2.4'
 
     // Play Services
     implementation 'com.google.android.play:core:1.7.3'
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt
new file mode 100644
index 000000000..45170cdb4
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/TestFragment.kt
@@ -0,0 +1,20 @@
+package de.rki.coronawarnapp
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+
+/**
+ * Test fragment with test view, [TextView] required for view lifecycle owner.
+ *
+ * @see [Fragment.getViewLifecycleOwner]
+ */
+class TestFragment : Fragment() {
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        return TextView(this.context)
+    }
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt
new file mode 100644
index 000000000..ebcab98c7
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/nearby/InternalExposureNotificationPermissionHelperTest.kt
@@ -0,0 +1,158 @@
+package de.rki.coronawarnapp.nearby
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.testing.FragmentScenario
+import androidx.fragment.app.testing.launchFragmentInContainer
+import androidx.localbroadcastmanager.content.LocalBroadcastManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.android.gms.common.api.ApiException
+import com.google.android.gms.common.api.Status
+import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
+import de.rki.coronawarnapp.CoronaWarnApplication
+import de.rki.coronawarnapp.TestFragment
+import io.mockk.coEvery
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.mockkObject
+import io.mockk.unmockkAll
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * InternalExposureNotificationPermissionHelper test.
+ */
+@RunWith(AndroidJUnit4::class)
+class InternalExposureNotificationPermissionHelperTest {
+    private lateinit var scenario: FragmentScenario<TestFragment>
+    private var fail = false
+    private var startSuccess = false
+    private var sharingSuccess = false
+    private val callback = object : InternalExposureNotificationPermissionHelper.Callback {
+        override fun onFailure(exception: Exception?) {
+            fail = true
+        }
+        override fun onStartPermissionGranted() {
+            startSuccess = true
+        }
+        override fun onKeySharePermissionGranted(keys: List<TemporaryExposureKey>) {
+            sharingSuccess = true
+        }
+    }
+
+    /**
+     * Launch test fragment, required for view lifecycle owner.
+     *
+     * @see [InternalExposureNotificationPermissionHelper]
+     * @see [Fragment.getViewLifecycleOwner]
+     */
+    @Before
+    fun setUp() {
+        fail = false
+        startSuccess = false
+        sharingSuccess = false
+        mockkObject(InternalExposureNotificationClient)
+        scenario = launchFragmentInContainer<TestFragment>()
+    }
+
+    /**
+     * Test tracing permission request assuming EN Client is enabled.
+     */
+    @Test
+    fun testRequestPermissionToStartTracingENIsEnabled() {
+        coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns true
+        scenario.onFragment {
+            val helper = InternalExposureNotificationPermissionHelper(it, callback)
+            helper.requestPermissionToStartTracing()
+        }
+        assertThat(fail, `is`(false))
+        assertThat(startSuccess, `is`(true))
+    }
+
+    /**
+     * Test tracing permission request assuming EN Client is disabled.
+     */
+    @Test
+    fun testRequestPermissionToStartTracingENIsNotEnabled() {
+        coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns false
+        // not every device/emulator has access to exposure notifications Google API:
+        coEvery { InternalExposureNotificationClient.asyncStart() } returns mockk()
+
+        scenario.onFragment {
+            val helper = InternalExposureNotificationPermissionHelper(it, callback)
+            helper.requestPermissionToStartTracing()
+        }
+        assertThat(fail, `is`(false))
+        assertThat(startSuccess, `is`(true))
+    }
+
+    /**
+     * Test tracing permission request exception handling.
+     */
+    @Test
+    fun testRequestPermissionToStartTracingExceptionHandling() {
+        coEvery { InternalExposureNotificationClient.asyncIsEnabled() } returns false
+
+        // not every device/emulator has access to exposure notifications Google API:
+        coEvery { InternalExposureNotificationClient.asyncStart() } throws mockApiException(Status.RESULT_CANCELED)
+
+        scenario.onFragment {
+            val helper = InternalExposureNotificationPermissionHelper(it, callback)
+            helper.requestPermissionToStartTracing()
+        }
+        assertThat(fail, `is`(true))
+        assertThat(startSuccess, `is`(false))
+    }
+
+    /**
+     * Test keys sharing permission request.
+     */
+    @Test
+    fun testRequestPermissionToShareKeys() {
+        // not every device/emulator has access to exposure notifications Google API:
+        coEvery { InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory() } returns mockk()
+
+        scenario.onFragment {
+            val helper = InternalExposureNotificationPermissionHelper(it, callback)
+            helper.requestPermissionToShareKeys()
+        }
+        assertThat(fail, `is`(false))
+        assertThat(sharingSuccess, `is`(true))
+    }
+
+    /**
+     * Test keys sharing permission request exception handling.
+     */
+    @Test
+    fun testRequestPermissionToShareKeysException() {
+        // not every device/emulator has access to exposure notifications Google API:
+        coEvery {
+            InternalExposureNotificationClient.asyncGetTemporaryExposureKeyHistory()
+        } throws mockApiException(Status.RESULT_CANCELED)
+
+        scenario.onFragment {
+            val helper = InternalExposureNotificationPermissionHelper(it, callback)
+            helper.requestPermissionToShareKeys()
+        }
+        assertThat(fail, `is`(true))
+        assertThat(sharingSuccess, `is`(false))
+    }
+
+    private fun mockApiException(status: Status): ApiException {
+        mockkObject(LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext()))
+        val exception = ApiException(status)
+        // don't need a dialog for exception
+        every {
+            LocalBroadcastManager.getInstance(CoronaWarnApplication.getAppContext()).sendBroadcast(any())
+        } returns true
+        return exception
+    }
+
+    @After
+    fun cleanUp() {
+        unmockkAll()
+    }
+}
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt
new file mode 100644
index 000000000..19ac4f2c8
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/receiver/ExposureStateUpdateReceiverTest.kt
@@ -0,0 +1,56 @@
+package de.rki.coronawarnapp.receiver
+
+import android.content.Context
+import android.content.Intent
+import androidx.work.WorkManager
+import androidx.work.WorkRequest
+import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import io.mockk.mockkStatic
+import io.mockk.unmockkAll
+import io.mockk.verify
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+/**
+ * ExposureStateUpdateReceiver test.
+ */
+class ExposureStateUpdateReceiverTest {
+    @MockK
+    private lateinit var context: Context
+    @MockK
+    private lateinit var intent: Intent
+
+    @Before
+    fun setUp() {
+        MockKAnnotations.init(this)
+        mockkStatic(WorkManager::class)
+        every { intent.action } returns ExposureNotificationClient.ACTION_EXPOSURE_STATE_UPDATED
+        every { intent.getStringExtra(ExposureNotificationClient.EXTRA_TOKEN) } returns "token"
+    }
+
+    /**
+     * Test ExposureStateUpdateReceiver.
+     */
+    @Test
+    fun testExposureStateUpdateReceiver() {
+        val wm = mockk<WorkManager>()
+        every { WorkManager.getInstance(context) } returns wm
+        every { wm.enqueue(any<WorkRequest>()) } answers { mockk() }
+
+        ExposureStateUpdateReceiver().onReceive(context, intent)
+
+        verify {
+            wm.enqueue(any<WorkRequest>())
+        }
+    }
+
+    @After
+    fun cleanUp() {
+        unmockkAll()
+    }
+}
-- 
GitLab