diff --git a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt index acb44e965307d9bd3935c45e514cec46a8b363e1..2bfd5578aa5ff7dc8d8ef530a04dd50c0f1c7438 100644 --- a/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt +++ b/app/src/main/java/foundation/e/apps/data/gplay/utils/GPlayHttpClient.kt @@ -19,6 +19,7 @@ package foundation.e.apps.data.gplay.utils +import androidx.annotation.VisibleForTesting import com.aurora.gplayapi.data.models.PlayResponse import com.aurora.gplayapi.network.IHttpClient import foundation.e.apps.data.login.AuthObject @@ -61,7 +62,8 @@ class GPlayHttpClient @Inject constructor( const val STATUS_CODE_TIMEOUT = 408 } - private val okHttpClient = OkHttpClient().newBuilder() + @VisibleForTesting + var okHttpClient = OkHttpClient().newBuilder() .retryOnConnectionFailure(false) .callTimeout(HTTP_TIMEOUT_IN_SECOND, TimeUnit.SECONDS) .followRedirects(true) diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt similarity index 99% rename from app/src/test/java/foundation/e/apps/FusedApiImplTest.kt rename to app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt index 3096c444c0309461cf941da1d3d1209197c0deb6..816394481bf93a1dbfd262897aec913cbe474d64 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/fused/FusedApiImplTest.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.apps +package foundation.e.apps.fused import android.content.Context import android.text.format.Formatter @@ -25,6 +25,8 @@ import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.SearchBundle +import foundation.e.apps.FakePreferenceModule +import foundation.e.apps.R import foundation.e.apps.data.cleanapk.data.categories.Categories import foundation.e.apps.data.cleanapk.data.search.Search import foundation.e.apps.data.cleanapk.repositories.CleanApkRepository @@ -682,7 +684,7 @@ class FusedApiImplTest { Mockito.`when`( gPlayAPIRepository.getCategories(CategoryType.APPLICATION) - ).thenThrow(RuntimeException()) + ).thenThrow() val categoryListResponse = fusedAPIImpl.getCategoriesList(CategoryType.APPLICATION) diff --git a/app/src/test/java/foundation/e/apps/FusedApiRepositoryTest.kt b/app/src/test/java/foundation/e/apps/fused/FusedApiRepositoryTest.kt similarity index 98% rename from app/src/test/java/foundation/e/apps/FusedApiRepositoryTest.kt rename to app/src/test/java/foundation/e/apps/fused/FusedApiRepositoryTest.kt index 8e04ce98e89935f2a9afa77e22afd23f0523aab3..801ae4437c2ef778c07e7fd80d0c709c953040d8 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiRepositoryTest.kt +++ b/app/src/test/java/foundation/e/apps/fused/FusedApiRepositoryTest.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package foundation.e.apps +package foundation.e.apps.fused import foundation.e.apps.data.fused.FusedAPIRepository import foundation.e.apps.data.fused.FusedApiImpl diff --git a/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt b/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f906f6fb983e1c6d262a87fcf15dd520264da4b7 --- /dev/null +++ b/app/src/test/java/foundation/e/apps/gplay/GplyHttpClientTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.gplay + +import com.aurora.gplayapi.data.models.PlayResponse +import foundation.e.apps.data.gplay.utils.GPlayHttpClient +import foundation.e.apps.data.login.AuthObject +import foundation.e.apps.util.FakeCall +import foundation.e.apps.util.MainCoroutineRule +import foundation.e.apps.utils.SystemInfoProvider +import foundation.e.apps.utils.eventBus.AppEvent +import foundation.e.apps.utils.eventBus.EventBus +import io.mockk.every +import io.mockk.mockkObject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import okhttp3.Cache +import okhttp3.OkHttpClient +import okhttp3.RequestBody.Companion.toRequestBody +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue + +@OptIn(ExperimentalCoroutinesApi::class) +class GplyHttpClientTest { + + @Mock + private lateinit var cache: Cache + + @Mock + private lateinit var okHttpClient: OkHttpClient + + private lateinit var call: FakeCall + + private lateinit var gPlayHttpClient: GPlayHttpClient + + @OptIn(ExperimentalCoroutinesApi::class) + @get:Rule + val coroutineTestRule = MainCoroutineRule() + + @Before + fun setup() { + MockitoAnnotations.openMocks(this) + gPlayHttpClient = GPlayHttpClient(cache) + gPlayHttpClient.okHttpClient = this.okHttpClient + call = FakeCall() + } + + @Test + fun testPostWithMapFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.post("http://abc.abc", mapOf(), mapOf()) + assertResponse(response) + } + + @Test + fun testPostWithRequestBodyFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.post("http://abc.abc", mapOf(), "".toRequestBody()) + assertResponse(response) + } + + @Test + fun testPostWithByteArrayFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.post("http://abc.abc", mapOf(), "".toByteArray()) + assertResponse(response) + } + + @Test + fun testGetWithoutParamsFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.get(FakeCall.FAKE_URL, mapOf()) + assertResponse(response) + } + + @Test + fun testGetWithStringParamsFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.get(FakeCall.FAKE_URL, mapOf(), "") + assertResponse(response) + } + + @Test + fun testGetWithMapParamsFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.get(FakeCall.FAKE_URL, mapOf(), mapOf()) + assertResponse(response) + } + + @Test + fun testPostAuthFailedWhenStatus401() = runTest { + initMocks() + val response = gPlayHttpClient.postAuth("http://abc.abc", "".toByteArray()) + assertResponse(response) + } + + private fun initMocks() { + call.willThrow401 = true + mockkObject(SystemInfoProvider) + every { SystemInfoProvider.getAppBuildInfo() } returns "" + Mockito.`when`(okHttpClient.newCall(any())).thenReturn(call) + } + private suspend fun assertResponse(response: PlayResponse) { + assertFalse(response.isSuccessful) + assertTrue(response.code == 401) + val event = EventBus.events.first() + assertTrue(event is AppEvent.InvalidAuthEvent) + assertTrue(event.data is String) + assertTrue(event.data == AuthObject.GPlayAuth::class.java.simpleName) + } +} diff --git a/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt b/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..01521a1fff76162299a3a1527e49cdab8f48db24 --- /dev/null +++ b/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.login + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.aurora.gplayapi.data.models.AuthData +import foundation.e.apps.data.ResultSupreme +import foundation.e.apps.data.enums.User +import foundation.e.apps.data.login.AuthObject +import foundation.e.apps.data.login.LoginSourceRepository +import foundation.e.apps.data.login.LoginViewModel +import okhttp3.Cache +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +class LoginViewModelTest { + + @Mock + private lateinit var loginSourceRepository: LoginSourceRepository + @Mock + private lateinit var cache: Cache + + private lateinit var loginViewModel: LoginViewModel + + @Suppress("unused") + @get:Rule + val instantTaskExecutorRule: InstantTaskExecutorRule = InstantTaskExecutorRule() + + @Before + fun setup() { + MockitoAnnotations.openMocks(this) + loginViewModel = LoginViewModel(loginSourceRepository, cache) + } + + @Test + fun testMarkInvalidAuthObject() { + val authObjectList = mutableListOf( + AuthObject.GPlayAuth( + ResultSupreme.Success(AuthData("aa@aa.com", "feri4234")), User.GOOGLE + ) + ) + loginViewModel.authObjects.value = authObjectList + + loginViewModel.markInvalidAuthObject(AuthObject.GPlayAuth::class.java.simpleName) + val currentAuthObjectList = loginViewModel.authObjects.value as List + val invalidGplayAuth = currentAuthObjectList.find { it is AuthObject.GPlayAuth } + + assert(invalidGplayAuth != null) + assert((invalidGplayAuth as AuthObject.GPlayAuth).result.isUnknownError()) + } +} \ No newline at end of file diff --git a/app/src/test/java/foundation/e/apps/util/FakeCall.kt b/app/src/test/java/foundation/e/apps/util/FakeCall.kt new file mode 100644 index 0000000000000000000000000000000000000000..1c6aa71d81dc64eb600d897a6eb7078b9f9ebc81 --- /dev/null +++ b/app/src/test/java/foundation/e/apps/util/FakeCall.kt @@ -0,0 +1,79 @@ +/* + * Copyright MURENA SAS 2023 + * Apps Quickly and easily install Android apps onto your device! + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package foundation.e.apps.util + +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Protocol +import okhttp3.Request +import okhttp3.Response +import okhttp3.ResponseBody +import okhttp3.ResponseBody.Companion.toResponseBody +import okio.Timeout + +class FakeCall : Call { + + var willThrow401 = false + + companion object { + const val FAKE_URL = "https://abc.abc" + } + + private val fakeRequest = Request.Builder().url(FAKE_URL).build() + override fun cancel() { + TODO("Not yet implemented") + } + + override fun clone(): Call { + TODO("Not yet implemented") + } + + override fun enqueue(responseCallback: Callback) { + TODO("Not yet implemented") + } + + override fun execute(): Response { + if (willThrow401) { + return Response.Builder() + .request(fakeRequest) + .protocol(Protocol.HTTP_2) + .message("") + .code(401) + .body("".toResponseBody()) + .build() + } + return Response.Builder().build() + } + + override fun isCanceled(): Boolean { + TODO("Not yet implemented") + } + + override fun isExecuted(): Boolean { + TODO("Not yet implemented") + } + + override fun request(): Request { + TODO("Not yet implemented") + } + + override fun timeout(): Timeout { + TODO("Not yet implemented") + } +} \ No newline at end of file